diff options
Diffstat (limited to 'arch/arm/mach-ixp4xx/ixp4xx_qmgr.c')
-rw-r--r-- | arch/arm/mach-ixp4xx/ixp4xx_qmgr.c | 135 |
1 files changed, 109 insertions, 26 deletions
diff --git a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c index bfddc73d0a20..bfdbe4b5a3cc 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,51 +28,112 @@ 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_irq1_a0(int irq, void *pdev) |
45 | { | 53 | { |
46 | int i; | 54 | int i, ret = 0; |
47 | u32 val = __raw_readl(&qmgr_regs->irqstat[0]); | 55 | u32 en_bitmap, src, stat; |
48 | __raw_writel(val, &qmgr_regs->irqstat[0]); /* ACK */ | 56 | |
49 | 57 | /* ACK - it may clear any bits so don't rely on it */ | |
50 | for (i = 0; i < HALF_QUEUES; i++) | 58 | __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[0]); |
51 | if (val & (1 << i)) | 59 | |
60 | en_bitmap = qmgr_regs->irqen[0]; | ||
61 | while (en_bitmap) { | ||
62 | i = __fls(en_bitmap); /* number of the last "low" queue */ | ||
63 | en_bitmap &= ~BIT(i); | ||
64 | src = qmgr_regs->irqsrc[i >> 3]; | ||
65 | stat = qmgr_regs->stat1[i >> 3]; | ||
66 | if (src & 4) /* the IRQ condition is inverted */ | ||
67 | stat = ~stat; | ||
68 | if (stat & BIT(src & 3)) { | ||
52 | irq_handlers[i](irq_pdevs[i]); | 69 | irq_handlers[i](irq_pdevs[i]); |
70 | ret = IRQ_HANDLED; | ||
71 | } | ||
72 | } | ||
73 | return ret; | ||
74 | } | ||
75 | |||
76 | |||
77 | static irqreturn_t qmgr_irq2_a0(int irq, void *pdev) | ||
78 | { | ||
79 | int i, ret = 0; | ||
80 | u32 req_bitmap; | ||
81 | |||
82 | /* ACK - it may clear any bits so don't rely on it */ | ||
83 | __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[1]); | ||
84 | |||
85 | req_bitmap = qmgr_regs->irqen[1] & qmgr_regs->statne_h; | ||
86 | while (req_bitmap) { | ||
87 | i = __fls(req_bitmap); /* number of the last "high" queue */ | ||
88 | req_bitmap &= ~BIT(i); | ||
89 | irq_handlers[HALF_QUEUES + i](irq_pdevs[HALF_QUEUES + i]); | ||
90 | ret = IRQ_HANDLED; | ||
91 | } | ||
92 | return ret; | ||
93 | } | ||
53 | 94 | ||
54 | return val ? IRQ_HANDLED : 0; | 95 | |
96 | static irqreturn_t qmgr_irq(int irq, void *pdev) | ||
97 | { | ||
98 | int i, half = (irq == IRQ_IXP4XX_QM1 ? 0 : 1); | ||
99 | u32 req_bitmap = __raw_readl(&qmgr_regs->irqstat[half]); | ||
100 | |||
101 | if (!req_bitmap) | ||
102 | return 0; | ||
103 | __raw_writel(req_bitmap, &qmgr_regs->irqstat[half]); /* ACK */ | ||
104 | |||
105 | while (req_bitmap) { | ||
106 | i = __fls(req_bitmap); /* number of the last queue */ | ||
107 | req_bitmap &= ~BIT(i); | ||
108 | i += half * HALF_QUEUES; | ||
109 | irq_handlers[i](irq_pdevs[i]); | ||
110 | } | ||
111 | return IRQ_HANDLED; | ||
55 | } | 112 | } |
56 | 113 | ||
57 | 114 | ||
58 | void qmgr_enable_irq(unsigned int queue) | 115 | void qmgr_enable_irq(unsigned int queue) |
59 | { | 116 | { |
60 | unsigned long flags; | 117 | unsigned long flags; |
118 | int half = queue / 32; | ||
119 | u32 mask = 1 << (queue & (HALF_QUEUES - 1)); | ||
61 | 120 | ||
62 | spin_lock_irqsave(&qmgr_lock, flags); | 121 | spin_lock_irqsave(&qmgr_lock, flags); |
63 | __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | (1 << queue), | 122 | __raw_writel(__raw_readl(&qmgr_regs->irqen[half]) | mask, |
64 | &qmgr_regs->irqen[0]); | 123 | &qmgr_regs->irqen[half]); |
65 | spin_unlock_irqrestore(&qmgr_lock, flags); | 124 | spin_unlock_irqrestore(&qmgr_lock, flags); |
66 | } | 125 | } |
67 | 126 | ||
68 | void qmgr_disable_irq(unsigned int queue) | 127 | void qmgr_disable_irq(unsigned int queue) |
69 | { | 128 | { |
70 | unsigned long flags; | 129 | unsigned long flags; |
130 | int half = queue / 32; | ||
131 | u32 mask = 1 << (queue & (HALF_QUEUES - 1)); | ||
71 | 132 | ||
72 | spin_lock_irqsave(&qmgr_lock, flags); | 133 | spin_lock_irqsave(&qmgr_lock, flags); |
73 | __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~(1 << queue), | 134 | __raw_writel(__raw_readl(&qmgr_regs->irqen[half]) & ~mask, |
74 | &qmgr_regs->irqen[0]); | 135 | &qmgr_regs->irqen[half]); |
75 | __raw_writel(1 << queue, &qmgr_regs->irqstat[0]); /* clear */ | 136 | __raw_writel(mask, &qmgr_regs->irqstat[half]); /* clear */ |
76 | spin_unlock_irqrestore(&qmgr_lock, flags); | 137 | spin_unlock_irqrestore(&qmgr_lock, flags); |
77 | } | 138 | } |
78 | 139 | ||
@@ -98,8 +159,7 @@ int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, | |||
98 | u32 cfg, addr = 0, mask[4]; /* in 16-dwords */ | 159 | u32 cfg, addr = 0, mask[4]; /* in 16-dwords */ |
99 | int err; | 160 | int err; |
100 | 161 | ||
101 | if (queue >= HALF_QUEUES) | 162 | BUG_ON(queue >= QUEUES); |
102 | return -ERANGE; | ||
103 | 163 | ||
104 | if ((nearly_empty_watermark | nearly_full_watermark) & ~7) | 164 | if ((nearly_empty_watermark | nearly_full_watermark) & ~7) |
105 | return -EINVAL; | 165 | return -EINVAL; |
@@ -180,7 +240,7 @@ void qmgr_release_queue(unsigned int queue) | |||
180 | { | 240 | { |
181 | u32 cfg, addr, mask[4]; | 241 | u32 cfg, addr, mask[4]; |
182 | 242 | ||
183 | BUG_ON(queue >= HALF_QUEUES); /* not in valid range */ | 243 | BUG_ON(queue >= QUEUES); /* not in valid range */ |
184 | 244 | ||
185 | spin_lock_irq(&qmgr_lock); | 245 | spin_lock_irq(&qmgr_lock); |
186 | cfg = __raw_readl(&qmgr_regs->sram[queue]); | 246 | cfg = __raw_readl(&qmgr_regs->sram[queue]); |
@@ -224,6 +284,8 @@ void qmgr_release_queue(unsigned int queue) | |||
224 | static int qmgr_init(void) | 284 | static int qmgr_init(void) |
225 | { | 285 | { |
226 | int i, err; | 286 | int i, err; |
287 | irq_handler_t handler1, handler2; | ||
288 | |||
227 | mem_res = request_mem_region(IXP4XX_QMGR_BASE_PHYS, | 289 | mem_res = request_mem_region(IXP4XX_QMGR_BASE_PHYS, |
228 | IXP4XX_QMGR_REGION_SIZE, | 290 | IXP4XX_QMGR_REGION_SIZE, |
229 | "IXP4xx Queue Manager"); | 291 | "IXP4xx Queue Manager"); |
@@ -247,23 +309,42 @@ static int qmgr_init(void) | |||
247 | __raw_writel(0, &qmgr_regs->irqen[i]); | 309 | __raw_writel(0, &qmgr_regs->irqen[i]); |
248 | } | 310 | } |
249 | 311 | ||
312 | __raw_writel(0xFFFFFFFF, &qmgr_regs->statne_h); | ||
313 | __raw_writel(0, &qmgr_regs->statf_h); | ||
314 | |||
250 | for (i = 0; i < QUEUES; i++) | 315 | for (i = 0; i < QUEUES; i++) |
251 | __raw_writel(0, &qmgr_regs->sram[i]); | 316 | __raw_writel(0, &qmgr_regs->sram[i]); |
252 | 317 | ||
253 | err = request_irq(IRQ_IXP4XX_QM1, qmgr_irq1, 0, | 318 | if (cpu_is_ixp42x_rev_a0()) { |
254 | "IXP4xx Queue Manager", NULL); | 319 | handler1 = qmgr_irq1_a0; |
320 | handler2 = qmgr_irq2_a0; | ||
321 | } else | ||
322 | handler1 = handler2 = qmgr_irq; | ||
323 | |||
324 | err = request_irq(IRQ_IXP4XX_QM1, handler1, 0, "IXP4xx Queue Manager", | ||
325 | NULL); | ||
255 | if (err) { | 326 | if (err) { |
256 | printk(KERN_ERR "qmgr: failed to request IRQ%i\n", | 327 | printk(KERN_ERR "qmgr: failed to request IRQ%i (%i)\n", |
257 | IRQ_IXP4XX_QM1); | 328 | IRQ_IXP4XX_QM1, err); |
258 | goto error_irq; | 329 | goto error_irq; |
259 | } | 330 | } |
260 | 331 | ||
332 | err = request_irq(IRQ_IXP4XX_QM2, handler2, 0, "IXP4xx Queue Manager", | ||
333 | NULL); | ||
334 | if (err) { | ||
335 | printk(KERN_ERR "qmgr: failed to request IRQ%i (%i)\n", | ||
336 | IRQ_IXP4XX_QM2, err); | ||
337 | goto error_irq2; | ||
338 | } | ||
339 | |||
261 | used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */ | 340 | used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */ |
262 | spin_lock_init(&qmgr_lock); | 341 | spin_lock_init(&qmgr_lock); |
263 | 342 | ||
264 | printk(KERN_INFO "IXP4xx Queue Manager initialized.\n"); | 343 | printk(KERN_INFO "IXP4xx Queue Manager initialized.\n"); |
265 | return 0; | 344 | return 0; |
266 | 345 | ||
346 | error_irq2: | ||
347 | free_irq(IRQ_IXP4XX_QM1, NULL); | ||
267 | error_irq: | 348 | error_irq: |
268 | iounmap(qmgr_regs); | 349 | iounmap(qmgr_regs); |
269 | error_map: | 350 | error_map: |
@@ -274,7 +355,9 @@ error_map: | |||
274 | static void qmgr_remove(void) | 355 | static void qmgr_remove(void) |
275 | { | 356 | { |
276 | free_irq(IRQ_IXP4XX_QM1, NULL); | 357 | free_irq(IRQ_IXP4XX_QM1, NULL); |
358 | free_irq(IRQ_IXP4XX_QM2, NULL); | ||
277 | synchronize_irq(IRQ_IXP4XX_QM1); | 359 | synchronize_irq(IRQ_IXP4XX_QM1); |
360 | synchronize_irq(IRQ_IXP4XX_QM2); | ||
278 | iounmap(qmgr_regs); | 361 | iounmap(qmgr_regs); |
279 | release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE); | 362 | release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE); |
280 | } | 363 | } |