2 * Intel IXP4xx Queue Manager driver for Linux
4 * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
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.
11 #include <linux/ioport.h>
12 #include <linux/interrupt.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <mach/qmgr.h>
17 struct qmgr_regs __iomem *qmgr_regs;
18 static struct resource *mem_res;
19 static spinlock_t qmgr_lock;
20 static u32 used_sram_bitmap[4]; /* 128 16-dword pages */
21 static void (*irq_handlers[HALF_QUEUES])(void *pdev);
22 static void *irq_pdevs[HALF_QUEUES];
25 char qmgr_queue_descs[QUEUES][32];
28 void qmgr_set_irq(unsigned int queue, int src,
29 void (*handler)(void *pdev), void *pdev)
31 u32 __iomem *reg = &qmgr_regs->irqsrc[queue / 8]; /* 8 queues / u32 */
32 int bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
36 spin_lock_irqsave(&qmgr_lock, flags);
37 __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg);
38 irq_handlers[queue] = handler;
39 irq_pdevs[queue] = pdev;
40 spin_unlock_irqrestore(&qmgr_lock, flags);
44 static irqreturn_t qmgr_irq1(int irq, void *pdev)
47 u32 val = __raw_readl(&qmgr_regs->irqstat[0]);
48 __raw_writel(val, &qmgr_regs->irqstat[0]); /* ACK */
50 for (i = 0; i < HALF_QUEUES; i++)
52 irq_handlers[i](irq_pdevs[i]);
54 return val ? IRQ_HANDLED : 0;
58 void qmgr_enable_irq(unsigned int queue)
62 spin_lock_irqsave(&qmgr_lock, flags);
63 __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | (1 << queue),
64 &qmgr_regs->irqen[0]);
65 spin_unlock_irqrestore(&qmgr_lock, flags);
68 void qmgr_disable_irq(unsigned int queue)
72 spin_lock_irqsave(&qmgr_lock, flags);
73 __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~(1 << queue),
74 &qmgr_regs->irqen[0]);
75 __raw_writel(1 << queue, &qmgr_regs->irqstat[0]); /* clear */
76 spin_unlock_irqrestore(&qmgr_lock, flags);
79 static inline void shift_mask(u32 *mask)
81 mask[3] = mask[3] << 1 | mask[2] >> 31;
82 mask[2] = mask[2] << 1 | mask[1] >> 31;
83 mask[1] = mask[1] << 1 | mask[0] >> 31;
88 int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
89 unsigned int nearly_empty_watermark,
90 unsigned int nearly_full_watermark,
91 const char *desc_format, const char* name)
93 int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
94 unsigned int nearly_empty_watermark,
95 unsigned int nearly_full_watermark)
98 u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
101 if (queue >= HALF_QUEUES)
104 if ((nearly_empty_watermark | nearly_full_watermark) & ~7)
128 cfg |= nearly_empty_watermark << 26;
129 cfg |= nearly_full_watermark << 29;
130 len /= 16; /* in 16-dwords: 1, 2, 4 or 8 */
131 mask[1] = mask[2] = mask[3] = 0;
133 if (!try_module_get(THIS_MODULE))
136 spin_lock_irq(&qmgr_lock);
137 if (__raw_readl(&qmgr_regs->sram[queue])) {
143 if (!(used_sram_bitmap[0] & mask[0]) &&
144 !(used_sram_bitmap[1] & mask[1]) &&
145 !(used_sram_bitmap[2] & mask[2]) &&
146 !(used_sram_bitmap[3] & mask[3]))
147 break; /* found free space */
151 if (addr + len > ARRAY_SIZE(qmgr_regs->sram)) {
152 printk(KERN_ERR "qmgr: no free SRAM space for"
153 " queue %i\n", queue);
159 used_sram_bitmap[0] |= mask[0];
160 used_sram_bitmap[1] |= mask[1];
161 used_sram_bitmap[2] |= mask[2];
162 used_sram_bitmap[3] |= mask[3];
163 __raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]);
165 snprintf(qmgr_queue_descs[queue], sizeof(qmgr_queue_descs[0]),
167 printk(KERN_DEBUG "qmgr: requested queue %s(%i) addr = 0x%02X\n",
168 qmgr_queue_descs[queue], queue, addr);
170 spin_unlock_irq(&qmgr_lock);
174 spin_unlock_irq(&qmgr_lock);
175 module_put(THIS_MODULE);
179 void qmgr_release_queue(unsigned int queue)
181 u32 cfg, addr, mask[4];
183 BUG_ON(queue >= HALF_QUEUES); /* not in valid range */
185 spin_lock_irq(&qmgr_lock);
186 cfg = __raw_readl(&qmgr_regs->sram[queue]);
187 addr = (cfg >> 14) & 0xFF;
189 BUG_ON(!addr); /* not requested */
191 switch ((cfg >> 24) & 3) {
192 case 0: mask[0] = 0x1; break;
193 case 1: mask[0] = 0x3; break;
194 case 2: mask[0] = 0xF; break;
195 case 3: mask[0] = 0xFF; break;
198 mask[1] = mask[2] = mask[3] = 0;
204 printk(KERN_DEBUG "qmgr: releasing queue %s(%i)\n",
205 qmgr_queue_descs[queue], queue);
206 qmgr_queue_descs[queue][0] = '\x0';
208 __raw_writel(0, &qmgr_regs->sram[queue]);
210 used_sram_bitmap[0] &= ~mask[0];
211 used_sram_bitmap[1] &= ~mask[1];
212 used_sram_bitmap[2] &= ~mask[2];
213 used_sram_bitmap[3] &= ~mask[3];
214 irq_handlers[queue] = NULL; /* catch IRQ bugs */
215 spin_unlock_irq(&qmgr_lock);
217 module_put(THIS_MODULE);
219 while ((addr = qmgr_get_entry(queue)))
220 printk(KERN_ERR "qmgr: released queue %i not empty: 0x%08X\n",
224 static int qmgr_init(void)
227 mem_res = request_mem_region(IXP4XX_QMGR_BASE_PHYS,
228 IXP4XX_QMGR_REGION_SIZE,
229 "IXP4xx Queue Manager");
233 qmgr_regs = ioremap(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
234 if (qmgr_regs == NULL) {
239 /* reset qmgr registers */
240 for (i = 0; i < 4; i++) {
241 __raw_writel(0x33333333, &qmgr_regs->stat1[i]);
242 __raw_writel(0, &qmgr_regs->irqsrc[i]);
244 for (i = 0; i < 2; i++) {
245 __raw_writel(0, &qmgr_regs->stat2[i]);
246 __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[i]); /* clear */
247 __raw_writel(0, &qmgr_regs->irqen[i]);
250 for (i = 0; i < QUEUES; i++)
251 __raw_writel(0, &qmgr_regs->sram[i]);
253 err = request_irq(IRQ_IXP4XX_QM1, qmgr_irq1, 0,
254 "IXP4xx Queue Manager", NULL);
256 printk(KERN_ERR "qmgr: failed to request IRQ%i\n",
261 used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */
262 spin_lock_init(&qmgr_lock);
264 printk(KERN_INFO "IXP4xx Queue Manager initialized.\n");
270 release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
274 static void qmgr_remove(void)
276 free_irq(IRQ_IXP4XX_QM1, NULL);
277 synchronize_irq(IRQ_IXP4XX_QM1);
279 release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
282 module_init(qmgr_init);
283 module_exit(qmgr_remove);
285 MODULE_LICENSE("GPL v2");
286 MODULE_AUTHOR("Krzysztof Halasa");
288 EXPORT_SYMBOL(qmgr_regs);
289 EXPORT_SYMBOL(qmgr_set_irq);
290 EXPORT_SYMBOL(qmgr_enable_irq);
291 EXPORT_SYMBOL(qmgr_disable_irq);
293 EXPORT_SYMBOL(qmgr_queue_descs);
294 EXPORT_SYMBOL(qmgr_request_queue);
296 EXPORT_SYMBOL(__qmgr_request_queue);
298 EXPORT_SYMBOL(qmgr_release_queue);