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