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