diff options
Diffstat (limited to 'drivers/net/e1000e/netdev.c')
| -rw-r--r-- | drivers/net/e1000e/netdev.c | 80 |
1 files changed, 76 insertions, 4 deletions
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 362f70382cdd..2198e615f241 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c | |||
| @@ -519,6 +519,63 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err, | |||
| 519 | } | 519 | } |
| 520 | 520 | ||
| 521 | /** | 521 | /** |
| 522 | * e1000e_update_tail_wa - helper function for e1000e_update_[rt]dt_wa() | ||
| 523 | * @hw: pointer to the HW structure | ||
| 524 | * @tail: address of tail descriptor register | ||
| 525 | * @i: value to write to tail descriptor register | ||
| 526 | * | ||
| 527 | * When updating the tail register, the ME could be accessing Host CSR | ||
| 528 | * registers at the same time. Normally, this is handled in h/w by an | ||
| 529 | * arbiter but on some parts there is a bug that acknowledges Host accesses | ||
| 530 | * later than it should which could result in the descriptor register to | ||
| 531 | * have an incorrect value. Workaround this by checking the FWSM register | ||
| 532 | * which has bit 24 set while ME is accessing Host CSR registers, wait | ||
| 533 | * if it is set and try again a number of times. | ||
| 534 | **/ | ||
| 535 | static inline s32 e1000e_update_tail_wa(struct e1000_hw *hw, u8 __iomem * tail, | ||
| 536 | unsigned int i) | ||
| 537 | { | ||
| 538 | unsigned int j = 0; | ||
| 539 | |||
| 540 | while ((j++ < E1000_ICH_FWSM_PCIM2PCI_COUNT) && | ||
| 541 | (er32(FWSM) & E1000_ICH_FWSM_PCIM2PCI)) | ||
| 542 | udelay(50); | ||
| 543 | |||
| 544 | writel(i, tail); | ||
| 545 | |||
| 546 | if ((j == E1000_ICH_FWSM_PCIM2PCI_COUNT) && (i != readl(tail))) | ||
| 547 | return E1000_ERR_SWFW_SYNC; | ||
| 548 | |||
| 549 | return 0; | ||
| 550 | } | ||
| 551 | |||
| 552 | static void e1000e_update_rdt_wa(struct e1000_adapter *adapter, unsigned int i) | ||
| 553 | { | ||
| 554 | u8 __iomem *tail = (adapter->hw.hw_addr + adapter->rx_ring->tail); | ||
| 555 | struct e1000_hw *hw = &adapter->hw; | ||
| 556 | |||
| 557 | if (e1000e_update_tail_wa(hw, tail, i)) { | ||
| 558 | u32 rctl = er32(RCTL); | ||
| 559 | ew32(RCTL, rctl & ~E1000_RCTL_EN); | ||
| 560 | e_err("ME firmware caused invalid RDT - resetting\n"); | ||
| 561 | schedule_work(&adapter->reset_task); | ||
| 562 | } | ||
| 563 | } | ||
| 564 | |||
| 565 | static void e1000e_update_tdt_wa(struct e1000_adapter *adapter, unsigned int i) | ||
| 566 | { | ||
| 567 | u8 __iomem *tail = (adapter->hw.hw_addr + adapter->tx_ring->tail); | ||
| 568 | struct e1000_hw *hw = &adapter->hw; | ||
| 569 | |||
| 570 | if (e1000e_update_tail_wa(hw, tail, i)) { | ||
| 571 | u32 tctl = er32(TCTL); | ||
| 572 | ew32(TCTL, tctl & ~E1000_TCTL_EN); | ||
| 573 | e_err("ME firmware caused invalid TDT - resetting\n"); | ||
| 574 | schedule_work(&adapter->reset_task); | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | /** | ||
| 522 | * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended | 579 | * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended |
| 523 | * @adapter: address of board private structure | 580 | * @adapter: address of board private structure |
| 524 | **/ | 581 | **/ |
| @@ -573,7 +630,10 @@ map_skb: | |||
| 573 | * such as IA-64). | 630 | * such as IA-64). |
| 574 | */ | 631 | */ |
| 575 | wmb(); | 632 | wmb(); |
| 576 | writel(i, adapter->hw.hw_addr + rx_ring->tail); | 633 | if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) |
| 634 | e1000e_update_rdt_wa(adapter, i); | ||
| 635 | else | ||
| 636 | writel(i, adapter->hw.hw_addr + rx_ring->tail); | ||
| 577 | } | 637 | } |
| 578 | i++; | 638 | i++; |
| 579 | if (i == rx_ring->count) | 639 | if (i == rx_ring->count) |
| @@ -673,7 +733,11 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, | |||
| 673 | * such as IA-64). | 733 | * such as IA-64). |
| 674 | */ | 734 | */ |
| 675 | wmb(); | 735 | wmb(); |
| 676 | writel(i << 1, adapter->hw.hw_addr + rx_ring->tail); | 736 | if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) |
| 737 | e1000e_update_rdt_wa(adapter, i << 1); | ||
| 738 | else | ||
| 739 | writel(i << 1, | ||
| 740 | adapter->hw.hw_addr + rx_ring->tail); | ||
| 677 | } | 741 | } |
| 678 | 742 | ||
| 679 | i++; | 743 | i++; |
| @@ -756,7 +820,10 @@ check_page: | |||
| 756 | * applicable for weak-ordered memory model archs, | 820 | * applicable for weak-ordered memory model archs, |
| 757 | * such as IA-64). */ | 821 | * such as IA-64). */ |
| 758 | wmb(); | 822 | wmb(); |
| 759 | writel(i, adapter->hw.hw_addr + rx_ring->tail); | 823 | if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) |
| 824 | e1000e_update_rdt_wa(adapter, i); | ||
| 825 | else | ||
| 826 | writel(i, adapter->hw.hw_addr + rx_ring->tail); | ||
| 760 | } | 827 | } |
| 761 | } | 828 | } |
| 762 | 829 | ||
| @@ -4689,7 +4756,12 @@ static void e1000_tx_queue(struct e1000_adapter *adapter, | |||
| 4689 | wmb(); | 4756 | wmb(); |
| 4690 | 4757 | ||
| 4691 | tx_ring->next_to_use = i; | 4758 | tx_ring->next_to_use = i; |
| 4692 | writel(i, adapter->hw.hw_addr + tx_ring->tail); | 4759 | |
| 4760 | if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) | ||
| 4761 | e1000e_update_tdt_wa(adapter, i); | ||
| 4762 | else | ||
| 4763 | writel(i, adapter->hw.hw_addr + tx_ring->tail); | ||
| 4764 | |||
| 4693 | /* | 4765 | /* |
| 4694 | * we need this if more than one processor can write to our tail | 4766 | * we need this if more than one processor can write to our tail |
| 4695 | * at a time, it synchronizes IO on IA64/Altix systems | 4767 | * at a time, it synchronizes IO on IA64/Altix systems |
