Commit 07fe9727 authored by Jeff Garzik's avatar Jeff Garzik

Merge redhat.com:/spare/repo/linux-2.6

into redhat.com:/spare/repo/netdev-2.6/epic100
parents 196c4ebd e38e1903
...@@ -96,9 +96,9 @@ static int rx_copybreak; ...@@ -96,9 +96,9 @@ static int rx_copybreak;
Making the Tx ring too large decreases the effectiveness of channel Making the Tx ring too large decreases the effectiveness of channel
bonding and packet priority. bonding and packet priority.
There are no ill effects from too-large receive rings. */ There are no ill effects from too-large receive rings. */
#define TX_RING_SIZE 16 #define TX_RING_SIZE 256
#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ #define TX_QUEUE_LEN 240 /* Limit ring entries actually used. */
#define RX_RING_SIZE 32 #define RX_RING_SIZE 256
#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct epic_tx_desc) #define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct epic_tx_desc)
#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct epic_rx_desc) #define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct epic_rx_desc)
...@@ -292,6 +292,12 @@ enum CommandBits { ...@@ -292,6 +292,12 @@ enum CommandBits {
StopTxDMA=0x20, StopRxDMA=0x40, RestartTx=0x80, StopTxDMA=0x20, StopRxDMA=0x40, RestartTx=0x80,
}; };
#define EpicRemoved 0xffffffff /* Chip failed or removed (CardBus) */
#define EpicNapiEvent (TxEmpty | TxDone | \
RxDone | RxStarted | RxEarlyWarn | RxOverflow | RxFull)
#define EpicNormalEvent (0x0000ffff & ~EpicNapiEvent)
static u16 media2miictl[16] = { static u16 media2miictl[16] = {
0, 0x0C00, 0x0C00, 0x2000, 0x0100, 0x2100, 0, 0, 0, 0x0C00, 0x0C00, 0x2000, 0x0100, 0x2100, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 }; 0, 0, 0, 0, 0, 0, 0, 0 };
...@@ -330,9 +336,12 @@ struct epic_private { ...@@ -330,9 +336,12 @@ struct epic_private {
/* Ring pointers. */ /* Ring pointers. */
spinlock_t lock; /* Group with Tx control cache line. */ spinlock_t lock; /* Group with Tx control cache line. */
spinlock_t napi_lock;
unsigned int reschedule_in_poll;
unsigned int cur_tx, dirty_tx; unsigned int cur_tx, dirty_tx;
unsigned int cur_rx, dirty_rx; unsigned int cur_rx, dirty_rx;
u32 irq_mask;
unsigned int rx_buf_sz; /* Based on MTU+slack. */ unsigned int rx_buf_sz; /* Based on MTU+slack. */
struct pci_dev *pci_dev; /* PCI bus location. */ struct pci_dev *pci_dev; /* PCI bus location. */
...@@ -359,7 +368,8 @@ static void epic_timer(unsigned long data); ...@@ -359,7 +368,8 @@ static void epic_timer(unsigned long data);
static void epic_tx_timeout(struct net_device *dev); static void epic_tx_timeout(struct net_device *dev);
static void epic_init_ring(struct net_device *dev); static void epic_init_ring(struct net_device *dev);
static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev); static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int epic_rx(struct net_device *dev); static int epic_rx(struct net_device *dev, int budget);
static int epic_poll(struct net_device *dev, int *budget);
static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static struct ethtool_ops netdev_ethtool_ops; static struct ethtool_ops netdev_ethtool_ops;
...@@ -378,7 +388,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ...@@ -378,7 +388,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
int irq; int irq;
struct net_device *dev; struct net_device *dev;
struct epic_private *ep; struct epic_private *ep;
int i, option = 0, duplex = 0; int i, ret, option = 0, duplex = 0;
void *ring_space; void *ring_space;
dma_addr_t ring_dma; dma_addr_t ring_dma;
...@@ -392,29 +402,33 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ...@@ -392,29 +402,33 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
card_idx++; card_idx++;
i = pci_enable_device(pdev); ret = pci_enable_device(pdev);
if (i) if (ret)
return i; goto out;
irq = pdev->irq; irq = pdev->irq;
if (pci_resource_len(pdev, 0) < pci_id_tbl[chip_idx].io_size) { if (pci_resource_len(pdev, 0) < pci_id_tbl[chip_idx].io_size) {
printk (KERN_ERR "card %d: no PCI region space\n", card_idx); printk (KERN_ERR "card %d: no PCI region space\n", card_idx);
return -ENODEV; ret = -ENODEV;
goto err_out_disable;
} }
pci_set_master(pdev); pci_set_master(pdev);
ret = pci_request_regions(pdev, DRV_NAME);
if (ret < 0)
goto err_out_disable;
ret = -ENOMEM;
dev = alloc_etherdev(sizeof (*ep)); dev = alloc_etherdev(sizeof (*ep));
if (!dev) { if (!dev) {
printk (KERN_ERR "card %d: no memory for eth device\n", card_idx); printk (KERN_ERR "card %d: no memory for eth device\n", card_idx);
return -ENOMEM; goto err_out_free_res;
} }
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev); SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_request_regions(pdev, DRV_NAME))
goto err_out_free_netdev;
#ifdef USE_IO_OPS #ifdef USE_IO_OPS
ioaddr = pci_resource_start (pdev, 0); ioaddr = pci_resource_start (pdev, 0);
#else #else
...@@ -422,7 +436,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ...@@ -422,7 +436,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1)); ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1));
if (!ioaddr) { if (!ioaddr) {
printk (KERN_ERR DRV_NAME " %d: ioremap failed\n", card_idx); printk (KERN_ERR DRV_NAME " %d: ioremap failed\n", card_idx);
goto err_out_free_res; goto err_out_free_netdev;
} }
#endif #endif
...@@ -459,7 +473,9 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ...@@ -459,7 +473,9 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
dev->base_addr = ioaddr; dev->base_addr = ioaddr;
dev->irq = irq; dev->irq = irq;
spin_lock_init (&ep->lock); spin_lock_init(&ep->lock);
spin_lock_init(&ep->napi_lock);
ep->reschedule_in_poll = 0;
/* Bring the chip out of low-power mode. */ /* Bring the chip out of low-power mode. */
outl(0x4200, ioaddr + GENCTL); outl(0x4200, ioaddr + GENCTL);
...@@ -489,6 +505,9 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ...@@ -489,6 +505,9 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
ep->pci_dev = pdev; ep->pci_dev = pdev;
ep->chip_id = chip_idx; ep->chip_id = chip_idx;
ep->chip_flags = pci_id_tbl[chip_idx].drv_flags; ep->chip_flags = pci_id_tbl[chip_idx].drv_flags;
ep->irq_mask =
(ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
| CntFull | TxUnderrun | EpicNapiEvent;
/* Find the connected MII xcvrs. /* Find the connected MII xcvrs.
Doing this in open() would allow detecting external xcvrs later, but Doing this in open() would allow detecting external xcvrs later, but
...@@ -543,10 +562,12 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ...@@ -543,10 +562,12 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
dev->ethtool_ops = &netdev_ethtool_ops; dev->ethtool_ops = &netdev_ethtool_ops;
dev->watchdog_timeo = TX_TIMEOUT; dev->watchdog_timeo = TX_TIMEOUT;
dev->tx_timeout = &epic_tx_timeout; dev->tx_timeout = &epic_tx_timeout;
dev->poll = epic_poll;
dev->weight = 64;
i = register_netdev(dev); ret = register_netdev(dev);
if (i) if (ret < 0)
goto err_out_unmap_tx; goto err_out_unmap_rx;
printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq); dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq);
...@@ -554,19 +575,24 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ...@@ -554,19 +575,24 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x:", dev->dev_addr[i]);
printk("%2.2x.\n", dev->dev_addr[i]); printk("%2.2x.\n", dev->dev_addr[i]);
return 0; out:
return ret;
err_out_unmap_rx:
pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma);
err_out_unmap_tx: err_out_unmap_tx:
pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma); pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma);
err_out_iounmap: err_out_iounmap:
#ifndef USE_IO_OPS #ifndef USE_IO_OPS
iounmap(ioaddr); iounmap(ioaddr);
err_out_free_res:
#endif
pci_release_regions(pdev);
err_out_free_netdev: err_out_free_netdev:
#endif
free_netdev(dev); free_netdev(dev);
return -ENODEV; err_out_free_res:
pci_release_regions(pdev);
err_out_disable:
pci_disable_device(pdev);
goto out;
} }
/* Serial EEPROM section. */ /* Serial EEPROM section. */
...@@ -592,6 +618,36 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ...@@ -592,6 +618,36 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
#define EE_READ256_CMD (6 << 8) #define EE_READ256_CMD (6 << 8)
#define EE_ERASE_CMD (7 << 6) #define EE_ERASE_CMD (7 << 6)
static void epic_disable_int(struct net_device *dev, struct epic_private *ep)
{
long ioaddr = dev->base_addr;
outl(0x00000000, ioaddr + INTMASK);
}
static inline void __epic_pci_commit(long ioaddr)
{
#ifndef USE_IO_OPS
inl(ioaddr + INTMASK);
#endif
}
static void epic_napi_irq_off(struct net_device *dev, struct epic_private *ep)
{
long ioaddr = dev->base_addr;
outl(ep->irq_mask & ~EpicNapiEvent, ioaddr + INTMASK);
__epic_pci_commit(ioaddr);
}
static void epic_napi_irq_on(struct net_device *dev, struct epic_private *ep)
{
long ioaddr = dev->base_addr;
/* No need to commit possible posted write */
outl(ep->irq_mask | EpicNapiEvent, ioaddr + INTMASK);
}
static int __devinit read_eeprom(long ioaddr, int location) static int __devinit read_eeprom(long ioaddr, int location)
{ {
int i; int i;
...@@ -752,9 +808,8 @@ static int epic_open(struct net_device *dev) ...@@ -752,9 +808,8 @@ static int epic_open(struct net_device *dev)
/* Enable interrupts by setting the interrupt mask. */ /* Enable interrupts by setting the interrupt mask. */
outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
| CntFull | TxUnderrun | TxDone | TxEmpty | CntFull | TxUnderrun
| RxError | RxOverflow | RxFull | RxHeader | RxDone, | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK);
ioaddr + INTMASK);
if (debug > 1) if (debug > 1)
printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x " printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x "
...@@ -795,7 +850,7 @@ static void epic_pause(struct net_device *dev) ...@@ -795,7 +850,7 @@ static void epic_pause(struct net_device *dev)
} }
/* Remove the packets on the Rx queue. */ /* Remove the packets on the Rx queue. */
epic_rx(dev); epic_rx(dev, RX_RING_SIZE);
} }
static void epic_restart(struct net_device *dev) static void epic_restart(struct net_device *dev)
...@@ -841,9 +896,9 @@ static void epic_restart(struct net_device *dev) ...@@ -841,9 +896,9 @@ static void epic_restart(struct net_device *dev)
/* Enable interrupts by setting the interrupt mask. */ /* Enable interrupts by setting the interrupt mask. */
outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170) outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
| CntFull | TxUnderrun | TxDone | TxEmpty | CntFull | TxUnderrun
| RxError | RxOverflow | RxFull | RxHeader | RxDone, | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK);
ioaddr + INTMASK);
printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x" printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x"
" interrupt %4.4x.\n", " interrupt %4.4x.\n",
dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL), dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL),
...@@ -929,7 +984,6 @@ static void epic_init_ring(struct net_device *dev) ...@@ -929,7 +984,6 @@ static void epic_init_ring(struct net_device *dev)
int i; int i;
ep->tx_full = 0; ep->tx_full = 0;
ep->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
ep->dirty_tx = ep->cur_tx = 0; ep->dirty_tx = ep->cur_tx = 0;
ep->cur_rx = ep->dirty_rx = 0; ep->cur_rx = ep->dirty_rx = 0;
ep->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); ep->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
...@@ -1029,6 +1083,76 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1029,6 +1083,76 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0; return 0;
} }
static void epic_tx_error(struct net_device *dev, struct epic_private *ep,
int status)
{
struct net_device_stats *stats = &ep->stats;
#ifndef final_version
/* There was an major error, log it. */
if (debug > 1)
printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
dev->name, status);
#endif
stats->tx_errors++;
if (status & 0x1050)
stats->tx_aborted_errors++;
if (status & 0x0008)
stats->tx_carrier_errors++;
if (status & 0x0040)
stats->tx_window_errors++;
if (status & 0x0010)
stats->tx_fifo_errors++;
}
static void epic_tx(struct net_device *dev, struct epic_private *ep)
{
unsigned int dirty_tx, cur_tx;
/*
* Note: if this lock becomes a problem we can narrow the locked
* region at the cost of occasionally grabbing the lock more times.
*/
cur_tx = ep->cur_tx;
for (dirty_tx = ep->dirty_tx; cur_tx - dirty_tx > 0; dirty_tx++) {
struct sk_buff *skb;
int entry = dirty_tx % TX_RING_SIZE;
int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus);
if (txstatus & DescOwn)
break; /* It still hasn't been Txed */
if (likely(txstatus & 0x0001)) {
ep->stats.collisions += (txstatus >> 8) & 15;
ep->stats.tx_packets++;
ep->stats.tx_bytes += ep->tx_skbuff[entry]->len;
} else
epic_tx_error(dev, ep, txstatus);
/* Free the original skb. */
skb = ep->tx_skbuff[entry];
pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr,
skb->len, PCI_DMA_TODEVICE);
dev_kfree_skb_irq(skb);
ep->tx_skbuff[entry] = 0;
}
#ifndef final_version
if (cur_tx - dirty_tx > TX_RING_SIZE) {
printk(KERN_WARNING
"%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
dev->name, dirty_tx, cur_tx, ep->tx_full);
dirty_tx += TX_RING_SIZE;
}
#endif
ep->dirty_tx = dirty_tx;
if (ep->tx_full && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) {
/* The ring is no longer full, allow new TX entries. */
ep->tx_full = 0;
netif_wake_queue(dev);
}
}
/* The interrupt handler does all of the Rx thread work and cleans up /* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */ after the Tx thread. */
static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
...@@ -1042,7 +1166,7 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *r ...@@ -1042,7 +1166,7 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *r
do { do {
status = inl(ioaddr + INTSTAT); status = inl(ioaddr + INTSTAT);
/* Acknowledge all of the current interrupt sources ASAP. */ /* Acknowledge all of the current interrupt sources ASAP. */
outl(status & 0x00007fff, ioaddr + INTSTAT); outl(status & EpicNormalEvent, ioaddr + INTSTAT);
if (debug > 4) if (debug > 4)
printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new " printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new "
...@@ -1053,74 +1177,21 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *r ...@@ -1053,74 +1177,21 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *r
break; break;
handled = 1; handled = 1;
if (status & (RxDone | RxStarted | RxEarlyWarn | RxOverflow)) if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) {
epic_rx(dev); spin_lock(&ep->napi_lock);
if (netif_rx_schedule_prep(dev)) {
if (status & (TxEmpty | TxDone)) { epic_napi_irq_off(dev, ep);
unsigned int dirty_tx, cur_tx; __netif_rx_schedule(dev);
/* Note: if this lock becomes a problem we can narrow the locked
region at the cost of occasionally grabbing the lock more
times. */
spin_lock(&ep->lock);
cur_tx = ep->cur_tx;
dirty_tx = ep->dirty_tx;
for (; cur_tx - dirty_tx > 0; dirty_tx++) {
struct sk_buff *skb;
int entry = dirty_tx % TX_RING_SIZE;
int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus);
if (txstatus & DescOwn)
break; /* It still hasn't been Txed */
if ( ! (txstatus & 0x0001)) {
/* There was an major error, log it. */
#ifndef final_version
if (debug > 1)
printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
dev->name, txstatus);
#endif
ep->stats.tx_errors++;
if (txstatus & 0x1050) ep->stats.tx_aborted_errors++;
if (txstatus & 0x0008) ep->stats.tx_carrier_errors++;
if (txstatus & 0x0040) ep->stats.tx_window_errors++;
if (txstatus & 0x0010) ep->stats.tx_fifo_errors++;
} else {
ep->stats.collisions += (txstatus >> 8) & 15;
ep->stats.tx_packets++;
ep->stats.tx_bytes += ep->tx_skbuff[entry]->len;
}
/* Free the original skb. */
skb = ep->tx_skbuff[entry];
pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr,
skb->len, PCI_DMA_TODEVICE);
dev_kfree_skb_irq(skb);
ep->tx_skbuff[entry] = 0;
}
#ifndef final_version
if (cur_tx - dirty_tx > TX_RING_SIZE) {
printk(KERN_WARNING "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
dev->name, dirty_tx, cur_tx, ep->tx_full);
dirty_tx += TX_RING_SIZE;
}
#endif
ep->dirty_tx = dirty_tx;
if (ep->tx_full
&& cur_tx - dirty_tx < TX_QUEUE_LEN - 4) {
/* The ring is no longer full, allow new TX entries. */
ep->tx_full = 0;
spin_unlock(&ep->lock);
netif_wake_queue(dev);
} else } else
spin_unlock(&ep->lock); ep->reschedule_in_poll++;
spin_unlock(&ep->napi_lock);
} }
status &= ~EpicNapiEvent;
/* Check uncommon events all at once. */ /* Check uncommon events all at once. */
if (status & (CntFull | TxUnderrun | RxOverflow | RxFull | if (status &
PCIBusErr170 | PCIBusErr175)) { (CntFull | TxUnderrun | PCIBusErr170 | PCIBusErr175)) {
if (status == 0xffffffff) /* Chip failed or removed (CardBus). */ if (status == EpicRemoved)
break; break;
/* Always update the error counts to avoid overhead later. */ /* Always update the error counts to avoid overhead later. */
ep->stats.rx_missed_errors += inb(ioaddr + MPCNT); ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);
...@@ -1133,11 +1204,6 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *r ...@@ -1133,11 +1204,6 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *r
/* Restart the transmit process. */ /* Restart the transmit process. */
outl(RestartTx, ioaddr + COMMAND); outl(RestartTx, ioaddr + COMMAND);
} }
if (status & RxOverflow) { /* Missed a Rx frame. */
ep->stats.rx_errors++;
}
if (status & (RxOverflow | RxFull))
outw(RxQueued, ioaddr + COMMAND);
if (status & PCIBusErr170) { if (status & PCIBusErr170) {
printk(KERN_ERR "%s: PCI Bus Error! EPIC status %4.4x.\n", printk(KERN_ERR "%s: PCI Bus Error! EPIC status %4.4x.\n",
dev->name, status); dev->name, status);
...@@ -1147,6 +1213,8 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *r ...@@ -1147,6 +1213,8 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *r
/* Clear all error sources. */ /* Clear all error sources. */
outl(status & 0x7f18, ioaddr + INTSTAT); outl(status & 0x7f18, ioaddr + INTSTAT);
} }
if (!(status & EpicNormalEvent))
break;
if (--boguscnt < 0) { if (--boguscnt < 0) {
printk(KERN_ERR "%s: Too much work at interrupt, " printk(KERN_ERR "%s: Too much work at interrupt, "
"IntrStatus=0x%8.8x.\n", "IntrStatus=0x%8.8x.\n",
...@@ -1164,7 +1232,7 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *r ...@@ -1164,7 +1232,7 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *r
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
} }
static int epic_rx(struct net_device *dev) static int epic_rx(struct net_device *dev, int budget)
{ {
struct epic_private *ep = dev->priv; struct epic_private *ep = dev->priv;
int entry = ep->cur_rx % RX_RING_SIZE; int entry = ep->cur_rx % RX_RING_SIZE;
...@@ -1174,6 +1242,10 @@ static int epic_rx(struct net_device *dev) ...@@ -1174,6 +1242,10 @@ static int epic_rx(struct net_device *dev)
if (debug > 4) if (debug > 4)
printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry, printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry,
ep->rx_ring[entry].rxstatus); ep->rx_ring[entry].rxstatus);
if (rx_work_limit > budget)
rx_work_limit = budget;
/* If we own the next entry, it's a new packet. Send it up. */ /* If we own the next entry, it's a new packet. Send it up. */
while ((ep->rx_ring[entry].rxstatus & cpu_to_le32(DescOwn)) == 0) { while ((ep->rx_ring[entry].rxstatus & cpu_to_le32(DescOwn)) == 0) {
int status = le32_to_cpu(ep->rx_ring[entry].rxstatus); int status = le32_to_cpu(ep->rx_ring[entry].rxstatus);
...@@ -1234,7 +1306,7 @@ static int epic_rx(struct net_device *dev) ...@@ -1234,7 +1306,7 @@ static int epic_rx(struct net_device *dev)
ep->rx_skbuff[entry] = NULL; ep->rx_skbuff[entry] = NULL;
} }
skb->protocol = eth_type_trans(skb, dev); skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb); netif_receive_skb(skb);
dev->last_rx = jiffies; dev->last_rx = jiffies;
ep->stats.rx_packets++; ep->stats.rx_packets++;
ep->stats.rx_bytes += pkt_len; ep->stats.rx_bytes += pkt_len;
...@@ -1262,6 +1334,61 @@ static int epic_rx(struct net_device *dev) ...@@ -1262,6 +1334,61 @@ static int epic_rx(struct net_device *dev)
return work_done; return work_done;
} }
static void epic_rx_err(struct net_device *dev, struct epic_private *ep)
{
long ioaddr = dev->base_addr;
int status;
status = inl(ioaddr + INTSTAT);
if (status == EpicRemoved)
return;
if (status & RxOverflow) /* Missed a Rx frame. */
ep->stats.rx_errors++;
if (status & (RxOverflow | RxFull))
outw(RxQueued, ioaddr + COMMAND);
}
static int epic_poll(struct net_device *dev, int *budget)
{
struct epic_private *ep = dev->priv;
int work_done, orig_budget;
long ioaddr = dev->base_addr;
orig_budget = (*budget > dev->quota) ? dev->quota : *budget;
rx_action:
epic_tx(dev, ep);
work_done = epic_rx(dev, *budget);
epic_rx_err(dev, ep);
*budget -= work_done;
dev->quota -= work_done;
if (netif_running(dev) && (work_done < orig_budget)) {
unsigned long flags;
spin_lock_irqsave(&ep->napi_lock, flags);
if (ep->reschedule_in_poll) {
ep->reschedule_in_poll--;
spin_unlock_irqrestore(&ep->napi_lock, flags);
goto rx_action;
}
outl(EpicNapiEvent, ioaddr + INTSTAT);
epic_napi_irq_on(dev, ep);
__netif_rx_complete(dev);
spin_unlock_irqrestore(&ep->napi_lock, flags);
}
return (work_done >= orig_budget);
}
static int epic_close(struct net_device *dev) static int epic_close(struct net_device *dev)
{ {
long ioaddr = dev->base_addr; long ioaddr = dev->base_addr;
...@@ -1276,9 +1403,13 @@ static int epic_close(struct net_device *dev) ...@@ -1276,9 +1403,13 @@ static int epic_close(struct net_device *dev)
dev->name, (int)inl(ioaddr + INTSTAT)); dev->name, (int)inl(ioaddr + INTSTAT));
del_timer_sync(&ep->timer); del_timer_sync(&ep->timer);
epic_pause(dev);
epic_disable_int(dev, ep);
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
epic_pause(dev);
/* Free all the skbuffs in the Rx queue. */ /* Free all the skbuffs in the Rx queue. */
for (i = 0; i < RX_RING_SIZE; i++) { for (i = 0; i < RX_RING_SIZE; i++) {
skb = ep->rx_skbuff[i]; skb = ep->rx_skbuff[i];
...@@ -1476,6 +1607,7 @@ static void __devexit epic_remove_one (struct pci_dev *pdev) ...@@ -1476,6 +1607,7 @@ static void __devexit epic_remove_one (struct pci_dev *pdev)
#endif #endif
pci_release_regions(pdev); pci_release_regions(pdev);
free_netdev(dev); free_netdev(dev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
/* pci_power_off(pdev, -1); */ /* pci_power_off(pdev, -1); */
} }
......
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