diff options
Diffstat (limited to 'drivers/net/ethernet/freescale')
-rw-r--r-- | drivers/net/ethernet/freescale/Kconfig | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fec_main.c | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fec_ptp.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fs_enet/mac-fcc.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fsl_pq_mdio.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/gianfar.c | 171 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/gianfar.h | 13 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/gianfar_ethtool.c | 45 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/gianfar_ptp.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/ucc_geth_ethtool.c | 2 |
10 files changed, 205 insertions, 46 deletions
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig index ff76d4e9d..bee32a9d9 100644 --- a/drivers/net/ethernet/freescale/Kconfig +++ b/drivers/net/ethernet/freescale/Kconfig @@ -7,7 +7,8 @@ config NET_VENDOR_FREESCALE default y depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \ M523x || M527x || M5272 || M528x || M520x || M532x || \ - ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM) + ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM) || \ + ARCH_LAYERSCAPE ---help--- If you have a network (Ethernet) card belonging to this class, say Y. diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index dd4ca39d5..b2a32209f 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3070,7 +3070,6 @@ static void fec_poll_controller(struct net_device *dev) } #endif -#define FEATURES_NEED_QUIESCE NETIF_F_RXCSUM static inline void fec_enet_set_netdev_features(struct net_device *netdev, netdev_features_t features) { @@ -3094,7 +3093,7 @@ static int fec_set_features(struct net_device *netdev, struct fec_enet_private *fep = netdev_priv(netdev); netdev_features_t changed = features ^ netdev->features; - if (netif_running(netdev) && changed & FEATURES_NEED_QUIESCE) { + if (netif_running(netdev) && changed & NETIF_F_RXCSUM) { napi_disable(&fep->napi); netif_tx_lock_bh(netdev); fec_stop(netdev); @@ -3262,7 +3261,7 @@ static void fec_reset_phy(struct platform_device *pdev) return; } msleep(msec); - gpio_set_value(phy_reset, 1); + gpio_set_value_cansleep(phy_reset, 1); } #else /* CONFIG_OF */ static void fec_reset_phy(struct platform_device *pdev) diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index 1543cf0e8..f9e74461b 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -112,9 +112,8 @@ static int fec_ptp_enable_pps(struct fec_enet_private *fep, uint enable) unsigned long flags; u32 val, tempval; int inc; - struct timespec ts; + struct timespec64 ts; u64 ns; - u32 remainder; val = 0; if (!(fep->hwts_tx_en || fep->hwts_rx_en)) { @@ -163,8 +162,7 @@ static int fec_ptp_enable_pps(struct fec_enet_private *fep, uint enable) tempval = readl(fep->hwp + FEC_ATIME); /* Convert the ptp local counter to 1588 timestamp */ ns = timecounter_cyc2time(&fep->tc, tempval); - ts.tv_sec = div_u64_rem(ns, 1000000000ULL, &remainder); - ts.tv_nsec = remainder; + ts = ns_to_timespec64(ns); /* The tempval is less than 3 seconds, and so val is less than * 4 seconds. No overflow for 32bit calculation. diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c index 08f5b911d..52e0091b4 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c +++ b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c @@ -552,7 +552,7 @@ static void tx_restart(struct net_device *dev) cbd_t __iomem *prev_bd; cbd_t __iomem *last_tx_bd; - last_tx_bd = fep->tx_bd_base + (fpi->tx_ring * sizeof(cbd_t)); + last_tx_bd = fep->tx_bd_base + ((fpi->tx_ring - 1) * sizeof(cbd_t)); /* get the current bd held in TBPTR and scan back from this point */ recheck_bd = curr_tbptr = (cbd_t __iomem *) diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c index 55c36230e..40071dad1 100644 --- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c +++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c @@ -464,7 +464,7 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev) * address). Print error message but continue anyway. */ if ((void *)tbipa > priv->map + resource_size(&res) - 4) - dev_err(&pdev->dev, "invalid register map (should be at least 0x%04x to contain TBI address)\n", + dev_err(&pdev->dev, "invalid register map (should be at least 0x%04zx to contain TBI address)\n", ((void *)tbipa - priv->map) + 4); iowrite32be(be32_to_cpup(prop), tbipa); diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index ce38d266f..3e233d924 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -107,7 +107,7 @@ #include "gianfar.h" -#define TX_TIMEOUT (1*HZ) +#define TX_TIMEOUT (5*HZ) const char gfar_driver_version[] = "2.0"; @@ -647,9 +647,9 @@ static int gfar_parse_group(struct device_node *np, if (model && strcasecmp(model, "FEC")) { gfar_irq(grp, RX)->irq = irq_of_parse_and_map(np, 1); gfar_irq(grp, ER)->irq = irq_of_parse_and_map(np, 2); - if (gfar_irq(grp, TX)->irq == NO_IRQ || - gfar_irq(grp, RX)->irq == NO_IRQ || - gfar_irq(grp, ER)->irq == NO_IRQ) + if (!gfar_irq(grp, TX)->irq || + !gfar_irq(grp, RX)->irq || + !gfar_irq(grp, ER)->irq) return -EINVAL; } @@ -894,7 +894,8 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) FSL_GIANFAR_DEV_HAS_VLAN | FSL_GIANFAR_DEV_HAS_MAGIC_PACKET | FSL_GIANFAR_DEV_HAS_EXTENDED_HASH | - FSL_GIANFAR_DEV_HAS_TIMER; + FSL_GIANFAR_DEV_HAS_TIMER | + FSL_GIANFAR_DEV_HAS_RX_FILER; err = of_property_read_string(np, "phy-connection-type", &ctype); @@ -907,6 +908,9 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) if (of_find_property(np, "fsl,magic-packet", NULL)) priv->device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET; + if (of_get_property(np, "fsl,wake-on-filer", NULL)) + priv->device_flags |= FSL_GIANFAR_DEV_HAS_WAKE_ON_FILER; + priv->phy_node = of_parse_phandle(np, "phy-handle", 0); /* In the case of a fixed PHY, the DT node associated @@ -1393,8 +1397,9 @@ static int gfar_probe(struct platform_device *ofdev) priv->rx_queue[i]->rxic = DEFAULT_RXIC; } - /* always enable rx filer */ - priv->rx_filer_enable = 1; + /* Always enable rx filer if available */ + priv->rx_filer_enable = + (priv->device_flags & FSL_GIANFAR_DEV_HAS_RX_FILER) ? 1 : 0; /* Enable most messages by default */ priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1; /* use pritority h/w tx queue scheduling for single queue devices */ @@ -1415,8 +1420,14 @@ static int gfar_probe(struct platform_device *ofdev) goto register_fail; } - device_set_wakeup_capable(&dev->dev, priv->device_flags & - FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) + priv->wol_supported |= GFAR_WOL_MAGIC; + + if ((priv->device_flags & FSL_GIANFAR_DEV_HAS_WAKE_ON_FILER) && + priv->rx_filer_enable) + priv->wol_supported |= GFAR_WOL_FILER_UCAST; + + device_set_wakeup_capable(&ofdev->dev, priv->wol_supported); /* fill out IRQ number and name fields */ for (i = 0; i < priv->num_grps; i++) { @@ -1479,15 +1490,122 @@ static int gfar_remove(struct platform_device *ofdev) #ifdef CONFIG_PM +static void __gfar_filer_disable(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + u32 temp; + + temp = gfar_read(®s->rctrl); + temp &= ~(RCTRL_FILREN | RCTRL_PRSDEP_INIT); + gfar_write(®s->rctrl, temp); +} + +static void __gfar_filer_enable(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + u32 temp; + + temp = gfar_read(®s->rctrl); + temp |= RCTRL_FILREN | RCTRL_PRSDEP_INIT; + gfar_write(®s->rctrl, temp); +} + +/* Filer rules implementing wol capabilities */ +static void gfar_filer_config_wol(struct gfar_private *priv) +{ + unsigned int i; + u32 rqfcr; + + __gfar_filer_disable(priv); + + /* clear the filer table, reject any packet by default */ + rqfcr = RQFCR_RJE | RQFCR_CMP_MATCH; + for (i = 0; i <= MAX_FILER_IDX; i++) + gfar_write_filer(priv, i, rqfcr, 0); + + i = 0; + if (priv->wol_opts & GFAR_WOL_FILER_UCAST) { + /* unicast packet, accept it */ + struct net_device *ndev = priv->ndev; + /* get the default rx queue index */ + u8 qindex = (u8)priv->gfargrp[0].rx_queue->qindex; + u32 dest_mac_addr = (ndev->dev_addr[0] << 16) | + (ndev->dev_addr[1] << 8) | + ndev->dev_addr[2]; + + rqfcr = (qindex << 10) | RQFCR_AND | + RQFCR_CMP_EXACT | RQFCR_PID_DAH; + + gfar_write_filer(priv, i++, rqfcr, dest_mac_addr); + + dest_mac_addr = (ndev->dev_addr[3] << 16) | + (ndev->dev_addr[4] << 8) | + ndev->dev_addr[5]; + rqfcr = (qindex << 10) | RQFCR_GPI | + RQFCR_CMP_EXACT | RQFCR_PID_DAL; + gfar_write_filer(priv, i++, rqfcr, dest_mac_addr); + } + + __gfar_filer_enable(priv); +} + +static void gfar_filer_restore_table(struct gfar_private *priv) +{ + u32 rqfcr, rqfpr; + unsigned int i; + + __gfar_filer_disable(priv); + + for (i = 0; i <= MAX_FILER_IDX; i++) { + rqfcr = priv->ftp_rqfcr[i]; + rqfpr = priv->ftp_rqfpr[i]; + gfar_write_filer(priv, i, rqfcr, rqfpr); + } + + __gfar_filer_enable(priv); +} + +/* gfar_start() for Rx only and with the FGPI filer interrupt enabled */ +static void gfar_start_wol_filer(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + u32 tempval; + int i = 0; + + /* Enable Rx hw queues */ + gfar_write(®s->rqueue, priv->rqueue); + + /* Initialize DMACTRL to have WWR and WOP */ + tempval = gfar_read(®s->dmactrl); + tempval |= DMACTRL_INIT_SETTINGS; + gfar_write(®s->dmactrl, tempval); + + /* Make sure we aren't stopped */ + tempval = gfar_read(®s->dmactrl); + tempval &= ~DMACTRL_GRS; + gfar_write(®s->dmactrl, tempval); + + for (i = 0; i < priv->num_grps; i++) { + regs = priv->gfargrp[i].regs; + /* Clear RHLT, so that the DMA starts polling now */ + gfar_write(®s->rstat, priv->gfargrp[i].rstat); + /* enable the Filer General Purpose Interrupt */ + gfar_write(®s->imask, IMASK_FGPI); + } + + /* Enable Rx DMA */ + tempval = gfar_read(®s->maccfg1); + tempval |= MACCFG1_RX_EN; + gfar_write(®s->maccfg1, tempval); +} + static int gfar_suspend(struct device *dev) { struct gfar_private *priv = dev_get_drvdata(dev); struct net_device *ndev = priv->ndev; struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 tempval; - int magic_packet = priv->wol_en && - (priv->device_flags & - FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); + u16 wol = priv->wol_opts; if (!netif_running(ndev)) return 0; @@ -1499,7 +1617,7 @@ static int gfar_suspend(struct device *dev) gfar_halt(priv); - if (magic_packet) { + if (wol & GFAR_WOL_MAGIC) { /* Enable interrupt on Magic Packet */ gfar_write(®s->imask, IMASK_MAG); @@ -1513,6 +1631,10 @@ static int gfar_suspend(struct device *dev) tempval |= MACCFG1_RX_EN; gfar_write(®s->maccfg1, tempval); + } else if (wol & GFAR_WOL_FILER_UCAST) { + gfar_filer_config_wol(priv); + gfar_start_wol_filer(priv); + } else { phy_stop(priv->phydev); } @@ -1526,18 +1648,22 @@ static int gfar_resume(struct device *dev) struct net_device *ndev = priv->ndev; struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 tempval; - int magic_packet = priv->wol_en && - (priv->device_flags & - FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); + u16 wol = priv->wol_opts; if (!netif_running(ndev)) return 0; - if (magic_packet) { + if (wol & GFAR_WOL_MAGIC) { /* Disable Magic Packet mode */ tempval = gfar_read(®s->maccfg2); tempval &= ~MACCFG2_MPEN; gfar_write(®s->maccfg2, tempval); + + } else if (wol & GFAR_WOL_FILER_UCAST) { + /* need to stop rx only, tx is already down */ + gfar_halt(priv); + gfar_filer_restore_table(priv); + } else { phy_start(priv->phydev); } @@ -1998,6 +2124,8 @@ static int register_grp_irqs(struct gfar_priv_grp *grp) gfar_irq(grp, RX)->irq); goto rx_irq_fail; } + enable_irq_wake(gfar_irq(grp, RX)->irq); + } else { err = request_irq(gfar_irq(grp, TX)->irq, gfar_interrupt, 0, gfar_irq(grp, TX)->name, grp); @@ -2743,7 +2871,14 @@ irqreturn_t gfar_receive(int irq, void *grp_id) { struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id; unsigned long flags; - u32 imask; + u32 imask, ievent; + + ievent = gfar_read(&grp->regs->ievent); + + if (unlikely(ievent & IEVENT_FGPI)) { + gfar_write(&grp->regs->ievent, IEVENT_FGPI); + return IRQ_HANDLED; + } if (likely(napi_schedule_prep(&grp->napi_rx))) { spin_lock_irqsave(&grp->grplock, flags); diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index 8c1994856..cb7766797 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -340,6 +340,7 @@ extern const char gfar_driver_version[]; #define IEVENT_MAG 0x00000800 #define IEVENT_GRSC 0x00000100 #define IEVENT_RXF0 0x00000080 +#define IEVENT_FGPI 0x00000010 #define IEVENT_FIR 0x00000008 #define IEVENT_FIQ 0x00000004 #define IEVENT_DPE 0x00000002 @@ -372,6 +373,7 @@ extern const char gfar_driver_version[]; #define IMASK_MAG 0x00000800 #define IMASK_GRSC 0x00000100 #define IMASK_RXFEN0 0x00000080 +#define IMASK_FGPI 0x00000010 #define IMASK_FIR 0x00000008 #define IMASK_FIQ 0x00000004 #define IMASK_DPE 0x00000002 @@ -540,6 +542,9 @@ extern const char gfar_driver_version[]; #define GFAR_INT_NAME_MAX (IFNAMSIZ + 6) /* '_g#_xx' */ +#define GFAR_WOL_MAGIC 0x00000001 +#define GFAR_WOL_FILER_UCAST 0x00000002 + struct txbd8 { union { @@ -917,6 +922,8 @@ struct gfar { #define FSL_GIANFAR_DEV_HAS_BD_STASHING 0x00000200 #define FSL_GIANFAR_DEV_HAS_BUF_STASHING 0x00000400 #define FSL_GIANFAR_DEV_HAS_TIMER 0x00000800 +#define FSL_GIANFAR_DEV_HAS_WAKE_ON_FILER 0x00001000 +#define FSL_GIANFAR_DEV_HAS_RX_FILER 0x00002000 #if (MAXGROUPS == 2) #define DEFAULT_MAPPING 0xAA @@ -1161,8 +1168,6 @@ struct gfar_private { extended_hash:1, bd_stash_en:1, rx_filer_enable:1, - /* Wake-on-LAN enabled */ - wol_en:1, /* Enable priorty based Tx scheduling in Hw */ prio_sched_en:1, /* Flow control flags */ @@ -1191,6 +1196,10 @@ struct gfar_private { u32 __iomem *hash_regs[16]; int hash_width; + /* wake-on-lan settings */ + u16 wol_opts; + u16 wol_supported; + /*Filer table*/ unsigned int ftp_rqfpr[MAX_FILER_IDX + 1]; unsigned int ftp_rqfcr[MAX_FILER_IDX + 1]; diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index a33e4a829..4b0ee855e 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -182,8 +182,6 @@ static void gfar_gdrvinfo(struct net_device *dev, sizeof(drvinfo->version)); strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); strlcpy(drvinfo->bus_info, "N/A", sizeof(drvinfo->bus_info)); - drvinfo->regdump_len = 0; - drvinfo->eedump_len = 0; } @@ -644,28 +642,49 @@ static void gfar_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct gfar_private *priv = netdev_priv(dev); - if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) { - wol->supported = WAKE_MAGIC; - wol->wolopts = priv->wol_en ? WAKE_MAGIC : 0; - } else { - wol->supported = wol->wolopts = 0; - } + wol->supported = 0; + wol->wolopts = 0; + + if (priv->wol_supported & GFAR_WOL_MAGIC) + wol->supported |= WAKE_MAGIC; + + if (priv->wol_supported & GFAR_WOL_FILER_UCAST) + wol->supported |= WAKE_UCAST; + + if (priv->wol_opts & GFAR_WOL_MAGIC) + wol->wolopts |= WAKE_MAGIC; + + if (priv->wol_opts & GFAR_WOL_FILER_UCAST) + wol->wolopts |= WAKE_UCAST; } static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct gfar_private *priv = netdev_priv(dev); + u16 wol_opts = 0; + int err; - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) && - wol->wolopts != 0) + if (!priv->wol_supported && wol->wolopts) return -EINVAL; - if (wol->wolopts & ~WAKE_MAGIC) + if (wol->wolopts & ~(WAKE_MAGIC | WAKE_UCAST)) return -EINVAL; - device_set_wakeup_enable(&dev->dev, wol->wolopts & WAKE_MAGIC); + if (wol->wolopts & WAKE_MAGIC) { + wol_opts |= GFAR_WOL_MAGIC; + } else { + if (wol->wolopts & WAKE_UCAST) + wol_opts |= GFAR_WOL_FILER_UCAST; + } + + wol_opts &= priv->wol_supported; + priv->wol_opts = 0; + + err = device_set_wakeup_enable(priv->dev, wol_opts); + if (err) + return err; - priv->wol_en = !!device_may_wakeup(&dev->dev); + priv->wol_opts = wol_opts; return 0; } diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c index 664d0c261..b40fba929 100644 --- a/drivers/net/ethernet/freescale/gianfar_ptp.c +++ b/drivers/net/ethernet/freescale/gianfar_ptp.c @@ -467,7 +467,7 @@ static int gianfar_ptp_probe(struct platform_device *dev) etsects->irq = platform_get_irq(dev, 0); - if (etsects->irq == NO_IRQ) { + if (etsects->irq < 0) { pr_err("irq not in device tree\n"); goto no_node; } diff --git a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c index cc83350d5..89714f5e0 100644 --- a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c +++ b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c @@ -351,8 +351,6 @@ uec_get_drvinfo(struct net_device *netdev, strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version)); strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); strlcpy(drvinfo->bus_info, "QUICC ENGINE", sizeof(drvinfo->bus_info)); - drvinfo->eedump_len = 0; - drvinfo->regdump_len = uec_get_regs_len(netdev); } #ifdef CONFIG_PM |