[PATCH] ARM: Support for IXP4xx hardware Queue Manager.

Jean-Christophe PLAGNIOL-VILLARD plagnioj at jcrosoft.com
Mon Apr 8 03:31:50 EDT 2013


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 at pm.waw.pl>
> 
> 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 at pm.waw.pl>
> + *
> + * 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 at pm.waw.pl>
> + *
> + * 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 at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox



More information about the barebox mailing list