[PATCH] ixp4xx_qmgr: support 64 queues
From: Miguel Ángel Álvarez
Date: Wed Dec 10 2008 - 06:32:49 EST
Hi
I have read Karl Hiramoto's patch for supporting 64 queues in
ixp4xx_qmgr, and the comments from Krzysztof Halasa.
I am not sure of some of the features implemented by Karl, but I think
that the work in supporting 64 queues is quite valuable.
I have remade the patch so that this "minimal" functionallity can be
analysed. Here it is.
diff -urN linux-2.6.26.7_hssorig/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
linux-2.6.26.7/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
--- linux-2.6.26.7_hssorig/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c 2008-10-22
23:46:18.000000000 +0200
+++ linux-2.6.26.7/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c 2008-12-10
11:26:28.000000000 +0100
@@ -26,13 +26,21 @@
void qmgr_set_irq(unsigned int queue, int src,
void (*handler)(void *pdev), void *pdev)
{
- u32 __iomem *reg = &qmgr_regs->irqsrc[queue / 8]; /* 8 queues / u32 */
- int bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
+ u32 __iomem *reg;
+ int bit;
unsigned long flags;
- src &= 7;
+ BUG_ON(queue >= HALF_QUEUES && src != QUEUE_IRQ_SRC_NOT_EMPTY);
+
spin_lock_irqsave(&qmgr_lock, flags);
- __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg);
+
+ if (queue < HALF_QUEUES) {
+ src &= 7;
+ reg = &qmgr_regs->irqsrc[queue / 8];
+ bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
+ __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg);
+ }
+
irq_handlers[queue] = handler;
irq_pdevs[queue] = pdev;
spin_unlock_irqrestore(&qmgr_lock, flags);
@@ -53,13 +61,31 @@
}
+static irqreturn_t qmgr_irq2(int irq, void *pdev)
+{
+ int i;
+ u32 val = __raw_readl(&qmgr_regs->irqstat[1]);
+ __raw_writel(val, &qmgr_regs->irqstat[1]); /* ACK */
+
+ for (i = HALF_QUEUES; i < QUEUES; i++)
+ if (val & (1 << i))
+ irq_handlers[i](irq_pdevs[i]);
+
+ return val ? IRQ_HANDLED : 0;
+}
+
+
void qmgr_enable_irq(unsigned int queue)
{
unsigned long flags;
spin_lock_irqsave(&qmgr_lock, flags);
- __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | (1 << queue),
- &qmgr_regs->irqen[0]);
+ if (queue < HALF_QUEUES)
+ __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | (1 << queue),
+ &qmgr_regs->irqen[0]);
+ else
+ __raw_writel(__raw_readl(&qmgr_regs->irqen[1]) |
+ (1 << (queue - HALF_QUEUES)), &qmgr_regs->irqen[1]);
spin_unlock_irqrestore(&qmgr_lock, flags);
}
@@ -68,8 +94,12 @@
unsigned long flags;
spin_lock_irqsave(&qmgr_lock, flags);
- __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~(1 << queue),
- &qmgr_regs->irqen[0]);
+ if (queue < HALF_QUEUES)
+ __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~(1 << queue),
+ &qmgr_regs->irqen[0]);
+ else
+ __raw_writel(__raw_readl(&qmgr_regs->irqen[1]) &
+ ~(1 << (queue - HALF_QUEUES)), &qmgr_regs->irqen[1]);
spin_unlock_irqrestore(&qmgr_lock, flags);
}
@@ -88,7 +118,7 @@
u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
int err;
- if (queue >= HALF_QUEUES)
+ if (queue >= QUEUES)
return -ERANGE;
if ((nearly_empty_watermark | nearly_full_watermark) & ~7)
@@ -169,7 +199,7 @@
{
u32 cfg, addr, mask[4];
- BUG_ON(queue >= HALF_QUEUES); /* not in valid range */
+ BUG_ON(queue >= QUEUES); /* not in valid range */
spin_lock_irq(&qmgr_lock);
cfg = __raw_readl(&qmgr_regs->sram[queue]);
@@ -234,20 +264,32 @@
__raw_writel(0, &qmgr_regs->sram[i]);
err = request_irq(IRQ_IXP4XX_QM1, qmgr_irq1, 0,
- "IXP4xx Queue Manager", NULL);
+ "IXP4xx Queue Manager QM1", NULL);
if (err) {
printk(KERN_ERR "qmgr: failed to request IRQ%i\n",
IRQ_IXP4XX_QM1);
- goto error_irq;
+ goto error_irq1;
+ }
+
+ err = request_irq(IRQ_IXP4XX_QM2, qmgr_irq2, 0,
+ "IXP4xx Queue Manager QM2", NULL);
+ if (err) {
+ printk(KERN_ERR "qmgr: failed to request IRQ%i\n",
+ IRQ_IXP4XX_QM2);
+ goto error_irq2;
}
+
used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */
spin_lock_init(&qmgr_lock);
printk(KERN_INFO "IXP4xx Queue Manager initialized.\n");
return 0;
-error_irq:
+error_irq2:
+ free_irq(IRQ_IXP4XX_QM1, NULL);
+ synchronize_irq(IRQ_IXP4XX_QM2);
+error_irq1:
iounmap(qmgr_regs);
error_map:
release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
@@ -257,7 +299,9 @@
static void qmgr_remove(void)
{
free_irq(IRQ_IXP4XX_QM1, NULL);
+ free_irq(IRQ_IXP4XX_QM2, NULL);
synchronize_irq(IRQ_IXP4XX_QM1);
+ synchronize_irq(IRQ_IXP4XX_QM2);
iounmap(qmgr_regs);
release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
}
diff -urN linux-2.6.26.7_hssorig/include/asm-arm/arch-ixp4xx/qmgr.h
linux-2.6.26.7/include/asm-arm/arch-ixp4xx/qmgr.h
--- linux-2.6.26.7_hssorig/include/asm-arm/arch-ixp4xx/qmgr.h 2008-10-22
23:46:18.000000000 +0200
+++ linux-2.6.26.7/include/asm-arm/arch-ixp4xx/qmgr.h 2008-12-10
11:31:00.000000000 +0100
@@ -1,5 +1,7 @@
/*
* Copyright (C) 2007 Krzysztof Halasa <khc@xxxxxxxxx>
+ * Portions Copyright (C) 2008 Karl Hiramoto <karl@xxxxxxxxxxxx>
+ * Portions Copyright (C) 2008 Miguel Angel Alvarez <gotzoncabanes@xxxxxxxxx>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
@@ -82,6 +84,7 @@
static inline int qmgr_get_stat1(unsigned int queue)
{
extern struct qmgr_regs __iomem *qmgr_regs;
+ BUG_ON(queue >= HALF_QUEUES);
return (__raw_readl(&qmgr_regs->stat1[queue >> 3])
>> ((queue & 7) << 2)) & 0xF;
}
@@ -89,37 +92,52 @@
static inline int qmgr_get_stat2(unsigned int queue)
{
extern struct qmgr_regs __iomem *qmgr_regs;
+ BUG_ON(queue >= HALF_QUEUES);
return (__raw_readl(&qmgr_regs->stat2[queue >> 4])
>> ((queue & 0xF) << 1)) & 0x3;
}
static inline int qmgr_stat_empty(unsigned int queue)
{
+ BUG_ON(queue >= HALF_QUEUES);
return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY);
}
static inline int qmgr_stat_nearly_empty(unsigned int queue)
{
- return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY);
+ extern struct qmgr_regs __iomem *qmgr_regs;
+ if (queue < HALF_QUEUES)
+ return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY);
+ else
+ return !!((__raw_readl(&qmgr_regs->statne_h)
+ >> (queue - HALF_QUEUES)) & 0x1);
}
static inline int qmgr_stat_nearly_full(unsigned int queue)
{
+ BUG_ON(queue >= HALF_QUEUES);
return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL);
}
static inline int qmgr_stat_full(unsigned int queue)
{
- return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_FULL);
+ extern struct qmgr_regs __iomem *qmgr_regs;
+ if (queue < HALF_QUEUES)
+ return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_FULL);
+ else
+ return !!((__raw_readl(&qmgr_regs->statf_h)
+ >> (queue - HALF_QUEUES)) & 0x1);
}
static inline int qmgr_stat_underflow(unsigned int queue)
{
+ BUG_ON(queue >= HALF_QUEUES);
return !!(qmgr_get_stat2(queue) & QUEUE_STAT2_UNDERFLOW);
}
static inline int qmgr_stat_overflow(unsigned int queue)
{
+ BUG_ON(queue >= HALF_QUEUES);
return !!(qmgr_get_stat2(queue) & QUEUE_STAT2_OVERFLOW);
}
I think it could be quite useful to add it to the mainstream.
Thanks
Miguel Ángel Álvarez
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/