1 /*
2 * Copyright (c) 2014, Mentor Graphics Corporation
3 * Copyright (c) 2018, Xilinx Inc.
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include <metal/io.h>
10 #include <metal/utilities.h>
11
12 #include "rsc_table_parser.h"
13
14 #define RSC_TAB_SUPPORTED_VERSION 1
15
16 /**
17 * @internal
18 *
19 * @brief Carveout resource handler.
20 *
21 * @param rproc Pointer to remote remoteproc
22 * @param rsc Pointer to carveout resource
23 *
24 * @return 0 for success, or negative value for failure
25 */
handle_carve_out_rsc(struct remoteproc * rproc,void * rsc)26 static int handle_carve_out_rsc(struct remoteproc *rproc, void *rsc)
27 {
28 struct fw_rsc_carveout *carve_rsc = rsc;
29 metal_phys_addr_t da;
30 metal_phys_addr_t pa;
31 size_t size;
32 unsigned int attribute;
33
34 /* Validate resource fields */
35 if (!carve_rsc) {
36 return -RPROC_ERR_RSC_TAB_NP;
37 }
38
39 if (carve_rsc->reserved) {
40 return -RPROC_ERR_RSC_TAB_RSVD;
41 }
42 pa = carve_rsc->pa;
43 da = carve_rsc->da;
44 size = carve_rsc->len;
45 attribute = carve_rsc->flags;
46 if (remoteproc_mmap(rproc, &pa, &da, size, attribute, NULL))
47 return 0;
48 else
49 return -RPROC_EINVAL;
50 }
51
52 /**
53 * @internal
54 *
55 * @brief Trace resource handler.
56 *
57 * @param rproc Pointer to remote remoteproc
58 * @param rsc Pointer to trace resource
59 *
60 * @return No service error
61 */
handle_trace_rsc(struct remoteproc * rproc,void * rsc)62 static int handle_trace_rsc(struct remoteproc *rproc, void *rsc)
63 {
64 struct fw_rsc_trace *vdev_rsc = rsc;
65 (void)rproc;
66
67 if (vdev_rsc->da != FW_RSC_U32_ADDR_ANY && vdev_rsc->len != 0)
68 return 0;
69 /* FIXME: The host should allocated a memory used by remote */
70
71 return -RPROC_ERR_RSC_TAB_NS;
72 }
73
handle_vdev_rsc(struct remoteproc * rproc,void * rsc)74 static int handle_vdev_rsc(struct remoteproc *rproc, void *rsc)
75 {
76 struct fw_rsc_vdev *vdev_rsc = rsc;
77 int i, num_vrings;
78 unsigned int notifyid;
79 struct fw_rsc_vdev_vring *vring_rsc;
80
81 /* only assign notification IDs but do not initialize vdev */
82 notifyid = vdev_rsc->notifyid;
83 notifyid = remoteproc_allocate_id(rproc,
84 notifyid,
85 notifyid == RSC_NOTIFY_ID_ANY ?
86 RSC_NOTIFY_ID_ANY : notifyid + 1);
87 if (notifyid != RSC_NOTIFY_ID_ANY)
88 vdev_rsc->notifyid = notifyid;
89 else
90 return -RPROC_ERR_RSC_TAB_NP;
91
92 num_vrings = vdev_rsc->num_of_vrings;
93 for (i = 0; i < num_vrings; i++) {
94 vring_rsc = &vdev_rsc->vring[i];
95 notifyid = vring_rsc->notifyid;
96 notifyid = remoteproc_allocate_id(rproc,
97 notifyid,
98 notifyid == RSC_NOTIFY_ID_ANY ?
99 RSC_NOTIFY_ID_ANY : notifyid + 1);
100 if (notifyid != RSC_NOTIFY_ID_ANY)
101 vring_rsc->notifyid = notifyid;
102 else
103 goto err;
104 }
105
106 return 0;
107
108 err:
109 for (i--; i >= 0; i--) {
110 vring_rsc = &vdev_rsc->vring[i];
111 metal_bitmap_clear_bit(&rproc->bitmap, vring_rsc->notifyid);
112 }
113 metal_bitmap_clear_bit(&rproc->bitmap, vdev_rsc->notifyid);
114
115 return -RPROC_ERR_RSC_TAB_NP;
116 }
117
handle_vendor_rsc(struct remoteproc * rproc,void * rsc)118 static int handle_vendor_rsc(struct remoteproc *rproc, void *rsc)
119 {
120 if (rproc && rproc->ops->handle_rsc) {
121 struct fw_rsc_vendor *vend_rsc = rsc;
122 size_t len = vend_rsc->len;
123
124 return rproc->ops->handle_rsc(rproc, rsc, len);
125 }
126 return -RPROC_ERR_RSC_TAB_NS;
127 }
128
129 /**
130 * @internal
131 *
132 * @brief Dummy resource handler.
133 *
134 * @param rproc Pointer to remote remoteproc
135 * @param rsc Pointer to trace resource
136 *
137 * @return No service error
138 */
handle_dummy_rsc(struct remoteproc * rproc,void * rsc)139 static int handle_dummy_rsc(struct remoteproc *rproc, void *rsc)
140 {
141 (void)rproc;
142 (void)rsc;
143
144 return -RPROC_ERR_RSC_TAB_NS;
145 }
146
147 /* Standard control request handling. */
148 typedef int (*rsc_handler)(struct remoteproc *rproc, void *rsc);
149
150 /* Resources handler */
151 static const rsc_handler rsc_handler_table[] = {
152 handle_carve_out_rsc, /**< carved out resource */
153 handle_dummy_rsc, /**< IOMMU dev mem resource */
154 handle_trace_rsc, /**< trace buffer resource */
155 handle_vdev_rsc, /**< virtio resource */
156 };
157
handle_rsc_table(struct remoteproc * rproc,struct resource_table * rsc_table,size_t size,struct metal_io_region * io)158 int handle_rsc_table(struct remoteproc *rproc,
159 struct resource_table *rsc_table, size_t size,
160 struct metal_io_region *io)
161 {
162 struct fw_rsc_hdr *hdr;
163 uint32_t rsc_type;
164 unsigned int idx, offset;
165 int status = 0;
166
167 /* Validate rsc table header fields */
168
169 /* Minimum rsc table size */
170 if (sizeof(struct resource_table) > size) {
171 return -RPROC_ERR_RSC_TAB_TRUNC;
172 }
173
174 /* Supported version */
175 if (rsc_table->ver != RSC_TAB_SUPPORTED_VERSION) {
176 return -RPROC_ERR_RSC_TAB_VER;
177 }
178
179 /* Offset array */
180 offset = sizeof(struct resource_table)
181 + rsc_table->num * sizeof(rsc_table->offset[0]);
182
183 if (offset > size) {
184 return -RPROC_ERR_RSC_TAB_TRUNC;
185 }
186
187 /* Reserved fields - must be zero */
188 if (rsc_table->reserved[0] != 0 || rsc_table->reserved[1] != 0) {
189 return -RPROC_ERR_RSC_TAB_RSVD;
190 }
191
192 /* Loop through the offset array and parse each resource entry */
193 for (idx = 0; idx < rsc_table->num; idx++) {
194 hdr = (void *)((char *)rsc_table + rsc_table->offset[idx]);
195 if (io && metal_io_virt_to_offset(io, hdr) == METAL_BAD_OFFSET)
196 return -RPROC_ERR_RSC_TAB_TRUNC;
197 rsc_type = hdr->type;
198 if (rsc_type < RSC_LAST)
199 status = rsc_handler_table[rsc_type](rproc, hdr);
200 else if (rsc_type >= RSC_VENDOR_START &&
201 rsc_type <= RSC_VENDOR_END)
202 status = handle_vendor_rsc(rproc, hdr);
203 if (status == -RPROC_ERR_RSC_TAB_NS) {
204 status = 0;
205 continue;
206 } else if (status) {
207 break;
208 }
209 }
210
211 return status;
212 }
213
find_rsc(void * rsc_table,unsigned int rsc_type,unsigned int index)214 size_t find_rsc(void *rsc_table, unsigned int rsc_type, unsigned int index)
215 {
216 struct resource_table *r_table = rsc_table;
217 struct fw_rsc_hdr *hdr;
218 unsigned int i, rsc_index;
219 unsigned int lrsc_type;
220
221 metal_assert(r_table);
222 if (!r_table)
223 return 0;
224
225 /* Loop through the offset array and parse each resource entry */
226 rsc_index = 0;
227 for (i = 0; i < r_table->num; i++) {
228 hdr = (void *)((char *)r_table + r_table->offset[i]);
229 lrsc_type = hdr->type;
230 if (lrsc_type == rsc_type) {
231 if (rsc_index++ == index)
232 return r_table->offset[i];
233 }
234 }
235 return 0;
236 }
237