Blame view

drivers/vme/vme.c 52.2 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
a17a75e26   Martyn Welch   Staging: VME Fram...
2
3
4
  /*
   * VME Bridge Framework
   *
66bd8db52   Martyn Welch   Staging: vme: Ren...
5
6
   * Author: Martyn Welch <martyn.welch@ge.com>
   * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
a17a75e26   Martyn Welch   Staging: VME Fram...
7
8
9
   *
   * Based on work by Tom Armistead and Ajit Prem
   * Copyright 2004 Motorola Inc.
a17a75e26   Martyn Welch   Staging: VME Fram...
10
   */
050c3d52c   Paul Gortmaker   vme: make core vm...
11
12
  #include <linux/init.h>
  #include <linux/export.h>
a17a75e26   Martyn Welch   Staging: VME Fram...
13
14
15
16
17
18
19
20
21
22
23
24
  #include <linux/mm.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/errno.h>
  #include <linux/pci.h>
  #include <linux/poll.h>
  #include <linux/highmem.h>
  #include <linux/interrupt.h>
  #include <linux/pagemap.h>
  #include <linux/device.h>
  #include <linux/dma-mapping.h>
  #include <linux/syscalls.h>
400822fec   Martyn Welch   Staging: Use prop...
25
  #include <linux/mutex.h>
a17a75e26   Martyn Welch   Staging: VME Fram...
26
  #include <linux/spinlock.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
27
  #include <linux/slab.h>
db3b9e990   Greg Kroah-Hartman   Staging: VME: mov...
28
  #include <linux/vme.h>
a17a75e26   Martyn Welch   Staging: VME Fram...
29

a17a75e26   Martyn Welch   Staging: VME Fram...
30
  #include "vme_bridge.h"
733e3ef0d   Manohar Vanga   staging: vme: kee...
31
  /* Bitmask and list of registered buses both protected by common mutex */
a17a75e26   Martyn Welch   Staging: VME Fram...
32
  static unsigned int vme_bus_numbers;
733e3ef0d   Manohar Vanga   staging: vme: kee...
33
34
  static LIST_HEAD(vme_bus_list);
  static DEFINE_MUTEX(vme_buses_lock);
a17a75e26   Martyn Welch   Staging: VME Fram...
35

ead1f3e30   Martyn Welch   Staging: vme: Fix...
36
  static int __init vme_init(void);
a17a75e26   Martyn Welch   Staging: VME Fram...
37

8f966dc44   Manohar Vanga   staging: vme: add...
38
  static struct vme_dev *dev_to_vme_dev(struct device *dev)
