same here no printf use dev_dbg or pr_debug On 21:55 Sun 07 Apr , Krzysztof Halasa wrote: > Signed-off-by: Krzysztof Hałasa <khc@xxxxxxxxx> > > diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig > index e69de29..9244be9 100644 > --- a/arch/arm/mach-ixp4xx/Kconfig > +++ b/arch/arm/mach-ixp4xx/Kconfig > @@ -0,0 +1,9 @@ > +if ARCH_IXP4XX > + > +config IXP4XX_QMGR > + tristate "IXP4xx Queue Manager support" > + help > + This driver supports IXP4xx built-in hardware queue manager > + and is required by the Ethernet driver. > + > +endif > diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile > index d8a3d7f..09a0d63 100644 > --- a/arch/arm/mach-ixp4xx/Makefile > +++ b/arch/arm/mach-ixp4xx/Makefile > @@ -1 +1,2 @@ > obj-y += generic.o > +obj-$(CONFIG_IXP4XX_QMGR) += qmgr.o > diff --git a/arch/arm/mach-ixp4xx/include/mach/qmgr.h b/arch/arm/mach-ixp4xx/include/mach/qmgr.h > new file mode 100644 > index 0000000..4e9b8d4 > --- /dev/null > +++ b/arch/arm/mach-ixp4xx/include/mach/qmgr.h > @@ -0,0 +1,164 @@ > +/* > + * Copyright (C) 2007 Krzysztof Halasa <khc@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 > + * as published by the Free Software Foundation. > + */ > + > +#ifndef IXP4XX_QMGR_H > +#define IXP4XX_QMGR_H > + > +#include <common.h> > +#include <mach/ixp4xx-regs.h> > +#include <asm/io.h> > + > +#define DEBUG_QMGR 0 > + > +#define HALF_QUEUES 32 > +#define QUEUES 64 > +#define MAX_QUEUE_LENGTH 4 /* in dwords */ > + > +#define QUEUE_STAT1_EMPTY 1 /* queue status bits */ > +#define QUEUE_STAT1_NEARLY_EMPTY 2 > +#define QUEUE_STAT1_NEARLY_FULL 4 > +#define QUEUE_STAT1_FULL 8 > +#define QUEUE_STAT2_UNDERFLOW 1 > +#define QUEUE_STAT2_OVERFLOW 2 > + > +#define QUEUE_WATERMARK_0_ENTRIES 0 > +#define QUEUE_WATERMARK_1_ENTRY 1 > +#define QUEUE_WATERMARK_2_ENTRIES 2 > +#define QUEUE_WATERMARK_4_ENTRIES 3 > +#define QUEUE_WATERMARK_8_ENTRIES 4 > +#define QUEUE_WATERMARK_16_ENTRIES 5 > +#define QUEUE_WATERMARK_32_ENTRIES 6 > +#define QUEUE_WATERMARK_64_ENTRIES 7 > + > +/* queue interrupt request conditions */ > +#define QUEUE_IRQ_SRC_EMPTY 0 > +#define QUEUE_IRQ_SRC_NEARLY_EMPTY 1 > +#define QUEUE_IRQ_SRC_NEARLY_FULL 2 > +#define QUEUE_IRQ_SRC_FULL 3 > +#define QUEUE_IRQ_SRC_NOT_EMPTY 4 > +#define QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY 5 > +#define QUEUE_IRQ_SRC_NOT_NEARLY_FULL 6 > +#define QUEUE_IRQ_SRC_NOT_FULL 7 > + > +struct qmgr_regs { > + u32 acc[QUEUES][MAX_QUEUE_LENGTH]; /* 0x000 - 0x3FF */ > + u32 stat1[4]; /* 0x400 - 0x40F */ > + u32 stat2[2]; /* 0x410 - 0x417 */ > + u32 statne_h; /* 0x418 - queue nearly empty */ > + u32 statf_h; /* 0x41C - queue full */ > + u32 irqsrc[4]; /* 0x420 - 0x42F IRC source */ > + u32 irqen[2]; /* 0x430 - 0x437 IRQ enabled */ > + u32 irqstat[2]; /* 0x438 - 0x43F - IRQ access only */ > + u32 reserved[1776]; > + u32 sram[2048]; /* 0x2000 - 0x3FFF - config and buffer */ > +}; > + > +static const struct qmgr_regs *qmgr_regs = (struct qmgr_regs *)IXP4XX_QMGR_BASE; > + > +void qmgr_set_irq(unsigned int queue, int src, > + void (*handler)(void *pdev), void *pdev); > +void qmgr_enable_irq(unsigned int queue); > +void qmgr_disable_irq(unsigned int queue); > + > +/* request_ and release_queue() must be called from non-IRQ context */ > + > +#if DEBUG_QMGR > +extern char qmgr_queue_descs[HALF_QUEUES][32]; > + > +void qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, > + unsigned int nearly_empty_watermark, > + unsigned int nearly_full_watermark, > + const char *desc_format, const char* name); > +#else > +void __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, > + unsigned int nearly_empty_watermark, > + unsigned int nearly_full_watermark); > +#define qmgr_request_queue(queue, len, nearly_empty_watermark, \ > + nearly_full_watermark, desc_format, name) \ > + __qmgr_request_queue(queue, len, nearly_empty_watermark, \ > + nearly_full_watermark) > +#endif > + > +void qmgr_release_queue(unsigned int queue); > + > + > +static inline void qmgr_put_entry(unsigned int queue, u32 val) > +{ > +#if DEBUG_QMGR > + BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */ > + > + fprintf(stderr, "Queue %s(%i) put %X\n", > + qmgr_queue_descs[queue], queue, val); > +#endif > + __raw_writel(val, &qmgr_regs->acc[queue][0]); > +} > + > +static inline u32 qmgr_get_entry(unsigned int queue) > +{ > + u32 val; > + val = __raw_readl(&qmgr_regs->acc[queue][0]); > +#if DEBUG_QMGR > + BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */ > + > + fprintf(stderr, "Queue %s(%i) get %X\n", > + qmgr_queue_descs[queue], queue, val); > +#endif > + return val; > +} > + > +static inline int __qmgr_get_stat1(unsigned int queue) > +{ > + return (__raw_readl(&qmgr_regs->stat1[queue >> 3]) > + >> ((queue & 7) << 2)) & 0xF; > +} > + > +/** > + * qmgr_stat_empty() - checks if a hardware queue is empty > + * @queue: queue number > + * > + * Returns non-zero value if the queue is empty. > + */ > +static inline int qmgr_stat_empty(unsigned int queue) > +{ > + return __qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY; > +} > + > +/** > + * qmgr_stat_below_low_watermark() - checks if a queue is below low watermark > + * @queue: queue number > + * > + * Returns non-zero value if the queue is below low watermark. > + */ > +static inline int qmgr_stat_below_low_watermark(unsigned int queue) > +{ > + return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY; > +} > + > +/** > + * qmgr_stat_above_high_watermark() - checks if a queue is above high watermark > + * @queue: queue number > + * > + * Returns non-zero value if the queue is above high watermark > + */ > +static inline int qmgr_stat_above_high_watermark(unsigned int queue) > +{ > + return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL; > +} > + > +/** > + * qmgr_stat_full() - checks if a hardware queue is full > + * @queue: queue number > + * > + * Returns non-zero value if the queue is full. > + */ > +static inline int qmgr_stat_full(unsigned int queue) > +{ > + return __qmgr_get_stat1(queue) & QUEUE_STAT1_FULL; > +} > + > +#endif > diff --git a/arch/arm/mach-ixp4xx/qmgr.c b/arch/arm/mach-ixp4xx/qmgr.c > new file mode 100644 > index 0000000..81b6522 > --- /dev/null > +++ b/arch/arm/mach-ixp4xx/qmgr.c > @@ -0,0 +1,259 @@ > +/* > + * Intel IXP4xx Queue Manager driver for Linux > + * > + * Copyright (C) 2007 Krzysztof Halasa <khc@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 > + * as published by the Free Software Foundation. > + */ > + > +#include <init.h> > +#include <errno.h> > +#include <mach/qmgr.h> > + > +static u32 used_sram_bitmap[4]; /* 128 16-dword pages */ > + > +#if DEBUG_QMGR > +char qmgr_queue_descs[HALF_QUEUES][32]; > +#endif > + > +#ifdef CONFIG_USE_IRQ > + > +static void (*irq_handlers[HALF_QUEUES])(void *pdev); > +static void *irq_pdevs[HALF_QUEUES]; > + > +void qmgr_set_irq(unsigned int queue, int src, > + void (*handler)(void *pdev), void *pdev) > +{ > + const u32 *reg; > + int bit; > + BUG_ON(src > QUEUE_IRQ_SRC_NOT_FULL); > + reg = &qmgr_regs->irqsrc[queue >> 3]; /* 8 queues per u32 */ > + 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; > +} > + > + > +static void qmgr_irq1_a0(void *data) > +{ > + int i; > + u32 en_bitmap, src, stat; > + > + /* ACK - it may clear any bits so don't rely on it */ > + __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[0]); > + > + en_bitmap = qmgr_regs->irqen[0]; > + while (en_bitmap) { > + i = fls(en_bitmap) - 1; /* number of the last "low" queue */ > + en_bitmap &= ~BIT(i); > + src = qmgr_regs->irqsrc[i >> 3]; > + stat = qmgr_regs->stat1[i >> 3]; > + if (src & 4) /* the IRQ condition is inverted */ > + stat = ~stat; > + if (stat & BIT(src & 3)) > + irq_handlers[i](irq_pdevs[i]); > + } > +} > + > + > +static void qmgr_irq1(void *data) > +{ > + int i; > + u32 req_bitmap = __raw_readl(&qmgr_regs->irqstat[0]); > + > + if (!req_bitmap) > + return; > + __raw_writel(req_bitmap, &qmgr_regs->irqstat[0]); /* ACK */ > + > + while (req_bitmap) { > + i = fls(req_bitmap) - 1; /* number of the last queue */ > + req_bitmap &= ~BIT(i); > + irq_handlers[i](irq_pdevs[i]); > + } > +} > + > + > +void qmgr_enable_irq(unsigned int queue) > +{ > + u32 mask = 1 << queue; > + > + __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | mask, > + &qmgr_regs->irqen[0]); > +} > + > +void qmgr_disable_irq(unsigned int queue) > +{ > + u32 mask = 1 << queue; > + > + __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~mask, > + &qmgr_regs->irqen[0]); > + __raw_writel(mask, &qmgr_regs->irqstat[0]); /* clear */ > +} > + > +#endif /* CONFIG_USE_IRQ */ > + > +static inline void shift_mask(u32 *mask) > +{ > + mask[3] = mask[3] << 1 | mask[2] >> 31; > + mask[2] = mask[2] << 1 | mask[1] >> 31; > + mask[1] = mask[1] << 1 | mask[0] >> 31; > + mask[0] <<= 1; > +} > + > +#if DEBUG_QMGR > +void qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, > + unsigned int nearly_empty_watermark, > + unsigned int nearly_full_watermark, > + const char *desc_format, const char* name) > +#else > +void __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, > + unsigned int nearly_empty_watermark, > + unsigned int nearly_full_watermark) > +#endif ?? > +{ > + u32 cfg, addr = 0, mask[4]; /* in 16-dwords */ > + > + BUG_ON(queue >= HALF_QUEUES); > + BUG_ON((nearly_empty_watermark | nearly_full_watermark) & ~7); > + > + switch (len) { > + case 16: > + cfg = 0 << 24; > + mask[0] = 0x1; > + break; > + case 32: > + cfg = 1 << 24; > + mask[0] = 0x3; > + break; > + case 64: > + cfg = 2 << 24; > + mask[0] = 0xF; > + break; > + case 128: > + cfg = 3 << 24; > + mask[0] = 0xFF; > + break; > + default: > + BUG(); > + } > + > + cfg |= nearly_empty_watermark << 26; > + cfg |= nearly_full_watermark << 29; > + len /= 16; /* in 16-dwords: 1, 2, 4 or 8 */ > + mask[1] = mask[2] = mask[3] = 0; > + > + BUG_ON(__raw_readl(&qmgr_regs->sram[queue])); > + > + while (1) { > + if (!(used_sram_bitmap[0] & mask[0]) && > + !(used_sram_bitmap[1] & mask[1]) && > + !(used_sram_bitmap[2] & mask[2]) && > + !(used_sram_bitmap[3] & mask[3])) > + break; /* found free space */ > + > + addr++; > + shift_mask(mask); > + if (addr + len > ARRAY_SIZE(qmgr_regs->sram)) { > + fprintf(stderr, "qmgr: no free SRAM space for" > + " queue %i\n", queue); > + BUG(); > + } > + } > + > + used_sram_bitmap[0] |= mask[0]; > + used_sram_bitmap[1] |= mask[1]; > + used_sram_bitmap[2] |= mask[2]; > + used_sram_bitmap[3] |= mask[3]; > + __raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]); > +#if DEBUG_QMGR > + /* no snprintf() */ > + sprintf(qmgr_queue_descs[queue], desc_format, name); > + fprintf(stderr, "qmgr: requested queue %s(%i) addr = 0x%02X\n", > + qmgr_queue_descs[queue], queue, addr); > +#endif > +} > + > +void qmgr_release_queue(unsigned int queue) > +{ > + u32 cfg, addr, mask[4]; > + > + BUG_ON(queue >= HALF_QUEUES); /* not in valid range */ > + > + cfg = __raw_readl(&qmgr_regs->sram[queue]); > + addr = (cfg >> 14) & 0xFF; > + > + BUG_ON(!addr); /* not requested */ > + > + switch ((cfg >> 24) & 3) { > + case 0: mask[0] = 0x1; break; > + case 1: mask[0] = 0x3; break; > + case 2: mask[0] = 0xF; break; > + case 3: mask[0] = 0xFF; break; > + } > + > + mask[1] = mask[2] = mask[3] = 0; > + > + while (addr--) > + shift_mask(mask); > + > +#if DEBUG_QMGR > + fprintf(stderr, "qmgr: releasing queue %s(%i)\n", > + qmgr_queue_descs[queue], queue); > + qmgr_queue_descs[queue][0] = '\x0'; > +#endif > + __raw_writel(0, &qmgr_regs->sram[queue]); > + > + used_sram_bitmap[0] &= ~mask[0]; > + used_sram_bitmap[1] &= ~mask[1]; > + used_sram_bitmap[2] &= ~mask[2]; > + used_sram_bitmap[3] &= ~mask[3]; > +#ifdef CONFIG_USE_IRQ > + irq_handlers[queue] = NULL; /* catch IRQ bugs */ > +#endif > + > + while ((addr = qmgr_get_entry(queue))) > + fprintf(stderr, "qmgr: released queue %i not empty: 0x%08X\n", > + queue, addr); > +} > + > +static int __init qmgr_init(void) > +{ > + int i; > +#ifdef CONFIG_USE_IRQ > + interrupt_handler_t *handler; we have no irq support on barebox > +#endif > + > + /* reset qmgr registers */ > + for (i = 0; i < 4; i++) { > + __raw_writel(0x33333333, &qmgr_regs->stat1[i]); > + __raw_writel(0, &qmgr_regs->irqsrc[i]); > + } > + for (i = 0; i < 2; i++) { > + __raw_writel(0, &qmgr_regs->stat2[i]); > + __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[i]); /* clear */ > + __raw_writel(0, &qmgr_regs->irqen[i]); > + } > + > + __raw_writel(0xFFFFFFFF, &qmgr_regs->statne_h); > + __raw_writel(0, &qmgr_regs->statf_h); > + > + for (i = 0; i < QUEUES; i++) > + __raw_writel(0, &qmgr_regs->sram[i]); > + > +#ifdef CONFIG_USE_IRQ > + if (cpu_is_ixp42x_rev_a0()) > + handler = qmgr_irq1_a0; > + else > + handler = qmgr_irq1; > + > + irq_install_handler(IXP425_QM1_IRQ, handler, NULL); > +#endif > + used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */ > + return 0; > +} > + > +coredevice_initcall(qmgr_init); > > _______________________________________________ > barebox mailing list > barebox@xxxxxxxxxxxxxxxxxxx > http://lists.infradead.org/mailman/listinfo/barebox _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox