LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] [V2] powerpc: Xilinx: PS2: Added new XPS PS2 driver
From: Grant Likely @ 2008-07-03 17:37 UTC (permalink / raw)
  To: John Linn; +Cc: Sadanand, dmitry.torokhov, linuxppc-dev, linux-input
In-Reply-To: <20080703164235.37739A006B@mail196-wa4.bigfish.com>

On Thu, Jul 03, 2008 at 09:42:31AM -0700, John Linn wrote:
> Added a new driver for Xilinx XPS PS2 IP. This driver is
> a flat driver to better match the Linux driver pattern.
> 
> Signed-off-by: Sadanand <sadanan@xilinx.com>
> Signed-off-by: John Linn <john.linn@xilinx.com>
> ---
> V2
> 	Updated the driver based on feedback from Dmitry, Peter, and Grant.
> 	We believe Montavista copyright is still valid.
> 
>  drivers/input/serio/Kconfig      |    5 +
>  drivers/input/serio/Makefile     |    1 +
>  drivers/input/serio/xilinx_ps2.c |  448 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 454 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/input/serio/xilinx_ps2.c
> 
> diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
> index ec4b661..0e62b39 100644
> --- a/drivers/input/serio/Kconfig
> +++ b/drivers/input/serio/Kconfig
> @@ -190,4 +190,9 @@ config SERIO_RAW
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called serio_raw.
>  
> +config SERIO_XILINX_XPS_PS2
> +	tristate "Xilinx XPS PS/2 Controller Support"
> +	help
> +	  This driver supports XPS PS/2 IP from Xilinx EDK.
> +
>  endif
> diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
> index 38b8868..9b6c813 100644
> --- a/drivers/input/serio/Makefile
> +++ b/drivers/input/serio/Makefile
> @@ -21,3 +21,4 @@ obj-$(CONFIG_SERIO_PCIPS2)	+= pcips2.o
>  obj-$(CONFIG_SERIO_MACEPS2)	+= maceps2.o
>  obj-$(CONFIG_SERIO_LIBPS2)	+= libps2.o
>  obj-$(CONFIG_SERIO_RAW)		+= serio_raw.o
> +obj-$(CONFIG_SERIO_XILINX_XPS_PS2)	+= xilinx_ps2.o
> diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c
> new file mode 100644
> index 0000000..152bf2c
> --- /dev/null
> +++ b/drivers/input/serio/xilinx_ps2.c
> @@ -0,0 +1,448 @@
> +/*
> + * Xilinx XPS PS/2 device driver
> + *
> + * (c) 2005 MontaVista Software, Inc.
> + * (c) 2008 Xilinx, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * option) any later version.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +
> +#include <linux/module.h>
> +#include <linux/serio.h>
> +#include <linux/interrupt.h>
> +#include <linux/errno.h>
> +#include <linux/init.h>
> +#include <linux/list.h>
> +#include <linux/io.h>
> +
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +
> +#define DRIVER_NAME		"xilinx_ps2"
> +
> +/* Register offsets for the xps2 device */
> +#define XPS2_SRST_OFFSET	0x00000000 /* Software Reset register */
> +#define XPS2_STATUS_OFFSET	0x00000004 /* Status register */
> +#define XPS2_RX_DATA_OFFSET	0x00000008 /* Receive Data register */
> +#define XPS2_TX_DATA_OFFSET	0x0000000C /* Transmit Data register */
> +#define XPS2_GIER_OFFSET	0x0000002C /* Global Interrupt Enable reg */
> +#define XPS2_IPISR_OFFSET	0x00000030 /* Interrupt Status register */
> +#define XPS2_IPIER_OFFSET	0x00000038 /* Interrupt Enable register */
> +
> +/* Reset Register Bit Definitions */
> +#define XPS2_SRST_RESET		0x0000000A /* Software Reset  */
> +
> +/* Status Register Bit Positions */
> +#define XPS2_STATUS_RX_FULL	0x00000001 /* Receive Full  */
> +#define XPS2_STATUS_TX_FULL	0x00000002 /* Transmit Full  */
> +
> +/* Bit definitions for ISR/IER registers. Both the registers have the same bit
> + * definitions and are only defined once. */
> +#define XPS2_IPIXR_WDT_TOUT	0x00000001 /* Watchdog Timeout Interrupt */
> +#define XPS2_IPIXR_TX_NOACK	0x00000002 /* Transmit No ACK Interrupt */
> +#define XPS2_IPIXR_TX_ACK	0x00000004 /* Transmit ACK (Data) Interrupt */
> +#define XPS2_IPIXR_RX_OVF	0x00000008 /* Receive Overflow Interrupt */
> +#define XPS2_IPIXR_RX_ERR	0x00000010 /* Receive Error Interrupt */
> +#define XPS2_IPIXR_RX_FULL	0x00000020 /* Receive Data Interrupt */
> +
> +/* Mask for all the Transmit Interrupts */
> +#define XPS2_IPIXR_TX_ALL	(XPS2_IPIXR_TX_NOACK | XPS2_IPIXR_TX_ACK)
> +
> +/* Mask for all the Receive Interrupts */
> +#define XPS2_IPIXR_RX_ALL	(XPS2_IPIXR_RX_OVF | XPS2_IPIXR_RX_ERR |  \
> +					XPS2_IPIXR_RX_FULL)
> +
> +/* Mask for all the Interrupts */
> +#define XPS2_IPIXR_ALL		(XPS2_IPIXR_TX_ALL | XPS2_IPIXR_RX_ALL |  \
> +					XPS2_IPIXR_WDT_TOUT)
> +
> +/* Global Interrupt Enable mask */
> +#define XPS2_GIER_GIE_MASK	0x80000000
> +
> +struct xps2data {
> +	int irq;
> +	u32 phys_addr;
> +	u32 remap_size;
> +	spinlock_t lock;
> +	u8 rxb;				/* Rx buffer */
> +	void __iomem *base_address;	/* virt. address of control registers */
> +	unsigned int dfl;
> +	struct serio serio;		/* serio */
> +	struct mutex cfg_mutex;
> +};
> +
> +/************************************/
> +/* XPS PS/2 data transmission calls */
> +/************************************/
> +
> +/*
> + * xps2_send() sends the specified byte of data to the PS/2 port.
> + */
> +static int xps2_send(struct xps2data *drvdata, u8 *byte)
> +{
> +	u32 sr;
> +	u32 ier;
> +	int retval = -1;
> +
> +	/* Enter a critical region by disabling the PS/2 transmit interrupts to
> +	 * allow this call to stop a previous operation that may be interrupt
> +	 * driven. Only stop the transmit interrupt since this critical region
> +	 * is not really exited in the normal manner */
> +	ier = in_be32(drvdata->base_address + XPS2_IPIER_OFFSET);
> +	ier &= (~(XPS2_IPIXR_TX_ALL & XPS2_IPIXR_ALL));
> +	out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, ier);
> +
> +	/* If the PS/2 transmitter is empty send a byte of data */
> +	sr = in_be32(drvdata->base_address + XPS2_STATUS_OFFSET);
> +	if ((sr & XPS2_STATUS_TX_FULL) == 0) {
> +		out_be32(drvdata->base_address + XPS2_TX_DATA_OFFSET, *byte);
> +		retval = 0;
> +	}
> +
> +	/* Enable the TX interrupts to track the status of the transmission */
> +	ier = in_be32(drvdata->base_address + XPS2_IPIER_OFFSET);
> +	ier |= (XPS2_IPIXR_TX_ALL | XPS2_IPIXR_WDT_TOUT);
> +	out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, ier);

If this is a critical region, Wouldn't it be more appropriate to use a
spinlock with spin_lock_irqsave()/spin_unlock_irqrestore()  here?

...

Actually, looking deeper into the file; xps2_send() is already protected
with a spin lock w/ irqsave.  Why do interrupts need to be disabled
at all?  It looks like this whole routine could be collapsed into a
about three lines of code in the sxps2_write() function.

> +
> +	return retval;
> +}
> +
> +/*
> + * xps2_recv() will attempt to receive a byte of data from the PS/2 port.
> + */
> +static int xps2_recv(struct xps2data *drvdata, u8 *byte)
> +{
> +	u32 sr;
> +	int retval = -1;
> +
> +	/* If there is data available in the PS/2 receiver, read it */
> +	sr = in_be32(drvdata->base_address + XPS2_STATUS_OFFSET);
> +	if (sr & XPS2_STATUS_RX_FULL) {
> +		*byte = in_be32(drvdata->base_address + XPS2_RX_DATA_OFFSET);
> +		retval = 0;
> +	}
> +
> +	return retval;
> +}
> +
> +/*********************/
> +/* Interrupt handler */
> +/*********************/
> +static irqreturn_t xps2_interrupt(int irq, void *dev_id)
> +{
> +	struct xps2data *drvdata = (struct xps2data *)dev_id;
> +	u32 intr_sr;
> +	u32 ier;
> +	u8 c;
> +	u8 retval;
> +
> +	/* Get the PS/2 interrupts and clear them */
> +	intr_sr = in_be32(drvdata->base_address + XPS2_IPISR_OFFSET);
> +	out_be32(drvdata->base_address + XPS2_IPISR_OFFSET, intr_sr);
> +
> +	/* Check which interrupt is active */
> +	if (intr_sr & XPS2_IPIXR_RX_OVF) {
> +		printk(KERN_ERR "%s: receive overrun error\n",
> +			drvdata->serio.name);
> +	}
> +
> +	if (intr_sr & XPS2_IPIXR_RX_ERR)
> +		drvdata->dfl |= SERIO_PARITY;
> +
> +	if (intr_sr & (XPS2_IPIXR_TX_NOACK | XPS2_IPIXR_WDT_TOUT))
> +		drvdata->dfl |= SERIO_TIMEOUT;
> +
> +	if (intr_sr & XPS2_IPIXR_RX_FULL) {
> +		retval = xps2_recv(drvdata, &drvdata->rxb);
> +
> +		/* Error, if a byte is not received */
> +		if (retval) {
> +			printk(KERN_ERR
> +				"%s: wrong rcvd byte count (%d)\n",
> +				drvdata->serio.name, retval);
> +		} else {
> +			c = drvdata->rxb;
> +			serio_interrupt(&drvdata->serio, c, drvdata->dfl);
> +			drvdata->dfl = 0;
> +		}
> +	}
> +
> +	if (intr_sr & XPS2_IPIXR_TX_ACK) {
> +
> +		/* Disable the TX interrupts after the transmission is
> +		 * complete */
> +		ier = in_be32(drvdata->base_address + XPS2_IPIER_OFFSET);
> +		ier &= (~(XPS2_IPIXR_TX_ACK & XPS2_IPIXR_ALL));
> +		out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, ier);
> +		drvdata->dfl = 0;
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +/*******************/
> +/* serio callbacks */
> +/*******************/
> +
> +/*
> + *	sxps2_write() - sends a byte out through the PS/2 interface.
> + */
> +static int sxps2_write(struct serio *pserio, unsigned char c)
> +{
> +	struct xps2data *drvdata = pserio->port_data;
> +	unsigned long flags;
> +	int retval;
> +
> +	spin_lock_irqsave(&drvdata->lock, flags);
> +	retval = xps2_send(drvdata, &c);
> +	spin_unlock_irqrestore(&drvdata->lock, flags);
> +
> +	return retval;
> +}
> +
> +/*
> + * sxps2_open() is called when a port is open by the higher layer.
> + */
> +static int sxps2_open(struct serio *pserio)
> +{
> +	struct xps2data *drvdata = pserio->port_data;
> +	int retval;
> +
> +	retval = request_irq(drvdata->irq, &xps2_interrupt, 0,
> +				DRIVER_NAME, drvdata);
> +	if (retval) {
> +		printk(KERN_ERR
> +			"%s: Couldn't allocate interrupt %d\n",
> +			drvdata->serio.name, drvdata->irq);
> +		return retval;
> +	}
> +
> +	/* start reception by enabling the interrupts */
> +	out_be32(drvdata->base_address + XPS2_GIER_OFFSET, XPS2_GIER_GIE_MASK);
> +	out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, XPS2_IPIXR_RX_ALL);
> +	(void)xps2_recv(drvdata, &drvdata->rxb);
> +
> +	return 0;		/* success */
> +}
> +
> +/*
> + * sxps2_close() frees the interrupt.
> + */
> +static void sxps2_close(struct serio *pserio)
> +{
> +	struct xps2data *drvdata = pserio->port_data;
> +
> +	/* Disable the PS2 interrupts */
> +	out_be32(drvdata->base_address + XPS2_GIER_OFFSET, 0x00);
> +	out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, 0x00);
> +	free_irq(drvdata->irq, drvdata);
> +}
> +
> +/******************************/
> +/* Device initialization code */
> +/******************************/
> +
> +/*
> + * xps2_initialize() initializes the Xilinx PS/2 device.
> + */
> +static int xps2_initialize(struct xps2data *drvdata)
> +{
> +	/* Disable all the interrupts, just in case */
> +	out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, 0);
> +
> +	/* Reset the PS2 device and abort any current transaction, to make sure
> +	 * we have the PS2 in a good state */
> +	out_be32(drvdata->base_address + XPS2_SRST_OFFSET, XPS2_SRST_RESET);
> +
> +	return 0;
> +}

This function is only called by xps2_setup() and should probably be
collapsed into it.

