vme.c revision 886953e9b70bcb6913716b49bdf21b69450a7cd6
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
37400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch/* Bitmask and mutex to keep track of bridge numbers */
38a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic unsigned int vme_bus_numbers;
391fe923ec740ad8d87e616afc50f5b00d88a75ed2Bill Pembertonstatic DEFINE_MUTEX(vme_bus_num_mtx);
40a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
41ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchstatic void __exit vme_exit(void);
42ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchstatic int __init vme_init(void);
43a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
44a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
45a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
46a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Find the bridge resource associated with a specific device resource
47a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
48a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic struct vme_bridge *dev_to_bridge(struct device *dev)
49a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
50a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return dev->platform_data;
51a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
52a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
53a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
54a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Find the bridge that the resource is associated with.
55a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
56a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic struct vme_bridge *find_bridge(struct vme_resource *resource)
57a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
58a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Get list to search */
59a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	switch (resource->type) {
60a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_MASTER:
61a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return list_entry(resource->entry, struct vme_master_resource,
62a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			list)->parent;
63a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
64a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_SLAVE:
65a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return list_entry(resource->entry, struct vme_slave_resource,
66a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			list)->parent;
67a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
68a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_DMA:
69a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return list_entry(resource->entry, struct vme_dma_resource,
70a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			list)->parent;
71a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
7242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	case VME_LM:
7342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		return list_entry(resource->entry, struct vme_lm_resource,
7442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			list)->parent;
7542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		break;
76a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	default:
77a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Unknown resource type\n");
78a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
79a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
80a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
81a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
82a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
83a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
84a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Allocate a contiguous block of memory for use by the driver. This is used to
85a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * create the buffers for the slave windows.
86a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch *
87a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * XXX VME bridges could be available on buses other than PCI. At the momment
88a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch *     this framework only supports PCI devices.
89a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
90ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchvoid *vme_alloc_consistent(struct vme_resource *resource, size_t size,
91a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_addr_t *dma)
92a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
93a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
94a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct pci_dev *pdev;
95a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
96ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (resource == NULL) {
97ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "No resource\n");
98a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
99a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
100a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
101a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = find_bridge(resource);
102ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (bridge == NULL) {
103ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Can't find bridge\n");
104a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
105a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
106a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
107a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Find pci_dev container of dev */
108a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->parent == NULL) {
109ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Dev entry NULL\n");
110a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
111a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
112a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pdev = container_of(bridge->parent, struct pci_dev, dev);
113a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
114a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return pci_alloc_consistent(pdev, size, dma);
115a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
116a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_alloc_consistent);
117a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
118a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
119a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Free previously allocated contiguous block of memory.
120a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch *
121a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * XXX VME bridges could be available on buses other than PCI. At the momment
122a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch *     this framework only supports PCI devices.
123a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
124a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchvoid vme_free_consistent(struct vme_resource *resource, size_t size,
125a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	void *vaddr, dma_addr_t dma)
126a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
127a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
128a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct pci_dev *pdev;
129a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
130ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (resource == NULL) {
131ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "No resource\n");
132a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
133a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
134a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
135a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = find_bridge(resource);
136ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (bridge == NULL) {
137ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Can't find bridge\n");
138a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
139a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
140a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
141a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Find pci_dev container of dev */
142a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pdev = container_of(bridge->parent, struct pci_dev, dev);
143a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
144a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pci_free_consistent(pdev, size, vaddr, dma);
145a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
146a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_free_consistent);
147a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
148a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchsize_t vme_get_size(struct vme_resource *resource)
149a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
150a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int enabled, retval;
151a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long base, size;
152a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_addr_t buf_base;
153a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t aspace;
154a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_cycle_t cycle;
155a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_width_t dwidth;
156a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
157a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	switch (resource->type) {
158a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_MASTER:
159a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = vme_master_get(resource, &enabled, &base, &size,
160a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			&aspace, &cycle, &dwidth);
161a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
162a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return size;
163a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
164a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_SLAVE:
165a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = vme_slave_get(resource, &enabled, &base, &size,
166a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			&buf_base, &aspace, &cycle);
167a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
168a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return size;
169a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
170a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_DMA:
171a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return 0;
172a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
173a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	default:
174a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Unknown resource type\n");
175a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return 0;
176a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
177a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
178a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
179a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_get_size);
180a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
181a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int vme_check_window(vme_address_t aspace, unsigned long long vme_base,
182a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long size)
183a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
184a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval = 0;
185a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
186a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	switch (aspace) {
187a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_A16:
188a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_base + size) > VME_A16_MAX) ||
189a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch				(vme_base > VME_A16_MAX))
190a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			retval = -EFAULT;
191a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
192a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_A24:
193a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_base + size) > VME_A24_MAX) ||
194a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch				(vme_base > VME_A24_MAX))
195a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			retval = -EFAULT;
196a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
197a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_A32:
198a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_base + size) > VME_A32_MAX) ||
199a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch				(vme_base > VME_A32_MAX))
200a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			retval = -EFAULT;
201a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
202a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_A64:
203a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/*
204a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 * Any value held in an unsigned long long can be used as the
205a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 * base
206a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 */
207a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
208a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_CRCSR:
209a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_base + size) > VME_CRCSR_MAX) ||
210a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch				(vme_base > VME_CRCSR_MAX))
211a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			retval = -EFAULT;
212a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
213a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_USER1:
214a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_USER2:
215a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_USER3:
216a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_USER4:
217a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/* User Defined */
218a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
219a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	default:
220ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Invalid address space\n");
221a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = -EINVAL;
222a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
223a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
224a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
225a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
226a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
227a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
228a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
229a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Request a slave image with specific attributes, return some unique
230a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * identifier.
231a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
232ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchstruct vme_resource *vme_slave_request(struct device *dev,
233a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t address, vme_cycle_t cycle)
234a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
235a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
236a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct list_head *slave_pos = NULL;
237a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *allocated_image = NULL;
238a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *slave_image = NULL;
239a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_resource *resource = NULL;
240a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
241a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
242a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
243a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
244a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_bus;
245a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
246a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
247a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Loop through slave resources */
248886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_for_each(slave_pos, &bridge->slave_resources) {
249a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		slave_image = list_entry(slave_pos,
250a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			struct vme_slave_resource, list);
251a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
252a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (slave_image == NULL) {
253ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			printk(KERN_ERR "Registered NULL Slave resource\n");
254a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			continue;
255a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
256a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
257a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/* Find an unlocked and compatible image */
258886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_lock(&slave_image->mtx);
259ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		if (((slave_image->address_attr & address) == address) &&
260a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			((slave_image->cycle_attr & cycle) == cycle) &&
261a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			(slave_image->locked == 0)) {
262a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
263a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			slave_image->locked = 1;
264886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			mutex_unlock(&slave_image->mtx);
265a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			allocated_image = slave_image;
266a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			break;
267a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
268886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_unlock(&slave_image->mtx);
269a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
270a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
271a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* No free image */
272a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (allocated_image == NULL)
273a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_image;
274a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
275a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
276a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource == NULL) {
277a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_WARNING "Unable to allocate resource structure\n");
278a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_alloc;
279a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
280a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource->type = VME_SLAVE;
281886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	resource->entry = &allocated_image->list;
282a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
283a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return resource;
284a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
285a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_alloc:
286a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Unlock image */
287886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&slave_image->mtx);
288a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	slave_image->locked = 0;
289886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&slave_image->mtx);
290a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_image:
291a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_bus:
292a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
293a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
294a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slave_request);
295a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
296ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchint vme_slave_set(struct vme_resource *resource, int enabled,
297a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long vme_base, unsigned long long size,
298a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_addr_t buf_base, vme_address_t aspace, vme_cycle_t cycle)
299a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
300a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
301a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *image;
302a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
303a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
304a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_SLAVE) {
305ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a slave resource\n");
306a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
307a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
308a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
309a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_slave_resource, list);
310a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
311a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->slave_set == NULL) {
312ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Function not supported\n");
313a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -ENOSYS;
314a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
315a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
316ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (!(((image->address_attr & aspace) == aspace) &&
317a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		((image->cycle_attr & cycle) == cycle))) {
318ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Invalid attributes\n");
319a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
320a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
321a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
322a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	retval = vme_check_window(aspace, vme_base, size);
323ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (retval)
324a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return retval;
325a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
326a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->slave_set(image, enabled, vme_base, size, buf_base,
327a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		aspace, cycle);
328a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
329a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slave_set);
330a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
331ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchint vme_slave_get(struct vme_resource *resource, int *enabled,
332a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long *vme_base, unsigned long long *size,
333a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_addr_t *buf_base, vme_address_t *aspace, vme_cycle_t *cycle)
334a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
335a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
336a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *image;
337a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
338a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_SLAVE) {
339ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a slave resource\n");
340a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
341a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
342a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
343a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_slave_resource, list);
344a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
34551a569f757f233bcffbffcdfeeff510916991a55Emilio G. Cota	if (bridge->slave_get == NULL) {
346ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "vme_slave_get not supported\n");
347a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
348a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
349a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
350a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->slave_get(image, enabled, vme_base, size, buf_base,
351a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		aspace, cycle);
352a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
353a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slave_get);
354a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
355a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchvoid vme_slave_free(struct vme_resource *resource)
356a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
357a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *slave_image;
358a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
359a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_SLAVE) {
360ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a slave resource\n");
361a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
362a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
363a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
364a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	slave_image = list_entry(resource->entry, struct vme_slave_resource,
365a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		list);
366a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (slave_image == NULL) {
367ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Can't find slave resource\n");
368a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
369a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
370a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
371a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Unlock image */
372886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&slave_image->mtx);
373a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (slave_image->locked == 0)
374a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Image is already free\n");
375a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
376a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	slave_image->locked = 0;
377886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&slave_image->mtx);
378a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
379a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Free up resource memory */
380a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(resource);
381a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
382a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slave_free);
383a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
384a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
385a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Request a master image with specific attributes, return some unique
386a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * identifier.
387a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
388ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchstruct vme_resource *vme_master_request(struct device *dev,
389a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t address, vme_cycle_t cycle, vme_width_t dwidth)
390a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
391a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
392a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct list_head *master_pos = NULL;
393a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *allocated_image = NULL;
394a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *master_image = NULL;
395a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_resource *resource = NULL;
396a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
397a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
398a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
399a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
400a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_bus;
401a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
402a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
403a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Loop through master resources */
404886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_for_each(master_pos, &bridge->master_resources) {
405a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		master_image = list_entry(master_pos,
406a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			struct vme_master_resource, list);
407a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
408a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (master_image == NULL) {
409a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			printk(KERN_WARNING "Registered NULL master resource\n");
410a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			continue;
411a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
412a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
413a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/* Find an unlocked and compatible image */
414886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		spin_lock(&master_image->lock);
415ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		if (((master_image->address_attr & address) == address) &&
416a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			((master_image->cycle_attr & cycle) == cycle) &&
417a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			((master_image->width_attr & dwidth) == dwidth) &&
418a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			(master_image->locked == 0)) {
419a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
420a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			master_image->locked = 1;
421886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			spin_unlock(&master_image->lock);
422a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			allocated_image = master_image;
423a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			break;
424a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
425886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		spin_unlock(&master_image->lock);
426a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
427a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
428a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Check to see if we found a resource */
429a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (allocated_image == NULL) {
430a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find a suitable resource\n");
431a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_image;
432a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
433a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
434a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
435a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource == NULL) {
436a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Unable to allocate resource structure\n");
437a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_alloc;
438a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
439a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource->type = VME_MASTER;
440886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	resource->entry = &allocated_image->list;
441a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
442a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return resource;
443a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
444a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(resource);
445a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_alloc:
446a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Unlock image */
447886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_lock(&master_image->lock);
448a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	master_image->locked = 0;
449886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_unlock(&master_image->lock);
450a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_image:
451a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_bus:
452a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
453a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
454a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_request);
455a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
456ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchint vme_master_set(struct vme_resource *resource, int enabled,
457a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long vme_base, unsigned long long size,
458a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth)
459a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
460a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
461a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *image;
462a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
463a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
464a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
465ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a master resource\n");
466a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
467a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
468a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
469a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_master_resource, list);
470a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
471a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->master_set == NULL) {
472ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "vme_master_set not supported\n");
473a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
474a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
475a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
476ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (!(((image->address_attr & aspace) == aspace) &&
477a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		((image->cycle_attr & cycle) == cycle) &&
478a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		((image->width_attr & dwidth) == dwidth))) {
479ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Invalid attributes\n");
480a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
481a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
482a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
483a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	retval = vme_check_window(aspace, vme_base, size);
484ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (retval)
485a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return retval;
486a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
487a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->master_set(image, enabled, vme_base, size, aspace,
488a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		cycle, dwidth);
489a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
490a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_set);
491a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
492ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchint vme_master_get(struct vme_resource *resource, int *enabled,
493a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long *vme_base, unsigned long long *size,
494a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth)
495a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
496a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
497a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *image;
498a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
499a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
500ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a master resource\n");
501a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
502a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
503a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
504a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_master_resource, list);
505a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
50651a569f757f233bcffbffcdfeeff510916991a55Emilio G. Cota	if (bridge->master_get == NULL) {
507ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "vme_master_set not supported\n");
508a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
509a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
510a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
511a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->master_get(image, enabled, vme_base, size, aspace,
512a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		cycle, dwidth);
513a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
514a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_get);
515a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
516a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
517a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Read data out of VME space into a buffer.
518a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
519ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchssize_t vme_master_read(struct vme_resource *resource, void *buf, size_t count,
520a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	loff_t offset)
521a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
522a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
523a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *image;
524a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	size_t length;
525a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
526a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->master_read == NULL) {
527ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Reading from resource not supported\n");
528a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
529a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
530a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
531a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
532ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a master resource\n");
533a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
534a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
535a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
536a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_master_resource, list);
537a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
538a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	length = vme_get_size(resource);
539a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
540a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (offset > length) {
541ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Invalid Offset\n");
542a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EFAULT;
543a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
544a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
545a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if ((offset + count) > length)
546a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		count = length - offset;
547a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
548a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->master_read(image, buf, count, offset);
549a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
550a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
551a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_read);
552a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
553a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
554a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Write data out to VME space from a buffer.
555a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
556ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchssize_t vme_master_write(struct vme_resource *resource, void *buf,
557a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	size_t count, loff_t offset)
558a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
559a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
560a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *image;
561a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	size_t length;
562a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
563a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->master_write == NULL) {
564ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Writing to resource not supported\n");
565a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
566a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
567a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
568a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
569ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a master resource\n");
570a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
571a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
572a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
573a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_master_resource, list);
574a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
575a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	length = vme_get_size(resource);
576a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
577a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (offset > length) {
578ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Invalid Offset\n");
579a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EFAULT;
580a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
581a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
582a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if ((offset + count) > length)
583a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		count = length - offset;
584a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
585a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->master_write(image, buf, count, offset);
586a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
587a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_write);
588a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
589a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
590a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Perform RMW cycle to provided location.
591a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
592ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchunsigned int vme_master_rmw(struct vme_resource *resource, unsigned int mask,
593a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned int compare, unsigned int swap, loff_t offset)
594a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
595a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
596a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *image;
597a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
598a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->master_rmw == NULL) {
599ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Writing to resource not supported\n");
600a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
601a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
602a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
603a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
604ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a master resource\n");
605a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
606a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
607a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
608a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_master_resource, list);
609a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
610a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->master_rmw(image, mask, compare, swap, offset);
611a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
612a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_rmw);
613a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
614a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchvoid vme_master_free(struct vme_resource *resource)
615a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
616a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *master_image;
617a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
618a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
619ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a master resource\n");
620a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
621a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
622a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
623a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	master_image = list_entry(resource->entry, struct vme_master_resource,
624a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		list);
625a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (master_image == NULL) {
626ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Can't find master resource\n");
627a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
628a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
629a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
630a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Unlock image */
631886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_lock(&master_image->lock);
632a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (master_image->locked == 0)
633a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Image is already free\n");
634a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
635a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	master_image->locked = 0;
636886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	spin_unlock(&master_image->lock);
637a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
638a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Free up resource memory */
639a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(resource);
640a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
641a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_free);
642a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
643a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
644a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Request a DMA controller with specific attributes, return some unique
645a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * identifier.
646a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
6474f723df45d3952c485ee0125fb6797ad615901c3Martyn Welchstruct vme_resource *vme_dma_request(struct device *dev, vme_dma_route_t route)
648a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
649a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
650a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct list_head *dma_pos = NULL;
651a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_resource *allocated_ctrlr = NULL;
652a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_resource *dma_ctrlr = NULL;
653a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_resource *resource = NULL;
654a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
655a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* XXX Not checking resource attributes */
656a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	printk(KERN_ERR "No VME resource Attribute tests done\n");
657a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
658a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
659a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
660a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
661a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_bus;
662a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
663a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
664a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Loop through DMA resources */
665886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_for_each(dma_pos, &bridge->dma_resources) {
666a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		dma_ctrlr = list_entry(dma_pos,
667a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			struct vme_dma_resource, list);
668a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
669a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (dma_ctrlr == NULL) {
670ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			printk(KERN_ERR "Registered NULL DMA resource\n");
671a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			continue;
672a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
673a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
6744f723df45d3952c485ee0125fb6797ad615901c3Martyn Welch		/* Find an unlocked and compatible controller */
675886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_lock(&dma_ctrlr->mtx);
6764f723df45d3952c485ee0125fb6797ad615901c3Martyn Welch		if (((dma_ctrlr->route_attr & route) == route) &&
6774f723df45d3952c485ee0125fb6797ad615901c3Martyn Welch			(dma_ctrlr->locked == 0)) {
6784f723df45d3952c485ee0125fb6797ad615901c3Martyn Welch
679a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			dma_ctrlr->locked = 1;
680886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			mutex_unlock(&dma_ctrlr->mtx);
681a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			allocated_ctrlr = dma_ctrlr;
682a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			break;
683a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
684886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_unlock(&dma_ctrlr->mtx);
685a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
686a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
687a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Check to see if we found a resource */
688a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (allocated_ctrlr == NULL)
689a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_ctrlr;
690a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
691a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
692a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource == NULL) {
693a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_WARNING "Unable to allocate resource structure\n");
694a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_alloc;
695a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
696a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource->type = VME_DMA;
697886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	resource->entry = &allocated_ctrlr->list;
698a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
699a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return resource;
700a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
701a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_alloc:
702a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Unlock image */
703886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&dma_ctrlr->mtx);
704a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_ctrlr->locked = 0;
705886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&dma_ctrlr->mtx);
706a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_ctrlr:
707a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_bus:
708a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
709a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
71058e507987b285f3df99f839c79da3985555ac220Martyn WelchEXPORT_SYMBOL(vme_dma_request);
711a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
712a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
713a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Start new list
714a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
715a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct vme_dma_list *vme_new_dma_list(struct vme_resource *resource)
716a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
717a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_resource *ctrlr;
718a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_list *dma_list;
719a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
720a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_DMA) {
721ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a DMA resource\n");
722a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
723a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
724a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
725a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
726a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
727ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	dma_list = kmalloc(sizeof(struct vme_dma_list), GFP_KERNEL);
728ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (dma_list == NULL) {
729ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for new dma list\n");
730a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
731a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
732886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	INIT_LIST_HEAD(&dma_list->entries);
733a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_list->parent = ctrlr;
734886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_init(&dma_list->mtx);
735a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
736a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return dma_list;
737a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
738a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_new_dma_list);
739a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
740a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
741a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Create "Pattern" type attributes
742a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
743a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern,
744a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_pattern_t type)
745a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
746a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_attr *attributes;
747a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_pattern *pattern_attr;
748a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
749ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
750ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (attributes == NULL) {
751ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for attributes "
752ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"structure\n");
753a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_attr;
754a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
755a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
756ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	pattern_attr = kmalloc(sizeof(struct vme_dma_pattern), GFP_KERNEL);
757ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (pattern_attr == NULL) {
758ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for pattern "
759ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"attributes\n");
760a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_pat;
761a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
762a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
763a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->type = VME_DMA_PATTERN;
764a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->private = (void *)pattern_attr;
765a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
766a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pattern_attr->pattern = pattern;
767a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pattern_attr->type = type;
768a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
769a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return attributes;
770a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
771a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(pattern_attr);
772a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_pat:
773a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(attributes);
774a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_attr:
775a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
776a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
777a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_pattern_attribute);
778a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
779a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
780a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Create "PCI" type attributes
781a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
782a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address)
783a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
784a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_attr *attributes;
785a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_pci *pci_attr;
786a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
787a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* XXX Run some sanity checks here */
788a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
789ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
790ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (attributes == NULL) {
791ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for attributes "
792ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"structure\n");
793a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_attr;
794a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
795a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
796ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	pci_attr = kmalloc(sizeof(struct vme_dma_pci), GFP_KERNEL);
797ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (pci_attr == NULL) {
798ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for pci "
799ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"attributes\n");
800a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_pci;
801a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
802a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
803a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
804a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
805a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->type = VME_DMA_PCI;
806a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->private = (void *)pci_attr;
807a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
808a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pci_attr->address = address;
809a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
810a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return attributes;
811a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
812a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(pci_attr);
813a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_pci:
814a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(attributes);
815a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_attr:
816a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
817a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
818a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_pci_attribute);
819a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
820a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
821a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Create "VME" type attributes
822a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
823a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address,
824a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth)
825a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
826a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_attr *attributes;
827a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_vme *vme_attr;
828a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
829ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	attributes = kmalloc(
830a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		sizeof(struct vme_dma_attr), GFP_KERNEL);
831ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (attributes == NULL) {
832ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for attributes "
833ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"structure\n");
834a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_attr;
835a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
836a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
837ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	vme_attr = kmalloc(sizeof(struct vme_dma_vme), GFP_KERNEL);
838ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (vme_attr == NULL) {
839ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for vme "
840ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"attributes\n");
841a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_vme;
842a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
843a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
844a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->type = VME_DMA_VME;
845a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->private = (void *)vme_attr;
846a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
847a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_attr->address = address;
848a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_attr->aspace = aspace;
849a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_attr->cycle = cycle;
850a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_attr->dwidth = dwidth;
851a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
852a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return attributes;
853a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
854a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(vme_attr);
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
994c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welchint vme_irq_request(struct device *dev, 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
1000a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
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
1037c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welchvoid vme_irq_free(struct device *dev, int level, int statid)
1038a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1039a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1040a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1041a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
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
1072c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welchint vme_irq_generate(struct device *dev, int level, int statid)
1073a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1074a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1075a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1076a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
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 */
109942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchstruct vme_resource *vme_lm_request(struct device *dev)
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
1107a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
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
1288a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_slot_get(struct device *bus)
1289a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1290a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1291a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1292a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(bus);
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
1310a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int vme_alloc_bus_num(void)
1311a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1312a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int i;
1313a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1314400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_lock(&vme_bus_num_mtx);
1315a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	for (i = 0; i < sizeof(vme_bus_numbers) * 8; i++) {
1316a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_bus_numbers >> i) & 0x1) == 0) {
1317a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			vme_bus_numbers |= (0x1 << i);
1318a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			break;
1319a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
1320a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1321400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_unlock(&vme_bus_num_mtx);
1322a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1323a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return i;
1324a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1325a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1326a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic void vme_free_bus_num(int bus)
1327a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1328400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_lock(&vme_bus_num_mtx);
1329a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_bus_numbers |= ~(0x1 << bus);
1330400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_unlock(&vme_bus_num_mtx);
1331a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1332a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1333ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchint vme_register_bridge(struct vme_bridge *bridge)
1334a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1335a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct device *dev;
1336a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
1337a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int i;
1338a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1339a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge->num = vme_alloc_bus_num();
1340a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1341a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* This creates 32 vme "slot" devices. This equates to a slot for each
1342a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	 * ID available in a system conforming to the ANSI/VITA 1-1994
1343a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	 * specification.
1344a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	 */
1345a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	for (i = 0; i < VME_SLOTS_MAX; i++) {
1346886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		dev = &bridge->dev[i];
1347a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		memset(dev, 0, sizeof(struct device));
1348a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1349a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		dev->parent = bridge->parent;
1350886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		dev->bus = &vme_bus_type;
1351a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/*
1352a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 * We save a pointer to the bridge in platform_data so that we
1353a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 * can get to it later. We keep driver_data for use by the
1354a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 * driver that binds against the slot
1355a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 */
1356a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		dev->platform_data = bridge;
1357a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		dev_set_name(dev, "vme-%x.%x", bridge->num, i + 1);
1358a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1359a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = device_register(dev);
1360ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		if (retval)
1361a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			goto err_reg;
1362a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1363a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1364a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
1365a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1366a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	i = VME_SLOTS_MAX;
1367a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_reg:
1368a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	while (i > -1) {
1369886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		dev = &bridge->dev[i];
1370a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		device_unregister(dev);
1371a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1372a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_free_bus_num(bridge->num);
1373a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
1374a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1375a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_register_bridge);
1376a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1377ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchvoid vme_unregister_bridge(struct vme_bridge *bridge)
1378a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1379a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int i;
1380a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct device *dev;
1381a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1382a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1383a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	for (i = 0; i < VME_SLOTS_MAX; i++) {
1384886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		dev = &bridge->dev[i];
1385a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		device_unregister(dev);
1386a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1387a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_free_bus_num(bridge->num);
1388a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1389a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_unregister_bridge);
1390a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1391a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1392a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/* - Driver Registration --------------------------------------------------- */
1393a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1394ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchint vme_register_driver(struct vme_driver *drv)
1395a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1396a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	drv->driver.name = drv->name;
1397a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	drv->driver.bus = &vme_bus_type;
1398a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1399a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return driver_register(&drv->driver);
1400a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1401a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_register_driver);
1402a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1403ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchvoid vme_unregister_driver(struct vme_driver *drv)
1404a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1405a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	driver_unregister(&drv->driver);
1406a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1407a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_unregister_driver);
1408a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1409a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/* - Bus Registration ------------------------------------------------------ */
1410a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1411b1a5fad4c36117b1399ed65899088fcb907e2cbdBill Pembertonstatic int vme_calc_slot(struct device *dev)
1412a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1413a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1414a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int num;
1415a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1416a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
1417a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1418a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Determine slot number */
1419a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	num = 0;
1420ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	while (num < VME_SLOTS_MAX) {
1421886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		if (&bridge->dev[num] == dev)
1422a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			break;
1423ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch
1424a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		num++;
1425a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1426a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (num == VME_SLOTS_MAX) {
1427a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		dev_err(dev, "Failed to identify slot\n");
1428a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		num = 0;
1429a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_dev;
1430a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1431a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	num++;
1432a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1433a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_dev:
1434a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return num;
1435a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1436a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1437a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic struct vme_driver *dev_to_vme_driver(struct device *dev)
1438a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1439ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (dev->driver == NULL)
1440ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Bugger dev->driver is NULL\n");
1441a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1442a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return container_of(dev->driver, struct vme_driver, driver);
1443a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1444a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1445a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int vme_bus_match(struct device *dev, struct device_driver *drv)
1446a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1447a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1448a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_driver *driver;
1449a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int i, num;
1450a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1451a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
1452a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	driver = container_of(drv, struct vme_driver, driver);
1453a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1454a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	num = vme_calc_slot(dev);
1455a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (!num)
1456a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_dev;
1457a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1458a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (driver->bind_table == NULL) {
1459a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		dev_err(dev, "Bind table NULL\n");
1460a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_table;
1461a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1462a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1463a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	i = 0;
1464ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	while ((driver->bind_table[i].bus != 0) ||
1465a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		(driver->bind_table[i].slot != 0)) {
1466a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1467a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch		if (bridge->num == driver->bind_table[i].bus) {
1468a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch			if (num == driver->bind_table[i].slot)
1469a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch				return 1;
1470a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch
1471a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch			if (driver->bind_table[i].slot == VME_SLOT_ALL)
1472a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch				return 1;
1473a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch
1474a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch			if ((driver->bind_table[i].slot == VME_SLOT_CURRENT) &&
1475a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch				(num == vme_slot_get(dev)))
1476a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch				return 1;
1477a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch		}
1478a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		i++;
1479a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1480a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1481a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_dev:
1482a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_table:
1483a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return 0;
1484a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1485a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1486a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int vme_bus_probe(struct device *dev)
1487a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1488a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1489a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_driver *driver;
1490a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval = -ENODEV;
1491a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1492a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	driver = dev_to_vme_driver(dev);
1493a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
1494a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1495ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (driver->probe != NULL)
1496a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = driver->probe(dev, bridge->num, vme_calc_slot(dev));
1497a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1498a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
1499a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1500a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1501a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int vme_bus_remove(struct device *dev)
1502a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1503a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1504a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_driver *driver;
1505a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval = -ENODEV;
1506a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1507a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	driver = dev_to_vme_driver(dev);
1508a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
1509a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1510ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (driver->remove != NULL)
1511a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = driver->remove(dev, bridge->num, vme_calc_slot(dev));
1512a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1513a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
1514a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1515a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1516a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct bus_type vme_bus_type = {
1517a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	.name = "vme",
1518a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	.match = vme_bus_match,
1519a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	.probe = vme_bus_probe,
1520a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	.remove = vme_bus_remove,
1521a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch};
1522a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_bus_type);
1523a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1524ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchstatic int __init vme_init(void)
1525a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1526a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bus_register(&vme_bus_type);
1527a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1528a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1529ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchstatic void __exit vme_exit(void)
1530a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1531a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bus_unregister(&vme_bus_type);
1532a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1533a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1534a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchMODULE_DESCRIPTION("VME bridge driver framework");
153566bd8db52ab48e7189e02d4bf1f23109cc1ede70Martyn WelchMODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
1536a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchMODULE_LICENSE("GPL");
1537a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1538a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchmodule_init(vme_init);
1539a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchmodule_exit(vme_exit);
1540