LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: Making Two ethernet interfaces up in Linux
From: Shantanu Nalage @ 2006-06-08  5:16 UTC (permalink / raw)
  To: Antonio Di Bacco, linuxppc-embedded
In-Reply-To: <200606032255.05997.antonio.dibacco@aruba.it>

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

Thanks for the reply.
The driver which we are using for the ethernet is provided by Xilinx.
In the Linux kernel source, it is located in net/xilinx_enet
directory. We are attaching the adapter file for the driver provided
by Xilinx for the ethernet.
When we gave a first try, it showed two ethernet interfaces eth0 and
eth1 as an output of ifconfig command but only eth0 works, when eth1
is disabled. When both interfaces are up, neither interface works.
While even when eth0 is disabled, eth1 interface doesn't work.

With regards,
Shantanu.

On 6/4/06, Antonio Di Bacco <antonio.dibacco@aruba.it> wrote:
> >          We are trying to port Linux on Xilinx Board XUPV2Pro which is
> > similar in most aspects to the Xilinx ML300 board. Linux is up and
> > running for the original board i.e. having only one ethrnet interface.
> > Now since we wanted to have the board working as router, we designed a
> > daughter board with two ethernet phy interfaces. The MACs required for
> > that are instantiated in Xilinx ....
>
> You have already the driver for the first MAC, then you should start from that
> modifying the init procedure for example and all the others. Your driver
> should initialize both the MACs and also create two devices calling
> init_etherdev tow times. If you post your driver I can suggest what to
> change. It is not so difficult.
>
> Bye,
> Antonio.
>
>

[-- Attachment #2: adapter.c --]
[-- Type: text/plain, Size: 58370 bytes --]

/*
 * adapter.c
 *
 * Xilinx Ethernet Adapter component to interface XEmac component to Linux
 *
 * Author: MontaVista Software, Inc.
 *         source@mvista.com
 *
 * 2002 (c) MontaVista, Software, Inc.  This file is licensed under the terms
 * of the GNU General Public License version 2.1.  This program is licensed
 * "as is" without any warranty of any kind, whether express or implied.
 */

/*
 * This driver is a bit unusual in that it is composed of two logical
 * parts where one part is the OS independent code and the other part is
 * the OS dependent code.  Xilinx provides their drivers split in this
 * fashion.  This file represents the Linux OS dependent part known as
 * the Linux adapter.  The other files in this directory are the OS
 * independent files as provided by Xilinx with no changes made to them.
 * The names exported by those files begin with XEmac_.  All functions
 * in this file that are called by Linux have names that begin with
 * xenet_.  The functions in this file that have Handler in their name
 * are registered as callbacks with the underlying Xilinx OS independent
 * layer.  Any other functions are static helper functions.
 */

#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/mii.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/atomic.h>
#include <linux/ethtool.h>

#include <xbasic_types.h>
#include "xemac.h"
#include "xemac_i.h"
#include "xipif_v1_23_b.h"

#undef XEM_DFT_SEND_DESC
#define XEM_DFT_SEND_DESC    64
#undef XEM_DFT_RECV_DESC
#define XEM_DFT_RECV_DESC   256

#define DRIVER_NAME "Xilinx Eth MAC driver"
#define DRIVER_VERSION "1.0"

MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
MODULE_DESCRIPTION(DRIVER_NAME);
MODULE_LICENSE("GPL");

#define TX_TIMEOUT   (60*HZ)	/* Transmission timeout is 60 seconds. */

/* On the OPB, the 10/100 EMAC requires data to be aligned to 4 bytes.
 * On the PLB, the 10/100 EMAC requires data to be aligned to 8 bytes.
 * For simplicity, we always align to 8 bytes.
 */
#define ALIGNMENT           32

/* BUFFER_ALIGN(adr) calculates the number of bytes to the next alignment. */
#define BUFFER_ALIGN(adr) ((ALIGNMENT - ((u32) adr)) % ALIGNMENT)

/* physical to virtual pointer conversion */
#define P_TO_V(InstancePtr, p) \
	((p) ? \
	 ((InstancePtr)->VirtPtr + ((u32)(p) - (u32)(InstancePtr)->PhyPtr)) : \
	 0)

int bh_entry = 0;

/*
 * Our private per device data.  When a net_device is allocated we will
 * ask for enough extra space for this.
 */
struct net_local {
	struct list_head rcv;
	XBufDescriptor * rcvBdPtr;
	int rcvBds;
	struct list_head xmit;
	XBufDescriptor * xmitBdPtr;
	int xmitBds;

	struct net_device_stats stats;	/* Statistics for this device */
	struct net_device *next_dev;	/* The next device in dev_list */
	struct net_device *dev;		/* this device */
	struct timer_list phy_timer;	/* PHY monitoring timer */
	u32 index;		/* Which interface is this */
	XInterruptHandler Isr;	/* Pointer to the XEmac ISR routine */
	u8 mii_addr;		/* The MII address of the PHY */
	/*
	 * The underlying OS independent code needs space as well.  A
	 * pointer to the following XEmac structure will be passed to
	 * any XEmac_ function that requires it.  However, we treat the
	 * data as an opaque object in this file (meaning that we never
	 * reference any of the fields inside of the structure).
	 */
	XEmac Emac;

	void *desc_space;
	dma_addr_t desc_space_handle;
	int desc_space_size;
    
        u8 *ddrVirtPtr;
        u32 ddrOffset;
        u32 ddrSize;

	struct sk_buff* deferred_skb;

        atomic_t availSendBds;
};

/* List of devices we're handling and a lock to give us atomic access. */
static struct net_device *dev_list = NULL;
static spinlock_t dev_lock = SPIN_LOCK_UNLOCKED;

/* for exclusion of all program flows (processes, ISRs and BHs) possible to share data with current one */
static spinlock_t reset_lock = SPIN_LOCK_UNLOCKED;

/* Helper function to determine if a given XEmac error warrants a reset. */
extern inline int
status_requires_reset(XStatus s)
{
	return (s == XST_DMA_ERROR || s == XST_FIFO_ERROR ||
		s == XST_RESET_ERROR || s == XST_DMA_SG_NO_LIST ||
		s == XST_DMA_SG_LIST_EMPTY);
}

/* BH statics */
LIST_HEAD(receivedQueue);
static spinlock_t rcvSpin = SPIN_LOCK_UNLOCKED;
LIST_HEAD(sentQueue);
static spinlock_t xmitSpin = SPIN_LOCK_UNLOCKED;

/* SAATODO: This function will be moved into the Xilinx code. */
/*****************************************************************************/
/**
*
* Lookup the device configuration based on the emac instance.  The table
* EmacConfigTable contains the configuration info for each device in the system.
*
* @param Instance is the index of the emac being looked up.
*
* @return
*
* A pointer to the configuration table entry corresponding to the given
* device ID, or NULL if no match is found.
*
* @note
*
* None.
*
******************************************************************************/
XEmac_Config *
XEmac_GetConfig(int Instance)
{
	if (Instance < 0 || Instance >= XPAR_XEMAC_NUM_INSTANCES) {
		return NULL;
	}

	return &XEmac_ConfigTable[Instance];
}

/*
 * The following are notes regarding the critical sections in this
 * driver and how they are protected.
 *
 * dev_list
 * There is a spinlock protecting the device list.  It isn't really
 * necessary yet because the list is only manipulated at init and
 * cleanup, but it's there because it is basically free and if we start
 * doing hot add and removal of ethernet devices when the FPGA is
 * reprogrammed while the system is up, we'll need to protect the list.
 *
 * XEmac_Start, XEmac_Stop and XEmac_SetOptions are not thread safe.
 * These functions are called from xenet_open(), xenet_close(), reset(),
 * and xenet_set_multicast_list().  xenet_open() and xenet_close()
 * should be safe because when they do start and stop, they don't have
 * interrupts or timers enabled.  The other side is that they won't be
 * called while a timer or interrupt is being handled.
 *
 * XEmac_PhyRead and XEmac_PhyWrite are not thread safe.
 * These functions are called from get_phy_status(), xenet_ioctl() and
 * probe().  probe() is only called from xenet_init() so it is not an
 * issue (nothing is really up and running yet).  get_phy_status() is
 * called from both poll_mii() (a timer bottom half) and xenet_open().
 * These shouldn't interfere with each other because xenet_open() is
 * what starts the poll_mii() timer.  xenet_open() and xenet_ioctl()
 * should be safe as well because they will be sequential.  That leaves
 * the interaction between poll_mii() and xenet_ioctl().  While the
 * timer bottom half is executing, a new ioctl won't come in so that is
 * taken care of.  That leaves the one case of the poll_mii timer
 * popping while handling an ioctl.  To take care of that case, the
 * timer is deleted when the ioctl comes in and then added back in after
 * the ioctl is finished.
 */

typedef enum DUPLEX { UNKNOWN_DUPLEX, HALF_DUPLEX, FULL_DUPLEX } DUPLEX;
static void
reset(struct net_device *dev, DUPLEX duplex)
{
	struct net_local *lp = (struct net_local *) dev->priv;
	u32 Options;
	u8 IfgPart1;
	u8 IfgPart2;
	u8 SendThreshold;
	u32 SendWaitBound;
	u8 RecvThreshold;
	u32 RecvWaitBound;
	int dma_works;

	/* Shouldn't really be necessary, but shouldn't hurt. */
	netif_stop_queue(dev);

	/*
	 * XEmac_Reset puts the device back to the default state.  We need
	 * to save all the settings we don't already know, reset, restore
	 * the settings, and then restart the emac.
	 */
	XEmac_GetInterframeGap(&lp->Emac, &IfgPart1, &IfgPart2);
	Options = XEmac_GetOptions(&lp->Emac);
	switch (duplex) {
	case HALF_DUPLEX:
		Options &= ~XEM_FDUPLEX_OPTION;
		break;
	case FULL_DUPLEX:
		Options |= XEM_FDUPLEX_OPTION;
		break;
	case UNKNOWN_DUPLEX:
		break;
	}

	if (XEmac_mIsSgDma(&lp->Emac)) {
		/*
		 * The following four functions will return an error if we are
		 * not doing scatter-gather DMA.  We just checked that so we
		 * can safely ignore the return values.  We cast them to void
		 * to make that explicit.
		 */
		dma_works = 1;
		(void) XEmac_GetPktThreshold(&lp->Emac, XEM_SEND,
					     &SendThreshold);
		(void) XEmac_GetPktWaitBound(&lp->Emac, XEM_SEND,
					     &SendWaitBound);
		(void) XEmac_GetPktThreshold(&lp->Emac, XEM_RECV,
					     &RecvThreshold);
		(void) XEmac_GetPktWaitBound(&lp->Emac, XEM_RECV,
					     &RecvWaitBound);
	} else
		dma_works = 0;

	XEmac_Reset(&lp->Emac);

	/*
	 * The following three functions will return an error if the
	 * EMAC is already started.  We just stopped it by calling
	 * XEmac_Reset() so we can safely ignore the return values.
	 * We cast them to void to make that explicit.
	 */
	(void) XEmac_SetMacAddress(&lp->Emac, dev->dev_addr);
	(void) XEmac_SetInterframeGap(&lp->Emac, IfgPart1, IfgPart2);
	(void) XEmac_SetOptions(&lp->Emac, Options);
	if (XEmac_mIsSgDma(&lp->Emac)) {
		/*
		 * The following four functions will return an error if
		 * we are not doing scatter-gather DMA or if the EMAC is
		 * already started.  We just checked that we are indeed
		 * doing scatter-gather and we just stopped the EMAC so
		 * we can safely ignore the return values.  We cast them
		 * to void to make that explicit.
		 */
		(void) XEmac_SetPktThreshold(&lp->Emac, XEM_SEND,
					     SendThreshold);
		(void) XEmac_SetPktWaitBound(&lp->Emac, XEM_SEND,
					     SendWaitBound);
		(void) XEmac_SetPktThreshold(&lp->Emac, XEM_RECV,
					     RecvThreshold);
		(void) XEmac_SetPktWaitBound(&lp->Emac, XEM_RECV,
					     RecvWaitBound);
	}

	/*
	 * XEmac_Start returns an error when: it is already started, the send
	 * and receive handlers are not set, or a scatter-gather DMA list is
	 * missing.  None of these can happen at this point, so we cast the
	 * return to void to make that explicit.
	 */

	if (dma_works) {
		int avail_plus = 0;
		while (!(XDmaChannel_IsSgListEmpty(&(lp->Emac.SendChannel)))) {	/* list isn't empty, has to be cleared */
			XStatus ret;
			XBufDescriptor* BdPtr;

			if ((ret = XDmaChannel_GetDescriptor (&(lp->Emac.SendChannel), &BdPtr)) != XST_SUCCESS) {
				printk (KERN_ERR "SgDma ring structure ERROR %d\n", ret);
				break;
			}
			avail_plus++;
			XBufDescriptor_Unlock(BdPtr);
			pci_unmap_single(NULL,
				(u32) XBufDescriptor_GetSrcAddress(BdPtr),
				 XBufDescriptor_GetLength(BdPtr), PCI_DMA_TODEVICE);
			lp->stats.tx_errors++;
		}
        	atomic_add(avail_plus,&lp->availSendBds);
	} else {
		if (lp->deferred_skb) {
			dev_kfree_skb(lp->deferred_skb);
			lp->deferred_skb = NULL;
			lp->stats.tx_errors++;
		}
	}

	dev->trans_start = 0xffffffff - TX_TIMEOUT - TX_TIMEOUT;	/* to exclude tx timeout */
	(void) XEmac_Start(&lp->Emac);
	/* We're all ready to go.  Start the queue in case it was stopped. */
	if (!bh_entry)
		netif_wake_queue(dev);
}

static int
get_phy_status(struct net_device *dev, DUPLEX * duplex, int *linkup)
{
	struct net_local *lp = (struct net_local *) dev->priv;
	u16 reg;
	XStatus xs;

	xs = XEmac_PhyRead(&lp->Emac, lp->mii_addr, MII_BMCR, &reg);
	if (xs != XST_SUCCESS) {
		printk(KERN_ERR
		       "%s: Could not read PHY control register; error %d\n",
		       dev->name, xs);
		return -1;
	}

	if (!(reg & BMCR_ANENABLE)) {
		/*
		 * Auto-negotiation is disabled so the full duplex bit in
		 * the control register tells us if the PHY is running
		 * half or full duplex.
		 */
		*duplex = (reg & BMCR_FULLDPLX) ? FULL_DUPLEX : HALF_DUPLEX;
	} else {
		/*
		 * Auto-negotiation is enabled.  Figure out what was
		 * negotiated by looking for the best mode in the union
		 * of what we and our partner advertise.
		 */
		u16 advertise, partner, negotiated;

		xs = XEmac_PhyRead(&lp->Emac, lp->mii_addr,
				   MII_ADVERTISE, &advertise);
		if (xs != XST_SUCCESS) {
			printk(KERN_ERR
			       "%s: Could not read PHY advertisement; error %d\n",
			       dev->name, xs);
			return -1;
		}
		xs = XEmac_PhyRead(&lp->Emac, lp->mii_addr, MII_LPA, &partner);
		if (xs != XST_SUCCESS) {
			printk(KERN_ERR
			       "%s: Could not read PHY LPA; error %d\n",
			       dev->name, xs);
			return -1;
		}

		negotiated = advertise & partner & ADVERTISE_ALL;
		if (negotiated & ADVERTISE_100FULL)
			*duplex = FULL_DUPLEX;
		else if (negotiated & ADVERTISE_100HALF)
			*duplex = HALF_DUPLEX;
		else if (negotiated & ADVERTISE_10FULL)
			*duplex = FULL_DUPLEX;
		else
			*duplex = HALF_DUPLEX;
	}

	xs = XEmac_PhyRead(&lp->Emac, lp->mii_addr, MII_BMSR, &reg);
	if (xs != XST_SUCCESS) {
		printk(KERN_ERR
		       "%s: Could not read PHY status register; error %d\n",
		       dev->name, xs);
		return -1;
	}

	*linkup = (reg & BMSR_LSTATUS) != 0;

	return 0;
}

/*
 * This routine is used for two purposes.  The first is to keep the
 * EMAC's duplex setting in sync with the PHY's.  The second is to keep
 * the system apprised of the state of the link.  Note that this driver
 * does not configure the PHY.  Either the PHY should be configured for
 * auto-negotiation or it should be handled by something like mii-tool.
 */
static void
poll_mii(unsigned long data)
{
	struct net_device *dev = (struct net_device *) data;
	struct net_local *lp = (struct net_local *) dev->priv;
	u32 Options;
	DUPLEX phy_duplex, mac_duplex;
	int phy_carrier, netif_carrier;
	unsigned long flags;

	/* First, find out what's going on with the PHY. */
	if (get_phy_status(dev, &phy_duplex, &phy_carrier)) {
		printk(KERN_ERR "%s: Terminating link monitoring.\n",
		       dev->name);
		return;
	}

	/* Second, figure out if we have the EMAC in half or full duplex. */
	Options = XEmac_GetOptions(&lp->Emac);
	mac_duplex = (Options & XEM_FDUPLEX_OPTION) ? FULL_DUPLEX : HALF_DUPLEX;

	/* Now see if there is a mismatch. */
	if (mac_duplex != phy_duplex) {
		/*
		 * Make sure that no interrupts come in that could cause
		 * reentrancy problems in reset.
		 */
		spin_lock_irqsave(reset_lock, flags);
		reset(dev, phy_duplex);		/* the function sets Emac options to match the PHY */
		spin_unlock_irqrestore(reset_lock, flags);
		if (mac_duplex == FULL_DUPLEX)
			printk(KERN_INFO "%s: Duplex has been changed: now %s\n",
				dev->name, "HALF_DUPLEX");
		else
			printk(KERN_INFO "%s: Duplex has been changed: now %s\n",
				dev->name, "FULL_DUPLEX");
	}
	netif_carrier = netif_carrier_ok(dev) != 0;

	if (phy_carrier != netif_carrier) {
		if (phy_carrier) {
			printk(KERN_INFO "%s: Link carrier restored.\n",
			       dev->name);
			netif_carrier_on(dev);
		} else {
			printk(KERN_INFO "%s: Link carrier lost.\n", dev->name);
			netif_carrier_off(dev);
		}
	}

	/* Set up the timer so we'll get called again in 2 seconds. */
	lp->phy_timer.expires = jiffies + 2 * HZ;
	add_timer(&lp->phy_timer);
}

/*
 * This routine is registered with the OS as the function to call when
 * the EMAC interrupts.  It in turn, calls the Xilinx OS independent
 * interrupt function.  There are different interrupt functions for FIFO
 * and scatter-gather so we just set a pointer (Isr) into our private
 * data so we don't have to figure it out here.  The Xilinx OS
 * independent interrupt function will in turn call any callbacks that
 * we have registered for various conditions.
 */
static void
xenet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
	struct net_device *dev = dev_id;
	struct net_local *lp = (struct net_local *) dev->priv;

	/* Call it. */
	(*(lp->Isr)) (&lp->Emac);
}

