aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/tg3.c
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@pobox.com>2005-09-24 00:26:49 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-09-24 00:26:49 -0400
commit98ed72deebfd2b55b7e1bb94c8175b1169999212 (patch)
treef1682a68f65e0a38159f55a58c054779d749f8df /drivers/net/tg3.c
parentdbaa9a9d2b37d838125fb7f2b9fdc5dc5fa4eaa9 (diff)
parent87e807b6c461bbd449496a4c3ab78ab164a4ba97 (diff)
Merge /spare/repo/linux-2.6/
Diffstat (limited to 'drivers/net/tg3.c')
-rw-r--r--drivers/net/tg3.c108
1 files changed, 47 insertions, 61 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 7599f52e15b..81f4aedf534 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -67,8 +67,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.39"
-#define DRV_MODULE_RELDATE "September 5, 2005"
+#define DRV_MODULE_VERSION "3.40"
+#define DRV_MODULE_RELDATE "September 15, 2005"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -3442,31 +3442,47 @@ static void tg3_tx_timeout(struct net_device *dev)
schedule_work(&tp->reset_task);
}
+/* Test for DMA buffers crossing any 4GB boundaries: 4G, 8G, etc */
+static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len)
+{
+ u32 base = (u32) mapping & 0xffffffff;
+
+ return ((base > 0xffffdcc0) &&
+ (base + len + 8 < base));
+}
+
static void tg3_set_txd(struct tg3 *, int, dma_addr_t, int, u32, u32);
static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
- u32 guilty_entry, int guilty_len,
- u32 last_plus_one, u32 *start, u32 mss)
+ u32 last_plus_one, u32 *start,
+ u32 base_flags, u32 mss)
{
struct sk_buff *new_skb = skb_copy(skb, GFP_ATOMIC);
- dma_addr_t new_addr;
+ dma_addr_t new_addr = 0;
u32 entry = *start;
- int i;
+ int i, ret = 0;
if (!new_skb) {
- dev_kfree_skb(skb);
- return -1;
+ ret = -1;
+ } else {
+ /* New SKB is guaranteed to be linear. */
+ entry = *start;
+ new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len,
+ PCI_DMA_TODEVICE);
+ /* Make sure new skb does not cross any 4G boundaries.
+ * Drop the packet if it does.
+ */
+ if (tg3_4g_overflow_test(new_addr, new_skb->len)) {
+ ret = -1;
+ dev_kfree_skb(new_skb);
+ new_skb = NULL;
+ } else {
+ tg3_set_txd(tp, entry, new_addr, new_skb->len,
+ base_flags, 1 | (mss << 1));
+ *start = NEXT_TX(entry);
+ }
}
- /* New SKB is guaranteed to be linear. */
- entry = *start;
- new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len,
- PCI_DMA_TODEVICE);
- tg3_set_txd(tp, entry, new_addr, new_skb->len,
- (skb->ip_summed == CHECKSUM_HW) ?
- TXD_FLAG_TCPUDP_CSUM : 0, 1 | (mss << 1));
- *start = NEXT_TX(entry);
-
/* Now clean up the sw ring entries. */
i = 0;
while (entry != last_plus_one) {
@@ -3491,7 +3507,7 @@ static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
dev_kfree_skb(skb);
- return 0;
+ return ret;
}
static void tg3_set_txd(struct tg3 *tp, int entry,
@@ -3517,19 +3533,10 @@ static void tg3_set_txd(struct tg3 *tp, int entry,
txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT;
}
-static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len)
-{
- u32 base = (u32) mapping & 0xffffffff;
-
- return ((base > 0xffffdcc0) &&
- (base + len + 8 < base));
-}
-
static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
dma_addr_t mapping;
- unsigned int i;
u32 len, entry, base_flags, mss;
int would_hit_hwbug;
@@ -3624,7 +3631,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
would_hit_hwbug = 0;
if (tg3_4g_overflow_test(mapping, len))
- would_hit_hwbug = entry + 1;
+ would_hit_hwbug = 1;
tg3_set_txd(tp, entry, mapping, len, base_flags,
(skb_shinfo(skb)->nr_frags == 0) | (mss << 1));
@@ -3648,12 +3655,8 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
tp->tx_buffers[entry].skb = NULL;
pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
- if (tg3_4g_overflow_test(mapping, len)) {
- /* Only one should match. */
- if (would_hit_hwbug)
- BUG();
- would_hit_hwbug = entry + 1;
- }
+ if (tg3_4g_overflow_test(mapping, len))
+ would_hit_hwbug = 1;
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
tg3_set_txd(tp, entry, mapping, len,
@@ -3669,34 +3672,15 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (would_hit_hwbug) {
u32 last_plus_one = entry;
u32 start;
- unsigned int len = 0;
-
- would_hit_hwbug -= 1;
- entry = entry - 1 - skb_shinfo(skb)->nr_frags;
- entry &= (TG3_TX_RING_SIZE - 1);
- start = entry;
- i = 0;
- while (entry != last_plus_one) {
- if (i == 0)
- len = skb_headlen(skb);
- else
- len = skb_shinfo(skb)->frags[i-1].size;
- if (entry == would_hit_hwbug)
- break;
-
- i++;
- entry = NEXT_TX(entry);
-
- }
+ start = entry - 1 - skb_shinfo(skb)->nr_frags;
+ start &= (TG3_TX_RING_SIZE - 1);
/* If the workaround fails due to memory/mapping
* failure, silently drop this packet.
*/
- if (tigon3_4gb_hwbug_workaround(tp, skb,
- entry, len,
- last_plus_one,
- &start, mss))
+ if (tigon3_4gb_hwbug_workaround(tp, skb, last_plus_one,
+ &start, base_flags, mss))
goto out_unlock;
entry = start;
@@ -9271,6 +9255,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
static struct pci_device_id write_reorder_chipsets[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD,
PCI_DEVICE_ID_AMD_FE_GATE_700C) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD,
+ PCI_DEVICE_ID_AMD_K8_NB) },
{ },
};
u32 misc_ctrl_reg;
@@ -9285,7 +9271,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->tg3_flags2 |= TG3_FLG2_SUN_570X;
#endif
- /* If we have an AMD 762 chipset, write
+ /* If we have an AMD 762 or K8 chipset, write
* reordering to the mailbox registers done by the host
* controller can cause major troubles. We read back from
* every mailbox register write to force the writes to be
@@ -9532,7 +9518,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->write32_rx_mbox = tg3_write_indirect_mbox;
iounmap(tp->regs);
- tp->regs = 0;
+ tp->regs = NULL;
pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd);
pci_cmd &= ~PCI_COMMAND_MEMORY;
@@ -10680,7 +10666,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
err_out_iounmap:
if (tp->regs) {
iounmap(tp->regs);
- tp->regs = 0;
+ tp->regs = NULL;
}
err_out_free_dev:
@@ -10705,7 +10691,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
unregister_netdev(dev);
if (tp->regs) {
iounmap(tp->regs);
- tp->regs = 0;
+ tp->regs = NULL;
}
free_netdev(dev);
pci_release_regions(pdev);