.. | .. |
---|
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); |
---|