Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb40dcbb authored by Andy Fleming's avatar Andy Fleming Committed by Jeff Garzik
Browse files

[netdrvr gianfar] use new phy layer

parent acc4b985
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -2075,6 +2075,8 @@ config SPIDER_NET
config GIANFAR
config GIANFAR
	tristate "Gianfar Ethernet"
	tristate "Gianfar Ethernet"
	depends on 85xx || 83xx
	depends on 85xx || 83xx
	select PHYLIB
	select PHYCONTROL
	help
	help
	  This driver supports the Gigabit TSEC on the MPC85xx 
	  This driver supports the Gigabit TSEC on the MPC85xx 
	  family of chips, and the FEC on the 8540
	  family of chips, and the FEC on the 8540
+1 −1
Original line number Original line Diff line number Diff line
@@ -13,7 +13,7 @@ obj-$(CONFIG_CHELSIO_T1) += chelsio/
obj-$(CONFIG_BONDING) += bonding/
obj-$(CONFIG_BONDING) += bonding/
obj-$(CONFIG_GIANFAR) += gianfar_driver.o
obj-$(CONFIG_GIANFAR) += gianfar_driver.o


gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_phy.o
gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_mii.o


#
#
# link order important here
# link order important here
+86 −326
Original line number Original line Diff line number Diff line
@@ -29,12 +29,7 @@
 *  define the configuration needed by the board are defined in a
 *  define the configuration needed by the board are defined in a
 *  board structure in arch/ppc/platforms (though I do not
 *  board structure in arch/ppc/platforms (though I do not
 *  discount the possibility that other architectures could one
 *  discount the possibility that other architectures could one
 *  day be supported.  One assumption the driver currently makes
 *  day be supported.
 *  is that the PHY is configured in such a way to advertise all
 *  capabilities.  This is a sensible default, and on certain
 *  PHYs, changing this default encounters substantial errata
 *  issues.  Future versions may remove this requirement, but for
 *  now, it is best for the firmware to ensure this is the case.
 *
 *
 *  The Gianfar Ethernet Controller uses a ring of buffer
 *  The Gianfar Ethernet Controller uses a ring of buffer
 *  descriptors.  The beginning is indicated by a register
 *  descriptors.  The beginning is indicated by a register
@@ -47,7 +42,7 @@
 *  corresponding bit in the IMASK register is also set (if
 *  corresponding bit in the IMASK register is also set (if
 *  interrupt coalescing is active, then the interrupt may not
 *  interrupt coalescing is active, then the interrupt may not
 *  happen immediately, but will wait until either a set number
 *  happen immediately, but will wait until either a set number
 *  of frames or amount of time have passed.).  In NAPI, the
 *  of frames or amount of time have passed).  In NAPI, the
 *  interrupt handler will signal there is work to be done, and
 *  interrupt handler will signal there is work to be done, and
 *  exit.  Without NAPI, the packet(s) will be handled
 *  exit.  Without NAPI, the packet(s) will be handled
 *  immediately.  Both methods will start at the last known empty
 *  immediately.  Both methods will start at the last known empty
@@ -75,6 +70,7 @@
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/init.h>
@@ -97,9 +93,11 @@
#include <linux/version.h>
#include <linux/version.h>
#include <linux/dma-mapping.h>
#include <linux/dma-mapping.h>
#include <linux/crc32.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/phy.h>


#include "gianfar.h"
#include "gianfar.h"
#include "gianfar_phy.h"
#include "gianfar_mii.h"


#define TX_TIMEOUT      (1*HZ)
#define TX_TIMEOUT      (1*HZ)
#define SKB_ALLOC_TIMEOUT 1000000
#define SKB_ALLOC_TIMEOUT 1000000
@@ -113,9 +111,8 @@
#endif
#endif


const char gfar_driver_name[] = "Gianfar Ethernet";
const char gfar_driver_name[] = "Gianfar Ethernet";
const char gfar_driver_version[] = "1.1";
const char gfar_driver_version[] = "1.2";


int startup_gfar(struct net_device *dev);
static int gfar_enet_open(struct net_device *dev);
static int gfar_enet_open(struct net_device *dev);
static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void gfar_timeout(struct net_device *dev);
static void gfar_timeout(struct net_device *dev);
@@ -126,17 +123,13 @@ static int gfar_set_mac_address(struct net_device *dev);
static int gfar_change_mtu(struct net_device *dev, int new_mtu);
static int gfar_change_mtu(struct net_device *dev, int new_mtu);
static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void gfar_phy_change(void *data);
static void gfar_phy_timer(unsigned long data);
static void adjust_link(struct net_device *dev);
static void adjust_link(struct net_device *dev);
static void init_registers(struct net_device *dev);
static void init_registers(struct net_device *dev);
static int init_phy(struct net_device *dev);
static int init_phy(struct net_device *dev);
static int gfar_probe(struct device *device);
static int gfar_probe(struct device *device);
static int gfar_remove(struct device *device);
static int gfar_remove(struct device *device);
void free_skb_resources(struct gfar_private *priv);
static void free_skb_resources(struct gfar_private *priv);
static void gfar_set_multi(struct net_device *dev);
static void gfar_set_multi(struct net_device *dev);
static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
#ifdef CONFIG_GFAR_NAPI
#ifdef CONFIG_GFAR_NAPI
@@ -144,7 +137,6 @@ static int gfar_poll(struct net_device *dev, int *budget);
#endif
#endif
int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length);
static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length);
static void gfar_phy_startup_timer(unsigned long data);
static void gfar_vlan_rx_register(struct net_device *netdev,
static void gfar_vlan_rx_register(struct net_device *netdev,
		                struct vlan_group *grp);
		                struct vlan_group *grp);
