]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/net/ethernet/freescale/gianfar.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide
[karo-tx-linux.git] / drivers / net / ethernet / freescale / gianfar.c
index 710715fcb23dea7765ce3fc579c88fcd29ecb0da..3e6b9b437497dba9431fdedd3cf03262c0af3b0f 100644 (file)
 
 #include "gianfar.h"
 
-#define TX_TIMEOUT      (1*HZ)
+#define TX_TIMEOUT      (5*HZ)
 
 const char gfar_driver_version[] = "2.0";
 
@@ -341,7 +341,7 @@ static void gfar_rx_offload_en(struct gfar_private *priv)
        if (priv->ndev->features & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_RX))
                priv->uses_rxfcb = 1;
 
-       if (priv->hwts_rx_en)
+       if (priv->hwts_rx_en || priv->rx_filer_enable)
                priv->uses_rxfcb = 1;
 }
 
@@ -351,7 +351,7 @@ static void gfar_mac_rx_config(struct gfar_private *priv)
        u32 rctrl = 0;
 
        if (priv->rx_filer_enable) {
-               rctrl |= RCTRL_FILREN;
+               rctrl |= RCTRL_FILREN | RCTRL_PRSDEP_INIT;
                /* Program the RIR0 reg with the required distribution */
                if (priv->poll_mode == GFAR_SQ_POLLING)
                        gfar_write(&regs->rir0, DEFAULT_2RXQ_RIR0);
@@ -907,6 +907,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
@@ -1415,8 +1418,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 +1488,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(&regs->rctrl);
+       temp &= ~(RCTRL_FILREN | RCTRL_PRSDEP_INIT);
+       gfar_write(&regs->rctrl, temp);
+}
+
+static void __gfar_filer_enable(struct gfar_private *priv)
+{
+       struct gfar __iomem *regs = priv->gfargrp[0].regs;
+       u32 temp;
+
+       temp = gfar_read(&regs->rctrl);
+       temp |= RCTRL_FILREN | RCTRL_PRSDEP_INIT;
+       gfar_write(&regs->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(&regs->rqueue, priv->rqueue);
+
+       /* Initialize DMACTRL to have WWR and WOP */
+       tempval = gfar_read(&regs->dmactrl);
+       tempval |= DMACTRL_INIT_SETTINGS;
+       gfar_write(&regs->dmactrl, tempval);
+
+       /* Make sure we aren't stopped */
+       tempval = gfar_read(&regs->dmactrl);
+       tempval &= ~DMACTRL_GRS;
+       gfar_write(&regs->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(&regs->rstat, priv->gfargrp[i].rstat);
+               /* enable the Filer General Purpose Interrupt */
+               gfar_write(&regs->imask, IMASK_FGPI);
+       }
+
+       /* Enable Rx DMA */
+       tempval = gfar_read(&regs->maccfg1);
+       tempval |= MACCFG1_RX_EN;
+       gfar_write(&regs->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 +1615,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(&regs->imask, IMASK_MAG);
 
@@ -1513,6 +1629,10 @@ static int gfar_suspend(struct device *dev)
                tempval |= MACCFG1_RX_EN;
                gfar_write(&regs->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 +1646,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(&regs->maccfg2);
                tempval &= ~MACCFG2_MPEN;
                gfar_write(&regs->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 +2122,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 +2869,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);
@@ -3462,11 +3595,9 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
                netif_dbg(priv, tx_err, dev, "Transmit Error\n");
        }
        if (events & IEVENT_BSY) {
-               dev->stats.rx_errors++;
+               dev->stats.rx_over_errors++;
                atomic64_inc(&priv->extra_stats.rx_bsy);
 
-               gfar_receive(irq, grp_id);
-
                netif_dbg(priv, rx_err, dev, "busy error (rstat: %x)\n",
                          gfar_read(&regs->rstat));
        }