| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * VME Bridge Framework | 
|  | 3 | * | 
|  | 4 | * Author: Martyn Welch <martyn.welch@ge.com> | 
|  | 5 | * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. | 
|  | 6 | * | 
|  | 7 | * Based on work by Tom Armistead and Ajit Prem | 
|  | 8 | * Copyright 2004 Motorola Inc. | 
|  | 9 | * | 
|  | 10 | * This program is free software; you can redistribute  it and/or modify it | 
|  | 11 | * under  the terms of  the GNU General  Public License as published by the | 
|  | 12 | * Free Software Foundation;  either version 2 of the  License, or (at your | 
|  | 13 | * option) any later version. | 
|  | 14 | */ | 
|  | 15 |  | 
|  | 16 | #include <linux/init.h> | 
|  | 17 | #include <linux/export.h> | 
|  | 18 | #include <linux/mm.h> | 
|  | 19 | #include <linux/types.h> | 
|  | 20 | #include <linux/kernel.h> | 
|  | 21 | #include <linux/errno.h> | 
|  | 22 | #include <linux/pci.h> | 
|  | 23 | #include <linux/poll.h> | 
|  | 24 | #include <linux/highmem.h> | 
|  | 25 | #include <linux/interrupt.h> | 
|  | 26 | #include <linux/pagemap.h> | 
|  | 27 | #include <linux/device.h> | 
|  | 28 | #include <linux/dma-mapping.h> | 
|  | 29 | #include <linux/syscalls.h> | 
|  | 30 | #include <linux/mutex.h> | 
|  | 31 | #include <linux/spinlock.h> | 
|  | 32 | #include <linux/slab.h> | 
|  | 33 | #include <linux/vme.h> | 
|  | 34 |  | 
|  | 35 | #include "vme_bridge.h" | 
|  | 36 |  | 
|  | 37 | /* Bitmask and list of registered buses both protected by common mutex */ | 
|  | 38 | static unsigned int vme_bus_numbers; | 
|  | 39 | static LIST_HEAD(vme_bus_list); | 
|  | 40 | static DEFINE_MUTEX(vme_buses_lock); | 
|  | 41 |  | 
|  | 42 | static int __init vme_init(void); | 
|  | 43 |  | 
|  | 44 | static struct vme_dev *dev_to_vme_dev(struct device *dev) | 
|  | 45 | { | 
|  | 46 | return container_of(dev, struct vme_dev, dev); | 
|  | 47 | } | 
|  | 48 |  | 
|  | 49 | /* | 
|  | 50 | * Find the bridge that the resource is associated with. | 
|  | 51 | */ | 
|  | 52 | static 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; | 
|  | 68 | case VME_LM: | 
|  | 69 | return list_entry(resource->entry, struct vme_lm_resource, | 
|  | 70 | list)->parent; | 
|  | 71 | break; | 
|  | 72 | default: | 
|  | 73 | printk(KERN_ERR "Unknown resource type\n"); | 
|  | 74 | return NULL; | 
|  | 75 | break; | 
|  | 76 | } | 
|  | 77 | } | 
|  | 78 |  | 
|  | 79 | /** | 
|  | 80 | * vme_free_consistent - Allocate contiguous memory. | 
|  | 81 | * @resource: Pointer to VME resource. | 
|  | 82 | * @size: Size of allocation required. | 
|  | 83 | * @dma: Pointer to variable to store physical address of allocation. | 
|  | 84 | * | 
|  | 85 | * Allocate a contiguous block of memory for use by the driver. This is used to | 
|  | 86 | * create the buffers for the slave windows. | 
|  | 87 | * | 
|  | 88 | * Return: Virtual address of allocation on success, NULL on failure. | 
|  | 89 | */ | 
|  | 90 | void *vme_alloc_consistent(struct vme_resource *resource, size_t size, | 
|  | 91 | dma_addr_t *dma) | 
|  | 92 | { | 
|  | 93 | struct vme_bridge *bridge; | 
|  | 94 |  | 
|  | 95 | if (!resource) { | 
|  | 96 | printk(KERN_ERR "No resource\n"); | 
|  | 97 | return NULL; | 
|  | 98 | } | 
|  | 99 |  | 
|  | 100 | bridge = find_bridge(resource); | 
|  | 101 | if (!bridge) { | 
|  | 102 | printk(KERN_ERR "Can't find bridge\n"); | 
|  | 103 | return NULL; | 
|  | 104 | } | 
|  | 105 |  | 
|  | 106 | if (!bridge->parent) { | 
|  | 107 | printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name); | 
|  | 108 | return NULL; | 
|  | 109 | } | 
|  | 110 |  | 
|  | 111 | if (!bridge->alloc_consistent) { | 
|  | 112 | printk(KERN_ERR "alloc_consistent not supported by bridge %s\n", | 
|  | 113 | bridge->name); | 
|  | 114 | return NULL; | 
|  | 115 | } | 
|  | 116 |  | 
|  | 117 | return bridge->alloc_consistent(bridge->parent, size, dma); | 
|  | 118 | } | 
|  | 119 | EXPORT_SYMBOL(vme_alloc_consistent); | 
|  | 120 |  | 
|  | 121 | /** | 
|  | 122 | * vme_free_consistent - Free previously allocated memory. | 
|  | 123 | * @resource: Pointer to VME resource. | 
|  | 124 | * @size: Size of allocation to free. | 
|  | 125 | * @vaddr: Virtual address of allocation. | 
|  | 126 | * @dma: Physical address of allocation. | 
|  | 127 | * | 
|  | 128 | * Free previously allocated block of contiguous memory. | 
|  | 129 | */ | 
|  | 130 | void vme_free_consistent(struct vme_resource *resource, size_t size, | 
|  | 131 | void *vaddr, dma_addr_t dma) | 
|  | 132 | { | 
|  | 133 | struct vme_bridge *bridge; | 
|  | 134 |  | 
|  | 135 | if (!resource) { | 
|  | 136 | printk(KERN_ERR "No resource\n"); | 
|  | 137 | return; | 
|  | 138 | } | 
|  | 139 |  | 
|  | 140 | bridge = find_bridge(resource); | 
|  | 141 | if (!bridge) { | 
|  | 142 | printk(KERN_ERR "Can't find bridge\n"); | 
|  | 143 | return; | 
|  | 144 | } | 
|  | 145 |  | 
|  | 146 | if (!bridge->parent) { | 
|  | 147 | printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name); | 
|  | 148 | return; | 
|  | 149 | } | 
|  | 150 |  | 
|  | 151 | if (!bridge->free_consistent) { | 
|  | 152 | printk(KERN_ERR "free_consistent not supported by bridge %s\n", | 
|  | 153 | bridge->name); | 
|  | 154 | return; | 
|  | 155 | } | 
|  | 156 |  | 
|  | 157 | bridge->free_consistent(bridge->parent, size, vaddr, dma); | 
|  | 158 | } | 
|  | 159 | EXPORT_SYMBOL(vme_free_consistent); | 
|  | 160 |  | 
|  | 161 | /** | 
|  | 162 | * vme_get_size - Helper function returning size of a VME window | 
|  | 163 | * @resource: Pointer to VME slave or master resource. | 
|  | 164 | * | 
|  | 165 | * Determine the size of the VME window provided. This is a helper | 
|  | 166 | * function, wrappering the call to vme_master_get or vme_slave_get | 
|  | 167 | * depending on the type of window resource handed to it. | 
|  | 168 | * | 
|  | 169 | * Return: Size of the window on success, zero on failure. | 
|  | 170 | */ | 
|  | 171 | size_t vme_get_size(struct vme_resource *resource) | 
|  | 172 | { | 
|  | 173 | int enabled, retval; | 
|  | 174 | unsigned long long base, size; | 
|  | 175 | dma_addr_t buf_base; | 
|  | 176 | u32 aspace, cycle, dwidth; | 
|  | 177 |  | 
|  | 178 | switch (resource->type) { | 
|  | 179 | case VME_MASTER: | 
|  | 180 | retval = vme_master_get(resource, &enabled, &base, &size, | 
|  | 181 | &aspace, &cycle, &dwidth); | 
|  | 182 | if (retval) | 
|  | 183 | return 0; | 
|  | 184 |  | 
|  | 185 | return size; | 
|  | 186 | break; | 
|  | 187 | case VME_SLAVE: | 
|  | 188 | retval = vme_slave_get(resource, &enabled, &base, &size, | 
|  | 189 | &buf_base, &aspace, &cycle); | 
|  | 190 | if (retval) | 
|  | 191 | return 0; | 
|  | 192 |  | 
|  | 193 | return size; | 
|  | 194 | break; | 
|  | 195 | case VME_DMA: | 
|  | 196 | return 0; | 
|  | 197 | break; | 
|  | 198 | default: | 
|  | 199 | printk(KERN_ERR "Unknown resource type\n"); | 
|  | 200 | return 0; | 
|  | 201 | break; | 
|  | 202 | } | 
|  | 203 | } | 
|  | 204 | EXPORT_SYMBOL(vme_get_size); | 
|  | 205 |  | 
|  | 206 | int vme_check_window(u32 aspace, unsigned long long vme_base, | 
|  | 207 | unsigned long long size) | 
|  | 208 | { | 
|  | 209 | int retval = 0; | 
|  | 210 |  | 
|  | 211 | if (vme_base + size < size) | 
|  | 212 | return -EINVAL; | 
|  | 213 |  | 
|  | 214 | switch (aspace) { | 
|  | 215 | case VME_A16: | 
|  | 216 | if (vme_base + size > VME_A16_MAX) | 
|  | 217 | retval = -EFAULT; | 
|  | 218 | break; | 
|  | 219 | case VME_A24: | 
|  | 220 | if (vme_base + size > VME_A24_MAX) | 
|  | 221 | retval = -EFAULT; | 
|  | 222 | break; | 
|  | 223 | case VME_A32: | 
|  | 224 | if (vme_base + size > VME_A32_MAX) | 
|  | 225 | retval = -EFAULT; | 
|  | 226 | break; | 
|  | 227 | case VME_A64: | 
|  | 228 | /* The VME_A64_MAX limit is actually U64_MAX + 1 */ | 
|  | 229 | break; | 
|  | 230 | case VME_CRCSR: | 
|  | 231 | if (vme_base + size > VME_CRCSR_MAX) | 
|  | 232 | retval = -EFAULT; | 
|  | 233 | break; | 
|  | 234 | case VME_USER1: | 
|  | 235 | case VME_USER2: | 
|  | 236 | case VME_USER3: | 
|  | 237 | case VME_USER4: | 
|  | 238 | /* User Defined */ | 
|  | 239 | break; | 
|  | 240 | default: | 
|  | 241 | printk(KERN_ERR "Invalid address space\n"); | 
|  | 242 | retval = -EINVAL; | 
|  | 243 | break; | 
|  | 244 | } | 
|  | 245 |  | 
|  | 246 | return retval; | 
|  | 247 | } | 
|  | 248 | EXPORT_SYMBOL(vme_check_window); | 
|  | 249 |  | 
|  | 250 | static u32 vme_get_aspace(int am) | 
|  | 251 | { | 
|  | 252 | switch (am) { | 
|  | 253 | case 0x29: | 
|  | 254 | case 0x2D: | 
|  | 255 | return VME_A16; | 
|  | 256 | case 0x38: | 
|  | 257 | case 0x39: | 
|  | 258 | case 0x3A: | 
|  | 259 | case 0x3B: | 
|  | 260 | case 0x3C: | 
|  | 261 | case 0x3D: | 
|  | 262 | case 0x3E: | 
|  | 263 | case 0x3F: | 
|  | 264 | return VME_A24; | 
|  | 265 | case 0x8: | 
|  | 266 | case 0x9: | 
|  | 267 | case 0xA: | 
|  | 268 | case 0xB: | 
|  | 269 | case 0xC: | 
|  | 270 | case 0xD: | 
|  | 271 | case 0xE: | 
|  | 272 | case 0xF: | 
|  | 273 | return VME_A32; | 
|  | 274 | case 0x0: | 
|  | 275 | case 0x1: | 
|  | 276 | case 0x3: | 
|  | 277 | return VME_A64; | 
|  | 278 | } | 
|  | 279 |  | 
|  | 280 | return 0; | 
|  | 281 | } | 
|  | 282 |  | 
|  | 283 | /** | 
|  | 284 | * vme_slave_request - Request a VME slave window resource. | 
|  | 285 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | 
|  | 286 | * @address: Required VME address space. | 
|  | 287 | * @cycle: Required VME data transfer cycle type. | 
|  | 288 | * | 
|  | 289 | * Request use of a VME window resource capable of being set for the requested | 
|  | 290 | * address space and data transfer cycle. | 
|  | 291 | * | 
|  | 292 | * Return: Pointer to VME resource on success, NULL on failure. | 
|  | 293 | */ | 
|  | 294 | struct vme_resource *vme_slave_request(struct vme_dev *vdev, u32 address, | 
|  | 295 | u32 cycle) | 
|  | 296 | { | 
|  | 297 | struct vme_bridge *bridge; | 
|  | 298 | struct list_head *slave_pos = NULL; | 
|  | 299 | struct vme_slave_resource *allocated_image = NULL; | 
|  | 300 | struct vme_slave_resource *slave_image = NULL; | 
|  | 301 | struct vme_resource *resource = NULL; | 
|  | 302 |  | 
|  | 303 | bridge = vdev->bridge; | 
|  | 304 | if (!bridge) { | 
|  | 305 | printk(KERN_ERR "Can't find VME bus\n"); | 
|  | 306 | goto err_bus; | 
|  | 307 | } | 
|  | 308 |  | 
|  | 309 | /* Loop through slave resources */ | 
|  | 310 | list_for_each(slave_pos, &bridge->slave_resources) { | 
|  | 311 | slave_image = list_entry(slave_pos, | 
|  | 312 | struct vme_slave_resource, list); | 
|  | 313 |  | 
|  | 314 | if (!slave_image) { | 
|  | 315 | printk(KERN_ERR "Registered NULL Slave resource\n"); | 
|  | 316 | continue; | 
|  | 317 | } | 
|  | 318 |  | 
|  | 319 | /* Find an unlocked and compatible image */ | 
|  | 320 | mutex_lock(&slave_image->mtx); | 
|  | 321 | if (((slave_image->address_attr & address) == address) && | 
|  | 322 | ((slave_image->cycle_attr & cycle) == cycle) && | 
|  | 323 | (slave_image->locked == 0)) { | 
|  | 324 |  | 
|  | 325 | slave_image->locked = 1; | 
|  | 326 | mutex_unlock(&slave_image->mtx); | 
|  | 327 | allocated_image = slave_image; | 
|  | 328 | break; | 
|  | 329 | } | 
|  | 330 | mutex_unlock(&slave_image->mtx); | 
|  | 331 | } | 
|  | 332 |  | 
|  | 333 | /* No free image */ | 
|  | 334 | if (!allocated_image) | 
|  | 335 | goto err_image; | 
|  | 336 |  | 
|  | 337 | resource = kmalloc(sizeof(*resource), GFP_KERNEL); | 
|  | 338 | if (!resource) | 
|  | 339 | goto err_alloc; | 
|  | 340 |  | 
|  | 341 | resource->type = VME_SLAVE; | 
|  | 342 | resource->entry = &allocated_image->list; | 
|  | 343 |  | 
|  | 344 | return resource; | 
|  | 345 |  | 
|  | 346 | err_alloc: | 
|  | 347 | /* Unlock image */ | 
|  | 348 | mutex_lock(&slave_image->mtx); | 
|  | 349 | slave_image->locked = 0; | 
|  | 350 | mutex_unlock(&slave_image->mtx); | 
|  | 351 | err_image: | 
|  | 352 | err_bus: | 
|  | 353 | return NULL; | 
|  | 354 | } | 
|  | 355 | EXPORT_SYMBOL(vme_slave_request); | 
|  | 356 |  | 
|  | 357 | /** | 
|  | 358 | * vme_slave_set - Set VME slave window configuration. | 
|  | 359 | * @resource: Pointer to VME slave resource. | 
|  | 360 | * @enabled: State to which the window should be configured. | 
|  | 361 | * @vme_base: Base address for the window. | 
|  | 362 | * @size: Size of the VME window. | 
|  | 363 | * @buf_base: Based address of buffer used to provide VME slave window storage. | 
|  | 364 | * @aspace: VME address space for the VME window. | 
|  | 365 | * @cycle: VME data transfer cycle type for the VME window. | 
|  | 366 | * | 
|  | 367 | * Set configuration for provided VME slave window. | 
|  | 368 | * | 
|  | 369 | * Return: Zero on success, -EINVAL if operation is not supported on this | 
|  | 370 | *         device, if an invalid resource has been provided or invalid | 
|  | 371 | *         attributes are provided. Hardware specific errors may also be | 
|  | 372 | *         returned. | 
|  | 373 | */ | 
|  | 374 | int vme_slave_set(struct vme_resource *resource, int enabled, | 
|  | 375 | unsigned long long vme_base, unsigned long long size, | 
|  | 376 | dma_addr_t buf_base, u32 aspace, u32 cycle) | 
|  | 377 | { | 
|  | 378 | struct vme_bridge *bridge = find_bridge(resource); | 
|  | 379 | struct vme_slave_resource *image; | 
|  | 380 | int retval; | 
|  | 381 |  | 
|  | 382 | if (resource->type != VME_SLAVE) { | 
|  | 383 | printk(KERN_ERR "Not a slave resource\n"); | 
|  | 384 | return -EINVAL; | 
|  | 385 | } | 
|  | 386 |  | 
|  | 387 | image = list_entry(resource->entry, struct vme_slave_resource, list); | 
|  | 388 |  | 
|  | 389 | if (!bridge->slave_set) { | 
|  | 390 | printk(KERN_ERR "Function not supported\n"); | 
|  | 391 | return -ENOSYS; | 
|  | 392 | } | 
|  | 393 |  | 
|  | 394 | if (!(((image->address_attr & aspace) == aspace) && | 
|  | 395 | ((image->cycle_attr & cycle) == cycle))) { | 
|  | 396 | printk(KERN_ERR "Invalid attributes\n"); | 
|  | 397 | return -EINVAL; | 
|  | 398 | } | 
|  | 399 |  | 
|  | 400 | retval = vme_check_window(aspace, vme_base, size); | 
|  | 401 | if (retval) | 
|  | 402 | return retval; | 
|  | 403 |  | 
|  | 404 | return bridge->slave_set(image, enabled, vme_base, size, buf_base, | 
|  | 405 | aspace, cycle); | 
|  | 406 | } | 
|  | 407 | EXPORT_SYMBOL(vme_slave_set); | 
|  | 408 |  | 
|  | 409 | /** | 
|  | 410 | * vme_slave_get - Retrieve VME slave window configuration. | 
|  | 411 | * @resource: Pointer to VME slave resource. | 
|  | 412 | * @enabled: Pointer to variable for storing state. | 
|  | 413 | * @vme_base: Pointer to variable for storing window base address. | 
|  | 414 | * @size: Pointer to variable for storing window size. | 
|  | 415 | * @buf_base: Pointer to variable for storing slave buffer base address. | 
|  | 416 | * @aspace: Pointer to variable for storing VME address space. | 
|  | 417 | * @cycle: Pointer to variable for storing VME data transfer cycle type. | 
|  | 418 | * | 
|  | 419 | * Return configuration for provided VME slave window. | 
|  | 420 | * | 
|  | 421 | * Return: Zero on success, -EINVAL if operation is not supported on this | 
|  | 422 | *         device or if an invalid resource has been provided. | 
|  | 423 | */ | 
|  | 424 | int vme_slave_get(struct vme_resource *resource, int *enabled, | 
|  | 425 | unsigned long long *vme_base, unsigned long long *size, | 
|  | 426 | dma_addr_t *buf_base, u32 *aspace, u32 *cycle) | 
|  | 427 | { | 
|  | 428 | struct vme_bridge *bridge = find_bridge(resource); | 
|  | 429 | struct vme_slave_resource *image; | 
|  | 430 |  | 
|  | 431 | if (resource->type != VME_SLAVE) { | 
|  | 432 | printk(KERN_ERR "Not a slave resource\n"); | 
|  | 433 | return -EINVAL; | 
|  | 434 | } | 
|  | 435 |  | 
|  | 436 | image = list_entry(resource->entry, struct vme_slave_resource, list); | 
|  | 437 |  | 
|  | 438 | if (!bridge->slave_get) { | 
|  | 439 | printk(KERN_ERR "vme_slave_get not supported\n"); | 
|  | 440 | return -EINVAL; | 
|  | 441 | } | 
|  | 442 |  | 
|  | 443 | return bridge->slave_get(image, enabled, vme_base, size, buf_base, | 
|  | 444 | aspace, cycle); | 
|  | 445 | } | 
|  | 446 | EXPORT_SYMBOL(vme_slave_get); | 
|  | 447 |  | 
|  | 448 | /** | 
|  | 449 | * vme_slave_free - Free VME slave window | 
|  | 450 | * @resource: Pointer to VME slave resource. | 
|  | 451 | * | 
|  | 452 | * Free the provided slave resource so that it may be reallocated. | 
|  | 453 | */ | 
|  | 454 | void vme_slave_free(struct vme_resource *resource) | 
|  | 455 | { | 
|  | 456 | struct vme_slave_resource *slave_image; | 
|  | 457 |  | 
|  | 458 | if (resource->type != VME_SLAVE) { | 
|  | 459 | printk(KERN_ERR "Not a slave resource\n"); | 
|  | 460 | return; | 
|  | 461 | } | 
|  | 462 |  | 
|  | 463 | slave_image = list_entry(resource->entry, struct vme_slave_resource, | 
|  | 464 | list); | 
|  | 465 | if (!slave_image) { | 
|  | 466 | printk(KERN_ERR "Can't find slave resource\n"); | 
|  | 467 | return; | 
|  | 468 | } | 
|  | 469 |  | 
|  | 470 | /* Unlock image */ | 
|  | 471 | mutex_lock(&slave_image->mtx); | 
|  | 472 | if (slave_image->locked == 0) | 
|  | 473 | printk(KERN_ERR "Image is already free\n"); | 
|  | 474 |  | 
|  | 475 | slave_image->locked = 0; | 
|  | 476 | mutex_unlock(&slave_image->mtx); | 
|  | 477 |  | 
|  | 478 | /* Free up resource memory */ | 
|  | 479 | kfree(resource); | 
|  | 480 | } | 
|  | 481 | EXPORT_SYMBOL(vme_slave_free); | 
|  | 482 |  | 
|  | 483 | /** | 
|  | 484 | * vme_master_request - Request a VME master window resource. | 
|  | 485 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | 
|  | 486 | * @address: Required VME address space. | 
|  | 487 | * @cycle: Required VME data transfer cycle type. | 
|  | 488 | * @dwidth: Required VME data transfer width. | 
|  | 489 | * | 
|  | 490 | * Request use of a VME window resource capable of being set for the requested | 
|  | 491 | * address space, data transfer cycle and width. | 
|  | 492 | * | 
|  | 493 | * Return: Pointer to VME resource on success, NULL on failure. | 
|  | 494 | */ | 
|  | 495 | struct vme_resource *vme_master_request(struct vme_dev *vdev, u32 address, | 
|  | 496 | u32 cycle, u32 dwidth) | 
|  | 497 | { | 
|  | 498 | struct vme_bridge *bridge; | 
|  | 499 | struct list_head *master_pos = NULL; | 
|  | 500 | struct vme_master_resource *allocated_image = NULL; | 
|  | 501 | struct vme_master_resource *master_image = NULL; | 
|  | 502 | struct vme_resource *resource = NULL; | 
|  | 503 |  | 
|  | 504 | bridge = vdev->bridge; | 
|  | 505 | if (!bridge) { | 
|  | 506 | printk(KERN_ERR "Can't find VME bus\n"); | 
|  | 507 | goto err_bus; | 
|  | 508 | } | 
|  | 509 |  | 
|  | 510 | /* Loop through master resources */ | 
|  | 511 | list_for_each(master_pos, &bridge->master_resources) { | 
|  | 512 | master_image = list_entry(master_pos, | 
|  | 513 | struct vme_master_resource, list); | 
|  | 514 |  | 
|  | 515 | if (!master_image) { | 
|  | 516 | printk(KERN_WARNING "Registered NULL master resource\n"); | 
|  | 517 | continue; | 
|  | 518 | } | 
|  | 519 |  | 
|  | 520 | /* Find an unlocked and compatible image */ | 
|  | 521 | spin_lock(&master_image->lock); | 
|  | 522 | if (((master_image->address_attr & address) == address) && | 
|  | 523 | ((master_image->cycle_attr & cycle) == cycle) && | 
|  | 524 | ((master_image->width_attr & dwidth) == dwidth) && | 
|  | 525 | (master_image->locked == 0)) { | 
|  | 526 |  | 
|  | 527 | master_image->locked = 1; | 
|  | 528 | spin_unlock(&master_image->lock); | 
|  | 529 | allocated_image = master_image; | 
|  | 530 | break; | 
|  | 531 | } | 
|  | 532 | spin_unlock(&master_image->lock); | 
|  | 533 | } | 
|  | 534 |  | 
|  | 535 | /* Check to see if we found a resource */ | 
|  | 536 | if (!allocated_image) { | 
|  | 537 | printk(KERN_ERR "Can't find a suitable resource\n"); | 
|  | 538 | goto err_image; | 
|  | 539 | } | 
|  | 540 |  | 
|  | 541 | resource = kmalloc(sizeof(*resource), GFP_KERNEL); | 
|  | 542 | if (!resource) | 
|  | 543 | goto err_alloc; | 
|  | 544 |  | 
|  | 545 | resource->type = VME_MASTER; | 
|  | 546 | resource->entry = &allocated_image->list; | 
|  | 547 |  | 
|  | 548 | return resource; | 
|  | 549 |  | 
|  | 550 | err_alloc: | 
|  | 551 | /* Unlock image */ | 
|  | 552 | spin_lock(&master_image->lock); | 
|  | 553 | master_image->locked = 0; | 
|  | 554 | spin_unlock(&master_image->lock); | 
|  | 555 | err_image: | 
|  | 556 | err_bus: | 
|  | 557 | return NULL; | 
|  | 558 | } | 
|  | 559 | EXPORT_SYMBOL(vme_master_request); | 
|  | 560 |  | 
|  | 561 | /** | 
|  | 562 | * vme_master_set - Set VME master window configuration. | 
|  | 563 | * @resource: Pointer to VME master resource. | 
|  | 564 | * @enabled: State to which the window should be configured. | 
|  | 565 | * @vme_base: Base address for the window. | 
|  | 566 | * @size: Size of the VME window. | 
|  | 567 | * @aspace: VME address space for the VME window. | 
|  | 568 | * @cycle: VME data transfer cycle type for the VME window. | 
|  | 569 | * @dwidth: VME data transfer width for the VME window. | 
|  | 570 | * | 
|  | 571 | * Set configuration for provided VME master window. | 
|  | 572 | * | 
|  | 573 | * Return: Zero on success, -EINVAL if operation is not supported on this | 
|  | 574 | *         device, if an invalid resource has been provided or invalid | 
|  | 575 | *         attributes are provided. Hardware specific errors may also be | 
|  | 576 | *         returned. | 
|  | 577 | */ | 
|  | 578 | int vme_master_set(struct vme_resource *resource, int enabled, | 
|  | 579 | unsigned long long vme_base, unsigned long long size, u32 aspace, | 
|  | 580 | u32 cycle, u32 dwidth) | 
|  | 581 | { | 
|  | 582 | struct vme_bridge *bridge = find_bridge(resource); | 
|  | 583 | struct vme_master_resource *image; | 
|  | 584 | int retval; | 
|  | 585 |  | 
|  | 586 | if (resource->type != VME_MASTER) { | 
|  | 587 | printk(KERN_ERR "Not a master resource\n"); | 
|  | 588 | return -EINVAL; | 
|  | 589 | } | 
|  | 590 |  | 
|  | 591 | image = list_entry(resource->entry, struct vme_master_resource, list); | 
|  | 592 |  | 
|  | 593 | if (!bridge->master_set) { | 
|  | 594 | printk(KERN_WARNING "vme_master_set not supported\n"); | 
|  | 595 | return -EINVAL; | 
|  | 596 | } | 
|  | 597 |  | 
|  | 598 | if (!(((image->address_attr & aspace) == aspace) && | 
|  | 599 | ((image->cycle_attr & cycle) == cycle) && | 
|  | 600 | ((image->width_attr & dwidth) == dwidth))) { | 
|  | 601 | printk(KERN_WARNING "Invalid attributes\n"); | 
|  | 602 | return -EINVAL; | 
|  | 603 | } | 
|  | 604 |  | 
|  | 605 | retval = vme_check_window(aspace, vme_base, size); | 
|  | 606 | if (retval) | 
|  | 607 | return retval; | 
|  | 608 |  | 
|  | 609 | return bridge->master_set(image, enabled, vme_base, size, aspace, | 
|  | 610 | cycle, dwidth); | 
|  | 611 | } | 
|  | 612 | EXPORT_SYMBOL(vme_master_set); | 
|  | 613 |  | 
|  | 614 | /** | 
|  | 615 | * vme_master_get - Retrieve VME master window configuration. | 
|  | 616 | * @resource: Pointer to VME master resource. | 
|  | 617 | * @enabled: Pointer to variable for storing state. | 
|  | 618 | * @vme_base: Pointer to variable for storing window base address. | 
|  | 619 | * @size: Pointer to variable for storing window size. | 
|  | 620 | * @aspace: Pointer to variable for storing VME address space. | 
|  | 621 | * @cycle: Pointer to variable for storing VME data transfer cycle type. | 
|  | 622 | * @dwidth: Pointer to variable for storing VME data transfer width. | 
|  | 623 | * | 
|  | 624 | * Return configuration for provided VME master window. | 
|  | 625 | * | 
|  | 626 | * Return: Zero on success, -EINVAL if operation is not supported on this | 
|  | 627 | *         device or if an invalid resource has been provided. | 
|  | 628 | */ | 
|  | 629 | int vme_master_get(struct vme_resource *resource, int *enabled, | 
|  | 630 | unsigned long long *vme_base, unsigned long long *size, u32 *aspace, | 
|  | 631 | u32 *cycle, u32 *dwidth) | 
|  | 632 | { | 
|  | 633 | struct vme_bridge *bridge = find_bridge(resource); | 
|  | 634 | struct vme_master_resource *image; | 
|  | 635 |  | 
|  | 636 | if (resource->type != VME_MASTER) { | 
|  | 637 | printk(KERN_ERR "Not a master resource\n"); | 
|  | 638 | return -EINVAL; | 
|  | 639 | } | 
|  | 640 |  | 
|  | 641 | image = list_entry(resource->entry, struct vme_master_resource, list); | 
|  | 642 |  | 
|  | 643 | if (!bridge->master_get) { | 
|  | 644 | printk(KERN_WARNING "%s not supported\n", __func__); | 
|  | 645 | return -EINVAL; | 
|  | 646 | } | 
|  | 647 |  | 
|  | 648 | return bridge->master_get(image, enabled, vme_base, size, aspace, | 
|  | 649 | cycle, dwidth); | 
|  | 650 | } | 
|  | 651 | EXPORT_SYMBOL(vme_master_get); | 
|  | 652 |  | 
|  | 653 | /** | 
|  | 654 | * vme_master_write - Read data from VME space into a buffer. | 
|  | 655 | * @resource: Pointer to VME master resource. | 
|  | 656 | * @buf: Pointer to buffer where data should be transferred. | 
|  | 657 | * @count: Number of bytes to transfer. | 
|  | 658 | * @offset: Offset into VME master window at which to start transfer. | 
|  | 659 | * | 
|  | 660 | * Perform read of count bytes of data from location on VME bus which maps into | 
|  | 661 | * the VME master window at offset to buf. | 
|  | 662 | * | 
|  | 663 | * Return: Number of bytes read, -EINVAL if resource is not a VME master | 
|  | 664 | *         resource or read operation is not supported. -EFAULT returned if | 
|  | 665 | *         invalid offset is provided. Hardware specific errors may also be | 
|  | 666 | *         returned. | 
|  | 667 | */ | 
|  | 668 | ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count, | 
|  | 669 | loff_t offset) | 
|  | 670 | { | 
|  | 671 | struct vme_bridge *bridge = find_bridge(resource); | 
|  | 672 | struct vme_master_resource *image; | 
|  | 673 | size_t length; | 
|  | 674 |  | 
|  | 675 | if (!bridge->master_read) { | 
|  | 676 | printk(KERN_WARNING "Reading from resource not supported\n"); | 
|  | 677 | return -EINVAL; | 
|  | 678 | } | 
|  | 679 |  | 
|  | 680 | if (resource->type != VME_MASTER) { | 
|  | 681 | printk(KERN_ERR "Not a master resource\n"); | 
|  | 682 | return -EINVAL; | 
|  | 683 | } | 
|  | 684 |  | 
|  | 685 | image = list_entry(resource->entry, struct vme_master_resource, list); | 
|  | 686 |  | 
|  | 687 | length = vme_get_size(resource); | 
|  | 688 |  | 
|  | 689 | if (offset > length) { | 
|  | 690 | printk(KERN_WARNING "Invalid Offset\n"); | 
|  | 691 | return -EFAULT; | 
|  | 692 | } | 
|  | 693 |  | 
|  | 694 | if ((offset + count) > length) | 
|  | 695 | count = length - offset; | 
|  | 696 |  | 
|  | 697 | return bridge->master_read(image, buf, count, offset); | 
|  | 698 |  | 
|  | 699 | } | 
|  | 700 | EXPORT_SYMBOL(vme_master_read); | 
|  | 701 |  | 
|  | 702 | /** | 
|  | 703 | * vme_master_write - Write data out to VME space from a buffer. | 
|  | 704 | * @resource: Pointer to VME master resource. | 
|  | 705 | * @buf: Pointer to buffer holding data to transfer. | 
|  | 706 | * @count: Number of bytes to transfer. | 
|  | 707 | * @offset: Offset into VME master window at which to start transfer. | 
|  | 708 | * | 
|  | 709 | * Perform write of count bytes of data from buf to location on VME bus which | 
|  | 710 | * maps into the VME master window at offset. | 
|  | 711 | * | 
|  | 712 | * Return: Number of bytes written, -EINVAL if resource is not a VME master | 
|  | 713 | *         resource or write operation is not supported. -EFAULT returned if | 
|  | 714 | *         invalid offset is provided. Hardware specific errors may also be | 
|  | 715 | *         returned. | 
|  | 716 | */ | 
|  | 717 | ssize_t vme_master_write(struct vme_resource *resource, void *buf, | 
|  | 718 | size_t count, loff_t offset) | 
|  | 719 | { | 
|  | 720 | struct vme_bridge *bridge = find_bridge(resource); | 
|  | 721 | struct vme_master_resource *image; | 
|  | 722 | size_t length; | 
|  | 723 |  | 
|  | 724 | if (!bridge->master_write) { | 
|  | 725 | printk(KERN_WARNING "Writing to resource not supported\n"); | 
|  | 726 | return -EINVAL; | 
|  | 727 | } | 
|  | 728 |  | 
|  | 729 | if (resource->type != VME_MASTER) { | 
|  | 730 | printk(KERN_ERR "Not a master resource\n"); | 
|  | 731 | return -EINVAL; | 
|  | 732 | } | 
|  | 733 |  | 
|  | 734 | image = list_entry(resource->entry, struct vme_master_resource, list); | 
|  | 735 |  | 
|  | 736 | length = vme_get_size(resource); | 
|  | 737 |  | 
|  | 738 | if (offset > length) { | 
|  | 739 | printk(KERN_WARNING "Invalid Offset\n"); | 
|  | 740 | return -EFAULT; | 
|  | 741 | } | 
|  | 742 |  | 
|  | 743 | if ((offset + count) > length) | 
|  | 744 | count = length - offset; | 
|  | 745 |  | 
|  | 746 | return bridge->master_write(image, buf, count, offset); | 
|  | 747 | } | 
|  | 748 | EXPORT_SYMBOL(vme_master_write); | 
|  | 749 |  | 
|  | 750 | /** | 
|  | 751 | * vme_master_rmw - Perform read-modify-write cycle. | 
|  | 752 | * @resource: Pointer to VME master resource. | 
|  | 753 | * @mask: Bits to be compared and swapped in operation. | 
|  | 754 | * @compare: Bits to be compared with data read from offset. | 
|  | 755 | * @swap: Bits to be swapped in data read from offset. | 
|  | 756 | * @offset: Offset into VME master window at which to perform operation. | 
|  | 757 | * | 
|  | 758 | * Perform read-modify-write cycle on provided location: | 
|  | 759 | * - Location on VME bus is read. | 
|  | 760 | * - Bits selected by mask are compared with compare. | 
|  | 761 | * - Where a selected bit matches that in compare and are selected in swap, | 
|  | 762 | * the bit is swapped. | 
|  | 763 | * - Result written back to location on VME bus. | 
|  | 764 | * | 
|  | 765 | * Return: Bytes written on success, -EINVAL if resource is not a VME master | 
|  | 766 | *         resource or RMW operation is not supported. Hardware specific | 
|  | 767 | *         errors may also be returned. | 
|  | 768 | */ | 
|  | 769 | unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask, | 
|  | 770 | unsigned int compare, unsigned int swap, loff_t offset) | 
|  | 771 | { | 
|  | 772 | struct vme_bridge *bridge = find_bridge(resource); | 
|  | 773 | struct vme_master_resource *image; | 
|  | 774 |  | 
|  | 775 | if (!bridge->master_rmw) { | 
|  | 776 | printk(KERN_WARNING "Writing to resource not supported\n"); | 
|  | 777 | return -EINVAL; | 
|  | 778 | } | 
|  | 779 |  | 
|  | 780 | if (resource->type != VME_MASTER) { | 
|  | 781 | printk(KERN_ERR "Not a master resource\n"); | 
|  | 782 | return -EINVAL; | 
|  | 783 | } | 
|  | 784 |  | 
|  | 785 | image = list_entry(resource->entry, struct vme_master_resource, list); | 
|  | 786 |  | 
|  | 787 | return bridge->master_rmw(image, mask, compare, swap, offset); | 
|  | 788 | } | 
|  | 789 | EXPORT_SYMBOL(vme_master_rmw); | 
|  | 790 |  | 
|  | 791 | /** | 
|  | 792 | * vme_master_mmap - Mmap region of VME master window. | 
|  | 793 | * @resource: Pointer to VME master resource. | 
|  | 794 | * @vma: Pointer to definition of user mapping. | 
|  | 795 | * | 
|  | 796 | * Memory map a region of the VME master window into user space. | 
|  | 797 | * | 
|  | 798 | * Return: Zero on success, -EINVAL if resource is not a VME master | 
|  | 799 | *         resource or -EFAULT if map exceeds window size. Other generic mmap | 
|  | 800 | *         errors may also be returned. | 
|  | 801 | */ | 
|  | 802 | int vme_master_mmap(struct vme_resource *resource, struct vm_area_struct *vma) | 
|  | 803 | { | 
|  | 804 | struct vme_master_resource *image; | 
|  | 805 | phys_addr_t phys_addr; | 
|  | 806 | unsigned long vma_size; | 
|  | 807 |  | 
|  | 808 | if (resource->type != VME_MASTER) { | 
|  | 809 | pr_err("Not a master resource\n"); | 
|  | 810 | return -EINVAL; | 
|  | 811 | } | 
|  | 812 |  | 
|  | 813 | image = list_entry(resource->entry, struct vme_master_resource, list); | 
|  | 814 | phys_addr = image->bus_resource.start + (vma->vm_pgoff << PAGE_SHIFT); | 
|  | 815 | vma_size = vma->vm_end - vma->vm_start; | 
|  | 816 |  | 
|  | 817 | if (phys_addr + vma_size > image->bus_resource.end + 1) { | 
|  | 818 | pr_err("Map size cannot exceed the window size\n"); | 
|  | 819 | return -EFAULT; | 
|  | 820 | } | 
|  | 821 |  | 
|  | 822 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | 
|  | 823 |  | 
|  | 824 | return vm_iomap_memory(vma, phys_addr, vma->vm_end - vma->vm_start); | 
|  | 825 | } | 
|  | 826 | EXPORT_SYMBOL(vme_master_mmap); | 
|  | 827 |  | 
|  | 828 | /** | 
|  | 829 | * vme_master_free - Free VME master window | 
|  | 830 | * @resource: Pointer to VME master resource. | 
|  | 831 | * | 
|  | 832 | * Free the provided master resource so that it may be reallocated. | 
|  | 833 | */ | 
|  | 834 | void vme_master_free(struct vme_resource *resource) | 
|  | 835 | { | 
|  | 836 | struct vme_master_resource *master_image; | 
|  | 837 |  | 
|  | 838 | if (resource->type != VME_MASTER) { | 
|  | 839 | printk(KERN_ERR "Not a master resource\n"); | 
|  | 840 | return; | 
|  | 841 | } | 
|  | 842 |  | 
|  | 843 | master_image = list_entry(resource->entry, struct vme_master_resource, | 
|  | 844 | list); | 
|  | 845 | if (!master_image) { | 
|  | 846 | printk(KERN_ERR "Can't find master resource\n"); | 
|  | 847 | return; | 
|  | 848 | } | 
|  | 849 |  | 
|  | 850 | /* Unlock image */ | 
|  | 851 | spin_lock(&master_image->lock); | 
|  | 852 | if (master_image->locked == 0) | 
|  | 853 | printk(KERN_ERR "Image is already free\n"); | 
|  | 854 |  | 
|  | 855 | master_image->locked = 0; | 
|  | 856 | spin_unlock(&master_image->lock); | 
|  | 857 |  | 
|  | 858 | /* Free up resource memory */ | 
|  | 859 | kfree(resource); | 
|  | 860 | } | 
|  | 861 | EXPORT_SYMBOL(vme_master_free); | 
|  | 862 |  | 
|  | 863 | /** | 
|  | 864 | * vme_dma_request - Request a DMA controller. | 
|  | 865 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | 
|  | 866 | * @route: Required src/destination combination. | 
|  | 867 | * | 
|  | 868 | * Request a VME DMA controller with capability to perform transfers bewteen | 
|  | 869 | * requested source/destination combination. | 
|  | 870 | * | 
|  | 871 | * Return: Pointer to VME DMA resource on success, NULL on failure. | 
|  | 872 | */ | 
|  | 873 | struct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 route) | 
|  | 874 | { | 
|  | 875 | struct vme_bridge *bridge; | 
|  | 876 | struct list_head *dma_pos = NULL; | 
|  | 877 | struct vme_dma_resource *allocated_ctrlr = NULL; | 
|  | 878 | struct vme_dma_resource *dma_ctrlr = NULL; | 
|  | 879 | struct vme_resource *resource = NULL; | 
|  | 880 |  | 
|  | 881 | /* XXX Not checking resource attributes */ | 
|  | 882 | printk(KERN_ERR "No VME resource Attribute tests done\n"); | 
|  | 883 |  | 
|  | 884 | bridge = vdev->bridge; | 
|  | 885 | if (!bridge) { | 
|  | 886 | printk(KERN_ERR "Can't find VME bus\n"); | 
|  | 887 | goto err_bus; | 
|  | 888 | } | 
|  | 889 |  | 
|  | 890 | /* Loop through DMA resources */ | 
|  | 891 | list_for_each(dma_pos, &bridge->dma_resources) { | 
|  | 892 | dma_ctrlr = list_entry(dma_pos, | 
|  | 893 | struct vme_dma_resource, list); | 
|  | 894 | if (!dma_ctrlr) { | 
|  | 895 | printk(KERN_ERR "Registered NULL DMA resource\n"); | 
|  | 896 | continue; | 
|  | 897 | } | 
|  | 898 |  | 
|  | 899 | /* Find an unlocked and compatible controller */ | 
|  | 900 | mutex_lock(&dma_ctrlr->mtx); | 
|  | 901 | if (((dma_ctrlr->route_attr & route) == route) && | 
|  | 902 | (dma_ctrlr->locked == 0)) { | 
|  | 903 |  | 
|  | 904 | dma_ctrlr->locked = 1; | 
|  | 905 | mutex_unlock(&dma_ctrlr->mtx); | 
|  | 906 | allocated_ctrlr = dma_ctrlr; | 
|  | 907 | break; | 
|  | 908 | } | 
|  | 909 | mutex_unlock(&dma_ctrlr->mtx); | 
|  | 910 | } | 
|  | 911 |  | 
|  | 912 | /* Check to see if we found a resource */ | 
|  | 913 | if (!allocated_ctrlr) | 
|  | 914 | goto err_ctrlr; | 
|  | 915 |  | 
|  | 916 | resource = kmalloc(sizeof(*resource), GFP_KERNEL); | 
|  | 917 | if (!resource) | 
|  | 918 | goto err_alloc; | 
|  | 919 |  | 
|  | 920 | resource->type = VME_DMA; | 
|  | 921 | resource->entry = &allocated_ctrlr->list; | 
|  | 922 |  | 
|  | 923 | return resource; | 
|  | 924 |  | 
|  | 925 | err_alloc: | 
|  | 926 | /* Unlock image */ | 
|  | 927 | mutex_lock(&dma_ctrlr->mtx); | 
|  | 928 | dma_ctrlr->locked = 0; | 
|  | 929 | mutex_unlock(&dma_ctrlr->mtx); | 
|  | 930 | err_ctrlr: | 
|  | 931 | err_bus: | 
|  | 932 | return NULL; | 
|  | 933 | } | 
|  | 934 | EXPORT_SYMBOL(vme_dma_request); | 
|  | 935 |  | 
|  | 936 | /** | 
|  | 937 | * vme_new_dma_list - Create new VME DMA list. | 
|  | 938 | * @resource: Pointer to VME DMA resource. | 
|  | 939 | * | 
|  | 940 | * Create a new VME DMA list. It is the responsibility of the user to free | 
|  | 941 | * the list once it is no longer required with vme_dma_list_free(). | 
|  | 942 | * | 
|  | 943 | * Return: Pointer to new VME DMA list, NULL on allocation failure or invalid | 
|  | 944 | *         VME DMA resource. | 
|  | 945 | */ | 
|  | 946 | struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource) | 
|  | 947 | { | 
|  | 948 | struct vme_dma_list *dma_list; | 
|  | 949 |  | 
|  | 950 | if (resource->type != VME_DMA) { | 
|  | 951 | printk(KERN_ERR "Not a DMA resource\n"); | 
|  | 952 | return NULL; | 
|  | 953 | } | 
|  | 954 |  | 
|  | 955 | dma_list = kmalloc(sizeof(*dma_list), GFP_KERNEL); | 
|  | 956 | if (!dma_list) | 
|  | 957 | return NULL; | 
|  | 958 |  | 
|  | 959 | INIT_LIST_HEAD(&dma_list->entries); | 
|  | 960 | dma_list->parent = list_entry(resource->entry, | 
|  | 961 | struct vme_dma_resource, | 
|  | 962 | list); | 
|  | 963 | mutex_init(&dma_list->mtx); | 
|  | 964 |  | 
|  | 965 | return dma_list; | 
|  | 966 | } | 
|  | 967 | EXPORT_SYMBOL(vme_new_dma_list); | 
|  | 968 |  | 
|  | 969 | /** | 
|  | 970 | * vme_dma_pattern_attribute - Create "Pattern" type VME DMA list attribute. | 
|  | 971 | * @pattern: Value to use used as pattern | 
|  | 972 | * @type: Type of pattern to be written. | 
|  | 973 | * | 
|  | 974 | * Create VME DMA list attribute for pattern generation. It is the | 
|  | 975 | * responsibility of the user to free used attributes using | 
|  | 976 | * vme_dma_free_attribute(). | 
|  | 977 | * | 
|  | 978 | * Return: Pointer to VME DMA attribute, NULL on failure. | 
|  | 979 | */ | 
|  | 980 | struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type) | 
|  | 981 | { | 
|  | 982 | struct vme_dma_attr *attributes; | 
|  | 983 | struct vme_dma_pattern *pattern_attr; | 
|  | 984 |  | 
|  | 985 | attributes = kmalloc(sizeof(*attributes), GFP_KERNEL); | 
|  | 986 | if (!attributes) | 
|  | 987 | goto err_attr; | 
|  | 988 |  | 
|  | 989 | pattern_attr = kmalloc(sizeof(*pattern_attr), GFP_KERNEL); | 
|  | 990 | if (!pattern_attr) | 
|  | 991 | goto err_pat; | 
|  | 992 |  | 
|  | 993 | attributes->type = VME_DMA_PATTERN; | 
|  | 994 | attributes->private = (void *)pattern_attr; | 
|  | 995 |  | 
|  | 996 | pattern_attr->pattern = pattern; | 
|  | 997 | pattern_attr->type = type; | 
|  | 998 |  | 
|  | 999 | return attributes; | 
|  | 1000 |  | 
|  | 1001 | err_pat: | 
|  | 1002 | kfree(attributes); | 
|  | 1003 | err_attr: | 
|  | 1004 | return NULL; | 
|  | 1005 | } | 
|  | 1006 | EXPORT_SYMBOL(vme_dma_pattern_attribute); | 
|  | 1007 |  | 
|  | 1008 | /** | 
|  | 1009 | * vme_dma_pci_attribute - Create "PCI" type VME DMA list attribute. | 
|  | 1010 | * @address: PCI base address for DMA transfer. | 
|  | 1011 | * | 
|  | 1012 | * Create VME DMA list attribute pointing to a location on PCI for DMA | 
|  | 1013 | * transfers. It is the responsibility of the user to free used attributes | 
|  | 1014 | * using vme_dma_free_attribute(). | 
|  | 1015 | * | 
|  | 1016 | * Return: Pointer to VME DMA attribute, NULL on failure. | 
|  | 1017 | */ | 
|  | 1018 | struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address) | 
|  | 1019 | { | 
|  | 1020 | struct vme_dma_attr *attributes; | 
|  | 1021 | struct vme_dma_pci *pci_attr; | 
|  | 1022 |  | 
|  | 1023 | /* XXX Run some sanity checks here */ | 
|  | 1024 |  | 
|  | 1025 | attributes = kmalloc(sizeof(*attributes), GFP_KERNEL); | 
|  | 1026 | if (!attributes) | 
|  | 1027 | goto err_attr; | 
|  | 1028 |  | 
|  | 1029 | pci_attr = kmalloc(sizeof(*pci_attr), GFP_KERNEL); | 
|  | 1030 | if (!pci_attr) | 
|  | 1031 | goto err_pci; | 
|  | 1032 |  | 
|  | 1033 | attributes->type = VME_DMA_PCI; | 
|  | 1034 | attributes->private = (void *)pci_attr; | 
|  | 1035 |  | 
|  | 1036 | pci_attr->address = address; | 
|  | 1037 |  | 
|  | 1038 | return attributes; | 
|  | 1039 |  | 
|  | 1040 | err_pci: | 
|  | 1041 | kfree(attributes); | 
|  | 1042 | err_attr: | 
|  | 1043 | return NULL; | 
|  | 1044 | } | 
|  | 1045 | EXPORT_SYMBOL(vme_dma_pci_attribute); | 
|  | 1046 |  | 
|  | 1047 | /** | 
|  | 1048 | * vme_dma_vme_attribute - Create "VME" type VME DMA list attribute. | 
|  | 1049 | * @address: VME base address for DMA transfer. | 
|  | 1050 | * @aspace: VME address space to use for DMA transfer. | 
|  | 1051 | * @cycle: VME bus cycle to use for DMA transfer. | 
|  | 1052 | * @dwidth: VME data width to use for DMA transfer. | 
|  | 1053 | * | 
|  | 1054 | * Create VME DMA list attribute pointing to a location on the VME bus for DMA | 
|  | 1055 | * transfers. It is the responsibility of the user to free used attributes | 
|  | 1056 | * using vme_dma_free_attribute(). | 
|  | 1057 | * | 
|  | 1058 | * Return: Pointer to VME DMA attribute, NULL on failure. | 
|  | 1059 | */ | 
|  | 1060 | struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address, | 
|  | 1061 | u32 aspace, u32 cycle, u32 dwidth) | 
|  | 1062 | { | 
|  | 1063 | struct vme_dma_attr *attributes; | 
|  | 1064 | struct vme_dma_vme *vme_attr; | 
|  | 1065 |  | 
|  | 1066 | attributes = kmalloc(sizeof(*attributes), GFP_KERNEL); | 
|  | 1067 | if (!attributes) | 
|  | 1068 | goto err_attr; | 
|  | 1069 |  | 
|  | 1070 | vme_attr = kmalloc(sizeof(*vme_attr), GFP_KERNEL); | 
|  | 1071 | if (!vme_attr) | 
|  | 1072 | goto err_vme; | 
|  | 1073 |  | 
|  | 1074 | attributes->type = VME_DMA_VME; | 
|  | 1075 | attributes->private = (void *)vme_attr; | 
|  | 1076 |  | 
|  | 1077 | vme_attr->address = address; | 
|  | 1078 | vme_attr->aspace = aspace; | 
|  | 1079 | vme_attr->cycle = cycle; | 
|  | 1080 | vme_attr->dwidth = dwidth; | 
|  | 1081 |  | 
|  | 1082 | return attributes; | 
|  | 1083 |  | 
|  | 1084 | err_vme: | 
|  | 1085 | kfree(attributes); | 
|  | 1086 | err_attr: | 
|  | 1087 | return NULL; | 
|  | 1088 | } | 
|  | 1089 | EXPORT_SYMBOL(vme_dma_vme_attribute); | 
|  | 1090 |  | 
|  | 1091 | /** | 
|  | 1092 | * vme_dma_free_attribute - Free DMA list attribute. | 
|  | 1093 | * @attributes: Pointer to DMA list attribute. | 
|  | 1094 | * | 
|  | 1095 | * Free VME DMA list attribute. VME DMA list attributes can be safely freed | 
|  | 1096 | * once vme_dma_list_add() has returned. | 
|  | 1097 | */ | 
|  | 1098 | void vme_dma_free_attribute(struct vme_dma_attr *attributes) | 
|  | 1099 | { | 
|  | 1100 | kfree(attributes->private); | 
|  | 1101 | kfree(attributes); | 
|  | 1102 | } | 
|  | 1103 | EXPORT_SYMBOL(vme_dma_free_attribute); | 
|  | 1104 |  | 
|  | 1105 | /** | 
|  | 1106 | * vme_dma_list_add - Add enty to a VME DMA list. | 
|  | 1107 | * @list: Pointer to VME list. | 
|  | 1108 | * @src: Pointer to DMA list attribute to use as source. | 
|  | 1109 | * @dest: Pointer to DMA list attribute to use as destination. | 
|  | 1110 | * @count: Number of bytes to transfer. | 
|  | 1111 | * | 
|  | 1112 | * Add an entry to the provided VME DMA list. Entry requires pointers to source | 
|  | 1113 | * and destination DMA attributes and a count. | 
|  | 1114 | * | 
|  | 1115 | * Please note, the attributes supported as source and destinations for | 
|  | 1116 | * transfers are hardware dependent. | 
|  | 1117 | * | 
|  | 1118 | * Return: Zero on success, -EINVAL if operation is not supported on this | 
|  | 1119 | *         device or if the link list has already been submitted for execution. | 
|  | 1120 | *         Hardware specific errors also possible. | 
|  | 1121 | */ | 
|  | 1122 | int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src, | 
|  | 1123 | struct vme_dma_attr *dest, size_t count) | 
|  | 1124 | { | 
|  | 1125 | struct vme_bridge *bridge = list->parent->parent; | 
|  | 1126 | int retval; | 
|  | 1127 |  | 
|  | 1128 | if (!bridge->dma_list_add) { | 
|  | 1129 | printk(KERN_WARNING "Link List DMA generation not supported\n"); | 
|  | 1130 | return -EINVAL; | 
|  | 1131 | } | 
|  | 1132 |  | 
|  | 1133 | if (!mutex_trylock(&list->mtx)) { | 
|  | 1134 | printk(KERN_ERR "Link List already submitted\n"); | 
|  | 1135 | return -EINVAL; | 
|  | 1136 | } | 
|  | 1137 |  | 
|  | 1138 | retval = bridge->dma_list_add(list, src, dest, count); | 
|  | 1139 |  | 
|  | 1140 | mutex_unlock(&list->mtx); | 
|  | 1141 |  | 
|  | 1142 | return retval; | 
|  | 1143 | } | 
|  | 1144 | EXPORT_SYMBOL(vme_dma_list_add); | 
|  | 1145 |  | 
|  | 1146 | /** | 
|  | 1147 | * vme_dma_list_exec - Queue a VME DMA list for execution. | 
|  | 1148 | * @list: Pointer to VME list. | 
|  | 1149 | * | 
|  | 1150 | * Queue the provided VME DMA list for execution. The call will return once the | 
|  | 1151 | * list has been executed. | 
|  | 1152 | * | 
|  | 1153 | * Return: Zero on success, -EINVAL if operation is not supported on this | 
|  | 1154 | *         device. Hardware specific errors also possible. | 
|  | 1155 | */ | 
|  | 1156 | int vme_dma_list_exec(struct vme_dma_list *list) | 
|  | 1157 | { | 
|  | 1158 | struct vme_bridge *bridge = list->parent->parent; | 
|  | 1159 | int retval; | 
|  | 1160 |  | 
|  | 1161 | if (!bridge->dma_list_exec) { | 
|  | 1162 | printk(KERN_ERR "Link List DMA execution not supported\n"); | 
|  | 1163 | return -EINVAL; | 
|  | 1164 | } | 
|  | 1165 |  | 
|  | 1166 | mutex_lock(&list->mtx); | 
|  | 1167 |  | 
|  | 1168 | retval = bridge->dma_list_exec(list); | 
|  | 1169 |  | 
|  | 1170 | mutex_unlock(&list->mtx); | 
|  | 1171 |  | 
|  | 1172 | return retval; | 
|  | 1173 | } | 
|  | 1174 | EXPORT_SYMBOL(vme_dma_list_exec); | 
|  | 1175 |  | 
|  | 1176 | /** | 
|  | 1177 | * vme_dma_list_free - Free a VME DMA list. | 
|  | 1178 | * @list: Pointer to VME list. | 
|  | 1179 | * | 
|  | 1180 | * Free the provided DMA list and all its entries. | 
|  | 1181 | * | 
|  | 1182 | * Return: Zero on success, -EINVAL on invalid VME resource, -EBUSY if resource | 
|  | 1183 | *         is still in use. Hardware specific errors also possible. | 
|  | 1184 | */ | 
|  | 1185 | int vme_dma_list_free(struct vme_dma_list *list) | 
|  | 1186 | { | 
|  | 1187 | struct vme_bridge *bridge = list->parent->parent; | 
|  | 1188 | int retval; | 
|  | 1189 |  | 
|  | 1190 | if (!bridge->dma_list_empty) { | 
|  | 1191 | printk(KERN_WARNING "Emptying of Link Lists not supported\n"); | 
|  | 1192 | return -EINVAL; | 
|  | 1193 | } | 
|  | 1194 |  | 
|  | 1195 | if (!mutex_trylock(&list->mtx)) { | 
|  | 1196 | printk(KERN_ERR "Link List in use\n"); | 
|  | 1197 | return -EBUSY; | 
|  | 1198 | } | 
|  | 1199 |  | 
|  | 1200 | /* | 
|  | 1201 | * Empty out all of the entries from the DMA list. We need to go to the | 
|  | 1202 | * low level driver as DMA entries are driver specific. | 
|  | 1203 | */ | 
|  | 1204 | retval = bridge->dma_list_empty(list); | 
|  | 1205 | if (retval) { | 
|  | 1206 | printk(KERN_ERR "Unable to empty link-list entries\n"); | 
|  | 1207 | mutex_unlock(&list->mtx); | 
|  | 1208 | return retval; | 
|  | 1209 | } | 
|  | 1210 | mutex_unlock(&list->mtx); | 
|  | 1211 | kfree(list); | 
|  | 1212 |  | 
|  | 1213 | return retval; | 
|  | 1214 | } | 
|  | 1215 | EXPORT_SYMBOL(vme_dma_list_free); | 
|  | 1216 |  | 
|  | 1217 | /** | 
|  | 1218 | * vme_dma_free - Free a VME DMA resource. | 
|  | 1219 | * @resource: Pointer to VME DMA resource. | 
|  | 1220 | * | 
|  | 1221 | * Free the provided DMA resource so that it may be reallocated. | 
|  | 1222 | * | 
|  | 1223 | * Return: Zero on success, -EINVAL on invalid VME resource, -EBUSY if resource | 
|  | 1224 | *         is still active. | 
|  | 1225 | */ | 
|  | 1226 | int vme_dma_free(struct vme_resource *resource) | 
|  | 1227 | { | 
|  | 1228 | struct vme_dma_resource *ctrlr; | 
|  | 1229 |  | 
|  | 1230 | if (resource->type != VME_DMA) { | 
|  | 1231 | printk(KERN_ERR "Not a DMA resource\n"); | 
|  | 1232 | return -EINVAL; | 
|  | 1233 | } | 
|  | 1234 |  | 
|  | 1235 | ctrlr = list_entry(resource->entry, struct vme_dma_resource, list); | 
|  | 1236 |  | 
|  | 1237 | if (!mutex_trylock(&ctrlr->mtx)) { | 
|  | 1238 | printk(KERN_ERR "Resource busy, can't free\n"); | 
|  | 1239 | return -EBUSY; | 
|  | 1240 | } | 
|  | 1241 |  | 
|  | 1242 | if (!(list_empty(&ctrlr->pending) && list_empty(&ctrlr->running))) { | 
|  | 1243 | printk(KERN_WARNING "Resource still processing transfers\n"); | 
|  | 1244 | mutex_unlock(&ctrlr->mtx); | 
|  | 1245 | return -EBUSY; | 
|  | 1246 | } | 
|  | 1247 |  | 
|  | 1248 | ctrlr->locked = 0; | 
|  | 1249 |  | 
|  | 1250 | mutex_unlock(&ctrlr->mtx); | 
|  | 1251 |  | 
|  | 1252 | kfree(resource); | 
|  | 1253 |  | 
|  | 1254 | return 0; | 
|  | 1255 | } | 
|  | 1256 | EXPORT_SYMBOL(vme_dma_free); | 
|  | 1257 |  | 
|  | 1258 | void vme_bus_error_handler(struct vme_bridge *bridge, | 
|  | 1259 | unsigned long long address, int am) | 
|  | 1260 | { | 
|  | 1261 | struct list_head *handler_pos = NULL; | 
|  | 1262 | struct vme_error_handler *handler; | 
|  | 1263 | int handler_triggered = 0; | 
|  | 1264 | u32 aspace = vme_get_aspace(am); | 
|  | 1265 |  | 
|  | 1266 | list_for_each(handler_pos, &bridge->vme_error_handlers) { | 
|  | 1267 | handler = list_entry(handler_pos, struct vme_error_handler, | 
|  | 1268 | list); | 
|  | 1269 | if ((aspace == handler->aspace) && | 
|  | 1270 | (address >= handler->start) && | 
|  | 1271 | (address < handler->end)) { | 
|  | 1272 | if (!handler->num_errors) | 
|  | 1273 | handler->first_error = address; | 
|  | 1274 | if (handler->num_errors != UINT_MAX) | 
|  | 1275 | handler->num_errors++; | 
|  | 1276 | handler_triggered = 1; | 
|  | 1277 | } | 
|  | 1278 | } | 
|  | 1279 |  | 
|  | 1280 | if (!handler_triggered) | 
|  | 1281 | dev_err(bridge->parent, | 
|  | 1282 | "Unhandled VME access error at address 0x%llx\n", | 
|  | 1283 | address); | 
|  | 1284 | } | 
|  | 1285 | EXPORT_SYMBOL(vme_bus_error_handler); | 
|  | 1286 |  | 
|  | 1287 | struct vme_error_handler *vme_register_error_handler( | 
|  | 1288 | struct vme_bridge *bridge, u32 aspace, | 
|  | 1289 | unsigned long long address, size_t len) | 
|  | 1290 | { | 
|  | 1291 | struct vme_error_handler *handler; | 
|  | 1292 |  | 
|  | 1293 | handler = kmalloc(sizeof(*handler), GFP_ATOMIC); | 
|  | 1294 | if (!handler) | 
|  | 1295 | return NULL; | 
|  | 1296 |  | 
|  | 1297 | handler->aspace = aspace; | 
|  | 1298 | handler->start = address; | 
|  | 1299 | handler->end = address + len; | 
|  | 1300 | handler->num_errors = 0; | 
|  | 1301 | handler->first_error = 0; | 
|  | 1302 | list_add_tail(&handler->list, &bridge->vme_error_handlers); | 
|  | 1303 |  | 
|  | 1304 | return handler; | 
|  | 1305 | } | 
|  | 1306 | EXPORT_SYMBOL(vme_register_error_handler); | 
|  | 1307 |  | 
|  | 1308 | void vme_unregister_error_handler(struct vme_error_handler *handler) | 
|  | 1309 | { | 
|  | 1310 | list_del(&handler->list); | 
|  | 1311 | kfree(handler); | 
|  | 1312 | } | 
|  | 1313 | EXPORT_SYMBOL(vme_unregister_error_handler); | 
|  | 1314 |  | 
|  | 1315 | void vme_irq_handler(struct vme_bridge *bridge, int level, int statid) | 
|  | 1316 | { | 
|  | 1317 | void (*call)(int, int, void *); | 
|  | 1318 | void *priv_data; | 
|  | 1319 |  | 
|  | 1320 | call = bridge->irq[level - 1].callback[statid].func; | 
|  | 1321 | priv_data = bridge->irq[level - 1].callback[statid].priv_data; | 
|  | 1322 | if (call) | 
|  | 1323 | call(level, statid, priv_data); | 
|  | 1324 | else | 
|  | 1325 | printk(KERN_WARNING "Spurious VME interrupt, level:%x, vector:%x\n", | 
|  | 1326 | level, statid); | 
|  | 1327 | } | 
|  | 1328 | EXPORT_SYMBOL(vme_irq_handler); | 
|  | 1329 |  | 
|  | 1330 | /** | 
|  | 1331 | * vme_irq_request - Request a specific VME interrupt. | 
|  | 1332 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | 
|  | 1333 | * @level: Interrupt priority being requested. | 
|  | 1334 | * @statid: Interrupt vector being requested. | 
|  | 1335 | * @callback: Pointer to callback function called when VME interrupt/vector | 
|  | 1336 | *            received. | 
|  | 1337 | * @priv_data: Generic pointer that will be passed to the callback function. | 
|  | 1338 | * | 
|  | 1339 | * Request callback to be attached as a handler for VME interrupts with provided | 
|  | 1340 | * level and statid. | 
|  | 1341 | * | 
|  | 1342 | * Return: Zero on success, -EINVAL on invalid vme device, level or if the | 
|  | 1343 | *         function is not supported, -EBUSY if the level/statid combination is | 
|  | 1344 | *         already in use. Hardware specific errors also possible. | 
|  | 1345 | */ | 
|  | 1346 | int vme_irq_request(struct vme_dev *vdev, int level, int statid, | 
|  | 1347 | void (*callback)(int, int, void *), | 
|  | 1348 | void *priv_data) | 
|  | 1349 | { | 
|  | 1350 | struct vme_bridge *bridge; | 
|  | 1351 |  | 
|  | 1352 | bridge = vdev->bridge; | 
|  | 1353 | if (!bridge) { | 
|  | 1354 | printk(KERN_ERR "Can't find VME bus\n"); | 
|  | 1355 | return -EINVAL; | 
|  | 1356 | } | 
|  | 1357 |  | 
|  | 1358 | if ((level < 1) || (level > 7)) { | 
|  | 1359 | printk(KERN_ERR "Invalid interrupt level\n"); | 
|  | 1360 | return -EINVAL; | 
|  | 1361 | } | 
|  | 1362 |  | 
|  | 1363 | if (!bridge->irq_set) { | 
|  | 1364 | printk(KERN_ERR "Configuring interrupts not supported\n"); | 
|  | 1365 | return -EINVAL; | 
|  | 1366 | } | 
|  | 1367 |  | 
|  | 1368 | mutex_lock(&bridge->irq_mtx); | 
|  | 1369 |  | 
|  | 1370 | if (bridge->irq[level - 1].callback[statid].func) { | 
|  | 1371 | mutex_unlock(&bridge->irq_mtx); | 
|  | 1372 | printk(KERN_WARNING "VME Interrupt already taken\n"); | 
|  | 1373 | return -EBUSY; | 
|  | 1374 | } | 
|  | 1375 |  | 
|  | 1376 | bridge->irq[level - 1].count++; | 
|  | 1377 | bridge->irq[level - 1].callback[statid].priv_data = priv_data; | 
|  | 1378 | bridge->irq[level - 1].callback[statid].func = callback; | 
|  | 1379 |  | 
|  | 1380 | /* Enable IRQ level */ | 
|  | 1381 | bridge->irq_set(bridge, level, 1, 1); | 
|  | 1382 |  | 
|  | 1383 | mutex_unlock(&bridge->irq_mtx); | 
|  | 1384 |  | 
|  | 1385 | return 0; | 
|  | 1386 | } | 
|  | 1387 | EXPORT_SYMBOL(vme_irq_request); | 
|  | 1388 |  | 
|  | 1389 | /** | 
|  | 1390 | * vme_irq_free - Free a VME interrupt. | 
|  | 1391 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | 
|  | 1392 | * @level: Interrupt priority of interrupt being freed. | 
|  | 1393 | * @statid: Interrupt vector of interrupt being freed. | 
|  | 1394 | * | 
|  | 1395 | * Remove previously attached callback from VME interrupt priority/vector. | 
|  | 1396 | */ | 
|  | 1397 | void vme_irq_free(struct vme_dev *vdev, int level, int statid) | 
|  | 1398 | { | 
|  | 1399 | struct vme_bridge *bridge; | 
|  | 1400 |  | 
|  | 1401 | bridge = vdev->bridge; | 
|  | 1402 | if (!bridge) { | 
|  | 1403 | printk(KERN_ERR "Can't find VME bus\n"); | 
|  | 1404 | return; | 
|  | 1405 | } | 
|  | 1406 |  | 
|  | 1407 | if ((level < 1) || (level > 7)) { | 
|  | 1408 | printk(KERN_ERR "Invalid interrupt level\n"); | 
|  | 1409 | return; | 
|  | 1410 | } | 
|  | 1411 |  | 
|  | 1412 | if (!bridge->irq_set) { | 
|  | 1413 | printk(KERN_ERR "Configuring interrupts not supported\n"); | 
|  | 1414 | return; | 
|  | 1415 | } | 
|  | 1416 |  | 
|  | 1417 | mutex_lock(&bridge->irq_mtx); | 
|  | 1418 |  | 
|  | 1419 | bridge->irq[level - 1].count--; | 
|  | 1420 |  | 
|  | 1421 | /* Disable IRQ level if no more interrupts attached at this level*/ | 
|  | 1422 | if (bridge->irq[level - 1].count == 0) | 
|  | 1423 | bridge->irq_set(bridge, level, 0, 1); | 
|  | 1424 |  | 
|  | 1425 | bridge->irq[level - 1].callback[statid].func = NULL; | 
|  | 1426 | bridge->irq[level - 1].callback[statid].priv_data = NULL; | 
|  | 1427 |  | 
|  | 1428 | mutex_unlock(&bridge->irq_mtx); | 
|  | 1429 | } | 
|  | 1430 | EXPORT_SYMBOL(vme_irq_free); | 
|  | 1431 |  | 
|  | 1432 | /** | 
|  | 1433 | * vme_irq_generate - Generate VME interrupt. | 
|  | 1434 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | 
|  | 1435 | * @level: Interrupt priority at which to assert the interrupt. | 
|  | 1436 | * @statid: Interrupt vector to associate with the interrupt. | 
|  | 1437 | * | 
|  | 1438 | * Generate a VME interrupt of the provided level and with the provided | 
|  | 1439 | * statid. | 
|  | 1440 | * | 
|  | 1441 | * Return: Zero on success, -EINVAL on invalid vme device, level or if the | 
|  | 1442 | *         function is not supported. Hardware specific errors also possible. | 
|  | 1443 | */ | 
|  | 1444 | int vme_irq_generate(struct vme_dev *vdev, int level, int statid) | 
|  | 1445 | { | 
|  | 1446 | struct vme_bridge *bridge; | 
|  | 1447 |  | 
|  | 1448 | bridge = vdev->bridge; | 
|  | 1449 | if (!bridge) { | 
|  | 1450 | printk(KERN_ERR "Can't find VME bus\n"); | 
|  | 1451 | return -EINVAL; | 
|  | 1452 | } | 
|  | 1453 |  | 
|  | 1454 | if ((level < 1) || (level > 7)) { | 
|  | 1455 | printk(KERN_WARNING "Invalid interrupt level\n"); | 
|  | 1456 | return -EINVAL; | 
|  | 1457 | } | 
|  | 1458 |  | 
|  | 1459 | if (!bridge->irq_generate) { | 
|  | 1460 | printk(KERN_WARNING "Interrupt generation not supported\n"); | 
|  | 1461 | return -EINVAL; | 
|  | 1462 | } | 
|  | 1463 |  | 
|  | 1464 | return bridge->irq_generate(bridge, level, statid); | 
|  | 1465 | } | 
|  | 1466 | EXPORT_SYMBOL(vme_irq_generate); | 
|  | 1467 |  | 
|  | 1468 | /** | 
|  | 1469 | * vme_lm_request - Request a VME location monitor | 
|  | 1470 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | 
|  | 1471 | * | 
|  | 1472 | * Allocate a location monitor resource to the driver. A location monitor | 
|  | 1473 | * allows the driver to monitor accesses to a contiguous number of | 
|  | 1474 | * addresses on the VME bus. | 
|  | 1475 | * | 
|  | 1476 | * Return: Pointer to a VME resource on success or NULL on failure. | 
|  | 1477 | */ | 
|  | 1478 | struct vme_resource *vme_lm_request(struct vme_dev *vdev) | 
|  | 1479 | { | 
|  | 1480 | struct vme_bridge *bridge; | 
|  | 1481 | struct list_head *lm_pos = NULL; | 
|  | 1482 | struct vme_lm_resource *allocated_lm = NULL; | 
|  | 1483 | struct vme_lm_resource *lm = NULL; | 
|  | 1484 | struct vme_resource *resource = NULL; | 
|  | 1485 |  | 
|  | 1486 | bridge = vdev->bridge; | 
|  | 1487 | if (!bridge) { | 
|  | 1488 | printk(KERN_ERR "Can't find VME bus\n"); | 
|  | 1489 | goto err_bus; | 
|  | 1490 | } | 
|  | 1491 |  | 
|  | 1492 | /* Loop through LM resources */ | 
|  | 1493 | list_for_each(lm_pos, &bridge->lm_resources) { | 
|  | 1494 | lm = list_entry(lm_pos, | 
|  | 1495 | struct vme_lm_resource, list); | 
|  | 1496 | if (!lm) { | 
|  | 1497 | printk(KERN_ERR "Registered NULL Location Monitor resource\n"); | 
|  | 1498 | continue; | 
|  | 1499 | } | 
|  | 1500 |  | 
|  | 1501 | /* Find an unlocked controller */ | 
|  | 1502 | mutex_lock(&lm->mtx); | 
|  | 1503 | if (lm->locked == 0) { | 
|  | 1504 | lm->locked = 1; | 
|  | 1505 | mutex_unlock(&lm->mtx); | 
|  | 1506 | allocated_lm = lm; | 
|  | 1507 | break; | 
|  | 1508 | } | 
|  | 1509 | mutex_unlock(&lm->mtx); | 
|  | 1510 | } | 
|  | 1511 |  | 
|  | 1512 | /* Check to see if we found a resource */ | 
|  | 1513 | if (!allocated_lm) | 
|  | 1514 | goto err_lm; | 
|  | 1515 |  | 
|  | 1516 | resource = kmalloc(sizeof(*resource), GFP_KERNEL); | 
|  | 1517 | if (!resource) | 
|  | 1518 | goto err_alloc; | 
|  | 1519 |  | 
|  | 1520 | resource->type = VME_LM; | 
|  | 1521 | resource->entry = &allocated_lm->list; | 
|  | 1522 |  | 
|  | 1523 | return resource; | 
|  | 1524 |  | 
|  | 1525 | err_alloc: | 
|  | 1526 | /* Unlock image */ | 
|  | 1527 | mutex_lock(&lm->mtx); | 
|  | 1528 | lm->locked = 0; | 
|  | 1529 | mutex_unlock(&lm->mtx); | 
|  | 1530 | err_lm: | 
|  | 1531 | err_bus: | 
|  | 1532 | return NULL; | 
|  | 1533 | } | 
|  | 1534 | EXPORT_SYMBOL(vme_lm_request); | 
|  | 1535 |  | 
|  | 1536 | /** | 
|  | 1537 | * vme_lm_count - Determine number of VME Addresses monitored | 
|  | 1538 | * @resource: Pointer to VME location monitor resource. | 
|  | 1539 | * | 
|  | 1540 | * The number of contiguous addresses monitored is hardware dependent. | 
|  | 1541 | * Return the number of contiguous addresses monitored by the | 
|  | 1542 | * location monitor. | 
|  | 1543 | * | 
|  | 1544 | * Return: Count of addresses monitored or -EINVAL when provided with an | 
|  | 1545 | *	   invalid location monitor resource. | 
|  | 1546 | */ | 
|  | 1547 | int vme_lm_count(struct vme_resource *resource) | 
|  | 1548 | { | 
|  | 1549 | struct vme_lm_resource *lm; | 
|  | 1550 |  | 
|  | 1551 | if (resource->type != VME_LM) { | 
|  | 1552 | printk(KERN_ERR "Not a Location Monitor resource\n"); | 
|  | 1553 | return -EINVAL; | 
|  | 1554 | } | 
|  | 1555 |  | 
|  | 1556 | lm = list_entry(resource->entry, struct vme_lm_resource, list); | 
|  | 1557 |  | 
|  | 1558 | return lm->monitors; | 
|  | 1559 | } | 
|  | 1560 | EXPORT_SYMBOL(vme_lm_count); | 
|  | 1561 |  | 
|  | 1562 | /** | 
|  | 1563 | * vme_lm_set - Configure location monitor | 
|  | 1564 | * @resource: Pointer to VME location monitor resource. | 
|  | 1565 | * @lm_base: Base address to monitor. | 
|  | 1566 | * @aspace: VME address space to monitor. | 
|  | 1567 | * @cycle: VME bus cycle type to monitor. | 
|  | 1568 | * | 
|  | 1569 | * Set the base address, address space and cycle type of accesses to be | 
|  | 1570 | * monitored by the location monitor. | 
|  | 1571 | * | 
|  | 1572 | * Return: Zero on success, -EINVAL when provided with an invalid location | 
|  | 1573 | *	   monitor resource or function is not supported. Hardware specific | 
|  | 1574 | *	   errors may also be returned. | 
|  | 1575 | */ | 
|  | 1576 | int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base, | 
|  | 1577 | u32 aspace, u32 cycle) | 
|  | 1578 | { | 
|  | 1579 | struct vme_bridge *bridge = find_bridge(resource); | 
|  | 1580 | struct vme_lm_resource *lm; | 
|  | 1581 |  | 
|  | 1582 | if (resource->type != VME_LM) { | 
|  | 1583 | printk(KERN_ERR "Not a Location Monitor resource\n"); | 
|  | 1584 | return -EINVAL; | 
|  | 1585 | } | 
|  | 1586 |  | 
|  | 1587 | lm = list_entry(resource->entry, struct vme_lm_resource, list); | 
|  | 1588 |  | 
|  | 1589 | if (!bridge->lm_set) { | 
|  | 1590 | printk(KERN_ERR "vme_lm_set not supported\n"); | 
|  | 1591 | return -EINVAL; | 
|  | 1592 | } | 
|  | 1593 |  | 
|  | 1594 | return bridge->lm_set(lm, lm_base, aspace, cycle); | 
|  | 1595 | } | 
|  | 1596 | EXPORT_SYMBOL(vme_lm_set); | 
|  | 1597 |  | 
|  | 1598 | /** | 
|  | 1599 | * vme_lm_get - Retrieve location monitor settings | 
|  | 1600 | * @resource: Pointer to VME location monitor resource. | 
|  | 1601 | * @lm_base: Pointer used to output the base address monitored. | 
|  | 1602 | * @aspace: Pointer used to output the address space monitored. | 
|  | 1603 | * @cycle: Pointer used to output the VME bus cycle type monitored. | 
|  | 1604 | * | 
|  | 1605 | * Retrieve the base address, address space and cycle type of accesses to | 
|  | 1606 | * be monitored by the location monitor. | 
|  | 1607 | * | 
|  | 1608 | * Return: Zero on success, -EINVAL when provided with an invalid location | 
|  | 1609 | *	   monitor resource or function is not supported. Hardware specific | 
|  | 1610 | *	   errors may also be returned. | 
|  | 1611 | */ | 
|  | 1612 | int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base, | 
|  | 1613 | u32 *aspace, u32 *cycle) | 
|  | 1614 | { | 
|  | 1615 | struct vme_bridge *bridge = find_bridge(resource); | 
|  | 1616 | struct vme_lm_resource *lm; | 
|  | 1617 |  | 
|  | 1618 | if (resource->type != VME_LM) { | 
|  | 1619 | printk(KERN_ERR "Not a Location Monitor resource\n"); | 
|  | 1620 | return -EINVAL; | 
|  | 1621 | } | 
|  | 1622 |  | 
|  | 1623 | lm = list_entry(resource->entry, struct vme_lm_resource, list); | 
|  | 1624 |  | 
|  | 1625 | if (!bridge->lm_get) { | 
|  | 1626 | printk(KERN_ERR "vme_lm_get not supported\n"); | 
|  | 1627 | return -EINVAL; | 
|  | 1628 | } | 
|  | 1629 |  | 
|  | 1630 | return bridge->lm_get(lm, lm_base, aspace, cycle); | 
|  | 1631 | } | 
|  | 1632 | EXPORT_SYMBOL(vme_lm_get); | 
|  | 1633 |  | 
|  | 1634 | /** | 
|  | 1635 | * vme_lm_attach - Provide callback for location monitor address | 
|  | 1636 | * @resource: Pointer to VME location monitor resource. | 
|  | 1637 | * @monitor: Offset to which callback should be attached. | 
|  | 1638 | * @callback: Pointer to callback function called when triggered. | 
|  | 1639 | * @data: Generic pointer that will be passed to the callback function. | 
|  | 1640 | * | 
|  | 1641 | * Attach a callback to the specificed offset into the location monitors | 
|  | 1642 | * monitored addresses. A generic pointer is provided to allow data to be | 
|  | 1643 | * passed to the callback when called. | 
|  | 1644 | * | 
|  | 1645 | * Return: Zero on success, -EINVAL when provided with an invalid location | 
|  | 1646 | *	   monitor resource or function is not supported. Hardware specific | 
|  | 1647 | *	   errors may also be returned. | 
|  | 1648 | */ | 
|  | 1649 | int vme_lm_attach(struct vme_resource *resource, int monitor, | 
|  | 1650 | void (*callback)(void *), void *data) | 
|  | 1651 | { | 
|  | 1652 | struct vme_bridge *bridge = find_bridge(resource); | 
|  | 1653 | struct vme_lm_resource *lm; | 
|  | 1654 |  | 
|  | 1655 | if (resource->type != VME_LM) { | 
|  | 1656 | printk(KERN_ERR "Not a Location Monitor resource\n"); | 
|  | 1657 | return -EINVAL; | 
|  | 1658 | } | 
|  | 1659 |  | 
|  | 1660 | lm = list_entry(resource->entry, struct vme_lm_resource, list); | 
|  | 1661 |  | 
|  | 1662 | if (!bridge->lm_attach) { | 
|  | 1663 | printk(KERN_ERR "vme_lm_attach not supported\n"); | 
|  | 1664 | return -EINVAL; | 
|  | 1665 | } | 
|  | 1666 |  | 
|  | 1667 | return bridge->lm_attach(lm, monitor, callback, data); | 
|  | 1668 | } | 
|  | 1669 | EXPORT_SYMBOL(vme_lm_attach); | 
|  | 1670 |  | 
|  | 1671 | /** | 
|  | 1672 | * vme_lm_detach - Remove callback for location monitor address | 
|  | 1673 | * @resource: Pointer to VME location monitor resource. | 
|  | 1674 | * @monitor: Offset to which callback should be removed. | 
|  | 1675 | * | 
|  | 1676 | * Remove the callback associated with the specificed offset into the | 
|  | 1677 | * location monitors monitored addresses. | 
|  | 1678 | * | 
|  | 1679 | * Return: Zero on success, -EINVAL when provided with an invalid location | 
|  | 1680 | *	   monitor resource or function is not supported. Hardware specific | 
|  | 1681 | *	   errors may also be returned. | 
|  | 1682 | */ | 
|  | 1683 | int vme_lm_detach(struct vme_resource *resource, int monitor) | 
|  | 1684 | { | 
|  | 1685 | struct vme_bridge *bridge = find_bridge(resource); | 
|  | 1686 | struct vme_lm_resource *lm; | 
|  | 1687 |  | 
|  | 1688 | if (resource->type != VME_LM) { | 
|  | 1689 | printk(KERN_ERR "Not a Location Monitor resource\n"); | 
|  | 1690 | return -EINVAL; | 
|  | 1691 | } | 
|  | 1692 |  | 
|  | 1693 | lm = list_entry(resource->entry, struct vme_lm_resource, list); | 
|  | 1694 |  | 
|  | 1695 | if (!bridge->lm_detach) { | 
|  | 1696 | printk(KERN_ERR "vme_lm_detach not supported\n"); | 
|  | 1697 | return -EINVAL; | 
|  | 1698 | } | 
|  | 1699 |  | 
|  | 1700 | return bridge->lm_detach(lm, monitor); | 
|  | 1701 | } | 
|  | 1702 | EXPORT_SYMBOL(vme_lm_detach); | 
|  | 1703 |  | 
|  | 1704 | /** | 
|  | 1705 | * vme_lm_free - Free allocated VME location monitor | 
|  | 1706 | * @resource: Pointer to VME location monitor resource. | 
|  | 1707 | * | 
|  | 1708 | * Free allocation of a VME location monitor. | 
|  | 1709 | * | 
|  | 1710 | * WARNING: This function currently expects that any callbacks that have | 
|  | 1711 | *          been attached to the location monitor have been removed. | 
|  | 1712 | * | 
|  | 1713 | * Return: Zero on success, -EINVAL when provided with an invalid location | 
|  | 1714 | *	   monitor resource. | 
|  | 1715 | */ | 
|  | 1716 | void vme_lm_free(struct vme_resource *resource) | 
|  | 1717 | { | 
|  | 1718 | struct vme_lm_resource *lm; | 
|  | 1719 |  | 
|  | 1720 | if (resource->type != VME_LM) { | 
|  | 1721 | printk(KERN_ERR "Not a Location Monitor resource\n"); | 
|  | 1722 | return; | 
|  | 1723 | } | 
|  | 1724 |  | 
|  | 1725 | lm = list_entry(resource->entry, struct vme_lm_resource, list); | 
|  | 1726 |  | 
|  | 1727 | mutex_lock(&lm->mtx); | 
|  | 1728 |  | 
|  | 1729 | /* XXX | 
|  | 1730 | * Check to see that there aren't any callbacks still attached, if | 
|  | 1731 | * there are we should probably be detaching them! | 
|  | 1732 | */ | 
|  | 1733 |  | 
|  | 1734 | lm->locked = 0; | 
|  | 1735 |  | 
|  | 1736 | mutex_unlock(&lm->mtx); | 
|  | 1737 |  | 
|  | 1738 | kfree(resource); | 
|  | 1739 | } | 
|  | 1740 | EXPORT_SYMBOL(vme_lm_free); | 
|  | 1741 |  | 
|  | 1742 | /** | 
|  | 1743 | * vme_slot_num - Retrieve slot ID | 
|  | 1744 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | 
|  | 1745 | * | 
|  | 1746 | * Retrieve the slot ID associated with the provided VME device. | 
|  | 1747 | * | 
|  | 1748 | * Return: The slot ID on success, -EINVAL if VME bridge cannot be determined | 
|  | 1749 | *         or the function is not supported. Hardware specific errors may also | 
|  | 1750 | *         be returned. | 
|  | 1751 | */ | 
|  | 1752 | int vme_slot_num(struct vme_dev *vdev) | 
|  | 1753 | { | 
|  | 1754 | struct vme_bridge *bridge; | 
|  | 1755 |  | 
|  | 1756 | bridge = vdev->bridge; | 
|  | 1757 | if (!bridge) { | 
|  | 1758 | printk(KERN_ERR "Can't find VME bus\n"); | 
|  | 1759 | return -EINVAL; | 
|  | 1760 | } | 
|  | 1761 |  | 
|  | 1762 | if (!bridge->slot_get) { | 
|  | 1763 | printk(KERN_WARNING "vme_slot_num not supported\n"); | 
|  | 1764 | return -EINVAL; | 
|  | 1765 | } | 
|  | 1766 |  | 
|  | 1767 | return bridge->slot_get(bridge); | 
|  | 1768 | } | 
|  | 1769 | EXPORT_SYMBOL(vme_slot_num); | 
|  | 1770 |  | 
|  | 1771 | /** | 
|  | 1772 | * vme_bus_num - Retrieve bus number | 
|  | 1773 | * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. | 
|  | 1774 | * | 
|  | 1775 | * Retrieve the bus enumeration associated with the provided VME device. | 
|  | 1776 | * | 
|  | 1777 | * Return: The bus number on success, -EINVAL if VME bridge cannot be | 
|  | 1778 | *         determined. | 
|  | 1779 | */ | 
|  | 1780 | int vme_bus_num(struct vme_dev *vdev) | 
|  | 1781 | { | 
|  | 1782 | struct vme_bridge *bridge; | 
|  | 1783 |  | 
|  | 1784 | bridge = vdev->bridge; | 
|  | 1785 | if (!bridge) { | 
|  | 1786 | pr_err("Can't find VME bus\n"); | 
|  | 1787 | return -EINVAL; | 
|  | 1788 | } | 
|  | 1789 |  | 
|  | 1790 | return bridge->num; | 
|  | 1791 | } | 
|  | 1792 | EXPORT_SYMBOL(vme_bus_num); | 
|  | 1793 |  | 
|  | 1794 | /* - Bridge Registration --------------------------------------------------- */ | 
|  | 1795 |  | 
|  | 1796 | static void vme_dev_release(struct device *dev) | 
|  | 1797 | { | 
|  | 1798 | kfree(dev_to_vme_dev(dev)); | 
|  | 1799 | } | 
|  | 1800 |  | 
|  | 1801 | /* Common bridge initialization */ | 
|  | 1802 | struct vme_bridge *vme_init_bridge(struct vme_bridge *bridge) | 
|  | 1803 | { | 
|  | 1804 | INIT_LIST_HEAD(&bridge->vme_error_handlers); | 
|  | 1805 | INIT_LIST_HEAD(&bridge->master_resources); | 
|  | 1806 | INIT_LIST_HEAD(&bridge->slave_resources); | 
|  | 1807 | INIT_LIST_HEAD(&bridge->dma_resources); | 
|  | 1808 | INIT_LIST_HEAD(&bridge->lm_resources); | 
|  | 1809 | mutex_init(&bridge->irq_mtx); | 
|  | 1810 |  | 
|  | 1811 | return bridge; | 
|  | 1812 | } | 
|  | 1813 | EXPORT_SYMBOL(vme_init_bridge); | 
|  | 1814 |  | 
|  | 1815 | int vme_register_bridge(struct vme_bridge *bridge) | 
|  | 1816 | { | 
|  | 1817 | int i; | 
|  | 1818 | int ret = -1; | 
|  | 1819 |  | 
|  | 1820 | mutex_lock(&vme_buses_lock); | 
|  | 1821 | for (i = 0; i < sizeof(vme_bus_numbers) * 8; i++) { | 
|  | 1822 | if ((vme_bus_numbers & (1 << i)) == 0) { | 
|  | 1823 | vme_bus_numbers |= (1 << i); | 
|  | 1824 | bridge->num = i; | 
|  | 1825 | INIT_LIST_HEAD(&bridge->devices); | 
|  | 1826 | list_add_tail(&bridge->bus_list, &vme_bus_list); | 
|  | 1827 | ret = 0; | 
|  | 1828 | break; | 
|  | 1829 | } | 
|  | 1830 | } | 
|  | 1831 | mutex_unlock(&vme_buses_lock); | 
|  | 1832 |  | 
|  | 1833 | return ret; | 
|  | 1834 | } | 
|  | 1835 | EXPORT_SYMBOL(vme_register_bridge); | 
|  | 1836 |  | 
|  | 1837 | void vme_unregister_bridge(struct vme_bridge *bridge) | 
|  | 1838 | { | 
|  | 1839 | struct vme_dev *vdev; | 
|  | 1840 | struct vme_dev *tmp; | 
|  | 1841 |  | 
|  | 1842 | mutex_lock(&vme_buses_lock); | 
|  | 1843 | vme_bus_numbers &= ~(1 << bridge->num); | 
|  | 1844 | list_for_each_entry_safe(vdev, tmp, &bridge->devices, bridge_list) { | 
|  | 1845 | list_del(&vdev->drv_list); | 
|  | 1846 | list_del(&vdev->bridge_list); | 
|  | 1847 | device_unregister(&vdev->dev); | 
|  | 1848 | } | 
|  | 1849 | list_del(&bridge->bus_list); | 
|  | 1850 | mutex_unlock(&vme_buses_lock); | 
|  | 1851 | } | 
|  | 1852 | EXPORT_SYMBOL(vme_unregister_bridge); | 
|  | 1853 |  | 
|  | 1854 | /* - Driver Registration --------------------------------------------------- */ | 
|  | 1855 |  | 
|  | 1856 | static int __vme_register_driver_bus(struct vme_driver *drv, | 
|  | 1857 | struct vme_bridge *bridge, unsigned int ndevs) | 
|  | 1858 | { | 
|  | 1859 | int err; | 
|  | 1860 | unsigned int i; | 
|  | 1861 | struct vme_dev *vdev; | 
|  | 1862 | struct vme_dev *tmp; | 
|  | 1863 |  | 
|  | 1864 | for (i = 0; i < ndevs; i++) { | 
|  | 1865 | vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); | 
|  | 1866 | if (!vdev) { | 
|  | 1867 | err = -ENOMEM; | 
|  | 1868 | goto err_devalloc; | 
|  | 1869 | } | 
|  | 1870 | vdev->num = i; | 
|  | 1871 | vdev->bridge = bridge; | 
|  | 1872 | vdev->dev.platform_data = drv; | 
|  | 1873 | vdev->dev.release = vme_dev_release; | 
|  | 1874 | vdev->dev.parent = bridge->parent; | 
|  | 1875 | vdev->dev.bus = &vme_bus_type; | 
|  | 1876 | dev_set_name(&vdev->dev, "%s.%u-%u", drv->name, bridge->num, | 
|  | 1877 | vdev->num); | 
|  | 1878 |  | 
|  | 1879 | err = device_register(&vdev->dev); | 
|  | 1880 | if (err) | 
|  | 1881 | goto err_reg; | 
|  | 1882 |  | 
|  | 1883 | if (vdev->dev.platform_data) { | 
|  | 1884 | list_add_tail(&vdev->drv_list, &drv->devices); | 
|  | 1885 | list_add_tail(&vdev->bridge_list, &bridge->devices); | 
|  | 1886 | } else | 
|  | 1887 | device_unregister(&vdev->dev); | 
|  | 1888 | } | 
|  | 1889 | return 0; | 
|  | 1890 |  | 
|  | 1891 | err_reg: | 
|  | 1892 | put_device(&vdev->dev); | 
|  | 1893 | kfree(vdev); | 
|  | 1894 | err_devalloc: | 
|  | 1895 | list_for_each_entry_safe(vdev, tmp, &drv->devices, drv_list) { | 
|  | 1896 | list_del(&vdev->drv_list); | 
|  | 1897 | list_del(&vdev->bridge_list); | 
|  | 1898 | device_unregister(&vdev->dev); | 
|  | 1899 | } | 
|  | 1900 | return err; | 
|  | 1901 | } | 
|  | 1902 |  | 
|  | 1903 | static int __vme_register_driver(struct vme_driver *drv, unsigned int ndevs) | 
|  | 1904 | { | 
|  | 1905 | struct vme_bridge *bridge; | 
|  | 1906 | int err = 0; | 
|  | 1907 |  | 
|  | 1908 | mutex_lock(&vme_buses_lock); | 
|  | 1909 | list_for_each_entry(bridge, &vme_bus_list, bus_list) { | 
|  | 1910 | /* | 
|  | 1911 | * This cannot cause trouble as we already have vme_buses_lock | 
|  | 1912 | * and if the bridge is removed, it will have to go through | 
|  | 1913 | * vme_unregister_bridge() to do it (which calls remove() on | 
|  | 1914 | * the bridge which in turn tries to acquire vme_buses_lock and | 
|  | 1915 | * will have to wait). | 
|  | 1916 | */ | 
|  | 1917 | err = __vme_register_driver_bus(drv, bridge, ndevs); | 
|  | 1918 | if (err) | 
|  | 1919 | break; | 
|  | 1920 | } | 
|  | 1921 | mutex_unlock(&vme_buses_lock); | 
|  | 1922 | return err; | 
|  | 1923 | } | 
|  | 1924 |  | 
|  | 1925 | /** | 
|  | 1926 | * vme_register_driver - Register a VME driver | 
|  | 1927 | * @drv: Pointer to VME driver structure to register. | 
|  | 1928 | * @ndevs: Maximum number of devices to allow to be enumerated. | 
|  | 1929 | * | 
|  | 1930 | * Register a VME device driver with the VME subsystem. | 
|  | 1931 | * | 
|  | 1932 | * Return: Zero on success, error value on registration failure. | 
|  | 1933 | */ | 
|  | 1934 | int vme_register_driver(struct vme_driver *drv, unsigned int ndevs) | 
|  | 1935 | { | 
|  | 1936 | int err; | 
|  | 1937 |  | 
|  | 1938 | drv->driver.name = drv->name; | 
|  | 1939 | drv->driver.bus = &vme_bus_type; | 
|  | 1940 | INIT_LIST_HEAD(&drv->devices); | 
|  | 1941 |  | 
|  | 1942 | err = driver_register(&drv->driver); | 
|  | 1943 | if (err) | 
|  | 1944 | return err; | 
|  | 1945 |  | 
|  | 1946 | err = __vme_register_driver(drv, ndevs); | 
|  | 1947 | if (err) | 
|  | 1948 | driver_unregister(&drv->driver); | 
|  | 1949 |  | 
|  | 1950 | return err; | 
|  | 1951 | } | 
|  | 1952 | EXPORT_SYMBOL(vme_register_driver); | 
|  | 1953 |  | 
|  | 1954 | /** | 
|  | 1955 | * vme_unregister_driver - Unregister a VME driver | 
|  | 1956 | * @drv: Pointer to VME driver structure to unregister. | 
|  | 1957 | * | 
|  | 1958 | * Unregister a VME device driver from the VME subsystem. | 
|  | 1959 | */ | 
|  | 1960 | void vme_unregister_driver(struct vme_driver *drv) | 
|  | 1961 | { | 
|  | 1962 | struct vme_dev *dev, *dev_tmp; | 
|  | 1963 |  | 
|  | 1964 | mutex_lock(&vme_buses_lock); | 
|  | 1965 | list_for_each_entry_safe(dev, dev_tmp, &drv->devices, drv_list) { | 
|  | 1966 | list_del(&dev->drv_list); | 
|  | 1967 | list_del(&dev->bridge_list); | 
|  | 1968 | device_unregister(&dev->dev); | 
|  | 1969 | } | 
|  | 1970 | mutex_unlock(&vme_buses_lock); | 
|  | 1971 |  | 
|  | 1972 | driver_unregister(&drv->driver); | 
|  | 1973 | } | 
|  | 1974 | EXPORT_SYMBOL(vme_unregister_driver); | 
|  | 1975 |  | 
|  | 1976 | /* - Bus Registration ------------------------------------------------------ */ | 
|  | 1977 |  | 
|  | 1978 | static int vme_bus_match(struct device *dev, struct device_driver *drv) | 
|  | 1979 | { | 
|  | 1980 | struct vme_driver *vme_drv; | 
|  | 1981 |  | 
|  | 1982 | vme_drv = container_of(drv, struct vme_driver, driver); | 
|  | 1983 |  | 
|  | 1984 | if (dev->platform_data == vme_drv) { | 
|  | 1985 | struct vme_dev *vdev = dev_to_vme_dev(dev); | 
|  | 1986 |  | 
|  | 1987 | if (vme_drv->match && vme_drv->match(vdev)) | 
|  | 1988 | return 1; | 
|  | 1989 |  | 
|  | 1990 | dev->platform_data = NULL; | 
|  | 1991 | } | 
|  | 1992 | return 0; | 
|  | 1993 | } | 
|  | 1994 |  | 
|  | 1995 | static int vme_bus_probe(struct device *dev) | 
|  | 1996 | { | 
|  | 1997 | struct vme_driver *driver; | 
|  | 1998 | struct vme_dev *vdev = dev_to_vme_dev(dev); | 
|  | 1999 |  | 
|  | 2000 | driver = dev->platform_data; | 
|  | 2001 | if (driver->probe) | 
|  | 2002 | return driver->probe(vdev); | 
|  | 2003 |  | 
|  | 2004 | return -ENODEV; | 
|  | 2005 | } | 
|  | 2006 |  | 
|  | 2007 | static int vme_bus_remove(struct device *dev) | 
|  | 2008 | { | 
|  | 2009 | struct vme_driver *driver; | 
|  | 2010 | struct vme_dev *vdev = dev_to_vme_dev(dev); | 
|  | 2011 |  | 
|  | 2012 | driver = dev->platform_data; | 
|  | 2013 | if (driver->remove) | 
|  | 2014 | return driver->remove(vdev); | 
|  | 2015 |  | 
|  | 2016 | return -ENODEV; | 
|  | 2017 | } | 
|  | 2018 |  | 
|  | 2019 | struct bus_type vme_bus_type = { | 
|  | 2020 | .name = "vme", | 
|  | 2021 | .match = vme_bus_match, | 
|  | 2022 | .probe = vme_bus_probe, | 
|  | 2023 | .remove = vme_bus_remove, | 
|  | 2024 | }; | 
|  | 2025 | EXPORT_SYMBOL(vme_bus_type); | 
|  | 2026 |  | 
|  | 2027 | static int __init vme_init(void) | 
|  | 2028 | { | 
|  | 2029 | return bus_register(&vme_bus_type); | 
|  | 2030 | } | 
|  | 2031 | subsys_initcall(vme_init); |