> +
> +/*
> + * XPS PS2 device setup code.
> + */
> +static int xps2_setup(struct device *dev, int id, struct resource *regs_res,
> +			struct resource *irq_res)
> +{
> +	struct xps2data *drvdata;
> +	struct serio *serio;
> +	unsigned long remap_size;
> +	int retval;
> +
> +	if (!dev)
> +		return -EINVAL;
> +
> +	drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL);
> +	if (!drvdata) {
> +		dev_err(dev, "Couldn't allocate device private record\n");
> +		return -ENOMEM;
> +	}
> +	spin_lock_init(&drvdata->lock);
> +	mutex_init(&drvdata->cfg_mutex);
> +	dev_set_drvdata(dev, drvdata);
> +
> +	if (!regs_res || !irq_res) {
> +		dev_err(dev, "IO resource(s) not found\n");
> +		retval = -EFAULT;
> +		goto failed1;
> +	}
> +
> +	drvdata->irq = irq_res->start;
> +	remap_size = regs_res->end - regs_res->start + 1;
> +	if (!request_mem_region(regs_res->start, remap_size, DRIVER_NAME)) {
> +
> +		dev_err(dev, "Couldn't lock memory region at 0x%08X\n",
> +			(unsigned int)regs_res->start);
> +		retval = -EBUSY;
> +		goto failed1;
> +	}
> +
> +	/* Fill in configuration data and add them to the list */
> +	drvdata->phys_addr = regs_res->start;
> +	drvdata->remap_size = remap_size;
> +	drvdata->base_address = ioremap(regs_res->start, remap_size);
> +	if (drvdata->base_address == NULL) {
> +
> +		dev_err(dev, "Couldn't ioremap memory at 0x%08X\n",
> +			(unsigned int)regs_res->start);
> +		retval = -EFAULT;
> +		goto failed2;
> +	}
> +
> +	/* Initialize the PS/2 interface */
> +	mutex_lock(&drvdata->cfg_mutex);
> +	if (xps2_initialize(drvdata)) {
> +		mutex_unlock(&drvdata->cfg_mutex);
> +		dev_err(dev, "Could not initialize device\n");
> +		retval = -ENODEV;
> +		goto failed3;
> +	}
> +	mutex_unlock(&drvdata->cfg_mutex);

This is the only user of cfg_mutex.  The IRQ isn't registered yet, and
the driver isn't registered with the serio layer either so you can just
drop the mutex entirely.

> +
> +	dev_info(dev, "Xilinx PS2 at 0x%08X mapped to 0x%08X, irq=%d\n",
> +		drvdata->phys_addr, (u32)drvdata->base_address, drvdata->irq);
> +
> +	serio = &drvdata->serio;
> +	serio->id.type = SERIO_8042;
> +	serio->write = sxps2_write;
> +	serio->open = sxps2_open;
> +	serio->close = sxps2_close;
> +	serio->port_data = drvdata;
> +	serio->dev.parent = dev;
> +	snprintf(drvdata->serio.name, sizeof(serio->name),
> +		 "Xilinx XPS PS/2 Port #%d", id);
> +	snprintf(drvdata->serio.phys, sizeof(serio->phys),
> +		 "xilinxps2/serio%d", id);
> +	serio_register_port(serio);
> +
> +	return 0;		/* success */
> +
> +failed3:
> +	iounmap(drvdata->base_address);
> +
> +failed2:
> +	release_mem_region(regs_res->start, remap_size);
> +
> +failed1:
> +	kfree(drvdata);
> +	dev_set_drvdata(dev, NULL);
> +
> +	return retval;
> +}
> +
> +/***************************/
> +/* OF Platform Bus Support */
> +/***************************/
> +
> +static int __devinit xps2_of_probe(struct of_device *ofdev, const struct
> +				   of_device_id * match)
> +{
> +	struct resource r_irq_struct;
> +	struct resource r_mem_struct;
> +	struct resource *r_irq = &r_irq_struct;	/* Interrupt resources */
> +	struct resource *r_mem = &r_mem_struct;	/* IO mem resources */

This is very vebose; do this instead:

+	struct resource r_irq;
+	struct resource r_mem;
[...]
+	rc = of_address_to_resource(ofdev->node, 0, &r_mem);
[...]
+	rc = of_irq_to_resource(ofdev->node, 0, &r_irq);
[...]
+	return xps2_setup(&ofdev->dev, id ? *id : -1, &r_mem, &r_irq);

> +	int rc = 0;
> +	const unsigned int *id;
> +
> +	printk(KERN_INFO "Device Tree Probing \'%s\'\n",
> +			ofdev->node->name);
> +
> +	/* Get iospace for the device */
> +	rc = of_address_to_resource(ofdev->node, 0, r_mem);
> +	if (rc) {
> +		dev_warn(&ofdev->dev, "invalid address\n");

Probably should be dev_err(...);

> +		return rc;
> +	}
> +
> +	/* Get IRQ for the device */
> +	rc = of_irq_to_resource(ofdev->node, 0, r_irq);
> +	if (rc == NO_IRQ) {
> +		dev_warn(&ofdev->dev, "no IRQ found\n");

ditto

> +		return rc;
> +	}
> +
> +	id = of_get_property(ofdev->node, "port-number", NULL);

Drop this line.  port-number is a poor way to specify a global value.
If really needed, you should search the aliases node for a matching 
property to get the id.  Otherwise, you should probably fall back to
using the physical address of the device instead of -1.  At least it
guarantees that the value is unique.

> +	return xps2_setup(&ofdev->dev, id ? *id : -1, r_mem, r_irq);
> +}
> +
> +static int __devexit xps2_of_remove(struct of_device *of_dev)
> +{
> +	struct xps2data *drvdata;
> +	struct device *dev;
> +
> +	dev = &of_dev->dev;
> +	if (!dev)
> +		return -EINVAL;
> +
> +	drvdata = (struct xps2data *)dev_get_drvdata(dev);
> +
> +	serio_unregister_port(&drvdata->serio);
> +
> +	iounmap(drvdata->base_address);
> +
> +	release_mem_region(drvdata->phys_addr, drvdata->remap_size);
> +
> +	kfree(drvdata);
> +	dev_set_drvdata(dev, NULL);
> +
> +	return 0;		/* success */
> +}
> +
> +/* Match table for of_platform binding */
> +static struct of_device_id __devinitdata xps2_of_match[] = {

__devinitdata in the wrong place; should be:

+static struct of_device_id xps2_of_match[] __devinitdata = {

> +	{ .compatible = "xlnx,xps-ps2-1.00.a", },
> +	{ /* end of list */ },
> +};
> +MODULE_DEVICE_TABLE(of, xps2_of_match);
> +
> +static struct of_platform_driver xps2_of_driver = {
> +	.name		= DRIVER_NAME,
> +	.match_table	= xps2_of_match,
> +	.probe		= xps2_of_probe,
> +	.remove		= __devexit_p(xps2_of_remove),
> +};
> +
> +static int __init xps2_init(void)
> +{
> +	return of_register_platform_driver(&xps2_of_driver);
> +}
> +
> +static void __exit xps2_cleanup(void)
> +{
> +	of_unregister_platform_driver(&xps2_of_driver);
> +}
> +
> +module_init(xps2_init);
> +module_exit(xps2_cleanup);
> +
> +MODULE_AUTHOR("Xilinx, Inc.");
> +MODULE_DESCRIPTION("Xilinx XPS PS/2 driver");
> +MODULE_LICENSE("GPL");
> +
> -- 
> 1.5.2.1
> 
> 
> 
> This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.
> 
> 

^ permalink raw reply

* Re: [PATCH] [V2] powerpc: Xilinx: PS2: Added new XPS PS2 driver
From: Dmitry Torokhov @ 2008-07-03 17:27 UTC (permalink / raw)
  To: John Linn; +Cc: Sadanand, linuxppc-dev, linux-input
In-Reply-To: <20080703164235.37739A006B@mail196-wa4.bigfish.com>

Hi John,

On Thu, Jul 03, 2008 at 09:42:31AM -0700, John Linn wrote:
> +
> +	/* Initialize the PS/2 interface */
> +	mutex_lock(&drvdata->cfg_mutex);
> +	if (xps2_initialize(drvdata)) {
> +		mutex_unlock(&drvdata->cfg_mutex);
> +		dev_err(dev, "Could not initialize device\n");
> +		retval = -ENODEV;
> +		goto failed3;
> +	}
> +	mutex_unlock(&drvdata->cfg_mutex);

The drvdata is allocated per-port and so both (there are 2 PS/2 ports,
right?) ports get their own copy of cfg_mutex. Since you are trying to
serialze access to resource shared by both ports it will not work.
The original driver-global mutex was appropriate (the only thing I
objected there was use of a counting semaphore instead of a mutex).

-- 
Dmitry

^ permalink raw reply

* [PATCH] [V2] powerpc: Xilinx: PS2: Added new XPS PS2 driver
From: John Linn @ 2008-07-03 16:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-input; +Cc: dmitry.torokhov, Sadanand, John Linn

Added a new driver for Xilinx XPS PS2 IP. This driver is
a flat driver to better match the Linux driver pattern.

Signed-off-by: Sadanand <sadanan@xilinx.com>
Signed-off-by: John Linn <john.linn@xilinx.com>
---
V2
	Updated the driver based on feedback from Dmitry, Peter, and Grant.
	We believe Montavista copyright is still valid.

 drivers/input/serio/Kconfig      |    5 +
 drivers/input/serio/Makefile     |    1 +
 drivers/input/serio/xilinx_ps2.c |  448 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 454 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/serio/xilinx_ps2.c

diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index ec4b661..0e62b39 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -190,4 +190,9 @@ config SERIO_RAW
 	  To compile this driver as a module, choose M here: the
 	  module will be called serio_raw.
 
+config SERIO_XILINX_XPS_PS2
+	tristate "Xilinx XPS PS/2 Controller Support"
+	help
+	  This driver supports XPS PS/2 IP from Xilinx EDK.
+
 endif
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 38b8868..9b6c813 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -21,3 +21,4 @@ obj-$(CONFIG_SERIO_PCIPS2)	+= pcips2.o
 obj-$(CONFIG_SERIO_MACEPS2)	+= maceps2.o
 obj-$(CONFIG_SERIO_LIBPS2)	+= libps2.o
 obj-$(CONFIG_SERIO_RAW)		+= serio_raw.o
+obj-$(CONFIG_SERIO_XILINX_XPS_PS2)	+= xilinx_ps2.o
diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c
new file mode 100644
index 0000000..152bf2c
--- /dev/null
+++ b/drivers/input/serio/xilinx_ps2.c
@@ -0,0 +1,448 @@
+/*
+ * Xilinx XPS PS/2 device driver
+ *
+ * (c) 2005 MontaVista Software, Inc.
+ * (c) 2008 Xilinx, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/serio.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/io.h>
+
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+#define DRIVER_NAME		"xilinx_ps2"
+
+/* Register offsets for the xps2 device */
+#define XPS2_SRST_OFFSET	0x00000000 /* Software Reset register */
+#define XPS2_STATUS_OFFSET	0x00000004 /* Status register */
+#define XPS2_RX_DATA_OFFSET	0x00000008 /* Receive Data register */
+#define XPS2_TX_DATA_OFFSET	0x0000000C /* Transmit Data register */
+#define XPS2_GIER_OFFSET	0x0000002C /* Global Interrupt Enable reg */
+#define XPS2_IPISR_OFFSET	0x00000030 /* Interrupt Status register */
+#define XPS2_IPIER_OFFSET	0x00000038 /* Interrupt Enable register */
+
+/* Reset Register Bit Definitions */
+#define XPS2_SRST_RESET		0x0000000A /* Software Reset  */
+
+/* Status Register Bit Positions */
+#define XPS2_STATUS_RX_FULL	0x00000001 /* Receive Full  */
+#define XPS2_STATUS_TX_FULL	0x00000002 /* Transmit Full  */
+
+/* Bit definitions for ISR/IER registers. Both the registers have the same bit
+ * definitions and are only defined once. */
+#define XPS2_IPIXR_WDT_TOUT	0x00000001 /* Watchdog Timeout Interrupt */
+#define XPS2_IPIXR_TX_NOACK	0x00000002 /* Transmit No ACK Interrupt */
+#define XPS2_IPIXR_TX_ACK	0x00000004 /* Transmit ACK (Data) Interrupt */
+#define XPS2_IPIXR_RX_OVF	0x00000008 /* Receive Overflow Interrupt */
+#define XPS2_IPIXR_RX_ERR	0x00000010 /* Receive Error Interrupt */
+#define XPS2_IPIXR_RX_FULL	0x00000020 /* Receive Data Interrupt */
+
+/* Mask for all the Transmit Interrupts */
+#define XPS2_IPIXR_TX_ALL	(XPS2_IPIXR_TX_NOACK | XPS2_IPIXR_TX_ACK)
+
+/* Mask for all the Receive Interrupts */
+#define XPS2_IPIXR_RX_ALL	(XPS2_IPIXR_RX_OVF | XPS2_IPIXR_RX_ERR |  \
+					XPS2_IPIXR_RX_FULL)
+
+/* Mask for all the Interrupts */
+#define XPS2_IPIXR_ALL		(XPS2_IPIXR_TX_ALL | XPS2_IPIXR_RX_ALL |  \
+					XPS2_IPIXR_WDT_TOUT)
+
+/* Global Interrupt Enable mask */
+#define XPS2_GIER_GIE_MASK	0x80000000
+
+struct xps2data {
+	int irq;
+	u32 phys_addr;
+	u32 remap_size;
+	spinlock_t lock;
+	u8 rxb;				/* Rx buffer */
+	void __iomem *base_address;	/* virt. address of control registers */
+	unsigned int dfl;
+	struct serio serio;		/* serio */
+	struct mutex cfg_mutex;
+};
+
+/************************************/
+/* XPS PS/2 data transmission calls */
+/************************************/
+
+/*
+ * xps2_send() sends the specified byte of data to the PS/2 port.
+ */
+static int xps2_send(struct xps2data *drvdata, u8 *byte)
+{
+	u32 sr;
+	u32 ier;
+	int retval = -1;
+
+	/* Enter a critical region by disabling the PS/2 transmit interrupts to
+	 * allow this call to stop a previous operation that may be interrupt
+	 * driven. Only stop the transmit interrupt since this critical region
+	 * is not really exited in the normal manner */
+	ier = in_be32(drvdata->base_address + XPS2_IPIER_OFFSET);
+	ier &= (~(XPS2_IPIXR_TX_ALL & XPS2_IPIXR_ALL));
+	out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, ier);
+
+	/* If the PS/2 transmitter is empty send a byte of data */
+	sr = in_be32(drvdata->base_address + XPS2_STATUS_OFFSET);
+	if ((sr & XPS2_STATUS_TX_FULL) == 0) {
+		out_be32(drvdata->base_address + XPS2_TX_DATA_OFFSET, *byte);
+		retval = 0;
+	}
+
+	/* Enable the TX interrupts to track the status of the transmission */
+	ier = in_be32(drvdata->base_address + XPS2_IPIER_OFFSET);
+	ier |= (XPS2_IPIXR_TX_ALL | XPS2_IPIXR_WDT_TOUT);
+	out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, ier);
+
+	return retval;
+}
+
+/*
+ * xps2_recv() will attempt to receive a byte of data from the PS/2 port.
+ */
+static int xps2_recv(struct xps2data *drvdata, u8 *byte)
+{
+	u32 sr;
+	int retval = -1;
+
+	/* If there is data available in the PS/2 receiver, read it */
+	sr = in_be32(drvdata->base_address + XPS2_STATUS_OFFSET);
+	if (sr & XPS2_STATUS_RX_FULL) {
+		*byte = in_be32(drvdata->base_address + XPS2_RX_DATA_OFFSET);
+		retval = 0;
+	}
+
+	return retval;
+}
+
+/*********************/
+/* Interrupt handler */
+/*********************/
+static irqreturn_t xps2_interrupt(int irq, void *dev_id)
+{
+	struct xps2data *drvdata = (struct xps2data *)dev_id;
+	u32 intr_sr;
+	u32 ier;
+	u8 c;
+	u8 retval;
+
+	/* Get the PS/2 interrupts and clear them */
+	intr_sr = in_be32(drvdata->base_address + XPS2_IPISR_OFFSET);
+	out_be32(drvdata->base_address + XPS2_IPISR_OFFSET, intr_sr);
+
+	/* Check which interrupt is active */
+	if (intr_sr & XPS2_IPIXR_RX_OVF) {
+		printk(KERN_ERR "%s: receive overrun error\n",
+			drvdata->serio.name);
+	}
+
+	if (intr_sr & XPS2_IPIXR_RX_ERR)
+		drvdata->dfl |= SERIO_PARITY;
+
+	if (intr_sr & (XPS2_IPIXR_TX_NOACK | XPS2_IPIXR_WDT_TOUT))
+		drvdata->dfl |= SERIO_TIMEOUT;
+
+	if (intr_sr & XPS2_IPIXR_RX_FULL) {
+		retval = xps2_recv(drvdata, &drvdata->rxb);
+
+		/* Error, if a byte is not received */
+		if (retval) {
+			printk(KERN_ERR
+				"%s: wrong rcvd byte count (%d)\n",
+				drvdata->serio.name, retval);
+		} else {
+			c = drvdata->rxb;
+			serio_interrupt(&drvdata->serio, c, drvdata->dfl);
+			drvdata->dfl = 0;
+		}
+	}
+
+	if (intr_sr & XPS2_IPIXR_TX_ACK) {
+
+		/* Disable the TX interrupts after the transmission is
+		 * complete */
+		ier = in_be32(drvdata->base_address + XPS2_IPIER_OFFSET);
+		ier &= (~(XPS2_IPIXR_TX_ACK & XPS2_IPIXR_ALL));
+		out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, ier);
+		drvdata->dfl = 0;
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*******************/
+/* serio callbacks */
+/*******************/
+
+/*
+ *	sxps2_write() - sends a byte out through the PS/2 interface.
+ */
+static int sxps2_write(struct serio *pserio, unsigned char c)
+{
+	struct xps2data *drvdata = pserio->port_data;
+	unsigned long flags;
+	int retval;
+
+	spin_lock_irqsave(&drvdata->lock, flags);
+	retval = xps2_send(drvdata, &c);
+	spin_unlock_irqrestore(&drvdata->lock, flags);
+
+	return retval;
+}
+
+/*
+ * sxps2_open() is called when a port is open by the higher layer.
+ */
+static int sxps2_open(struct serio *pserio)
+{
+	struct xps2data *drvdata = pserio->port_data;
+	int retval;
+
+	retval = request_irq(drvdata->irq, &xps2_interrupt, 0,
+				DRIVER_NAME, drvdata);
+	if (retval) {
+		printk(KERN_ERR
+			"%s: Couldn't allocate interrupt %d\n",
+			drvdata->serio.name, drvdata->irq);
+		return retval;
+	}
+
+	/* start reception by enabling the interrupts */
+	out_be32(drvdata->base_address + XPS2_GIER_OFFSET, XPS2_GIER_GIE_MASK);
+	out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, XPS2_IPIXR_RX_ALL);
+	(void)xps2_recv(drvdata, &drvdata->rxb);
+
+	return 0;		/* success */
+}
+
+/*
+ * sxps2_close() frees the interrupt.
+ */
+static void sxps2_close(struct serio *pserio)
+{
+	struct xps2data *drvdata = pserio->port_data;
+
+	/* Disable the PS2 interrupts */
+	out_be32(drvdata->base_address + XPS2_GIER_OFFSET, 0x00);
+	out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, 0x00);
+	free_irq(drvdata->irq, drvdata);
+}
+
+/******************************/
+/* Device initialization code */
+/******************************/
+
+/*
+ * xps2_initialize() initializes the Xilinx PS/2 device.
+ */
+static int xps2_initialize(struct xps2data *drvdata)
+{
+	/* Disable all the interrupts, just in case */
+	out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, 0);
+
+	/* Reset the PS2 device and abort any current transaction, to make sure
+	 * we have the PS2 in a good state */
+	out_be32(drvdata->base_address + XPS2_SRST_OFFSET, XPS2_SRST_RESET);
+
+	return 0;
+}
+
+/*
+ * XPS PS2 device setup code.
+ */
+static int xps2_setup(struct device *dev, int id, struct resource *regs_res,
+			struct resource *irq_res)
+{
+	struct xps2data *drvdata;
+	struct serio *serio;
+	unsigned long remap_size;
+	int retval;
+
+	if (!dev)
+		return -EINVAL;
+
+	drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL);
+	if (!drvdata) {
+		dev_err(dev, "Couldn't allocate device private record\n");
+		return -ENOMEM;
+	}
+	spin_lock_init(&drvdata->lock);
+	mutex_init(&drvdata->cfg_mutex);
+	dev_set_drvdata(dev, drvdata);
+
+	if (!regs_res || !irq_res) {
+		dev_err(dev, "IO resource(s) not found\n");
+		retval = -EFAULT;
+		goto failed1;
+	}
+
+	drvdata->irq = irq_res->start;
+	remap_size = regs_res->end - regs_res->start + 1;
+	if (!request_mem_region(regs_res->start, remap_size, DRIVER_NAME)) {
+
+		dev_err(dev, "Couldn't lock memory region at 0x%08X\n",
+			(unsigned int)regs_res->start);
+		retval = -EBUSY;
+		goto failed1;
+	}
+
+	/* Fill in configuration data and add them to the list */
+	drvdata->phys_addr = regs_res->start;
+	drvdata->remap_size = remap_size;
+	drvdata->base_address = ioremap(regs_res->start, remap_size);
+	if (drvdata->base_address == NULL) {
+
+		dev_err(dev, "Couldn't ioremap memory at 0x%08X\n",
+			(unsigned int)regs_res->start);
+		retval = -EFAULT;
+		goto failed2;
+	}
+
+	/* Initialize the PS/2 interface */
+	mutex_lock(&drvdata->cfg_mutex);
+	if (xps2_initialize(drvdata)) {
+		mutex_unlock(&drvdata->cfg_mutex);
+		dev_err(dev, "Could not initialize device\n");
+		retval = -ENODEV;
+		goto failed3;
+	}
+	mutex_unlock(&drvdata->cfg_mutex);
+
+	dev_info(dev, "Xilinx PS2 at 0x%08X mapped to 0x%08X, irq=%d\n",
+		drvdata->phys_addr, (u32)drvdata->base_address, drvdata->irq);
+
+	serio = &drvdata->serio;
+	serio->id.type = SERIO_8042;
+	serio->write = sxps2_write;
+	serio->open = sxps2_open;
+	serio->close = sxps2_close;
+	serio->port_data = drvdata;
+	serio->dev.parent = dev;
+	snprintf(drvdata->serio.name, sizeof(serio->name),
+		 "Xilinx XPS PS/2 Port #%d", id);
+	snprintf(drvdata->serio.phys, sizeof(serio->phys),
+		 "xilinxps2/serio%d", id);
+	serio_register_port(serio);
+
+	return 0;		/* success */
+
+failed3:
+	iounmap(drvdata->base_address);
+
+failed2:
+	release_mem_region(regs_res->start, remap_size);
+
+failed1:
+	kfree(drvdata);
+	dev_set_drvdata(dev, NULL);
+
+	return retval;
+}
+
+/***************************/
+/* OF Platform Bus Support */
+/***************************/
+
+static int __devinit xps2_of_probe(struct of_device *ofdev, const struct
+				   of_device_id * match)
+{
+	struct resource r_irq_struct;
+	struct resource r_mem_struct;
+	struct resource *r_irq = &r_irq_struct;	/* Interrupt resources */
+	struct resource *r_mem = &r_mem_struct;	/* IO mem resources */
+	int rc = 0;
+	const unsigned int *id;
+
+	printk(KERN_INFO "Device Tree Probing \'%s\'\n",
+			ofdev->node->name);
+
+	/* Get iospace for the device */
+	rc = of_address_to_resource(ofdev->node, 0, r_mem);
+	if (rc) {
+		dev_warn(&ofdev->dev, "invalid address\n");
+		return rc;
+	}
+
+	/* Get IRQ for the device */
+	rc = of_irq_to_resource(ofdev->node, 0, r_irq);
+	if (rc == NO_IRQ) {
+		dev_warn(&ofdev->dev, "no IRQ found\n");
+		return rc;
+	}
+
+	id = of_get_property(ofdev->node, "port-number", NULL);
+	return xps2_setup(&ofdev->dev, id ? *id : -1, r_mem, r_irq);
+}
+
+static int __devexit xps2_of_remove(struct of_device *of_dev)
+{
+	struct xps2data *drvdata;
+	struct device *dev;
+
+	dev = &of_dev->dev;
+	if (!dev)
+		return -EINVAL;
+
+	drvdata = (struct xps2data *)dev_get_drvdata(dev);
+
+	serio_unregister_port(&drvdata->serio);
+
+	iounmap(drvdata->base_address);
+
+	release_mem_region(drvdata->phys_addr, drvdata->remap_size);
+
+	kfree(drvdata);
+	dev_set_drvdata(dev, NULL);
+
+	return 0;		/* success */
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id __devinitdata xps2_of_match[] = {
+	{ .compatible = "xlnx,xps-ps2-1.00.a", },
+	{ /* end of list */ },
+};
+MODULE_DEVICE_TABLE(of, xps2_of_match);
+
+static struct of_platform_driver xps2_of_driver = {
+	.name		= DRIVER_NAME,
+	.match_table	= xps2_of_match,
+	.probe		= xps2_of_probe,
+	.remove		= __devexit_p(xps2_of_remove),
+};
+
+static int __init xps2_init(void)
+{
+	return of_register_platform_driver(&xps2_of_driver);
+}
+
+static void __exit xps2_cleanup(void)
+{
+	of_unregister_platform_driver(&xps2_of_driver);
+}
+
+module_init(xps2_init);
+module_exit(xps2_cleanup);
+
+MODULE_AUTHOR("Xilinx, Inc.");
+MODULE_DESCRIPTION("Xilinx XPS PS/2 driver");
+MODULE_LICENSE("GPL");
+
-- 
1.5.2.1



This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

^ permalink raw reply related

* Re: [alsa-devel] [PATCH 1/3] ALSA SoC: Add OpenFirmware helper for matching bus and codec drivers
From: Grant Likely @ 2008-07-03 16:33 UTC (permalink / raw)
  To: Jon Smirl; +Cc: liam.girdwood, alsa-devel, broonie, timur, linuxppc-dev
In-Reply-To: <9e4733910807020827k115fe63r7a0dd09daffc1895@mail.gmail.com>

On Wed, Jul 02, 2008 at 11:27:17AM -0400, Jon Smirl wrote:
> On 7/1/08, Grant Likely <grant.likely@secretlab.ca> wrote:
> >  +static struct of_snd_soc_device *
> >  +of_snd_soc_get_device(struct device_node *codec_node)
> >  +{
> >  +       struct of_snd_soc_device *of_soc;
> >  +
> >  +       list_for_each_entry(of_soc, &of_snd_soc_device_list, list) {
> >  +               if (of_soc->codec_node == codec_node)
> >  +                       return of_soc;
> >  +       }
> >  +
> >  +       of_soc = kzalloc(sizeof(struct of_snd_soc_device), GFP_KERNEL);
> >  +       if (!of_soc)
> >  +               return NULL;
> >  +
> >  +       /* Initialize the structure and add it to the global list */
> >  +       of_soc->codec_node = codec_node;
> >  +       of_soc->id = of_snd_soc_next_index++;
> >  +       of_soc->machine.dai_link = &of_soc->dai_link;
> >  +       of_soc->machine.num_links = 1;
> >  +       of_soc->device.machine = &of_soc->machine;
> >  +       of_soc->dai_link.ops = &of_snd_soc_ops;
> >  +       list_add(&of_soc->list, &of_snd_soc_device_list);
> >  +
> >  +       return of_soc;
> >  +}
> 
> Isn't this performing the same basic function as this code (except for
> spi)? Should this list be maintained in alsa or should there be an
> equivalent for searching the spi bus? If you follow the link to the
> codec node and get it's parent you know which bus to search. But it
> might be simpler to just search the buses sequentially for the node.
> 
> static int of_dev_node_match(struct device *dev, void *data)
> {
>         return dev->archdata.of_node == data;
> }
> 
> struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
> {
> 	struct device *dev;
> 	
> 	dev = bus_find_device(&i2c_bus_type, NULL, node,
> 					 of_dev_node_match);
> 	if (!dev)
> 		return NULL;
> 		
> 	return to_i2c_client(dev);
> }
> EXPORT_SYMBOL(of_find_i2c_device_by_node);

Yes, but you hadn't written these functions when I wrote this helper.
:-P.  I believe ASoC v2 makes all this stuff unnecessary, but I'm
waiting for v2 to hit mainline before I port forward.

g.

^ permalink raw reply

* Re: [alsa-devel] [PATCH 2/3] ALSA SoC: Add mpc5200-psc I2S driver
From: Grant Likely @ 2008-07-03 16:30 UTC (permalink / raw)
  To: Jon Smirl; +Cc: liam.girdwood, alsa-devel, broonie, timur, linuxppc-dev
In-Reply-To: <9e4733910807020819sdb6f442q75dc7f10f9f605a5@mail.gmail.com>

