This patch fixes a bug in ns83820.c in conjunction with the pci
dma fix and allows zero copy tx from highmem to function again.
It also removes the cruft from the pre-pci highmem days to bring
the driver into compliance with the pci dma mapping api.
-ben
--
"You will be reincarnated as a toad; and you will be much happier."
:r ~/patches/v2.4/v2.4.19-pre10-ns83820-0.18.diff
diff -urN v2.4.19-pre10/drivers/net/ns83820.c ns83820-v2.4.19-pre10/drivers/net/ns83820.c
--- v2.4.19-pre10/drivers/net/ns83820.c Thu Jun 6 20:10:02 2002
+++ ns83820-v2.4.19-pre10/drivers/net/ns83820.c Mon Jun 10 21:50:27 2002
@@ -1,10 +1,12 @@
-#define _VERSION "0.17"
-/* ns83820.c by Benjamin LaHaise <[email protected]> with contributions.
+#define _VERSION "0.18"
+/* ns83820.c by Benjamin LaHaise with contributions.
*
- * $Revision: 1.34.2.14 $
+ * Questions/comments/discussion to [email protected].
+ *
+ * $Revision: 1.34.2.16 $
*
* Copyright 2001 Benjamin LaHaise.
- * Copyright 2001 Red Hat.
+ * Copyright 2001, 2002 Red Hat.
*
* Mmmm, chocolate vanilla mocha...
*
@@ -53,6 +55,8 @@
* 20011204 0.15 get ppc (big endian) working
* 20011218 0.16 various cleanups
* 20020310 0.17 speedups
+ * 20020610 0.18 - actually use the pci dma api for highmem
+ * - remove pci latency register fiddling
*
* Driver Overview
* ===============
@@ -105,54 +109,16 @@
#undef Dprintk
#define Dprintk dprintk
-#ifdef CONFIG_HIGHMEM64G
-#define USE_64BIT_ADDR "+"
-#elif defined(__ia64__)
+#if defined(CONFIG_HIGHMEM64G) || defined(__ia64__)
#define USE_64BIT_ADDR "+"
#endif
-/* Tell davem to fix the pci dma api. Grrr. */
-/* stolen from acenic.c */
-#if 0 //def CONFIG_HIGHMEM
-#if defined(CONFIG_X86)
-#define DMAADDR_OFFSET 0
-#if defined(CONFIG_HIGHMEM64G)
-typedef u64 dmaaddr_high_t;
-#else
-typedef u32 dmaaddr_high_t;
-#endif
-#elif defined(CONFIG_PPC)
-#define DMAADDR_OFFSET PCI_DRAM_OFFSET
-typedef unsigned long dmaaddr_high_t;
-#endif
-
-static inline dmaaddr_high_t
-pci_map_single_high(struct pci_dev *hwdev, struct page *page,
- int offset, size_t size, int dir)
-{
- u64 phys;
- phys = page - mem_map;
- phys <<= PAGE_SHIFT;
- phys += offset;
- phys += DMAADDR_OFFSET;
- return phys;
-}
-#else
-
-typedef unsigned long dmaaddr_high_t;
-
-static inline dmaaddr_high_t
-pci_map_single_high(struct pci_dev *hwdev, struct page *page,
- int offset, size_t size, int dir)
-{
- return pci_map_single(hwdev, page_address(page) + offset, size, dir);
-}
-#endif
-
#if defined(USE_64BIT_ADDR)
#define VERSION _VERSION USE_64BIT_ADDR
+#define TRY_DAC 1
#else
#define VERSION _VERSION
+#define TRY_DAC 0
#endif
/* tunables */
@@ -384,13 +350,22 @@
} while(0)
#ifdef USE_64BIT_ADDR
-typedef u64 hw_addr_t;
+#define HW_ADDR_LEN 8
+#define desc_addr_set(desc, addr) \
+ do { \
+ u64 __addr = (addr); \
+ desc[BUFPTR] = cpu_to_le32(__addr); \
+ desc[BUFPTR+1] = cpu_to_le32(__addr >> 32); \
+ } while(0)
+#define desc_addr_get(desc) \
+ (((u64)le32_to_cpu(desc[BUFPTR+1]) << 32) \
+ | le32_to_cpu(desc[BUFPTR]))
#else
-typedef u32 hw_addr_t;
+#define HW_ADDR_LEN 4
+#define desc_addr_set(desc, addr) (desc[BUFPTR] = cpu_to_le32(addr))
+#define desc_addr_get(desc) (le32_to_cpu(desc[BUFPTR]))
#endif
-#define HW_ADDR_LEN (sizeof(hw_addr_t))
-
#define LINK 0
#define BUFPTR (LINK + HW_ADDR_LEN/4)
#define CMDSTS (BUFPTR + HW_ADDR_LEN/4)
@@ -402,6 +377,7 @@
#define CMDSTS_INTR 0x20000000
#define CMDSTS_ERR 0x10000000
#define CMDSTS_OK 0x08000000
+#define CMDSTS_LEN_MASK 0x0000ffff
#define CMDSTS_DEST_MASK 0x01800000
#define CMDSTS_DEST_SELF 0x00800000
@@ -515,7 +491,7 @@
unsigned next_empty;
u32 cmdsts;
u32 *sg;
- hw_addr_t buf;
+ dma_addr_t buf;
next_empty = dev->rx_info.next_empty;
@@ -848,7 +824,7 @@
(cmdsts != CMDSTS_OWN)) {
struct sk_buff *skb;
u32 extsts = le32_to_cpu(desc[EXTSTS]);
- dmaaddr_high_t bufptr = le32_to_cpu(desc[BUFPTR]);
+ dma_addr_t bufptr = desc_addr_get(desc);
dprintk("cmdsts: %08x\n", cmdsts);
dprintk("link: %08x\n", cpu_to_le32(desc[LINK]));
@@ -936,6 +912,8 @@
while ((tx_done_idx != dev->tx_free_idx) &&
!(CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[CMDSTS]))) ) {
struct sk_buff *skb;
+ unsigned len;
+ dma_addr_t addr;
if (cmdsts & CMDSTS_ERR)
dev->stats.tx_errors ++;
@@ -949,13 +927,20 @@
skb = dev->tx_skbs[tx_done_idx];
dev->tx_skbs[tx_done_idx] = NULL;
dprintk("done(%p)\n", skb);
+
+ len = cmdsts & CMDSTS_LEN_MASK;
+ addr = desc_addr_get(desc);
if (skb) {
pci_unmap_single(dev->pci_dev,
- le32_to_cpu(desc[BUFPTR]),
- skb->len,
+ addr,
+ len,
PCI_DMA_TODEVICE);
dev_kfree_skb_irq(skb);
- }
+ } else
+ pci_unmap_page(dev->pci_dev,
+ addr,
+ len,
+ PCI_DMA_TODEVICE);
tx_done_idx = (tx_done_idx + 1) % NR_TX_DESC;
dev->tx_done_idx = tx_done_idx;
@@ -1001,7 +986,7 @@
u32 free_idx, cmdsts, extsts;
int nr_free, nr_frags;
unsigned tx_done_idx;
- dmaaddr_high_t buf;
+ dma_addr_t buf;
unsigned len;
skb_frag_t *frag;
int stopped = 0;
@@ -1075,7 +1060,7 @@
(unsigned long long)buf);
free_idx = (free_idx + 1) % NR_TX_DESC;
desc[LINK] = cpu_to_le32(dev->tx_phy_descs + (free_idx * DESC_SIZE * 4));
- desc[BUFPTR] = cpu_to_le32(buf);
+ desc_addr_set(desc, buf);
desc[EXTSTS] = cpu_to_le32(extsts);
cmdsts = ((nr_frags|residue) ? CMDSTS_MORE : do_intr ? CMDSTS_INTR : 0);
@@ -1092,11 +1077,12 @@
if (!nr_frags)
break;
- buf = pci_map_single_high(dev->pci_dev, frag->page,
- frag->page_offset,
- frag->size, PCI_DMA_TODEVICE);
- dprintk("frag: buf=%08Lx page=%08lx\n",
- (long long)buf, (long)(frag->page - mem_map));
+ buf = pci_map_page(dev->pci_dev, frag->page,
+ frag->page_offset,
+ frag->size, PCI_DMA_TODEVICE);
+ printk("frag: buf=%08Lx page=%08lx offset=%08lx\n",
+ (long long)buf, (long)(frag->page - mem_map),
+ frag->page_offset);
len = frag->size;
frag++;
nr_frags--;
@@ -1427,6 +1413,16 @@
struct ns83820 *dev;
long addr;
int err;
+ int using_dac = 0;
+
+ if (TRY_DAC && !pci_set_dma_mask(pci_dev, 0xffffffffffffffff)) {
+ using_dac = 1;
+ } else if (!pci_set_dma_mask(pci_dev, 0xffffffff)) {
+ using_dac = 0;
+ } else {
+ printk(KERN_WARNING "ns83820.c: pci_set_dma_mask failed!\n");
+ return -ENODEV;
+ }
dev = (struct ns83820 *)alloc_etherdev((sizeof *dev) - (sizeof dev->net_dev));
err = -ENOMEM;
@@ -1536,6 +1532,9 @@
#ifdef USE_64BIT_ADDR
dev->CFG_cache |= CFG_M64ADDR;
#endif
+ if (using_dac)
+ dev->CFG_cache |= CFG_T64ADDR;
+
/* Big endian mode does not seem to do what the docs suggest */
dev->CFG_cache &= ~CFG_BEM;
@@ -1561,7 +1560,7 @@
writel(dev->CFG_cache, dev->base + CFG);
dprintk("CFG: %08x\n", dev->CFG_cache);
-#if 1 /* Huh? This sets the PCI latency register. Should be done via
+#if 0 /* Huh? This sets the PCI latency register. Should be done via
* the PCI layer. FIXME.
*/
if (readl(dev->base + SRR))
@@ -1614,13 +1613,12 @@
/* Yes, we support dumb IP checksum on transmit */
dev->net_dev.features |= NETIF_F_SG;
dev->net_dev.features |= NETIF_F_IP_CSUM;
-#if defined(USE_64BIT_ADDR) || defined(CONFIG_HIGHMEM4G)
- if ((dev->CFG_cache & CFG_T64ADDR)) {
+
+ if (using_dac) {
printk(KERN_INFO "%s: using 64 bit addressing.\n",
dev->net_dev.name);
dev->net_dev.features |= NETIF_F_HIGHDMA;
}
-#endif
printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %02x:%02x:%02x:%02x:%02x:%02x io=0x%08lx irq=%d f=%s\n",
dev->net_dev.name,