static int
xenet_open(struct net_device *dev)
{
	struct net_local *lp = (struct net_local *) dev->priv;
	u32 Options;
	DUPLEX phy_duplex, mac_duplex;
	int phy_carrier;

	/*
	 * Just to be safe, stop the device first.  If the device is already
	 * stopped, an error will be returned.  In this case, we don't really
	 * care, so cast it to void to make it explicit.
	 */
	(void) XEmac_Stop(&lp->Emac);
	/* Set the MAC address each time opened. */
	if (XEmac_SetMacAddress(&lp->Emac, dev->dev_addr) != XST_SUCCESS) {
		printk(KERN_ERR "%s: Could not set MAC address.\n", dev->name);
		return -EIO;
	}

	/*
	 * If the device is not configured for polled mode, connect to the
	 * interrupt controller and enable interrupts.  Currently, there
	 * isn't any code to set polled mode, so this check is probably
	 * superfluous.
	 */
	Options = XEmac_GetOptions(&lp->Emac);
	if ((Options & XEM_POLLED_OPTION) == 0) {
		int retval;
		/* Grab the IRQ */
		retval =
		    request_irq(dev->irq, &xenet_interrupt, 0, dev->name, dev);
		if (retval) {
			printk(KERN_ERR
			       "%s: Could not allocate interrupt %d.\n",
			       dev->name, dev->irq);
			return retval;
		}
	}

	/* Set the EMAC's duplex setting based upon what the PHY says. */
	if (!get_phy_status(dev, &phy_duplex, &phy_carrier)) {
		/* We successfully got the PHY status. */
		mac_duplex = ((Options & XEM_FDUPLEX_OPTION)
			      ? FULL_DUPLEX : HALF_DUPLEX);
		if (mac_duplex != phy_duplex) {
			switch (phy_duplex) {
			case HALF_DUPLEX:
				Options &= ~XEM_FDUPLEX_OPTION;
				break;
			case FULL_DUPLEX:
				Options |= XEM_FDUPLEX_OPTION;
				break;
			case UNKNOWN_DUPLEX:
				break;
			}
			/*
			 * The following function will return an error
			 * if the EMAC is already started.  We know it
			 * isn't started so we can safely ignore the
			 * return value.  We cast it to void to make
			 * that explicit.
			 */
		}
	}
	Options |= XEM_FLOW_CONTROL_OPTION;
	(void) XEmac_SetOptions(&lp->Emac, Options);

	INIT_LIST_HEAD(&(lp->rcv));
	lp->rcvBds = 0;
	INIT_LIST_HEAD(&(lp->xmit));
	lp->xmitBds = 0;

	if (XEmac_Start(&lp->Emac) != XST_SUCCESS) {
		printk(KERN_ERR "%s: Could not start device.\n", dev->name);
		free_irq(dev->irq, dev);
		return -EBUSY;
	}

	/* We're ready to go. */
	MOD_INC_USE_COUNT;
	netif_start_queue(dev);

	/* Set up the PHY monitoring timer. */
	lp->phy_timer.expires = jiffies + 2 * HZ;
	lp->phy_timer.data = (unsigned long) dev;
	lp->phy_timer.function = &poll_mii;
	add_timer(&lp->phy_timer);
	return 0;
}
static int
xenet_close(struct net_device *dev)
{
	struct net_local *lp = (struct net_local *) dev->priv;
	unsigned long flags;

	/* Shut down the PHY monitoring timer. */
	del_timer_sync(&lp->phy_timer);

	netif_stop_queue(dev);

	/*
	 * If not in polled mode, free the interrupt.  Currently, there
	 * isn't any code to set polled mode, so this check is probably
	 * superfluous.
	 */
	if ((XEmac_GetOptions(&lp->Emac) & XEM_POLLED_OPTION) == 0)
		free_irq(dev->irq, dev);

	spin_lock_irqsave(rcvSpin, flags);
	list_del(&(lp->rcv));
	spin_unlock_irqrestore(rcvSpin, flags);
	spin_lock_irqsave(xmitSpin, flags);
	list_del(&(lp->xmit));
	spin_unlock_irqrestore(xmitSpin, flags);

	if (XEmac_Stop(&lp->Emac) != XST_SUCCESS) {
		printk(KERN_ERR "%s: Could not stop device.\n", dev->name);
		return -EBUSY;
	}

	MOD_DEC_USE_COUNT;
	return 0;
}
static struct net_device_stats *
xenet_get_stats(struct net_device *dev)
{
	struct net_local *lp = (struct net_local *) dev->priv;
	return &lp->stats;
}

static int
xenet_FifoSend(struct sk_buff *orig_skb, struct net_device *dev)
{
	struct net_local *lp = (struct net_local *) dev->priv;
	struct sk_buff *new_skb;
	unsigned int len, align;
	unsigned long flags;

	len = orig_skb->len;

        /* PR FIXME: what follows can be removed if the asserts in the Xilinx
         * independent drivers change. There is really no need to align the
         * buffers in FIFO mode. The story is different for simple DMA.
         */

        /*
	 * The packet FIFO requires the buffers to be 32/64 bit aligned.
	 * The sk_buff data is not 32/64 bit aligned, so we have to do this
	 * copy.  As you probably well know, this is not optimal.
	 */
	if (!(new_skb = alloc_skb(len + ALIGNMENT, GFP_ATOMIC))) {
		/* We couldn't get another skb. */
		dev_kfree_skb(orig_skb);
		lp->stats.tx_dropped++;
		printk(KERN_ERR "%s: Could not allocate transmit buffer.\n",
		       dev->name);
		netif_wake_queue(dev);
		return -EBUSY;
	}
	/*
	 * A new skb should have the data word aligned, but this code is
	 * here just in case that isn't true...  Calculate how many
	 * bytes we should reserve to get the data to start on a word
	 * boundary.  */
	align = BUFFER_ALIGN(new_skb->data);
	if (align)
		skb_reserve(new_skb, align);

	/* Copy the data from the original skb to the new one. */
	skb_put(new_skb, len);
	memcpy(new_skb->data, orig_skb->data, len);
        
	/* Get rid of the original skb. */
	dev_kfree_skb(orig_skb);
        spin_lock_irqsave(reset_lock, flags);
	if (XEmac_FifoSend(&lp->Emac, (u8 *) new_skb->data, len) != XST_SUCCESS) {
		netif_stop_queue(dev);
		lp->deferred_skb = new_skb;
		spin_unlock_irqrestore(reset_lock, flags);
		return 0;
	}
	spin_unlock_irqrestore(reset_lock, flags);

	lp->stats.tx_bytes += len;
        dev_kfree_skb(new_skb);
	dev->trans_start = jiffies;

	return 0;
}

/* The callback function for completed frames sent in FIFO mode. */
static void
FifoSendHandler(void *CallbackRef)
{
	struct net_device *dev = (struct net_device *) CallbackRef;
	struct net_local *lp = (struct net_local *) dev->priv;

	if (lp->deferred_skb) {
		if (XEmac_FifoSend(&lp->Emac, (u8 *) lp->deferred_skb->data, lp->deferred_skb->len) != XST_SUCCESS) {
			return;
		} else {
			dev_kfree_skb(lp->deferred_skb);
			lp->deferred_skb = NULL;
			netif_wake_queue(dev);
		}
	}
	lp->stats.tx_packets++;
}

/* The send function for frames sent in DMA mode. */
static int
xenet_SgSend(struct sk_buff *skb, struct net_device *dev)
{
        struct net_local *lp = (struct net_local *) dev->priv;
	unsigned int len;
	XBufDescriptor bd;
	int result;
        u32 physAddr;
        u8 *virtAddr;
	unsigned long flags;

        len = skb->len;
        virtAddr = lp->ddrVirtPtr + lp->ddrOffset;

        if (skb->ip_summed == CHECKSUM_NONE)
          /*cacheable_*/memcpy(virtAddr, skb->data, len);
        else
          skb_copy_and_csum_dev(skb, virtAddr);
        
        dev_kfree_skb(skb);

	physAddr = (u32) pci_map_single(NULL, virtAddr, len, PCI_DMA_TODEVICE);
	/*
	 * lock the buffer descriptor to prevent lower layers from reusing
	 * it before the adapter has a chance to deallocate the buffer
	 * attached to it. The adapter will unlock it in the callback function
	 * that handles confirmation of transmits
	 */
	XBufDescriptor_Initialize(&bd);
	XBufDescriptor_Lock(&bd);
	XBufDescriptor_SetSrcAddress(&bd, physAddr);
	XBufDescriptor_SetLength(&bd, len);
	XBufDescriptor_SetLast(&bd);

        lp->ddrOffset += len + BUFFER_ALIGN(len);
        if (lp->ddrOffset + XEM_MAX_FRAME_SIZE > lp->ddrSize)
          lp->ddrOffset = 0;

	spin_lock_irqsave(reset_lock, flags);
        result = XEmac_SgSend(&lp->Emac, &bd, XEM_SGDMA_NODELAY);
	if (result != XST_SUCCESS) {
		lp->stats.tx_dropped++;
		printk(KERN_ERR "%s: ERROR, could not send transmit buffer (%d).\n",
		       dev->name, result);
                /* we should never get here in the first place, but
                 * for some reason the kernel doesn't like -EBUSY here,
                 * so just return 0 and let the stack handle dropped packets.
                 */
                /*		return -EBUSY; */
		spin_unlock_irqrestore(reset_lock, flags);
                return 0;
	}
        
        if (atomic_dec_and_test(&lp->availSendBds)) {
		netif_stop_queue(dev);
        }

	dev->trans_start = jiffies;
	spin_unlock_irqrestore(reset_lock, flags);
	return 0;
}

/* The callback function for completed frames sent in DMA mode. */
static void SgSendHandlerBH (unsigned long p);
static void SgRecvHandlerBH (unsigned long p);

DECLARE_TASKLET (SgSendBH, SgSendHandlerBH, 0);
DECLARE_TASKLET (SgRecvBH, SgRecvHandlerBH, 0);

static void
SgSendHandlerBH (unsigned long p)
{
	struct net_device *dev;
	struct net_local *lp;
	XBufDescriptor * BdPtr;
	u32 NumBds;
	u32 len;
	XBufDescriptor *curbd;
	unsigned long flags;

	while (1) {
		spin_lock_irqsave(xmitSpin,flags);
		if (list_empty(&sentQueue)) {
			spin_unlock_irqrestore(xmitSpin,flags);
			break;
		}
		lp = list_entry(sentQueue.next, struct net_local, xmit);
		list_del_init(&(lp->xmit));
		NumBds = lp->xmitBds;
		BdPtr = lp->xmitBdPtr;
		dev = lp->dev;
		atomic_add(NumBds, &lp->availSendBds);
		while(NumBds != 0) {
			NumBds--;

			len = XBufDescriptor_GetLength(BdPtr);
			pci_unmap_single(NULL,
				(u32) XBufDescriptor_GetSrcAddress(BdPtr),
				 len, PCI_DMA_TODEVICE);

			lp->stats.tx_bytes += len;
			lp->stats.tx_packets++;

			curbd = BdPtr;
			BdPtr = P_TO_V(&lp->Emac.SendChannel,
				XBufDescriptor_GetNextPtr(BdPtr));
			XBufDescriptor_Unlock(curbd);
		}
		spin_unlock_irqrestore(xmitSpin,flags);
		netif_wake_queue(dev);
	}
}

static void
SgSendHandler(void *CallBackRef, XBufDescriptor * BdPtr, u32 NumBds)
{
	struct net_device *dev = (struct net_device *) CallBackRef;
	struct net_local *lp = (struct net_local *) dev->priv;
	struct list_head* cur_lp = NULL;

	spin_lock(xmitSpin);
	list_for_each (cur_lp, &sentQueue) {
		if (cur_lp == &(lp->xmit)) {
			lp->xmitBds += NumBds;
			break;
		}
	}
	if (cur_lp != &(lp->xmit)) {
		lp->xmitBds = NumBds;
		lp->xmitBdPtr = BdPtr;
		list_add_tail(&lp->xmit,&sentQueue);
		bh_entry++;
		tasklet_schedule (&SgSendBH);
	}
	spin_unlock(xmitSpin);
}

static void
SgRecvHandlerBH (unsigned long p)
{
	struct net_device *dev;
	struct net_local *lp;
	XBufDescriptor* BdPtr;
	int NumBds;
	struct sk_buff *skb, *new_skb;
	u32 len, new_skb_vaddr;
	dma_addr_t skb_vaddr;
	u32 align;
	XStatus result;
	XBufDescriptor *curbd;
	unsigned long flags;

	while (1) {
		spin_lock_irqsave(rcvSpin,flags);
		if (list_empty(&receivedQueue)) {
			spin_unlock_irqrestore(rcvSpin,flags);
			break;
		}
		lp = list_entry(receivedQueue.next, struct net_local, rcv);
		list_del_init(&(lp->rcv));
		NumBds = lp->rcvBds;
		BdPtr = lp->rcvBdPtr;
		dev = lp->dev;
		spin_unlock_irqrestore(rcvSpin,flags);
		while (NumBds != 0) {
			NumBds--;

			/* get ptr to skb */
			skb = (struct sk_buff *) XBufDescriptor_GetId(BdPtr);
			len = XBufDescriptor_GetLength(BdPtr);

			/* we have all the information we need - move on */
			curbd = BdPtr;
			BdPtr = P_TO_V(&lp->Emac.RecvChannel,
				XBufDescriptor_GetNextPtr(curbd));

			skb_vaddr = (dma_addr_t)XBufDescriptor_GetDestAddress(curbd);
			pci_unmap_single(NULL, skb_vaddr, len, PCI_DMA_FROMDEVICE);

			/* replace skb with a new one */
			new_skb = alloc_skb(XEM_MAX_FRAME_SIZE + ALIGNMENT, GFP_ATOMIC);
			if (new_skb == 0) {
				printk("SgRecvHandler: no mem for new_skb\n");
				return;
			}

			/* make sure we're long-word aligned */
			align = BUFFER_ALIGN(new_skb->data);
			if (align) {
				skb_reserve(new_skb, align);
			}

			new_skb_vaddr = (u32) pci_map_single(NULL, new_skb->data,
						     XEM_MAX_FRAME_SIZE,
						     PCI_DMA_FROMDEVICE);

			XBufDescriptor_SetDestAddress(curbd, new_skb_vaddr);
			XBufDescriptor_SetLength(curbd, XEM_MAX_FRAME_SIZE);
			XBufDescriptor_SetId(curbd, new_skb);
			XBufDescriptor_Unlock(curbd);

			/* give the descriptor back to the driver */
			result = XEmac_SgRecv(&lp->Emac, curbd);
			if (result != XST_SUCCESS) {
				printk("SgRecvHandler: SgRecv unsuccessful\n");
				return;
			}

			/* back to the original skb */
			skb->len = len;
			skb->dev = dev;
			skb->protocol = eth_type_trans(skb, dev);
			skb->ip_summed = CHECKSUM_NONE;

			lp->stats.rx_packets++;
			lp->stats.rx_bytes += len;

			netif_rx(skb);          /* Send the packet upstream. */
		}
	}
}

static void
SgRecvHandler(void *CallBackRef, XBufDescriptor * BdPtr, u32 NumBds)
{
	struct net_device *dev = (struct net_device *) CallBackRef;
	struct net_local *lp = (struct net_local *) dev->priv;
	struct list_head* cur_lp = NULL;

	spin_lock(rcvSpin);
	list_for_each (cur_lp, &receivedQueue) {
		if (cur_lp == &(lp->rcv)) {
			lp->rcvBds += NumBds;
			break;
		}
	}
	if (cur_lp != &(lp->rcv)) {
		lp->rcvBds = NumBds;
		lp->rcvBdPtr = BdPtr;
		list_add_tail(&lp->rcv, &receivedQueue);
		tasklet_schedule (&SgRecvBH);
	}
	spin_unlock(rcvSpin);
}

static void
xenet_tx_timeout(struct net_device *dev)
{
	struct net_local *lp = (struct net_local *) dev->priv;
	unsigned long flags;

	printk("%s: Exceeded transmit timeout of %lu ms.\n",
	       dev->name, TX_TIMEOUT * 1000UL / HZ);

	lp->stats.tx_errors++;
	spin_lock_irqsave(reset_lock, flags);
	reset(dev, UNKNOWN_DUPLEX);
	spin_unlock_irqrestore(reset_lock, flags);
}

/* The callback function for frames received when in FIFO mode. */
static void
FifoRecvHandler(void *CallbackRef)
{
	struct net_device *dev = (struct net_device *) CallbackRef;
	struct net_local *lp = (struct net_local *) dev->priv;
	struct sk_buff *skb;
	unsigned int align;
	u32 len;
	XStatus Result;

	/*
	 * The OS independent Xilinx EMAC code does not provide a
	 * function to get the length of an incoming packet and a
	 * separate call to actually get the packet data.  It does this
	 * because they didn't add any code to keep the hardware's
	 * receive length and data FIFOs in sync.  Instead, they require
	 * that you send a maximal length buffer so that they can read
	 * the length and data FIFOs in a single chunk of code so that
	 * they can't get out of sync.  So, we need to allocate an skb
	 * that can hold a maximal sized packet.  The OS independent
	 * code needs to see the data 32/64-bit aligned, so we tack on an
	 * extra four just in case we need to do an skb_reserve to get
	 * it that way.
	 */
	len = XEM_MAX_FRAME_SIZE;
	if (!(skb = alloc_skb(len + ALIGNMENT, GFP_ATOMIC))) {
		/* Couldn't get memory. */
		lp->stats.rx_dropped++;
		printk(KERN_ERR "%s: Could not allocate receive buffer.\n",
		       dev->name);
		return;
	}

	/*
	 * A new skb should have the data word aligned, but this code is
	 * here just in case that isn't true...  Calculate how many
	 * bytes we should reserve to get the data to start on a word
	 * boundary.  */
	align = BUFFER_ALIGN(skb->data);
	if (align)
		skb_reserve(skb, align);

	Result = XEmac_FifoRecv(&lp->Emac, (u8 *) skb->data, &len);
	if (Result != XST_SUCCESS) {
		int need_reset = status_requires_reset(Result);

		lp->stats.rx_errors++;
		dev_kfree_skb(skb);
		printk(KERN_ERR "%s: Could not receive buffer, error=%d%s.\n",
		       dev->name, Result,
			need_reset ? ", resetting device." : "");
		if (need_reset) {
			spin_lock(reset_lock);
			reset(dev, UNKNOWN_DUPLEX);
			spin_unlock(reset_lock);
		}

		return;
	}

	skb_put(skb, len);	/* Tell the skb how much data we got. */
	skb->dev = dev;		/* Fill out required meta-data. */
	skb->protocol = eth_type_trans(skb, dev);
        skb->ip_summed = CHECKSUM_NONE;

	lp->stats.rx_packets++;
	lp->stats.rx_bytes += len;

	netif_rx(skb);		/* Send the packet upstream. */
}

/* The callback function for errors. */
static void
ErrorHandler(void *CallbackRef, XStatus Code)
{
	struct net_device *dev = (struct net_device *) CallbackRef;
	int need_reset = status_requires_reset(Code);
	unsigned long flags;

        /* ignore some errors */
        if (Code == XST_DMA_ERROR)
          return;
	printk(KERN_ERR "%s: device error %d%s\n",
	       dev->name, Code,need_reset ? ", resetting device." : "");
	if (need_reset) {
		spin_lock_irqsave(reset_lock, flags);
		reset(dev, UNKNOWN_DUPLEX);
		spin_unlock_irqrestore(reset_lock, flags);
	}
}

static int
descriptor_init(struct net_device *dev)
{
	struct net_local *lp = (struct net_local *) dev->priv;
	int i, recvsize, sendsize;
	int dftsize;
	u32 *recvpoolptr, *sendpoolptr;
	void *recvpoolphy, *sendpoolphy;

	/* calc size of descriptor space pool; alloc from non-cached memory */
	dftsize = (XEM_DFT_RECV_DESC + XEM_DFT_SEND_DESC) *
	    sizeof (XBufDescriptor);
        
	lp->desc_space = consistent_alloc(GFP_ATOMIC, dftsize,
					  &lp->desc_space_handle);
	if (lp->desc_space == 0) {
		return -1;
	}
	lp->desc_space_size = dftsize;

        lp->ddrSize = XEM_DFT_SEND_DESC * (XEM_MAX_FRAME_SIZE + ALIGNMENT);
        lp->ddrOffset = 0;
        lp->ddrVirtPtr = kmalloc(lp->ddrSize, GFP_ATOMIC);
        
        if (lp->ddrVirtPtr == 0)
          return -1;

        atomic_set(&lp->availSendBds, XEM_DFT_SEND_DESC);

	/* calc size of send and recv descriptor space */
	recvsize = XEM_DFT_RECV_DESC * sizeof (XBufDescriptor);
	sendsize = XEM_DFT_SEND_DESC * sizeof (XBufDescriptor);

	recvpoolptr = lp->desc_space;
	sendpoolptr = (void *) ((u32) lp->desc_space + recvsize);

	recvpoolphy = (void *) lp->desc_space_handle;
	sendpoolphy = (void *) ((u32) lp->desc_space_handle + recvsize);

	/* add ptr to descriptor space to the driver */
	XEmac_SetSgRecvSpace(&lp->Emac, recvpoolptr, recvsize, recvpoolphy);
	XEmac_SetSgSendSpace(&lp->Emac, sendpoolptr, sendsize, sendpoolphy);

	/* allocate skb's and give them to the dma engine */
	for (i = 0; i < XEM_DFT_RECV_DESC; i++) {
		struct sk_buff *skb;
		XBufDescriptor bd;
		int result;
		u32 skb_vaddr, align;

		skb = alloc_skb(XEM_MAX_FRAME_SIZE + ALIGNMENT, GFP_ATOMIC);
		if (skb == 0) {
			return -1;
		}

		align = BUFFER_ALIGN(skb->data);
		if (align)
			skb_reserve(skb, align);

		skb_vaddr = (u32) pci_map_single(NULL, skb->data,
						 XEM_MAX_FRAME_SIZE,
						 PCI_DMA_FROMDEVICE);

		/*
		 * initialize descriptors and set buffer address
		 * buffer length gets max frame size
		 */
		XBufDescriptor_Initialize(&bd);
		XBufDescriptor_Lock(&bd);
		XBufDescriptor_SetDestAddress(&bd, skb_vaddr);
		XBufDescriptor_SetLength(&bd, XEM_MAX_FRAME_SIZE);
		XBufDescriptor_SetId(&bd, skb);

		/*
		 * descriptor with attached buffer to the driver and
		 * let it make it ready for frame reception
		 */
		result = XEmac_SgRecv(&lp->Emac, &bd);
		if (result != XST_SUCCESS) {
			return -1;
		}
	}

	return 0;
}

