diff options
Diffstat (limited to 'drivers/net/ethernet/freescale/fec.c')
| -rw-r--r-- | drivers/net/ethernet/freescale/fec.c | 79 | 
1 files changed, 53 insertions, 26 deletions
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c index 1124ce0a159..20c2e3f3e18 100644 --- a/drivers/net/ethernet/freescale/fec.c +++ b/drivers/net/ethernet/freescale/fec.c @@ -99,7 +99,7 @@ static struct platform_device_id fec_devtype[] = {  MODULE_DEVICE_TABLE(platform, fec_devtype);  enum imx_fec_type { -	IMX25_FEC = 1, 	/* runs on i.mx25/50/53 */ +	IMX25_FEC = 1,	/* runs on i.mx25/50/53 */  	IMX27_FEC,	/* runs on i.mx27/35/51 */  	IMX28_FEC,  	IMX6Q_FEC, @@ -132,7 +132,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");  #elif defined (CONFIG_M5272C3)  #define	FEC_FLASHMAC	(0xffe04000 + 4)  #elif defined(CONFIG_MOD5272) -#define FEC_FLASHMAC 	0xffc0406b +#define FEC_FLASHMAC	0xffc0406b  #else  #define	FEC_FLASHMAC	0  #endif @@ -232,6 +232,7 @@ struct fec_enet_private {  	struct	platform_device *pdev;  	int	opened; +	int	dev_id;  	/* Phylib and MDIO interface */  	struct	mii_bus *mii_bus; @@ -254,11 +255,13 @@ struct fec_enet_private {  #define FEC_MMFR_TA		(2 << 16)  #define FEC_MMFR_DATA(v)	(v & 0xffff) -#define FEC_MII_TIMEOUT		1000 /* us */ +#define FEC_MII_TIMEOUT		30000 /* us */  /* Transmitter timeout */  #define TX_TIMEOUT (2 * HZ) +static int mii_cnt; +  static void *swap_buffer(void *bufaddr, int len)  {  	int i; @@ -515,6 +518,7 @@ fec_stop(struct net_device *ndev)  	struct fec_enet_private *fep = netdev_priv(ndev);  	const struct platform_device_id *id_entry =  				platform_get_device_id(fep->pdev); +	u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8);  	/* We cannot expect a graceful transmit stop without link !!! */  	if (fep->link) { @@ -531,8 +535,10 @@ fec_stop(struct net_device *ndev)  	writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);  	/* We have to keep ENET enabled to have MII interrupt stay working */ -	if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) +	if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {  		writel(2, fep->hwp + FEC_ECNTRL); +		writel(rmii_mode, fep->hwp + FEC_R_CNTRL); +	}  } @@ -818,7 +824,7 @@ static void __inline__ fec_get_mac(struct net_device *ndev)  			iap = (unsigned char *)FEC_FLASHMAC;  #else  		if (pdata) -			memcpy(iap, pdata->mac, ETH_ALEN); +			iap = (unsigned char *)&pdata->mac;  #endif  	} @@ -837,7 +843,7 @@ static void __inline__ fec_get_mac(struct net_device *ndev)  	/* Adjust MAC if using macaddr */  	if (iap == macaddr) -		 ndev->dev_addr[ETH_ALEN-1] = macaddr[ETH_ALEN-1] + fep->pdev->id; +		 ndev->dev_addr[ETH_ALEN-1] = macaddr[ETH_ALEN-1] + fep->dev_id;  }  /* ------------------------------------------------------------------------- */ @@ -865,6 +871,8 @@ static void fec_enet_adjust_link(struct net_device *ndev)  	if (phy_dev->link) {  		if (fep->full_duplex != phy_dev->duplex) {  			fec_restart(ndev, phy_dev->duplex); +			/* prevent unnecessary second fec_restart() below */ +			fep->link = phy_dev->link;  			status_change = 1;  		}  	} @@ -953,7 +961,7 @@ static int fec_enet_mii_probe(struct net_device *ndev)  	char mdio_bus_id[MII_BUS_ID_SIZE];  	char phy_name[MII_BUS_ID_SIZE + 3];  	int phy_id; -	int dev_id = fep->pdev->id; +	int dev_id = fep->dev_id;  	fep->phy_dev = NULL; @@ -972,8 +980,9 @@ static int fec_enet_mii_probe(struct net_device *ndev)  	}  	if (phy_id >= PHY_MAX_ADDR) { -		printk(KERN_INFO "%s: no PHY, assuming direct connection " -			"to switch\n", ndev->name); +		printk(KERN_INFO +			"%s: no PHY, assuming direct connection to switch\n", +			ndev->name);  		strncpy(mdio_bus_id, "0", MII_BUS_ID_SIZE);  		phy_id = 0;  	} @@ -998,8 +1007,9 @@ static int fec_enet_mii_probe(struct net_device *ndev)  	fep->link = 0;  	fep->full_duplex = 0; -	printk(KERN_INFO "%s: Freescale FEC PHY driver [%s] " -		"(mii_bus:phy_addr=%s, irq=%d)\n", ndev->name, +	printk(KERN_INFO +		"%s: Freescale FEC PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", +		ndev->name,  		fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev),  		fep->phy_dev->irq); @@ -1031,10 +1041,14 @@ static int fec_enet_mii_init(struct platform_device *pdev)  	 * mdio interface in board design, and need to be configured by  	 * fec0 mii_bus.  	 */ -	if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && pdev->id > 0) { +	if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && fep->dev_id > 0) {  		/* fec1 uses fec0 mii_bus */ -		fep->mii_bus = fec0_mii_bus; -		return 0; +		if (mii_cnt && fec0_mii_bus) { +			fep->mii_bus = fec0_mii_bus; +			mii_cnt++; +			return 0; +		} +		return -ENOENT;  	}  	fep->mii_timeout = 0; @@ -1063,7 +1077,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)  	fep->mii_bus->read = fec_enet_mdio_read;  	fep->mii_bus->write = fec_enet_mdio_write;  	fep->mii_bus->reset = fec_enet_mdio_reset; -	snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id + 1); +	snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%x", fep->dev_id + 1);  	fep->mii_bus->priv = fep;  	fep->mii_bus->parent = &pdev->dev; @@ -1079,6 +1093,8 @@ static int fec_enet_mii_init(struct platform_device *pdev)  	if (mdiobus_register(fep->mii_bus))  		goto err_out_free_mdio_irq; +	mii_cnt++; +  	/* save fec0 mii_bus */  	if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)  		fec0_mii_bus = fep->mii_bus; @@ -1095,11 +1111,11 @@ err_out:  static void fec_enet_mii_remove(struct fec_enet_private *fep)  { -	if (fep->phy_dev) -		phy_disconnect(fep->phy_dev); -	mdiobus_unregister(fep->mii_bus); -	kfree(fep->mii_bus->irq); -	mdiobus_free(fep->mii_bus); +	if (--mii_cnt == 0) { +		mdiobus_unregister(fep->mii_bus); +		kfree(fep->mii_bus->irq); +		mdiobus_free(fep->mii_bus); +	}  }  static int fec_enet_get_settings(struct net_device *ndev, @@ -1136,7 +1152,7 @@ static void fec_enet_get_drvinfo(struct net_device *ndev,  	strcpy(info->bus_info, dev_name(&ndev->dev));  } -static struct ethtool_ops fec_enet_ethtool_ops = { +static const struct ethtool_ops fec_enet_ethtool_ops = {  	.get_settings		= fec_enet_get_settings,  	.set_settings		= fec_enet_set_settings,  	.get_drvinfo		= fec_enet_get_drvinfo, @@ -1521,6 +1537,7 @@ fec_probe(struct platform_device *pdev)  	int i, irq, ret = 0;  	struct resource *r;  	const struct of_device_id *of_id; +	static int dev_id;  	of_id = of_match_device(fec_dt_ids, &pdev->dev);  	if (of_id) @@ -1548,6 +1565,7 @@ fec_probe(struct platform_device *pdev)  	fep->hwp = ioremap(r->start, resource_size(r));  	fep->pdev = pdev; +	fep->dev_id = dev_id++;  	if (!fep->hwp) {  		ret = -ENOMEM; @@ -1571,8 +1589,12 @@ fec_probe(struct platform_device *pdev)  	for (i = 0; i < FEC_IRQ_NUM; i++) {  		irq = platform_get_irq(pdev, i); -		if (i && irq < 0) -			break; +		if (irq < 0) { +			if (i) +				break; +			ret = irq; +			goto failed_irq; +		}  		ret = request_irq(irq, fec_enet_interrupt, IRQF_DISABLED, pdev->name, ndev);  		if (ret) {  			while (--i >= 0) { @@ -1583,7 +1605,7 @@ fec_probe(struct platform_device *pdev)  		}  	} -	fep->clk = clk_get(&pdev->dev, "fec_clk"); +	fep->clk = clk_get(&pdev->dev, NULL);  	if (IS_ERR(fep->clk)) {  		ret = PTR_ERR(fep->clk);  		goto failed_clk; @@ -1635,13 +1657,18 @@ fec_drv_remove(struct platform_device *pdev)  	struct net_device *ndev = platform_get_drvdata(pdev);  	struct fec_enet_private *fep = netdev_priv(ndev);  	struct resource *r; +	int i; -	fec_stop(ndev); +	unregister_netdev(ndev);  	fec_enet_mii_remove(fep); +	for (i = 0; i < FEC_IRQ_NUM; i++) { +		int irq = platform_get_irq(pdev, i); +		if (irq > 0) +			free_irq(irq, ndev); +	}  	clk_disable(fep->clk);  	clk_put(fep->clk);  	iounmap(fep->hwp); -	unregister_netdev(ndev);  	free_netdev(ndev);  	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);  |