diff options
author | Matthew Vick <matthew.vick@intel.com> | 2012-08-18 03:26:33 -0400 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2012-09-17 05:04:24 -0400 |
commit | 1f6e8178d6851951876ad8524f4de7a0e6b111be (patch) | |
tree | e7a363f6216bc4456ae57d4cd1895bcf5f958ce8 | |
parent | 201987e3d03fadf0d87980981b7421198e3e5922 (diff) |
igb: Prevent dropped Tx timestamps via work items and interrupts.
In rare circumstances, it's possible a descriptor writeback will occur
before a timestamped Tx packet will go out on the wire, leading to the
driver believing the hardware failed to timestamp the packet. Schedule a
work item for 82576 and use the available time sync interrupt registers
on 82580 and above to account for this.
Cc: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: Matthew Vick <matthew.vick@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_defines.h | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_regs.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb.h | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb_main.c | 61 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb_ptp.c | 102 |
5 files changed, 153 insertions, 25 deletions
diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h index ec7e4fe3e3ee..0b27e8fe06bf 100644 --- a/drivers/net/ethernet/intel/igb/e1000_defines.h +++ b/drivers/net/ethernet/intel/igb/e1000_defines.h | |||
@@ -360,6 +360,7 @@ | |||
360 | #define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ | 360 | #define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ |
361 | #define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ | 361 | #define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ |
362 | #define E1000_ICR_VMMB 0x00000100 /* VM MB event */ | 362 | #define E1000_ICR_VMMB 0x00000100 /* VM MB event */ |
363 | #define E1000_ICR_TS 0x00080000 /* Time Sync Interrupt */ | ||
363 | #define E1000_ICR_DRSTA 0x40000000 /* Device Reset Asserted */ | 364 | #define E1000_ICR_DRSTA 0x40000000 /* Device Reset Asserted */ |
364 | /* If this bit asserted, the driver should claim the interrupt */ | 365 | /* If this bit asserted, the driver should claim the interrupt */ |
365 | #define E1000_ICR_INT_ASSERTED 0x80000000 | 366 | #define E1000_ICR_INT_ASSERTED 0x80000000 |
@@ -399,6 +400,7 @@ | |||
399 | #define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ | 400 | #define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ |
400 | #define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ | 401 | #define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ |
401 | #define E1000_IMS_VMMB E1000_ICR_VMMB /* Mail box activity */ | 402 | #define E1000_IMS_VMMB E1000_ICR_VMMB /* Mail box activity */ |
403 | #define E1000_IMS_TS E1000_ICR_TS /* Time Sync Interrupt */ | ||
402 | #define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ | 404 | #define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ |
403 | #define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ | 405 | #define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ |
404 | #define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ | 406 | #define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ |
@@ -510,6 +512,9 @@ | |||
510 | 512 | ||
511 | #define E1000_TIMINCA_16NS_SHIFT 24 | 513 | #define E1000_TIMINCA_16NS_SHIFT 24 |
512 | 514 | ||
515 | #define E1000_TSICR_TXTS 0x00000002 | ||
516 | #define E1000_TSIM_TXTS 0x00000002 | ||
517 | |||
513 | #define E1000_MDICNFG_EXT_MDIO 0x80000000 /* MDI ext/int destination */ | 518 | #define E1000_MDICNFG_EXT_MDIO 0x80000000 /* MDI ext/int destination */ |
514 | #define E1000_MDICNFG_COM_MDIO 0x40000000 /* MDI shared w/ lan 0 */ | 519 | #define E1000_MDICNFG_COM_MDIO 0x40000000 /* MDI shared w/ lan 0 */ |
515 | #define E1000_MDICNFG_PHY_MASK 0x03E00000 | 520 | #define E1000_MDICNFG_PHY_MASK 0x03E00000 |
diff --git a/drivers/net/ethernet/intel/igb/e1000_regs.h b/drivers/net/ethernet/intel/igb/e1000_regs.h index 28394bea5253..faec840a5a8a 100644 --- a/drivers/net/ethernet/intel/igb/e1000_regs.h +++ b/drivers/net/ethernet/intel/igb/e1000_regs.h | |||
@@ -91,6 +91,8 @@ | |||
91 | #define E1000_TIMINCA 0x0B608 /* Increment attributes register - RW */ | 91 | #define E1000_TIMINCA 0x0B608 /* Increment attributes register - RW */ |
92 | #define E1000_TSAUXC 0x0B640 /* Timesync Auxiliary Control register */ | 92 | #define E1000_TSAUXC 0x0B640 /* Timesync Auxiliary Control register */ |
93 | #define E1000_SYSTIMR 0x0B6F8 /* System time register Residue */ | 93 | #define E1000_SYSTIMR 0x0B6F8 /* System time register Residue */ |
94 | #define E1000_TSICR 0x0B66C /* Interrupt Cause Register */ | ||
95 | #define E1000_TSIM 0x0B674 /* Interrupt Mask Register */ | ||
94 | 96 | ||
95 | /* Filtering Registers */ | 97 | /* Filtering Registers */ |
96 | #define E1000_SAQF(_n) (0x5980 + 4 * (_n)) | 98 | #define E1000_SAQF(_n) (0x5980 + 4 * (_n)) |
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index 797346998d52..43c8e2914263 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h | |||
@@ -381,6 +381,8 @@ struct igb_adapter { | |||
381 | struct ptp_clock *ptp_clock; | 381 | struct ptp_clock *ptp_clock; |
382 | struct ptp_clock_info ptp_caps; | 382 | struct ptp_clock_info ptp_caps; |
383 | struct delayed_work ptp_overflow_work; | 383 | struct delayed_work ptp_overflow_work; |
384 | struct work_struct ptp_tx_work; | ||
385 | struct sk_buff *ptp_tx_skb; | ||
384 | spinlock_t tmreg_lock; | 386 | spinlock_t tmreg_lock; |
385 | struct cyclecounter cc; | 387 | struct cyclecounter cc; |
386 | struct timecounter tc; | 388 | struct timecounter tc; |
@@ -394,6 +396,7 @@ struct igb_adapter { | |||
394 | #define IGB_FLAG_QUAD_PORT_A (1 << 2) | 396 | #define IGB_FLAG_QUAD_PORT_A (1 << 2) |
395 | #define IGB_FLAG_QUEUE_PAIRS (1 << 3) | 397 | #define IGB_FLAG_QUEUE_PAIRS (1 << 3) |
396 | #define IGB_FLAG_DMAC (1 << 4) | 398 | #define IGB_FLAG_DMAC (1 << 4) |
399 | #define IGB_FLAG_PTP (1 << 5) | ||
397 | 400 | ||
398 | /* DMA Coalescing defines */ | 401 | /* DMA Coalescing defines */ |
399 | #define IGB_MIN_TXPBSIZE 20408 | 402 | #define IGB_MIN_TXPBSIZE 20408 |
@@ -440,8 +443,9 @@ extern void igb_set_fw_version(struct igb_adapter *); | |||
440 | #ifdef CONFIG_IGB_PTP | 443 | #ifdef CONFIG_IGB_PTP |
441 | extern void igb_ptp_init(struct igb_adapter *adapter); | 444 | extern void igb_ptp_init(struct igb_adapter *adapter); |
442 | extern void igb_ptp_stop(struct igb_adapter *adapter); | 445 | extern void igb_ptp_stop(struct igb_adapter *adapter); |
443 | extern void igb_ptp_tx_hwtstamp(struct igb_q_vector *q_vector, | 446 | extern void igb_ptp_reset(struct igb_adapter *adapter); |
444 | struct igb_tx_buffer *buffer_info); | 447 | extern void igb_ptp_tx_work(struct work_struct *work); |
448 | extern void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter); | ||
445 | extern void igb_ptp_rx_hwtstamp(struct igb_q_vector *q_vector, | 449 | extern void igb_ptp_rx_hwtstamp(struct igb_q_vector *q_vector, |
446 | union e1000_adv_rx_desc *rx_desc, | 450 | union e1000_adv_rx_desc *rx_desc, |
447 | struct sk_buff *skb); | 451 | struct sk_buff *skb); |
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 6e39f0ca9fc4..19d7666dfccb 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c | |||
@@ -1751,6 +1751,11 @@ void igb_reset(struct igb_adapter *adapter) | |||
1751 | /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ | 1751 | /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ |
1752 | wr32(E1000_VET, ETHERNET_IEEE_VLAN_TYPE); | 1752 | wr32(E1000_VET, ETHERNET_IEEE_VLAN_TYPE); |
1753 | 1753 | ||
1754 | #ifdef CONFIG_IGB_PTP | ||
1755 | /* Re-enable PTP, where applicable. */ | ||
1756 | igb_ptp_reset(adapter); | ||
1757 | #endif /* CONFIG_IGB_PTP */ | ||
1758 | |||
1754 | igb_get_phy_info(hw); | 1759 | igb_get_phy_info(hw); |
1755 | } | 1760 | } |
1756 | 1761 | ||
@@ -4234,7 +4239,7 @@ static __le32 igb_tx_cmd_type(u32 tx_flags) | |||
4234 | 4239 | ||
4235 | #ifdef CONFIG_IGB_PTP | 4240 | #ifdef CONFIG_IGB_PTP |
4236 | /* set timestamp bit if present */ | 4241 | /* set timestamp bit if present */ |
4237 | if (tx_flags & IGB_TX_FLAGS_TSTAMP) | 4242 | if (unlikely(tx_flags & IGB_TX_FLAGS_TSTAMP)) |
4238 | cmd_type |= cpu_to_le32(E1000_ADVTXD_MAC_TSTAMP); | 4243 | cmd_type |= cpu_to_le32(E1000_ADVTXD_MAC_TSTAMP); |
4239 | #endif /* CONFIG_IGB_PTP */ | 4244 | #endif /* CONFIG_IGB_PTP */ |
4240 | 4245 | ||
@@ -4445,6 +4450,9 @@ static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size) | |||
4445 | netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, | 4450 | netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, |
4446 | struct igb_ring *tx_ring) | 4451 | struct igb_ring *tx_ring) |
4447 | { | 4452 | { |
4453 | #ifdef CONFIG_IGB_PTP | ||
4454 | struct igb_adapter *adapter = netdev_priv(tx_ring->netdev); | ||
4455 | #endif /* CONFIG_IGB_PTP */ | ||
4448 | struct igb_tx_buffer *first; | 4456 | struct igb_tx_buffer *first; |
4449 | int tso; | 4457 | int tso; |
4450 | u32 tx_flags = 0; | 4458 | u32 tx_flags = 0; |
@@ -4468,9 +4476,14 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, | |||
4468 | first->gso_segs = 1; | 4476 | first->gso_segs = 1; |
4469 | 4477 | ||
4470 | #ifdef CONFIG_IGB_PTP | 4478 | #ifdef CONFIG_IGB_PTP |
4471 | if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { | 4479 | if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && |
4480 | !(adapter->ptp_tx_skb))) { | ||
4472 | skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; | 4481 | skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; |
4473 | tx_flags |= IGB_TX_FLAGS_TSTAMP; | 4482 | tx_flags |= IGB_TX_FLAGS_TSTAMP; |
4483 | |||
4484 | adapter->ptp_tx_skb = skb_get(skb); | ||
4485 | if (adapter->hw.mac.type == e1000_82576) | ||
4486 | schedule_work(&adapter->ptp_tx_work); | ||
4474 | } | 4487 | } |
4475 | #endif /* CONFIG_IGB_PTP */ | 4488 | #endif /* CONFIG_IGB_PTP */ |
4476 | 4489 | ||
@@ -4859,6 +4872,19 @@ static irqreturn_t igb_msix_other(int irq, void *data) | |||
4859 | mod_timer(&adapter->watchdog_timer, jiffies + 1); | 4872 | mod_timer(&adapter->watchdog_timer, jiffies + 1); |
4860 | } | 4873 | } |
4861 | 4874 | ||
4875 | #ifdef CONFIG_IGB_PTP | ||
4876 | if (icr & E1000_ICR_TS) { | ||
4877 | u32 tsicr = rd32(E1000_TSICR); | ||
4878 | |||
4879 | if (tsicr & E1000_TSICR_TXTS) { | ||
4880 | /* acknowledge the interrupt */ | ||
4881 | wr32(E1000_TSICR, E1000_TSICR_TXTS); | ||
4882 | /* retrieve hardware timestamp */ | ||
4883 | schedule_work(&adapter->ptp_tx_work); | ||
4884 | } | ||
4885 | } | ||
4886 | #endif /* CONFIG_IGB_PTP */ | ||
4887 | |||
4862 | wr32(E1000_EIMS, adapter->eims_other); | 4888 | wr32(E1000_EIMS, adapter->eims_other); |
4863 | 4889 | ||
4864 | return IRQ_HANDLED; | 4890 | return IRQ_HANDLED; |
@@ -5650,6 +5676,19 @@ static irqreturn_t igb_intr_msi(int irq, void *data) | |||
5650 | mod_timer(&adapter->watchdog_timer, jiffies + 1); | 5676 | mod_timer(&adapter->watchdog_timer, jiffies + 1); |
5651 | } | 5677 | } |
5652 | 5678 | ||
5679 | #ifdef CONFIG_IGB_PTP | ||
5680 | if (icr & E1000_ICR_TS) { | ||
5681 | u32 tsicr = rd32(E1000_TSICR); | ||
5682 | |||
5683 | if (tsicr & E1000_TSICR_TXTS) { | ||
5684 | /* acknowledge the interrupt */ | ||
5685 | wr32(E1000_TSICR, E1000_TSICR_TXTS); | ||
5686 | /* retrieve hardware timestamp */ | ||
5687 | schedule_work(&adapter->ptp_tx_work); | ||
5688 | } | ||
5689 | } | ||
5690 | #endif /* CONFIG_IGB_PTP */ | ||
5691 | |||
5653 | napi_schedule(&q_vector->napi); | 5692 | napi_schedule(&q_vector->napi); |
5654 | 5693 | ||
5655 | return IRQ_HANDLED; | 5694 | return IRQ_HANDLED; |
@@ -5691,6 +5730,19 @@ static irqreturn_t igb_intr(int irq, void *data) | |||
5691 | mod_timer(&adapter->watchdog_timer, jiffies + 1); | 5730 | mod_timer(&adapter->watchdog_timer, jiffies + 1); |
5692 | } | 5731 | } |
5693 | 5732 | ||
5733 | #ifdef CONFIG_IGB_PTP | ||
5734 | if (icr & E1000_ICR_TS) { | ||
5735 | u32 tsicr = rd32(E1000_TSICR); | ||
5736 | |||
5737 | if (tsicr & E1000_TSICR_TXTS) { | ||
5738 | /* acknowledge the interrupt */ | ||
5739 | wr32(E1000_TSICR, E1000_TSICR_TXTS); | ||
5740 | /* retrieve hardware timestamp */ | ||
5741 | schedule_work(&adapter->ptp_tx_work); | ||
5742 | } | ||
5743 | } | ||
5744 | #endif /* CONFIG_IGB_PTP */ | ||
5745 | |||
5694 | napi_schedule(&q_vector->napi); | 5746 | napi_schedule(&q_vector->napi); |
5695 | 5747 | ||
5696 | return IRQ_HANDLED; | 5748 | return IRQ_HANDLED; |
@@ -5794,11 +5846,6 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector) | |||
5794 | total_bytes += tx_buffer->bytecount; | 5846 | total_bytes += tx_buffer->bytecount; |
5795 | total_packets += tx_buffer->gso_segs; | 5847 | total_packets += tx_buffer->gso_segs; |
5796 | 5848 | ||
5797 | #ifdef CONFIG_IGB_PTP | ||
5798 | /* retrieve hardware timestamp */ | ||
5799 | igb_ptp_tx_hwtstamp(q_vector, tx_buffer); | ||
5800 | #endif /* CONFIG_IGB_PTP */ | ||
5801 | |||
5802 | /* free the skb */ | 5849 | /* free the skb */ |
5803 | dev_kfree_skb_any(tx_buffer->skb); | 5850 | dev_kfree_skb_any(tx_buffer->skb); |
5804 | tx_buffer->skb = NULL; | 5851 | tx_buffer->skb = NULL; |
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index e69555f1f73e..d57060c0813d 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c | |||
@@ -289,6 +289,31 @@ static int igb_ptp_enable(struct ptp_clock_info *ptp, | |||
289 | return -EOPNOTSUPP; | 289 | return -EOPNOTSUPP; |
290 | } | 290 | } |
291 | 291 | ||
292 | /** | ||
293 | * igb_ptp_tx_work | ||
294 | * @work: pointer to work struct | ||
295 | * | ||
296 | * This work function polls the TSYNCTXCTL valid bit to determine when a | ||
297 | * timestamp has been taken for the current stored skb. | ||
298 | */ | ||
299 | void igb_ptp_tx_work(struct work_struct *work) | ||
300 | { | ||
301 | struct igb_adapter *adapter = container_of(work, struct igb_adapter, | ||
302 | ptp_tx_work); | ||
303 | struct e1000_hw *hw = &adapter->hw; | ||
304 | u32 tsynctxctl; | ||
305 | |||
306 | if (!adapter->ptp_tx_skb) | ||
307 | return; | ||
308 | |||
309 | tsynctxctl = rd32(E1000_TSYNCTXCTL); | ||
310 | if (tsynctxctl & E1000_TSYNCTXCTL_VALID) | ||
311 | igb_ptp_tx_hwtstamp(adapter); | ||
312 | else | ||
313 | /* reschedule to check later */ | ||
314 | schedule_work(&adapter->ptp_tx_work); | ||
315 | } | ||
316 | |||
292 | static void igb_ptp_overflow_check(struct work_struct *work) | 317 | static void igb_ptp_overflow_check(struct work_struct *work) |
293 | { | 318 | { |
294 | struct igb_adapter *igb = | 319 | struct igb_adapter *igb = |
@@ -305,31 +330,25 @@ static void igb_ptp_overflow_check(struct work_struct *work) | |||
305 | 330 | ||
306 | /** | 331 | /** |
307 | * igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp | 332 | * igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp |
308 | * @q_vector: pointer to q_vector containing needed info | 333 | * @adapter: Board private structure. |
309 | * @buffer: pointer to igb_tx_buffer structure | ||
310 | * | 334 | * |
311 | * If we were asked to do hardware stamping and such a time stamp is | 335 | * If we were asked to do hardware stamping and such a time stamp is |
312 | * available, then it must have been for this skb here because we only | 336 | * available, then it must have been for this skb here because we only |
313 | * allow only one such packet into the queue. | 337 | * allow only one such packet into the queue. |
314 | */ | 338 | */ |
315 | void igb_ptp_tx_hwtstamp(struct igb_q_vector *q_vector, | 339 | void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter) |
316 | struct igb_tx_buffer *buffer_info) | ||
317 | { | 340 | { |
318 | struct igb_adapter *adapter = q_vector->adapter; | ||
319 | struct e1000_hw *hw = &adapter->hw; | 341 | struct e1000_hw *hw = &adapter->hw; |
320 | struct skb_shared_hwtstamps shhwtstamps; | 342 | struct skb_shared_hwtstamps shhwtstamps; |
321 | u64 regval; | 343 | u64 regval; |
322 | 344 | ||
323 | /* if skb does not support hw timestamp or TX stamp not valid exit */ | ||
324 | if (likely(!(buffer_info->tx_flags & IGB_TX_FLAGS_TSTAMP)) || | ||
325 | !(rd32(E1000_TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID)) | ||
326 | return; | ||
327 | |||
328 | regval = rd32(E1000_TXSTMPL); | 345 | regval = rd32(E1000_TXSTMPL); |
329 | regval |= (u64)rd32(E1000_TXSTMPH) << 32; | 346 | regval |= (u64)rd32(E1000_TXSTMPH) << 32; |
330 | 347 | ||
331 | igb_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval); | 348 | igb_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval); |
332 | skb_tstamp_tx(buffer_info->skb, &shhwtstamps); | 349 | skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps); |
350 | dev_kfree_skb_any(adapter->ptp_tx_skb); | ||
351 | adapter->ptp_tx_skb = NULL; | ||
333 | } | 352 | } |
334 | 353 | ||
335 | void igb_ptp_rx_hwtstamp(struct igb_q_vector *q_vector, | 354 | void igb_ptp_rx_hwtstamp(struct igb_q_vector *q_vector, |
@@ -603,16 +622,26 @@ void igb_ptp_init(struct igb_adapter *adapter) | |||
603 | 622 | ||
604 | spin_lock_init(&adapter->tmreg_lock); | 623 | spin_lock_init(&adapter->tmreg_lock); |
605 | 624 | ||
625 | INIT_WORK(&adapter->ptp_tx_work, igb_ptp_tx_work); | ||
626 | |||
606 | schedule_delayed_work(&adapter->ptp_overflow_work, | 627 | schedule_delayed_work(&adapter->ptp_overflow_work, |
607 | IGB_SYSTIM_OVERFLOW_PERIOD); | 628 | IGB_SYSTIM_OVERFLOW_PERIOD); |
608 | 629 | ||
630 | /* Initialize the time sync interrupts for devices that support it. */ | ||
631 | if (hw->mac.type >= e1000_82580) { | ||
632 | wr32(E1000_TSIM, E1000_TSIM_TXTS); | ||
633 | wr32(E1000_IMS, E1000_IMS_TS); | ||
634 | } | ||
635 | |||
609 | adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps); | 636 | adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps); |
610 | if (IS_ERR(adapter->ptp_clock)) { | 637 | if (IS_ERR(adapter->ptp_clock)) { |
611 | adapter->ptp_clock = NULL; | 638 | adapter->ptp_clock = NULL; |
612 | dev_err(&adapter->pdev->dev, "ptp_clock_register failed\n"); | 639 | dev_err(&adapter->pdev->dev, "ptp_clock_register failed\n"); |
613 | } else | 640 | } else { |
614 | dev_info(&adapter->pdev->dev, "added PHC on %s\n", | 641 | dev_info(&adapter->pdev->dev, "added PHC on %s\n", |
615 | adapter->netdev->name); | 642 | adapter->netdev->name); |
643 | adapter->flags |= IGB_FLAG_PTP; | ||
644 | } | ||
616 | } | 645 | } |
617 | 646 | ||
618 | /** | 647 | /** |
@@ -624,20 +653,61 @@ void igb_ptp_init(struct igb_adapter *adapter) | |||
624 | void igb_ptp_stop(struct igb_adapter *adapter) | 653 | void igb_ptp_stop(struct igb_adapter *adapter) |
625 | { | 654 | { |
626 | switch (adapter->hw.mac.type) { | 655 | switch (adapter->hw.mac.type) { |
627 | case e1000_i211: | ||
628 | case e1000_i210: | ||
629 | case e1000_i350: | ||
630 | case e1000_82580: | ||
631 | case e1000_82576: | 656 | case e1000_82576: |
657 | case e1000_82580: | ||
658 | case e1000_i350: | ||
632 | cancel_delayed_work_sync(&adapter->ptp_overflow_work); | 659 | cancel_delayed_work_sync(&adapter->ptp_overflow_work); |
633 | break; | 660 | break; |
661 | case e1000_i210: | ||
662 | case e1000_i211: | ||
663 | /* No delayed work to cancel. */ | ||
664 | break; | ||
634 | default: | 665 | default: |
635 | return; | 666 | return; |
636 | } | 667 | } |
637 | 668 | ||
669 | cancel_work_sync(&adapter->ptp_tx_work); | ||
670 | |||
638 | if (adapter->ptp_clock) { | 671 | if (adapter->ptp_clock) { |
639 | ptp_clock_unregister(adapter->ptp_clock); | 672 | ptp_clock_unregister(adapter->ptp_clock); |
640 | dev_info(&adapter->pdev->dev, "removed PHC on %s\n", | 673 | dev_info(&adapter->pdev->dev, "removed PHC on %s\n", |
641 | adapter->netdev->name); | 674 | adapter->netdev->name); |
675 | adapter->flags &= ~IGB_FLAG_PTP; | ||
642 | } | 676 | } |
643 | } | 677 | } |
678 | |||
679 | /** | ||
680 | * igb_ptp_reset - Re-enable the adapter for PTP following a reset. | ||
681 | * @adapter: Board private structure. | ||
682 | * | ||
683 | * This function handles the reset work required to re-enable the PTP device. | ||
684 | **/ | ||
685 | void igb_ptp_reset(struct igb_adapter *adapter) | ||
686 | { | ||
687 | struct e1000_hw *hw = &adapter->hw; | ||
688 | |||
689 | if (!(adapter->flags & IGB_FLAG_PTP)) | ||
690 | return; | ||
691 | |||
692 | switch (adapter->hw.mac.type) { | ||
693 | case e1000_82576: | ||
694 | /* Dial the nominal frequency. */ | ||
695 | wr32(E1000_TIMINCA, INCPERIOD_82576 | INCVALUE_82576); | ||
696 | break; | ||
697 | case e1000_82580: | ||
698 | case e1000_i350: | ||
699 | case e1000_i210: | ||
700 | case e1000_i211: | ||
701 | /* Enable the timer functions and interrupts. */ | ||
702 | wr32(E1000_TSAUXC, 0x0); | ||
703 | wr32(E1000_TSIM, E1000_TSIM_TXTS); | ||
704 | wr32(E1000_IMS, E1000_IMS_TS); | ||
705 | break; | ||
706 | default: | ||
707 | /* No work to do. */ | ||
708 | return; | ||
709 | } | ||
710 | |||
711 | timecounter_init(&adapter->tc, &adapter->cc, | ||
712 | ktime_to_ns(ktime_get_real())); | ||
713 | } | ||