void
free_descriptor_skb (struct net_device *dev)
{
	struct net_local *lp = (struct net_local *) dev->priv;
	int i;
	XBufDescriptor* BdPtr;
	struct sk_buff* skb;

	BdPtr = (XBufDescriptor*)lp->Emac.RecvChannel.VirtPtr;
	for (i=0; i<XEM_DFT_RECV_DESC; i++) {
		skb = (struct sk_buff*)XBufDescriptor_GetId(BdPtr);
		pci_unmap_single(NULL, virt_to_bus(skb->data), XBufDescriptor_GetLength(BdPtr), PCI_DMA_FROMDEVICE);
		dev_kfree_skb(skb);
		BdPtr = P_TO_V(&lp->Emac.RecvChannel,XBufDescriptor_GetNextPtr(BdPtr));
	}
}

static void
xenet_set_multicast_list(struct net_device *dev)
{
	struct net_local *lp = (struct net_local *) dev->priv;
	u32 Options;
	int ret = 0;
	unsigned long flags;

	/*
	 * XEmac_Start, XEmac_Stop and XEmac_SetOptions are supposed to
	 * be protected by a semaphore. We do have one area in which
	 * this is a problem.
	 *
	 * xenet_set_multicast_list() is called while the link is up and
	 * interrupts are enabled, so at any point in time we could get
	 * an error that causes our reset() to be called.  reset() calls
	 * the aforementioned functions, and we need to call them from
	 * here as well.
	 *
	 * The solution is to make sure that we don't get interrupts or
	 * timers popping while we are in this function.
	 */
        spin_lock_irqsave(reset_lock, flags);

	if ((ret = XEmac_Stop(&lp->Emac)) == XST_SUCCESS) {

		Options = XEmac_GetOptions(&lp->Emac);

		/* Clear out the bits we may set. */
		Options &= ~(XEM_PROMISC_OPTION | XEM_MULTICAST_OPTION);

		if (dev->flags & IFF_PROMISC)
			Options |= XEM_PROMISC_OPTION;
#if 0
		else {
			/*
			 * SAATODO: Xilinx is going to add multicast support to their
			 * VxWorks adapter and OS independent layer.  After that is
			 * done, this skeleton code should be fleshed out.  Note that
			 * IFF_MULTICAST is being masked out from dev->flags in probe,
			 * so that will need to be removed to actually do multidrop.
			 */
			if ((dev->flags & IFF_ALLMULTI)
			    || dev->mc_count > MAX_MULTICAST ? ? ?) {
				xemac_get_all_multicast ? ? ? ();
				Options |= XEM_MULTICAST_OPTION;
			} else if (dev->mc_count != 0) {
				struct dev_mc_list *mc;

				XEmac_MulticastClear(&lp->Emac);
				for (mc = dev->mc_list; mc; mc = mc->next)
						XEmac_MulticastAdd(&lp->Emac, mc->dmi_addr);
					Options |= XEM_MULTICAST_OPTION;
			}
		}
#endif

		/*
		 * The following function will return an error if the EMAC is already
		 * started.  We know it isn't started so we can safely ignore the
		 * return value.  We cast it to void to make that explicit.
		 */
		(void) XEmac_SetOptions(&lp->Emac, Options);

		/*
		 * XEmac_Start returns an error when: it is already started, the send
		 * and receive handlers are not set, or a scatter-gather DMA list is
		 * missing.  None of these can happen at this point, so we cast the
		 * return to void to make that explicit.
		 */
		(void) XEmac_Start(&lp->Emac);
	}
	/* All done, get those interrupts and timers going again. */
	spin_unlock_irqrestore(reset_lock, flags);
}

static int
xenet_ethtool_get_settings (struct net_device *dev, struct ethtool_cmd* ecmd)
{
	int ret;
	struct net_local *lp = (struct net_local *) dev->priv;
	u32 mac_options;
	u8 threshold;
	u16 mii_cmd;
	u16 mii_status;
	u16 mii_advControl;
	XStatus xs;

	memset (ecmd, 0, sizeof(struct ethtool_cmd));
	mac_options = XEmac_GetOptions (&(lp->Emac));
	xs = XEmac_PhyRead(&lp->Emac, lp->mii_addr, MII_BMCR, &mii_cmd);
	if (xs != XST_SUCCESS) {
		printk(KERN_ERR
		       "%s: Could not read mii command register; error %d\n",
		       dev->name, xs);
		return -1;
	}
	xs = XEmac_PhyRead(&lp->Emac, lp->mii_addr, MII_BMSR, &mii_status);
	if (xs != XST_SUCCESS) {
		printk(KERN_ERR
		       "%s: Could not read mii status register; error %d\n",
		       dev->name, xs);
		return -1;
	}
	xs = XEmac_PhyRead(&lp->Emac, lp->mii_addr, MII_ADVERTISE, &mii_advControl);
	if (xs != XST_SUCCESS) {
		printk(KERN_ERR
		       "%s: Could not read mii advertisement control register; error %d\n",
		       dev->name, xs);
		return -1;
	}

	if (mac_options & XEM_FDUPLEX_OPTION)
		ecmd->duplex = DUPLEX_FULL;
	else
		ecmd->duplex = DUPLEX_HALF;
	if (mii_status & BMSR_100FULL)
		ecmd->supported |= SUPPORTED_100baseT_Full;
	if (mii_status & BMSR_100HALF)
		ecmd->supported |= SUPPORTED_100baseT_Half;
	if (mii_status & BMSR_10FULL)
		ecmd->supported |= SUPPORTED_10baseT_Full;
	if (mii_status & BMSR_10HALF)
		ecmd->supported |= SUPPORTED_10baseT_Half;
	if (XEmac_mHasMii(&(lp->Emac)))
		ecmd->supported |= SUPPORTED_MII;
	else
		ecmd->supported &= (~SUPPORTED_MII);
	if (mii_status & BMSR_ANEGCAPABLE)
		ecmd->supported |= SUPPORTED_Autoneg;
	if (mii_status & BMSR_ANEGCOMPLETE) {
		ecmd->autoneg = AUTONEG_ENABLE;
		ecmd->advertising |= ADVERTISED_Autoneg;
		if ((mii_advControl & ADVERTISE_100FULL) || (mii_advControl & ADVERTISE_100HALF))
			ecmd->speed = SPEED_100;
		else
			ecmd->speed = SPEED_10;
	} else {
		ecmd->autoneg = AUTONEG_DISABLE;
		if (mii_cmd & BMCR_SPEED100)
			ecmd->speed = SPEED_100;
		else
			ecmd->speed = SPEED_10;
	}
	if (mii_advControl & ADVERTISE_10FULL)
		ecmd->advertising |= ADVERTISED_10baseT_Full;
	if (mii_advControl & ADVERTISE_10HALF)
		ecmd->advertising |= ADVERTISED_10baseT_Half;
	if (mii_advControl & ADVERTISE_100FULL)
		ecmd->advertising |= ADVERTISED_100baseT_Full;
	if (mii_advControl & ADVERTISE_100HALF)
		ecmd->advertising |= ADVERTISED_100baseT_Half;
	ecmd->advertising |= ADVERTISED_MII;
	ecmd->port = PORT_MII;
	ecmd->phy_address = lp->Emac.PhysAddress;
	ecmd->transceiver = XCVR_INTERNAL;
	if (XEmac_mIsSgDma(&lp->Emac)) {
		if ((ret = XEmac_GetPktThreshold(&lp->Emac, XEM_SEND, &threshold)) == XST_SUCCESS) {
			ecmd->maxtxpkt = threshold;
		} else
			return -EIO;
		if ((ret = XEmac_GetPktThreshold(&lp->Emac, XEM_RECV, &threshold)) == XST_SUCCESS) {
			ecmd->maxrxpkt = threshold;
		} else
			return -EIO;
	}
	return 0;
}

static int
xenet_ethtool_get_coalesce (struct net_device *dev, struct ethtool_coalesce* ec)
{
	int ret;
	struct net_local *lp = (struct net_local *) dev->priv;
	u8 threshold;

	memset (ec, 0, sizeof(struct ethtool_coalesce));
	if ((ret = XEmac_GetPktThreshold(&lp->Emac, XEM_RECV, &threshold)) != XST_SUCCESS) {
		printk(KERN_INFO "XEmac_GetPktThreshold error %d\n", ret);
		return -EIO;
	}
	ec->rx_max_coalesced_frames = threshold;
	if ((ret = XEmac_GetPktWaitBound (&lp->Emac, XEM_RECV, &(ec->rx_coalesce_usecs))) != XST_SUCCESS) {
		printk (KERN_INFO "XEmac_GetPktWaitBound error %d\n", ret);
		return -EIO;
	}
	if ((ret = XEmac_GetPktThreshold(&lp->Emac, XEM_SEND, &threshold)) != XST_SUCCESS) {
		printk (KERN_INFO "XEmac_GetPktThreshold send error %d\n", ret);
		return -EIO;
	}
	ec->tx_max_coalesced_frames = threshold; 
	if ((ret = XEmac_GetPktWaitBound (&lp->Emac, XEM_SEND, &(ec->tx_coalesce_usecs))) != XST_SUCCESS) {
		printk (KERN_INFO "XEmac_GetPktWaitBound send error %d\n", ret);
		return -EIO;
	}
	return 0;
}

static int
xenet_ethtool_set_coalesce (struct net_device *dev, struct ethtool_coalesce* ec)
{
	int ret;
	struct net_local *lp = (struct net_local *) dev->priv;
	unsigned long flags;

	spin_lock_irqsave(reset_lock, flags);
	if ((ret = XEmac_Stop(&lp->Emac)) != XST_SUCCESS)
		return -EIO;
	if ((ret = XEmac_SetPktThreshold(&lp->Emac, XEM_RECV, ec->rx_max_coalesced_frames)) != XST_SUCCESS) {
		printk (KERN_INFO "XEmac_SetPktThreshold error %d\n", ret);
		return -EIO;
	} 
	if ((ret = XEmac_SetPktWaitBound (&lp->Emac, XEM_RECV, ec->rx_coalesce_usecs)) != XST_SUCCESS) {
		printk (KERN_INFO "XEmac_SetPktWaitBound error %d\n", ret);
		return -EIO;
	}
	if ((ret = XEmac_SetPktThreshold(&lp->Emac, XEM_SEND, ec->tx_max_coalesced_frames)) != XST_SUCCESS) {
		printk (KERN_INFO "XEmac_SetPktThreshold send error %d\n", ret);
		return -EIO;
	} 
	if ((ret = XEmac_SetPktWaitBound (&lp->Emac, XEM_SEND, ec->tx_coalesce_usecs)) != XST_SUCCESS) {
		printk (KERN_INFO "XEmac_SetPktWaitBound send error %d\n", ret);
		return -EIO;
	}
	if ((ret = XEmac_Start(&lp->Emac)) != XST_SUCCESS)
		return -EIO;
	spin_unlock_irqrestore(reset_lock, flags);
	return 0;
}

static int
xenet_ethtool_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo* ed)
{
	memset (ed, 0, sizeof(struct ethtool_drvinfo));
	strcpy (ed->driver, DRIVER_NAME);
	strcpy (ed->version, DRIVER_VERSION);
	return 0; 
}

static int
xenet_ethtool_get_ringparam (struct net_device *dev, struct ethtool_ringparam* erp)
{
	memset (erp, 0, sizeof(struct ethtool_ringparam));
	erp->rx_max_pending = XEM_DFT_RECV_DESC;
	erp->tx_max_pending = XEM_DFT_SEND_DESC;
	erp->rx_pending = XEM_DFT_RECV_DESC;
	erp->tx_pending = XEM_DFT_SEND_DESC;
	return 0;
}

#define EMAG_REGS_N	32
struct mac_regsDump {
	struct ethtool_regs hd;
	u16 data[EMAG_REGS_N];
};

static void
xenet_ethtool_get_regs (struct net_device *dev, struct ethtool_regs* regs, void* ret)
{
	struct net_local *lp = (struct net_local *) dev->priv;
	struct mac_regsDump* dump = (struct mac_regsDump*)regs;
	int i;
	XStatus r;

	dump->hd.version = 0;
	dump->hd.len = EMAG_REGS_N * sizeof(dump->data);
	for (i=0; i<EMAG_REGS_N; i++) {
		if ((r = XEmac_PhyRead (&(lp->Emac), lp->mii_addr, i, &(dump->data[i]))) != XST_SUCCESS) {
			printk (KERN_INFO "PhyRead ERROR %d\n", r);
			*(int*)ret = -EIO;
			return;
		}
	}
	*(int*)ret = 0;
}

static int
xenet_do_ethtool_ioctl (struct net_device *dev, struct ifreq *rq)
{
	struct net_local *lp = (struct net_local *) dev->priv;
	struct ethtool_cmd ecmd;
	struct ethtool_coalesce eco;
	struct ethtool_drvinfo edrv;
	struct ethtool_ringparam erp;
	struct ethtool_pauseparam epp;
	struct mac_regsDump regs;
	int ret = -EOPNOTSUPP;
	XStatus result;
	u32 Options;
	u16 mii_reg_sset;
	u16 mii_reg_spause;
	u16 mii_reg_autoneg;
	u32 flags;

	if (copy_from_user(&ecmd, rq->ifr_data, sizeof (ecmd.cmd)))
		return -EFAULT;
	switch (ecmd.cmd) {
	case ETHTOOL_GSET:
		ret = xenet_ethtool_get_settings(dev, &ecmd);
		if (ret >= 0) {
			if (copy_to_user(rq->ifr_data, &ecmd, sizeof (ecmd)))
				ret = -EFAULT;
		}
		break;
	case ETHTOOL_SSET:
		if (copy_from_user(&ecmd, rq->ifr_data, sizeof (struct ethtool_cmd)))
			return -EFAULT;
		mii_reg_sset = 0;
		if (ecmd.speed == SPEED_100)
			mii_reg_sset |= BMCR_SPEED100;
		if (ecmd.duplex == DUPLEX_FULL)
			mii_reg_sset |= BMCR_FULLDPLX;
		if (ecmd.autoneg == AUTONEG_ENABLE) {
			mii_reg_sset |= (BMCR_ANENABLE | BMCR_ANRESTART);
			spin_lock_irqsave(reset_lock, flags);
			result = XEmac_PhyWrite(&lp->Emac, lp->mii_addr,
						MII_BMCR, mii_reg_sset);
			if (result != XST_SUCCESS) {
				spin_unlock_irqrestore(reset_lock, flags);
				ret = -EIO;
				break;
			}
			result = XEmac_PhyRead(&lp->Emac, lp->mii_addr, MII_ADVERTISE, &mii_reg_sset);
			if (result != XST_SUCCESS) {
				spin_unlock_irqrestore(reset_lock, flags);
				ret = -EIO;
				break;
			}
			if (ecmd.speed == SPEED_100) {
				if (ecmd.duplex == DUPLEX_FULL) {
					mii_reg_sset |= (ADVERTISE_10FULL | ADVERTISE_100FULL |
						ADVERTISE_10HALF | ADVERTISE_100HALF);
				} else {
					mii_reg_sset |= (ADVERTISE_10HALF | ADVERTISE_100HALF);
					mii_reg_sset &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL);
				}
			} else {
				if (ecmd.duplex == DUPLEX_FULL) {
					mii_reg_sset |= (ADVERTISE_10FULL | ADVERTISE_10HALF);
					mii_reg_sset &= ~(ADVERTISE_100FULL| ADVERTISE_100HALF);
				} else {
					mii_reg_sset |= (ADVERTISE_10HALF);
					mii_reg_sset &= ~(ADVERTISE_100FULL| ADVERTISE_100HALF | ADVERTISE_10FULL);
				}
			}
			result = XEmac_PhyWrite(&lp->Emac, lp->mii_addr, MII_ADVERTISE, mii_reg_sset);
			spin_unlock_irqrestore(reset_lock, flags);
			if (result != XST_SUCCESS) {
				ret = -EIO;
				break;
			}
		} else {
			mii_reg_sset &= ~(BMCR_ANENABLE | BMCR_ANRESTART);
			if (ecmd.duplex == DUPLEX_FULL) {
				mii_reg_sset |= BMCR_FULLDPLX;
			} else {
				mii_reg_sset &= ~BMCR_FULLDPLX;
			}
			if (ecmd.speed == SPEED_100) {
				mii_reg_sset |= BMCR_SPEED100;
			} else {
				mii_reg_sset &= ~BMCR_SPEED100;
			}
			spin_lock_irqsave(reset_lock, flags);
			result = XEmac_PhyWrite(&lp->Emac, lp->mii_addr,
						MII_BMCR, mii_reg_sset);
			spin_unlock_irqrestore(reset_lock, flags);
			if (result != XST_SUCCESS) {
				ret = -EIO;
				break;
			}
		}
		ret = 0;
		break;
	case ETHTOOL_GPAUSEPARAM:
		ret = xenet_ethtool_get_settings(dev, &ecmd);
		if (ret < 0) {
			break;
		}
		epp.cmd = ecmd.cmd;
		epp.autoneg = ecmd.autoneg;
		Options = XEmac_GetOptions(&lp->Emac);
		if (Options & XEM_INSERT_PAD_OPTION) {
			epp.rx_pause = 1;
			epp.tx_pause = 1;
		} else {
			epp.rx_pause = 0;
			epp.tx_pause = 0;
		}
		if (copy_to_user(rq->ifr_data, &epp, sizeof(struct ethtool_pauseparam)))
			ret = -EFAULT;
		else
			ret = 0;
		break;
	case ETHTOOL_SPAUSEPARAM:
		if (copy_from_user(&epp, rq->ifr_data, sizeof (struct ethtool_pauseparam)))
			return -EFAULT;
		ret = xenet_ethtool_get_settings(dev, &ecmd);
		if (ret < 0) {
			break;
		}
		epp.cmd = ecmd.cmd;
		mii_reg_spause = 0;
		if (epp.autoneg == AUTONEG_ENABLE) {
			mii_reg_spause |= (BMCR_ANENABLE | BMCR_ANRESTART);
		} else {
			if (ecmd.speed == SPEED_100)
				mii_reg_spause |= BMCR_SPEED100;
			if (ecmd.duplex == DUPLEX_FULL)
				mii_reg_spause |= BMCR_FULLDPLX;
		}
		spin_lock_irqsave(reset_lock, flags);
		result = XEmac_PhyWrite(&lp->Emac, lp->mii_addr,
					MII_BMCR, mii_reg_spause);
		spin_unlock_irqrestore(reset_lock, flags);
		if (result != XST_SUCCESS) {
			ret = -EIO;
			break;
		}
		if (epp.rx_pause != epp.tx_pause) {
			ret = 0;
			break;
		} else {
			spin_lock_irqsave(reset_lock, flags);
			(void)XEmac_Stop(&(lp->Emac));
			Options = XEmac_GetOptions(&lp->Emac);
			if (epp.rx_pause)
				Options |= XEM_INSERT_PAD_OPTION;
			else
				Options &= ~XEM_INSERT_PAD_OPTION;
			(void)XEmac_SetOptions(&lp->Emac,Options);
			(void)XEmac_Start(&(lp->Emac));
			spin_unlock_irqrestore(reset_lock, flags);
		}
		ret = 0;
		break;
	case ETHTOOL_GCOALESCE:
		eco.cmd = ecmd.cmd;
		ret = xenet_ethtool_get_coalesce(dev, &eco);
		if (ret >= 0) {
			if (copy_to_user(rq->ifr_data, &eco, sizeof (struct ethtool_coalesce)))
				ret = -EFAULT;
		}
		break;
	case ETHTOOL_SCOALESCE:
		if (copy_from_user(&eco, rq->ifr_data, sizeof (struct ethtool_coalesce)))
			return -EFAULT;
		ret = xenet_ethtool_set_coalesce(dev, &eco);
		break;
	case ETHTOOL_GDRVINFO:
		edrv.cmd = edrv.cmd;
		ret = xenet_ethtool_get_drvinfo(dev, &edrv);
		if (ret >= 0) {
			if (copy_to_user(rq->ifr_data, &edrv, sizeof (struct ethtool_drvinfo)))
				ret = -EFAULT;
		}
		break;
	case ETHTOOL_GREGS:
		regs.hd.cmd = edrv.cmd;
		xenet_ethtool_get_regs (dev, &(regs.hd), &ret);
		if (ret >= 0) {
			if (copy_to_user(rq->ifr_data, &regs, sizeof (struct mac_regsDump)))
				ret = -EFAULT;
		}
		break;
	case ETHTOOL_GRINGPARAM:
		erp.cmd = edrv.cmd;
		ret = xenet_ethtool_get_ringparam (dev, &(erp));
		if (ret >= 0) {
			if (copy_to_user(rq->ifr_data, &erp, sizeof (struct ethtool_ringparam)))
				ret = -EFAULT;
		}
		break;
	case ETHTOOL_NWAY_RST:
		epp.cmd = ecmd.cmd;
		mii_reg_autoneg = 0;
		mii_reg_autoneg |= (BMCR_ANENABLE | BMCR_ANRESTART);
		spin_lock_irqsave(reset_lock, flags);
		result = XEmac_PhyWrite(&lp->Emac, lp->mii_addr,
					MII_BMCR, mii_reg_autoneg);
		spin_unlock_irqrestore(reset_lock, flags);
		if (result != XST_SUCCESS) {
			ret = -EIO;
			break;
		}
		ret = 0;
		break;
	default:
		break;
	}
	return ret;
}