static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
@@ -162,6 +154,9 @@ int gfar_uses_fcb(struct gfar_private *priv)
	else
	else
		return 0;
		return 0;
}
}

/* Set up the ethernet device structure, private data,
 * and anything else we need before we start */
static int gfar_probe(struct device *device)
static int gfar_probe(struct device *device)
{
{
	u32 tempval;
	u32 tempval;
@@ -175,7 +170,7 @@ static int gfar_probe(struct device *device)


	einfo = (struct gianfar_platform_data *) pdev->dev.platform_data;
	einfo = (struct gianfar_platform_data *) pdev->dev.platform_data;


	if (einfo == NULL) {
	if (NULL == einfo) {
		printk(KERN_ERR "gfar %d: Missing additional data!\n",
		printk(KERN_ERR "gfar %d: Missing additional data!\n",
		       pdev->id);
		       pdev->id);


@@ -185,7 +180,7 @@ static int gfar_probe(struct device *device)
	/* Create an ethernet device instance */
	/* Create an ethernet device instance */
	dev = alloc_etherdev(sizeof (*priv));
	dev = alloc_etherdev(sizeof (*priv));


	if (dev == NULL)
	if (NULL == dev)
		return -ENOMEM;
		return -ENOMEM;


	priv = netdev_priv(dev);
	priv = netdev_priv(dev);
@@ -207,20 +202,11 @@ static int gfar_probe(struct device *device)
	priv->regs = (struct gfar *)
	priv->regs = (struct gfar *)
		ioremap(r->start, sizeof (struct gfar));
		ioremap(r->start, sizeof (struct gfar));


	if (priv->regs == NULL) {
	if (NULL == priv->regs) {
		err = -ENOMEM;
		err = -ENOMEM;
		goto regs_fail;
		goto regs_fail;
	}
	}


	/* Set the PHY base address */
	priv->phyregs = (struct gfar *)
	    ioremap(einfo->phy_reg_addr, sizeof (struct gfar));

	if (priv->phyregs == NULL) {
		err = -ENOMEM;
		goto phy_regs_fail;
	}

	spin_lock_init(&priv->lock);
	spin_lock_init(&priv->lock);


	dev_set_drvdata(device, dev);
	dev_set_drvdata(device, dev);
@@ -386,12 +372,10 @@ static int gfar_probe(struct device *device)
	return 0;
	return 0;


register_fail:
register_fail:
	iounmap((void *) priv->phyregs);
phy_regs_fail:
	iounmap((void *) priv->regs);
	iounmap((void *) priv->regs);
regs_fail:
regs_fail:
	free_netdev(dev);
	free_netdev(dev);
	return -ENOMEM;
	return err;
}
}


static int gfar_remove(struct device *device)
static int gfar_remove(struct device *device)
@@ -402,108 +386,41 @@ static int gfar_remove(struct device *device)
	dev_set_drvdata(device, NULL);
	dev_set_drvdata(device, NULL);


	iounmap((void *) priv->regs);
	iounmap((void *) priv->regs);
	iounmap((void *) priv->phyregs);
	free_netdev(dev);
	free_netdev(dev);


	return 0;
	return 0;
}
}




