From 28879a472950e74fd6919a2f6aab3e6c83edcf0b Mon Sep 17 00:00:00 2001 From: Zeng Zhaoming Date: Tue, 5 Jul 2011 09:19:52 +0800 Subject: ENGR00152528-2 ENET: add enet support for mx6q. Enabled all speed mode, 10M/100M/1G. add "fec_mac" kernel parameter to set mac address. Since clock and board rework issue, some hard code stays to make it work. Signed-off-by: Zeng Zhaoming --- drivers/net/fec.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 5 deletions(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 885d8baff7d5..eaf9420844e4 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -18,7 +18,7 @@ * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) * Copyright (c) 2004-2006 Macq Electronique SA. * - * Copyright (C) 2010 Freescale Semiconductor, Inc. + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. */ #include @@ -68,10 +68,18 @@ #define FEC_QUIRK_SWAP_FRAME (1 << 1) static struct platform_device_id fec_devtype[] = { +#ifdef CONFIG_SOC_IMX6Q + { + .name = DRIVER_NAME, + .driver_data = FEC_QUIRK_ENET_MAC, + }, +#else { .name = DRIVER_NAME, .driver_data = 0, - }, { + }, +#endif + { .name = "imx28-fec", .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME, }, @@ -860,6 +868,31 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, return 0; } +#ifdef CONFIG_MACH_MX6Q_SABREAUTO + +static int mx6_sabreauto_rework(struct mii_bus *bus) +{ + unsigned short val; + + /* To enable AR8031 ouput a 125MHz clk from CLK_25M */ + fec_enet_mdio_write(bus, 0, 0xd, 0x7); + fec_enet_mdio_write(bus, 0, 0xe, 0x8016); + fec_enet_mdio_write(bus, 0, 0xd, 0x4007); + val = fec_enet_mdio_read(bus, 0, 0xe); + + val &= 0xffe3; + val |= 0x18; + fec_enet_mdio_write(bus, 0, 0xe, val); + + /* introduce tx clock delay */ + fec_enet_mdio_write(bus, 0, 0x1d, 0x5); + val = fec_enet_mdio_read(bus, 0, 0x1e); + val |= 0x0100; + fec_enet_mdio_write(bus, 0, 0x1e, val); + + return 0; +} +#endif static int fec_enet_mdio_reset(struct mii_bus *bus) { @@ -899,15 +932,20 @@ static int fec_enet_mii_probe(struct net_device *ndev) } snprintf(phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id); - phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link, 0, - PHY_INTERFACE_MODE_MII); + phy_dev = phy_connect(dev, phy_name, &fec_enet_adjust_link, 0, + fep->phy_interface); + if (IS_ERR(phy_dev)) { printk(KERN_ERR "%s: could not attach to PHY\n", ndev->name); return PTR_ERR(phy_dev); } /* mask with MAC supported features */ - phy_dev->supported &= PHY_BASIC_FEATURES; + if (cpu_is_mx6q()) + phy_dev->supported &= PHY_GBIT_FEATURES; + else + phy_dev->supported &= PHY_BASIC_FEATURES; + phy_dev->advertising = phy_dev->supported; fep->phy_dev = phy_dev; @@ -959,6 +997,11 @@ static int fec_enet_mii_init(struct platform_device *pdev) * Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed) */ fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000) << 1; + +#ifdef CONFIG_MACH_MX6Q_SABREAUTO + /* FIXME: hard code to 0x1a for clock issue */ + fep->phy_speed = 0x11a; +#endif writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); fep->mii_bus = mdiobus_alloc(); @@ -975,6 +1018,10 @@ static int fec_enet_mii_init(struct platform_device *pdev) fep->mii_bus->priv = fep; fep->mii_bus->parent = &pdev->dev; +#ifdef CONFIG_MACH_MX6Q_SABREAUTO + mx6_sabreauto_rework(fep->mii_bus); +#endif + fep->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); if (!fep->mii_bus->irq) { err = -ENOMEM; @@ -1151,6 +1198,7 @@ fec_enet_open(struct net_device *ndev) fec_enet_free_buffers(ndev); return ret; } + phy_start(fep->phy_dev); netif_start_queue(ndev); fep->opened = 1; @@ -1537,6 +1585,31 @@ static struct platform_driver fec_driver = { .remove = __devexit_p(fec_drv_remove), }; +static int fec_mac_addr_setup(char *mac_addr) +{ + char *ptr, *p = mac_addr; + unsigned long tmp; + int i = 0, ret = 0; + + while (p && (*p) && i < 6) { + ptr = strchr(p, ':'); + if (ptr) + *ptr++ = '\0'; + + if (strlen(p)) { + ret = strict_strtoul(p, 16, &tmp); + if (ret < 0 || tmp > 0xff) + break; + macaddr[i++] = tmp; + } + p = ptr; + } + + return 0; +} + +__setup("fec_mac=", fec_mac_addr_setup); + static int __init fec_enet_module_init(void) { -- cgit v1.2.3 From 6825ac73d1e8c4b20eb8431d9ca8b3874edb33c5 Mon Sep 17 00:00:00 2001 From: Zeng Zhaoming Date: Thu, 14 Jul 2011 10:21:08 +0800 Subject: ENGR00153127 ENET: Enet not works in 1G mode Mx6 not works when connnect to a 1G switch. This is caused by phy_dev->supported != PHY_GBIT_FEATURES, more bits will set to phy_dev->supported when negotiation complete. Signed-off-by: Zeng Zhaoming --- drivers/net/fec.c | 308 +++++++++++++++++++++++++++++------------------------- 1 file changed, 164 insertions(+), 144 deletions(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index eaf9420844e4..79eba6965896 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -337,150 +337,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NETDEV_TX_OK; } -/* This function is called to start or restart the FEC during a link - * change. This only happens when switching between half and full - * duplex. - */ -static void -fec_restart(struct net_device *ndev, int duplex) -{ - struct fec_enet_private *fep = netdev_priv(ndev); - const struct platform_device_id *id_entry = - platform_get_device_id(fep->pdev); - int i; - u32 temp_mac[2]; - u32 rcntl = OPT_FRAME_SIZE | 0x04; - - /* Whack a reset. We should wait for this. */ - writel(1, fep->hwp + FEC_ECNTRL); - udelay(10); - - /* - * enet-mac reset will reset mac address registers too, - * so need to reconfigure it. - */ - if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { - memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN); - writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW); - writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH); - } - - /* Clear any outstanding interrupt. */ - writel(0xffc00000, fep->hwp + FEC_IEVENT); - - /* Reset all multicast. */ - writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); - writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); -#ifndef CONFIG_M5272 - writel(0, fep->hwp + FEC_HASH_TABLE_HIGH); - writel(0, fep->hwp + FEC_HASH_TABLE_LOW); -#endif - - /* Set maximum receive buffer size. */ - writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE); - - /* Set receive and transmit descriptor base. */ - writel(fep->bd_dma, fep->hwp + FEC_R_DES_START); - writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE, - fep->hwp + FEC_X_DES_START); - - fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; - fep->cur_rx = fep->rx_bd_base; - - /* Reset SKB transmit buffers. */ - fep->skb_cur = fep->skb_dirty = 0; - for (i = 0; i <= TX_RING_MOD_MASK; i++) { - if (fep->tx_skbuff[i]) { - dev_kfree_skb_any(fep->tx_skbuff[i]); - fep->tx_skbuff[i] = NULL; - } - } - - /* Enable MII mode */ - if (duplex) { - /* FD enable */ - writel(0x04, fep->hwp + FEC_X_CNTRL); - } else { - /* No Rcv on Xmit */ - rcntl |= 0x02; - writel(0x0, fep->hwp + FEC_X_CNTRL); - } - - fep->full_duplex = duplex; - - /* Set MII speed */ - writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); - - /* - * The phy interface and speed need to get configured - * differently on enet-mac. - */ - if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { - /* Enable flow control and length check */ - rcntl |= 0x40000000 | 0x00000020; - - /* MII or RMII */ - if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) - rcntl |= (1 << 8); - else - rcntl &= ~(1 << 8); - - /* 10M or 100M */ - if (fep->phy_dev && fep->phy_dev->speed == SPEED_100) - rcntl &= ~(1 << 9); - else - rcntl |= (1 << 9); - - } else { -#ifdef FEC_MIIGSK_ENR - if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) { - /* disable the gasket and wait */ - writel(0, fep->hwp + FEC_MIIGSK_ENR); - while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4) - udelay(1); - - /* - * configure the gasket: - * RMII, 50 MHz, no loopback, no echo - */ - writel(1, fep->hwp + FEC_MIIGSK_CFGR); - - /* re-enable the gasket */ - writel(2, fep->hwp + FEC_MIIGSK_ENR); - } -#endif - } - writel(rcntl, fep->hwp + FEC_R_CNTRL); - - /* And last, enable the transmit and receive processing */ - writel(2, fep->hwp + FEC_ECNTRL); - writel(0, fep->hwp + FEC_R_DES_ACTIVE); - - /* Enable interrupts we wish to service */ - writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); -} - -static void -fec_stop(struct net_device *ndev) -{ - struct fec_enet_private *fep = netdev_priv(ndev); - - /* We cannot expect a graceful transmit stop without link !!! */ - if (fep->link) { - writel(1, fep->hwp + FEC_X_CNTRL); /* Graceful transmit stop */ - udelay(10); - if (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_GRA)) - printk("fec_stop : Graceful transmit stop did not complete !\n"); - } - - /* Whack a reset. We should wait for this. */ - writel(1, fep->hwp + FEC_ECNTRL); - udelay(10); - writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); - writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); -} - - static void fec_timeout(struct net_device *ndev) { @@ -1403,6 +1259,170 @@ static int fec_enet_init(struct net_device *ndev) return 0; } +/* This function is called to start or restart the FEC during a link + * change. This only happens when switching between half and full + * duplex. + */ +static void +fec_restart(struct net_device *dev, int duplex) +{ + struct fec_enet_private *fep = netdev_priv(dev); + const struct platform_device_id *id_entry = + platform_get_device_id(fep->pdev); + int i; + u32 val, temp_mac[2]; + + /* Whack a reset. We should wait for this. */ + writel(1, fep->hwp + FEC_ECNTRL); + udelay(10); + + /* + * enet-mac reset will reset mac address registers too, + * so need to reconfigure it. + */ + if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { + memcpy(&temp_mac, dev->dev_addr, ETH_ALEN); + writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW); + writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH); + } + + /* Clear any outstanding interrupt. */ + writel(0xffc00000, fep->hwp + FEC_IEVENT); + + /* Reset all multicast. */ + writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); +#ifndef CONFIG_M5272 + writel(0, fep->hwp + FEC_HASH_TABLE_HIGH); + writel(0, fep->hwp + FEC_HASH_TABLE_LOW); +#endif + + /* Set maximum receive buffer size. */ + writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE); + + /* Set receive and transmit descriptor base. */ + writel(fep->bd_dma, fep->hwp + FEC_R_DES_START); + writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE, + fep->hwp + FEC_X_DES_START); + + fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; + fep->cur_rx = fep->rx_bd_base; + + /* Reset SKB transmit buffers. */ + fep->skb_cur = fep->skb_dirty = 0; + for (i = 0; i <= TX_RING_MOD_MASK; i++) { + if (fep->tx_skbuff[i]) { + dev_kfree_skb_any(fep->tx_skbuff[i]); + fep->tx_skbuff[i] = NULL; + } + } + + /* Enable MII mode */ + if (duplex) { + /* MII enable / FD enable */ + writel(OPT_FRAME_SIZE | 0x04, fep->hwp + FEC_R_CNTRL); + writel(0x04, fep->hwp + FEC_X_CNTRL); + } else { + /* MII enable / No Rcv on Xmit */ + writel(OPT_FRAME_SIZE | 0x06, fep->hwp + FEC_R_CNTRL); + writel(0x0, fep->hwp + FEC_X_CNTRL); + } + fep->full_duplex = duplex; + + /* Set MII speed */ + writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); + + /* + * The phy interface and speed need to get configured + * differently on enet-mac. + */ + if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { + val = readl(fep->hwp + FEC_R_CNTRL); + + /* MII or RMII */ + if (fep->phy_interface == PHY_INTERFACE_MODE_RGMII) + val |= (1 << 6); + else if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) + val |= (1 << 8); + else + val &= ~(1 << 8); + + /* 10M or 100M */ + if (fep->phy_dev && fep->phy_dev->speed == SPEED_100) + val &= ~(1 << 9); + else + val |= (1 << 9); + + writel(val, fep->hwp + FEC_R_CNTRL); + } else { +#ifdef FEC_MIIGSK_ENR + if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) { + /* disable the gasket and wait */ + writel(0, fep->hwp + FEC_MIIGSK_ENR); + while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4) + udelay(1); + + /* + * configure the gasket: + * RMII, 50 MHz, no loopback, no echo + */ + writel(1, fep->hwp + FEC_MIIGSK_CFGR); + + /* re-enable the gasket */ + writel(2, fep->hwp + FEC_MIIGSK_ENR); + } +#endif + } + + /* ENET enable */ + val = (0x1 << 1); + + /* if phy work at 1G mode, set ENET RGMII speed to 1G */ + if (fep->phy_dev && (fep->phy_dev->supported & + (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)) && + fep->phy_interface == PHY_INTERFACE_MODE_RGMII && + fep->phy_dev->speed == SPEED_1000) + val |= (0x1 << 5); + + if (cpu_is_mx6q()) { + /* enable endian swap */ + val |= (0x1 << 8); + /* enable ENET store and forward mode */ + writel(0x1 << 8, fep->hwp + FEC_X_WMRK); + } + writel(val, fep->hwp + FEC_ECNTRL); + + writel(0, fep->hwp + FEC_R_DES_ACTIVE); + + /* Enable interrupts we wish to service */ + writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); +} + +static void +fec_stop(struct net_device *dev) +{ + struct fec_enet_private *fep = netdev_priv(dev); + + /* We cannot expect a graceful transmit stop without link !!! */ + if (fep->link) { + writel(1, fep->hwp + FEC_X_CNTRL); /* Graceful transmit stop */ + udelay(10); + if (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_GRA)) + printk("fec_stop : Graceful transmit stop did not complete !\n"); + } + + /* Whack a reset. We should wait for this. */ + writel(1, fep->hwp + FEC_ECNTRL); + udelay(10); + + if (cpu_is_mx6q()) + /* FIXME: we have to enable enet to keep mii interrupt works. */ + writel(2, fep->hwp + FEC_ECNTRL); + + writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); + writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); +} + static int __devinit fec_probe(struct platform_device *pdev) { -- cgit v1.2.3 From b9fff5a0b66feb55beb4c5a6710aa4170c6fec78 Mon Sep 17 00:00:00 2001 From: Mahesh Mahadevan Date: Tue, 25 Oct 2011 08:29:15 -0500 Subject: ENGR00160709-2 Move board specific code out of FEC driver Move the board specific code out of the FEC driver to the platform layer Signed-off-by: Mahesh Mahadevan --- drivers/net/fec.c | 47 ++++++++++++----------------------------------- 1 file changed, 12 insertions(+), 35 deletions(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 79eba6965896..0fc9d108bcc1 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -690,7 +690,7 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) usecs_to_jiffies(FEC_MII_TIMEOUT)); if (time_left == 0) { fep->mii_timeout = 1; - printk(KERN_ERR "FEC: MDIO read timeout\n"); + printk(KERN_ERR "FEC: MDIO read timeout, mii_id=%d\n", mii_id); return -ETIMEDOUT; } @@ -718,37 +718,12 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, usecs_to_jiffies(FEC_MII_TIMEOUT)); if (time_left == 0) { fep->mii_timeout = 1; - printk(KERN_ERR "FEC: MDIO write timeout\n"); + printk(KERN_ERR "FEC: MDIO write timeout, mii_id=%d\n", mii_id); return -ETIMEDOUT; } return 0; } -#ifdef CONFIG_MACH_MX6Q_SABREAUTO - -static int mx6_sabreauto_rework(struct mii_bus *bus) -{ - unsigned short val; - - /* To enable AR8031 ouput a 125MHz clk from CLK_25M */ - fec_enet_mdio_write(bus, 0, 0xd, 0x7); - fec_enet_mdio_write(bus, 0, 0xe, 0x8016); - fec_enet_mdio_write(bus, 0, 0xd, 0x4007); - val = fec_enet_mdio_read(bus, 0, 0xe); - - val &= 0xffe3; - val |= 0x18; - fec_enet_mdio_write(bus, 0, 0xe, val); - - /* introduce tx clock delay */ - fec_enet_mdio_write(bus, 0, 0x1d, 0x5); - val = fec_enet_mdio_read(bus, 0, 0x1e); - val |= 0x0100; - fec_enet_mdio_write(bus, 0, 0x1e, val); - - return 0; -} -#endif static int fec_enet_mdio_reset(struct mii_bus *bus) { @@ -854,10 +829,10 @@ static int fec_enet_mii_init(struct platform_device *pdev) */ fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000) << 1; -#ifdef CONFIG_MACH_MX6Q_SABREAUTO - /* FIXME: hard code to 0x1a for clock issue */ - fep->phy_speed = 0x11a; -#endif + if (cpu_is_mx6q()) + /* FIXME: hard code to 0x1a for clock issue */ + fep->phy_speed = 0x11a; + writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); fep->mii_bus = mdiobus_alloc(); @@ -874,10 +849,6 @@ static int fec_enet_mii_init(struct platform_device *pdev) fep->mii_bus->priv = fep; fep->mii_bus->parent = &pdev->dev; -#ifdef CONFIG_MACH_MX6Q_SABREAUTO - mx6_sabreauto_rework(fep->mii_bus); -#endif - fep->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); if (!fep->mii_bus->irq) { err = -ENOMEM; @@ -1038,6 +1009,7 @@ static int fec_enet_open(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); + struct fec_platform_data *pdata = fep->pdev->dev.platform_data; int ret; /* I should reset the ring buffers here, but I don't yet know @@ -1058,6 +1030,11 @@ fec_enet_open(struct net_device *ndev) phy_start(fep->phy_dev); netif_start_queue(ndev); fep->opened = 1; + + ret = -EINVAL; + if (pdata->init && pdata->init(fep->phy_dev)) + return ret; + return 0; } -- cgit v1.2.3 From bacc136fbaa939c2a9b56568f6a35dc80e8fe237 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Wed, 2 Nov 2011 12:26:49 +0800 Subject: ENGR00161207 - FEC: Add IEEE 1588 driver for imx6 - Support time stamp sync with networking master timer. - Support ipg 40MHz clock, and precision is about 20ns. - Don't support ipg 66MHz clock. - Test flow: 1. Enable CONFIG_FEC_1588 in imx6_defconfig file. 2. Select pll3 for ipg clk 40M in uboot plugin code. I. set reg 0x20c8028 value to 0x10000; II.set reg 0x20c8024 value to 0x3040; III. set reg 0x20c4014[25] to 0x1 IV. set reg 0x20c4014[12:10] to 0x5 3. Rebuid uboot and setup the ethernet environment. 4. Run the 1588 stack ptp_main in master and slave. Signed-off-by: Fugang Duan --- drivers/net/fec.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 6 deletions(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 0fc9d108bcc1..9730f6e5ac84 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -18,6 +18,7 @@ * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) * Copyright (c) 2004-2006 Macq Electronique SA. * + * Support for FEC IEEE 1588. * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. */ @@ -53,6 +54,7 @@ #endif #include "fec.h" +#include "fec_1588.h" #if defined(CONFIG_ARM) #define FEC_ALIGNMENT 0xf @@ -140,8 +142,16 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */ #define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */ #define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */ +#define FEC_ENET_TS_AVAIL ((uint)0x00010000) +#define FEC_ENET_TS_TIMER ((uint)0x00008000) +#if defined(CONFIG_FEC_1588) && (defined(CONFIG_ARCH_MX28) || \ + defined(CONFIG_ARCH_MX6)) +#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII | \ + FEC_ENET_TS_AVAIL | FEC_ENET_TS_TIMER) +#else #define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII) +#endif /* The FEC stores dest/src/type, data, and checksum for receive packets. */ @@ -209,9 +219,13 @@ struct fec_enet_private { int mii_timeout; uint phy_speed; phy_interface_t phy_interface; + int index; int link; int full_duplex; struct completion mdio_done; + + struct fec_ptp_private *ptp_priv; + uint ptimer_present; }; /* FEC MII MMFR bits definition */ @@ -248,6 +262,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct bufdesc *bdp; void *bufaddr; unsigned short status; + unsigned long estatus; unsigned long flags; if (!fep->link) { @@ -289,6 +304,17 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) bufaddr = fep->tx_bounce[index]; } + if (fep->ptimer_present) { + if (fec_ptp_do_txstamp(skb)) { + estatus = BD_ENET_TX_TS; + status |= BD_ENET_TX_PTP; + } else + estatus = 0; +#ifdef CONFIG_ENHANCED_BD + bdp->cbd_esc = (estatus | BD_ENET_TX_INT); + bdp->cbd_bdu = 0; +#endif + } /* * Some design made an incorrect assumption on endian mode of * the system that it's running on. As the result, driver has to @@ -352,11 +378,14 @@ static void fec_enet_tx(struct net_device *ndev) { struct fec_enet_private *fep; + struct fec_ptp_private *fpp; struct bufdesc *bdp; unsigned short status; + unsigned long estatus; struct sk_buff *skb; fep = netdev_priv(ndev); + fpp = fep->ptp_priv; spin_lock(&fep->hw_lock); bdp = fep->dirty_tx; @@ -397,6 +426,19 @@ fec_enet_tx(struct net_device *ndev) if (status & BD_ENET_TX_DEF) ndev->stats.collisions++; +#if defined(CONFIG_ENHANCED_BD) + if (fep->ptimer_present) { + estatus = bdp->cbd_esc; + if (estatus & BD_ENET_TX_TS) + fec_ptp_store_txstamp(fpp, skb, bdp); + } +#elif defined(CONFIG_IN_BAND) + if (fep->ptimer_present) { + if (status & BD_ENET_TX_PTP) + fec_ptp_store_txstamp(fpp, skb, bdp); + } +#endif + /* Free the sk buffer associated with this last transmit */ dev_kfree_skb_any(skb); fep->tx_skbuff[fep->skb_dirty] = NULL; @@ -430,6 +472,7 @@ static void fec_enet_rx(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); + struct fec_ptp_private *fpp = fep->ptp_priv; const struct platform_device_id *id_entry = platform_get_device_id(fep->pdev); struct bufdesc *bdp; @@ -513,7 +556,10 @@ fec_enet_rx(struct net_device *ndev) skb_reserve(skb, NET_IP_ALIGN); skb_put(skb, pkt_len - 4); /* Make room */ skb_copy_to_linear_data(skb, data, pkt_len - 4); - skb->protocol = eth_type_trans(skb, ndev); + /* 1588 messeage TS handle */ + if (fep->ptimer_present) + fec_ptp_store_rxstamp(fpp, skb, bdp); + skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); } @@ -526,6 +572,11 @@ rx_processing_done: /* Mark the buffer empty */ status |= BD_ENET_RX_EMPTY; bdp->cbd_sc = status; +#ifdef CONFIG_ENHANCED_BD + bdp->cbd_esc = BD_ENET_RX_INT; + bdp->cbd_prot = 0; + bdp->cbd_bdu = 0; +#endif /* Update BD pointer to next entry */ if (status & BD_ENET_RX_WRAP) @@ -982,6 +1033,9 @@ static int fec_enet_alloc_buffers(struct net_device *ndev) bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data, FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); bdp->cbd_sc = BD_ENET_RX_EMPTY; +#ifdef CONFIG_ENHANCED_BD + bdp->cbd_esc = BD_ENET_RX_INT; +#endif bdp++; } @@ -995,6 +1049,9 @@ static int fec_enet_alloc_buffers(struct net_device *ndev) bdp->cbd_sc = 0; bdp->cbd_bufaddr = 0; +#ifdef CONFIG_ENHANCED_BD + bdp->cbd_esc = BD_ENET_TX_INT; +#endif bdp++; } @@ -1246,8 +1303,8 @@ fec_restart(struct net_device *dev, int duplex) struct fec_enet_private *fep = netdev_priv(dev); const struct platform_device_id *id_entry = platform_get_device_id(fep->pdev); - int i; - u32 val, temp_mac[2]; + int i, ret; + u32 val, temp_mac[2], reg = 0; /* Whack a reset. We should wait for this. */ writel(1, fep->hwp + FEC_ECNTRL); @@ -1331,7 +1388,22 @@ fec_restart(struct net_device *dev, int duplex) val |= (1 << 9); writel(val, fep->hwp + FEC_R_CNTRL); - } else { + + if (fep->ptimer_present) { + /* Set Timer count */ + ret = fec_ptp_start(fep->ptp_priv); + if (ret) { + fep->ptimer_present = 0; + reg = 0x0; + } else +#if defined(CONFIG_SOC_IMX28) || defined(CONFIG_ARCH_MX6) + reg = 0x00000010; +#else + reg = 0x0; +#endif + } else + reg = 0x0; + #ifdef FEC_MIIGSK_ENR if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) { /* disable the gasket and wait */ @@ -1352,7 +1424,7 @@ fec_restart(struct net_device *dev, int duplex) } /* ENET enable */ - val = (0x1 << 1); + val = reg | (0x1 << 1); /* if phy work at 1G mode, set ENET RGMII speed to 1G */ if (fep->phy_dev && (fep->phy_dev->supported & @@ -1397,6 +1469,8 @@ fec_stop(struct net_device *dev) writel(2, fep->hwp + FEC_ECNTRL); writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); + if (fep->ptimer_present) + fec_ptp_stop(fep->ptp_priv); writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); } @@ -1473,6 +1547,18 @@ fec_probe(struct platform_device *pdev) if (ret) goto failed_mii_init; + if (fec_ptp_malloc_priv(&(fep->ptp_priv))) { + if (fep->ptp_priv) { + fep->ptp_priv->hwp = fep->hwp; + ret = fec_ptp_init(fep->ptp_priv, pdev->id); + if (ret) + printk(KERN_WARNING "IEEE1588: ptp-timer is unavailable\n"); + else + fep->ptimer_present = 1; + } else + printk(KERN_ERR "IEEE1588: failed to malloc memory\n"); + } + /* Carrier starts down, phylib will bring it up */ netif_carrier_off(ndev); @@ -1484,6 +1570,9 @@ fec_probe(struct platform_device *pdev) failed_register: fec_enet_mii_remove(fep); + if (fep->ptimer_present) + fec_ptp_cleanup(fep->ptp_priv); + kfree(fep->ptp_priv); failed_mii_init: failed_init: clk_disable(fep->clk); @@ -1515,7 +1604,10 @@ fec_drv_remove(struct platform_device *pdev) fec_enet_mii_remove(fep); clk_disable(fep->clk); clk_put(fep->clk); - iounmap(fep->hwp); + iounmap((void __iomem *)ndev->base_addr); + if (fep->ptimer_present) + fec_ptp_cleanup(fep->ptp_priv); + kfree(fep->ptp_priv); unregister_netdev(ndev); free_netdev(ndev); -- cgit v1.2.3 From f6b03161361d8d3e4b999faa37096f01776a9759 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Thu, 3 Nov 2011 13:58:16 +0800 Subject: ENGR00161312 - FEC: fix build warning fix build warning: > drivers/net/fec.c:435: warning: unused variable 'estatus' Signed-off-by: Fugang Duan --- drivers/net/fec.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 9730f6e5ac84..710824044abc 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -381,7 +381,6 @@ fec_enet_tx(struct net_device *ndev) struct fec_ptp_private *fpp; struct bufdesc *bdp; unsigned short status; - unsigned long estatus; struct sk_buff *skb; fep = netdev_priv(ndev); @@ -428,8 +427,7 @@ fec_enet_tx(struct net_device *ndev) #if defined(CONFIG_ENHANCED_BD) if (fep->ptimer_present) { - estatus = bdp->cbd_esc; - if (estatus & BD_ENET_TX_TS) + if (bdp->cbd_esc & BD_ENET_TX_TS) fec_ptp_store_txstamp(fpp, skb, bdp); } #elif defined(CONFIG_IN_BAND) -- cgit v1.2.3 From a5025df24d702fb9bd2ff0eca241b728bf5efd0f Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Fri, 4 Nov 2011 16:13:43 +0800 Subject: ENGR00159982 - FEC: low power mode when FEC is no use. - Set phy AR8031 to save power mode when no cable connect. - Close enet clock gate when FEC is no use. Signed-off-by: Fugang Duan --- drivers/net/fec.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 710824044abc..f9f73505891e 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -684,6 +685,7 @@ static void fec_enet_adjust_link(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); struct phy_device *phy_dev = fep->phy_dev; + struct fec_platform_data *pdata = fep->pdev->dev.platform_data; unsigned long flags; int status_change = 0; @@ -698,6 +700,8 @@ static void fec_enet_adjust_link(struct net_device *ndev) /* Duplex link change */ if (phy_dev->link) { + if (!clk_get_usecount(fep->clk)) + clk_enable(fep->clk); if (fep->full_duplex != phy_dev->duplex) { fec_restart(ndev, phy_dev->duplex); status_change = 1; @@ -717,8 +721,11 @@ static void fec_enet_adjust_link(struct net_device *ndev) spin_unlock: spin_unlock_irqrestore(&fep->hw_lock, flags); - if (status_change) + if (status_change) { + if (!phy_dev->link && phy_dev && pdata && pdata->power_hibernate) + pdata->power_hibernate(phy_dev); phy_print_status(phy_dev); + } } static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) @@ -1071,7 +1078,9 @@ fec_enet_open(struct net_device *ndev) * a simple way to do that. */ - ret = fec_enet_alloc_buffers(ndev); + if (!clk_get_usecount(fep->clk)) + clk_enable(fep->clk); + ret = fec_enet_alloc_buffers(dev); if (ret) return ret; @@ -1110,6 +1119,10 @@ fec_enet_close(struct net_device *ndev) fec_enet_free_buffers(ndev); + /* Clock gate close for saving power */ + if (clk_get_usecount(fep->clk)) + clk_disable(fep->clk); + return 0; } -- cgit v1.2.3 From 05ee5a7f9e3217fddc301ad9e080d33d67810e50 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Fri, 11 Nov 2011 14:25:11 +0800 Subject: ENGR00162013 - FEC : Fix loss interrupt when add "rootwait" - MII timeout when config ipg 40MHz mode and add "rootwait" para in uboot. Kernel will delay before peripheral equipment are ready, which lead to CPU loss interrupt. - So, prolong the timeout time, and increase the MII clock. Signed-off-by: Fugang Duan --- drivers/net/fec.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index f9f73505891e..dc6349c2edf7 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -238,7 +238,7 @@ 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 2000 /* us */ /* Transmitter timeout */ #define TX_TIMEOUT (2 * HZ) @@ -885,9 +885,13 @@ static int fec_enet_mii_init(struct platform_device *pdev) */ fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000) << 1; - if (cpu_is_mx6q()) - /* FIXME: hard code to 0x1a for clock issue */ - fep->phy_speed = 0x11a; + if (cpu_is_mx6q()) { + /* FIXME: non-1588 MII clk: 66MHz, 1588 mode : 40MHz */ + if (fep->ptimer_present) + fep->phy_speed = 0xe; + else + fep->phy_speed = 0x11a; + } writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); -- cgit v1.2.3 From e6e0db4ca2aac4e84bbb2a540d3bbee4cc66d156 Mon Sep 17 00:00:00 2001 From: Jason Liu Date: Wed, 14 Dec 2011 22:03:31 +0800 Subject: build fix and driver fix Signed-off-by: Jason Liu --- drivers/net/fec.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) mode change 100644 => 100755 drivers/net/fec.c (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c old mode 100644 new mode 100755 index dc6349c2edf7..b56a623875d2 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -57,7 +57,7 @@ #include "fec.h" #include "fec_1588.h" -#if defined(CONFIG_ARM) +#if defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28) #define FEC_ALIGNMENT 0xf #else #define FEC_ALIGNMENT 0x3 @@ -167,7 +167,8 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); * account when setting it. */ #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ - defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) + defined(CONFIG_M520x) || defined(CONFIG_M532x) || \ + defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28) #define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) #else #define OPT_FRAME_SIZE 0 @@ -229,6 +230,13 @@ struct fec_enet_private { uint ptimer_present; }; +static irqreturn_t fec_enet_interrupt(int irq, void * dev_id); +static void fec_enet_tx(struct net_device *dev); +static void fec_enet_rx(struct net_device *dev); +static int fec_enet_close(struct net_device *dev); +static void fec_restart(struct net_device *dev, int duplex); +static void fec_stop(struct net_device *dev); + /* FEC MII MMFR bits definition */ #define FEC_MMFR_ST (1 << 30) #define FEC_MMFR_OP_READ (2 << 28) @@ -301,7 +309,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (((unsigned long) bufaddr) & FEC_ALIGNMENT) { unsigned int index; index = bdp - fep->tx_bd_base; - memcpy(fep->tx_bounce[index], skb->data, skb->len); + memcpy(fep->tx_bounce[index], (void *)skb->data, skb->len); bufaddr = fep->tx_bounce[index]; } @@ -558,7 +566,7 @@ fec_enet_rx(struct net_device *ndev) /* 1588 messeage TS handle */ if (fep->ptimer_present) fec_ptp_store_rxstamp(fpp, skb, bdp); - skb->protocol = eth_type_trans(skb, dev); + skb->protocol = eth_type_trans(skb, ndev); netif_rx(skb); } @@ -819,7 +827,7 @@ static int fec_enet_mii_probe(struct net_device *ndev) } snprintf(phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id); - phy_dev = phy_connect(dev, phy_name, &fec_enet_adjust_link, 0, + phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link, 0, fep->phy_interface); if (IS_ERR(phy_dev)) { @@ -1084,7 +1092,7 @@ fec_enet_open(struct net_device *ndev) if (!clk_get_usecount(fep->clk)) clk_enable(fep->clk); - ret = fec_enet_alloc_buffers(dev); + ret = fec_enet_alloc_buffers(ndev); if (ret) return ret; -- cgit v1.2.3 From ca039b2c721f4458df16ba926d9db98b1ef11184 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Wed, 21 Dec 2011 18:32:11 +0800 Subject: ENGR00170784 - FEC : dma skb buffer map is not used rightly. Enable "CONFIG_DMA_API_DEBUG" in kernel, and system print: DMA-API: device driver tries to free DMA memory it has not allocated [device address=0x0000000046688020]...[<80222494>] (debug_dma_unmap_page+0x8c/0x98) from [<802a36a0>] (fec_enet_interrupt+0x430/0x5ac) Correct the usage of "dma_map_single" function. Signed-off-by: Fugang Duan --- drivers/net/fec.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index b56a623875d2..c3cb63799c73 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -401,7 +401,8 @@ fec_enet_tx(struct net_device *ndev) if (bdp == fep->cur_tx && fep->tx_full == 0) break; - dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, + if (bdp->cbd_bufaddr) + dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE); bdp->cbd_bufaddr = 0; @@ -542,7 +543,8 @@ fec_enet_rx(struct net_device *ndev) ndev->stats.rx_bytes += pkt_len; data = (__u8*)__va(bdp->cbd_bufaddr); - dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, + if (bdp->cbd_bufaddr) + dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, FEC_ENET_TX_FRSIZE, DMA_FROM_DEVICE); if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) @@ -1089,7 +1091,6 @@ fec_enet_open(struct net_device *ndev) /* I should reset the ring buffers here, but I don't yet know * a simple way to do that. */ - if (!clk_get_usecount(fep->clk)) clk_enable(fep->clk); ret = fec_enet_alloc_buffers(ndev); @@ -1290,6 +1291,7 @@ static int fec_enet_init(struct net_device *ndev) /* Initialize the BD for every fragment in the page. */ bdp->cbd_sc = 0; + bdp->cbd_bufaddr = 0; bdp++; } -- cgit v1.2.3 From 579d8fde0a6b676965b5c70664817ee01323590f Mon Sep 17 00:00:00 2001 From: Rogerio Pimentel Date: Mon, 26 Dec 2011 10:23:48 -0800 Subject: ENGR00161871: ENET: Changing MDIO read and write timeout The original FEC_MII_TIMEOUT was set to 1ms, which is too low when passed to the usecs_to_jiffies macro. On ARM one jiffy is 10ms, so use msecs_to_jiffies instead and use a timeout of 30ms, which corresponds to 3 jiffies. After running 3 hours NFS boots, the MDIO timeout do not occur anymore. Signed-off-by: Rogerio Pimentel --- drivers/net/fec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index c3cb63799c73..18d356e0a8eb 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -246,7 +246,7 @@ static void fec_stop(struct net_device *dev); #define FEC_MMFR_TA (2 << 16) #define FEC_MMFR_DATA(v) (v & 0xffff) -#define FEC_MII_TIMEOUT 2000 /* us */ +#define FEC_MII_TIMEOUT 30 /* ms */ /* Transmitter timeout */ #define TX_TIMEOUT (2 * HZ) @@ -753,7 +753,7 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) /* wait for end of transfer */ time_left = wait_for_completion_timeout(&fep->mdio_done, - usecs_to_jiffies(FEC_MII_TIMEOUT)); + msecs_to_jiffies(FEC_MII_TIMEOUT)); if (time_left == 0) { fep->mii_timeout = 1; printk(KERN_ERR "FEC: MDIO read timeout, mii_id=%d\n", mii_id); @@ -781,7 +781,7 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, /* wait for end of transfer */ time_left = wait_for_completion_timeout(&fep->mdio_done, - usecs_to_jiffies(FEC_MII_TIMEOUT)); + msecs_to_jiffies(FEC_MII_TIMEOUT)); if (time_left == 0) { fep->mii_timeout = 1; printk(KERN_ERR "FEC: MDIO write timeout, mii_id=%d\n", mii_id); -- cgit v1.2.3 From 909ab3ef6cff22339cbf1ec3023170c82c569ce2 Mon Sep 17 00:00:00 2001 From: Jason Liu Date: Tue, 7 Feb 2012 14:30:42 +0800 Subject: ENGR00173869-9: i.mx6dl: add the misc drivers support This patch change is very trivial and simply just add cpu_is_mx6dl() or using cpu_is_mx6 to replace cpu_is_mx6q each driver owner will check it and adjust it accordingly later, such as sdhc etc. Signed-off-by: Jason Liu --- drivers/net/fec.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 18d356e0a8eb..f2733145e892 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -19,7 +19,7 @@ * Copyright (c) 2004-2006 Macq Electronique SA. * * Support for FEC IEEE 1588. - * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2010-2012 Freescale Semiconductor, Inc. */ #include @@ -838,7 +838,7 @@ static int fec_enet_mii_probe(struct net_device *ndev) } /* mask with MAC supported features */ - if (cpu_is_mx6q()) + if (cpu_is_mx6q() || cpu_is_mx6dl()) phy_dev->supported &= PHY_GBIT_FEATURES; else phy_dev->supported &= PHY_BASIC_FEATURES; @@ -895,7 +895,7 @@ static int fec_enet_mii_init(struct platform_device *pdev) */ fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000) << 1; - if (cpu_is_mx6q()) { + if (cpu_is_mx6q() || cpu_is_mx6dl()) { /* FIXME: non-1588 MII clk: 66MHz, 1588 mode : 40MHz */ if (fep->ptimer_present) fep->phy_speed = 0xe; @@ -1458,7 +1458,7 @@ fec_restart(struct net_device *dev, int duplex) fep->phy_dev->speed == SPEED_1000) val |= (0x1 << 5); - if (cpu_is_mx6q()) { + if (cpu_is_mx6q() || cpu_is_mx6dl()) { /* enable endian swap */ val |= (0x1 << 8); /* enable ENET store and forward mode */ @@ -1489,7 +1489,7 @@ fec_stop(struct net_device *dev) writel(1, fep->hwp + FEC_ECNTRL); udelay(10); - if (cpu_is_mx6q()) + if (cpu_is_mx6q() || cpu_is_mx6dl()) /* FIXME: we have to enable enet to keep mii interrupt works. */ writel(2, fep->hwp + FEC_ECNTRL); -- cgit v1.2.3 From 9097d4e27b4a1afc64e3f8479ce68387ed9b1755 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Wed, 8 Feb 2012 11:39:25 +0800 Subject: ENGR00172274-02 - IEEE-1588: rework ts_clk in MX6 ARIK CPU board. Default use RMII 50MHz clock for ts_clk. Test result: Enet work fine at 100/1000Mbps in TO1.1 and Rigel. IEEE 1588 timestamp is convergent for 25M & 50M & 100MHz timestamp clock. Signed-off-by: Fugang Duan --- drivers/net/fec.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index f2733145e892..872b7c4c5cc6 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -145,6 +145,8 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */ #define FEC_ENET_TS_AVAIL ((uint)0x00010000) #define FEC_ENET_TS_TIMER ((uint)0x00008000) +#define FEC_ENET_MII_CLK ((uint)2500000) +#define FEC_ENET_HOLD_TIME ((uint)0x100) /* 2 internal clock cycle*/ #if defined(CONFIG_FEC_1588) && (defined(CONFIG_ARCH_MX28) || \ defined(CONFIG_ARCH_MX6)) @@ -608,6 +610,7 @@ fec_enet_interrupt(int irq, void *dev_id) { struct net_device *ndev = dev_id; struct fec_enet_private *fep = netdev_priv(ndev); + struct fec_ptp_private *fpp = fep->ptp_priv; uint int_events; irqreturn_t ret = IRQ_NONE; @@ -629,6 +632,12 @@ fec_enet_interrupt(int irq, void *dev_id) fec_enet_tx(ndev); } + if (int_events & FEC_ENET_TS_TIMER) { + ret = IRQ_HANDLED; + if (fep->ptimer_present && fpp) + fpp->prtc++; + } + if (int_events & FEC_ENET_MII) { ret = IRQ_HANDLED; complete(&fep->mdio_done); @@ -838,7 +847,7 @@ static int fec_enet_mii_probe(struct net_device *ndev) } /* mask with MAC supported features */ - if (cpu_is_mx6q() || cpu_is_mx6dl()) + if (cpu_is_mx6()) phy_dev->supported &= PHY_GBIT_FEATURES; else phy_dev->supported &= PHY_BASIC_FEATURES; @@ -893,15 +902,12 @@ static int fec_enet_mii_init(struct platform_device *pdev) /* * Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed) */ - fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000) << 1; + fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), + (FEC_ENET_MII_CLK << 2)) << 1; - if (cpu_is_mx6q() || cpu_is_mx6dl()) { - /* FIXME: non-1588 MII clk: 66MHz, 1588 mode : 40MHz */ - if (fep->ptimer_present) - fep->phy_speed = 0xe; - else - fep->phy_speed = 0x11a; - } + /* set hold time to 2 internal clock cycle */ + if (cpu_is_mx6()) + fep->phy_speed |= FEC_ENET_HOLD_TIME; writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); @@ -1458,7 +1464,7 @@ fec_restart(struct net_device *dev, int duplex) fep->phy_dev->speed == SPEED_1000) val |= (0x1 << 5); - if (cpu_is_mx6q() || cpu_is_mx6dl()) { + if (cpu_is_mx6()) { /* enable endian swap */ val |= (0x1 << 8); /* enable ENET store and forward mode */ @@ -1489,7 +1495,7 @@ fec_stop(struct net_device *dev) writel(1, fep->hwp + FEC_ECNTRL); udelay(10); - if (cpu_is_mx6q() || cpu_is_mx6dl()) + if (cpu_is_mx6()) /* FIXME: we have to enable enet to keep mii interrupt works. */ writel(2, fep->hwp + FEC_ECNTRL); -- cgit v1.2.3 From ff143240d36c3687542ae021ede4eaa5b3fae641 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Fri, 6 Apr 2012 12:59:36 +0800 Subject: ENGR00172303 - FEC : fix 'eth0: tx queue full!' issue. The issue is hard to reproduce in normal envrionment. And the reproduce rate is about 40% when doing VTE auto test. while the driver did report being busy when the link is down or no transmission buffers are available, it did not stop the queue, causing instant retries. furthermore, transmission being triggered with link down was caused by unconditional queue wakes, especially on timeouts. Now, wake queue only if link is up and transmission buffers are available, and dont forget to wake queue when link has been adjusted. next, add stop queue notification upon driver induced transmission problems, so network stack has a chance to handle the situation. Signed-off-by: Fugang Duan --- drivers/net/fec.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 872b7c4c5cc6..2078ef8d25f0 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -276,12 +276,14 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) unsigned long estatus; unsigned long flags; + spin_lock_irqsave(&fep->hw_lock, flags); if (!fep->link) { /* Link is down or autonegotiation is in progress. */ + netif_stop_queue(ndev); + spin_unlock_irqrestore(&fep->hw_lock, flags); return NETDEV_TX_BUSY; } - spin_lock_irqsave(&fep->hw_lock, flags); /* Fill in a Tx ring entry */ bdp = fep->cur_tx; @@ -292,6 +294,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) * This should not happen, since ndev->tbusy should be set. */ printk("%s: tx queue full!.\n", ndev->name); + netif_stop_queue(ndev); spin_unlock_irqrestore(&fep->hw_lock, flags); return NETDEV_TX_BUSY; } @@ -311,8 +314,8 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (((unsigned long) bufaddr) & FEC_ALIGNMENT) { unsigned int index; index = bdp - fep->tx_bd_base; - memcpy(fep->tx_bounce[index], (void *)skb->data, skb->len); - bufaddr = fep->tx_bounce[index]; + bufaddr = PTR_ALIGN(fep->tx_bounce[index], FEC_ALIGNMENT + 1); + memcpy(bufaddr, (void *)skb->data, skb->len); } if (fep->ptimer_present) { @@ -382,7 +385,8 @@ fec_timeout(struct net_device *ndev) ndev->stats.tx_errors++; fec_restart(ndev, fep->full_duplex); - netif_wake_queue(ndev); + if (fep->link && !fep->tx_full) + netif_wake_queue(ndev); } static void @@ -409,6 +413,8 @@ fec_enet_tx(struct net_device *ndev) bdp->cbd_bufaddr = 0; skb = fep->tx_skbuff[fep->skb_dirty]; + if (!skb) + break; /* Check for errors. */ if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN | @@ -730,9 +736,11 @@ static void fec_enet_adjust_link(struct net_device *ndev) /* Link on or off change */ if (phy_dev->link != fep->link) { fep->link = phy_dev->link; - if (phy_dev->link) + if (phy_dev->link) { fec_restart(ndev, phy_dev->duplex); - else + if (!fep->tx_full) + netif_wake_queue(ndev); + } else fec_stop(ndev); status_change = 1; } @@ -1071,6 +1079,10 @@ static int fec_enet_alloc_buffers(struct net_device *ndev) bdp = fep->tx_bd_base; for (i = 0; i < TX_RING_SIZE; i++) { fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL); + if (!fep->tx_bounce[i]) { + fec_enet_free_buffers(ndev); + return -ENOMEM; + } bdp->cbd_sc = 0; bdp->cbd_bufaddr = 0; -- cgit v1.2.3 From f3641201d5ee3abc7c1b284ed74c1c3c35e5253d Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Fri, 13 Apr 2012 16:57:10 +0800 Subject: ENGR00179636-01 - FEC : Enet RX FIFO overruns issue. - Add NAPI methods. NAPI can improve the performance of high-speed networking, which can reduce the cpu loading of interrupt generate and drop packets. - Enet RX FIFO overruns number has been reduced by NAPI method. Signed-off-by: Fugang Duan --- drivers/net/fec.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 199 insertions(+), 5 deletions(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 2078ef8d25f0..a93ac31e690f 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -230,10 +230,22 @@ struct fec_enet_private { struct fec_ptp_private *ptp_priv; uint ptimer_present; + + struct napi_struct napi; + int napi_weight; + bool use_napi; }; +#define FEC_NAPI_WEIGHT 64 +#ifdef CONFIG_FEC_NAPI +#define FEC_NAPI_ENABLE TRUE +#else +#define FEC_NAPI_ENABLE FALSE +#endif + static irqreturn_t fec_enet_interrupt(int irq, void * dev_id); static void fec_enet_tx(struct net_device *dev); +static int fec_rx_poll(struct napi_struct *napi, int budget); static void fec_enet_rx(struct net_device *dev); static int fec_enet_close(struct net_device *dev); static void fec_restart(struct net_device *dev, int duplex); @@ -389,6 +401,29 @@ fec_timeout(struct net_device *ndev) netif_wake_queue(ndev); } +static void +fec_rx_int_is_enabled(struct net_device *ndev, bool enabled) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + uint int_events; + + int_events = readl(fep->hwp + FEC_IMASK); + if (enabled) + int_events |= FEC_ENET_RXF; + else + int_events &= ~FEC_ENET_RXF; + writel(int_events, fep->hwp + FEC_IMASK); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void fec_enet_netpoll(struct net_device *ndev) +{ + disable_irq(ndev->irq); + fec_enet_interrupt(ndev->irq, ndev); + enable_irq(ndev->irq); +} +#endif + static void fec_enet_tx(struct net_device *ndev) { @@ -478,6 +513,144 @@ fec_enet_tx(struct net_device *ndev) spin_unlock(&fep->hw_lock); } +/*NAPI polling Receive packets */ +static int fec_rx_poll(struct napi_struct *napi, int budget) +{ + struct fec_enet_private *fep = + container_of(napi, struct fec_enet_private, napi); + struct net_device *ndev = napi->dev; + struct fec_ptp_private *fpp = fep->ptp_priv; + const struct platform_device_id *id_entry = + platform_get_device_id(fep->pdev); + int pkt_received = 0; + struct bufdesc *bdp; + unsigned short status; + struct sk_buff *skb; + ushort pkt_len; + __u8 *data; + + if (fep->use_napi) + WARN_ON(!budget); + +#ifdef CONFIG_M532x + flush_cache_all(); +#endif + + /* First, grab all of the stats for the incoming packet. + * These get messed up if we get called due to a busy condition. + */ + bdp = fep->cur_rx; + + while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { + if (pkt_received >= budget) + break; + pkt_received++; + + /* Since we have allocated space to hold a complete frame, + * the last indicator should be set. + */ + if ((status & BD_ENET_RX_LAST) == 0) + dev_err(&ndev->dev, "FEC ENET: rcv is not +last\n"); + + if (!fep->opened) + goto rx_processing_done; + + /* Check for errors. */ + if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | + BD_ENET_RX_CR | BD_ENET_RX_OV)) { + ndev->stats.rx_errors++; + if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { + /* Frame too long or too short. */ + ndev->stats.rx_length_errors++; + } + if (status & BD_ENET_RX_NO) /* Frame alignment */ + ndev->stats.rx_frame_errors++; + if (status & BD_ENET_RX_CR) /* CRC Error */ + ndev->stats.rx_crc_errors++; + if (status & BD_ENET_RX_OV) /* FIFO overrun */ + ndev->stats.rx_fifo_errors++; + } + + /* Report late collisions as a frame error. + * On this error, the BD is closed, but we don't know what we + * have in the buffer. So, just drop this frame on the floor. + */ + if (status & BD_ENET_RX_CL) { + ndev->stats.rx_errors++; + ndev->stats.rx_frame_errors++; + goto rx_processing_done; + } + + /* Process the incoming frame. */ + ndev->stats.rx_packets++; + pkt_len = bdp->cbd_datlen; + ndev->stats.rx_bytes += pkt_len; + data = (__u8 *)__va(bdp->cbd_bufaddr); + + if (bdp->cbd_bufaddr) + dma_unmap_single(&ndev->dev, bdp->cbd_bufaddr, + FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); + + if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) + swap_buffer(data, pkt_len); + + /* This does 16 byte alignment, exactly what we need. + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ + skb = dev_alloc_skb(pkt_len - 4 + NET_IP_ALIGN); + + if (unlikely(!skb)) { + dev_err(&ndev->dev, + "%s: Memory squeeze, dropping packet.\n", ndev->name); + ndev->stats.rx_dropped++; + } else { + skb_reserve(skb, NET_IP_ALIGN); + skb_put(skb, pkt_len - 4); /* Make room */ + skb_copy_to_linear_data(skb, data, pkt_len - 4); + /* 1588 messeage TS handle */ + if (fep->ptimer_present) + fec_ptp_store_rxstamp(fpp, skb, bdp); + skb->protocol = eth_type_trans(skb, ndev); + netif_receive_skb(skb); + } + + bdp->cbd_bufaddr = dma_map_single(&ndev->dev, data, + FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); +rx_processing_done: + /* Clear the status flags for this buffer */ + status &= ~BD_ENET_RX_STATS; + + /* Mark the buffer empty */ + status |= BD_ENET_RX_EMPTY; + bdp->cbd_sc = status; +#ifdef CONFIG_ENHANCED_BD + bdp->cbd_esc = BD_ENET_RX_INT; + bdp->cbd_prot = 0; + bdp->cbd_bdu = 0; +#endif + + /* Update BD pointer to next entry */ + if (status & BD_ENET_RX_WRAP) + bdp = fep->rx_bd_base; + else + bdp++; + /* Doing this here will keep the FEC running while we process + * incoming frames. On a heavily loaded network, we should be + * able to keep up at the expense of system resources. + */ + writel(0, fep->hwp + FEC_R_DES_ACTIVE); + } + fep->cur_rx = bdp; + + if (pkt_received < budget) { + napi_complete(napi); + fec_rx_int_is_enabled(ndev, true); + } + + return pkt_received; +} /* During a receive, the cur_rx points to the current incoming buffer. * When we update through the ring, if the next incoming buffer has @@ -501,8 +674,6 @@ fec_enet_rx(struct net_device *ndev) flush_cache_all(); #endif - spin_lock(&fep->hw_lock); - /* First, grab all of the stats for the incoming packet. * These get messed up if we get called due to a busy condition. */ @@ -607,8 +778,6 @@ rx_processing_done: writel(0, fep->hwp + FEC_R_DES_ACTIVE); } fep->cur_rx = bdp; - - spin_unlock(&fep->hw_lock); } static irqreturn_t @@ -618,6 +787,7 @@ fec_enet_interrupt(int irq, void *dev_id) struct fec_enet_private *fep = netdev_priv(ndev); struct fec_ptp_private *fpp = fep->ptp_priv; uint int_events; + ulong flags; irqreturn_t ret = IRQ_NONE; do { @@ -626,7 +796,18 @@ fec_enet_interrupt(int irq, void *dev_id) if (int_events & FEC_ENET_RXF) { ret = IRQ_HANDLED; - fec_enet_rx(ndev); + spin_lock_irqsave(&fep->hw_lock, flags); + + if (fep->use_napi) { + /* Disable the RX interrupt */ + if (napi_schedule_prep(&fep->napi)) { + fec_rx_int_is_enabled(ndev, false); + __napi_schedule(&fep->napi); + } + } else + fec_enet_rx(ndev); + + spin_unlock_irqrestore(&fep->hw_lock, flags); } /* Transmit OK, or non-fatal error. Update the buffer @@ -1106,6 +1287,9 @@ fec_enet_open(struct net_device *ndev) struct fec_platform_data *pdata = fep->pdev->dev.platform_data; int ret; + if (fep->use_napi) + napi_enable(&fep->napi); + /* I should reset the ring buffers here, but I don't yet know * a simple way to do that. */ @@ -1266,6 +1450,9 @@ static const struct net_device_ops fec_netdev_ops = { .ndo_tx_timeout = fec_timeout, .ndo_set_mac_address = fec_set_mac_address, .ndo_do_ioctl = fec_enet_ioctl, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = fec_enet_netpoll, +#endif }; /* @@ -1303,6 +1490,13 @@ static int fec_enet_init(struct net_device *ndev) ndev->netdev_ops = &fec_netdev_ops; ndev->ethtool_ops = &fec_enet_ethtool_ops; + fep->use_napi = FEC_NAPI_ENABLE; + fep->napi_weight = FEC_NAPI_WEIGHT; + if (fep->use_napi) { + fec_rx_int_is_enabled(ndev, false); + netif_napi_add(ndev, &fep->napi, fec_rx_poll, fep->napi_weight); + } + /* Initialize the receive buffer descriptors. */ bdp = fep->rx_bd_base; for (i = 0; i < RX_RING_SIZE; i++) { -- cgit v1.2.3 From bce9486f83781e90897d52c973796beeec6afa44 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Fri, 20 Apr 2012 18:16:24 +0800 Subject: ENGR00179636-02 - FEC : Enet RX FIFO overruns issue. - Increase RX BD size to 384 entrys from 16 entrys, which can reduce the overruns number in busy system. Signed-off-by: Fugang Duan --- drivers/net/fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index a93ac31e690f..0fe11753b4c0 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -119,7 +119,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); * We don't need to allocate pages for the transmitter. We just use * the skbuffer directly. */ -#define FEC_ENET_RX_PAGES 8 +#define FEC_ENET_RX_PAGES 192 #define FEC_ENET_RX_FRSIZE 2048 #define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE) #define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES) -- cgit v1.2.3 From 4e042997cd8e19609105407021044b6e5e79ff01 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Fri, 4 May 2012 15:48:42 +0800 Subject: ENGR00181514 - FEC : fix kernel dump warning with suspend/resume. - Fix clock enable/disable match operation to avoid kernel dump warning "clock enable/disable mismatch". Signed-off-by: Fugang Duan --- drivers/net/fec.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 0fe11753b4c0..7897de31b9a0 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -906,8 +906,6 @@ static void fec_enet_adjust_link(struct net_device *ndev) /* Duplex link change */ if (phy_dev->link) { - if (!clk_get_usecount(fep->clk)) - clk_enable(fep->clk); if (fep->full_duplex != phy_dev->duplex) { fec_restart(ndev, phy_dev->duplex); status_change = 1; @@ -1293,8 +1291,7 @@ fec_enet_open(struct net_device *ndev) /* I should reset the ring buffers here, but I don't yet know * a simple way to do that. */ - if (!clk_get_usecount(fep->clk)) - clk_enable(fep->clk); + clk_enable(fep->clk); ret = fec_enet_alloc_buffers(ndev); if (ret) return ret; @@ -1325,6 +1322,10 @@ fec_enet_close(struct net_device *ndev) /* Don't know what to do yet. */ fep->opened = 0; netif_stop_queue(ndev); + netif_carrier_off(ndev); + if (fep->use_napi) + napi_disable(&fep->napi); + fec_stop(ndev); if (fep->phy_dev) { @@ -1335,8 +1336,7 @@ fec_enet_close(struct net_device *ndev) fec_enet_free_buffers(ndev); /* Clock gate close for saving power */ - if (clk_get_usecount(fep->clk)) - clk_disable(fep->clk); + clk_disable(fep->clk); return 0; } @@ -1798,6 +1798,7 @@ fec_probe(struct platform_device *pdev) /* Carrier starts down, phylib will bring it up */ netif_carrier_off(ndev); + clk_disable(fep->clk); ret = register_netdev(ndev); if (ret) @@ -1865,10 +1866,11 @@ fec_suspend(struct device *dev) struct fec_enet_private *fep = netdev_priv(ndev); if (netif_running(ndev)) { - fec_stop(ndev); netif_device_detach(ndev); + fec_stop(ndev); + netif_carrier_off(ndev); + clk_disable(fep->clk); } - clk_disable(fep->clk); return 0; } @@ -1879,8 +1881,8 @@ fec_resume(struct device *dev) struct net_device *ndev = dev_get_drvdata(dev); struct fec_enet_private *fep = netdev_priv(ndev); - clk_enable(fep->clk); if (netif_running(ndev)) { + clk_enable(fep->clk); fec_restart(ndev, fep->full_duplex); netif_device_attach(ndev); } -- cgit v1.2.3 From 025d404cad7297956aaf8229b25df4aedcf2c2fb Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Mon, 7 May 2012 15:14:23 +0800 Subject: ENGR00179636-04 - FEC : allocate the enough DMA size for BD. - Increase RX BD size to 384 entrys from 16 entrys, and allocate the enough DMA memory for buffer description. Signed-off-by: Fugang Duan --- drivers/net/fec.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 7897de31b9a0..6e710e11f1a4 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -128,9 +128,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define TX_RING_SIZE 16 /* Must be power of two */ #define TX_RING_MOD_MASK 15 /* for this to work */ -#if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE) -#error "FEC: descriptor ring size constants too large" -#endif +#define BUFDES_SIZE ((RX_RING_SIZE + TX_RING_SIZE) * sizeof(struct bufdesc)) /* Interrupt events/masks. */ #define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */ @@ -1467,7 +1465,7 @@ static int fec_enet_init(struct net_device *ndev) int i; /* Allocate memory for buffer descriptors. */ - cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma, + cbd_base = dma_alloc_coherent(NULL, BUFDES_SIZE, &fep->bd_dma, GFP_KERNEL); if (!cbd_base) { printk("FEC: allocate descriptor memory failed?\n"); -- cgit v1.2.3 From eb6dc302cf6db91d2800d4f743d0c75d048a663d Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Wed, 16 May 2012 17:57:53 +0800 Subject: ENGR00209520-03 - FEC : Add support for MX6SL MSL. - Modify the the platform macro define like as cpu_is_xxx() for supporting Mergrez chip. - Config MIIGSK for FEC IP to enable RMII mode. MX25,MX53, and MX6Sololite use FEC IP, which need to config the MIIGSK registers memory map for RMII and MII. - Correct device id_table entry name for differnt IP. - Rewrite FEC MAC address by net_device address when reset FEC, which can avoid invalid MAC address to result in FEC cannot work. Signed-off-by: Fugang Duan --- drivers/net/fec.c | 75 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 33 deletions(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 6e710e11f1a4..acb2965ae77d 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -71,17 +71,14 @@ #define FEC_QUIRK_SWAP_FRAME (1 << 1) static struct platform_device_id fec_devtype[] = { -#ifdef CONFIG_SOC_IMX6Q { - .name = DRIVER_NAME, + .name = "enet", .driver_data = FEC_QUIRK_ENET_MAC, }, -#else { - .name = DRIVER_NAME, + .name = "fec", .driver_data = 0, }, -#endif { .name = "imx28-fec", .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME, @@ -146,12 +143,11 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define FEC_ENET_MII_CLK ((uint)2500000) #define FEC_ENET_HOLD_TIME ((uint)0x100) /* 2 internal clock cycle*/ -#if defined(CONFIG_FEC_1588) && (defined(CONFIG_ARCH_MX28) || \ - defined(CONFIG_ARCH_MX6)) -#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII | \ - FEC_ENET_TS_AVAIL | FEC_ENET_TS_TIMER) -#else #define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII) +#if defined(CONFIG_FEC_1588) +#define FEC_1588_IMASK (FEC_ENET_TS_AVAIL | FEC_ENET_TS_TIMER) +#else +#define FEC_1588_IMASK 0 #endif /* The FEC stores dest/src/type, data, and checksum for receive packets. @@ -1032,7 +1028,7 @@ static int fec_enet_mii_probe(struct net_device *ndev) } /* mask with MAC supported features */ - if (cpu_is_mx6()) + if (cpu_is_mx6q() || cpu_is_mx6dl()) phy_dev->supported &= PHY_GBIT_FEATURES; else phy_dev->supported &= PHY_BASIC_FEATURES; @@ -1091,7 +1087,7 @@ static int fec_enet_mii_init(struct platform_device *pdev) (FEC_ENET_MII_CLK << 2)) << 1; /* set hold time to 2 internal clock cycle */ - if (cpu_is_mx6()) + if (cpu_is_mx6q() || cpu_is_mx6dl()) fep->phy_speed |= FEC_ENET_HOLD_TIME; writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); @@ -1546,14 +1542,14 @@ fec_restart(struct net_device *dev, int duplex) udelay(10); /* - * enet-mac reset will reset mac address registers too, - * so need to reconfigure it. + /* if uboot don't set MAC address, get MAC address + * from command line; if command line don't set MAC + * address, get from OCOTP; otherwise, allocate random + * address. */ - if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { - memcpy(&temp_mac, dev->dev_addr, ETH_ALEN); - writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW); - writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH); - } + memcpy(&temp_mac, dev->dev_addr, ETH_ALEN); + writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW); + writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH); /* Clear any outstanding interrupt. */ writel(0xffc00000, fep->hwp + FEC_IEVENT); @@ -1623,23 +1619,24 @@ fec_restart(struct net_device *dev, int duplex) val |= (1 << 9); writel(val, fep->hwp + FEC_R_CNTRL); + } - if (fep->ptimer_present) { - /* Set Timer count */ - ret = fec_ptp_start(fep->ptp_priv); - if (ret) { - fep->ptimer_present = 0; - reg = 0x0; - } else + if (fep->ptimer_present) { + /* Set Timer count */ + ret = fec_ptp_start(fep->ptp_priv); + if (ret) { + fep->ptimer_present = 0; + reg = 0x0; + } else #if defined(CONFIG_SOC_IMX28) || defined(CONFIG_ARCH_MX6) - reg = 0x00000010; + reg = 0x00000010; #else - reg = 0x0; + reg = 0x0; #endif } else reg = 0x0; -#ifdef FEC_MIIGSK_ENR + if (cpu_is_mx25() || cpu_is_mx53() || cpu_is_mx6sl()) { if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) { /* disable the gasket and wait */ writel(0, fep->hwp + FEC_MIIGSK_ENR); @@ -1654,8 +1651,14 @@ fec_restart(struct net_device *dev, int duplex) /* re-enable the gasket */ writel(2, fep->hwp + FEC_MIIGSK_ENR); + udelay(10); + if (!(readl(fep->hwp + FEC_MIIGSK_ENR) & 4)) { + udelay(100); + if (!(readl(fep->hwp + FEC_MIIGSK_ENR) & 4)) + dev_err(&fep->pdev->dev, + "switch to RMII failed!\n"); + } } -#endif } /* ENET enable */ @@ -1668,7 +1671,7 @@ fec_restart(struct net_device *dev, int duplex) fep->phy_dev->speed == SPEED_1000) val |= (0x1 << 5); - if (cpu_is_mx6()) { + if (cpu_is_mx6q() || cpu_is_mx6dl()) { /* enable endian swap */ val |= (0x1 << 8); /* enable ENET store and forward mode */ @@ -1679,7 +1682,11 @@ fec_restart(struct net_device *dev, int duplex) writel(0, fep->hwp + FEC_R_DES_ACTIVE); /* Enable interrupts we wish to service */ - writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); + if (cpu_is_mx6q() || cpu_is_mx6dl() || cpu_is_mx2() || cpu_is_mx3()) + val = (FEC_1588_IMASK | FEC_DEFAULT_IMASK); + else + val = FEC_DEFAULT_IMASK; + writel(val, fep->hwp + FEC_IMASK); } static void @@ -1699,7 +1706,7 @@ fec_stop(struct net_device *dev) writel(1, fep->hwp + FEC_ECNTRL); udelay(10); - if (cpu_is_mx6()) + if (cpu_is_mx6q() || cpu_is_mx6dl()) /* FIXME: we have to enable enet to keep mii interrupt works. */ writel(2, fep->hwp + FEC_ECNTRL); @@ -1707,6 +1714,8 @@ fec_stop(struct net_device *dev) if (fep->ptimer_present) fec_ptp_stop(fep->ptp_priv); writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); + netif_stop_queue(dev); + fep->link = 0; } static int __devinit -- cgit v1.2.3 From 1519e115e70cf586a004251b014fb27d191c9e39 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Thu, 19 Jul 2012 15:29:52 +0800 Subject: ENGR00217616 - FEC : fix the typo to avoid build warning - Fix the typo to avoid kernel build warning. Signed-off-by: Fugang Duan --- drivers/net/fec.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/fec.c') diff --git a/drivers/net/fec.c b/drivers/net/fec.c index acb2965ae77d..1ae6cb0f0210 100755 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1541,7 +1541,6 @@ fec_restart(struct net_device *dev, int duplex) writel(1, fep->hwp + FEC_ECNTRL); udelay(10); - /* /* if uboot don't set MAC address, get MAC address * from command line; if command line don't set MAC * address, get from OCOTP; otherwise, allocate random -- cgit v1.2.3