blob: 3cbc69c65d780f759fa5c8b6a0329f0f4885421c [file] [log] [blame]
Martyn Welcha17a75e2009-07-31 09:28:17 +01001/*
2 * VME Bridge Framework
3 *
Martyn Welch66bd8db2010-02-18 15:12:52 +00004 * Author: Martyn Welch <martyn.welch@ge.com>
5 * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
Martyn Welcha17a75e2009-07-31 09:28:17 +01006 *
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
Martyn Welcha17a75e2009-07-31 09:28:17 +010016#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>
Martyn Welch400822f2009-08-11 16:20:22 +010030#include <linux/mutex.h>
Martyn Welcha17a75e2009-07-31 09:28:17 +010031#include <linux/spinlock.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Martyn Welcha17a75e2009-07-31 09:28:17 +010033
34#include "vme.h"
35#include "vme_bridge.h"
36
Manohar Vanga733e3ef2011-08-12 12:30:48 +020037/* Bitmask and list of registered buses both protected by common mutex */
Martyn Welcha17a75e2009-07-31 09:28:17 +010038static unsigned int vme_bus_numbers;
Manohar Vanga733e3ef2011-08-12 12:30:48 +020039static LIST_HEAD(vme_bus_list);
40static DEFINE_MUTEX(vme_buses_lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +010041
Martyn Welchead1f3e2009-12-15 08:43:02 +000042static void __exit vme_exit(void);
43static int __init vme_init(void);
Martyn Welcha17a75e2009-07-31 09:28:17 +010044
Manohar Vanga8f966dc2011-09-26 11:27:15 +020045static struct vme_dev *dev_to_vme_dev(struct device *dev)
Martyn Welcha17a75e2009-07-31 09:28:17 +010046{
Manohar Vanga8f966dc2011-09-26 11:27:15 +020047 return container_of(dev, struct vme_dev, dev);
Martyn Welcha17a75e2009-07-31 09:28:17 +010048}
49
50/*
51 * Find the bridge that the resource is associated with.
52 */
53static 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;
Martyn Welch42fb5032009-08-11 17:44:56 +010069 case VME_LM:
70 return list_entry(resource->entry, struct vme_lm_resource,
71 list)->parent;
72 break;
Martyn Welcha17a75e2009-07-31 09:28:17 +010073 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.
Martyn Welcha17a75e2009-07-31 09:28:17 +010083 */
Martyn Welchead1f3e2009-12-15 08:43:02 +000084void *vme_alloc_consistent(struct vme_resource *resource, size_t size,
Martyn Welcha17a75e2009-07-31 09:28:17 +010085 dma_addr_t *dma)
86{
87 struct vme_bridge *bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +010088
Martyn Welchead1f3e2009-12-15 08:43:02 +000089 if (resource == NULL) {
90 printk(KERN_ERR "No resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +010091 return NULL;
92 }
93
94 bridge = find_bridge(resource);
Martyn Welchead1f3e2009-12-15 08:43:02 +000095 if (bridge == NULL) {
96 printk(KERN_ERR "Can't find bridge\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +010097 return NULL;
98 }
99
Martyn Welcha17a75e2009-07-31 09:28:17 +0100100 if (bridge->parent == NULL) {
Manohar Vanga7f58f022011-08-10 11:33:46 +0200101 printk(KERN_ERR "Dev entry NULL for"
102 " bridge %s\n", bridge->name);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100103 return NULL;
104 }
Martyn Welcha17a75e2009-07-31 09:28:17 +0100105
Manohar Vanga7f58f022011-08-10 11:33:46 +0200106 if (bridge->alloc_consistent == NULL) {
107 printk(KERN_ERR "alloc_consistent not supported by"
108 " bridge %s\n", bridge->name);
109 return NULL;
110 }
111
112 return bridge->alloc_consistent(bridge->parent, size, dma);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100113}
114EXPORT_SYMBOL(vme_alloc_consistent);
115
116/*
117 * Free previously allocated contiguous block of memory.
Martyn Welcha17a75e2009-07-31 09:28:17 +0100118 */
119void vme_free_consistent(struct vme_resource *resource, size_t size,
120 void *vaddr, dma_addr_t dma)
121{
122 struct vme_bridge *bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +0100123
Martyn Welchead1f3e2009-12-15 08:43:02 +0000124 if (resource == NULL) {
125 printk(KERN_ERR "No resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100126 return;
127 }
128
129 bridge = find_bridge(resource);
Martyn Welchead1f3e2009-12-15 08:43:02 +0000130 if (bridge == NULL) {
131 printk(KERN_ERR "Can't find bridge\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100132 return;
133 }
134
Manohar Vanga7f58f022011-08-10 11:33:46 +0200135 if (bridge->parent == NULL) {
136 printk(KERN_ERR "Dev entry NULL for"
137 " bridge %s\n", bridge->name);
138 return;
139 }
Martyn Welcha17a75e2009-07-31 09:28:17 +0100140
Manohar Vanga7f58f022011-08-10 11:33:46 +0200141 if (bridge->free_consistent == NULL) {
142 printk(KERN_ERR "free_consistent not supported by"
143 " bridge %s\n", bridge->name);
144 return;
145 }
146
147 bridge->free_consistent(bridge->parent, size, vaddr, dma);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100148}
149EXPORT_SYMBOL(vme_free_consistent);
150
151size_t vme_get_size(struct vme_resource *resource)
152{
153 int enabled, retval;
154 unsigned long long base, size;
155 dma_addr_t buf_base;
156 vme_address_t aspace;
157 vme_cycle_t cycle;
158 vme_width_t dwidth;
159
160 switch (resource->type) {
161 case VME_MASTER:
162 retval = vme_master_get(resource, &enabled, &base, &size,
163 &aspace, &cycle, &dwidth);
164
165 return size;
166 break;
167 case VME_SLAVE:
168 retval = vme_slave_get(resource, &enabled, &base, &size,
169 &buf_base, &aspace, &cycle);
170
171 return size;
172 break;
173 case VME_DMA:
174 return 0;
175 break;
176 default:
177 printk(KERN_ERR "Unknown resource type\n");
178 return 0;
179 break;
180 }
181}
182EXPORT_SYMBOL(vme_get_size);
183
184static int vme_check_window(vme_address_t aspace, unsigned long long vme_base,
185 unsigned long long size)
186{
187 int retval = 0;
188
189 switch (aspace) {
190 case VME_A16:
191 if (((vme_base + size) > VME_A16_MAX) ||
192 (vme_base > VME_A16_MAX))
193 retval = -EFAULT;
194 break;
195 case VME_A24:
196 if (((vme_base + size) > VME_A24_MAX) ||
197 (vme_base > VME_A24_MAX))
198 retval = -EFAULT;
199 break;
200 case VME_A32:
201 if (((vme_base + size) > VME_A32_MAX) ||
202 (vme_base > VME_A32_MAX))
203 retval = -EFAULT;
204 break;
205 case VME_A64:
206 /*
207 * Any value held in an unsigned long long can be used as the
208 * base
209 */
210 break;
211 case VME_CRCSR:
212 if (((vme_base + size) > VME_CRCSR_MAX) ||
213 (vme_base > VME_CRCSR_MAX))
214 retval = -EFAULT;
215 break;
216 case VME_USER1:
217 case VME_USER2:
218 case VME_USER3:
219 case VME_USER4:
220 /* User Defined */
221 break;
222 default:
Martyn Welchead1f3e2009-12-15 08:43:02 +0000223 printk(KERN_ERR "Invalid address space\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100224 retval = -EINVAL;
225 break;
226 }
227
228 return retval;
229}
230
231/*
232 * Request a slave image with specific attributes, return some unique
233 * identifier.
234 */
Manohar Vanga8f966dc2011-09-26 11:27:15 +0200235struct vme_resource *vme_slave_request(struct vme_dev *vdev,
Martyn Welcha17a75e2009-07-31 09:28:17 +0100236 vme_address_t address, vme_cycle_t cycle)
237{
238 struct vme_bridge *bridge;
239 struct list_head *slave_pos = NULL;
240 struct vme_slave_resource *allocated_image = NULL;
241 struct vme_slave_resource *slave_image = NULL;
242 struct vme_resource *resource = NULL;
243
Manohar Vanga8f966dc2011-09-26 11:27:15 +0200244 bridge = vdev->bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +0100245 if (bridge == NULL) {
246 printk(KERN_ERR "Can't find VME bus\n");
247 goto err_bus;
248 }
249
250 /* Loop through slave resources */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000251 list_for_each(slave_pos, &bridge->slave_resources) {
Martyn Welcha17a75e2009-07-31 09:28:17 +0100252 slave_image = list_entry(slave_pos,
253 struct vme_slave_resource, list);
254
255 if (slave_image == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000256 printk(KERN_ERR "Registered NULL Slave resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100257 continue;
258 }
259
260 /* Find an unlocked and compatible image */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000261 mutex_lock(&slave_image->mtx);
Martyn Welchead1f3e2009-12-15 08:43:02 +0000262 if (((slave_image->address_attr & address) == address) &&
Martyn Welcha17a75e2009-07-31 09:28:17 +0100263 ((slave_image->cycle_attr & cycle) == cycle) &&
264 (slave_image->locked == 0)) {
265
266 slave_image->locked = 1;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000267 mutex_unlock(&slave_image->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100268 allocated_image = slave_image;
269 break;
270 }
Emilio G. Cota886953e2010-11-12 11:14:07 +0000271 mutex_unlock(&slave_image->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100272 }
273
274 /* No free image */
275 if (allocated_image == NULL)
276 goto err_image;
277
278 resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
279 if (resource == NULL) {
280 printk(KERN_WARNING "Unable to allocate resource structure\n");
281 goto err_alloc;
282 }
283 resource->type = VME_SLAVE;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000284 resource->entry = &allocated_image->list;
Martyn Welcha17a75e2009-07-31 09:28:17 +0100285
286 return resource;
287
288err_alloc:
289 /* Unlock image */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000290 mutex_lock(&slave_image->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100291 slave_image->locked = 0;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000292 mutex_unlock(&slave_image->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100293err_image:
294err_bus:
295 return NULL;
296}
297EXPORT_SYMBOL(vme_slave_request);
298
Martyn Welchead1f3e2009-12-15 08:43:02 +0000299int vme_slave_set(struct vme_resource *resource, int enabled,
Martyn Welcha17a75e2009-07-31 09:28:17 +0100300 unsigned long long vme_base, unsigned long long size,
301 dma_addr_t buf_base, vme_address_t aspace, vme_cycle_t cycle)
302{
303 struct vme_bridge *bridge = find_bridge(resource);
304 struct vme_slave_resource *image;
305 int retval;
306
307 if (resource->type != VME_SLAVE) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000308 printk(KERN_ERR "Not a slave resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100309 return -EINVAL;
310 }
311
312 image = list_entry(resource->entry, struct vme_slave_resource, list);
313
314 if (bridge->slave_set == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000315 printk(KERN_ERR "Function not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100316 return -ENOSYS;
317 }
318
Martyn Welchead1f3e2009-12-15 08:43:02 +0000319 if (!(((image->address_attr & aspace) == aspace) &&
Martyn Welcha17a75e2009-07-31 09:28:17 +0100320 ((image->cycle_attr & cycle) == cycle))) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000321 printk(KERN_ERR "Invalid attributes\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100322 return -EINVAL;
323 }
324
325 retval = vme_check_window(aspace, vme_base, size);
Martyn Welchead1f3e2009-12-15 08:43:02 +0000326 if (retval)
Martyn Welcha17a75e2009-07-31 09:28:17 +0100327 return retval;
328
329 return bridge->slave_set(image, enabled, vme_base, size, buf_base,
330 aspace, cycle);
331}
332EXPORT_SYMBOL(vme_slave_set);
333
Martyn Welchead1f3e2009-12-15 08:43:02 +0000334int vme_slave_get(struct vme_resource *resource, int *enabled,
Martyn Welcha17a75e2009-07-31 09:28:17 +0100335 unsigned long long *vme_base, unsigned long long *size,
336 dma_addr_t *buf_base, vme_address_t *aspace, vme_cycle_t *cycle)
337{
338 struct vme_bridge *bridge = find_bridge(resource);
339 struct vme_slave_resource *image;
340
341 if (resource->type != VME_SLAVE) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000342 printk(KERN_ERR "Not a slave resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100343 return -EINVAL;
344 }
345
346 image = list_entry(resource->entry, struct vme_slave_resource, list);
347
Emilio G. Cota51a569f2009-08-10 16:52:42 +0200348 if (bridge->slave_get == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000349 printk(KERN_ERR "vme_slave_get not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100350 return -EINVAL;
351 }
352
353 return bridge->slave_get(image, enabled, vme_base, size, buf_base,
354 aspace, cycle);
355}
356EXPORT_SYMBOL(vme_slave_get);
357
358void vme_slave_free(struct vme_resource *resource)
359{
360 struct vme_slave_resource *slave_image;
361
362 if (resource->type != VME_SLAVE) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000363 printk(KERN_ERR "Not a slave resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100364 return;
365 }
366
367 slave_image = list_entry(resource->entry, struct vme_slave_resource,
368 list);
369 if (slave_image == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000370 printk(KERN_ERR "Can't find slave resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100371 return;
372 }
373
374 /* Unlock image */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000375 mutex_lock(&slave_image->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100376 if (slave_image->locked == 0)
377 printk(KERN_ERR "Image is already free\n");
378
379 slave_image->locked = 0;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000380 mutex_unlock(&slave_image->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100381
382 /* Free up resource memory */
383 kfree(resource);
384}
385EXPORT_SYMBOL(vme_slave_free);
386
387/*
388 * Request a master image with specific attributes, return some unique
389 * identifier.
390 */
Manohar Vanga8f966dc2011-09-26 11:27:15 +0200391struct vme_resource *vme_master_request(struct vme_dev *vdev,
Martyn Welcha17a75e2009-07-31 09:28:17 +0100392 vme_address_t address, vme_cycle_t cycle, vme_width_t dwidth)
393{
394 struct vme_bridge *bridge;
395 struct list_head *master_pos = NULL;
396 struct vme_master_resource *allocated_image = NULL;
397 struct vme_master_resource *master_image = NULL;
398 struct vme_resource *resource = NULL;
399
Manohar Vanga8f966dc2011-09-26 11:27:15 +0200400 bridge = vdev->bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +0100401 if (bridge == NULL) {
402 printk(KERN_ERR "Can't find VME bus\n");
403 goto err_bus;
404 }
405
406 /* Loop through master resources */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000407 list_for_each(master_pos, &bridge->master_resources) {
Martyn Welcha17a75e2009-07-31 09:28:17 +0100408 master_image = list_entry(master_pos,
409 struct vme_master_resource, list);
410
411 if (master_image == NULL) {
412 printk(KERN_WARNING "Registered NULL master resource\n");
413 continue;
414 }
415
416 /* Find an unlocked and compatible image */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000417 spin_lock(&master_image->lock);
Martyn Welchead1f3e2009-12-15 08:43:02 +0000418 if (((master_image->address_attr & address) == address) &&
Martyn Welcha17a75e2009-07-31 09:28:17 +0100419 ((master_image->cycle_attr & cycle) == cycle) &&
420 ((master_image->width_attr & dwidth) == dwidth) &&
421 (master_image->locked == 0)) {
422
423 master_image->locked = 1;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000424 spin_unlock(&master_image->lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100425 allocated_image = master_image;
426 break;
427 }
Emilio G. Cota886953e2010-11-12 11:14:07 +0000428 spin_unlock(&master_image->lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100429 }
430
431 /* Check to see if we found a resource */
432 if (allocated_image == NULL) {
433 printk(KERN_ERR "Can't find a suitable resource\n");
434 goto err_image;
435 }
436
437 resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
438 if (resource == NULL) {
439 printk(KERN_ERR "Unable to allocate resource structure\n");
440 goto err_alloc;
441 }
442 resource->type = VME_MASTER;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000443 resource->entry = &allocated_image->list;
Martyn Welcha17a75e2009-07-31 09:28:17 +0100444
445 return resource;
446
Martyn Welcha17a75e2009-07-31 09:28:17 +0100447err_alloc:
448 /* Unlock image */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000449 spin_lock(&master_image->lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100450 master_image->locked = 0;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000451 spin_unlock(&master_image->lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100452err_image:
453err_bus:
454 return NULL;
455}
456EXPORT_SYMBOL(vme_master_request);
457
Martyn Welchead1f3e2009-12-15 08:43:02 +0000458int vme_master_set(struct vme_resource *resource, int enabled,
Martyn Welcha17a75e2009-07-31 09:28:17 +0100459 unsigned long long vme_base, unsigned long long size,
460 vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth)
461{
462 struct vme_bridge *bridge = find_bridge(resource);
463 struct vme_master_resource *image;
464 int retval;
465
466 if (resource->type != VME_MASTER) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000467 printk(KERN_ERR "Not a master resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100468 return -EINVAL;
469 }
470
471 image = list_entry(resource->entry, struct vme_master_resource, list);
472
473 if (bridge->master_set == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000474 printk(KERN_WARNING "vme_master_set not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100475 return -EINVAL;
476 }
477
Martyn Welchead1f3e2009-12-15 08:43:02 +0000478 if (!(((image->address_attr & aspace) == aspace) &&
Martyn Welcha17a75e2009-07-31 09:28:17 +0100479 ((image->cycle_attr & cycle) == cycle) &&
480 ((image->width_attr & dwidth) == dwidth))) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000481 printk(KERN_WARNING "Invalid attributes\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100482 return -EINVAL;
483 }
484
485 retval = vme_check_window(aspace, vme_base, size);
Martyn Welchead1f3e2009-12-15 08:43:02 +0000486 if (retval)
Martyn Welcha17a75e2009-07-31 09:28:17 +0100487 return retval;
488
489 return bridge->master_set(image, enabled, vme_base, size, aspace,
490 cycle, dwidth);
491}
492EXPORT_SYMBOL(vme_master_set);
493
Martyn Welchead1f3e2009-12-15 08:43:02 +0000494int vme_master_get(struct vme_resource *resource, int *enabled,
Martyn Welcha17a75e2009-07-31 09:28:17 +0100495 unsigned long long *vme_base, unsigned long long *size,
496 vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth)
497{
498 struct vme_bridge *bridge = find_bridge(resource);
499 struct vme_master_resource *image;
500
501 if (resource->type != VME_MASTER) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000502 printk(KERN_ERR "Not a master resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100503 return -EINVAL;
504 }
505
506 image = list_entry(resource->entry, struct vme_master_resource, list);
507
Emilio G. Cota51a569f2009-08-10 16:52:42 +0200508 if (bridge->master_get == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000509 printk(KERN_WARNING "vme_master_set not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100510 return -EINVAL;
511 }
512
513 return bridge->master_get(image, enabled, vme_base, size, aspace,
514 cycle, dwidth);
515}
516EXPORT_SYMBOL(vme_master_get);
517
518/*
519 * Read data out of VME space into a buffer.
520 */
Martyn Welchead1f3e2009-12-15 08:43:02 +0000521ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count,
Martyn Welcha17a75e2009-07-31 09:28:17 +0100522 loff_t offset)
523{
524 struct vme_bridge *bridge = find_bridge(resource);
525 struct vme_master_resource *image;
526 size_t length;
527
528 if (bridge->master_read == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000529 printk(KERN_WARNING "Reading from resource not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100530 return -EINVAL;
531 }
532
533 if (resource->type != VME_MASTER) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000534 printk(KERN_ERR "Not a master resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100535 return -EINVAL;
536 }
537
538 image = list_entry(resource->entry, struct vme_master_resource, list);
539
540 length = vme_get_size(resource);
541
542 if (offset > length) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000543 printk(KERN_WARNING "Invalid Offset\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100544 return -EFAULT;
545 }
546
547 if ((offset + count) > length)
548 count = length - offset;
549
550 return bridge->master_read(image, buf, count, offset);
551
552}
553EXPORT_SYMBOL(vme_master_read);
554
555/*
556 * Write data out to VME space from a buffer.
557 */
Martyn Welchead1f3e2009-12-15 08:43:02 +0000558ssize_t vme_master_write(struct vme_resource *resource, void *buf,
Martyn Welcha17a75e2009-07-31 09:28:17 +0100559 size_t count, loff_t offset)
560{
561 struct vme_bridge *bridge = find_bridge(resource);
562 struct vme_master_resource *image;
563 size_t length;
564
565 if (bridge->master_write == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000566 printk(KERN_WARNING "Writing to resource not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100567 return -EINVAL;
568 }
569
570 if (resource->type != VME_MASTER) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000571 printk(KERN_ERR "Not a master resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100572 return -EINVAL;
573 }
574
575 image = list_entry(resource->entry, struct vme_master_resource, list);
576
577 length = vme_get_size(resource);
578
579 if (offset > length) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000580 printk(KERN_WARNING "Invalid Offset\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100581 return -EFAULT;
582 }
583
584 if ((offset + count) > length)
585 count = length - offset;
586
587 return bridge->master_write(image, buf, count, offset);
588}
589EXPORT_SYMBOL(vme_master_write);
590
591/*
592 * Perform RMW cycle to provided location.
593 */
Martyn Welchead1f3e2009-12-15 08:43:02 +0000594unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask,
Martyn Welcha17a75e2009-07-31 09:28:17 +0100595 unsigned int compare, unsigned int swap, loff_t offset)
596{
597 struct vme_bridge *bridge = find_bridge(resource);
598 struct vme_master_resource *image;
599
600 if (bridge->master_rmw == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000601 printk(KERN_WARNING "Writing to resource not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100602 return -EINVAL;
603 }
604
605 if (resource->type != VME_MASTER) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000606 printk(KERN_ERR "Not a master resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100607 return -EINVAL;
608 }
609
610 image = list_entry(resource->entry, struct vme_master_resource, list);
611
612 return bridge->master_rmw(image, mask, compare, swap, offset);
613}
614EXPORT_SYMBOL(vme_master_rmw);
615
616void vme_master_free(struct vme_resource *resource)
617{
618 struct vme_master_resource *master_image;
619
620 if (resource->type != VME_MASTER) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000621 printk(KERN_ERR "Not a master resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100622 return;
623 }
624
625 master_image = list_entry(resource->entry, struct vme_master_resource,
626 list);
627 if (master_image == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000628 printk(KERN_ERR "Can't find master resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100629 return;
630 }
631
632 /* Unlock image */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000633 spin_lock(&master_image->lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100634 if (master_image->locked == 0)
635 printk(KERN_ERR "Image is already free\n");
636
637 master_image->locked = 0;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000638 spin_unlock(&master_image->lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100639
640 /* Free up resource memory */
641 kfree(resource);
642}
643EXPORT_SYMBOL(vme_master_free);
644
645/*
646 * Request a DMA controller with specific attributes, return some unique
647 * identifier.
648 */
Manohar Vanga8f966dc2011-09-26 11:27:15 +0200649struct vme_resource *vme_dma_request(struct vme_dev *vdev,
650 vme_dma_route_t route)
Martyn Welcha17a75e2009-07-31 09:28:17 +0100651{
652 struct vme_bridge *bridge;
653 struct list_head *dma_pos = NULL;
654 struct vme_dma_resource *allocated_ctrlr = NULL;
655 struct vme_dma_resource *dma_ctrlr = NULL;
656 struct vme_resource *resource = NULL;
657
658 /* XXX Not checking resource attributes */
659 printk(KERN_ERR "No VME resource Attribute tests done\n");
660
Manohar Vanga8f966dc2011-09-26 11:27:15 +0200661 bridge = vdev->bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +0100662 if (bridge == NULL) {
663 printk(KERN_ERR "Can't find VME bus\n");
664 goto err_bus;
665 }
666
667 /* Loop through DMA resources */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000668 list_for_each(dma_pos, &bridge->dma_resources) {
Martyn Welcha17a75e2009-07-31 09:28:17 +0100669 dma_ctrlr = list_entry(dma_pos,
670 struct vme_dma_resource, list);
671
672 if (dma_ctrlr == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000673 printk(KERN_ERR "Registered NULL DMA resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100674 continue;
675 }
676
Martyn Welch4f723df2010-02-18 15:12:58 +0000677 /* Find an unlocked and compatible controller */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000678 mutex_lock(&dma_ctrlr->mtx);
Martyn Welch4f723df2010-02-18 15:12:58 +0000679 if (((dma_ctrlr->route_attr & route) == route) &&
680 (dma_ctrlr->locked == 0)) {
681
Martyn Welcha17a75e2009-07-31 09:28:17 +0100682 dma_ctrlr->locked = 1;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000683 mutex_unlock(&dma_ctrlr->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100684 allocated_ctrlr = dma_ctrlr;
685 break;
686 }
Emilio G. Cota886953e2010-11-12 11:14:07 +0000687 mutex_unlock(&dma_ctrlr->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100688 }
689
690 /* Check to see if we found a resource */
691 if (allocated_ctrlr == NULL)
692 goto err_ctrlr;
693
694 resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
695 if (resource == NULL) {
696 printk(KERN_WARNING "Unable to allocate resource structure\n");
697 goto err_alloc;
698 }
699 resource->type = VME_DMA;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000700 resource->entry = &allocated_ctrlr->list;
Martyn Welcha17a75e2009-07-31 09:28:17 +0100701
702 return resource;
703
704err_alloc:
705 /* Unlock image */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000706 mutex_lock(&dma_ctrlr->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100707 dma_ctrlr->locked = 0;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000708 mutex_unlock(&dma_ctrlr->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100709err_ctrlr:
710err_bus:
711 return NULL;
712}
Martyn Welch58e50792009-10-29 16:35:20 +0000713EXPORT_SYMBOL(vme_dma_request);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100714
715/*
716 * Start new list
717 */
718struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource)
719{
720 struct vme_dma_resource *ctrlr;
721 struct vme_dma_list *dma_list;
722
723 if (resource->type != VME_DMA) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000724 printk(KERN_ERR "Not a DMA resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100725 return NULL;
726 }
727
728 ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
729
Martyn Welchead1f3e2009-12-15 08:43:02 +0000730 dma_list = kmalloc(sizeof(struct vme_dma_list), GFP_KERNEL);
731 if (dma_list == NULL) {
732 printk(KERN_ERR "Unable to allocate memory for new dma list\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100733 return NULL;
734 }
Emilio G. Cota886953e2010-11-12 11:14:07 +0000735 INIT_LIST_HEAD(&dma_list->entries);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100736 dma_list->parent = ctrlr;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000737 mutex_init(&dma_list->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100738
739 return dma_list;
740}
741EXPORT_SYMBOL(vme_new_dma_list);
742
743/*
744 * Create "Pattern" type attributes
745 */
746struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern,
747 vme_pattern_t type)
748{
749 struct vme_dma_attr *attributes;
750 struct vme_dma_pattern *pattern_attr;
751
Martyn Welchead1f3e2009-12-15 08:43:02 +0000752 attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
753 if (attributes == NULL) {
754 printk(KERN_ERR "Unable to allocate memory for attributes "
755 "structure\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100756 goto err_attr;
757 }
758
Martyn Welchead1f3e2009-12-15 08:43:02 +0000759 pattern_attr = kmalloc(sizeof(struct vme_dma_pattern), GFP_KERNEL);
760 if (pattern_attr == NULL) {
761 printk(KERN_ERR "Unable to allocate memory for pattern "
762 "attributes\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100763 goto err_pat;
764 }
765
766 attributes->type = VME_DMA_PATTERN;
767 attributes->private = (void *)pattern_attr;
768
769 pattern_attr->pattern = pattern;
770 pattern_attr->type = type;
771
772 return attributes;
773
Martyn Welcha17a75e2009-07-31 09:28:17 +0100774err_pat:
775 kfree(attributes);
776err_attr:
777 return NULL;
778}
779EXPORT_SYMBOL(vme_dma_pattern_attribute);
780
781/*
782 * Create "PCI" type attributes
783 */
784struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address)
785{
786 struct vme_dma_attr *attributes;
787 struct vme_dma_pci *pci_attr;
788
789 /* XXX Run some sanity checks here */
790
Martyn Welchead1f3e2009-12-15 08:43:02 +0000791 attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
792 if (attributes == NULL) {
793 printk(KERN_ERR "Unable to allocate memory for attributes "
794 "structure\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100795 goto err_attr;
796 }
797
Martyn Welchead1f3e2009-12-15 08:43:02 +0000798 pci_attr = kmalloc(sizeof(struct vme_dma_pci), GFP_KERNEL);
799 if (pci_attr == NULL) {
800 printk(KERN_ERR "Unable to allocate memory for pci "
801 "attributes\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100802 goto err_pci;
803 }
804
805
806
807 attributes->type = VME_DMA_PCI;
808 attributes->private = (void *)pci_attr;
809
810 pci_attr->address = address;
811
812 return attributes;
813
Martyn Welcha17a75e2009-07-31 09:28:17 +0100814err_pci:
815 kfree(attributes);
816err_attr:
817 return NULL;
818}
819EXPORT_SYMBOL(vme_dma_pci_attribute);
820
821/*
822 * Create "VME" type attributes
823 */
824struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address,
825 vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth)
826{
827 struct vme_dma_attr *attributes;
828 struct vme_dma_vme *vme_attr;
829
Martyn Welchead1f3e2009-12-15 08:43:02 +0000830 attributes = kmalloc(
Martyn Welcha17a75e2009-07-31 09:28:17 +0100831 sizeof(struct vme_dma_attr), GFP_KERNEL);
Martyn Welchead1f3e2009-12-15 08:43:02 +0000832 if (attributes == NULL) {
833 printk(KERN_ERR "Unable to allocate memory for attributes "
834 "structure\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100835 goto err_attr;
836 }
837
Martyn Welchead1f3e2009-12-15 08:43:02 +0000838 vme_attr = kmalloc(sizeof(struct vme_dma_vme), GFP_KERNEL);
839 if (vme_attr == NULL) {
840 printk(KERN_ERR "Unable to allocate memory for vme "
841 "attributes\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100842 goto err_vme;
843 }
844
845 attributes->type = VME_DMA_VME;
846 attributes->private = (void *)vme_attr;
847
848 vme_attr->address = address;
849 vme_attr->aspace = aspace;
850 vme_attr->cycle = cycle;
851 vme_attr->dwidth = dwidth;
852
853 return attributes;
854
Martyn Welcha17a75e2009-07-31 09:28:17 +0100855err_vme:
856 kfree(attributes);
857err_attr:
858 return NULL;
859}
860EXPORT_SYMBOL(vme_dma_vme_attribute);
861
862/*
863 * Free attribute
864 */
865void vme_dma_free_attribute(struct vme_dma_attr *attributes)
866{
867 kfree(attributes->private);
868 kfree(attributes);
869}
870EXPORT_SYMBOL(vme_dma_free_attribute);
871
872int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
873 struct vme_dma_attr *dest, size_t count)
874{
875 struct vme_bridge *bridge = list->parent->parent;
876 int retval;
877
878 if (bridge->dma_list_add == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000879 printk(KERN_WARNING "Link List DMA generation not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100880 return -EINVAL;
881 }
882
Emilio G. Cota886953e2010-11-12 11:14:07 +0000883 if (!mutex_trylock(&list->mtx)) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000884 printk(KERN_ERR "Link List already submitted\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100885 return -EINVAL;
886 }
887
888 retval = bridge->dma_list_add(list, src, dest, count);
889
Emilio G. Cota886953e2010-11-12 11:14:07 +0000890 mutex_unlock(&list->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100891
892 return retval;
893}
894EXPORT_SYMBOL(vme_dma_list_add);
895
896int vme_dma_list_exec(struct vme_dma_list *list)
897{
898 struct vme_bridge *bridge = list->parent->parent;
899 int retval;
900
901 if (bridge->dma_list_exec == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000902 printk(KERN_ERR "Link List DMA execution not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100903 return -EINVAL;
904 }
905
Emilio G. Cota886953e2010-11-12 11:14:07 +0000906 mutex_lock(&list->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100907
908 retval = bridge->dma_list_exec(list);
909
Emilio G. Cota886953e2010-11-12 11:14:07 +0000910 mutex_unlock(&list->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100911
912 return retval;
913}
914EXPORT_SYMBOL(vme_dma_list_exec);
915
916int vme_dma_list_free(struct vme_dma_list *list)
917{
918 struct vme_bridge *bridge = list->parent->parent;
919 int retval;
920
921 if (bridge->dma_list_empty == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000922 printk(KERN_WARNING "Emptying of Link Lists not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100923 return -EINVAL;
924 }
925
Emilio G. Cota886953e2010-11-12 11:14:07 +0000926 if (!mutex_trylock(&list->mtx)) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000927 printk(KERN_ERR "Link List in use\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100928 return -EINVAL;
929 }
930
931 /*
932 * Empty out all of the entries from the dma list. We need to go to the
933 * low level driver as dma entries are driver specific.
934 */
935 retval = bridge->dma_list_empty(list);
936 if (retval) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000937 printk(KERN_ERR "Unable to empty link-list entries\n");
Emilio G. Cota886953e2010-11-12 11:14:07 +0000938 mutex_unlock(&list->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100939 return retval;
940 }
Emilio G. Cota886953e2010-11-12 11:14:07 +0000941 mutex_unlock(&list->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100942 kfree(list);
943
944 return retval;
945}
946EXPORT_SYMBOL(vme_dma_list_free);
947
948int vme_dma_free(struct vme_resource *resource)
949{
950 struct vme_dma_resource *ctrlr;
951
952 if (resource->type != VME_DMA) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000953 printk(KERN_ERR "Not a DMA resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100954 return -EINVAL;
955 }
956
957 ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
958
Emilio G. Cota886953e2010-11-12 11:14:07 +0000959 if (!mutex_trylock(&ctrlr->mtx)) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000960 printk(KERN_ERR "Resource busy, can't free\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100961 return -EBUSY;
962 }
963
Emilio G. Cota886953e2010-11-12 11:14:07 +0000964 if (!(list_empty(&ctrlr->pending) && list_empty(&ctrlr->running))) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000965 printk(KERN_WARNING "Resource still processing transfers\n");
Emilio G. Cota886953e2010-11-12 11:14:07 +0000966 mutex_unlock(&ctrlr->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100967 return -EBUSY;
968 }
969
970 ctrlr->locked = 0;
971
Emilio G. Cota886953e2010-11-12 11:14:07 +0000972 mutex_unlock(&ctrlr->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100973
974 return 0;
975}
976EXPORT_SYMBOL(vme_dma_free);
977
Martyn Welchc813f592009-10-29 16:34:54 +0000978void vme_irq_handler(struct vme_bridge *bridge, int level, int statid)
979{
980 void (*call)(int, int, void *);
981 void *priv_data;
982
983 call = bridge->irq[level - 1].callback[statid].func;
984 priv_data = bridge->irq[level - 1].callback[statid].priv_data;
985
986 if (call != NULL)
987 call(level, statid, priv_data);
988 else
989 printk(KERN_WARNING "Spurilous VME interrupt, level:%x, "
990 "vector:%x\n", level, statid);
991}
992EXPORT_SYMBOL(vme_irq_handler);
993
Manohar Vanga8f966dc2011-09-26 11:27:15 +0200994int vme_irq_request(struct vme_dev *vdev, int level, int statid,
Martyn Welch29848ac2010-02-18 15:13:05 +0000995 void (*callback)(int, int, void *),
Martyn Welcha17a75e2009-07-31 09:28:17 +0100996 void *priv_data)
997{
998 struct vme_bridge *bridge;
999
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001000 bridge = vdev->bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001001 if (bridge == NULL) {
1002 printk(KERN_ERR "Can't find VME bus\n");
1003 return -EINVAL;
1004 }
1005
Martyn Welchead1f3e2009-12-15 08:43:02 +00001006 if ((level < 1) || (level > 7)) {
Martyn Welchc813f592009-10-29 16:34:54 +00001007 printk(KERN_ERR "Invalid interrupt level\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001008 return -EINVAL;
1009 }
1010
Martyn Welchc813f592009-10-29 16:34:54 +00001011 if (bridge->irq_set == NULL) {
1012 printk(KERN_ERR "Configuring interrupts not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001013 return -EINVAL;
1014 }
1015
Emilio G. Cota886953e2010-11-12 11:14:07 +00001016 mutex_lock(&bridge->irq_mtx);
Martyn Welchc813f592009-10-29 16:34:54 +00001017
1018 if (bridge->irq[level - 1].callback[statid].func) {
Emilio G. Cota886953e2010-11-12 11:14:07 +00001019 mutex_unlock(&bridge->irq_mtx);
Martyn Welchc813f592009-10-29 16:34:54 +00001020 printk(KERN_WARNING "VME Interrupt already taken\n");
1021 return -EBUSY;
1022 }
1023
1024 bridge->irq[level - 1].count++;
1025 bridge->irq[level - 1].callback[statid].priv_data = priv_data;
1026 bridge->irq[level - 1].callback[statid].func = callback;
1027
1028 /* Enable IRQ level */
Martyn Welch29848ac2010-02-18 15:13:05 +00001029 bridge->irq_set(bridge, level, 1, 1);
Martyn Welchc813f592009-10-29 16:34:54 +00001030
Emilio G. Cota886953e2010-11-12 11:14:07 +00001031 mutex_unlock(&bridge->irq_mtx);
Martyn Welchc813f592009-10-29 16:34:54 +00001032
1033 return 0;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001034}
Martyn Welchc813f592009-10-29 16:34:54 +00001035EXPORT_SYMBOL(vme_irq_request);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001036
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001037void vme_irq_free(struct vme_dev *vdev, int level, int statid)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001038{
1039 struct vme_bridge *bridge;
1040
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001041 bridge = vdev->bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001042 if (bridge == NULL) {
1043 printk(KERN_ERR "Can't find VME bus\n");
1044 return;
1045 }
1046
Martyn Welchead1f3e2009-12-15 08:43:02 +00001047 if ((level < 1) || (level > 7)) {
Martyn Welchc813f592009-10-29 16:34:54 +00001048 printk(KERN_ERR "Invalid interrupt level\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001049 return;
1050 }
1051
Martyn Welchc813f592009-10-29 16:34:54 +00001052 if (bridge->irq_set == NULL) {
1053 printk(KERN_ERR "Configuring interrupts not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001054 return;
1055 }
1056
Emilio G. Cota886953e2010-11-12 11:14:07 +00001057 mutex_lock(&bridge->irq_mtx);
Martyn Welchc813f592009-10-29 16:34:54 +00001058
1059 bridge->irq[level - 1].count--;
1060
1061 /* Disable IRQ level if no more interrupts attached at this level*/
1062 if (bridge->irq[level - 1].count == 0)
Martyn Welch29848ac2010-02-18 15:13:05 +00001063 bridge->irq_set(bridge, level, 0, 1);
Martyn Welchc813f592009-10-29 16:34:54 +00001064
1065 bridge->irq[level - 1].callback[statid].func = NULL;
1066 bridge->irq[level - 1].callback[statid].priv_data = NULL;
1067
Emilio G. Cota886953e2010-11-12 11:14:07 +00001068 mutex_unlock(&bridge->irq_mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001069}
Martyn Welchc813f592009-10-29 16:34:54 +00001070EXPORT_SYMBOL(vme_irq_free);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001071
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001072int vme_irq_generate(struct vme_dev *vdev, int level, int statid)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001073{
1074 struct vme_bridge *bridge;
1075
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001076 bridge = vdev->bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001077 if (bridge == NULL) {
1078 printk(KERN_ERR "Can't find VME bus\n");
1079 return -EINVAL;
1080 }
1081
Martyn Welchead1f3e2009-12-15 08:43:02 +00001082 if ((level < 1) || (level > 7)) {
Martyn Welcha17a75e2009-07-31 09:28:17 +01001083 printk(KERN_WARNING "Invalid interrupt level\n");
1084 return -EINVAL;
1085 }
1086
Martyn Welchc813f592009-10-29 16:34:54 +00001087 if (bridge->irq_generate == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +00001088 printk(KERN_WARNING "Interrupt generation not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001089 return -EINVAL;
1090 }
1091
Martyn Welch29848ac2010-02-18 15:13:05 +00001092 return bridge->irq_generate(bridge, level, statid);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001093}
Martyn Welchc813f592009-10-29 16:34:54 +00001094EXPORT_SYMBOL(vme_irq_generate);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001095
Martyn Welch42fb5032009-08-11 17:44:56 +01001096/*
1097 * Request the location monitor, return resource or NULL
1098 */
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001099struct vme_resource *vme_lm_request(struct vme_dev *vdev)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001100{
1101 struct vme_bridge *bridge;
Martyn Welch42fb5032009-08-11 17:44:56 +01001102 struct list_head *lm_pos = NULL;
1103 struct vme_lm_resource *allocated_lm = NULL;
1104 struct vme_lm_resource *lm = NULL;
1105 struct vme_resource *resource = NULL;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001106
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001107 bridge = vdev->bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001108 if (bridge == NULL) {
1109 printk(KERN_ERR "Can't find VME bus\n");
Martyn Welch42fb5032009-08-11 17:44:56 +01001110 goto err_bus;
1111 }
1112
1113 /* Loop through DMA resources */
Emilio G. Cota886953e2010-11-12 11:14:07 +00001114 list_for_each(lm_pos, &bridge->lm_resources) {
Martyn Welch42fb5032009-08-11 17:44:56 +01001115 lm = list_entry(lm_pos,
1116 struct vme_lm_resource, list);
1117
1118 if (lm == NULL) {
1119 printk(KERN_ERR "Registered NULL Location Monitor "
1120 "resource\n");
1121 continue;
1122 }
1123
1124 /* Find an unlocked controller */
Emilio G. Cota886953e2010-11-12 11:14:07 +00001125 mutex_lock(&lm->mtx);
Martyn Welch42fb5032009-08-11 17:44:56 +01001126 if (lm->locked == 0) {
1127 lm->locked = 1;
Emilio G. Cota886953e2010-11-12 11:14:07 +00001128 mutex_unlock(&lm->mtx);
Martyn Welch42fb5032009-08-11 17:44:56 +01001129 allocated_lm = lm;
1130 break;
1131 }
Emilio G. Cota886953e2010-11-12 11:14:07 +00001132 mutex_unlock(&lm->mtx);
Martyn Welch42fb5032009-08-11 17:44:56 +01001133 }
1134
1135 /* Check to see if we found a resource */
1136 if (allocated_lm == NULL)
1137 goto err_lm;
1138
1139 resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
1140 if (resource == NULL) {
1141 printk(KERN_ERR "Unable to allocate resource structure\n");
1142 goto err_alloc;
1143 }
1144 resource->type = VME_LM;
Emilio G. Cota886953e2010-11-12 11:14:07 +00001145 resource->entry = &allocated_lm->list;
Martyn Welch42fb5032009-08-11 17:44:56 +01001146
1147 return resource;
1148
1149err_alloc:
1150 /* Unlock image */
Emilio G. Cota886953e2010-11-12 11:14:07 +00001151 mutex_lock(&lm->mtx);
Martyn Welch42fb5032009-08-11 17:44:56 +01001152 lm->locked = 0;
Emilio G. Cota886953e2010-11-12 11:14:07 +00001153 mutex_unlock(&lm->mtx);
Martyn Welch42fb5032009-08-11 17:44:56 +01001154err_lm:
1155err_bus:
1156 return NULL;
1157}
1158EXPORT_SYMBOL(vme_lm_request);
1159
1160int vme_lm_count(struct vme_resource *resource)
1161{
1162 struct vme_lm_resource *lm;
1163
1164 if (resource->type != VME_LM) {
1165 printk(KERN_ERR "Not a Location Monitor resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001166 return -EINVAL;
1167 }
1168
Martyn Welch42fb5032009-08-11 17:44:56 +01001169 lm = list_entry(resource->entry, struct vme_lm_resource, list);
1170
1171 return lm->monitors;
1172}
1173EXPORT_SYMBOL(vme_lm_count);
1174
1175int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base,
1176 vme_address_t aspace, vme_cycle_t cycle)
1177{
1178 struct vme_bridge *bridge = find_bridge(resource);
1179 struct vme_lm_resource *lm;
1180
1181 if (resource->type != VME_LM) {
1182 printk(KERN_ERR "Not a Location Monitor resource\n");
1183 return -EINVAL;
1184 }
1185
1186 lm = list_entry(resource->entry, struct vme_lm_resource, list);
1187
Martyn Welcha17a75e2009-07-31 09:28:17 +01001188 if (bridge->lm_set == NULL) {
Martyn Welch42fb5032009-08-11 17:44:56 +01001189 printk(KERN_ERR "vme_lm_set not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001190 return -EINVAL;
1191 }
1192
Martyn Welch8be92262009-10-29 16:35:08 +00001193 return bridge->lm_set(lm, lm_base, aspace, cycle);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001194}
1195EXPORT_SYMBOL(vme_lm_set);
1196
Martyn Welch42fb5032009-08-11 17:44:56 +01001197int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base,
1198 vme_address_t *aspace, vme_cycle_t *cycle)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001199{
Martyn Welch42fb5032009-08-11 17:44:56 +01001200 struct vme_bridge *bridge = find_bridge(resource);
1201 struct vme_lm_resource *lm;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001202
Martyn Welch42fb5032009-08-11 17:44:56 +01001203 if (resource->type != VME_LM) {
1204 printk(KERN_ERR "Not a Location Monitor resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001205 return -EINVAL;
1206 }
1207
Martyn Welch42fb5032009-08-11 17:44:56 +01001208 lm = list_entry(resource->entry, struct vme_lm_resource, list);
1209
Martyn Welcha17a75e2009-07-31 09:28:17 +01001210 if (bridge->lm_get == NULL) {
Martyn Welch42fb5032009-08-11 17:44:56 +01001211 printk(KERN_ERR "vme_lm_get not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001212 return -EINVAL;
1213 }
1214
Martyn Welch42fb5032009-08-11 17:44:56 +01001215 return bridge->lm_get(lm, lm_base, aspace, cycle);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001216}
1217EXPORT_SYMBOL(vme_lm_get);
1218
Martyn Welch42fb5032009-08-11 17:44:56 +01001219int vme_lm_attach(struct vme_resource *resource, int monitor,
1220 void (*callback)(int))
Martyn Welcha17a75e2009-07-31 09:28:17 +01001221{
Martyn Welch42fb5032009-08-11 17:44:56 +01001222 struct vme_bridge *bridge = find_bridge(resource);
1223 struct vme_lm_resource *lm;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001224
Martyn Welch42fb5032009-08-11 17:44:56 +01001225 if (resource->type != VME_LM) {
1226 printk(KERN_ERR "Not a Location Monitor resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001227 return -EINVAL;
1228 }
1229
Martyn Welch42fb5032009-08-11 17:44:56 +01001230 lm = list_entry(resource->entry, struct vme_lm_resource, list);
1231
Martyn Welcha17a75e2009-07-31 09:28:17 +01001232 if (bridge->lm_attach == NULL) {
Martyn Welch42fb5032009-08-11 17:44:56 +01001233 printk(KERN_ERR "vme_lm_attach not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001234 return -EINVAL;
1235 }
1236
Martyn Welch42fb5032009-08-11 17:44:56 +01001237 return bridge->lm_attach(lm, monitor, callback);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001238}
1239EXPORT_SYMBOL(vme_lm_attach);
1240
Martyn Welch42fb5032009-08-11 17:44:56 +01001241int vme_lm_detach(struct vme_resource *resource, int monitor)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001242{
Martyn Welch42fb5032009-08-11 17:44:56 +01001243 struct vme_bridge *bridge = find_bridge(resource);
1244 struct vme_lm_resource *lm;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001245
Martyn Welch42fb5032009-08-11 17:44:56 +01001246 if (resource->type != VME_LM) {
1247 printk(KERN_ERR "Not a Location Monitor resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001248 return -EINVAL;
1249 }
1250
Martyn Welch42fb5032009-08-11 17:44:56 +01001251 lm = list_entry(resource->entry, struct vme_lm_resource, list);
1252
Martyn Welcha17a75e2009-07-31 09:28:17 +01001253 if (bridge->lm_detach == NULL) {
Martyn Welch42fb5032009-08-11 17:44:56 +01001254 printk(KERN_ERR "vme_lm_detach not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001255 return -EINVAL;
1256 }
1257
Martyn Welch42fb5032009-08-11 17:44:56 +01001258 return bridge->lm_detach(lm, monitor);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001259}
1260EXPORT_SYMBOL(vme_lm_detach);
1261
Martyn Welch42fb5032009-08-11 17:44:56 +01001262void vme_lm_free(struct vme_resource *resource)
1263{
1264 struct vme_lm_resource *lm;
1265
1266 if (resource->type != VME_LM) {
1267 printk(KERN_ERR "Not a Location Monitor resource\n");
1268 return;
1269 }
1270
1271 lm = list_entry(resource->entry, struct vme_lm_resource, list);
1272
Emilio G. Cota886953e2010-11-12 11:14:07 +00001273 mutex_lock(&lm->mtx);
Martyn Welch42fb5032009-08-11 17:44:56 +01001274
Martyn Welch8be92262009-10-29 16:35:08 +00001275 /* XXX
1276 * Check to see that there aren't any callbacks still attached, if
1277 * there are we should probably be detaching them!
1278 */
Martyn Welch42fb5032009-08-11 17:44:56 +01001279
1280 lm->locked = 0;
1281
Emilio G. Cota886953e2010-11-12 11:14:07 +00001282 mutex_unlock(&lm->mtx);
Martyn Welch8be92262009-10-29 16:35:08 +00001283
1284 kfree(resource);
Martyn Welch42fb5032009-08-11 17:44:56 +01001285}
1286EXPORT_SYMBOL(vme_lm_free);
1287
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001288int vme_slot_get(struct vme_dev *vdev)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001289{
1290 struct vme_bridge *bridge;
1291
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001292 bridge = vdev->bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001293 if (bridge == NULL) {
1294 printk(KERN_ERR "Can't find VME bus\n");
1295 return -EINVAL;
1296 }
1297
1298 if (bridge->slot_get == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +00001299 printk(KERN_WARNING "vme_slot_get not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001300 return -EINVAL;
1301 }
1302
Martyn Welch29848ac2010-02-18 15:13:05 +00001303 return bridge->slot_get(bridge);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001304}
1305EXPORT_SYMBOL(vme_slot_get);
1306
1307
1308/* - Bridge Registration --------------------------------------------------- */
1309
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001310static int vme_add_bus(struct vme_bridge *bridge)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001311{
1312 int i;
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001313 int ret = -1;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001314
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001315 mutex_lock(&vme_buses_lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001316 for (i = 0; i < sizeof(vme_bus_numbers) * 8; i++) {
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001317 if ((vme_bus_numbers & (1 << i)) == 0) {
1318 vme_bus_numbers |= (1 << i);
1319 bridge->num = i;
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001320 INIT_LIST_HEAD(&bridge->devices);
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001321 list_add_tail(&bridge->bus_list, &vme_bus_list);
1322 ret = 0;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001323 break;
1324 }
1325 }
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001326 mutex_unlock(&vme_buses_lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001327
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001328 return ret;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001329}
1330
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001331static void vme_remove_bus(struct vme_bridge *bridge)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001332{
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001333 struct vme_dev *vdev;
1334 struct vme_dev *tmp;
1335
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001336 mutex_lock(&vme_buses_lock);
1337 vme_bus_numbers &= ~(1 << bridge->num);
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001338 list_for_each_entry_safe(vdev, tmp, &bridge->devices, bridge_list) {
1339 list_del(&vdev->drv_list);
1340 list_del(&vdev->bridge_list);
1341 device_unregister(&vdev->dev);
1342 }
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001343 list_del(&bridge->bus_list);
1344 mutex_unlock(&vme_buses_lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001345}
1346
Manohar Vangaf6c39d42011-09-01 11:15:24 +02001347static void vme_dev_release(struct device *dev)
1348{
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001349 kfree(dev_to_vme_dev(dev));
Manohar Vangaf6c39d42011-09-01 11:15:24 +02001350}
1351
Martyn Welchead1f3e2009-12-15 08:43:02 +00001352int vme_register_bridge(struct vme_bridge *bridge)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001353{
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001354 return vme_add_bus(bridge);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001355}
1356EXPORT_SYMBOL(vme_register_bridge);
1357
Martyn Welchead1f3e2009-12-15 08:43:02 +00001358void vme_unregister_bridge(struct vme_bridge *bridge)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001359{
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001360 vme_remove_bus(bridge);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001361}
1362EXPORT_SYMBOL(vme_unregister_bridge);
1363
Martyn Welcha17a75e2009-07-31 09:28:17 +01001364/* - Driver Registration --------------------------------------------------- */
1365
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001366static int __vme_register_driver_bus(struct vme_driver *drv,
1367 struct vme_bridge *bridge, unsigned int ndevs)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001368{
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001369 int err;
1370 unsigned int i;
1371 struct vme_dev *vdev;
1372 struct vme_dev *tmp;
1373
1374 for (i = 0; i < ndevs; i++) {
1375 vdev = kzalloc(sizeof(struct vme_dev), GFP_KERNEL);
1376 if (!vdev) {
1377 err = -ENOMEM;
1378 goto err_devalloc;
1379 }
Manohar Vangaa916a392011-09-26 11:27:17 +02001380 vdev->num = i;
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001381 vdev->bridge = bridge;
1382 vdev->dev.platform_data = drv;
1383 vdev->dev.release = vme_dev_release;
1384 vdev->dev.parent = bridge->parent;
1385 vdev->dev.bus = &vme_bus_type;
Manohar Vangaa916a392011-09-26 11:27:17 +02001386 dev_set_name(&vdev->dev, "%s.%u-%u", drv->name, bridge->num,
1387 vdev->num);
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001388
1389 err = device_register(&vdev->dev);
1390 if (err)
1391 goto err_reg;
1392
1393 if (vdev->dev.platform_data) {
1394 list_add_tail(&vdev->drv_list, &drv->devices);
1395 list_add_tail(&vdev->bridge_list, &bridge->devices);
1396 } else
1397 device_unregister(&vdev->dev);
1398 }
1399 return 0;
1400
1401err_reg:
1402 kfree(vdev);
1403err_devalloc:
1404 list_for_each_entry_safe(vdev, tmp, &drv->devices, drv_list) {
1405 list_del(&vdev->drv_list);
1406 list_del(&vdev->bridge_list);
1407 device_unregister(&vdev->dev);
1408 }
1409 return err;
1410}
1411
1412static int __vme_register_driver(struct vme_driver *drv, unsigned int ndevs)
1413{
1414 struct vme_bridge *bridge;
1415 int err = 0;
1416
1417 mutex_lock(&vme_buses_lock);
1418 list_for_each_entry(bridge, &vme_bus_list, bus_list) {
1419 /*
1420 * This cannot cause trouble as we already have vme_buses_lock
1421 * and if the bridge is removed, it will have to go through
1422 * vme_unregister_bridge() to do it (which calls remove() on
1423 * the bridge which in turn tries to acquire vme_buses_lock and
Manohar Vangac26f6112011-11-04 11:12:29 +01001424 * will have to wait).
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001425 */
1426 err = __vme_register_driver_bus(drv, bridge, ndevs);
1427 if (err)
1428 break;
1429 }
1430 mutex_unlock(&vme_buses_lock);
1431 return err;
1432}
1433
1434int vme_register_driver(struct vme_driver *drv, unsigned int ndevs)
1435{
1436 int err;
1437
Martyn Welcha17a75e2009-07-31 09:28:17 +01001438 drv->driver.name = drv->name;
1439 drv->driver.bus = &vme_bus_type;
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001440 INIT_LIST_HEAD(&drv->devices);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001441
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001442 err = driver_register(&drv->driver);
1443 if (err)
1444 return err;
1445
1446 err = __vme_register_driver(drv, ndevs);
1447 if (err)
1448 driver_unregister(&drv->driver);
1449
1450 return err;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001451}
1452EXPORT_SYMBOL(vme_register_driver);
1453
Martyn Welchead1f3e2009-12-15 08:43:02 +00001454void vme_unregister_driver(struct vme_driver *drv)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001455{
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001456 struct vme_dev *dev, *dev_tmp;
1457
1458 mutex_lock(&vme_buses_lock);
1459 list_for_each_entry_safe(dev, dev_tmp, &drv->devices, drv_list) {
1460 list_del(&dev->drv_list);
1461 list_del(&dev->bridge_list);
1462 device_unregister(&dev->dev);
1463 }
1464 mutex_unlock(&vme_buses_lock);
1465
Martyn Welcha17a75e2009-07-31 09:28:17 +01001466 driver_unregister(&drv->driver);
1467}
1468EXPORT_SYMBOL(vme_unregister_driver);
1469
1470/* - Bus Registration ------------------------------------------------------ */
1471
Martyn Welcha17a75e2009-07-31 09:28:17 +01001472static int vme_bus_match(struct device *dev, struct device_driver *drv)
1473{
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001474 struct vme_driver *vme_drv;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001475
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001476 vme_drv = container_of(drv, struct vme_driver, driver);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001477
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001478 if (dev->platform_data == vme_drv) {
1479 struct vme_dev *vdev = dev_to_vme_dev(dev);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001480
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001481 if (vme_drv->match && vme_drv->match(vdev))
1482 return 1;
1483
1484 dev->platform_data = NULL;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001485 }
Martyn Welcha17a75e2009-07-31 09:28:17 +01001486 return 0;
1487}
1488
1489static int vme_bus_probe(struct device *dev)
1490{
Martyn Welcha17a75e2009-07-31 09:28:17 +01001491 int retval = -ENODEV;
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001492 struct vme_driver *driver;
1493 struct vme_dev *vdev = dev_to_vme_dev(dev);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001494
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001495 driver = dev->platform_data;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001496
Martyn Welchead1f3e2009-12-15 08:43:02 +00001497 if (driver->probe != NULL)
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001498 retval = driver->probe(vdev);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001499
1500 return retval;
1501}
1502
1503static int vme_bus_remove(struct device *dev)
1504{
Martyn Welcha17a75e2009-07-31 09:28:17 +01001505 int retval = -ENODEV;
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001506 struct vme_driver *driver;
1507 struct vme_dev *vdev = dev_to_vme_dev(dev);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001508
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001509 driver = dev->platform_data;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001510
Martyn Welchead1f3e2009-12-15 08:43:02 +00001511 if (driver->remove != NULL)
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001512 retval = driver->remove(vdev);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001513
1514 return retval;
1515}
1516
1517struct bus_type vme_bus_type = {
1518 .name = "vme",
1519 .match = vme_bus_match,
1520 .probe = vme_bus_probe,
1521 .remove = vme_bus_remove,
1522};
1523EXPORT_SYMBOL(vme_bus_type);
1524
Martyn Welchead1f3e2009-12-15 08:43:02 +00001525static int __init vme_init(void)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001526{
1527 return bus_register(&vme_bus_type);
1528}
1529
Martyn Welchead1f3e2009-12-15 08:43:02 +00001530static void __exit vme_exit(void)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001531{
1532 bus_unregister(&vme_bus_type);
1533}
1534
1535MODULE_DESCRIPTION("VME bridge driver framework");
Martyn Welch66bd8db2010-02-18 15:12:52 +00001536MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001537MODULE_LICENSE("GPL");
1538
1539module_init(vme_init);
1540module_exit(vme_exit);