patch-2.3.99-pre6 linux/drivers/atm/eni.c
Next file: linux/drivers/atm/eni.h
Previous file: linux/drivers/atm/atmdev_init.c
Back to the patch index
Back to the overall index
- Lines: 327
- Date:
Fri Apr 14 09:37:10 2000
- Orig file:
v2.3.99-pre5/linux/drivers/atm/eni.c
- Orig date:
Mon Mar 27 08:08:23 2000
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/atm/eni.c linux/drivers/atm/eni.c
@@ -879,14 +879,13 @@
set_current_state(TASK_UNINTERRUPTIBLE);
}
for (;;) {
- unsigned long flags;
int at_end;
u32 tmp;
- spin_lock_irqsave(&eni_dev->lock,flags);
+ tasklet_disable(&eni_dev->task);
tmp = readl(eni_dev->vci+vcc->vci*16+4) & MID_VCI_READ;
at_end = eni_vcc->rx_pos == tmp >> MID_VCI_READ_SHIFT;
- spin_unlock_irqrestore(&eni_dev->lock,flags);
+ tasklet_enable(&eni_dev->task);
if (at_end) break;
EVENT("drain discard (host 0x%lx, nic 0x%lx)\n",
eni_vcc->rx_pos,tmp);
@@ -972,8 +971,8 @@
}
#ifdef CONFIG_ATM_ENI_BURST_TX_16W /* may work with some PCI chipsets ... */
if (words & ~15) {
- DPRINTK("put_dma: %lx DMA: %d*16/%d words\n",paddr,words >> 4,
- words);
+ DPRINTK("put_dma: %lx DMA: %d*16/%d words\n",
+ (unsigned long) paddr,words >> 4,words);
dma[(*j)++] = MID_DT_16W | ((words >> 4) << MID_DMA_COUNT_SHIFT)
| (chan << MID_DMA_CHAN_SHIFT);
dma[(*j)++] = paddr;
@@ -994,8 +993,8 @@
#endif
#ifdef CONFIG_ATM_ENI_BURST_TX_4W /* probably useless if TX_8W or TX_16W */
if (words & ~3) {
- DPRINTK("put_dma: %lx DMA: %d*4/%d words\n",paddr,words >> 2,
- words);
+ DPRINTK("put_dma: %lx DMA: %d*4/%d words\n",
+ (unsigned long) paddr,words >> 2,words);
dma[(*j)++] = MID_DT_4W | ((words >> 2) << MID_DMA_COUNT_SHIFT)
| (chan << MID_DMA_CHAN_SHIFT);
dma[(*j)++] = paddr;
@@ -1005,8 +1004,8 @@
#endif
#ifdef CONFIG_ATM_ENI_BURST_TX_2W /* probably useless if TX_4W, TX_8W, ... */
if (words & ~1) {
- DPRINTK("put_dma: %lx DMA: %d*2/%d words\n",paddr,words >> 1,
- words);
+ DPRINTK("put_dma: %lx DMA: %d*2/%d words\n",
+ (unsigned long) paddr,words >> 1,words);
dma[(*j)++] = MID_DT_2W | ((words >> 1) << MID_DMA_COUNT_SHIFT)
| (chan << MID_DMA_CHAN_SHIFT);
dma[(*j)++] = paddr;
@@ -1188,7 +1187,7 @@
if (tx->send)
while ((skb = skb_dequeue(&tx->backlog))) {
res = do_tx(skb);
- if (res == enq_ok) tx->backlog_len--;
+ if (res == enq_ok) atomic_dec(&tx->backlog_len);
else {
DPRINTK("re-queuing TX PDU\n");
skb_queue_head(&tx->backlog,skb);
@@ -1327,7 +1326,7 @@
tx->send = mem;
tx->words = size >> 2;
skb_queue_head_init(&tx->backlog);
- tx->backlog_len = 0;
+ atomic_set(&tx->backlog_len,0);
for (order = 0; size > (1 << (order+10)); order++);
eni_out((order << MID_SIZE_SHIFT) |
((tx->send-eni_dev->ram) >> (MID_LOC_SKIP+2)),
@@ -1399,12 +1398,11 @@
add_wait_queue(&eni_dev->tx_wait,&wait);
set_current_state(TASK_UNINTERRUPTIBLE);
for (;;) {
- unsigned long flags;
int txing;
- spin_lock_irqsave(&eni_dev->lock,flags);
+ tasklet_disable(&eni_dev->task);
txing = skb_peek(&eni_vcc->tx->backlog) || eni_vcc->txing;
- spin_unlock_irqrestore(&eni_dev->lock,flags);
+ tasklet_enable(&eni_dev->task);
if (!txing) break;
DPRINTK("%d TX left\n",eni_vcc->txing);
schedule();
@@ -1468,44 +1466,24 @@
#endif
-static void misc_int(struct atm_dev *dev,unsigned long reason)
+static void bug_int(struct atm_dev *dev,unsigned long reason)
{
struct eni_dev *eni_dev;
- DPRINTK(">misc_int\n");
+ DPRINTK(">bug_int\n");
eni_dev = ENI_DEV(dev);
- if (reason & MID_STAT_OVFL) {
- EVENT("stat overflow\n",0,0);
- eni_dev->lost += eni_in(MID_STAT) & MID_OVFL_TRASH;
- }
- if (reason & MID_SUNI_INT) {
- EVENT("SUNI int\n",0,0);
- dev->phy->interrupt(dev);
-#if 0
- foo();
-#endif
- }
- if (reason & MID_DMA_ERR_ACK) {
+ if (reason & MID_DMA_ERR_ACK)
printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - DMA "
"error\n",dev->number);
- EVENT("---dump ends here---\n",0,0);
- printk(KERN_NOTICE "---recent events---\n");
- event_dump();
- }
- if (reason & MID_TX_IDENT_MISM) {
+ if (reason & MID_TX_IDENT_MISM)
printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - ident "
"mismatch\n",dev->number);
- EVENT("---dump ends here---\n",0,0);
- printk(KERN_NOTICE "---recent events---\n");
- event_dump();
- }
- if (reason & MID_TX_DMA_OVFL) {
+ if (reason & MID_TX_DMA_OVFL)
printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - DMA "
"overflow\n",dev->number);
- EVENT("---dump ends here---\n",0,0);
- printk(KERN_NOTICE "---recent events---\n");
- event_dump();
- }
+ EVENT("---dump ends here---\n",0,0);
+ printk(KERN_NOTICE "---recent events---\n");
+ event_dump();
}
@@ -1513,54 +1491,78 @@
{
struct atm_dev *dev;
struct eni_dev *eni_dev;
- unsigned long reason;
+ u32 reason;
DPRINTK(">eni_int\n");
dev = dev_id;
eni_dev = ENI_DEV(dev);
- while ((reason = eni_in(MID_ISA))) {
- DPRINTK(DEV_LABEL ": int 0x%lx\n",reason);
- if (reason & MID_RX_DMA_COMPLETE) {
- EVENT("INT: RX DMA complete, starting dequeue_rx\n",
- 0,0);
- spin_lock(&eni_dev->lock);
- dequeue_rx(dev);
- EVENT("dequeue_rx done, starting poll_rx\n",0,0);
- poll_rx(dev);
- spin_unlock(&eni_dev->lock);
- EVENT("poll_rx done\n",0,0);
- /* poll_tx ? */
- }
- if (reason & MID_SERVICE) {
- EVENT("INT: service, starting get_service\n",0,0);
- spin_lock(&eni_dev->lock);
- get_service(dev);
- EVENT("get_service done, starting poll_rx\n",0,0);
- poll_rx(dev);
- spin_unlock(&eni_dev->lock);
- EVENT("poll_rx done\n",0,0);
- }
- if (reason & MID_TX_DMA_COMPLETE) {
- EVENT("INT: TX DMA COMPLETE\n",0,0);
- spin_lock(&eni_dev->lock);
- dequeue_tx(dev);
- spin_unlock(&eni_dev->lock);
- }
- if (reason & MID_TX_COMPLETE) {
- EVENT("INT: TX COMPLETE\n",0,0);
+ reason = eni_in(MID_ISA);
+ DPRINTK(DEV_LABEL ": int 0x%lx\n",(unsigned long) reason);
+ /*
+ * Must handle these two right now, because reading ISA doesn't clear
+ * them, so they re-occur and we never make it to the tasklet. Since
+ * they're rare, we don't mind the occasional invocation of eni_tasklet
+ * with eni_dev->events == 0.
+ */
+ if (reason & MID_STAT_OVFL) {
+ EVENT("stat overflow\n",0,0);
+ eni_dev->lost += eni_in(MID_STAT) & MID_OVFL_TRASH;
+ }
+ if (reason & MID_SUNI_INT) {
+ EVENT("SUNI int\n",0,0);
+ dev->phy->interrupt(dev);
+#if 0
+ foo();
+#endif
+ }
+ spin_lock(&eni_dev->lock);
+ eni_dev->events |= reason;
+ spin_unlock(&eni_dev->lock);
+ tasklet_schedule(&eni_dev->task);
+}
+
+
+static void eni_tasklet(unsigned long data)
+{
+ struct atm_dev *dev = (struct atm_dev *) data;
+ struct eni_dev *eni_dev = ENI_DEV(dev);
+ unsigned long flags;
+ u32 events;
+
+ DPRINTK("eni_tasklet (dev %p)\n",dev);
+ spin_lock_irqsave(&eni_dev->lock,flags);
+ events = xchg(&eni_dev->events,0);
+ spin_unlock_irqrestore(&eni_dev->lock,flags);
+ if (events & MID_RX_DMA_COMPLETE) {
+ EVENT("INT: RX DMA complete, starting dequeue_rx\n",0,0);
+ dequeue_rx(dev);
+ EVENT("dequeue_rx done, starting poll_rx\n",0,0);
+ poll_rx(dev);
+ EVENT("poll_rx done\n",0,0);
+ /* poll_tx ? */
+ }
+ if (events & MID_SERVICE) {
+ EVENT("INT: service, starting get_service\n",0,0);
+ get_service(dev);
+ EVENT("get_service done, starting poll_rx\n",0,0);
+ poll_rx(dev);
+ EVENT("poll_rx done\n",0,0);
+ }
+ if (events & MID_TX_DMA_COMPLETE) {
+ EVENT("INT: TX DMA COMPLETE\n",0,0);
+ dequeue_tx(dev);
+ }
+ if (events & MID_TX_COMPLETE) {
+ EVENT("INT: TX COMPLETE\n",0,0);
tx_complete++;
- spin_lock(&eni_dev->lock);
- poll_tx(dev);
- spin_unlock(&eni_dev->lock);
- wake_up(&eni_dev->tx_wait);
- /* poll_rx ? */
- }
- if (reason & (MID_STAT_OVFL | MID_SUNI_INT | MID_DMA_ERR_ACK |
- MID_TX_IDENT_MISM | MID_TX_DMA_OVFL)) {
- EVENT("misc interrupt\n",0,0);
- misc_int(dev,reason);
- }
+ wake_up(&eni_dev->tx_wait);
+ /* poll_rx ? */
+ }
+ if (events & (MID_DMA_ERR_ACK | MID_TX_IDENT_MISM | MID_TX_DMA_OVFL)) {
+ EVENT("bug interrupt\n",0,0);
+ bug_int(dev,events);
}
+ poll_tx(dev);
}
@@ -1824,6 +1826,8 @@
eni_dev->vci,eni_dev->rx_dma,eni_dev->tx_dma,
eni_dev->service,buf);
spin_lock_init(&eni_dev->lock);
+ tasklet_init(&eni_dev->task,eni_tasklet,(unsigned long) dev);
+ eni_dev->events = 0;
/* initialize memory management */
buffer_mem = eni_dev->mem-(buf-eni_dev->ram);
eni_dev->free_list_size = buffer_mem/MID_MIN_BUF_SIZE/2;
@@ -1969,7 +1973,6 @@
struct eni_dev *eni_dev = ENI_DEV(vcc->dev);
struct eni_tx *tx = ENI_VCC(vcc)->tx;
struct sk_buff *skb;
- unsigned long flags;
int error,rate,rsv,shp;
if (qos->txtp.traffic_class == ATM_NONE) return 0;
@@ -1989,7 +1992,7 @@
* Walk through the send buffer and patch the rate information in all
* segmentation buffer descriptors of this VCC.
*/
- spin_lock_irqsave(&eni_dev->lock,flags);
+ tasklet_disable(&eni_dev->task);
for (skb = eni_dev->tx_queue.next; skb !=
(struct sk_buff *) &eni_dev->tx_queue; skb = skb->next) {
unsigned long dsc;
@@ -2000,7 +2003,7 @@
(tx->prescaler << MID_SEG_PR_SHIFT) |
(tx->resolution << MID_SEG_RATE_SHIFT), dsc);
}
- spin_unlock_irqrestore(&eni_dev->lock,flags);
+ tasklet_enable(&eni_dev->task);
return 0;
}
@@ -2061,8 +2064,6 @@
static int eni_send(struct atm_vcc *vcc,struct sk_buff *skb)
{
- unsigned long flags;
-
DPRINTK(">eni_send\n");
if (!ENI_VCC(vcc)->tx) {
if (vcc->pop) vcc->pop(vcc,skb);
@@ -2084,13 +2085,10 @@
}
submitted++;
ATM_SKB(skb)->vcc = vcc;
- spin_lock_irqsave(&ENI_DEV(vcc->dev)->lock,flags); /* brute force */
- if (skb_peek(&ENI_VCC(vcc)->tx->backlog) || do_tx(skb)) {
- skb_queue_tail(&ENI_VCC(vcc)->tx->backlog,skb);
- ENI_VCC(vcc)->tx->backlog_len++;
+ skb_queue_tail(&ENI_VCC(vcc)->tx->backlog,skb);
+ atomic_inc(&ENI_VCC(vcc)->tx->backlog_len);
backlogged++;
- }
- spin_unlock_irqrestore(&ENI_DEV(vcc->dev)->lock,flags);
+ tasklet_schedule(&ENI_DEV(vcc->dev)->task);
return 0;
}
@@ -2189,7 +2187,7 @@
}
if (--left) continue;
return sprintf(page,"%10sbacklog %d bytes\n","",
- tx->backlog_len);
+ atomic_read(&tx->backlog_len));
}
for (vcc = dev->vccs; vcc; vcc = vcc->next) {
struct eni_vcc *eni_vcc = ENI_VCC(vcc);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)