summaryrefslogtreecommitdiffstats
path: root/drivers/atm
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-04-28 01:09:25 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-04-28 01:09:25 +0000
commitb9ba7aeb165cffecdffb60aec8c3fa8d590d9ca9 (patch)
tree42d07b0c7246ae2536a702e7c5de9e2732341116 /drivers/atm
parent7406b0a326f2d70ade2671c37d1beef62249db97 (diff)
Merge with 2.3.99-pre6.
Diffstat (limited to 'drivers/atm')
-rw-r--r--drivers/atm/Config.in12
-rw-r--r--drivers/atm/Makefile56
-rw-r--r--drivers/atm/ambassador.c8
-rw-r--r--drivers/atm/ambassador.h2
-rw-r--r--drivers/atm/atmdev_init.c20
-rw-r--r--drivers/atm/eni.c190
-rw-r--r--drivers/atm/eni.h5
-rw-r--r--drivers/atm/fore200e.c80
-rw-r--r--drivers/atm/fore200e.h15
-rw-r--r--drivers/atm/horizon.c13
-rw-r--r--drivers/atm/uPD98402.c2
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;