/* Configure the PHY for dev.
/* Initializes driver's PHY state, and attaches to the PHY.
 * returns 0 if success.  -1 if failure
 * Returns 0 on success.
 */
 */
static int init_phy(struct net_device *dev)
static int init_phy(struct net_device *dev)
{
{
	struct gfar_private *priv = netdev_priv(dev);
	struct gfar_private *priv = netdev_priv(dev);
	struct phy_info *curphy;
	uint gigabit_support =
	unsigned int timeout = PHY_INIT_TIMEOUT;
		priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ?
	struct gfar *phyregs = priv->phyregs;
		SUPPORTED_1000baseT_Full : 0;
	struct gfar_mii_info *mii_info;
	struct phy_device *phydev;
	int err;


	priv->oldlink = 0;
	priv->oldlink = 0;
	priv->oldspeed = 0;
	priv->oldspeed = 0;
	priv->oldduplex = -1;
	priv->oldduplex = -1;


	mii_info = kmalloc(sizeof(struct gfar_mii_info),
	phydev = phy_connect(dev, priv->einfo->bus_id, &adjust_link, 0);
			GFP_KERNEL);

	if(NULL == mii_info) {
		if (netif_msg_ifup(priv))
			printk(KERN_ERR "%s: Could not allocate mii_info\n",
					dev->name);
		return -ENOMEM;
	}

	mii_info->speed = SPEED_1000;
	mii_info->duplex = DUPLEX_FULL;
	mii_info->pause = 0;
	mii_info->link = 1;

	mii_info->advertising = (ADVERTISED_10baseT_Half |
			ADVERTISED_10baseT_Full |
			ADVERTISED_100baseT_Half |
			ADVERTISED_100baseT_Full |
			ADVERTISED_1000baseT_Full);
	mii_info->autoneg = 1;

	spin_lock_init(&mii_info->mdio_lock);


	mii_info->mii_id = priv->einfo->phyid;
	if (IS_ERR(phydev)) {

		printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
	mii_info->dev = dev;
		return PTR_ERR(phydev);

	mii_info->mdio_read = &read_phy_reg;
	mii_info->mdio_write = &write_phy_reg;

	priv->mii_info = mii_info;

	/* Reset the management interface */
	gfar_write(&phyregs->miimcfg, MIIMCFG_RESET);

	/* Setup the MII Mgmt clock speed */
	gfar_write(&phyregs->miimcfg, MIIMCFG_INIT_VALUE);

	/* Wait until the bus is free */
	while ((gfar_read(&phyregs->miimind) & MIIMIND_BUSY) &&
			timeout--)
		cpu_relax();

	if(timeout <= 0) {
		printk(KERN_ERR "%s: The MII Bus is stuck!\n",
				dev->name);
		err = -1;
		goto bus_fail;
	}

	/* get info for this PHY */
	curphy = get_phy_info(priv->mii_info);

	if (curphy == NULL) {
		if (netif_msg_ifup(priv))
			printk(KERN_ERR "%s: No PHY found\n", dev->name);
		err = -1;
		goto no_phy;
	}
	}


	mii_info->phyinfo = curphy;
	/* Remove any features not supported by the controller */

	phydev->supported &= (GFAR_SUPPORTED | gigabit_support);
	/* Run the commands which initialize the PHY */
	phydev->advertising = phydev->supported;
	if(curphy->init) {
		err = curphy->init(priv->mii_info);


		if (err)
	priv->phydev = phydev;
			goto phy_init_fail;
	}


	return 0;
	return 0;

phy_init_fail:
no_phy:
bus_fail:
	kfree(mii_info);

	return err;
}
}


