|
@@ -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(®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 +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(®s->imask, IMASK_MAG);
|
|
|
|
|
@@ -1513,6 +1629,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 +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(®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 +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);
|