Root/
1 | /* |
2 | * VME Bridge Framework |
3 | * |
4 | * Author: Martyn Welch <martyn.welch@ge.com> |
5 | * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. |
6 | * |
7 | * Based on work by Tom Armistead and Ajit Prem |
8 | * Copyright 2004 Motorola Inc. |
9 | * |
10 | * This program is free software; you can redistribute it and/or modify it |
11 | * under the terms of the GNU General Public License as published by the |
12 | * Free Software Foundation; either version 2 of the License, or (at your |
13 | * option) any later version. |
14 | */ |
15 | |
16 | #include <linux/module.h> |
17 | #include <linux/moduleparam.h> |
18 | #include <linux/mm.h> |
19 | #include <linux/types.h> |
20 | #include <linux/kernel.h> |
21 | #include <linux/errno.h> |
22 | #include <linux/pci.h> |
23 | #include <linux/poll.h> |
24 | #include <linux/highmem.h> |
25 | #include <linux/interrupt.h> |
26 | #include <linux/pagemap.h> |
27 | #include <linux/device.h> |
28 | #include <linux/dma-mapping.h> |
29 | #include <linux/syscalls.h> |
30 | #include <linux/mutex.h> |
31 | #include <linux/spinlock.h> |
32 | #include <linux/slab.h> |
33 | #include <linux/vme.h> |
34 | |
35 | #include "vme_bridge.h" |
36 | |
37 | /* Bitmask and list of registered buses both protected by common mutex */ |
38 | static unsigned int vme_bus_numbers; |
39 | static LIST_HEAD(vme_bus_list); |
40 | static DEFINE_MUTEX(vme_buses_lock); |
41 | |
42 | static void __exit vme_exit(void); |
43 | static int __init vme_init(void); |
44 | |
45 | static struct vme_dev *dev_to_vme_dev(struct device *dev) |
46 | { |
47 | return container_of(dev, struct vme_dev, dev); |
48 | } |
49 | |
50 | /* |
51 | * Find the bridge that the resource is associated with. |
52 | */ |
53 | static struct vme_bridge *find_bridge(struct vme_resource *resource) |
54 | { |
55 | /* Get list to search */ |
56 | switch (resource->type) { |
57 | case VME_MASTER: |
58 | return list_entry(resource->entry, struct vme_master_resource, |
59 | list)->parent; |
60 | break; |
61 | case VME_SLAVE: |
62 | return list_entry(resource->entry, struct vme_slave_resource, |
63 | list)->parent; |
64 | break; |
65 | case VME_DMA: |
66 | return list_entry(resource->entry, struct vme_dma_resource, |
67 | list)->parent; |
68 | break; |
69 | case VME_LM: |
70 | return list_entry(resource->entry, struct vme_lm_resource, |
71 | list)->parent; |
72 | break; |
73 | default: |
74 | printk(KERN_ERR "Unknown resource type\n"); |
75 | return NULL; |
76 | break; |
77 | } |
78 | } |
79 | |
80 | /* |
81 | * Allocate a contiguous block of memory for use by the driver. This is used to |
82 | * create the buffers for the slave windows. |
83 | */ |
84 | void *vme_alloc_consistent(struct vme_resource *resource, size_t size, |
85 | dma_addr_t *dma) |
86 | { |
87 | struct vme_bridge *bridge; |
88 | |
89 | if (resource == NULL) { |
90 | printk(KERN_ERR "No resource\n"); |
91 | return NULL; |
92 | } |
93 | |
94 | bridge = find_bridge(resource); |
95 | if (bridge == NULL) { |
96 | printk(KERN_ERR "Can't find bridge\n"); |
97 | return NULL; |
98 | } |
99 | |
100 | if (bridge->parent == NULL) { |
101 | printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name); |
102 | return NULL; |
103 | } |
104 | |
105 | if (bridge->alloc_consistent == NULL) { |
106 | printk(KERN_ERR "alloc_consistent not supported by bridge %s\n", |
107 | bridge->name); |
108 | return NULL; |
109 | } |
110 | |
111 | return bridge->alloc_consistent(bridge->parent, size, dma); |
112 | } |
113 | EXPORT_SYMBOL(vme_alloc_consistent); |
114 | |
115 | /* |
116 | * Free previously allocated contiguous block of memory. |
117 | */ |
118 | void vme_free_consistent(struct vme_resource *resource, size_t size, |
119 | void *vaddr, dma_addr_t dma) |
120 | { |
121 | struct vme_bridge *bridge; |
122 | |
123 | if (resource == NULL) { |
124 | printk(KERN_ERR "No resource\n"); |
125 | return; |
126 | } |
127 | |
128 | bridge = find_bridge(resource); |
129 | if (bridge == NULL) { |
130 | printk(KERN_ERR "Can't find bridge\n"); |
131 | return; |
132 | } |
133 | |
134 | if (bridge->parent == NULL) { |
135 | printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name); |
136 | return; |
137 | } |
138 | |
139 | if (bridge->free_consistent == NULL) { |
140 | printk(KERN_ERR "free_consistent not supported by bridge %s\n", |
141 | bridge->name); |
142 | return; |
143 | } |
144 | |
145 | bridge->free_consistent(bridge->parent, size, vaddr, dma); |
146 | } |
147 | EXPORT_SYMBOL(vme_free_consistent); |
148 | |
149 | size_t vme_get_size(struct vme_resource *resource) |
150 | { |
151 | int enabled, retval; |
152 | unsigned long long base, size; |
153 | dma_addr_t buf_base; |
154 | u32 aspace, cycle, dwidth; |
155 | |
156 | switch (resource->type) { |
157 | case VME_MASTER: |
158 | retval = vme_master_get(resource, &enabled, &base, &size, |
159 | &aspace, &cycle, &dwidth); |
160 | |
161 | return size; |
162 | break; |
163 | case VME_SLAVE: |
164 | retval = vme_slave_get(resource, &enabled, &base, &size, |
165 | &buf_base, &aspace, &cycle); |
166 | |
167 | return size; |
168 | break; |
169 | case VME_DMA: |
170 | return 0; |
171 | break; |
172 | default: |
173 | printk(KERN_ERR "Unknown resource type\n"); |
174 | return 0; |
175 | break; |
176 | } |
177 | } |
178 | EXPORT_SYMBOL(vme_get_size); |
179 | |
180 | static int vme_check_window(u32 aspace, unsigned long long vme_base, |
181 | unsigned long long size) |
182 | { |
183 | int retval = 0; |
184 | |
185 | switch (aspace) { |
186 | case VME_A16: |
187 | if (((vme_base + size) > VME_A16_MAX) || |
188 | (vme_base > VME_A16_MAX)) |
189 | retval = -EFAULT; |
190 | break; |
191 | case VME_A24: |
192 | if (((vme_base + size) > VME_A24_MAX) || |
193 | (vme_base > VME_A24_MAX)) |
194 | retval = -EFAULT; |
195 | break; |
196 | case VME_A32: |
197 | if (((vme_base + size) > VME_A32_MAX) || |
198 | (vme_base > VME_A32_MAX)) |
199 | retval = -EFAULT; |
200 | break; |
201 | case VME_A64: |
202 | /* |
203 | * Any value held in an unsigned long long can be used as the |
204 | * base |
205 | */ |
206 | break; |
207 | case VME_CRCSR: |
208 | if (((vme_base + size) > VME_CRCSR_MAX) || |
209 | (vme_base > VME_CRCSR_MAX)) |
210 | retval = -EFAULT; |
211 | break; |
212 | case VME_USER1: |
213 | case VME_USER2: |
214 | case VME_USER3: |
215 | case VME_USER4: |
216 | /* User Defined */ |
217 | break; |
218 | default: |
219 | printk(KERN_ERR "Invalid address space\n"); |
220 | retval = -EINVAL; |
221 | break; |
222 | } |
223 | |
224 | return retval; |
225 | } |
226 | |
227 | /* |
228 | * Request a slave image with specific attributes, return some unique |
229 | * identifier. |
230 | */ |
231 | struct vme_resource *vme_slave_request(struct vme_dev *vdev, u32 address, |
232 | u32 cycle) |
233 | { |
234 | struct vme_bridge *bridge; |
235 | struct list_head *slave_pos = NULL; |
236 | struct vme_slave_resource *allocated_image = NULL; |
237 | struct vme_slave_resource *slave_image = NULL; |
238 | struct vme_resource *resource = NULL; |
239 | |
240 | bridge = vdev->bridge; |
241 | if (bridge == NULL) { |
242 | printk(KERN_ERR "Can't find VME bus\n"); |
243 | goto err_bus; |
244 | } |
245 | |
246 | /* Loop through slave resources */ |
247 | list_for_each(slave_pos, &bridge->slave_resources) { |
248 | slave_image = list_entry(slave_pos, |
249 | struct vme_slave_resource, list); |
250 | |
251 | if (slave_image == NULL) { |
252 | printk(KERN_ERR "Registered NULL Slave resource\n"); |
253 | continue; |
254 | } |
255 | |
256 | /* Find an unlocked and compatible image */ |
257 | mutex_lock(&slave_image->mtx); |
258 | if (((slave_image->address_attr & address) == address) && |
259 | ((slave_image->cycle_attr & cycle) == cycle) && |
260 | (slave_image->locked == 0)) { |
261 | |
262 | slave_image->locked = 1; |
263 | mutex_unlock(&slave_image->mtx); |
264 | allocated_image = slave_image; |
265 | break; |
266 | } |
267 | mutex_unlock(&slave_image->mtx); |
268 | } |
269 | |
270 | /* No free image */ |
271 | if (allocated_image == NULL) |
272 | goto err_image; |
273 | |
274 | resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL); |
275 | if (resource == NULL) { |
276 | printk(KERN_WARNING "Unable to allocate resource structure\n"); |
277 | goto err_alloc; |
278 | } |
279 | resource->type = VME_SLAVE; |
280 | resource->entry = &allocated_image->list; |
281 | |
282 | return resource; |
283 | |
284 | err_alloc: |
285 | /* Unlock image */ |
286 | mutex_lock(&slave_image->mtx); |
287 | slave_image->locked = 0; |
288 | mutex_unlock(&slave_image->mtx); |
289 | err_image: |
290 | err_bus: |
291 | return NULL; |
292 | } |
293 | EXPORT_SYMBOL(vme_slave_request); |
294 | |
295 | int vme_slave_set(struct vme_resource *resource, int enabled, |
296 | unsigned long long vme_base, unsigned long long size, |
297 | dma_addr_t buf_base, u32 aspace, u32 cycle) |
298 | { |
299 | struct vme_bridge *bridge = find_bridge(resource); |
300 | struct vme_slave_resource *image; |
301 | int retval; |
302 | |
303 | if (resource->type != VME_SLAVE) { |
304 | printk(KERN_ERR "Not a slave resource\n"); |
305 | return -EINVAL; |
306 | } |
307 | |
308 | image = list_entry(resource->entry, struct vme_slave_resource, list); |
309 | |
310 | if (bridge->slave_set == NULL) { |
311 | printk(KERN_ERR "Function not supported\n"); |
312 | return -ENOSYS; |
313 | } |
314 | |
315 | if (!(((image->address_attr & aspace) == aspace) && |
316 | ((image->cycle_attr & cycle) == cycle))) { |
317 | printk(KERN_ERR "Invalid attributes\n"); |
318 | return -EINVAL; |
319 | } |
320 | |
321 | retval = vme_check_window(aspace, vme_base, size); |
322 | if (retval) |
323 | return retval; |
324 | |
325 | return bridge->slave_set(image, enabled, vme_base, size, buf_base, |
326 | aspace, cycle); |
327 | } |
328 | EXPORT_SYMBOL(vme_slave_set); |
329 | |
330 | int vme_slave_get(struct vme_resource *resource, int *enabled, |
331 | unsigned long long *vme_base, unsigned long long *size, |
332 | dma_addr_t *buf_base, u32 *aspace, u32 *cycle) |
333 | { |
334 | struct vme_bridge *bridge = find_bridge(resource); |
335 | struct vme_slave_resource *image; |
336 | |
337 | if (resource->type != VME_SLAVE) { |
338 | printk(KERN_ERR "Not a slave resource\n"); |
339 | return -EINVAL; |
340 | } |
341 | |
342 | image = list_entry(resource->entry, struct vme_slave_resource, list); |
343 | |
344 | if (bridge->slave_get == NULL) { |
345 | printk(KERN_ERR "vme_slave_get not supported\n"); |
346 | return -EINVAL; |
347 | } |
348 | |
349 | return bridge->slave_get(image, enabled, vme_base, size, buf_base, |
350 | aspace, cycle); |
351 | } |
352 | EXPORT_SYMBOL(vme_slave_get); |
353 | |
354 | void vme_slave_free(struct vme_resource *resource) |
355 | { |
356 | struct vme_slave_resource *slave_image; |
357 | |
358 | if (resource->type != VME_SLAVE) { |
359 | printk(KERN_ERR "Not a slave resource\n"); |
360 | return; |
361 | } |
362 | |
363 | slave_image = list_entry(resource->entry, struct vme_slave_resource, |
364 | list); |
365 | if (slave_image == NULL) { |
366 | printk(KERN_ERR "Can't find slave resource\n"); |
367 | return; |
368 | } |
369 | |
370 | /* Unlock image */ |
371 | mutex_lock(&slave_image->mtx); |
372 | if (slave_image->locked == 0) |
373 | printk(KERN_ERR "Image is already free\n"); |
374 | |
375 | slave_image->locked = 0; |
376 | mutex_unlock(&slave_image->mtx); |
377 | |
378 | /* Free up resource memory */ |
379 | kfree(resource); |
380 | } |
381 | EXPORT_SYMBOL(vme_slave_free); |
382 | |
383 | /* |
384 | * Request a master image with specific attributes, return some unique |
385 | * identifier. |
386 | */ |
387 | struct vme_resource *vme_master_request(struct vme_dev *vdev, u32 address, |
388 | u32 cycle, u32 dwidth) |
389 | { |
390 | struct vme_bridge *bridge; |
391 | struct list_head *master_pos = NULL; |
392 | struct vme_master_resource *allocated_image = NULL; |
393 | struct vme_master_resource *master_image = NULL; |
394 | struct vme_resource *resource = NULL; |
395 | |
396 | bridge = vdev->bridge; |
397 | if (bridge == NULL) { |
398 | printk(KERN_ERR "Can't find VME bus\n"); |
399 | goto err_bus; |
400 | } |
401 | |
402 | /* Loop through master resources */ |
403 | list_for_each(master_pos, &bridge->master_resources) { |
404 | master_image = list_entry(master_pos, |
405 | struct vme_master_resource, list); |
406 | |
407 | if (master_image == NULL) { |
408 | printk(KERN_WARNING "Registered NULL master resource\n"); |
409 | continue; |
410 | } |
411 | |
412 | /* Find an unlocked and compatible image */ |
413 | spin_lock(&master_image->lock); |
414 | if (((master_image->address_attr & address) == address) && |
415 | ((master_image->cycle_attr & cycle) == cycle) && |
416 | ((master_image->width_attr & dwidth) == dwidth) && |
417 | (master_image->locked == 0)) { |
418 | |
419 | master_image->locked = 1; |
420 | spin_unlock(&master_image->lock); |
421 | allocated_image = master_image; |
422 | break; |
423 | } |
424 | spin_unlock(&master_image->lock); |
425 | } |
426 | |
427 | /* Check to see if we found a resource */ |
428 | if (allocated_image == NULL) { |
429 | printk(KERN_ERR "Can't find a suitable resource\n"); |
430 | goto err_image; |
431 | } |
432 | |
433 | resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL); |
434 | if (resource == NULL) { |
435 | printk(KERN_ERR "Unable to allocate resource structure\n"); |
436 | goto err_alloc; |
437 | } |
438 | resource->type = VME_MASTER; |
439 | resource->entry = &allocated_image->list; |
440 | |
441 | return resource; |
442 | |
443 | err_alloc: |
444 | /* Unlock image */ |
445 | spin_lock(&master_image->lock); |
446 | master_image->locked = 0; |
447 | spin_unlock(&master_image->lock); |
448 | err_image: |
449 | err_bus: |
450 | return NULL; |
451 | } |
452 | EXPORT_SYMBOL(vme_master_request); |
453 | |
454 | int vme_master_set(struct vme_resource *resource, int enabled, |
455 | unsigned long long vme_base, unsigned long long size, u32 aspace, |
456 | u32 cycle, u32 dwidth) |
457 | { |
458 | struct vme_bridge *bridge = find_bridge(resource); |
459 | struct vme_master_resource *image; |
460 | int retval; |
461 | |
462 | if (resource->type != VME_MASTER) { |
463 | printk(KERN_ERR "Not a master resource\n"); |
464 | return -EINVAL; |
465 | } |
466 | |
467 | image = list_entry(resource->entry, struct vme_master_resource, list); |
468 | |
469 | if (bridge->master_set == NULL) { |
470 | printk(KERN_WARNING "vme_master_set not supported\n"); |
471 | return -EINVAL; |
472 | } |
473 | |
474 | if (!(((image->address_attr & aspace) == aspace) && |
475 | ((image->cycle_attr & cycle) == cycle) && |
476 | ((image->width_attr & dwidth) == dwidth))) { |
477 | printk(KERN_WARNING "Invalid attributes\n"); |
478 | return -EINVAL; |
479 | } |
480 | |
481 | retval = vme_check_window(aspace, vme_base, size); |
482 | if (retval) |
483 | return retval; |
484 | |
485 | return bridge->master_set(image, enabled, vme_base, size, aspace, |
486 | cycle, dwidth); |
487 | } |
488 | EXPORT_SYMBOL(vme_master_set); |
489 | |
490 | int vme_master_get(struct vme_resource *resource, int *enabled, |
491 | unsigned long long *vme_base, unsigned long long *size, u32 *aspace, |
492 | u32 *cycle, u32 *dwidth) |
493 | { |
494 | struct vme_bridge *bridge = find_bridge(resource); |
495 | struct vme_master_resource *image; |
496 | |
497 | if (resource->type != VME_MASTER) { |
498 | printk(KERN_ERR "Not a master resource\n"); |
499 | return -EINVAL; |
500 | } |
501 | |
502 | image = list_entry(resource->entry, struct vme_master_resource, list); |
503 | |
504 | if (bridge->master_get == NULL) { |
505 | printk(KERN_WARNING "vme_master_set not supported\n"); |
506 | return -EINVAL; |
507 | } |
508 | |
509 | return bridge->master_get(image, enabled, vme_base, size, aspace, |
510 | cycle, dwidth); |
511 | } |
512 | EXPORT_SYMBOL(vme_master_get); |
513 | |
514 | /* |
515 | * Read data out of VME space into a buffer. |
516 | */ |
517 | ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count, |
518 | loff_t offset) |
519 | { |
520 | struct vme_bridge *bridge = find_bridge(resource); |
521 | struct vme_master_resource *image; |
522 | size_t length; |
523 | |
524 | if (bridge->master_read == NULL) { |
525 | printk(KERN_WARNING "Reading from resource not supported\n"); |
526 | return -EINVAL; |
527 | } |
528 | |
529 | if (resource->type != VME_MASTER) { |
530 | printk(KERN_ERR "Not a master resource\n"); |
531 | return -EINVAL; |
532 | } |
533 | |
534 | image = list_entry(resource->entry, struct vme_master_resource, list); |
535 | |
536 | length = vme_get_size(resource); |
537 | |
538 | if (offset > length) { |
539 | printk(KERN_WARNING "Invalid Offset\n"); |
540 | return -EFAULT; |
541 | } |
542 | |
543 | if ((offset + count) > length) |
544 | count = length - offset; |
545 | |
546 | return bridge->master_read(image, buf, count, offset); |
547 | |
548 | } |
549 | EXPORT_SYMBOL(vme_master_read); |
550 | |
551 | /* |
552 | * Write data out to VME space from a buffer. |
553 | */ |
554 | ssize_t vme_master_write(struct vme_resource *resource, void *buf, |
555 | size_t count, loff_t offset) |
556 | { |
557 | struct vme_bridge *bridge = find_bridge(resource); |
558 | struct vme_master_resource *image; |
559 | size_t length; |
560 | |
561 | if (bridge->master_write == NULL) { |
562 | printk(KERN_WARNING "Writing to resource not supported\n"); |
563 | return -EINVAL; |
564 | } |
565 | |
566 | if (resource->type != VME_MASTER) { |
567 | printk(KERN_ERR "Not a master resource\n"); |
568 | return -EINVAL; |
569 | } |
570 | |
571 | image = list_entry(resource->entry, struct vme_master_resource, list); |
572 | |
573 | length = vme_get_size(resource); |
574 | |
575 | if (offset > length) { |
576 | printk(KERN_WARNING "Invalid Offset\n"); |
577 | return -EFAULT; |
578 | } |
579 | |
580 | if ((offset + count) > length) |
581 | count = length - offset; |
582 | |
583 | return bridge->master_write(image, buf, count, offset); |
584 | } |
585 | EXPORT_SYMBOL(vme_master_write); |
586 | |
587 | /* |
588 | * Perform RMW cycle to provided location. |
589 | */ |
590 | unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask, |
591 | unsigned int compare, unsigned int swap, loff_t offset) |
592 | { |
593 | struct vme_bridge *bridge = find_bridge(resource); |
594 | struct vme_master_resource *image; |
595 | |
596 | if (bridge->master_rmw == NULL) { |
597 | printk(KERN_WARNING "Writing to resource not supported\n"); |
598 | return -EINVAL; |
599 | } |
600 | |
601 | if (resource->type != VME_MASTER) { |
602 | printk(KERN_ERR "Not a master resource\n"); |
603 | return -EINVAL; |
604 | } |
605 | |
606 | image = list_entry(resource->entry, struct vme_master_resource, list); |
607 | |
608 | return bridge->master_rmw(image, mask, compare, swap, offset); |
609 | } |
610 | EXPORT_SYMBOL(vme_master_rmw); |
611 | |
612 | void vme_master_free(struct vme_resource *resource) |
613 | { |
614 | struct vme_master_resource *master_image; |
615 | |
616 | if (resource->type != VME_MASTER) { |
617 | printk(KERN_ERR "Not a master resource\n"); |
618 | return; |
619 | } |
620 | |
621 | master_image = list_entry(resource->entry, struct vme_master_resource, |
622 | list); |
623 | if (master_image == NULL) { |
624 | printk(KERN_ERR "Can't find master resource\n"); |
625 | return; |
626 | } |
627 | |
628 | /* Unlock image */ |
629 | spin_lock(&master_image->lock); |
630 | if (master_image->locked == 0) |
631 | printk(KERN_ERR "Image is already free\n"); |
632 | |
633 | master_image->locked = 0; |
634 | spin_unlock(&master_image->lock); |
635 | |
636 | /* Free up resource memory */ |
637 | kfree(resource); |
638 | } |
639 | EXPORT_SYMBOL(vme_master_free); |
640 | |
641 | /* |
642 | * Request a DMA controller with specific attributes, return some unique |
643 | * identifier. |
644 | */ |
645 | struct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 route) |
646 | { |
647 | struct vme_bridge *bridge; |
648 | struct list_head *dma_pos = NULL; |
649 | struct vme_dma_resource *allocated_ctrlr = NULL; |
650 | struct vme_dma_resource *dma_ctrlr = NULL; |
651 | struct vme_resource *resource = NULL; |
652 | |
653 | /* XXX Not checking resource attributes */ |
654 | printk(KERN_ERR "No VME resource Attribute tests done\n"); |
655 | |
656 | bridge = vdev->bridge; |
657 | if (bridge == NULL) { |
658 | printk(KERN_ERR "Can't find VME bus\n"); |
659 | goto err_bus; |
660 | } |
661 | |
662 | /* Loop through DMA resources */ |
663 | list_for_each(dma_pos, &bridge->dma_resources) { |
664 | dma_ctrlr = list_entry(dma_pos, |
665 | struct vme_dma_resource, list); |
666 | |
667 | if (dma_ctrlr == NULL) { |
668 | printk(KERN_ERR "Registered NULL DMA resource\n"); |
669 | continue; |
670 | } |
671 | |
672 | /* Find an unlocked and compatible controller */ |
673 | mutex_lock(&dma_ctrlr->mtx); |
674 | if (((dma_ctrlr->route_attr & route) == route) && |
675 | (dma_ctrlr->locked == 0)) { |
676 | |
677 | dma_ctrlr->locked = 1; |
678 | mutex_unlock(&dma_ctrlr->mtx); |
679 | allocated_ctrlr = dma_ctrlr; |
680 | break; |
681 | } |
682 | mutex_unlock(&dma_ctrlr->mtx); |
683 | } |
684 | |
685 | /* Check to see if we found a resource */ |
686 | if (allocated_ctrlr == NULL) |
687 | goto err_ctrlr; |
688 | |
689 | resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL); |
690 | if (resource == NULL) { |
691 | printk(KERN_WARNING "Unable to allocate resource structure\n"); |
692 | goto err_alloc; |
693 | } |
694 | resource->type = VME_DMA; |
695 | resource->entry = &allocated_ctrlr->list; |
696 | |
697 | return resource; |
698 | |
699 | err_alloc: |
700 | /* Unlock image */ |
701 | mutex_lock(&dma_ctrlr->mtx); |
702 | dma_ctrlr->locked = 0; |
703 | mutex_unlock(&dma_ctrlr->mtx); |
704 | err_ctrlr: |
705 | err_bus: |
706 | return NULL; |
707 | } |
708 | EXPORT_SYMBOL(vme_dma_request); |
709 | |
710 | /* |
711 | * Start new list |
712 | */ |
713 | struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource) |
714 | { |
715 | struct vme_dma_resource *ctrlr; |
716 | struct vme_dma_list *dma_list; |
717 | |
718 | if (resource->type != VME_DMA) { |
719 | printk(KERN_ERR "Not a DMA resource\n"); |
720 | return NULL; |
721 | } |
722 | |
723 | ctrlr = list_entry(resource->entry, struct vme_dma_resource, list); |
724 | |
725 | dma_list = kmalloc(sizeof(struct vme_dma_list), GFP_KERNEL); |
726 | if (dma_list == NULL) { |
727 | printk(KERN_ERR "Unable to allocate memory for new dma list\n"); |
728 | return NULL; |
729 | } |
730 | INIT_LIST_HEAD(&dma_list->entries); |
731 | dma_list->parent = ctrlr; |
732 | mutex_init(&dma_list->mtx); |
733 | |
734 | return dma_list; |
735 | } |
736 | EXPORT_SYMBOL(vme_new_dma_list); |
737 | |
738 | /* |
739 | * Create "Pattern" type attributes |
740 | */ |
741 | struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type) |
742 | { |
743 | struct vme_dma_attr *attributes; |
744 | struct vme_dma_pattern *pattern_attr; |
745 | |
746 | attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL); |
747 | if (attributes == NULL) { |
748 | printk(KERN_ERR "Unable to allocate memory for attributes structure\n"); |
749 | goto err_attr; |
750 | } |
751 | |
752 | pattern_attr = kmalloc(sizeof(struct vme_dma_pattern), GFP_KERNEL); |
753 | if (pattern_attr == NULL) { |
754 | printk(KERN_ERR "Unable to allocate memory for pattern attributes\n"); |
755 | goto err_pat; |
756 | } |
757 | |
758 | attributes->type = VME_DMA_PATTERN; |
759 | attributes->private = (void *)pattern_attr; |
760 | |
761 | pattern_attr->pattern = pattern; |
762 | pattern_attr->type = type; |
763 | |
764 | return attributes; |
765 | |
766 | err_pat: |
767 | kfree(attributes); |
768 | err_attr: |
769 | return NULL; |
770 | } |
771 | EXPORT_SYMBOL(vme_dma_pattern_attribute); |
772 | |
773 | /* |
774 | * Create "PCI" type attributes |
775 | */ |
776 | struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address) |
777 | { |
778 | struct vme_dma_attr *attributes; |
779 | struct vme_dma_pci *pci_attr; |
780 | |
781 | /* XXX Run some sanity checks here */ |
782 | |
783 | attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL); |
784 | if (attributes == NULL) { |
785 | printk(KERN_ERR "Unable to allocate memory for attributes structure\n"); |
786 | goto err_attr; |
787 | } |
788 | |
789 | pci_attr = kmalloc(sizeof(struct vme_dma_pci), GFP_KERNEL); |
790 | if (pci_attr == NULL) { |
791 | printk(KERN_ERR "Unable to allocate memory for pci attributes\n"); |
792 | goto err_pci; |
793 | } |
794 | |
795 | |
796 | |
797 | attributes->type = VME_DMA_PCI; |
798 | attributes->private = (void *)pci_attr; |
799 | |
800 | pci_attr->address = address; |
801 | |
802 | return attributes; |
803 | |
804 | err_pci: |
805 | kfree(attributes); |
806 | err_attr: |
807 | return NULL; |
808 | } |
809 | EXPORT_SYMBOL(vme_dma_pci_attribute); |
810 | |
811 | /* |
812 | * Create "VME" type attributes |
813 | */ |
814 | struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address, |
815 | u32 aspace, u32 cycle, u32 dwidth) |
816 | { |
817 | struct vme_dma_attr *attributes; |
818 | struct vme_dma_vme *vme_attr; |
819 | |
820 | attributes = kmalloc( |
821 | sizeof(struct vme_dma_attr), GFP_KERNEL); |
822 | if (attributes == NULL) { |
823 | printk(KERN_ERR "Unable to allocate memory for attributes structure\n"); |
824 | goto err_attr; |
825 | } |
826 | |
827 | vme_attr = kmalloc(sizeof(struct vme_dma_vme), GFP_KERNEL); |
828 | if (vme_attr == NULL) { |
829 | printk(KERN_ERR "Unable to allocate memory for vme attributes\n"); |
830 | goto err_vme; |
831 | } |
832 | |
833 | attributes->type = VME_DMA_VME; |
834 | attributes->private = (void *)vme_attr; |
835 | |
836 | vme_attr->address = address; |
837 | vme_attr->aspace = aspace; |
838 | vme_attr->cycle = cycle; |
839 | vme_attr->dwidth = dwidth; |
840 | |
841 | return attributes; |
842 | |
843 | err_vme: |
844 | kfree(attributes); |
845 | err_attr: |
846 | return NULL; |
847 | } |
848 | EXPORT_SYMBOL(vme_dma_vme_attribute); |
849 | |
850 | /* |
851 | * Free attribute |
852 | */ |
853 | void vme_dma_free_attribute(struct vme_dma_attr *attributes) |
854 | { |
855 | kfree(attributes->private); |
856 | kfree(attributes); |
857 | } |
858 | EXPORT_SYMBOL(vme_dma_free_attribute); |
859 | |
860 | int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, |
861 | struct vme_dma_attr *dest, size_t count) |
862 | { |
863 | struct vme_bridge *bridge = list->parent->parent; |
864 | int retval; |
865 | |
866 | if (bridge->dma_list_add == NULL) { |
867 | printk(KERN_WARNING "Link List DMA generation not supported\n"); |
868 | return -EINVAL; |
869 | } |
870 | |
871 | if (!mutex_trylock(&list->mtx)) { |
872 | printk(KERN_ERR "Link List already submitted\n"); |
873 | return -EINVAL; |
874 | } |
875 | |
876 | retval = bridge->dma_list_add(list, src, dest, count); |
877 | |
878 | mutex_unlock(&list->mtx); |
879 | |
880 | return retval; |
881 | } |
882 | EXPORT_SYMBOL(vme_dma_list_add); |
883 | |
884 | int vme_dma_list_exec(struct vme_dma_list *list) |
885 | { |
886 | struct vme_bridge *bridge = list->parent->parent; |
887 | int retval; |
888 | |
889 | if (bridge->dma_list_exec == NULL) { |
890 | printk(KERN_ERR "Link List DMA execution not supported\n"); |
891 | return -EINVAL; |
892 | } |
893 | |
894 | mutex_lock(&list->mtx); |
895 | |
896 | retval = bridge->dma_list_exec(list); |
897 | |
898 | mutex_unlock(&list->mtx); |
899 | |
900 | return retval; |
901 | } |
902 | EXPORT_SYMBOL(vme_dma_list_exec); |
903 | |
904 | int vme_dma_list_free(struct vme_dma_list *list) |
905 | { |
906 | struct vme_bridge *bridge = list->parent->parent; |
907 | int retval; |
908 | |
909 | if (bridge->dma_list_empty == NULL) { |
910 | printk(KERN_WARNING "Emptying of Link Lists not supported\n"); |
911 | return -EINVAL; |
912 | } |
913 | |
914 | if (!mutex_trylock(&list->mtx)) { |
915 | printk(KERN_ERR "Link List in use\n"); |
916 | return -EINVAL; |
917 | } |
918 | |
919 | /* |
920 | * Empty out all of the entries from the dma list. We need to go to the |
921 | * low level driver as dma entries are driver specific. |
922 | */ |
923 | retval = bridge->dma_list_empty(list); |
924 | if (retval) { |
925 | printk(KERN_ERR "Unable to empty link-list entries\n"); |
926 | mutex_unlock(&list->mtx); |
927 | return retval; |
928 | } |
929 | mutex_unlock(&list->mtx); |
930 | kfree(list); |
931 | |
932 | return retval; |
933 | } |
934 | EXPORT_SYMBOL(vme_dma_list_free); |
935 | |
936 | int vme_dma_free(struct vme_resource *resource) |
937 | { |
938 | struct vme_dma_resource *ctrlr; |
939 | |
940 | if (resource->type != VME_DMA) { |
941 | printk(KERN_ERR "Not a DMA resource\n"); |
942 | return -EINVAL; |
943 | } |
944 | |
945 | ctrlr = list_entry(resource->entry, struct vme_dma_resource, list); |
946 | |
947 | if (!mutex_trylock(&ctrlr->mtx)) { |
948 | printk(KERN_ERR "Resource busy, can't free\n"); |
949 | return -EBUSY; |
950 | } |
951 | |
952 | if (!(list_empty(&ctrlr->pending) && list_empty(&ctrlr->running))) { |
953 | printk(KERN_WARNING "Resource still processing transfers\n"); |
954 | mutex_unlock(&ctrlr->mtx); |
955 | return -EBUSY; |
956 | } |
957 | |
958 | ctrlr->locked = 0; |
959 | |
960 | mutex_unlock(&ctrlr->mtx); |
961 | |
962 | return 0; |
963 | } |
964 | EXPORT_SYMBOL(vme_dma_free); |
965 | |
966 | void vme_irq_handler(struct vme_bridge *bridge, int level, int statid) |
967 | { |
968 | void (*call)(int, int, void *); |
969 | void *priv_data; |
970 | |
971 | call = bridge->irq[level - 1].callback[statid].func; |
972 | priv_data = bridge->irq[level - 1].callback[statid].priv_data; |
973 | |
974 | if (call != NULL) |
975 | call(level, statid, priv_data); |
976 | else |
977 | printk(KERN_WARNING "Spurilous VME interrupt, level:%x, vector:%x\n", |
978 | level, statid); |
979 | } |
980 | EXPORT_SYMBOL(vme_irq_handler); |
981 | |
982 | int vme_irq_request(struct vme_dev *vdev, int level, int statid, |
983 | void (*callback)(int, int, void *), |
984 | void *priv_data) |
985 | { |
986 | struct vme_bridge *bridge; |
987 | |
988 | bridge = vdev->bridge; |
989 | if (bridge == NULL) { |
990 | printk(KERN_ERR "Can't find VME bus\n"); |
991 | return -EINVAL; |
992 | } |
993 | |
994 | if ((level < 1) || (level > 7)) { |
995 | printk(KERN_ERR "Invalid interrupt level\n"); |
996 | return -EINVAL; |
997 | } |
998 | |
999 | if (bridge->irq_set == NULL) { |
1000 | printk(KERN_ERR "Configuring interrupts not supported\n"); |
1001 | return -EINVAL; |
1002 | } |
1003 | |
1004 | mutex_lock(&bridge->irq_mtx); |
1005 | |
1006 | if (bridge->irq[level - 1].callback[statid].func) { |
1007 | mutex_unlock(&bridge->irq_mtx); |
1008 | printk(KERN_WARNING "VME Interrupt already taken\n"); |
1009 | return -EBUSY; |
1010 | } |
1011 | |
1012 | bridge->irq[level - 1].count++; |
1013 | bridge->irq[level - 1].callback[statid].priv_data = priv_data; |
1014 | bridge->irq[level - 1].callback[statid].func = callback; |
1015 | |
1016 | /* Enable IRQ level */ |
1017 | bridge->irq_set(bridge, level, 1, 1); |
1018 | |
1019 | mutex_unlock(&bridge->irq_mtx); |
1020 | |
1021 | return 0; |
1022 | } |
1023 | EXPORT_SYMBOL(vme_irq_request); |
1024 | |
1025 | void vme_irq_free(struct vme_dev *vdev, int level, int statid) |
1026 | { |
1027 | struct vme_bridge *bridge; |
1028 | |
1029 | bridge = vdev->bridge; |
1030 | if (bridge == NULL) { |
1031 | printk(KERN_ERR "Can't find VME bus\n"); |
1032 | return; |
1033 | } |
1034 | |
1035 | if ((level < 1) || (level > 7)) { |
1036 | printk(KERN_ERR "Invalid interrupt level\n"); |
1037 | return; |
1038 | } |
1039 | |
1040 | if (bridge->irq_set == NULL) { |
1041 | printk(KERN_ERR "Configuring interrupts not supported\n"); |
1042 | return; |
1043 | } |
1044 | |
1045 | mutex_lock(&bridge->irq_mtx); |
1046 | |
1047 | bridge->irq[level - 1].count--; |
1048 | |
1049 | /* Disable IRQ level if no more interrupts attached at this level*/ |
1050 | if (bridge->irq[level - 1].count == 0) |
1051 | bridge->irq_set(bridge, level, 0, 1); |
1052 | |
1053 | bridge->irq[level - 1].callback[statid].func = NULL; |
1054 | bridge->irq[level - 1].callback[statid].priv_data = NULL; |
1055 | |
1056 | mutex_unlock(&bridge->irq_mtx); |
1057 | } |
1058 | EXPORT_SYMBOL(vme_irq_free); |
1059 | |
1060 | int vme_irq_generate(struct vme_dev *vdev, int level, int statid) |
1061 | { |
1062 | struct vme_bridge *bridge; |
1063 | |
1064 | bridge = vdev->bridge; |
1065 | if (bridge == NULL) { |
1066 | printk(KERN_ERR "Can't find VME bus\n"); |
1067 | return -EINVAL; |
1068 | } |
1069 | |
1070 | if ((level < 1) || (level > 7)) { |
1071 | printk(KERN_WARNING "Invalid interrupt level\n"); |
1072 | return -EINVAL; |
1073 | } |
1074 | |
1075 | if (bridge->irq_generate == NULL) { |
1076 | printk(KERN_WARNING "Interrupt generation not supported\n"); |
1077 | return -EINVAL; |
1078 | } |
1079 | |
1080 | return bridge->irq_generate(bridge, level, statid); |
1081 | } |
1082 | EXPORT_SYMBOL(vme_irq_generate); |
1083 | |
1084 | /* |
1085 | * Request the location monitor, return resource or NULL |
1086 | */ |
1087 | struct vme_resource *vme_lm_request(struct vme_dev *vdev) |
1088 | { |
1089 | struct vme_bridge *bridge; |
1090 | struct list_head *lm_pos = NULL; |
1091 | struct vme_lm_resource *allocated_lm = NULL; |
1092 | struct vme_lm_resource *lm = NULL; |
1093 | struct vme_resource *resource = NULL; |
1094 | |
1095 | bridge = vdev->bridge; |
1096 | if (bridge == NULL) { |
1097 | printk(KERN_ERR "Can't find VME bus\n"); |
1098 | goto err_bus; |
1099 | } |
1100 | |
1101 | /* Loop through DMA resources */ |
1102 | list_for_each(lm_pos, &bridge->lm_resources) { |
1103 | lm = list_entry(lm_pos, |
1104 | struct vme_lm_resource, list); |
1105 | |
1106 | if (lm == NULL) { |
1107 | printk(KERN_ERR "Registered NULL Location Monitor resource\n"); |
1108 | continue; |
1109 | } |
1110 | |
1111 | /* Find an unlocked controller */ |
1112 | mutex_lock(&lm->mtx); |
1113 | if (lm->locked == 0) { |
1114 | lm->locked = 1; |
1115 | mutex_unlock(&lm->mtx); |
1116 | allocated_lm = lm; |
1117 | break; |
1118 | } |
1119 | mutex_unlock(&lm->mtx); |
1120 | } |
1121 | |
1122 | /* Check to see if we found a resource */ |
1123 | if (allocated_lm == NULL) |
1124 | goto err_lm; |
1125 | |
1126 | resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL); |
1127 | if (resource == NULL) { |
1128 | printk(KERN_ERR "Unable to allocate resource structure\n"); |
1129 | goto err_alloc; |
1130 | } |
1131 | resource->type = VME_LM; |
1132 | resource->entry = &allocated_lm->list; |
1133 | |
1134 | return resource; |
1135 | |
1136 | err_alloc: |
1137 | /* Unlock image */ |
1138 | mutex_lock(&lm->mtx); |
1139 | lm->locked = 0; |
1140 | mutex_unlock(&lm->mtx); |
1141 | err_lm: |
1142 | err_bus: |
1143 | return NULL; |
1144 | } |
1145 | EXPORT_SYMBOL(vme_lm_request); |
1146 | |
1147 | int vme_lm_count(struct vme_resource *resource) |
1148 | { |
1149 | struct vme_lm_resource *lm; |
1150 | |
1151 | if (resource->type != VME_LM) { |
1152 | printk(KERN_ERR "Not a Location Monitor resource\n"); |
1153 | return -EINVAL; |
1154 | } |
1155 | |
1156 | lm = list_entry(resource->entry, struct vme_lm_resource, list); |
1157 | |
1158 | return lm->monitors; |
1159 | } |
1160 | EXPORT_SYMBOL(vme_lm_count); |
1161 | |
1162 | int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base, |
1163 | u32 aspace, u32 cycle) |
1164 | { |
1165 | struct vme_bridge *bridge = find_bridge(resource); |
1166 | struct vme_lm_resource *lm; |
1167 | |
1168 | if (resource->type != VME_LM) { |
1169 | printk(KERN_ERR "Not a Location Monitor resource\n"); |
1170 | return -EINVAL; |
1171 | } |
1172 | |
1173 | lm = list_entry(resource->entry, struct vme_lm_resource, list); |
1174 | |
1175 | if (bridge->lm_set == NULL) { |
1176 | printk(KERN_ERR "vme_lm_set not supported\n"); |
1177 | return -EINVAL; |
1178 | } |
1179 | |
1180 | return bridge->lm_set(lm, lm_base, aspace, cycle); |
1181 | } |
1182 | EXPORT_SYMBOL(vme_lm_set); |
1183 | |
1184 | int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base, |
1185 | u32 *aspace, u32 *cycle) |
1186 | { |
1187 | struct vme_bridge *bridge = find_bridge(resource); |
1188 | struct vme_lm_resource *lm; |
1189 | |
1190 | if (resource->type != VME_LM) { |
1191 | printk(KERN_ERR "Not a Location Monitor resource\n"); |
1192 | return -EINVAL; |
1193 | } |
1194 | |
1195 | lm = list_entry(resource->entry, struct vme_lm_resource, list); |
1196 | |
1197 | if (bridge->lm_get == NULL) { |
1198 | printk(KERN_ERR "vme_lm_get not supported\n"); |
1199 | return -EINVAL; |
1200 | } |
1201 | |
1202 | return bridge->lm_get(lm, lm_base, aspace, cycle); |
1203 | } |
1204 | EXPORT_SYMBOL(vme_lm_get); |
1205 | |
1206 | int vme_lm_attach(struct vme_resource *resource, int monitor, |
1207 | void (*callback)(int)) |
1208 | { |
1209 | struct vme_bridge *bridge = find_bridge(resource); |
1210 | struct vme_lm_resource *lm; |
1211 | |
1212 | if (resource->type != VME_LM) { |
1213 | printk(KERN_ERR "Not a Location Monitor resource\n"); |
1214 | return -EINVAL; |
1215 | } |
1216 | |
1217 | lm = list_entry(resource->entry, struct vme_lm_resource, list); |
1218 | |
1219 | if (bridge->lm_attach == NULL) { |
1220 | printk(KERN_ERR "vme_lm_attach not supported\n"); |
1221 | return -EINVAL; |
1222 | } |
1223 | |
1224 | return bridge->lm_attach(lm, monitor, callback); |
1225 | } |
1226 | EXPORT_SYMBOL(vme_lm_attach); |
1227 | |
1228 | int vme_lm_detach(struct vme_resource *resource, int monitor) |
1229 | { |
1230 | struct vme_bridge *bridge = find_bridge(resource); |
1231 | struct vme_lm_resource *lm; |
1232 | |
1233 | if (resource->type != VME_LM) { |
1234 | printk(KERN_ERR "Not a Location Monitor resource\n"); |
1235 | return -EINVAL; |
1236 | } |
1237 | |
1238 | lm = list_entry(resource->entry, struct vme_lm_resource, list); |
1239 | |
1240 | if (bridge->lm_detach == NULL) { |
1241 | printk(KERN_ERR "vme_lm_detach not supported\n"); |
1242 | return -EINVAL; |
1243 | } |
1244 | |
1245 | return bridge->lm_detach(lm, monitor); |
1246 | } |
1247 | EXPORT_SYMBOL(vme_lm_detach); |
1248 | |
1249 | void vme_lm_free(struct vme_resource *resource) |
1250 | { |
1251 | struct vme_lm_resource *lm; |
1252 | |
1253 | if (resource->type != VME_LM) { |
1254 | printk(KERN_ERR "Not a Location Monitor resource\n"); |
1255 | return; |
1256 | } |
1257 | |
1258 | lm = list_entry(resource->entry, struct vme_lm_resource, list); |
1259 | |
1260 | mutex_lock(&lm->mtx); |
1261 | |
1262 | /* XXX |
1263 | * Check to see that there aren't any callbacks still attached, if |
1264 | * there are we should probably be detaching them! |
1265 | */ |
1266 | |
1267 | lm->locked = 0; |
1268 | |
1269 | mutex_unlock(&lm->mtx); |
1270 | |
1271 | kfree(resource); |
1272 | } |
1273 | EXPORT_SYMBOL(vme_lm_free); |
1274 | |
1275 | int vme_slot_get(struct vme_dev *vdev) |
1276 | { |
1277 | struct vme_bridge *bridge; |
1278 | |
1279 | bridge = vdev->bridge; |
1280 | if (bridge == NULL) { |
1281 | printk(KERN_ERR "Can't find VME bus\n"); |
1282 | return -EINVAL; |
1283 | } |
1284 | |
1285 | if (bridge->slot_get == NULL) { |
1286 | printk(KERN_WARNING "vme_slot_get not supported\n"); |
1287 | return -EINVAL; |
1288 | } |
1289 | |
1290 | return bridge->slot_get(bridge); |
1291 | } |
1292 | EXPORT_SYMBOL(vme_slot_get); |
1293 | |
1294 | |
1295 | /* - Bridge Registration --------------------------------------------------- */ |
1296 | |
1297 | static void vme_dev_release(struct device *dev) |
1298 | { |
1299 | kfree(dev_to_vme_dev(dev)); |
1300 | } |
1301 | |
1302 | int vme_register_bridge(struct vme_bridge *bridge) |
1303 | { |
1304 | int i; |
1305 | int ret = -1; |
1306 | |
1307 | mutex_lock(&vme_buses_lock); |
1308 | for (i = 0; i < sizeof(vme_bus_numbers) * 8; i++) { |
1309 | if ((vme_bus_numbers & (1 << i)) == 0) { |
1310 | vme_bus_numbers |= (1 << i); |
1311 | bridge->num = i; |
1312 | INIT_LIST_HEAD(&bridge->devices); |
1313 | list_add_tail(&bridge->bus_list, &vme_bus_list); |
1314 | ret = 0; |
1315 | break; |
1316 | } |
1317 | } |
1318 | mutex_unlock(&vme_buses_lock); |
1319 | |
1320 | return ret; |
1321 | } |
1322 | EXPORT_SYMBOL(vme_register_bridge); |
1323 | |
1324 | void vme_unregister_bridge(struct vme_bridge *bridge) |
1325 | { |
1326 | struct vme_dev *vdev; |
1327 | struct vme_dev *tmp; |
1328 | |
1329 | mutex_lock(&vme_buses_lock); |
1330 | vme_bus_numbers &= ~(1 << bridge->num); |
1331 | list_for_each_entry_safe(vdev, tmp, &bridge->devices, bridge_list) { |
1332 | list_del(&vdev->drv_list); |
1333 | list_del(&vdev->bridge_list); |
1334 | device_unregister(&vdev->dev); |
1335 | } |
1336 | list_del(&bridge->bus_list); |
1337 | mutex_unlock(&vme_buses_lock); |
1338 | } |
1339 | EXPORT_SYMBOL(vme_unregister_bridge); |
1340 | |
1341 | /* - Driver Registration --------------------------------------------------- */ |
1342 | |
1343 | static int __vme_register_driver_bus(struct vme_driver *drv, |
1344 | struct vme_bridge *bridge, unsigned int ndevs) |
1345 | { |
1346 | int err; |
1347 | unsigned int i; |
1348 | struct vme_dev *vdev; |
1349 | struct vme_dev *tmp; |
1350 | |
1351 | for (i = 0; i < ndevs; i++) { |
1352 | vdev = kzalloc(sizeof(struct vme_dev), GFP_KERNEL); |
1353 | if (!vdev) { |
1354 | err = -ENOMEM; |
1355 | goto err_devalloc; |
1356 | } |
1357 | vdev->num = i; |
1358 | vdev->bridge = bridge; |
1359 | vdev->dev.platform_data = drv; |
1360 | vdev->dev.release = vme_dev_release; |
1361 | vdev->dev.parent = bridge->parent; |
1362 | vdev->dev.bus = &vme_bus_type; |
1363 | dev_set_name(&vdev->dev, "%s.%u-%u", drv->name, bridge->num, |
1364 | vdev->num); |
1365 | |
1366 | err = device_register(&vdev->dev); |
1367 | if (err) |
1368 | goto err_reg; |
1369 | |
1370 | if (vdev->dev.platform_data) { |
1371 | list_add_tail(&vdev->drv_list, &drv->devices); |
1372 | list_add_tail(&vdev->bridge_list, &bridge->devices); |
1373 | } else |
1374 | device_unregister(&vdev->dev); |
1375 | } |
1376 | return 0; |
1377 | |
1378 | err_reg: |
1379 | put_device(&vdev->dev); |
1380 | kfree(vdev); |
1381 | err_devalloc: |
1382 | list_for_each_entry_safe(vdev, tmp, &drv->devices, drv_list) { |
1383 | list_del(&vdev->drv_list); |
1384 | list_del(&vdev->bridge_list); |
1385 | device_unregister(&vdev->dev); |
1386 | } |
1387 | return err; |
1388 | } |
1389 | |
1390 | static int __vme_register_driver(struct vme_driver *drv, unsigned int ndevs) |
1391 | { |
1392 | struct vme_bridge *bridge; |
1393 | int err = 0; |
1394 | |
1395 | mutex_lock(&vme_buses_lock); |
1396 | list_for_each_entry(bridge, &vme_bus_list, bus_list) { |
1397 | /* |
1398 | * This cannot cause trouble as we already have vme_buses_lock |
1399 | * and if the bridge is removed, it will have to go through |
1400 | * vme_unregister_bridge() to do it (which calls remove() on |
1401 | * the bridge which in turn tries to acquire vme_buses_lock and |
1402 | * will have to wait). |
1403 | */ |
1404 | err = __vme_register_driver_bus(drv, bridge, ndevs); |
1405 | if (err) |
1406 | break; |
1407 | } |
1408 | mutex_unlock(&vme_buses_lock); |
1409 | return err; |
1410 | } |
1411 | |
1412 | int vme_register_driver(struct vme_driver *drv, unsigned int ndevs) |
1413 | { |
1414 | int err; |
1415 | |
1416 | drv->driver.name = drv->name; |
1417 | drv->driver.bus = &vme_bus_type; |
1418 | INIT_LIST_HEAD(&drv->devices); |
1419 | |
1420 | err = driver_register(&drv->driver); |
1421 | if (err) |
1422 | return err; |
1423 | |
1424 | err = __vme_register_driver(drv, ndevs); |
1425 | if (err) |
1426 | driver_unregister(&drv->driver); |
1427 | |
1428 | return err; |
1429 | } |
1430 | EXPORT_SYMBOL(vme_register_driver); |
1431 | |
1432 | void vme_unregister_driver(struct vme_driver *drv) |
1433 | { |
1434 | struct vme_dev *dev, *dev_tmp; |
1435 | |
1436 | mutex_lock(&vme_buses_lock); |
1437 | list_for_each_entry_safe(dev, dev_tmp, &drv->devices, drv_list) { |
1438 | list_del(&dev->drv_list); |
1439 | list_del(&dev->bridge_list); |
1440 | device_unregister(&dev->dev); |
1441 | } |
1442 | mutex_unlock(&vme_buses_lock); |
1443 | |
1444 | driver_unregister(&drv->driver); |
1445 | } |
1446 | EXPORT_SYMBOL(vme_unregister_driver); |
1447 | |
1448 | /* - Bus Registration ------------------------------------------------------ */ |
1449 | |
1450 | static int vme_bus_match(struct device *dev, struct device_driver *drv) |
1451 | { |
1452 | struct vme_driver *vme_drv; |
1453 | |
1454 | vme_drv = container_of(drv, struct vme_driver, driver); |
1455 | |
1456 | if (dev->platform_data == vme_drv) { |
1457 | struct vme_dev *vdev = dev_to_vme_dev(dev); |
1458 | |
1459 | if (vme_drv->match && vme_drv->match(vdev)) |
1460 | return 1; |
1461 | |
1462 | dev->platform_data = NULL; |
1463 | } |
1464 | return 0; |
1465 | } |
1466 | |
1467 | static int vme_bus_probe(struct device *dev) |
1468 | { |
1469 | int retval = -ENODEV; |
1470 | struct vme_driver *driver; |
1471 | struct vme_dev *vdev = dev_to_vme_dev(dev); |
1472 | |
1473 | driver = dev->platform_data; |
1474 | |
1475 | if (driver->probe != NULL) |
1476 | retval = driver->probe(vdev); |
1477 | |
1478 | return retval; |
1479 | } |
1480 | |
1481 | static int vme_bus_remove(struct device *dev) |
1482 | { |
1483 | int retval = -ENODEV; |
1484 | struct vme_driver *driver; |
1485 | struct vme_dev *vdev = dev_to_vme_dev(dev); |
1486 | |
1487 | driver = dev->platform_data; |
1488 | |
1489 | if (driver->remove != NULL) |
1490 | retval = driver->remove(vdev); |
1491 | |
1492 | return retval; |
1493 | } |
1494 | |
1495 | struct bus_type vme_bus_type = { |
1496 | .name = "vme", |
1497 | .match = vme_bus_match, |
1498 | .probe = vme_bus_probe, |
1499 | .remove = vme_bus_remove, |
1500 | }; |
1501 | EXPORT_SYMBOL(vme_bus_type); |
1502 | |
1503 | static int __init vme_init(void) |
1504 | { |
1505 | return bus_register(&vme_bus_type); |
1506 | } |
1507 | |
1508 | static void __exit vme_exit(void) |
1509 | { |
1510 | bus_unregister(&vme_bus_type); |
1511 | } |
1512 | |
1513 | MODULE_DESCRIPTION("VME bridge driver framework"); |
1514 | MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com"); |
1515 | MODULE_LICENSE("GPL"); |
1516 | |
1517 | module_init(vme_init); |
1518 | module_exit(vme_exit); |
1519 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9