static void init_registers(struct net_device *dev)
static void init_registers(struct net_device *dev)
@@ -603,24 +520,13 @@ void stop_gfar(struct net_device *dev)
	struct gfar *regs = priv->regs;
	struct gfar *regs = priv->regs;
	unsigned long flags;
	unsigned long flags;


	phy_stop(priv->phydev);

	/* Lock it down */
	/* Lock it down */
	spin_lock_irqsave(&priv->lock, flags);
	spin_lock_irqsave(&priv->lock, flags);


	/* Tell the kernel the link is down */
	priv->mii_info->link = 0;
	adjust_link(dev);

	gfar_halt(dev);
	gfar_halt(dev);


	if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
		/* Clear any pending interrupts */
		mii_clear_phy_interrupt(priv->mii_info);

		/* Disable PHY Interrupts */
		mii_configure_phy_interrupt(priv->mii_info,
				MII_INTERRUPT_DISABLED);
	}

	spin_unlock_irqrestore(&priv->lock, flags);
	spin_unlock_irqrestore(&priv->lock, flags);


	/* Free the IRQs */
	/* Free the IRQs */
@@ -632,12 +538,6 @@ void stop_gfar(struct net_device *dev)
 		free_irq(priv->interruptTransmit, dev);
 		free_irq(priv->interruptTransmit, dev);
	}
	}


	if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
		free_irq(priv->einfo->interruptPHY, dev);
	} else {
		del_timer_sync(&priv->phy_info_timer);
	}

	free_skb_resources(priv);
	free_skb_resources(priv);


	dma_free_coherent(NULL,
	dma_free_coherent(NULL,
@@ -649,7 +549,7 @@ void stop_gfar(struct net_device *dev)


/* If there are any tx skbs or rx skbs still around, free them.
/* If there are any tx skbs or rx skbs still around, free them.
 * Then free tx_skbuff and rx_skbuff */
 * Then free tx_skbuff and rx_skbuff */
void free_skb_resources(struct gfar_private *priv)
static void free_skb_resources(struct gfar_private *priv)
{
{
	struct rxbd8 *rxbdp;
	struct rxbd8 *rxbdp;
	struct txbd8 *txbdp;
	struct txbd8 *txbdp;
@@ -770,7 +670,7 @@ int startup_gfar(struct net_device *dev)
	    (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) *
	    (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) *
					priv->tx_ring_size, GFP_KERNEL);
					priv->tx_ring_size, GFP_KERNEL);


	if (priv->tx_skbuff == NULL) {
	if (NULL == priv->tx_skbuff) {
		if (netif_msg_ifup(priv))
		if (netif_msg_ifup(priv))
			printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
			printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
					dev->name);
					dev->name);
@@ -785,7 +685,7 @@ int startup_gfar(struct net_device *dev)
	    (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) *
	    (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) *
					priv->rx_ring_size, GFP_KERNEL);
					priv->rx_ring_size, GFP_KERNEL);


	if (priv->rx_skbuff == NULL) {
	if (NULL == priv->rx_skbuff) {
		if (netif_msg_ifup(priv))
		if (netif_msg_ifup(priv))
			printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
			printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
					dev->name);
					dev->name);
@@ -879,13 +779,7 @@ int startup_gfar(struct net_device *dev)
		}
		}
	}
	}


	/* Set up the PHY change work queue */
	phy_start(priv->phydev);
	INIT_WORK(&priv->tq, gfar_phy_change, dev);

	init_timer(&priv->phy_info_timer);
	priv->phy_info_timer.function = &gfar_phy_startup_timer;
	priv->phy_info_timer.data = (unsigned long) priv->mii_info;
	mod_timer(&priv->phy_info_timer, jiffies + HZ);


	/* Configure the coalescing support */
	/* Configure the coalescing support */
	if (priv->txcoalescing)
	if (priv->txcoalescing)
@@ -933,11 +827,6 @@ tx_skb_fail:
			priv->tx_bd_base,
			priv->tx_bd_base,
			gfar_read(&regs->tbase0));
			gfar_read(&regs->tbase0));


	if (priv->mii_info->phyinfo->close)
		priv->mii_info->phyinfo->close(priv->mii_info);

	kfree(priv->mii_info);

	return err;
	return err;
}
}


