diff options
author | Krzysztof Hałasa <khc@pm.waw.pl> | 2009-02-19 19:01:33 -0500 |
---|---|---|
committer | Krzysztof Hałasa <khc@pm.waw.pl> | 2009-05-20 09:27:07 -0400 |
commit | a6a9fb857b5599b3cefef5576967389c1c43eb4c (patch) | |
tree | 3a6d3d8e9d7560c1c496fc6c38698687196fab55 /arch/arm/mach-ixp4xx | |
parent | 1406de8e11eb043681297adf86d6892ff8efc27a (diff) |
IXP4xx: Add support for the second half of the 64 hardware queues.
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
Diffstat (limited to 'arch/arm/mach-ixp4xx')
-rw-r--r-- | arch/arm/mach-ixp4xx/include/mach/qmgr.h | 65 | ||||
-rw-r--r-- | arch/arm/mach-ixp4xx/ixp4xx_qmgr.c | 71 |
2 files changed, 105 insertions, 31 deletions
diff --git a/arch/arm/mach-ixp4xx/include/mach/qmgr.h b/arch/arm/mach-ixp4xx/include/mach/qmgr.h index 0cbe6ceb67c5..32077e11f17a 100644 --- a/arch/arm/mach-ixp4xx/include/mach/qmgr.h +++ b/arch/arm/mach-ixp4xx/include/mach/qmgr.h | |||
@@ -15,7 +15,7 @@ | |||
15 | #define DEBUG_QMGR 0 | 15 | #define DEBUG_QMGR 0 |
16 | 16 | ||
17 | #define HALF_QUEUES 32 | 17 | #define HALF_QUEUES 32 |
18 | #define QUEUES 64 /* only 32 lower queues currently supported */ | 18 | #define QUEUES 64 |
19 | #define MAX_QUEUE_LENGTH 4 /* in dwords */ | 19 | #define MAX_QUEUE_LENGTH 4 /* in dwords */ |
20 | 20 | ||
21 | #define QUEUE_STAT1_EMPTY 1 /* queue status bits */ | 21 | #define QUEUE_STAT1_EMPTY 1 /* queue status bits */ |
@@ -110,48 +110,95 @@ static inline u32 qmgr_get_entry(unsigned int queue) | |||
110 | return val; | 110 | return val; |
111 | } | 111 | } |
112 | 112 | ||
113 | static inline int qmgr_get_stat1(unsigned int queue) | 113 | static inline int __qmgr_get_stat1(unsigned int queue) |
114 | { | 114 | { |
115 | extern struct qmgr_regs __iomem *qmgr_regs; | 115 | extern struct qmgr_regs __iomem *qmgr_regs; |
116 | return (__raw_readl(&qmgr_regs->stat1[queue >> 3]) | 116 | return (__raw_readl(&qmgr_regs->stat1[queue >> 3]) |
117 | >> ((queue & 7) << 2)) & 0xF; | 117 | >> ((queue & 7) << 2)) & 0xF; |
118 | } | 118 | } |
119 | 119 | ||
120 | static inline int qmgr_get_stat2(unsigned int queue) | 120 | static inline int __qmgr_get_stat2(unsigned int queue) |
121 | { | 121 | { |
122 | extern struct qmgr_regs __iomem *qmgr_regs; | 122 | extern struct qmgr_regs __iomem *qmgr_regs; |
123 | BUG_ON(queue >= HALF_QUEUES); | ||
123 | return (__raw_readl(&qmgr_regs->stat2[queue >> 4]) | 124 | return (__raw_readl(&qmgr_regs->stat2[queue >> 4]) |
124 | >> ((queue & 0xF) << 1)) & 0x3; | 125 | >> ((queue & 0xF) << 1)) & 0x3; |
125 | } | 126 | } |
126 | 127 | ||
128 | /** | ||
129 | * qmgr_stat_empty() - checks if a hardware queue is empty | ||
130 | * @queue: queue number | ||
131 | * | ||
132 | * Returns non-zero value if the queue is empty. | ||
133 | */ | ||
127 | static inline int qmgr_stat_empty(unsigned int queue) | 134 | static inline int qmgr_stat_empty(unsigned int queue) |
128 | { | 135 | { |
129 | return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY); | 136 | BUG_ON(queue >= HALF_QUEUES); |
137 | return __qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY; | ||
130 | } | 138 | } |
131 | 139 | ||
140 | /** | ||
141 | * qmgr_stat_empty() - checks if a hardware queue is nearly empty | ||
142 | * @queue: queue number | ||
143 | * | ||
144 | * Returns non-zero value if the queue is nearly or completely empty. | ||
145 | */ | ||
132 | static inline int qmgr_stat_nearly_empty(unsigned int queue) | 146 | static inline int qmgr_stat_nearly_empty(unsigned int queue) |
133 | { | 147 | { |
134 | return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY); | 148 | extern struct qmgr_regs __iomem *qmgr_regs; |
149 | if (queue >= HALF_QUEUES) | ||
150 | return (__raw_readl(&qmgr_regs->statne_h) >> | ||
151 | (queue - HALF_QUEUES)) & 0x01; | ||
152 | return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY; | ||
135 | } | 153 | } |
136 | 154 | ||
155 | /** | ||
156 | * qmgr_stat_empty() - checks if a hardware queue is nearly full | ||
157 | * @queue: queue number | ||
158 | * | ||
159 | * Returns non-zero value if the queue is nearly or completely full. | ||
160 | */ | ||
137 | static inline int qmgr_stat_nearly_full(unsigned int queue) | 161 | static inline int qmgr_stat_nearly_full(unsigned int queue) |
138 | { | 162 | { |
139 | return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL); | 163 | BUG_ON(queue >= HALF_QUEUES); |
164 | return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL; | ||
140 | } | 165 | } |
141 | 166 | ||
167 | /** | ||
168 | * qmgr_stat_empty() - checks if a hardware queue is full | ||
169 | * @queue: queue number | ||
170 | * | ||
171 | * Returns non-zero value if the queue is full. | ||
172 | */ | ||
142 | static inline int qmgr_stat_full(unsigned int queue) | 173 | static inline int qmgr_stat_full(unsigned int queue) |
143 | { | 174 | { |
144 | return !!(qmgr_get_stat1(queue) & QUEUE_STAT1_FULL); | 175 | extern struct qmgr_regs __iomem *qmgr_regs; |
176 | if (queue >= HALF_QUEUES) | ||
177 | return (__raw_readl(&qmgr_regs->statf_h) >> | ||
178 | (queue - HALF_QUEUES)) & 0x01; | ||
179 | return __qmgr_get_stat1(queue) & QUEUE_STAT1_FULL; | ||
145 | } | 180 | } |
146 | 181 | ||
182 | /** | ||
183 | * qmgr_stat_empty() - checks if a hardware queue experienced underflow | ||
184 | * @queue: queue number | ||
185 | * | ||
186 | * Returns non-zero value if empty. | ||
187 | */ | ||
147 | static inline int qmgr_stat_underflow(unsigned int queue) | 188 | static inline int qmgr_stat_underflow(unsigned int queue) |
148 | { | 189 | { |
149 | return !!(qmgr_get_stat2(queue) & QUEUE_STAT2_UNDERFLOW); | 190 | return __qmgr_get_stat2(queue) & QUEUE_STAT2_UNDERFLOW; |
150 | } | 191 | } |
151 | 192 | ||
193 | /** | ||
194 | * qmgr_stat_empty() - checks if a hardware queue experienced overflow | ||
195 | * @queue: queue number | ||
196 | * | ||
197 | * Returns non-zero value if empty. | ||
198 | */ | ||
152 | static inline int qmgr_stat_overflow(unsigned int queue) | 199 | static inline int qmgr_stat_overflow(unsigned int queue) |
153 | { | 200 | { |
154 | return !!(qmgr_get_stat2(queue) & QUEUE_STAT2_OVERFLOW); | 201 | return __qmgr_get_stat2(queue) & QUEUE_STAT2_OVERFLOW; |
155 | } | 202 | } |
156 | 203 | ||
157 | #endif | 204 | #endif |
diff --git a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c index bfddc73d0a20..7531bfdb7b4e 100644 --- a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c +++ b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c | |||
@@ -18,8 +18,8 @@ struct qmgr_regs __iomem *qmgr_regs; | |||
18 | static struct resource *mem_res; | 18 | static struct resource *mem_res; |
19 | static spinlock_t qmgr_lock; | 19 | static spinlock_t qmgr_lock; |
20 | static u32 used_sram_bitmap[4]; /* 128 16-dword pages */ | 20 | static u32 used_sram_bitmap[4]; /* 128 16-dword pages */ |
21 | static void (*irq_handlers[HALF_QUEUES])(void *pdev); | 21 | static void (*irq_handlers[QUEUES])(void *pdev); |
22 | static void *irq_pdevs[HALF_QUEUES]; | 22 | static void *irq_pdevs[QUEUES]; |
23 | 23 | ||
24 | #if DEBUG_QMGR | 24 | #if DEBUG_QMGR |
25 | char qmgr_queue_descs[QUEUES][32]; | 25 | char qmgr_queue_descs[QUEUES][32]; |
@@ -28,29 +28,38 @@ char qmgr_queue_descs[QUEUES][32]; | |||
28 | void qmgr_set_irq(unsigned int queue, int src, | 28 | void qmgr_set_irq(unsigned int queue, int src, |
29 | void (*handler)(void *pdev), void *pdev) | 29 | void (*handler)(void *pdev), void *pdev) |
30 | { | 30 | { |
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 */ | ||
33 | unsigned long flags; | 31 | unsigned long flags; |
34 | 32 | ||
35 | src &= 7; | ||
36 | spin_lock_irqsave(&qmgr_lock, flags); | 33 | spin_lock_irqsave(&qmgr_lock, flags); |
37 | __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg); | 34 | if (queue < HALF_QUEUES) { |
35 | u32 __iomem *reg; | ||
36 | int bit; | ||
37 | BUG_ON(src > QUEUE_IRQ_SRC_NOT_FULL); | ||
38 | reg = &qmgr_regs->irqsrc[queue >> 3]; /* 8 queues per u32 */ | ||
39 | bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */ | ||
40 | __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), | ||
41 | reg); | ||
42 | } else | ||
43 | /* IRQ source for queues 32-63 is fixed */ | ||
44 | BUG_ON(src != QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY); | ||
45 | |||
38 | irq_handlers[queue] = handler; | 46 | irq_handlers[queue] = handler; |
39 | irq_pdevs[queue] = pdev; | 47 | irq_pdevs[queue] = pdev; |
40 | spin_unlock_irqrestore(&qmgr_lock, flags); | 48 | spin_unlock_irqrestore(&qmgr_lock, flags); |
41 | } | 49 | } |
42 | 50 | ||
43 | 51 | ||
44 | static irqreturn_t qmgr_irq1(int irq, void *pdev) | 52 | static irqreturn_t qmgr_irq(int irq, void *pdev) |
45 | { | 53 | { |
46 | int i; | 54 | int i, half = (irq == IRQ_IXP4XX_QM1 ? 0 : 1); |
47 | u32 val = __raw_readl(&qmgr_regs->irqstat[0]); | 55 | u32 val = __raw_readl(&qmgr_regs->irqstat[half]); |
48 | __raw_writel(val, &qmgr_regs->irqstat[0]); /* ACK */ | 56 | __raw_writel(val, &qmgr_regs->irqstat[half]); /* ACK */ |
49 | 57 | ||
50 | for (i = 0; i < HALF_QUEUES; i++) | 58 | for (i = 0; i < HALF_QUEUES; i++) |
51 | if (val & (1 << i)) | 59 | if (val & (1 << i)) { |
52 | irq_handlers[i](irq_pdevs[i]); | 60 | int irq = half * HALF_QUEUES + i; |
53 | 61 | irq_handlers[irq](irq_pdevs[irq]); | |
62 | } | ||
54 | return val ? IRQ_HANDLED : 0; | 63 | return val ? IRQ_HANDLED : 0; |
55 | } | 64 | } |
56 | 65 | ||
@@ -58,21 +67,25 @@ static irqreturn_t qmgr_irq1(int irq, void *pdev) | |||
58 | void qmgr_enable_irq(unsigned int queue) | 67 | void qmgr_enable_irq(unsigned int queue) |
59 | { | 68 | { |
60 | unsigned long flags; | 69 | unsigned long flags; |
70 | int half = queue / 32; | ||
71 | u32 mask = 1 << (queue & (HALF_QUEUES - 1)); | ||
61 | 72 | ||
62 | spin_lock_irqsave(&qmgr_lock, flags); | 73 | spin_lock_irqsave(&qmgr_lock, flags); |
63 | __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | (1 << queue), | 74 | __raw_writel(__raw_readl(&qmgr_regs->irqen[half]) | mask, |
64 | &qmgr_regs->irqen[0]); | 75 | &qmgr_regs->irqen[half]); |
65 | spin_unlock_irqrestore(&qmgr_lock, flags); | 76 | spin_unlock_irqrestore(&qmgr_lock, flags); |
66 | } | 77 | } |
67 | 78 | ||
68 | void qmgr_disable_irq(unsigned int queue) | 79 | void qmgr_disable_irq(unsigned int queue) |
69 | { | 80 | { |
70 | unsigned long flags; | 81 | unsigned long flags; |
82 | int half = queue / 32; | ||
83 | u32 mask = 1 << (queue & (HALF_QUEUES - 1)); | ||
71 | 84 | ||
72 | spin_lock_irqsave(&qmgr_lock, flags); | 85 | spin_lock_irqsave(&qmgr_lock, flags); |
73 | __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~(1 << queue), | 86 | __raw_writel(__raw_readl(&qmgr_regs->irqen[half]) & ~mask, |
74 | &qmgr_regs->irqen[0]); | 87 | &qmgr_regs->irqen[half]); |
75 | __raw_writel(1 << queue, &qmgr_regs->irqstat[0]); /* clear */ | 88 | __raw_writel(mask, &qmgr_regs->irqstat[half]); /* clear */ |
76 | spin_unlock_irqrestore(&qmgr_lock, flags); | 89 | spin_unlock_irqrestore(&qmgr_lock, flags); |
77 | } | 90 | } |
78 | 91 | ||
@@ -98,8 +111,7 @@ int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, | |||
98 | u32 cfg, addr = 0, mask[4]; /* in 16-dwords */ | 111 | u32 cfg, addr = 0, mask[4]; /* in 16-dwords */ |
99 | int err; | 112 | int err; |
100 | 113 | ||
101 | if (queue >= HALF_QUEUES) | 114 | BUG_ON(queue >= QUEUES); |
102 | return -ERANGE; | ||
103 | 115 | ||
104 | if ((nearly_empty_watermark | nearly_full_watermark) & ~7) | 116 | if ((nearly_empty_watermark | nearly_full_watermark) & ~7) |
105 | return -EINVAL; | 117 | return -EINVAL; |
@@ -180,7 +192,7 @@ void qmgr_release_queue(unsigned int queue) | |||
180 | { | 192 | { |
181 | u32 cfg, addr, mask[4]; | 193 | u32 cfg, addr, mask[4]; |
182 | 194 | ||
183 | BUG_ON(queue >= HALF_QUEUES); /* not in valid range */ | 195 | BUG_ON(queue >= QUEUES); /* not in valid range */ |
184 | 196 | ||
185 | spin_lock_irq(&qmgr_lock); | 197 | spin_lock_irq(&qmgr_lock); |
186 | cfg = __raw_readl(&qmgr_regs->sram[queue]); | 198 | cfg = __raw_readl(&qmgr_regs->sram[queue]); |
@@ -247,10 +259,13 @@ static int qmgr_init(void) | |||
247 | __raw_writel(0, &qmgr_regs->irqen[i]); | 259 | __raw_writel(0, &qmgr_regs->irqen[i]); |
248 | } | 260 | } |
249 | 261 | ||
262 | __raw_writel(0xFFFFFFFF, &qmgr_regs->statne_h); | ||
263 | __raw_writel(0, &qmgr_regs->statf_h); | ||
264 | |||
250 | for (i = 0; i < QUEUES; i++) | 265 | for (i = 0; i < QUEUES; i++) |
251 | __raw_writel(0, &qmgr_regs->sram[i]); | 266 | __raw_writel(0, &qmgr_regs->sram[i]); |
252 | 267 | ||
253 | err = request_irq(IRQ_IXP4XX_QM1, qmgr_irq1, 0, | 268 | err = request_irq(IRQ_IXP4XX_QM1, qmgr_irq, 0, |
254 | "IXP4xx Queue Manager", NULL); | 269 | "IXP4xx Queue Manager", NULL); |
255 | if (err) { | 270 | if (err) { |
256 | printk(KERN_ERR "qmgr: failed to request IRQ%i\n", | 271 | printk(KERN_ERR "qmgr: failed to request IRQ%i\n", |
@@ -258,12 +273,22 @@ static int qmgr_init(void) | |||
258 | goto error_irq; | 273 | goto error_irq; |
259 | } | 274 | } |
260 | 275 | ||
276 | err = request_irq(IRQ_IXP4XX_QM2, qmgr_irq, 0, | ||
277 | "IXP4xx Queue Manager", NULL); | ||
278 | if (err) { | ||
279 | printk(KERN_ERR "qmgr: failed to request IRQ%i\n", | ||
280 | IRQ_IXP4XX_QM2); | ||
281 | goto error_irq2; | ||
282 | } | ||
283 | |||
261 | used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */ | 284 | used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */ |
262 | spin_lock_init(&qmgr_lock); | 285 | spin_lock_init(&qmgr_lock); |
263 | 286 | ||
264 | printk(KERN_INFO "IXP4xx Queue Manager initialized.\n"); | 287 | printk(KERN_INFO "IXP4xx Queue Manager initialized.\n"); |
265 | return 0; | 288 | return 0; |
266 | 289 | ||
290 | error_irq2: | ||
291 | free_irq(IRQ_IXP4XX_QM1, NULL); | ||
267 | error_irq: | 292 | error_irq: |
268 | iounmap(qmgr_regs); | 293 | iounmap(qmgr_regs); |
269 | error_map: | 294 | error_map: |
@@ -274,7 +299,9 @@ error_map: | |||
274 | static void qmgr_remove(void) | 299 | static void qmgr_remove(void) |
275 | { | 300 | { |
276 | free_irq(IRQ_IXP4XX_QM1, NULL); | 301 | free_irq(IRQ_IXP4XX_QM1, NULL); |
302 | free_irq(IRQ_IXP4XX_QM2, NULL); | ||
277 | synchronize_irq(IRQ_IXP4XX_QM1); | 303 | synchronize_irq(IRQ_IXP4XX_QM1); |
304 | synchronize_irq(IRQ_IXP4XX_QM2); | ||
278 | iounmap(qmgr_regs); | 305 | iounmap(qmgr_regs); |
279 | release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE); | 306 | release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE); |
280 | } | 307 | } |