aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/cchips/voyagergx/consistent.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/cchips/voyagergx/consistent.c')
-rw-r--r--arch/sh/cchips/voyagergx/consistent.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/arch/sh/cchips/voyagergx/consistent.c b/arch/sh/cchips/voyagergx/consistent.c
new file mode 100644
index 000000000000..5b92585a38d2
--- /dev/null
+++ b/arch/sh/cchips/voyagergx/consistent.c
@@ -0,0 +1,126 @@
1/*
2 * arch/sh/cchips/voyagergx/consistent.c
3 *
4 * Copyright (C) 2004 Paul Mundt
5 *
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>
19
20struct voya_alloc_entry {
21 struct list_head list;
22 unsigned long ofs;
23 unsigned long len;
24};
25
26static DEFINE_SPINLOCK(voya_list_lock);
27static LIST_HEAD(voya_alloc_list);
28
29#define OHCI_SRAM_START 0xb0000000
30#define OHCI_HCCA_SIZE 0x100
31#define OHCI_SRAM_SIZE 0x10000
32
33void *voyagergx_consistent_alloc(struct device *dev, size_t size,
34 dma_addr_t *handle, int flag)
35{
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;
41
42 /*
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.
46 *
47 * Everything else goes through consistent_alloc().
48 */
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;
53
54 start = OHCI_SRAM_START + OHCI_HCCA_SIZE;
55
56 entry = kmalloc(sizeof(struct voya_alloc_entry), GFP_ATOMIC);
57 if (!entry)
58 return ERR_PTR(-ENOMEM);
59
60 entry->len = (size + 15) & ~15;
61
62 /*
63 * The basis for this allocator is dwmw2's malloc.. the
64 * Matrox allocator :-)
65 */
66 spin_lock_irqsave(&voya_list_lock, flags);
67 list_for_each(list, &voya_alloc_list) {
68 struct voya_alloc_entry *p;
69
70 p = list_entry(list, struct voya_alloc_entry, list);
71
72 if (p->ofs - start >= size)
73 goto out;
74
75 start = p->ofs + p->len;
76 }
77
78 end = start + (OHCI_SRAM_SIZE - OHCI_HCCA_SIZE);
79 list = &voya_alloc_list;
80
81 if (end - start >= size) {
82out:
83 entry->ofs = start;
84 list_add_tail(&entry->list, list);
85 spin_unlock_irqrestore(&voya_list_lock, flags);
86
87 *handle = start;
88 return (void *)start;
89 }
90
91 kfree(entry);
92 spin_unlock_irqrestore(&voya_list_lock, flags);
93
94 return ERR_PTR(-EINVAL);
95}
96
97int voyagergx_consistent_free(struct device *dev, size_t size,
98 void *vaddr, dma_addr_t handle)
99{
100 struct voya_alloc_entry *entry;
101 struct sh_dev *shdev = to_sh_dev(dev);
102 unsigned long flags;
103
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;
108
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;
113
114 list_del(&entry->list);
115 kfree(entry);
116
117 break;
118 }
119 spin_unlock_irqrestore(&voya_list_lock, flags);
120
121 return 0;
122}
123
124EXPORT_SYMBOL(voyagergx_consistent_alloc);
125EXPORT_SYMBOL(voyagergx_consistent_free);
126