>> From: David Mosberger <davidm@napali.hpl.hp.com> Date: Sat, 7
>> Jun 2003 00:05:06 -0700
>> Isn't the proper fix to (a) get a new buffer, (b) create a
>> mapping for the new buffer, (c) destroy the mapping for the old
>> buffer. That should guarantee a different bus address, no matter
>> what the DMA-mapping implementation.
> I suppose this would work, fell free to code this up for the tg3
> driver for me because I certainly lack the time to do this.
How about the attached patch?
The non-PCI_DMA_BUS_IS_PHYS code should work already, because it
creates the new mapping before destroying the old one(s).
The patch has been compiled-tested but not runtime-tested: I can't
trigger the bug on ia64, because there, the end of the 4GB space is
reserved for firmware purposes, so we'll never have available memory
near address 0xffffdcc0.
The performance impact should be negligible, as the probability of
hitting the bug case should be vanishingly small.
--david
===== drivers/net/tg3.c 1.68 vs edited =====
--- 1.68/drivers/net/tg3.c Wed Apr 23 20:02:11 2003
+++ edited/drivers/net/tg3.c Tue Jun 10 12:53:15 2003
@@ -2234,73 +2234,17 @@
schedule_work(&tp->reset_task);
}
-#if !PCI_DMA_BUS_IS_PHYS
-static void tg3_set_txd_addr(struct tg3 *tp, int entry, dma_addr_t mapping)
-{
- if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
- struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry];
-
- txd->addr_hi = ((u64) mapping >> 32);
- txd->addr_lo = ((u64) mapping & 0xffffffff);
- } else {
- unsigned long txd;
-
- txd = (tp->regs +
- NIC_SRAM_WIN_BASE +
- NIC_SRAM_TX_BUFFER_DESC);
- txd += (entry * TXD_SIZE);
-
- if (sizeof(dma_addr_t) != sizeof(u32))
- writel(((u64) mapping >> 32),
- txd + TXD_ADDR + TG3_64BIT_REG_HIGH);
-
- writel(((u64) mapping & 0xffffffff),
- txd + TXD_ADDR + TG3_64BIT_REG_LOW);
- }
-}
-#endif
-
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)
{
+ struct sk_buff *new_skb = skb_copy(skb, GFP_ATOMIC);
dma_addr_t new_addr;
u32 entry = *start;
int i;
-#if !PCI_DMA_BUS_IS_PHYS
- /* IOMMU, just map the guilty area again which is guaranteed to
- * use different addresses.
- */
-
- i = 0;
- while (entry != guilty_entry) {
- entry = NEXT_TX(entry);
- i++;
- }
- if (i == 0) {
- new_addr = pci_map_single(tp->pdev, skb->data, guilty_len,
- PCI_DMA_TODEVICE);
- } else {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1];
-
- new_addr = pci_map_page(tp->pdev,
- frag->page, frag->page_offset,
- guilty_len, PCI_DMA_TODEVICE);
- }
- pci_unmap_single(tp->pdev, pci_unmap_addr(&tp->tx_buffers[guilty_entry],
- mapping),
- guilty_len, PCI_DMA_TODEVICE);
- tg3_set_txd_addr(tp, guilty_entry, new_addr);
- pci_unmap_addr_set(&tp->tx_buffers[guilty_entry], mapping,
- new_addr);
- *start = last_plus_one;
-#else
- /* Oh well, no IOMMU, have to allocate a whole new SKB. */
- struct sk_buff *new_skb = skb_copy(skb, GFP_ATOMIC);
-
if (!new_skb) {
dev_kfree_skb(skb);
return -1;
@@ -2337,7 +2281,6 @@
}
dev_kfree_skb(skb);
-#endif
return 0;
}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/