static int
xenet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
	struct net_local *lp = (struct net_local *) dev->priv;
	/* mii_ioctl_data has 4 u16 fields: phy_id, reg_num, val_in & val_out */
	struct mii_ioctl_data *data = (struct mii_ioctl_data *) &rq->ifr_data;
	struct {
		__u8 threshold;
		__u32 direction;
	} thr_arg;
	struct {
		__u32 waitbound;
		__u32 direction;
	} wbnd_arg ;
	XStatus ret;
	unsigned long flags;

	XStatus Result;

	switch (cmd) {
	case SIOCETHTOOL:
		return xenet_do_ethtool_ioctl(dev, rq);
	case SIOCGMIIPHY:	/* Get address of MII PHY in use. */
	case SIOCDEVPRIVATE:	/* for binary compat, remove in 2.5 */
		data->phy_id = lp->mii_addr;
		/* Fall Through */

	case SIOCGMIIREG:	/* Read MII PHY register. */
	case SIOCDEVPRIVATE + 1:	/* for binary compat, remove in 2.5 */
		if (data->phy_id > 31 || data->reg_num > 31)
			return -ENXIO;

		/* Stop the PHY timer to prevent reentrancy. */
		del_timer_sync(&lp->phy_timer);
		spin_lock_irqsave(reset_lock, flags);
		Result = XEmac_PhyRead(&lp->Emac, data->phy_id,
				       data->reg_num, &data->val_out);
		/* Start the PHY timer up again. */
		spin_unlock_irqrestore(reset_lock, flags);
		lp->phy_timer.expires = jiffies + 2 * HZ;
		add_timer(&lp->phy_timer);

		if (Result != XST_SUCCESS) {
			printk(KERN_ERR
			       "%s: Could not read from PHY, error=%d.\n",
			       dev->name, Result);
			return (Result == XST_EMAC_MII_BUSY) ? -EBUSY : -EIO;
		}
		return 0;

	case SIOCSMIIREG:	/* Write MII PHY register. */
	case SIOCDEVPRIVATE + 2:	/* for binary compat, remove in 2.5 */
		if (!capable(CAP_NET_ADMIN))
			return -EPERM;

		if (data->phy_id > 31 || data->reg_num > 31)
			return -ENXIO;

		/* Stop the PHY timer to prevent reentrancy. */
		del_timer_sync(&lp->phy_timer);
		spin_lock_irqsave(reset_lock, flags);
		Result = XEmac_PhyWrite(&lp->Emac, data->phy_id,
					data->reg_num, data->val_in);
		spin_unlock_irqrestore(reset_lock, flags);
		/* Start the PHY timer up again. */
		lp->phy_timer.expires = jiffies + 2 * HZ;
		add_timer(&lp->phy_timer);

		if (Result != XST_SUCCESS) {
			printk(KERN_ERR
			       "%s: Could not write to PHY, error=%d.\n",
			       dev->name, Result);
			return (Result == XST_EMAC_MII_BUSY) ? -EBUSY : -EIO;
		}
		return 0;

	case SIOCDEVPRIVATE + 3:		/* set THRESHOLD */
		if (copy_from_user(&thr_arg, rq->ifr_data, sizeof(thr_arg))) {
			return -EFAULT;
		}
		spin_lock_irqsave(reset_lock, flags);
		if ((ret = XEmac_Stop(&lp->Emac)) != XST_SUCCESS) {
			return -EIO;
		}
		if ((ret = XEmac_SetPktThreshold(&lp->Emac, thr_arg.direction, thr_arg.threshold)) != XST_SUCCESS) {
			return -EIO;
		}
		if ((ret = XEmac_Start(&lp->Emac)) != XST_SUCCESS) {
			return -EIO;
		}
		spin_unlock_irqrestore(reset_lock, flags);
		return 0;

	case SIOCDEVPRIVATE + 4:		/* set WAITBOUND */
		if (copy_from_user(&wbnd_arg, rq->ifr_data, sizeof(wbnd_arg))) {
			return -EFAULT;
		}
		spin_lock_irqsave(reset_lock, flags);
		if ((ret = XEmac_Stop(&lp->Emac)) != XST_SUCCESS) {
			return -EIO;
		}
		if ((ret = XEmac_SetPktWaitBound(&lp->Emac, wbnd_arg.direction, wbnd_arg.waitbound)) != XST_SUCCESS) {
			return -EIO;
		}
		if ((ret = XEmac_Start(&lp->Emac)) != XST_SUCCESS) {
			return -EIO;
		}
		spin_unlock_irqrestore(reset_lock, flags);
		return 0;

	case SIOCDEVPRIVATE + 5:		/* get THRESHOLD */
		if (copy_from_user(&thr_arg, rq->ifr_data, sizeof(thr_arg))) {
			return -EFAULT;
		}
		if ((ret = XEmac_GetPktThreshold(&lp->Emac, thr_arg.direction, &(thr_arg.threshold))) != XST_SUCCESS) {
			return -EIO;
		}
		if (copy_to_user(rq->ifr_data, &thr_arg, sizeof(thr_arg))) {
			return -EFAULT;
		}
		return 0;


	case SIOCDEVPRIVATE + 6:		/* get WAITBOUND */
		if (copy_from_user(&wbnd_arg, rq->ifr_data, sizeof(wbnd_arg))) {
			return -EFAULT;
		}
		if ((ret = XEmac_GetPktWaitBound(&lp->Emac, wbnd_arg.direction, &(wbnd_arg.waitbound))) != XST_SUCCESS) {
			return -EIO;
		}
		if (copy_to_user(rq->ifr_data, &wbnd_arg, sizeof(wbnd_arg))) {
			return -EFAULT;
		}
		return 0;

	default:
		return -EOPNOTSUPP;
	}
}

static void
remove_head_dev(void)
{
	struct net_local *lp;
	struct net_device *dev;
	XEmac_Config *cfg;

	/* Pull the head off of dev_list. */
	spin_lock(&dev_lock);
	dev = dev_list;
	lp = (struct net_local *) dev->priv;
	dev_list = lp->next_dev;
	spin_unlock(&dev_lock);

	/* Put the physical address back */
	cfg = XEmac_GetConfig(lp->index);
	iounmap((void *) cfg->BaseAddress);
	cfg->BaseAddress = cfg->PhysAddress;

	/* Free up the memory. */
	if (lp->desc_space)
        {
		free_descriptor_skb(dev);
		consistent_free(lp->desc_space);
        }

        if (lp->ddrVirtPtr) {
	 	kfree (lp->ddrVirtPtr);
	}

	unregister_netdev(dev);
	kfree(dev);
}

static int __init
probe(int index)
{
	static const unsigned long remap_size
	    = XPAR_EMAC_0_HIGHADDR - XPAR_EMAC_0_BASEADDR + 1;
	struct net_device *dev;
	struct net_local *lp;
	XEmac_Config *cfg;
	unsigned int irq;
	u32 maddr;

	switch (index) {
#if defined(XPAR_INTC_0_EMAC_0_VEC_ID)
	case 0:
		irq = 31 - XPAR_INTC_0_EMAC_0_VEC_ID;
		break;
#if defined(XPAR_INTC_0_EMAC_1_VEC_ID)
	case 1:
		irq = 31 - XPAR_INTC_0_EMAC_1_VEC_ID;
		break;
#if defined(XPAR_INTC_0_EMAC_2_VEC_ID)
	case 2:
		irq = 31 - XPAR_INTC_0_EMAC_2_VEC_ID;
		break;
#if defined(XPAR_INTC_0_EMAC_3_VEC_ID)
#error Edit this file to add more devices.
#endif				/* 3 */
#endif				/* 2 */
#endif				/* 1 */
#endif				/* 0 */
	default:
		return -ENODEV;
	}

	/* Find the config for our device. */
	cfg = XEmac_GetConfig(index);
	if (!cfg)
		return -ENODEV;

	dev = init_etherdev(0, sizeof (struct net_local));
	if (!dev) {
		printk(KERN_ERR "Could not allocate Xilinx enet device %d.\n",
		       index);
		return -ENOMEM;
	}
	SET_MODULE_OWNER(dev);

	ether_setup(dev);
	dev->irq = irq;

	/* Initialize our private data. */
	lp = (struct net_local *) dev->priv;
	memset(lp, 0, sizeof (struct net_local));
	lp->index = index;
	lp->dev = dev;

	/* Make it the head of dev_list. */
	spin_lock(&dev_lock);
	lp->next_dev = dev_list;
	dev_list = dev;
	spin_unlock(&dev_lock);

	/* Change the addresses to be virtual */
	cfg->PhysAddress = cfg->BaseAddress;
	cfg->BaseAddress = (u32) ioremap(cfg->PhysAddress, remap_size);

	if (XEmac_Initialize(&lp->Emac, cfg->DeviceId) != XST_SUCCESS) {
		printk(KERN_ERR "%s: Could not initialize device.\n",
		       dev->name);
		remove_head_dev();
		return -ENODEV;
	}

	memcpy(dev->dev_addr, ((bd_t *) __res)->bi_enetaddr, 6);
	if (XEmac_SetMacAddress(&lp->Emac, dev->dev_addr) != XST_SUCCESS) {
		/* should not fail right after an initialize */
		printk(KERN_ERR "%s: Could not set MAC address.\n", dev->name);
		remove_head_dev();
		return -EIO;
	}

	if (XEmac_mIsSgDma(&lp->Emac)) {
		int result;

		printk(KERN_ERR "%s: using sgDMA mode.\n", dev->name);
		XEmac_SetSgRecvHandler(&lp->Emac, dev, SgRecvHandler);
		XEmac_SetSgSendHandler(&lp->Emac, dev, SgSendHandler);
		dev->hard_start_xmit = xenet_SgSend;
		lp->Isr = XEmac_IntrHandlerDma;

		result = descriptor_init(dev);
		if (result) {
			remove_head_dev();
			return -EIO;
		}

                /* set the packet threshold and waitbound*/
                XEmac_SetPktThreshold(&lp->Emac, XEM_SEND, 31);
                XEmac_SetPktThreshold(&lp->Emac, XEM_RECV, 31);  
                (void) XEmac_SetPktWaitBound(&lp->Emac, XEM_SEND, 5);
                (void) XEmac_SetPktWaitBound(&lp->Emac, XEM_RECV, 5);

                /* disable SGEND interrupt */
                XEmac_SetOptions(&lp->Emac, XEmac_GetOptions(&lp->Emac) |
                                 XEM_NO_SGEND_INT_OPTION);
	} else {
		printk(KERN_ERR "%s: using fifo mode.\n", dev->name);
		XEmac_SetFifoRecvHandler(&lp->Emac, dev, FifoRecvHandler);
		XEmac_SetFifoSendHandler(&lp->Emac, dev, FifoSendHandler);
		dev->hard_start_xmit = xenet_FifoSend;
		lp->Isr = XEmac_IntrHandlerFifo;
	}
	XEmac_SetErrorHandler(&lp->Emac, dev, ErrorHandler);

	/* Scan to find the PHY. */
	lp->mii_addr = 0xFF;
	for (maddr = 0; maddr < 31; maddr++) {
		XStatus Result;
		u16 reg;

		Result = XEmac_PhyRead(&lp->Emac, maddr, MII_BMCR, &reg);
		/*
		 * XEmac_PhyRead is currently returning XST_SUCCESS even
		 * when reading from non-existent addresses.  Work
		 * around this by doing a primitive validation on the
		 * control word we get back.
		 */
		if (Result == XST_SUCCESS && (reg & BMCR_RESV) == 0) {
			lp->mii_addr = maddr;
			break;
		}
	}
	if (lp->mii_addr == 0xFF) {
		lp->mii_addr = 0;
		printk(KERN_WARNING
		       "%s: No PHY detected.  Assuming a PHY at address %d.\n",
		       dev->name, lp->mii_addr);
	}

	dev->open = xenet_open;
	dev->stop = xenet_close;
	dev->get_stats = xenet_get_stats;
	dev->flags &= ~IFF_MULTICAST;
	dev->set_multicast_list = xenet_set_multicast_list;
	dev->do_ioctl = xenet_ioctl;
	dev->tx_timeout = xenet_tx_timeout;
	dev->watchdog_timeo = TX_TIMEOUT;

        dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HW_CSUM;

	printk(KERN_INFO
	       "%s: Xilinx EMAC #%d at 0x%08X mapped to 0x%08X, irq=%d\n",
	       dev->name, index, cfg->PhysAddress, cfg->BaseAddress, dev->irq);

	/* print h/w id  */
	{
		u32 id = XIo_In32(cfg->BaseAddress + XIIF_V123B_RESETR_OFFSET);

		printk("%s: id %d.%d%c; block id %d, type %d\n",
		       dev->name, (id >> 28) & 0xf, (id >> 21) & 0x7f,
		       ((id >> 16) & 0x1f) + 'a',
		       (id >> 16) & 0xff, (id >> 0) & 0xff);
	}

	return 0;
}

static int __init
xenet_init(void)
{
	int index = 0;

	while (probe(index++) == 0) ;
	/* If we found at least one, report success. */
	return (index > 1) ? 0 : -ENODEV;
}

static void __exit
xenet_cleanup(void)
{
	while (dev_list)
		remove_head_dev();
}

EXPORT_NO_SYMBOLS;

module_init(xenet_init);
module_exit(xenet_cleanup);

^ permalink raw reply

* Re: [PATCH 2/3] powerpc: Add early debugging / xmon support for Cell
From: Michael Ellerman @ 2006-06-08  5:22 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linuxppc-dev
In-Reply-To: <20060502095406.C25DA67B3B@ozlabs.org>

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

On Tue, 2006-05-02 at 19:54 +1000, Michael Ellerman wrote:
> This patch adds udbg routines for cell, and hooks them up for use as an early
> debugging console or for xmon.
> 
> With this patch xmon seems to work. On one occasion after sitting in xmon
> for a while I lost hard disk interrupts and had to power off, not sure what
> the story was there.
> 
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>

This patch is no good, it allows you to inadvertently call rtas before
it's ready which causes the kernel to die. I think we can structure
things so that a) rtas is callable earlier, and b) rtas_call fails
gracefully when rtas isn't setup yet.

The BML guys now use these rtas calls too, so I'll do a version under
kernel/ so they can use it too.

New patch RSN.

cheers

-- 
Michael Ellerman
IBM OzLabs

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 191 bytes --]

^ permalink raw reply

* does Gianfar Ethernet Controller Version 1.1 support MARVELL 88E1111?
From: 郭 剑非 @ 2006-06-08  7:43 UTC (permalink / raw)
  To: Linuxppc-embedded

Hi all,
I'm debugging my board with MPC 8540 and marvell 88e1111 designed on it. 
I'm sure the hardware connection is correct, and the phy's ID could be read 
through terminal port. But anyway, phy can not work. I wonder if it is the 
driver's problem? Since the Gianfar Ethernet Controller Version 1.1 
surpport 88e1011s, but some 88e1111's registers are different from 
88e1011s'. Actually I'm a new guy to Linux. Has anybody ever used 88e1111 
phy in Linux envirenmemt? Please  
give me some points. Thank you! 
I have read the Gianfar ethernet controller driver, but it's difficult for 
me to find out the sofware flow.

^ permalink raw reply

* RE: does Gianfar Ethernet Controller Version 1.1 support MARVELL 88E1111?
From: Liu Dave-r63238 @ 2006-06-08  8:41 UTC (permalink / raw)
  To: '郭 剑非', Linuxppc-embedded

> Hi all,
> I'm debugging my board with MPC 8540 and marvell 88e1111 
> designed on it. 
> I'm sure the hardware connection is correct, and the phy's ID 
> could be read 
> through terminal port. But anyway, phy can not work. I wonder 

Are you sure the hardware is no problem?
Can you successfully tftp files with the port in u-boot?
What is the phy interface mode you used? 

> if it is the 
> driver's problem? Since the Gianfar Ethernet Controller Version 1.1 
> surpport 88e1011s, but some 88e1111's registers are different from 
> 88e1011s'. Actually I'm a new guy to Linux. Has anybody ever 
> used 88e1111 
> phy in Linux envirenmemt? Please  

Basically, the 88e1111 is same 88e1011s.

> give me some points. Thank you! 
> I have read the Gianfar ethernet controller driver, but it's 
> difficult for 
> me to find out the sofware flow.
> 
Change the board-specific things, for example
PHY address, PHY interrupt. 
Please reference /arch/ppc/platforms/85xx/mpc8540_ads.c

-Dave

^ permalink raw reply

* (no subject)
From: huseyin_yeter1977 @ 2006-06-08  8:57 UTC (permalink / raw)
  To: Linuxppc-embedded

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

thank you

