Commit 0ec7a504 authored by Jeff Garzik's avatar Jeff Garzik

Merge ns83820 GigE net driver changes from 2.4.x kernel:

0.13a - optical transceiver support added
	by Michael Clark <michael@metaparadigm.com>
0.13b - call register_netdev earlier in initialization
	suppress duplicate link status messages
0.15	get ppc (big endian) working

Via Dave Jones.
parent 62402ec8
#define VERSION "0.14" #define _VERSION "0.15"
/* ns83820.c by Benjamin LaHaise <bcrl@redhat.com> /* ns83820.c by Benjamin LaHaise <bcrl@redhat.com> with contributions.
* *
* $Revision: 1.34.2.8 $ * $Revision: 1.34.2.12 $
* *
* Copyright 2001 Benjamin LaHaise. * Copyright 2001 Benjamin LaHaise.
* Copyright 2001 Red Hat. * Copyright 2001 Red Hat.
...@@ -45,7 +45,12 @@ ...@@ -45,7 +45,12 @@
* 0.12 - add statistics counters * 0.12 - add statistics counters
* - add allmulti/promisc support * - add allmulti/promisc support
* 20011009 0.13 - hotplug support, other smaller pci api cleanups * 20011009 0.13 - hotplug support, other smaller pci api cleanups
* 20011204 0.13a - optical transceiver support added
* 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
* 20011204 0.15 get ppc (big endian) working
* *
* Driver Overview * Driver Overview
* =============== * ===============
...@@ -66,6 +71,7 @@ ...@@ -66,6 +71,7 @@
* D-Link DGE-500T * D-Link DGE-500T
* PureData PDP8023Z-TG * PureData PDP8023Z-TG
* SMC SMC9452TX SMC9462TX * SMC SMC9452TX SMC9462TX
* Netgear GA621
* *
* Special thanks to SMC for providing hardware to test this driver on. * Special thanks to SMC for providing hardware to test this driver on.
* *
...@@ -98,14 +104,14 @@ ...@@ -98,14 +104,14 @@
#define Dprintk dprintk #define Dprintk dprintk
#ifdef CONFIG_HIGHMEM64G #ifdef CONFIG_HIGHMEM64G
#define USE_64BIT_ADDR #define USE_64BIT_ADDR "+"
#elif defined(__ia64__) #elif defined(__ia64__)
#define USE_64BIT_ADDR #define USE_64BIT_ADDR "+"
#endif #endif
/* Tell davem to fix the pci dma api. Grrr. */ /* Tell davem to fix the pci dma api. Grrr. */
/* stolen from acenic.c */ /* stolen from acenic.c */
#ifdef CONFIG_HIGHMEM #if 0 //def CONFIG_HIGHMEM
#if defined(CONFIG_X86) #if defined(CONFIG_X86)
#define DMAADDR_OFFSET 0 #define DMAADDR_OFFSET 0
#if defined(CONFIG_HIGHMEM64G) #if defined(CONFIG_HIGHMEM64G)
...@@ -141,6 +147,12 @@ pci_map_single_high(struct pci_dev *hwdev, struct page *page, ...@@ -141,6 +147,12 @@ pci_map_single_high(struct pci_dev *hwdev, struct page *page,
} }
#endif #endif
#if defined(USE_64BIT_ADDR)
#define VERSION _VERSION USE_64BIT_ADDR
#else
#define VERSION _VERSION
#endif
/* tunables */ /* tunables */
#define RX_BUF_SIZE 6144 /* 8192 */ #define RX_BUF_SIZE 6144 /* 8192 */
#define NR_RX_DESC 256 #define NR_RX_DESC 256
...@@ -216,6 +228,7 @@ pci_map_single_high(struct pci_dev *hwdev, struct page *page, ...@@ -216,6 +228,7 @@ pci_map_single_high(struct pci_dev *hwdev, struct page *page,
#define CFG_DUPSTS 0x10000000 #define CFG_DUPSTS 0x10000000
#define CFG_TBI_EN 0x01000000 #define CFG_TBI_EN 0x01000000
#define CFG_MODE_1000 0x00400000 #define CFG_MODE_1000 0x00400000
#define CFG_AUTO_1000 0x00200000
#define CFG_PINT_CTL 0x001c0000 #define CFG_PINT_CTL 0x001c0000
#define CFG_PINT_DUPSTS 0x00100000 #define CFG_PINT_DUPSTS 0x00100000
#define CFG_PINT_LNKSTS 0x00080000 #define CFG_PINT_LNKSTS 0x00080000
...@@ -319,6 +332,36 @@ pci_map_single_high(struct pci_dev *hwdev, struct page *page, ...@@ -319,6 +332,36 @@ pci_map_single_high(struct pci_dev *hwdev, struct page *page,
#define VDR 0xc4 #define VDR 0xc4
#define CCSR 0xcc #define CCSR 0xcc
#define TBICR 0xe0
#define TBISR 0xe4
#define TANAR 0xe8
#define TANLPAR 0xec
#define TANER 0xf0
#define TESR 0xf4
#define TBICR_MR_AN_ENABLE 0x00001000
#define TBICR_MR_RESTART_AN 0x00000200
#define TBISR_MR_LINK_STATUS 0x00000020
#define TBISR_MR_AN_COMPLETE 0x00000004
#define TANAR_PS2 0x00000100
#define TANAR_PS1 0x00000080
#define TANAR_HALF_DUP 0x00000040
#define TANAR_FULL_DUP 0x00000020
#define GPIOR_GP5_OE 0x00000200
#define GPIOR_GP4_OE 0x00000100
#define GPIOR_GP3_OE 0x00000080
#define GPIOR_GP2_OE 0x00000040
#define GPIOR_GP1_OE 0x00000020
#define GPIOR_GP3_OUT 0x00000004
#define GPIOR_GP1_OUT 0x00000001
#define LINK_AUTONEGOTIATE 0x01
#define LINK_DOWN 0x02
#define LINK_UP 0x04
#define __kick_rx(dev) writel(CR_RXE, dev->base + CR) #define __kick_rx(dev) writel(CR_RXE, dev->base + CR)
#define kick_rx(dev) do { \ #define kick_rx(dev) do { \
...@@ -393,6 +436,7 @@ struct ns83820 { ...@@ -393,6 +436,7 @@ struct ns83820 {
u32 IMR_cache; u32 IMR_cache;
struct eeprom ee; struct eeprom ee;
unsigned linkstate;
spinlock_t tx_lock; spinlock_t tx_lock;
...@@ -444,11 +488,11 @@ static inline void build_rx_desc64(struct ns83820 *dev, u32 *desc, u64 link, u64 ...@@ -444,11 +488,11 @@ static inline void build_rx_desc64(struct ns83820 *dev, u32 *desc, u64 link, u64
static inline void build_rx_desc32(struct ns83820 *dev, u32 *desc, u32 link, u32 buf, u32 cmdsts, u32 extsts) static inline void build_rx_desc32(struct ns83820 *dev, u32 *desc, u32 link, u32 buf, u32 cmdsts, u32 extsts)
{ {
desc[0] = link; desc[0] = cpu_to_le32(link);
desc[1] = buf; desc[1] = cpu_to_le32(buf);
desc[3] = extsts; desc[3] = cpu_to_le32(extsts);
mb(); mb();
desc[2] = cmdsts; desc[2] = cpu_to_le32(cmdsts);
} }
#define build_rx_desc build_rx_desc32 #define build_rx_desc build_rx_desc32
...@@ -489,7 +533,7 @@ static inline int ns83820_add_rx_skb(struct ns83820 *dev, struct sk_buff *skb) ...@@ -489,7 +533,7 @@ static inline int ns83820_add_rx_skb(struct ns83820 *dev, struct sk_buff *skb)
build_rx_desc(dev, sg, 0, buf, cmdsts, 0); build_rx_desc(dev, sg, 0, buf, cmdsts, 0);
/* update link of previous rx */ /* update link of previous rx */
if (next_empty != dev->rx_info.next_rx) if (next_empty != dev->rx_info.next_rx)
dev->rx_info.descs[((NR_RX_DESC + next_empty - 1) % NR_RX_DESC) * DESC_SIZE] = dev->rx_info.phy_descs + (next_empty * DESC_SIZE * 4); dev->rx_info.descs[((NR_RX_DESC + next_empty - 1) % NR_RX_DESC) * DESC_SIZE] = cpu_to_le32(dev->rx_info.phy_descs + (next_empty * DESC_SIZE * 4));
return 0; return 0;
} }
...@@ -548,12 +592,59 @@ static inline void clear_rx_desc(struct ns83820 *dev, unsigned i) ...@@ -548,12 +592,59 @@ static inline void clear_rx_desc(struct ns83820 *dev, unsigned i)
static void phy_intr(struct ns83820 *dev) static void phy_intr(struct ns83820 *dev)
{ {
static char *speeds[] = { "10", "100", "1000", "1000(?)" }; static char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" };
u32 cfg, new_cfg; u32 cfg, new_cfg;
u32 tbisr, tanar, tanlpar;
int speed, fullduplex, newlinkstate;
new_cfg = dev->CFG_cache & ~(CFG_SB | CFG_MODE_1000 | CFG_SPDSTS);
cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY; cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
if (dev->CFG_cache & CFG_TBI_EN) {
/* we have an optical transceiver */
tbisr = readl(dev->base + TBISR);
tanar = readl(dev->base + TANAR);
tanlpar = readl(dev->base + TANLPAR);
dprintk("phy_intr: tbisr=%08x, tanar=%08x, tanlpar=%08x\n",
tbisr, tanar, tanlpar);
if ( (fullduplex = (tanlpar & TANAR_FULL_DUP)
&& (tanar & TANAR_FULL_DUP)) ) {
/* both of us are full duplex */
writel(readl(dev->base + TXCFG)
| TXCFG_CSI | TXCFG_HBI | TXCFG_ATP,
dev->base + TXCFG);
writel(readl(dev->base + RXCFG) | RXCFG_RX_FD,
dev->base + RXCFG);
/* Light up full duplex LED */
writel(readl(dev->base + GPIOR) | GPIOR_GP1_OUT,
dev->base + GPIOR);
} else if(((tanlpar & TANAR_HALF_DUP)
&& (tanar & TANAR_HALF_DUP))
|| ((tanlpar & TANAR_FULL_DUP)
&& (tanar & TANAR_HALF_DUP))
|| ((tanlpar & TANAR_HALF_DUP)
&& (tanar & TANAR_FULL_DUP))) {
/* one or both of us are half duplex */
writel((readl(dev->base + TXCFG)
& ~(TXCFG_CSI | TXCFG_HBI)) | TXCFG_ATP,
dev->base + TXCFG);
writel(readl(dev->base + RXCFG) & ~RXCFG_RX_FD,
dev->base + RXCFG);
/* Turn off full duplex LED */
writel(readl(dev->base + GPIOR) & ~GPIOR_GP1_OUT,
dev->base + GPIOR);
}
speed = 4; /* 1000F */
} else {
/* we have a copper transceiver */
new_cfg = dev->CFG_cache & ~(CFG_SB | CFG_MODE_1000 | CFG_SPDSTS);
if (cfg & CFG_SPDSTS1) if (cfg & CFG_SPDSTS1)
new_cfg |= CFG_MODE_1000 | CFG_SB; new_cfg |= CFG_MODE_1000 | CFG_SB;
else else
...@@ -567,20 +658,27 @@ static void phy_intr(struct ns83820 *dev) ...@@ -567,20 +658,27 @@ static void phy_intr(struct ns83820 *dev)
dev->CFG_cache &= ~CFG_SPDSTS; dev->CFG_cache &= ~CFG_SPDSTS;
dev->CFG_cache |= cfg & CFG_SPDSTS; dev->CFG_cache |= cfg & CFG_SPDSTS;
if (cfg & CFG_LNKSTS) { speed = ((cfg / CFG_SPDSTS0) & 3);
netif_start_queue(&dev->net_dev); fullduplex = (cfg & CFG_DUPSTS);
netif_wake_queue(&dev->net_dev);
} else {
netif_stop_queue(&dev->net_dev);
} }
if (cfg & CFG_LNKSTS) newlinkstate = (cfg & CFG_LNKSTS) ? LINK_UP : LINK_DOWN;
if (newlinkstate & LINK_UP
&& dev->linkstate != newlinkstate) {
netif_start_queue(&dev->net_dev);
netif_wake_queue(&dev->net_dev);
printk(KERN_INFO "%s: link now %s mbps, %s duplex and up.\n", printk(KERN_INFO "%s: link now %s mbps, %s duplex and up.\n",
dev->net_dev.name, dev->net_dev.name,
speeds[((cfg / CFG_SPDSTS0) & 3)], speeds[speed],
(cfg & CFG_DUPSTS) ? "full" : "half"); fullduplex ? "full" : "half");
else } else if (newlinkstate & LINK_DOWN
&& dev->linkstate != newlinkstate) {
netif_stop_queue(&dev->net_dev);
printk(KERN_INFO "%s: link now down.\n", dev->net_dev.name); printk(KERN_INFO "%s: link now down.\n", dev->net_dev.name);
}
dev->linkstate = newlinkstate;
} }
static int ns83820_setup_rx(struct ns83820 *dev) static int ns83820_setup_rx(struct ns83820 *dev)
...@@ -701,15 +799,15 @@ static void rx_irq(struct ns83820 *dev) ...@@ -701,15 +799,15 @@ static void rx_irq(struct ns83820 *dev)
dprintk("walking descs\n"); dprintk("walking descs\n");
next_rx = info->next_rx; next_rx = info->next_rx;
desc = info->descs + (DESC_SIZE * next_rx); desc = info->descs + (DESC_SIZE * next_rx);
while ((CMDSTS_OWN & (cmdsts = desc[CMDSTS])) && while ((CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[CMDSTS]))) &&
(cmdsts != CMDSTS_OWN)) { (cmdsts != CMDSTS_OWN)) {
struct sk_buff *skb; struct sk_buff *skb;
u32 extsts = desc[EXTSTS]; u32 extsts = le32_to_cpu(desc[EXTSTS]);
dmaaddr_high_t bufptr = *(hw_addr_t *)(desc + BUFPTR); dmaaddr_high_t bufptr = le32_to_cpu(desc[BUFPTR]);
dprintk("cmdsts: %08x\n", cmdsts); dprintk("cmdsts: %08x\n", cmdsts);
dprintk("link: %08x\n", desc[LINK]); dprintk("link: %08x\n", cpu_to_le32(desc[LINK]));
dprintk("extsts: %08x\n", desc[EXTSTS]); dprintk("extsts: %08x\n", extsts);
skb = info->skbs[next_rx]; skb = info->skbs[next_rx];
info->skbs[next_rx] = NULL; info->skbs[next_rx] = NULL;
...@@ -721,14 +819,14 @@ static void rx_irq(struct ns83820 *dev) ...@@ -721,14 +819,14 @@ static void rx_irq(struct ns83820 *dev)
pci_unmap_single(dev->pci_dev, bufptr, pci_unmap_single(dev->pci_dev, bufptr,
RX_BUF_SIZE, PCI_DMA_FROMDEVICE); RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
if (CMDSTS_OK & cmdsts) { if (CMDSTS_OK & cmdsts) {
#ifndef __i386__ #if 0 //ndef __i386__
struct sk_buff *tmp; struct sk_buff *tmp;
#endif #endif
int len = cmdsts & 0xffff; int len = cmdsts & 0xffff;
if (!skb) if (!skb)
BUG(); BUG();
skb_put(skb, len); skb_put(skb, len);
#ifndef __i386__ /* I hate the network stack sometimes */ #if 0 //ndef __i386__ /* I hate the network stack sometimes */
tmp = __dev_alloc_skb(RX_BUF_SIZE+16, GFP_ATOMIC); tmp = __dev_alloc_skb(RX_BUF_SIZE+16, GFP_ATOMIC);
if (!tmp) if (!tmp)
goto done; goto done;
...@@ -750,7 +848,7 @@ static void rx_irq(struct ns83820 *dev) ...@@ -750,7 +848,7 @@ static void rx_irq(struct ns83820 *dev)
skb->protocol = eth_type_trans(skb, &dev->net_dev); skb->protocol = eth_type_trans(skb, &dev->net_dev);
if (NET_RX_DROP == netif_rx(skb)) if (NET_RX_DROP == netif_rx(skb))
dev->stats.rx_dropped ++; dev->stats.rx_dropped ++;
#ifndef __i386__ #if 0 //ndef __i386__
done:; done:;
#endif #endif
} else { } else {
...@@ -791,9 +889,9 @@ static void do_tx_done(struct ns83820 *dev) ...@@ -791,9 +889,9 @@ static void do_tx_done(struct ns83820 *dev)
desc = dev->tx_descs + (tx_done_idx * DESC_SIZE); desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
dprintk("tx_done_idx=%d free_idx=%d cmdsts=%08x\n", dprintk("tx_done_idx=%d free_idx=%d cmdsts=%08x\n",
tx_done_idx, dev->tx_free_idx, desc[CMDSTS]); tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[CMDSTS]));
while ((tx_done_idx != dev->tx_free_idx) && while ((tx_done_idx != dev->tx_free_idx) &&
!(CMDSTS_OWN & (cmdsts = desc[CMDSTS])) ) { !(CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[CMDSTS]))) ) {
struct sk_buff *skb; struct sk_buff *skb;
if (cmdsts & CMDSTS_ERR) if (cmdsts & CMDSTS_ERR)
...@@ -804,13 +902,13 @@ static void do_tx_done(struct ns83820 *dev) ...@@ -804,13 +902,13 @@ static void do_tx_done(struct ns83820 *dev)
dev->stats.tx_bytes += cmdsts & 0xffff; dev->stats.tx_bytes += cmdsts & 0xffff;
dprintk("tx_done_idx=%d free_idx=%d cmdsts=%08x\n", dprintk("tx_done_idx=%d free_idx=%d cmdsts=%08x\n",
tx_done_idx, dev->tx_free_idx, desc[CMDSTS]); tx_done_idx, dev->tx_free_idx, cmdsts);
skb = dev->tx_skbs[tx_done_idx]; skb = dev->tx_skbs[tx_done_idx];
dev->tx_skbs[tx_done_idx] = NULL; dev->tx_skbs[tx_done_idx] = NULL;
dprintk("done(%p)\n", skb); dprintk("done(%p)\n", skb);
if (skb) { if (skb) {
pci_unmap_single(dev->pci_dev, pci_unmap_single(dev->pci_dev,
*(hw_addr_t *)(desc + BUFPTR), le32_to_cpu(desc[BUFPTR]),
skb->len, skb->len,
PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
dev_kfree_skb_irq(skb); dev_kfree_skb_irq(skb);
...@@ -818,7 +916,7 @@ static void do_tx_done(struct ns83820 *dev) ...@@ -818,7 +916,7 @@ static void do_tx_done(struct ns83820 *dev)
tx_done_idx = (tx_done_idx + 1) % NR_TX_DESC; tx_done_idx = (tx_done_idx + 1) % NR_TX_DESC;
dev->tx_done_idx = tx_done_idx; dev->tx_done_idx = tx_done_idx;
desc[CMDSTS] = 0; desc[CMDSTS] = cpu_to_le32(0);
barrier(); barrier();
desc = dev->tx_descs + (tx_done_idx * DESC_SIZE); desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
} }
...@@ -939,17 +1037,17 @@ static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *_dev) ...@@ -939,17 +1037,17 @@ static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *_dev)
} }
#endif #endif
dprintk("frag[%3u]: %4u @ 0x%x%08Lx\n", free_idx, len, dprintk("frag[%3u]: %4u @ 0x%08Lx\n", free_idx, len,
(unsigned long long)buf); (unsigned long long)buf);
free_idx = (free_idx + 1) % NR_TX_DESC; free_idx = (free_idx + 1) % NR_TX_DESC;
desc[LINK] = dev->tx_phy_descs + (free_idx * DESC_SIZE * 4); desc[LINK] = cpu_to_le32(dev->tx_phy_descs + (free_idx * DESC_SIZE * 4));
*(hw_addr_t *)(desc + BUFPTR) = buf; desc[BUFPTR] = cpu_to_le32(buf);
desc[EXTSTS] = extsts; desc[EXTSTS] = cpu_to_le32(extsts);
cmdsts = ((nr_frags|residue) ? CMDSTS_MORE : do_intr ? CMDSTS_INTR : 0); cmdsts = ((nr_frags|residue) ? CMDSTS_MORE : do_intr ? CMDSTS_INTR : 0);
cmdsts |= (desc == first_desc) ? 0 : CMDSTS_OWN; cmdsts |= (desc == first_desc) ? 0 : CMDSTS_OWN;
cmdsts |= len; cmdsts |= len;
desc[CMDSTS] = cmdsts; desc[CMDSTS] = cpu_to_le32(cmdsts);
if (residue) { if (residue) {
buf += len; buf += len;
...@@ -960,7 +1058,8 @@ static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *_dev) ...@@ -960,7 +1058,8 @@ static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *_dev)
if (!nr_frags) if (!nr_frags)
break; break;
buf = pci_map_single_high(dev->pci_dev, frag->page, 0, buf = pci_map_single_high(dev->pci_dev, frag->page,
frag->page_offset,
frag->size, PCI_DMA_TODEVICE); frag->size, PCI_DMA_TODEVICE);
dprintk("frag: buf=%08Lx page=%08lx\n", dprintk("frag: buf=%08Lx page=%08lx\n",
(long long)buf, (long)(frag->page - mem_map)); (long long)buf, (long)(frag->page - mem_map));
...@@ -970,7 +1069,7 @@ static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *_dev) ...@@ -970,7 +1069,7 @@ static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *_dev)
} }
dprintk("done pkt\n"); dprintk("done pkt\n");
dev->tx_skbs[free_idx] = skb; dev->tx_skbs[free_idx] = skb;
first_desc[CMDSTS] |= CMDSTS_OWN; first_desc[CMDSTS] |= cpu_to_le32(CMDSTS_OWN);
dev->tx_free_idx = free_idx; dev->tx_free_idx = free_idx;
kick_tx(dev); kick_tx(dev);
...@@ -1014,24 +1113,24 @@ static int ns83820_ethtool_ioctl (struct ns83820 *dev, void *useraddr) ...@@ -1014,24 +1113,24 @@ static int ns83820_ethtool_ioctl (struct ns83820 *dev, void *useraddr)
{ {
u32 ethcmd; u32 ethcmd;
if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd))) if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
return -EFAULT; return -EFAULT;
switch (ethcmd) { switch (ethcmd) {
case ETHTOOL_GDRVINFO: case ETHTOOL_GDRVINFO:
{ {
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
strcpy (info.driver, "ns83820"); strcpy(info.driver, "ns83820");
strcpy (info.version, VERSION); strcpy(info.version, VERSION);
strcpy (info.bus_info, dev->pci_dev->slot_name); strcpy(info.bus_info, dev->pci_dev->slot_name);
if (copy_to_user (useraddr, &info, sizeof (info))) if (copy_to_user(useraddr, &info, sizeof (info)))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
/* get link status */ /* get link status */
case ETHTOOL_GLINK: { case ETHTOOL_GLINK: {
struct ethtool_value edata = {ETHTOOL_GLINK}; struct ethtool_value edata = { ETHTOOL_GLINK };
u32 cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY; u32 cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
if (cfg & CFG_LNKSTS) if (cfg & CFG_LNKSTS)
...@@ -1104,10 +1203,14 @@ static void ns83820_irq(int foo, void *data, struct pt_regs *regs) ...@@ -1104,10 +1203,14 @@ static void ns83820_irq(int foo, void *data, struct pt_regs *regs)
Dprintk("BAD\n"); Dprintk("BAD\n");
} }
if (ISR_RXSOVR & isr) if (unlikely(ISR_RXSOVR & isr)) {
Dprintk("overrun\n"); Dprintk("overrun: rxsovr\n");
if (ISR_RXORN & isr) dev->stats.rx_over_errors ++;
Dprintk("overrun\n"); }
if (unlikely(ISR_RXORN & isr)) {
Dprintk("overrun: rxorn\n");
dev->stats.rx_over_errors ++;
}
if ((ISR_RXRCMP & isr) && dev->rx_info.up) if ((ISR_RXRCMP & isr) && dev->rx_info.up)
writel(CR_RXE, dev->base + CR); writel(CR_RXE, dev->base + CR);
...@@ -1206,9 +1309,10 @@ static int ns83820_open(struct net_device *_dev) ...@@ -1206,9 +1309,10 @@ static int ns83820_open(struct net_device *_dev)
memset(dev->tx_descs, 0, 4 * NR_TX_DESC * DESC_SIZE); memset(dev->tx_descs, 0, 4 * NR_TX_DESC * DESC_SIZE);
for (i=0; i<NR_TX_DESC; i++) { for (i=0; i<NR_TX_DESC; i++) {
*(hw_addr_t *)(dev->tx_descs + (i * DESC_SIZE) + LINK) dev->tx_descs[(i * DESC_SIZE) + LINK]
= dev->tx_phy_descs = cpu_to_le32(
+ ((i+1) % NR_TX_DESC) * DESC_SIZE * 4; dev->tx_phy_descs
+ ((i+1) % NR_TX_DESC) * DESC_SIZE * 4);
} }
dev->tx_idx = 0; dev->tx_idx = 0;
...@@ -1246,6 +1350,9 @@ static void ns83820_getmac(struct ns83820 *dev, u8 *mac) ...@@ -1246,6 +1350,9 @@ static void ns83820_getmac(struct ns83820 *dev, u8 *mac)
#if 0 /* I've left this in as an example of how to use eeprom.h */ #if 0 /* I've left this in as an example of how to use eeprom.h */
data = eeprom_readw(&dev->ee, 0xa + 2 - i); data = eeprom_readw(&dev->ee, 0xa + 2 - i);
#else #else
/* Read from the perfect match memory: this is loaded by
* the chip from the EEPROM via the EELOAD self test.
*/
writel(i*2, dev->base + RFCR); writel(i*2, dev->base + RFCR);
data = readl(dev->base + RFDR); data = readl(dev->base + RFDR);
#endif #endif
...@@ -1343,6 +1450,8 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ ...@@ -1343,6 +1450,8 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
goto out_unmap; goto out_unmap;
} }
if(register_netdev(&dev->net_dev)) goto out_unmap;
dev->net_dev.open = ns83820_open; dev->net_dev.open = ns83820_open;
dev->net_dev.stop = ns83820_stop; dev->net_dev.stop = ns83820_stop;
dev->net_dev.hard_start_xmit = ns83820_hard_start_xmit; dev->net_dev.hard_start_xmit = ns83820_hard_start_xmit;
...@@ -1375,12 +1484,15 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ ...@@ -1375,12 +1484,15 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
dev->CFG_cache = readl(dev->base + CFG); dev->CFG_cache = readl(dev->base + CFG);
if ((dev->CFG_cache & CFG_PCI64_DET)) { if ((dev->CFG_cache & CFG_PCI64_DET)) {
printk("%s: enabling 64 bit PCI.\n", dev->net_dev.name); printk("%s: enabling 64 bit PCI addressing.\n",
dev->net_dev.name);
dev->CFG_cache |= CFG_T64ADDR | CFG_DATA64_EN; dev->CFG_cache |= CFG_T64ADDR | CFG_DATA64_EN;
} else { #if defined(USE_64BIT_ADDR)
printk("%s: disabling 64 bit PCI.\n", dev->net_dev.name); dev->net_dev.features |= NETIF_F_HIGHDMA;
#endif
} else
dev->CFG_cache &= ~(CFG_T64ADDR | CFG_DATA64_EN); dev->CFG_cache &= ~(CFG_T64ADDR | CFG_DATA64_EN);
}
dev->CFG_cache &= (CFG_TBI_EN | CFG_MRM_DIS | CFG_MWI_DIS | dev->CFG_cache &= (CFG_TBI_EN | CFG_MRM_DIS | CFG_MWI_DIS |
CFG_T64ADDR | CFG_DATA64_EN | CFG_EXT_125 | CFG_T64ADDR | CFG_DATA64_EN | CFG_EXT_125 |
CFG_M64ADDR); CFG_M64ADDR);
...@@ -1390,15 +1502,28 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ ...@@ -1390,15 +1502,28 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
dev->CFG_cache |= CFG_POW; dev->CFG_cache |= CFG_POW;
#ifdef USE_64BIT_ADDR #ifdef USE_64BIT_ADDR
dev->CFG_cache |= CFG_M64ADDR; dev->CFG_cache |= CFG_M64ADDR;
printk("using 64 bit addressing\n");
#endif #endif
#ifdef __LITTLE_ENDIAN /* Big endian mode does not seem to do what the docs suggest */
dev->CFG_cache &= ~CFG_BEM; dev->CFG_cache &= ~CFG_BEM;
#elif defined(__BIG_ENDIAN)
dev->CFG_cache |= CFG_BEM; /* setup optical transceiver if we have one */
#else if (dev->CFG_cache & CFG_TBI_EN) {
#error This driver only works for big or little endian!!! printk("%s: enabling optical transceiver\n", dev->net_dev.name);
#endif writel(readl(dev->base + GPIOR) | 0x3e8, dev->base + GPIOR);
/* setup auto negotiation feature advertisement */
writel(readl(dev->base + TANAR)
| TANAR_HALF_DUP | TANAR_FULL_DUP,
dev->base + TANAR);
/* start auto negotiation */
writel(TBICR_MR_AN_ENABLE | TBICR_MR_RESTART_AN,
dev->base + TBICR);
writel(TBICR_MR_AN_ENABLE, dev->base + TBICR);
dev->linkstate = LINK_AUTONEGOTIATE;
dev->CFG_cache |= CFG_MODE_1000;
}
writel(dev->CFG_cache, dev->base + CFG); writel(dev->CFG_cache, dev->base + CFG);
dprintk("CFG: %08x\n", dev->CFG_cache); dprintk("CFG: %08x\n", dev->CFG_cache);
...@@ -1454,15 +1579,15 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ ...@@ -1454,15 +1579,15 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
dev->net_dev.features |= NETIF_F_HIGHDMA; dev->net_dev.features |= NETIF_F_HIGHDMA;
#endif #endif
register_netdev(&dev->net_dev); 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",
printk(KERN_INFO "%s: ns83820.c v" VERSION ": DP83820 %02x:%02x:%02x:%02x:%02x:%02x pciaddr=0x%08lx irq=%d rev 0x%x\n",
dev->net_dev.name, dev->net_dev.name,
(unsigned)readl(dev->base + SRR) >> 8,
(unsigned)readl(dev->base + SRR) & 0xff,
dev->net_dev.dev_addr[0], dev->net_dev.dev_addr[1], dev->net_dev.dev_addr[0], dev->net_dev.dev_addr[1],
dev->net_dev.dev_addr[2], dev->net_dev.dev_addr[3], dev->net_dev.dev_addr[2], dev->net_dev.dev_addr[3],
dev->net_dev.dev_addr[4], dev->net_dev.dev_addr[5], dev->net_dev.dev_addr[4], dev->net_dev.dev_addr[5],
addr, pci_dev->irq, addr, pci_dev->irq,
(unsigned)readl(dev->base + SRR) (dev->net_dev.features & NETIF_F_HIGHDMA) ? "sg" : "h,sg"
); );
return 0; return 0;
......
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