a17a75e26   Martyn Welch   Staging: VME Fram...
39
  {
8f966dc44   Manohar Vanga   staging: vme: add...
40
  	return container_of(dev, struct vme_dev, dev);
a17a75e26   Martyn Welch   Staging: VME Fram...
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  }
  
  /*
   * Find the bridge that the resource is associated with.
   */
  static struct vme_bridge *find_bridge(struct vme_resource *resource)
  {
  	/* Get list to search */
  	switch (resource->type) {
  	case VME_MASTER:
  		return list_entry(resource->entry, struct vme_master_resource,
  			list)->parent;
  		break;
  	case VME_SLAVE:
  		return list_entry(resource->entry, struct vme_slave_resource,
  			list)->parent;
  		break;
  	case VME_DMA:
  		return list_entry(resource->entry, struct vme_dma_resource,
  			list)->parent;
  		break;
42fb50312   Martyn Welch   Staging: vme: add...
62
63
64
65
  	case VME_LM:
  		return list_entry(resource->entry, struct vme_lm_resource,
  			list)->parent;
  		break;
a17a75e26   Martyn Welch   Staging: VME Fram...
66
67
68
69
70
71
72
  	default:
  		printk(KERN_ERR "Unknown resource type
  ");
  		return NULL;
  		break;
  	}
  }
b5bc980a4   Martyn Welch   docs: Add kernel-...
73
74
75
76
77
78
  /**
   * vme_free_consistent - Allocate contiguous memory.
   * @resource: Pointer to VME resource.
   * @size: Size of allocation required.
   * @dma: Pointer to variable to store physical address of allocation.
   *
a17a75e26   Martyn Welch   Staging: VME Fram...
79
80
   * Allocate a contiguous block of memory for use by the driver. This is used to
   * create the buffers for the slave windows.
b5bc980a4   Martyn Welch   docs: Add kernel-...
81
82
   *
   * Return: Virtual address of allocation on success, NULL on failure.
a17a75e26   Martyn Welch   Staging: VME Fram...
83
   */
ead1f3e30   Martyn Welch   Staging: vme: Fix...
84
  void *vme_alloc_consistent(struct vme_resource *resource, size_t size,
a17a75e26   Martyn Welch   Staging: VME Fram...
85
86
87
  	dma_addr_t *dma)
  {
  	struct vme_bridge *bridge;
a17a75e26   Martyn Welch   Staging: VME Fram...
88

61282c049   Markus Elfring   vme: Adjust 48 ch...
89
  	if (!resource) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
90
91
  		printk(KERN_ERR "No resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
92
93
94
95
  		return NULL;
  	}
  
  	bridge = find_bridge(resource);
61282c049   Markus Elfring   vme: Adjust 48 ch...
96
  	if (!bridge) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
97
98
  		printk(KERN_ERR "Can't find bridge
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
99
100
  		return NULL;
  	}
61282c049   Markus Elfring   vme: Adjust 48 ch...
101
  	if (!bridge->parent) {
25958ce32   Greg Kroah-Hartman   staging: vme: vme...
102
103
  		printk(KERN_ERR "Dev entry NULL for bridge %s
  ", bridge->name);
7f58f0255   Manohar Vanga   staging: vme: mak...
104
105
  		return NULL;
  	}
61282c049   Markus Elfring   vme: Adjust 48 ch...
106
  	if (!bridge->alloc_consistent) {
25958ce32   Greg Kroah-Hartman   staging: vme: vme...
107
108
109
  		printk(KERN_ERR "alloc_consistent not supported by bridge %s
  ",
  		       bridge->name);
a17a75e26   Martyn Welch   Staging: VME Fram...
110
111
  		return NULL;
  	}
a17a75e26   Martyn Welch   Staging: VME Fram...
112

7f58f0255   Manohar Vanga   staging: vme: mak...
113
  	return bridge->alloc_consistent(bridge->parent, size, dma);
a17a75e26   Martyn Welch   Staging: VME Fram...
114
115
  }
  EXPORT_SYMBOL(vme_alloc_consistent);
b5bc980a4   Martyn Welch   docs: Add kernel-...
116
117
118
119
120
121
122
123
  /**
   * vme_free_consistent - Free previously allocated memory.
   * @resource: Pointer to VME resource.
   * @size: Size of allocation to free.
   * @vaddr: Virtual address of allocation.
   * @dma: Physical address of allocation.
   *
   * Free previously allocated block of contiguous memory.
a17a75e26   Martyn Welch   Staging: VME Fram...
124
125
126
127
128
   */
  void vme_free_consistent(struct vme_resource *resource, size_t size,
  	void *vaddr, dma_addr_t dma)
  {
  	struct vme_bridge *bridge;
a17a75e26   Martyn Welch   Staging: VME Fram...
129

61282c049   Markus Elfring   vme: Adjust 48 ch...
130
  	if (!resource) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
131
132
  		printk(KERN_ERR "No resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
133
134
135
136
  		return;
  	}
  
  	bridge = find_bridge(resource);
61282c049   Markus Elfring   vme: Adjust 48 ch...
137
  	if (!bridge) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
138
139
  		printk(KERN_ERR "Can't find bridge
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
140
141
  		return;
  	}
61282c049   Markus Elfring   vme: Adjust 48 ch...
142
  	if (!bridge->parent) {
25958ce32   Greg Kroah-Hartman   staging: vme: vme...
143
144
  		printk(KERN_ERR "Dev entry NULL for bridge %s
  ", bridge->name);
7f58f0255   Manohar Vanga   staging: vme: mak...
145
146
  		return;
  	}
61282c049   Markus Elfring   vme: Adjust 48 ch...
147
  	if (!bridge->free_consistent) {
25958ce32   Greg Kroah-Hartman   staging: vme: vme...
148
149
150
  		printk(KERN_ERR "free_consistent not supported by bridge %s
  ",
  		       bridge->name);
7f58f0255   Manohar Vanga   staging: vme: mak...
151
152
  		return;
  	}
a17a75e26   Martyn Welch   Staging: VME Fram...
153

7f58f0255   Manohar Vanga   staging: vme: mak...
154
  	bridge->free_consistent(bridge->parent, size, vaddr, dma);
a17a75e26   Martyn Welch   Staging: VME Fram...
155
156
  }
  EXPORT_SYMBOL(vme_free_consistent);
b5bc980a4   Martyn Welch   docs: Add kernel-...
157
158
159
160
161
162
163
164
165
166
  /**
   * vme_get_size - Helper function returning size of a VME window
   * @resource: Pointer to VME slave or master resource.
   *
   * Determine the size of the VME window provided. This is a helper
   * function, wrappering the call to vme_master_get or vme_slave_get
   * depending on the type of window resource handed to it.
   *
   * Return: Size of the window on success, zero on failure.
   */
a17a75e26   Martyn Welch   Staging: VME Fram...
167
168
169
170
171
  size_t vme_get_size(struct vme_resource *resource)
  {
  	int enabled, retval;
  	unsigned long long base, size;
  	dma_addr_t buf_base;
6af04b065   Martyn Welch   Staging: VME: Rem...
172
  	u32 aspace, cycle, dwidth;
a17a75e26   Martyn Welch   Staging: VME Fram...
173
174
175
176
177
  
  	switch (resource->type) {
  	case VME_MASTER:
  		retval = vme_master_get(resource, &enabled, &base, &size,
  			&aspace, &cycle, &dwidth);
6ad37567b   Martyn Welch   vme: vme_get_size...
178
179
  		if (retval)
  			return 0;
a17a75e26   Martyn Welch   Staging: VME Fram...
180
181
182
183
184
185
  
  		return size;
  		break;
  	case VME_SLAVE:
  		retval = vme_slave_get(resource, &enabled, &base, &size,
  			&buf_base, &aspace, &cycle);
6ad37567b   Martyn Welch   vme: vme_get_size...
186
187
  		if (retval)
  			return 0;
a17a75e26   Martyn Welch   Staging: VME Fram...
188
189
190
191
192
193
194
195
196
197
198
199
200
201
  
  		return size;
  		break;
  	case VME_DMA:
  		return 0;
  		break;
  	default:
  		printk(KERN_ERR "Unknown resource type
  ");
  		return 0;
  		break;
  	}
  }
  EXPORT_SYMBOL(vme_get_size);
ef73f886b   Dmitry Kalinkin   vme: export vme_c...
202
203
  int vme_check_window(u32 aspace, unsigned long long vme_base,
  		     unsigned long long size)
a17a75e26   Martyn Welch   Staging: VME Fram...
204
205
  {
  	int retval = 0;
bd1479865   Dan Carpenter   vme: Fix integer ...
206
207
  	if (vme_base + size < size)
  		return -EINVAL;
a17a75e26   Martyn Welch   Staging: VME Fram...
208
209
  	switch (aspace) {
  	case VME_A16:
bd1479865   Dan Carpenter   vme: Fix integer ...
210
  		if (vme_base + size > VME_A16_MAX)
a17a75e26   Martyn Welch   Staging: VME Fram...
211
212
213
  			retval = -EFAULT;
  		break;
  	case VME_A24:
bd1479865   Dan Carpenter   vme: Fix integer ...
214
  		if (vme_base + size > VME_A24_MAX)
a17a75e26   Martyn Welch   Staging: VME Fram...
215
216
217
  			retval = -EFAULT;
  		break;
  	case VME_A32:
bd1479865   Dan Carpenter   vme: Fix integer ...
218
  		if (vme_base + size > VME_A32_MAX)
a17a75e26   Martyn Welch   Staging: VME Fram...
219
220
221
  			retval = -EFAULT;
  		break;
  	case VME_A64:
bd1479865   Dan Carpenter   vme: Fix integer ...
222
  		/* The VME_A64_MAX limit is actually U64_MAX + 1 */
a17a75e26   Martyn Welch   Staging: VME Fram...
223
224
  		break;
  	case VME_CRCSR:
bd1479865   Dan Carpenter   vme: Fix integer ...
225
  		if (vme_base + size > VME_CRCSR_MAX)
a17a75e26   Martyn Welch   Staging: VME Fram...
226
227
228
229
230
231
232
233
234
  			retval = -EFAULT;
  		break;
  	case VME_USER1:
  	case VME_USER2:
  	case VME_USER3:
  	case VME_USER4:
  		/* User Defined */
  		break;
  	default:
ead1f3e30   Martyn Welch   Staging: vme: Fix...
235
236
  		printk(KERN_ERR "Invalid address space
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
237
238
239
240
241
242
  		retval = -EINVAL;
  		break;
  	}
  
  	return retval;
  }
ef73f886b   Dmitry Kalinkin   vme: export vme_c...
243
  EXPORT_SYMBOL(vme_check_window);
a17a75e26   Martyn Welch   Staging: VME Fram...
244

472f16f33   Dmitry Kalinkin   vme: include addr...
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  static u32 vme_get_aspace(int am)
  {
  	switch (am) {
  	case 0x29:
  	case 0x2D:
  		return VME_A16;
  	case 0x38:
  	case 0x39:
  	case 0x3A:
  	case 0x3B:
  	case 0x3C:
  	case 0x3D:
  	case 0x3E:
  	case 0x3F:
  		return VME_A24;
  	case 0x8:
  	case 0x9:
  	case 0xA:
  	case 0xB:
  	case 0xC:
  	case 0xD:
  	case 0xE:
  	case 0xF:
  		return VME_A32;
  	case 0x0:
  	case 0x1:
  	case 0x3:
  		return VME_A64;
  	}
  
  	return 0;
  }
b5bc980a4   Martyn Welch   docs: Add kernel-...
277
278
279
280
281
282
283
284
285
286
  /**
   * vme_slave_request - Request a VME slave window resource.
   * @vdev: Pointer to VME device struct vme_dev assigned to driver instance.
   * @address: Required VME address space.
   * @cycle: Required VME data transfer cycle type.
   *
   * Request use of a VME window resource capable of being set for the requested
   * address space and data transfer cycle.
   *
   * Return: Pointer to VME resource on success, NULL on failure.
a17a75e26   Martyn Welch   Staging: VME Fram...
287
   */
6af04b065   Martyn Welch   Staging: VME: Rem...
288
289
  struct vme_resource *vme_slave_request(struct vme_dev *vdev, u32 address,
  	u32 cycle)
a17a75e26   Martyn Welch   Staging: VME Fram...
290
291
292
293
294
295
  {
  	struct vme_bridge *bridge;
  	struct list_head *slave_pos = NULL;
  	struct vme_slave_resource *allocated_image = NULL;
  	struct vme_slave_resource *slave_image = NULL;
  	struct vme_resource *resource = NULL;
8f966dc44   Manohar Vanga   staging: vme: add...
296
  	bridge = vdev->bridge;
61282c049   Markus Elfring   vme: Adjust 48 ch...
297
  	if (!bridge) {
a17a75e26   Martyn Welch   Staging: VME Fram...
298
299
300
301
302
303
  		printk(KERN_ERR "Can't find VME bus
  ");
  		goto err_bus;
  	}
  
  	/* Loop through slave resources */
886953e9b   Emilio G. Cota   staging: vme: sty...
304
  	list_for_each(slave_pos, &bridge->slave_resources) {
a17a75e26   Martyn Welch   Staging: VME Fram...
305
306
  		slave_image = list_entry(slave_pos,
  			struct vme_slave_resource, list);
61282c049   Markus Elfring   vme: Adjust 48 ch...
307
  		if (!slave_image) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
308
309
  			printk(KERN_ERR "Registered NULL Slave resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
310
311
312
313
  			continue;
  		}
  
  		/* Find an unlocked and compatible image */
886953e9b   Emilio G. Cota   staging: vme: sty...
314
  		mutex_lock(&slave_image->mtx);
ead1f3e30   Martyn Welch   Staging: vme: Fix...
315
  		if (((slave_image->address_attr & address) == address) &&
a17a75e26   Martyn Welch   Staging: VME Fram...
316
317
318
319
  			((slave_image->cycle_attr & cycle) == cycle) &&
  			(slave_image->locked == 0)) {
  
  			slave_image->locked = 1;
886953e9b   Emilio G. Cota   staging: vme: sty...
320
  			mutex_unlock(&slave_image->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
321
322
323
  			allocated_image = slave_image;
  			break;
  		}
886953e9b   Emilio G. Cota   staging: vme: sty...
324
  		mutex_unlock(&slave_image->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
325
326
327
  	}
  
  	/* No free image */
61282c049   Markus Elfring   vme: Adjust 48 ch...
328
  	if (!allocated_image)
a17a75e26   Martyn Welch   Staging: VME Fram...
329
  		goto err_image;
1ff0a19ce   Markus Elfring   vme: Improve 11 s...
330
  	resource = kmalloc(sizeof(*resource), GFP_KERNEL);
94eefcc1c   Markus Elfring   vme: Delete 11 er...
331
  	if (!resource)
a17a75e26   Martyn Welch   Staging: VME Fram...
332
  		goto err_alloc;
94eefcc1c   Markus Elfring   vme: Delete 11 er...
333

a17a75e26   Martyn Welch   Staging: VME Fram...
334
  	resource->type = VME_SLAVE;
886953e9b   Emilio G. Cota   staging: vme: sty...
335
  	resource->entry = &allocated_image->list;
a17a75e26   Martyn Welch   Staging: VME Fram...
336
337
338
339
340
  
  	return resource;
  
  err_alloc:
  	/* Unlock image */
886953e9b   Emilio G. Cota   staging: vme: sty...
341
  	mutex_lock(&slave_image->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
342
  	slave_image->locked = 0;
886953e9b   Emilio G. Cota   staging: vme: sty...
343
  	mutex_unlock(&slave_image->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
344
345
346
347
348
  err_image:
  err_bus:
  	return NULL;
  }
  EXPORT_SYMBOL(vme_slave_request);
b5bc980a4   Martyn Welch   docs: Add kernel-...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
  /**
   * vme_slave_set - Set VME slave window configuration.
   * @resource: Pointer to VME slave resource.
   * @enabled: State to which the window should be configured.
   * @vme_base: Base address for the window.
   * @size: Size of the VME window.
   * @buf_base: Based address of buffer used to provide VME slave window storage.
   * @aspace: VME address space for the VME window.
   * @cycle: VME data transfer cycle type for the VME window.
   *
   * Set configuration for provided VME slave window.
   *
   * Return: Zero on success, -EINVAL if operation is not supported on this
   *         device, if an invalid resource has been provided or invalid
   *         attributes are provided. Hardware specific errors may also be
   *         returned.
   */
ead1f3e30   Martyn Welch   Staging: vme: Fix...
366
  int vme_slave_set(struct vme_resource *resource, int enabled,
a17a75e26   Martyn Welch   Staging: VME Fram...
367
  	unsigned long long vme_base, unsigned long long size,
6af04b065   Martyn Welch   Staging: VME: Rem...
368
  	dma_addr_t buf_base, u32 aspace, u32 cycle)
a17a75e26   Martyn Welch   Staging: VME Fram...
369
370
371
372
373
374
  {
  	struct vme_bridge *bridge = find_bridge(resource);
  	struct vme_slave_resource *image;
  	int retval;
  
  	if (resource->type != VME_SLAVE) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
375
376
  		printk(KERN_ERR "Not a slave resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
377
378
379
380
  		return -EINVAL;
  	}
  
  	image = list_entry(resource->entry, struct vme_slave_resource, list);
61282c049   Markus Elfring   vme: Adjust 48 ch...
381
  	if (!bridge->slave_set) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
382
383
  		printk(KERN_ERR "Function not supported
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
384
385
  		return -ENOSYS;
  	}
ead1f3e30   Martyn Welch   Staging: vme: Fix...
386
  	if (!(((image->address_attr & aspace) == aspace) &&
a17a75e26   Martyn Welch   Staging: VME Fram...
387
  		((image->cycle_attr & cycle) == cycle))) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
388
389
  		printk(KERN_ERR "Invalid attributes
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
390
391
392
393
  		return -EINVAL;
  	}
  
  	retval = vme_check_window(aspace, vme_base, size);
ead1f3e30   Martyn Welch   Staging: vme: Fix...
394
  	if (retval)
a17a75e26   Martyn Welch   Staging: VME Fram...
395
396
397
398
399
400
  		return retval;
  
  	return bridge->slave_set(image, enabled, vme_base, size, buf_base,
  		aspace, cycle);
  }
  EXPORT_SYMBOL(vme_slave_set);
b5bc980a4   Martyn Welch   docs: Add kernel-...
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
  /**
   * vme_slave_get - Retrieve VME slave window configuration.
   * @resource: Pointer to VME slave resource.
   * @enabled: Pointer to variable for storing state.
   * @vme_base: Pointer to variable for storing window base address.
   * @size: Pointer to variable for storing window size.
   * @buf_base: Pointer to variable for storing slave buffer base address.
   * @aspace: Pointer to variable for storing VME address space.
   * @cycle: Pointer to variable for storing VME data transfer cycle type.
   *
   * Return configuration for provided VME slave window.
   *
   * Return: Zero on success, -EINVAL if operation is not supported on this
   *         device or if an invalid resource has been provided.
   */
ead1f3e30   Martyn Welch   Staging: vme: Fix...
416
  int vme_slave_get(struct vme_resource *resource, int *enabled,
a17a75e26   Martyn Welch   Staging: VME Fram...
417
  	unsigned long long *vme_base, unsigned long long *size,
6af04b065   Martyn Welch   Staging: VME: Rem...
418
  	dma_addr_t *buf_base, u32 *aspace, u32 *cycle)
a17a75e26   Martyn Welch   Staging: VME Fram...
419
420
421
422
423
  {
  	struct vme_bridge *bridge = find_bridge(resource);
  	struct vme_slave_resource *image;
  
  	if (resource->type != VME_SLAVE) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
424
425
  		printk(KERN_ERR "Not a slave resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
426
427
428
429
  		return -EINVAL;
  	}
  
  	image = list_entry(resource->entry, struct vme_slave_resource, list);
61282c049   Markus Elfring   vme: Adjust 48 ch...
430
  	if (!bridge->slave_get) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
431
432
  		printk(KERN_ERR "vme_slave_get not supported
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
433
434
435
436
437
438
439
  		return -EINVAL;
  	}
  
  	return bridge->slave_get(image, enabled, vme_base, size, buf_base,
  		aspace, cycle);
  }
  EXPORT_SYMBOL(vme_slave_get);
b5bc980a4   Martyn Welch   docs: Add kernel-...
440
441
442
443
444
445
  /**
   * vme_slave_free - Free VME slave window
   * @resource: Pointer to VME slave resource.
   *
   * Free the provided slave resource so that it may be reallocated.
   */
a17a75e26   Martyn Welch   Staging: VME Fram...
446
447
448
449
450
  void vme_slave_free(struct vme_resource *resource)
  {
  	struct vme_slave_resource *slave_image;
  
  	if (resource->type != VME_SLAVE) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
451
452
  		printk(KERN_ERR "Not a slave resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
453
454
455
456
457
  		return;
  	}
  
  	slave_image = list_entry(resource->entry, struct vme_slave_resource,
  		list);
61282c049   Markus Elfring   vme: Adjust 48 ch...
458
  	if (!slave_image) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
459
460
  		printk(KERN_ERR "Can't find slave resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
461
462
463
464
  		return;
  	}
  
  	/* Unlock image */
886953e9b   Emilio G. Cota   staging: vme: sty...
465
  	mutex_lock(&slave_image->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
466
467
468
469
470
  	if (slave_image->locked == 0)
  		printk(KERN_ERR "Image is already free
  ");
  
  	slave_image->locked = 0;
886953e9b   Emilio G. Cota   staging: vme: sty...
471
  	mutex_unlock(&slave_image->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
472
473
474
475
476
  
  	/* Free up resource memory */
  	kfree(resource);
  }
  EXPORT_SYMBOL(vme_slave_free);
b5bc980a4   Martyn Welch   docs: Add kernel-...
477
478
479
480
481
482
483
484
485
486
487
  /**
   * vme_master_request - Request a VME master window resource.
   * @vdev: Pointer to VME device struct vme_dev assigned to driver instance.
   * @address: Required VME address space.
   * @cycle: Required VME data transfer cycle type.
   * @dwidth: Required VME data transfer width.
   *
   * Request use of a VME window resource capable of being set for the requested
   * address space, data transfer cycle and width.
   *
   * Return: Pointer to VME resource on success, NULL on failure.
a17a75e26   Martyn Welch   Staging: VME Fram...
488
   */
6af04b065   Martyn Welch   Staging: VME: Rem...
489
490
  struct vme_resource *vme_master_request(struct vme_dev *vdev, u32 address,
  	u32 cycle, u32 dwidth)
a17a75e26   Martyn Welch   Staging: VME Fram...
491
492
493
494
495
496
  {
  	struct vme_bridge *bridge;
  	struct list_head *master_pos = NULL;
  	struct vme_master_resource *allocated_image = NULL;
  	struct vme_master_resource *master_image = NULL;
  	struct vme_resource *resource = NULL;
8f966dc44   Manohar Vanga   staging: vme: add...
497
  	bridge = vdev->bridge;
61282c049   Markus Elfring   vme: Adjust 48 ch...
498
  	if (!bridge) {
a17a75e26   Martyn Welch   Staging: VME Fram...
499
500
501
502
503
504
  		printk(KERN_ERR "Can't find VME bus
  ");
  		goto err_bus;
  	}
  
  	/* Loop through master resources */
886953e9b   Emilio G. Cota   staging: vme: sty...
505
  	list_for_each(master_pos, &bridge->master_resources) {
a17a75e26   Martyn Welch   Staging: VME Fram...
506
507
  		master_image = list_entry(master_pos,
  			struct vme_master_resource, list);
61282c049   Markus Elfring   vme: Adjust 48 ch...
508
  		if (!master_image) {
a17a75e26   Martyn Welch   Staging: VME Fram...
509
510
511
512
513
514
  			printk(KERN_WARNING "Registered NULL master resource
  ");
  			continue;
  		}
  
  		/* Find an unlocked and compatible image */
886953e9b   Emilio G. Cota   staging: vme: sty...
515
  		spin_lock(&master_image->lock);
ead1f3e30   Martyn Welch   Staging: vme: Fix...
516
  		if (((master_image->address_attr & address) == address) &&
a17a75e26   Martyn Welch   Staging: VME Fram...
517
518
519
520
521
  			((master_image->cycle_attr & cycle) == cycle) &&
  			((master_image->width_attr & dwidth) == dwidth) &&
  			(master_image->locked == 0)) {
  
  			master_image->locked = 1;
886953e9b   Emilio G. Cota   staging: vme: sty...
522
  			spin_unlock(&master_image->lock);
a17a75e26   Martyn Welch   Staging: VME Fram...
523
524
525
  			allocated_image = master_image;
  			break;
  		}
886953e9b   Emilio G. Cota   staging: vme: sty...
526
  		spin_unlock(&master_image->lock);
a17a75e26   Martyn Welch   Staging: VME Fram...
527
528
529
  	}
  
  	/* Check to see if we found a resource */
61282c049   Markus Elfring   vme: Adjust 48 ch...
530
  	if (!allocated_image) {
a17a75e26   Martyn Welch   Staging: VME Fram...
531
532
533
534
  		printk(KERN_ERR "Can't find a suitable resource
  ");
  		goto err_image;
  	}
1ff0a19ce   Markus Elfring   vme: Improve 11 s...
535
  	resource = kmalloc(sizeof(*resource), GFP_KERNEL);
94eefcc1c   Markus Elfring   vme: Delete 11 er...
536
  	if (!resource)
a17a75e26   Martyn Welch   Staging: VME Fram...
537
  		goto err_alloc;
94eefcc1c   Markus Elfring   vme: Delete 11 er...
538

a17a75e26   Martyn Welch   Staging: VME Fram...
539
  	resource->type = VME_MASTER;
886953e9b   Emilio G. Cota   staging: vme: sty...
540
  	resource->entry = &allocated_image->list;
a17a75e26   Martyn Welch   Staging: VME Fram...
541
542
  
  	return resource;
a17a75e26   Martyn Welch   Staging: VME Fram...
543
544
  err_alloc:
  	/* Unlock image */
886953e9b   Emilio G. Cota   staging: vme: sty...
545
  	spin_lock(&master_image->lock);
a17a75e26   Martyn Welch   Staging: VME Fram...
546
  	master_image->locked = 0;
886953e9b   Emilio G. Cota   staging: vme: sty...
547
  	spin_unlock(&master_image->lock);
a17a75e26   Martyn Welch   Staging: VME Fram...
548
549
550
551
552
  err_image:
  err_bus:
  	return NULL;
  }
  EXPORT_SYMBOL(vme_master_request);
b5bc980a4   Martyn Welch   docs: Add kernel-...
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
  /**
   * vme_master_set - Set VME master window configuration.
   * @resource: Pointer to VME master resource.
   * @enabled: State to which the window should be configured.
   * @vme_base: Base address for the window.
   * @size: Size of the VME window.
   * @aspace: VME address space for the VME window.
   * @cycle: VME data transfer cycle type for the VME window.
   * @dwidth: VME data transfer width for the VME window.
   *
   * Set configuration for provided VME master window.
   *
   * Return: Zero on success, -EINVAL if operation is not supported on this
   *         device, if an invalid resource has been provided or invalid
   *         attributes are provided. Hardware specific errors may also be
   *         returned.
   */
ead1f3e30   Martyn Welch   Staging: vme: Fix...
570
  int vme_master_set(struct vme_resource *resource, int enabled,
6af04b065   Martyn Welch   Staging: VME: Rem...
571
572
  	unsigned long long vme_base, unsigned long long size, u32 aspace,
  	u32 cycle, u32 dwidth)
a17a75e26   Martyn Welch   Staging: VME Fram...
573
574
575
576
577
578
  {
  	struct vme_bridge *bridge = find_bridge(resource);
  	struct vme_master_resource *image;
  	int retval;
  
  	if (resource->type != VME_MASTER) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
579
580
  		printk(KERN_ERR "Not a master resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
581
582
583
584
  		return -EINVAL;
  	}
  
  	image = list_entry(resource->entry, struct vme_master_resource, list);
61282c049   Markus Elfring   vme: Adjust 48 ch...
585
  	if (!bridge->master_set) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
586
587
  		printk(KERN_WARNING "vme_master_set not supported
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
588
589
  		return -EINVAL;
  	}
ead1f3e30   Martyn Welch   Staging: vme: Fix...
590
  	if (!(((image->address_attr & aspace) == aspace) &&
a17a75e26   Martyn Welch   Staging: VME Fram...
591
592
  		((image->cycle_attr & cycle) == cycle) &&
  		((image->width_attr & dwidth) == dwidth))) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
593
594
  		printk(KERN_WARNING "Invalid attributes
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
595
596
597
598
  		return -EINVAL;
  	}
  
  	retval = vme_check_window(aspace, vme_base, size);
ead1f3e30   Martyn Welch   Staging: vme: Fix...
599
  	if (retval)
a17a75e26   Martyn Welch   Staging: VME Fram...
600
601
602
603
604
605
  		return retval;
  
  	return bridge->master_set(image, enabled, vme_base, size, aspace,
  		cycle, dwidth);
  }
  EXPORT_SYMBOL(vme_master_set);
b5bc980a4   Martyn Welch   docs: Add kernel-...
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
  /**
   * vme_master_get - Retrieve VME master window configuration.
   * @resource: Pointer to VME master resource.
   * @enabled: Pointer to variable for storing state.
   * @vme_base: Pointer to variable for storing window base address.
   * @size: Pointer to variable for storing window size.
   * @aspace: Pointer to variable for storing VME address space.
   * @cycle: Pointer to variable for storing VME data transfer cycle type.
   * @dwidth: Pointer to variable for storing VME data transfer width.
   *
   * Return configuration for provided VME master window.
   *
   * Return: Zero on success, -EINVAL if operation is not supported on this
   *         device or if an invalid resource has been provided.
   */
ead1f3e30   Martyn Welch   Staging: vme: Fix...
621
  int vme_master_get(struct vme_resource *resource, int *enabled,
6af04b065   Martyn Welch   Staging: VME: Rem...
622
623
  	unsigned long long *vme_base, unsigned long long *size, u32 *aspace,
  	u32 *cycle, u32 *dwidth)
a17a75e26   Martyn Welch   Staging: VME Fram...
624
625
626
627
628
  {
  	struct vme_bridge *bridge = find_bridge(resource);
  	struct vme_master_resource *image;
  
  	if (resource->type != VME_MASTER) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
629
630
  		printk(KERN_ERR "Not a master resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
631
632
633
634
  		return -EINVAL;
  	}
  
  	image = list_entry(resource->entry, struct vme_master_resource, list);
61282c049   Markus Elfring   vme: Adjust 48 ch...
635
  	if (!bridge->master_get) {
c1038307c   Julia Lawall   vme: fix misspell...
636
637
  		printk(KERN_WARNING "%s not supported
  ", __func__);
a17a75e26   Martyn Welch   Staging: VME Fram...
638
639
640
641
642
643
644
  		return -EINVAL;
  	}
  
  	return bridge->master_get(image, enabled, vme_base, size, aspace,
  		cycle, dwidth);
  }
  EXPORT_SYMBOL(vme_master_get);
b5bc980a4   Martyn Welch   docs: Add kernel-...
645
646
647
648
649
650
651
652
653
654
655
656
657
658
  /**
   * vme_master_write - Read data from VME space into a buffer.
   * @resource: Pointer to VME master resource.
   * @buf: Pointer to buffer where data should be transferred.
   * @count: Number of bytes to transfer.
   * @offset: Offset into VME master window at which to start transfer.
   *
   * Perform read of count bytes of data from location on VME bus which maps into
   * the VME master window at offset to buf.
   *
   * Return: Number of bytes read, -EINVAL if resource is not a VME master
   *         resource or read operation is not supported. -EFAULT returned if
   *         invalid offset is provided. Hardware specific errors may also be
   *         returned.
a17a75e26   Martyn Welch   Staging: VME Fram...
659
   */
ead1f3e30   Martyn Welch   Staging: vme: Fix...
660
  ssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count,
a17a75e26   Martyn Welch   Staging: VME Fram...
661
662
663
664
665
  	loff_t offset)
  {
  	struct vme_bridge *bridge = find_bridge(resource);
  	struct vme_master_resource *image;
  	size_t length;
61282c049   Markus Elfring   vme: Adjust 48 ch...
666
  	if (!bridge->master_read) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
667
668
  		printk(KERN_WARNING "Reading from resource not supported
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
669
670
671
672
  		return -EINVAL;
  	}
  
  	if (resource->type != VME_MASTER) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
673
674
  		printk(KERN_ERR "Not a master resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
675
676
677
678
679
680
681
682
  		return -EINVAL;
  	}
  
  	image = list_entry(resource->entry, struct vme_master_resource, list);
  
  	length = vme_get_size(resource);
  
  	if (offset > length) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
683
684
  		printk(KERN_WARNING "Invalid Offset
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
685
686
687
688
689
690
691
692
693
694
  		return -EFAULT;
  	}
  
  	if ((offset + count) > length)
  		count = length - offset;
  
  	return bridge->master_read(image, buf, count, offset);
  
  }
  EXPORT_SYMBOL(vme_master_read);
b5bc980a4   Martyn Welch   docs: Add kernel-...
695
696
697
698
699
700
701
702
703
704
705
706
707
708
  /**
   * vme_master_write - Write data out to VME space from a buffer.
   * @resource: Pointer to VME master resource.
   * @buf: Pointer to buffer holding data to transfer.
   * @count: Number of bytes to transfer.
   * @offset: Offset into VME master window at which to start transfer.
   *
   * Perform write of count bytes of data from buf to location on VME bus which
   * maps into the VME master window at offset.
   *
   * Return: Number of bytes written, -EINVAL if resource is not a VME master
   *         resource or write operation is not supported. -EFAULT returned if
   *         invalid offset is provided. Hardware specific errors may also be
   *         returned.
a17a75e26   Martyn Welch   Staging: VME Fram...
709
   */
ead1f3e30   Martyn Welch   Staging: vme: Fix...
710
  ssize_t vme_master_write(struct vme_resource *resource, void *buf,
a17a75e26   Martyn Welch   Staging: VME Fram...
711
712
713
714
715
  	size_t count, loff_t offset)
  {
  	struct vme_bridge *bridge = find_bridge(resource);
  	struct vme_master_resource *image;
  	size_t length;
61282c049   Markus Elfring   vme: Adjust 48 ch...
716
  	if (!bridge->master_write) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
717
718
  		printk(KERN_WARNING "Writing to resource not supported
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
719
720
721
722
  		return -EINVAL;
  	}
  
  	if (resource->type != VME_MASTER) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
723
724
  		printk(KERN_ERR "Not a master resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
725
726
727
728
729
730
731
732
  		return -EINVAL;
  	}
  
  	image = list_entry(resource->entry, struct vme_master_resource, list);
  
  	length = vme_get_size(resource);
  
  	if (offset > length) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
733
734
  		printk(KERN_WARNING "Invalid Offset
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
735
736
737
738
739
740
741
742
743
  		return -EFAULT;
  	}
  
  	if ((offset + count) > length)
  		count = length - offset;
  
  	return bridge->master_write(image, buf, count, offset);
  }
  EXPORT_SYMBOL(vme_master_write);
b5bc980a4   Martyn Welch   docs: Add kernel-...
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
  /**
   * vme_master_rmw - Perform read-modify-write cycle.
   * @resource: Pointer to VME master resource.
   * @mask: Bits to be compared and swapped in operation.
   * @compare: Bits to be compared with data read from offset.
   * @swap: Bits to be swapped in data read from offset.
   * @offset: Offset into VME master window at which to perform operation.
   *
   * Perform read-modify-write cycle on provided location:
   * - Location on VME bus is read.
   * - Bits selected by mask are compared with compare.
   * - Where a selected bit matches that in compare and are selected in swap,
   * the bit is swapped.
   * - Result written back to location on VME bus.
   *
   * Return: Bytes written on success, -EINVAL if resource is not a VME master
   *         resource or RMW operation is not supported. Hardware specific
   *         errors may also be returned.
a17a75e26   Martyn Welch   Staging: VME Fram...
762
   */
ead1f3e30   Martyn Welch   Staging: vme: Fix...
763
  unsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask,
a17a75e26   Martyn Welch   Staging: VME Fram...
764
765
766
767
  	unsigned int compare, unsigned int swap, loff_t offset)
  {
  	struct vme_bridge *bridge = find_bridge(resource);
  	struct vme_master_resource *image;
61282c049   Markus Elfring   vme: Adjust 48 ch...
768
  	if (!bridge->master_rmw) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
769
770
  		printk(KERN_WARNING "Writing to resource not supported
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
771
772
773
774
  		return -EINVAL;
  	}
  
  	if (resource->type != VME_MASTER) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
775
776
  		printk(KERN_ERR "Not a master resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
777
778
779
780
781
782
783
784
  		return -EINVAL;
  	}
  
  	image = list_entry(resource->entry, struct vme_master_resource, list);
  
  	return bridge->master_rmw(image, mask, compare, swap, offset);
  }
  EXPORT_SYMBOL(vme_master_rmw);
b5bc980a4   Martyn Welch   docs: Add kernel-...
785
786
787
788
789
790
791
792
793
794
795
  /**
   * vme_master_mmap - Mmap region of VME master window.
   * @resource: Pointer to VME master resource.
   * @vma: Pointer to definition of user mapping.
   *
   * Memory map a region of the VME master window into user space.
   *
   * Return: Zero on success, -EINVAL if resource is not a VME master
   *         resource or -EFAULT if map exceeds window size. Other generic mmap
   *         errors may also be returned.
   */
c74a804f1   Dmitry Kalinkin   staging: vme: mma...
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
  int vme_master_mmap(struct vme_resource *resource, struct vm_area_struct *vma)
  {
  	struct vme_master_resource *image;
  	phys_addr_t phys_addr;
  	unsigned long vma_size;
  
  	if (resource->type != VME_MASTER) {
  		pr_err("Not a master resource
  ");
  		return -EINVAL;
  	}
  
  	image = list_entry(resource->entry, struct vme_master_resource, list);
  	phys_addr = image->bus_resource.start + (vma->vm_pgoff << PAGE_SHIFT);
  	vma_size = vma->vm_end - vma->vm_start;
  
  	if (phys_addr + vma_size > image->bus_resource.end + 1) {
  		pr_err("Map size cannot exceed the window size
  ");
  		return -EFAULT;
  	}
  
  	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
  
  	return vm_iomap_memory(vma, phys_addr, vma->vm_end - vma->vm_start);
  }
  EXPORT_SYMBOL(vme_master_mmap);
b5bc980a4   Martyn Welch   docs: Add kernel-...
823
824
825
826
827
828
  /**
   * vme_master_free - Free VME master window
   * @resource: Pointer to VME master resource.
   *
   * Free the provided master resource so that it may be reallocated.
   */
a17a75e26   Martyn Welch   Staging: VME Fram...
829
830
831
832
833
  void vme_master_free(struct vme_resource *resource)
  {
  	struct vme_master_resource *master_image;
  
  	if (resource->type != VME_MASTER) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
834
835
  		printk(KERN_ERR "Not a master resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
836
837
838
839
840
  		return;
  	}
  
  	master_image = list_entry(resource->entry, struct vme_master_resource,
  		list);
61282c049   Markus Elfring   vme: Adjust 48 ch...
841
  	if (!master_image) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
842
843
  		printk(KERN_ERR "Can't find master resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
844
845
846
847
  		return;
  	}
  
  	/* Unlock image */
886953e9b   Emilio G. Cota   staging: vme: sty...
848
  	spin_lock(&master_image->lock);
a17a75e26   Martyn Welch   Staging: VME Fram...
849
850
851
852
853
  	if (master_image->locked == 0)
  		printk(KERN_ERR "Image is already free
  ");
  
  	master_image->locked = 0;
886953e9b   Emilio G. Cota   staging: vme: sty...
854
  	spin_unlock(&master_image->lock);
a17a75e26   Martyn Welch   Staging: VME Fram...
855
856
857
858
859
  
  	/* Free up resource memory */
  	kfree(resource);
  }
  EXPORT_SYMBOL(vme_master_free);
b5bc980a4   Martyn Welch   docs: Add kernel-...
860
861
862
863
864
865
866
867
868
  /**
   * vme_dma_request - Request a DMA controller.
   * @vdev: Pointer to VME device struct vme_dev assigned to driver instance.
   * @route: Required src/destination combination.
   *
   * Request a VME DMA controller with capability to perform transfers bewteen
   * requested source/destination combination.
   *
   * Return: Pointer to VME DMA resource on success, NULL on failure.
a17a75e26   Martyn Welch   Staging: VME Fram...
869
   */
6af04b065   Martyn Welch   Staging: VME: Rem...
870
  struct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 route)
a17a75e26   Martyn Welch   Staging: VME Fram...
871
872
873
874
875
876
877
878
879
880
  {
  	struct vme_bridge *bridge;
  	struct list_head *dma_pos = NULL;
  	struct vme_dma_resource *allocated_ctrlr = NULL;
  	struct vme_dma_resource *dma_ctrlr = NULL;
  	struct vme_resource *resource = NULL;
  
  	/* XXX Not checking resource attributes */
  	printk(KERN_ERR "No VME resource Attribute tests done
  ");
8f966dc44   Manohar Vanga   staging: vme: add...
881
  	bridge = vdev->bridge;
61282c049   Markus Elfring   vme: Adjust 48 ch...
882
  	if (!bridge) {
a17a75e26   Martyn Welch   Staging: VME Fram...
883
884
885
886
887
888
  		printk(KERN_ERR "Can't find VME bus
  ");
  		goto err_bus;
  	}
  
  	/* Loop through DMA resources */
886953e9b   Emilio G. Cota   staging: vme: sty...
889
  	list_for_each(dma_pos, &bridge->dma_resources) {
a17a75e26   Martyn Welch   Staging: VME Fram...
890
891
  		dma_ctrlr = list_entry(dma_pos,
  			struct vme_dma_resource, list);
61282c049   Markus Elfring   vme: Adjust 48 ch...
892
  		if (!dma_ctrlr) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
893
894
  			printk(KERN_ERR "Registered NULL DMA resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
895
896
  			continue;
  		}
4f723df45   Martyn Welch   Staging: vme: Att...
897
  		/* Find an unlocked and compatible controller */
886953e9b   Emilio G. Cota   staging: vme: sty...
898
  		mutex_lock(&dma_ctrlr->mtx);
4f723df45   Martyn Welch   Staging: vme: Att...
899
900
  		if (((dma_ctrlr->route_attr & route) == route) &&
  			(dma_ctrlr->locked == 0)) {
a17a75e26   Martyn Welch   Staging: VME Fram...
901
  			dma_ctrlr->locked = 1;
886953e9b   Emilio G. Cota   staging: vme: sty...
902
  			mutex_unlock(&dma_ctrlr->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
903
904
905
  			allocated_ctrlr = dma_ctrlr;
  			break;
  		}
886953e9b   Emilio G. Cota   staging: vme: sty...
906
  		mutex_unlock(&dma_ctrlr->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
907
908
909
  	}
  
  	/* Check to see if we found a resource */
61282c049   Markus Elfring   vme: Adjust 48 ch...
910
  	if (!allocated_ctrlr)
a17a75e26   Martyn Welch   Staging: VME Fram...
911
  		goto err_ctrlr;
1ff0a19ce   Markus Elfring   vme: Improve 11 s...
912
  	resource = kmalloc(sizeof(*resource), GFP_KERNEL);
94eefcc1c   Markus Elfring   vme: Delete 11 er...
913
  	if (!resource)
a17a75e26   Martyn Welch   Staging: VME Fram...
914
  		goto err_alloc;
94eefcc1c   Markus Elfring   vme: Delete 11 er...
915

a17a75e26   Martyn Welch   Staging: VME Fram...
916
  	resource->type = VME_DMA;
886953e9b   Emilio G. Cota   staging: vme: sty...
917
  	resource->entry = &allocated_ctrlr->list;
a17a75e26   Martyn Welch   Staging: VME Fram...
918
919
920
921
922
  
  	return resource;
  
  err_alloc:
  	/* Unlock image */
886953e9b   Emilio G. Cota   staging: vme: sty...
923
  	mutex_lock(&dma_ctrlr->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
924
  	dma_ctrlr->locked = 0;
886953e9b   Emilio G. Cota   staging: vme: sty...
925
  	mutex_unlock(&dma_ctrlr->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
926
927
928
929
  err_ctrlr:
  err_bus:
  	return NULL;
  }
58e507987   Martyn Welch   Staging: vme: Ren...
930
  EXPORT_SYMBOL(vme_dma_request);
a17a75e26   Martyn Welch   Staging: VME Fram...
931

b5bc980a4   Martyn Welch   docs: Add kernel-...
932
933
934
935
936
937
938
939
940
  /**
   * vme_new_dma_list - Create new VME DMA list.
   * @resource: Pointer to VME DMA resource.
   *
   * Create a new VME DMA list. It is the responsibility of the user to free
   * the list once it is no longer required with vme_dma_list_free().
   *
   * Return: Pointer to new VME DMA list, NULL on allocation failure or invalid
   *         VME DMA resource.
a17a75e26   Martyn Welch   Staging: VME Fram...
941
942
943
   */
  struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource)
  {
a17a75e26   Martyn Welch   Staging: VME Fram...
944
945
946
  	struct vme_dma_list *dma_list;
  
  	if (resource->type != VME_DMA) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
947
948
  		printk(KERN_ERR "Not a DMA resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
949
950
  		return NULL;
  	}
1ff0a19ce   Markus Elfring   vme: Improve 11 s...
951
  	dma_list = kmalloc(sizeof(*dma_list), GFP_KERNEL);
94eefcc1c   Markus Elfring   vme: Delete 11 er...
952
  	if (!dma_list)
a17a75e26   Martyn Welch   Staging: VME Fram...
953
  		return NULL;
94eefcc1c   Markus Elfring   vme: Delete 11 er...
954

886953e9b   Emilio G. Cota   staging: vme: sty...
955
  	INIT_LIST_HEAD(&dma_list->entries);
a384b2cc1   Markus Elfring   vme: Move an assi...
956
957
958
  	dma_list->parent = list_entry(resource->entry,
  				      struct vme_dma_resource,
  				      list);
886953e9b   Emilio G. Cota   staging: vme: sty...
959
  	mutex_init(&dma_list->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
960
961
962
963
  
  	return dma_list;
  }
  EXPORT_SYMBOL(vme_new_dma_list);
b5bc980a4   Martyn Welch   docs: Add kernel-...
964
965
966
967
968
969
970
971
972
973
  /**
   * vme_dma_pattern_attribute - Create "Pattern" type VME DMA list attribute.
   * @pattern: Value to use used as pattern
   * @type: Type of pattern to be written.
   *
   * Create VME DMA list attribute for pattern generation. It is the
   * responsibility of the user to free used attributes using
   * vme_dma_free_attribute().
   *
   * Return: Pointer to VME DMA attribute, NULL on failure.
a17a75e26   Martyn Welch   Staging: VME Fram...
974
   */
6af04b065   Martyn Welch   Staging: VME: Rem...
975
  struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type)
a17a75e26   Martyn Welch   Staging: VME Fram...
976
977
978
  {
  	struct vme_dma_attr *attributes;
  	struct vme_dma_pattern *pattern_attr;
1ff0a19ce   Markus Elfring   vme: Improve 11 s...
979
  	attributes = kmalloc(sizeof(*attributes), GFP_KERNEL);
94eefcc1c   Markus Elfring   vme: Delete 11 er...
980
  	if (!attributes)
a17a75e26   Martyn Welch   Staging: VME Fram...
981
  		goto err_attr;
a17a75e26   Martyn Welch   Staging: VME Fram...
982

1ff0a19ce   Markus Elfring   vme: Improve 11 s...
983
  	pattern_attr = kmalloc(sizeof(*pattern_attr), GFP_KERNEL);
94eefcc1c   Markus Elfring   vme: Delete 11 er...
984
  	if (!pattern_attr)
a17a75e26   Martyn Welch   Staging: VME Fram...
985
  		goto err_pat;
a17a75e26   Martyn Welch   Staging: VME Fram...
986
987
988
989
990
991
992
993
  
  	attributes->type = VME_DMA_PATTERN;
  	attributes->private = (void *)pattern_attr;
  
  	pattern_attr->pattern = pattern;
  	pattern_attr->type = type;
  
  	return attributes;
a17a75e26   Martyn Welch   Staging: VME Fram...
994
995
996
997
998
999
  err_pat:
  	kfree(attributes);
  err_attr:
  	return NULL;
  }
  EXPORT_SYMBOL(vme_dma_pattern_attribute);
b5bc980a4   Martyn Welch   docs: Add kernel-...
1000
1001
1002
1003
1004
1005
1006
1007
1008
  /**
   * vme_dma_pci_attribute - Create "PCI" type VME DMA list attribute.
   * @address: PCI base address for DMA transfer.
   *
   * Create VME DMA list attribute pointing to a location on PCI for DMA
   * transfers. It is the responsibility of the user to free used attributes
   * using vme_dma_free_attribute().
   *
   * Return: Pointer to VME DMA attribute, NULL on failure.
a17a75e26   Martyn Welch   Staging: VME Fram...
1009
1010
1011
1012
1013
1014
1015
   */
  struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address)
  {
  	struct vme_dma_attr *attributes;
  	struct vme_dma_pci *pci_attr;
  
  	/* XXX Run some sanity checks here */
1ff0a19ce   Markus Elfring   vme: Improve 11 s...
1016
  	attributes = kmalloc(sizeof(*attributes), GFP_KERNEL);
94eefcc1c   Markus Elfring   vme: Delete 11 er...
1017
  	if (!attributes)
a17a75e26   Martyn Welch   Staging: VME Fram...
1018
  		goto err_attr;
a17a75e26   Martyn Welch   Staging: VME Fram...
1019

1ff0a19ce   Markus Elfring   vme: Improve 11 s...
1020
  	pci_attr = kmalloc(sizeof(*pci_attr), GFP_KERNEL);
94eefcc1c   Markus Elfring   vme: Delete 11 er...
1021
  	if (!pci_attr)
a17a75e26   Martyn Welch   Staging: VME Fram...
1022
  		goto err_pci;
a17a75e26   Martyn Welch   Staging: VME Fram...
1023
1024
1025
1026
1027
1028
1029
  
  	attributes->type = VME_DMA_PCI;
  	attributes->private = (void *)pci_attr;
  
  	pci_attr->address = address;
  
  	return attributes;
a17a75e26   Martyn Welch   Staging: VME Fram...
1030
1031
1032
1033
1034
1035
  err_pci:
  	kfree(attributes);
  err_attr:
  	return NULL;
  }
  EXPORT_SYMBOL(vme_dma_pci_attribute);
b5bc980a4   Martyn Welch   docs: Add kernel-...
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
  /**
   * vme_dma_vme_attribute - Create "VME" type VME DMA list attribute.
   * @address: VME base address for DMA transfer.
   * @aspace: VME address space to use for DMA transfer.
   * @cycle: VME bus cycle to use for DMA transfer.
   * @dwidth: VME data width to use for DMA transfer.
   *
   * Create VME DMA list attribute pointing to a location on the VME bus for DMA
   * transfers. It is the responsibility of the user to free used attributes
   * using vme_dma_free_attribute().
   *
   * Return: Pointer to VME DMA attribute, NULL on failure.
a17a75e26   Martyn Welch   Staging: VME Fram...
1048
1049
   */
  struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address,
6af04b065   Martyn Welch   Staging: VME: Rem...
1050
  	u32 aspace, u32 cycle, u32 dwidth)
a17a75e26   Martyn Welch   Staging: VME Fram...
1051
1052
1053
  {
  	struct vme_dma_attr *attributes;
  	struct vme_dma_vme *vme_attr;
1ff0a19ce   Markus Elfring   vme: Improve 11 s...
1054
  	attributes = kmalloc(sizeof(*attributes), GFP_KERNEL);
94eefcc1c   Markus Elfring   vme: Delete 11 er...
1055
  	if (!attributes)
a17a75e26   Martyn Welch   Staging: VME Fram...
1056
  		goto err_attr;
a17a75e26   Martyn Welch   Staging: VME Fram...
1057

1ff0a19ce   Markus Elfring   vme: Improve 11 s...
1058
  	vme_attr = kmalloc(sizeof(*vme_attr), GFP_KERNEL);
94eefcc1c   Markus Elfring   vme: Delete 11 er...
1059
  	if (!vme_attr)
a17a75e26   Martyn Welch   Staging: VME Fram...
1060
  		goto err_vme;
a17a75e26   Martyn Welch   Staging: VME Fram...
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
  
  	attributes->type = VME_DMA_VME;
  	attributes->private = (void *)vme_attr;
  
  	vme_attr->address = address;
  	vme_attr->aspace = aspace;
  	vme_attr->cycle = cycle;
  	vme_attr->dwidth = dwidth;
  
  	return attributes;
a17a75e26   Martyn Welch   Staging: VME Fram...
1071
1072
1073
1074
1075
1076
  err_vme:
  	kfree(attributes);
  err_attr:
  	return NULL;
  }
  EXPORT_SYMBOL(vme_dma_vme_attribute);
b5bc980a4   Martyn Welch   docs: Add kernel-...
1077
1078
1079
1080
1081
1082
  /**
   * vme_dma_free_attribute - Free DMA list attribute.
   * @attributes: Pointer to DMA list attribute.
   *
   * Free VME DMA list attribute. VME DMA list attributes can be safely freed
   * once vme_dma_list_add() has returned.
a17a75e26   Martyn Welch   Staging: VME Fram...
1083
1084
1085
1086
1087
1088
1089
   */
  void vme_dma_free_attribute(struct vme_dma_attr *attributes)
  {
  	kfree(attributes->private);
  	kfree(attributes);
  }
  EXPORT_SYMBOL(vme_dma_free_attribute);
b5bc980a4   Martyn Welch   docs: Add kernel-...
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
  /**
   * vme_dma_list_add - Add enty to a VME DMA list.
   * @list: Pointer to VME list.
   * @src: Pointer to DMA list attribute to use as source.
   * @dest: Pointer to DMA list attribute to use as destination.
   * @count: Number of bytes to transfer.
   *
   * Add an entry to the provided VME DMA list. Entry requires pointers to source
   * and destination DMA attributes and a count.
   *
   * Please note, the attributes supported as source and destinations for
   * transfers are hardware dependent.
   *
   * Return: Zero on success, -EINVAL if operation is not supported on this
   *         device or if the link list has already been submitted for execution.
   *         Hardware specific errors also possible.
   */
a17a75e26   Martyn Welch   Staging: VME Fram...
1107
1108
1109
1110
1111
  int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
  	struct vme_dma_attr *dest, size_t count)
  {
  	struct vme_bridge *bridge = list->parent->parent;
  	int retval;
61282c049   Markus Elfring   vme: Adjust 48 ch...
1112
  	if (!bridge->dma_list_add) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
1113
1114
  		printk(KERN_WARNING "Link List DMA generation not supported
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1115
1116
  		return -EINVAL;
  	}
886953e9b   Emilio G. Cota   staging: vme: sty...
1117
  	if (!mutex_trylock(&list->mtx)) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
1118
1119
  		printk(KERN_ERR "Link List already submitted
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1120
1121
1122
1123
  		return -EINVAL;
  	}
  
  	retval = bridge->dma_list_add(list, src, dest, count);
886953e9b   Emilio G. Cota   staging: vme: sty...
1124
  	mutex_unlock(&list->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
1125
1126
1127
1128
  
  	return retval;
  }
  EXPORT_SYMBOL(vme_dma_list_add);
b5bc980a4   Martyn Welch   docs: Add kernel-...
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
  /**
   * vme_dma_list_exec - Queue a VME DMA list for execution.
   * @list: Pointer to VME list.
   *
   * Queue the provided VME DMA list for execution. The call will return once the
   * list has been executed.
   *
   * Return: Zero on success, -EINVAL if operation is not supported on this
   *         device. Hardware specific errors also possible.
   */
a17a75e26   Martyn Welch   Staging: VME Fram...
1139
1140
1141
1142
  int vme_dma_list_exec(struct vme_dma_list *list)
  {
  	struct vme_bridge *bridge = list->parent->parent;
  	int retval;
61282c049   Markus Elfring   vme: Adjust 48 ch...
1143
  	if (!bridge->dma_list_exec) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
1144
1145
  		printk(KERN_ERR "Link List DMA execution not supported
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1146
1147
  		return -EINVAL;
  	}
886953e9b   Emilio G. Cota   staging: vme: sty...
1148
  	mutex_lock(&list->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
1149
1150
  
  	retval = bridge->dma_list_exec(list);
886953e9b   Emilio G. Cota   staging: vme: sty...
1151
  	mutex_unlock(&list->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
1152
1153
1154
1155
  
  	return retval;
  }
  EXPORT_SYMBOL(vme_dma_list_exec);
b5bc980a4   Martyn Welch   docs: Add kernel-...
1156
1157
1158
1159
1160
1161
1162
1163
1164
  /**
   * vme_dma_list_free - Free a VME DMA list.
   * @list: Pointer to VME list.
   *
   * Free the provided DMA list and all its entries.
   *
   * Return: Zero on success, -EINVAL on invalid VME resource, -EBUSY if resource
   *         is still in use. Hardware specific errors also possible.
   */
a17a75e26   Martyn Welch   Staging: VME Fram...
1165
1166
1167
1168
  int vme_dma_list_free(struct vme_dma_list *list)
  {
  	struct vme_bridge *bridge = list->parent->parent;
  	int retval;
61282c049   Markus Elfring   vme: Adjust 48 ch...
1169
  	if (!bridge->dma_list_empty) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
1170
1171
  		printk(KERN_WARNING "Emptying of Link Lists not supported
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1172
1173
  		return -EINVAL;
  	}
886953e9b   Emilio G. Cota   staging: vme: sty...
1174
  	if (!mutex_trylock(&list->mtx)) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
1175
1176
  		printk(KERN_ERR "Link List in use
  ");
f13d1a8a8   Martyn Welch   VME: Return -EBUS...
1177
  		return -EBUSY;
a17a75e26   Martyn Welch   Staging: VME Fram...
1178
1179
1180
  	}
  
  	/*
f56c3d4f5   Aaron Sierra   vme: trivial spel...
1181
1182
  	 * Empty out all of the entries from the DMA list. We need to go to the
  	 * low level driver as DMA entries are driver specific.
a17a75e26   Martyn Welch   Staging: VME Fram...
1183
1184
1185
  	 */
  	retval = bridge->dma_list_empty(list);
  	if (retval) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
1186
1187
  		printk(KERN_ERR "Unable to empty link-list entries
  ");
886953e9b   Emilio G. Cota   staging: vme: sty...
1188
  		mutex_unlock(&list->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
1189
1190
  		return retval;
  	}
886953e9b   Emilio G. Cota   staging: vme: sty...
1191
  	mutex_unlock(&list->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
1192
1193
1194
1195
1196
  	kfree(list);
  
  	return retval;
  }
  EXPORT_SYMBOL(vme_dma_list_free);
b5bc980a4   Martyn Welch   docs: Add kernel-...
1197
1198
1199
1200
1201
1202
1203
1204
1205
  /**
   * vme_dma_free - Free a VME DMA resource.
   * @resource: Pointer to VME DMA resource.
   *
   * Free the provided DMA resource so that it may be reallocated.
   *
   * Return: Zero on success, -EINVAL on invalid VME resource, -EBUSY if resource
   *         is still active.
   */
a17a75e26   Martyn Welch   Staging: VME Fram...
1206
1207
1208
1209
1210
  int vme_dma_free(struct vme_resource *resource)
  {
  	struct vme_dma_resource *ctrlr;
  
  	if (resource->type != VME_DMA) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
1211
1212
  		printk(KERN_ERR "Not a DMA resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1213
1214
1215
1216
  		return -EINVAL;
  	}
  
  	ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
886953e9b   Emilio G. Cota   staging: vme: sty...
1217
  	if (!mutex_trylock(&ctrlr->mtx)) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
1218
1219
  		printk(KERN_ERR "Resource busy, can't free
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1220
1221
  		return -EBUSY;
  	}
886953e9b   Emilio G. Cota   staging: vme: sty...
1222
  	if (!(list_empty(&ctrlr->pending) && list_empty(&ctrlr->running))) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
1223
1224
  		printk(KERN_WARNING "Resource still processing transfers
  ");
886953e9b   Emilio G. Cota   staging: vme: sty...
1225
  		mutex_unlock(&ctrlr->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
1226
1227
1228
1229
  		return -EBUSY;
  	}
  
  	ctrlr->locked = 0;
886953e9b   Emilio G. Cota   staging: vme: sty...
1230
  	mutex_unlock(&ctrlr->mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
1231

fd5c25614   Martyn Welch   vme: Free DMA res...
1232
  	kfree(resource);
a17a75e26   Martyn Welch   Staging: VME Fram...
1233
1234
1235
  	return 0;
  }
  EXPORT_SYMBOL(vme_dma_free);
e2c6393fd   Dmitry Kalinkin   vme: move tsi148 ...
1236
  void vme_bus_error_handler(struct vme_bridge *bridge,
472f16f33   Dmitry Kalinkin   vme: include addr...
1237
  			   unsigned long long address, int am)
e2c6393fd   Dmitry Kalinkin   vme: move tsi148 ...
1238
  {
0b0496625   Dmitry Kalinkin   vme: change bus e...
1239
1240
  	struct list_head *handler_pos = NULL;
  	struct vme_error_handler *handler;
448535a35   Dmitry Kalinkin   vme: print unhand...
1241
  	int handler_triggered = 0;
0b0496625   Dmitry Kalinkin   vme: change bus e...
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
  	u32 aspace = vme_get_aspace(am);
  
  	list_for_each(handler_pos, &bridge->vme_error_handlers) {
  		handler = list_entry(handler_pos, struct vme_error_handler,
  				     list);
  		if ((aspace == handler->aspace) &&
  		    (address >= handler->start) &&
  		    (address < handler->end)) {
  			if (!handler->num_errors)
  				handler->first_error = address;
  			if (handler->num_errors != UINT_MAX)
  				handler->num_errors++;
448535a35   Dmitry Kalinkin   vme: print unhand...
1254
  			handler_triggered = 1;
0b0496625   Dmitry Kalinkin   vme: change bus e...
1255
  		}
e2c6393fd   Dmitry Kalinkin   vme: move tsi148 ...
1256
  	}
448535a35   Dmitry Kalinkin   vme: print unhand...
1257
1258
1259
1260
1261
1262
  
  	if (!handler_triggered)
  		dev_err(bridge->parent,
  			"Unhandled VME access error at address 0x%llx
  ",
  			address);
e2c6393fd   Dmitry Kalinkin   vme: move tsi148 ...
1263
1264
  }
  EXPORT_SYMBOL(vme_bus_error_handler);
0b0496625   Dmitry Kalinkin   vme: change bus e...
1265
1266
1267
  struct vme_error_handler *vme_register_error_handler(
  	struct vme_bridge *bridge, u32 aspace,
  	unsigned long long address, size_t len)
e2c6393fd   Dmitry Kalinkin   vme: move tsi148 ...
1268
  {
0b0496625   Dmitry Kalinkin   vme: change bus e...
1269
  	struct vme_error_handler *handler;
e2c6393fd   Dmitry Kalinkin   vme: move tsi148 ...
1270

97784615e   Jia-Ju Bai   vme: Fix a possib...
1271
  	handler = kmalloc(sizeof(*handler), GFP_ATOMIC);
0b0496625   Dmitry Kalinkin   vme: change bus e...
1272
1273
  	if (!handler)
  		return NULL;
e2c6393fd   Dmitry Kalinkin   vme: move tsi148 ...
1274

0b0496625   Dmitry Kalinkin   vme: change bus e...
1275
1276
1277
1278
1279
1280
  	handler->aspace = aspace;
  	handler->start = address;
  	handler->end = address + len;
  	handler->num_errors = 0;
  	handler->first_error = 0;
  	list_add_tail(&handler->list, &bridge->vme_error_handlers);
e2c6393fd   Dmitry Kalinkin   vme: move tsi148 ...
1281

0b0496625   Dmitry Kalinkin   vme: change bus e...
1282
  	return handler;
e2c6393fd   Dmitry Kalinkin   vme: move tsi148 ...
1283
  }
0b0496625   Dmitry Kalinkin   vme: change bus e...
1284
  EXPORT_SYMBOL(vme_register_error_handler);
e2c6393fd   Dmitry Kalinkin   vme: move tsi148 ...
1285

0b0496625   Dmitry Kalinkin   vme: change bus e...
1286
  void vme_unregister_error_handler(struct vme_error_handler *handler)
e2c6393fd   Dmitry Kalinkin   vme: move tsi148 ...
1287
  {
0b0496625   Dmitry Kalinkin   vme: change bus e...
1288
1289
  	list_del(&handler->list);
  	kfree(handler);
e2c6393fd   Dmitry Kalinkin   vme: move tsi148 ...
1290
  }
0b0496625   Dmitry Kalinkin   vme: change bus e...
1291
  EXPORT_SYMBOL(vme_unregister_error_handler);
e2c6393fd   Dmitry Kalinkin   vme: move tsi148 ...
1292

c813f592a   Martyn Welch   Staging: vme: Pul...
1293
1294
1295
1296
1297
1298
1299
  void vme_irq_handler(struct vme_bridge *bridge, int level, int statid)
  {
  	void (*call)(int, int, void *);
  	void *priv_data;
  
  	call = bridge->irq[level - 1].callback[statid].func;
  	priv_data = bridge->irq[level - 1].callback[statid].priv_data;
61282c049   Markus Elfring   vme: Adjust 48 ch...
1300
  	if (call)
c813f592a   Martyn Welch   Staging: vme: Pul...
1301
1302
  		call(level, statid, priv_data);
  	else
f56c3d4f5   Aaron Sierra   vme: trivial spel...
1303
1304
  		printk(KERN_WARNING "Spurious VME interrupt, level:%x, vector:%x
  ",
25958ce32   Greg Kroah-Hartman   staging: vme: vme...
1305
  		       level, statid);
c813f592a   Martyn Welch   Staging: vme: Pul...
1306
1307
  }
  EXPORT_SYMBOL(vme_irq_handler);
b5bc980a4   Martyn Welch   docs: Add kernel-...
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
  /**
   * vme_irq_request - Request a specific VME interrupt.
   * @vdev: Pointer to VME device struct vme_dev assigned to driver instance.
   * @level: Interrupt priority being requested.
   * @statid: Interrupt vector being requested.
   * @callback: Pointer to callback function called when VME interrupt/vector
   *            received.
   * @priv_data: Generic pointer that will be passed to the callback function.
   *
   * Request callback to be attached as a handler for VME interrupts with provided
   * level and statid.
   *
   * Return: Zero on success, -EINVAL on invalid vme device, level or if the
   *         function is not supported, -EBUSY if the level/statid combination is
   *         already in use. Hardware specific errors also possible.
   */
8f966dc44   Manohar Vanga   staging: vme: add...
1324
  int vme_irq_request(struct vme_dev *vdev, int level, int statid,
29848ac9f   Martyn Welch   Staging: vme: Ena...
1325
  	void (*callback)(int, int, void *),
a17a75e26   Martyn Welch   Staging: VME Fram...
1326
1327
1328
  	void *priv_data)
  {
  	struct vme_bridge *bridge;
8f966dc44   Manohar Vanga   staging: vme: add...
1329
  	bridge = vdev->bridge;
61282c049   Markus Elfring   vme: Adjust 48 ch...
1330
  	if (!bridge) {
a17a75e26   Martyn Welch   Staging: VME Fram...
1331
1332
1333
1334
  		printk(KERN_ERR "Can't find VME bus
  ");
  		return -EINVAL;
  	}
ead1f3e30   Martyn Welch   Staging: vme: Fix...
1335
  	if ((level < 1) || (level > 7)) {
c813f592a   Martyn Welch   Staging: vme: Pul...
1336
1337
  		printk(KERN_ERR "Invalid interrupt level
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1338
1339
  		return -EINVAL;
  	}
61282c049   Markus Elfring   vme: Adjust 48 ch...
1340
  	if (!bridge->irq_set) {
c813f592a   Martyn Welch   Staging: vme: Pul...
1341
1342
  		printk(KERN_ERR "Configuring interrupts not supported
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1343
1344
  		return -EINVAL;
  	}
886953e9b   Emilio G. Cota   staging: vme: sty...
1345
  	mutex_lock(&bridge->irq_mtx);
c813f592a   Martyn Welch   Staging: vme: Pul...
1346
1347
  
  	if (bridge->irq[level - 1].callback[statid].func) {
886953e9b   Emilio G. Cota   staging: vme: sty...
1348
  		mutex_unlock(&bridge->irq_mtx);
c813f592a   Martyn Welch   Staging: vme: Pul...
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
  		printk(KERN_WARNING "VME Interrupt already taken
  ");
  		return -EBUSY;
  	}
  
  	bridge->irq[level - 1].count++;
  	bridge->irq[level - 1].callback[statid].priv_data = priv_data;
  	bridge->irq[level - 1].callback[statid].func = callback;
  
  	/* Enable IRQ level */
29848ac9f   Martyn Welch   Staging: vme: Ena...
1359
  	bridge->irq_set(bridge, level, 1, 1);
c813f592a   Martyn Welch   Staging: vme: Pul...
1360

886953e9b   Emilio G. Cota   staging: vme: sty...
1361
  	mutex_unlock(&bridge->irq_mtx);
c813f592a   Martyn Welch   Staging: vme: Pul...
1362
1363
  
  	return 0;
a17a75e26   Martyn Welch   Staging: VME Fram...
1364
  }
c813f592a   Martyn Welch   Staging: vme: Pul...
1365
  EXPORT_SYMBOL(vme_irq_request);
a17a75e26   Martyn Welch   Staging: VME Fram...
1366

b5bc980a4   Martyn Welch   docs: Add kernel-...
1367
1368
1369
1370
1371
1372
1373
1374
  /**
   * vme_irq_free - Free a VME interrupt.
   * @vdev: Pointer to VME device struct vme_dev assigned to driver instance.
   * @level: Interrupt priority of interrupt being freed.
   * @statid: Interrupt vector of interrupt being freed.
   *
   * Remove previously attached callback from VME interrupt priority/vector.
   */
8f966dc44   Manohar Vanga   staging: vme: add...
1375
  void vme_irq_free(struct vme_dev *vdev, int level, int statid)
a17a75e26   Martyn Welch   Staging: VME Fram...
1376
1377
  {
  	struct vme_bridge *bridge;
8f966dc44   Manohar Vanga   staging: vme: add...
1378
  	bridge = vdev->bridge;
61282c049   Markus Elfring   vme: Adjust 48 ch...
1379
  	if (!bridge) {
a17a75e26   Martyn Welch   Staging: VME Fram...
1380
1381
1382
1383
  		printk(KERN_ERR "Can't find VME bus
  ");
  		return;
  	}
ead1f3e30   Martyn Welch   Staging: vme: Fix...
1384
  	if ((level < 1) || (level > 7)) {
c813f592a   Martyn Welch   Staging: vme: Pul...
1385
1386
  		printk(KERN_ERR "Invalid interrupt level
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1387
1388
  		return;
  	}
61282c049   Markus Elfring   vme: Adjust 48 ch...
1389
  	if (!bridge->irq_set) {
c813f592a   Martyn Welch   Staging: vme: Pul...
1390
1391
  		printk(KERN_ERR "Configuring interrupts not supported
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1392
1393
  		return;
  	}
886953e9b   Emilio G. Cota   staging: vme: sty...
1394
  	mutex_lock(&bridge->irq_mtx);
c813f592a   Martyn Welch   Staging: vme: Pul...
1395
1396
1397
1398
1399
  
  	bridge->irq[level - 1].count--;
  
  	/* Disable IRQ level if no more interrupts attached at this level*/
  	if (bridge->irq[level - 1].count == 0)
29848ac9f   Martyn Welch   Staging: vme: Ena...
1400
  		bridge->irq_set(bridge, level, 0, 1);
c813f592a   Martyn Welch   Staging: vme: Pul...
1401
1402
1403
  
  	bridge->irq[level - 1].callback[statid].func = NULL;
  	bridge->irq[level - 1].callback[statid].priv_data = NULL;
886953e9b   Emilio G. Cota   staging: vme: sty...
1404
  	mutex_unlock(&bridge->irq_mtx);
a17a75e26   Martyn Welch   Staging: VME Fram...
1405
  }
c813f592a   Martyn Welch   Staging: vme: Pul...
1406
  EXPORT_SYMBOL(vme_irq_free);
a17a75e26   Martyn Welch   Staging: VME Fram...
1407

b5bc980a4   Martyn Welch   docs: Add kernel-...
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
  /**
   * vme_irq_generate - Generate VME interrupt.
   * @vdev: Pointer to VME device struct vme_dev assigned to driver instance.
   * @level: Interrupt priority at which to assert the interrupt.
   * @statid: Interrupt vector to associate with the interrupt.
   *
   * Generate a VME interrupt of the provided level and with the provided
   * statid.
   *
   * Return: Zero on success, -EINVAL on invalid vme device, level or if the
   *         function is not supported. Hardware specific errors also possible.
   */
8f966dc44   Manohar Vanga   staging: vme: add...
1420
  int vme_irq_generate(struct vme_dev *vdev, int level, int statid)
a17a75e26   Martyn Welch   Staging: VME Fram...
1421
1422
  {
  	struct vme_bridge *bridge;
8f966dc44   Manohar Vanga   staging: vme: add...
1423
  	bridge = vdev->bridge;
61282c049   Markus Elfring   vme: Adjust 48 ch...
1424
  	if (!bridge) {
a17a75e26   Martyn Welch   Staging: VME Fram...
1425
1426
1427
1428
  		printk(KERN_ERR "Can't find VME bus
  ");
  		return -EINVAL;
  	}
ead1f3e30   Martyn Welch   Staging: vme: Fix...
1429
  	if ((level < 1) || (level > 7)) {
a17a75e26   Martyn Welch   Staging: VME Fram...
1430
1431
1432
1433
  		printk(KERN_WARNING "Invalid interrupt level
  ");
  		return -EINVAL;
  	}
61282c049   Markus Elfring   vme: Adjust 48 ch...
1434
  	if (!bridge->irq_generate) {
ead1f3e30   Martyn Welch   Staging: vme: Fix...
1435
1436
  		printk(KERN_WARNING "Interrupt generation not supported
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1437
1438
  		return -EINVAL;
  	}
29848ac9f   Martyn Welch   Staging: vme: Ena...
1439
  	return bridge->irq_generate(bridge, level, statid);
a17a75e26   Martyn Welch   Staging: VME Fram...
1440
  }
c813f592a   Martyn Welch   Staging: vme: Pul...
1441
  EXPORT_SYMBOL(vme_irq_generate);
a17a75e26   Martyn Welch   Staging: VME Fram...
1442

b5bc980a4   Martyn Welch   docs: Add kernel-...
1443
1444
1445
1446
1447
1448
1449
1450
1451
  /**
   * vme_lm_request - Request a VME location monitor
   * @vdev: Pointer to VME device struct vme_dev assigned to driver instance.
   *
   * Allocate a location monitor resource to the driver. A location monitor
   * allows the driver to monitor accesses to a contiguous number of
   * addresses on the VME bus.
   *
   * Return: Pointer to a VME resource on success or NULL on failure.
42fb50312   Martyn Welch   Staging: vme: add...
1452
   */
8f966dc44   Manohar Vanga   staging: vme: add...
1453
  struct vme_resource *vme_lm_request(struct vme_dev *vdev)
a17a75e26   Martyn Welch   Staging: VME Fram...
1454
1455
  {
  	struct vme_bridge *bridge;
42fb50312   Martyn Welch   Staging: vme: add...
1456
1457
1458
1459
  	struct list_head *lm_pos = NULL;
  	struct vme_lm_resource *allocated_lm = NULL;
  	struct vme_lm_resource *lm = NULL;
  	struct vme_resource *resource = NULL;
a17a75e26   Martyn Welch   Staging: VME Fram...
1460

8f966dc44   Manohar Vanga   staging: vme: add...
1461
  	bridge = vdev->bridge;
61282c049   Markus Elfring   vme: Adjust 48 ch...
1462
  	if (!bridge) {
a17a75e26   Martyn Welch   Staging: VME Fram...
1463
1464
  		printk(KERN_ERR "Can't find VME bus
  ");
42fb50312   Martyn Welch   Staging: vme: add...
1465
1466
  		goto err_bus;
  	}
b5bc980a4   Martyn Welch   docs: Add kernel-...
1467
  	/* Loop through LM resources */
886953e9b   Emilio G. Cota   staging: vme: sty...
1468
  	list_for_each(lm_pos, &bridge->lm_resources) {
42fb50312   Martyn Welch   Staging: vme: add...
1469
1470
  		lm = list_entry(lm_pos,
  			struct vme_lm_resource, list);
61282c049   Markus Elfring   vme: Adjust 48 ch...
1471
  		if (!lm) {
25958ce32   Greg Kroah-Hartman   staging: vme: vme...
1472
1473
  			printk(KERN_ERR "Registered NULL Location Monitor resource
  ");
42fb50312   Martyn Welch   Staging: vme: add...
1474
1475
1476
1477
  			continue;
  		}
  
  		/* Find an unlocked controller */
886953e9b   Emilio G. Cota   staging: vme: sty...
1478
  		mutex_lock(&lm->mtx);
42fb50312   Martyn Welch   Staging: vme: add...
1479
1480
  		if (lm->locked == 0) {
  			lm->locked = 1;
886953e9b   Emilio G. Cota   staging: vme: sty...
1481
  			mutex_unlock(&lm->mtx);
42fb50312   Martyn Welch   Staging: vme: add...
1482
1483
1484
  			allocated_lm = lm;
  			break;
  		}
886953e9b   Emilio G. Cota   staging: vme: sty...
1485
  		mutex_unlock(&lm->mtx);
42fb50312   Martyn Welch   Staging: vme: add...
1486
1487
1488
  	}
  
  	/* Check to see if we found a resource */
61282c049   Markus Elfring   vme: Adjust 48 ch...
1489
  	if (!allocated_lm)
42fb50312   Martyn Welch   Staging: vme: add...
1490
  		goto err_lm;
1ff0a19ce   Markus Elfring   vme: Improve 11 s...
1491
  	resource = kmalloc(sizeof(*resource), GFP_KERNEL);
94eefcc1c   Markus Elfring   vme: Delete 11 er...
1492
  	if (!resource)
42fb50312   Martyn Welch   Staging: vme: add...
1493
  		goto err_alloc;
94eefcc1c   Markus Elfring   vme: Delete 11 er...
1494

42fb50312   Martyn Welch   Staging: vme: add...
1495
  	resource->type = VME_LM;
886953e9b   Emilio G. Cota   staging: vme: sty...
1496
  	resource->entry = &allocated_lm->list;
42fb50312   Martyn Welch   Staging: vme: add...
1497
1498
1499
1500
1501
  
  	return resource;
  
  err_alloc:
  	/* Unlock image */
886953e9b   Emilio G. Cota   staging: vme: sty...
1502
  	mutex_lock(&lm->mtx);
42fb50312   Martyn Welch   Staging: vme: add...
1503
  	lm->locked = 0;
886953e9b   Emilio G. Cota   staging: vme: sty...
1504
  	mutex_unlock(&lm->mtx);
42fb50312   Martyn Welch   Staging: vme: add...
1505
1506
1507
1508
1509
  err_lm:
  err_bus:
  	return NULL;
  }
  EXPORT_SYMBOL(vme_lm_request);
b5bc980a4   Martyn Welch   docs: Add kernel-...
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
  /**
   * vme_lm_count - Determine number of VME Addresses monitored
   * @resource: Pointer to VME location monitor resource.
   *
   * The number of contiguous addresses monitored is hardware dependent.
   * Return the number of contiguous addresses monitored by the
   * location monitor.
   *
   * Return: Count of addresses monitored or -EINVAL when provided with an
   *	   invalid location monitor resource.
   */
42fb50312   Martyn Welch   Staging: vme: add...
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
  int vme_lm_count(struct vme_resource *resource)
  {
  	struct vme_lm_resource *lm;
  
  	if (resource->type != VME_LM) {
  		printk(KERN_ERR "Not a Location Monitor resource
  ");
  		return -EINVAL;
  	}
  
  	lm = list_entry(resource->entry, struct vme_lm_resource, list);
  
  	return lm->monitors;
  }
  EXPORT_SYMBOL(vme_lm_count);
b5bc980a4   Martyn Welch   docs: Add kernel-...
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
  /**
   * vme_lm_set - Configure location monitor
   * @resource: Pointer to VME location monitor resource.
   * @lm_base: Base address to monitor.
   * @aspace: VME address space to monitor.
   * @cycle: VME bus cycle type to monitor.
   *
   * Set the base address, address space and cycle type of accesses to be
   * monitored by the location monitor.
   *
   * Return: Zero on success, -EINVAL when provided with an invalid location
   *	   monitor resource or function is not supported. Hardware specific
   *	   errors may also be returned.
   */
42fb50312   Martyn Welch   Staging: vme: add...
1550
  int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base,
6af04b065   Martyn Welch   Staging: VME: Rem...
1551
  	u32 aspace, u32 cycle)
42fb50312   Martyn Welch   Staging: vme: add...
1552
1553
1554
1555
1556
1557
1558
  {
  	struct vme_bridge *bridge = find_bridge(resource);
  	struct vme_lm_resource *lm;
  
  	if (resource->type != VME_LM) {
  		printk(KERN_ERR "Not a Location Monitor resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1559
1560
  		return -EINVAL;
  	}
42fb50312   Martyn Welch   Staging: vme: add...
1561
  	lm = list_entry(resource->entry, struct vme_lm_resource, list);
61282c049   Markus Elfring   vme: Adjust 48 ch...
1562
  	if (!bridge->lm_set) {
42fb50312   Martyn Welch   Staging: vme: add...
1563
1564
  		printk(KERN_ERR "vme_lm_set not supported
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1565
1566
  		return -EINVAL;
  	}
8be9226c8   Martyn Welch   Staging: vme: Cor...
1567
  	return bridge->lm_set(lm, lm_base, aspace, cycle);
a17a75e26   Martyn Welch   Staging: VME Fram...
1568
1569
  }
  EXPORT_SYMBOL(vme_lm_set);
b5bc980a4   Martyn Welch   docs: Add kernel-...
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
  /**
   * vme_lm_get - Retrieve location monitor settings
   * @resource: Pointer to VME location monitor resource.
   * @lm_base: Pointer used to output the base address monitored.
   * @aspace: Pointer used to output the address space monitored.
   * @cycle: Pointer used to output the VME bus cycle type monitored.
   *
   * Retrieve the base address, address space and cycle type of accesses to
   * be monitored by the location monitor.
   *
   * Return: Zero on success, -EINVAL when provided with an invalid location
   *	   monitor resource or function is not supported. Hardware specific
   *	   errors may also be returned.
   */
42fb50312   Martyn Welch   Staging: vme: add...
1584
  int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base,
6af04b065   Martyn Welch   Staging: VME: Rem...
1585
  	u32 *aspace, u32 *cycle)
a17a75e26   Martyn Welch   Staging: VME Fram...
1586
  {
42fb50312   Martyn Welch   Staging: vme: add...
1587
1588
  	struct vme_bridge *bridge = find_bridge(resource);
  	struct vme_lm_resource *lm;
a17a75e26   Martyn Welch   Staging: VME Fram...
1589

42fb50312   Martyn Welch   Staging: vme: add...
1590
1591
1592
  	if (resource->type != VME_LM) {
  		printk(KERN_ERR "Not a Location Monitor resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1593
1594
  		return -EINVAL;
  	}
42fb50312   Martyn Welch   Staging: vme: add...
1595
  	lm = list_entry(resource->entry, struct vme_lm_resource, list);
61282c049   Markus Elfring   vme: Adjust 48 ch...
1596
  	if (!bridge->lm_get) {
42fb50312   Martyn Welch   Staging: vme: add...
1597
1598
  		printk(KERN_ERR "vme_lm_get not supported
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1599
1600
  		return -EINVAL;
  	}
42fb50312   Martyn Welch   Staging: vme: add...
1601
  	return bridge->lm_get(lm, lm_base, aspace, cycle);
a17a75e26   Martyn Welch   Staging: VME Fram...
1602
1603
  }
  EXPORT_SYMBOL(vme_lm_get);
b5bc980a4   Martyn Welch   docs: Add kernel-...
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
  /**
   * vme_lm_attach - Provide callback for location monitor address
   * @resource: Pointer to VME location monitor resource.
   * @monitor: Offset to which callback should be attached.
   * @callback: Pointer to callback function called when triggered.
   * @data: Generic pointer that will be passed to the callback function.
   *
   * Attach a callback to the specificed offset into the location monitors
   * monitored addresses. A generic pointer is provided to allow data to be
   * passed to the callback when called.
   *
   * Return: Zero on success, -EINVAL when provided with an invalid location
   *	   monitor resource or function is not supported. Hardware specific
   *	   errors may also be returned.
   */
42fb50312   Martyn Welch   Staging: vme: add...
1619
  int vme_lm_attach(struct vme_resource *resource, int monitor,
fa54b3268   Aaron Sierra   vme: change LM ca...
1620
  	void (*callback)(void *), void *data)
a17a75e26   Martyn Welch   Staging: VME Fram...
1621
  {
42fb50312   Martyn Welch   Staging: vme: add...
1622
1623
  	struct vme_bridge *bridge = find_bridge(resource);
  	struct vme_lm_resource *lm;
a17a75e26   Martyn Welch   Staging: VME Fram...
1624

42fb50312   Martyn Welch   Staging: vme: add...
1625
1626
1627
  	if (resource->type != VME_LM) {
  		printk(KERN_ERR "Not a Location Monitor resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1628
1629
  		return -EINVAL;
  	}
42fb50312   Martyn Welch   Staging: vme: add...
1630
  	lm = list_entry(resource->entry, struct vme_lm_resource, list);
61282c049   Markus Elfring   vme: Adjust 48 ch...
1631
  	if (!bridge->lm_attach) {
42fb50312   Martyn Welch   Staging: vme: add...
1632
1633
  		printk(KERN_ERR "vme_lm_attach not supported
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1634
1635
  		return -EINVAL;
  	}
fa54b3268   Aaron Sierra   vme: change LM ca...
1636
  	return bridge->lm_attach(lm, monitor, callback, data);
a17a75e26   Martyn Welch   Staging: VME Fram...
1637
1638
  }
  EXPORT_SYMBOL(vme_lm_attach);
b5bc980a4   Martyn Welch   docs: Add kernel-...
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
  /**
   * vme_lm_detach - Remove callback for location monitor address
   * @resource: Pointer to VME location monitor resource.
   * @monitor: Offset to which callback should be removed.
   *
   * Remove the callback associated with the specificed offset into the
   * location monitors monitored addresses.
   *
   * Return: Zero on success, -EINVAL when provided with an invalid location
   *	   monitor resource or function is not supported. Hardware specific
   *	   errors may also be returned.
   */
42fb50312   Martyn Welch   Staging: vme: add...
1651
  int vme_lm_detach(struct vme_resource *resource, int monitor)
a17a75e26   Martyn Welch   Staging: VME Fram...
1652
  {
42fb50312   Martyn Welch   Staging: vme: add...
1653
1654
  	struct vme_bridge *bridge = find_bridge(resource);
  	struct vme_lm_resource *lm;
a17a75e26   Martyn Welch   Staging: VME Fram...
1655

42fb50312   Martyn Welch   Staging: vme: add...
1656
1657
1658
  	if (resource->type != VME_LM) {
  		printk(KERN_ERR "Not a Location Monitor resource
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1659
1660
  		return -EINVAL;
  	}
42fb50312   Martyn Welch   Staging: vme: add...
1661
  	lm = list_entry(resource->entry, struct vme_lm_resource, list);
61282c049   Markus Elfring   vme: Adjust 48 ch...
1662
  	if (!bridge->lm_detach) {
42fb50312   Martyn Welch   Staging: vme: add...
1663
1664
  		printk(KERN_ERR "vme_lm_detach not supported
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1665
1666
  		return -EINVAL;
  	}
42fb50312   Martyn Welch   Staging: vme: add...
1667
  	return bridge->lm_detach(lm, monitor);
a17a75e26   Martyn Welch   Staging: VME Fram...
1668
1669
  }
  EXPORT_SYMBOL(vme_lm_detach);
b5bc980a4   Martyn Welch   docs: Add kernel-...
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
  /**
   * vme_lm_free - Free allocated VME location monitor
   * @resource: Pointer to VME location monitor resource.
   *
   * Free allocation of a VME location monitor.
   *
   * WARNING: This function currently expects that any callbacks that have
   *          been attached to the location monitor have been removed.
   *
   * Return: Zero on success, -EINVAL when provided with an invalid location
   *	   monitor resource.
   */
42fb50312   Martyn Welch   Staging: vme: add...
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
  void vme_lm_free(struct vme_resource *resource)
  {
  	struct vme_lm_resource *lm;
  
  	if (resource->type != VME_LM) {
  		printk(KERN_ERR "Not a Location Monitor resource
  ");
  		return;
  	}
  
  	lm = list_entry(resource->entry, struct vme_lm_resource, list);
886953e9b   Emilio G. Cota   staging: vme: sty...
1693
  	mutex_lock(&lm->mtx);
42fb50312   Martyn Welch   Staging: vme: add...
1694

8be9226c8   Martyn Welch   Staging: vme: Cor...
1695
1696
1697
1698
  	/* XXX
  	 * Check to see that there aren't any callbacks still attached, if
  	 * there are we should probably be detaching them!
  	 */
42fb50312   Martyn Welch   Staging: vme: add...
1699
1700
  
  	lm->locked = 0;
886953e9b   Emilio G. Cota   staging: vme: sty...
1701
  	mutex_unlock(&lm->mtx);
8be9226c8   Martyn Welch   Staging: vme: Cor...
1702
1703
  
  	kfree(resource);
42fb50312   Martyn Welch   Staging: vme: add...
1704
1705
  }
  EXPORT_SYMBOL(vme_lm_free);
b5bc980a4   Martyn Welch   docs: Add kernel-...
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
  /**
   * vme_slot_num - Retrieve slot ID
   * @vdev: Pointer to VME device struct vme_dev assigned to driver instance.
   *
   * Retrieve the slot ID associated with the provided VME device.
   *
   * Return: The slot ID on success, -EINVAL if VME bridge cannot be determined
   *         or the function is not supported. Hardware specific errors may also
   *         be returned.
   */
d7729f0fc   Martyn Welch   VME: Rename vme_s...
1716
  int vme_slot_num(struct vme_dev *vdev)
a17a75e26   Martyn Welch   Staging: VME Fram...
1717
1718
  {
  	struct vme_bridge *bridge;
8f966dc44   Manohar Vanga   staging: vme: add...
1719
  	bridge = vdev->bridge;
61282c049   Markus Elfring   vme: Adjust 48 ch...
1720
  	if (!bridge) {
a17a75e26   Martyn Welch   Staging: VME Fram...
1721
1722
1723
1724
  		printk(KERN_ERR "Can't find VME bus
  ");
  		return -EINVAL;
  	}
61282c049   Markus Elfring   vme: Adjust 48 ch...
1725
  	if (!bridge->slot_get) {
d7729f0fc   Martyn Welch   VME: Rename vme_s...
1726
1727
  		printk(KERN_WARNING "vme_slot_num not supported
  ");
a17a75e26   Martyn Welch   Staging: VME Fram...
1728
1729
  		return -EINVAL;
  	}
29848ac9f   Martyn Welch   Staging: vme: Ena...
1730
  	return bridge->slot_get(bridge);
a17a75e26   Martyn Welch   Staging: VME Fram...
1731
  }
d7729f0fc   Martyn Welch   VME: Rename vme_s...
1732
  EXPORT_SYMBOL(vme_slot_num);
a17a75e26   Martyn Welch   Staging: VME Fram...
1733

b5bc980a4   Martyn Welch   docs: Add kernel-...
1734
1735
1736
1737
1738
1739
1740
1741
1742
  /**
   * vme_bus_num - Retrieve bus number
   * @vdev: Pointer to VME device struct vme_dev assigned to driver instance.
   *
   * Retrieve the bus enumeration associated with the provided VME device.
   *
   * Return: The bus number on success, -EINVAL if VME bridge cannot be
   *         determined.
   */
978f47d64   Martyn Welch   VME: Provide acce...
1743
1744
1745
1746
1747
  int vme_bus_num(struct vme_dev *vdev)
  {
  	struct vme_bridge *bridge;
  
  	bridge = vdev->bridge;
61282c049   Markus Elfring   vme: Adjust 48 ch...
1748
  	if (!bridge) {
978f47d64   Martyn Welch   VME: Provide acce...
1749
1750
1751
1752
1753
1754
1755
1756
  		pr_err("Can't find VME bus
  ");
  		return -EINVAL;
  	}
  
  	return bridge->num;
  }
  EXPORT_SYMBOL(vme_bus_num);
a17a75e26   Martyn Welch   Staging: VME Fram...
1757
1758
  
  /* - Bridge Registration --------------------------------------------------- */
5b93c2a2f   Manohar Vanga   staging: vme: rem...
1759
1760
1761
1762
  static void vme_dev_release(struct device *dev)
  {
  	kfree(dev_to_vme_dev(dev));
  }
326071b3c   Aaron Sierra   vme: add vme_init...
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
  /* Common bridge initialization */
  struct vme_bridge *vme_init_bridge(struct vme_bridge *bridge)
  {
  	INIT_LIST_HEAD(&bridge->vme_error_handlers);
  	INIT_LIST_HEAD(&bridge->master_resources);
  	INIT_LIST_HEAD(&bridge->slave_resources);
  	INIT_LIST_HEAD(&bridge->dma_resources);
  	INIT_LIST_HEAD(&bridge->lm_resources);
  	mutex_init(&bridge->irq_mtx);
  
  	return bridge;
  }
  EXPORT_SYMBOL(vme_init_bridge);
5b93c2a2f   Manohar Vanga   staging: vme: rem...
1776
  int vme_register_bridge(struct vme_bridge *bridge)
a17a75e26   Martyn Welch   Staging: VME Fram...
1777
1778
  {
  	int i;
733e3ef0d   Manohar Vanga   staging: vme: kee...
1779
  	int ret = -1;
a17a75e26   Martyn Welch   Staging: VME Fram...
1780

733e3ef0d   Manohar Vanga   staging: vme: kee...
1781
  	mutex_lock(&vme_buses_lock);
a17a75e26   Martyn Welch   Staging: VME Fram...
1782
  	for (i = 0; i < sizeof(vme_bus_numbers) * 8; i++) {
733e3ef0d   Manohar Vanga   staging: vme: kee...
1783
1784
1785
  		if ((vme_bus_numbers & (1 << i)) == 0) {
  			vme_bus_numbers |= (1 << i);
  			bridge->num = i;
5d6abf379   Manohar Vanga   staging: vme: mak...
1786
  			INIT_LIST_HEAD(&bridge->devices);
733e3ef0d   Manohar Vanga   staging: vme: kee...
1787
1788
  			list_add_tail(&bridge->bus_list, &vme_bus_list);
  			ret = 0;
a17a75e26   Martyn Welch   Staging: VME Fram...
1789
1790
1791
  			break;
  		}
  	}
733e3ef0d   Manohar Vanga   staging: vme: kee...
1792
  	mutex_unlock(&vme_buses_lock);
a17a75e26   Martyn Welch   Staging: VME Fram...
1793

733e3ef0d   Manohar Vanga   staging: vme: kee...
1794
  	return ret;
a17a75e26   Martyn Welch   Staging: VME Fram...
1795
  }
5b93c2a2f   Manohar Vanga   staging: vme: rem...
1796
  EXPORT_SYMBOL(vme_register_bridge);
a17a75e26   Martyn Welch   Staging: VME Fram...
1797

5b93c2a2f   Manohar Vanga   staging: vme: rem...
1798
  void vme_unregister_bridge(struct vme_bridge *bridge)
a17a75e26   Martyn Welch   Staging: VME Fram...
1799
  {
5d6abf379   Manohar Vanga   staging: vme: mak...
1800
1801
  	struct vme_dev *vdev;
  	struct vme_dev *tmp;
733e3ef0d   Manohar Vanga   staging: vme: kee...
1802
1803
  	mutex_lock(&vme_buses_lock);
  	vme_bus_numbers &= ~(1 << bridge->num);
5d6abf379   Manohar Vanga   staging: vme: mak...
1804
1805
1806
1807
1808
  	list_for_each_entry_safe(vdev, tmp, &bridge->devices, bridge_list) {
  		list_del(&vdev->drv_list);
  		list_del(&vdev->bridge_list);
  		device_unregister(&vdev->dev);
  	}
733e3ef0d   Manohar Vanga   staging: vme: kee...
1809
1810
  	list_del(&bridge->bus_list);
  	mutex_unlock(&vme_buses_lock);
a17a75e26   Martyn Welch   Staging: VME Fram...
1811
  }
5d6abf379   Manohar Vanga   staging: vme: mak...
1812
  EXPORT_SYMBOL(vme_unregister_bridge);
a17a75e26   Martyn Welch   Staging: VME Fram...
1813

5d6abf379   Manohar Vanga   staging: vme: mak...
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
  /* - Driver Registration --------------------------------------------------- */
  
  static int __vme_register_driver_bus(struct vme_driver *drv,
  	struct vme_bridge *bridge, unsigned int ndevs)
  {
  	int err;
  	unsigned int i;
  	struct vme_dev *vdev;
  	struct vme_dev *tmp;
  
  	for (i = 0; i < ndevs; i++) {
1ff0a19ce   Markus Elfring   vme: Improve 11 s...
1825
  		vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
5d6abf379   Manohar Vanga   staging: vme: mak...
1826
1827
  		if (!vdev) {
  			err = -ENOMEM;
f6c39d4f2   Manohar Vanga   staging: vme: cha...
1828
1829
  			goto err_devalloc;
  		}
a916a391d   Manohar Vanga   staging: vme: get...
1830
  		vdev->num = i;
8f966dc44   Manohar Vanga   staging: vme: add...
1831
  		vdev->bridge = bridge;
5d6abf379   Manohar Vanga   staging: vme: mak...
1832
1833
  		vdev->dev.platform_data = drv;
  		vdev->dev.release = vme_dev_release;
8f966dc44   Manohar Vanga   staging: vme: add...
1834
1835
  		vdev->dev.parent = bridge->parent;
  		vdev->dev.bus = &vme_bus_type;
a916a391d   Manohar Vanga   staging: vme: get...
1836
1837
  		dev_set_name(&vdev->dev, "%s.%u-%u", drv->name, bridge->num,
  			vdev->num);
a17a75e26   Martyn Welch   Staging: VME Fram...
1838

5d6abf379   Manohar Vanga   staging: vme: mak...
1839
1840
  		err = device_register(&vdev->dev);
  		if (err)
a17a75e26   Martyn Welch   Staging: VME Fram...
1841
  			goto err_reg;
a17a75e26   Martyn Welch   Staging: VME Fram...
1842

5d6abf379   Manohar Vanga   staging: vme: mak...
1843
1844
1845
1846
1847
1848
1849
  		if (vdev->dev.platform_data) {
  			list_add_tail(&vdev->drv_list, &drv->devices);
  			list_add_tail(&vdev->bridge_list, &bridge->devices);
  		} else
  			device_unregister(&vdev->dev);
  	}
  	return 0;
a17a75e26   Martyn Welch   Staging: VME Fram...
1850

a17a75e26   Martyn Welch   Staging: VME Fram...
1851
  err_reg:
def1820d2   Emilio G. Cota   vme: add missing ...
1852
  	put_device(&vdev->dev);
f6c39d4f2   Manohar Vanga   staging: vme: cha...
1853
  err_devalloc:
5d6abf379   Manohar Vanga   staging: vme: mak...
1854
1855
1856
  	list_for_each_entry_safe(vdev, tmp, &drv->devices, drv_list) {
  		list_del(&vdev->drv_list);
  		list_del(&vdev->bridge_list);
8f966dc44   Manohar Vanga   staging: vme: add...
1857
  		device_unregister(&vdev->dev);
a17a75e26   Martyn Welch   Staging: VME Fram...
1858
  	}
5d6abf379   Manohar Vanga   staging: vme: mak...
1859
  	return err;
a17a75e26   Martyn Welch   Staging: VME Fram...
1860
  }
a17a75e26   Martyn Welch   Staging: VME Fram...
1861

5d6abf379   Manohar Vanga   staging: vme: mak...
1862
  static int __vme_register_driver(struct vme_driver *drv, unsigned int ndevs)
a17a75e26   Martyn Welch   Staging: VME Fram...
1863
  {
5d6abf379   Manohar Vanga   staging: vme: mak...
1864
1865
  	struct vme_bridge *bridge;
  	int err = 0;
a17a75e26   Martyn Welch   Staging: VME Fram...
1866

5d6abf379   Manohar Vanga   staging: vme: mak...
1867
1868
1869
1870
1871
1872
1873
  	mutex_lock(&vme_buses_lock);
  	list_for_each_entry(bridge, &vme_bus_list, bus_list) {
  		/*
  		 * This cannot cause trouble as we already have vme_buses_lock
  		 * and if the bridge is removed, it will have to go through
  		 * vme_unregister_bridge() to do it (which calls remove() on
  		 * the bridge which in turn tries to acquire vme_buses_lock and
c26f61129   Manohar Vanga   staging: vme: fix...
1874
  		 * will have to wait).
5d6abf379   Manohar Vanga   staging: vme: mak...
1875
1876
1877
1878
  		 */
  		err = __vme_register_driver_bus(drv, bridge, ndevs);
  		if (err)
  			break;
a17a75e26   Martyn Welch   Staging: VME Fram...
1879
  	}
5d6abf379   Manohar Vanga   staging: vme: mak...
1880
1881
  	mutex_unlock(&vme_buses_lock);
  	return err;
a17a75e26   Martyn Welch   Staging: VME Fram...
1882
  }
a17a75e26   Martyn Welch   Staging: VME Fram...
1883

b5bc980a4   Martyn Welch   docs: Add kernel-...
1884
1885
1886
1887
1888
1889
1890
1891
1892
  /**
   * vme_register_driver - Register a VME driver
   * @drv: Pointer to VME driver structure to register.
   * @ndevs: Maximum number of devices to allow to be enumerated.
   *
   * Register a VME device driver with the VME subsystem.
   *
   * Return: Zero on success, error value on registration failure.
   */
5d6abf379   Manohar Vanga   staging: vme: mak...
1893
  int vme_register_driver(struct vme_driver *drv, unsigned int ndevs)
a17a75e26   Martyn Welch   Staging: VME Fram...
1894
  {
5d6abf379   Manohar Vanga   staging: vme: mak...
1895
  	int err;
a17a75e26   Martyn Welch   Staging: VME Fram...
1896
1897
  	drv->driver.name = drv->name;
  	drv->driver.bus = &vme_bus_type;
5d6abf379   Manohar Vanga   staging: vme: mak...
1898
1899
1900
1901
1902
  	INIT_LIST_HEAD(&drv->devices);
  
  	err = driver_register(&drv->driver);
  	if (err)
  		return err;
a17a75e26   Martyn Welch   Staging: VME Fram...
1903

5d6abf379   Manohar Vanga   staging: vme: mak...
1904
1905
1906
1907
1908
  	err = __vme_register_driver(drv, ndevs);
  	if (err)
  		driver_unregister(&drv->driver);
  
  	return err;
a17a75e26   Martyn Welch   Staging: VME Fram...
1909
1910
  }
  EXPORT_SYMBOL(vme_register_driver);
b5bc980a4   Martyn Welch   docs: Add kernel-...
1911
1912
1913
1914
1915
1916
  /**
   * vme_unregister_driver - Unregister a VME driver
   * @drv: Pointer to VME driver structure to unregister.
   *
   * Unregister a VME device driver from the VME subsystem.
   */
ead1f3e30   Martyn Welch   Staging: vme: Fix...
1917
  void vme_unregister_driver(struct vme_driver *drv)
a17a75e26   Martyn Welch   Staging: VME Fram...
1918
  {
5d6abf379   Manohar Vanga   staging: vme: mak...
1919
1920
1921
1922
1923
1924
1925
1926
1927
  	struct vme_dev *dev, *dev_tmp;
  
  	mutex_lock(&vme_buses_lock);
  	list_for_each_entry_safe(dev, dev_tmp, &drv->devices, drv_list) {
  		list_del(&dev->drv_list);
  		list_del(&dev->bridge_list);
  		device_unregister(&dev->dev);
  	}
  	mutex_unlock(&vme_buses_lock);
a17a75e26   Martyn Welch   Staging: VME Fram...
1928
1929
1930
1931
1932
  	driver_unregister(&drv->driver);
  }
  EXPORT_SYMBOL(vme_unregister_driver);
  
  /* - Bus Registration ------------------------------------------------------ */
a17a75e26   Martyn Welch   Staging: VME Fram...
1933
1934
  static int vme_bus_match(struct device *dev, struct device_driver *drv)
  {
5d6abf379   Manohar Vanga   staging: vme: mak...
1935
  	struct vme_driver *vme_drv;
a17a75e26   Martyn Welch   Staging: VME Fram...
1936

5d6abf379   Manohar Vanga   staging: vme: mak...
1937
  	vme_drv = container_of(drv, struct vme_driver, driver);
a17a75e26   Martyn Welch   Staging: VME Fram...
1938

5d6abf379   Manohar Vanga   staging: vme: mak...
1939
1940
  	if (dev->platform_data == vme_drv) {
  		struct vme_dev *vdev = dev_to_vme_dev(dev);
a17a75e26   Martyn Welch   Staging: VME Fram...
1941

5d6abf379   Manohar Vanga   staging: vme: mak...
1942
1943
  		if (vme_drv->match && vme_drv->match(vdev))
  			return 1;
a37b0dad8   Martyn Welch   Staging: vme: Ext...
1944

5d6abf379   Manohar Vanga   staging: vme: mak...
1945
  		dev->platform_data = NULL;
a17a75e26   Martyn Welch   Staging: VME Fram...
1946
  	}
a17a75e26   Martyn Welch   Staging: VME Fram...
1947
1948
1949
1950
1951
  	return 0;
  }
  
  static int vme_bus_probe(struct device *dev)
  {
5d6abf379   Manohar Vanga   staging: vme: mak...
1952
1953
  	struct vme_driver *driver;
  	struct vme_dev *vdev = dev_to_vme_dev(dev);
a17a75e26   Martyn Welch   Staging: VME Fram...
1954

5d6abf379   Manohar Vanga   staging: vme: mak...
1955
  	driver = dev->platform_data;
61282c049   Markus Elfring   vme: Adjust 48 ch...
1956
  	if (driver->probe)
8af70cd9d   Markus Elfring   vme: Return direc...
1957
  		return driver->probe(vdev);
a17a75e26   Martyn Welch   Staging: VME Fram...
1958

8af70cd9d   Markus Elfring   vme: Return direc...
1959
  	return -ENODEV;
a17a75e26   Martyn Welch   Staging: VME Fram...
1960
  }
9797484ba   Stefano Babic   VME: restore bus_...
1961
1962
  static int vme_bus_remove(struct device *dev)
  {
9797484ba   Stefano Babic   VME: restore bus_...
1963
1964
1965
1966
  	struct vme_driver *driver;
  	struct vme_dev *vdev = dev_to_vme_dev(dev);
  
  	driver = dev->platform_data;
61282c049   Markus Elfring   vme: Adjust 48 ch...
1967
  	if (driver->remove)
8af70cd9d   Markus Elfring   vme: Return direc...
1968
  		return driver->remove(vdev);
9797484ba   Stefano Babic   VME: restore bus_...
1969

8af70cd9d   Markus Elfring   vme: Return direc...
1970
  	return -ENODEV;
9797484ba   Stefano Babic   VME: restore bus_...
1971
  }
a17a75e26   Martyn Welch   Staging: VME Fram...
1972
1973
1974
1975
  struct bus_type vme_bus_type = {
  	.name = "vme",
  	.match = vme_bus_match,
  	.probe = vme_bus_probe,
9797484ba   Stefano Babic   VME: restore bus_...
1976
  	.remove = vme_bus_remove,
a17a75e26   Martyn Welch   Staging: VME Fram...
1977
1978
  };
  EXPORT_SYMBOL(vme_bus_type);
ead1f3e30   Martyn Welch   Staging: vme: Fix...
1979
  static int __init vme_init(void)
a17a75e26   Martyn Welch   Staging: VME Fram...
1980
1981
1982
  {
  	return bus_register(&vme_bus_type);
  }
c326cc023   Aaron Sierra   vme: Convert VME ...
1983
  subsys_initcall(vme_init);