net: fec: Let fec_ptp have its own interrupt routine
authorTroy Kisky <troy.kisky@boundarydevices.com>
Fri, 3 Nov 2017 17:29:59 +0000 (10:29 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 8 Nov 2017 01:36:11 +0000 (10:36 +0900)
This is better for code locality and should slightly
speed up normal interrupts.

This also allows PPS clock output to start working for
i.mx7. This is because i.mx7 was already using the limit
of 3 interrupts, and needed another.

Signed-off-by: Troy Kisky <troy.kisky@boundarydevices.com>
Acked-by: Fugang Duan <fugang.duan@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Documentation/devicetree/bindings/net/fsl-fec.txt
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fec_ptp.c

index 6f55bdd52f8a99be3c0741cf6411a00554c85778..f0dc94409107130d1279c2144c50eec7be122633 100644 (file)
@@ -34,6 +34,19 @@ Optional properties:
 - fsl,err006687-workaround-present: If present indicates that the system has
   the hardware workaround for ERR006687 applied and does not need a software
   workaround.
+ -interrupt-names:  names of the interrupts listed in interrupts property in
+  the same order. The defaults if not specified are
+  __Number of interrupts__   __Default__
+       1                       "int0"
+       2                       "int0", "pps"
+       3                       "int0", "int1", "int2"
+       4                       "int0", "int1", "int2", "pps"
+  The order may be changed as long as they correspond to the interrupts
+  property. Currently, only i.mx7 uses "int1" and "int2". They correspond to
+  tx/rx queues 1 and 2. "int0" will be used for queue 0 and ENET_MII interrupts.
+  For imx6sx, "int0" handles all 3 queues and ENET_MII. "pps" is for the pulse
+  per second interrupt associated with 1588 precision time protocol(PTP).
+
 
 Optional subnodes:
 - mdio : specifies the mdio bus in the FEC, used as a container for phy nodes
index 44720f83af273f299d25d7ba437a2ed4604b0788..5385074b3b7da87e5bfb737b57c28f87957c2fb2 100644 (file)
@@ -583,12 +583,11 @@ struct fec_enet_private {
        u64 ethtool_stats[0];
 };
 
-void fec_ptp_init(struct platform_device *pdev);
+void fec_ptp_init(struct platform_device *pdev, int irq_idx);
 void fec_ptp_stop(struct platform_device *pdev);
 void fec_ptp_start_cyclecounter(struct net_device *ndev);
 int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr);
 int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr);
-uint fec_ptp_check_pps_event(struct fec_enet_private *fep);
 
 /****************************************************************************/
 #endif /* FEC_H */
index 3dc2d771a222147c89a3814a34d736e0bcf0d5c4..6105738552134809fc0d0abf8caadfa76f5e1f8a 100644 (file)
@@ -1602,10 +1602,6 @@ fec_enet_interrupt(int irq, void *dev_id)
                ret = IRQ_HANDLED;
                complete(&fep->mdio_done);
        }
-
-       if (fep->ptp_clock)
-               if (fec_ptp_check_pps_event(fep))
-                       ret = IRQ_HANDLED;
        return ret;
 }
 
@@ -3312,6 +3308,19 @@ fec_enet_get_queue_num(struct platform_device *pdev, int *num_tx, int *num_rx)
 
 }
 
