Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/sparc/kernel/ebus.c
10817 views
1
/* ebus.c: EBUS DMA library code.
2
*
3
* Copyright (C) 1997 Eddie C. Dost ([email protected])
4
* Copyright (C) 1999 David S. Miller ([email protected])
5
*/
6
7
#include <linux/module.h>
8
#include <linux/kernel.h>
9
#include <linux/types.h>
10
#include <linux/init.h>
11
#include <linux/interrupt.h>
12
#include <linux/delay.h>
13
14
#include <asm/ebus_dma.h>
15
#include <asm/io.h>
16
17
#define EBDMA_CSR 0x00UL /* Control/Status */
18
#define EBDMA_ADDR 0x04UL /* DMA Address */
19
#define EBDMA_COUNT 0x08UL /* DMA Count */
20
21
#define EBDMA_CSR_INT_PEND 0x00000001
22
#define EBDMA_CSR_ERR_PEND 0x00000002
23
#define EBDMA_CSR_DRAIN 0x00000004
24
#define EBDMA_CSR_INT_EN 0x00000010
25
#define EBDMA_CSR_RESET 0x00000080
26
#define EBDMA_CSR_WRITE 0x00000100
27
#define EBDMA_CSR_EN_DMA 0x00000200
28
#define EBDMA_CSR_CYC_PEND 0x00000400
29
#define EBDMA_CSR_DIAG_RD_DONE 0x00000800
30
#define EBDMA_CSR_DIAG_WR_DONE 0x00001000
31
#define EBDMA_CSR_EN_CNT 0x00002000
32
#define EBDMA_CSR_TC 0x00004000
33
#define EBDMA_CSR_DIS_CSR_DRN 0x00010000
34
#define EBDMA_CSR_BURST_SZ_MASK 0x000c0000
35
#define EBDMA_CSR_BURST_SZ_1 0x00080000
36
#define EBDMA_CSR_BURST_SZ_4 0x00000000
37
#define EBDMA_CSR_BURST_SZ_8 0x00040000
38
#define EBDMA_CSR_BURST_SZ_16 0x000c0000
39
#define EBDMA_CSR_DIAG_EN 0x00100000
40
#define EBDMA_CSR_DIS_ERR_PEND 0x00400000
41
#define EBDMA_CSR_TCI_DIS 0x00800000
42
#define EBDMA_CSR_EN_NEXT 0x01000000
43
#define EBDMA_CSR_DMA_ON 0x02000000
44
#define EBDMA_CSR_A_LOADED 0x04000000
45
#define EBDMA_CSR_NA_LOADED 0x08000000
46
#define EBDMA_CSR_DEV_ID_MASK 0xf0000000
47
48
#define EBUS_DMA_RESET_TIMEOUT 10000
49
50
static void __ebus_dma_reset(struct ebus_dma_info *p, int no_drain)
51
{
52
int i;
53
u32 val = 0;
54
55
writel(EBDMA_CSR_RESET, p->regs + EBDMA_CSR);
56
udelay(1);
57
58
if (no_drain)
59
return;
60
61
for (i = EBUS_DMA_RESET_TIMEOUT; i > 0; i--) {
62
val = readl(p->regs + EBDMA_CSR);
63
64
if (!(val & (EBDMA_CSR_DRAIN | EBDMA_CSR_CYC_PEND)))
65
break;
66
udelay(10);
67
}
68
}
69
70
static irqreturn_t ebus_dma_irq(int irq, void *dev_id)
71
{
72
struct ebus_dma_info *p = dev_id;
73
unsigned long flags;
74
u32 csr = 0;
75
76
spin_lock_irqsave(&p->lock, flags);
77
csr = readl(p->regs + EBDMA_CSR);
78
writel(csr, p->regs + EBDMA_CSR);
79
spin_unlock_irqrestore(&p->lock, flags);
80
81
if (csr & EBDMA_CSR_ERR_PEND) {
82
printk(KERN_CRIT "ebus_dma(%s): DMA error!\n", p->name);
83
p->callback(p, EBUS_DMA_EVENT_ERROR, p->client_cookie);
84
return IRQ_HANDLED;
85
} else if (csr & EBDMA_CSR_INT_PEND) {
86
p->callback(p,
87
(csr & EBDMA_CSR_TC) ?
88
EBUS_DMA_EVENT_DMA : EBUS_DMA_EVENT_DEVICE,
89
p->client_cookie);
90
return IRQ_HANDLED;
91
}
92
93
return IRQ_NONE;
94
95
}
96
97
int ebus_dma_register(struct ebus_dma_info *p)
98
{
99
u32 csr;
100
101
if (!p->regs)
102
return -EINVAL;
103
if (p->flags & ~(EBUS_DMA_FLAG_USE_EBDMA_HANDLER |
104
EBUS_DMA_FLAG_TCI_DISABLE))
105
return -EINVAL;
106
if ((p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) && !p->callback)
107
return -EINVAL;
108
if (!strlen(p->name))
109
return -EINVAL;
110
111
__ebus_dma_reset(p, 1);
112
113
csr = EBDMA_CSR_BURST_SZ_16 | EBDMA_CSR_EN_CNT;
114
115
if (p->flags & EBUS_DMA_FLAG_TCI_DISABLE)
116
csr |= EBDMA_CSR_TCI_DIS;
117
118
writel(csr, p->regs + EBDMA_CSR);
119
120
return 0;
121
}
122
EXPORT_SYMBOL(ebus_dma_register);
123
124
int ebus_dma_irq_enable(struct ebus_dma_info *p, int on)
125
{
126
unsigned long flags;
127
u32 csr;
128
129
if (on) {
130
if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {
131
if (request_irq(p->irq, ebus_dma_irq, IRQF_SHARED, p->name, p))
132
return -EBUSY;
133
}
134
135
spin_lock_irqsave(&p->lock, flags);
136
csr = readl(p->regs + EBDMA_CSR);
137
csr |= EBDMA_CSR_INT_EN;
138
writel(csr, p->regs + EBDMA_CSR);
139
spin_unlock_irqrestore(&p->lock, flags);
140
} else {
141
spin_lock_irqsave(&p->lock, flags);
142
csr = readl(p->regs + EBDMA_CSR);
143
csr &= ~EBDMA_CSR_INT_EN;
144
writel(csr, p->regs + EBDMA_CSR);
145
spin_unlock_irqrestore(&p->lock, flags);
146
147
if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {
148
free_irq(p->irq, p);
149
}
150
}
151
152
return 0;
153
}
154
EXPORT_SYMBOL(ebus_dma_irq_enable);
155
156
void ebus_dma_unregister(struct ebus_dma_info *p)
157
{
158
unsigned long flags;
159
u32 csr;
160
int irq_on = 0;
161
162
spin_lock_irqsave(&p->lock, flags);
163
csr = readl(p->regs + EBDMA_CSR);
164
if (csr & EBDMA_CSR_INT_EN) {
165
csr &= ~EBDMA_CSR_INT_EN;
166
writel(csr, p->regs + EBDMA_CSR);
167
irq_on = 1;
168
}
169
spin_unlock_irqrestore(&p->lock, flags);
170
171
if (irq_on)
172
free_irq(p->irq, p);
173
}
174
EXPORT_SYMBOL(ebus_dma_unregister);
175
176
int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr, size_t len)
177
{
178
unsigned long flags;
179
u32 csr;
180
int err;
181
182
if (len >= (1 << 24))
183
return -EINVAL;
184
185
spin_lock_irqsave(&p->lock, flags);
186
csr = readl(p->regs + EBDMA_CSR);
187
err = -EINVAL;
188
if (!(csr & EBDMA_CSR_EN_DMA))
189
goto out;
190
err = -EBUSY;
191
if (csr & EBDMA_CSR_NA_LOADED)
192
goto out;
193
194
writel(len, p->regs + EBDMA_COUNT);
195
writel(bus_addr, p->regs + EBDMA_ADDR);
196
err = 0;
197
198
out:
199
spin_unlock_irqrestore(&p->lock, flags);
200
201
return err;
202
}
203
EXPORT_SYMBOL(ebus_dma_request);
204
205
void ebus_dma_prepare(struct ebus_dma_info *p, int write)
206
{
207
unsigned long flags;
208
u32 csr;
209
210
spin_lock_irqsave(&p->lock, flags);
211
__ebus_dma_reset(p, 0);
212
213
csr = (EBDMA_CSR_INT_EN |
214
EBDMA_CSR_EN_CNT |
215
EBDMA_CSR_BURST_SZ_16 |
216
EBDMA_CSR_EN_NEXT);
217
218
if (write)
219
csr |= EBDMA_CSR_WRITE;
220
if (p->flags & EBUS_DMA_FLAG_TCI_DISABLE)
221
csr |= EBDMA_CSR_TCI_DIS;
222
223
writel(csr, p->regs + EBDMA_CSR);
224
225
spin_unlock_irqrestore(&p->lock, flags);
226
}
227
EXPORT_SYMBOL(ebus_dma_prepare);
228
229
unsigned int ebus_dma_residue(struct ebus_dma_info *p)
230
{
231
return readl(p->regs + EBDMA_COUNT);
232
}
233
EXPORT_SYMBOL(ebus_dma_residue);
234
235
unsigned int ebus_dma_addr(struct ebus_dma_info *p)
236
{
237
return readl(p->regs + EBDMA_ADDR);
238
}
239
EXPORT_SYMBOL(ebus_dma_addr);
240
241
void ebus_dma_enable(struct ebus_dma_info *p, int on)
242
{
243
unsigned long flags;
244
u32 orig_csr, csr;
245
246
spin_lock_irqsave(&p->lock, flags);
247
orig_csr = csr = readl(p->regs + EBDMA_CSR);
248
if (on)
249
csr |= EBDMA_CSR_EN_DMA;
250
else
251
csr &= ~EBDMA_CSR_EN_DMA;
252
if ((orig_csr & EBDMA_CSR_EN_DMA) !=
253
(csr & EBDMA_CSR_EN_DMA))
254
writel(csr, p->regs + EBDMA_CSR);
255
spin_unlock_irqrestore(&p->lock, flags);
256
}
257
EXPORT_SYMBOL(ebus_dma_enable);
258
259