| .. | .. |
|---|
| 134 | 134 | * |
|---|
| 135 | 135 | * We need to convert the system time value stored in the RX/TXSTMP registers |
|---|
| 136 | 136 | * into a hwtstamp which can be used by the upper level timestamping functions. |
|---|
| 137 | + * |
|---|
| 138 | + * Returns 0 on success. |
|---|
| 137 | 139 | **/ |
|---|
| 138 | | -static void igc_ptp_systim_to_hwtstamp(struct igc_adapter *adapter, |
|---|
| 139 | | - struct skb_shared_hwtstamps *hwtstamps, |
|---|
| 140 | | - u64 systim) |
|---|
| 140 | +static int igc_ptp_systim_to_hwtstamp(struct igc_adapter *adapter, |
|---|
| 141 | + struct skb_shared_hwtstamps *hwtstamps, |
|---|
| 142 | + u64 systim) |
|---|
| 141 | 143 | { |
|---|
| 142 | 144 | switch (adapter->hw.mac.type) { |
|---|
| 143 | 145 | case igc_i225: |
|---|
| .. | .. |
|---|
| 147 | 149 | systim & 0xFFFFFFFF); |
|---|
| 148 | 150 | break; |
|---|
| 149 | 151 | default: |
|---|
| 150 | | - break; |
|---|
| 152 | + return -EINVAL; |
|---|
| 151 | 153 | } |
|---|
| 154 | + return 0; |
|---|
| 152 | 155 | } |
|---|
| 153 | 156 | |
|---|
| 154 | 157 | /** |
|---|
| .. | .. |
|---|
| 320 | 323 | return 0; |
|---|
| 321 | 324 | } |
|---|
| 322 | 325 | |
|---|
| 326 | +/* Requires adapter->ptp_tx_lock held by caller. */ |
|---|
| 323 | 327 | static void igc_ptp_tx_timeout(struct igc_adapter *adapter) |
|---|
| 324 | 328 | { |
|---|
| 325 | 329 | struct igc_hw *hw = &adapter->hw; |
|---|
| .. | .. |
|---|
| 327 | 331 | dev_kfree_skb_any(adapter->ptp_tx_skb); |
|---|
| 328 | 332 | adapter->ptp_tx_skb = NULL; |
|---|
| 329 | 333 | adapter->tx_hwtstamp_timeouts++; |
|---|
| 330 | | - clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state); |
|---|
| 331 | 334 | /* Clear the tx valid bit in TSYNCTXCTL register to enable interrupt. */ |
|---|
| 332 | 335 | rd32(IGC_TXSTMPH); |
|---|
| 333 | 336 | netdev_warn(adapter->netdev, "Tx timestamp timeout\n"); |
|---|
| .. | .. |
|---|
| 335 | 338 | |
|---|
| 336 | 339 | void igc_ptp_tx_hang(struct igc_adapter *adapter) |
|---|
| 337 | 340 | { |
|---|
| 338 | | - bool timeout = time_is_before_jiffies(adapter->ptp_tx_start + |
|---|
| 339 | | - IGC_PTP_TX_TIMEOUT); |
|---|
| 341 | + unsigned long flags; |
|---|
| 340 | 342 | |
|---|
| 341 | | - if (!test_bit(__IGC_PTP_TX_IN_PROGRESS, &adapter->state)) |
|---|
| 342 | | - return; |
|---|
| 343 | + spin_lock_irqsave(&adapter->ptp_tx_lock, flags); |
|---|
| 343 | 344 | |
|---|
| 344 | | - /* If we haven't received a timestamp within the timeout, it is |
|---|
| 345 | | - * reasonable to assume that it will never occur, so we can unlock the |
|---|
| 346 | | - * timestamp bit when this occurs. |
|---|
| 347 | | - */ |
|---|
| 348 | | - if (timeout) { |
|---|
| 349 | | - cancel_work_sync(&adapter->ptp_tx_work); |
|---|
| 350 | | - igc_ptp_tx_timeout(adapter); |
|---|
| 351 | | - } |
|---|
| 345 | + if (!adapter->ptp_tx_skb) |
|---|
| 346 | + goto unlock; |
|---|
| 347 | + |
|---|
| 348 | + if (time_is_after_jiffies(adapter->ptp_tx_start + IGC_PTP_TX_TIMEOUT)) |
|---|
| 349 | + goto unlock; |
|---|
| 350 | + |
|---|
| 351 | + igc_ptp_tx_timeout(adapter); |
|---|
| 352 | + |
|---|
| 353 | +unlock: |
|---|
| 354 | + spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags); |
|---|
| 352 | 355 | } |
|---|
| 353 | 356 | |
|---|
| 354 | 357 | /** |
|---|
| .. | .. |
|---|
| 358 | 361 | * If we were asked to do hardware stamping and such a time stamp is |
|---|
| 359 | 362 | * available, then it must have been for this skb here because we only |
|---|
| 360 | 363 | * allow only one such packet into the queue. |
|---|
| 364 | + * |
|---|
| 365 | + * Context: Expects adapter->ptp_tx_lock to be held by caller. |
|---|
| 361 | 366 | */ |
|---|
| 362 | 367 | static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter) |
|---|
| 363 | 368 | { |
|---|
| .. | .. |
|---|
| 372 | 377 | |
|---|
| 373 | 378 | regval = rd32(IGC_TXSTMPL); |
|---|
| 374 | 379 | regval |= (u64)rd32(IGC_TXSTMPH) << 32; |
|---|
| 375 | | - igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval); |
|---|
| 380 | + if (igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval)) |
|---|
| 381 | + return; |
|---|
| 376 | 382 | |
|---|
| 377 | 383 | switch (adapter->link_speed) { |
|---|
| 378 | 384 | case SPEED_10: |
|---|
| .. | .. |
|---|
| 392 | 398 | shhwtstamps.hwtstamp = |
|---|
| 393 | 399 | ktime_add_ns(shhwtstamps.hwtstamp, adjust); |
|---|
| 394 | 400 | |
|---|
| 395 | | - /* Clear the lock early before calling skb_tstamp_tx so that |
|---|
| 396 | | - * applications are not woken up before the lock bit is clear. We use |
|---|
| 397 | | - * a copy of the skb pointer to ensure other threads can't change it |
|---|
| 398 | | - * while we're notifying the stack. |
|---|
| 399 | | - */ |
|---|
| 400 | 401 | adapter->ptp_tx_skb = NULL; |
|---|
| 401 | | - clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state); |
|---|
| 402 | 402 | |
|---|
| 403 | 403 | /* Notify the stack and free the skb after we've unlocked */ |
|---|
| 404 | 404 | skb_tstamp_tx(skb, &shhwtstamps); |
|---|
| .. | .. |
|---|
| 409 | 409 | * igc_ptp_tx_work |
|---|
| 410 | 410 | * @work: pointer to work struct |
|---|
| 411 | 411 | * |
|---|
| 412 | | - * This work function polls the TSYNCTXCTL valid bit to determine when a |
|---|
| 413 | | - * timestamp has been taken for the current stored skb. |
|---|
| 412 | + * This work function checks the TSYNCTXCTL valid bit to determine when |
|---|
| 413 | + * a timestamp has been taken for the current stored skb. |
|---|
| 414 | 414 | */ |
|---|
| 415 | 415 | static void igc_ptp_tx_work(struct work_struct *work) |
|---|
| 416 | 416 | { |
|---|
| 417 | 417 | struct igc_adapter *adapter = container_of(work, struct igc_adapter, |
|---|
| 418 | 418 | ptp_tx_work); |
|---|
| 419 | 419 | struct igc_hw *hw = &adapter->hw; |
|---|
| 420 | + unsigned long flags; |
|---|
| 420 | 421 | u32 tsynctxctl; |
|---|
| 421 | 422 | |
|---|
| 422 | | - if (!test_bit(__IGC_PTP_TX_IN_PROGRESS, &adapter->state)) |
|---|
| 423 | | - return; |
|---|
| 423 | + spin_lock_irqsave(&adapter->ptp_tx_lock, flags); |
|---|
| 424 | + |
|---|
| 425 | + if (!adapter->ptp_tx_skb) |
|---|
| 426 | + goto unlock; |
|---|
| 424 | 427 | |
|---|
| 425 | 428 | tsynctxctl = rd32(IGC_TSYNCTXCTL); |
|---|
| 426 | | - if (WARN_ON_ONCE(!(tsynctxctl & IGC_TSYNCTXCTL_TXTT_0))) |
|---|
| 427 | | - return; |
|---|
| 429 | + tsynctxctl &= IGC_TSYNCTXCTL_TXTT_0; |
|---|
| 430 | + if (!tsynctxctl) { |
|---|
| 431 | + WARN_ONCE(1, "Received a TSTAMP interrupt but no TSTAMP is ready.\n"); |
|---|
| 432 | + goto unlock; |
|---|
| 433 | + } |
|---|
| 428 | 434 | |
|---|
| 429 | 435 | igc_ptp_tx_hwtstamp(adapter); |
|---|
| 436 | + |
|---|
| 437 | +unlock: |
|---|
| 438 | + spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags); |
|---|
| 430 | 439 | } |
|---|
| 431 | 440 | |
|---|
| 432 | 441 | /** |
|---|
| .. | .. |
|---|
| 502 | 511 | return; |
|---|
| 503 | 512 | } |
|---|
| 504 | 513 | |
|---|
| 514 | + spin_lock_init(&adapter->ptp_tx_lock); |
|---|
| 505 | 515 | spin_lock_init(&adapter->tmreg_lock); |
|---|
| 506 | 516 | INIT_WORK(&adapter->ptp_tx_work, igc_ptp_tx_work); |
|---|
| 507 | 517 | |
|---|
| .. | .. |
|---|
| 555 | 565 | cancel_work_sync(&adapter->ptp_tx_work); |
|---|
| 556 | 566 | dev_kfree_skb_any(adapter->ptp_tx_skb); |
|---|
| 557 | 567 | adapter->ptp_tx_skb = NULL; |
|---|
| 558 | | - clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state); |
|---|
| 559 | 568 | |
|---|
| 560 | 569 | if (pci_device_is_present(adapter->pdev)) |
|---|
| 561 | 570 | igc_ptp_time_save(adapter); |
|---|