blob: 15b64076bc26257abffd02a60de7b2fe4b22c4e0 [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
Paul Gortmaker050c3d52016-07-03 14:05:56 -040016#include <linux/init.h>
17#include <linux/export.h>
Martyn Welcha17a75e2009-07-31 09:28:17 +010018#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>
Greg Kroah-Hartmandb3b9e92012-04-26 12:34:58 -070033#include <linux/vme.h>
Martyn Welcha17a75e2009-07-31 09:28:17 +010034
Martyn Welcha17a75e2009-07-31 09:28:17 +010035#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 int __init vme_init(void);
Martyn Welcha17a75e2009-07-31 09:28:17 +010043
Manohar Vanga8f966dc2011-09-26 11:27:15 +020044static struct vme_dev *dev_to_vme_dev(struct device *dev)
Martyn Welcha17a75e2009-07-31 09:28:17 +010045{
Manohar Vanga8f966dc2011-09-26 11:27:15 +020046 return container_of(dev, struct vme_dev, dev);
Martyn Welcha17a75e2009-07-31 09:28:17 +010047}
48
49/*
50 * Find the bridge that the resource is associated with.
51 */
52static struct vme_bridge *find_bridge(struct vme_resource *resource)
53{
54 /* Get list to search */
55 switch (resource->type) {
56 case VME_MASTER:
57 return list_entry(resource->entry, struct vme_master_resource,
58 list)->parent;
59 break;
60 case VME_SLAVE:
61 return list_entry(resource->entry, struct vme_slave_resource,
62 list)->parent;
63 break;
64 case VME_DMA:
65 return list_entry(resource->entry, struct vme_dma_resource,
66 list)->parent;
67 break;
Martyn Welch42fb5032009-08-11 17:44:56 +010068 case VME_LM:
69 return list_entry(resource->entry, struct vme_lm_resource,
70 list)->parent;
71 break;
Martyn Welcha17a75e2009-07-31 09:28:17 +010072 default:
73 printk(KERN_ERR "Unknown resource type\n");
74 return NULL;
75 break;
76 }
77}
78
79/*
80 * Allocate a contiguous block of memory for use by the driver. This is used to
81 * create the buffers for the slave windows.
Martyn Welcha17a75e2009-07-31 09:28:17 +010082 */
Martyn Welchead1f3e2009-12-15 08:43:02 +000083void *vme_alloc_consistent(struct vme_resource *resource, size_t size,
Martyn Welcha17a75e2009-07-31 09:28:17 +010084 dma_addr_t *dma)
85{
86 struct vme_bridge *bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +010087
Martyn Welchead1f3e2009-12-15 08:43:02 +000088 if (resource == NULL) {
89 printk(KERN_ERR "No resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +010090 return NULL;
91 }
92
93 bridge = find_bridge(resource);
Martyn Welchead1f3e2009-12-15 08:43:02 +000094 if (bridge == NULL) {
95 printk(KERN_ERR "Can't find bridge\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +010096 return NULL;
97 }
98
Martyn Welcha17a75e2009-07-31 09:28:17 +010099 if (bridge->parent == NULL) {
Greg Kroah-Hartman25958ce2012-04-25 11:25:46 -0700100 printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100101 return NULL;
102 }
Martyn Welcha17a75e2009-07-31 09:28:17 +0100103
Manohar Vanga7f58f022011-08-10 11:33:46 +0200104 if (bridge->alloc_consistent == NULL) {
Greg Kroah-Hartman25958ce2012-04-25 11:25:46 -0700105 printk(KERN_ERR "alloc_consistent not supported by bridge %s\n",
106 bridge->name);
Manohar Vanga7f58f022011-08-10 11:33:46 +0200107 return NULL;
108 }
109
110 return bridge->alloc_consistent(bridge->parent, size, dma);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100111}
112EXPORT_SYMBOL(vme_alloc_consistent);
113
114/*
115 * Free previously allocated contiguous block of memory.
Martyn Welcha17a75e2009-07-31 09:28:17 +0100116 */
117void vme_free_consistent(struct vme_resource *resource, size_t size,
118 void *vaddr, dma_addr_t dma)
119{
120 struct vme_bridge *bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +0100121
Martyn Welchead1f3e2009-12-15 08:43:02 +0000122 if (resource == NULL) {
123 printk(KERN_ERR "No resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100124 return;
125 }
126
127 bridge = find_bridge(resource);
Martyn Welchead1f3e2009-12-15 08:43:02 +0000128 if (bridge == NULL) {
129 printk(KERN_ERR "Can't find bridge\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100130 return;
131 }
132
Manohar Vanga7f58f022011-08-10 11:33:46 +0200133 if (bridge->parent == NULL) {
Greg Kroah-Hartman25958ce2012-04-25 11:25:46 -0700134 printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name);
Manohar Vanga7f58f022011-08-10 11:33:46 +0200135 return;
136 }
Martyn Welcha17a75e2009-07-31 09:28:17 +0100137
Manohar Vanga7f58f022011-08-10 11:33:46 +0200138 if (bridge->free_consistent == NULL) {
Greg Kroah-Hartman25958ce2012-04-25 11:25:46 -0700139 printk(KERN_ERR "free_consistent not supported by bridge %s\n",
140 bridge->name);
Manohar Vanga7f58f022011-08-10 11:33:46 +0200141 return;
142 }
143
144 bridge->free_consistent(bridge->parent, size, vaddr, dma);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100145}
146EXPORT_SYMBOL(vme_free_consistent);
147
148size_t vme_get_size(struct vme_resource *resource)
149{
150 int enabled, retval;
151 unsigned long long base, size;
152 dma_addr_t buf_base;
Martyn Welch6af04b02011-12-01 17:06:29 +0000153 u32 aspace, cycle, dwidth;
Martyn Welcha17a75e2009-07-31 09:28:17 +0100154
155 switch (resource->type) {
156 case VME_MASTER:
157 retval = vme_master_get(resource, &enabled, &base, &size,
158 &aspace, &cycle, &dwidth);
159
160 return size;
161 break;
162 case VME_SLAVE:
163 retval = vme_slave_get(resource, &enabled, &base, &size,
164 &buf_base, &aspace, &cycle);
165
166 return size;
167 break;
168 case VME_DMA:
169 return 0;
170 break;
171 default:
172 printk(KERN_ERR "Unknown resource type\n");
173 return 0;
174 break;
175 }
176}
177EXPORT_SYMBOL(vme_get_size);
178
Dmitry Kalinkinef73f882015-05-28 15:07:04 +0300179int vme_check_window(u32 aspace, unsigned long long vme_base,
180 unsigned long long size)
Martyn Welcha17a75e2009-07-31 09:28:17 +0100181{
182 int retval = 0;
183
184 switch (aspace) {
185 case VME_A16:
186 if (((vme_base + size) > VME_A16_MAX) ||
187 (vme_base > VME_A16_MAX))
188 retval = -EFAULT;
189 break;
190 case VME_A24:
191 if (((vme_base + size) > VME_A24_MAX) ||
192 (vme_base > VME_A24_MAX))
193 retval = -EFAULT;
194 break;
195 case VME_A32:
196 if (((vme_base + size) > VME_A32_MAX) ||
197 (vme_base > VME_A32_MAX))
198 retval = -EFAULT;
199 break;
200 case VME_A64:
Dmitry Kalinkine7fd80c2015-05-28 15:07:03 +0300201 if ((size != 0) && (vme_base > U64_MAX + 1 - size))
202 retval = -EFAULT;
Martyn Welcha17a75e2009-07-31 09:28:17 +0100203 break;
204 case VME_CRCSR:
205 if (((vme_base + size) > VME_CRCSR_MAX) ||
206 (vme_base > VME_CRCSR_MAX))
207 retval = -EFAULT;
208 break;
209 case VME_USER1:
210 case VME_USER2:
211 case VME_USER3:
212 case VME_USER4:
213 /* User Defined */
214 break;
215 default:
Martyn Welchead1f3e2009-12-15 08:43:02 +0000216 printk(KERN_ERR "Invalid address space\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100217 retval = -EINVAL;
218 break;
219 }
220
221 return retval;
222}
Dmitry Kalinkinef73f882015-05-28 15:07:04 +0300223EXPORT_SYMBOL(vme_check_window);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100224
Dmitry Kalinkin472f16f2015-09-18 02:01:43 +0300225static u32 vme_get_aspace(int am)
226{
227 switch (am) {
228 case 0x29:
229 case 0x2D:
230 return VME_A16;
231 case 0x38:
232 case 0x39:
233 case 0x3A:
234 case 0x3B:
235 case 0x3C:
236 case 0x3D:
237 case 0x3E:
238 case 0x3F:
239 return VME_A24;
240 case 0x8:
241 case 0x9:
242 case 0xA:
243 case 0xB:
244 case 0xC:
245 case 0xD:
246 case 0xE:
247 case 0xF:
248 return VME_A32;
249 case 0x0:
250 case 0x1:
251 case 0x3:
252 return VME_A64;
253 }
254
255 return 0;
256}
257
Martyn Welcha17a75e2009-07-31 09:28:17 +0100258/*
259 * Request a slave image with specific attributes, return some unique
260 * identifier.
261 */
Martyn Welch6af04b02011-12-01 17:06:29 +0000262struct vme_resource *vme_slave_request(struct vme_dev *vdev, u32 address,
263 u32 cycle)
Martyn Welcha17a75e2009-07-31 09:28:17 +0100264{
265 struct vme_bridge *bridge;
266 struct list_head *slave_pos = NULL;
267 struct vme_slave_resource *allocated_image = NULL;
268 struct vme_slave_resource *slave_image = NULL;
269 struct vme_resource *resource = NULL;
270
Manohar Vanga8f966dc2011-09-26 11:27:15 +0200271 bridge = vdev->bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +0100272 if (bridge == NULL) {
273 printk(KERN_ERR "Can't find VME bus\n");
274 goto err_bus;
275 }
276
277 /* Loop through slave resources */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000278 list_for_each(slave_pos, &bridge->slave_resources) {
Martyn Welcha17a75e2009-07-31 09:28:17 +0100279 slave_image = list_entry(slave_pos,
280 struct vme_slave_resource, list);
281
282 if (slave_image == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000283 printk(KERN_ERR "Registered NULL Slave resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100284 continue;
285 }
286
287 /* Find an unlocked and compatible image */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000288 mutex_lock(&slave_image->mtx);
Martyn Welchead1f3e2009-12-15 08:43:02 +0000289 if (((slave_image->address_attr & address) == address) &&
Martyn Welcha17a75e2009-07-31 09:28:17 +0100290 ((slave_image->cycle_attr & cycle) == cycle) &&
291 (slave_image->locked == 0)) {
292
293 slave_image->locked = 1;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000294 mutex_unlock(&slave_image->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100295 allocated_image = slave_image;
296 break;
297 }
Emilio G. Cota886953e2010-11-12 11:14:07 +0000298 mutex_unlock(&slave_image->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100299 }
300
301 /* No free image */
302 if (allocated_image == NULL)
303 goto err_image;
304
305 resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
306 if (resource == NULL) {
307 printk(KERN_WARNING "Unable to allocate resource structure\n");
308 goto err_alloc;
309 }
310 resource->type = VME_SLAVE;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000311 resource->entry = &allocated_image->list;
Martyn Welcha17a75e2009-07-31 09:28:17 +0100312
313 return resource;
314
315err_alloc:
316 /* Unlock image */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000317 mutex_lock(&slave_image->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100318 slave_image->locked = 0;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000319 mutex_unlock(&slave_image->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100320err_image:
321err_bus:
322 return NULL;
323}
324EXPORT_SYMBOL(vme_slave_request);
325
Martyn Welchead1f3e2009-12-15 08:43:02 +0000326int vme_slave_set(struct vme_resource *resource, int enabled,
Martyn Welcha17a75e2009-07-31 09:28:17 +0100327 unsigned long long vme_base, unsigned long long size,
Martyn Welch6af04b02011-12-01 17:06:29 +0000328 dma_addr_t buf_base, u32 aspace, u32 cycle)
Martyn Welcha17a75e2009-07-31 09:28:17 +0100329{
330 struct vme_bridge *bridge = find_bridge(resource);
331 struct vme_slave_resource *image;
332 int retval;
333
334 if (resource->type != VME_SLAVE) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000335 printk(KERN_ERR "Not a slave resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100336 return -EINVAL;
337 }
338
339 image = list_entry(resource->entry, struct vme_slave_resource, list);
340
341 if (bridge->slave_set == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000342 printk(KERN_ERR "Function not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100343 return -ENOSYS;
344 }
345
Martyn Welchead1f3e2009-12-15 08:43:02 +0000346 if (!(((image->address_attr & aspace) == aspace) &&
Martyn Welcha17a75e2009-07-31 09:28:17 +0100347 ((image->cycle_attr & cycle) == cycle))) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000348 printk(KERN_ERR "Invalid attributes\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100349 return -EINVAL;
350 }
351
352 retval = vme_check_window(aspace, vme_base, size);
Martyn Welchead1f3e2009-12-15 08:43:02 +0000353 if (retval)
Martyn Welcha17a75e2009-07-31 09:28:17 +0100354 return retval;
355
356 return bridge->slave_set(image, enabled, vme_base, size, buf_base,
357 aspace, cycle);
358}
359EXPORT_SYMBOL(vme_slave_set);
360
Martyn Welchead1f3e2009-12-15 08:43:02 +0000361int vme_slave_get(struct vme_resource *resource, int *enabled,
Martyn Welcha17a75e2009-07-31 09:28:17 +0100362 unsigned long long *vme_base, unsigned long long *size,
Martyn Welch6af04b02011-12-01 17:06:29 +0000363 dma_addr_t *buf_base, u32 *aspace, u32 *cycle)
Martyn Welcha17a75e2009-07-31 09:28:17 +0100364{
365 struct vme_bridge *bridge = find_bridge(resource);
366 struct vme_slave_resource *image;
367
368 if (resource->type != VME_SLAVE) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000369 printk(KERN_ERR "Not a slave resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100370 return -EINVAL;
371 }
372
373 image = list_entry(resource->entry, struct vme_slave_resource, list);
374
Emilio G. Cota51a569f2009-08-10 16:52:42 +0200375 if (bridge->slave_get == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000376 printk(KERN_ERR "vme_slave_get not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100377 return -EINVAL;
378 }
379
380 return bridge->slave_get(image, enabled, vme_base, size, buf_base,
381 aspace, cycle);
382}
383EXPORT_SYMBOL(vme_slave_get);
384
385void vme_slave_free(struct vme_resource *resource)
386{
387 struct vme_slave_resource *slave_image;
388
389 if (resource->type != VME_SLAVE) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000390 printk(KERN_ERR "Not a slave resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100391 return;
392 }
393
394 slave_image = list_entry(resource->entry, struct vme_slave_resource,
395 list);
396 if (slave_image == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000397 printk(KERN_ERR "Can't find slave resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100398 return;
399 }
400
401 /* Unlock image */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000402 mutex_lock(&slave_image->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100403 if (slave_image->locked == 0)
404 printk(KERN_ERR "Image is already free\n");
405
406 slave_image->locked = 0;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000407 mutex_unlock(&slave_image->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100408
409 /* Free up resource memory */
410 kfree(resource);
411}
412EXPORT_SYMBOL(vme_slave_free);
413
414/*
415 * Request a master image with specific attributes, return some unique
416 * identifier.
417 */
Martyn Welch6af04b02011-12-01 17:06:29 +0000418struct vme_resource *vme_master_request(struct vme_dev *vdev, u32 address,
419 u32 cycle, u32 dwidth)
Martyn Welcha17a75e2009-07-31 09:28:17 +0100420{
421 struct vme_bridge *bridge;
422 struct list_head *master_pos = NULL;
423 struct vme_master_resource *allocated_image = NULL;
424 struct vme_master_resource *master_image = NULL;
425 struct vme_resource *resource = NULL;
426
Manohar Vanga8f966dc2011-09-26 11:27:15 +0200427 bridge = vdev->bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +0100428 if (bridge == NULL) {
429 printk(KERN_ERR "Can't find VME bus\n");
430 goto err_bus;
431 }
432
433 /* Loop through master resources */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000434 list_for_each(master_pos, &bridge->master_resources) {
Martyn Welcha17a75e2009-07-31 09:28:17 +0100435 master_image = list_entry(master_pos,
436 struct vme_master_resource, list);
437
438 if (master_image == NULL) {
439 printk(KERN_WARNING "Registered NULL master resource\n");
440 continue;
441 }
442
443 /* Find an unlocked and compatible image */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000444 spin_lock(&master_image->lock);
Martyn Welchead1f3e2009-12-15 08:43:02 +0000445 if (((master_image->address_attr & address) == address) &&
Martyn Welcha17a75e2009-07-31 09:28:17 +0100446 ((master_image->cycle_attr & cycle) == cycle) &&
447 ((master_image->width_attr & dwidth) == dwidth) &&
448 (master_image->locked == 0)) {
449
450 master_image->locked = 1;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000451 spin_unlock(&master_image->lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100452 allocated_image = master_image;
453 break;
454 }
Emilio G. Cota886953e2010-11-12 11:14:07 +0000455 spin_unlock(&master_image->lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100456 }
457
458 /* Check to see if we found a resource */
459 if (allocated_image == NULL) {
460 printk(KERN_ERR "Can't find a suitable resource\n");
461 goto err_image;
462 }
463
464 resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
465 if (resource == NULL) {
466 printk(KERN_ERR "Unable to allocate resource structure\n");
467 goto err_alloc;
468 }
469 resource->type = VME_MASTER;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000470 resource->entry = &allocated_image->list;
Martyn Welcha17a75e2009-07-31 09:28:17 +0100471
472 return resource;
473
Martyn Welcha17a75e2009-07-31 09:28:17 +0100474err_alloc:
475 /* Unlock image */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000476 spin_lock(&master_image->lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100477 master_image->locked = 0;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000478 spin_unlock(&master_image->lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100479err_image:
480err_bus:
481 return NULL;
482}
483EXPORT_SYMBOL(vme_master_request);
484
Martyn Welchead1f3e2009-12-15 08:43:02 +0000485int vme_master_set(struct vme_resource *resource, int enabled,
Martyn Welch6af04b02011-12-01 17:06:29 +0000486 unsigned long long vme_base, unsigned long long size, u32 aspace,
487 u32 cycle, u32 dwidth)
Martyn Welcha17a75e2009-07-31 09:28:17 +0100488{
489 struct vme_bridge *bridge = find_bridge(resource);
490 struct vme_master_resource *image;
491 int retval;
492
493 if (resource->type != VME_MASTER) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000494 printk(KERN_ERR "Not a master resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100495 return -EINVAL;
496 }
497
498 image = list_entry(resource->entry, struct vme_master_resource, list);
499
500 if (bridge->master_set == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000501 printk(KERN_WARNING "vme_master_set not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100502 return -EINVAL;
503 }
504
Martyn Welchead1f3e2009-12-15 08:43:02 +0000505 if (!(((image->address_attr & aspace) == aspace) &&
Martyn Welcha17a75e2009-07-31 09:28:17 +0100506 ((image->cycle_attr & cycle) == cycle) &&
507 ((image->width_attr & dwidth) == dwidth))) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000508 printk(KERN_WARNING "Invalid attributes\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100509 return -EINVAL;
510 }
511
512 retval = vme_check_window(aspace, vme_base, size);
Martyn Welchead1f3e2009-12-15 08:43:02 +0000513 if (retval)
Martyn Welcha17a75e2009-07-31 09:28:17 +0100514 return retval;
515
516 return bridge->master_set(image, enabled, vme_base, size, aspace,
517 cycle, dwidth);
518}
519EXPORT_SYMBOL(vme_master_set);
520
Martyn Welchead1f3e2009-12-15 08:43:02 +0000521int vme_master_get(struct vme_resource *resource, int *enabled,
Martyn Welch6af04b02011-12-01 17:06:29 +0000522 unsigned long long *vme_base, unsigned long long *size, u32 *aspace,
523 u32 *cycle, u32 *dwidth)
Martyn Welcha17a75e2009-07-31 09:28:17 +0100524{
525 struct vme_bridge *bridge = find_bridge(resource);
526 struct vme_master_resource *image;
527
528 if (resource->type != VME_MASTER) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000529 printk(KERN_ERR "Not a master resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100530 return -EINVAL;
531 }
532
533 image = list_entry(resource->entry, struct vme_master_resource, list);
534
Emilio G. Cota51a569f2009-08-10 16:52:42 +0200535 if (bridge->master_get == NULL) {
Julia Lawallc1038302014-12-07 20:20:53 +0100536 printk(KERN_WARNING "%s not supported\n", __func__);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100537 return -EINVAL;
538 }
539
540 return bridge->master_get(image, enabled, vme_base, size, aspace,
541 cycle, dwidth);
542}
543EXPORT_SYMBOL(vme_master_get);
544
545/*
546 * Read data out of VME space into a buffer.
547 */
Martyn Welchead1f3e2009-12-15 08:43:02 +0000548ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count,
Martyn Welcha17a75e2009-07-31 09:28:17 +0100549 loff_t offset)
550{
551 struct vme_bridge *bridge = find_bridge(resource);
552 struct vme_master_resource *image;
553 size_t length;
554
555 if (bridge->master_read == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000556 printk(KERN_WARNING "Reading from resource not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100557 return -EINVAL;
558 }
559
560 if (resource->type != VME_MASTER) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000561 printk(KERN_ERR "Not a master resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100562 return -EINVAL;
563 }
564
565 image = list_entry(resource->entry, struct vme_master_resource, list);
566
567 length = vme_get_size(resource);
568
569 if (offset > length) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000570 printk(KERN_WARNING "Invalid Offset\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100571 return -EFAULT;
572 }
573
574 if ((offset + count) > length)
575 count = length - offset;
576
577 return bridge->master_read(image, buf, count, offset);
578
579}
580EXPORT_SYMBOL(vme_master_read);
581
582/*
583 * Write data out to VME space from a buffer.
584 */
Martyn Welchead1f3e2009-12-15 08:43:02 +0000585ssize_t vme_master_write(struct vme_resource *resource, void *buf,
Martyn Welcha17a75e2009-07-31 09:28:17 +0100586 size_t count, loff_t offset)
587{
588 struct vme_bridge *bridge = find_bridge(resource);
589 struct vme_master_resource *image;
590 size_t length;
591
592 if (bridge->master_write == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000593 printk(KERN_WARNING "Writing to resource not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100594 return -EINVAL;
595 }
596
597 if (resource->type != VME_MASTER) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000598 printk(KERN_ERR "Not a master resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100599 return -EINVAL;
600 }
601
602 image = list_entry(resource->entry, struct vme_master_resource, list);
603
604 length = vme_get_size(resource);
605
606 if (offset > length) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000607 printk(KERN_WARNING "Invalid Offset\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100608 return -EFAULT;
609 }
610
611 if ((offset + count) > length)
612 count = length - offset;
613
614 return bridge->master_write(image, buf, count, offset);
615}
616EXPORT_SYMBOL(vme_master_write);
617
618/*
619 * Perform RMW cycle to provided location.
620 */
Martyn Welchead1f3e2009-12-15 08:43:02 +0000621unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask,
Martyn Welcha17a75e2009-07-31 09:28:17 +0100622 unsigned int compare, unsigned int swap, loff_t offset)
623{
624 struct vme_bridge *bridge = find_bridge(resource);
625 struct vme_master_resource *image;
626
627 if (bridge->master_rmw == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000628 printk(KERN_WARNING "Writing to resource not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100629 return -EINVAL;
630 }
631
632 if (resource->type != VME_MASTER) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000633 printk(KERN_ERR "Not a master resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100634 return -EINVAL;
635 }
636
637 image = list_entry(resource->entry, struct vme_master_resource, list);
638
639 return bridge->master_rmw(image, mask, compare, swap, offset);
640}
641EXPORT_SYMBOL(vme_master_rmw);
642
Dmitry Kalinkinc74a8042015-02-26 18:53:10 +0300643int vme_master_mmap(struct vme_resource *resource, struct vm_area_struct *vma)
644{
645 struct vme_master_resource *image;
646 phys_addr_t phys_addr;
647 unsigned long vma_size;
648
649 if (resource->type != VME_MASTER) {
650 pr_err("Not a master resource\n");
651 return -EINVAL;
652 }
653
654 image = list_entry(resource->entry, struct vme_master_resource, list);
655 phys_addr = image->bus_resource.start + (vma->vm_pgoff << PAGE_SHIFT);
656 vma_size = vma->vm_end - vma->vm_start;
657
658 if (phys_addr + vma_size > image->bus_resource.end + 1) {
659 pr_err("Map size cannot exceed the window size\n");
660 return -EFAULT;
661 }
662
663 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
664
665 return vm_iomap_memory(vma, phys_addr, vma->vm_end - vma->vm_start);
666}
667EXPORT_SYMBOL(vme_master_mmap);
668
Martyn Welcha17a75e2009-07-31 09:28:17 +0100669void vme_master_free(struct vme_resource *resource)
670{
671 struct vme_master_resource *master_image;
672
673 if (resource->type != VME_MASTER) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000674 printk(KERN_ERR "Not a master resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100675 return;
676 }
677
678 master_image = list_entry(resource->entry, struct vme_master_resource,
679 list);
680 if (master_image == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000681 printk(KERN_ERR "Can't find master resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100682 return;
683 }
684
685 /* Unlock image */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000686 spin_lock(&master_image->lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100687 if (master_image->locked == 0)
688 printk(KERN_ERR "Image is already free\n");
689
690 master_image->locked = 0;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000691 spin_unlock(&master_image->lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100692
693 /* Free up resource memory */
694 kfree(resource);
695}
696EXPORT_SYMBOL(vme_master_free);
697
698/*
699 * Request a DMA controller with specific attributes, return some unique
700 * identifier.
701 */
Martyn Welch6af04b02011-12-01 17:06:29 +0000702struct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 route)
Martyn Welcha17a75e2009-07-31 09:28:17 +0100703{
704 struct vme_bridge *bridge;
705 struct list_head *dma_pos = NULL;
706 struct vme_dma_resource *allocated_ctrlr = NULL;
707 struct vme_dma_resource *dma_ctrlr = NULL;
708 struct vme_resource *resource = NULL;
709
710 /* XXX Not checking resource attributes */
711 printk(KERN_ERR "No VME resource Attribute tests done\n");
712
Manohar Vanga8f966dc2011-09-26 11:27:15 +0200713 bridge = vdev->bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +0100714 if (bridge == NULL) {
715 printk(KERN_ERR "Can't find VME bus\n");
716 goto err_bus;
717 }
718
719 /* Loop through DMA resources */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000720 list_for_each(dma_pos, &bridge->dma_resources) {
Martyn Welcha17a75e2009-07-31 09:28:17 +0100721 dma_ctrlr = list_entry(dma_pos,
722 struct vme_dma_resource, list);
723
724 if (dma_ctrlr == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000725 printk(KERN_ERR "Registered NULL DMA resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100726 continue;
727 }
728
Martyn Welch4f723df2010-02-18 15:12:58 +0000729 /* Find an unlocked and compatible controller */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000730 mutex_lock(&dma_ctrlr->mtx);
Martyn Welch4f723df2010-02-18 15:12:58 +0000731 if (((dma_ctrlr->route_attr & route) == route) &&
732 (dma_ctrlr->locked == 0)) {
733
Martyn Welcha17a75e2009-07-31 09:28:17 +0100734 dma_ctrlr->locked = 1;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000735 mutex_unlock(&dma_ctrlr->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100736 allocated_ctrlr = dma_ctrlr;
737 break;
738 }
Emilio G. Cota886953e2010-11-12 11:14:07 +0000739 mutex_unlock(&dma_ctrlr->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100740 }
741
742 /* Check to see if we found a resource */
743 if (allocated_ctrlr == NULL)
744 goto err_ctrlr;
745
746 resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
747 if (resource == NULL) {
748 printk(KERN_WARNING "Unable to allocate resource structure\n");
749 goto err_alloc;
750 }
751 resource->type = VME_DMA;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000752 resource->entry = &allocated_ctrlr->list;
Martyn Welcha17a75e2009-07-31 09:28:17 +0100753
754 return resource;
755
756err_alloc:
757 /* Unlock image */
Emilio G. Cota886953e2010-11-12 11:14:07 +0000758 mutex_lock(&dma_ctrlr->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100759 dma_ctrlr->locked = 0;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000760 mutex_unlock(&dma_ctrlr->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100761err_ctrlr:
762err_bus:
763 return NULL;
764}
Martyn Welch58e50792009-10-29 16:35:20 +0000765EXPORT_SYMBOL(vme_dma_request);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100766
767/*
768 * Start new list
769 */
770struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource)
771{
772 struct vme_dma_resource *ctrlr;
773 struct vme_dma_list *dma_list;
774
775 if (resource->type != VME_DMA) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000776 printk(KERN_ERR "Not a DMA resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100777 return NULL;
778 }
779
780 ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
781
Martyn Welchead1f3e2009-12-15 08:43:02 +0000782 dma_list = kmalloc(sizeof(struct vme_dma_list), GFP_KERNEL);
783 if (dma_list == NULL) {
Aaron Sierraf56c3d42016-04-21 11:18:22 -0500784 printk(KERN_ERR "Unable to allocate memory for new DMA list\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100785 return NULL;
786 }
Emilio G. Cota886953e2010-11-12 11:14:07 +0000787 INIT_LIST_HEAD(&dma_list->entries);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100788 dma_list->parent = ctrlr;
Emilio G. Cota886953e2010-11-12 11:14:07 +0000789 mutex_init(&dma_list->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100790
791 return dma_list;
792}
793EXPORT_SYMBOL(vme_new_dma_list);
794
795/*
796 * Create "Pattern" type attributes
797 */
Martyn Welch6af04b02011-12-01 17:06:29 +0000798struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type)
Martyn Welcha17a75e2009-07-31 09:28:17 +0100799{
800 struct vme_dma_attr *attributes;
801 struct vme_dma_pattern *pattern_attr;
802
Martyn Welchead1f3e2009-12-15 08:43:02 +0000803 attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
804 if (attributes == NULL) {
Greg Kroah-Hartman25958ce2012-04-25 11:25:46 -0700805 printk(KERN_ERR "Unable to allocate memory for attributes structure\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100806 goto err_attr;
807 }
808
Martyn Welchead1f3e2009-12-15 08:43:02 +0000809 pattern_attr = kmalloc(sizeof(struct vme_dma_pattern), GFP_KERNEL);
810 if (pattern_attr == NULL) {
Greg Kroah-Hartman25958ce2012-04-25 11:25:46 -0700811 printk(KERN_ERR "Unable to allocate memory for pattern attributes\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100812 goto err_pat;
813 }
814
815 attributes->type = VME_DMA_PATTERN;
816 attributes->private = (void *)pattern_attr;
817
818 pattern_attr->pattern = pattern;
819 pattern_attr->type = type;
820
821 return attributes;
822
Martyn Welcha17a75e2009-07-31 09:28:17 +0100823err_pat:
824 kfree(attributes);
825err_attr:
826 return NULL;
827}
828EXPORT_SYMBOL(vme_dma_pattern_attribute);
829
830/*
831 * Create "PCI" type attributes
832 */
833struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address)
834{
835 struct vme_dma_attr *attributes;
836 struct vme_dma_pci *pci_attr;
837
838 /* XXX Run some sanity checks here */
839
Martyn Welchead1f3e2009-12-15 08:43:02 +0000840 attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
841 if (attributes == NULL) {
Greg Kroah-Hartman25958ce2012-04-25 11:25:46 -0700842 printk(KERN_ERR "Unable to allocate memory for attributes structure\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100843 goto err_attr;
844 }
845
Martyn Welchead1f3e2009-12-15 08:43:02 +0000846 pci_attr = kmalloc(sizeof(struct vme_dma_pci), GFP_KERNEL);
847 if (pci_attr == NULL) {
Aaron Sierraf56c3d42016-04-21 11:18:22 -0500848 printk(KERN_ERR "Unable to allocate memory for PCI attributes\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100849 goto err_pci;
850 }
851
852
853
854 attributes->type = VME_DMA_PCI;
855 attributes->private = (void *)pci_attr;
856
857 pci_attr->address = address;
858
859 return attributes;
860
Martyn Welcha17a75e2009-07-31 09:28:17 +0100861err_pci:
862 kfree(attributes);
863err_attr:
864 return NULL;
865}
866EXPORT_SYMBOL(vme_dma_pci_attribute);
867
868/*
869 * Create "VME" type attributes
870 */
871struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address,
Martyn Welch6af04b02011-12-01 17:06:29 +0000872 u32 aspace, u32 cycle, u32 dwidth)
Martyn Welcha17a75e2009-07-31 09:28:17 +0100873{
874 struct vme_dma_attr *attributes;
875 struct vme_dma_vme *vme_attr;
876
Martyn Welchead1f3e2009-12-15 08:43:02 +0000877 attributes = kmalloc(
Martyn Welcha17a75e2009-07-31 09:28:17 +0100878 sizeof(struct vme_dma_attr), GFP_KERNEL);
Martyn Welchead1f3e2009-12-15 08:43:02 +0000879 if (attributes == NULL) {
Greg Kroah-Hartman25958ce2012-04-25 11:25:46 -0700880 printk(KERN_ERR "Unable to allocate memory for attributes structure\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100881 goto err_attr;
882 }
883
Martyn Welchead1f3e2009-12-15 08:43:02 +0000884 vme_attr = kmalloc(sizeof(struct vme_dma_vme), GFP_KERNEL);
885 if (vme_attr == NULL) {
Aaron Sierraf56c3d42016-04-21 11:18:22 -0500886 printk(KERN_ERR "Unable to allocate memory for VME attributes\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100887 goto err_vme;
888 }
889
890 attributes->type = VME_DMA_VME;
891 attributes->private = (void *)vme_attr;
892
893 vme_attr->address = address;
894 vme_attr->aspace = aspace;
895 vme_attr->cycle = cycle;
896 vme_attr->dwidth = dwidth;
897
898 return attributes;
899
Martyn Welcha17a75e2009-07-31 09:28:17 +0100900err_vme:
901 kfree(attributes);
902err_attr:
903 return NULL;
904}
905EXPORT_SYMBOL(vme_dma_vme_attribute);
906
907/*
908 * Free attribute
909 */
910void vme_dma_free_attribute(struct vme_dma_attr *attributes)
911{
912 kfree(attributes->private);
913 kfree(attributes);
914}
915EXPORT_SYMBOL(vme_dma_free_attribute);
916
917int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
918 struct vme_dma_attr *dest, size_t count)
919{
920 struct vme_bridge *bridge = list->parent->parent;
921 int retval;
922
923 if (bridge->dma_list_add == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000924 printk(KERN_WARNING "Link List DMA generation not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100925 return -EINVAL;
926 }
927
Emilio G. Cota886953e2010-11-12 11:14:07 +0000928 if (!mutex_trylock(&list->mtx)) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000929 printk(KERN_ERR "Link List already submitted\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100930 return -EINVAL;
931 }
932
933 retval = bridge->dma_list_add(list, src, dest, count);
934
Emilio G. Cota886953e2010-11-12 11:14:07 +0000935 mutex_unlock(&list->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100936
937 return retval;
938}
939EXPORT_SYMBOL(vme_dma_list_add);
940
941int vme_dma_list_exec(struct vme_dma_list *list)
942{
943 struct vme_bridge *bridge = list->parent->parent;
944 int retval;
945
946 if (bridge->dma_list_exec == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000947 printk(KERN_ERR "Link List DMA execution not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100948 return -EINVAL;
949 }
950
Emilio G. Cota886953e2010-11-12 11:14:07 +0000951 mutex_lock(&list->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100952
953 retval = bridge->dma_list_exec(list);
954
Emilio G. Cota886953e2010-11-12 11:14:07 +0000955 mutex_unlock(&list->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100956
957 return retval;
958}
959EXPORT_SYMBOL(vme_dma_list_exec);
960
961int vme_dma_list_free(struct vme_dma_list *list)
962{
963 struct vme_bridge *bridge = list->parent->parent;
964 int retval;
965
966 if (bridge->dma_list_empty == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000967 printk(KERN_WARNING "Emptying of Link Lists not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100968 return -EINVAL;
969 }
970
Emilio G. Cota886953e2010-11-12 11:14:07 +0000971 if (!mutex_trylock(&list->mtx)) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000972 printk(KERN_ERR "Link List in use\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100973 return -EINVAL;
974 }
975
976 /*
Aaron Sierraf56c3d42016-04-21 11:18:22 -0500977 * Empty out all of the entries from the DMA list. We need to go to the
978 * low level driver as DMA entries are driver specific.
Martyn Welcha17a75e2009-07-31 09:28:17 +0100979 */
980 retval = bridge->dma_list_empty(list);
981 if (retval) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000982 printk(KERN_ERR "Unable to empty link-list entries\n");
Emilio G. Cota886953e2010-11-12 11:14:07 +0000983 mutex_unlock(&list->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100984 return retval;
985 }
Emilio G. Cota886953e2010-11-12 11:14:07 +0000986 mutex_unlock(&list->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +0100987 kfree(list);
988
989 return retval;
990}
991EXPORT_SYMBOL(vme_dma_list_free);
992
993int vme_dma_free(struct vme_resource *resource)
994{
995 struct vme_dma_resource *ctrlr;
996
997 if (resource->type != VME_DMA) {
Martyn Welchead1f3e2009-12-15 08:43:02 +0000998 printk(KERN_ERR "Not a DMA resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +0100999 return -EINVAL;
1000 }
1001
1002 ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
1003
Emilio G. Cota886953e2010-11-12 11:14:07 +00001004 if (!mutex_trylock(&ctrlr->mtx)) {
Martyn Welchead1f3e2009-12-15 08:43:02 +00001005 printk(KERN_ERR "Resource busy, can't free\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001006 return -EBUSY;
1007 }
1008
Emilio G. Cota886953e2010-11-12 11:14:07 +00001009 if (!(list_empty(&ctrlr->pending) && list_empty(&ctrlr->running))) {
Martyn Welchead1f3e2009-12-15 08:43:02 +00001010 printk(KERN_WARNING "Resource still processing transfers\n");
Emilio G. Cota886953e2010-11-12 11:14:07 +00001011 mutex_unlock(&ctrlr->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001012 return -EBUSY;
1013 }
1014
1015 ctrlr->locked = 0;
1016
Emilio G. Cota886953e2010-11-12 11:14:07 +00001017 mutex_unlock(&ctrlr->mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001018
Martyn Welchfd5c2562013-06-06 12:29:16 +01001019 kfree(resource);
1020
Martyn Welcha17a75e2009-07-31 09:28:17 +01001021 return 0;
1022}
1023EXPORT_SYMBOL(vme_dma_free);
1024
Dmitry Kalinkine2c63932015-09-18 02:01:42 +03001025void vme_bus_error_handler(struct vme_bridge *bridge,
Dmitry Kalinkin472f16f2015-09-18 02:01:43 +03001026 unsigned long long address, int am)
Dmitry Kalinkine2c63932015-09-18 02:01:42 +03001027{
Dmitry Kalinkin0b049662015-09-18 02:01:44 +03001028 struct list_head *handler_pos = NULL;
1029 struct vme_error_handler *handler;
Dmitry Kalinkin448535a2015-09-18 02:01:45 +03001030 int handler_triggered = 0;
Dmitry Kalinkin0b049662015-09-18 02:01:44 +03001031 u32 aspace = vme_get_aspace(am);
Dmitry Kalinkine2c63932015-09-18 02:01:42 +03001032
Dmitry Kalinkin0b049662015-09-18 02:01:44 +03001033 list_for_each(handler_pos, &bridge->vme_error_handlers) {
1034 handler = list_entry(handler_pos, struct vme_error_handler,
1035 list);
1036 if ((aspace == handler->aspace) &&
1037 (address >= handler->start) &&
1038 (address < handler->end)) {
1039 if (!handler->num_errors)
1040 handler->first_error = address;
1041 if (handler->num_errors != UINT_MAX)
1042 handler->num_errors++;
Dmitry Kalinkin448535a2015-09-18 02:01:45 +03001043 handler_triggered = 1;
Dmitry Kalinkin0b049662015-09-18 02:01:44 +03001044 }
Dmitry Kalinkine2c63932015-09-18 02:01:42 +03001045 }
Dmitry Kalinkin448535a2015-09-18 02:01:45 +03001046
1047 if (!handler_triggered)
1048 dev_err(bridge->parent,
1049 "Unhandled VME access error at address 0x%llx\n",
1050 address);
Dmitry Kalinkine2c63932015-09-18 02:01:42 +03001051}
1052EXPORT_SYMBOL(vme_bus_error_handler);
1053
Dmitry Kalinkin0b049662015-09-18 02:01:44 +03001054struct vme_error_handler *vme_register_error_handler(
1055 struct vme_bridge *bridge, u32 aspace,
1056 unsigned long long address, size_t len)
Dmitry Kalinkine2c63932015-09-18 02:01:42 +03001057{
Dmitry Kalinkin0b049662015-09-18 02:01:44 +03001058 struct vme_error_handler *handler;
Dmitry Kalinkine2c63932015-09-18 02:01:42 +03001059
Dmitry Kalinkin0b049662015-09-18 02:01:44 +03001060 handler = kmalloc(sizeof(*handler), GFP_KERNEL);
1061 if (!handler)
1062 return NULL;
Dmitry Kalinkine2c63932015-09-18 02:01:42 +03001063
Dmitry Kalinkin0b049662015-09-18 02:01:44 +03001064 handler->aspace = aspace;
1065 handler->start = address;
1066 handler->end = address + len;
1067 handler->num_errors = 0;
1068 handler->first_error = 0;
1069 list_add_tail(&handler->list, &bridge->vme_error_handlers);
Dmitry Kalinkine2c63932015-09-18 02:01:42 +03001070
Dmitry Kalinkin0b049662015-09-18 02:01:44 +03001071 return handler;
Dmitry Kalinkine2c63932015-09-18 02:01:42 +03001072}
Dmitry Kalinkin0b049662015-09-18 02:01:44 +03001073EXPORT_SYMBOL(vme_register_error_handler);
Dmitry Kalinkine2c63932015-09-18 02:01:42 +03001074
Dmitry Kalinkin0b049662015-09-18 02:01:44 +03001075void vme_unregister_error_handler(struct vme_error_handler *handler)
Dmitry Kalinkine2c63932015-09-18 02:01:42 +03001076{
Dmitry Kalinkin0b049662015-09-18 02:01:44 +03001077 list_del(&handler->list);
1078 kfree(handler);
Dmitry Kalinkine2c63932015-09-18 02:01:42 +03001079}
Dmitry Kalinkin0b049662015-09-18 02:01:44 +03001080EXPORT_SYMBOL(vme_unregister_error_handler);
Dmitry Kalinkine2c63932015-09-18 02:01:42 +03001081
Martyn Welchc813f592009-10-29 16:34:54 +00001082void vme_irq_handler(struct vme_bridge *bridge, int level, int statid)
1083{
1084 void (*call)(int, int, void *);
1085 void *priv_data;
1086
1087 call = bridge->irq[level - 1].callback[statid].func;
1088 priv_data = bridge->irq[level - 1].callback[statid].priv_data;
1089
1090 if (call != NULL)
1091 call(level, statid, priv_data);
1092 else
Aaron Sierraf56c3d42016-04-21 11:18:22 -05001093 printk(KERN_WARNING "Spurious VME interrupt, level:%x, vector:%x\n",
Greg Kroah-Hartman25958ce2012-04-25 11:25:46 -07001094 level, statid);
Martyn Welchc813f592009-10-29 16:34:54 +00001095}
1096EXPORT_SYMBOL(vme_irq_handler);
1097
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001098int vme_irq_request(struct vme_dev *vdev, int level, int statid,
Martyn Welch29848ac2010-02-18 15:13:05 +00001099 void (*callback)(int, int, void *),
Martyn Welcha17a75e2009-07-31 09:28:17 +01001100 void *priv_data)
1101{
1102 struct vme_bridge *bridge;
1103
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001104 bridge = vdev->bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001105 if (bridge == NULL) {
1106 printk(KERN_ERR "Can't find VME bus\n");
1107 return -EINVAL;
1108 }
1109
Martyn Welchead1f3e2009-12-15 08:43:02 +00001110 if ((level < 1) || (level > 7)) {
Martyn Welchc813f592009-10-29 16:34:54 +00001111 printk(KERN_ERR "Invalid interrupt level\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001112 return -EINVAL;
1113 }
1114
Martyn Welchc813f592009-10-29 16:34:54 +00001115 if (bridge->irq_set == NULL) {
1116 printk(KERN_ERR "Configuring interrupts not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001117 return -EINVAL;
1118 }
1119
Emilio G. Cota886953e2010-11-12 11:14:07 +00001120 mutex_lock(&bridge->irq_mtx);
Martyn Welchc813f592009-10-29 16:34:54 +00001121
1122 if (bridge->irq[level - 1].callback[statid].func) {
Emilio G. Cota886953e2010-11-12 11:14:07 +00001123 mutex_unlock(&bridge->irq_mtx);
Martyn Welchc813f592009-10-29 16:34:54 +00001124 printk(KERN_WARNING "VME Interrupt already taken\n");
1125 return -EBUSY;
1126 }
1127
1128 bridge->irq[level - 1].count++;
1129 bridge->irq[level - 1].callback[statid].priv_data = priv_data;
1130 bridge->irq[level - 1].callback[statid].func = callback;
1131
1132 /* Enable IRQ level */
Martyn Welch29848ac2010-02-18 15:13:05 +00001133 bridge->irq_set(bridge, level, 1, 1);
Martyn Welchc813f592009-10-29 16:34:54 +00001134
Emilio G. Cota886953e2010-11-12 11:14:07 +00001135 mutex_unlock(&bridge->irq_mtx);
Martyn Welchc813f592009-10-29 16:34:54 +00001136
1137 return 0;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001138}
Martyn Welchc813f592009-10-29 16:34:54 +00001139EXPORT_SYMBOL(vme_irq_request);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001140
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001141void vme_irq_free(struct vme_dev *vdev, int level, int statid)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001142{
1143 struct vme_bridge *bridge;
1144
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001145 bridge = vdev->bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001146 if (bridge == NULL) {
1147 printk(KERN_ERR "Can't find VME bus\n");
1148 return;
1149 }
1150
Martyn Welchead1f3e2009-12-15 08:43:02 +00001151 if ((level < 1) || (level > 7)) {
Martyn Welchc813f592009-10-29 16:34:54 +00001152 printk(KERN_ERR "Invalid interrupt level\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001153 return;
1154 }
1155
Martyn Welchc813f592009-10-29 16:34:54 +00001156 if (bridge->irq_set == NULL) {
1157 printk(KERN_ERR "Configuring interrupts not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001158 return;
1159 }
1160
Emilio G. Cota886953e2010-11-12 11:14:07 +00001161 mutex_lock(&bridge->irq_mtx);
Martyn Welchc813f592009-10-29 16:34:54 +00001162
1163 bridge->irq[level - 1].count--;
1164
1165 /* Disable IRQ level if no more interrupts attached at this level*/
1166 if (bridge->irq[level - 1].count == 0)
Martyn Welch29848ac2010-02-18 15:13:05 +00001167 bridge->irq_set(bridge, level, 0, 1);
Martyn Welchc813f592009-10-29 16:34:54 +00001168
1169 bridge->irq[level - 1].callback[statid].func = NULL;
1170 bridge->irq[level - 1].callback[statid].priv_data = NULL;
1171
Emilio G. Cota886953e2010-11-12 11:14:07 +00001172 mutex_unlock(&bridge->irq_mtx);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001173}
Martyn Welchc813f592009-10-29 16:34:54 +00001174EXPORT_SYMBOL(vme_irq_free);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001175
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001176int vme_irq_generate(struct vme_dev *vdev, int level, int statid)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001177{
1178 struct vme_bridge *bridge;
1179
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001180 bridge = vdev->bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001181 if (bridge == NULL) {
1182 printk(KERN_ERR "Can't find VME bus\n");
1183 return -EINVAL;
1184 }
1185
Martyn Welchead1f3e2009-12-15 08:43:02 +00001186 if ((level < 1) || (level > 7)) {
Martyn Welcha17a75e2009-07-31 09:28:17 +01001187 printk(KERN_WARNING "Invalid interrupt level\n");
1188 return -EINVAL;
1189 }
1190
Martyn Welchc813f592009-10-29 16:34:54 +00001191 if (bridge->irq_generate == NULL) {
Martyn Welchead1f3e2009-12-15 08:43:02 +00001192 printk(KERN_WARNING "Interrupt generation not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001193 return -EINVAL;
1194 }
1195
Martyn Welch29848ac2010-02-18 15:13:05 +00001196 return bridge->irq_generate(bridge, level, statid);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001197}
Martyn Welchc813f592009-10-29 16:34:54 +00001198EXPORT_SYMBOL(vme_irq_generate);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001199
Martyn Welch42fb5032009-08-11 17:44:56 +01001200/*
1201 * Request the location monitor, return resource or NULL
1202 */
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001203struct vme_resource *vme_lm_request(struct vme_dev *vdev)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001204{
1205 struct vme_bridge *bridge;
Martyn Welch42fb5032009-08-11 17:44:56 +01001206 struct list_head *lm_pos = NULL;
1207 struct vme_lm_resource *allocated_lm = NULL;
1208 struct vme_lm_resource *lm = NULL;
1209 struct vme_resource *resource = NULL;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001210
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001211 bridge = vdev->bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001212 if (bridge == NULL) {
1213 printk(KERN_ERR "Can't find VME bus\n");
Martyn Welch42fb5032009-08-11 17:44:56 +01001214 goto err_bus;
1215 }
1216
1217 /* Loop through DMA resources */
Emilio G. Cota886953e2010-11-12 11:14:07 +00001218 list_for_each(lm_pos, &bridge->lm_resources) {
Martyn Welch42fb5032009-08-11 17:44:56 +01001219 lm = list_entry(lm_pos,
1220 struct vme_lm_resource, list);
1221
1222 if (lm == NULL) {
Greg Kroah-Hartman25958ce2012-04-25 11:25:46 -07001223 printk(KERN_ERR "Registered NULL Location Monitor resource\n");
Martyn Welch42fb5032009-08-11 17:44:56 +01001224 continue;
1225 }
1226
1227 /* Find an unlocked controller */
Emilio G. Cota886953e2010-11-12 11:14:07 +00001228 mutex_lock(&lm->mtx);
Martyn Welch42fb5032009-08-11 17:44:56 +01001229 if (lm->locked == 0) {
1230 lm->locked = 1;
Emilio G. Cota886953e2010-11-12 11:14:07 +00001231 mutex_unlock(&lm->mtx);
Martyn Welch42fb5032009-08-11 17:44:56 +01001232 allocated_lm = lm;
1233 break;
1234 }
Emilio G. Cota886953e2010-11-12 11:14:07 +00001235 mutex_unlock(&lm->mtx);
Martyn Welch42fb5032009-08-11 17:44:56 +01001236 }
1237
1238 /* Check to see if we found a resource */
1239 if (allocated_lm == NULL)
1240 goto err_lm;
1241
1242 resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
1243 if (resource == NULL) {
1244 printk(KERN_ERR "Unable to allocate resource structure\n");
1245 goto err_alloc;
1246 }
1247 resource->type = VME_LM;
Emilio G. Cota886953e2010-11-12 11:14:07 +00001248 resource->entry = &allocated_lm->list;
Martyn Welch42fb5032009-08-11 17:44:56 +01001249
1250 return resource;
1251
1252err_alloc:
1253 /* Unlock image */
Emilio G. Cota886953e2010-11-12 11:14:07 +00001254 mutex_lock(&lm->mtx);
Martyn Welch42fb5032009-08-11 17:44:56 +01001255 lm->locked = 0;
Emilio G. Cota886953e2010-11-12 11:14:07 +00001256 mutex_unlock(&lm->mtx);
Martyn Welch42fb5032009-08-11 17:44:56 +01001257err_lm:
1258err_bus:
1259 return NULL;
1260}
1261EXPORT_SYMBOL(vme_lm_request);
1262
1263int vme_lm_count(struct vme_resource *resource)
1264{
1265 struct vme_lm_resource *lm;
1266
1267 if (resource->type != VME_LM) {
1268 printk(KERN_ERR "Not a Location Monitor resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001269 return -EINVAL;
1270 }
1271
Martyn Welch42fb5032009-08-11 17:44:56 +01001272 lm = list_entry(resource->entry, struct vme_lm_resource, list);
1273
1274 return lm->monitors;
1275}
1276EXPORT_SYMBOL(vme_lm_count);
1277
1278int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base,
Martyn Welch6af04b02011-12-01 17:06:29 +00001279 u32 aspace, u32 cycle)
Martyn Welch42fb5032009-08-11 17:44:56 +01001280{
1281 struct vme_bridge *bridge = find_bridge(resource);
1282 struct vme_lm_resource *lm;
1283
1284 if (resource->type != VME_LM) {
1285 printk(KERN_ERR "Not a Location Monitor resource\n");
1286 return -EINVAL;
1287 }
1288
1289 lm = list_entry(resource->entry, struct vme_lm_resource, list);
1290
Martyn Welcha17a75e2009-07-31 09:28:17 +01001291 if (bridge->lm_set == NULL) {
Martyn Welch42fb5032009-08-11 17:44:56 +01001292 printk(KERN_ERR "vme_lm_set not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001293 return -EINVAL;
1294 }
1295
Martyn Welch8be92262009-10-29 16:35:08 +00001296 return bridge->lm_set(lm, lm_base, aspace, cycle);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001297}
1298EXPORT_SYMBOL(vme_lm_set);
1299
Martyn Welch42fb5032009-08-11 17:44:56 +01001300int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base,
Martyn Welch6af04b02011-12-01 17:06:29 +00001301 u32 *aspace, u32 *cycle)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001302{
Martyn Welch42fb5032009-08-11 17:44:56 +01001303 struct vme_bridge *bridge = find_bridge(resource);
1304 struct vme_lm_resource *lm;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001305
Martyn Welch42fb5032009-08-11 17:44:56 +01001306 if (resource->type != VME_LM) {
1307 printk(KERN_ERR "Not a Location Monitor resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001308 return -EINVAL;
1309 }
1310
Martyn Welch42fb5032009-08-11 17:44:56 +01001311 lm = list_entry(resource->entry, struct vme_lm_resource, list);
1312
Martyn Welcha17a75e2009-07-31 09:28:17 +01001313 if (bridge->lm_get == NULL) {
Martyn Welch42fb5032009-08-11 17:44:56 +01001314 printk(KERN_ERR "vme_lm_get not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001315 return -EINVAL;
1316 }
1317
Martyn Welch42fb5032009-08-11 17:44:56 +01001318 return bridge->lm_get(lm, lm_base, aspace, cycle);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001319}
1320EXPORT_SYMBOL(vme_lm_get);
1321
Martyn Welch42fb5032009-08-11 17:44:56 +01001322int vme_lm_attach(struct vme_resource *resource, int monitor,
Aaron Sierrafa54b322016-04-29 16:41:02 -05001323 void (*callback)(void *), void *data)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001324{
Martyn Welch42fb5032009-08-11 17:44:56 +01001325 struct vme_bridge *bridge = find_bridge(resource);
1326 struct vme_lm_resource *lm;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001327
Martyn Welch42fb5032009-08-11 17:44:56 +01001328 if (resource->type != VME_LM) {
1329 printk(KERN_ERR "Not a Location Monitor resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001330 return -EINVAL;
1331 }
1332
Martyn Welch42fb5032009-08-11 17:44:56 +01001333 lm = list_entry(resource->entry, struct vme_lm_resource, list);
1334
Martyn Welcha17a75e2009-07-31 09:28:17 +01001335 if (bridge->lm_attach == NULL) {
Martyn Welch42fb5032009-08-11 17:44:56 +01001336 printk(KERN_ERR "vme_lm_attach not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001337 return -EINVAL;
1338 }
1339
Aaron Sierrafa54b322016-04-29 16:41:02 -05001340 return bridge->lm_attach(lm, monitor, callback, data);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001341}
1342EXPORT_SYMBOL(vme_lm_attach);
1343
Martyn Welch42fb5032009-08-11 17:44:56 +01001344int vme_lm_detach(struct vme_resource *resource, int monitor)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001345{
Martyn Welch42fb5032009-08-11 17:44:56 +01001346 struct vme_bridge *bridge = find_bridge(resource);
1347 struct vme_lm_resource *lm;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001348
Martyn Welch42fb5032009-08-11 17:44:56 +01001349 if (resource->type != VME_LM) {
1350 printk(KERN_ERR "Not a Location Monitor resource\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001351 return -EINVAL;
1352 }
1353
Martyn Welch42fb5032009-08-11 17:44:56 +01001354 lm = list_entry(resource->entry, struct vme_lm_resource, list);
1355
Martyn Welcha17a75e2009-07-31 09:28:17 +01001356 if (bridge->lm_detach == NULL) {
Martyn Welch42fb5032009-08-11 17:44:56 +01001357 printk(KERN_ERR "vme_lm_detach not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001358 return -EINVAL;
1359 }
1360
Martyn Welch42fb5032009-08-11 17:44:56 +01001361 return bridge->lm_detach(lm, monitor);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001362}
1363EXPORT_SYMBOL(vme_lm_detach);
1364
Martyn Welch42fb5032009-08-11 17:44:56 +01001365void vme_lm_free(struct vme_resource *resource)
1366{
1367 struct vme_lm_resource *lm;
1368
1369 if (resource->type != VME_LM) {
1370 printk(KERN_ERR "Not a Location Monitor resource\n");
1371 return;
1372 }
1373
1374 lm = list_entry(resource->entry, struct vme_lm_resource, list);
1375
Emilio G. Cota886953e2010-11-12 11:14:07 +00001376 mutex_lock(&lm->mtx);
Martyn Welch42fb5032009-08-11 17:44:56 +01001377
Martyn Welch8be92262009-10-29 16:35:08 +00001378 /* XXX
1379 * Check to see that there aren't any callbacks still attached, if
1380 * there are we should probably be detaching them!
1381 */
Martyn Welch42fb5032009-08-11 17:44:56 +01001382
1383 lm->locked = 0;
1384
Emilio G. Cota886953e2010-11-12 11:14:07 +00001385 mutex_unlock(&lm->mtx);
Martyn Welch8be92262009-10-29 16:35:08 +00001386
1387 kfree(resource);
Martyn Welch42fb5032009-08-11 17:44:56 +01001388}
1389EXPORT_SYMBOL(vme_lm_free);
1390
Martyn Welchd7729f02013-11-08 11:58:35 +00001391int vme_slot_num(struct vme_dev *vdev)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001392{
1393 struct vme_bridge *bridge;
1394
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001395 bridge = vdev->bridge;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001396 if (bridge == NULL) {
1397 printk(KERN_ERR "Can't find VME bus\n");
1398 return -EINVAL;
1399 }
1400
1401 if (bridge->slot_get == NULL) {
Martyn Welchd7729f02013-11-08 11:58:35 +00001402 printk(KERN_WARNING "vme_slot_num not supported\n");
Martyn Welcha17a75e2009-07-31 09:28:17 +01001403 return -EINVAL;
1404 }
1405
Martyn Welch29848ac2010-02-18 15:13:05 +00001406 return bridge->slot_get(bridge);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001407}
Martyn Welchd7729f02013-11-08 11:58:35 +00001408EXPORT_SYMBOL(vme_slot_num);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001409
Martyn Welch978f47d2013-11-08 11:58:34 +00001410int vme_bus_num(struct vme_dev *vdev)
1411{
1412 struct vme_bridge *bridge;
1413
1414 bridge = vdev->bridge;
1415 if (bridge == NULL) {
1416 pr_err("Can't find VME bus\n");
1417 return -EINVAL;
1418 }
1419
1420 return bridge->num;
1421}
1422EXPORT_SYMBOL(vme_bus_num);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001423
1424/* - Bridge Registration --------------------------------------------------- */
1425
Manohar Vanga5b93c2a2011-11-04 11:12:30 +01001426static void vme_dev_release(struct device *dev)
1427{
1428 kfree(dev_to_vme_dev(dev));
1429}
1430
Aaron Sierra326071b2016-04-24 15:11:38 -05001431/* Common bridge initialization */
1432struct vme_bridge *vme_init_bridge(struct vme_bridge *bridge)
1433{
1434 INIT_LIST_HEAD(&bridge->vme_error_handlers);
1435 INIT_LIST_HEAD(&bridge->master_resources);
1436 INIT_LIST_HEAD(&bridge->slave_resources);
1437 INIT_LIST_HEAD(&bridge->dma_resources);
1438 INIT_LIST_HEAD(&bridge->lm_resources);
1439 mutex_init(&bridge->irq_mtx);
1440
1441 return bridge;
1442}
1443EXPORT_SYMBOL(vme_init_bridge);
1444
Manohar Vanga5b93c2a2011-11-04 11:12:30 +01001445int vme_register_bridge(struct vme_bridge *bridge)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001446{
1447 int i;
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001448 int ret = -1;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001449
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001450 mutex_lock(&vme_buses_lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001451 for (i = 0; i < sizeof(vme_bus_numbers) * 8; i++) {
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001452 if ((vme_bus_numbers & (1 << i)) == 0) {
1453 vme_bus_numbers |= (1 << i);
1454 bridge->num = i;
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001455 INIT_LIST_HEAD(&bridge->devices);
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001456 list_add_tail(&bridge->bus_list, &vme_bus_list);
1457 ret = 0;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001458 break;
1459 }
1460 }
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001461 mutex_unlock(&vme_buses_lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001462
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001463 return ret;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001464}
Manohar Vanga5b93c2a2011-11-04 11:12:30 +01001465EXPORT_SYMBOL(vme_register_bridge);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001466
Manohar Vanga5b93c2a2011-11-04 11:12:30 +01001467void vme_unregister_bridge(struct vme_bridge *bridge)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001468{
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001469 struct vme_dev *vdev;
1470 struct vme_dev *tmp;
1471
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001472 mutex_lock(&vme_buses_lock);
1473 vme_bus_numbers &= ~(1 << bridge->num);
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001474 list_for_each_entry_safe(vdev, tmp, &bridge->devices, bridge_list) {
1475 list_del(&vdev->drv_list);
1476 list_del(&vdev->bridge_list);
1477 device_unregister(&vdev->dev);
1478 }
Manohar Vanga733e3ef2011-08-12 12:30:48 +02001479 list_del(&bridge->bus_list);
1480 mutex_unlock(&vme_buses_lock);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001481}
Martyn Welcha17a75e2009-07-31 09:28:17 +01001482EXPORT_SYMBOL(vme_unregister_bridge);
1483
Martyn Welcha17a75e2009-07-31 09:28:17 +01001484/* - Driver Registration --------------------------------------------------- */
1485
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001486static int __vme_register_driver_bus(struct vme_driver *drv,
1487 struct vme_bridge *bridge, unsigned int ndevs)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001488{
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001489 int err;
1490 unsigned int i;
1491 struct vme_dev *vdev;
1492 struct vme_dev *tmp;
1493
1494 for (i = 0; i < ndevs; i++) {
1495 vdev = kzalloc(sizeof(struct vme_dev), GFP_KERNEL);
1496 if (!vdev) {
1497 err = -ENOMEM;
1498 goto err_devalloc;
1499 }
Manohar Vangaa916a392011-09-26 11:27:17 +02001500 vdev->num = i;
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001501 vdev->bridge = bridge;
1502 vdev->dev.platform_data = drv;
1503 vdev->dev.release = vme_dev_release;
1504 vdev->dev.parent = bridge->parent;
1505 vdev->dev.bus = &vme_bus_type;
Manohar Vangaa916a392011-09-26 11:27:17 +02001506 dev_set_name(&vdev->dev, "%s.%u-%u", drv->name, bridge->num,
1507 vdev->num);
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001508
1509 err = device_register(&vdev->dev);
1510 if (err)
1511 goto err_reg;
1512
1513 if (vdev->dev.platform_data) {
1514 list_add_tail(&vdev->drv_list, &drv->devices);
1515 list_add_tail(&vdev->bridge_list, &bridge->devices);
1516 } else
1517 device_unregister(&vdev->dev);
1518 }
1519 return 0;
1520
1521err_reg:
Emilio G. Cotadef18202013-02-13 13:47:54 -05001522 put_device(&vdev->dev);
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001523 kfree(vdev);
1524err_devalloc:
1525 list_for_each_entry_safe(vdev, tmp, &drv->devices, drv_list) {
1526 list_del(&vdev->drv_list);
1527 list_del(&vdev->bridge_list);
1528 device_unregister(&vdev->dev);
1529 }
1530 return err;
1531}
1532
1533static int __vme_register_driver(struct vme_driver *drv, unsigned int ndevs)
1534{
1535 struct vme_bridge *bridge;
1536 int err = 0;
1537
1538 mutex_lock(&vme_buses_lock);
1539 list_for_each_entry(bridge, &vme_bus_list, bus_list) {
1540 /*
1541 * This cannot cause trouble as we already have vme_buses_lock
1542 * and if the bridge is removed, it will have to go through
1543 * vme_unregister_bridge() to do it (which calls remove() on
1544 * the bridge which in turn tries to acquire vme_buses_lock and
Manohar Vangac26f6112011-11-04 11:12:29 +01001545 * will have to wait).
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001546 */
1547 err = __vme_register_driver_bus(drv, bridge, ndevs);
1548 if (err)
1549 break;
1550 }
1551 mutex_unlock(&vme_buses_lock);
1552 return err;
1553}
1554
1555int vme_register_driver(struct vme_driver *drv, unsigned int ndevs)
1556{
1557 int err;
1558
Martyn Welcha17a75e2009-07-31 09:28:17 +01001559 drv->driver.name = drv->name;
1560 drv->driver.bus = &vme_bus_type;
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001561 INIT_LIST_HEAD(&drv->devices);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001562
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001563 err = driver_register(&drv->driver);
1564 if (err)
1565 return err;
1566
1567 err = __vme_register_driver(drv, ndevs);
1568 if (err)
1569 driver_unregister(&drv->driver);
1570
1571 return err;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001572}
1573EXPORT_SYMBOL(vme_register_driver);
1574
Martyn Welchead1f3e2009-12-15 08:43:02 +00001575void vme_unregister_driver(struct vme_driver *drv)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001576{
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001577 struct vme_dev *dev, *dev_tmp;
1578
1579 mutex_lock(&vme_buses_lock);
1580 list_for_each_entry_safe(dev, dev_tmp, &drv->devices, drv_list) {
1581 list_del(&dev->drv_list);
1582 list_del(&dev->bridge_list);
1583 device_unregister(&dev->dev);
1584 }
1585 mutex_unlock(&vme_buses_lock);
1586
Martyn Welcha17a75e2009-07-31 09:28:17 +01001587 driver_unregister(&drv->driver);
1588}
1589EXPORT_SYMBOL(vme_unregister_driver);
1590
1591/* - Bus Registration ------------------------------------------------------ */
1592
Martyn Welcha17a75e2009-07-31 09:28:17 +01001593static int vme_bus_match(struct device *dev, struct device_driver *drv)
1594{
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001595 struct vme_driver *vme_drv;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001596
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001597 vme_drv = container_of(drv, struct vme_driver, driver);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001598
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001599 if (dev->platform_data == vme_drv) {
1600 struct vme_dev *vdev = dev_to_vme_dev(dev);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001601
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001602 if (vme_drv->match && vme_drv->match(vdev))
1603 return 1;
1604
1605 dev->platform_data = NULL;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001606 }
Martyn Welcha17a75e2009-07-31 09:28:17 +01001607 return 0;
1608}
1609
1610static int vme_bus_probe(struct device *dev)
1611{
Martyn Welcha17a75e2009-07-31 09:28:17 +01001612 int retval = -ENODEV;
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001613 struct vme_driver *driver;
1614 struct vme_dev *vdev = dev_to_vme_dev(dev);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001615
Manohar Vanga5d6abf32011-09-26 11:27:16 +02001616 driver = dev->platform_data;
Martyn Welcha17a75e2009-07-31 09:28:17 +01001617
Martyn Welchead1f3e2009-12-15 08:43:02 +00001618 if (driver->probe != NULL)
Manohar Vanga8f966dc2011-09-26 11:27:15 +02001619 retval = driver->probe(vdev);
Martyn Welcha17a75e2009-07-31 09:28:17 +01001620
1621 return retval;
1622}
1623
Martyn Welcha17a75e2009-07-31 09:28:17 +01001624struct bus_type vme_bus_type = {
1625 .name = "vme",
1626 .match = vme_bus_match,
1627 .probe = vme_bus_probe,
Martyn Welcha17a75e2009-07-31 09:28:17 +01001628};
1629EXPORT_SYMBOL(vme_bus_type);
1630
Martyn Welchead1f3e2009-12-15 08:43:02 +00001631static int __init vme_init(void)
Martyn Welcha17a75e2009-07-31 09:28:17 +01001632{
1633 return bus_register(&vme_bus_type);
1634}
Aaron Sierrac326cc02013-12-09 09:54:42 -06001635subsys_initcall(vme_init);