On Wed, Jul 02, 2008 at 11:19:18AM -0400, Jon Smirl wrote:
> On 7/1/08, Grant Likely <grant.likely@secretlab.ca> wrote:
> >  +               /* Due to errata in the i2s mode; need to line up enabling
> >  +                * the transmitter with a transition on the frame sync
> >  +                * line */
> >  +
> >  +               spin_lock_irqsave(&psc_i2s->lock, flags);
> >  +               /* first make sure it is low */
> >  +               while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) != 0);
> 
> Could this be moved to the front of the routine, to increase parallelism?
> 
> Once you detect the 0, it will be a fixed interval before the 1
> happens. Might as well overlap the computations.
> 

Good point.  I'll try this out and see if it remains stable.  If this
gets done wrong, then left and right channels will often get swapped.

g.

^ permalink raw reply

* Re: [alsa-devel] [PATCH 2/3] ALSA SoC: Add mpc5200-psc I2S driver
From: Grant Likely @ 2008-07-03 16:28 UTC (permalink / raw)
  To: Jon Smirl; +Cc: liam.girdwood, alsa-devel, broonie, timur, linuxppc-dev
In-Reply-To: <9e4733910807020651u368763en9362653ed613b2d1@mail.gmail.com>

On Wed, Jul 02, 2008 at 09:51:59AM -0400, Jon Smirl wrote:
> DMA, needs to be split out. Efika is AC97 on the MPC5200 and needs to
> share DMA code. The new Phytec pcm030 baseboard is AC97 too.

I agree, but I'm not sure the best way to organize a split.  I'm not
doing anything with the Efika at the moment and I haven't dug into the
details of what needs to be done for AC97.

> What does the device tree look like?

Here is the relevant excerpt, but it is not documented yet.  I haven't
made any attempt encode the layout into the device tree (clocking, etc.)

	spi@f00 {
		#address-cells = <1>;
		#size-cells = <0>;
		compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
		reg = <0xf00 0x20>;
		num-slaves = <32>;
		interrupts = <2 13 0 2 14 0>;
		interrupt-parent = <&mpc5200_pic>;

		codec1: codec@2 {
			compatible = "ti,tlv320aic26";
			linux,modalias = "tlv320aic26";
			max-speed = <1000000>;
			reg = <2>;
		};

		codec2: codec@3 {
			compatible = "ti,tlv320aic26";
			linux,modalias = "tlv320aic26";
			max-speed = <1000000>;
			reg = <3>;
		};
	};

	i2s@2200 {		// PSC2
		compatible = "fsl,mpc5200b-psc-i2s","fsl,mpc5200-psc-i2s";
		cell-index = <1>;
		reg = <0x2200 0x100>;
		interrupts = <2 2 0>;
		interrupt-parent = <&mpc5200_pic>;
		codec-handle = <&codec1>;
	};
	i2s@2400 {		// PSC3
		compatible = "fsl,mpc5200b-psc-i2s","fsl,mpc5200-psc-i2s";
		cell-index = <2>;
		reg = <0x2400 0x100>;
		interrupts = <2 3 0>;
		interrupt-parent = <&mpc5200_pic>;
		codec-handle = <&codec2>;
	};

^ permalink raw reply

* Re: Updating glibc on SELF image
From: Detlev Zundel @ 2008-07-03 16:24 UTC (permalink / raw)
  To: Dave Cogley; +Cc: linuxppc-embedded
In-Reply-To: <1215026295.3492.15.camel@localhost.localdomain>

Hi Dave,

> Thank you for the reply. I did not build the initial SELF image it was
> provided to me from the board vendor. I used it as a starting point to
> get something up and running on SELF. Can you point me to the
> documentation on how to use the SELF RPM system?

Rebuilding the SELF image boils down to rebuilding the SELF "target
package" having nothing SELF specific in the process.  This is explained
in the DULG[1].

Cheers
  Detlev

[1] http://www.denx.de/wiki/view/DULG/ELDKRebuildingComponents#Section_3.7.2.

-- 
... that every year or so they're going to give you a new release full
of 50 000  additional lines of code all  written  by monkeys.  Because
they generally follow  the  ``million monkeys typing,   and eventually
they'll come up with something useful'' school of system development.
	                                    -- Richard M. Stallman
--
DENX Software Engineering GmbH,      MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich,  Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-40 Fax: (+49)-8142-66989-80 Email: dzu@denx.de

^ permalink raw reply

* Re: More commits added to powerpc.git master and powerpc-next branches
From: Anton Vorontsov @ 2008-07-03 16:06 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <18540.41013.722932.726273@cargo.ozlabs.ibm.com>

On Thu, Jul 03, 2008 at 07:47:33PM +1000, Paul Mackerras wrote:
> The following patches have been added to the master and powerpc-next
> branches of powerpc.git.

These seems to be lost:

[OF] of_gpio: should use new <linux/gpio.h> header
http://patchwork.ozlabs.org/linuxppc/patch?id=18750

[POWERPC] booting-without-of: fix GPIO section mis-numbering
http://patchwork.ozlabs.org/linuxppc/patch?id=18661

^^ these two are powerpc-next material.

Thanks,

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

^ permalink raw reply

* Re: patches for 2.6.27...
From: Anton Vorontsov @ 2008-07-03 15:59 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev@ozlabs.org list
In-Reply-To: <068935A1-11BE-4AEB-9C0E-E1AB53F1618E@kernel.crashing.org>

On Wed, Jul 02, 2008 at 02:56:16AM -0500, Kumar Gala wrote:
> Please point out any patches that have been posted but havent made it  
> into a git tree related to Freescale chips.

How about RTC work for MPC8610HPCD/MPC8572DS:

[PATCH 1/4] powerpc: fsl_uli1575: fix RTC quirk to work on MPC8572DS and MPC8610HPCD
http://patchwork.ozlabs.org/linuxppc/patch?id=18913

[PATCH 2/4] powerpc/85xx/86xx: some refactoring for fsl_uli1575 code
http://patchwork.ozlabs.org/linuxppc/patch?id=18914

[PATCH 3/4] powerpc: rtc_cmos_setup: assign interrupts only if there is i8259 PIC
http://patchwork.ozlabs.org/linuxppc/patch?id=18915

[PATCH 4/4] powerpc/86xx: mpc8610_hpcd: add support for ULI RTC
http://patchwork.ozlabs.org/linuxppc/patch?id=18916


And mpc83xx_defconfig update for MPC8360E-RDK:

[PATCH v3] powerpc/83xx: update mpc83xx_defconfig to support MPC8360E-RDK
http://patchwork.ozlabs.org/linuxppc/patch?id=18903

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

^ permalink raw reply

* Linux issues on Xilinx XUPV2P board
From: Alan Casey @ 2008-07-03 15:18 UTC (permalink / raw)
  To: linuxppc-embedded; +Cc: alan.casey5

Hi,

  I have tried running the Linux 2.6.24 and Linux 2.6.26 kernels from   
  git.xilinx.com on the Xilinx XUPV2P board but have run into a few probl=
ems.

  Cross-compiler i use to compile applications was built using Crosstools=

and
  based on gcc 3.3.4. I use Xilinx EDK 7.1 for integrating hardware perip=
herals
  onto the board.

  The problems i've seen are:

  (i) gettimeofday software function returns time of 0 all the time.

  (ii) The Linux 2.6.24 kernel's Xilinx Framebuffer driver and/or the Xil=
inx

       PLB TFT Controller IP block (plb_tft_cntlr_ref_v1_00_d) does not a=
ppear

       to centre the display on a VGA screen properly(vertically offset).=


  (iii) 64-bit write/read access to peripheral integrated onto the Xilinx=


        Virtex-II Pro FPGA either causes a system crash or only lower par=
t

        of 32-bit data to be written (i.e. lower part of 64-bit data appe=
ars
        to be mirrored on the upper and lower 32-bits of the system bus).=

        However, 32-bit write/read access to the peripheral passes as wel=
l
        as 64-bit write/read access to the SDRAM memory address space.
        Peripheral interface has been verified to be IBM PLB compliant 
        via IBM bus functional model simulations. 

   (iv) The Linux 2.6.26 Xilinx Framebuffer driver on the Xilinx XUPV2P b=
oard

        does not appear to be working - nothing displayed to screen/conso=
le

        not switching to framebuffer device on bootup. 

   Just wondering if anybody has seen these issues before and know how to=

   resolve them?

   Any info. appreciated,
   Regards,
   Alan.

  

^ permalink raw reply

* Re: [PATCH]: [MPC5200] (v2) Add ATA DMA support
From: Tim Yamin @ 2008-07-03 15:35 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev
In-Reply-To: <20080702173040.GB23846@secretlab.ca>

[-- Attachment #1: Type: text/plain, Size: 1068 bytes --]

On Wed, Jul 2, 2008 at 6:30 PM, Grant Likely <grant.likely@secretlab.ca> wrote:
> I know that only ATA uses this; but it is nice to have fixes to things
> that are obviously wrong in existing code to be split into their own
> patches.  That way, even if the ATA patch gets backed out, the bug fix
> will remain.

Ok, so I've split the patch up into two pieces now...

>> +static void
>> +mpc52xx_bmdma_start(struct ata_queued_cmd *qc)
>> +{
>> +     struct ata_port *ap = qc->ap;
>> +     struct mpc52xx_ata_priv *priv = ap->host->private_data;
>> +
>> +     /* LocalBus lock */
>> +     while (test_and_set_bit(0, &pata_mpc52xx_ata_dma_lock) != 0)
>> +             ;
>
> Need to be able to bail on timeout.

A deadlock can't occur within the PATA driver because you won't have
two DMA requests happening at once, so there is no point in adding a
timeout. And even if you do have a timeout, you'd have to drop the I/O
request somehow, so it's not really a good idea. If anything else
needs to touch the DMA lock, it should do so in a sensible fashion...

Thanks,

Tim

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: bestcomm-ata-fixes.patch --]
[-- Type: text/x-patch; name=bestcomm-ata-fixes.patch, Size: 4212 bytes --]

1) ata.h has dst_pa in the wrong place (needs to match what the BestComm
   task microcode in bcom_ata_task.c expects); fix it.

2) The BestComm ATA task priority was changed to maximum in bestcomm_priv.h;
   this fixes a deadlock issue I was experiencing when heavy DMA was
   occuring on both the ATA and Ethernet BestComm tasks, e.g. when
   downloading a large file over a LAN to disk.

3) The ATA BestComm driver uses bcom_ata_bd which is bigger than bcom_bd
   and this causes problems because the various bcom_... functions do not
   dereference the correct location. I've introduced bcom_get_bd which
   uses bcom_task.bd_size and this fixes the problem.

Signed-off-by: Tim Yamin <plasm@roo.me.uk>

diff -urp linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/ata.h linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/ata.h
--- linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/ata.h	2008-04-17 03:49:44.000000000 +0100
+++ linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/ata.h	2008-07-03 16:17:05.000000000 +0100
@@ -16,8 +16,8 @@
 
 struct bcom_ata_bd {
 	u32	status;
-	u32	dst_pa;
 	u32	src_pa;
+	u32	dst_pa;
 };
 
 extern struct bcom_task *
diff -urp linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm.h linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/bestcomm.h
--- linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm.h	2008-04-17 03:49:44.000000000 +0100
+++ linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/bestcomm.h	2008-07-03 16:17:05.000000000 +0100
@@ -38,7 +38,7 @@ struct bcom_task {
 	unsigned int	flags;
 	int		irq;
 
-	struct bcom_bd	*bd;
+	void		*bd;
 	phys_addr_t	bd_pa;
 	void		**cookie;
 	unsigned short	index;
@@ -140,15 +140,29 @@ bcom_queue_full(struct bcom_task *tsk)
 }
 
 /**
+ * bcom_get_bd - Get a BD from the queue
+ * @tsk: The BestComm task structure
+ * index: Index of the BD to fetch
+ */
+static inline struct bcom_bd
+*bcom_get_bd(struct bcom_task *tsk, unsigned int index)
+{
+	return tsk->bd + index * tsk->bd_size;
+}
+
+/**
  * bcom_buffer_done - Checks if a BestComm 
  * @tsk: The BestComm task structure
  */
 static inline int
 bcom_buffer_done(struct bcom_task *tsk)
 {
+	struct bcom_bd *bd;
 	if (bcom_queue_empty(tsk))
 		return 0;
-	return !(tsk->bd[tsk->outdex].status & BCOM_BD_READY);
+
+	bd = bcom_get_bd(tsk, tsk->outdex);
+	return !(bd->status & BCOM_BD_READY);
 }
 
 /**
@@ -160,16 +174,21 @@ bcom_buffer_done(struct bcom_task *tsk)
 static inline struct bcom_bd *
 bcom_prepare_next_buffer(struct bcom_task *tsk)
 {
-	tsk->bd[tsk->index].status = 0;	/* cleanup last status */
-	return &tsk->bd[tsk->index];
+	struct bcom_bd *bd;
+
+	bd = bcom_get_bd(tsk, tsk->index);
+	bd->status = 0;	/* cleanup last status */
+	return bd;
 }
 
 static inline void
 bcom_submit_next_buffer(struct bcom_task *tsk, void *cookie)
 {
+	struct bcom_bd *bd = bcom_get_bd(tsk, tsk->index);
+
 	tsk->cookie[tsk->index] = cookie;
 	mb();	/* ensure the bd is really up-to-date */
-	tsk->bd[tsk->index].status |= BCOM_BD_READY;
+	bd->status |= BCOM_BD_READY;
 	tsk->index = _bcom_next_index(tsk);
 	if (tsk->flags & BCOM_FLAGS_ENABLE_TASK)
 		bcom_enable(tsk);
@@ -179,10 +198,12 @@ static inline void *
 bcom_retrieve_buffer(struct bcom_task *tsk, u32 *p_status, struct bcom_bd **p_bd)
 {
 	void *cookie = tsk->cookie[tsk->outdex];
+	struct bcom_bd *bd = bcom_get_bd(tsk, tsk->outdex);
+
 	if (p_status)
-		*p_status = tsk->bd[tsk->outdex].status;
+		*p_status = bd->status;
 	if (p_bd)
-		*p_bd = &tsk->bd[tsk->outdex];
+		*p_bd = bd;
 	tsk->outdex = _bcom_next_outdex(tsk);
 	return cookie;
 }
diff -urp linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
--- linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h	2008-04-17 03:49:44.000000000 +0100
+++ linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h	2008-07-03 16:17:05.000000000 +0100
@@ -198,8 +198,8 @@ struct bcom_task_header {
 #define BCOM_IPR_SCTMR_1	2
 #define BCOM_IPR_FEC_RX		6
 #define BCOM_IPR_FEC_TX		5
-#define BCOM_IPR_ATA_RX		4
-#define BCOM_IPR_ATA_TX		3
+#define BCOM_IPR_ATA_RX		7
+#define BCOM_IPR_ATA_TX		7
 #define BCOM_IPR_SCPCI_RX	2
 #define BCOM_IPR_SCPCI_TX	2
 #define BCOM_IPR_PSC3_RX	2

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: pata_mpc52xx-add-dma.patch --]
[-- Type: text/x-patch; name=pata_mpc52xx-add-dma.patch, Size: 19524 bytes --]

This patch adds MDMA/UDMA support (using BestComm for DMA) on the MPC5200
platform. Patch requires the ATA BestComm fixes to function properly.

Based heavily on previous work by Freescale (Bernard Kuhn, John Rigby)
and Domen Puncer.

Using a SanDisk Extreme IV CF card I get read speeds of approximately
26.70 MB/sec.

There's also what I believe to be a hardware bug if you have high levels
of BestComm ATA DMA activity along with heavy LocalPlus Bus activity;
the address bus seems to sometimes get corrupted with ATA commands while
the LocalPlus Bus operation is still active (i.e. Chip Select is asserted).

I've asked Freescale about this but have not received a reply yet -- if
anybody from Freescale has any ideas please contact me; I can supply some
analyzer traces if needed. Therefore, for now, do not enable DMA if you
need reliable LocalPlus Bus unless you do a fixup in your driver as
follows:

Locking example:

        while (test_and_set_bit(0, &pata_mpc52xx_ata_dma_lock) != 0)
        {
                struct bcom_task_2 *tsk = pata_mpc52xx_ata_dma_task;

                if(bcom_buffer_done_2(tsk))
                        return 1;
        }

	return 0;

(Save the return value to `flags`)

Unlocking example:

        if(flags == 0)
                clear_bit(0, &pata_mpc52xx_ata_dma_lock);

Comments and testing would of course be very welcome.

Thanks,

Signed-off-by: Tim Yamin <plasm@roo.me.uk>

diff -urp linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm.c linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/bestcomm.c
--- linux-2.6.26-rc6/arch/powerpc/sysdev/bestcomm/bestcomm.c	2008-04-17 03:49:44.000000000 +0100
+++ linux-2.6.26-rc6-ata/arch/powerpc/sysdev/bestcomm/bestcomm.c	2008-07-03 16:17:05.000000000 +0100
@@ -330,11 +330,16 @@ bcom_engine_init(void)
 	/* Init 'always' initiator */
 	out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS);
 
