Linux-2.6.12-rc2
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / arch / sh / cchips / voyagergx / consistent.c
blob5b92585a38d2b3512889557b9cb18e30f78921bc
1 /*
2 * arch/sh/cchips/voyagergx/consistent.c
4 * Copyright (C) 2004 Paul Mundt
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10 #include <linux/mm.h>
11 #include <linux/dma-mapping.h>
12 #include <linux/slab.h>
13 #include <linux/list.h>
14 #include <linux/types.h>
15 #include <linux/module.h>
16 #include <linux/device.h>
17 #include <asm/io.h>
18 #include <asm/bus-sh.h>
20 struct voya_alloc_entry {
21 struct list_head list;
22 unsigned long ofs;
23 unsigned long len;
26 static DEFINE_SPINLOCK(voya_list_lock);
27 static LIST_HEAD(voya_alloc_list);
29 #define OHCI_SRAM_START 0xb0000000
30 #define OHCI_HCCA_SIZE 0x100
31 #define OHCI_SRAM_SIZE 0x10000
33 void *voyagergx_consistent_alloc(struct device *dev, size_t size,
34 dma_addr_t *handle, int flag)
36 struct list_head *list = &voya_alloc_list;
37 struct voya_alloc_entry *entry;
38 struct sh_dev *shdev = to_sh_dev(dev);
39 unsigned long start, end;
40 unsigned long flags;
43 * The SM501 contains an integrated 8051 with its own SRAM.
44 * Devices within the cchip can all hook into the 8051 SRAM.
45 * We presently use this for the OHCI.
47 * Everything else goes through consistent_alloc().
49 if (!dev || dev->bus != &sh_bus_types[SH_BUS_VIRT] ||
50 (dev->bus == &sh_bus_types[SH_BUS_VIRT] &&
51 shdev->dev_id != SH_DEV_ID_USB_OHCI))
52 return NULL;
54 start = OHCI_SRAM_START + OHCI_HCCA_SIZE;
56 entry = kmalloc(sizeof(struct voya_alloc_entry), GFP_ATOMIC);
57 if (!entry)
58 return ERR_PTR(-ENOMEM);
60 entry->len = (size + 15) & ~15;
63 * The basis for this allocator is dwmw2's malloc.. the
64 * Matrox allocator :-)
66 spin_lock_irqsave(&voya_list_lock, flags);
67 list_for_each(list, &voya_alloc_list) {
68 struct voya_alloc_entry *p;
70 p = list_entry(list, struct voya_alloc_entry, list);
72 if (p->ofs - start >= size)
73 goto out;
75 start = p->ofs + p->len;
78 end = start + (OHCI_SRAM_SIZE - OHCI_HCCA_SIZE);
79 list = &voya_alloc_list;
81 if (end - start >= size) {
82 out:
83 entry->ofs = start;
84 list_add_tail(&entry->list, list);
85 spin_unlock_irqrestore(&voya_list_lock, flags);
87 *handle = start;
88 return (void *)start;
91 kfree(entry);
92 spin_unlock_irqrestore(&voya_list_lock, flags);
94 return ERR_PTR(-EINVAL);
97 int voyagergx_consistent_free(struct device *dev, size_t size,
98 void *vaddr, dma_addr_t handle)
100 struct voya_alloc_entry *entry;
101 struct sh_dev *shdev = to_sh_dev(dev);
102 unsigned long flags;
104 if (!dev || dev->bus != &sh_bus_types[SH_BUS_VIRT] ||
105 (dev->bus == &sh_bus_types[SH_BUS_VIRT] &&
106 shdev->dev_id != SH_DEV_ID_USB_OHCI))
107 return -EINVAL;
109 spin_lock_irqsave(&voya_list_lock, flags);
110 list_for_each_entry(entry, &voya_alloc_list, list) {
111 if (entry->ofs != handle)
112 continue;
114 list_del(&entry->list);
115 kfree(entry);
117 break;
119 spin_unlock_irqrestore(&voya_list_lock, flags);
121 return 0;
124 EXPORT_SYMBOL(voyagergx_consistent_alloc);
125 EXPORT_SYMBOL(voyagergx_consistent_free);