vme.c revision c26f6112990b90977db429596ed0640d153b3a32
1a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
2a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * VME Bridge Framework
3a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch *
466bd8db52ab48e7189e02d4bf1f23109cc1ede70Martyn Welch * Author: Martyn Welch <martyn.welch@ge.com>
566bd8db52ab48e7189e02d4bf1f23109cc1ede70Martyn Welch * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
6a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch *
7a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Based on work by Tom Armistead and Ajit Prem
8a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Copyright 2004 Motorola Inc.
9a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch *
10a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * This program is free software; you can redistribute  it and/or modify it
11a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * under  the terms of  the GNU General  Public License as published by the
12a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Free Software Foundation;  either version 2 of the  License, or (at your
13a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * option) any later version.
14a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
15a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
16a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/module.h>
17a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/moduleparam.h>
18a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/mm.h>
19a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/types.h>
20a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/kernel.h>
21a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/errno.h>
22a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/pci.h>
23a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/poll.h>
24a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/highmem.h>
25a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/interrupt.h>
26a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/pagemap.h>
27a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/device.h>
28a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/dma-mapping.h>
29a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/syscalls.h>
30400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch#include <linux/mutex.h>
31a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/spinlock.h>
325a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
33a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
34a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include "vme.h"
35a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include "vme_bridge.h"
36a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
37733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga/* Bitmask and list of registered buses both protected by common mutex */
38a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic unsigned int vme_bus_numbers;
39733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vangastatic LIST_HEAD(vme_bus_list);
40733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vangastatic DEFINE_MUTEX(vme_buses_lock);
41a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
42ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchstatic void __exit vme_exit(void);
43ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchstatic int __init vme_init(void);
44a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
458f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangastatic struct vme_dev *dev_to_vme_dev(struct device *dev)
46a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
478f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	return container_of(dev, struct vme_dev, dev);
48a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
49a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
50a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
51a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Find the bridge that the resource is associated with.
52a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
53a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic struct vme_bridge *find_bridge(struct vme_resource *resource)
54a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
55a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Get list to search */
56a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	switch (resource->type) {
57a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_MASTER:
58a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return list_entry(resource->entry, struct vme_master_resource,
59a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			list)->parent;
60a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
61a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_SLAVE:
62a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return list_entry(resource->entry, struct vme_slave_resource,
63a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			list)->parent;
64a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
65a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_DMA:
66a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return list_entry(resource->entry, struct vme_dma_resource,
67a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			list)->parent;
68a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
6942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	case VME_LM:
7042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		return list_entry(resource->entry, struct vme_lm_resource,
7142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			list)->parent;
7242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		break;
73a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	default:
74a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Unknown resource type\n");
75a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
76a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
77a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
78a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
79a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
80a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
81a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Allocate a contiguous block of memory for use by the driver. This is used to
82a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * create the buffers for the slave windows.
83a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
84ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchvoid *vme_alloc_consistent(struct vme_resource *resource, size_t size,
85a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_addr_t *dma)
86a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
87a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
88a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
89ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (resource == NULL) {
90ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "No resource\n");
91a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
92a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
93a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
94a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = find_bridge(resource);
95ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (bridge == NULL) {
96ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Can't find bridge\n");
97a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
98a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
99a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
100a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->parent == NULL) {
1017f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga		printk(KERN_ERR "Dev entry NULL for"
1027f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga			" bridge %s\n", bridge->name);
1037f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga		return NULL;
1047f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	}
1057f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga
1067f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	if (bridge->alloc_consistent == NULL) {
1077f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga		printk(KERN_ERR "alloc_consistent not supported by"
1087f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga			" bridge %s\n", bridge->name);
109a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
110a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
111a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1127f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	return bridge->alloc_consistent(bridge->parent, size, dma);
113a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
114a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_alloc_consistent);
115a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
116a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
117a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Free previously allocated contiguous block of memory.
118a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
119a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchvoid vme_free_consistent(struct vme_resource *resource, size_t size,
120a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	void *vaddr, dma_addr_t dma)
121a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
122a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
123a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
124ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (resource == NULL) {
125ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "No resource\n");
126a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
127a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
128a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
129a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = find_bridge(resource);
130ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (bridge == NULL) {
131ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Can't find bridge\n");
132a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
133a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
134a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1357f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	if (bridge->parent == NULL) {
1367f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga		printk(KERN_ERR "Dev entry NULL for"
1377f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga			" bridge %s\n", bridge->name);
1387f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga		return;
1397f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	}
1407f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga
1417f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	if (bridge->free_consistent == NULL) {
1427f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga		printk(KERN_ERR "free_consistent not supported by"
1437f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga			" bridge %s\n", bridge->name);
1447f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga		return;
1457f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	}
146a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1477f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	bridge->free_consistent(bridge->parent, size, vaddr, dma);
148a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
149a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_free_consistent);
150a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
151a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchsize_t vme_get_size(struct vme_resource *resource)
152a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
153a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int enabled, retval;
154a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long base, size;
155a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_addr_t buf_base;
156a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t aspace;
157a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_cycle_t cycle;
158a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_width_t dwidth;
159a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
160a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	switch (resource->type) {
161a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_MASTER:
162a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = vme_master_get(resource, &enabled, &base, &size,
163a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			&aspace, &cycle, &dwidth);
164a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
165a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return size;
166a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
167a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_SLAVE:
168a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = vme_slave_get(resource, &enabled, &base, &size,
169a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			&buf_base, &aspace, &cycle);
170a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
171a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return size;
172a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
173a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_DMA:
174a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return 0;
175a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
176a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	default:
177a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Unknown resource type\n");
178a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return 0;
179a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
180a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
181a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
182a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_get_size);
183a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
184a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int vme_check_window(vme_address_t aspace, unsigned long long vme_base,
185a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long size)
186a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
187a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval = 0;
188a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
189a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	switch (aspace) {
190a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_A16:
191a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_base + size) > VME_A16_MAX) ||
192a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch				(vme_base > VME_A16_MAX))
193a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			retval = -EFAULT;
194a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
195a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_A24:
196a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_base + size) > VME_A24_MAX) ||
197a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch				(vme_base > VME_A24_MAX))
198a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			retval = -EFAULT;
199a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
200a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_A32:
201a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_base + size) > VME_A32_MAX) ||
202a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch				(vme_base > VME_A32_MAX))
203a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			retval = -EFAULT;
204a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
205a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_A64:
206a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/*
207a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 * Any value held in an unsigned long long can be used as the
208a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 * base
209a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 */
210a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
211a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_CRCSR:
212a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_base + size) > VME_CRCSR_MAX) ||
213a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch				(vme_base > VME_CRCSR_MAX))
214a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			retval = -EFAULT;
215a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
216a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_USER1:
217a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_USER2:
218a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_USER3:
219a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_USER4:
220a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/* User Defined */
221a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
222a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	default:
223ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Invalid address space\n");
224a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = -EINVAL;
225a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
226a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
227a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
228a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
229a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
230a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
231a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
232a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Request a slave image with specific attributes, return some unique
233a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * identifier.
234a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
2358f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangastruct vme_resource *vme_slave_request(struct vme_dev *vdev,
236a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t address, vme_cycle_t cycle)
237a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
238a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
239a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct list_head *slave_pos = NULL;
240a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *allocated_image = NULL;
241a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *slave_image = NULL;
242a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_resource *resource = NULL;
243a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
2448f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	bridge = vdev->bridge;
245a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
246a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
247a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_bus;
248a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
249a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
250a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Loop through slave resources */
251886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_for_each(slave_pos, &bridge->slave_resources) {
252a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		slave_image = list_entry(slave_pos,
253a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			struct vme_slave_resource, list);
254a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
255a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (slave_image == NULL) {
256ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			printk(KERN_ERR "Registered NULL Slave resource\n");
257a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			continue;
258a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
259a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
260a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/* Find an unlocked and compatible image */
261886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_lock(&slave_image->mtx);
262ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		if (((slave_image->address_attr & address) == address) &&
263a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			((slave_image->cycle_attr & cycle) == cycle) &&
264a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			(slave_image->locked == 0)) {
265a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
266a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			slave_image->locked = 1;
267886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			mutex_unlock(&slave_image->mtx);
268a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			allocated_image = slave_image;
269a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			break;
270a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
271886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_unlock(&slave_image->mtx);
272a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
273a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
274a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* No free image */
275a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (allocated_image == NULL)
276a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_image;
277a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
278a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
279a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource == NULL) {
280a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_WARNING "Unable to allocate resource structure\n");
281a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_alloc;
282a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
283a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource->type = VME_SLAVE;
284886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	resource->entry = &allocated_image->list;
285a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
286a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return resource;
287a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
288a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_alloc:
289a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Unlock image */
290886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&slave_image->mtx);
291a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	slave_image->locked = 0;
292886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&slave_image->mtx);
293a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_image:
294a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_bus:
295a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
296a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
297a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slave_request);
298a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
299ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchint vme_slave_set(struct vme_resource *resource, int enabled,
300a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long vme_base, unsigned long long size,
301a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_addr_t buf_base, vme_address_t aspace, vme_cycle_t cycle)
302a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
303a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
304a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *image;
305a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
306a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
307a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_SLAVE) {
308ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a slave resource\n");
309a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
310a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
311a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
312a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_slave_resource, list);
313a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
314a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->slave_set == NULL) {
315ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Function not supported\n");
316a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -ENOSYS;
317a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
318a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
319ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (!(((image->address_attr & aspace) == aspace) &&
320a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		((image->cycle_attr & cycle) == cycle))) {
321ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Invalid attributes\n");
322a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
323a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
324a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
325a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	retval = vme_check_window(aspace, vme_base, size);
326ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (retval)
327a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return retval;
328a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
329a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->slave_set(image, enabled, vme_base, size, buf_base,
330a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		aspace, cycle);
331a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
332a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slave_set);
333a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
334ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchint vme_slave_get(struct vme_resource *resource, int *enabled,
335a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long *vme_base, unsigned long long *size,
336a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_addr_t *buf_base, vme_address_t *aspace, vme_cycle_t *cycle)
337a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
338a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
339a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *image;
340a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
341a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_SLAVE) {
342ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a slave resource\n");
343a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
344a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
345a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
346a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_slave_resource, list);
347a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
34851a569f757f233bcffbffcdfeeff510916991a55Emilio G. Cota	if (bridge->slave_get == NULL) {
349ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "vme_slave_get not supported\n");
350a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
351a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
352a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
353a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->slave_get(image, enabled, vme_base, size, buf_base,
354a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		aspace, cycle);
355a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
356a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slave_get);
357a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
358a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchvoid vme_slave_free(struct vme_resource *resource)
359a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
360a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *slave_image;
361a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
362a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_SLAVE) {
363ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a slave resource\n");
364a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
365a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
366a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
367a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	slave_image = list_entry(resource->entry, struct vme_slave_resource,
368a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		list);
369a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (slave_image == NULL) {
370ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Can't find slave resource\n");
371a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
372a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
373a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
374a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Unlock image */
375886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&slave_image->mtx);
376a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (slave_image->locked == 0)
377a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Image is already free\n");
378a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
379a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	slave_image->locked = 0;
380886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&slave_image->mtx);
381a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
382a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Free up resource memory */
383a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(resource);
384a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
385a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slave_free);
386a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
387a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
388a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Request a master image with specific attributes, return some unique
389a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * identifier.
390a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
3918f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangastruct vme_resource *vme_master_request(struct vme_dev *vdev,
392a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t address, vme_cycle_t cycle, vme_width_t dwidth)
393a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
394a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
395a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct list_head *master_pos = NULL;
396a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *allocated_image = NULL;
397a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *master_image = NULL;
398a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_resource *resource = NULL;
399a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
4008f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	bridge = vdev->bridge;
401a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
402a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
403a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_bus;
404a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
405a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
406a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Loop through master resources */
407886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_for_each(master_pos, &bridge->master_resources) {
408a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		master_image = list_entry(master_pos,
409a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			struct vme_master_resource, list);
410a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
411a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (master_image == NULL) {
412a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			printk(KERN_WARNING "Registered NULL master resource\n");
413a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			continue;
414a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
415a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
416a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/* Find an unlocked and compatible image */
417886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		spin_lock(&master_image->lock);
418ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		if (((master_image->address_attr & address) == address) &&
419a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			((master_image->cycle_attr & cycle) == cycle) &&
420a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			((master_image->width_attr & dwidth) == dwidth) &&
421a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			(master_image->locked == 0)) {
422a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
423a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			master_image->locked = 1;
424886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			spin_unlock(&master_image->lock);
425a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			allocated_image = master_image;
426a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			break;
427a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
428886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		spin_unlock(&master_image->lock);
429a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
430a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
431a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Check to see if we found a resource */
432a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (allocated_image == NULL) {
433a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find a suitable resource\n");
434a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_image;
435a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
436a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
437a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
438a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource == NULL) {
439a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Unable to allocate resource structure\n");
440a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_alloc;
441a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
442a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource->type = VME_MASTER;
443886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	resource->entry = &allocated_image->list;
444a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
445a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return resource;
446a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
447a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_alloc:
448a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Unlock image */
449886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_lock(&master_image->lock);
450a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	master_image->locked = 0;
451886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_unlock(&master_image->lock);
452a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_image:
453a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_bus:
454a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
455a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
456a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_request);
457a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
458ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchint vme_master_set(struct vme_resource *resource, int enabled,
459a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long vme_base, unsigned long long size,
460a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth)
461a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
462a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
463a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *image;
464a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
465a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
466a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
467ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a master resource\n");
468a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
469a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
470a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
471a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_master_resource, list);
472a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
473a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->master_set == NULL) {
474ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "vme_master_set not supported\n");
475a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
476a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
477a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
478ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (!(((image->address_attr & aspace) == aspace) &&
479a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		((image->cycle_attr & cycle) == cycle) &&
480a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		((image->width_attr & dwidth) == dwidth))) {
481ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Invalid attributes\n");
482a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
483a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
484a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
485a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	retval = vme_check_window(aspace, vme_base, size);
486ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (retval)
487a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return retval;
488a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
489a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->master_set(image, enabled, vme_base, size, aspace,
490a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		cycle, dwidth);
491a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
492a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_set);
493a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
494ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchint vme_master_get(struct vme_resource *resource, int *enabled,
495a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long *vme_base, unsigned long long *size,
496a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth)
497a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
498a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
499a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *image;
500a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
501a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
502ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a master resource\n");
503a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
504a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
505a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
506a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_master_resource, list);
507a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
50851a569f757f233bcffbffcdfeeff510916991a55Emilio G. Cota	if (bridge->master_get == NULL) {
509ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "vme_master_set not supported\n");
510a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
511a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
512a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
513a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->master_get(image, enabled, vme_base, size, aspace,
514a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		cycle, dwidth);
515a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
516a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_get);
517a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
518a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
519a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Read data out of VME space into a buffer.
520a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
521ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count,
522a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	loff_t offset)
523a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
524a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
525a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *image;
526a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	size_t length;
527a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
528a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->master_read == NULL) {
529ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Reading from resource not supported\n");
530a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
531a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
532a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
533a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
534ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a master resource\n");
535a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
536a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
537a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
538a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_master_resource, list);
539a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
540a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	length = vme_get_size(resource);
541a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
542a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (offset > length) {
543ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Invalid Offset\n");
544a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EFAULT;
545a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
546a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
547a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if ((offset + count) > length)
548a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		count = length - offset;
549a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
550a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->master_read(image, buf, count, offset);
551a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
552a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
553a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_read);
554a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
555a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
556a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Write data out to VME space from a buffer.
557a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
558ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchssize_t vme_master_write(struct vme_resource *resource, void *buf,
559a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	size_t count, loff_t offset)
560a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
561a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
562a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *image;
563a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	size_t length;
564a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
565a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->master_write == NULL) {
566ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Writing to resource not supported\n");
567a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
568a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
569a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
570a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
571ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a master resource\n");
572a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
573a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
574a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
575a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_master_resource, list);
576a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
577a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	length = vme_get_size(resource);
578a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
579a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (offset > length) {
580ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Invalid Offset\n");
581a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EFAULT;
582a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
583a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
584a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if ((offset + count) > length)
585a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		count = length - offset;
586a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
587a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->master_write(image, buf, count, offset);
588a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
589a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_write);
590a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
591a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
592a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Perform RMW cycle to provided location.
593a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
594ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchunsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask,
595a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned int compare, unsigned int swap, loff_t offset)
596a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
597a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
598a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *image;
599a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
600a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->master_rmw == NULL) {
601ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Writing to resource not supported\n");
602a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
603a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
604a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
605a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
606ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a master resource\n");
607a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
608a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
609a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
610a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_master_resource, list);
611a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
612a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->master_rmw(image, mask, compare, swap, offset);
613a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
614a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_rmw);
615a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
616a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchvoid vme_master_free(struct vme_resource *resource)
617a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
618a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *master_image;
619a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
620a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
621ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a master resource\n");
622a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
623a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
624a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
625a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	master_image = list_entry(resource->entry, struct vme_master_resource,
626a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		list);
627a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (master_image == NULL) {
628ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Can't find master resource\n");
629a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
630a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
631a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
632a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Unlock image */
633886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_lock(&master_image->lock);
634a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (master_image->locked == 0)
635a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Image is already free\n");
636a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
637a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	master_image->locked = 0;
638886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_unlock(&master_image->lock);
639a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
640a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Free up resource memory */
641a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(resource);
642a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
643a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_free);
644a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
645a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
646a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Request a DMA controller with specific attributes, return some unique
647a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * identifier.
648a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
6498f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangastruct vme_resource *vme_dma_request(struct vme_dev *vdev,
6508f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	vme_dma_route_t route)
651a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
652a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
653a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct list_head *dma_pos = NULL;
654a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_resource *allocated_ctrlr = NULL;
655a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_resource *dma_ctrlr = NULL;
656a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_resource *resource = NULL;
657a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
658a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* XXX Not checking resource attributes */
659a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	printk(KERN_ERR "No VME resource Attribute tests done\n");
660a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
6618f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	bridge = vdev->bridge;
662a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
663a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
664a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_bus;
665a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
666a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
667a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Loop through DMA resources */
668886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_for_each(dma_pos, &bridge->dma_resources) {
669a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		dma_ctrlr = list_entry(dma_pos,
670a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			struct vme_dma_resource, list);
671a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
672a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (dma_ctrlr == NULL) {
673ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			printk(KERN_ERR "Registered NULL DMA resource\n");
674a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			continue;
675a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
676a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
6774f723df45d3952c485ee0125fb6797ad615901c3Martyn Welch		/* Find an unlocked and compatible controller */
678886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_lock(&dma_ctrlr->mtx);
6794f723df45d3952c485ee0125fb6797ad615901c3Martyn Welch		if (((dma_ctrlr->route_attr & route) == route) &&
6804f723df45d3952c485ee0125fb6797ad615901c3Martyn Welch			(dma_ctrlr->locked == 0)) {
6814f723df45d3952c485ee0125fb6797ad615901c3Martyn Welch
682a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			dma_ctrlr->locked = 1;
683886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			mutex_unlock(&dma_ctrlr->mtx);
684a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			allocated_ctrlr = dma_ctrlr;
685a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			break;
686a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
687886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_unlock(&dma_ctrlr->mtx);
688a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
689a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
690a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Check to see if we found a resource */
691a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (allocated_ctrlr == NULL)
692a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_ctrlr;
693a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
694a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
695a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource == NULL) {
696a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_WARNING "Unable to allocate resource structure\n");
697a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_alloc;
698a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
699a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource->type = VME_DMA;
700886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	resource->entry = &allocated_ctrlr->list;
701a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
702a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return resource;
703a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
704a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_alloc:
705a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Unlock image */
706886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&dma_ctrlr->mtx);
707a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_ctrlr->locked = 0;
708886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&dma_ctrlr->mtx);
709a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_ctrlr:
710a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_bus:
711a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
712a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
71358e507987b285f3df99f839c79da3985555ac220Martyn WelchEXPORT_SYMBOL(vme_dma_request);
714a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
715a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
716a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Start new list
717a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
718a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct vme_dma_list *vme_new_dma_list(struct vme_resource *resource)
719a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
720a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_resource *ctrlr;
721a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_list *dma_list;
722a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
723a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_DMA) {
724ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a DMA resource\n");
725a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
726a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
727a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
728a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
729a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
730ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	dma_list = kmalloc(sizeof(struct vme_dma_list), GFP_KERNEL);
731ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (dma_list == NULL) {
732ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for new dma list\n");
733a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
734a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
735886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	INIT_LIST_HEAD(&dma_list->entries);
736a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_list->parent = ctrlr;
737886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_init(&dma_list->mtx);
738a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
739a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return dma_list;
740a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
741a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_new_dma_list);
742a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
743a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
744a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Create "Pattern" type attributes
745a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
746a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern,
747a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_pattern_t type)
748a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
749a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_attr *attributes;
750a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_pattern *pattern_attr;
751a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
752ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
753ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (attributes == NULL) {
754ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for attributes "
755ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"structure\n");
756a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_attr;
757a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
758a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
759ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	pattern_attr = kmalloc(sizeof(struct vme_dma_pattern), GFP_KERNEL);
760ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (pattern_attr == NULL) {
761ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for pattern "
762ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"attributes\n");
763a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_pat;
764a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
765a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
766a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->type = VME_DMA_PATTERN;
767a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->private = (void *)pattern_attr;
768a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
769a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pattern_attr->pattern = pattern;
770a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pattern_attr->type = type;
771a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
772a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return attributes;
773a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
774a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_pat:
775a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(attributes);
776a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_attr:
777a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
778a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
779a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_pattern_attribute);
780a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
781a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
782a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Create "PCI" type attributes
783a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
784a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address)
785a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
786a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_attr *attributes;
787a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_pci *pci_attr;
788a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
789a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* XXX Run some sanity checks here */
790a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
791ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
792ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (attributes == NULL) {
793ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for attributes "
794ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"structure\n");
795a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_attr;
796a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
797a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
798ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	pci_attr = kmalloc(sizeof(struct vme_dma_pci), GFP_KERNEL);
799ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (pci_attr == NULL) {
800ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for pci "
801ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"attributes\n");
802a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_pci;
803a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
804a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
805a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
806a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
807a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->type = VME_DMA_PCI;
808a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->private = (void *)pci_attr;
809a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
810a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pci_attr->address = address;
811a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
812a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return attributes;
813a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
814a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_pci:
815a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(attributes);
816a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_attr:
817a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
818a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
819a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_pci_attribute);
820a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
821a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
822a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Create "VME" type attributes
823a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
824a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address,
825a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth)
826a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
827a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_attr *attributes;
828a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_vme *vme_attr;
829a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
830ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	attributes = kmalloc(
831a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		sizeof(struct vme_dma_attr), GFP_KERNEL);
832ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (attributes == NULL) {
833ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for attributes "
834ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"structure\n");
835a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_attr;
836a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
837a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
838ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	vme_attr = kmalloc(sizeof(struct vme_dma_vme), GFP_KERNEL);
839ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (vme_attr == NULL) {
840ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for vme "
841ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"attributes\n");
842a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_vme;
843a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
844a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
845a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->type = VME_DMA_VME;
846a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->private = (void *)vme_attr;
847a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
848a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_attr->address = address;
849a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_attr->aspace = aspace;
850a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_attr->cycle = cycle;
851a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_attr->dwidth = dwidth;
852a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
853a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return attributes;
854a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
855a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_vme:
856a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(attributes);
857a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_attr:
858a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
859a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
860a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_vme_attribute);
861a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
862a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
863a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Free attribute
864a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
865a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchvoid vme_dma_free_attribute(struct vme_dma_attr *attributes)
866a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
867a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(attributes->private);
868a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(attributes);
869a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
870a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_free_attribute);
871a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
872a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
873a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_attr *dest, size_t count)
874a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
875a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = list->parent->parent;
876a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
877a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
878a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->dma_list_add == NULL) {
879ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Link List DMA generation not supported\n");
880a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
881a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
882a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
883886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	if (!mutex_trylock(&list->mtx)) {
884ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Link List already submitted\n");
885a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
886a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
887a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
888a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	retval = bridge->dma_list_add(list, src, dest, count);
889a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
890886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&list->mtx);
891a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
892a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
893a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
894a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_list_add);
895a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
896a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_dma_list_exec(struct vme_dma_list *list)
897a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
898a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = list->parent->parent;
899a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
900a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
901a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->dma_list_exec == NULL) {
902ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Link List DMA execution not supported\n");
903a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
904a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
905a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
906886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&list->mtx);
907a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
908a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	retval = bridge->dma_list_exec(list);
909a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
910886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&list->mtx);
911a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
912a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
913a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
914a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_list_exec);
915a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
916a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_dma_list_free(struct vme_dma_list *list)
917a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
918a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = list->parent->parent;
919a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
920a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
921a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->dma_list_empty == NULL) {
922ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Emptying of Link Lists not supported\n");
923a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
924a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
925a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
926886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	if (!mutex_trylock(&list->mtx)) {
927ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Link List in use\n");
928a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
929a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
930a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
931a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/*
932a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	 * Empty out all of the entries from the dma list. We need to go to the
933a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	 * low level driver as dma entries are driver specific.
934a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	 */
935a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	retval = bridge->dma_list_empty(list);
936a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (retval) {
937ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to empty link-list entries\n");
938886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_unlock(&list->mtx);
939a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return retval;
940a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
941886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&list->mtx);
942a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(list);
943a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
944a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
945a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
946a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_list_free);
947a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
948a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_dma_free(struct vme_resource *resource)
949a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
950a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_resource *ctrlr;
951a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
952a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_DMA) {
953ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a DMA resource\n");
954a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
955a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
956a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
957a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
958a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
959886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	if (!mutex_trylock(&ctrlr->mtx)) {
960ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Resource busy, can't free\n");
961a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EBUSY;
962a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
963a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
964886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	if (!(list_empty(&ctrlr->pending) && list_empty(&ctrlr->running))) {
965ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Resource still processing transfers\n");
966886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_unlock(&ctrlr->mtx);
967a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EBUSY;
968a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
969a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
970a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	ctrlr->locked = 0;
971a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
972886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&ctrlr->mtx);
973a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
974a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return 0;
975a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
976a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_free);
977a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
978c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welchvoid vme_irq_handler(struct vme_bridge *bridge, int level, int statid)
979c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch{
980c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	void (*call)(int, int, void *);
981c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	void *priv_data;
982c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
983c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	call = bridge->irq[level - 1].callback[statid].func;
984c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	priv_data = bridge->irq[level - 1].callback[statid].priv_data;
985c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
986c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (call != NULL)
987c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		call(level, statid, priv_data);
988c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	else
989c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_WARNING "Spurilous VME interrupt, level:%x, "
990c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch			"vector:%x\n", level, statid);
991c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch}
992c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn WelchEXPORT_SYMBOL(vme_irq_handler);
993c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
9948f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangaint vme_irq_request(struct vme_dev *vdev, int level, int statid,
99529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	void (*callback)(int, int, void *),
996a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	void *priv_data)
997a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
998a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
999a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
10008f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	bridge = vdev->bridge;
1001a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
1002a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
1003a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1004a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1005a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1006ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if ((level < 1) || (level > 7)) {
1007c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_ERR "Invalid interrupt level\n");
1008a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1009a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1010a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1011c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (bridge->irq_set == NULL) {
1012c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_ERR "Configuring interrupts not supported\n");
1013a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1014a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1015a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1016886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&bridge->irq_mtx);
1017c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1018c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (bridge->irq[level - 1].callback[statid].func) {
1019886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_unlock(&bridge->irq_mtx);
1020c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_WARNING "VME Interrupt already taken\n");
1021c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		return -EBUSY;
1022c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	}
1023c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1024c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].count++;
1025c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].callback[statid].priv_data = priv_data;
1026c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].callback[statid].func = callback;
1027c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1028c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	/* Enable IRQ level */
102929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge->irq_set(bridge, level, 1, 1);
1030c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1031886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&bridge->irq_mtx);
1032c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1033c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	return 0;
1034a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1035c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn WelchEXPORT_SYMBOL(vme_irq_request);
1036a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
10378f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangavoid vme_irq_free(struct vme_dev *vdev, int level, int statid)
1038a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1039a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1040a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
10418f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	bridge = vdev->bridge;
1042a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
1043a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
1044a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
1045a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1046a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1047ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if ((level < 1) || (level > 7)) {
1048c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_ERR "Invalid interrupt level\n");
1049a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
1050a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1051a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1052c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (bridge->irq_set == NULL) {
1053c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_ERR "Configuring interrupts not supported\n");
1054a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
1055a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1056a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1057886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&bridge->irq_mtx);
1058c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1059c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].count--;
1060c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1061c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	/* Disable IRQ level if no more interrupts attached at this level*/
1062c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (bridge->irq[level - 1].count == 0)
106329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		bridge->irq_set(bridge, level, 0, 1);
1064c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1065c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].callback[statid].func = NULL;
1066c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].callback[statid].priv_data = NULL;
1067c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1068886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&bridge->irq_mtx);
1069a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1070c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn WelchEXPORT_SYMBOL(vme_irq_free);
1071a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
10728f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangaint vme_irq_generate(struct vme_dev *vdev, int level, int statid)
1073a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1074a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1075a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
10768f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	bridge = vdev->bridge;
1077a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
1078a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
1079a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1080a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1081a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1082ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if ((level < 1) || (level > 7)) {
1083a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_WARNING "Invalid interrupt level\n");
1084a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1085a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1086a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1087c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (bridge->irq_generate == NULL) {
1088ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Interrupt generation not supported\n");
1089a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1090a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1091a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
109229848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	return bridge->irq_generate(bridge, level, statid);
1093a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1094c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn WelchEXPORT_SYMBOL(vme_irq_generate);
1095a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
109642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch/*
109742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch * Request the location monitor, return resource or NULL
109842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch */
10998f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangastruct vme_resource *vme_lm_request(struct vme_dev *vdev)
1100a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1101a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
110242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct list_head *lm_pos = NULL;
110342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *allocated_lm = NULL;
110442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm = NULL;
110542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_resource *resource = NULL;
1106a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
11078f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	bridge = vdev->bridge;
1108a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
1109a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
111042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		goto err_bus;
111142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	}
111242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
111342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	/* Loop through DMA resources */
1114886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_for_each(lm_pos, &bridge->lm_resources) {
111542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		lm = list_entry(lm_pos,
111642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			struct vme_lm_resource, list);
111742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
111842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		if (lm == NULL) {
111942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			printk(KERN_ERR "Registered NULL Location Monitor "
112042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch				"resource\n");
112142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			continue;
112242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		}
112342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
112442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		/* Find an unlocked controller */
1125886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_lock(&lm->mtx);
112642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		if (lm->locked == 0) {
112742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			lm->locked = 1;
1128886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			mutex_unlock(&lm->mtx);
112942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			allocated_lm = lm;
113042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			break;
113142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		}
1132886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_unlock(&lm->mtx);
113342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	}
113442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
113542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	/* Check to see if we found a resource */
113642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (allocated_lm == NULL)
113742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		goto err_lm;
113842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
113942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
114042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource == NULL) {
114142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Unable to allocate resource structure\n");
114242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		goto err_alloc;
114342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	}
114442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	resource->type = VME_LM;
1145886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	resource->entry = &allocated_lm->list;
114642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
114742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return resource;
114842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
114942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welcherr_alloc:
115042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	/* Unlock image */
1151886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&lm->mtx);
115242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm->locked = 0;
1153886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&lm->mtx);
115442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welcherr_lm:
115542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welcherr_bus:
115642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return NULL;
115742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch}
115842fb503122d8cd428b5b1078bd473847ca2b206cMartyn WelchEXPORT_SYMBOL(vme_lm_request);
115942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
116042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchint vme_lm_count(struct vme_resource *resource)
116142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch{
116242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
116342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
116442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
116542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
116642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		return -EINVAL;
116742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	}
116842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
116942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
117042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
117142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return lm->monitors;
117242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch}
117342fb503122d8cd428b5b1078bd473847ca2b206cMartyn WelchEXPORT_SYMBOL(vme_lm_count);
117442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
117542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchint vme_lm_set(struct vme_resource *resource, unsigned long long lm_base,
117642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	vme_address_t aspace, vme_cycle_t cycle)
117742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch{
117842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
117942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
118042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
118142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
118242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
1183a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1184a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1185a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
118642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
118742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
1188a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->lm_set == NULL) {
118942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "vme_lm_set not supported\n");
1190a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1191a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1192a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
11938be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	return bridge->lm_set(lm, lm_base, aspace, cycle);
1194a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1195a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_lm_set);
1196a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
119742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchint vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base,
119842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	vme_address_t *aspace, vme_cycle_t *cycle)
1199a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
120042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
120142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
1202a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
120342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
120442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
1205a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1206a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1207a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
120842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
120942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
1210a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->lm_get == NULL) {
121142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "vme_lm_get not supported\n");
1212a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1213a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1214a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
121542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return bridge->lm_get(lm, lm_base, aspace, cycle);
1216a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1217a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_lm_get);
1218a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
121942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchint vme_lm_attach(struct vme_resource *resource, int monitor,
122042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	void (*callback)(int))
1221a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
122242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
122342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
1224a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
122542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
122642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
1227a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1228a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1229a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
123042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
123142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
1232a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->lm_attach == NULL) {
123342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "vme_lm_attach not supported\n");
1234a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1235a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1236a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
123742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return bridge->lm_attach(lm, monitor, callback);
1238a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1239a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_lm_attach);
1240a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
124142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchint vme_lm_detach(struct vme_resource *resource, int monitor)
1242a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
124342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
124442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
1245a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
124642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
124742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
1248a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1249a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1250a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
125142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
125242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
1253a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->lm_detach == NULL) {
125442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "vme_lm_detach not supported\n");
1255a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1256a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1257a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
125842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return bridge->lm_detach(lm, monitor);
1259a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1260a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_lm_detach);
1261a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
126242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchvoid vme_lm_free(struct vme_resource *resource)
126342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch{
126442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
126542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
126642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
126742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
126842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		return;
126942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	}
127042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
127142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
127242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
1273886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&lm->mtx);
127442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
12758be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	/* XXX
12768be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	 * Check to see that there aren't any callbacks still attached, if
12778be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	 * there are we should probably be detaching them!
12788be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	 */
127942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
128042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm->locked = 0;
128142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
1282886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&lm->mtx);
12838be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch
12848be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	kfree(resource);
128542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch}
128642fb503122d8cd428b5b1078bd473847ca2b206cMartyn WelchEXPORT_SYMBOL(vme_lm_free);
128742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
12888f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangaint vme_slot_get(struct vme_dev *vdev)
1289a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1290a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1291a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
12928f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	bridge = vdev->bridge;
1293a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
1294a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
1295a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1296a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1297a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1298a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->slot_get == NULL) {
1299ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "vme_slot_get not supported\n");
1300a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1301a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1302a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
130329848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	return bridge->slot_get(bridge);
1304a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1305a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slot_get);
1306a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1307a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1308a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/* - Bridge Registration --------------------------------------------------- */
1309a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1310733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vangastatic int vme_add_bus(struct vme_bridge *bridge)
1311a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1312a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int i;
1313733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga	int ret = -1;
1314a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1315733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga	mutex_lock(&vme_buses_lock);
1316a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	for (i = 0; i < sizeof(vme_bus_numbers) * 8; i++) {
1317733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga		if ((vme_bus_numbers & (1 << i)) == 0) {
1318733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga			vme_bus_numbers |= (1 << i);
1319733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga			bridge->num = i;
13205d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga			INIT_LIST_HEAD(&bridge->devices);
1321733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga			list_add_tail(&bridge->bus_list, &vme_bus_list);
1322733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga			ret = 0;
1323a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			break;
1324a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
1325a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1326733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga	mutex_unlock(&vme_buses_lock);
1327a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1328733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga	return ret;
1329a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1330a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1331733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vangastatic void vme_remove_bus(struct vme_bridge *bridge)
1332a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
13335d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_dev *vdev;
13345d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_dev *tmp;
13355d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga
1336733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga	mutex_lock(&vme_buses_lock);
1337733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga	vme_bus_numbers &= ~(1 << bridge->num);
13385d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	list_for_each_entry_safe(vdev, tmp, &bridge->devices, bridge_list) {
13395d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		list_del(&vdev->drv_list);
13405d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		list_del(&vdev->bridge_list);
13415d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		device_unregister(&vdev->dev);
13425d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	}
1343733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga	list_del(&bridge->bus_list);
1344733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga	mutex_unlock(&vme_buses_lock);
1345a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1346a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1347f6c39d4f2d350df049a844b658eb6b08c5833e51Manohar Vangastatic void vme_dev_release(struct device *dev)
1348f6c39d4f2d350df049a844b658eb6b08c5833e51Manohar Vanga{
13498f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	kfree(dev_to_vme_dev(dev));
1350f6c39d4f2d350df049a844b658eb6b08c5833e51Manohar Vanga}
1351f6c39d4f2d350df049a844b658eb6b08c5833e51Manohar Vanga
1352ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchint vme_register_bridge(struct vme_bridge *bridge)
1353a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
13545d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	return vme_add_bus(bridge);
13555d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga}
13565d6abf379d73efe390488e8edba972af4e93cb1cManohar VangaEXPORT_SYMBOL(vme_register_bridge);
1357a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
13585d6abf379d73efe390488e8edba972af4e93cb1cManohar Vangavoid vme_unregister_bridge(struct vme_bridge *bridge)
13595d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga{
13605d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	vme_remove_bus(bridge);
13615d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga}
13625d6abf379d73efe390488e8edba972af4e93cb1cManohar VangaEXPORT_SYMBOL(vme_unregister_bridge);
1363a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
13645d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga/* - Driver Registration --------------------------------------------------- */
13655d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga
13665d6abf379d73efe390488e8edba972af4e93cb1cManohar Vangastatic int __vme_register_driver_bus(struct vme_driver *drv,
13675d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_bridge *bridge, unsigned int ndevs)
13685d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga{
13695d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	int err;
13705d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	unsigned int i;
13715d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_dev *vdev;
13725d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_dev *tmp;
13735d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga
13745d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	for (i = 0; i < ndevs; i++) {
13755d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		vdev = kzalloc(sizeof(struct vme_dev), GFP_KERNEL);
13765d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		if (!vdev) {
13775d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga			err = -ENOMEM;
1378f6c39d4f2d350df049a844b658eb6b08c5833e51Manohar Vanga			goto err_devalloc;
1379f6c39d4f2d350df049a844b658eb6b08c5833e51Manohar Vanga		}
1380a916a391d3e19593a104a8c3c4779a3084f1ca5bManohar Vanga		vdev->num = i;
13818f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga		vdev->bridge = bridge;
13825d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		vdev->dev.platform_data = drv;
13835d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		vdev->dev.release = vme_dev_release;
13848f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga		vdev->dev.parent = bridge->parent;
13858f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga		vdev->dev.bus = &vme_bus_type;
1386a916a391d3e19593a104a8c3c4779a3084f1ca5bManohar Vanga		dev_set_name(&vdev->dev, "%s.%u-%u", drv->name, bridge->num,
1387a916a391d3e19593a104a8c3c4779a3084f1ca5bManohar Vanga			vdev->num);
1388a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
13895d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		err = device_register(&vdev->dev);
13905d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		if (err)
1391a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			goto err_reg;
1392a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
13935d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		if (vdev->dev.platform_data) {
13945d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga			list_add_tail(&vdev->drv_list, &drv->devices);
13955d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga			list_add_tail(&vdev->bridge_list, &bridge->devices);
13965d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		} else
13975d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga			device_unregister(&vdev->dev);
13985d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	}
13995d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	return 0;
1400a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1401a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_reg:
14028f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	kfree(vdev);
1403f6c39d4f2d350df049a844b658eb6b08c5833e51Manohar Vangaerr_devalloc:
14045d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	list_for_each_entry_safe(vdev, tmp, &drv->devices, drv_list) {
14055d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		list_del(&vdev->drv_list);
14065d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		list_del(&vdev->bridge_list);
14078f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga		device_unregister(&vdev->dev);
1408a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
14095d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	return err;
1410a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1411a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
14125d6abf379d73efe390488e8edba972af4e93cb1cManohar Vangastatic int __vme_register_driver(struct vme_driver *drv, unsigned int ndevs)
1413a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
14145d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_bridge *bridge;
14155d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	int err = 0;
1416a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
14175d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	mutex_lock(&vme_buses_lock);
14185d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	list_for_each_entry(bridge, &vme_bus_list, bus_list) {
14195d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		/*
14205d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		 * This cannot cause trouble as we already have vme_buses_lock
14215d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		 * and if the bridge is removed, it will have to go through
14225d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		 * vme_unregister_bridge() to do it (which calls remove() on
14235d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		 * the bridge which in turn tries to acquire vme_buses_lock and
1424c26f6112990b90977db429596ed0640d153b3a32Manohar Vanga		 * will have to wait).
14255d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		 */
14265d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		err = __vme_register_driver_bus(drv, bridge, ndevs);
14275d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		if (err)
14285d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga			break;
1429a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
14305d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	mutex_unlock(&vme_buses_lock);
14315d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	return err;
1432a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1433a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
14345d6abf379d73efe390488e8edba972af4e93cb1cManohar Vangaint vme_register_driver(struct vme_driver *drv, unsigned int ndevs)
1435a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
14365d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	int err;
14375d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga
1438a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	drv->driver.name = drv->name;
1439a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	drv->driver.bus = &vme_bus_type;
14405d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	INIT_LIST_HEAD(&drv->devices);
14415d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga
14425d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	err = driver_register(&drv->driver);
14435d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	if (err)
14445d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		return err;
1445a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
14465d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	err = __vme_register_driver(drv, ndevs);
14475d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	if (err)
14485d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		driver_unregister(&drv->driver);
14495d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga
14505d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	return err;
1451a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1452a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_register_driver);
1453a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1454ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchvoid vme_unregister_driver(struct vme_driver *drv)
1455a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
14565d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_dev *dev, *dev_tmp;
14575d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga
14585d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	mutex_lock(&vme_buses_lock);
14595d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	list_for_each_entry_safe(dev, dev_tmp, &drv->devices, drv_list) {
14605d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		list_del(&dev->drv_list);
14615d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		list_del(&dev->bridge_list);
14625d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		device_unregister(&dev->dev);
14635d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	}
14645d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	mutex_unlock(&vme_buses_lock);
14655d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga
1466a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	driver_unregister(&drv->driver);
1467a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1468a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_unregister_driver);
1469a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1470a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/* - Bus Registration ------------------------------------------------------ */
1471a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1472a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int vme_bus_match(struct device *dev, struct device_driver *drv)
1473a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
14745d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_driver *vme_drv;
1475a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
14765d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	vme_drv = container_of(drv, struct vme_driver, driver);
1477a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
14785d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	if (dev->platform_data == vme_drv) {
14795d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		struct vme_dev *vdev = dev_to_vme_dev(dev);
1480a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
14815d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		if (vme_drv->match && vme_drv->match(vdev))
14825d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga			return 1;
1483a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch
14845d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		dev->platform_data = NULL;
1485a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1486a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return 0;
1487a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1488a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1489a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int vme_bus_probe(struct device *dev)
1490a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1491a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval = -ENODEV;
14925d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_driver *driver;
14935d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_dev *vdev = dev_to_vme_dev(dev);
1494a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
14955d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	driver = dev->platform_data;
1496a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1497ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (driver->probe != NULL)
14988f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga		retval = driver->probe(vdev);
1499a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1500a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
1501a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1502a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1503a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int vme_bus_remove(struct device *dev)
1504a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1505a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval = -ENODEV;
15065d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_driver *driver;
15075d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_dev *vdev = dev_to_vme_dev(dev);
1508a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
15095d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	driver = dev->platform_data;
1510a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1511ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (driver->remove != NULL)
15128f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga		retval = driver->remove(vdev);
1513a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1514a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
1515a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1516a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1517a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct bus_type vme_bus_type = {
1518a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	.name = "vme",
1519a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	.match = vme_bus_match,
1520a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	.probe = vme_bus_probe,
1521a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	.remove = vme_bus_remove,
1522a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch};
1523a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_bus_type);
1524a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1525ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchstatic int __init vme_init(void)
1526a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1527a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bus_register(&vme_bus_type);
1528a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1529a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1530ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchstatic void __exit vme_exit(void)
1531a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1532a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bus_unregister(&vme_bus_type);
1533a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1534a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1535a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchMODULE_DESCRIPTION("VME bridge driver framework");
153666bd8db52ab48e7189e02d4bf1f23109cc1ede70Martyn WelchMODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
1537a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchMODULE_LICENSE("GPL");
1538a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1539a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchmodule_init(vme_init);
1540a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchmodule_exit(vme_exit);
1541