+	/* If ATA DMA is enabled, always turn prefetch off (it breaks things) */
+#ifndef CONFIG_PATA_MPC52xx_DMA
 	/* Disable COMM Bus Prefetch on the original 5200; it's broken */
 	if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) {
+#endif
 		regval = in_be16(&bcom_eng->regs->PtdCntrl);
 		out_be16(&bcom_eng->regs->PtdCntrl,  regval | 1);
+#ifndef CONFIG_PATA_MPC52xx_DMA
 	}
+#endif
 
 	/* Init lock */
 	spin_lock_init(&bcom_eng->lock);
diff -urp linux-2.6.26-rc6/drivers/ata/Kconfig linux-2.6.26-rc6-ata/drivers/ata/Kconfig
--- linux-2.6.26-rc6/drivers/ata/Kconfig	2008-07-03 13:06:35.000000000 +0100
+++ linux-2.6.26-rc6-ata/drivers/ata/Kconfig	2008-07-03 16:16:32.000000000 +0100
@@ -462,6 +462,15 @@ config PATA_MPC52xx
 
 	  If unsure, say N.
 
+config PATA_MPC52xx_DMA
+	tristate "Freescale MPC52xx SoC internal IDE DMA"
+	depends on PATA_MPC52xx
+	help
+	  This option enables support for DMA on the MPC52xx SoC PATA
+	  controller.
+
+	  If unsure, say N.
+
 config PATA_MPIIX
 	tristate "Intel PATA MPIIX support"
 	depends on PCI
diff -urp linux-2.6.26-rc6/drivers/ata/pata_mpc52xx.c linux-2.6.26-rc6-ata/drivers/ata/pata_mpc52xx.c
--- linux-2.6.26-rc6/drivers/ata/pata_mpc52xx.c	2008-07-03 13:06:35.000000000 +0100
+++ linux-2.6.26-rc6-ata/drivers/ata/pata_mpc52xx.c	2008-07-03 16:16:32.000000000 +0100
@@ -6,6 +6,9 @@
  * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
  * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
  *
+ * UDMA support based on patches by Freescale (Bernard Kuhn, John Rigby),
+ * Domen Puncer and Tim Yamin.
+ *
  * This file is licensed under the terms of the GNU General Public License
  * version 2. This program is licensed "as is" without any warranty of any
  * kind, whether express or implied.
@@ -17,28 +20,47 @@
 #include <linux/delay.h>
 #include <linux/libata.h>
 
+#include <asm/cacheflush.h>
 #include <asm/types.h>
 #include <asm/prom.h>
 #include <asm/of_platform.h>
 #include <asm/mpc52xx.h>
 
+#include <sysdev/bestcomm/bestcomm.h>
+#include <sysdev/bestcomm/bestcomm_priv.h>
+#include <sysdev/bestcomm/ata.h>
 
 #define DRV_NAME	"mpc52xx_ata"
 #define DRV_VERSION	"0.1.2"
 
-
 /* Private structures used by the driver */
 struct mpc52xx_ata_timings {
 	u32	pio1;
 	u32	pio2;
+	u32	mdma1;
+	u32	mdma2;
+	u32	udma1;
+	u32	udma2;
+	u32	udma3;
+	u32	udma4;
+	u32	udma5;
+	int	using_udma;
 };
 
 struct mpc52xx_ata_priv {
 	unsigned int			ipb_period;
 	struct mpc52xx_ata __iomem *	ata_regs;
+	phys_addr_t			ata_regs_pa;
 	int				ata_irq;
 	struct mpc52xx_ata_timings	timings[2];
 	int				csel;
+
+	/* DMA */
+	struct bcom_task		*dmatsk;
+	const struct udmaspec		*udmaspec;
+	const struct mdmaspec		*mdmaspec;
+	int 				mpc52xx_ata_dma_last_write;
+	int				waiting_for_dma;
 };
 
 
