diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-04-28 01:09:25 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-04-28 01:09:25 +0000 |
commit | b9ba7aeb165cffecdffb60aec8c3fa8d590d9ca9 (patch) | |
tree | 42d07b0c7246ae2536a702e7c5de9e2732341116 /drivers/atm | |
parent | 7406b0a326f2d70ade2671c37d1beef62249db97 (diff) |
Merge with 2.3.99-pre6.
Diffstat (limited to 'drivers/atm')
-rw-r--r-- | drivers/atm/Config.in | 12 | ||||
-rw-r--r-- | drivers/atm/Makefile | 56 | ||||
-rw-r--r-- | drivers/atm/ambassador.c | 8 | ||||
-rw-r--r-- | drivers/atm/ambassador.h | 2 | ||||
-rw-r--r-- | drivers/atm/atmdev_init.c | 20 | ||||
-rw-r--r-- | drivers/atm/eni.c | 190 | ||||
-rw-r--r-- | drivers/atm/eni.h | 5 | ||||
-rw-r--r-- | drivers/atm/fore200e.c | 80 | ||||
-rw-r--r-- | drivers/atm/fore200e.h | 15 | ||||
-rw-r--r-- | drivers/atm/horizon.c | 13 | ||||
-rw-r--r-- | drivers/atm/uPD98402.c | 2 |
11 files changed, 233 insertions, 170 deletions
diff --git a/drivers/atm/Config.in b/drivers/atm/Config.in index 8fb55632a..c603f71af 100644 --- a/drivers/atm/Config.in +++ b/drivers/atm/Config.in @@ -52,8 +52,8 @@ if [ "$CONFIG_PCI" = "y" ]; then fi fi if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SBUS" = "y" ]; then - tristate 'FORE Systems 200E-series' CONFIG_ATM_FORE200E - if [ "$CONFIG_ATM_FORE200E" != "n" ]; then + tristate 'FORE Systems 200E-series' CONFIG_ATM_FORE200E_MAYBE + if [ "$CONFIG_ATM_FORE200E_MAYBE" != "n" ]; then if [ "$CONFIG_PCI" = "y" ]; then bool ' PCA-200E support' CONFIG_ATM_FORE200E_PCA y if [ "$CONFIG_ATM_FORE200E_PCA" = "y" ]; then @@ -72,8 +72,16 @@ if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SBUS" = "y" ]; then fi fi fi + fi + if [ "$CONFIG_ATM_FORE200E_PCA" = "y" -o "$CONFIG_ATM_FORE200E_SBA" = "y" ]; \ + then int ' Maximum number of tx retries' CONFIG_ATM_FORE200E_TX_RETRY 16 int ' Debugging level (0-3)' CONFIG_ATM_FORE200E_DEBUG 0 + if [ "$CONFIG_ATM_FORE200E_MAYBE" = "y" ]; then + define_tristate CONFIG_ATM_FORE200E y + else + define_tristate CONFIG_ATM_FORE200E m + fi fi fi endmenu diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile index 8dbf1364a..330d5d1c3 100644 --- a/drivers/atm/Makefile +++ b/drivers/atm/Makefile @@ -30,10 +30,6 @@ else endif endif -ifeq ($(CONFIG_ATM_TNETA1570),y) -O_OBJS += tneta1570.o suni.o -endif - ifeq ($(CONFIG_ATM_NICSTAR),y) O_OBJS += nicstar.o ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y) @@ -101,23 +97,29 @@ else endif ifeq ($(CONFIG_ATM_FORE200E_PCA),y) -FORE200E_FW_OBJS += fore200e_pca_fw.o + FORE200E_FW_OBJS += fore200e_pca_fw.o + ifeq ($(strip $(CONFIG_ATM_FORE200E_PCA_FW)),"") + CONFIG_ATM_FORE200E_PCA_DEFAULT_FW := y + endif ifeq ($(CONFIG_ATM_FORE200E_PCA_DEFAULT_FW),y) # guess the target endianess to choose the right PCA-200E firmware image CONFIG_ATM_FORE200E_PCA_FW := $(shell if test -n "`$(CC) -E -dM ../../include/asm/byteorder.h | grep ' __LITTLE_ENDIAN '`"; then echo pca200e.bin; else echo pca200e_ecd.bin2; fi) endif endif ifeq ($(CONFIG_ATM_FORE200E_SBA),y) -FORE200E_FW_OBJS += fore200e_sba_fw.o + FORE200E_FW_OBJS += fore200e_sba_fw.o + ifeq ($(strip $(CONFIG_ATM_FORE200E_SBA_FW)),"") + CONFIG_ATM_FORE200E_SBA_DEFAULT_FW := y + endif ifeq ($(CONFIG_ATM_FORE200E_SBA_DEFAULT_FW),y) CONFIG_ATM_FORE200E_SBA_FW := sba200e_ecd.bin2 endif endif ifeq ($(CONFIG_ATM_FORE200E),y) -O_OBJS += fore200e.o $(FORE200E_FW_OBJS) + O_OBJS += fore200e.o $(FORE200E_FW_OBJS) else ifeq ($(CONFIG_ATM_FORE200E),m) - M_OBJS += fore_200e.o + M_OBJS += fore_200e.o endif endif @@ -125,33 +127,51 @@ EXTRA_CFLAGS=-g include $(TOPDIR)/Rules.make + # FORE Systems 200E-series firmware magic fore200e_pca_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_PCA_FW)) \ fore200e_mkfirm ./fore200e_mkfirm -k -b _fore200e_pca_fw \ -i $(CONFIG_ATM_FORE200E_PCA_FW) -o $@ + @ ( \ + echo 'ifeq ($(strip $(CONFIG_ATM_FORE200E_PCA_FW)), $$(CONFIG_ATM_FORE200E_PCA_FW))'; \ + echo 'FORE200E_FW_UP_TO_DATE += $@'; \ + echo 'endif' \ + ) >.$@.fw fore200e_sba_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_SBA_FW)) \ fore200e_mkfirm ./fore200e_mkfirm -k -b _fore200e_sba_fw \ -i $(CONFIG_ATM_FORE200E_SBA_FW) -o $@ + @ ( \ + echo 'ifeq ($(strip $(CONFIG_ATM_FORE200E_SBA_FW)), $$(CONFIG_ATM_FORE200E_SBA_FW))'; \ + echo 'FORE200E_FW_UP_TO_DATE += $@'; \ + echo 'endif' \ + ) >.$@.fw fore200e_mkfirm: fore200e_mkfirm.c $(HOSTCC) $(HOSTCFLAGS) $< -o $@ -# deal with the various suffixes of the firmware images -%.bin: %.data - objcopy -Iihex $< -Obinary $@.gz - gzip -df $@.gz - -%.bin1: %.data - objcopy -Iihex $< -Obinary $@.gz - gzip -df $@.gz - -%.bin2: %.data +# deal with the various suffixes of the binary firmware images +%.bin %.bin1 %.bin2: %.data objcopy -Iihex $< -Obinary $@.gz gzip -df $@.gz # module build fore_200e.o: fore200e.o $(FORE200E_FW_OBJS) $(LD) -r -o $@ $< $(FORE200E_FW_OBJS) + +# firmware dependency stuff taken from drivers/sound/Makefile +FORE200E_FW_UP_TO_DATE := + +FORE200E_FW_FILES := $(wildcard .fore200e_*.fw) +ifneq ($(FORE200E_FW_FILES),) +include $(FORE200E_FW_FILES) +endif + +FORE200E_FW_CHANGED := $(filter-out $(FORE200E_FW_UP_TO_DATE), \ + fore200e_pca_fw.c fore200e_sba_fw.c) + +ifneq ($(FORE200E_FW_CHANGED),) +$(FORE200E_FW_CHANGED): dummy +endif diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index a71884db7..151704c95 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -1251,10 +1251,15 @@ static int amb_open (struct atm_vcc * atm_vcc, short vpi, int vci) { } } + // prevent module unload while sleeping (kmalloc/down) + // doing this any earlier would complicate more error return paths + MOD_INC_USE_COUNT; + // get space for our vcc stuff vcc = kmalloc (sizeof(amb_vcc), GFP_KERNEL); if (!vcc) { PRINTK (KERN_ERR, "out of memory!"); + MOD_DEC_USE_COUNT; return -ENOMEM; } atm_vcc->dev_data = (void *) vcc; @@ -1340,7 +1345,6 @@ static int amb_open (struct atm_vcc * atm_vcc, short vpi, int vci) { // indicate readiness set_bit(ATM_VF_READY,&atm_vcc->flags); - MOD_INC_USE_COUNT; return 0; } @@ -1420,7 +1424,9 @@ static void amb_close (struct atm_vcc * atm_vcc) { // say the VPI/VCI is free again clear_bit(ATM_VF_ADDR,&atm_vcc->flags); + MOD_DEC_USE_COUNT; + return; } /********** DebugIoctl **********/ diff --git a/drivers/atm/ambassador.h b/drivers/atm/ambassador.h index 11ce866da..e8c3456e3 100644 --- a/drivers/atm/ambassador.h +++ b/drivers/atm/ambassador.h @@ -631,7 +631,7 @@ struct amb_dev { u32 iobase; u32 * membase; -#if 0 +#ifdef FILL_RX_POOLS_IN_BH struct tq_struct bh; #endif diff --git a/drivers/atm/atmdev_init.c b/drivers/atm/atmdev_init.c index 443831a82..73c785fe0 100644 --- a/drivers/atm/atmdev_init.c +++ b/drivers/atm/atmdev_init.c @@ -1,21 +1,15 @@ /* drivers/atm/atmdev_init.c - ATM device driver initialization */ -/* Written 1995-1997 by Werner Almesberger, EPFL LRC */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #include <linux/config.h> #include <linux/init.h> -#ifdef CONFIG_ATM_ENI -extern int eni_detect(void); -#endif #ifdef CONFIG_ATM_ZATM extern int zatm_detect(void); #endif -#ifdef CONFIG_ATM_TNETA1570 -extern int tneta1570_detect(void); -#endif #ifdef CONFIG_ATM_NICSTAR extern int nicstar_detect(void); #endif @@ -33,20 +27,20 @@ extern int fore200e_detect(void); #endif +/* + * For historical reasons, atmdev_init returns the number of devices found. + * Note that some detections may not go via atmdev_init (e.g. eni.c), so this + * number is meaningless. + */ + int __init atmdev_init(void) { int devs; devs = 0; -#ifdef CONFIG_ATM_ENI -// devs += eni_detect(); -#endif #ifdef CONFIG_ATM_ZATM devs += zatm_detect(); #endif -#ifdef CONFIG_ATM_TNETA1570 - devs += tneta1570_detect(); -#endif #ifdef CONFIG_ATM_NICSTAR devs += nicstar_detect(); #endif diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index b3240d498..df6ae2eda 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -879,14 +879,13 @@ static void close_rx(struct atm_vcc *vcc) 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 @@ static inline void put_dma(int chan,u32 *dma,int *j,dma_addr_t paddr, } #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 @@ static inline void put_dma(int chan,u32 *dma,int *j,dma_addr_t paddr, #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 @@ static inline void put_dma(int chan,u32 *dma,int *j,dma_addr_t paddr, #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 @@ static void poll_tx(struct atm_dev *dev) 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 @@ static int reserve_or_set_tx(struct atm_vcc *vcc,struct atm_trafprm *txtp, 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 @@ static void close_tx(struct atm_vcc *vcc) 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 @@ if (eni_boards) printk(KERN_INFO "loss: %ld\n",ENI_DEV(eni_boards)->lost); #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 @@ static void eni_int(int irq,void *dev_id,struct pt_regs *regs) { 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 @@ static int __devinit eni_start(struct atm_dev *dev) 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 @@ static int eni_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flgs) 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 @@ static int eni_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flgs) * 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 @@ static int eni_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flgs) (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_setsockopt(struct atm_vcc *vcc,int level,int optname, 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 @@ static int eni_send(struct atm_vcc *vcc,struct sk_buff *skb) } 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 @@ static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page) } 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); diff --git a/drivers/atm/eni.h b/drivers/atm/eni.h index 23ba60fb1..12a3e196c 100644 --- a/drivers/atm/eni.h +++ b/drivers/atm/eni.h @@ -13,6 +13,7 @@ #include <linux/time.h> #include <linux/pci.h> #include <linux/spinlock.h> +#include <asm/atomic.h> #include "midway.h" @@ -46,7 +47,7 @@ struct eni_tx { int reserved; /* reserved peak cell rate */ int shaping; /* shaped peak cell rate */ struct sk_buff_head backlog; /* queue of waiting TX buffers */ - int backlog_len; /* length of backlog in bytes */ + atomic_t backlog_len; /* length of backlog in bytes */ }; struct eni_vcc { @@ -68,6 +69,8 @@ struct eni_vcc { struct eni_dev { /*-------------------------------- spinlock */ spinlock_t lock; /* sync with interrupt */ + struct tasklet_struct task; /* tasklet for interrupt work */ + u32 events; /* pending events */ /*-------------------------------- base pointers into Midway address space */ unsigned long phy; /* PHY interface chip registers */ diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 1fec6e006..d9d5a66c5 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -1,8 +1,8 @@ /* - $Id: fore200e.c,v 1.2 2000/03/21 21:19:24 davem Exp $ + $Id: fore200e.c,v 1.5 2000/04/14 10:10:34 davem Exp $ A FORE Systems 200E-series driver for ATM on Linux. - Christophe Lizzi (lizzi@cnam.fr), October 1999-February 2000. + Christophe Lizzi (lizzi@cnam.fr), October 1999-March 2000. Based on the PCA-200E driver from Uwe Dannowski (Uwe.Dannowski@inf.tu-dresden.de). @@ -32,10 +32,11 @@ #include <linux/init.h> #include <linux/capability.h> #include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/bitops.h> #include <linux/atmdev.h> #include <linux/sonet.h> #include <linux/atm_suni.h> -#include <linux/bitops.h> #include <asm/io.h> #include <asm/string.h> #include <asm/segment.h> @@ -66,7 +67,7 @@ #define FORE200E_52BYTE_AAL0_SDU #endif -#define FORE200E_VERSION "0.2b" +#define FORE200E_VERSION "0.2d" #define FORE200E "fore200e: " @@ -444,6 +445,7 @@ fore200e_shutdown(struct fore200e* fore200e) } + #ifdef CONFIG_ATM_FORE200E_PCA static u32 fore200e_pca_read(volatile u32* addr) @@ -477,7 +479,8 @@ fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int d static void fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction) { - DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); + DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d\n", + dma_addr, size, direction); pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction); } @@ -496,7 +499,8 @@ fore200e_pca_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size, int dir (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */ static int -fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int nbr, int alignment) +fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, + int size, int nbr, int alignment) { #if defined(__sparc_v9__) /* returned chunks are page-aligned */ @@ -659,6 +663,7 @@ fore200e_pca_detect(const struct fore200e_bus* bus, int index) sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1); + pci_enable_device(pci_dev); pci_set_master(pci_dev); return fore200e; @@ -756,7 +761,8 @@ fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int d static void fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction) { - DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n", dma_addr, size, direction); + DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n", + dma_addr, size, direction); sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction); } @@ -775,7 +781,8 @@ fore200e_sba_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size, int dir (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */ static int -fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int nbr, int alignment) +fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, + int size, int nbr, int alignment) { chunk->alloc_size = chunk->align_size = size * nbr; @@ -1234,15 +1241,25 @@ fore200e_interrupt(int irq, void* dev, struct pt_regs* regs) } DPRINTK(3, "valid interrupt on device %c\n", fore200e->name[9]); - fore200e_irq_rx(fore200e); + tasklet_schedule(&fore200e->tasklet); + + fore200e->bus->irq_ack(fore200e); +} + + +static void +fore200e_tasklet(unsigned long data) +{ + struct fore200e* fore200e = (struct fore200e*) data; + fore200e_irq_rx(fore200e); + if (fore200e->host_txq.txing) fore200e_irq_tx(fore200e); - - fore200e->bus->irq_ack(fore200e); } + static int fore200e_select_scheme(struct atm_vcc* vcc) { @@ -1400,7 +1417,7 @@ fore200e_open(struct atm_vcc *vcc, short vpi, int vci) if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) return 0; - set_bit(ATM_VF_ADDR,&vcc->flags); + set_bit(ATM_VF_ADDR, &vcc->flags); vcc->itf = vcc->dev->number; DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " @@ -1463,7 +1480,7 @@ fore200e_open(struct atm_vcc *vcc, short vpi, int vci) fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = 65536; fore200e_vcc->tx_max_pdu = fore200e_vcc->rx_max_pdu = 0; - clear_bit(ATM_VF_READY,&vcc->flags); + set_bit(ATM_VF_READY, &vcc->flags); return 0; } @@ -1489,6 +1506,8 @@ fore200e_close(struct atm_vcc* vcc) fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; up(&fore200e->rate_sf); } + + clear_bit(ATM_VF_READY, &vcc->flags); } @@ -1506,7 +1525,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) struct host_txq_entry* entry; struct tpd* tpd; struct tpd_haddr tpd_haddr; - unsigned long flags; + //unsigned long flags; int retry = CONFIG_ATM_FORE200E_TX_RETRY; int tx_copy = 0; int tx_len = skb->len; @@ -1531,7 +1550,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) retry_here: - spin_lock_irqsave(&fore200e->tx_lock, flags); + tasklet_disable(&fore200e->tasklet); entry = &txq->host_entry[ txq->head ]; @@ -1542,7 +1561,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) if (*entry->status != STATUS_FREE) { - spin_unlock_irqrestore(&fore200e->tx_lock, flags); + tasklet_enable(&fore200e->tasklet); /* retry once again? */ if(--retry > 0) @@ -1582,7 +1601,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) entry->data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA); if (entry->data == NULL) { - spin_unlock_irqrestore(&fore200e->tx_lock, flags); + tasklet_enable(&fore200e->tasklet); if (vcc->pop) vcc->pop(vcc, skb); else @@ -1606,10 +1625,10 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX); txq->txing++; - spin_unlock_irqrestore(&fore200e->tx_lock, flags); - + tasklet_enable(&fore200e->tasklet); + /* ensure DMA synchronisation */ - fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE); + fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE); DPRINTK(3, "tx on %d.%d.%d:%d, len = %u (%u)\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), @@ -1934,8 +1953,7 @@ fore200e_ioctl(struct atm_dev* dev, unsigned int cmd, void* arg) return put_user(fore200e->loop_mode, (int*)arg) ? -EFAULT : 0; case ATM_QUERYLOOP: - return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY, (int*)arg) ? - -EFAULT : 0; + return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY, (int*)arg) ? -EFAULT : 0; } return -ENOSYS; /* not implemented */ @@ -1976,7 +1994,7 @@ fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags) /* update rate control parameters */ fore200e_rate_ctrl(qos, &fore200e_vcc->rate); - set_bit(ATM_VF_HASQOS,&vcc->flags); + set_bit(ATM_VF_HASQOS, &vcc->flags); return 0; } @@ -1997,6 +2015,8 @@ fore200e_irq_request(struct fore200e* fore200e) printk(FORE200E "IRQ %s reserved for device %s\n", fore200e_irq_itoa(fore200e->irq), fore200e->name); + tasklet_init(&fore200e->tasklet, fore200e_tasklet, (unsigned long)fore200e); + fore200e->state = FORE200E_STATE_IRQ; return 0; } @@ -2338,7 +2358,6 @@ fore200e_initialize(struct fore200e* fore200e) DPRINTK(2, "device %s being initialized\n", fore200e->name); - spin_lock_init(&fore200e->tx_lock); init_MUTEX(&fore200e->rate_sf); cpq = fore200e->cp_queues = (struct cp_queues*) (fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET); @@ -2714,7 +2733,7 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page) if (media_index < 0 || media_index > 4) media_index = 5; - switch(fore200e->loop_mode) { + switch (fore200e->loop_mode) { case ATM_LM_NONE: oc3_index = 0; break; case ATM_LM_LOC_PHY: oc3_index = 1; @@ -2900,21 +2919,24 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page) #ifdef MODULE -unsigned int -init_module(void) +static unsigned int __init +fore200e_module_init(void) { DPRINTK(1, "module loaded\n"); return fore200e_detect() == 0; } -void -cleanup_module(void) +static void __exit +fore200e_module_cleanup(void) { while (fore200e_boards) { fore200e_cleanup(&fore200e_boards); } DPRINTK(1, "module being removed\n"); } + +module_init(fore200e_module_init); +module_exit(fore200e_module_cleanup); #endif diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h index f29fbde97..e56afd2b6 100644 --- a/drivers/atm/fore200e.h +++ b/drivers/atm/fore200e.h @@ -1,3 +1,4 @@ +/* $Id: fore200e.h,v 1.4 2000/04/14 10:10:34 davem Exp $ */ #ifndef _FORE200E_H #define _FORE200E_H @@ -827,14 +828,18 @@ typedef struct fore200e_bus { # else /* in that case, we'll need to add an extra indirection, e.g. fore200e->bus->dma_direction[ fore200e_dma_direction ] */ -# error PCI and SBUS DMA direction flags differ! +# error PCI and SBUS DMA direction flags have different values! # endif # else -# define FORE200E_DMA_BIDIRECTIONAL SBA_DMA_BIDIRECTIONAL -# define FORE200E_DMA_TODEVICE SBA_DMA_TODEVICE -# define FORE200E_DMA_FROMDEVICE SBA_DMA_FROMDEVICE +# define FORE200E_DMA_BIDIRECTIONAL SBUS_DMA_BIDIRECTIONAL +# define FORE200E_DMA_TODEVICE SBUS_DMA_TODEVICE +# define FORE200E_DMA_FROMDEVICE SBUS_DMA_FROMDEVICE # endif #else +# ifndef CONFIG_ATM_FORE200E_PCA +# warning compiling the fore200e driver without any hardware support enabled! +# include <linux/pci.h> +# endif # define FORE200E_DMA_BIDIRECTIONAL PCI_DMA_BIDIRECTIONAL # define FORE200E_DMA_TODEVICE PCI_DMA_TODEVICE # define FORE200E_DMA_FROMDEVICE PCI_DMA_FROMDEVICE @@ -874,7 +879,7 @@ typedef struct fore200e { struct stats* stats; /* last snapshot of the stats */ struct semaphore rate_sf; /* protects rate reservation ops */ - spinlock_t tx_lock; /* protects tx ops */ + struct tasklet_struct tasklet; /* performs interrupt work */ } fore200e_t; diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index f0dff7011..f39845f85 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -2490,10 +2490,15 @@ static int hrz_open (struct atm_vcc * atm_vcc, short vpi, int vci) { return -EINVAL; } + // prevent module unload while sleeping (kmalloc) + // doing this any earlier would complicate more error return paths + MOD_INC_USE_COUNT; + // get space for our vcc stuff and copy parameters into it vccp = kmalloc (sizeof(hrz_vcc), GFP_KERNEL); if (!vccp) { PRINTK (KERN_ERR, "out of memory!"); + MOD_DEC_USE_COUNT; return -ENOMEM; } *vccp = vcc; @@ -2525,6 +2530,7 @@ static int hrz_open (struct atm_vcc * atm_vcc, short vpi, int vci) { if (error) { PRINTD (DBG_QOS|DBG_VCC, "insufficient cell rate resources"); kfree (vccp); + MOD_DEC_USE_COUNT; return error; } @@ -2537,11 +2543,13 @@ static int hrz_open (struct atm_vcc * atm_vcc, short vpi, int vci) { if (rxtp->traffic_class != ATM_NONE) { if (dev->rxer[channel]) { PRINTD (DBG_ERR|DBG_VCC, "VC already open for RX"); - return -EBUSY; + error = -EBUSY; } - error = hrz_open_rx (dev, channel); + if (!error) + error = hrz_open_rx (dev, channel); if (error) { kfree (vccp); + MOD_DEC_USE_COUNT; return error; } // this link allows RX frames through @@ -2556,7 +2564,6 @@ static int hrz_open (struct atm_vcc * atm_vcc, short vpi, int vci) { // indicate readiness set_bit(ATM_VF_READY,&atm_vcc->flags); - MOD_INC_USE_COUNT; return 0; } diff --git a/drivers/atm/uPD98402.c b/drivers/atm/uPD98402.c index 7c5f57579..8f0613334 100644 --- a/drivers/atm/uPD98402.c +++ b/drivers/atm/uPD98402.c @@ -141,7 +141,7 @@ static int uPD98402_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) return fetch_stats(dev,(struct sonet_stats *) arg, cmd == SONET_GETSTATZ); case SONET_SETFRAMING: - return set_framing(dev,(int) arg); + return set_framing(dev,(int) (long) arg); case SONET_GETFRAMING: return put_user(PRIV(dev)->framing,(int *) arg) ? -EFAULT : 0; |