]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
ARM: ixp4xx: Convert to SPARSE_IRQ
[mirror_ubuntu-focal-kernel.git] / arch / arm / mach-ixp4xx / ixp4xx_qmgr.c
CommitLineData
82a96f57
KH
1/*
2 * Intel IXP4xx Queue Manager driver for Linux
3 *
4 * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of version 2 of the GNU General Public License
8 * as published by the Free Software Foundation.
9 */
10
11#include <linux/ioport.h>
12#include <linux/interrupt.h>
13#include <linux/kernel.h>
14#include <linux/module.h>
a09e64fb 15#include <mach/qmgr.h>
82a96f57 16
dc8ef8cd
LW
17#include "irqs.h"
18
0d2c9f05 19static struct qmgr_regs __iomem *qmgr_regs = IXP4XX_QMGR_BASE_VIRT;
82a96f57
KH
20static struct resource *mem_res;
21static spinlock_t qmgr_lock;
22static u32 used_sram_bitmap[4]; /* 128 16-dword pages */
a6a9fb85
KH
23static void (*irq_handlers[QUEUES])(void *pdev);
24static void *irq_pdevs[QUEUES];
82a96f57 25
e6da96ac
KH
26#if DEBUG_QMGR
27char qmgr_queue_descs[QUEUES][32];
28#endif
29
82a96f57
KH
30void qmgr_set_irq(unsigned int queue, int src,
31 void (*handler)(void *pdev), void *pdev)
32{
82a96f57
KH
33 unsigned long flags;
34
82a96f57 35 spin_lock_irqsave(&qmgr_lock, flags);
a6a9fb85 36 if (queue < HALF_QUEUES) {
0d2c9f05 37 u32 __iomem *reg;
a6a9fb85
KH
38 int bit;
39 BUG_ON(src > QUEUE_IRQ_SRC_NOT_FULL);
40 reg = &qmgr_regs->irqsrc[queue >> 3]; /* 8 queues per u32 */
41 bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
42 __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit),
43 reg);
44 } else
45 /* IRQ source for queues 32-63 is fixed */
46 BUG_ON(src != QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY);
47
82a96f57
KH
48 irq_handlers[queue] = handler;
49 irq_pdevs[queue] = pdev;
50 spin_unlock_irqrestore(&qmgr_lock, flags);
51}
52
53
d4c9e9fc
KH
54static irqreturn_t qmgr_irq1_a0(int irq, void *pdev)
55{
56 int i, ret = 0;
0771c693 57 u32 en_bitmap, src, stat;
d4c9e9fc
KH
58
59 /* ACK - it may clear any bits so don't rely on it */
60 __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[0]);
61
0771c693
KH
62 en_bitmap = qmgr_regs->irqen[0];
63 while (en_bitmap) {
64 i = __fls(en_bitmap); /* number of the last "low" queue */
65 en_bitmap &= ~BIT(i);
d4c9e9fc
KH
66 src = qmgr_regs->irqsrc[i >> 3];
67 stat = qmgr_regs->stat1[i >> 3];
68 if (src & 4) /* the IRQ condition is inverted */
69 stat = ~stat;
70 if (stat & BIT(src & 3)) {
71 irq_handlers[i](irq_pdevs[i]);
72 ret = IRQ_HANDLED;
73 }
74 }
75 return ret;
76}
77
78
79static irqreturn_t qmgr_irq2_a0(int irq, void *pdev)
80{
81 int i, ret = 0;
82 u32 req_bitmap;
83
84 /* ACK - it may clear any bits so don't rely on it */
85 __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[1]);
86
87 req_bitmap = qmgr_regs->irqen[1] & qmgr_regs->statne_h;
0771c693
KH
88 while (req_bitmap) {
89 i = __fls(req_bitmap); /* number of the last "high" queue */
90 req_bitmap &= ~BIT(i);
d4c9e9fc
KH
91 irq_handlers[HALF_QUEUES + i](irq_pdevs[HALF_QUEUES + i]);
92 ret = IRQ_HANDLED;
93 }
94 return ret;
95}
96
97
a6a9fb85 98static irqreturn_t qmgr_irq(int irq, void *pdev)
82a96f57 99{
a6a9fb85 100 int i, half = (irq == IRQ_IXP4XX_QM1 ? 0 : 1);
0771c693 101 u32 req_bitmap = __raw_readl(&qmgr_regs->irqstat[half]);
82a96f57 102
0771c693
KH
103 if (!req_bitmap)
104 return 0;
105 __raw_writel(req_bitmap, &qmgr_regs->irqstat[half]); /* ACK */
106
107 while (req_bitmap) {
108 i = __fls(req_bitmap); /* number of the last queue */
109 req_bitmap &= ~BIT(i);
110 i += half * HALF_QUEUES;
111 irq_handlers[i](irq_pdevs[i]);
112 }
113 return IRQ_HANDLED;
82a96f57
KH
114}
115
116
117void qmgr_enable_irq(unsigned int queue)
118{
119 unsigned long flags;
a6a9fb85
KH
120 int half = queue / 32;
121 u32 mask = 1 << (queue & (HALF_QUEUES - 1));
82a96f57
KH
122
123 spin_lock_irqsave(&qmgr_lock, flags);
a6a9fb85
KH
124 __raw_writel(__raw_readl(&qmgr_regs->irqen[half]) | mask,
125 &qmgr_regs->irqen[half]);
82a96f57
KH
126 spin_unlock_irqrestore(&qmgr_lock, flags);
127}
128
129void qmgr_disable_irq(unsigned int queue)
130{
131 unsigned long flags;
a6a9fb85
KH
132 int half = queue / 32;
133 u32 mask = 1 << (queue & (HALF_QUEUES - 1));
82a96f57
KH
134
135 spin_lock_irqsave(&qmgr_lock, flags);
a6a9fb85
KH
136 __raw_writel(__raw_readl(&qmgr_regs->irqen[half]) & ~mask,
137 &qmgr_regs->irqen[half]);
138 __raw_writel(mask, &qmgr_regs->irqstat[half]); /* clear */
82a96f57
KH
139 spin_unlock_irqrestore(&qmgr_lock, flags);
140}
141
142static inline void shift_mask(u32 *mask)
143{
144 mask[3] = mask[3] << 1 | mask[2] >> 31;
145 mask[2] = mask[2] << 1 | mask[1] >> 31;
146 mask[1] = mask[1] << 1 | mask[0] >> 31;
147 mask[0] <<= 1;
148}
149
e6da96ac 150#if DEBUG_QMGR
82a96f57
KH
151int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
152 unsigned int nearly_empty_watermark,
e6da96ac
KH
153 unsigned int nearly_full_watermark,
154 const char *desc_format, const char* name)
155#else
156int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
157 unsigned int nearly_empty_watermark,
158 unsigned int nearly_full_watermark)
159#endif
82a96f57
KH
160{
161 u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
162 int err;
163
a6a9fb85 164 BUG_ON(queue >= QUEUES);
82a96f57
KH
165
166 if ((nearly_empty_watermark | nearly_full_watermark) & ~7)
167 return -EINVAL;
168
169 switch (len) {
170 case 16:
171 cfg = 0 << 24;
172 mask[0] = 0x1;
173 break;
174 case 32:
175 cfg = 1 << 24;
176 mask[0] = 0x3;
177 break;
178 case 64:
179 cfg = 2 << 24;
180 mask[0] = 0xF;
181 break;
182 case 128:
183 cfg = 3 << 24;
184 mask[0] = 0xFF;
185 break;
186 default:
187 return -EINVAL;
188 }
189
190 cfg |= nearly_empty_watermark << 26;
191 cfg |= nearly_full_watermark << 29;
192 len /= 16; /* in 16-dwords: 1, 2, 4 or 8 */
193 mask[1] = mask[2] = mask[3] = 0;
194
195 if (!try_module_get(THIS_MODULE))
196 return -ENODEV;
197
198 spin_lock_irq(&qmgr_lock);
199 if (__raw_readl(&qmgr_regs->sram[queue])) {
200 err = -EBUSY;
201 goto err;
202 }
203
204 while (1) {
205 if (!(used_sram_bitmap[0] & mask[0]) &&
206 !(used_sram_bitmap[1] & mask[1]) &&
207 !(used_sram_bitmap[2] & mask[2]) &&
208 !(used_sram_bitmap[3] & mask[3]))
209 break; /* found free space */
210
211 addr++;
212 shift_mask(mask);
213 if (addr + len > ARRAY_SIZE(qmgr_regs->sram)) {
214 printk(KERN_ERR "qmgr: no free SRAM space for"
215 " queue %i\n", queue);
216 err = -ENOMEM;
217 goto err;
218 }
219 }
220
221 used_sram_bitmap[0] |= mask[0];
222 used_sram_bitmap[1] |= mask[1];
223 used_sram_bitmap[2] |= mask[2];
224 used_sram_bitmap[3] |= mask[3];
225 __raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]);
e6da96ac
KH
226#if DEBUG_QMGR
227 snprintf(qmgr_queue_descs[queue], sizeof(qmgr_queue_descs[0]),
228 desc_format, name);
229 printk(KERN_DEBUG "qmgr: requested queue %s(%i) addr = 0x%02X\n",
230 qmgr_queue_descs[queue], queue, addr);
82a96f57 231#endif
e6da96ac 232 spin_unlock_irq(&qmgr_lock);
82a96f57
KH
233 return 0;
234
235err:
236 spin_unlock_irq(&qmgr_lock);
237 module_put(THIS_MODULE);
238 return err;
239}
240
241void qmgr_release_queue(unsigned int queue)
242{
243 u32 cfg, addr, mask[4];
244
a6a9fb85 245 BUG_ON(queue >= QUEUES); /* not in valid range */
82a96f57
KH
246
247 spin_lock_irq(&qmgr_lock);
248 cfg = __raw_readl(&qmgr_regs->sram[queue]);
249 addr = (cfg >> 14) & 0xFF;
250
251 BUG_ON(!addr); /* not requested */
252
253 switch ((cfg >> 24) & 3) {
254 case 0: mask[0] = 0x1; break;
255 case 1: mask[0] = 0x3; break;
256 case 2: mask[0] = 0xF; break;
257 case 3: mask[0] = 0xFF; break;
258 }
259
dac2f83f
KH
260 mask[1] = mask[2] = mask[3] = 0;
261
82a96f57
KH
262 while (addr--)
263 shift_mask(mask);
264
e6da96ac
KH
265#if DEBUG_QMGR
266 printk(KERN_DEBUG "qmgr: releasing queue %s(%i)\n",
267 qmgr_queue_descs[queue], queue);
268 qmgr_queue_descs[queue][0] = '\x0';
269#endif
3c3a3b4c
KH
270
271 while ((addr = qmgr_get_entry(queue)))
272 printk(KERN_ERR "qmgr: released queue %i not empty: 0x%08X\n",
273 queue, addr);
274
82a96f57
KH
275 __raw_writel(0, &qmgr_regs->sram[queue]);
276
277 used_sram_bitmap[0] &= ~mask[0];
278 used_sram_bitmap[1] &= ~mask[1];
279 used_sram_bitmap[2] &= ~mask[2];
280 used_sram_bitmap[3] &= ~mask[3];
281 irq_handlers[queue] = NULL; /* catch IRQ bugs */
282 spin_unlock_irq(&qmgr_lock);
283
284 module_put(THIS_MODULE);
82a96f57
KH
285}
286
287static int qmgr_init(void)
288{
289 int i, err;
d4c9e9fc
KH
290 irq_handler_t handler1, handler2;
291
82a96f57
KH
292 mem_res = request_mem_region(IXP4XX_QMGR_BASE_PHYS,
293 IXP4XX_QMGR_REGION_SIZE,
294 "IXP4xx Queue Manager");
295 if (mem_res == NULL)
296 return -EBUSY;
297
82a96f57
KH
298 /* reset qmgr registers */
299 for (i = 0; i < 4; i++) {
300 __raw_writel(0x33333333, &qmgr_regs->stat1[i]);
301 __raw_writel(0, &qmgr_regs->irqsrc[i]);
302 }
303 for (i = 0; i < 2; i++) {
304 __raw_writel(0, &qmgr_regs->stat2[i]);
305 __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[i]); /* clear */
306 __raw_writel(0, &qmgr_regs->irqen[i]);
307 }
308
a6a9fb85
KH
309 __raw_writel(0xFFFFFFFF, &qmgr_regs->statne_h);
310 __raw_writel(0, &qmgr_regs->statf_h);
311
82a96f57
KH
312 for (i = 0; i < QUEUES; i++)
313 __raw_writel(0, &qmgr_regs->sram[i]);
314
d4c9e9fc
KH
315 if (cpu_is_ixp42x_rev_a0()) {
316 handler1 = qmgr_irq1_a0;
317 handler2 = qmgr_irq2_a0;
318 } else
319 handler1 = handler2 = qmgr_irq;
320
321 err = request_irq(IRQ_IXP4XX_QM1, handler1, 0, "IXP4xx Queue Manager",
322 NULL);
82a96f57 323 if (err) {
d4c9e9fc
KH
324 printk(KERN_ERR "qmgr: failed to request IRQ%i (%i)\n",
325 IRQ_IXP4XX_QM1, err);
82a96f57
KH
326 goto error_irq;
327 }
328
d4c9e9fc
KH
329 err = request_irq(IRQ_IXP4XX_QM2, handler2, 0, "IXP4xx Queue Manager",
330 NULL);
a6a9fb85 331 if (err) {
d4c9e9fc
KH
332 printk(KERN_ERR "qmgr: failed to request IRQ%i (%i)\n",
333 IRQ_IXP4XX_QM2, err);
a6a9fb85
KH
334 goto error_irq2;
335 }
336
82a96f57
KH
337 used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */
338 spin_lock_init(&qmgr_lock);
339
340 printk(KERN_INFO "IXP4xx Queue Manager initialized.\n");
341 return 0;
342
a6a9fb85
KH
343error_irq2:
344 free_irq(IRQ_IXP4XX_QM1, NULL);
82a96f57 345error_irq:
82a96f57
KH
346 release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
347 return err;
348}
349
350static void qmgr_remove(void)
351{
352 free_irq(IRQ_IXP4XX_QM1, NULL);
a6a9fb85 353 free_irq(IRQ_IXP4XX_QM2, NULL);
82a96f57 354 synchronize_irq(IRQ_IXP4XX_QM1);
a6a9fb85 355 synchronize_irq(IRQ_IXP4XX_QM2);
82a96f57
KH
356 release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
357}
358
359module_init(qmgr_init);
360module_exit(qmgr_remove);
361
362MODULE_LICENSE("GPL v2");
363MODULE_AUTHOR("Krzysztof Halasa");
364
82a96f57
KH
365EXPORT_SYMBOL(qmgr_set_irq);
366EXPORT_SYMBOL(qmgr_enable_irq);
367EXPORT_SYMBOL(qmgr_disable_irq);
e6da96ac
KH
368#if DEBUG_QMGR
369EXPORT_SYMBOL(qmgr_queue_descs);
82a96f57 370EXPORT_SYMBOL(qmgr_request_queue);
e6da96ac
KH
371#else
372EXPORT_SYMBOL(__qmgr_request_queue);
373#endif
82a96f57 374EXPORT_SYMBOL(qmgr_release_queue);