@@ -1103,11 +992,9 @@ static int gfar_close(struct net_device *dev)
	struct gfar_private *priv = netdev_priv(dev);
	struct gfar_private *priv = netdev_priv(dev);
	stop_gfar(dev);
	stop_gfar(dev);


	/* Shutdown the PHY */
	/* Disconnect from the PHY */
	if (priv->mii_info->phyinfo->close)
	phy_disconnect(priv->phydev);
		priv->mii_info->phyinfo->close(priv->mii_info);
	priv->phydev = NULL;

	kfree(priv->mii_info);


	netif_stop_queue(dev);
	netif_stop_queue(dev);


@@ -1343,7 +1230,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
	while ((!skb) && timeout--)
	while ((!skb) && timeout--)
		skb = dev_alloc_skb(priv->rx_buffer_size + RXBUF_ALIGNMENT);
		skb = dev_alloc_skb(priv->rx_buffer_size + RXBUF_ALIGNMENT);


	if (skb == NULL)
	if (NULL == skb)
		return NULL;
		return NULL;


	/* We need the data buffer to be aligned properly.  We will reserve
	/* We need the data buffer to be aligned properly.  We will reserve
@@ -1490,7 +1377,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
	struct gfar_private *priv = netdev_priv(dev);
	struct gfar_private *priv = netdev_priv(dev);
	struct rxfcb *fcb = NULL;
	struct rxfcb *fcb = NULL;


	if (skb == NULL) {
	if (NULL == skb) {
		if (netif_msg_rx_err(priv))
		if (netif_msg_rx_err(priv))
			printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name);
			printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name);
		priv->stats.rx_dropped++;
		priv->stats.rx_dropped++;
@@ -1718,131 +1605,9 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
	return IRQ_HANDLED;
	return IRQ_HANDLED;
}
}


static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
	struct net_device *dev = (struct net_device *) dev_id;
	struct gfar_private *priv = netdev_priv(dev);

	/* Clear the interrupt */
	mii_clear_phy_interrupt(priv->mii_info);

	/* Disable PHY interrupts */
	mii_configure_phy_interrupt(priv->mii_info,
			MII_INTERRUPT_DISABLED);

	/* Schedule the phy change */
	schedule_work(&priv->tq);

	return IRQ_HANDLED;
}

/* Scheduled by the phy_interrupt/timer to handle PHY changes */
static void gfar_phy_change(void *data)
{
	struct net_device *dev = (struct net_device *) data;
	struct gfar_private *priv = netdev_priv(dev);
	int result = 0;

	/* Delay to give the PHY a chance to change the
	 * register state */
	msleep(1);

	/* Update the link, speed, duplex */
	result = priv->mii_info->phyinfo->read_status(priv->mii_info);

	/* Adjust the known status as long as the link
	 * isn't still coming up */
	if((0 == result) || (priv->mii_info->link == 0))
		adjust_link(dev);

	/* Reenable interrupts, if needed */
	if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR)
		mii_configure_phy_interrupt(priv->mii_info,
				MII_INTERRUPT_ENABLED);
}

/* Called every so often on systems that don't interrupt
 * the core for PHY changes */
static void gfar_phy_timer(unsigned long data)
{
	struct net_device *dev = (struct net_device *) data;
	struct gfar_private *priv = netdev_priv(dev);

	schedule_work(&priv->tq);

	mod_timer(&priv->phy_info_timer, jiffies +
			GFAR_PHY_CHANGE_TIME * HZ);
}

/* Keep trying aneg for some time
 * If, after GFAR_AN_TIMEOUT seconds, it has not
 * finished, we switch to forced.
 * Either way, once the process has completed, we either
 * request the interrupt, or switch the timer over to
 * using gfar_phy_timer to check status */
