]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 2017 Hisilicon Limited, All Rights Reserved. | |
3 | * Author: Zhichang Yuan <yuanzhichang@hisilicon.com> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | */ | |
17 | ||
18 | #include <linux/of.h> | |
19 | #include <linux/io.h> | |
20 | #include <linux/acpi.h> | |
21 | #include <linux/mm.h> | |
22 | #include <linux/rculist.h> | |
23 | #include <linux/sizes.h> | |
24 | #include <linux/slab.h> | |
25 | ||
26 | /* A list of all the IO hosts registered. ONLY THE HOST nodes. */ | |
27 | static LIST_HEAD(io_range_list); | |
28 | static DEFINE_MUTEX(io_range_mutex); | |
29 | ||
30 | /* | |
31 | * allocate a free range for this registration. | |
32 | * | |
33 | * @new_range: point to the node awaiting this registration. | |
34 | * part of the fields are as input parameters. This node | |
35 | * is allocated and initialized by caller; | |
36 | * @prev: points to the last node before the return; | |
37 | * | |
38 | * return 0 for success, other are fail. | |
39 | */ | |
40 | static int libio_alloc_range(struct libio_range *new_range, | |
41 | struct list_head **prev) | |
42 | { | |
43 | struct libio_range *entry; | |
44 | unsigned long align = 1; | |
45 | unsigned long tmp_start; | |
46 | unsigned long idle_start, idle_end; | |
47 | ||
48 | if (new_range->flags & IO_CPU_MMIO) | |
49 | align = PAGE_SIZE; | |
50 | idle_start = 0; | |
51 | *prev = &io_range_list; | |
52 | list_for_each_entry_rcu(entry, &io_range_list, list) { | |
53 | if (idle_start > entry->io_start) { | |
54 | WARN(1, "skip an invalid io range during traversal!\n"); | |
55 | goto nextentry; | |
56 | } | |
57 | /* set the end edge. */ | |
58 | if (idle_start == entry->io_start) { | |
59 | struct libio_range *next; | |
60 | ||
61 | idle_start = entry->io_start + entry->size; | |
62 | next = list_next_or_null_rcu(&io_range_list, | |
63 | &entry->list, struct libio_range, list); | |
64 | if (next) { | |
65 | entry = next; | |
66 | } else { | |
67 | *prev = &entry->list; | |
68 | break; | |
69 | } | |
70 | } | |
71 | idle_end = entry->io_start - 1; | |
72 | ||
73 | /* contiguous range... */ | |
74 | if (idle_start > idle_end) | |
75 | goto nextentry; | |
76 | ||
77 | tmp_start = idle_start; | |
78 | idle_start = ALIGN(idle_start, align); | |
79 | if (idle_start >= tmp_start && | |
80 | idle_start + new_range->size <= idle_end) { | |
81 | new_range->io_start = idle_start; | |
82 | *prev = &entry->list; | |
83 | return 0; | |
84 | } | |
85 | ||
86 | nextentry: | |
87 | idle_start = entry->io_start + entry->size; | |
88 | *prev = &entry->list; | |
89 | } | |
90 | /* check the last free gap... */ | |
91 | idle_end = IO_SPACE_LIMIT; | |
92 | ||
93 | tmp_start = idle_start; | |
94 | idle_start = ALIGN(idle_start, align); | |
95 | if (idle_start >= tmp_start && | |
96 | idle_start + new_range->size <= idle_end) { | |
97 | new_range->io_start = idle_start; | |
98 | return 0; | |
99 | } | |
100 | ||
101 | return -EBUSY; | |
102 | } | |
103 | ||
104 | /* | |
105 | * traverse the io_range_list to find the registered node whose device node | |
106 | * and/or physical IO address match to. | |
107 | */ | |
108 | struct libio_range *find_io_range_from_fwnode(struct fwnode_handle *fwnode) | |
109 | { | |
110 | struct libio_range *range; | |
111 | ||
112 | list_for_each_entry_rcu(range, &io_range_list, list) { | |
113 | if (range->node == fwnode) | |
114 | return range; | |
115 | } | |
116 | return NULL; | |
117 | } | |
118 | ||
119 | /* | |
120 | * Search a io_range registered which match the fwnode and addr. | |
121 | * | |
122 | * @fwnode: the host fwnode which must be valid; | |
123 | * @start: the start hardware address of this search; | |
124 | * @end: the end hardware address of this search. can be equal to @start; | |
125 | * | |
126 | * return NULL when there is no matched node; IS_ERR() means ERROR; | |
127 | * valid virtual address represent a matched node was found. | |
128 | */ | |
129 | static struct libio_range * | |
130 | libio_find_range_byaddr(struct fwnode_handle *fwnode, | |
131 | resource_size_t start, resource_size_t end) | |
132 | { | |
133 | struct libio_range *entry; | |
134 | ||
135 | list_for_each_entry_rcu(entry, &io_range_list, list) { | |
136 | if (entry->node != fwnode) | |
137 | continue; | |
138 | /* without any overlap with current range */ | |
139 | if (start >= entry->hw_start + entry->size || | |
140 | end < entry->hw_start) | |
141 | continue; | |
142 | /* overlap is not supported now. */ | |
143 | if (start < entry->hw_start || | |
144 | end >= entry->hw_start + entry->size) | |
145 | return ERR_PTR(-EBUSY); | |
146 | /* had been registered. */ | |
147 | return entry; | |
148 | } | |
149 | ||
150 | return NULL; | |
151 | } | |
152 | ||
153 | /* | |
154 | * register a io range node in the io range list. | |
155 | * | |
156 | * @newrange: pointer to the io range to be registered. | |
157 | * | |
158 | * return 'newrange' when success, ERR_VALUE() is for failures. | |
159 | * specially, return a valid pointer which is not equal to 'newrange' when | |
160 | * the io range had been registered before. | |
161 | */ | |
162 | struct libio_range *register_libio_range(struct libio_range *newrange) | |
163 | { | |
164 | int err; | |
165 | struct libio_range *range; | |
166 | struct list_head *prev; | |
167 | ||
168 | if (!newrange || !newrange->node || !newrange->size) | |
169 | return ERR_PTR(-EINVAL); | |
170 | ||
171 | mutex_lock(&io_range_mutex); | |
172 | range = libio_find_range_byaddr(newrange->node, newrange->hw_start, | |
173 | newrange->hw_start + newrange->size - 1); | |
174 | if (range) { | |
175 | if (!IS_ERR(range)) | |
176 | pr_info("the request IO range had been registered!\n"); | |
177 | else | |
178 | pr_err("registering IO[%pa - sz%pa) got failed!\n", | |
179 | &newrange->hw_start, &newrange->size); | |
180 | return range; | |
181 | } | |
182 | ||
183 | err = libio_alloc_range(newrange, &prev); | |
184 | if (!err) | |
185 | /* the bus IO range list is ordered by pio. */ | |
186 | list_add_rcu(&newrange->list, prev); | |
187 | else | |
188 | pr_err("can't find free %pa logical IO range!\n", | |
189 | &newrange->size); | |
190 | ||
191 | mutex_unlock(&io_range_mutex); | |
192 | return err ? ERR_PTR(err) : newrange; | |
193 | } | |
194 | ||
195 | /* | |
196 | * Translate the input logical pio to the corresponding hardware address. | |
197 | * The input pio should be unique in the whole logical PIO space. | |
198 | */ | |
199 | resource_size_t libio_to_hwaddr(unsigned long pio) | |
200 | { | |
201 | struct libio_range *range; | |
202 | ||
203 | list_for_each_entry_rcu(range, &io_range_list, list) { | |
204 | if (pio < range->io_start) | |
205 | break; | |
206 | ||
207 | if (pio < range->io_start + range->size) | |
208 | return pio - range->io_start + range->hw_start; | |
209 | } | |
210 | ||
211 | return -1; | |
212 | } | |
213 | ||
214 | /* | |
215 | * This function is generic for translating a hardware address to logical PIO. | |
216 | * @hw_addr: the hardware address of host, can be CPU address or host-local | |
217 | * address; | |
218 | */ | |
219 | unsigned long | |
220 | libio_translate_hwaddr(struct fwnode_handle *fwnode, resource_size_t addr) | |
221 | { | |
222 | struct libio_range *range; | |
223 | ||
224 | range = libio_find_range_byaddr(fwnode, addr, addr); | |
225 | if (!range) | |
226 | return -1; | |
227 | ||
228 | return addr - range->hw_start + range->io_start; | |
229 | } | |
230 | ||
231 | unsigned long | |
232 | libio_translate_cpuaddr(resource_size_t addr) | |
233 | { | |
234 | struct libio_range *range; | |
235 | ||
236 | list_for_each_entry_rcu(range, &io_range_list, list) { | |
237 | if (!(range->flags & IO_CPU_MMIO)) | |
238 | continue; | |
239 | if (addr >= range->hw_start && | |
240 | addr < range->hw_start + range->size) | |
241 | return addr - range->hw_start + range->io_start; | |
242 | } | |
243 | return -1; | |
244 | } | |
245 | ||
246 | #ifdef CONFIG_ACPI | |
247 | static inline bool acpi_libio_supported_resource(struct acpi_resource *res) | |
248 | { | |
249 | switch (res->type) { | |
250 | case ACPI_RESOURCE_TYPE_ADDRESS32: | |
251 | case ACPI_RESOURCE_TYPE_ADDRESS64: | |
252 | return true; | |
253 | } | |
254 | return false; | |
255 | } | |
256 | ||
257 | static acpi_status acpi_count_libiores(struct acpi_resource *res, | |
258 | void *data) | |
259 | { | |
260 | int *res_cnt = data; | |
261 | ||
262 | if (acpi_libio_supported_resource(res) && | |
263 | !acpi_dev_filter_resource_type(res, IORESOURCE_IO)) | |
264 | (*res_cnt)++; | |
265 | ||
266 | return AE_OK; | |
267 | } | |
268 | ||
269 | static acpi_status acpi_read_one_libiores(struct acpi_resource *res, | |
270 | void *data) | |
271 | { | |
272 | struct acpi_resource **resource = data; | |
273 | ||
274 | if (acpi_libio_supported_resource(res) && | |
275 | !acpi_dev_filter_resource_type(res, IORESOURCE_IO)) { | |
276 | memcpy((*resource), res, sizeof(struct acpi_resource)); | |
277 | (*resource)->length = sizeof(struct acpi_resource); | |
278 | (*resource)->type = res->type; | |
279 | (*resource)++; | |
280 | } | |
281 | ||
282 | return AE_OK; | |
283 | } | |
284 | ||
285 | static acpi_status | |
286 | acpi_build_libiores_template(struct acpi_device *adev, | |
287 | struct acpi_buffer *buffer) | |
288 | { | |
289 | acpi_handle handle = adev->handle; | |
290 | struct acpi_resource *resource; | |
291 | acpi_status status; | |
292 | int res_cnt = 0; | |
293 | ||
294 | status = acpi_walk_resources(handle, METHOD_NAME__CRS, | |
295 | acpi_count_libiores, &res_cnt); | |
296 | if (ACPI_FAILURE(status) || !res_cnt) { | |
297 | dev_err(&adev->dev, "can't evaluate _CRS: %d\n", status); | |
298 | return -EINVAL; | |
299 | } | |
300 | ||
301 | buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1; | |
302 | buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL); | |
303 | if (!buffer->pointer) | |
304 | return -ENOMEM; | |
305 | ||
306 | resource = (struct acpi_resource *)buffer->pointer; | |
307 | status = acpi_walk_resources(handle, METHOD_NAME__CRS, | |
308 | acpi_read_one_libiores, &resource); | |
309 | if (ACPI_FAILURE(status)) { | |
310 | kfree(buffer->pointer); | |
311 | dev_err(&adev->dev, "can't evaluate _CRS: %d\n", status); | |
312 | return -EINVAL; | |
313 | } | |
314 | ||
315 | resource->type = ACPI_RESOURCE_TYPE_END_TAG; | |
316 | resource->length = sizeof(struct acpi_resource); | |
317 | ||
318 | return 0; | |
319 | } | |
320 | ||
321 | static int acpi_translate_libiores(struct acpi_device *adev, | |
322 | struct acpi_device *host, struct acpi_buffer *buffer) | |
323 | { | |
324 | int res_cnt = (buffer->length - 1) / sizeof(struct acpi_resource) - 1; | |
325 | struct acpi_resource *resource = buffer->pointer; | |
326 | struct acpi_resource_address64 addr; | |
327 | unsigned long sys_port; | |
328 | struct device *dev = &adev->dev; | |
329 | ||
330 | /* only one I/O resource now */ | |
331 | if (res_cnt != 1) { | |
332 | dev_err(dev, "encode %d resources whose type is(%d)!\n", | |
333 | res_cnt, resource->type); | |
334 | return -EINVAL; | |
335 | } | |
336 | ||
337 | if (ACPI_FAILURE(acpi_resource_to_address64(resource, &addr))) { | |
338 | dev_err(dev, "convert acpi resource(%d) as addr64 FAIL!\n", | |
339 | resource->type); | |
340 | return -EFAULT; | |
341 | } | |
342 | ||
343 | /* For indirect-IO, addr length must be fixed. (>0, 0/1, 0/1)(0,0,0) */ | |
344 | if (addr.min_address_fixed != addr.max_address_fixed) { | |
345 | dev_warn(dev, "variable I/O resource is invalid!\n"); | |
346 | return -EINVAL; | |
347 | } | |
348 | ||
349 | dev_dbg(dev, "CRS IO: len=0x%llx [0x%llx - 0x%llx]\n", | |
350 | addr.address.address_length, addr.address.minimum, | |
351 | addr.address.maximum); | |
352 | sys_port = libio_translate_hwaddr(&host->fwnode, addr.address.minimum); | |
353 | if (sys_port == -1) { | |
354 | dev_err(dev, "translate bus-addr(0x%llx) fail!\n", | |
355 | addr.address.minimum); | |
356 | return -EFAULT; | |
357 | } | |
358 | ||
359 | switch (resource->type) { | |
360 | case ACPI_RESOURCE_TYPE_ADDRESS32: | |
361 | { | |
362 | struct acpi_resource_address32 *out_res; | |
363 | ||
364 | out_res = &resource->data.address32; | |
365 | if (!addr.address.address_length) | |
366 | addr.address.address_length = out_res->address.maximum - | |
367 | out_res->address.minimum + 1; | |
368 | out_res->address.minimum = sys_port; | |
369 | out_res->address.maximum = sys_port + | |
370 | addr.address.address_length - 1; | |
371 | out_res->address.address_length = addr.address.address_length; | |
372 | ||
373 | dev_info(dev, "_SRS 32IO: [0x%x - 0x%x] len = 0x%x\n", | |
374 | out_res->address.minimum, | |
375 | out_res->address.maximum, | |
376 | out_res->address.address_length); | |
377 | ||
378 | break; | |
379 | } | |
380 | ||
381 | case ACPI_RESOURCE_TYPE_ADDRESS64: | |
382 | { | |
383 | struct acpi_resource_address64 *out_res; | |
384 | ||
385 | out_res = &resource->data.address64; | |
386 | if (!addr.address.address_length) | |
387 | addr.address.address_length = out_res->address.maximum - | |
388 | out_res->address.minimum + 1; | |
389 | out_res->address.minimum = sys_port; | |
390 | out_res->address.maximum = sys_port + | |
391 | addr.address.address_length - 1; | |
392 | out_res->address.address_length = addr.address.address_length; | |
393 | ||
394 | dev_info(dev, "_SRS 64IO: [0x%llx - 0x%llx] len = 0x%llx\n", | |
395 | out_res->address.minimum, | |
396 | out_res->address.maximum, | |
397 | out_res->address.address_length); | |
398 | ||
399 | break; | |
400 | } | |
401 | ||
402 | default: | |
403 | return -EINVAL; | |
404 | ||
405 | } | |
406 | ||
407 | return 0; | |
408 | } | |
409 | ||
410 | /* | |
411 | * update/set the current I/O resource of the designated device node. | |
412 | * after this calling, the enumeration can be started as the I/O resource | |
413 | * had been translated to logicial I/O from bus-local I/O. | |
414 | * | |
415 | * @adev: the device node to be updated the I/O resource; | |
416 | * @host: the device node where 'adev' is attached, which can be not | |
417 | * the parent of 'adev'; | |
418 | * | |
419 | * return 0 when successful, negative is for failure. | |
420 | */ | |
421 | int acpi_set_libio_resource(struct device *child, | |
422 | struct device *hostdev) | |
423 | { | |
424 | struct acpi_device *adev; | |
425 | struct acpi_device *host; | |
426 | struct acpi_buffer buffer; | |
427 | acpi_status status; | |
428 | int ret; | |
429 | ||
430 | if (!child || !hostdev) | |
431 | return -EINVAL; | |
432 | ||
433 | host = to_acpi_device(hostdev); | |
434 | adev = to_acpi_device(child); | |
435 | ||
436 | /* check the device state */ | |
437 | if (!adev->status.present) { | |
438 | dev_info(child, "ACPI: device is not present!\n"); | |
439 | return 0; | |
440 | } | |
441 | /* whether the child had been enumerated? */ | |
442 | if (acpi_device_enumerated(adev)) { | |
443 | dev_info(child, "ACPI: had been enumerated!\n"); | |
444 | return 0; | |
445 | } | |
446 | ||
447 | /* read the _CRS and convert as acpi_buffer */ | |
448 | status = acpi_build_libiores_template(adev, &buffer); | |
449 | if (ACPI_FAILURE(status)) { | |
450 | dev_warn(child, "Failure evaluating %s\n", METHOD_NAME__CRS); | |
451 | return -ENODEV; | |
452 | } | |
453 | ||
454 | /* translate the I/O resources */ | |
455 | ret = acpi_translate_libiores(adev, host, &buffer); | |
456 | if (ret) { | |
457 | kfree(buffer.pointer); | |
458 | dev_err(child, "Translate I/O range FAIL!\n"); | |
459 | return ret; | |
460 | } | |
461 | ||
462 | /* set current resource... */ | |
463 | status = acpi_set_current_resources(adev->handle, &buffer); | |
464 | kfree(buffer.pointer); | |
465 | if (ACPI_FAILURE(status)) { | |
466 | dev_err(child, "Error evaluating _SRS (0x%x)\n", status); | |
467 | ret = -EIO; | |
468 | } | |
469 | ||
470 | return ret; | |
471 | } | |
472 | #endif | |
473 | ||
474 | #ifdef PCI_IOBASE | |
475 | static struct libio_range *find_io_range(unsigned long pio) | |
476 | { | |
477 | struct libio_range *range; | |
478 | ||
479 | list_for_each_entry_rcu(range, &io_range_list, list) { | |
480 | if (range->io_start > pio) | |
481 | return NULL; | |
482 | if (pio < range->io_start + range->size) | |
483 | return range; | |
484 | } | |
485 | return NULL; | |
486 | } | |
487 | ||
488 | #define BUILD_IO(bw, type) \ | |
489 | type libio_in##bw(unsigned long addr) \ | |
490 | { \ | |
491 | struct libio_range *entry = find_io_range(addr); \ | |
492 | \ | |
493 | if (entry && entry->ops) \ | |
494 | return entry->ops->pfin(entry->devpara, \ | |
495 | addr, sizeof(type)); \ | |
496 | return read##bw(PCI_IOBASE + addr); \ | |
497 | } \ | |
498 | \ | |
499 | void libio_out##bw(type value, unsigned long addr) \ | |
500 | { \ | |
501 | struct libio_range *entry = find_io_range(addr); \ | |
502 | \ | |
503 | if (entry && entry->ops) \ | |
504 | entry->ops->pfout(entry->devpara, \ | |
505 | addr, value, sizeof(type)); \ | |
506 | else \ | |
507 | write##bw(value, PCI_IOBASE + addr); \ | |
508 | } \ | |
509 | \ | |
510 | void libio_ins##bw(unsigned long addr, void *buffer, unsigned int count)\ | |
511 | { \ | |
512 | struct libio_range *entry = find_io_range(addr); \ | |
513 | \ | |
514 | if (entry && entry->ops) \ | |
515 | entry->ops->pfins(entry->devpara, \ | |
516 | addr, buffer, sizeof(type), count); \ | |
517 | else \ | |
518 | reads##bw(PCI_IOBASE + addr, buffer, count); \ | |
519 | } \ | |
520 | \ | |
521 | void libio_outs##bw(unsigned long addr, const void *buffer, \ | |
522 | unsigned int count) \ | |
523 | { \ | |
524 | struct libio_range *entry = find_io_range(addr); \ | |
525 | \ | |
526 | if (entry && entry->ops) \ | |
527 | entry->ops->pfouts(entry->devpara, \ | |
528 | addr, buffer, sizeof(type), count); \ | |
529 | else \ | |
530 | writes##bw(PCI_IOBASE + addr, buffer, count); \ | |
531 | } | |
532 | ||
533 | BUILD_IO(b, u8) | |
534 | ||
535 | EXPORT_SYMBOL(libio_inb); | |
536 | EXPORT_SYMBOL(libio_outb); | |
537 | EXPORT_SYMBOL(libio_insb); | |
538 | EXPORT_SYMBOL(libio_outsb); | |
539 | ||
540 | BUILD_IO(w, u16) | |
541 | ||
542 | EXPORT_SYMBOL(libio_inw); | |
543 | EXPORT_SYMBOL(libio_outw); | |
544 | EXPORT_SYMBOL(libio_insw); | |
545 | EXPORT_SYMBOL(libio_outsw); | |
546 | ||
547 | BUILD_IO(l, u32) | |
548 | ||
549 | EXPORT_SYMBOL(libio_inl); | |
550 | EXPORT_SYMBOL(libio_outl); | |
551 | EXPORT_SYMBOL(libio_insl); | |
552 | EXPORT_SYMBOL(libio_outsl); | |
553 | #endif /* PCI_IOBASE */ |