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