static void gfar_phy_startup_timer(unsigned long data)
{
	int result;
	static int secondary = GFAR_AN_TIMEOUT;
	struct gfar_mii_info *mii_info = (struct gfar_mii_info *)data;
	struct gfar_private *priv = netdev_priv(mii_info->dev);

	/* Configure the Auto-negotiation */
	result = mii_info->phyinfo->config_aneg(mii_info);

	/* If autonegotiation failed to start, and
	 * we haven't timed out, reset the timer, and return */
	if (result && secondary--) {
		mod_timer(&priv->phy_info_timer, jiffies + HZ);
		return;
	} else if (result) {
		/* Couldn't start autonegotiation.
		 * Try switching to forced */
		mii_info->autoneg = 0;
		result = mii_info->phyinfo->config_aneg(mii_info);

		/* Forcing failed!  Give up */
		if(result) {
			if (netif_msg_link(priv))
				printk(KERN_ERR "%s: Forcing failed!\n",
						mii_info->dev->name);
			return;
		}
	}

	/* Kill the timer so it can be restarted */
	del_timer_sync(&priv->phy_info_timer);

	/* Grab the PHY interrupt, if necessary/possible */
	if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
		if (request_irq(priv->einfo->interruptPHY,
					phy_interrupt,
					SA_SHIRQ,
					"phy_interrupt",
					mii_info->dev) < 0) {
			if (netif_msg_intr(priv))
				printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n",
						mii_info->dev->name,
					priv->einfo->interruptPHY);
		} else {
			mii_configure_phy_interrupt(priv->mii_info,
					MII_INTERRUPT_ENABLED);
			return;
		}
	}

	/* Start the timer again, this time in order to
	 * handle a change in status */
	init_timer(&priv->phy_info_timer);
	priv->phy_info_timer.function = &gfar_phy_timer;
	priv->phy_info_timer.data = (unsigned long) mii_info->dev;
	mod_timer(&priv->phy_info_timer, jiffies +
			GFAR_PHY_CHANGE_TIME * HZ);
}

/* Called every time the controller might need to be made
/* Called every time the controller might need to be made
 * aware of new link state.  The PHY code conveys this
 * aware of new link state.  The PHY code conveys this
 * information through variables in the priv structure, and this
 * information through variables in the phydev structure, and this
 * function converts those variables into the appropriate
 * function converts those variables into the appropriate
 * register values, and can bring down the device if needed.
 * register values, and can bring down the device if needed.
 */
 */