@@ -53,6 +75,107 @@ static const int ataspec_ta[5]    = { 35
 
 #define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c)))
 
+/* ======================================================================== */
+
+/* ATAPI-4 MDMA specs (in clocks) */
+struct mdmaspec {
+	u32 t0M;
+	u32 td;
+	u32 th;
+	u32 tj;
+	u32 tkw;
+	u32 tm;
+	u32 tn;
+};
+
+static const struct mdmaspec mdmaspec66[3] = {
+	{ .t0M = 32, .td = 15, .th = 2, .tj = 2, .tkw = 15, .tm = 4, .tn = 1 },
+	{ .t0M = 10, .td = 6,  .th = 1, .tj = 1, .tkw = 4,  .tm = 2, .tn = 1 },
+	{ .t0M = 8,  .td = 5,  .th = 1, .tj = 1, .tkw = 2,  .tm = 2, .tn = 1 },
+};
+
+static const struct mdmaspec mdmaspec132[3] = {
+	{ .t0M = 64, .td = 29, .th = 3, .tj = 3, .tkw = 29, .tm = 7, .tn = 2 },
+	{ .t0M = 20, .td = 11, .th = 2, .tj = 1, .tkw = 7,  .tm = 4, .tn = 1 },
+	{ .t0M = 16, .td = 10, .th = 2, .tj = 1, .tkw = 4,  .tm = 4, .tn = 1 },
+};
+
+/* ATAPI-4 UDMA specs (in clocks) */
+struct udmaspec {
+	u32 tcyc;
+	u32 t2cyc;
+	u32 tds;
+	u32 tdh;
+	u32 tdvs;
+	u32 tdvh;
+	u32 tfs;
+	u32 tli;
+	u32 tmli;
+	u32 taz;
+	u32 tzah;
+	u32 tenv;
+	u32 tsr;
+	u32 trfs;
+	u32 trp;
+	u32 tack;
+	u32 tss;
+};
+
+static const struct udmaspec udmaspec66[6] = {
+	{ .tcyc = 8,  .t2cyc = 16, .tds  = 1,  .tdh  = 1, .tdvs = 5,  .tdvh = 1,
+	  .tfs  = 16, .tli   = 10, .tmli = 2,  .taz  = 1, .tzah = 2,  .tenv = 2,
+	  .tsr  = 3,  .trfs  = 5,  .trp  = 11, .tack = 2, .tss  = 4,
+	},
+	{ .tcyc = 5,  .t2cyc = 11, .tds  = 1,  .tdh  = 1, .tdvs = 4,  .tdvh = 1,
+	  .tfs  = 14, .tli   = 10, .tmli = 2,  .taz  = 1, .tzah = 2,  .tenv = 2,
+	  .tsr  = 2,  .trfs  = 5,  .trp  = 9,  .tack = 2, .tss  = 4,
+	},
+	{ .tcyc = 4,  .t2cyc = 8,  .tds  = 1,  .tdh  = 1, .tdvs = 3,  .tdvh = 1,
+	  .tfs  = 12, .tli   = 10, .tmli = 2,  .taz  = 1, .tzah = 2,  .tenv = 2,
+	  .tsr  = 2,  .trfs  = 4,  .trp  = 7,  .tack = 2, .tss  = 4,
+	},
+	{ .tcyc = 3,  .t2cyc = 6,  .tds  = 1,  .tdh  = 1, .tdvs = 2,  .tdvh = 1,
+	  .tfs  = 9,  .tli   = 7,  .tmli = 2,  .taz  = 1, .tzah = 2,  .tenv = 2,
+	  .tsr  = 2,  .trfs  = 4,  .trp  = 7,  .tack = 2, .tss  = 4,
+	},
+	{ .tcyc = 2,  .t2cyc = 4,  .tds  = 1,  .tdh  = 1, .tdvs = 1,  .tdvh = 1,
+	  .tfs  = 8,  .tli   = 8,  .tmli = 2,  .taz  = 1, .tzah = 2,  .tenv = 2,
+	  .tsr  = 2,  .trfs  = 4,  .trp  = 7,  .tack = 2, .tss  = 4,
+	},
+	{ .tcyc = 2,  .t2cyc = 2,  .tds  = 1,  .tdh  = 1, .tdvs = 1,  .tdvh = 1,
+	  .tfs  = 6,  .tli   = 5,  .tmli = 2,  .taz  = 1, .tzah = 2,  .tenv = 2,
+	  .tsr  = 2,  .trfs  = 4,  .trp  = 6,  .tack = 2, .tss  = 4,
+	},
+};
+
+static const struct udmaspec udmaspec132[6] = {
+	{ .tcyc = 15, .t2cyc = 31, .tds  = 2,  .tdh  = 1, .tdvs = 10, .tdvh = 1,
+	  .tfs  = 30, .tli   = 20, .tmli = 3,  .taz  = 2, .tzah = 3,  .tenv = 3,
+	  .tsr  = 7,  .trfs  = 10, .trp  = 22, .tack = 3, .tss  = 7,
+	},
+	{ .tcyc = 10, .t2cyc = 21, .tds  = 2,  .tdh  = 1, .tdvs = 7,  .tdvh = 1,
+	  .tfs  = 27, .tli   = 20, .tmli = 3,  .taz  = 2, .tzah = 3,  .tenv = 3,
+	  .tsr  = 4,  .trfs  = 10, .trp  = 17, .tack = 3, .tss  = 7,
+	},
+	{ .tcyc = 6,  .t2cyc = 12, .tds  = 1,  .tdh  = 1, .tdvs = 5,  .tdvh = 1,
+	  .tfs  = 23, .tli   = 20, .tmli = 3,  .taz  = 2, .tzah = 3,  .tenv = 3,
+	  .tsr  = 3,  .trfs  = 8,  .trp  = 14, .tack = 3, .tss  = 7,
+	},
+	{ .tcyc = 7,  .t2cyc = 12, .tds  = 1,  .tdh  = 1, .tdvs = 3,  .tdvh = 1,
+	  .tfs  = 15, .tli   = 13, .tmli = 3,  .taz  = 2, .tzah = 3,  .tenv = 3,
+	  .tsr  = 3,  .trfs  = 8,  .trp  = 14, .tack = 3, .tss  = 7,
+	},
+	{ .tcyc = 2,  .t2cyc = 5,  .tds  = 0,  .tdh  = 0, .tdvs = 1,  .tdvh = 1,
+	  .tfs  = 16, .tli   = 14, .tmli = 2,  .taz  = 1, .tzah = 2,  .tenv = 2,
+	  .tsr  = 2,  .trfs  = 7,  .trp  = 13, .tack = 2, .tss  = 6,
+	},
+	{ .tcyc = 3,  .t2cyc = 6,  .tds  = 1,  .tdh  = 1, .tdvs = 1,  .tdvh = 1,
+	  .tfs  = 12, .tli   = 10, .tmli = 3,  .taz  = 2, .tzah = 3,  .tenv = 3,
+	  .tsr  = 3,  .trfs  = 7,  .trp  = 12, .tack = 3, .tss  = 7,
+	},
+};
+
+/* ======================================================================== */
 
 /* Bit definitions inside the registers */
 #define MPC52xx_ATA_HOSTCONF_SMR	0x80000000UL /* State machine reset */
@@ -66,6 +189,7 @@ static const int ataspec_ta[5]    = { 35
 #define MPC52xx_ATA_HOSTSTAT_WERR	0x01000000UL /* Write Error */
 
 #define MPC52xx_ATA_FIFOSTAT_EMPTY	0x01 /* FIFO Empty */
+#define MPC52xx_ATA_FIFOSTAT_ERROR	0x40 /* FIFO Error */
 
 #define MPC52xx_ATA_DMAMODE_WRITE	0x01 /* Write DMA */
 #define MPC52xx_ATA_DMAMODE_READ	0x02 /* Read DMA */
@@ -75,6 +199,8 @@ static const int ataspec_ta[5]    = { 35
 #define MPC52xx_ATA_DMAMODE_FR		0x20 /* FIFO Reset */
 #define MPC52xx_ATA_DMAMODE_HUT		0x40 /* Host UDMA burst terminate */
 
+#define MAX_DMA_BUFFERS 128
+#define MAX_DMA_BUFFER_SIZE 0x20000u
 
 /* Structure of the hardware registers */
 struct mpc52xx_ata {
@@ -133,6 +259,9 @@ struct mpc52xx_ata {
 	u8  reserved21[2];
 };
 
+/* BestComm locking */
+unsigned long pata_mpc52xx_ata_dma_lock;
+struct bcom_task *pata_mpc52xx_ata_dma_task;
 
 /* ======================================================================== */
 /* Aux fns                                                                  */
@@ -165,6 +294,41 @@ mpc52xx_ata_compute_pio_timings(struct m
 	return 0;
 }
 
+static int
+mpc52xx_ata_compute_mdma_timings(struct mpc52xx_ata_priv *priv, int dev, int speed)
+{
+	struct mpc52xx_ata_timings *timing = &priv->timings[dev];
+	const struct mdmaspec *s = &priv->mdmaspec[speed];
+
+	if (speed < 0 || speed > 2)
+		return -EINVAL;
+
+	timing->mdma1 = (s->t0M << 24) | (s->td << 16) | (s->tkw << 8) | (s->tm);
+	timing->mdma2 = (s->th << 24) | (s->tj << 16) | (s->tn << 8);
+	timing->using_udma = 0;
+
+	return 0;
+}
+
+static int
+mpc52xx_ata_compute_udma_timings(struct mpc52xx_ata_priv *priv, int dev, int speed)
+{
+	struct mpc52xx_ata_timings *timing = &priv->timings[dev];
+	const struct udmaspec *s = &priv->udmaspec[speed];
+
+	if (speed < 0 || speed > 2)
+		return -EINVAL;
+
+	timing->udma1 = (s->t2cyc << 24) | (s->tcyc << 16) | (s->tds << 8) | (s->tdh);
+	timing->udma2 = (s->tdvs << 24) | (s->tdvh << 16) | (s->tfs << 8) | (s->tli);
+	timing->udma3 = (s->tmli << 24) | (s->taz << 16) | (s->tenv << 8) | (s->tsr);
+	timing->udma4 = (s->tss << 24) | (s->trfs << 16) | (s->trp << 8) | (s->tack);
+	timing->udma5 = (s->tzah << 24);
+	timing->using_udma = 1;
+
+	return 0;
+}
+
 static void
 mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device)
 {
@@ -173,14 +337,13 @@ mpc52xx_ata_apply_timings(struct mpc52xx
 
 	out_be32(&regs->pio1,  timing->pio1);
 	out_be32(&regs->pio2,  timing->pio2);
-	out_be32(&regs->mdma1, 0);
-	out_be32(&regs->mdma2, 0);
-	out_be32(&regs->udma1, 0);
-	out_be32(&regs->udma2, 0);
-	out_be32(&regs->udma3, 0);
-	out_be32(&regs->udma4, 0);
-	out_be32(&regs->udma5, 0);
-
+	out_be32(&regs->mdma1, timing->mdma1);
+	out_be32(&regs->mdma2, timing->mdma2);
+	out_be32(&regs->udma1, timing->udma1);
+	out_be32(&regs->udma2, timing->udma2);
+	out_be32(&regs->udma3, timing->udma3);
+	out_be32(&regs->udma4, timing->udma4);
+	out_be32(&regs->udma5, timing->udma5);
 	priv->csel = device;
 }
 
@@ -245,6 +408,29 @@ mpc52xx_ata_set_piomode(struct ata_port 
 	mpc52xx_ata_apply_timings(priv, adev->devno);
 }
 static void
+mpc52xx_ata_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+	struct mpc52xx_ata_priv *priv = ap->host->private_data;
+	int rv;
+
+	if (adev->dma_mode >= XFER_UDMA_0) {
+		int dma = adev->dma_mode - XFER_UDMA_0;
+		rv = mpc52xx_ata_compute_udma_timings(priv, adev->devno, dma);
+	} else {
+		int dma = adev->dma_mode - XFER_MW_DMA_0;
+		rv = mpc52xx_ata_compute_mdma_timings(priv, adev->devno, dma);
+	}
+
+	if (rv) {
+		dev_alert(ap->dev,
+			"Trying to select invalid DMA mode %d\n",
+			adev->dma_mode);
+		return;
+	}
+
+	mpc52xx_ata_apply_timings(priv, adev->devno);
+}
+static void
 mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device)
 {
 	struct mpc52xx_ata_priv *priv = ap->host->private_data;
@@ -255,16 +441,192 @@ mpc52xx_ata_dev_select(struct ata_port *
 	ata_sff_dev_select(ap,device);
 }
 
+static int
+mpc52xx_ata_build_dmatable(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct mpc52xx_ata_priv *priv = ap->host->private_data;
+	unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE), si;
+	struct scatterlist *sg;
+	int count = 0;
+
+	if (read)
+		bcom_ata_rx_prepare(priv->dmatsk);
+	else
+		bcom_ata_tx_prepare(priv->dmatsk);
+
+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
+		dma_addr_t cur_addr = sg_dma_address(sg);
+		u32 cur_len = sg_dma_len(sg);
+
+		while (cur_len) {
+			unsigned int tc = min(cur_len, MAX_DMA_BUFFER_SIZE);
+			struct bcom_ata_bd *bd = (struct bcom_ata_bd *) bcom_prepare_next_buffer(priv->dmatsk);
+
+			if (read) {
+				bd->status = tc;
+				bd->src_pa = (__force u32) priv->ata_regs_pa +
+					offsetof(struct mpc52xx_ata, fifo_data);
+				bd->dst_pa = (__force u32) cur_addr;
+			} else {
+				bd->status = tc;
+				bd->src_pa = (__force u32) cur_addr;
+				bd->dst_pa = (__force u32) priv->ata_regs_pa +
+					offsetof(struct mpc52xx_ata, fifo_data);
+			}
+
+			bcom_submit_next_buffer(priv->dmatsk, NULL);
+
+			cur_addr += tc;
+			cur_len -= tc;
+			count++;
+
+			if (count > MAX_DMA_BUFFERS) {
+				dev_alert(ap->dev, "dma table"
+					"too small\n");
+				goto use_pio_instead;
+			}
+		}
+	}
+	return 1;
+
+ use_pio_instead:
+	bcom_ata_reset_bd(priv->dmatsk);
+	return 0;
+}
+
+static void
+mpc52xx_bmdma_setup(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct mpc52xx_ata_priv *priv = ap->host->private_data;
+	struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+
+	unsigned int read = !(qc->tf.flags & ATA_TFLAG_WRITE);
+	u8 dma_mode;
+
+	if (!mpc52xx_ata_build_dmatable(qc))
+		dev_alert(ap->dev, "%s: %i, return 1?\n",
+			__func__, __LINE__);
+
+	/* Check FIFO is OK... */
+	if(in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR)
+		dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n",
+			__func__, in_8(&priv->ata_regs->fifo_status));
+
+	if (read) {
+		dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_READ |
+				MPC52xx_ATA_DMAMODE_FE;
+
+		/* Setup FIFO if direction changed */
+		if (priv->mpc52xx_ata_dma_last_write != 0) {
+			priv->mpc52xx_ata_dma_last_write = 0;
+
+			/* Configure FIFO with granularity to 7 */
+			out_8(&regs->fifo_control, 7);
+			out_be16(&regs->fifo_alarm, 128);
+
+			/* Set FIFO Reset bit (FR) */
+			out_8(&regs->dma_mode, MPC52xx_ATA_DMAMODE_FR);
+		}
+	} else {
+		dma_mode = MPC52xx_ATA_DMAMODE_IE | MPC52xx_ATA_DMAMODE_WRITE;
+
+		/* Setup FIFO if direction changed */
+		if (priv->mpc52xx_ata_dma_last_write != 1) {
+			priv->mpc52xx_ata_dma_last_write = 1;
+
+			/* Configure FIFO with granularity to 4 */
+			out_8(&regs->fifo_control, 4);
+			out_be16(&regs->fifo_alarm, 128);
+		}
+	}
+
+	if (priv->timings[qc->dev->devno].using_udma)
+		dma_mode |= MPC52xx_ATA_DMAMODE_UDMA;
+
+	out_8(&regs->dma_mode, dma_mode);
+	priv->waiting_for_dma = ATA_DMA_ACTIVE;
+
+	ata_wait_idle(ap);
+	ap->ops->sff_exec_command(ap, &qc->tf);
+}
+
+static void
+mpc52xx_bmdma_start(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct mpc52xx_ata_priv *priv = ap->host->private_data;
+
+	/* LocalBus lock */
+	while (test_and_set_bit(0, &pata_mpc52xx_ata_dma_lock) != 0)
+		;
+
+	bcom_set_task_auto_start(priv->dmatsk->tasknum, priv->dmatsk->tasknum);
+	bcom_enable(priv->dmatsk);
+}
+
+static void
+mpc52xx_bmdma_stop(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct mpc52xx_ata_priv *priv = ap->host->private_data;
+
+	bcom_disable(priv->dmatsk);
+	bcom_ata_reset_bd(priv->dmatsk);
+
+	/* LocalBus unlock*/
+	clear_bit(0, &pata_mpc52xx_ata_dma_lock);
+
+	priv->waiting_for_dma = 0;
+
+	/* Check FIFO is OK... */
+	if(in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR)
+		dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n",
+			__func__, in_8(&priv->ata_regs->fifo_status));
+}
+
+static u8
+mpc52xx_bmdma_status(struct ata_port *ap)
+{
+	struct mpc52xx_ata_priv *priv = ap->host->private_data;
+
+	/* Check FIFO is OK... */
+	if(in_8(&priv->ata_regs->fifo_status) & MPC52xx_ATA_FIFOSTAT_ERROR) {
+		dev_alert(ap->dev, "%s: FIFO error detected: 0x%02x!\n",
+			__func__, in_8(&priv->ata_regs->fifo_status));
+		return priv->waiting_for_dma | ATA_DMA_ERR;
+	}
+
+	return priv->waiting_for_dma;
+}
+
+static irqreturn_t
+mpc52xx_ata_task_irq(int irq, void *vpriv)
+{
+	struct mpc52xx_ata_priv *priv = vpriv;
+	priv->waiting_for_dma |= ATA_DMA_INTR;
+
+	return IRQ_HANDLED;
+}
+
 static struct scsi_host_template mpc52xx_ata_sht = {
 	ATA_PIO_SHT(DRV_NAME),
 };
 
 static struct ata_port_operations mpc52xx_ata_port_ops = {
 	.inherits		= &ata_sff_port_ops,
-	.sff_dev_select		= mpc52xx_ata_dev_select,
-	.cable_detect		= ata_cable_40wire,
+
 	.set_piomode		= mpc52xx_ata_set_piomode,
-	.post_internal_cmd	= ATA_OP_NULL,
+	.set_dmamode		= mpc52xx_ata_set_dmamode,
+	.sff_dev_select		= mpc52xx_ata_dev_select,
+
+	.bmdma_setup		= mpc52xx_bmdma_setup,
+	.bmdma_start		= mpc52xx_bmdma_start,
+	.bmdma_stop		= mpc52xx_bmdma_stop,
+	.bmdma_status		= mpc52xx_bmdma_status,
+
+	.qc_prep		= ata_noop_qc_prep,
 };
 
 static int __devinit
@@ -281,9 +643,11 @@ mpc52xx_ata_init_one(struct device *dev,
 
 	ap = host->ports[0];
 	ap->flags		|= ATA_FLAG_SLAVE_POSS;
-	ap->pio_mask		= 0x1f;	/* Up to PIO4 */
-	ap->mwdma_mask		= 0x00;	/* No MWDMA   */
-	ap->udma_mask		= 0x00;	/* No UDMA    */
+	ap->pio_mask		= ATA_PIO4;	/* Up to PIO4 */
+#ifdef CONFIG_PATA_MPC52xx_DMA
+	ap->mwdma_mask		= ATA_MWDMA2;	/* Up to MWDMA2 */
+	ap->udma_mask		= ATA_UDMA2;	/* Up to UDMA2 */
+#endif
 	ap->ops			= &mpc52xx_ata_port_ops;
 	host->private_data	= priv;
 
@@ -333,7 +697,7 @@ mpc52xx_ata_probe(struct of_device *op, 
 	int ata_irq;
 	struct mpc52xx_ata __iomem *ata_regs;
 	struct mpc52xx_ata_priv *priv;
-	int rv;
+	int rv, ret, task_irq;
 
 	/* Get ipb frequency */
 	ipb_freq = mpc52xx_find_ipb_freq(op->node);
@@ -389,8 +753,34 @@ mpc52xx_ata_probe(struct of_device *op, 
 
 	priv->ipb_period = 1000000000 / (ipb_freq / 1000);
 	priv->ata_regs = ata_regs;
+	priv->ata_regs_pa = res_mem.start;
 	priv->ata_irq = ata_irq;
 	priv->csel = -1;
+	priv->mpc52xx_ata_dma_last_write = -1;
+
+	if (ipb_freq/1000000 == 66) {
+		priv->mdmaspec = mdmaspec66;
+		priv->udmaspec = udmaspec66;
+	} else {
+		priv->mdmaspec = mdmaspec132;
+		priv->udmaspec = udmaspec132;
+	}
+
+	pata_mpc52xx_ata_dma_lock = 0;
+	priv->dmatsk = bcom_ata_init(MAX_DMA_BUFFERS, MAX_DMA_BUFFER_SIZE);
+	pata_mpc52xx_ata_dma_task = priv->dmatsk;
+	if (!priv->dmatsk) {
+		dev_alert(&op->dev, "Failed to initialize BestComm task!\n");
+		rv = -ENOMEM;
+		goto err;
+	}
+
+	task_irq = bcom_get_task_irq(priv->dmatsk);
+	ret = request_irq(task_irq, &mpc52xx_ata_task_irq, IRQF_DISABLED,
+				"ATA task", priv);
+	if (ret)
+		dev_alert(&op->dev, "request_irq failed with: "
+					"%i\n", ret);
 
 	/* Init the hw */
 	rv = mpc52xx_ata_hw_init(priv);

^ permalink raw reply

* Re: [PATCH] powerpc: Xilinx: add 440 platform support
From: Grant Likely @ 2008-07-03 15:26 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev, John Linn
In-Reply-To: <20080703091448.4e298ce8@zod.rchland.ibm.com>

On Thu, Jul 03, 2008 at 09:14:48AM -0400, Josh Boyer wrote:
> On Tue, 1 Jul 2008 15:48:26 -0700 John Linn <john.linn@xilinx.com> wrote:
> > +config XILINX_VIRTEX440_GENERIC_BOARD
> > +	bool "Generic Xilinx Virtex 440 board"
> > +	depends on 44x
> > +	default n
> > +	select XILINX_VIRTEX_5_FXT
> 
> If this is for generic Virtex 440 board support, why is it selecting a
> specific Virtex 5 board?  Or am I confused as to what
> XILINX_VIRTEX_5_FXT is?

Virtex 5 FXT if the FPGA chip

Virtex440 is a Virtex 5 with a bitstream that enables the embedded 440
processor.

g.

^ permalink raw reply

* Re: linux-next: manual merge of the powerpc tree
From: Grant Likely @ 2008-07-03 15:24 UTC (permalink / raw)
  To: Jon Smirl
  Cc: Stephen Rothwell, linuxppc-dev, linux-next, Paul Mackerras,
	Jean Delvare, Timur Tabi
In-Reply-To: <9e4733910807030522h1aa0bl1801ecc5fc877c25@mail.gmail.com>

On Thu, Jul 03, 2008 at 08:22:18AM -0400, Jon Smirl wrote:
> Testing was good when the patch was initially posted in January. In
> the last six months the initial patch set has been sliced and diced
> into a bunch of different pieces but the contents of this patch are
> essentially unchanged.
> 
> I don't care which tree it uses to get to mainline, I'd just like to
> see it get merged.

Me too, but it is used by some of the mpc8xxx platforms too, so I'd like
to see an ack from one of those users also.

Cheers,
g.

^ permalink raw reply

* Re: gianfar in SGMII mode
From: Nate Case @ 2008-07-03 15:23 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev
In-Reply-To: <1215039186.7559.548.camel@localhost.localdomain>

On Wed, 2008-07-02 at 17:53 -0500, Nate Case wrote:
> I'm looking at gfar_configure_serdes() and I'm at a loss as to why
> this
> is always called when the MAC is in SGMII mode.  It looks like it
> assumes the use of TBI for some reason.  On my board it's just a
> regular
> SGMII interface to a bcm5482 PHY in SGMII mode, so there is no TBI
> involved.
> 
> I'm guessing this is a case of the driver making incorrect assumptions
> based on the existing Freescale boards.  Or am I missing something
> here? 

Answering my own question: I see now that TBI is used internally on the
chip for the SerDes interface which implements SGMII..  so maybe there's
no problem with what the driver is doing after all.

-- 
Nate Case <ncase@xes-inc.com>

^ permalink raw reply

* Re: where can i find a kdb patch for my MPC8313 platform
From: Scott Wood @ 2008-07-03 14:21 UTC (permalink / raw)
  To: 旭 罗; +Cc: linuxppc-dev
In-Reply-To: <638697.26526.qm@web15910.mail.cnb.yahoo.com>

旭 罗 wrote:
> Hello all:
>      I hope add the KDB function for my mpc8313 platform. I find some 
> informations from the ftp://oss.sgi.com/projects/kdb/download . But i 
> only find the comman patch and a patch for X86 system. Hi Scoott i think 
> you have ever used the KDB to debug the MPC8313. Could you tell me where 
> can i find the patch for the MPC8313.

I have never used KDB, sorry.

-Scott

^ permalink raw reply

* [PATCH 2/3] ehea: add MODULE_DEVICE_TABLE
From: Jan-Bernd Themann @ 2008-07-03 14:18 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: Thomas Klein, Jan-Bernd Themann, netdev, hering2, linux-kernel,
	kamalesh, linux-ppc, Christoph Raisch, Marcus Eder

Required to allow distros to easily detect when ehea
module needs to be loaded

Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>


---

diff -Nurp -X dontdiff linux-2.6.26-rc8/drivers/net/ehea/ehea_main.c patched_kernel/drivers/net/ehea/ehea_main.c
--- linux-2.6.26-rc8/drivers/net/ehea/ehea_main.c	2008-07-02 13:27:03.000000000 +0200
+++ patched_kernel/drivers/net/ehea/ehea_main.c	2008-07-02 13:48:21.000000000 +0200
@@ -118,6 +118,7 @@ static struct of_device_id ehea_device_t
 	},
 	{},
 };
+MODULE_DEVICE_TABLE(of, ehea_device_table);
 
 static struct of_platform_driver ehea_driver = {
 	.name = "ehea",

^ permalink raw reply

* [PATCH 1/3] ehea: fix might sleep problem
From: Jan-Bernd Themann @ 2008-07-03 14:18 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: Thomas Klein, Jan-Bernd Themann, netdev, hering2, linux-kernel,
	kamalesh, linux-ppc, Christoph Raisch, Marcus Eder

A mutex has to be replaced by spinlocks as it can be called from
a context which does not allow sleeping.
The kzalloc flag GFP_KERNEL has to be replaced by GFP_ATOMIC
for the same reason.

Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>

---

diff -Nurp -X dontdiff linux-2.6.26-rc8/drivers/net/ehea/ehea.h patched_kernel/drivers/net/ehea/ehea.h
--- linux-2.6.26-rc8/drivers/net/ehea/ehea.h	2008-06-25 03:58:20.000000000 +0200
+++ patched_kernel/drivers/net/ehea/ehea.h	2008-07-02 12:38:05.000000000 +0200
@@ -452,7 +452,7 @@ struct ehea_bcmc_reg_entry {
 struct ehea_bcmc_reg_array {
 	struct ehea_bcmc_reg_entry *arr;
 	int num_entries;
-	struct mutex lock;
+	spinlock_t lock;
 };
 
 #define EHEA_PORT_UP 1
diff -Nurp -X dontdiff linux-2.6.26-rc8/drivers/net/ehea/ehea_main.c patched_kernel/drivers/net/ehea/ehea_main.c
--- linux-2.6.26-rc8/drivers/net/ehea/ehea_main.c	2008-06-25 03:58:20.000000000 +0200
+++ patched_kernel/drivers/net/ehea/ehea_main.c	2008-07-02 12:38:05.000000000 +0200
@@ -241,7 +241,7 @@ static void ehea_update_bcmc_registratio
 		}
 
 	if (num_registrations) {
-		arr = kzalloc(num_registrations * sizeof(*arr), GFP_KERNEL);
+		arr = kzalloc(num_registrations * sizeof(*arr), GFP_ATOMIC);
 		if (!arr)
 			return;  /* Keep the existing array */
 	} else
@@ -301,7 +301,7 @@ static struct net_device_stats *ehea_get
 
 	memset(stats, 0, sizeof(*stats));
 
-	cb2 = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	cb2 = kzalloc(PAGE_SIZE, GFP_ATOMIC);
 	if (!cb2) {
 		ehea_error("no mem for cb2");
 		goto out;
@@ -1763,7 +1763,7 @@ static int ehea_set_mac_addr(struct net_
 
 	memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len);
 
-	mutex_lock(&ehea_bcmc_regs.lock);
+	spin_lock(&ehea_bcmc_regs.lock);
 
 	/* Deregister old MAC in pHYP */
 	if (port->state == EHEA_PORT_UP) {
@@ -1785,7 +1785,7 @@ static int ehea_set_mac_addr(struct net_
 
 out_upregs:
 	ehea_update_bcmc_registrations();
-	mutex_unlock(&ehea_bcmc_regs.lock);
+	spin_unlock(&ehea_bcmc_regs.lock);
 out_free:
 	kfree(cb0);
 out:
@@ -1947,7 +1947,7 @@ static void ehea_set_multicast_list(stru
 	}
 	ehea_promiscuous(dev, 0);
 
-	mutex_lock(&ehea_bcmc_regs.lock);
+	spin_lock(&ehea_bcmc_regs.lock);
 
 	if (dev->flags & IFF_ALLMULTI) {
 		ehea_allmulti(dev, 1);
@@ -1978,7 +1978,7 @@ static void ehea_set_multicast_list(stru
 	}
 out:
 	ehea_update_bcmc_registrations();
-	mutex_unlock(&ehea_bcmc_regs.lock);
+	spin_unlock(&ehea_bcmc_regs.lock);
 	return;
 }
 
@@ -2497,7 +2497,7 @@ static int ehea_up(struct net_device *de
 		}
 	}
 
-	mutex_lock(&ehea_bcmc_regs.lock);
+	spin_lock(&ehea_bcmc_regs.lock);
 
 	ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
 	if (ret) {
@@ -2520,7 +2520,7 @@ out:
 		ehea_info("Failed starting %s. ret=%i", dev->name, ret);
 
 	ehea_update_bcmc_registrations();
-	mutex_unlock(&ehea_bcmc_regs.lock);
+	spin_unlock(&ehea_bcmc_regs.lock);
 
 	ehea_update_firmware_handles();
 	mutex_unlock(&ehea_fw_handles.lock);
@@ -2575,7 +2575,7 @@ static int ehea_down(struct net_device *
 
 	mutex_lock(&ehea_fw_handles.lock);
 
-	mutex_lock(&ehea_bcmc_regs.lock);
+	spin_lock(&ehea_bcmc_regs.lock);
 	ehea_drop_multicast_list(dev);
 	ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
 
@@ -2584,7 +2584,7 @@ static int ehea_down(struct net_device *
 	port->state = EHEA_PORT_DOWN;
 
 	ehea_update_bcmc_registrations();
-	mutex_unlock(&ehea_bcmc_regs.lock);
+	spin_unlock(&ehea_bcmc_regs.lock);
 
 	ret = ehea_clean_all_portres(port);
 	if (ret)
@@ -3590,7 +3590,7 @@ int __init ehea_module_init(void)
 	memset(&ehea_bcmc_regs, 0, sizeof(ehea_bcmc_regs));
 
 	mutex_init(&ehea_fw_handles.lock);
-	mutex_init(&ehea_bcmc_regs.lock);
+	spin_lock_init(&ehea_bcmc_regs.lock);
 
 	ret = check_module_parm();
 	if (ret)

^ permalink raw reply

* [PATCH 3/3] ehea: fix race condition
From: Jan-Bernd Themann @ 2008-07-03 14:18 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: Thomas Klein, Jan-Bernd Themann, netdev, hering2, linux-kernel,
	kamalesh, linux-ppc, Christoph Raisch, Marcus Eder

When ehea_stop is called the function 
cancel_work_sync(&port->reset_task) is used to ensure
that the reset task is not running anymore. We need an 
additional flag to ensure that it can not be scheduled
after this call again for a certain time.


Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>

---

diff -Nurp -X dontdiff linux-2.6.26-rc8/drivers/net/ehea/ehea.h patched_kernel/drivers/net/ehea/ehea.h
--- linux-2.6.26-rc8/drivers/net/ehea/ehea.h	2008-07-02 16:52:13.000000000 +0200
+++ patched_kernel/drivers/net/ehea/ehea.h	2008-07-02 17:01:39.000000000 +0200
@@ -40,7 +40,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME	"ehea"
-#define DRV_VERSION	"EHEA_0091"
+#define DRV_VERSION	"EHEA_0092"
 
 /* eHEA capability flags */
 #define DLPAR_PORT_ADD_REM 1
@@ -478,6 +478,7 @@ struct ehea_port {
 	int num_add_tx_qps;
 	int num_mcs;
 	int resets;
+	u64 flags;
 	u64 mac_addr;
 	u32 logical_port_id;
 	u32 port_speed;
@@ -501,7 +502,8 @@ struct port_res_cfg {
 };
 
 enum ehea_flag_bits {
-	__EHEA_STOP_XFER
+	__EHEA_STOP_XFER,
+	__EHEA_DISABLE_PORT_RESET
 };
 
 void ehea_set_ethtool_ops(struct net_device *netdev);
diff -Nurp -X dontdiff linux-2.6.26-rc8/drivers/net/ehea/ehea_main.c patched_kernel/drivers/net/ehea/ehea_main.c
--- linux-2.6.26-rc8/drivers/net/ehea/ehea_main.c	2008-07-02 17:01:18.000000000 +0200
+++ patched_kernel/drivers/net/ehea/ehea_main.c	2008-07-02 17:01:39.000000000 +0200
@@ -138,6 +138,12 @@ void ehea_dump(void *adr, int len, char 
 	}
 }
 
+void ehea_schedule_port_reset(struct ehea_port *port)
+{
+	if (!test_bit(__EHEA_DISABLE_PORT_RESET, &port->flags))
+		schedule_work(&port->reset_task);
+}
+
 static void ehea_update_firmware_handles(void)
 {
 	struct ehea_fw_handle_entry *arr = NULL;
@@ -588,7 +594,7 @@ static int ehea_treat_poll_error(struct 
 				   "Resetting port.", pr->qp->init_attr.qp_nr);
 			ehea_dump(cqe, sizeof(*cqe), "CQE");
 		}
-		schedule_work(&pr->port->reset_task);
+		ehea_schedule_port_reset(pr->port);
 		return 1;
 	}
 
@@ -766,7 +772,7 @@ static struct ehea_cqe *ehea_proc_cqes(s
 			ehea_error("Send Completion Error: Resetting port");
 			if (netif_msg_tx_err(pr->port))
 				ehea_dump(cqe, sizeof(*cqe), "Send CQE");
-			schedule_work(&pr->port->reset_task);
+			ehea_schedule_port_reset(pr->port);
 			break;
 		}
 
@@ -886,7 +892,7 @@ static irqreturn_t ehea_qp_aff_irq_handl
 		eqe = ehea_poll_eq(port->qp_eq);
 	}
 
-	schedule_work(&port->reset_task);
+	ehea_schedule_port_reset(port);
 
 	return IRQ_HANDLED;
 }
@@ -2606,13 +2612,14 @@ static int ehea_stop(struct net_device *
 	if (netif_msg_ifdown(port))
 		ehea_info("disabling port %s", dev->name);
 
+	set_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);
 	cancel_work_sync(&port->reset_task);
-
 	mutex_lock(&port->port_lock);
 	netif_stop_queue(dev);
 	port_napi_disable(port);
 	ret = ehea_down(dev);
 	mutex_unlock(&port->port_lock);
+	clear_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);
 	return ret;
 }
 
@@ -2942,7 +2949,7 @@ static void ehea_tx_watchdog(struct net_
 
 	if (netif_carrier_ok(dev) &&
 	    !test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
-		schedule_work(&port->reset_task);
+		ehea_schedule_port_reset(port);
 }
 
 int ehea_sense_adapter_attr(struct ehea_adapter *adapter)

^ permalink raw reply

* [PATCH] [V3] powerpc: Xilinx: add 440 platform support
From: John Linn @ 2008-07-03 14:05 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: John Linn

Support for the Xilinx Virtex5 FXT 440 is being
added.

Signed-off-by: John Linn <john.linn@xilinx.com>
---
V1 & V2
	bad mailing list address, never got to mailing list
V3
	added more help to Kconfig, requested from Josh

 arch/powerpc/platforms/44x/Kconfig  |   26 +++++++++++++++
 arch/powerpc/platforms/44x/Makefile |    1 +
 arch/powerpc/platforms/44x/virtex.c |   60 +++++++++++++++++++++++++++++++++++
 3 files changed, 87 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/platforms/44x/virtex.c

diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index 6abe913..429ae34 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -102,6 +102,22 @@ config YOSEMITE
 #	help
 #	  This option enables support for the IBM PPC440GX evaluation board.
 
+config XILINX_VIRTEX440_GENERIC_BOARD
+	bool "Generic Xilinx Virtex 440 board"
+	depends on 44x
+	default n
+	select XILINX_VIRTEX_5_FXT
+	help
+	  This option enables generic support for Xilinx Virtex based boards
+	  that use a 440 based processor in the Virtex 5 FXT FPGA architecture.
+
+	  The generic virtex board support matches any device tree which
+	  specifies 'xlnx,virtex440' in its compatible field.  This includes
+	  the Xilinx ML5xx reference designs using the powerpc core.
+
+	  Most Virtex 5 designs should use this unless it needs to do some
+	  special configuration at board probe time.
+
 # 44x specific CPU modules, selected based on the board above.
 config 440EP
 	bool
@@ -152,3 +168,13 @@ config 460EX
 # 44x errata/workaround config symbols, selected by the CPU models above
 config IBM440EP_ERR42
 	bool
+
+# Xilinx specific config options.
+config XILINX_VIRTEX
+	bool
+
+# Xilinx Virtex 5 FXT FPGA architecture, selected by a Xilinx board above
+config XILINX_VIRTEX_5_FXT
+	bool
+	select XILINX_VIRTEX
+
diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile
index 774165f..dbfae1d 100644
--- a/arch/powerpc/platforms/44x/Makefile
+++ b/arch/powerpc/platforms/44x/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_RAINIER)	+= rainier.o
 obj-$(CONFIG_WARP)	+= warp.o
 obj-$(CONFIG_WARP)	+= warp-nand.o
 obj-$(CONFIG_CANYONLANDS) += canyonlands.o
+obj-$(CONFIG_XILINX_VIRTEX_5_FXT) += virtex.o
diff --git a/arch/powerpc/platforms/44x/virtex.c b/arch/powerpc/platforms/44x/virtex.c
new file mode 100644
index 0000000..68637fa
--- /dev/null
+++ b/arch/powerpc/platforms/44x/virtex.c
@@ -0,0 +1,60 @@
+/*
+ * Xilinx Virtex 5FXT based board support, derived from
+ * the Xilinx Virtex (IIpro & 4FX) based board support
+ *
+ * Copyright 2007 Secret Lab Technologies Ltd.
+ * Copyright 2008 Xilinx, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/of_platform.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/time.h>
+#include <asm/xilinx_intc.h>
+#include <asm/reg.h>
+#include <asm/ppc4xx.h>
+#include "44x.h"
+
+static struct of_device_id xilinx_of_bus_ids[] __initdata = {
+	{ .compatible = "simple-bus", },
+	{ .compatible = "xlnx,plb-v46-1.00.a", },
+	{ .compatible = "xlnx,plb-v46-1.02.a", },
+	{ .compatible = "xlnx,plb-v34-1.01.a", },
+	{ .compatible = "xlnx,plb-v34-1.02.a", },
+	{ .compatible = "xlnx,opb-v20-1.10.c", },
+	{ .compatible = "xlnx,dcr-v29-1.00.a", },
+	{ .compatible = "xlnx,compound", },
+	{}
+};
+
+static int __init virtex_device_probe(void)
+{
+	of_platform_bus_probe(NULL, xilinx_of_bus_ids, NULL);
+
+	return 0;
+}
+machine_device_initcall(virtex, virtex_device_probe);
+
+static int __init virtex_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	if (!of_flat_dt_is_compatible(root, "xlnx,virtex440"))
+		return 0;
+
+	return 1;
+}
+
+define_machine(virtex) {
+	.name			= "Xilinx Virtex440",
+	.probe			= virtex_probe,
+	.init_IRQ		= xilinx_intc_init_tree,
+	.get_irq		= xilinx_intc_get_irq,
+	.calibrate_decr		= generic_calibrate_decr,
+	.restart		= ppc4xx_reset_system,
+};
-- 
1.5.2.1



This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

^ permalink raw reply related

* Re: [PATCH] powerpc: add of_find_next_property andof_get_aliased_index
From: Stefan Roese @ 2008-07-03 13:43 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev, Timur Tabi, Sean MacLennan
In-Reply-To: <20080703093313.478e6773@zod.rchland.ibm.com>

On Thursday 03 July 2008, Josh Boyer wrote:
> > Now I have no idea how to support I2C on the other 4xx boards. Perhaps
> > Josh could advise how this should be done?
>
> As David said elsewhere, cell-index is fine for figuring out how to
> access the CPM registers, etc.  But it's not good for enumerating
> across the whole system.
>
> For I2C specifically, I think Sean already has a patch to switch the
> 4xx driver to not use the numbered functions, which eliminates the need
> for the enumeration all together.  That seems like the right approach
> to me.

Yes. I'm waiting for Sean's next patch version... :)

Best regards,
Stefan

^ permalink raw reply

* Re: [PATCH] powerpc: add of_find_next_property andof_get_aliased_index
From: Josh Boyer @ 2008-07-03 13:33 UTC (permalink / raw)
  To: Stefan Roese; +Cc: linuxppc-dev, Timur Tabi, Sean MacLennan
In-Reply-To: <200806262041.12275.sr@denx.de>

On Thu, 26 Jun 2008 20:41:12 +0200
Stefan Roese <sr@denx.de> wrote:

> On Thursday 26 June 2008, Sean MacLennan wrote:
> > > Well, there's a lot of disagreement on this subject.  Not only do we
> > > not agree on a method of enumerating devices, a lot of people have a
> > > problem with the concept of enumerating them in the first place!
> >
> > An interesting point is that I enforced an index in the i2c-ibm_iic
> > driver with no disagreement at all ;)
> 
> You have been lucky I suppose. :)
> 
> I could easily just have used this existing "index" property for the other 4xx 
> boards, but expected NAK's for this. That and because FSL uses "cell-index" 
> is why I asked prior to sending patches.
> 
> Now I have no idea how to support I2C on the other 4xx boards. Perhaps Josh 
> could advise how this should be done?

As David said elsewhere, cell-index is fine for figuring out how to
access the CPM registers, etc.  But it's not good for enumerating
across the whole system.

For I2C specifically, I think Sean already has a patch to switch the
4xx driver to not use the numbered functions, which eliminates the need
for the enumeration all together.  That seems like the right approach
to me.

josh

^ permalink raw reply

* RE: [PATCH] powerpc: Xilinx: add 440 platform support
From: John Linn @ 2008-07-03 13:25 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev
In-Reply-To: <20080703092107.3c0d9122@zod.rchland.ibm.com>

Not a problem, I'll add it and respin the patch.

> -----Original Message-----
> From: Josh Boyer [mailto:jwboyer@linux.vnet.ibm.com]
> Sent: Thursday, July 03, 2008 7:21 AM
> To: John Linn
> Cc: linuxppc-dev@ozlabs.org; grant.likely@secretlab.ca
> Subject: Re: [PATCH] powerpc: Xilinx: add 440 platform support
> =

> On Thu, 3 Jul 2008 07:20:45 -0600
> John Linn <John.Linn@xilinx.com> wrote:
> =

> > XILINX_VIRTEX_5_FXT is the FPGA architecture, which has a 440 and
can be
> > on a number of different boards.
> =

> Could you add that as some help text under the config option for
5_FXT?
> That way you don't have to answer that question over and over from
> stupid people like me :)
> =

> josh


This email and any attachments are intended for the sole use of the named r=
ecipient(s) and contain(s) confidential information that may be proprietary=
, privileged or copyrighted under applicable law. If you are not the intend=
ed recipient, do not read, copy, or forward this email message or any attac=
hments. Delete this email message and any attachments immediately.

^ permalink raw reply

* Re: [PATCH] powerpc: Xilinx: add 440 platform support
From: Josh Boyer @ 2008-07-03 13:21 UTC (permalink / raw)
  To: John Linn; +Cc: linuxppc-dev
In-Reply-To: <20080703132047.62AA8A20055@mail137-wa4.bigfish.com>

On Thu, 3 Jul 2008 07:20:45 -0600
John Linn <John.Linn@xilinx.com> wrote:

> XILINX_VIRTEX_5_FXT is the FPGA architecture, which has a 440 and can be
> on a number of different boards.

Could you add that as some help text under the config option for 5_FXT?
That way you don't have to answer that question over and over from
stupid people like me :)

josh

^ permalink raw reply

* RE: [PATCH] powerpc: Xilinx: add 440 platform support
From: John Linn @ 2008-07-03 13:20 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev
In-Reply-To: <20080703091448.4e298ce8@zod.rchland.ibm.com>

XILINX_VIRTEX_5_FXT is the FPGA architecture, which has a 440 and can be
on a number of different boards.

Thanks,
John

> -----Original Message-----
> From: Josh Boyer [mailto:jwboyer@linux.vnet.ibm.com]
> Sent: Thursday, July 03, 2008 7:15 AM
> To: John Linn
> Cc: linuxppc-dev@ozlabs.org; grant.likely@secretlab.ca; John Linn
> Subject: Re: [PATCH] powerpc: Xilinx: add 440 platform support
> =

> On Tue, 1 Jul 2008 15:48:26 -0700
> John Linn <john.linn@xilinx.com> wrote:
> =

> > Support for the Xilinx Virtex5 FXT 440 is being
> > added.
> >
> > Signed-off-by: John Linn <john.linn@xilinx.com>
> > ---
> >  arch/powerpc/platforms/44x/Kconfig  |   25 ++++++++++++++
> >  arch/powerpc/platforms/44x/Makefile |    1 +
> >  arch/powerpc/platforms/44x/virtex.c |   60
+++++++++++++++++++++++++++++++++++
> >  3 files changed, 86 insertions(+), 0 deletions(-)
> >  create mode 100644 arch/powerpc/platforms/44x/virtex.c
> >
> > diff --git a/arch/powerpc/platforms/44x/Kconfig
b/arch/powerpc/platforms/44x/Kconfig
> > index 6abe913..84eb847 100644
> > --- a/arch/powerpc/platforms/44x/Kconfig
> > +++ b/arch/powerpc/platforms/44x/Kconfig
> > @@ -102,6 +102,22 @@ config YOSEMITE
> >  #	help
> >  #	  This option enables support for the IBM PPC440GX evaluation
board.
> >
> > +config XILINX_VIRTEX440_GENERIC_BOARD
> > +	bool "Generic Xilinx Virtex 440 board"
> > +	depends on 44x
> > +	default n
> > +	select XILINX_VIRTEX_5_FXT
> =

> If this is for generic Virtex 440 board support, why is it selecting a
> specific Virtex 5 board?  Or am I confused as to what
> XILINX_VIRTEX_5_FXT is?
> =

> josh


This email and any attachments are intended for the sole use of the named r=
ecipient(s) and contain(s) confidential information that may be proprietary=
, privileged or copyrighted under applicable law. If you are not the intend=
ed recipient, do not read, copy, or forward this email message or any attac=
hments. Delete this email message and any attachments immediately.

^ permalink raw reply

* Re: [PATCH] powerpc: Xilinx: add 440 platform support
From: Josh Boyer @ 2008-07-03 13:14 UTC (permalink / raw)
  To: John Linn; +Cc: linuxppc-dev, John Linn
In-Reply-To: <20080701224829.EC51111E8013@mail35-sin.bigfish.com>

On Tue, 1 Jul 2008 15:48:26 -0700
John Linn <john.linn@xilinx.com> wrote:

> Support for the Xilinx Virtex5 FXT 440 is being
> added.
> 
> Signed-off-by: John Linn <john.linn@xilinx.com>
> ---
>  arch/powerpc/platforms/44x/Kconfig  |   25 ++++++++++++++
>  arch/powerpc/platforms/44x/Makefile |    1 +
>  arch/powerpc/platforms/44x/virtex.c |   60 +++++++++++++++++++++++++++++++++++
>  3 files changed, 86 insertions(+), 0 deletions(-)
>  create mode 100644 arch/powerpc/platforms/44x/virtex.c
> 
> diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
> index 6abe913..84eb847 100644
> --- a/arch/powerpc/platforms/44x/Kconfig
> +++ b/arch/powerpc/platforms/44x/Kconfig
> @@ -102,6 +102,22 @@ config YOSEMITE
>  #	help
>  #	  This option enables support for the IBM PPC440GX evaluation board.
> 
> +config XILINX_VIRTEX440_GENERIC_BOARD
> +	bool "Generic Xilinx Virtex 440 board"
> +	depends on 44x
> +	default n
> +	select XILINX_VIRTEX_5_FXT

If this is for generic Virtex 440 board support, why is it selecting a
specific Virtex 5 board?  Or am I confused as to what
XILINX_VIRTEX_5_FXT is?

josh

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox