Commit 04dac2e1 authored by Jeff Garzik's avatar Jeff Garzik

Cleanup and fixes to sleeping/scheduling in the olympic token ring

net driver.  Also included are a couple of minor error reporting
updates and the proper detection for cardbus removal.

Contributor:
Mike Phillips
Linux Token Ring Project
parent b2f8ccd8
...@@ -51,9 +51,15 @@ ...@@ -51,9 +51,15 @@
* *
* 06/02/01 - Clean up, copy skb for small packets * 06/02/01 - Clean up, copy skb for small packets
* *
* 06/22/01 - Add EISR error handling routines
*
* 07/19/01 - Improve bad LAA reporting, strip out freemem
* into a separate function, its called from 3
* different places now.
* 02/09/01 - Replaced sleep_on.
*
* To Do: * To Do:
* *
* Complete full Cardbus / hot-swap support.
* Wake on lan * Wake on lan
* *
* If Problems do Occur * If Problems do Occur
...@@ -105,7 +111,7 @@ ...@@ -105,7 +111,7 @@
*/ */
static char version[] __devinitdata = static char version[] __devinitdata =
"Olympic.c v0.9.7 6/02/01 - Peter De Schrijver & Mike Phillips" ; "Olympic.c v1.0.0 2/9/02 - Peter De Schrijver & Mike Phillips" ;
static char *open_maj_error[] = {"No error", "Lobe Media Test", "Physical Insertion", static char *open_maj_error[] = {"No error", "Lobe Media Test", "Physical Insertion",
"Address Verification", "Neighbor Notification (Ring Poll)", "Address Verification", "Neighbor Notification (Ring Poll)",
...@@ -172,6 +178,7 @@ static int olympic_open(struct net_device *dev); ...@@ -172,6 +178,7 @@ static int olympic_open(struct net_device *dev);
static int olympic_xmit(struct sk_buff *skb, struct net_device *dev); static int olympic_xmit(struct sk_buff *skb, struct net_device *dev);
static int olympic_close(struct net_device *dev); static int olympic_close(struct net_device *dev);
static void olympic_set_rx_mode(struct net_device *dev); static void olympic_set_rx_mode(struct net_device *dev);
static void olympic_freemem(struct net_device *dev) ;
static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static struct net_device_stats * olympic_get_stats(struct net_device *dev); static struct net_device_stats * olympic_get_stats(struct net_device *dev);
static int olympic_set_mac_address(struct net_device *dev, void *addr) ; static int olympic_set_mac_address(struct net_device *dev, void *addr) ;
...@@ -396,6 +403,8 @@ static int olympic_open(struct net_device *dev) ...@@ -396,6 +403,8 @@ static int olympic_open(struct net_device *dev)
char open_error[255] ; char open_error[255] ;
int i, open_finished = 1 ; int i, open_finished = 1 ;
DECLARE_WAITQUEUE(wait,current) ;
if(request_irq(dev->irq, &olympic_interrupt, SA_SHIRQ , "olympic", dev)) { if(request_irq(dev->irq, &olympic_interrupt, SA_SHIRQ , "olympic", dev)) {
return -EAGAIN; return -EAGAIN;
} }
...@@ -442,7 +451,11 @@ static int olympic_open(struct net_device *dev) ...@@ -442,7 +451,11 @@ static int olympic_open(struct net_device *dev)
else else
writew(swab16(OPEN_ADAPTER_ENABLE_FDX), init_srb+8); writew(swab16(OPEN_ADAPTER_ENABLE_FDX), init_srb+8);
if (olympic_priv->olympic_laa[0]) { /* Test OR of first 3 bytes as its totally possible for
* someone to set the first 2 bytes to be zero, although this
* is an error, the first byte must have bit 6 set to 1 */
if (olympic_priv->olympic_laa[0] | olympic_priv->olympic_laa[1] | olympic_priv->olympic_laa[2]) {
writeb(olympic_priv->olympic_laa[0],init_srb+12); writeb(olympic_priv->olympic_laa[0],init_srb+12);
writeb(olympic_priv->olympic_laa[1],init_srb+13); writeb(olympic_priv->olympic_laa[1],init_srb+13);
writeb(olympic_priv->olympic_laa[2],init_srb+14); writeb(olympic_priv->olympic_laa[2],init_srb+14);
...@@ -458,8 +471,12 @@ static int olympic_open(struct net_device *dev) ...@@ -458,8 +471,12 @@ static int olympic_open(struct net_device *dev)
writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
t = jiffies ; t = jiffies ;
add_wait_queue(&olympic_priv->srb_wait,&wait) ;
set_current_state(TASK_INTERRUPTIBLE) ;
while(olympic_priv->srb_queued) { while(olympic_priv->srb_queued) {
interruptible_sleep_on_timeout(&olympic_priv->srb_wait, 60*HZ); schedule() ;
if(signal_pending(current)) { if(signal_pending(current)) {
printk(KERN_WARNING "%s: Signal received in open.\n", printk(KERN_WARNING "%s: Signal received in open.\n",
dev->name); dev->name);
...@@ -474,7 +491,11 @@ static int olympic_open(struct net_device *dev) ...@@ -474,7 +491,11 @@ static int olympic_open(struct net_device *dev)
olympic_priv->srb_queued=0; olympic_priv->srb_queued=0;
break ; break ;
} }
set_current_state(TASK_INTERRUPTIBLE) ;
} }
remove_wait_queue(&olympic_priv->srb_wait,&wait) ;
set_current_state(TASK_RUNNING) ;
restore_flags(flags); restore_flags(flags);
#if OLYMPIC_DEBUG #if OLYMPIC_DEBUG
printk("init_srb(%p): ",init_srb); printk("init_srb(%p): ",init_srb);
...@@ -515,6 +536,17 @@ static int olympic_open(struct net_device *dev) ...@@ -515,6 +536,17 @@ static int olympic_open(struct net_device *dev)
return -EIO ; return -EIO ;
} /* if autosense && open_finished */ } /* if autosense && open_finished */
} else if (init_srb[2] == 0x32) {
printk(KERN_WARNING "%s: Invalid LAA: %02x:%02x:%02x:%02x:%02x:%02x\n",
dev->name,
olympic_priv->olympic_laa[0],
olympic_priv->olympic_laa[1],
olympic_priv->olympic_laa[2],
olympic_priv->olympic_laa[3],
olympic_priv->olympic_laa[4],
olympic_priv->olympic_laa[5]) ;
free_irq(dev->irq,dev) ;
return -EIO ;
} else { } else {
printk(KERN_WARNING "%s: Bad OPEN response: %x\n", dev->name,init_srb[2]); printk(KERN_WARNING "%s: Bad OPEN response: %x\n", dev->name,init_srb[2]);
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
...@@ -634,7 +666,10 @@ static int olympic_open(struct net_device *dev) ...@@ -634,7 +666,10 @@ static int olympic_open(struct net_device *dev)
olympic_priv->tx_ring_free=0; /* next entry in tx ring to use */ olympic_priv->tx_ring_free=0; /* next entry in tx ring to use */
olympic_priv->tx_ring_last_status=OLYMPIC_TX_RING_SIZE-1; /* last processed tx status */ olympic_priv->tx_ring_last_status=OLYMPIC_TX_RING_SIZE-1; /* last processed tx status */
writel(SISR_TX1_EOF | SISR_ADAPTER_CHECK | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_ASB_FREE,olympic_mmio+SISR_MASK_SUM); writel(0xffffffff, olympic_mmio+EISR_RWM) ; /* clean the eisr */
writel(0,olympic_mmio+EISR) ;
writel(EISR_MASK_OPTIONS,olympic_mmio+EISR_MASK) ; /* enables most of the TX error interrupts */
writel(SISR_TX1_EOF | SISR_ADAPTER_CHECK | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_ASB_FREE | SISR_ERR,olympic_mmio+SISR_MASK_SUM);
#if OLYMPIC_DEBUG #if OLYMPIC_DEBUG
printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM)); printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM));
...@@ -822,6 +857,35 @@ static void olympic_rx(struct net_device *dev) ...@@ -822,6 +857,35 @@ static void olympic_rx(struct net_device *dev)
} }
static void olympic_freemem(struct net_device *dev)
{
struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
int i;
for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
dev_kfree_skb_irq(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]);
if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) {
pci_unmap_single(olympic_priv->pdev,
le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer),
olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE);
}
olympic_priv->rx_status_last_received++;
olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
}
/* unmap rings */
pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_status_ring_dma_addr,
sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE);
pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_ring_dma_addr,
sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE);
pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_status_ring_dma_addr,
sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE);
pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_ring_dma_addr,
sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE, PCI_DMA_TODEVICE);
return ;
}
static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs) static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
struct net_device *dev= (struct net_device *)dev_id; struct net_device *dev= (struct net_device *)dev_id;
...@@ -842,8 +906,32 @@ static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -842,8 +906,32 @@ static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_lock(&olympic_priv->olympic_lock); spin_lock(&olympic_priv->olympic_lock);
/* Hotswap gives us this on removal */
if (sisr == 0xffffffff) {
printk(KERN_WARNING "%s: Hotswap adapter removal.\n",dev->name) ;
olympic_freemem(dev) ;
free_irq(dev->irq, dev) ;
dev->stop = NULL ;
spin_unlock(&olympic_priv->olympic_lock) ;
return ;
}
if (sisr & (SISR_SRB_REPLY | SISR_TX1_EOF | SISR_RX_STATUS | SISR_ADAPTER_CHECK | if (sisr & (SISR_SRB_REPLY | SISR_TX1_EOF | SISR_RX_STATUS | SISR_ADAPTER_CHECK |
SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_RX_NOBUF)) { SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_RX_NOBUF | SISR_ERR)) {
/* If we ever get this the adapter is seriously dead. Only a reset is going to
* bring it back to life. We're talking pci bus errors and such like :( */
if((sisr & SISR_ERR) && (readl(olympic_mmio+EISR) & EISR_MASK_OPTIONS)) {
printk(KERN_ERR "Olympic: EISR Error, EISR=%08x\n",readl(olympic_mmio+EISR)) ;
printk(KERN_ERR "The adapter must be reset to clear this condition.\n") ;
printk(KERN_ERR "Please report this error to the driver maintainer and/\n") ;
printk(KERN_ERR "or the linux-tr mailing list.\n") ;
olympic_freemem(dev) ;
free_irq(dev->irq, dev) ;
dev->stop = NULL ;
spin_unlock(&olympic_priv->olympic_lock) ;
return ;
} /* SISR_ERR */
if(sisr & SISR_SRB_REPLY) { if(sisr & SISR_SRB_REPLY) {
if(olympic_priv->srb_queued==1) { if(olympic_priv->srb_queued==1) {
...@@ -878,34 +966,12 @@ static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -878,34 +966,12 @@ static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
} /* SISR_RX_STATUS */ } /* SISR_RX_STATUS */
if (sisr & SISR_ADAPTER_CHECK) { if (sisr & SISR_ADAPTER_CHECK) {
int i ;
netif_stop_queue(dev); netif_stop_queue(dev);
printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name); printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name);
writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA); writel(readl(olympic_mmio+LAPWWC),olympic_mmio+LAPA);
adapter_check_area = (u8 *)(olympic_mmio+LAPWWO) ; adapter_check_area = olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWC)) & (~0xf800)) ;
printk(KERN_WARNING "%s: Bytes %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(adapter_check_area+0), readb(adapter_check_area+1), readb(adapter_check_area+2), readb(adapter_check_area+3), readb(adapter_check_area+4), readb(adapter_check_area+5), readb(adapter_check_area+6), readb(adapter_check_area+7)) ; printk(KERN_WARNING "%s: Bytes %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(adapter_check_area+0), readb(adapter_check_area+1), readb(adapter_check_area+2), readb(adapter_check_area+3), readb(adapter_check_area+4), readb(adapter_check_area+5), readb(adapter_check_area+6), readb(adapter_check_area+7)) ;
/* The adapter is effectively dead, clean up and exit */ olympic_freemem(dev) ;
for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
dev_kfree_skb_irq(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]);
if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) {
pci_unmap_single(olympic_priv->pdev,
le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer),
olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE);
}
olympic_priv->rx_status_last_received++;
olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
}
/* unmap rings */
pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_status_ring_dma_addr,
sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE);
pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_ring_dma_addr,
sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE);
pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_status_ring_dma_addr,
sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE);
pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_ring_dma_addr,
sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE, PCI_DMA_TODEVICE);
free_irq(dev->irq, dev) ; free_irq(dev->irq, dev) ;
dev->stop = NULL ; dev->stop = NULL ;
spin_unlock(&olympic_priv->olympic_lock) ; spin_unlock(&olympic_priv->olympic_lock) ;
...@@ -980,7 +1046,8 @@ static int olympic_close(struct net_device *dev) ...@@ -980,7 +1046,8 @@ static int olympic_close(struct net_device *dev)
struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
u8 *olympic_mmio=olympic_priv->olympic_mmio,*srb; u8 *olympic_mmio=olympic_priv->olympic_mmio,*srb;
unsigned long t,flags; unsigned long t,flags;
int i;
DECLARE_WAITQUEUE(wait,current) ;
netif_stop_queue(dev); netif_stop_queue(dev);
...@@ -999,8 +1066,12 @@ static int olympic_close(struct net_device *dev) ...@@ -999,8 +1066,12 @@ static int olympic_close(struct net_device *dev)
writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
t = jiffies ; t = jiffies ;
add_wait_queue(&olympic_priv->srb_wait,&wait) ;
set_current_state(TASK_INTERRUPTIBLE) ;
while(olympic_priv->srb_queued) { while(olympic_priv->srb_queued) {
interruptible_sleep_on_timeout(&olympic_priv->srb_wait, jiffies+60*HZ); schedule() ;
if(signal_pending(current)) { if(signal_pending(current)) {
printk(KERN_WARNING "%s: SRB timed out.\n",dev->name); printk(KERN_WARNING "%s: SRB timed out.\n",dev->name);
printk(KERN_WARNING "SISR=%x MISR=%x\n",readl(olympic_mmio+SISR),readl(olympic_mmio+LISR)); printk(KERN_WARNING "SISR=%x MISR=%x\n",readl(olympic_mmio+SISR),readl(olympic_mmio+LISR));
...@@ -1012,32 +1083,16 @@ static int olympic_close(struct net_device *dev) ...@@ -1012,32 +1083,16 @@ static int olympic_close(struct net_device *dev)
olympic_priv->srb_queued=0; olympic_priv->srb_queued=0;
break ; break ;
} }
set_current_state(TASK_INTERRUPTIBLE) ;
} }
remove_wait_queue(&olympic_priv->srb_wait,&wait) ;
set_current_state(TASK_RUNNING) ;
restore_flags(flags) ; restore_flags(flags) ;
olympic_priv->rx_status_last_received++; olympic_priv->rx_status_last_received++;
olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) { olympic_freemem(dev) ;
dev_kfree_skb(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]);
if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) {
pci_unmap_single(olympic_priv->pdev,
le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer),
olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE);
}
olympic_priv->rx_status_last_received++;
olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
}
/* unmap rings */
pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_status_ring_dma_addr,
sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE);
pci_unmap_single(olympic_priv->pdev, olympic_priv->rx_ring_dma_addr,
sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE);
pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_status_ring_dma_addr,
sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE);
pci_unmap_single(olympic_priv->pdev, olympic_priv->tx_ring_dma_addr,
sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE, PCI_DMA_TODEVICE);
/* reset tx/rx fifo's and busmaster logic */ /* reset tx/rx fifo's and busmaster logic */
......
...@@ -79,6 +79,7 @@ ...@@ -79,6 +79,7 @@
#define EISR 0x34 #define EISR 0x34
#define EISR_RWM 0x38 #define EISR_RWM 0x38
#define EISR_MASK 0x3c #define EISR_MASK 0x3c
#define EISR_MASK_OPTIONS 0x001FFF7F
#define LAPA 0x60 #define LAPA 0x60
#define LAPWWO 0x64 #define LAPWWO 0x64
......
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