Commit 84ce7c18 authored by Benjamin LaHaise's avatar Benjamin LaHaise

[PATCH] ns83820.c update to 0.18

This patch fixes a highmem issue with ns83820.c when used with the
pci dma fix for x86.  The patch was successfully tested on a highmem
machine with 5GB of ram and a file in high memory.  Cruft from the
pre-64 bit pci dma era is also removed.
parent 726f11b1
#define _VERSION "0.17"
/* ns83820.c by Benjamin LaHaise <bcrl@redhat.com> with contributions.
#define _VERSION "0.18"
/* ns83820.c by Benjamin LaHaise with contributions.
*
* $Revision: 1.34.2.14 $
* Questions/comments/discussion to linux-ns83820@kvack.org.
*
* $Revision: 1.34.2.16 $
*
* Copyright 2001 Benjamin LaHaise.
* Copyright 2001 Red Hat.
* Copyright 2001, 2002 Red Hat.
*
* Mmmm, chocolate vanilla mocha...
*
......@@ -49,10 +51,12 @@
* by Michael Clark <michael@metaparadigm.com>
* 20011205 0.13b - call register_netdev earlier in initialization
* suppress duplicate link status messages
* 20011117 0.14 - ethtool GDRVINFO, GLINK support
* 20011117 0.14 - ethtool GDRVINFO, GLINK support from jgarzik
* 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 @@ pci_map_single_high(struct pci_dev *hwdev, struct page *page,
} 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 @@ typedef u32 hw_addr_t;
#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 @@ static inline int ns83820_add_rx_skb(struct ns83820 *dev, struct sk_buff *skb)
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 @@ static void rx_irq(struct ns83820 *dev)
(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 @@ static void do_tx_done(struct ns83820 *dev)
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 @@ static void do_tx_done(struct ns83820 *dev)
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 @@ static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *_dev)
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 @@ static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *_dev)
(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 @@ static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *_dev)
if (!nr_frags)
break;
buf = pci_map_single_high(dev->pci_dev, frag->page,
buf = pci_map_page(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));
dprintk("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 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
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 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
#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 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
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 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
/* 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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment