1a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
2a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * VME Bridge Framework
3a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch *
466bd8db52ab48e7189e02d4bf1f23109cc1ede70Martyn Welch * Author: Martyn Welch <martyn.welch@ge.com>
566bd8db52ab48e7189e02d4bf1f23109cc1ede70Martyn Welch * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
6a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch *
7a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Based on work by Tom Armistead and Ajit Prem
8a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Copyright 2004 Motorola Inc.
9a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch *
10a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * This program is free software; you can redistribute  it and/or modify it
11a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * under  the terms of  the GNU General  Public License as published by the
12a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Free Software Foundation;  either version 2 of the  License, or (at your
13a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * option) any later version.
14a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
15a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
16a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/module.h>
17a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/moduleparam.h>
18a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/mm.h>
19a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/types.h>
20a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/kernel.h>
21a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/errno.h>
22a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/pci.h>
23a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/poll.h>
24a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/highmem.h>
25a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/interrupt.h>
26a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/pagemap.h>
27a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/device.h>
28a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/dma-mapping.h>
29a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/syscalls.h>
30400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch#include <linux/mutex.h>
31a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/spinlock.h>
325a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
33a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
34a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include "vme.h"
35a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include "vme_bridge.h"
36a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
37733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga/* Bitmask and list of registered buses both protected by common mutex */
38a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic unsigned int vme_bus_numbers;
39733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vangastatic LIST_HEAD(vme_bus_list);
40733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vangastatic DEFINE_MUTEX(vme_buses_lock);
41a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
42ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchstatic void __exit vme_exit(void);
43ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchstatic int __init vme_init(void);
44a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
458f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangastatic struct vme_dev *dev_to_vme_dev(struct device *dev)
46a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
478f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	return container_of(dev, struct vme_dev, dev);
48a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
49a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
50a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
51a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Find the bridge that the resource is associated with.
52a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
53a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic struct vme_bridge *find_bridge(struct vme_resource *resource)
54a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
55a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Get list to search */
56a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	switch (resource->type) {
57a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_MASTER:
58a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return list_entry(resource->entry, struct vme_master_resource,
59a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			list)->parent;
60a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
61a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_SLAVE:
62a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return list_entry(resource->entry, struct vme_slave_resource,
63a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			list)->parent;
64a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
65a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_DMA:
66a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return list_entry(resource->entry, struct vme_dma_resource,
67a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			list)->parent;
68a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
6942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	case VME_LM:
7042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		return list_entry(resource->entry, struct vme_lm_resource,
7142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			list)->parent;
7242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		break;
73a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	default:
74a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Unknown resource type\n");
75a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
76a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
77a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
78a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
79a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
80a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
81a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Allocate a contiguous block of memory for use by the driver. This is used to
82a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * create the buffers for the slave windows.
83a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
84ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchvoid *vme_alloc_consistent(struct vme_resource *resource, size_t size,
85a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_addr_t *dma)
86a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
87a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
88a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
89ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (resource == NULL) {
90ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "No resource\n");
91a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
92a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
93a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
94a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = find_bridge(resource);
95ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (bridge == NULL) {
96ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Can't find bridge\n");
97a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
98a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
99a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
100a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->parent == NULL) {
1017f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga		printk(KERN_ERR "Dev entry NULL for"
1027f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga			" bridge %s\n", bridge->name);
1037f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga		return NULL;
1047f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	}
1057f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga
1067f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	if (bridge->alloc_consistent == NULL) {
1077f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga		printk(KERN_ERR "alloc_consistent not supported by"
1087f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga			" bridge %s\n", bridge->name);
109a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
110a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
111a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1127f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	return bridge->alloc_consistent(bridge->parent, size, dma);
113a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
114a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_alloc_consistent);
115a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
116a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
117a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Free previously allocated contiguous block of memory.
118a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
119a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchvoid vme_free_consistent(struct vme_resource *resource, size_t size,
120a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	void *vaddr, dma_addr_t dma)
121a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
122a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
123a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
124ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (resource == NULL) {
125ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "No resource\n");
126a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
127a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
128a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
129a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = find_bridge(resource);
130ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (bridge == NULL) {
131ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Can't find bridge\n");
132a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
133a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
134a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1357f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	if (bridge->parent == NULL) {
1367f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga		printk(KERN_ERR "Dev entry NULL for"
1377f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga			" bridge %s\n", bridge->name);
1387f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga		return;
1397f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	}
1407f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga
1417f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	if (bridge->free_consistent == NULL) {
1427f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga		printk(KERN_ERR "free_consistent not supported by"
1437f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga			" bridge %s\n", bridge->name);
1447f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga		return;
1457f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	}
146a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1477f58f0255aec0b933e0b26ef64d3d533c362a3d3Manohar Vanga	bridge->free_consistent(bridge->parent, size, vaddr, dma);
148a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
149a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_free_consistent);
150a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
151a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchsize_t vme_get_size(struct vme_resource *resource)
152a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
153a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int enabled, retval;
154a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long base, size;
155a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_addr_t buf_base;
1566af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 aspace, cycle, dwidth;
157a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
158a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	switch (resource->type) {
159a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_MASTER:
160a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = vme_master_get(resource, &enabled, &base, &size,
161a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			&aspace, &cycle, &dwidth);
162a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
163a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return size;
164a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
165a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_SLAVE:
166a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = vme_slave_get(resource, &enabled, &base, &size,
167a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			&buf_base, &aspace, &cycle);
168a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
169a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return size;
170a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
171a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_DMA:
172a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return 0;
173a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
174a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	default:
175a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Unknown resource type\n");
176a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return 0;
177a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
178a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
179a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
180a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_get_size);
181a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1826af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welchstatic int vme_check_window(u32 aspace, unsigned long long vme_base,
183a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long size)
184a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
185a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval = 0;
186a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
187a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	switch (aspace) {
188a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_A16:
189a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_base + size) > VME_A16_MAX) ||
190a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch				(vme_base > VME_A16_MAX))
191a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			retval = -EFAULT;
192a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
193a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_A24:
194a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_base + size) > VME_A24_MAX) ||
195a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch				(vme_base > VME_A24_MAX))
196a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			retval = -EFAULT;
197a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
198a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_A32:
199a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_base + size) > VME_A32_MAX) ||
200a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch				(vme_base > VME_A32_MAX))
201a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			retval = -EFAULT;
202a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
203a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_A64:
204a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/*
205a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 * Any value held in an unsigned long long can be used as the
206a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 * base
207a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 */
208a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
209a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_CRCSR:
210a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_base + size) > VME_CRCSR_MAX) ||
211a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch				(vme_base > VME_CRCSR_MAX))
212a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			retval = -EFAULT;
213a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
214a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_USER1:
215a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_USER2:
216a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_USER3:
217a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_USER4:
218a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/* User Defined */
219a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
220a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	default:
221ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Invalid address space\n");
222a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = -EINVAL;
223a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
224a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
225a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
226a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
227a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
228a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
229a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
230a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Request a slave image with specific attributes, return some unique
231a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * identifier.
232a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
2336af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welchstruct vme_resource *vme_slave_request(struct vme_dev *vdev, u32 address,
2346af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 cycle)
235a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
236a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
237a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct list_head *slave_pos = NULL;
238a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *allocated_image = NULL;
239a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *slave_image = NULL;
240a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_resource *resource = NULL;
241a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
2428f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	bridge = vdev->bridge;
243a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
244a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
245a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_bus;
246a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
247a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
248a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Loop through slave resources */
249886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_for_each(slave_pos, &bridge->slave_resources) {
250a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		slave_image = list_entry(slave_pos,
251a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			struct vme_slave_resource, list);
252a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
253a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (slave_image == NULL) {
254ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			printk(KERN_ERR "Registered NULL Slave resource\n");
255a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			continue;
256a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
257a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
258a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/* Find an unlocked and compatible image */
259886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_lock(&slave_image->mtx);
260ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		if (((slave_image->address_attr & address) == address) &&
261a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			((slave_image->cycle_attr & cycle) == cycle) &&
262a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			(slave_image->locked == 0)) {
263a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
264a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			slave_image->locked = 1;
265886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			mutex_unlock(&slave_image->mtx);
266a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			allocated_image = slave_image;
267a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			break;
268a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
269886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_unlock(&slave_image->mtx);
270a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
271a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
272a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* No free image */
273a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (allocated_image == NULL)
274a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_image;
275a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
276a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
277a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource == NULL) {
278a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_WARNING "Unable to allocate resource structure\n");
279a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_alloc;
280a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
281a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource->type = VME_SLAVE;
282886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	resource->entry = &allocated_image->list;
283a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
284a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return resource;
285a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
286a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_alloc:
287a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Unlock image */
288886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&slave_image->mtx);
289a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	slave_image->locked = 0;
290886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&slave_image->mtx);
291a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_image:
292a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_bus:
293a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
294a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
295a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slave_request);
296a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
297ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchint vme_slave_set(struct vme_resource *resource, int enabled,
298a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long vme_base, unsigned long long size,
2996af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	dma_addr_t buf_base, u32 aspace, u32 cycle)
300a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
301a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
302a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *image;
303a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
304a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
305a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_SLAVE) {
306ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a slave resource\n");
307a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
308a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
309a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
310a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_slave_resource, list);
311a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
312a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->slave_set == NULL) {
313ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Function not supported\n");
314a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -ENOSYS;
315a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
316a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
317ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (!(((image->address_attr & aspace) == aspace) &&
318a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		((image->cycle_attr & cycle) == cycle))) {
319ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Invalid attributes\n");
320a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
321a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
322a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
323a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	retval = vme_check_window(aspace, vme_base, size);
324ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (retval)
325a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return retval;
326a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
327a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->slave_set(image, enabled, vme_base, size, buf_base,
328a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		aspace, cycle);
329a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
330a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slave_set);
331a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
332ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchint vme_slave_get(struct vme_resource *resource, int *enabled,
333a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long *vme_base, unsigned long long *size,
3346af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	dma_addr_t *buf_base, u32 *aspace, u32 *cycle)
335a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
336a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
337a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *image;
338a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
339a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_SLAVE) {
340ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a slave resource\n");
341a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
342a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
343a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
344a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_slave_resource, list);
345a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
34651a569f757f233bcffbffcdfeeff510916991a55Emilio G. Cota	if (bridge->slave_get == NULL) {
347ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "vme_slave_get not supported\n");
348a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
349a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
350a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
351a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->slave_get(image, enabled, vme_base, size, buf_base,
352a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		aspace, cycle);
353a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
354a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slave_get);
355a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
356a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchvoid vme_slave_free(struct vme_resource *resource)
357a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
358a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *slave_image;
359a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
360a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_SLAVE) {
361ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a slave resource\n");
362a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
363a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
364a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
365a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	slave_image = list_entry(resource->entry, struct vme_slave_resource,
366a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		list);
367a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (slave_image == NULL) {
368ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Can't find slave resource\n");
369a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
370a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
371a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
372a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Unlock image */
373886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&slave_image->mtx);
374a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (slave_image->locked == 0)
375a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Image is already free\n");
376a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
377a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	slave_image->locked = 0;
378886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&slave_image->mtx);
379a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
380a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Free up resource memory */
381a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(resource);
382a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
383a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slave_free);
384a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
385a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
386a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Request a master image with specific attributes, return some unique
387a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * identifier.
388a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
3896af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welchstruct vme_resource *vme_master_request(struct vme_dev *vdev, u32 address,
3906af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 cycle, u32 dwidth)
391a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
392a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
393a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct list_head *master_pos = NULL;
394a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *allocated_image = NULL;
395a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *master_image = NULL;
396a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_resource *resource = NULL;
397a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
3988f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	bridge = vdev->bridge;
399a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
400a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
401a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_bus;
402a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
403a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
404a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Loop through master resources */
405886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_for_each(master_pos, &bridge->master_resources) {
406a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		master_image = list_entry(master_pos,
407a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			struct vme_master_resource, list);
408a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
409a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (master_image == NULL) {
410a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			printk(KERN_WARNING "Registered NULL master resource\n");
411a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			continue;
412a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
413a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
414a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/* Find an unlocked and compatible image */
415886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		spin_lock(&master_image->lock);
416ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		if (((master_image->address_attr & address) == address) &&
417a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			((master_image->cycle_attr & cycle) == cycle) &&
418a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			((master_image->width_attr & dwidth) == dwidth) &&
419a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			(master_image->locked == 0)) {
420a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
421a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			master_image->locked = 1;
422886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			spin_unlock(&master_image->lock);
423a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			allocated_image = master_image;
424a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			break;
425a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
426886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		spin_unlock(&master_image->lock);
427a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
428a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
429a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Check to see if we found a resource */
430a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (allocated_image == NULL) {
431a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find a suitable resource\n");
432a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_image;
433a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
434a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
435a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
436a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource == NULL) {
437a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Unable to allocate resource structure\n");
438a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_alloc;
439a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
440a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource->type = VME_MASTER;
441886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	resource->entry = &allocated_image->list;
442a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
443a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return resource;
444a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
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,
4576af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	unsigned long long vme_base, unsigned long long size, u32 aspace,
4586af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 cycle, u32 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,
4936af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	unsigned long long *vme_base, unsigned long long *size, u32 *aspace,
4946af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 *cycle, u32 *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 */
6476af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welchstruct vme_resource *vme_dma_request(struct vme_dev *vdev, u32 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
6588f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	bridge = vdev->bridge;
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 */
7436af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welchstruct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type)
744a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
745a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_attr *attributes;
746a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_pattern *pattern_attr;
747a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
748ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
749ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (attributes == NULL) {
750ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for attributes "
751ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"structure\n");
752a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_attr;
753a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
754a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
755ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	pattern_attr = kmalloc(sizeof(struct vme_dma_pattern), GFP_KERNEL);
756ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (pattern_attr == NULL) {
757ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for pattern "
758ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"attributes\n");
759a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_pat;
760a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
761a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
762a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->type = VME_DMA_PATTERN;
763a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->private = (void *)pattern_attr;
764a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
765a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pattern_attr->pattern = pattern;
766a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pattern_attr->type = type;
767a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
768a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return attributes;
769a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
770a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_pat:
771a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(attributes);
772a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_attr:
773a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
774a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
775a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_pattern_attribute);
776a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
777a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
778a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Create "PCI" type attributes
779a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
780a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address)
781a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
782a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_attr *attributes;
783a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_pci *pci_attr;
784a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
785a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* XXX Run some sanity checks here */
786a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
787ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
788ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (attributes == NULL) {
789ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for attributes "
790ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"structure\n");
791a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_attr;
792a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
793a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
794ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	pci_attr = kmalloc(sizeof(struct vme_dma_pci), GFP_KERNEL);
795ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (pci_attr == NULL) {
796ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for pci "
797ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"attributes\n");
798a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_pci;
799a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
800a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
801a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
802a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
803a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->type = VME_DMA_PCI;
804a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->private = (void *)pci_attr;
805a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
806a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pci_attr->address = address;
807a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
808a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return attributes;
809a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
810a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_pci:
811a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(attributes);
812a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_attr:
813a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
814a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
815a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_pci_attribute);
816a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
817a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
818a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Create "VME" type attributes
819a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
820a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address,
8216af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 aspace, u32 cycle, u32 dwidth)
822a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
823a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_attr *attributes;
824a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_vme *vme_attr;
825a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
826ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	attributes = kmalloc(
827a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		sizeof(struct vme_dma_attr), GFP_KERNEL);
828ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (attributes == NULL) {
829ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for attributes "
830ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"structure\n");
831a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_attr;
832a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
833a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
834ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	vme_attr = kmalloc(sizeof(struct vme_dma_vme), GFP_KERNEL);
835ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (vme_attr == NULL) {
836ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to allocate memory for vme "
837ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch			"attributes\n");
838a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_vme;
839a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
840a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
841a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->type = VME_DMA_VME;
842a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->private = (void *)vme_attr;
843a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
844a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_attr->address = address;
845a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_attr->aspace = aspace;
846a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_attr->cycle = cycle;
847a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_attr->dwidth = dwidth;
848a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
849a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return attributes;
850a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
851a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_vme:
852a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(attributes);
853a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_attr:
854a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
855a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
856a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_vme_attribute);
857a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
858a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
859a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Free attribute
860a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
861a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchvoid vme_dma_free_attribute(struct vme_dma_attr *attributes)
862a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
863a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(attributes->private);
864a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(attributes);
865a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
866a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_free_attribute);
867a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
868a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
869a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_attr *dest, size_t count)
870a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
871a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = list->parent->parent;
872a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
873a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
874a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->dma_list_add == NULL) {
875ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Link List DMA generation not supported\n");
876a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
877a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
878a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
879886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	if (!mutex_trylock(&list->mtx)) {
880ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Link List already submitted\n");
881a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
882a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
883a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
884a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	retval = bridge->dma_list_add(list, src, dest, count);
885a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
886886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&list->mtx);
887a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
888a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
889a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
890a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_list_add);
891a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
892a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_dma_list_exec(struct vme_dma_list *list)
893a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
894a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = list->parent->parent;
895a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
896a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
897a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->dma_list_exec == NULL) {
898ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Link List DMA execution not supported\n");
899a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
900a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
901a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
902886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&list->mtx);
903a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
904a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	retval = bridge->dma_list_exec(list);
905a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
906886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&list->mtx);
907a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
908a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
909a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
910a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_list_exec);
911a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
912a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_dma_list_free(struct vme_dma_list *list)
913a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
914a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = list->parent->parent;
915a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
916a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
917a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->dma_list_empty == NULL) {
918ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Emptying of Link Lists not supported\n");
919a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
920a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
921a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
922886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	if (!mutex_trylock(&list->mtx)) {
923ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Link List in use\n");
924a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
925a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
926a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
927a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/*
928a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	 * Empty out all of the entries from the dma list. We need to go to the
929a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	 * low level driver as dma entries are driver specific.
930a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	 */
931a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	retval = bridge->dma_list_empty(list);
932a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (retval) {
933ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Unable to empty link-list entries\n");
934886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_unlock(&list->mtx);
935a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return retval;
936a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
937886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&list->mtx);
938a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(list);
939a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
940a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
941a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
942a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_list_free);
943a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
944a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_dma_free(struct vme_resource *resource)
945a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
946a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_resource *ctrlr;
947a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
948a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_DMA) {
949ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Not a DMA resource\n");
950a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
951a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
952a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
953a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
954a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
955886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	if (!mutex_trylock(&ctrlr->mtx)) {
956ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_ERR "Resource busy, can't free\n");
957a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EBUSY;
958a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
959a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
960886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	if (!(list_empty(&ctrlr->pending) && list_empty(&ctrlr->running))) {
961ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Resource still processing transfers\n");
962886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_unlock(&ctrlr->mtx);
963a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EBUSY;
964a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
965a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
966a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	ctrlr->locked = 0;
967a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
968886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&ctrlr->mtx);
969a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
970a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return 0;
971a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
972a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_free);
973a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
974c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welchvoid vme_irq_handler(struct vme_bridge *bridge, int level, int statid)
975c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch{
976c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	void (*call)(int, int, void *);
977c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	void *priv_data;
978c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
979c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	call = bridge->irq[level - 1].callback[statid].func;
980c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	priv_data = bridge->irq[level - 1].callback[statid].priv_data;
981c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
982c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (call != NULL)
983c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		call(level, statid, priv_data);
984c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	else
985c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_WARNING "Spurilous VME interrupt, level:%x, "
986c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch			"vector:%x\n", level, statid);
987c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch}
988c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn WelchEXPORT_SYMBOL(vme_irq_handler);
989c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
9908f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangaint vme_irq_request(struct vme_dev *vdev, int level, int statid,
99129848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	void (*callback)(int, int, void *),
992a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	void *priv_data)
993a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
994a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
995a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
9968f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	bridge = vdev->bridge;
997a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
998a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
999a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1000a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1001a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1002ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if ((level < 1) || (level > 7)) {
1003c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_ERR "Invalid interrupt level\n");
1004a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1005a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1006a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1007c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (bridge->irq_set == NULL) {
1008c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_ERR "Configuring interrupts not supported\n");
1009a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1010a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1011a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1012886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&bridge->irq_mtx);
1013c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1014c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (bridge->irq[level - 1].callback[statid].func) {
1015886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_unlock(&bridge->irq_mtx);
1016c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_WARNING "VME Interrupt already taken\n");
1017c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		return -EBUSY;
1018c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	}
1019c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1020c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].count++;
1021c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].callback[statid].priv_data = priv_data;
1022c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].callback[statid].func = callback;
1023c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1024c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	/* Enable IRQ level */
102529848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	bridge->irq_set(bridge, level, 1, 1);
1026c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1027886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&bridge->irq_mtx);
1028c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1029c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	return 0;
1030a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1031c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn WelchEXPORT_SYMBOL(vme_irq_request);
1032a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
10338f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangavoid vme_irq_free(struct vme_dev *vdev, int level, int statid)
1034a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1035a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1036a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
10378f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	bridge = vdev->bridge;
1038a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
1039a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
1040a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
1041a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1042a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1043ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if ((level < 1) || (level > 7)) {
1044c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_ERR "Invalid interrupt level\n");
1045a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
1046a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1047a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1048c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (bridge->irq_set == NULL) {
1049c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_ERR "Configuring interrupts not supported\n");
1050a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
1051a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1052a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1053886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&bridge->irq_mtx);
1054c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1055c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].count--;
1056c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1057c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	/* Disable IRQ level if no more interrupts attached at this level*/
1058c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (bridge->irq[level - 1].count == 0)
105929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch		bridge->irq_set(bridge, level, 0, 1);
1060c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1061c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].callback[statid].func = NULL;
1062c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].callback[statid].priv_data = NULL;
1063c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1064886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&bridge->irq_mtx);
1065a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1066c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn WelchEXPORT_SYMBOL(vme_irq_free);
1067a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
10688f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangaint vme_irq_generate(struct vme_dev *vdev, int level, int statid)
1069a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1070a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1071a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
10728f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	bridge = vdev->bridge;
1073a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
1074a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
1075a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1076a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1077a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1078ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if ((level < 1) || (level > 7)) {
1079a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_WARNING "Invalid interrupt level\n");
1080a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1081a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1082a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1083c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (bridge->irq_generate == NULL) {
1084ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "Interrupt generation not supported\n");
1085a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1086a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1087a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
108829848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	return bridge->irq_generate(bridge, level, statid);
1089a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1090c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn WelchEXPORT_SYMBOL(vme_irq_generate);
1091a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
109242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch/*
109342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch * Request the location monitor, return resource or NULL
109442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch */
10958f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangastruct vme_resource *vme_lm_request(struct vme_dev *vdev)
1096a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1097a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
109842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct list_head *lm_pos = NULL;
109942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *allocated_lm = NULL;
110042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm = NULL;
110142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_resource *resource = NULL;
1102a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
11038f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	bridge = vdev->bridge;
1104a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
1105a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
110642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		goto err_bus;
110742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	}
110842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
110942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	/* Loop through DMA resources */
1110886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	list_for_each(lm_pos, &bridge->lm_resources) {
111142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		lm = list_entry(lm_pos,
111242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			struct vme_lm_resource, list);
111342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
111442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		if (lm == NULL) {
111542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			printk(KERN_ERR "Registered NULL Location Monitor "
111642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch				"resource\n");
111742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			continue;
111842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		}
111942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
112042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		/* Find an unlocked controller */
1121886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_lock(&lm->mtx);
112242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		if (lm->locked == 0) {
112342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			lm->locked = 1;
1124886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota			mutex_unlock(&lm->mtx);
112542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			allocated_lm = lm;
112642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			break;
112742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		}
1128886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota		mutex_unlock(&lm->mtx);
112942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	}
113042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
113142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	/* Check to see if we found a resource */
113242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (allocated_lm == NULL)
113342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		goto err_lm;
113442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
113542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
113642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource == NULL) {
113742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Unable to allocate resource structure\n");
113842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		goto err_alloc;
113942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	}
114042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	resource->type = VME_LM;
1141886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	resource->entry = &allocated_lm->list;
114242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
114342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return resource;
114442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
114542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welcherr_alloc:
114642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	/* Unlock image */
1147886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&lm->mtx);
114842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm->locked = 0;
1149886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&lm->mtx);
115042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welcherr_lm:
115142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welcherr_bus:
115242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return NULL;
115342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch}
115442fb503122d8cd428b5b1078bd473847ca2b206cMartyn WelchEXPORT_SYMBOL(vme_lm_request);
115542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
115642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchint vme_lm_count(struct vme_resource *resource)
115742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch{
115842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
115942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
116042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
116142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
116242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		return -EINVAL;
116342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	}
116442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
116542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
116642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
116742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return lm->monitors;
116842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch}
116942fb503122d8cd428b5b1078bd473847ca2b206cMartyn WelchEXPORT_SYMBOL(vme_lm_count);
117042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
117142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchint vme_lm_set(struct vme_resource *resource, unsigned long long lm_base,
11726af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 aspace, u32 cycle)
117342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch{
117442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
117542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
117642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
117742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
117842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
1179a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1180a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1181a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
118242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
118342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
1184a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->lm_set == NULL) {
118542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "vme_lm_set not supported\n");
1186a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1187a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1188a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
11898be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	return bridge->lm_set(lm, lm_base, aspace, cycle);
1190a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1191a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_lm_set);
1192a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
119342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchint vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base,
11946af04b065b048e47bbd5a6f2d9776c08206ef26cMartyn Welch	u32 *aspace, u32 *cycle)
1195a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
119642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
119742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
1198a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
119942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
120042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
1201a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1202a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1203a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
120442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
120542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
1206a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->lm_get == NULL) {
120742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "vme_lm_get not supported\n");
1208a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1209a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1210a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
121142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return bridge->lm_get(lm, lm_base, aspace, cycle);
1212a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1213a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_lm_get);
1214a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
121542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchint vme_lm_attach(struct vme_resource *resource, int monitor,
121642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	void (*callback)(int))
1217a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
121842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
121942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
1220a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
122142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
122242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
1223a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1224a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1225a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
122642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
122742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
1228a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->lm_attach == NULL) {
122942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "vme_lm_attach not supported\n");
1230a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1231a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1232a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
123342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return bridge->lm_attach(lm, monitor, callback);
1234a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1235a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_lm_attach);
1236a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
123742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchint vme_lm_detach(struct vme_resource *resource, int monitor)
1238a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
123942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
124042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
1241a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
124242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
124342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
1244a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1245a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1246a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
124742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
124842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
1249a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->lm_detach == NULL) {
125042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "vme_lm_detach not supported\n");
1251a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1252a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1253a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
125442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return bridge->lm_detach(lm, monitor);
1255a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1256a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_lm_detach);
1257a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
125842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchvoid vme_lm_free(struct vme_resource *resource)
125942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch{
126042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
126142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
126242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
126342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
126442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		return;
126542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	}
126642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
126742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
126842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
1269886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_lock(&lm->mtx);
127042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
12718be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	/* XXX
12728be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	 * Check to see that there aren't any callbacks still attached, if
12738be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	 * there are we should probably be detaching them!
12748be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	 */
127542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
127642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm->locked = 0;
127742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
1278886953e9b70bcb6913716b49bdf21b69450a7cd6Emilio G. Cota	mutex_unlock(&lm->mtx);
12798be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch
12808be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	kfree(resource);
128142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch}
128242fb503122d8cd428b5b1078bd473847ca2b206cMartyn WelchEXPORT_SYMBOL(vme_lm_free);
128342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
12848f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vangaint vme_slot_get(struct vme_dev *vdev)
1285a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1286a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1287a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
12888f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	bridge = vdev->bridge;
1289a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
1290a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
1291a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1292a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1293a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1294a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->slot_get == NULL) {
1295ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch		printk(KERN_WARNING "vme_slot_get not supported\n");
1296a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1297a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1298a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
129929848ac9f3b33bf171439ae2d66d40e6a71446c4Martyn Welch	return bridge->slot_get(bridge);
1300a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1301a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slot_get);
1302a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1303a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1304a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/* - Bridge Registration --------------------------------------------------- */
1305a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
13065b93c2a2f1d560463cbcd6e3fca5366b75e99b4bManohar Vangastatic void vme_dev_release(struct device *dev)
13075b93c2a2f1d560463cbcd6e3fca5366b75e99b4bManohar Vanga{
13085b93c2a2f1d560463cbcd6e3fca5366b75e99b4bManohar Vanga	kfree(dev_to_vme_dev(dev));
13095b93c2a2f1d560463cbcd6e3fca5366b75e99b4bManohar Vanga}
13105b93c2a2f1d560463cbcd6e3fca5366b75e99b4bManohar Vanga
13115b93c2a2f1d560463cbcd6e3fca5366b75e99b4bManohar Vangaint vme_register_bridge(struct vme_bridge *bridge)
1312a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1313a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int i;
1314733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga	int ret = -1;
1315a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1316733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga	mutex_lock(&vme_buses_lock);
1317a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	for (i = 0; i < sizeof(vme_bus_numbers) * 8; i++) {
1318733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga		if ((vme_bus_numbers & (1 << i)) == 0) {
1319733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga			vme_bus_numbers |= (1 << i);
1320733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga			bridge->num = i;
13215d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga			INIT_LIST_HEAD(&bridge->devices);
1322733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga			list_add_tail(&bridge->bus_list, &vme_bus_list);
1323733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga			ret = 0;
1324a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			break;
1325a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
1326a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1327733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga	mutex_unlock(&vme_buses_lock);
1328a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1329733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga	return ret;
1330a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
13315b93c2a2f1d560463cbcd6e3fca5366b75e99b4bManohar VangaEXPORT_SYMBOL(vme_register_bridge);
1332a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
13335b93c2a2f1d560463cbcd6e3fca5366b75e99b4bManohar Vangavoid vme_unregister_bridge(struct vme_bridge *bridge)
1334a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
13355d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_dev *vdev;
13365d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_dev *tmp;
13375d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga
1338733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga	mutex_lock(&vme_buses_lock);
1339733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga	vme_bus_numbers &= ~(1 << bridge->num);
13405d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	list_for_each_entry_safe(vdev, tmp, &bridge->devices, bridge_list) {
13415d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		list_del(&vdev->drv_list);
13425d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		list_del(&vdev->bridge_list);
13435d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		device_unregister(&vdev->dev);
13445d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	}
1345733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga	list_del(&bridge->bus_list);
1346733e3ef0d364b7e6757a897e7f1862a70c89305aManohar Vanga	mutex_unlock(&vme_buses_lock);
1347a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
13485d6abf379d73efe390488e8edba972af4e93cb1cManohar VangaEXPORT_SYMBOL(vme_unregister_bridge);
1349a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
13505d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga/* - Driver Registration --------------------------------------------------- */
13515d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga
13525d6abf379d73efe390488e8edba972af4e93cb1cManohar Vangastatic int __vme_register_driver_bus(struct vme_driver *drv,
13535d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_bridge *bridge, unsigned int ndevs)
13545d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga{
13555d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	int err;
13565d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	unsigned int i;
13575d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_dev *vdev;
13585d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_dev *tmp;
13595d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga
13605d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	for (i = 0; i < ndevs; i++) {
13615d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		vdev = kzalloc(sizeof(struct vme_dev), GFP_KERNEL);
13625d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		if (!vdev) {
13635d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga			err = -ENOMEM;
1364f6c39d4f2d350df049a844b658eb6b08c5833e51Manohar Vanga			goto err_devalloc;
1365f6c39d4f2d350df049a844b658eb6b08c5833e51Manohar Vanga		}
1366a916a391d3e19593a104a8c3c4779a3084f1ca5bManohar Vanga		vdev->num = i;
13678f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga		vdev->bridge = bridge;
13685d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		vdev->dev.platform_data = drv;
13695d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		vdev->dev.release = vme_dev_release;
13708f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga		vdev->dev.parent = bridge->parent;
13718f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga		vdev->dev.bus = &vme_bus_type;
1372a916a391d3e19593a104a8c3c4779a3084f1ca5bManohar Vanga		dev_set_name(&vdev->dev, "%s.%u-%u", drv->name, bridge->num,
1373a916a391d3e19593a104a8c3c4779a3084f1ca5bManohar Vanga			vdev->num);
1374a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
13755d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		err = device_register(&vdev->dev);
13765d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		if (err)
1377a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			goto err_reg;
1378a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
13795d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		if (vdev->dev.platform_data) {
13805d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga			list_add_tail(&vdev->drv_list, &drv->devices);
13815d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga			list_add_tail(&vdev->bridge_list, &bridge->devices);
13825d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		} else
13835d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga			device_unregister(&vdev->dev);
13845d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	}
13855d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	return 0;
1386a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1387a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_reg:
13888f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga	kfree(vdev);
1389f6c39d4f2d350df049a844b658eb6b08c5833e51Manohar Vangaerr_devalloc:
13905d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	list_for_each_entry_safe(vdev, tmp, &drv->devices, drv_list) {
13915d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		list_del(&vdev->drv_list);
13925d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		list_del(&vdev->bridge_list);
13938f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga		device_unregister(&vdev->dev);
1394a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
13955d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	return err;
1396a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1397a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
13985d6abf379d73efe390488e8edba972af4e93cb1cManohar Vangastatic int __vme_register_driver(struct vme_driver *drv, unsigned int ndevs)
1399a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
14005d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_bridge *bridge;
14015d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	int err = 0;
1402a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
14035d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	mutex_lock(&vme_buses_lock);
14045d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	list_for_each_entry(bridge, &vme_bus_list, bus_list) {
14055d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		/*
14065d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		 * This cannot cause trouble as we already have vme_buses_lock
14075d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		 * and if the bridge is removed, it will have to go through
14085d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		 * vme_unregister_bridge() to do it (which calls remove() on
14095d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		 * the bridge which in turn tries to acquire vme_buses_lock and
1410c26f6112990b90977db429596ed0640d153b3a32Manohar Vanga		 * will have to wait).
14115d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		 */
14125d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		err = __vme_register_driver_bus(drv, bridge, ndevs);
14135d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		if (err)
14145d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga			break;
1415a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
14165d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	mutex_unlock(&vme_buses_lock);
14175d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	return err;
1418a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1419a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
14205d6abf379d73efe390488e8edba972af4e93cb1cManohar Vangaint vme_register_driver(struct vme_driver *drv, unsigned int ndevs)
1421a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
14225d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	int err;
14235d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga
1424a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	drv->driver.name = drv->name;
1425a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	drv->driver.bus = &vme_bus_type;
14265d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	INIT_LIST_HEAD(&drv->devices);
14275d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga
14285d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	err = driver_register(&drv->driver);
14295d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	if (err)
14305d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		return err;
1431a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
14325d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	err = __vme_register_driver(drv, ndevs);
14335d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	if (err)
14345d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		driver_unregister(&drv->driver);
14355d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga
14365d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	return err;
1437a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1438a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_register_driver);
1439a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1440ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchvoid vme_unregister_driver(struct vme_driver *drv)
1441a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
14425d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_dev *dev, *dev_tmp;
14435d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga
14445d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	mutex_lock(&vme_buses_lock);
14455d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	list_for_each_entry_safe(dev, dev_tmp, &drv->devices, drv_list) {
14465d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		list_del(&dev->drv_list);
14475d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		list_del(&dev->bridge_list);
14485d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		device_unregister(&dev->dev);
14495d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	}
14505d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	mutex_unlock(&vme_buses_lock);
14515d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga
1452a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	driver_unregister(&drv->driver);
1453a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1454a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_unregister_driver);
1455a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1456a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/* - Bus Registration ------------------------------------------------------ */
1457a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1458a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int vme_bus_match(struct device *dev, struct device_driver *drv)
1459a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
14605d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_driver *vme_drv;
1461a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
14625d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	vme_drv = container_of(drv, struct vme_driver, driver);
1463a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
14645d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	if (dev->platform_data == vme_drv) {
14655d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		struct vme_dev *vdev = dev_to_vme_dev(dev);
1466a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
14675d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		if (vme_drv->match && vme_drv->match(vdev))
14685d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga			return 1;
1469a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch
14705d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga		dev->platform_data = NULL;
1471a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1472a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return 0;
1473a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1474a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1475a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int vme_bus_probe(struct device *dev)
1476a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1477a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval = -ENODEV;
14785d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_driver *driver;
14795d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_dev *vdev = dev_to_vme_dev(dev);
1480a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
14815d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	driver = dev->platform_data;
1482a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1483ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (driver->probe != NULL)
14848f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga		retval = driver->probe(vdev);
1485a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1486a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
1487a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1488a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1489a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int vme_bus_remove(struct device *dev)
1490a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1491a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval = -ENODEV;
14925d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_driver *driver;
14935d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	struct vme_dev *vdev = dev_to_vme_dev(dev);
1494a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
14955d6abf379d73efe390488e8edba972af4e93cb1cManohar Vanga	driver = dev->platform_data;
1496a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1497ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welch	if (driver->remove != NULL)
14988f966dc444b11adff6011a1d1fce424abdd876d8Manohar Vanga		retval = driver->remove(vdev);
1499a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1500a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
1501a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1502a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1503a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct bus_type vme_bus_type = {
1504a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	.name = "vme",
1505a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	.match = vme_bus_match,
1506a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	.probe = vme_bus_probe,
1507a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	.remove = vme_bus_remove,
1508a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch};
1509a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_bus_type);
1510a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1511ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchstatic int __init vme_init(void)
1512a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1513a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bus_register(&vme_bus_type);
1514a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1515a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1516ead1f3e301e2d886ef89f8d0c82b4d495f2a81c2Martyn Welchstatic void __exit vme_exit(void)
1517a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1518a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bus_unregister(&vme_bus_type);
1519a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1520a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1521a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchMODULE_DESCRIPTION("VME bridge driver framework");
152266bd8db52ab48e7189e02d4bf1f23109cc1ede70Martyn WelchMODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
1523a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchMODULE_LICENSE("GPL");
1524a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1525a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchmodule_init(vme_init);
1526a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchmodule_exit(vme_exit);
1527