igc: Enable internal i225 PPS
authorEderson de Souza <ederson.desouza@intel.com>
Fri, 19 Feb 2021 01:31:03 +0000 (17:31 -0800)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Fri, 16 Apr 2021 20:15:45 +0000 (13:15 -0700)
The i225 device can produce one interrupt on the full second, much
like i210 - from where this patch is inspired.

This patch sets up the full second interruption on the i225 and when
receiving it, it sends a PPS event to PTP (Precision Time Protocol)
kernel subsystem.

The PTP subsystem exposes the PPS events via ioctl and sysfs, and one
can use the `testptp` tool (tools/testing/selftests/ptp) to check that
the events are being generated.

Signed-off-by: Ederson de Souza <ederson.desouza@intel.com>
Tested-by: Dvora Fuxbrumer <dvorax.fuxbrumer@linux.intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
drivers/net/ethernet/intel/igc/igc.h
drivers/net/ethernet/intel/igc/igc_main.c
drivers/net/ethernet/intel/igc/igc_ptp.c

index 91493a7..7c404c2 100644 (file)
@@ -223,6 +223,8 @@ struct igc_adapter {
        char fw_version[32];
 
        struct bpf_prog *xdp_prog;
+
+       bool pps_sys_wrap_on;
 };
 
 void igc_up(struct igc_adapter *adapter);
index 1076549..ac93c0e 100644 (file)
@@ -4251,9 +4251,17 @@ igc_features_check(struct sk_buff *skb, struct net_device *dev,
 static void igc_tsync_interrupt(struct igc_adapter *adapter)
 {
        struct igc_hw *hw = &adapter->hw;
+       struct ptp_clock_event event;
        u32 tsicr = rd32(IGC_TSICR);
        u32 ack = 0;
 
+       if (tsicr & IGC_TSICR_SYS_WRAP) {
+               event.type = PTP_CLOCK_PPS;
+               if (adapter->ptp_caps.pps)
+                       ptp_clock_event(adapter->ptp_clock, &event);
+               ack |= IGC_TSICR_SYS_WRAP;
+       }
+
        if (tsicr & IGC_TSICR_TXTS) {
                /* retrieve hardware timestamp */
                schedule_work(&adapter->ptp_tx_work);
index dfa3b24..8d6fbf6 100644 (file)
@@ -123,6 +123,29 @@ static int igc_ptp_settime_i225(struct ptp_clock_info *ptp,
 static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp,
                                       struct ptp_clock_request *rq, int on)
 {
+       struct igc_adapter *igc =
+               container_of(ptp, struct igc_adapter, ptp_caps);
+       struct igc_hw *hw = &igc->hw;
+       unsigned long flags;
+       u32 tsim;
+
+       switch (rq->type) {
+       case PTP_CLK_REQ_PPS:
+               spin_lock_irqsave(&igc->tmreg_lock, flags);
+               tsim = rd32(IGC_TSIM);
+               if (on)
+                       tsim |= IGC_TSICR_SYS_WRAP;
+               else
+                       tsim &= ~IGC_TSICR_SYS_WRAP;
+               igc->pps_sys_wrap_on = on;
+               wr32(IGC_TSIM, tsim);
+               spin_unlock_irqrestore(&igc->tmreg_lock, flags);
+               return 0;
+
+       default:
+               break;
+       }
+
        return -EOPNOTSUPP;
 }
 
@@ -497,6 +520,7 @@ void igc_ptp_init(struct igc_adapter *adapter)
                adapter->ptp_caps.gettimex64 = igc_ptp_gettimex64_i225;
                adapter->ptp_caps.settime64 = igc_ptp_settime_i225;
                adapter->ptp_caps.enable = igc_ptp_feature_enable_i225;
+               adapter->ptp_caps.pps = 1;
                break;
        default:
                adapter->ptp_clock = NULL;
@@ -598,7 +622,9 @@ void igc_ptp_reset(struct igc_adapter *adapter)
        case igc_i225:
                wr32(IGC_TSAUXC, 0x0);
                wr32(IGC_TSSDP, 0x0);
-               wr32(IGC_TSIM, IGC_TSICR_INTERRUPTS);
+               wr32(IGC_TSIM,
+                    IGC_TSICR_INTERRUPTS |
+                    (adapter->pps_sys_wrap_on ? IGC_TSICR_SYS_WRAP : 0));
                wr32(IGC_IMS, IGC_IMS_TS);
                break;
        default: