Commit 052a883c authored by Jeff Garzik's avatar Jeff Garzik

Merge redhat.com:/spare/repo/netdev-2.6/fealnx

into redhat.com:/spare/repo/net-drivers-2.6
parents bd7b6c43 b173de9e
......@@ -84,6 +84,7 @@ static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/crc32.h>
#include <linux/delay.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
......@@ -233,15 +234,29 @@ enum intr_status_bits {
RxErr = 0x00000002, /* receive error */
};
/* Bits in the NetworkConfig register. */
/* Bits in the NetworkConfig register, W for writing, R for reading */
/* FIXME: some names are invented by me. Marked with (name?) */
/* If you have docs and know bit names, please fix 'em */
enum rx_mode_bits {
RxModeMask = 0xe0,
PROM = 0x80, /* promiscuous mode */
AB = 0x40, /* accept broadcast */
AM = 0x20, /* accept mutlicast */
ARP = 0x08, /* receive runt pkt */
ALP = 0x04, /* receive long pkt */
SEP = 0x02, /* receive error pkt */
CR_W_ENH = 0x02000000, /* enhanced mode (name?) */
CR_W_FD = 0x00100000, /* full duplex */
CR_W_PS10 = 0x00080000, /* 10 mbit */
CR_W_TXEN = 0x00040000, /* tx enable (name?) */
CR_W_PS1000 = 0x00010000, /* 1000 mbit */
/* CR_W_RXBURSTMASK= 0x00000e00, Im unsure about this */
CR_W_RXMODEMASK = 0x000000e0,
CR_W_PROM = 0x00000080, /* promiscuous mode */
CR_W_AB = 0x00000040, /* accept broadcast */
CR_W_AM = 0x00000020, /* accept mutlicast */
CR_W_ARP = 0x00000008, /* receive runt pkt */
CR_W_ALP = 0x00000004, /* receive long pkt */
CR_W_SEP = 0x00000002, /* receive error pkt */
CR_W_RXEN = 0x00000001, /* rx enable (unicast?) (name?) */
CR_R_TXSTOP = 0x04000000, /* tx stopped (name?) */
CR_R_FD = 0x00100000, /* full duplex detected */
CR_R_PS10 = 0x00080000, /* 10 mbit detected */
CR_R_RXSTOP = 0x00008000, /* rx stopped (name?) */
};
/* The Tulip Rx and Tx buffer descriptors. */
......@@ -375,10 +390,7 @@ enum tx_desc_control_bits {
#define LXT1000_Full 0x200
// 89/12/29 add, for phy specific status register, levelone phy, (end)
/* for 3-in-1 case */
#define PS10 0x00080000
#define FD 0x00100000
#define PS1000 0x00010000
/* for 3-in-1 case, BMCRSR register */
#define LinkIsUp2 0x00040000
/* for PHY */
......@@ -400,6 +412,12 @@ struct netdev_private {
/* Media monitoring timer. */
struct timer_list timer;
/* Reset timer */
struct timer_list reset_timer;
int reset_timer_armed;
unsigned long crvalue_sv;
unsigned long imrvalue_sv;
/* Frequently used values: keep some adjacent for cache effect. */
int flags;
struct pci_dev *pci_dev;
......@@ -435,49 +453,44 @@ static int netdev_open(struct net_device *dev);
static void getlinktype(struct net_device *dev);
static void getlinkstatus(struct net_device *dev);
static void netdev_timer(unsigned long data);
static void reset_timer(unsigned long data);
static void tx_timeout(struct net_device *dev);
static void init_ring(struct net_device *dev);
static int start_tx(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
static int netdev_rx(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
static void __set_rx_mode(struct net_device *dev);
static struct net_device_stats *get_stats(struct net_device *dev);
static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static struct ethtool_ops netdev_ethtool_ops;
static int netdev_close(struct net_device *dev);
static void reset_rx_descriptors(struct net_device *dev);
static void reset_tx_descriptors(struct net_device *dev);
void stop_nic_tx(long ioaddr, long crvalue)
static void stop_nic_rx(long ioaddr, long crvalue)
{
writel(crvalue & (~0x40000), ioaddr + TCRRCR);
/* wait for tx stop */
{
int i = 0, delay = 0x1000;
while ((!(readl(ioaddr + TCRRCR) & 0x04000000)) && (i < delay)) {
++i;
}
int delay = 0x1000;
writel(crvalue & ~(CR_W_RXEN), ioaddr + TCRRCR);
while (--delay) {
if ( (readl(ioaddr + TCRRCR) & CR_R_RXSTOP) == CR_R_RXSTOP)
break;
}
}
void stop_nic_rx(long ioaddr, long crvalue)
static void stop_nic_rxtx(long ioaddr, long crvalue)
{
writel(crvalue & (~0x1), ioaddr + TCRRCR);
/* wait for rx stop */
{
int i = 0, delay = 0x1000;
while ((!(readl(ioaddr + TCRRCR) & 0x00008000)) && (i < delay)) {
++i;
}
int delay = 0x1000;
writel(crvalue & ~(CR_W_RXEN+CR_W_TXEN), ioaddr + TCRRCR);
while (--delay) {
if ( (readl(ioaddr + TCRRCR) & (CR_R_RXSTOP+CR_R_TXSTOP))
== (CR_R_RXSTOP+CR_R_TXSTOP) )
break;
}
}
static int __devinit fealnx_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
......@@ -495,7 +508,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
#ifndef MODULE
static int printed_version;
if (!printed_version++)
printk (version);
printk(version);
#endif
card_idx++;
......@@ -622,7 +635,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
np->phys[0] = 32;
/* 89/6/23 add, (begin) */
/* get phy type */
if (readl(dev->base_addr + PHYIDENTIFIER) == MysonPHYID)
if (readl(ioaddr + PHYIDENTIFIER) == MysonPHYID)
np->PHYType = MysonPHY;
else
np->PHYType = OtherPHY;
......@@ -657,7 +670,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
if (np->flags == HAS_MII_XCVR)
mdio_write(dev, np->phys[0], MII_ADVERTISE, ADVERTISE_FULL);
else
writel(ADVERTISE_FULL, dev->base_addr + ANARANLPAR);
writel(ADVERTISE_FULL, ioaddr + ANARANLPAR);
np->mii.force_media = 1;
}
......@@ -669,7 +682,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
dev->set_multicast_list = &set_rx_mode;
dev->do_ioctl = &mii_ioctl;
dev->ethtool_ops = &netdev_ethtool_ops;
dev->tx_timeout = tx_timeout;
dev->tx_timeout = &tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
err = register_netdev(dev);
......@@ -699,6 +712,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
return err;
}
static void __devexit fealnx_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
......@@ -721,42 +735,6 @@ static void __devexit fealnx_remove_one(struct pci_dev *pdev)
printk(KERN_ERR "fealnx: remove for unknown device\n");
}
unsigned int m80x_read_tick(void)
/* function: Reads the Timer tick count register which decrements by 2 from */
/* 65536 to 0 every 1/36.414 of a second. Each 2 decrements of the *//* count represents 838 nsec's. */
/* input : none. */
/* output : none. */
{
unsigned char tmp;
int value;
writeb((char) 0x06, 0x43); // Command 8254 to latch T0's count
// now read the count.
tmp = (unsigned char) readb(0x40);
value = ((int) tmp) << 8;
tmp = (unsigned char) readb(0x40);
value |= (((int) tmp) & 0xff);
return (value);
}
void m80x_delay(unsigned int interval)
/* function: to wait for a specified time. */
/* input : interval ... the specified time. */
/* output : none. */
{
unsigned int interval1, interval2, i = 0;
interval1 = m80x_read_tick(); // get initial value
do {
interval2 = m80x_read_tick();
if (interval1 < interval2)
interval1 = interval2;
++i;
} while (((interval1 - interval2) < (ushort) interval) && (i < 65535));
}
static ulong m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad)
{
......@@ -796,7 +774,7 @@ static ulong m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad
/* high MDC */
miir |= MASK_MIIR_MII_MDC;
writel(miir, miiport);
m80x_delay(30);
udelay(30);
/* next */
mask >>= 1;
......@@ -831,7 +809,7 @@ static int mdio_read(struct net_device *dev, int phyad, int regad)
/* high MDC, and wait */
miir |= MASK_MIIR_MII_MDC;
writel(miir, miiport);
m80x_delay((int) 30);
udelay(30);
/* next */
mask >>= 1;
......@@ -873,8 +851,6 @@ static void mdio_write(struct net_device *dev, int phyad, int regad, int data)
/* low MDC */
miir &= ~MASK_MIIR_MII_MDC;
writel(miir, miiport);
return;
}
......@@ -949,7 +925,7 @@ static int netdev_open(struct net_device *dev)
np->imrvalue = TUNF | CNTOVF | RBU | TI | RI;
if (np->pci_dev->device == 0x891) {
np->bcrvalue |= 0x200; /* set PROG bit */
np->crvalue |= 0x02000000; /* set enhanced bit */
np->crvalue |= CR_W_ENH; /* set enhanced bit */
np->imrvalue |= ETI;
}
writel(np->bcrvalue, ioaddr + BCR);
......@@ -957,7 +933,7 @@ static int netdev_open(struct net_device *dev)
if (dev->if_port == 0)
dev->if_port = np->default_port;
writel(0, dev->base_addr + RXPDR);
writel(0, ioaddr + RXPDR);
// 89/9/1 modify,
// np->crvalue = 0x00e40001; /* tx store and forward, tx/rx enable */
np->crvalue |= 0x00e40001; /* tx store and forward, tx/rx enable */
......@@ -965,7 +941,7 @@ static int netdev_open(struct net_device *dev)
getlinkstatus(dev);
if (np->linkok)
getlinktype(dev);
set_rx_mode(dev);
__set_rx_mode(dev);
netif_start_queue(dev);
......@@ -985,6 +961,11 @@ static int netdev_open(struct net_device *dev)
/* timer handler */
add_timer(&np->timer);
init_timer(&np->reset_timer);
np->reset_timer.data = (unsigned long) dev;
np->reset_timer.function = &reset_timer;
np->reset_timer_armed = 0;
return 0;
}
......@@ -1005,8 +986,7 @@ static void getlinkstatus(struct net_device *dev)
np->linkok = 1;
return;
}
// delay
m80x_delay(100);
udelay(100);
}
} else {
for (i = 0; i < DelayTime; ++i) {
......@@ -1014,8 +994,7 @@ static void getlinkstatus(struct net_device *dev)
np->linkok = 1;
return;
}
// delay
m80x_delay(100);
udelay(100);
}
}
}
......@@ -1026,11 +1005,11 @@ static void getlinktype(struct net_device *dev)
struct netdev_private *np = dev->priv;
if (np->PHYType == MysonPHY) { /* 3-in-1 case */
if (readl(dev->base_addr + TCRRCR) & FD)
if (readl(dev->base_addr + TCRRCR) & CR_R_FD)
np->duplexmode = 2; /* full duplex */
else
np->duplexmode = 1; /* half duplex */
if (readl(dev->base_addr + TCRRCR) & PS10)
if (readl(dev->base_addr + TCRRCR) & CR_R_PS10)
np->line_speed = 1; /* 10M */
else
np->line_speed = 2; /* 100M */
......@@ -1112,19 +1091,18 @@ static void getlinktype(struct net_device *dev)
else
np->line_speed = 1; /* 10M */
}
// chage crvalue
// np->crvalue&=(~PS10)&(~FD);
np->crvalue &= (~PS10) & (~FD) & (~PS1000);
np->crvalue &= (~CR_W_PS10) & (~CR_W_FD) & (~CR_W_PS1000);
if (np->line_speed == 1)
np->crvalue |= PS10;
np->crvalue |= CR_W_PS10;
else if (np->line_speed == 3)
np->crvalue |= PS1000;
np->crvalue |= CR_W_PS1000;
if (np->duplexmode == 2)
np->crvalue |= FD;
np->crvalue |= CR_W_FD;
}
}
/* Take lock before calling this */
static void allocate_rx_buffers(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
......@@ -1134,15 +1112,17 @@ static void allocate_rx_buffers(struct net_device *dev)
struct sk_buff *skb;
skb = dev_alloc_skb(np->rx_buf_sz);
np->lack_rxbuf->skbuff = skb;
if (skb == NULL)
break; /* Better luck next round. */
while (np->lack_rxbuf->skbuff)
np->lack_rxbuf = np->lack_rxbuf->next_desc_logical;
skb->dev = dev; /* Mark as being used by this device. */
np->lack_rxbuf->skbuff = skb;
np->lack_rxbuf->buffer = pci_map_single(np->pci_dev, skb->tail,
np->rx_buf_sz, PCI_DMA_FROMDEVICE);
np->lack_rxbuf = np->lack_rxbuf->next_desc_logical;
np->lack_rxbuf->status = RXOWN;
++np->really_rx_count;
}
}
......@@ -1153,22 +1133,23 @@ static void netdev_timer(unsigned long data)
struct net_device *dev = (struct net_device *) data;
struct netdev_private *np = dev->priv;
long ioaddr = dev->base_addr;
int next_tick = 10 * HZ;
int old_crvalue = np->crvalue;
unsigned int old_linkok = np->linkok;
unsigned long flags;
if (debug)
printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x "
"config %8.8x.\n", dev->name, readl(ioaddr + ISR),
readl(ioaddr + TCRRCR));
spin_lock_irqsave(&np->lock, flags);
if (np->flags == HAS_MII_XCVR) {
getlinkstatus(dev);
if ((old_linkok == 0) && (np->linkok == 1)) { /* we need to detect the media type again */
getlinktype(dev);
if (np->crvalue != old_crvalue) {
stop_nic_tx(ioaddr, np->crvalue);
stop_nic_rx(ioaddr, np->crvalue & (~0x40000));
stop_nic_rxtx(ioaddr, np->crvalue);
writel(np->crvalue, ioaddr + TCRRCR);
}
}
......@@ -1176,69 +1157,120 @@ static void netdev_timer(unsigned long data)
allocate_rx_buffers(dev);
np->timer.expires = RUN_AT(next_tick);
spin_unlock_irqrestore(&np->lock, flags);
np->timer.expires = RUN_AT(10 * HZ);
add_timer(&np->timer);
}
static void tx_timeout(struct net_device *dev)
/* Take lock before calling */
/* Reset chip and disable rx, tx and interrupts */
static void reset_and_disable_rxtx(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
long ioaddr = dev->base_addr;
int i;
printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
" resetting...\n", dev->name, readl(ioaddr + ISR));
{
printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++)
printk(" %8.8x", (unsigned int) np->rx_ring[i].status);
printk("\n" KERN_DEBUG " Tx ring %p: ", np->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++)
printk(" %4.4x", np->tx_ring[i].status);
printk("\n");
}
/* Reinit. Gross */
int delay=51;
/* Reset the chip's Tx and Rx processes. */
stop_nic_tx(ioaddr, 0);
reset_rx_descriptors(dev);
stop_nic_rxtx(ioaddr, 0);
/* Disable interrupts by clearing the interrupt mask. */
writel(0x0000, ioaddr + IMR);
writel(0, ioaddr + IMR);
/* Reset the chip to erase previous misconfiguration. */
writel(0x00000001, ioaddr + BCR);
/* Ueimor: wait for 50 PCI cycles (and flush posted writes btw).
We surely wait too long (address+data phase). Who cares ? */
for (i = 0; i < 50; i++) {
We surely wait too long (address+data phase). Who cares? */
while (--delay) {
readl(ioaddr + BCR);
rmb();
}
}
/* Take lock before calling */
/* Restore chip after reset */
static void enable_rxtx(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
long ioaddr = dev->base_addr;
writel((np->cur_tx - np->tx_ring)*sizeof(struct fealnx_desc) +
np->tx_ring_dma, ioaddr + TXLBA);
writel((np->cur_rx - np->rx_ring)*sizeof(struct fealnx_desc) +
np->rx_ring_dma, ioaddr + RXLBA);
reset_rx_descriptors(dev);
writel(np->tx_ring_dma + ((char*)np->cur_tx - (char*)np->tx_ring),
ioaddr + TXLBA);
writel(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring),
ioaddr + RXLBA);
writel(np->bcrvalue, ioaddr + BCR);
writel(0, dev->base_addr + RXPDR);
set_rx_mode(dev);
writel(0, ioaddr + RXPDR);
__set_rx_mode(dev); /* changes np->crvalue, writes it into TCRRCR */
/* Clear and Enable interrupts by setting the interrupt mask. */
writel(FBE | TUNF | CNTOVF | RBU | TI | RI, ioaddr + ISR);
writel(np->imrvalue, ioaddr + IMR);
writel(0, dev->base_addr + TXPDR);
writel(0, ioaddr + TXPDR);
}
static void reset_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
struct netdev_private *np = dev->priv;
unsigned long flags;
printk(KERN_WARNING "%s: resetting tx and rx machinery\n", dev->name);
spin_lock_irqsave(&np->lock, flags);
np->crvalue = np->crvalue_sv;
np->imrvalue = np->imrvalue_sv;
reset_and_disable_rxtx(dev);
/* works for me without this:
reset_tx_descriptors(dev); */
enable_rxtx(dev);
netif_start_queue(dev); /* FIXME: or netif_wake_queue(dev); ? */
np->reset_timer_armed = 0;
spin_unlock_irqrestore(&np->lock, flags);
}
static void tx_timeout(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
long ioaddr = dev->base_addr;
unsigned long flags;
int i;
printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
" resetting...\n", dev->name, readl(ioaddr + ISR));
{
printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++)
printk(" %8.8x", (unsigned int) np->rx_ring[i].status);
printk("\n" KERN_DEBUG " Tx ring %p: ", np->tx_ring);
for (i = 0; i < TX_RING_SIZE; i++)
printk(" %4.4x", np->tx_ring[i].status);
printk("\n");
}
spin_lock_irqsave(&np->lock, flags);
reset_and_disable_rxtx(dev);
reset_tx_descriptors(dev);
enable_rxtx(dev);
spin_unlock_irqrestore(&np->lock, flags);
dev->trans_start = jiffies;
np->stats.tx_errors++;
return;
netif_wake_queue(dev); /* or .._start_.. ?? */
}
......@@ -1251,7 +1283,7 @@ static void init_ring(struct net_device *dev)
/* initialize rx variables */
np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
np->cur_rx = &np->rx_ring[0];
np->lack_rxbuf = NULL;
np->lack_rxbuf = np->rx_ring;
np->really_rx_count = 0;
/* initial rx descriptors. */
......@@ -1294,6 +1326,7 @@ static void init_ring(struct net_device *dev)
for (i = 0; i < TX_RING_SIZE; i++) {
np->tx_ring[i].status = 0;
/* do we need np->tx_ring[i].control = XXX; ?? */
np->tx_ring[i].next_desc = np->tx_ring_dma +
(i + 1)*sizeof(struct fealnx_desc);
np->tx_ring[i].next_desc_logical = &np->tx_ring[i + 1];
......@@ -1341,7 +1374,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
np->cur_tx_copy->control |= (BPT << TBSShift); /* buffer size */
/* for the last descriptor */
next = (struct fealnx *) np->cur_tx_copy.next_desc_logical;
next = np->cur_tx_copy->next_desc_logical;
next->skbuff = skb;
next->control = TXIC | TXLD | CRCEnable | PADEnable;
next->control |= (skb->len << PKTSShift); /* pkt size */
......@@ -1383,35 +1416,59 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
}
void free_one_rx_descriptor(struct netdev_private *np)
/* Take lock before calling */
/* Chip probably hosed tx ring. Clean up. */
static void reset_tx_descriptors(struct net_device *dev)
{
if (np->really_rx_count == RX_RING_SIZE)
np->cur_rx->status = RXOWN;
else {
np->lack_rxbuf->skbuff = np->cur_rx->skbuff;
np->lack_rxbuf->buffer = np->cur_rx->buffer;
np->lack_rxbuf->status = RXOWN;
++np->really_rx_count;
np->lack_rxbuf = np->lack_rxbuf->next_desc_logical;
struct netdev_private *np = dev->priv;
struct fealnx_desc *cur;
int i;
/* initialize tx variables */
np->cur_tx = &np->tx_ring[0];
np->cur_tx_copy = &np->tx_ring[0];
np->really_tx_count = 0;
np->free_tx_count = TX_RING_SIZE;
for (i = 0; i < TX_RING_SIZE; i++) {
cur = &np->tx_ring[i];
if (cur->skbuff) {
pci_unmap_single(np->pci_dev, cur->buffer,
cur->skbuff->len, PCI_DMA_TODEVICE);
dev_kfree_skb(cur->skbuff);
/* or dev_kfree_skb_irq(cur->skbuff); ? */
cur->skbuff = NULL;
}
cur->status = 0;
cur->control = 0; /* needed? */
/* probably not needed. We do it for purely paranoid reasons */
cur->next_desc = np->tx_ring_dma +
(i + 1)*sizeof(struct fealnx_desc);
cur->next_desc_logical = &np->tx_ring[i + 1];
}
np->cur_rx = np->cur_rx->next_desc_logical;
/* for the last tx descriptor */
np->tx_ring[TX_RING_SIZE - 1].next_desc = np->tx_ring_dma;
np->tx_ring[TX_RING_SIZE - 1].next_desc_logical = &np->tx_ring[0];
}
void reset_rx_descriptors(struct net_device *dev)
/* Take lock and stop rx before calling this */
static void reset_rx_descriptors(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
stop_nic_rx(dev->base_addr, np->crvalue);
while (!(np->cur_rx->status & RXOWN))
free_one_rx_descriptor(np);
struct fealnx_desc *cur = np->cur_rx;
int i;
allocate_rx_buffers(dev);
writel(np->rx_ring_dma + (np->cur_rx - np->rx_ring),
for (i = 0; i < RX_RING_SIZE; i++) {
if (cur->skbuff)
cur->status = RXOWN;
cur = cur->next_desc_logical;
}
writel(np->rx_ring_dma + ((char*)np->cur_rx - (char*)np->rx_ring),
dev->base_addr + RXLBA);
writel(np->crvalue, dev->base_addr + TCRRCR);
}
......@@ -1421,16 +1478,14 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
{
struct net_device *dev = (struct net_device *) dev_instance;
struct netdev_private *np = dev->priv;
long ioaddr, boguscnt = max_interrupt_work;
long ioaddr = dev->base_addr;
long boguscnt = max_interrupt_work;
unsigned int num_tx = 0;
int handled = 0;
spin_lock(&np->lock);
writel(0, dev->base_addr + IMR);
ioaddr = dev->base_addr;
np = dev->priv;
writel(0, ioaddr + IMR);
do {
u32 intr_status = readl(ioaddr + ISR);
......@@ -1471,8 +1526,11 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
if (intr_status & (RI | RBU)) {
if (intr_status & RI)
netdev_rx(dev);
else
else {
stop_nic_rx(ioaddr, np->crvalue);
reset_rx_descriptors(dev);
writel(np->crvalue, ioaddr + TCRRCR);
}
}
while (np->really_tx_count) {
......@@ -1490,7 +1548,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
if (tx_status & TXOWN)
break;
if (!(np->crvalue & 0x02000000)) {
if (!(np->crvalue & CR_W_ENH)) {
if (tx_status & (CSL | LC | EC | UDF | HF)) {
np->stats.tx_errors++;
if (tx_status & EC)
......@@ -1539,7 +1597,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
netif_wake_queue(dev);
/* read transmit status for enhanced mode only */
if (np->crvalue & 0x02000000) {
if (np->crvalue & CR_W_ENH) {
long data;
data = readl(ioaddr + TSR);
......@@ -1552,6 +1610,20 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
if (--boguscnt < 0) {
printk(KERN_WARNING "%s: Too much work at interrupt, "
"status=0x%4.4x.\n", dev->name, intr_status);
if (!np->reset_timer_armed) {
np->reset_timer_armed = 1;
np->reset_timer.expires = RUN_AT(HZ/2);
add_timer(&np->reset_timer);
stop_nic_rxtx(ioaddr, 0);
netif_stop_queue(dev);
/* or netif_tx_disable(dev); ?? */
/* Prevent other paths from enabling tx,rx,intrs */
np->crvalue_sv = np->crvalue;
np->imrvalue_sv = np->imrvalue;
np->crvalue &= ~(CR_W_TXEN | CR_W_RXEN); /* or simply = 0? */
np->imrvalue = 0;
}
break;
}
} while (1);
......@@ -1580,9 +1652,10 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
static int netdev_rx(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
long ioaddr = dev->base_addr;
/* If EOP is set on the next entry, it's a new packet. Send it up. */
while (!(np->cur_rx->status & RXOWN)) {
while (!(np->cur_rx->status & RXOWN) && np->cur_rx->skbuff) {
s32 rx_status = np->cur_rx->status;
if (np->really_rx_count == 0)
......@@ -1634,11 +1707,20 @@ static int netdev_rx(struct net_device *dev)
np->stats.rx_length_errors++;
/* free all rx descriptors related this long pkt */
for (i = 0; i < desno; ++i)
free_one_rx_descriptor(np);
for (i = 0; i < desno; ++i) {
if (!np->cur_rx->skbuff) {
printk(KERN_DEBUG
"%s: I'm scared\n", dev->name);
break;
}
np->cur_rx->status = RXOWN;
np->cur_rx = np->cur_rx->next_desc_logical;
}
continue;
} else { /* something error, need to reset this chip */
} else { /* rx error, need to reset this chip */
stop_nic_rx(ioaddr, np->crvalue);
reset_rx_descriptors(dev);
writel(np->crvalue, ioaddr + TCRRCR);
}
break; /* exit the while loop */
}
......@@ -1685,8 +1767,6 @@ static int netdev_rx(struct net_device *dev)
PCI_DMA_FROMDEVICE);
skb_put(skb = np->cur_rx->skbuff, pkt_len);
np->cur_rx->skbuff = NULL;
if (np->really_rx_count == RX_RING_SIZE)
np->lack_rxbuf = np->cur_rx;
--np->really_rx_count;
}
skb->protocol = eth_type_trans(skb, dev);
......@@ -1696,24 +1776,7 @@ static int netdev_rx(struct net_device *dev)
np->stats.rx_bytes += pkt_len;
}
if (np->cur_rx->skbuff == NULL) {
struct sk_buff *skb;
skb = dev_alloc_skb(np->rx_buf_sz);
if (skb != NULL) {
skb->dev = dev; /* Mark as being used by this device. */
np->cur_rx->buffer = pci_map_single(np->pci_dev,
skb->tail,
np->rx_buf_sz,
PCI_DMA_FROMDEVICE);
np->cur_rx->skbuff = skb;
++np->really_rx_count;
}
}
if (np->cur_rx->skbuff != NULL)
free_one_rx_descriptor(np);
np->cur_rx = np->cur_rx->next_desc_logical;
} /* end of while loop */
/* allocate skb for rx buffers */
......@@ -1737,7 +1800,20 @@ static struct net_device_stats *get_stats(struct net_device *dev)
return &np->stats;
}
/* for dev->set_multicast_list */
static void set_rx_mode(struct net_device *dev)
{
spinlock_t *lp = &((struct netdev_private *)dev->priv)->lock;
unsigned long flags;
spin_lock_irqsave(lp, flags);
__set_rx_mode(dev);
spin_unlock_irqrestore(&lp, flags);
}
/* Take lock before calling */
static void __set_rx_mode(struct net_device *dev)
{
struct netdev_private *np = dev->priv;
long ioaddr = dev->base_addr;
......@@ -1748,12 +1824,12 @@ static void set_rx_mode(struct net_device *dev)
/* Unconditionally log net taps. */
printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
memset(mc_filter, 0xff, sizeof(mc_filter));
rx_mode = PROM | AB | AM;
rx_mode = CR_W_PROM | CR_W_AB | CR_W_AM;
} else if ((dev->mc_count > multicast_filter_limit)
|| (dev->flags & IFF_ALLMULTI)) {
/* Too many to match, or accept all multicasts. */
memset(mc_filter, 0xff, sizeof(mc_filter));
rx_mode = AB | AM;
rx_mode = CR_W_AB | CR_W_AM;
} else {
struct dev_mc_list *mclist;
int i;
......@@ -1765,26 +1841,25 @@ static void set_rx_mode(struct net_device *dev)
bit = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F;
mc_filter[bit >> 5] |= (1 << bit);
}
rx_mode = AB | AM;
rx_mode = CR_W_AB | CR_W_AM;
}
stop_nic_tx(ioaddr, np->crvalue);
stop_nic_rx(ioaddr, np->crvalue & (~0x40000));
stop_nic_rxtx(ioaddr, np->crvalue);
writel(mc_filter[0], ioaddr + MAR0);
writel(mc_filter[1], ioaddr + MAR1);
np->crvalue &= ~RxModeMask;
np->crvalue &= ~CR_W_RXMODEMASK;
np->crvalue |= rx_mode;
writel(np->crvalue, ioaddr + TCRRCR);
}
static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct netdev_private *np = dev->priv;
strcpy (info->driver, DRV_NAME);
strcpy (info->version, DRV_VERSION);
strcpy (info->bus_info, pci_name(np->pci_dev));
strcpy(info->driver, DRV_NAME);
strcpy(info->version, DRV_VERSION);
strcpy(info->bus_info, pci_name(np->pci_dev));
}
static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
......@@ -1874,10 +1949,10 @@ static int netdev_close(struct net_device *dev)
writel(0x0000, ioaddr + IMR);
/* Stop the chip's Tx and Rx processes. */
stop_nic_tx(ioaddr, 0);
stop_nic_rx(ioaddr, 0);
stop_nic_rxtx(ioaddr, 0);
del_timer_sync(&np->timer);
del_timer_sync(&np->reset_timer);
free_irq(dev->irq, dev);
......@@ -1928,7 +2003,7 @@ static int __init fealnx_init(void)
{
/* when a module, this is printed whether or not devices are found in probe */
#ifdef MODULE
printk (version);
printk(version);
#endif
return pci_module_init(&fealnx_driver);
......
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