tg3: 5701 DMA corruption fix
Herbert Xu's commit fb93134dfc
, entitled
"[TCP]: Fix size calculation in sk_stream_alloc_pskb", has triggered a
bug in the 5701 where the 5701 DMA engine will corrupt outgoing
packets. This problem only happens when the starting address of the
packet matches a certain range of offsets and only when the 5701 is
placed downstream of a particular Intel bridge.
This patch detects the problematic bridge and if present, readjusts the
starting address of the packet data to a dword aligned boundary.
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
36ef408061
commit
41588ba1ae
|
@ -64,8 +64,8 @@
|
|||
|
||||
#define DRV_MODULE_NAME "tg3"
|
||||
#define PFX DRV_MODULE_NAME ": "
|
||||
#define DRV_MODULE_VERSION "3.90"
|
||||
#define DRV_MODULE_RELDATE "April 12, 2008"
|
||||
#define DRV_MODULE_VERSION "3.91"
|
||||
#define DRV_MODULE_RELDATE "April 18, 2008"
|
||||
|
||||
#define TG3_DEF_MAC_MODE 0
|
||||
#define TG3_DEF_RX_MODE 0
|
||||
|
@ -4135,11 +4135,21 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
|
|||
u32 last_plus_one, u32 *start,
|
||||
u32 base_flags, u32 mss)
|
||||
{
|
||||
struct sk_buff *new_skb = skb_copy(skb, GFP_ATOMIC);
|
||||
struct sk_buff *new_skb;
|
||||
dma_addr_t new_addr = 0;
|
||||
u32 entry = *start;
|
||||
int i, ret = 0;
|
||||
|
||||
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
|
||||
new_skb = skb_copy(skb, GFP_ATOMIC);
|
||||
else {
|
||||
int more_headroom = 4 - ((unsigned long)skb->data & 3);
|
||||
|
||||
new_skb = skb_copy_expand(skb,
|
||||
skb_headroom(skb) + more_headroom,
|
||||
skb_tailroom(skb), GFP_ATOMIC);
|
||||
}
|
||||
|
||||
if (!new_skb) {
|
||||
ret = -1;
|
||||
} else {
|
||||
|
@ -4462,7 +4472,9 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
|
|||
|
||||
would_hit_hwbug = 0;
|
||||
|
||||
if (tg3_4g_overflow_test(mapping, len))
|
||||
if (tp->tg3_flags3 & TG3_FLG3_5701_DMA_BUG)
|
||||
would_hit_hwbug = 1;
|
||||
else if (tg3_4g_overflow_test(mapping, len))
|
||||
would_hit_hwbug = 1;
|
||||
|
||||
tg3_set_txd(tp, entry, mapping, len, base_flags,
|
||||
|
@ -11339,6 +11351,38 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
|
|||
}
|
||||
}
|
||||
|
||||
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
|
||||
static struct tg3_dev_id {
|
||||
u32 vendor;
|
||||
u32 device;
|
||||
} bridge_chipsets[] = {
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_0 },
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_1 },
|
||||
{ },
|
||||
};
|
||||
struct tg3_dev_id *pci_id = &bridge_chipsets[0];
|
||||
struct pci_dev *bridge = NULL;
|
||||
|
||||
while (pci_id->vendor != 0) {
|
||||
bridge = pci_get_device(pci_id->vendor,
|
||||
pci_id->device,
|
||||
bridge);
|
||||
if (!bridge) {
|
||||
pci_id++;
|
||||
continue;
|
||||
}
|
||||
if (bridge->subordinate &&
|
||||
(bridge->subordinate->number <=
|
||||
tp->pdev->bus->number) &&
|
||||
(bridge->subordinate->subordinate >=
|
||||
tp->pdev->bus->number)) {
|
||||
tp->tg3_flags3 |= TG3_FLG3_5701_DMA_BUG;
|
||||
pci_dev_put(bridge);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The EPB bridge inside 5714, 5715, and 5780 cannot support
|
||||
* DMA addresses > 40-bit. This bridge may have other additional
|
||||
* 57xx devices behind it in some 4-port NIC designs for example.
|
||||
|
|
|
@ -2476,6 +2476,7 @@ struct tg3 {
|
|||
#define TG3_FLG3_NO_NVRAM_ADDR_TRANS 0x00000001
|
||||
#define TG3_FLG3_ENABLE_APE 0x00000002
|
||||
#define TG3_FLG3_5761_5784_AX_FIXES 0x00000004
|
||||
#define TG3_FLG3_5701_DMA_BUG 0x00000008
|
||||
|
||||
struct timer_list timer;
|
||||
u16 timer_counter;
|
||||
|
|
Loading…
Reference in a new issue