+static int fec_enet_get_irq_cnt(struct platform_device *pdev)
+{
+       int irq_cnt = platform_irq_count(pdev);
+
+       if (irq_cnt > FEC_IRQ_NUM)
+               irq_cnt = FEC_IRQ_NUM;  /* last for pps */
+       else if (irq_cnt == 2)
+               irq_cnt = 1;    /* last for pps */
+       else if (irq_cnt <= 0)
+               irq_cnt = 1;    /* At least 1 irq is needed */
+       return irq_cnt;
+}
+
 static int
 fec_probe(struct platform_device *pdev)
 {
@@ -3325,6 +3334,8 @@ fec_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node, *phy_node;
        int num_tx_qs;
        int num_rx_qs;
+       char irq_name[8];
+       int irq_cnt;
 
        fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
 
@@ -3465,18 +3476,20 @@ fec_probe(struct platform_device *pdev)
        if (ret)
                goto failed_reset;
 
+       irq_cnt = fec_enet_get_irq_cnt(pdev);
        if (fep->bufdesc_ex)
-               fec_ptp_init(pdev);
+               fec_ptp_init(pdev, irq_cnt);
 
        ret = fec_enet_init(ndev);
        if (ret)
                goto failed_init;
 
-       for (i = 0; i < FEC_IRQ_NUM; i++) {
-               irq = platform_get_irq(pdev, i);
+       for (i = 0; i < irq_cnt; i++) {
+               sprintf(irq_name, "int%d", i);
+               irq = platform_get_irq_byname(pdev, irq_name);
+               if (irq < 0)
+                       irq = platform_get_irq(pdev, i);
                if (irq < 0) {
-                       if (i)
-                               break;
                        ret = irq;
                        goto failed_irq;
                }
index 6ebad3fac81d17e3513de1f7c3d9eec31e56b71e..f81439796ac77dfdd47e9a350b576122bfc0b1d9 100644 (file)
@@ -549,6 +549,37 @@ static void fec_time_keep(struct work_struct *work)
        schedule_delayed_work(&fep->time_keep, HZ);
 }
 
+/* This function checks the pps event and reloads the timer compare counter. */
+static irqreturn_t fec_pps_interrupt(int irq, void *dev_id)
+{
+       struct net_device *ndev = dev_id;
+       struct fec_enet_private *fep = netdev_priv(ndev);
+       u32 val;
+       u8 channel = fep->pps_channel;
+       struct ptp_clock_event event;
+
+       val = readl(fep->hwp + FEC_TCSR(channel));
+       if (val & FEC_T_TF_MASK) {
+               /* Write the next next compare(not the next according the spec)
+                * value to the register
+                */
+               writel(fep->next_counter, fep->hwp + FEC_TCCR(channel));
+               do {
+                       writel(val, fep->hwp + FEC_TCSR(channel));
+               } while (readl(fep->hwp + FEC_TCSR(channel)) & FEC_T_TF_MASK);
+
+               /* Update the counter; */
+               fep->next_counter = (fep->next_counter + fep->reload_period) &
+                               fep->cc.mask;
+
+               event.type = PTP_CLOCK_PPS;
+               ptp_clock_event(fep->ptp_clock, &event);
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
 /**
  * fec_ptp_init
  * @ndev: The FEC network adapter
@@ -558,10 +589,12 @@ static void fec_time_keep(struct work_struct *work)
  * cyclecounter init routine and exits.
  */
 
-void fec_ptp_init(struct platform_device *pdev)
+void fec_ptp_init(struct platform_device *pdev, int irq_idx)
 {
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct fec_enet_private *fep = netdev_priv(ndev);
+       int irq;
+       int ret;
 
        fep->ptp_caps.owner = THIS_MODULE;
        snprintf(fep->ptp_caps.name, 16, "fec ptp");
@@ -587,6 +620,20 @@ void fec_ptp_init(struct platform_device *pdev)
 
        INIT_DELAYED_WORK(&fep->time_keep, fec_time_keep);
 
+       irq = platform_get_irq_byname(pdev, "pps");
+       if (irq < 0)
+               irq = platform_get_irq(pdev, irq_idx);
+       /* Failure to get an irq is not fatal,
+        * only the PTP_CLOCK_PPS clock events should stop
+        */
+       if (irq >= 0) {
+               ret = devm_request_irq(&pdev->dev, irq, fec_pps_interrupt,
+                                      0, pdev->name, ndev);
+               if (ret < 0)
+                       dev_warn(&pdev->dev, "request for pps irq failed(%d)\n",
+                                ret);
+       }
+
        fep->ptp_clock = ptp_clock_register(&fep->ptp_caps, &pdev->dev);
        if (IS_ERR(fep->ptp_clock)) {
                fep->ptp_clock = NULL;
@@ -605,36 +652,3 @@ void fec_ptp_stop(struct platform_device *pdev)
        if (fep->ptp_clock)
                ptp_clock_unregister(fep->ptp_clock);
 }
-
-/**
- * fec_ptp_check_pps_event
- * @fep: the fec_enet_private structure handle
- *
- * This function check the pps event and reload the timer compare counter.
- */
-uint fec_ptp_check_pps_event(struct fec_enet_private *fep)
-{
-       u32 val;
-       u8 channel = fep->pps_channel;
-       struct ptp_clock_event event;
-
-       val = readl(fep->hwp + FEC_TCSR(channel));
-       if (val & FEC_T_TF_MASK) {
-               /* Write the next next compare(not the next according the spec)
-                * value to the register
-                */
-               writel(fep->next_counter, fep->hwp + FEC_TCCR(channel));
-               do {
-                       writel(val, fep->hwp + FEC_TCSR(channel));
-               } while (readl(fep->hwp + FEC_TCSR(channel)) & FEC_T_TF_MASK);
-
-               /* Update the counter; */
-               fep->next_counter = (fep->next_counter + fep->reload_period) & fep->cc.mask;
-
-               event.type = PTP_CLOCK_PPS;
-               ptp_clock_event(fep->ptp_clock, &event);
-               return 1;
-       }
-
-       return 0;
-}