[-- Attachment #2: Type: text/html, Size: 47 bytes --]

^ permalink raw reply

* a problem of kernel-module version mismatch.
From: Ming Liu @ 2006-06-08 13:27 UTC (permalink / raw)
  To: Linuxppc-embedded

Hello everyone,
Now I am trying to cross-compile the driver for a customed FIFO peripheral 
in my design. My embedded platform is Xilinx ML403 development board 
(Virtex4) and the host linux is suse 64-bit. I use the cross-compiler to 
compile the driver source files provided by Xilinx EDK. But the problem 
happens:

# insmod FIFO.o
insmod: kernel-module version mismatch
        FIFO.o was compiled for kernel version
        while this kernel is version 2.4.26

If I use "-f" option, it shows:

insmod: kernel-module version mismatch
        FIFO.o was compiled for kernel version
        while this kernel is version 2.4.26
insmod: unresolved symbol XIo_In32
insmod: unresolved symbol XIO_Out32

My embedded linux kernel version is 2.4.26. My compiler is 
"powerpc-405-linux-gnu-gcc 3.4.1". I don't know how the version mismatch 
happened. Shall I change another cross-compiler version? I will appreciate 
a lot if someone could tell me how to solve it. Thanks a lot.

Regards
Ming

_________________________________________________________________
与联机的朋友进行交流,请使用 MSN Messenger:  http://messenger.msn.com/cn  

^ permalink raw reply

* Re: a problem of kernel-module version mismatch.
From: Arnd Bergmann @ 2006-06-08 13:36 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <BAY110-F1B771BD82DFE542552C0BB28B0@phx.gbl>

On Thursday 08 June 2006 15:27, Ming Liu wrote:
> My embedded linux kernel version is 2.4.26. My compiler is 
> "powerpc-405-linux-gnu-gcc 3.4.1". I don't know how the version mismatch 
> happened. Shall I change another cross-compiler version? I will appreciate 
> a lot if someone could tell me how to solve it. Thanks a lot.

The easiest way is usually to put the driver in your source tree
and compile everything together. That also makes it easier to
distribute the complete source tree to your users.

> insmod: unresolved symbol XIo_In32
> insmod: unresolved symbol XIO_Out32

that looks like part of your module is missing. Try to find where thses
functions are defined in there and why that isn't compiled.

	Arnd <><

^ permalink raw reply

* Re: [PATCH 1/10] Add the mpc8641 hpcn Kconfig and Makefiles.
From: Jon Loeliger @ 2006-06-08 13:35 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <0EC9507F-27EE-46E4-A92A-E4150A2FA312@kernel.crashing.org>

On Wed, 2006-06-07 at 23:44, Kumar Gala wrote:
> On Jun 7, 2006, at 5:34 PM, Jon Loeliger wrote:


> >  config PPC_I8259
> >  	bool
> > +	default y if PPC_86xx
> >  	default n
> 
> This dependancy seems too generic, shouldn't it be based on some  
> board (its not like 86xx actually has an i8259 in it).

> > +# Makefile for the PowerPC 86xx linux kernel.
> > +#
> > +
> > +obj-$(CONFIG_PPC_86xx)		+= mpc86xx_hpcn.o misc.o
> 
> Seems like mpc86xx_hpcn.o is board specific code and should move down  
> one line.

> > +
> > +config I8259_LEVEL_TRIGGER
> > +	bool
> > +	depends on MPC8641
> > +	default y
> 
> again, seems like it should depend on a board & not MPC8641

OK, I'll fix all of those.


> > diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> > index d6d4494..fbeae82 100644
> > --- a/drivers/i2c/busses/Kconfig
> > +++ b/drivers/i2c/busses/Kconfig
> > @@ -252,12 +252,12 @@ config I2C_POWERMAC
> >  
> should probably separate this out into its own patch for the I2C  
> maintainer.

Ah, OK.  Who is that then?

Thanks,
jdl

^ permalink raw reply

* Re: [PATCH 7/10] Add use of mpc86xx.h include files in legacy header files.
From: Jon Loeliger @ 2006-06-08 13:36 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <542A1CA4-6A5A-41DA-98D2-C61D5376B761@kernel.crashing.org>

On Wed, 2006-06-07 at 23:49, Kumar Gala wrote:
> On Jun 7, 2006, at 5:42 PM, Jon Loeliger wrote:
> 
> >
> > Signed-off-by: Xianghua Xiao <x.xiao@freescale.com>
> > Signed-off-by: Jon Loeliger <jdl@freescale.com>
> >
> > ---
> >
> >  include/asm-ppc/io.h      |    2 ++
> >  include/asm-ppc/ppc_sys.h |    2 ++
> >  include/asm-ppc/serial.h  |    2 ++
> >  3 files changed, 6 insertions(+), 0 deletions(-)
> 
> Are the io.h & serial.h really needed for ARCH=powerpc?  What does  
> serial.h get from asm/mpc86xx.h?  I can see the possibility of io.h  
> needing some stuff from asm/mpc86xx.h

I'll check and do a round of include scrubbing.
There was some silliness going on there earlier,
but it could have been cleaned up along the way too.


> > index 40f197a..4eaf80d 100644
> > --- a/include/asm-ppc/ppc_sys.h
> > +++ b/include/asm-ppc/ppc_sys.h
> > @@ -27,6 +27,8 @@ #elif defined(CONFIG_83xx)
> >  #include <asm/mpc83xx.h>
> >  #elif defined(CONFIG_85xx)
> >  #include <asm/mpc85xx.h>
> > +#elif defined(CONFIG_PPC_86xx)
> > +#include <asm/mpc86xx.h>
> 
> this should go since I can't imagine your using ppc_sys.

Right.  Leftover cleaning tidbits.  It's gone.

Thanks,
jdl

^ permalink raw reply

* Re: [PATCH 6/10] Add 8641 Register space and IRQ definitions.
From: Jon Loeliger @ 2006-06-08 13:39 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <EDB92A0C-28BA-4E18-98ED-F37C1EEDF8C2@kernel.crashing.org>

On Wed, 2006-06-07 at 23:57, Kumar Gala wrote:


> > +/* Offset from CCSRBAR */
> > +#define MPC86xx_DMA_OFFSET	(0x21000)
> > +#define MPC86xx_DMA_SIZE	(0x01000)
> > +#define MPC86xx_DMA0_OFFSET	(0x21100)
> > +#define MPC86xx_DMA0_SIZE	(0x00080)
> > +#define MPC86xx_DMA1_OFFSET	(0x21180)
> > +#define MPC86xx_DMA1_SIZE	(0x00080)
> > +#define MPC86xx_DMA2_OFFSET	(0x21200)
> > +#define MPC86xx_DMA2_SIZE	(0x00080)
> > +#define MPC86xx_DMA3_OFFSET	(0x21280)
> > +#define MPC86xx_DMA3_SIZE	(0x00080)
> > +
> > +#define MPC86xx_GUTS_OFFSET	(0xe0000)
> > +#define MPC86xx_GUTS_SIZE	(0x01000)
> > +
> > +#define MPC86xx_OPENPIC_OFFSET	(0x40000)
> > +#define MPC86xx_OPENPIC_SIZE	(0x40000)
> > +#define MPC86xx_PEX1_OFFSET	(0x08000)
> > +#define MPC86xx_PEX1_SIZE	(0x01000)
> > +#define MPC86xx_PEX2_OFFSET	(0x09000)
> > +#define MPC86xx_PEX2_SIZE	(0x01000)
> > +#define MPC86xx_PERFMON_OFFSET	(0xe1000)
> > +#define MPC86xx_PERFMON_SIZE	(0x01000)
> > +#define MPC86xx_UART0_OFFSET	(0x04500)
> > +#define MPC86xx_UART0_SIZE	(0x00100)
> > +#define MPC86xx_UART1_OFFSET	(0x04600)
> > +#define MPC86xx_UART1_SIZE	(0x00100)
> > +#define MPC86xx_MCM_OFFSET      (0x00000)
> > +#define MPC86xx_MCM_SIZE        (0x02000)
> > +
> > +#define MPC86xx_CCSRBAR_SIZE	(1024*1024)
> 
> Let's kill any OFFSET & SIZEs that aren't actually needed in code.  I  
> would hope most of these are going from the flat dev tree.

OK.  I'll trim this set down.


> > +enum ppc_sys_devices {
> > +	MPC86xx_TSEC1,
> > +	MPC86xx_TSEC2,
> > +	MPC86xx_TSEC3,
> > +	MPC86xx_TSEC4,
> > +	MPC86xx_DUART,
> > +	MPC86xx_MDIO,
> > +	MPC86xx_IIC1,
> > +	MPC86xx_IIC2,
> > +	NUM_PPC_SYS_DEVS,
> > +};
> 
> please kill, I can't imagine any code actually using this.

Yep.  Again, leftover tidbits.  I'll fix it.


> > +#define PVR_8641	0x80040000
> 
> Does anything code use this define, if not let's kill it.  I think we  
> are trying to reduce such things.

I'll check and remove as possible!

Thanks,
jdl

^ permalink raw reply

* Re: a problem of kernel-module version mismatch.
From: Ming Liu @ 2006-06-08 13:52 UTC (permalink / raw)
  To: arnd.bergmann; +Cc: linuxppc-embedded
In-Reply-To: <200606081536.15145.arnd.bergmann@de.ibm.com>

Thanks for your telling first.

>The easiest way is usually to put the driver in your source tree
>and compile everything together. That also makes it easier to
>distribute the complete source tree to your users.

Sorry that I am a novice in Linux. I don't know how can I put the driver in 
my source tree and compile everything together. It looks like that there is 
no option in the menuconfig to choose a specially customed peripheral. So I 
think I only can include the customed peripheral as a module. Could you 
please say in a detail on how to do that? 


> > insmod: unresolved symbol XIo_In32
> > insmod: unresolved symbol XIO_Out32
>
>that looks like part of your module is missing. Try to find where thses
>functions are defined in there and why that isn't compiled.

It's very strange because I have checked the source. In the header file of 
xio.h, there are the following sentences,

/************************** Function Prototypes 
******************************/

/* The following functions allow the software to be transportable across
 * processors which may use memory mapped I/O or I/O which is mapped into a
 * seperate address space such as X86.  The functions are better suited for
 * debugging and are therefore the default implementation. Macros can 
instead
 * be used if USE_IO_MACROS is defined.
 */
#ifndef USE_IO_MACROS

/* Functions */
Xuint8 XIo_In8(XIo_Address InAddress);
Xuint16 XIo_In16(XIo_Address InAddress);
Xuint32 XIo_In32(XIo_Address InAddress);

void XIo_Out8(XIo_Address OutAddress, Xuint8 Value);
void XIo_Out16(XIo_Address OutAddress, Xuint16 Value);
void XIo_Out32(XIo_Address OutAddress, Xuint32 Value);

#else

/* The following macros allow optimized I/O operations for memory mapped 
I/O
 * Note that the SYNCHRONIZE_IO may be moved by the compiler during
 * optimization.
 */

#define XIo_In8(InputPtr)  (*(volatile Xuint8  *)(InputPtr)); 
SYNCHRONIZE_IO;
#define XIo_In16(InputPtr) (*(volatile Xuint16 *)(InputPtr)); 
SYNCHRONIZE_IO;
#define XIo_In32(InputPtr) (*(volatile Xuint32 *)(InputPtr)); 
SYNCHRONIZE_IO;

#define XIo_Out8(OutputPtr, Value)  \
    { (*(volatile Xuint8  *)(OutputPtr) = Value); SYNCHRONIZE_IO; }
#define XIo_Out16(OutputPtr, Value) \
    { (*(volatile Xuint16 *)(OutputPtr) = Value); SYNCHRONIZE_IO; }
#define XIo_Out32(OutputPtr, Value) \
    { (*(volatile Xuint32 *)(OutputPtr) = Value); SYNCHRONIZE_IO; }

#endif

I think these are the defination of XIo_In32 and XIo_Out32. Also, during 
the compilation, there is no error to complain that "XIo_In32 or XIo_Out32 
undeclared". 

More suggestions are appreciated. Thanks.

BR
Ming

_________________________________________________________________
免费下载 MSN Explorer:   http://explorer.msn.com/lccn/  

^ permalink raw reply

* A Couple of 2.6/Xilinx Questions
From: rakirtley @ 2006-06-08 14:45 UTC (permalink / raw)
  To: linuxppc-embedded

All,
    I've been attempting to get a 2.6 version running on the Xilinx ML403 and only really need the ethernet and compact flash devices at this point.  I've tried versions from mvista, kernel.org, etc; all only have the serial8250 device enabled.  Obviously adding devices is a lot of work and it appears that you all have already made great progress enabling ethernet.
   Are any of  the advanced versions upon which you all work generally available?  If so could you please provide a location? Apologies in advance for polluting your emailboxes and thanks in advance for any help/pointers that you can provide. I'll be more than happy to share any mods that I make (if any)
         Rance Kirtley
         Applied Systems Intelligence
         Roswell, GA USA
   

^ permalink raw reply

* Re: a problem of kernel-module version mismatch.
From: Arnd Bergmann @ 2006-06-08 15:25 UTC (permalink / raw)
  To: Ming Liu; +Cc: linuxppc-embedded
In-Reply-To: <BAY110-F11CA5067CA16CB9E95E997B28B0@phx.gbl>

On Thursday 08 June 2006 15:52, Ming Liu wrote:
> >The easiest way is usually to put the driver in your source tree
> >and compile everything together. That also makes it easier to
> >distribute the complete source tree to your users.
>=20
> Sorry that I am a novice in Linux. I don't know how can I put the driver =
in=20
> my source tree and compile everything together. It looks like that there =
is=20
> no option in the menuconfig to choose a specially customed peripheral. So=
 I=20
> think I only can include the customed peripheral as a module. Could you=20
> please say in a detail on how to do that?=20

The most simple way would be to put it into linux/drivers/misc and add it
to the Makefile in there.

> > > insmod: unresolved symbol XIo_In32
> > > insmod: unresolved symbol XIO_Out32
> >
> >that looks like part of your module is missing. Try to find where thses
> >functions are defined in there and why that isn't compiled.
>=20
> It's very strange because I have checked the source. In the header file o=
f=20
> xio.h, there are the following sentences,
>=20
> /************************** Function Prototypes=20
> ******************************/
>=20
> /* The following functions allow the software to be transportable across
> =A0* processors which may use memory mapped I/O or I/O which is mapped in=
to a
> =A0* seperate address space such as X86. =A0The functions are better suit=
ed for
> =A0* debugging and are therefore the default implementation. Macros can=20
> instead
> =A0* be used if USE_IO_MACROS is defined.
> =A0*/
> #ifndef USE_IO_MACROS

The comment tells you that you either need to implement these functions
youself or #define USE_IO_MACROS in the code before this.

> /* Functions */
> Xuint8 XIo_In8(XIo_Address InAddress);
> Xuint16 XIo_In16(XIo_Address InAddress);
> Xuint32 XIo_In32(XIo_Address InAddress);
>=20
> void XIo_Out8(XIo_Address OutAddress, Xuint8 Value);
> void XIo_Out16(XIo_Address OutAddress, Xuint16 Value);
> void XIo_Out32(XIo_Address OutAddress, Xuint32 Value);
>=20
> #else
>=20
> /* The following macros allow optimized I/O operations for memory mapped=
=20
> I/O
> =A0* Note that the SYNCHRONIZE_IO may be moved by the compiler during
> =A0* optimization.
> =A0*/
>=20
> #define XIo_In8(InputPtr) =A0(*(volatile Xuint8 =A0*)(InputPtr));=20
> SYNCHRONIZE_IO;
> #define XIo_In16(InputPtr) (*(volatile Xuint16 *)(InputPtr));=20
> SYNCHRONIZE_IO;
> #define XIo_In32(InputPtr) (*(volatile Xuint32 *)(InputPtr));=20
> SYNCHRONIZE_IO;
>=20
> #define XIo_Out8(OutputPtr, Value) =A0\
> =A0 =A0 { (*(volatile Xuint8 =A0*)(OutputPtr) =3D Value); SYNCHRONIZE_IO;=
 }
> #define XIo_Out16(OutputPtr, Value) \
> =A0 =A0 { (*(volatile Xuint16 *)(OutputPtr) =3D Value); SYNCHRONIZE_IO; }
> #define XIo_Out32(OutputPtr, Value) \
> =A0 =A0 { (*(volatile Xuint32 *)(OutputPtr) =3D Value); SYNCHRONIZE_IO; }
>=20
> #endif

These macros are probably broken on powerpc.

>=20
> I think these are the defination of XIo_In32 and XIo_Out32. Also, during=
=20
> the compilation, there is no error to complain that "XIo_In32 or XIo_Out3=
2=20
> undeclared".=20
>=20

I would suggest you remove that part of the header file completely, and
replace it with:

#define XIo_In32(p) in_le32(x)
#define XIO_Out32(p,v) out_le32(p, v)

	Arnd <><

^ permalink raw reply

* RE: Making Two ethernet interfaces up in Linux
From: Rick Moleres @ 2006-06-08 15:30 UTC (permalink / raw)
  To: Shantanu Nalage, Antonio Di Bacco, linuxppc-embedded

Shantanu,

Can you post the xemac_g.c file in the xilinx_enet directory?  Also,
which version of the EDK are you using?  There was a bug in EDK 7.x that
prevented multiple Ethernet interfaces from working properly.

It would also be helpful to see xparameters_ml300.h from the
arch/ppc/platforms/xilinx_ocp directory.

Thanks,
-Rick

-----Original Message-----
From: linuxppc-embedded-bounces+moleres=3Dxilinx.com@ozlabs.org
[mailto:linuxppc-embedded-bounces+moleres=3Dxilinx.com@ozlabs.org] On
Behalf Of Shantanu Nalage
Sent: Wednesday, June 07, 2006 11:16 PM
To: Antonio Di Bacco; linuxppc-embedded@ozlabs.org
Subject: Re: Making Two ethernet interfaces up in Linux

Thanks for the reply.
The driver which we are using for the ethernet is provided by Xilinx.
In the Linux kernel source, it is located in net/xilinx_enet
directory. We are attaching the adapter file for the driver provided
by Xilinx for the ethernet.
When we gave a first try, it showed two ethernet interfaces eth0 and
eth1 as an output of ifconfig command but only eth0 works, when eth1
is disabled. When both interfaces are up, neither interface works.
While even when eth0 is disabled, eth1 interface doesn't work.

With regards,
Shantanu.

On 6/4/06, Antonio Di Bacco <antonio.dibacco@aruba.it> wrote:
> >          We are trying to port Linux on Xilinx Board XUPV2Pro which
is
> > similar in most aspects to the Xilinx ML300 board. Linux is up and
> > running for the original board i.e. having only one ethrnet
interface.
> > Now since we wanted to have the board working as router, we designed
a
> > daughter board with two ethernet phy interfaces. The MACs required
for
> > that are instantiated in Xilinx ....
>
> You have already the driver for the first MAC, then you should start
from that
> modifying the init procedure for example and all the others. Your
driver
> should initialize both the MACs and also create two devices calling
> init_etherdev tow times. If you post your driver I can suggest what to
> change. It is not so difficult.
>
> Bye,
> Antonio.
>
>

^ permalink raw reply

* Re: a problem of kernel-module version mismatch.
From: Ming Liu @ 2006-06-08 15:54 UTC (permalink / raw)
  To: arnd.bergmann; +Cc: linuxppc-embedded
In-Reply-To: <200606081725.37621.arnd.bergmann@de.ibm.com>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=gb2312; format=flowed, Size: 4010 bytes --]

Dear Arnd,
Thanks a lot for your help. Now I have solved the problem of version 
mismatch. The reason is I haven't include the sentence of "#define MODULE". 


However the problem of unresolved symbol XIo_In32 and XIo_Out32 still 
exists. I will try to solve it following your suggestion. If any question, 
I will ask you again. Thanks a lot for your help.

Regards
Ming


>From: Arnd Bergmann <arnd.bergmann@de.ibm.com>
>To: "Ming Liu" <eemingliu@hotmail.com>
>CC: linuxppc-embedded@ozlabs.org
>Subject: Re: a problem of kernel-module version mismatch.
>Date: Thu, 8 Jun 2006 17:25:37 +0200
>
>On Thursday 08 June 2006 15:52, Ming Liu wrote:
> > >The easiest way is usually to put the driver in your source tree
> > >and compile everything together. That also makes it easier to
> > >distribute the complete source tree to your users.
> >
> > Sorry that I am a novice in Linux. I don't know how can I put the 
driver in
> > my source tree and compile everything together. It looks like that 
there is
> > no option in the menuconfig to choose a specially customed peripheral. 
So I
> > think I only can include the customed peripheral as a module. Could you
> > please say in a detail on how to do that?
>
>The most simple way would be to put it into linux/drivers/misc and add it
>to the Makefile in there.
>
> > > > insmod: unresolved symbol XIo_In32
> > > > insmod: unresolved symbol XIO_Out32
> > >
> > >that looks like part of your module is missing. Try to find where 
thses
> > >functions are defined in there and why that isn't compiled.
> >
> > It's very strange because I have checked the source. In the header file 
of
> > xio.h, there are the following sentences,
> >
> > /************************** Function Prototypes
> > ******************************/
> >
> > /* The following functions allow the software to be transportable 
across
> > ? processors which may use memory mapped I/O or I/O which is mapped 
into a
> > ? seperate address space such as X86.  The functions are better suited 
for
> > ? debugging and are therefore the default implementation. Macros can
> > instead
> > ? be used if USE_IO_MACROS is defined.
> > ?/
> > #ifndef USE_IO_MACROS
>
>The comment tells you that you either need to implement these functions
>youself or #define USE_IO_MACROS in the code before this.
>
> > /* Functions */
> > Xuint8 XIo_In8(XIo_Address InAddress);
> > Xuint16 XIo_In16(XIo_Address InAddress);
> > Xuint32 XIo_In32(XIo_Address InAddress);
> >
> > void XIo_Out8(XIo_Address OutAddress, Xuint8 Value);
> > void XIo_Out16(XIo_Address OutAddress, Xuint16 Value);
> > void XIo_Out32(XIo_Address OutAddress, Xuint32 Value);
> >
> > #else
> >
> > /* The following macros allow optimized I/O operations for memory 
mapped
> > I/O
> > ? Note that the SYNCHRONIZE_IO may be moved by the compiler during
> > ? optimization.
> > ?/
> >
> > #define XIo_In8(InputPtr) ?*(volatile Xuint8 ?)(InputPtr));
> > SYNCHRONIZE_IO;
> > #define XIo_In16(InputPtr) (*(volatile Xuint16 *)(InputPtr));
> > SYNCHRONIZE_IO;
> > #define XIo_In32(InputPtr) (*(volatile Xuint32 *)(InputPtr));
> > SYNCHRONIZE_IO;
> >
> > #define XIo_Out8(OutputPtr, Value)  \
> > ??{ (*(volatile Xuint8 ?)(OutputPtr) = Value); SYNCHRONIZE_IO; }
> > #define XIo_Out16(OutputPtr, Value) \
> > ??{ (*(volatile Xuint16 *)(OutputPtr) = Value); SYNCHRONIZE_IO; }
> > #define XIo_Out32(OutputPtr, Value) \
> > ??{ (*(volatile Xuint32 *)(OutputPtr) = Value); SYNCHRONIZE_IO; }
> >
> > #endif
>
>These macros are probably broken on powerpc.
>
> >
> > I think these are the defination of XIo_In32 and XIo_Out32. Also, 
during
> > the compilation, there is no error to complain that "XIo_In32 or 
XIo_Out32
> > undeclared".
> >
>
>I would suggest you remove that part of the header file completely, and
>replace it with:
>
>#define XIo_In32(p) in_le32(x)
>#define XIO_Out32(p,v) out_le32(p, v)
>
>	Arnd <><

_________________________________________________________________
ÓëÁª»úµÄÅóÓѽøÐн»Á÷£¬ÇëʹÓà MSN Messenger:  http://messenger.msn.com/cn  

^ permalink raw reply

* Re: MPC5200B SPI PSC3 Problem
From: John Rigby @ 2006-06-08 16:04 UTC (permalink / raw)
  To: Trueskew; +Cc: linuxppc-embedded
In-Reply-To: <44875165.40800d0c.36a8.3e2e@mx.gmail.com>

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

There seems to be a conflict between two sections of the 5200 User manual.
In section 7.3 where port_config is documented the PSC3 configuration
bits (20:23)
defined as:

0000 = All PSC3 pins are GPIOs
0001 = USB2 on PSC3, no GPIOs available, see Note 3
001X = Reserved
0100 = UART functionality without CD
0101 = UARTe functionality with CD
0110 = CODEC3 functionality
0111 = CODEC3 functionality (with MCLK)
100X = SPI
101X = Reserved
1100 = SPI with UART3
1101 = SPI with UART3e
111X = SPI with CODEC3

but in the psc chapter in table 15-85 it says to set port config to
0x00000600 but
the description says "Select the Pin-Muxing for PSC3 Codec mode"

It appears that table 15-85 is wrong.

I have attached some spi code that is embedded in a touchscreen
driver.  It might be helpful.





On 6/7/06, Trueskew <trueskew@gmail.com> wrote:
>
>
> We have an AIC26 codec connected to our Lite5200B platform via J21.  I've
> used MPC5200BUG to configure PSC3 as an SPI master, along with some samples
> I've found online (including here) and some I received from Freescale.
> Although the transfers seem to be working as expected (please see the output
> file at the end of this message), I get only 0xffff back.  This occurs
> whether or not the device is attached to J21.  A scope shows that PSC3_8
> (SPI_SS) and PSC3_9 (SPI_CLK) are low at all times, and I'm concerned I'm
> still doing something wrong with respect to enabling SPI over PSC3.
>
> I'm including my driver initialization code, my write code, and output
> showing the write behavior.  If someone could comment on it, I would greatly
> appreciate it... or if someone flat out has code to do this, I'd be happy to
> take it from you.  I've seen a few variations, but whether I use them
> directly or modify them as I need to, I can't seem to get past this.  Of
> course, any other suggestions are welcome.
>
> Thanks.
> Sal
>
> ---------------------------------------------------------------------------
> Initialization Code
> ---------------------------------------------------------------------------
> #define GPIO_PSC3_PORT_CONFIG_MASK 0x00000f00
> #ifdef SPI_USE_MCLK
>    #define      GPIO_PSC3_PORT_CONFIG 0x00000700  /* PSC3 mode with mclk */
> #else  /* SPI_USE_MCLK */
>    #define      GPIO_PSC3_PORT_CONFIG 0x00000600  /* PSC3 mode */
> #endif /* SPI_USE_MCLK */
>
> #define       CDM_PSC3_MCLK_ENABLE 0x00000080
> #define       CDM_PSC3_MCLK_CONFIG 0x8020      /* Divide Fvco ftom 528 to
>                                                   16Mhz */
>
> #define        PSC3_SICR_REG_VALUE 0x0280f000  /* 16-bit select Codec SPI
>                                                   master
> mode, msb first,
>                                                   UseEOF=1.
> GenClk=1, SIM,
>                                                   CPOL and
> CPHA are
>                                                   function
> input */
> ...
>    /* Select the Pin-Muxing for PSC3 Codec mode */
>    gpio = (struct mpc52xx_gpio *) ioremap(MPC52xx_GPIO,
>      sizeof(struct mpc52xx_gpio));
>    if(gpio)
>    {
>       port_config = gpio->port_config;
>       port_config &= ~GPIO_PSC3_PORT_CONFIG_MASK;
>       port_config |= GPIO_PSC3_PORT_CONFIG;
>       gpio->port_config = port_config;
>       iounmap(gpio);
>    }
>    else
>    {
>       return(-1);
>    }
>
> #ifdef SPI_USE_MCLK
>    /* PSC clock enable */
>    g_pCDM->clk_enables |= CDM_PSC3_MCLK_ENABLE;
>    g_pCDM->mclken_div_psc3 = CDM_PSC3_MCLK_CONFIG;
> #endif /* SPI_USE_MCLK */
>
>    /* Disable rx and tx */
>    g_pPSC->command = MPC52xx_PSC_RST_RX;
>    g_pPSC->command = MPC52xx_PSC_RST_TX;
>    g_pPSC->command = MPC52xx_PSC_SEL_MODE_REG_1;
>    g_pPSC->command = MPC52xx_PSC_RST_ERR_STAT;
>    g_pPSC->command = MPC52xx_PSC_RX_DISABLE | MPC52xx_PSC_TX_DISABLE;
>
>    g_pPSC->mode = 0;
>    g_pPSC->sicr = PSC3_SICR_REG_VALUE;
>
>    #ifdef SPI_USE_MCLK
>    g_pPSC->ccr=0x0703;       /* set SCK and DSCKL delay */
>    #else  /* SPI_USE_MCLK */
>    g_pPSC->ccr=0x0003;       /* set SCK and DSCKL delay must be > 2 */
>    #endif /* SPI_USE_MCLK */
>
>    g_pPSC->ctur=0x00;        /* Set DTL delay 2us */
>    g_pPSC->ctlr=0x84;
>
>    g_pPSC->rfalarm=100;      /* Alarm values taken from SPI example sample
> */
>    g_pPSC->tfalarm=1;
>
>    g_pPSC->rfcntl &= 0xf8;       /* 0 byte granularity */
>    g_pPSC->tfcntl = 1;
>
>    /* Enable rx & tx */
>    g_pPSC->command = MPC52xx_PSC_RST_RX;
>    g_pPSC->command = MPC52xx_PSC_RST_TX;
>    g_pPSC->command = MPC52xx_PSC_SEL_MODE_REG_1;
>    g_pPSC->command = MPC52xx_PSC_RST_ERR_STAT;
>    g_pPSC->command = MPC52xx_PSC_RX_ENABLE | MPC52xx_PSC_TX_ENABLE;
>
> ---------------------------------------------------------------------------
> Write code
> ---------------------------------------------------------------------------
> static int mpc52xx_spi_transfer(u16 *p_usBuffer, u16 p_usCount)
> {
>    u16 usIndex, usTemp;
>
>
> printk("------------------------------------------------------\n");
>    printk("Entry:         psc=%x status=%04x tfstat=%04x rfstat=%04x
> mode=%02x\n   tfnum %3d  rfnum %3d\n",
>
> (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
>      g_pPSC->tfnum, g_pPSC->rfnum);
>    g_pPSC->command = MPC52xx_PSC_RST_RX;
>    g_pPSC->command = MPC52xx_PSC_RST_TX;
>    g_pPSC->command = MPC52xx_PSC_SEL_MODE_REG_1;
>    g_pPSC->command = MPC52xx_PSC_RST_ERR_STAT;
>    g_pPSC->command = MPC52xx_PSC_RX_ENABLE | MPC52xx_PSC_TX_ENABLE;
>    printk("TX-RX Enable:  psc=%x status=%04x tfstat=%04x rfstat=%04x
> mode=%02x\n   tfnum %3d  rfnum %3d\n",
>
> (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
>      g_pPSC->tfnum, g_pPSC->rfnum);
>
>    /* Clean out the read FIFO */
>    usIndex = 0;
>    while(g_pPSC->mpc52xx_psc_status & MPC52xx_PSC_SR_RXRDY)
>    {
>       usTemp = g_pPSC->mpc52xx_psc_buffer_16;
>       printk("Flushing Rx FIFO: psc=%x status=%04x tfstat=%04x rfstat=%04x
> mode=%02x\n   tfnum %3d  rfnum %3d\n",
>
> (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
>         g_pPSC->tfnum, g_pPSC->rfnum);
>       udelay(100000);
>       udelay(100000);
>       udelay(100000);
>       udelay(100000);
>       udelay(100000);
>       usIndex++;
>       if(usIndex == 10) return(-1);
>    }
>
>    /* Send out the buffer */
>    g_pPSC->command = MPC52xx_PSC_RX_ENABLE | MPC52xx_PSC_TX_DISABLE;
>    for(usIndex=0; usIndex<p_usCount; usIndex++)
>    {
>       printk("Sending %04x:  psc=%x status=%04x tfstat=%04x rfstat=%04x
> mode=%02x\n   tfnum %3d  rfnum %3d\n",
>         p_usBuffer[usIndex],
> (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
>         g_pPSC->tfnum, g_pPSC->rfnum);
>       g_pPSC->mpc52xx_psc_buffer_16 = p_usBuffer[usIndex];
>       printk("Sent:          psc=%x status=%04x tfstat=%04x rfstat=%04x
> mode=%02x\n   tfnum %3d  rfnum %3d\n",
>
> (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
>         g_pPSC->tfnum, g_pPSC->rfnum);
>    }
>    g_pPSC->command = MPC52xx_PSC_RX_ENABLE | MPC52xx_PSC_TX_ENABLE;
>    usTemp = 0;
>    while(g_pPSC->tfnum)
>    {
>       printk("TFNUM Wait:   psc=%x status=%04x tfstat=%04x rfstat=%04x
> mode=%02x\n   tfnum %3d  rfnum %3d\n",
>
> (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
>         g_pPSC->tfnum, g_pPSC->rfnum);
>       udelay(100000);
>       udelay(100000);
>       udelay(100000);
>       udelay(100000);
>       udelay(100000);
>       usTemp++;
>       if(usTemp == 10) return(-1);
>    };
>    printk("TxRDY:         psc=%x status=%04x tfstat=%04x rfstat=%04x
> mode=%02x\n   tfnum %3d  rfnum %3d\n",
>
> (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
>      g_pPSC->tfnum, g_pPSC->rfnum);
>    for(usIndex=0; usIndex<p_usCount; usIndex++)
>    {
>       usTemp = 0;
>       while(!(g_pPSC->mpc52xx_psc_status &
> MPC52xx_PSC_SR_RXRDY))
>       {
>          printk("RxRDY Wait:    psc=%x status=%04x tfstat=%04x rfstat=%04x
> mode=%02x\n   tfnum %3d  rfnum %3d\n",
>
> (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
>            g_pPSC->tfnum, g_pPSC->rfnum);
>          udelay(100000);
>          udelay(100000);
>          udelay(100000);
>          udelay(100000);
>          udelay(100000);
>          usTemp++;
>          if(usTemp == 10) return(-1);
>       };
>       printk("RxRDY:         psc=%x status=%04x tfstat=%04x rfstat=%04x
> mode=%02x\n   tfnum %3d  rfnum %3d\n",
>
> (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
>         g_pPSC->tfnum, g_pPSC->rfnum);
>       p_usBuffer[usIndex] = g_pPSC->mpc52xx_psc_buffer_16;
>       printk("  Received %04x\n", p_usBuffer[usIndex]);
>    }
>
>    printk("EXIT:          psc=%x status=%04x tfstat=%04x rfstat=%04x
> mode=%02x\n   tfnum %3d  rfnum %3d\n",
>
> (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
>      g_pPSC->tfnum, g_pPSC->rfnum);
>    return(usIndex);
> }
>
>
> ---------------------------------------------------------------------------
> Output
> ---------------------------------------------------------------------------
> The lines below are a capture of register settings from my driver,
> along with output lines when trying to write 16 bit words to our
> device.  This output is consistent whether the device is connected
> or not (via J21).  Basic operation, delimited by "------...---":
>
>   - Disable TX, Enable RX (despite the "TX-RX Enable" heading)
>   - Send word 1
>   - Send word 2
>   - Enable TX, Enable RX
>   - Wait for tfnum == 0
>   - Receive data
>
> port_config=91051624 sicr=0280f000 clk_enables=00ffffff div_psc3=800f
> ------------------------------------------------------
> Entry:         psc=f0002400 status=0400 tfstat=0003 rfstat=0003 mode=33
>    tfnum   0  rfnum   0
> TX-RX Enable:  psc=f0002400 status=0400 tfstat=0003 rfstat=0003 mode=33
>    tfnum   0  rfnum   0
> Sending 0880:  psc=f0002400 status=0400 tfstat=0003 rfstat=0003 mode=07
>    tfnum   0  rfnum   0
> Sent:          psc=f0002400 status=0000 tfstat=0002 rfstat=0002 mode=07
>    tfnum   2  rfnum   0
> Sending bb00:  psc=f0002400 status=0000 tfstat=0002 rfstat=0002 mode=07
>    tfnum   2  rfnum   0
> Sent:          psc=f0002400 status=0000 tfstat=0002 rfstat=0002 mode=07
>    tfnum   4  rfnum   0
> TFNUM Wait:   psc=f0002400 status=0000 tfstat=0002 rfstat=0002 mode=07
>    tfnum   2  rfnum   0
> TxRDY:         psc=f0002400 status=0500 tfstat=0003 rfstat=0003 mode=07
>    tfnum   0  rfnum   4
> RxRDY:         psc=f0002400 status=0500 tfstat=0003 rfstat=0003 mode=07
>    tfnum   0  rfnum   4
>   Received ffff
> RxRDY:         psc=f0002400 status=0500 tfstat=0003 rfstat=0003 mode=07
>    tfnum   0  rfnum   2
>   Received ffff
> EXIT:          psc=f0002400 status=0400 tfstat=0003 rfstat=0003 mode=07
>    tfnum   0  rfnum   0
> ------------------------------------------------------
> Entry:         psc=f0002400 status=0400 tfstat=0003 rfstat=0003 mode=07
>    tfnum   0  rfnum   0
> TX-RX Enable:  psc=f0002400 status=0400 tfstat=0003 rfstat=0003 mode=33
>    tfnum   0  rfnum   0
> Sending 8820:  psc=f0002400 status=0400 tfstat=0003 rfstat=0003 mode=07
>    tfnum   0  rfnum   0
> Sent:          psc=f0002400 status=0000 tfstat=0002 rfstat=0002 mode=07
>    tfnum   2  rfnum   0
> Sending 0000:  psc=f0002400 status=0000 tfstat=0002 rfstat=0002 mode=07
>    tfnum   2  rfnum   0
> Sent:          psc=f0002400 status=0000 tfstat=0002 rfstat=0002 mode=07
>    tfnum   4  rfnum   0
> TFNUM Wait:   psc=f0002400 status=0000 tfstat=0002 rfstat=0002 mode=07
>    tfnum   2  rfnum   0
> TxRDY:         psc=f0002400 status=0500 tfstat=0003 rfstat=0003 mode=07
>    tfnum   0  rfnum   4
> RxRDY:         psc=f0002400 status=0500 tfstat=0003 rfstat=0003 mode=07
>    tfnum   0  rfnum   4
>   Received ffff
> RxRDY:         psc=f0002400 status=0500 tfstat=0003 rfstat=0003 mode=07
>    tfnum   0  rfnum   2
>   Received ffff
> EXIT:          psc=f0002400 status=0400 tfstat=0003 rfstat=0003 mode=07
>    tfnum   0  rfnum   0
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>
>

[-- Attachment #2: mpc5200_ts_spi.c --]
[-- Type: text/plain, Size: 6172 bytes --]

/*
 * Media5200 touchscreen driver
 *
 * Copyright (c) 2006 Freescale
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 */

/*
	File : mpc5200_ts_spi.c
	Summary : touchscreen spi driver
*/

#include "mpc5200_ts_spi.h"
#include "asm/io.h"


/**************** Public functions ****************/

/* 
	Initialize and configure spi 
	- configure mux port on psc3
	- configure spi mode
	- configure spi baud rate
	
*/
int spi_init (void) 
{
	struct mpc52xx_gpio __iomem *gpio;
	struct mpc52xx_intr __iomem *intr;

	/* Map zones */
	gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE);
	intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE);

	if (!gpio || !intr) {
		printk(KERN_ERR __FILE__ ": "
				"Error while mapping GPIO/INTR during "
				"spi_init\n");
		goto unmap_regs;
	}

	SPI_Config_T 	spi_config; /* spi configuration */

	PDEBUG3("spin_init: initializing SPI in spi_init()\n");

	/* enable interrupt */
	intr->per_mask &= INTR_PER_MASK_SPI_OFF;


	/* initialize mux port PSC3 to SPI */
	gpio->port_config |= GPIO_CONFIG_PORT_SPI_MASK;

	/* initialze data structure */	
	SPI_Regs = (SPI_Regs_T *)(SPI_BASE_ADDRESS);
	memset(&spi_config, 0, sizeof(SPI_Config_T)); 

	/* set spi config attributes */
	spi_config.SPI_Master = SPI_MASTER_DEFAULT;
	spi_config.ClockPolarity = SPI_CPOL_DEFAULT;
	spi_config.ClockPhase = SPI_CPHA_DEFAULT;
	spi_config.WiredOR = SPI_WOR_DEFAULT;
	spi_config.SSoutput = SPI_SSOE_DEFAULT;

	spi_config.SPI_Enable = SPI_SPE_DEFAULT;
	spi_config.BaudRate = SPI_BAUD_DEFAULT;    

	/* modify according to touchscreen driver spi config */   
	spi_config.ClockPolarity = 0;
	spi_config.ClockPhase = 0 ;
	spi_config.WiredOR = 0;


	/*Set the SS pin to low by set SPIPORT register*/ 
	SPI_Regs->SPIPORT = 0x00;

	/* now initialize the spi hardware */
	SPI_SetConfig(&spi_config);

	/* Unmap reg zone */
unmap_regs:
	if (gpio) iounmap(gpio);
	if (intr) iounmap(intr);

	return (TS_OK);
}







/* assume *buffer already alocated to be at least nbytes long */
int read_spi(u8 *buffer, u32 nbytes)
{
    int i;

	for (i = 0; i < nbytes; i++) {
	    buffer[i] = ReadRegister(SPI_Regs->SPIDR);
    } /* for */

	return (nbytes);
} /* read_spi */












int write_spi( u8 *buffer, u32 nbytes)
{
    u32 len;
    u8 reg_value;
    

    // Move this to one devctl command 
    // SPI_Regs->SPIPORT = 0x00;   
     
    for ( len = 0; len < nbytes; len++ )
    {
     

	    PDEBUG9("in write_spi: buffer = %x\n", *buffer);

        WriteRegister(SPI_Regs->SPIDR,*buffer);

        /* Wait several nanoseconds and then check the WCOL flag in status 
         * register.  WeiWei systest replace it with the for-loop directly
         */
        //  WAIT(NANOSECS_PER_WRITE);
        while(1)
        {
             reg_value = ReadRegister(SPI_Regs->SPISR); 
             if (reg_value & SPI_WCOL) 
             {
                WriteRegister(SPI_Regs->SPIDR,*buffer);
                continue;
             }
             if ( reg_value & SPI_SPIF )       
                 break;
	    }

        //SPI_Isr();
        buffer++;
    }
    /* WeiWei add : hardware team suggestion, but it is optional  */
    // SPI_Regs->SPIPORT = 0x08;   
    return len;
}





/*************** Private functions ********************/
static int SPI_SetConfig(SPI_Config_T * Config_Ptr )
{
    u8 control_reg = 0x00;

       
	/* initialize direction register for SPI */
    WriteRegister ( SPI_Regs->SPIDDR, 0x0e );   
      
    /* Set Baud Rate */
    if(SPI_SetBaudrate( Config_Ptr -> BaudRate) == TS_ERROR )
    {
        PDEBUG3("SPI_SetConfig: Error in Set baudrate \n");
        
        WriteRegister(SPI_Regs->SPICR1, control_reg | SPI_SPE);
        return TS_ERROR;
    }   

	/* aways master */     
	control_reg |= SPI_MASTER_MODE;
	/* The SSOE for master mode */          
	control_reg &= ~SPI_SSOE;     
       
	if(Config_Ptr -> ClockPolarity)
	    control_reg |= SPI_CPOL;
	else 
	    control_reg &= ~SPI_CPOL;
	    
	if(Config_Ptr -> ClockPhase)
	    control_reg |= SPI_CPHA;
	else 
	    control_reg &= ~SPI_CPHA;
	    
	if(Config_Ptr -> WiredOR)
	    control_reg |= SPI_SPWOM;
	else 
	    control_reg &= ~SPI_SPWOM;
        
    /* always enable SPI */    
    control_reg |= SPI_SPE;        
      

    /* Enable the interrupt and set the register : WeiWei systest */
    WriteRegister(SPI_Regs->SPICR1, control_reg | SPI_SPIE );
  
    PDEBUG3("SPI_SetCconfig : SPICR1 =%x \n",SPI_Regs->SPICR1);


    return TS_OK ;

}



static int SPI_SetBaudrate(u32 BaudRate)
{
    int i;
    u16 clockdivisor;

    /* Compute the Clock Divisor from module clock divided by BaudRate */ 
    clockdivisor = SPI_MODULE_CLOCK/BaudRate;
 
    /* Find the value of the Baud Rate Register from the array. 
     * If no accurate value can be found, select the closest one 
     */  
    for (i = 0; i < SPI_DIVISOR_NUM-1; i++)
    {
        if(( clockdivisor >= Clock_Divisor[i].clockdivisor ) && \
           ( clockdivisor < Clock_Divisor[i+1].clockdivisor))
        {      
            u16 middle;
            middle = (Clock_Divisor[i].clockdivisor + \
                   Clock_Divisor[i+1].clockdivisor)/2;
            if ( clockdivisor <= middle ) {
                WriteRegister(SPI_Regs->SPIBR,  \
                          Clock_Divisor[i].reg_value);
                PDEBUG3("SPI_SetBaudrate: Baudrate %d\n", SPI_MODULE_CLOCK/Clock_Divisor[i].clockdivisor); 
            } else {
                WriteRegister(SPI_Regs->SPIBR, \
                          Clock_Divisor[i+1].reg_value);
				PDEBUG3("SPI_SetBaudrate: Baudrate %d\n", SPI_MODULE_CLOCK/Clock_Divisor[i+1].clockdivisor);                          
            }
    
            return TS_OK;
        }
    }
    if ( clockdivisor == Clock_Divisor[i].clockdivisor )
    {     
       
        WriteRegister(SPI_Regs->SPIBR, Clock_Divisor[i].reg_value);   
        PDEBUG3("SPI_SetBaudrate: Exact Baudrate %d\n", SPI_MODULE_CLOCK/clockdivisor);
         
        return TS_OK;
    }
    else 
        return TS_ERROR;
}



^ permalink raw reply

* Re: MPC5200B SPI PSC3 Problem
From: John Rigby @ 2006-06-08 16:11 UTC (permalink / raw)
  To: Trueskew; +Cc: linuxppc-embedded
In-Reply-To: <4b73d43f0606080904v52e3cbe1kf9585bc1b0ba26a5@mail.gmail.com>

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

Here's an include file that goes with file in the last email.

On 6/8/06, John Rigby <jcrigby@gmail.com> wrote:
> There seems to be a conflict between two sections of the 5200 User manual.
> In section 7.3 where port_config is documented the PSC3 configuration
> bits (20:23)
> defined as:
>
> 0000 = All PSC3 pins are GPIOs
> 0001 = USB2 on PSC3, no GPIOs available, see Note 3
> 001X = Reserved
> 0100 = UART functionality without CD
> 0101 = UARTe functionality with CD
> 0110 = CODEC3 functionality
> 0111 = CODEC3 functionality (with MCLK)
> 100X = SPI
> 101X = Reserved
> 1100 = SPI with UART3
> 1101 = SPI with UART3e
> 111X = SPI with CODEC3
>
> but in the psc chapter in table 15-85 it says to set port config to
> 0x00000600 but
> the description says "Select the Pin-Muxing for PSC3 Codec mode"
>
> It appears that table 15-85 is wrong.
>
> I have attached some spi code that is embedded in a touchscreen
> driver.  It might be helpful.
>
>
>
>
>
> On 6/7/06, Trueskew <trueskew@gmail.com> wrote:
> >
> >
> > We have an AIC26 codec connected to our Lite5200B platform via J21.  I've
> > used MPC5200BUG to configure PSC3 as an SPI master, along with some samples
> > I've found online (including here) and some I received from Freescale.
> > Although the transfers seem to be working as expected (please see the output
> > file at the end of this message), I get only 0xffff back.  This occurs
> > whether or not the device is attached to J21.  A scope shows that PSC3_8
> > (SPI_SS) and PSC3_9 (SPI_CLK) are low at all times, and I'm concerned I'm
> > still doing something wrong with respect to enabling SPI over PSC3.
> >
> > I'm including my driver initialization code, my write code, and output
> > showing the write behavior.  If someone could comment on it, I would greatly
> > appreciate it... or if someone flat out has code to do this, I'd be happy to
> > take it from you.  I've seen a few variations, but whether I use them
> > directly or modify them as I need to, I can't seem to get past this.  Of
> > course, any other suggestions are welcome.
> >
> > Thanks.
> > Sal
> >
> > ---------------------------------------------------------------------------
> > Initialization Code
> > ---------------------------------------------------------------------------
> > #define GPIO_PSC3_PORT_CONFIG_MASK 0x00000f00
> > #ifdef SPI_USE_MCLK
> >    #define      GPIO_PSC3_PORT_CONFIG 0x00000700  /* PSC3 mode with mclk */
> > #else  /* SPI_USE_MCLK */
> >    #define      GPIO_PSC3_PORT_CONFIG 0x00000600  /* PSC3 mode */
> > #endif /* SPI_USE_MCLK */
> >
> > #define       CDM_PSC3_MCLK_ENABLE 0x00000080
> > #define       CDM_PSC3_MCLK_CONFIG 0x8020      /* Divide Fvco ftom 528 to
> >                                                   16Mhz */
> >
> > #define        PSC3_SICR_REG_VALUE 0x0280f000  /* 16-bit select Codec SPI
> >                                                   master
> > mode, msb first,
> >                                                   UseEOF=1.
> > GenClk=1, SIM,
> >                                                   CPOL and
> > CPHA are
> >                                                   function
> > input */
> > ...
> >    /* Select the Pin-Muxing for PSC3 Codec mode */
> >    gpio = (struct mpc52xx_gpio *) ioremap(MPC52xx_GPIO,
> >      sizeof(struct mpc52xx_gpio));
> >    if(gpio)
> >    {
> >       port_config = gpio->port_config;
> >       port_config &= ~GPIO_PSC3_PORT_CONFIG_MASK;
> >       port_config |= GPIO_PSC3_PORT_CONFIG;
> >       gpio->port_config = port_config;
> >       iounmap(gpio);
> >    }
> >    else
> >    {
> >       return(-1);
> >    }
> >
> > #ifdef SPI_USE_MCLK
> >    /* PSC clock enable */
> >    g_pCDM->clk_enables |= CDM_PSC3_MCLK_ENABLE;
> >    g_pCDM->mclken_div_psc3 = CDM_PSC3_MCLK_CONFIG;
> > #endif /* SPI_USE_MCLK */
> >
> >    /* Disable rx and tx */
> >    g_pPSC->command = MPC52xx_PSC_RST_RX;
> >    g_pPSC->command = MPC52xx_PSC_RST_TX;
> >    g_pPSC->command = MPC52xx_PSC_SEL_MODE_REG_1;
> >    g_pPSC->command = MPC52xx_PSC_RST_ERR_STAT;
> >    g_pPSC->command = MPC52xx_PSC_RX_DISABLE | MPC52xx_PSC_TX_DISABLE;
> >
> >    g_pPSC->mode = 0;
> >    g_pPSC->sicr = PSC3_SICR_REG_VALUE;
> >
> >    #ifdef SPI_USE_MCLK
> >    g_pPSC->ccr=0x0703;       /* set SCK and DSCKL delay */
> >    #else  /* SPI_USE_MCLK */
> >    g_pPSC->ccr=0x0003;       /* set SCK and DSCKL delay must be > 2 */
> >    #endif /* SPI_USE_MCLK */
> >
> >    g_pPSC->ctur=0x00;        /* Set DTL delay 2us */
> >    g_pPSC->ctlr=0x84;
> >
> >    g_pPSC->rfalarm=100;      /* Alarm values taken from SPI example sample
> > */
> >    g_pPSC->tfalarm=1;
> >
> >    g_pPSC->rfcntl &= 0xf8;       /* 0 byte granularity */
> >    g_pPSC->tfcntl = 1;
> >
> >    /* Enable rx & tx */
> >    g_pPSC->command = MPC52xx_PSC_RST_RX;
> >    g_pPSC->command = MPC52xx_PSC_RST_TX;
> >    g_pPSC->command = MPC52xx_PSC_SEL_MODE_REG_1;
> >    g_pPSC->command = MPC52xx_PSC_RST_ERR_STAT;
> >    g_pPSC->command = MPC52xx_PSC_RX_ENABLE | MPC52xx_PSC_TX_ENABLE;
> >
> > ---------------------------------------------------------------------------
> > Write code
> > ---------------------------------------------------------------------------
> > static int mpc52xx_spi_transfer(u16 *p_usBuffer, u16 p_usCount)
> > {
> >    u16 usIndex, usTemp;
> >
> >
> > printk("------------------------------------------------------\n");
> >    printk("Entry:         psc=%x status=%04x tfstat=%04x rfstat=%04x
> > mode=%02x\n   tfnum %3d  rfnum %3d\n",
> >
> > (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
> >      g_pPSC->tfnum, g_pPSC->rfnum);
> >    g_pPSC->command = MPC52xx_PSC_RST_RX;
> >    g_pPSC->command = MPC52xx_PSC_RST_TX;
> >    g_pPSC->command = MPC52xx_PSC_SEL_MODE_REG_1;
> >    g_pPSC->command = MPC52xx_PSC_RST_ERR_STAT;
> >    g_pPSC->command = MPC52xx_PSC_RX_ENABLE | MPC52xx_PSC_TX_ENABLE;
> >    printk("TX-RX Enable:  psc=%x status=%04x tfstat=%04x rfstat=%04x
> > mode=%02x\n   tfnum %3d  rfnum %3d\n",
> >
> > (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
> >      g_pPSC->tfnum, g_pPSC->rfnum);
> >
> >    /* Clean out the read FIFO */
> >    usIndex = 0;
> >    while(g_pPSC->mpc52xx_psc_status & MPC52xx_PSC_SR_RXRDY)
> >    {
> >       usTemp = g_pPSC->mpc52xx_psc_buffer_16;
> >       printk("Flushing Rx FIFO: psc=%x status=%04x tfstat=%04x rfstat=%04x
> > mode=%02x\n   tfnum %3d  rfnum %3d\n",
> >
> > (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
> >         g_pPSC->tfnum, g_pPSC->rfnum);
> >       udelay(100000);
> >       udelay(100000);
> >       udelay(100000);
> >       udelay(100000);
> >       udelay(100000);
> >       usIndex++;
> >       if(usIndex == 10) return(-1);
> >    }
> >
> >    /* Send out the buffer */
> >    g_pPSC->command = MPC52xx_PSC_RX_ENABLE | MPC52xx_PSC_TX_DISABLE;
> >    for(usIndex=0; usIndex<p_usCount; usIndex++)
> >    {
> >       printk("Sending %04x:  psc=%x status=%04x tfstat=%04x rfstat=%04x
> > mode=%02x\n   tfnum %3d  rfnum %3d\n",
> >         p_usBuffer[usIndex],
> > (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
> >         g_pPSC->tfnum, g_pPSC->rfnum);
> >       g_pPSC->mpc52xx_psc_buffer_16 = p_usBuffer[usIndex];
> >       printk("Sent:          psc=%x status=%04x tfstat=%04x rfstat=%04x
> > mode=%02x\n   tfnum %3d  rfnum %3d\n",
> >
> > (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
> >         g_pPSC->tfnum, g_pPSC->rfnum);
> >    }
> >    g_pPSC->command = MPC52xx_PSC_RX_ENABLE | MPC52xx_PSC_TX_ENABLE;
> >    usTemp = 0;
> >    while(g_pPSC->tfnum)
> >    {
> >       printk("TFNUM Wait:   psc=%x status=%04x tfstat=%04x rfstat=%04x
> > mode=%02x\n   tfnum %3d  rfnum %3d\n",
> >
> > (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
> >         g_pPSC->tfnum, g_pPSC->rfnum);
> >       udelay(100000);
> >       udelay(100000);
> >       udelay(100000);
> >       udelay(100000);
> >       udelay(100000);
> >       usTemp++;
> >       if(usTemp == 10) return(-1);
> >    };
> >    printk("TxRDY:         psc=%x status=%04x tfstat=%04x rfstat=%04x
> > mode=%02x\n   tfnum %3d  rfnum %3d\n",
> >
> > (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
> >      g_pPSC->tfnum, g_pPSC->rfnum);
> >    for(usIndex=0; usIndex<p_usCount; usIndex++)
> >    {
> >       usTemp = 0;
> >       while(!(g_pPSC->mpc52xx_psc_status &
> > MPC52xx_PSC_SR_RXRDY))
> >       {
> >          printk("RxRDY Wait:    psc=%x status=%04x tfstat=%04x rfstat=%04x
> > mode=%02x\n   tfnum %3d  rfnum %3d\n",
> >
> > (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
> >            g_pPSC->tfnum, g_pPSC->rfnum);
> >          udelay(100000);
> >          udelay(100000);
> >          udelay(100000);
> >          udelay(100000);
> >          udelay(100000);
> >          usTemp++;
> >          if(usTemp == 10) return(-1);
> >       };
> >       printk("RxRDY:         psc=%x status=%04x tfstat=%04x rfstat=%04x
> > mode=%02x\n   tfnum %3d  rfnum %3d\n",
> >
> > (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
> >         g_pPSC->tfnum, g_pPSC->rfnum);
> >       p_usBuffer[usIndex] = g_pPSC->mpc52xx_psc_buffer_16;
> >       printk("  Received %04x\n", p_usBuffer[usIndex]);
> >    }
> >
> >    printk("EXIT:          psc=%x status=%04x tfstat=%04x rfstat=%04x
> > mode=%02x\n   tfnum %3d  rfnum %3d\n",
> >
> > (int)g_pPSC,g_pPSC->mpc52xx_psc_status,g_pPSC->tfstat,g_pPSC->tfstat,g_pPSC->mode,
> >      g_pPSC->tfnum, g_pPSC->rfnum);
> >    return(usIndex);
> > }
> >
> >
> > ---------------------------------------------------------------------------
> > Output
> > ---------------------------------------------------------------------------
> > The lines below are a capture of register settings from my driver,
> > along with output lines when trying to write 16 bit words to our
> > device.  This output is consistent whether the device is connected
> > or not (via J21).  Basic operation, delimited by "------...---":
> >
> >   - Disable TX, Enable RX (despite the "TX-RX Enable" heading)
> >   - Send word 1
> >   - Send word 2
> >   - Enable TX, Enable RX
> >   - Wait for tfnum == 0
> >   - Receive data
> >
> > port_config=91051624 sicr=0280f000 clk_enables=00ffffff div_psc3=800f
> > ------------------------------------------------------
> > Entry:         psc=f0002400 status=0400 tfstat=0003 rfstat=0003 mode=33
> >    tfnum   0  rfnum   0
> > TX-RX Enable:  psc=f0002400 status=0400 tfstat=0003 rfstat=0003 mode=33
> >    tfnum   0  rfnum   0
> > Sending 0880:  psc=f0002400 status=0400 tfstat=0003 rfstat=0003 mode=07
> >    tfnum   0  rfnum   0
> > Sent:          psc=f0002400 status=0000 tfstat=0002 rfstat=0002 mode=07
> >    tfnum   2  rfnum   0
> > Sending bb00:  psc=f0002400 status=0000 tfstat=0002 rfstat=0002 mode=07
> >    tfnum   2  rfnum   0
> > Sent:          psc=f0002400 status=0000 tfstat=0002 rfstat=0002 mode=07
> >    tfnum   4  rfnum   0
> > TFNUM Wait:   psc=f0002400 status=0000 tfstat=0002 rfstat=0002 mode=07
> >    tfnum   2  rfnum   0
> > TxRDY:         psc=f0002400 status=0500 tfstat=0003 rfstat=0003 mode=07
> >    tfnum   0  rfnum   4
> > RxRDY:         psc=f0002400 status=0500 tfstat=0003 rfstat=0003 mode=07
> >    tfnum   0  rfnum   4
> >   Received ffff
> > RxRDY:         psc=f0002400 status=0500 tfstat=0003 rfstat=0003 mode=07
> >    tfnum   0  rfnum   2
> >   Received ffff
> > EXIT:          psc=f0002400 status=0400 tfstat=0003 rfstat=0003 mode=07
> >    tfnum   0  rfnum   0
> > ------------------------------------------------------
> > Entry:         psc=f0002400 status=0400 tfstat=0003 rfstat=0003 mode=07
> >    tfnum   0  rfnum   0
> > TX-RX Enable:  psc=f0002400 status=0400 tfstat=0003 rfstat=0003 mode=33
> >    tfnum   0  rfnum   0
> > Sending 8820:  psc=f0002400 status=0400 tfstat=0003 rfstat=0003 mode=07
> >    tfnum   0  rfnum   0
> > Sent:          psc=f0002400 status=0000 tfstat=0002 rfstat=0002 mode=07
> >    tfnum   2  rfnum   0
> > Sending 0000:  psc=f0002400 status=0000 tfstat=0002 rfstat=0002 mode=07
> >    tfnum   2  rfnum   0
> > Sent:          psc=f0002400 status=0000 tfstat=0002 rfstat=0002 mode=07
> >    tfnum   4  rfnum   0
> > TFNUM Wait:   psc=f0002400 status=0000 tfstat=0002 rfstat=0002 mode=07
> >    tfnum   2  rfnum   0
> > TxRDY:         psc=f0002400 status=0500 tfstat=0003 rfstat=0003 mode=07
> >    tfnum   0  rfnum   4
> > RxRDY:         psc=f0002400 status=0500 tfstat=0003 rfstat=0003 mode=07
> >    tfnum   0  rfnum   4
> >   Received ffff
> > RxRDY:         psc=f0002400 status=0500 tfstat=0003 rfstat=0003 mode=07
> >    tfnum   0  rfnum   2
> >   Received ffff
> > EXIT:          psc=f0002400 status=0400 tfstat=0003 rfstat=0003 mode=07
> >    tfnum   0  rfnum   0
> > _______________________________________________
> > Linuxppc-embedded mailing list
> > Linuxppc-embedded@ozlabs.org
> > https://ozlabs.org/mailman/listinfo/linuxppc-embedded
> >
> >
>
>
>

[-- Attachment #2: mpc5200_ts_spi.h --]
[-- Type: text/plain, Size: 3296 bytes --]

/*
 * Media5200 touchscreen driver
 *
 * Copyright (c) 2006 Freescale
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 */

/*
	File : "mpc5200_ts_spi.h"
	Summary: spi header file


*/

#ifndef __MPC5200_TS_SPI_H
#define __MPC5200_TS_SPI_H

/* headers */
#include "mpc5200_ts_common.h"
#include "mpc5200_ts_spi_dfn.h"

typedef struct SPI_Config_Type
{
    u8  SPI_Master;      /* 1 =  SPI device is Master; */
                             /* 0 = SPI device is Slave */
    u8  ClockPolarity;   /* 1 = Active-low clocks selected;*/ 
                             /* 0 = Active-high clocks selected */
    u8  ClockPhase;      /* Clock Phase */
    u8  WiredOR;         /* 1 = Wired-OR mode */
    u8  SPI_Enable;      /* 1 = SPI system enable */
    u8  SSoutput;        /* 1 = SS as general-purpose output*/
    u32 BaudRate;        /* Baud Rate ,the unit is KHz */ 
} SPI_Config_T;


typedef struct ClockDivisor_Type
{
    u8    reg_value;    /* The corresponding register value */
    u16    clockdivisor; /* Clock Divisor */
} ClockDivisor_T;


/* The following are default values of SPI configuration : code review */
#define SPI_MASTER_DEFAULT                  1
#define SPI_CPOL_DEFAULT                    1
#define SPI_CPHA_DEFAULT                    1
#define SPI_WOR_DEFAULT                     1
#define SPI_SPE_DEFAULT                     1
#define SPI_SSOE_DEFAULT                    1   /*WeiWei add it for SSOE bit */
//#define SPI_BAUD_DEFAULT                  206250 // with 66MHZ clock, should yield 320 divisor .. this may solve errata sheet where SPIF set before data ready below 200KHZ 50000
#define SPI_BAUD_DEFAULT                  128900 // with 132MHz bus, 1024
//#define SPI_BAUD_DEFAULT                  50000
#define RCVBUF_SIZE_DEFAULT               512
#define RCVBUF_MIN_SIZE                   4
#define RCVBUF_MAX_SIZE                   4096
#define MSG_MAX_SIZE                      2048
#define BUFSIZE                           512

/* setting for module clock is now 132MHZ for Media5200 */
#define SPI_MODULE_CLOCK                  132000000

#define SPI_DIVISOR_NUM                   36
#define NANOSECS_PER_WRITE                1000000
#define NANOSECS_FOR_WCOL                 1000000
#define LOOPS                             10


/* Clock Divisor Selections Array. All clock divisor selections the spi driver 
 * can support are arranged between 640 to 2048 in ascending order. The supported 
 * baudrate range will rely on the SPI module clock( system clock).  
 * Given 66MHz system clock, the baudrate ranged between 33000Hz to 100000Hz.
 */
/* For memory leak : up the baud rate to 100KHz */
ClockDivisor_T Clock_Divisor[SPI_DIVISOR_NUM] =
{ { 0x45, 320},{ 0x46, 640 }, { 0x56, 768 }, { 0x66, 896 }, { 0x76, 1024 }, { 0x47, 1280 }, { 0x57, 1536 },{ 0x67, 1792}, { 0x77, 2048 } };





SPI_Regs_T		*SPI_Regs; /* spi register struct */



/* public function prototyping */
int spi_init (void);
int write_spi(u8 *buffer, u32 nbytes);
int read_spi(u8 *buffer, u32 nbytes);

/* private functions prototyping */
static int SPI_SetConfig(SPI_Config_T * Config_Ptr );
static int SPI_SetBaudrate( u32 BaudRate);

#endif

^ permalink raw reply

* Re: does Gianfar Ethernet Controller Version 1.1 support MARVELL 88E1111?
From: Andy Fleming @ 2006-06-08 16:15 UTC (permalink / raw)
  To: 郭 剑非; +Cc: Linuxppc-embedded
In-Reply-To: <BAY113-F12840A9A3ACBD5515A1350988B0@phx.gbl>


On Jun 8, 2006, at 02:43, =E9=83=AD =E5=89=91=E9=9D=9E wrote:

> Hi all,
> I'm debugging my board with MPC 8540 and marvell 88e1111 designed =20
> on it.
> I'm sure the hardware connection is correct, and the phy's ID could =20=

> be read
> through terminal port. But anyway, phy can not work. I wonder if it =20=

> is the
> driver's problem? Since the Gianfar Ethernet Controller Version 1.1
> surpport 88e1011s, but some 88e1111's registers are different from
> 88e1011s'. Actually I'm a new guy to Linux. Has anybody ever used =20
> 88e1111
> phy in Linux envirenmemt? Please
> give me some points. Thank you!
> I have read the Gianfar ethernet controller driver, but it's =20
> difficult for
> me to find out the sofware flow.


It would be better if you upgraded to the latest kernel.  The PHY =20
subsystem in the driver has changed significantly since version 1.1 =20
of the driver.  What leads you to believe that the PHY doesn't work?  =20=

What errors do you see?  I'm fairly certain the 88e1111 works with =20
the 88e1011 driver, but it's been a while.

^ permalink raw reply

* Re: [PATCH 3/3] RTAS MSI
From: Jake Moilanen @ 2006-06-08 16:13 UTC (permalink / raw)
  To: Nathan Lynch; +Cc: linuxppc-dev, paulus
In-Reply-To: <20060607225843.GW8934@localdomain>

Here's a version addressing Nathan's concerns.

Signed-off-by: Jake Moilanen <moilanen@austin.ibm.com>

Index: 2.6/drivers/pci/Makefile
===================================================================
--- 2.6.orig/drivers/pci/Makefile	2006-06-08 10:30:14.000000000 -0500
+++ 2.6/drivers/pci/Makefile	2006-06-08 10:30:21.000000000 -0500
@@ -26,7 +26,14 @@
 obj-$(CONFIG_PPC64) += setup-bus.o
 obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
 obj-$(CONFIG_X86_VISWS) += setup-irq.o
-obj-$(CONFIG_PCI_MSI) += msi.o
+
+msiobj-$(CONFIG_X86) += msi.o msi-apic.o msi-intel.o
+msiobj-$(CONFIG_IA64) += msi.o msi-apic.o msi-intel.o
+msiobj-$(CONFIG_IA64_GENERIC) += msi.o msi-altix.o
+msiobj-$(CONFIG_IA64_SGI_SN2) += msi.o msi-altix.o
+msiobj-$(CONFIG_PPC_PSERIES) += msi-rtas.o
+
+obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
 
 #
 # ACPI Related PCI FW Functions
Index: 2.6/drivers/pci/msi-rtas.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ 2.6/drivers/pci/msi-rtas.c	2006-06-08 10:51:13.000000000 -0500
@@ -0,0 +1,150 @@
+/*
+ * Jake Moilanen <moilanen@austin.ibm.com>
+ * Copyright (C) 2006 IBM
+ *
+ * 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; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <asm/rtas.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+int rtas_enable_msi(struct pci_dev* pdev)
+{
+	int seq_num = 1;
+	int i;
+	int rc;
+	int query_token = rtas_token("ibm,query-interrupt-source-number");
+	int devfn;
+	int busno;
+	u32 *reg;
+	int reglen;
+	int ret[3];
+	int dummy;
+	unsigned int virq;
+	unsigned int addr;
+	unsigned long buid = -1;
+	struct device_node * dn;
+
+	BUG_ON(!pdev);
+
+	dn = pci_device_to_OF_node(pdev);
+
+	if (!of_find_property(dn, "ibm,req#msi", &dummy))
+		return -ENOENT;
+
+	reg = (u32 *) get_property(dn, "reg", &reglen);
+	if (reg == NULL || reglen < 20)
+		return -ENXIO;
+
+	devfn = (reg[0] >> 8) & 0xff;
+	busno = (reg[0] >> 16) & 0xff;
+
+	buid = get_phb_buid(dn->parent);
+	addr = (busno << 16) | (devfn << 8);
+
+	do {
+		rc = rtas_call(rtas_token("ibm,change-msi"), 6, 3, ret, addr,
+			       buid >> 32, buid & 0xffffffff,
+			       0, 0, seq_num);
+
+		seq_num = ret[1];
+	} while (rtas_busy_delay(rc));
+
+	if (rc)
+	{
+		printk(KERN_WARNING "error[%d]: getting the number of "
+		       "MSI interrupts for %s\n", rc, dn->name);
+		return -EIO;
+	}
+
+	/* Return if there's no MSI interrupts */
+	if (!ret[0])
+		return -ENOENT;
+
+	dn->n_intrs = ret[0];
+
+	dn->intrs = kmalloc(dn->n_intrs * sizeof(*(dn->intrs)), GFP_KERNEL);
+	if (!dn->intrs) {
+		printk(KERN_WARNING "rtas_enable_msi: can't allocate space\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < dn->n_intrs; i++) {
+		do {
+			rc = rtas_call(query_token, 4, 3, ret, addr,
+				       buid >> 32, buid & 0xffffffff, i);
+		} while (rtas_busy_delay(rc));
+
+		if (!rc) {
+			virq = virt_irq_create_mapping(ret[0]);
+
+			dn->intrs[i].line = irq_offset_up(virq);
+			dn->intrs[i].sense = ret[1];
+		} else {
+			printk(KERN_WARNING "error[%d]: query-interrupt-source-number for %s\n",
+			       rc, dn->name);
+		}
+	}
+
+	/* Just give the first vector out for now */
+	pdev->irq = dn->intrs[0].line;
+
+	return 0;
+}
+
+void rtas_disable_msi(struct pci_dev* pdev)
+{
+	int seq_num = 1;
+	struct device_node * dn;
+	int rc;
+	int devfn;
+	int busno;
+	u32 *reg;
+	int reglen;
+	int ret[3];
+	int dummy;
+	unsigned int addr;
+	unsigned long buid = -1;
+
+	BUG_ON(!pdev);
+
+	dn = pci_device_to_OF_node(pdev);
+
+	if (!of_find_property(dn, "ibm,req#msi", &dummy))
+		return;
+
+	reg = (u32 *) get_property(dn, "reg", &reglen);
+	if (reg == NULL || reglen < 20)
+		return;
+
+	devfn = (reg[0] >> 8) & 0xff;
+	busno = (reg[0] >> 16) & 0xff;
+
+	buid = get_phb_buid(dn->parent);
+	addr = (busno << 16) | (devfn << 8);
+
+	do {
+		rc = rtas_call(rtas_token("ibm,change-msi"), 6, 3, ret, addr,
+			       buid >> 32, buid & 0xffffffff,
+			       2, 0, seq_num);
+
+		seq_num = ret[1];
+	} while (rtas_busy_delay(rc));
+
+	if (rc) {
+		printk(KERN_WARNING "error[%d]: setting the number of "
+		       "MSI interrupts for %s\n", rc, dn->name);
+		return;
+	}
+
+	dn->n_intrs = 0;
+
+	kfree(dn->intrs);
+}
Index: 2.6/drivers/pci/Kconfig
===================================================================
--- 2.6.orig/drivers/pci/Kconfig	2006-06-08 10:30:14.000000000 -0500
+++ 2.6/drivers/pci/Kconfig	2006-06-08 10:30:21.000000000 -0500
@@ -4,7 +4,7 @@
 config PCI_MSI
 	bool "Message Signaled Interrupts (MSI and MSI-X)"
 	depends on PCI
-	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64
+	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 || PPC_PSERIES
 	help
 	   This allows device drivers to enable MSI (Message Signaled
 	   Interrupts).  Message Signaled Interrupts enable a device to
Index: 2.6/arch/powerpc/platforms/pseries/setup.c
===================================================================
--- 2.6.orig/arch/powerpc/platforms/pseries/setup.c	2006-06-08 10:30:14.000000000 -0500
+++ 2.6/arch/powerpc/platforms/pseries/setup.c	2006-06-08 10:30:21.000000000 -0500
@@ -205,6 +205,10 @@
 	} else {
 		ppc_md.init_IRQ       = xics_init_IRQ;
 		ppc_md.get_irq        = xics_get_irq;
+#ifdef CONFIG_PCI_MSI
+		ppc_md.enable_msi	= rtas_enable_msi;
+		ppc_md.disable_msi	= rtas_disable_msi;
+#endif
 	}
 
 #ifdef CONFIG_SMP
Index: 2.6/include/asm-powerpc/rtas.h
===================================================================
--- 2.6.orig/include/asm-powerpc/rtas.h	2006-06-08 10:30:21.000000000 -0500
+++ 2.6/include/asm-powerpc/rtas.h	2006-06-08 10:30:21.000000000 -0500
@@ -4,6 +4,7 @@
 
 #include <linux/spinlock.h>
 #include <asm/page.h>
+#include <linux/pci.h>
 
 /*
  * Definitions for talking to the RTAS on CHRP machines.
@@ -182,6 +183,9 @@
 
 extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal);
 
+extern int rtas_enable_msi(struct pci_dev* pdev);
+extern void rtas_disable_msi(struct pci_dev * pdev);
+
 /* Error types logged.  */
 #define ERR_FLAG_ALREADY_LOGGED	0x0
 #define ERR_FLAG_BOOT		0x1 	/* log was pulled from NVRAM on boot */

^ permalink raw reply

* Re: A Couple of 2.6/Xilinx Questions
From: Grant Likely @ 2006-06-08 17:17 UTC (permalink / raw)
  To: rakirtley@bellsouth.net; +Cc: linuxppc-embedded
In-Reply-To: <20060608144535.RSPS5063.ibm70aec.bellsouth.net@mail.bellsouth.net>

On 6/8/06, rakirtley@bellsouth.net <rakirtley@bellsouth.net> wrote:
> All,
>     I've been attempting to get a 2.6 version running on the Xilinx ML403 and only really need the ethernet and compact flash devices at this point.  I've tried versions from mvista, kernel.org, etc; all only have the serial8250 device enabled.  Obviously adding devices is a lot of work and it appears that you all have already made great progress enabling ethernet.
>    Are any of  the advanced versions upon which you all work generally available?  If so could you please provide a location? Apologies in advance for polluting your emailboxes and thanks in advance for any help/pointers that you can provide. I'll be more than happy to share any mods that I make (if any)

Mvista published patches for a TEMAC driver a month or two ago onto
this mailing list.  Last I heard, mvista will be releasing 2.6 support
for the V2/V4 parts by the end of this month.

Cheers,
g.

-- 
Grant Likely, B.Sc. P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195

^ permalink raw reply

* VFS: Cannot open root device ...
From: Chris Dumoulin @ 2006-06-08 17:20 UTC (permalink / raw)
  To: linuxppc-embedded

I'm trying to port a 2.6 kernel to a V2Pro-based board that I've got. I 
get the following output when trying to boot:

RAMDISK: Compressed image found at block 0
VFS: Mounted root (ext2 filesystem).
VFS: Cannot open root device "<NULL>" or unknown-block(0,0)
Please append a correct "root=" boot option
Kernel panic - not syncing: VFS: Unable to mount root fs on 
unknown-block(0,0)

I'm trying to use an initrd RAMDISK, and I've made sure that RAMDISK and 
initrd support are both enabled in the kernel configuration. Any ideas 
would be appreciated.

Cheers,
Chris Dumoulin
-- 
*--Christopher Dumoulin--*
Software Team Leader

<http://ics-ltd.com/>
<http://ics-ltd.com/>

Interactive Circuits and Systems Ltd.
5430 Canotek Road
Ottawa, ON
K1J 9G2
(613)749-9241
1-800-267-9794 (USA only)

------------------------------------------------------------------------
This e-mail is private and confidential and is for the addressee only. 
If misdirected, please notify us by telephone and confirm that it has 
been deleted from your system and any hard copies destroyed. You are 
strictly prohibited from using, printing, distributing or disseminating 
it or any information contained in it save to the intended recipient.

^ permalink raw reply

* Re: does Gianfar Ethernet Controller Version 1.1 support MARVELL 88E1111?
From: Guo Jaffe @ 2006-06-08 17:51 UTC (permalink / raw)
  To: afleming; +Cc: Linuxppc-embedded
In-Reply-To: <912A1A11-36AB-4E68-BC29-7F584270C4F0@freescale.com>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=gb2312; format=flowed, Size: 1805 bytes --]

Hi Andy,

Thank you for your information. So the driver is not the issue, but better 
to upgraded.

I will check the board once more. The PHY doesn't work because the 8bit bus 
between MAC and PHY is locked(TX_EN and RX_DV all disabled from the scope's 
view) and also you can't see any signals exist at the Magnetic side(nor LED 
signals). It seems that only MDC/MDIO and CLOCK reference pin works. The 
PHY's ID must be read from MDC/MDIO interface and Clocks are right showed 
on the scope.

Best Regards,
Jaffe


>From: Andy Fleming <afleming@freescale.com>
>To: 郁\x7f 剑非 <jianfei616@hotmail.com>
>CC: Linuxppc-embedded@ozlabs.org
>Subject: Re: does Gianfar Ethernet Controller Version 1.1 support MARVELL 
88E1111?
>Date: Thu, 8 Jun 2006 11:15:32 -0500
>
>
>On Jun 8, 2006, at 02:43, 郁\x7f 剑非 wrote:
>
>>Hi all,
>>I'm debugging my board with MPC 8540 and marvell 88e1111 designed  
>>on it.
>>I'm sure the hardware connection is correct, and the phy's ID could 
>>  be read
>>through terminal port. But anyway, phy can not work. I wonder if it 
>>  is the
>>driver's problem? Since the Gianfar Ethernet Controller Version 1.1
>>surpport 88e1011s, but some 88e1111's registers are different from
>>88e1011s'. Actually I'm a new guy to Linux. Has anybody ever used  
>>88e1111
>>phy in Linux envirenmemt? Please
>>give me some points. Thank you!
>>I have read the Gianfar ethernet controller driver, but it's  
>>difficult for
>>me to find out the sofware flow.
>
>
>It would be better if you upgraded to the latest kernel.  The PHY  
>subsystem in the driver has changed significantly since version 1.1  
>of the driver.  What leads you to believe that the PHY doesn't work? 
>   What errors do you see?  I'm fairly certain the 88e1111 works 
>with  the 88e1011 driver, but it's been a while.
>

^ permalink raw reply

* Re: VFS: Cannot open root device ...
From: Steve Iribarne (GMail) @ 2006-06-08 18:39 UTC (permalink / raw)
  To: Chris Dumoulin; +Cc: linuxppc-embedded
In-Reply-To: <44885C45.7020009@ics-ltd.com>

On 6/8/06, Chris Dumoulin <cdumoulin@ics-ltd.com> wrote:
> I'm trying to port a 2.6 kernel to a V2Pro-based board that I've got. I
> get the following output when trying to boot:
>
> RAMDISK: Compressed image found at block 0
> VFS: Mounted root (ext2 filesystem).
> VFS: Cannot open root device "<NULL>" or unknown-block(0,0)
> Please append a correct "root=" boot option
> Kernel panic - not syncing: VFS: Unable to mount root fs on
> unknown-block(0,0)

What boot loader are you using?  In the boot loader where does it
think the root fs is located?  My guess is /dev/ram0 or something like
that?

So I'd check your ramdisk to see that it has a /dev/ram0.
Make sure you have rights to it.

-stv
>
> I'm trying to use an initrd RAMDISK, and I've made sure that RAMDISK and
> initrd support are both enabled in the kernel configuration. Any ideas
> would be appreciated.
>
> Cheers,
> Chris Dumoulin
> --
> *--Christopher Dumoulin--*
> Software Team Leader
>
> <http://ics-ltd.com/>
> <http://ics-ltd.com/>
>
> Interactive Circuits and Systems Ltd.
> 5430 Canotek Road
> Ottawa, ON
> K1J 9G2
> (613)749-9241
> 1-800-267-9794 (USA only)
>
> ------------------------------------------------------------------------
> This e-mail is private and confidential and is for the addressee only.
> If misdirected, please notify us by telephone and confirm that it has
> been deleted from your system and any hard copies destroyed. You are
> strictly prohibited from using, printing, distributing or disseminating
> it or any information contained in it save to the intended recipient.
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>

^ permalink raw reply

* Re: does Gianfar Ethernet Controller Version 1.1 support MARVELL 88E1111?
From: Andy Fleming @ 2006-06-08 19:25 UTC (permalink / raw)
  To: Guo Jaffe; +Cc: Linuxppc-embedded
In-Reply-To: <BAY113-F70D5359537D7DC16B4678988B0@phx.gbl>


On Jun 8, 2006, at 12:51, Guo Jaffe wrote:

> Hi Andy,
>
> Thank you for your information. So the driver is not the issue, but  
> better to upgraded.
>
> I will check the board once more. The PHY doesn't work because the  
> 8bit bus between MAC and PHY is locked(TX_EN and RX_DV all disabled  
> from the scope's view) and also you can't see any signals exist at  
> the Magnetic side(nor LED signals). It seems that only MDC/MDIO and  
> CLOCK reference pin works. The PHY's ID must be read from MDC/MDIO  
> interface and Clocks are right showed on the scope.


But what error are you getting?  What are the symptoms of your  
problem?  The GMII interface (the 8-bit bus) is inconsequential to  
PHY configuration and management.  Only the MDC/MDIO bus is used.   
Therefore the PHY id should be quite readable.  What version of Linux  
are you using?  Please describe what the kernel prints out when you  
boot, and when you try to bring up the interface (assuming you don't  
do that at boot).

Andy

^ permalink raw reply

* Re: [PATCH 9/10] Add Vitesse 8244 PHY for MPC8641 HPCN platform.
From: Jeff Garzik @ 2006-06-08 19:34 UTC (permalink / raw)
  To: Jon Loeliger; +Cc: linuxppc-dev@ozlabs.org, netdev
In-Reply-To: <1149720298.23938.207.camel@cashmere.sps.mot.com>

Jon Loeliger wrote:
> Signed-off-by: Kriston Carson <KristonCarson@freescale.com>
> Signed-off-by: Xianghua Xiao <x.xiao@freescale.com>
> Signed-off-by: Jon Loeliger <jdl@freescale.com>

ACK, but patch does not apply to netdev-2.6.git#upstream.

	Jeff

^ 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