ixp4xx_qmgr.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /*
  2. * Intel IXP4xx Queue Manager driver for Linux
  3. *
  4. * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of version 2 of the GNU General Public License
  8. * as published by the Free Software Foundation.
  9. */
  10. #include <linux/ioport.h>
  11. #include <linux/interrupt.h>
  12. #include <linux/kernel.h>
  13. #include <linux/module.h>
  14. #include <mach/qmgr.h>
  15. #define DEBUG 0
  16. struct qmgr_regs __iomem *qmgr_regs;
  17. static struct resource *mem_res;
  18. static spinlock_t qmgr_lock;
  19. static u32 used_sram_bitmap[4]; /* 128 16-dword pages */
  20. static void (*irq_handlers[HALF_QUEUES])(void *pdev);
  21. static void *irq_pdevs[HALF_QUEUES];
  22. void qmgr_set_irq(unsigned int queue, int src,
  23. void (*handler)(void *pdev), void *pdev)
  24. {
  25. u32 __iomem *reg = &qmgr_regs->irqsrc[queue / 8]; /* 8 queues / u32 */
  26. int bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
  27. unsigned long flags;
  28. src &= 7;
  29. spin_lock_irqsave(&qmgr_lock, flags);
  30. __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg);
  31. irq_handlers[queue] = handler;
  32. irq_pdevs[queue] = pdev;
  33. spin_unlock_irqrestore(&qmgr_lock, flags);
  34. }
  35. static irqreturn_t qmgr_irq1(int irq, void *pdev)
  36. {
  37. int i;
  38. u32 val = __raw_readl(&qmgr_regs->irqstat[0]);
  39. __raw_writel(val, &qmgr_regs->irqstat[0]); /* ACK */
  40. for (i = 0; i < HALF_QUEUES; i++)
  41. if (val & (1 << i))
  42. irq_handlers[i](irq_pdevs[i]);
  43. return val ? IRQ_HANDLED : 0;
  44. }
  45. void qmgr_enable_irq(unsigned int queue)
  46. {
  47. unsigned long flags;
  48. spin_lock_irqsave(&qmgr_lock, flags);
  49. __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | (1 << queue),
  50. &qmgr_regs->irqen[0]);
  51. spin_unlock_irqrestore(&qmgr_lock, flags);
  52. }
  53. void qmgr_disable_irq(unsigned int queue)
  54. {
  55. unsigned long flags;
  56. spin_lock_irqsave(&qmgr_lock, flags);
  57. __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~(1 << queue),
  58. &qmgr_regs->irqen[0]);
  59. spin_unlock_irqrestore(&qmgr_lock, flags);
  60. }
  61. static inline void shift_mask(u32 *mask)
  62. {
  63. mask[3] = mask[3] << 1 | mask[2] >> 31;
  64. mask[2] = mask[2] << 1 | mask[1] >> 31;
  65. mask[1] = mask[1] << 1 | mask[0] >> 31;
  66. mask[0] <<= 1;
  67. }
  68. int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
  69. unsigned int nearly_empty_watermark,
  70. unsigned int nearly_full_watermark)
  71. {
  72. u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
  73. int err;
  74. if (queue >= HALF_QUEUES)
  75. return -ERANGE;
  76. if ((nearly_empty_watermark | nearly_full_watermark) & ~7)
  77. return -EINVAL;
  78. switch (len) {
  79. case 16:
  80. cfg = 0 << 24;
  81. mask[0] = 0x1;
  82. break;
  83. case 32:
  84. cfg = 1 << 24;
  85. mask[0] = 0x3;
  86. break;
  87. case 64:
  88. cfg = 2 << 24;
  89. mask[0] = 0xF;
  90. break;
  91. case 128:
  92. cfg = 3 << 24;
  93. mask[0] = 0xFF;
  94. break;
  95. default:
  96. return -EINVAL;
  97. }
  98. cfg |= nearly_empty_watermark << 26;
  99. cfg |= nearly_full_watermark << 29;
  100. len /= 16; /* in 16-dwords: 1, 2, 4 or 8 */
  101. mask[1] = mask[2] = mask[3] = 0;
  102. if (!try_module_get(THIS_MODULE))
  103. return -ENODEV;
  104. spin_lock_irq(&qmgr_lock);
  105. if (__raw_readl(&qmgr_regs->sram[queue])) {
  106. err = -EBUSY;
  107. goto err;
  108. }
  109. while (1) {
  110. if (!(used_sram_bitmap[0] & mask[0]) &&
  111. !(used_sram_bitmap[1] & mask[1]) &&
  112. !(used_sram_bitmap[2] & mask[2]) &&
  113. !(used_sram_bitmap[3] & mask[3]))
  114. break; /* found free space */
  115. addr++;
  116. shift_mask(mask);
  117. if (addr + len > ARRAY_SIZE(qmgr_regs->sram)) {
  118. printk(KERN_ERR "qmgr: no free SRAM space for"
  119. " queue %i\n", queue);
  120. err = -ENOMEM;
  121. goto err;
  122. }
  123. }
  124. used_sram_bitmap[0] |= mask[0];
  125. used_sram_bitmap[1] |= mask[1];
  126. used_sram_bitmap[2] |= mask[2];
  127. used_sram_bitmap[3] |= mask[3];
  128. __raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]);
  129. spin_unlock_irq(&qmgr_lock);
  130. #if DEBUG
  131. printk(KERN_DEBUG "qmgr: requested queue %i, addr = 0x%02X\n",
  132. queue, addr);
  133. #endif
  134. return 0;
  135. err:
  136. spin_unlock_irq(&qmgr_lock);
  137. module_put(THIS_MODULE);
  138. return err;
  139. }
  140. void qmgr_release_queue(unsigned int queue)
  141. {
  142. u32 cfg, addr, mask[4];
  143. BUG_ON(queue >= HALF_QUEUES); /* not in valid range */
  144. spin_lock_irq(&qmgr_lock);
  145. cfg = __raw_readl(&qmgr_regs->sram[queue]);
  146. addr = (cfg >> 14) & 0xFF;
  147. BUG_ON(!addr); /* not requested */
  148. switch ((cfg >> 24) & 3) {
  149. case 0: mask[0] = 0x1; break;
  150. case 1: mask[0] = 0x3; break;
  151. case 2: mask[0] = 0xF; break;
  152. case 3: mask[0] = 0xFF; break;
  153. }
  154. mask[1] = mask[2] = mask[3] = 0;
  155. while (addr--)
  156. shift_mask(mask);
  157. __raw_writel(0, &qmgr_regs->sram[queue]);
  158. used_sram_bitmap[0] &= ~mask[0];
  159. used_sram_bitmap[1] &= ~mask[1];
  160. used_sram_bitmap[2] &= ~mask[2];
  161. used_sram_bitmap[3] &= ~mask[3];
  162. irq_handlers[queue] = NULL; /* catch IRQ bugs */
  163. spin_unlock_irq(&qmgr_lock);
  164. module_put(THIS_MODULE);
  165. #if DEBUG
  166. printk(KERN_DEBUG "qmgr: released queue %i\n", queue);
  167. #endif
  168. }
  169. static int qmgr_init(void)
  170. {
  171. int i, err;
  172. mem_res = request_mem_region(IXP4XX_QMGR_BASE_PHYS,
  173. IXP4XX_QMGR_REGION_SIZE,
  174. "IXP4xx Queue Manager");
  175. if (mem_res == NULL)
  176. return -EBUSY;
  177. qmgr_regs = ioremap(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
  178. if (qmgr_regs == NULL) {
  179. err = -ENOMEM;
  180. goto error_map;
  181. }
  182. /* reset qmgr registers */
  183. for (i = 0; i < 4; i++) {
  184. __raw_writel(0x33333333, &qmgr_regs->stat1[i]);
  185. __raw_writel(0, &qmgr_regs->irqsrc[i]);
  186. }
  187. for (i = 0; i < 2; i++) {
  188. __raw_writel(0, &qmgr_regs->stat2[i]);
  189. __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[i]); /* clear */
  190. __raw_writel(0, &qmgr_regs->irqen[i]);
  191. }
  192. for (i = 0; i < QUEUES; i++)
  193. __raw_writel(0, &qmgr_regs->sram[i]);
  194. err = request_irq(IRQ_IXP4XX_QM1, qmgr_irq1, 0,
  195. "IXP4xx Queue Manager", NULL);
  196. if (err) {
  197. printk(KERN_ERR "qmgr: failed to request IRQ%i\n",
  198. IRQ_IXP4XX_QM1);
  199. goto error_irq;
  200. }
  201. used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */
  202. spin_lock_init(&qmgr_lock);
  203. printk(KERN_INFO "IXP4xx Queue Manager initialized.\n");
  204. return 0;
  205. error_irq:
  206. iounmap(qmgr_regs);
  207. error_map:
  208. release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
  209. return err;
  210. }
  211. static void qmgr_remove(void)
  212. {
  213. free_irq(IRQ_IXP4XX_QM1, NULL);
  214. synchronize_irq(IRQ_IXP4XX_QM1);
  215. iounmap(qmgr_regs);
  216. release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
  217. }
  218. module_init(qmgr_init);
  219. module_exit(qmgr_remove);
  220. MODULE_LICENSE("GPL v2");
  221. MODULE_AUTHOR("Krzysztof Halasa");
  222. EXPORT_SYMBOL(qmgr_regs);
  223. EXPORT_SYMBOL(qmgr_set_irq);
  224. EXPORT_SYMBOL(qmgr_enable_irq);
  225. EXPORT_SYMBOL(qmgr_disable_irq);
  226. EXPORT_SYMBOL(qmgr_request_queue);
  227. EXPORT_SYMBOL(qmgr_release_queue);