182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa/* 282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa * Intel IXP4xx Queue Manager driver for Linux 382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa * 482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl> 582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa * 682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa * This program is free software; you can redistribute it and/or modify it 782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa * under the terms of version 2 of the GNU General Public License 882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa * as published by the Free Software Foundation. 982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa */ 1082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 1182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa#include <linux/ioport.h> 1282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa#include <linux/interrupt.h> 1382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa#include <linux/kernel.h> 1482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa#include <linux/module.h> 15a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/qmgr.h> 1682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 170d2c9f0517e915ce03a04e91d3207827e0d274a8Arnd Bergmannstatic struct qmgr_regs __iomem *qmgr_regs = IXP4XX_QMGR_BASE_VIRT; 1882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasastatic struct resource *mem_res; 1982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasastatic spinlock_t qmgr_lock; 2082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasastatic u32 used_sram_bitmap[4]; /* 128 16-dword pages */ 21a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasastatic void (*irq_handlers[QUEUES])(void *pdev); 22a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasastatic void *irq_pdevs[QUEUES]; 2382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 24e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa#if DEBUG_QMGR 25e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasachar qmgr_queue_descs[QUEUES][32]; 26e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa#endif 27e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa 2882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasavoid qmgr_set_irq(unsigned int queue, int src, 2982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa void (*handler)(void *pdev), void *pdev) 3082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa{ 3182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa unsigned long flags; 3282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 3382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa spin_lock_irqsave(&qmgr_lock, flags); 34a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa if (queue < HALF_QUEUES) { 350d2c9f0517e915ce03a04e91d3207827e0d274a8Arnd Bergmann u32 __iomem *reg; 36a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa int bit; 37a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa BUG_ON(src > QUEUE_IRQ_SRC_NOT_FULL); 38a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa reg = &qmgr_regs->irqsrc[queue >> 3]; /* 8 queues per u32 */ 39a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */ 40a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), 41a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa reg); 42a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa } else 43a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa /* IRQ source for queues 32-63 is fixed */ 44a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa BUG_ON(src != QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY); 45a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa 4682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa irq_handlers[queue] = handler; 4782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa irq_pdevs[queue] = pdev; 4882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa spin_unlock_irqrestore(&qmgr_lock, flags); 4982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa} 5082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 5182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 52d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasastatic irqreturn_t qmgr_irq1_a0(int irq, void *pdev) 53d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa{ 54d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa int i, ret = 0; 550771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa u32 en_bitmap, src, stat; 56d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa 57d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa /* ACK - it may clear any bits so don't rely on it */ 58d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[0]); 59d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa 600771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa en_bitmap = qmgr_regs->irqen[0]; 610771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa while (en_bitmap) { 620771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa i = __fls(en_bitmap); /* number of the last "low" queue */ 630771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa en_bitmap &= ~BIT(i); 64d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa src = qmgr_regs->irqsrc[i >> 3]; 65d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa stat = qmgr_regs->stat1[i >> 3]; 66d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa if (src & 4) /* the IRQ condition is inverted */ 67d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa stat = ~stat; 68d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa if (stat & BIT(src & 3)) { 69d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa irq_handlers[i](irq_pdevs[i]); 70d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa ret = IRQ_HANDLED; 71d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa } 72d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa } 73d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa return ret; 74d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa} 75d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa 76d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa 77d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasastatic irqreturn_t qmgr_irq2_a0(int irq, void *pdev) 78d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa{ 79d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa int i, ret = 0; 80d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa u32 req_bitmap; 81d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa 82d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa /* ACK - it may clear any bits so don't rely on it */ 83d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[1]); 84d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa 85d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa req_bitmap = qmgr_regs->irqen[1] & qmgr_regs->statne_h; 860771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa while (req_bitmap) { 870771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa i = __fls(req_bitmap); /* number of the last "high" queue */ 880771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa req_bitmap &= ~BIT(i); 89d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa irq_handlers[HALF_QUEUES + i](irq_pdevs[HALF_QUEUES + i]); 90d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa ret = IRQ_HANDLED; 91d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa } 92d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa return ret; 93d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa} 94d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa 95d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa 96a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasastatic irqreturn_t qmgr_irq(int irq, void *pdev) 9782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa{ 98a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa int i, half = (irq == IRQ_IXP4XX_QM1 ? 0 : 1); 990771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa u32 req_bitmap = __raw_readl(&qmgr_regs->irqstat[half]); 10082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 1010771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa if (!req_bitmap) 1020771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa return 0; 1030771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa __raw_writel(req_bitmap, &qmgr_regs->irqstat[half]); /* ACK */ 1040771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa 1050771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa while (req_bitmap) { 1060771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa i = __fls(req_bitmap); /* number of the last queue */ 1070771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa req_bitmap &= ~BIT(i); 1080771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa i += half * HALF_QUEUES; 1090771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa irq_handlers[i](irq_pdevs[i]); 1100771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa } 1110771c6939484d2ebe0ec28257c2570aecd9911e0Krzysztof Hałasa return IRQ_HANDLED; 11282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa} 11382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 11482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 11582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasavoid qmgr_enable_irq(unsigned int queue) 11682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa{ 11782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa unsigned long flags; 118a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa int half = queue / 32; 119a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa u32 mask = 1 << (queue & (HALF_QUEUES - 1)); 12082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 12182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa spin_lock_irqsave(&qmgr_lock, flags); 122a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa __raw_writel(__raw_readl(&qmgr_regs->irqen[half]) | mask, 123a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa &qmgr_regs->irqen[half]); 12482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa spin_unlock_irqrestore(&qmgr_lock, flags); 12582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa} 12682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 12782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasavoid qmgr_disable_irq(unsigned int queue) 12882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa{ 12982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa unsigned long flags; 130a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa int half = queue / 32; 131a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa u32 mask = 1 << (queue & (HALF_QUEUES - 1)); 13282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 13382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa spin_lock_irqsave(&qmgr_lock, flags); 134a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa __raw_writel(__raw_readl(&qmgr_regs->irqen[half]) & ~mask, 135a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa &qmgr_regs->irqen[half]); 136a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa __raw_writel(mask, &qmgr_regs->irqstat[half]); /* clear */ 13782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa spin_unlock_irqrestore(&qmgr_lock, flags); 13882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa} 13982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 14082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasastatic inline void shift_mask(u32 *mask) 14182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa{ 14282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa mask[3] = mask[3] << 1 | mask[2] >> 31; 14382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa mask[2] = mask[2] << 1 | mask[1] >> 31; 14482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa mask[1] = mask[1] << 1 | mask[0] >> 31; 14582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa mask[0] <<= 1; 14682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa} 14782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 148e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa#if DEBUG_QMGR 14982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasaint qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, 15082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa unsigned int nearly_empty_watermark, 151e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa unsigned int nearly_full_watermark, 152e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa const char *desc_format, const char* name) 153e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa#else 154e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasaint __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, 155e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa unsigned int nearly_empty_watermark, 156e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa unsigned int nearly_full_watermark) 157e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa#endif 15882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa{ 15982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa u32 cfg, addr = 0, mask[4]; /* in 16-dwords */ 16082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa int err; 16182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 162a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa BUG_ON(queue >= QUEUES); 16382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 16482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa if ((nearly_empty_watermark | nearly_full_watermark) & ~7) 16582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa return -EINVAL; 16682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 16782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa switch (len) { 16882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa case 16: 16982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa cfg = 0 << 24; 17082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa mask[0] = 0x1; 17182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa break; 17282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa case 32: 17382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa cfg = 1 << 24; 17482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa mask[0] = 0x3; 17582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa break; 17682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa case 64: 17782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa cfg = 2 << 24; 17882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa mask[0] = 0xF; 17982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa break; 18082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa case 128: 18182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa cfg = 3 << 24; 18282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa mask[0] = 0xFF; 18382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa break; 18482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa default: 18582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa return -EINVAL; 18682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa } 18782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 18882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa cfg |= nearly_empty_watermark << 26; 18982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa cfg |= nearly_full_watermark << 29; 19082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa len /= 16; /* in 16-dwords: 1, 2, 4 or 8 */ 19182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa mask[1] = mask[2] = mask[3] = 0; 19282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 19382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa if (!try_module_get(THIS_MODULE)) 19482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa return -ENODEV; 19582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 19682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa spin_lock_irq(&qmgr_lock); 19782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa if (__raw_readl(&qmgr_regs->sram[queue])) { 19882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa err = -EBUSY; 19982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa goto err; 20082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa } 20182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 20282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa while (1) { 20382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa if (!(used_sram_bitmap[0] & mask[0]) && 20482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa !(used_sram_bitmap[1] & mask[1]) && 20582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa !(used_sram_bitmap[2] & mask[2]) && 20682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa !(used_sram_bitmap[3] & mask[3])) 20782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa break; /* found free space */ 20882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 20982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa addr++; 21082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa shift_mask(mask); 21182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa if (addr + len > ARRAY_SIZE(qmgr_regs->sram)) { 21282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa printk(KERN_ERR "qmgr: no free SRAM space for" 21382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa " queue %i\n", queue); 21482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa err = -ENOMEM; 21582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa goto err; 21682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa } 21782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa } 21882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 21982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa used_sram_bitmap[0] |= mask[0]; 22082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa used_sram_bitmap[1] |= mask[1]; 22182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa used_sram_bitmap[2] |= mask[2]; 22282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa used_sram_bitmap[3] |= mask[3]; 22382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa __raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]); 224e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa#if DEBUG_QMGR 225e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa snprintf(qmgr_queue_descs[queue], sizeof(qmgr_queue_descs[0]), 226e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa desc_format, name); 227e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa printk(KERN_DEBUG "qmgr: requested queue %s(%i) addr = 0x%02X\n", 228e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa qmgr_queue_descs[queue], queue, addr); 22982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa#endif 230e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa spin_unlock_irq(&qmgr_lock); 23182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa return 0; 23282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 23382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasaerr: 23482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa spin_unlock_irq(&qmgr_lock); 23582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa module_put(THIS_MODULE); 23682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa return err; 23782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa} 23882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 23982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasavoid qmgr_release_queue(unsigned int queue) 24082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa{ 24182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa u32 cfg, addr, mask[4]; 24282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 243a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa BUG_ON(queue >= QUEUES); /* not in valid range */ 24482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 24582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa spin_lock_irq(&qmgr_lock); 24682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa cfg = __raw_readl(&qmgr_regs->sram[queue]); 24782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa addr = (cfg >> 14) & 0xFF; 24882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 24982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa BUG_ON(!addr); /* not requested */ 25082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 25182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa switch ((cfg >> 24) & 3) { 25282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa case 0: mask[0] = 0x1; break; 25382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa case 1: mask[0] = 0x3; break; 25482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa case 2: mask[0] = 0xF; break; 25582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa case 3: mask[0] = 0xFF; break; 25682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa } 25782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 258dac2f83fce01f0c2900918a4a8abd4c652151804Krzysztof Halasa mask[1] = mask[2] = mask[3] = 0; 259dac2f83fce01f0c2900918a4a8abd4c652151804Krzysztof Halasa 26082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa while (addr--) 26182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa shift_mask(mask); 26282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 263e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa#if DEBUG_QMGR 264e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa printk(KERN_DEBUG "qmgr: releasing queue %s(%i)\n", 265e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa qmgr_queue_descs[queue], queue); 266e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa qmgr_queue_descs[queue][0] = '\x0'; 267e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa#endif 2683c3a3b4c12bdda8dd098fcdd4499a298548d6f31Krzysztof Hałasa 2693c3a3b4c12bdda8dd098fcdd4499a298548d6f31Krzysztof Hałasa while ((addr = qmgr_get_entry(queue))) 2703c3a3b4c12bdda8dd098fcdd4499a298548d6f31Krzysztof Hałasa printk(KERN_ERR "qmgr: released queue %i not empty: 0x%08X\n", 2713c3a3b4c12bdda8dd098fcdd4499a298548d6f31Krzysztof Hałasa queue, addr); 2723c3a3b4c12bdda8dd098fcdd4499a298548d6f31Krzysztof Hałasa 27382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa __raw_writel(0, &qmgr_regs->sram[queue]); 27482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 27582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa used_sram_bitmap[0] &= ~mask[0]; 27682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa used_sram_bitmap[1] &= ~mask[1]; 27782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa used_sram_bitmap[2] &= ~mask[2]; 27882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa used_sram_bitmap[3] &= ~mask[3]; 27982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa irq_handlers[queue] = NULL; /* catch IRQ bugs */ 28082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa spin_unlock_irq(&qmgr_lock); 28182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 28282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa module_put(THIS_MODULE); 28382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa} 28482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 28582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasastatic int qmgr_init(void) 28682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa{ 28782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa int i, err; 288d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa irq_handler_t handler1, handler2; 289d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa 29082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa mem_res = request_mem_region(IXP4XX_QMGR_BASE_PHYS, 29182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa IXP4XX_QMGR_REGION_SIZE, 29282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa "IXP4xx Queue Manager"); 29382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa if (mem_res == NULL) 29482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa return -EBUSY; 29582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 29682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa /* reset qmgr registers */ 29782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa for (i = 0; i < 4; i++) { 29882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa __raw_writel(0x33333333, &qmgr_regs->stat1[i]); 29982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa __raw_writel(0, &qmgr_regs->irqsrc[i]); 30082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa } 30182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa for (i = 0; i < 2; i++) { 30282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa __raw_writel(0, &qmgr_regs->stat2[i]); 30382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[i]); /* clear */ 30482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa __raw_writel(0, &qmgr_regs->irqen[i]); 30582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa } 30682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 307a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa __raw_writel(0xFFFFFFFF, &qmgr_regs->statne_h); 308a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa __raw_writel(0, &qmgr_regs->statf_h); 309a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa 31082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa for (i = 0; i < QUEUES; i++) 31182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa __raw_writel(0, &qmgr_regs->sram[i]); 31282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 313d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa if (cpu_is_ixp42x_rev_a0()) { 314d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa handler1 = qmgr_irq1_a0; 315d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa handler2 = qmgr_irq2_a0; 316d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa } else 317d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa handler1 = handler2 = qmgr_irq; 318d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa 319d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa err = request_irq(IRQ_IXP4XX_QM1, handler1, 0, "IXP4xx Queue Manager", 320d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa NULL); 32182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa if (err) { 322d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa printk(KERN_ERR "qmgr: failed to request IRQ%i (%i)\n", 323d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa IRQ_IXP4XX_QM1, err); 32482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa goto error_irq; 32582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa } 32682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 327d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa err = request_irq(IRQ_IXP4XX_QM2, handler2, 0, "IXP4xx Queue Manager", 328d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa NULL); 329a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa if (err) { 330d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa printk(KERN_ERR "qmgr: failed to request IRQ%i (%i)\n", 331d4c9e9fc97515588529e7fe48c7d5725292c6734Krzysztof Hałasa IRQ_IXP4XX_QM2, err); 332a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa goto error_irq2; 333a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa } 334a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa 33582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */ 33682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa spin_lock_init(&qmgr_lock); 33782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 33882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa printk(KERN_INFO "IXP4xx Queue Manager initialized.\n"); 33982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa return 0; 34082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 341a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasaerror_irq2: 342a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa free_irq(IRQ_IXP4XX_QM1, NULL); 34382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasaerror_irq: 34482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE); 34582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa return err; 34682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa} 34782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 34882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasastatic void qmgr_remove(void) 34982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa{ 35082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa free_irq(IRQ_IXP4XX_QM1, NULL); 351a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa free_irq(IRQ_IXP4XX_QM2, NULL); 35282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa synchronize_irq(IRQ_IXP4XX_QM1); 353a6a9fb857b5599b3cefef5576967389c1c43eb4cKrzysztof Hałasa synchronize_irq(IRQ_IXP4XX_QM2); 35482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE); 35582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa} 35682a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 35782a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasamodule_init(qmgr_init); 35882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasamodule_exit(qmgr_remove); 35982a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 36082a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof HalasaMODULE_LICENSE("GPL v2"); 36182a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof HalasaMODULE_AUTHOR("Krzysztof Halasa"); 36282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof Halasa 36382a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof HalasaEXPORT_SYMBOL(qmgr_set_irq); 36482a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof HalasaEXPORT_SYMBOL(qmgr_enable_irq); 36582a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof HalasaEXPORT_SYMBOL(qmgr_disable_irq); 366e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa#if DEBUG_QMGR 367e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof HałasaEXPORT_SYMBOL(qmgr_queue_descs); 36882a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof HalasaEXPORT_SYMBOL(qmgr_request_queue); 369e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa#else 370e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof HałasaEXPORT_SYMBOL(__qmgr_request_queue); 371e6da96ace859dad966fe85cc9552b89f48bbc930Krzysztof Hałasa#endif 37282a96f5790ac93a406be72ed8f308dd29ad7e6afKrzysztof HalasaEXPORT_SYMBOL(qmgr_release_queue); 373