@@ -1850,84 +1615,68 @@ static void adjust_link(struct net_device *dev)
{
{
	struct gfar_private *priv = netdev_priv(dev);
	struct gfar_private *priv = netdev_priv(dev);
	struct gfar *regs = priv->regs;
	struct gfar *regs = priv->regs;
	u32 tempval;
	unsigned long flags;
	struct gfar_mii_info *mii_info = priv->mii_info;
	struct phy_device *phydev = priv->phydev;
	int new_state = 0;

	spin_lock_irqsave(&priv->lock, flags);
	if (phydev->link) {
		u32 tempval = gfar_read(&regs->maccfg2);


	if (mii_info->link) {
		/* Now we make sure that we can be in full duplex mode.
		/* Now we make sure that we can be in full duplex mode.
		 * If not, we operate in half-duplex mode. */
		 * If not, we operate in half-duplex mode. */
		if (mii_info->duplex != priv->oldduplex) {
		if (phydev->duplex != priv->oldduplex) {
			if (!(mii_info->duplex)) {
			new_state = 1;
				tempval = gfar_read(&regs->maccfg2);
			if (!(phydev->duplex))
				tempval &= ~(MACCFG2_FULL_DUPLEX);
				tempval &= ~(MACCFG2_FULL_DUPLEX);
				gfar_write(&regs->maccfg2, tempval);
			else

				if (netif_msg_link(priv))
					printk(KERN_INFO "%s: Half Duplex\n",
							dev->name);
			} else {
				tempval = gfar_read(&regs->maccfg2);
				tempval |= MACCFG2_FULL_DUPLEX;
				tempval |= MACCFG2_FULL_DUPLEX;
				gfar_write(&regs->maccfg2, tempval);

				if (netif_msg_link(priv))
					printk(KERN_INFO "%s: Full Duplex\n",
							dev->name);
			}


			priv->oldduplex = mii_info->duplex;
			priv->oldduplex = phydev->duplex;
		}
		}


		if (mii_info->speed != priv->oldspeed) {
		if (phydev->speed != priv->oldspeed) {
			switch (mii_info->speed) {
			new_state = 1;
			switch (phydev->speed) {
			case 1000:
			case 1000:
				tempval = gfar_read(&regs->maccfg2);
				tempval =
				tempval =
				    ((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII);
				    ((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII);
				gfar_write(&regs->maccfg2, tempval);
				break;
				break;
			case 100:
			case 100:
			case 10:
			case 10:
				tempval = gfar_read(&regs->maccfg2);
				tempval =
				tempval =
				    ((tempval & ~(MACCFG2_IF)) | MACCFG2_MII);
				    ((tempval & ~(MACCFG2_IF)) | MACCFG2_MII);
				gfar_write(&regs->maccfg2, tempval);
				break;
				break;
			default:
			default:
				if (netif_msg_link(priv))
				if (netif_msg_link(priv))
					printk(KERN_WARNING
					printk(KERN_WARNING
						"%s: Ack!  Speed (%d) is not 10/100/1000!\n",
						"%s: Ack!  Speed (%d) is not 10/100/1000!\n",
							dev->name, mii_info->speed);
						dev->name, phydev->speed);
				break;
				break;
			}
			}


			if (netif_msg_link(priv))
			priv->oldspeed = phydev->speed;
				printk(KERN_INFO "%s: Speed %dBT\n", dev->name,
						mii_info->speed);

			priv->oldspeed = mii_info->speed;
		}
		}


		gfar_write(&regs->maccfg2, tempval);

		if (!priv->oldlink) {
		if (!priv->oldlink) {
			if (netif_msg_link(priv))
			new_state = 1;
				printk(KERN_INFO "%s: Link is up\n", dev->name);
			priv->oldlink = 1;
			priv->oldlink = 1;
			netif_carrier_on(dev);
			netif_schedule(dev);
			netif_schedule(dev);
		}
		}
	} else {
	} else if (priv->oldlink) {
		if (priv->oldlink) {
		new_state = 1;
			if (netif_msg_link(priv))
				printk(KERN_INFO "%s: Link is down\n",
						dev->name);
		priv->oldlink = 0;
		priv->oldlink = 0;
		priv->oldspeed = 0;
		priv->oldspeed = 0;
		priv->oldduplex = -1;
		priv->oldduplex = -1;
			netif_carrier_off(dev);
		}
	}
	}
	}


	if (new_state && netif_msg_link(priv))
		phy_print_status(phydev);

	spin_unlock_irqrestore(&priv->lock, flags);
}


/* Update the hash table based on the current list of multicast
/* Update the hash table based on the current list of multicast
 * addresses we subscribe to.  Also, change the promiscuity of
 * addresses we subscribe to.  Also, change the promiscuity of
@@ -2122,12 +1871,23 @@ static struct device_driver gfar_driver = {


static int __init gfar_init(void)
static int __init gfar_init(void)
{
{
	return driver_register(&gfar_driver);
	int err = gfar_mdio_init();

	if (err)
		return err;

	err = driver_register(&gfar_driver);

	if (err)
		gfar_mdio_exit();
	
	return err;
}
}


static void __exit gfar_exit(void)
static void __exit gfar_exit(void)
{
{
	driver_unregister(&gfar_driver);
	driver_unregister(&gfar_driver);
	gfar_mdio_exit();
}
}


module_init(gfar_init);
module_init(gfar_init);
+16 −14
Original line number Original line Diff line number Diff line
@@ -17,7 +17,6 @@
 *
 *
 *  Still left to do:
 *  Still left to do:
 *      -Add support for module parameters
 *      -Add support for module parameters
 *	-Add support for ethtool -s
 *	-Add patch for ethtool phys id
 *	-Add patch for ethtool phys id
 */
 */
#ifndef __GIANFAR_H
#ifndef __GIANFAR_H
@@ -37,7 +36,8 @@
#include <linux/skbuff.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/fsl_devices.h>
#include <linux/mii.h>
#include <linux/phy.h>


#include <asm/io.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/irq.h>
@@ -48,7 +48,8 @@
#include <linux/workqueue.h>
#include <linux/workqueue.h>
#include <linux/ethtool.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h>
#include <linux/netdevice.h>
#include "gianfar_phy.h"
#include <linux/fsl_devices.h>
#include "gianfar_mii.h"


/* The maximum number of packets to be handled in one call of gfar_poll */
/* The maximum number of packets to be handled in one call of gfar_poll */
#define GFAR_DEV_WEIGHT 64
#define GFAR_DEV_WEIGHT 64
@@ -73,7 +74,7 @@
#define PHY_INIT_TIMEOUT 100000
#define PHY_INIT_TIMEOUT 100000
#define GFAR_PHY_CHANGE_TIME 2
#define GFAR_PHY_CHANGE_TIME 2


#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.1, "
#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.2, "
#define DRV_NAME "gfar-enet"
#define DRV_NAME "gfar-enet"
extern const char gfar_driver_name[];
extern const char gfar_driver_name[];
extern const char gfar_driver_version[];
extern const char gfar_driver_version[];
@@ -578,12 +579,7 @@ struct gfar {
	u32	hafdup;		/* 0x.50c - Half Duplex Register */
	u32	hafdup;		/* 0x.50c - Half Duplex Register */
	u32	maxfrm;		/* 0x.510 - Maximum Frame Length Register */
	u32	maxfrm;		/* 0x.510 - Maximum Frame Length Register */
	u8	res18[12];
	u8	res18[12];
	u32	miimcfg;	/* 0x.520 - MII Management Configuration Register */
	u8	gfar_mii_regs[24];	/* See gianfar_phy.h */
	u32	miimcom;	/* 0x.524 - MII Management Command Register */
	u32	miimadd;	/* 0x.528 - MII Management Address Register */
	u32	miimcon;	/* 0x.52c - MII Management Control Register */
	u32	miimstat;	/* 0x.530 - MII Management Status Register */
	u32	miimind;	/* 0x.534 - MII Management Indicator Register */
	u8	res19[4];
	u8	res19[4];
	u32	ifstat;		/* 0x.53c - Interface Status Register */
	u32	ifstat;		/* 0x.53c - Interface Status Register */
	u32	macstnaddr1;	/* 0x.540 - Station Address Part 1 Register */
	u32	macstnaddr1;	/* 0x.540 - Station Address Part 1 Register */
@@ -688,9 +684,6 @@ struct gfar_private {
	struct gfar *regs;	/* Pointer to the GFAR memory mapped Registers */
	struct gfar *regs;	/* Pointer to the GFAR memory mapped Registers */
	u32 *hash_regs[16];
	u32 *hash_regs[16];
	int hash_width;
	int hash_width;
	struct gfar *phyregs;
	struct work_struct tq;
	struct timer_list phy_info_timer;
	struct net_device_stats stats; /* linux network statistics */
	struct net_device_stats stats; /* linux network statistics */
	struct gfar_extra_stats extra_stats;
	struct gfar_extra_stats extra_stats;
	spinlock_t lock;
	spinlock_t lock;
@@ -710,7 +703,8 @@ struct gfar_private {
	unsigned int interruptError;
	unsigned int interruptError;
	struct gianfar_platform_data *einfo;
	struct gianfar_platform_data *einfo;


	struct gfar_mii_info *mii_info;
	struct phy_device *phydev;
	struct mii_bus *mii_bus;
	int oldspeed;
	int oldspeed;
	int oldduplex;
	int oldduplex;
	int oldlink;
	int oldlink;
@@ -732,4 +726,12 @@ extern inline void gfar_write(volatile unsigned *addr, u32 val)


extern struct ethtool_ops *gfar_op_array[];
extern struct ethtool_ops *gfar_op_array[];


extern irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
extern int startup_gfar(struct net_device *dev);
extern void stop_gfar(struct net_device *dev);
extern void gfar_halt(struct net_device *dev);
extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev,
		int enable, u32 regnum, u32 read);
void gfar_setup_stashing(struct net_device *dev);

#endif /* __GIANFAR_H */
#endif /* __GIANFAR_H */
+64 −36

File changed.

Preview size limit exceeded, changes collapsed.

Loading