summaryrefslogtreecommitdiffstats
path: root/drivers/atm
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-03-27 23:54:12 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-03-27 23:54:12 +0000
commitd3e71cb08747743fce908122bab08b479eb403a5 (patch)
treecbec6948fdbdee9af81cf3ecfb504070d2745d7b /drivers/atm
parentfe7ff1706e323d0e5ed83972960a1ecc1ee538b3 (diff)
Merge with Linux 2.3.99-pre3.
Diffstat (limited to 'drivers/atm')
-rw-r--r--drivers/atm/Makefile28
-rw-r--r--drivers/atm/ambassador.c551
-rw-r--r--drivers/atm/ambassador.h22
-rw-r--r--drivers/atm/atmdev_init.c2
-rw-r--r--drivers/atm/atmtcp.c61
-rw-r--r--drivers/atm/eni.c271
-rw-r--r--drivers/atm/eni.h3
-rw-r--r--drivers/atm/fore200e.c174
-rw-r--r--drivers/atm/fore200e.h33
-rw-r--r--drivers/atm/horizon.c124
-rw-r--r--drivers/atm/horizon.h2
-rw-r--r--drivers/atm/idt77105.c64
-rw-r--r--drivers/atm/iphase.c161
-rw-r--r--drivers/atm/nicstar.c141
-rw-r--r--drivers/atm/nicstar.h2
-rw-r--r--drivers/atm/suni.c169
-rw-r--r--drivers/atm/suni.h4
-rw-r--r--drivers/atm/uPD98402.c123
-rw-r--r--drivers/atm/zatm.c26
19 files changed, 1128 insertions, 833 deletions
diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile
index f126bd232..8dbf1364a 100644
--- a/drivers/atm/Makefile
+++ b/drivers/atm/Makefile
@@ -3,15 +3,15 @@
# Makefile for the Linux network (ATM) device drivers.
#
-L_TARGET := atm.a
-L_OBJS := atmdev_init.o
+O_TARGET := atm.o
+O_OBJS := atmdev_init.o
M_OBJS :=
MOD_LIST_NAME := ATM_MODULES
include ../../.config
ifeq ($(CONFIG_ATM_ENI),y)
-L_OBJS += eni.o
+O_OBJS += eni.o
NEED_SUNI_LX = suni.o
else
ifeq ($(CONFIG_ATM_ENI),m)
@@ -21,8 +21,8 @@ else
endif
ifeq ($(CONFIG_ATM_ZATM),y)
-L_OBJS += zatm.o
-LX_OBJS += uPD98402.o
+O_OBJS += zatm.o
+OX_OBJS += uPD98402.o
else
ifeq ($(CONFIG_ATM_ZATM),m)
M_OBJS += zatm.o
@@ -31,11 +31,11 @@ else
endif
ifeq ($(CONFIG_ATM_TNETA1570),y)
-L_OBJS += tneta1570.o suni.o
+O_OBJS += tneta1570.o suni.o
endif
ifeq ($(CONFIG_ATM_NICSTAR),y)
-L_OBJS += nicstar.o
+O_OBJS += nicstar.o
ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y)
NEED_SUNI_LX = suni.o
endif
@@ -55,7 +55,7 @@ else
endif
ifeq ($(CONFIG_ATM_HORIZON),y)
-L_OBJS += horizon.o
+O_OBJS += horizon.o
else
ifeq ($(CONFIG_ATM_HORIZON),m)
M_OBJS += horizon.o
@@ -63,7 +63,7 @@ else
endif
ifeq ($(CONFIG_ATM_AMBASSADOR),y)
-L_OBJS += ambassador.o
+O_OBJS += ambassador.o
else
ifeq ($(CONFIG_ATM_AMBASSADOR),m)
M_OBJS += ambassador.o
@@ -71,7 +71,7 @@ else
endif
ifeq ($(CONFIG_ATM_TCP),y)
-L_OBJS += atmtcp.o
+O_OBJS += atmtcp.o
else
ifeq ($(CONFIG_ATM_TCP),m)
M_OBJS += atmtcp.o
@@ -79,7 +79,7 @@ else
endif
ifeq ($(CONFIG_ATM_IA),y)
-L_OBJS += iphase.o
+O_OBJS += iphase.o
NEED_SUNI_LX = suni.o
else
ifeq ($(CONFIG_ATM_IA),m)
@@ -91,13 +91,13 @@ endif
ifeq ($(NEED_SUNI_LX),)
MX_OBJS += $(NEED_SUNI_MX)
else
- LX_OBJS += $(NEED_SUNI_LX)
+ OX_OBJS += $(NEED_SUNI_LX)
endif
ifeq ($(NEED_IDT77105_LX),)
MX_OBJS += $(NEED_IDT77105_MX)
else
- LX_OBJS += $(NEED_IDT77105_LX)
+ OX_OBJS += $(NEED_IDT77105_LX)
endif
ifeq ($(CONFIG_ATM_FORE200E_PCA),y)
@@ -114,7 +114,7 @@ FORE200E_FW_OBJS += fore200e_sba_fw.o
endif
endif
ifeq ($(CONFIG_ATM_FORE200E),y)
-L_OBJS += fore200e.o $(FORE200E_FW_OBJS)
+O_OBJS += fore200e.o $(FORE200E_FW_OBJS)
else
ifeq ($(CONFIG_ATM_FORE200E),m)
M_OBJS += fore_200e.o
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 8ec9960c1..a71884db7 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -32,6 +32,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <asm/atomic.h>
#include <asm/io.h>
#include <asm/byteorder.h>
@@ -39,7 +40,7 @@
#define maintainer_string "Giuliano Procida at Madge Networks <gprocida@madge.com>"
#define description_string "Madge ATM Ambassador driver"
-#define version_string "1.2"
+#define version_string "1.2.4"
static inline void __init show_version (void) {
printk ("%s version %s\n", description_string, version_string);
@@ -97,8 +98,8 @@ static inline void __init show_version (void) {
The adapter is quite intelligent (fast) and has a simple interface
(few features). VPI is always zero, 1024 VCIs are supported. There
- is limited cell rate support. UBR channels can be kept and ABR
- (explicit rate, bu not EFCI) is supported. There is no CBR or VBR
+ is limited cell rate support. UBR channels can be capped and ABR
+ (explicit rate, but not EFCI) is supported. There is no CBR or VBR
support.
1. Driver <-> Adapter Communication
@@ -321,8 +322,29 @@ static unsigned int rxs_bs[NUM_RX_POOLS] = { 4080, 12240, 36720, 65535 };
static unsigned int rx_lats = 7;
static unsigned char pci_lat = 0;
+static const unsigned long onegigmask = -1 << 30;
+
/********** access to adapter **********/
+static inline void wr_plain (const amb_dev * dev, const u32 * addr, u32 data) {
+ PRINTD (DBG_FLOW|DBG_REGS, "wr: %p <- %08x", addr, data);
+#ifdef AMB_MMIO
+ dev->membase[addr - (u32 *) 0] = data;
+#else
+ outl (data, dev->iobase + (addr - (u32 *) 0) * sizeof(u32));
+#endif
+}
+
+static inline u32 rd_plain (const amb_dev * dev, const u32 * addr) {
+#ifdef AMB_MMIO
+ u32 data = dev->membase[addr - (u32 *) 0];
+#else
+ u32 data = inl (dev->iobase + (addr - (u32 *) 0) * sizeof(u32));
+#endif
+ PRINTD (DBG_FLOW|DBG_REGS, "rd: %p -> %08x", addr, data);
+ return data;
+}
+
static const amb_mem * const mem = 0;
static inline void wr_mem (const amb_dev * dev, const u32 * addr, u32 data) {
@@ -342,7 +364,7 @@ static inline u32 rd_mem (const amb_dev * dev, const u32 * addr) {
u32 be = inl (dev->iobase + (addr - (u32 *) 0) * sizeof(u32));
#endif
u32 data = be32_to_cpu (be);
- PRINTD (DBG_FLOW|DBG_REGS, "rd: %p -> %08x b[%08x]", addr, data, be);
+ PRINTD (DBG_FLOW|DBG_REGS, "rd: %p -> %08x b[%08x]", addr, data, be);
return data;
}
@@ -350,14 +372,18 @@ static inline u32 rd_mem (const amb_dev * dev, const u32 * addr) {
static inline void dump_registers (const amb_dev * dev) {
#ifdef DEBUG_AMBASSADOR
- // u32 * i;
- // PRINTD (DBG_REGS, "mailboxes: ");
- // for (i = (u32 *) 0x40; i < (u32 *) 0x60; ++i)
- // PRINTD (DBG_REGS, "%08x ", rd_mem (dev, i));
- PRINTD (DBG_REGS, "doorb %08x", rd_mem (dev, (u32 *) 0x60));
- PRINTD (DBG_REGS, "irqev %08x", rd_mem (dev, (u32 *) 0x64));
- PRINTD (DBG_REGS, "irqen %08x", rd_mem (dev, (u32 *) 0x68));
- PRINTD (DBG_REGS, "reset %08x", rd_mem (dev, (u32 *) 0x6c));
+ if (debug & DBG_REGS) {
+ u32 * i;
+ PRINTD (DBG_REGS, "reading PLX control: ");
+ for (i = (u32 *) 0x00; i < (u32 *) 0x30; ++i)
+ rd_mem (dev, i);
+ PRINTD (DBG_REGS, "reading mailboxes: ");
+ for (i = (u32 *) 0x40; i < (u32 *) 0x60; ++i)
+ rd_mem (dev, i);
+ PRINTD (DBG_REGS, "reading doorb irqev irqen reset:");
+ for (i = (u32 *) 0x60; i < (u32 *) 0x70; ++i)
+ rd_mem (dev, i);
+ }
#else
(void) dev;
#endif
@@ -414,8 +440,8 @@ static inline void dump_skb (char * prefix, unsigned int vc, struct sk_buff * sk
static inline int check_area (void * start, size_t length) {
// assumes length > 0
- const u32 fourmegmask = (-1)<<22;
- const u32 twofivesixmask = (-1)<<8;
+ const u32 fourmegmask = -1 << 22;
+ const u32 twofivesixmask = -1 << 8;
const u32 starthole = 0xE0000000;
u32 startaddress = virt_to_bus (start);
u32 lastaddress = startaddress+length-1;
@@ -435,7 +461,7 @@ static inline void amb_kfree_skb (struct sk_buff * skb) {
if (ATM_SKB(skb)->vcc->pop) {
ATM_SKB(skb)->vcc->pop (ATM_SKB(skb)->vcc, skb);
} else {
- dev_kfree_skb (skb);
+ dev_kfree_skb_any (skb);
}
}
@@ -448,7 +474,7 @@ static inline void tx_complete (amb_dev * dev, tx_out * tx) {
PRINTD (DBG_FLOW|DBG_TX, "tx_complete %p %p", dev, tx);
// VC layer stats
- ATM_SKB(skb)->vcc->stats->tx++;
+ atomic_inc(&ATM_SKB(skb)->vcc->stats->tx);
// free the descriptor
kfree (tx_descr);
@@ -489,7 +515,7 @@ static void rx_complete (amb_dev * dev, rx_out * rx) {
dump_skb ("<<<", vc, skb);
// VC layer stats
- atm_vcc->stats->rx++;
+ atomic_inc(&atm_vcc->stats->rx);
skb->stamp = xtime;
// end of our responsability
atm_vcc->push (atm_vcc, skb);
@@ -504,7 +530,7 @@ static void rx_complete (amb_dev * dev, rx_out * rx) {
} else {
PRINTK (KERN_INFO, "dropped over-size frame");
// should we count this?
- atm_vcc->stats->rx_drop++;
+ atomic_inc(&atm_vcc->stats->rx_drop);
}
} else {
@@ -524,7 +550,7 @@ static void rx_complete (amb_dev * dev, rx_out * rx) {
dev->stats.rx.unused++;
}
- dev_kfree_skb (skb);
+ dev_kfree_skb_any (skb);
return;
}
@@ -548,7 +574,8 @@ static void rx_complete (amb_dev * dev, rx_out * rx) {
// sometimes does 16-bit accesses (yuk yuk yuk)
static int command_do (amb_dev * dev, command * cmd) {
- volatile amb_cq * cq = &dev->cq;
+ amb_cq * cq = &dev->cq;
+ volatile amb_cq_ptrs * ptrs = &cq->ptrs;
command * my_slot;
unsigned long timeout;
@@ -562,18 +589,18 @@ static int command_do (amb_dev * dev, command * cmd) {
// if not full...
if (cq->pending < cq->maximum) {
// remember my slot for later
- my_slot = cq->in;
+ my_slot = ptrs->in;
PRINTD (DBG_CMD, "command in slot %p", my_slot);
dump_command (cmd);
// copy command in
- *cq->in = *cmd;
+ *ptrs->in = *cmd;
cq->pending++;
- cq->in = NEXTQ (cq->in, cq->start, cq->limit);
+ ptrs->in = NEXTQ (ptrs->in, ptrs->start, ptrs->limit);
// mail the command
- wr_mem (dev, &mem->mb.adapter.cmd_address, virt_to_bus (cq->in));
+ wr_mem (dev, &mem->mb.adapter.cmd_address, virt_to_bus (ptrs->in));
// prepare to wait for cq->pending milliseconds
// effectively one centisecond on i386
@@ -591,13 +618,13 @@ static int command_do (amb_dev * dev, command * cmd) {
}
// wait for my slot to be reached (all waiters are here or above, until...)
- while (cq->out != my_slot) {
- PRINTD (DBG_CMD, "wait: command slot (now at %p)", cq->out);
+ while (ptrs->out != my_slot) {
+ PRINTD (DBG_CMD, "wait: command slot (now at %p)", ptrs->out);
schedule();
}
// wait on my slot (... one gets to its slot, and... )
- while (cq->out->request != cpu_to_be32 (SRB_COMPLETE)) {
+ while (ptrs->out->request != cpu_to_be32 (SRB_COMPLETE)) {
PRINTD (DBG_CMD, "wait: command slot completion");
schedule();
}
@@ -607,12 +634,13 @@ static int command_do (amb_dev * dev, command * cmd) {
spin_lock (&cq->lock);
cq->pending--;
// copy command out
- *cmd = *cq->out;
- cq->out = NEXTQ (cq->out, cq->start, cq->limit);
+ *cmd = *ptrs->out;
+ ptrs->out = NEXTQ (ptrs->out, ptrs->start, ptrs->limit);
spin_unlock (&cq->lock);
return 0;
} else {
+ cq->filled++;
spin_unlock (&cq->lock);
return -EAGAIN;
}
@@ -796,7 +824,7 @@ static inline void fill_rx_pool (amb_dev * dev, unsigned char pool, int priority
return;
}
if (check_area (skb->data, skb->truesize)) {
- dev_kfree_skb (skb);
+ dev_kfree_skb_any (skb);
return;
}
// cast needed as there is no %? for pointer differences
@@ -805,14 +833,14 @@ static inline void fill_rx_pool (amb_dev * dev, unsigned char pool, int priority
rx.handle = virt_to_bus (skb);
rx.host_address = cpu_to_be32 (virt_to_bus (skb->data));
if (rx_give (dev, &rx, pool))
- dev_kfree_skb (skb);
+ dev_kfree_skb_any (skb);
}
return;
}
-// top up all RX pools (also called as a bottom half)
+// top up all RX pools (can also be called as a bottom half)
static void fill_rx_pools (amb_dev * dev) {
unsigned char pool;
@@ -827,25 +855,23 @@ static void fill_rx_pools (amb_dev * dev) {
/********** enable host interrupts **********/
static inline void interrupts_on (amb_dev * dev) {
- wr_mem (dev, &mem->interrupt_control,
- rd_mem (dev, &mem->interrupt_control)
- | AMB_INTERRUPT_BITS);
+ wr_plain (dev, &mem->interrupt_control,
+ rd_plain (dev, &mem->interrupt_control)
+ | AMB_INTERRUPT_BITS);
}
/********** disable host interrupts **********/
static inline void interrupts_off (amb_dev * dev) {
- wr_mem (dev, &mem->interrupt_control,
- rd_mem (dev, &mem->interrupt_control)
- &~ AMB_INTERRUPT_BITS);
+ wr_plain (dev, &mem->interrupt_control,
+ rd_plain (dev, &mem->interrupt_control)
+ &~ AMB_INTERRUPT_BITS);
}
/********** interrupt handling **********/
static void interrupt_handler (int irq, void * dev_id, struct pt_regs * pt_regs) {
amb_dev * dev = amb_devs;
- unsigned int irq_ok;
- unsigned int irq_ok_old;
(void) pt_regs;
PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler: %p", dev_id);
@@ -860,50 +886,56 @@ static void interrupt_handler (int irq, void * dev_id, struct pt_regs * pt_regs)
break;
dev = dev->prev;
}
+ // impossible - unless we add the device to our list after both
+ // registering the IRQ handler for it and enabling interrupts, AND
+ // the card generates an IRQ at startup - should not happen again
if (!dev) {
- PRINTD (DBG_IRQ, "irq not for me: %d", irq);
+ PRINTD (DBG_IRQ, "irq for unknown device: %d", irq);
return;
}
+ // impossible - unless we have memory corruption of dev or kernel
if (irq != dev->irq) {
PRINTD (DBG_IRQ|DBG_ERR, "irq mismatch: %d", irq);
return;
}
- // definitely for us
- irq_ok = 0;
- irq_ok_old = -1;
+ {
+ u32 interrupt = rd_plain (dev, &mem->interrupt);
- // perhaps disable interrupts? (disabled at PIC by Linux)
- // interrupts_off (dev);
+ // for us or someone else sharing the same interrupt
+ if (!interrupt) {
+ PRINTD (DBG_IRQ, "irq not for me: %d", irq);
+ return;
+ }
+
+ // definitely for us
+ PRINTD (DBG_IRQ, "FYI: interrupt was %08x", interrupt);
+ wr_plain (dev, &mem->interrupt, -1);
+ }
- while (irq_ok_old != irq_ok && irq_ok < 100) {
+ {
+ unsigned int irq_work = 0;
unsigned char pool;
- PRINTD (DBG_IRQ, "FYI: interrupt was %08x, work %u",
- rd_mem (dev, &mem->interrupt), irq_ok);
- wr_mem (dev, &mem->interrupt, -1);
- irq_ok_old = irq_ok;
for (pool = 0; pool < NUM_RX_POOLS; ++pool)
while (!rx_take (dev, pool))
- ++irq_ok;
+ ++irq_work;
while (!tx_take (dev))
- ++irq_ok;
- }
+ ++irq_work;
- if (irq_ok) {
-#if 0
- queue_task (&dev->bh, &tq_immediate);
- mark_bh (IMMEDIATE_BH);
+ if (irq_work) {
+#ifdef FILL_RX_POOLS_IN_BH
+ queue_task (&dev->bh, &tq_immediate);
+ mark_bh (IMMEDIATE_BH);
#else
- fill_rx_pools (dev);
+ fill_rx_pools (dev);
#endif
- PRINTD (DBG_IRQ, "work done: %u", irq_ok);
- } else {
- PRINTD (DBG_IRQ|DBG_WARN, "no work done");
+ PRINTD (DBG_IRQ, "work done: %u", irq_work);
+ } else {
+ PRINTD (DBG_IRQ|DBG_WARN, "no work done");
+ }
}
- // perhaps re-enable interrupts? (re-enabled at PIC by Linux)
- // interrupts_on (dev);
PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler done: %p", dev_id);
return;
}
@@ -913,6 +945,7 @@ static void interrupt_handler (int irq, void * dev_id, struct pt_regs * pt_regs)
#ifdef DEBUG_AMBASSADOR
static void dont_panic (amb_dev * dev) {
amb_cq * cq = &dev->cq;
+ volatile amb_cq_ptrs * ptrs = &cq->ptrs;
amb_txq * txq;
amb_rxq * rxq;
command * cmd;
@@ -926,10 +959,11 @@ static void dont_panic (amb_dev * dev) {
cli();
PRINTK (KERN_INFO, "don't panic - putting adapter into reset");
- wr_mem (dev, &mem->reset_control, rd_mem (dev, &mem->reset_control) | AMB_RESET);
+ wr_plain (dev, &mem->reset_control,
+ rd_plain (dev, &mem->reset_control) | AMB_RESET_BITS);
PRINTK (KERN_INFO, "marking all commands complete");
- for (cmd = cq->start; cmd < cq->limit; ++cmd)
+ for (cmd = ptrs->start; cmd < ptrs->limit; ++cmd)
cmd->request = cpu_to_be32 (SRB_COMPLETE);
PRINTK (KERN_INFO, "completing all TXs");
@@ -952,7 +986,7 @@ static void dont_panic (amb_dev * dev) {
if (rx == rxq->in.start)
rx = rxq->in.limit;
--rx;
- dev_kfree_skb (bus_to_virt (rx->handle));
+ dev_kfree_skb_any (bus_to_virt (rx->handle));
}
}
@@ -972,18 +1006,19 @@ static unsigned int make_rate (unsigned int rate, rounding r,
PRINTD (DBG_FLOW|DBG_QOS, "make_rate %u", rate);
- // rates in cells per second, ITU format (nasty 16bit fp)
+ // rates in cells per second, ITU format (nasty 16-bit floating-point)
// given 5-bit e and 9-bit m:
// rate = EITHER (1+m/2^9)*2^e OR 0
// bits = EITHER 1<<14 | e<<9 | m OR 0
// (bit 15 is "reserved", bit 14 "non-zero")
// smallest rate is 0 (special representation)
// largest rate is (1+511/512)*2^31 = 4290772992 (< 2^32-1)
+ // smallest non-zero rate is (1+0/512)*2^0 = 1 (> 0)
// simple algorithm:
// find position of top bit, this gives e
// remove top bit and shift (rounding if feeling clever) by 9-e
- // ucode bug: please don't set bit 14! 0 not representable
+ // ucode bug: please don't set bit 14! so 0 rate not representable
if (rate > 0xffc00000U) {
// larger than largest representable rate
@@ -1228,7 +1263,7 @@ static int amb_open (struct atm_vcc * atm_vcc, short vpi, int vci) {
// we are not really "immediately before allocating the connection
// identifier in hardware", but it will just have to do!
- atm_vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&atm_vcc->flags);
if (txtp->traffic_class != ATM_NONE) {
command cmd;
@@ -1303,7 +1338,7 @@ static int amb_open (struct atm_vcc * atm_vcc, short vpi, int vci) {
atm_vcc->vci = vci;
// indicate readiness
- atm_vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&atm_vcc->flags);
MOD_INC_USE_COUNT;
return 0;
@@ -1319,7 +1354,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
PRINTD (DBG_VCC|DBG_FLOW, "amb_close");
// indicate unreadiness
- atm_vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&atm_vcc->flags);
// disable TXing
if (atm_vcc->qos.txtp.traffic_class != ATM_NONE) {
@@ -1384,7 +1419,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
kfree (vcc);
// say the VPI/VCI is free again
- atm_vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
MOD_DEC_USE_COUNT;
}
@@ -1394,6 +1429,8 @@ static void amb_close (struct atm_vcc * atm_vcc) {
static int amb_ioctl (struct atm_dev * dev, unsigned int cmd, void * arg) {
unsigned short newdebug;
if (cmd == AMB_SETDEBUG) {
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
if (copy_from_user (&newdebug, arg, sizeof(newdebug))) {
// moan
return -EFAULT;
@@ -1402,6 +1439,8 @@ static int amb_ioctl (struct atm_dev * dev, unsigned int cmd, void * arg) {
return 0;
}
} else if (cmd == AMB_DONTPANIC) {
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
dont_panic (dev);
} else {
// moan
@@ -1453,7 +1492,7 @@ static int amb_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
}
if (check_area (skb->data, skb->len)) {
- atm_vcc->stats->tx_err++;
+ atomic_inc(&atm_vcc->stats->tx_err);
return -ENOMEM; // ?
}
@@ -1564,7 +1603,7 @@ static void amb_free_rx_skb (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
// at. However, I note that the ATM layer calls kfree_skb rather
// than dev_kfree_skb at this point so we are least covered as far
// as buffer locking goes. There may be bugs if pcap clones RX skbs.
-
+
PRINTD (DBG_FLOW|DBG_SKB, "amb_rx_free skb %p (atm_vcc %p, vcc %p)",
skb, atm_vcc, vcc);
@@ -1582,7 +1621,7 @@ static void amb_free_rx_skb (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
}
// just do what the ATM layer would have done
- kfree_skb (skb);
+ dev_kfree_skb_any (skb);
return;
}
@@ -1733,12 +1772,12 @@ static int __init create_queues (amb_dev * dev, unsigned int cmds,
cq->high = 0;
cq->maximum = cmds - 1;
- cq->start = cmd;
- cq->in = cmd;
- cq->out = cmd;
- cq->limit = cmd + cmds;
+ cq->ptrs.start = cmd;
+ cq->ptrs.in = cmd;
+ cq->ptrs.out = cmd;
+ cq->ptrs.limit = cmd + cmds;
- memory = cq->limit;
+ memory = cq->ptrs.limit;
}
PRINTD (DBG_TX, "TX queue pair at %p", memory);
@@ -1810,7 +1849,7 @@ static int __init create_queues (amb_dev * dev, unsigned int cmds,
static void destroy_queues (amb_dev * dev) {
// all queues assumed empty
- void * memory = dev->cq.start;
+ void * memory = dev->cq.ptrs.start;
// includes txq.in, txq.out, rxq[].in and rxq[].out
PRINTD (DBG_FLOW, "destroy_queues %p", dev);
@@ -1823,9 +1862,8 @@ static void destroy_queues (amb_dev * dev) {
/********** basic loader commands and error handling **********/
-static int __init do_loader_command (const amb_dev * dev, loader_command cmd,
- volatile loader_block * lb) {
-
+static int __init do_loader_command (volatile loader_block * lb,
+ const amb_dev * dev, loader_command cmd) {
// centisecond timeouts - guessing away here
unsigned int command_timeouts [] = {
[host_memory_test] = 15,
@@ -1939,8 +1977,9 @@ static int __init do_loader_command (const amb_dev * dev, loader_command cmd,
lb->result = 0;
lb->command = cpu_to_be32 (cmd);
lb->valid = cpu_to_be32 (DMA_VALID);
+ // dump_registers (dev);
// dump_loader_block (lb);
- wr_mem (dev, &mem->doorbell, virt_to_bus (lb));
+ wr_mem (dev, &mem->doorbell, virt_to_bus (lb) & ~onegigmask);
timeout = command_timeouts[cmd] * HZ/100;
@@ -1957,7 +1996,7 @@ static int __init do_loader_command (const amb_dev * dev, loader_command cmd,
if (cmd == adapter_start) {
// wait for start command to acknowledge...
timeout = HZ/10;
- while (rd_mem (dev, &mem->doorbell))
+ while (rd_plain (dev, &mem->doorbell))
if (timeout) {
timeout = schedule_timeout (timeout);
} else {
@@ -1975,27 +2014,27 @@ static int __init do_loader_command (const amb_dev * dev, loader_command cmd,
/* loader: determine loader version */
-static int __init get_loader_version (const amb_dev * dev, u32 * version) {
- loader_block lb;
+static int __init get_loader_version (loader_block * lb,
+ const amb_dev * dev, u32 * version) {
int res;
PRINTD (DBG_FLOW|DBG_LOAD, "get_loader_version");
- res = do_loader_command (dev, get_version_number, &lb);
+ res = do_loader_command (lb, dev, get_version_number);
if (res)
return res;
if (version)
- *version = be32_to_cpu (lb.payload.version);
+ *version = be32_to_cpu (lb->payload.version);
return 0;
}
-/* loader: read or verify memory data blocks */
+/* loader: write memory data blocks */
-static int __init loader_write (const amb_dev * dev, const u32 * data,
+static int __init loader_write (loader_block * lb,
+ const amb_dev * dev, const u32 * data,
u32 address, unsigned int count) {
unsigned int i;
- loader_block lb;
- transfer_block * tb = &lb.payload.transfer;
+ transfer_block * tb = &lb->payload.transfer;
PRINTD (DBG_FLOW|DBG_LOAD, "loader_write");
@@ -2005,14 +2044,16 @@ static int __init loader_write (const amb_dev * dev, const u32 * data,
tb->count = cpu_to_be32 (count);
for (i = 0; i < count; ++i)
tb->data[i] = cpu_to_be32 (data[i]);
- return do_loader_command (dev, write_adapter_memory, &lb);
+ return do_loader_command (lb, dev, write_adapter_memory);
}
-static int __init loader_verify (const amb_dev * dev, const u32 * data,
+/* loader: verify memory data blocks */
+
+static int __init loader_verify (loader_block * lb,
+ const amb_dev * dev, const u32 * data,
u32 address, unsigned int count) {
unsigned int i;
- loader_block lb;
- transfer_block * tb = &lb.payload.transfer;
+ transfer_block * tb = &lb->payload.transfer;
int res;
PRINTD (DBG_FLOW|DBG_LOAD, "loader_verify");
@@ -2021,7 +2062,7 @@ static int __init loader_verify (const amb_dev * dev, const u32 * data,
return -EINVAL;
tb->address = cpu_to_be32 (address);
tb->count = cpu_to_be32 (count);
- res = do_loader_command (dev, read_adapter_memory, &lb);
+ res = do_loader_command (lb, dev, read_adapter_memory);
if (!res)
for (i = 0; i < count; ++i)
if (tb->data[i] != cpu_to_be32 (data[i])) {
@@ -2031,13 +2072,14 @@ static int __init loader_verify (const amb_dev * dev, const u32 * data,
return res;
}
-static int __init loader_start (const amb_dev * dev, u32 address) {
- loader_block lb;
-
+/* loader: start microcode */
+
+static int __init loader_start (loader_block * lb,
+ const amb_dev * dev, u32 address) {
PRINTD (DBG_FLOW|DBG_LOAD, "loader_start");
- lb.payload.start = cpu_to_be32 (address);
- return do_loader_command (dev, adapter_start, &lb);
+ lb->payload.start = cpu_to_be32 (address);
+ return do_loader_command (lb, dev, adapter_start);
}
/********** reset card **********/
@@ -2047,19 +2089,21 @@ static int amb_reset (amb_dev * dev, int diags) {
PRINTD (DBG_FLOW|DBG_LOAD, "amb_reset");
- word = rd_mem (dev, &mem->reset_control);
-#if 0
- // clear all interrupts just in case
- wr_mem (dev, &mem->interrupt, -1);
-#endif
+ word = rd_plain (dev, &mem->reset_control);
// put card into reset state
- wr_mem (dev, &mem->reset_control, word | AMB_RESET);
+ wr_plain (dev, &mem->reset_control, word | AMB_RESET_BITS);
// wait a short while
udelay (10);
+#if 1
+ // put card into known good state
+ wr_plain (dev, &mem->interrupt_control, AMB_DOORBELL_BITS);
+ // clear all interrupts just in case
+ wr_plain (dev, &mem->interrupt, -1);
+#endif
// clear self-test done flag
- wr_mem (dev, &mem->mb.loader.ready, 0);
+ wr_plain (dev, &mem->mb.loader.ready, 0);
// take card out of reset state
- wr_mem (dev, &mem->reset_control, word &~ AMB_RESET);
+ wr_plain (dev, &mem->reset_control, word &~ AMB_RESET_BITS);
if (diags) {
unsigned long timeout;
@@ -2069,7 +2113,7 @@ static int amb_reset (amb_dev * dev, int diags) {
timeout = schedule_timeout (timeout);
// half second time-out
timeout = HZ/2;
- while (!rd_mem (dev, &mem->mb.loader.ready))
+ while (!rd_plain (dev, &mem->mb.loader.ready))
if (timeout) {
timeout = schedule_timeout (timeout);
} else {
@@ -2078,6 +2122,7 @@ static int amb_reset (amb_dev * dev, int diags) {
}
// get results of self-test
+ // XXX double check byte-order
word = rd_mem (dev, &mem->mb.loader.result);
if (word & SELF_TEST_FAILURE) {
void sf (const char * msg) {
@@ -2105,7 +2150,7 @@ static int amb_reset (amb_dev * dev, int diags) {
/********** transfer and start the microcode **********/
-static int __init ucode_init (amb_dev * dev) {
+static int __init ucode_init (loader_block * lb, amb_dev * dev) {
unsigned int i = 0;
unsigned int total = 0;
const u32 * pointer = ucode_data;
@@ -2125,10 +2170,10 @@ static int __init ucode_init (amb_dev * dev) {
else
words = MAX_TRANSFER_DATA;
total += words;
- res = loader_write (dev, pointer, address, words);
+ res = loader_write (lb, dev, pointer, address, words);
if (res)
return res;
- res = loader_verify (dev, pointer, address, words);
+ res = loader_verify (lb, dev, pointer, address, words);
if (res)
return res;
count -= words;
@@ -2138,7 +2183,7 @@ static int __init ucode_init (amb_dev * dev) {
i += 1;
}
if (*pointer == 0xdeadbeef) {
- return loader_start (dev, ucode_start);
+ return loader_start (lb, dev, ucode_start);
} else {
// cast needed as there is no %? for pointer differnces
PRINTD (DBG_LOAD|DBG_ERR,
@@ -2156,14 +2201,14 @@ static int __init amb_talk (amb_dev * dev) {
unsigned char pool;
unsigned long timeout;
- static inline u32 x (void * addr) {
+ u32 x (void * addr) {
return cpu_to_be32 (virt_to_bus (addr));
}
PRINTD (DBG_FLOW, "amb_talk %p", dev);
- a.command_start = x (dev->cq.start);
- a.command_end = x (dev->cq.limit);
+ a.command_start = x (dev->cq.ptrs.start);
+ a.command_end = x (dev->cq.ptrs.limit);
a.tx_start = x (dev->txq.in.start);
a.tx_end = x (dev->txq.in.limit);
a.txcom_start = x (dev->txq.out.start);
@@ -2192,7 +2237,7 @@ static int __init amb_talk (amb_dev * dev) {
timeout = schedule_timeout (timeout);
// give the adapter another half second?
timeout = HZ/2;
- while (rd_mem (dev, &mem->doorbell))
+ while (rd_plain (dev, &mem->doorbell))
if (timeout) {
timeout = schedule_timeout (timeout);
} else {
@@ -2259,38 +2304,55 @@ static void __init amb_esi (amb_dev * dev, u8 * esi) {
}
static int __init amb_init (amb_dev * dev) {
- u32 version;
+ loader_block lb;
+
+ void fixup_plx_window (void) {
+ // fix up the PLX-mapped window base address to match the block
+ unsigned long blb;
+ u32 mapreg;
+ blb = virt_to_bus (&lb);
+ // the kernel stack had better not ever cross a 1Gb boundary!
+ mapreg = rd_plain (dev, &mem->stuff[10]);
+ mapreg &= ~onegigmask;
+ mapreg |= blb & onegigmask;
+ wr_plain (dev, &mem->stuff[10], mapreg);
+ return;
+ }
- /* enable adapter doorbell */
- wr_mem (dev, &mem->interrupt_control,
- rd_mem (dev, &mem->interrupt_control)
- | AMB_DOORBELL_BITS);
+ u32 version;
if (amb_reset (dev, 1)) {
PRINTK (KERN_ERR, "card reset failed!");
- } else if (get_loader_version (dev, &version)) {
- PRINTK (KERN_INFO, "failed to get loader version");
} else {
- PRINTK (KERN_INFO, "loader version is %08x", version);
+ fixup_plx_window ();
- if (ucode_init (dev)) {
- PRINTK (KERN_ERR, "microcode failure");
- } else if (create_queues (dev, cmds, txs, rxs, rxs_bs)) {
- PRINTK (KERN_ERR, "failed to get memory for queues");
+ if (get_loader_version (&lb, dev, &version)) {
+ PRINTK (KERN_INFO, "failed to get loader version");
} else {
+ PRINTK (KERN_INFO, "loader version is %08x", version);
- if (amb_talk (dev)) {
- PRINTK (KERN_ERR, "adapter did not accept queues");
+ if (ucode_init (&lb, dev)) {
+ PRINTK (KERN_ERR, "microcode failure");
+ } else if (create_queues (dev, cmds, txs, rxs, rxs_bs)) {
+ PRINTK (KERN_ERR, "failed to get memory for queues");
} else {
- amb_ucode_version (dev);
- return 0;
- } /* amb_talk */
+ if (amb_talk (dev)) {
+ PRINTK (KERN_ERR, "adapter did not accept queues");
+ } else {
+
+ amb_ucode_version (dev);
+ return 0;
+
+ } /* amb_talk */
+
+ destroy_queues (dev);
+ } /* create_queues, ucode_init */
- destroy_queues (dev);
- } /* create_queues, ucode_init */
+ amb_reset (dev, 0);
+ } /* get_loader_version */
- } /* get_loader_version, amb_reset */
+ } /* amb_reset */
return -1;
}
@@ -2303,81 +2365,57 @@ static int __init amb_probe (void) {
amb_dev * dev;
// read resources from PCI configuration space
- u32 * membase = bus_to_virt
- (pci_dev->resource[0].start);
- u32 iobase = pci_dev->resource[1].start;
u8 irq = pci_dev->irq;
+ u32 * membase = bus_to_virt (pci_dev->resource[0].start);
+ u32 iobase = pci_dev->resource[1].start;
- // check IO region
- if (check_region (iobase, AMB_EXTENT)) {
- PRINTK (KERN_ERR, "IO range already in use!");
- return;
- }
-
- dev = kmalloc (sizeof(amb_dev), GFP_KERNEL);
- if (!dev) {
- // perhaps we should be nice: deregister all adapters and abort?
- PRINTK (KERN_ERR, "out of memory!");
- return;
- }
- memset (dev, 0, sizeof(amb_dev));
-
- // set up known dev items straight away
- dev->pci_dev = pci_dev;
-
- dev->iobase = iobase;
- dev->irq = irq;
- dev->membase = membase;
-
- // flags (currently only dead)
- dev->flags = 0;
-
- // Allocate cell rates (fibre)
- // ATM_OC3_PCR = 1555200000/8/270*260/53 - 29/53
- // to be really pedantic, this should be ATM_OC3c_PCR
- dev->tx_avail = ATM_OC3_PCR;
- dev->rx_avail = ATM_OC3_PCR;
-
-#if 0
- // initialise bottom half
- dev->bh.next = 0;
- dev->bh.sync = 0;
- dev->bh.routine = (void (*)(void *)) fill_rx_pools;
- dev->bh.data = dev;
-#endif
-
- // semaphore for txer/rxer modifications - we cannot use a
- // spinlock as the critical region needs to switch processes
- init_MUTEX (&dev->vcc_sf);
- // queue manipulation spinlocks; we want atomic reads and
- // writes to the queue descriptors (handles IRQ and SMP)
- // consider replacing "int pending" -> "atomic_t available"
- // => problem related to who gets to move queue pointers
- spin_lock_init (&dev->cq.lock);
- spin_lock_init (&dev->txq.lock);
- {
+ void setup_dev (void) {
unsigned char pool;
+ memset (dev, 0, sizeof(amb_dev));
+
+ // set up known dev items straight away
+ dev->pci_dev = pci_dev;
+
+ dev->iobase = iobase;
+ dev->irq = irq;
+ dev->membase = membase;
+
+ // flags (currently only dead)
+ dev->flags = 0;
+
+ // Allocate cell rates (fibre)
+ // ATM_OC3_PCR = 1555200000/8/270*260/53 - 29/53
+ // to be really pedantic, this should be ATM_OC3c_PCR
+ dev->tx_avail = ATM_OC3_PCR;
+ dev->rx_avail = ATM_OC3_PCR;
+
+#ifdef FILL_RX_POOLS_IN_BH
+ // initialise bottom half
+ dev->bh.next = 0;
+ dev->bh.sync = 0;
+ dev->bh.routine = (void (*)(void *)) fill_rx_pools;
+ dev->bh.data = dev;
+#endif
+
+ // semaphore for txer/rxer modifications - we cannot use a
+ // spinlock as the critical region needs to switch processes
+ init_MUTEX (&dev->vcc_sf);
+ // queue manipulation spinlocks; we want atomic reads and
+ // writes to the queue descriptors (handles IRQ and SMP)
+ // consider replacing "int pending" -> "atomic_t available"
+ // => problem related to who gets to move queue pointers
+ spin_lock_init (&dev->cq.lock);
+ spin_lock_init (&dev->txq.lock);
for (pool = 0; pool < NUM_RX_POOLS; ++pool)
spin_lock_init (&dev->rxq[pool].lock);
}
- // grab (but share) IRQ and install handler
- if (request_irq (irq, interrupt_handler, SA_SHIRQ, DEV_LABEL, dev)) {
- PRINTK (KERN_ERR, "request IRQ failed!");
- // free_irq is at "endif"
- } else {
-
+ void setup_pci_dev (void) {
unsigned char lat;
- // reserve IO region
- request_region (iobase, AMB_EXTENT, DEV_LABEL);
-
- PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at IO %x, IRQ %u, MEM %p",
- iobase, irq, membase);
-
// enable bus master accesses
pci_set_master (pci_dev);
-
+
// frobnicate latency (upwards, usually)
pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat);
if (pci_lat) {
@@ -2389,43 +2427,78 @@ static int __init amb_probe (void) {
"increasing", lat, MIN_PCI_LATENCY);
pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, MIN_PCI_LATENCY);
}
+ }
+
+ PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at"
+ " IO %x, IRQ %u, MEM %p", iobase, irq, membase);
+
+ // check IO region
+ if (check_region (iobase, AMB_EXTENT)) {
+ PRINTK (KERN_ERR, "IO range already in use!");
+ return;
+ }
+
+ dev = kmalloc (sizeof(amb_dev), GFP_KERNEL);
+ if (!dev) {
+ // perhaps we should be nice: deregister all adapters and abort?
+ PRINTK (KERN_ERR, "out of memory!");
+ return;
+ }
+
+ setup_dev();
+
+ if (amb_init (dev)) {
+ PRINTK (KERN_ERR, "adapter initialisation failure");
+ } else {
+
+ setup_pci_dev();
- if (amb_init (dev)) {
- PRINTK (KERN_ERR, "adapter initialisation failure");
- } else if (!(dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, 0))) {
- PRINTD (DBG_ERR, "failed to register Madge ATM adapter");
+ // grab (but share) IRQ and install handler
+ if (request_irq (irq, interrupt_handler, SA_SHIRQ, DEV_LABEL, dev)) {
+ PRINTK (KERN_ERR, "request IRQ failed!");
+ // free_irq is at "endif"
} else {
- PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p",
- dev->atm_dev->number, dev, dev->atm_dev);
- dev->atm_dev->dev_data = (void *) dev;
+ // reserve IO region
+ request_region (iobase, AMB_EXTENT, DEV_LABEL);
- // register our address
- amb_esi (dev, dev->atm_dev->esi);
-
- // 0 bits for vpi, 10 bits for vci
- dev->atm_dev->ci_range.vpi_bits = NUM_VPI_BITS;
- dev->atm_dev->ci_range.vci_bits = NUM_VCI_BITS;
-
- fill_rx_pools (dev);
-
- /* enable host interrupts */
- interrupts_on (dev);
-
- // update count and linked list
- ++devs;
- dev->prev = amb_devs;
- amb_devs = dev;
- // success
- return;
+ dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, NULL);
+ if (!dev->atm_dev) {
+ PRINTD (DBG_ERR, "failed to register Madge ATM adapter");
+ } else {
+
+ PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p",
+ dev->atm_dev->number, dev, dev->atm_dev);
+ dev->atm_dev->dev_data = (void *) dev;
+
+ // register our address
+ amb_esi (dev, dev->atm_dev->esi);
+
+ // 0 bits for vpi, 10 bits for vci
+ dev->atm_dev->ci_range.vpi_bits = NUM_VPI_BITS;
+ dev->atm_dev->ci_range.vci_bits = NUM_VCI_BITS;
+
+ // update count and linked list
+ ++devs;
+ dev->prev = amb_devs;
+ amb_devs = dev;
+
+ // enable host interrupts
+ interrupts_on (dev);
+
+ // success
+ return;
+
+ // not currently reached
+ atm_dev_deregister (dev->atm_dev);
+ } /* atm_dev_register */
- // not currently reached
- atm_dev_deregister (dev->atm_dev);
- } /* atm_dev_register, amb_init */
+ release_region (iobase, AMB_EXTENT);
+ free_irq (irq, dev);
+ } /* request_region, request_irq */
- release_region (iobase, AMB_EXTENT);
- free_irq (irq, dev);
- } /* request_region, request_irq */
+ amb_reset (dev, 0);
+ } /* amb_init */
kfree (dev);
} /* kmalloc, end-of-fn */
@@ -2529,7 +2602,6 @@ int init_module (void) {
show_version();
- // check arguments
amb_check_args();
// get the juice
@@ -2566,8 +2638,8 @@ void cleanup_module (void) {
PRINTD (DBG_INFO|DBG_INIT, "closing %p (atm_dev = %p)", dev, dev->atm_dev);
// the drain should not be necessary
drain_rx_pools (dev);
- amb_reset (dev, 0);
interrupts_off (dev);
+ amb_reset (dev, 0);
destroy_queues (dev);
atm_dev_deregister (dev->atm_dev);
free_irq (dev->irq, dev);
@@ -2594,7 +2666,6 @@ int __init amb_detect (void) {
show_version();
- // check arguments
amb_check_args();
// get the juice
diff --git a/drivers/atm/ambassador.h b/drivers/atm/ambassador.h
index 93e458644..11ce866da 100644
--- a/drivers/atm/ambassador.h
+++ b/drivers/atm/ambassador.h
@@ -237,8 +237,6 @@
#define FP_155_RATE 0x24b1
#define FP_25_RATE 0x1f9d
-#define AMB_RESET 0x40
-
/* #define VERSION_NUMBER 0x01000000 // initial release */
/* #define VERSION_NUMBER 0x01010000 // fixed startup probs PLX MB0 not cleared */
/* #define VERSION_NUMBER 0x01020000 // changed SUNI reset timings; allowed r/w onchip */
@@ -333,9 +331,10 @@ typedef struct {
u32 reset_control;
} amb_mem;
-/* IRQ (card to host) and doorbell (host to card) enable bits */
-#define AMB_INTERRUPT_BITS 0x00030000
-#define AMB_DOORBELL_BITS 0x00000300
+/* RESET bit, IRQ (card to host) and doorbell (host to card) enable bits */
+#define AMB_RESET_BITS 0x40000000
+#define AMB_INTERRUPT_BITS 0x00000300
+#define AMB_DOORBELL_BITS 0x00030000
/* loader commands */
@@ -543,14 +542,19 @@ typedef enum {
( (current)+1 < (limit) ? (current)+1 : (start) )
typedef struct {
- spinlock_t lock;
- unsigned int pending;
- unsigned int high;
- unsigned int maximum; // size - 1 (q implementation)
command * start;
command * in;
command * out;
command * limit;
+} amb_cq_ptrs;
+
+typedef struct {
+ spinlock_t lock;
+ unsigned int pending;
+ unsigned int high;
+ unsigned int filled;
+ unsigned int maximum; // size - 1 (q implementation)
+ amb_cq_ptrs ptrs;
} amb_cq;
typedef struct {
diff --git a/drivers/atm/atmdev_init.c b/drivers/atm/atmdev_init.c
index 357cbdbe0..443831a82 100644
--- a/drivers/atm/atmdev_init.c
+++ b/drivers/atm/atmdev_init.c
@@ -39,7 +39,7 @@ int __init atmdev_init(void)
devs = 0;
#ifdef CONFIG_ATM_ENI
- devs += eni_detect();
+// devs += eni_detect();
#endif
#ifdef CONFIG_ATM_ZATM
devs += zatm_detect();
diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
index cc13eb06f..64c25420e 100644
--- a/drivers/atm/atmtcp.c
+++ b/drivers/atm/atmtcp.c
@@ -7,7 +7,9 @@
#include <linux/wait.h>
#include <linux/atmdev.h>
#include <linux/atm_tcp.h>
+#include <linux/bitops.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
extern int atm_init_aal5(struct atm_vcc *vcc); /* "raw" AAL5 transport */
@@ -36,12 +38,14 @@ struct atmtcp_dev_data {
static int atmtcp_send_control(struct atm_vcc *vcc,int type,
- const struct atmtcp_control *msg,unsigned short flag)
+ const struct atmtcp_control *msg,int flag)
{
+ DECLARE_WAITQUEUE(wait,current);
struct atm_vcc *out_vcc;
struct sk_buff *skb;
struct atmtcp_control *new_msg;
- unsigned short old_flags;
+ int old_test;
+ int error = 0;
out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL;
if (!out_vcc) return -EUNATCH;
@@ -60,16 +64,21 @@ static int atmtcp_send_control(struct atm_vcc *vcc,int type,
new_msg->type = type;
memset(&new_msg->vcc,0,sizeof(atm_kptr_t));
*(struct atm_vcc **) &new_msg->vcc = vcc;
- old_flags = vcc->flags;
+ old_test = test_bit(flag,&vcc->flags);
out_vcc->push(out_vcc,skb);
- while (!((vcc->flags ^ old_flags) & flag)) {
+ add_wait_queue(&vcc->sleep,&wait);
+ while (test_bit(flag,&vcc->flags) == old_test) {
mb();
out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL;
- if (!out_vcc) return -EUNATCH;
- sleep_on(&vcc->sleep);
-
+ if (!out_vcc) {
+ error = -EUNATCH;
+ break;
+ }
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
}
- return 0;
+ remove_wait_queue(&vcc->sleep,&wait);
+ return error;
}
@@ -83,10 +92,10 @@ static int atmtcp_recv_control(const struct atmtcp_control *msg)
vcc->reply = msg->result;
switch (msg->type) {
case ATMTCP_CTRL_OPEN:
- vcc->flags ^= ATM_VF_READY;
+ change_bit(ATM_VF_READY,&vcc->flags);
break;
case ATMTCP_CTRL_CLOSE:
- vcc->flags ^= ATM_VF_ADDR;
+ change_bit(ATM_VF_ADDR,&vcc->flags);
break;
default:
printk(KERN_ERR "atmtcp_recv_control: unknown type %d\n",
@@ -120,8 +129,8 @@ static int atmtcp_v_open(struct atm_vcc *vcc,short vpi,int vci)
if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) return 0;
msg.type = ATMTCP_CTRL_OPEN;
msg.qos = vcc->qos;
- vcc->flags |= ATM_VF_ADDR;
- vcc->flags &= ~ATM_VF_READY; /* just in case ... */
+ set_bit(ATM_VF_ADDR,&vcc->flags);
+ clear_bit(ATM_VF_READY,&vcc->flags); /* just in case ... */
error = atmtcp_send_control(vcc,ATMTCP_CTRL_OPEN,&msg,ATM_VF_READY);
if (error) return error;
return vcc->reply;
@@ -136,7 +145,7 @@ static void atmtcp_v_close(struct atm_vcc *vcc)
msg.addr.sap_family = AF_ATMPVC;
msg.addr.sap_addr.vpi = vcc->vpi;
msg.addr.sap_addr.vci = vcc->vci;
- vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
(void) atmtcp_send_control(vcc,ATMTCP_CTRL_CLOSE,&msg,ATM_VF_ADDR);
}
@@ -168,13 +177,18 @@ static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb)
struct atmtcp_hdr *hdr;
int size;
+ if (vcc->qos.txtp.traffic_class == ATM_NONE) {
+ if (vcc->pop) vcc->pop(vcc,skb);
+ else dev_kfree_skb(skb);
+ return -EINVAL;
+ }
dev_data = PRIV(vcc->dev);
if (dev_data) out_vcc = dev_data->vcc;
if (!dev_data || !out_vcc) {
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb(skb);
if (dev_data) return 0;
- vcc->stats->tx_err++;
+ atomic_inc(&vcc->stats->tx_err);
return -ENOLINK;
}
size = skb->len+sizeof(struct atmtcp_hdr);
@@ -182,7 +196,7 @@ static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb)
if (!new_skb) {
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb(skb);
- vcc->stats->tx_err++;
+ atomic_inc(&vcc->stats->tx_err);
return -ENOBUFS;
}
hdr = (void *) skb_put(new_skb,sizeof(struct atmtcp_hdr));
@@ -193,8 +207,8 @@ static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb)
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb(skb);
out_vcc->push(out_vcc,new_skb);
- vcc->stats->tx++;
- out_vcc->stats->rx++;
+ atomic_inc(&vcc->stats->tx);
+ atomic_inc(&out_vcc->stats->rx);
return 0;
}
@@ -251,7 +265,7 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
out_vcc->qos.rxtp.traffic_class != ATM_NONE)
break;
if (!out_vcc) {
- vcc->stats->tx_err++;
+ atomic_inc(&vcc->stats->tx_err);
goto done;
}
skb_pull(skb,sizeof(struct atmtcp_hdr));
@@ -263,8 +277,8 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
new_skb->stamp = xtime;
memcpy(skb_put(new_skb,skb->len),skb->data,skb->len);
out_vcc->push(out_vcc,new_skb);
- vcc->stats->tx++;
- out_vcc->stats->rx++;
+ atomic_inc(&vcc->stats->tx);
+ atomic_inc(&out_vcc->stats->rx);
done:
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb(skb);
@@ -305,7 +319,7 @@ static struct atm_dev atmtcp_control_dev = {
999, /* dummy device number */
NULL,NULL, /* pretend not to have any VCCs */
NULL,NULL, /* no data */
- 0, /* no flags */
+ { 0 }, /* no flags */
NULL, /* no local address */
{ 0 } /* no ESI, no statistics */
};
@@ -318,7 +332,7 @@ static int atmtcp_create(int itf,int persist,struct atm_dev **result)
dev_data = kmalloc(sizeof(*dev_data),GFP_KERNEL);
if (!dev_data) return -ENOMEM;
- dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,0);
+ dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,NULL);
if (!dev) {
kfree(dev_data);
return itf == -1 ? -ENOMEM : -EBUSY;
@@ -352,7 +366,8 @@ int atmtcp_attach(struct atm_vcc *vcc,int itf)
}
PRIV(dev)->vcc = vcc;
bind_vcc(vcc,&atmtcp_control_dev);
- vcc->flags |= ATM_VF_READY | ATM_VF_META;
+ set_bit(ATM_VF_META,&vcc->flags);
+ set_bit(ATM_VF_READY,&vcc->flags);
vcc->dev_data = dev;
(void) atm_init_aal5(vcc); /* @@@ losing AAL in transit ... */
vcc->stats = &atmtcp_control_dev.stats.aal5;
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 081fcdfed..b3240d498 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -19,8 +19,10 @@
#include <linux/uio.h>
#include <linux/init.h>
#include <linux/atm_eni.h>
+#include <linux/bitops.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <asm/string.h>
#include <asm/byteorder.h>
@@ -526,7 +528,7 @@ static int rx_aal0(struct atm_vcc *vcc)
DPRINTK(DEV_LABEL "(itf %d): trashing empty cell\n",
vcc->dev->number);
length = 0;
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
}
else {
length = ATM_CELL_SIZE-1; /* no HEC */
@@ -581,7 +583,7 @@ static int rx_aal5(struct atm_vcc *vcc)
size);
}
eff = length = 0;
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
}
else {
size = (descr & MID_RED_COUNT)*(ATM_CELL_PAYLOAD >> 2);
@@ -598,7 +600,7 @@ static int rx_aal5(struct atm_vcc *vcc)
"(VCI=%d,length=%ld,size=%ld (descr 0x%lx))\n",
vcc->dev->number,vcc->vci,length,size << 2,descr);
length = eff = 0;
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
}
}
skb = eff ? atm_alloc_charge(vcc,eff << 2,GFP_ATOMIC) : NULL;
@@ -663,6 +665,7 @@ static void poll_rx(struct atm_dev *dev)
if (rx_vcc(curr)) return;
eni_dev->fast = ENI_VCC(curr)->next;
ENI_VCC(curr)->next = ENI_VCC_NOS;
+ barrier();
ENI_VCC(curr)->servicing--;
}
while ((curr = eni_dev->slow)) {
@@ -670,6 +673,7 @@ static void poll_rx(struct atm_dev *dev)
if (rx_vcc(curr)) return;
eni_dev->slow = ENI_VCC(curr)->next;
ENI_VCC(curr)->next = ENI_VCC_NOS;
+ barrier();
ENI_VCC(curr)->servicing--;
}
}
@@ -768,7 +772,7 @@ rx_dequeued++;
vcc->push(vcc,skb);
pushed++;
}
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
wake_up(&eni_dev->rx_wait);
}
@@ -836,10 +840,10 @@ static int open_rx_second(struct atm_vcc *vcc)
static void close_rx(struct atm_vcc *vcc)
{
- unsigned long here,flags;
+ DECLARE_WAITQUEUE(wait,current);
+ unsigned long here;
struct eni_dev *eni_dev;
struct eni_vcc *eni_vcc;
- u32 tmp;
eni_vcc = ENI_VCC(vcc);
if (!eni_vcc->rx) return;
@@ -858,25 +862,41 @@ static void close_rx(struct atm_vcc *vcc)
/* wait for RX queue to drain */
DPRINTK("eni_close: waiting for RX ...\n");
EVENT("RX closing\n",0,0);
- save_flags(flags);
- cli();
- while (eni_vcc->rxing || eni_vcc->servicing) {
+ add_wait_queue(&eni_dev->rx_wait,&wait);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ barrier();
+ for (;;) {
+ /* transition service->rx: rxing++, servicing-- */
+ if (!eni_vcc->servicing) {
+ barrier();
+ if (!eni_vcc->rxing) break;
+ }
EVENT("drain PDUs (rx %ld, serv %ld)\n",eni_vcc->rxing,
eni_vcc->servicing);
printk(KERN_INFO "%d+%d RX left\n",eni_vcc->servicing,
eni_vcc->rxing);
- sleep_on(&eni_dev->rx_wait);
+ schedule();
+ set_current_state(TASK_UNINTERRUPTIBLE);
}
- while (eni_vcc->rx_pos != (tmp =
- readl(eni_dev->vci+vcc->vci*16+4) & MID_VCI_READ)>>
- MID_VCI_READ_SHIFT) {
+ for (;;) {
+ unsigned long flags;
+ int at_end;
+ u32 tmp;
+
+ spin_lock_irqsave(&eni_dev->lock,flags);
+ 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);
+ if (at_end) break;
EVENT("drain discard (host 0x%lx, nic 0x%lx)\n",
eni_vcc->rx_pos,tmp);
printk(KERN_INFO "draining RX: host 0x%lx, nic 0x%x\n",
eni_vcc->rx_pos,tmp);
- sleep_on(&eni_dev->rx_wait);
+ schedule();
+ set_current_state(TASK_UNINTERRUPTIBLE);
}
- restore_flags(flags);
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&eni_dev->rx_wait,&wait);
}
eni_free_mem(eni_dev,eni_vcc->recv,eni_vcc->words << 2);
eni_vcc->rx = NULL;
@@ -1054,8 +1074,9 @@ static enum enq_res do_tx(struct sk_buff *skb)
* 1 DMA xfer & 2 DMA'ed bytes (protocol layering is for wimps :-)
*/
+ aal5 = vcc->qos.aal == ATM_AAL5;
/* check space in buffer */
- if (!(aal5 = vcc->qos.aal == ATM_AAL5))
+ if (!aal5)
size = (ATM_CELL_PAYLOAD >> 2)+TX_DESCR_SIZE;
/* cell without HEC plus segmentation header (includes
four-byte cell header) */
@@ -1207,7 +1228,7 @@ static void dequeue_tx(struct atm_dev *dev)
PCI_DMA_TODEVICE);
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb_irq(skb);
- vcc->stats->tx++;
+ atomic_inc(&vcc->stats->tx);
wake_up(&eni_dev->tx_wait);
dma_complete++;
}
@@ -1366,34 +1387,40 @@ static int open_tx_second(struct atm_vcc *vcc)
static void close_tx(struct atm_vcc *vcc)
{
+ DECLARE_WAITQUEUE(wait,current);
struct eni_dev *eni_dev;
struct eni_vcc *eni_vcc;
- unsigned long flags;
eni_vcc = ENI_VCC(vcc);
if (!eni_vcc->tx) return;
eni_dev = ENI_DEV(vcc->dev);
/* wait for TX queue to drain */
DPRINTK("eni_close: waiting for TX ...\n");
- save_flags(flags);
- cli();
- while (skb_peek(&eni_vcc->tx->backlog) || eni_vcc->txing) {
+ 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);
+ txing = skb_peek(&eni_vcc->tx->backlog) || eni_vcc->txing;
+ spin_unlock_irqrestore(&eni_dev->lock,flags);
+ if (!txing) break;
DPRINTK("%d TX left\n",eni_vcc->txing);
- sleep_on(&eni_dev->tx_wait);
- }
- /*
- * Looping a few times in here is probably far cheaper than keeping
- * track of TX completions all the time, so let's poll a bit ...
- */
- while (eni_in(MID_TX_RDPTR(eni_vcc->tx->index)) !=
- eni_in(MID_TX_DESCRSTART(eni_vcc->tx->index)))
schedule();
- restore_flags(flags);
-#if 0
- if (skb_peek(&eni_vcc->tx->backlog))
- printk(KERN_CRIT DEV_LABEL "SKBs in BACKLOG !!!\n");
-#endif
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&eni_dev->tx_wait,&wait);
if (eni_vcc->tx != eni_dev->ubr) {
+ /*
+ * Looping a few times in here is probably far cheaper than
+ * keeping track of TX completions all the time, so let's poll
+ * a bit ...
+ */
+ while (eni_in(MID_TX_RDPTR(eni_vcc->tx->index)) !=
+ eni_in(MID_TX_DESCRSTART(eni_vcc->tx->index)))
+ schedule();
eni_free_mem(eni_dev,eni_vcc->tx->send,eni_vcc->tx->words << 2);
eni_vcc->tx->send = 0;
eni_dev->tx_bw += eni_vcc->tx->reserved;
@@ -1496,28 +1523,36 @@ static void eni_int(int irq,void *dev_id,struct pt_regs *regs)
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);
tx_complete++;
- wake_up(&eni_dev->tx_wait);
+ 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 |
@@ -1532,7 +1567,7 @@ tx_complete++;
/*--------------------------------- entries ---------------------------------*/
-static const char *media_name[] __initdata = {
+static const char *media_name[] __devinitdata = {
"MMF", "SMF", "MMF", "03?", /* 0- 3 */
"UTP", "05?", "06?", "07?", /* 4- 7 */
"TAXI","09?", "10?", "11?", /* 8-11 */
@@ -1556,7 +1591,7 @@ static const char *media_name[] __initdata = {
} })
-static int __init get_esi_asic(struct atm_dev *dev)
+static int __devinit get_esi_asic(struct atm_dev *dev)
{
struct eni_dev *eni_dev;
unsigned char tonga;
@@ -1648,7 +1683,7 @@ static int __init get_esi_asic(struct atm_dev *dev)
#undef GET_SEPROM
-static int __init get_esi_fpga(struct atm_dev *dev,unsigned long base)
+static int __devinit get_esi_fpga(struct atm_dev *dev,unsigned long base)
{
unsigned long mac_base;
int i;
@@ -1659,7 +1694,7 @@ static int __init get_esi_fpga(struct atm_dev *dev,unsigned long base)
}
-static int __init eni_init(struct atm_dev *dev)
+static int __devinit eni_do_init(struct atm_dev *dev)
{
struct midway_eprom *eprom;
struct eni_dev *eni_dev;
@@ -1748,7 +1783,7 @@ static int __init eni_init(struct atm_dev *dev)
}
-static int __init eni_start(struct atm_dev *dev)
+static int __devinit eni_start(struct atm_dev *dev)
{
struct eni_dev *eni_dev;
unsigned long buf,buffer_mem;
@@ -1788,6 +1823,7 @@ static int __init eni_start(struct atm_dev *dev)
DPRINTK("vci 0x%lx,rx 0x%lx, tx 0x%lx,srv 0x%lx,buf 0x%lx\n",
eni_dev->vci,eni_dev->rx_dma,eni_dev->tx_dma,
eni_dev->service,buf);
+ spin_lock_init(&eni_dev->lock);
/* initialize memory management */
buffer_mem = eni_dev->mem-(buf-eni_dev->ram);
eni_dev->free_list_size = buffer_mem/MID_MIN_BUF_SIZE/2;
@@ -1830,14 +1866,14 @@ static void eni_close(struct atm_vcc *vcc)
{
DPRINTK(">eni_close\n");
if (!ENI_VCC(vcc)) return;
- vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
close_rx(vcc);
close_tx(vcc);
DPRINTK("eni_close: done waiting\n");
/* deallocate memory */
kfree(ENI_VCC(vcc));
ENI_VCC(vcc) = NULL;
- vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
/*foo();*/
}
@@ -1855,8 +1891,8 @@ static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci)
if (vcc->qos.txtp.traffic_class != ATM_NONE) {
for (walk = vcc->dev->vccs; walk;
walk = walk->next)
- if ((walk->flags & ATM_VF_ADDR) &&
- walk->vci == *vci &&
+ if (test_bit(ATM_VF_ADDR,&walk->flags)
+ && walk->vci == *vci &&
walk->qos.txtp.traffic_class !=
ATM_NONE)
break;
@@ -1872,7 +1908,7 @@ static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci)
return -EADDRINUSE;
if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0;
for (walk = vcc->dev->vccs; walk; walk = walk->next)
- if ((walk->flags & ATM_VF_ADDR) && walk->vci == *vci &&
+ if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vci == *vci &&
walk->qos.txtp.traffic_class != ATM_NONE)
return -EADDRINUSE;
return 0;
@@ -1887,19 +1923,19 @@ static int eni_open(struct atm_vcc *vcc,short vpi,int vci)
DPRINTK(">eni_open\n");
EVENT("eni_open\n",0,0);
- if (!(vcc->flags & ATM_VF_PARTIAL)) ENI_VCC(vcc) = NULL;
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) ENI_VCC(vcc) = NULL;
eni_dev = ENI_DEV(vcc->dev);
error = get_ci(vcc,&vpi,&vci);
if (error) return error;
vcc->vpi = vpi;
vcc->vci = vci;
if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC)
- vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&vcc->flags);
if (vcc->qos.aal != ATM_AAL0 && vcc->qos.aal != ATM_AAL5)
return -EINVAL;
DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi,
vcc->vci);
- if (!(vcc->flags & ATM_VF_PARTIAL)) {
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) {
eni_vcc = kmalloc(sizeof(struct eni_vcc),GFP_KERNEL);
if (!eni_vcc) return -ENOMEM;
ENI_VCC(vcc) = eni_vcc;
@@ -1922,7 +1958,7 @@ static int eni_open(struct atm_vcc *vcc,short vpi,int vci)
eni_close(vcc);
return error;
}
- vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&vcc->flags);
/* should power down SUNI while !ref_count @@@ */
return 0;
}
@@ -1953,8 +1989,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.
*/
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&eni_dev->lock,flags);
for (skb = eni_dev->tx_queue.next; skb !=
(struct sk_buff *) &eni_dev->tx_queue; skb = skb->next) {
unsigned long dsc;
@@ -1965,7 +2000,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);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&eni_dev->lock,flags);
return 0;
}
@@ -2049,14 +2084,13 @@ static int eni_send(struct atm_vcc *vcc,struct sk_buff *skb)
}
submitted++;
ATM_SKB(skb)->vcc = vcc;
- save_flags(flags);
- cli(); /* brute force */
+ 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++;
backlogged++;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&ENI_DEV(vcc->dev)->lock,flags);
return 0;
}
@@ -2206,79 +2240,86 @@ static const struct atmdev_ops ops = {
};
-int __init eni_detect(void)
+static int __devinit eni_init_one(struct pci_dev *pci_dev,
+ const struct pci_device_id *ent)
{
struct atm_dev *dev;
struct eni_dev *eni_dev;
- int devs,type;
- struct sk_buff *skb;
+ int error = -ENOMEM;
- DPRINTK("eni_detect\n");
- if (sizeof(skb->cb) < sizeof(struct eni_skb_prv)) {
- printk(KERN_ERR "eni_detect: skb->cb is too small (%d < %d)\n",
- sizeof(skb->cb),sizeof(struct eni_skb_prv));
- return 0;
- }
- eni_dev = (struct eni_dev *) kmalloc(sizeof(struct eni_dev),
- GFP_KERNEL);
+ DPRINTK("eni_init_one\n");
+ eni_dev = (struct eni_dev *) kmalloc(sizeof(struct eni_dev),GFP_KERNEL);
if (!eni_dev) return -ENOMEM;
- devs = 0;
- for (type = 0; type < 2; type++) {
- struct pci_dev *pci_dev;
-
- pci_dev = NULL;
- while ((pci_dev = pci_find_device(PCI_VENDOR_ID_EF,type ?
- PCI_DEVICE_ID_EF_ATM_ASIC : PCI_DEVICE_ID_EF_ATM_FPGA,
- pci_dev))) {
- if (!devs) {
- cpu_zeroes = pci_alloc_consistent(pci_dev,
- ENI_ZEROES_SIZE,&zeroes);
- if (!cpu_zeroes) {
- kfree(eni_dev);
- return -ENOMEM;
- }
- }
- dev = atm_dev_register(DEV_LABEL,&ops,-1,0);
- if (!dev) break;
- eni_dev->pci_dev = pci_dev;
- ENI_DEV(dev) = eni_dev;
- eni_dev->asic = type;
- if (eni_init(dev) || eni_start(dev)) {
- atm_dev_deregister(dev);
- break;
- }
- eni_dev->more = eni_boards;
- eni_boards = dev;
- devs++;
- eni_dev = (struct eni_dev *) kmalloc(sizeof(struct
- eni_dev),GFP_KERNEL);
- if (!eni_dev) break;
- }
- }
- if (!devs && cpu_zeroes) {
- pci_free_consistent(eni_dev->pci_dev,ENI_ZEROES_SIZE,
- cpu_zeroes,zeroes);
- cpu_zeroes = NULL;
- }
+ if (!cpu_zeroes) {
+ cpu_zeroes = pci_alloc_consistent(pci_dev,ENI_ZEROES_SIZE,
+ &zeroes);
+ if (!cpu_zeroes) goto out1;
+ }
+ dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL);
+ if (!dev) goto out2;
+ pci_dev->driver_data = dev;
+ eni_dev->pci_dev = pci_dev;
+ ENI_DEV(dev) = eni_dev;
+ eni_dev->asic = ent->driver_data;
+ error = eni_do_init(dev);
+ if (error) goto out3;
+ error = eni_start(dev);
+ if (error) goto out3;
+ eni_dev->more = eni_boards;
+ eni_boards = dev;
+ MOD_INC_USE_COUNT; /* @@@ we don't support unloading yet */
+ return 0;
+out3:
+ atm_dev_deregister(dev);
+out2:
+ pci_free_consistent(eni_dev->pci_dev,ENI_ZEROES_SIZE,cpu_zeroes,zeroes);
+ cpu_zeroes = NULL;
+out1:
kfree(eni_dev);
- return devs;
+ return error;
}
-#ifdef MODULE
+static struct pci_device_id eni_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_EF, PCI_DEVICE_ID_EF_ATM_FPGA, PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, 0 /* FPGA */ },
+ { PCI_VENDOR_ID_EF, PCI_DEVICE_ID_EF_ATM_ASIC, PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, 1 /* ASIC */ },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci,eni_pci_tbl);
+
-int init_module(void)
+static void __devexit eni_remove_one(struct pci_dev *pci_dev)
{
- if (!eni_detect()) {
- printk(KERN_ERR DEV_LABEL ": no adapter found\n");
- return -ENXIO;
+ /* grrr */
+}
+
+
+static struct pci_driver eni_driver = {
+ name: DEV_LABEL,
+ id_table: eni_pci_tbl,
+ probe: eni_init_one,
+ remove: eni_remove_one,
+};
+
+
+static int __init eni_init(void)
+{
+ struct sk_buff *skb; /* dummy for sizeof */
+
+ if (sizeof(skb->cb) < sizeof(struct eni_skb_prv)) {
+ printk(KERN_ERR "eni_detect: skb->cb is too small (%d < %d)\n",
+ sizeof(skb->cb),sizeof(struct eni_skb_prv));
+ return -EIO;
}
- MOD_INC_USE_COUNT;
- return 0;
+ if (pci_register_driver(&eni_driver) > 0) return 0;
+ pci_unregister_driver (&eni_driver);
+ return -ENODEV;
}
-void cleanup_module(void)
+static void __exit eni_cleanup(void)
{
/*
* Well, there's no way to get rid of the driver yet, so we don't
@@ -2286,4 +2327,6 @@ void cleanup_module(void)
*/
}
-#endif
+
+module_init(eni_init);
+module_exit(eni_cleanup);
diff --git a/drivers/atm/eni.h b/drivers/atm/eni.h
index 76d0dd482..23ba60fb1 100644
--- a/drivers/atm/eni.h
+++ b/drivers/atm/eni.h
@@ -12,6 +12,7 @@
#include <linux/skbuff.h>
#include <linux/time.h>
#include <linux/pci.h>
+#include <linux/spinlock.h>
#include "midway.h"
@@ -65,6 +66,8 @@ struct eni_vcc {
};
struct eni_dev {
+ /*-------------------------------- spinlock */
+ spinlock_t lock; /* sync with interrupt */
/*-------------------------------- 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 4c07f2e7f..96c022842 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -1,5 +1,5 @@
/*
- $Id: fore200e.c,v 1.1 2000/02/21 16:04:31 davem Exp $
+ $Id: fore200e.c,v 1.2 2000/03/21 21:19:24 davem Exp $
A FORE Systems 200E-series driver for ATM on Linux.
Christophe Lizzi (lizzi@cnam.fr), October 1999-February 2000.
@@ -35,6 +35,7 @@
#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>
@@ -43,6 +44,7 @@
#include <asm/dma.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#ifdef CONFIG_ATM_FORE200E_PCA
#include <linux/pci.h>
@@ -67,7 +69,7 @@
#define FORE200E_52BYTE_AAL0_SDU
#endif
-#define FORE200E_VERSION "0.2a"
+#define FORE200E_VERSION "0.2b"
#define FORE200E "fore200e: "
@@ -187,10 +189,10 @@ fore200e_kfree(void* chunk)
/* allocate and align a chunk of memory intended to hold the data behing exchanged
- between the driver and the adapter (using streaming DVMA on SBUS hosts) */
+ between the driver and the adapter (using streaming DVMA) */
static int
-fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int alignment)
+fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int alignment, int direction)
{
unsigned long offset = 0;
@@ -199,6 +201,7 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i
chunk->alloc_size = size + alignment;
chunk->align_size = size;
+ chunk->direction = direction;
chunk->alloc_addr = fore200e_kmalloc(chunk->alloc_size, GFP_KERNEL | GFP_DMA);
if (chunk->alloc_addr == NULL)
@@ -209,7 +212,7 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i
chunk->align_addr = chunk->alloc_addr + offset;
- chunk->dma_addr = fore200e->bus->dma_map(fore200e, chunk->align_addr, chunk->align_size);
+ chunk->dma_addr = fore200e->bus->dma_map(fore200e, chunk->align_addr, chunk->align_size, direction);
return 0;
}
@@ -220,7 +223,7 @@ fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, i
static void
fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
{
- fore200e->bus->dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size);
+ fore200e->bus->dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size, chunk->direction);
fore200e_kfree(chunk->alloc_addr);
}
@@ -463,34 +466,32 @@ static void fore200e_pca_write(u32 val, volatile u32* addr)
static u32
-fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size)
+fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction)
{
- u32 dma_addr = pci_map_single((struct pci_dev*)fore200e->bus_dev, virt_addr, size, PCI_DMA_BIDIRECTIONAL);
+ u32 dma_addr = pci_map_single((struct pci_dev*)fore200e->bus_dev, virt_addr, size, direction);
- DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d --> dma_addr = 0x%08x\n",
- virt_addr, size, dma_addr);
+ DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d, --> dma_addr = 0x%08x\n",
+ virt_addr, size, direction, dma_addr);
return dma_addr;
}
static void
-fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size)
+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\n", dma_addr, size);
+ 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,
- PCI_DMA_BIDIRECTIONAL);
+ pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction);
}
static void
-fore200e_pca_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size)
+fore200e_pca_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
{
- DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d\n", dma_addr, size);
+ DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
- pci_dma_sync_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size,
- PCI_DMA_BIDIRECTIONAL);
+ pci_dma_sync_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction);
}
@@ -511,10 +512,8 @@ fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int
chunk->align_addr = chunk->alloc_addr;
#else
- if (fore200e_chunk_alloc(fore200e, chunk, size * nbr, alignment) < 0)
+ if (fore200e_chunk_alloc(fore200e, chunk, size * nbr, alignment, FORE200E_DMA_BIDIRECTIONAL) < 0)
return -ENOMEM;
-
- chunk->dma_addr = fore200e_pca_dma_map(fore200e, chunk->align_addr, chunk->align_size);
#endif
return 0;
@@ -532,8 +531,6 @@ fore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
chunk->alloc_addr,
chunk->dma_addr);
#else
- fore200e_pca_dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size);
-
fore200e_chunk_free(fore200e, chunk);
#endif
}
@@ -685,7 +682,7 @@ fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom)
opcode.opcode = OPCODE_GET_PROM;
opcode.pad = 0;
- prom_dma = fore200e->bus->dma_map(fore200e, prom, sizeof(struct prom_data));
+ prom_dma = fore200e->bus->dma_map(fore200e, prom, sizeof(struct prom_data), FORE200E_DMA_FROMDEVICE);
fore200e->bus->write(prom_dma, &entry->cp_entry->cmd.prom_block.prom_haddr);
@@ -697,7 +694,7 @@ fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom)
*entry->status = STATUS_FREE;
- fore200e->bus->dma_unmap(fore200e, prom_dma, sizeof(struct prom_data));
+ fore200e->bus->dma_unmap(fore200e, prom_dma, sizeof(struct prom_data), FORE200E_DMA_FROMDEVICE);
if (ok == 0) {
printk(FORE200E "unable to get PROM data from device %s\n", fore200e->name);
@@ -748,31 +745,32 @@ fore200e_sba_write(u32 val, volatile u32* addr)
static u32
-fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size)
+fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction)
{
- u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size);
+ u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size, direction);
- DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d --> dma_addr = 0x%08x\n", virt_addr, size, dma_addr);
+ DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n",
+ virt_addr, size, direction, dma_addr);
return dma_addr;
}
static void
-fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size)
+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\n", dma_addr, size);
+ 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);
+ sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
}
static void
-fore200e_sba_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size)
+fore200e_sba_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
{
- DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d\n", dma_addr, size);
+ DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
- sbus_dma_sync_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size);
+ sbus_dma_sync_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
}
@@ -1002,7 +1000,8 @@ fore200e_irq_tx(struct fore200e* fore200e)
kfree(entry->data);
/* remove DMA mapping */
- fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length);
+ fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
+ FORE200E_DMA_TODEVICE);
/* notify tx completion */
if (entry->vcc->pop)
@@ -1012,9 +1011,9 @@ fore200e_irq_tx(struct fore200e* fore200e)
/* check error condition */
if (*entry->status & STATUS_ERROR)
- entry->vcc->stats->tx_err++;
+ atomic_inc(&entry->vcc->stats->tx_err);
else
- entry->vcc->stats->tx++;
+ atomic_inc(&entry->vcc->stats->tx);
*entry->status = STATUS_FREE;
@@ -1127,7 +1126,7 @@ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd)
if (skb == NULL) {
printk(FORE200E "unable to alloc new skb, rx PDU length = %d\n", pdu_len);
- vcc->stats->rx_drop++;
+ atomic_inc(&vcc->stats->rx_drop);
return;
}
@@ -1146,7 +1145,7 @@ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd)
buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle);
/* ensure DMA synchronisation */
- fore200e->bus->dma_sync(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length);
+ fore200e->bus->dma_sync(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, FORE200E_DMA_FROMDEVICE);
memcpy(skb_put(skb, rpd->rsd[ i ].length), buffer->data.align_addr, rpd->rsd[ i ].length);
}
@@ -1169,7 +1168,7 @@ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd)
}
vcc->push(vcc, skb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
@@ -1404,7 +1403,7 @@ fore200e_open(struct atm_vcc *vcc, short vpi, int vci)
if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC)
return 0;
- vcc->flags |= ATM_VF_ADDR;
+ 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; "
@@ -1467,7 +1466,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;
- vcc->flags |= ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
return 0;
}
@@ -1552,11 +1551,14 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
if(--retry > 0)
goto retry_here;
- vcc->stats->tx_err++;
+ atomic_inc(&vcc->stats->tx_err);
printk(FORE200E "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n",
fore200e->name, fore200e->cp_queues->heartbeat);
-
+ if (vcc->pop)
+ vcc->pop(vcc, skb);
+ else
+ dev_kfree_skb(skb);
return -EIO;
}
}
@@ -1584,6 +1586,10 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
if (entry->data == NULL) {
spin_unlock_irqrestore(&fore200e->tx_lock, flags);
+ if (vcc->pop)
+ vcc->pop(vcc, skb);
+ else
+ dev_kfree_skb(skb);
return -ENOMEM;
}
@@ -1591,11 +1597,11 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
if (skb_len < tx_len)
memset(entry->data + skb_len, 0x00, tx_len - skb_len);
- tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, entry->data, tx_len);
+ tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, entry->data, tx_len, FORE200E_DMA_TODEVICE);
}
else {
entry->data = NULL;
- tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, skb_data, tx_len);
+ tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, skb_data, tx_len, FORE200E_DMA_TODEVICE);
}
tpd->tsd[ 0 ].length = tx_len;
@@ -1606,7 +1612,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
spin_unlock_irqrestore(&fore200e->tx_lock, flags);
/* ensure DMA synchronisation */
- fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length);
+ 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),
@@ -1661,27 +1667,29 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
int ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 10);
- fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length);
+ fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
+ FORE200E_DMA_TODEVICE);
- if (ok == 0) {
- printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci);
-
- entry->vcc->stats->tx_err++;
- return -EIO;
- }
- entry->vcc->stats->tx++;
-
- DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci);
-
/* free tmp copy of misaligned data */
if (entry->data)
kfree(entry->data);
-
+
/* notify tx completion */
if (vcc->pop)
vcc->pop(vcc, skb);
else
dev_kfree_skb(skb);
+
+ if (ok == 0) {
+ printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci);
+
+ atomic_inc(&entry->vcc->stats->tx_err);
+ return -EIO;
+ }
+ atomic_inc(&entry->vcc->stats->tx);
+
+ DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci);
+
}
#endif
@@ -1704,7 +1712,7 @@ fore200e_getstats(struct fore200e* fore200e)
return -ENOMEM;
}
- stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, sizeof(struct stats));
+ stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, sizeof(struct stats), FORE200E_DMA_FROMDEVICE);
FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD);
@@ -1721,7 +1729,7 @@ fore200e_getstats(struct fore200e* fore200e)
*entry->status = STATUS_FREE;
- fore200e->bus->dma_unmap(fore200e, stats_dma_addr, sizeof(struct stats));
+ fore200e->bus->dma_unmap(fore200e, stats_dma_addr, sizeof(struct stats), FORE200E_DMA_FROMDEVICE);
if (ok == 0) {
printk(FORE200E "unable to get statistics from device %s\n", fore200e->name);
@@ -1766,7 +1774,7 @@ fore200e_get_oc3(struct fore200e* fore200e, struct oc3_regs* regs)
int ok;
u32 oc3_regs_dma_addr;
- oc3_regs_dma_addr = fore200e->bus->dma_map(fore200e, regs, sizeof(struct oc3_regs));
+ oc3_regs_dma_addr = fore200e->bus->dma_map(fore200e, regs, sizeof(struct oc3_regs), FORE200E_DMA_FROMDEVICE);
FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD);
@@ -1785,7 +1793,7 @@ fore200e_get_oc3(struct fore200e* fore200e, struct oc3_regs* regs)
*entry->status = STATUS_FREE;
- fore200e->bus_dma_unmap(fore200e, oc3_regs_dma_addr, sizeof(struct oc3_regs));
+ fore200e->bus->dma_unmap(fore200e, oc3_regs_dma_addr, sizeof(struct oc3_regs), FORE200E_DMA_FROMDEVICE);
if (ok == 0) {
printk(FORE200E "unable to get OC-3 regs of device %s\n", fore200e->name);
@@ -1842,16 +1850,16 @@ fore200e_setloop(struct fore200e* fore200e, int loop_mode)
switch (loop_mode) {
- case SUNI_LM_NONE:
+ case ATM_LM_NONE:
mct_value = 0;
mct_mask = SUNI_MCT_DLE | SUNI_MCT_LLE;
break;
- case SUNI_LM_DIAG:
+ case ATM_LM_LOC_PHY:
mct_value = mct_mask = SUNI_MCT_DLE;
break;
- case SUNI_LM_LOOP:
+ case ATM_LM_RMT_PHY:
mct_value = mct_mask = SUNI_MCT_LLE;
break;
@@ -1921,12 +1929,16 @@ fore200e_ioctl(struct atm_dev* dev, unsigned int cmd, void* arg)
case SONET_GETDIAG:
return put_user(0, (int*)arg) ? -EFAULT : 0;
-
- case SUNI_SETLOOP:
+
+ case ATM_SETLOOP:
return fore200e_setloop(fore200e, (int)(unsigned long)arg);
- case SUNI_GETLOOP:
+ case ATM_GETLOOP:
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 -ENOSYS; /* not implemented */
@@ -1967,7 +1979,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);
- vcc->flags |= ATM_VF_HASQOS;
+ set_bit(ATM_VF_HASQOS,&vcc->flags);
return 0;
}
@@ -2051,7 +2063,8 @@ fore200e_alloc_rx_buf(struct fore200e* fore200e)
/* allocate the receive buffer body */
if (fore200e_chunk_alloc(fore200e,
- &buffer[ i ].data, size, fore200e->bus->buffer_alignment) < 0) {
+ &buffer[ i ].data, size, fore200e->bus->buffer_alignment,
+ FORE200E_DMA_FROMDEVICE) < 0) {
while (i > 0)
fore200e_chunk_free(fore200e, &buffer[ --i ].data);
@@ -2485,7 +2498,8 @@ fore200e_register(struct fore200e* fore200e)
DPRINTK(2, "device %s being registered\n", fore200e->name);
- atm_dev = atm_dev_register(fore200e->bus->proc_name, &fore200e_ops, -1, 0);
+ atm_dev = atm_dev_register(fore200e->bus->proc_name, &fore200e_ops, -1,
+ NULL);
if (atm_dev == NULL) {
printk(FORE200E "unable to register device %s\n", fore200e->name);
return -ENODEV;
@@ -2690,17 +2704,29 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
static const char* oc3_mode[] = {
"normal operation",
"diagnostic loopback",
- "line loopback"
+ "line loopback",
+ "unknown"
};
u32 fw_release = fore200e->bus->read(&fore200e->cp_queues->fw_release);
u32 mon960_release = fore200e->bus->read(&fore200e->cp_queues->mon960_release);
u32 oc3_revision = fore200e->bus->read(&fore200e->cp_queues->oc3_revision);
u32 media_index = FORE200E_MEDIA_INDEX(fore200e->bus->read(&fore200e->cp_queues->media_type));
+ u32 oc3_index;
if (media_index < 0 || media_index > 4)
media_index = 5;
+ switch(fore200e->loop_mode) {
+ case ATM_LM_NONE: oc3_index = 0;
+ break;
+ case ATM_LM_LOC_PHY: oc3_index = 1;
+ break;
+ case ATM_LM_RMT_PHY: oc3_index = 2;
+ break;
+ default: oc3_index = 3;
+ }
+
return sprintf(page,
" firmware release:\t\t%d.%d.%d\n"
" monitor release:\t\t%d.%d\n"
@@ -2711,7 +2737,7 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
mon960_release >> 16, mon960_release << 16 >> 16,
media_name[ media_index ],
oc3_revision,
- oc3_mode[ fore200e->loop_mode ]);
+ oc3_mode[ oc3_index ]);
}
if (!left--) {
diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h
index eea20162b..f29fbde97 100644
--- a/drivers/atm/fore200e.h
+++ b/drivers/atm/fore200e.h
@@ -2,6 +2,7 @@
#define _FORE200E_H
#ifdef __KERNEL__
+#include <linux/config.h>
/* rx buffer sizes */
@@ -559,6 +560,7 @@ typedef struct chunk {
void* alloc_addr; /* base address of allocated chunk */
void* align_addr; /* base address of aligned chunk */
u32 dma_addr; /* DMA address of aligned chunk */
+ int direction; /* direction of DMA mapping */
u32 alloc_size; /* length of allocated chunk */
u32 align_size; /* length of aligned chunk */
} chunk_t;
@@ -796,9 +798,9 @@ typedef struct fore200e_bus {
const unsigned int* fw_size; /* address of firmware data size */
u32 (*read)(volatile u32*);
void (*write)(u32, volatile u32*);
- u32 (*dma_map)(struct fore200e*, void*, int);
- void (*dma_unmap)(struct fore200e*, u32, int);
- void (*dma_sync)(struct fore200e*, u32, int);
+ u32 (*dma_map)(struct fore200e*, void*, int, int);
+ void (*dma_unmap)(struct fore200e*, u32, int, int);
+ void (*dma_sync)(struct fore200e*, u32, int, int);
int (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int);
void (*dma_chunk_free)(struct fore200e*, struct chunk*);
struct fore200e* (*detect)(const struct fore200e_bus*, int);
@@ -814,6 +816,31 @@ typedef struct fore200e_bus {
} fore200e_bus_t;
+#if defined(CONFIG_ATM_FORE200E_SBA)
+# if defined(CONFIG_ATM_FORE200E_PCA)
+# if (PCI_DMA_BIDIRECTIONAL == SBUS_DMA_BIDIRECTIONAL) && \
+ (PCI_DMA_TODEVICE == SBUS_DMA_TODEVICE) && \
+ (PCI_DMA_FROMDEVICE == SBUS_DMA_FROMDEVICE)
+# define FORE200E_DMA_BIDIRECTIONAL PCI_DMA_BIDIRECTIONAL
+# define FORE200E_DMA_TODEVICE PCI_DMA_TODEVICE
+# define FORE200E_DMA_FROMDEVICE PCI_DMA_FROMDEVICE
+# 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!
+# endif
+# else
+# define FORE200E_DMA_BIDIRECTIONAL SBA_DMA_BIDIRECTIONAL
+# define FORE200E_DMA_TODEVICE SBA_DMA_TODEVICE
+# define FORE200E_DMA_FROMDEVICE SBA_DMA_FROMDEVICE
+# endif
+#else
+# define FORE200E_DMA_BIDIRECTIONAL PCI_DMA_BIDIRECTIONAL
+# define FORE200E_DMA_TODEVICE PCI_DMA_TODEVICE
+# define FORE200E_DMA_FROMDEVICE PCI_DMA_FROMDEVICE
+#endif
+
+
/* per-device data */
typedef struct fore200e {
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
index 0a412667e..f0dff7011 100644
--- a/drivers/atm/horizon.c
+++ b/drivers/atm/horizon.c
@@ -42,6 +42,7 @@
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <asm/string.h>
#include <asm/byteorder.h>
@@ -50,7 +51,7 @@
#define maintainer_string "Giuliano Procida at Madge Networks <gprocida@madge.com>"
#define description_string "Madge ATM Horizon [Ultra] driver"
-#define version_string "1.2"
+#define version_string "1.2.1"
static inline void __init show_version (void) {
printk ("%s version %s\n", description_string, version_string);
@@ -246,7 +247,7 @@ static inline void __init show_version (void) {
Atomic test and set tx_busy until we succeed; we should implement
some sort of timeout so that tx_busy will never be stuck at true.
- If no TX channel is setup for this VC we wait for an idle one (if
+ If no TX channel is set up for this VC we wait for an idle one (if
necessary) and set it up.
At this point we have a TX channel ready for use. We wait for enough
@@ -276,7 +277,7 @@ static inline void __init show_version (void) {
available handler is locked out over the same period.
Data available on the card triggers an interrupt. If the data is not
- suitable for out existing RX channels or we cannot allocate a buffer
+ suitable for our existing RX channels or we cannot allocate a buffer
it is flushed. Otherwise an RX receive is scheduled. Multiple RX
transfers may be scheduled for the same frame.
@@ -321,7 +322,7 @@ static inline void __init show_version (void) {
and the frame continues to be received.
The solution is to make sure any received frames are flushed when
- ready. This is currently done just before the solution to 3.
+ ready. This is currently done just before the solution to 2.
4. PCI bus (original Horizon only, fixed in Ultra)
@@ -608,7 +609,7 @@ static int make_rate (const hrz_dev * dev, u32 c, rounding r,
u32 pre;
// local fn to build the timer bits
- inline int set_cr (void) {
+ int set_cr (void) {
// paranoia
if (div > CR_MAXD || (!pre) || pre > 1<<CR_MAXPEXP) {
PRINTD (DBG_QOS, "set_cr internal failure: d=%u p=%u",
@@ -813,7 +814,7 @@ static inline void hrz_kfree_skb (struct sk_buff * skb) {
if (ATM_SKB(skb)->vcc->pop) {
ATM_SKB(skb)->vcc->pop (ATM_SKB(skb)->vcc, skb);
} else {
- dev_kfree_skb (skb);
+ dev_kfree_skb_any (skb);
}
}
@@ -961,12 +962,11 @@ static void hrz_close_rx (hrz_dev * dev, u16 vc) {
static void rx_schedule (hrz_dev * dev, int irq) {
unsigned int rx_bytes;
- int pio_instead;
+ int pio_instead = 0;
#ifndef TAILRECURSIONWORKS
- do {
+ pio_instead = 1;
+ while (pio_instead) {
#endif
- pio_instead = 0;
-
// bytes waiting for RX transfer
rx_bytes = dev->rx_bytes;
@@ -1047,7 +1047,7 @@ static void rx_schedule (hrz_dev * dev, int irq) {
{
struct atm_vcc * vcc = ATM_SKB(skb)->vcc;
// VC layer stats
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
skb->stamp = xtime;
// end of our responsability
vcc->push (vcc, skb);
@@ -1078,12 +1078,12 @@ static void rx_schedule (hrz_dev * dev, int irq) {
#ifdef TAILRECURSIONWORKS
// and we all bless optimised tail calls
if (pio_instead)
- rx_schedule (dev, 0);
+ return rx_schedule (dev, 0);
return;
#else
// grrrrrrr!
irq = 0;
- } while (pio_instead);
+ }
return;
#endif
}
@@ -1130,11 +1130,11 @@ static void tx_schedule (hrz_dev * const dev, int irq) {
int append_desc = 0;
- int pio_instead;
+ int pio_instead = 0;
#ifndef TAILRECURSIONWORKS
- do {
+ pio_instead = 1;
+ while (pio_instead) {
#endif
- pio_instead = 0;
// bytes in current region waiting for TX transfer
tx_bytes = dev->tx_bytes;
@@ -1201,7 +1201,7 @@ static void tx_schedule (hrz_dev * const dev, int irq) {
dev->tx_iovec = 0;
// VC layer stats
- ATM_SKB(skb)->vcc->stats->tx++;
+ atomic_inc(&ATM_SKB(skb)->vcc->stats->tx);
// free the skb
hrz_kfree_skb (skb);
@@ -1236,12 +1236,12 @@ static void tx_schedule (hrz_dev * const dev, int irq) {
#ifdef TAILRECURSIONWORKS
// and we all bless optimised tail calls
if (pio_instead)
- tx_schedule (dev, 0);
+ return tx_schedule (dev, 0);
return;
#else
// grrrrrrr!
irq = 0;
- } while (pio_instead);
+ }
return;
#endif
}
@@ -1340,37 +1340,33 @@ static inline void rx_data_av_handler (hrz_dev * dev) {
if (atm_vcc->qos.rxtp.traffic_class != ATM_NONE) {
if (rx_len <= atm_vcc->qos.rxtp.max_sdu) {
- struct sk_buff *skb = atm_alloc_charge(atm_vcc,rx_len,GFP_ATOMIC);
-
- // If everyone has to call atm_pdu2... why isn't it part of
- // atm_charge? B'cos some people already have skb->truesize!
- // WA: well. even if they think they do, they might not ... :-)
-
- if (skb) {
- // remember this so we can push it later
- dev->rx_skb = skb;
- // remember this so we can flush it later
- dev->rx_channel = rx_channel;
-
- // prepare socket buffer
- skb_put (skb, rx_len);
- ATM_SKB(skb)->vcc = atm_vcc;
-
- // simple transfer
- // dev->rx_regions = 0;
- // dev->rx_iovec = 0;
- dev->rx_bytes = rx_len;
- dev->rx_addr = skb->data;
- PRINTD (DBG_RX, "RX start simple transfer (addr %p, len %d)",
- skb->data, rx_len);
-
- // do the business
- rx_schedule (dev, 0);
- return;
-
- } else {
- PRINTD (DBG_INFO, "failed to get skb");
- }
+
+ struct sk_buff * skb = atm_alloc_charge (atm_vcc, rx_len, GFP_ATOMIC);
+ if (skb) {
+ // remember this so we can push it later
+ dev->rx_skb = skb;
+ // remember this so we can flush it later
+ dev->rx_channel = rx_channel;
+
+ // prepare socket buffer
+ skb_put (skb, rx_len);
+ ATM_SKB(skb)->vcc = atm_vcc;
+
+ // simple transfer
+ // dev->rx_regions = 0;
+ // dev->rx_iovec = 0;
+ dev->rx_bytes = rx_len;
+ dev->rx_addr = skb->data;
+ PRINTD (DBG_RX, "RX start simple transfer (addr %p, len %d)",
+ skb->data, rx_len);
+
+ // do the business
+ rx_schedule (dev, 0);
+ return;
+
+ } else {
+ PRINTD (DBG_SKB|DBG_WARN, "failed to get skb");
+ }
} else {
PRINTK (KERN_INFO, "frame received on TX-only VC %x", rx_channel);
@@ -1662,6 +1658,7 @@ static int hrz_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
if (!channel) {
PRINTD (DBG_ERR|DBG_TX, "attempt to transmit on zero (rx_)channel");
+ hrz_kfree_skb (skb);
return -EIO;
}
@@ -1699,9 +1696,11 @@ static int hrz_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
#endif
// wait until TX is free and grab lock
- if (tx_hold (dev))
+ if (tx_hold (dev)) {
+ hrz_kfree_skb (skb);
return -ERESTARTSYS;
-
+ }
+
// Wait for enough space to be available in transmit buffer memory.
// should be number of cells needed + 2 (according to hardware docs)
@@ -1722,6 +1721,7 @@ static int hrz_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
PRINTD (DBG_TX|DBG_ERR, "spun out waiting for tx buffers, got %d of %d",
free_buffers, buffers_required);
tx_release (dev);
+ hrz_kfree_skb (skb);
return -ERESTARTSYS;
}
}
@@ -1820,12 +1820,12 @@ static u16 __init read_bia (const hrz_dev * dev, u16 addr) {
u32 ctrl = rd_regl (dev, CONTROL_0_REG);
- inline void WRITE_IT_WAIT (void) {
+ void WRITE_IT_WAIT (void) {
wr_regl (dev, CONTROL_0_REG, ctrl);
udelay (5);
}
- inline void CLOCK_IT (void) {
+ void CLOCK_IT (void) {
// DI must be valid around rising SK edge
ctrl &= ~SEEPROM_SK;
WRITE_IT_WAIT();
@@ -2530,7 +2530,7 @@ static int hrz_open (struct atm_vcc * atm_vcc, short vpi, int vci) {
// this is "immediately before allocating the connection identifier
// in hardware" - so long as the next call does not fail :)
- atm_vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&atm_vcc->flags);
// any errors here are very serious and should never occur
@@ -2554,7 +2554,7 @@ static int hrz_open (struct atm_vcc * atm_vcc, short vpi, int vci) {
atm_vcc->dev_data = (void *) vccp;
// indicate readiness
- atm_vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&atm_vcc->flags);
MOD_INC_USE_COUNT;
return 0;
@@ -2569,7 +2569,7 @@ static void hrz_close (struct atm_vcc * atm_vcc) {
PRINTD (DBG_VCC|DBG_FLOW, "hrz_close");
// indicate unreadiness
- atm_vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&atm_vcc->flags);
if (atm_vcc->qos.txtp.traffic_class != ATM_NONE) {
unsigned int i;
@@ -2611,7 +2611,7 @@ static void hrz_close (struct atm_vcc * atm_vcc) {
// free our structure
kfree (vcc);
// say the VPI/VCI is free again
- atm_vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
MOD_DEC_USE_COUNT;
}
@@ -2758,13 +2758,13 @@ static int __init hrz_probe (void) {
devs = 0;
pci_dev = NULL;
while ((pci_dev = pci_find_device
- (PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_HORIZON, pci_dev)
- )) {
+ (PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_HORIZON, pci_dev)
+ )) {
hrz_dev * dev;
// adapter slot free, read resources from PCI configuration space
u32 iobase = pci_dev->resource[0].start;
- u32 * membase = bus_to_virt(pci_dev->resource[1].start);
+ u32 * membase = bus_to_virt (pci_dev->resource[1].start);
u8 irq = pci_dev->irq;
// check IO region
@@ -2795,7 +2795,7 @@ static int __init hrz_probe (void) {
PRINTD (DBG_INFO, "found Madge ATM adapter (hrz) at: IO %x, IRQ %u, MEM %p",
iobase, irq, membase);
- dev->atm_dev = atm_dev_register (DEV_LABEL, &hrz_ops, -1, 0);
+ dev->atm_dev = atm_dev_register (DEV_LABEL, &hrz_ops, -1, NULL);
if (!(dev->atm_dev)) {
PRINTD (DBG_ERR, "failed to register Madge ATM adapter");
} else {
diff --git a/drivers/atm/horizon.h b/drivers/atm/horizon.h
index be5e5c726..6655bdc1c 100644
--- a/drivers/atm/horizon.h
+++ b/drivers/atm/horizon.h
@@ -31,10 +31,8 @@
#define DRIVER_ATM_HORIZON_H
#include <linux/config.h>
-
#include <linux/version.h>
-
#ifdef CONFIG_ATM_HORIZON_DEBUG
#define DEBUG_HORIZON
#endif
diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c
index 3d305858a..31503ed1e 100644
--- a/drivers/atm/idt77105.c
+++ b/drivers/atm/idt77105.c
@@ -157,36 +157,54 @@ static int fetch_stats(struct atm_dev *dev,struct idt77105_stats *arg,int zero)
}
+static int set_loopback(struct atm_dev *dev,int mode)
+{
+ int diag;
+
+ diag = GET(DIAG) & ~IDT77105_DIAG_LCMASK;
+ switch (mode) {
+ case ATM_LM_NONE:
+ break;
+ case ATM_LM_LOC_ATM:
+ diag |= IDT77105_DIAG_LC_PHY_LOOPBACK;
+ break;
+ case ATM_LM_RMT_ATM:
+ diag |= IDT77105_DIAG_LC_LINE_LOOPBACK;
+ break;
+ default:
+ return -EINVAL;
+ }
+ PUT(diag,DIAG);
+ printk(KERN_NOTICE "%s(%d) Loopback mode is: %s\n", dev->type,
+ dev->number,
+ (mode == ATM_LM_NONE ? "NONE" :
+ (mode == ATM_LM_LOC_ATM ? "DIAG (local)" :
+ (mode == IDT77105_DIAG_LC_LINE_LOOPBACK ? "LOOP (remote)" :
+ "unknown")))
+ );
+ PRIV(dev)->loop_mode = mode;
+ return 0;
+}
+
static int idt77105_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
{
printk(KERN_NOTICE "%s(%d) idt77105_ioctl() called\n",dev->type,dev->number);
switch (cmd) {
case IDT77105_GETSTATZ:
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ /* fall through */
case IDT77105_GETSTAT:
return fetch_stats(dev,(struct idt77105_stats *) arg,
cmd == IDT77105_GETSTATZ);
- case IDT77105_SETLOOP:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- if ((int) arg < 0 || (int) arg > IDT77105_LM_LOOP)
- return -EINVAL;
- PUT((GET(DIAG) & ~IDT77105_DIAG_LCMASK) |
- ((int) arg == IDT77105_LM_NONE ? IDT77105_DIAG_LC_NORMAL : 0) |
- ((int) arg == IDT77105_LM_DIAG ? IDT77105_DIAG_LC_PHY_LOOPBACK : 0) |
- ((int) arg == IDT77105_LM_LOOP ? IDT77105_DIAG_LC_LINE_LOOPBACK : 0),
- DIAG);
- printk(KERN_NOTICE "%s(%d) Loopback mode is: %s\n",
- dev->type, dev->number,
- ((int) arg == IDT77105_LM_NONE ? "NONE" :
- ((int) arg == IDT77105_LM_DIAG ? "DIAG (local)" :
- ((int) arg == IDT77105_LM_LOOP ? "LOOP (remote)" :
- "unknown")))
- );
- PRIV(dev)->loop_mode = (int) arg;
- return 0;
- case IDT77105_GETLOOP:
+ case ATM_SETLOOP:
+ return set_loopback(dev,(int) (long) arg);
+ case ATM_GETLOOP:
return put_user(PRIV(dev)->loop_mode,(int *) arg) ?
- -EFAULT : sizeof(int);
+ -EFAULT : 0;
+ case ATM_QUERYLOOP:
+ return put_user(ATM_LM_LOC_ATM | ATM_LM_RMT_ATM,
+ (int *) arg) ? -EFAULT : 0;
default:
return -ENOIOCTLCMD;
}
@@ -266,13 +284,13 @@ static int idt77105_start(struct atm_dev *dev)
/* initialise loop mode from hardware */
switch ( GET(DIAG) & IDT77105_DIAG_LCMASK ) {
case IDT77105_DIAG_LC_NORMAL:
- PRIV(dev)->loop_mode = IDT77105_LM_NONE;
+ PRIV(dev)->loop_mode = ATM_LM_NONE;
break;
case IDT77105_DIAG_LC_PHY_LOOPBACK:
- PRIV(dev)->loop_mode = IDT77105_LM_DIAG;
+ PRIV(dev)->loop_mode = ATM_LM_LOC_ATM;
break;
case IDT77105_DIAG_LC_LINE_LOOPBACK:
- PRIV(dev)->loop_mode = IDT77105_LM_LOOP;
+ PRIV(dev)->loop_mode = ATM_LM_RMT_ATM;
break;
}
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 84bdda6d6..cd1714a53 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -59,6 +59,7 @@
#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <asm/string.h>
#include <asm/byteorder.h>
@@ -68,7 +69,7 @@
#include "suni.h"
#define swap(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8))
struct suni_priv {
- struct sonet_stats sonet_stats; /* link diagnostics */
+ struct k_sonet_stats sonet_stats; /* link diagnostics */
unsigned char loop_mode; /* loopback mode */
struct atm_dev *dev; /* device back-pointer */
struct suni_priv *next; /* next SUNI */
@@ -625,12 +626,12 @@ static int ia_que_tx (IADEV *iadev) {
num_desc = ia_avail_descs(iadev);
while (num_desc && (skb = skb_dequeue(&iadev->tx_backlog))) {
if (!(vcc = ATM_SKB(skb)->vcc)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
printk("ia_que_tx: Null vcc\n");
break;
}
- if ((vcc->flags & ATM_VF_READY) == 0 ) {
- dev_kfree_skb(skb);
+ if (!test_bit(ATM_VF_READY,&vcc->flags)) {
+ dev_kfree_skb_any(skb);
printk("Free the SKB on closed vci %d \n", vcc->vci);
break;
}
@@ -658,14 +659,14 @@ void ia_tx_poll (IADEV *iadev) {
vcc = ATM_SKB(skb)->vcc;
if (!vcc) {
printk("ia_tx_poll: vcc is null\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return;
}
iavcc = INPH_IA_VCC(vcc);
if (!iavcc) {
printk("ia_tx_poll: iavcc is null\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return;
}
@@ -682,7 +683,7 @@ void ia_tx_poll (IADEV *iadev) {
(long)skb1);)
}
else
- dev_kfree_skb(skb1);
+ dev_kfree_skb_any(skb1);
skb1 = skb_dequeue(&iavcc->txing_skb);
}
if (!skb1) {
@@ -696,7 +697,7 @@ void ia_tx_poll (IADEV *iadev) {
IF_EVENT(printk("Tx Done - skb 0x%lx return\n",(long)skb);)
}
else
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
kfree(rtne);
}
ia_que_tx(iadev);
@@ -1128,7 +1129,7 @@ static int rx_pkt(struct atm_dev *dev)
status = (u_short) (buf_desc_ptr->desc_mode);
if (status & (RX_CER | RX_PTE | RX_OFL))
{
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
IF_ERR(printk("IA: bad packet, dropping it");)
if (status & RX_CER) {
IF_ERR(printk(" cause: packet CRC error\n");)
@@ -1152,7 +1153,7 @@ static int rx_pkt(struct atm_dev *dev)
len = dma_addr - buf_addr;
if (len > iadev->rx_buf_sz) {
printk("Over %d bytes sdu received, dropped!!!\n", iadev->rx_buf_sz);
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
free_desc(dev, desc);
return 0;
}
@@ -1166,7 +1167,7 @@ static int rx_pkt(struct atm_dev *dev)
if (!skb)
{
IF_ERR(printk("can't allocate memory for recv, drop pkt!\n");)
- vcc->stats->rx_drop++;
+ atomic_inc(&vcc->stats->rx_drop);
atm_return(vcc, atm_pdu2truesize(len));
free_desc(dev, desc);
return 0;
@@ -1297,7 +1298,7 @@ static void rx_dle_intr(struct atm_dev *dev)
if (!skb->len)
{
printk("rx_dle_intr: skb len 0\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
else
{
@@ -1308,15 +1309,15 @@ static void rx_dle_intr(struct atm_dev *dev)
vcc = ATM_SKB(skb)->vcc;
if (!vcc) {
printk("IA: null vcc\n");
- vcc->stats->rx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->rx_err);
+ dev_kfree_skb_any(skb);
goto INCR_DLE;
}
ia_vcc = INPH_IA_VCC(vcc);
if (ia_vcc == NULL)
{
- vcc->stats->rx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->rx_err);
+ dev_kfree_skb_any(skb);
#if LINUX_VERSION_CODE >= 0x20312
atm_return(vcc, atm_guess_pdu2truesize(skb->len));
#else
@@ -1331,8 +1332,8 @@ static void rx_dle_intr(struct atm_dev *dev)
if ((length > iadev->rx_buf_sz) || (length >
(skb->len - sizeof(struct cpcs_trailer))))
{
- vcc->stats->rx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->rx_err);
+ dev_kfree_skb_any(skb);
IF_ERR(printk("rx_dle_intr: Bad AAL5 trailer %d (skb len %d)",
length, skb->len);)
#if LINUX_VERSION_CODE >= 0x20312
@@ -1351,7 +1352,7 @@ static void rx_dle_intr(struct atm_dev *dev)
IF_RX(printk("rx_dle_intr: skb push");)
vcc->push(vcc,skb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
iadev->rx_pkt_cnt++;
}
INCR_DLE:
@@ -1710,13 +1711,13 @@ static void tx_dle_intr(struct atm_dev *dev)
vcc = ATM_SKB(skb)->vcc;
if (!vcc) {
printk("tx_dle_intr: vcc is null\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return;
}
iavcc = INPH_IA_VCC(vcc);
if (!iavcc) {
printk("tx_dle_intr: iavcc is null\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return;
}
if (vcc->qos.txtp.pcr >= iadev->rate_limit) {
@@ -1725,7 +1726,7 @@ static void tx_dle_intr(struct atm_dev *dev)
vcc->pop(vcc, skb);
}
else {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
}
else { /* Hold the rate-limited skb for flow control */
@@ -2601,7 +2602,7 @@ static void ia_close(struct atm_vcc *vcc)
IF_EVENT(printk("ia_close: ia_vcc->vc_desc_cnt = %d vci = %d\n",
ia_vcc->vc_desc_cnt,vcc->vci);)
- vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
skb_queue_head_init (&tmp_tx_backlog);
skb_queue_head_init (&tmp_vcc_backlog);
if (vcc->qos.txtp.traffic_class != ATM_NONE) {
@@ -2611,7 +2612,7 @@ static void ia_close(struct atm_vcc *vcc)
while((skb = skb_dequeue(&iadev->tx_backlog))) {
if (ATM_SKB(skb)->vcc == vcc){
if (vcc->pop) vcc->pop(vcc, skb);
- else dev_kfree_skb(skb);
+ else dev_kfree_skb_any(skb);
}
else
skb_queue_tail(&tmp_tx_backlog, skb);
@@ -2669,7 +2670,7 @@ static void ia_close(struct atm_vcc *vcc)
kfree(INPH_IA_VCC(vcc));
ia_vcc = NULL;
INPH_IA_VCC(vcc) = NULL;
- vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return;
}
@@ -2678,7 +2679,7 @@ static int ia_open(struct atm_vcc *vcc, short vpi, int vci)
IADEV *iadev;
struct ia_vcc *ia_vcc;
int error;
- if (!(vcc->flags & ATM_VF_PARTIAL))
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags))
{
IF_EVENT(printk("ia: not partially allocated resources\n");)
INPH_IA_VCC(vcc) = NULL;
@@ -2695,7 +2696,7 @@ static int ia_open(struct atm_vcc *vcc, short vpi, int vci)
if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC)
{
IF_EVENT(printk("iphase open: unspec part\n");)
- vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&vcc->flags);
}
if (vcc->qos.aal != ATM_AAL5)
return -EINVAL;
@@ -2721,7 +2722,7 @@ static int ia_open(struct atm_vcc *vcc, short vpi, int vci)
return error;
}
- vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&vcc->flags);
#ifndef MODULE
{
@@ -2749,7 +2750,7 @@ static int ia_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flags)
static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
{
- PIA_CMDBUF ia_cmds;
+ IA_CMDBUF ia_cmds;
IADEV *iadev;
int i, board;
u16 *tmps;
@@ -2757,34 +2758,37 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
if (cmd != IA_CMD) {
if (!dev->phy->ioctl) return -EINVAL;
return dev->phy->ioctl(dev,cmd,arg);
- }
- ia_cmds = (PIA_CMDBUF)arg;
- board = ia_cmds->status;
+ }
+ if (copy_from_user(&ia_cmds, arg, sizeof ia_cmds)) return -EFAULT;
+ board = ia_cmds.status;
if ((board < 0) || (board > iadev_count))
board = 0;
iadev = ia_dev[board];
- switch (ia_cmds->cmd) {
+ switch (ia_cmds.cmd) {
case MEMDUMP:
{
- switch (ia_cmds->sub_cmd) {
+ switch (ia_cmds.sub_cmd) {
case MEMDUMP_DEV:
- memcpy((char*)ia_cmds->buf, (char*)iadev,
- sizeof(IADEV));
- ia_cmds->status = 0;
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ if (copy_to_user(ia_cmds.buf, iadev, sizeof(IADEV)))
+ return -EFAULT;
+ ia_cmds.status = 0;
break;
case MEMDUMP_SEGREG:
- tmps = (u16 *)ia_cmds->buf;
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ tmps = (u16 *)ia_cmds.buf;
for(i=0; i<0x80; i+=2, tmps++)
- *tmps = *(u16*)(iadev->seg_reg+i);
- ia_cmds->status = 0;
- ia_cmds->len = 0x80;
+ if(put_user(*(u16*)(iadev->seg_reg+i), tmps)) return -EFAULT;
+ ia_cmds.status = 0;
+ ia_cmds.len = 0x80;
break;
case MEMDUMP_REASSREG:
- tmps = (u16 *)ia_cmds->buf;
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ tmps = (u16 *)ia_cmds.buf;
for(i=0; i<0x80; i+=2, tmps++)
- *tmps = *(u16*)(iadev->reass_reg+i);
- ia_cmds->status = 0;
- ia_cmds->len = 0x80;
+ if(put_user(*(u16*)(iadev->reass_reg+i), tmps)) return -EFAULT;
+ ia_cmds.status = 0;
+ ia_cmds.len = 0x80;
break;
case MEMDUMP_FFL:
{
@@ -2792,6 +2796,7 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
ffredn_t *ffL = &regs_local.ffredn;
rfredn_t *rfL = &regs_local.rfredn;
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
/* Copy real rfred registers into the local copy */
for (i=0; i<(sizeof (rfredn_t))/4; i++)
((u_int *)rfL)[i] = ((u_int *)iadev->reass_reg)[i] & 0xffff;
@@ -2799,63 +2804,67 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
for (i=0; i<(sizeof (ffredn_t))/4; i++)
((u_int *)ffL)[i] = ((u_int *)iadev->seg_reg)[i] & 0xffff;
- memcpy((char*)ia_cmds->buf,(char*)&regs_local,sizeof(ia_regs_t));
+ if (copy_to_user(ia_cmds.buf, &regs_local,sizeof(ia_regs_t)))
+ return -EFAULT;
printk("Board %d registers dumped\n", board);
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
}
break;
case READ_REG:
{
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
desc_dbg(iadev);
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
}
break;
case 0x6:
{
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
printk("skb = 0x%lx\n", (long)skb_peek(&iadev->tx_backlog));
printk("rtn_q: 0x%lx\n",(long)ia_deque_rtn_q(&iadev->tx_return_q));
}
break;
case 0x8:
{
- struct sonet_stats *stats;
+ struct k_sonet_stats *stats;
stats = &PRIV(_ia_dev[board])->sonet_stats;
- printk("section_bip: %d\n", stats->section_bip);
- printk("line_bip : %d\n", stats->line_bip);
- printk("path_bip : %d\n", stats->path_bip);
- printk("line_febe : %d\n", stats->line_febe);
- printk("path_febe : %d\n", stats->path_febe);
- printk("corr_hcs : %d\n", stats->corr_hcs);
- printk("uncorr_hcs : %d\n", stats->uncorr_hcs);
- printk("tx_cells : %d\n", stats->tx_cells);
- printk("rx_cells : %d\n", stats->rx_cells);
+ printk("section_bip: %d\n", atomic_read(&stats->section_bip));
+ printk("line_bip : %d\n", atomic_read(&stats->line_bip));
+ printk("path_bip : %d\n", atomic_read(&stats->path_bip));
+ printk("line_febe : %d\n", atomic_read(&stats->line_febe));
+ printk("path_febe : %d\n", atomic_read(&stats->path_febe));
+ printk("corr_hcs : %d\n", atomic_read(&stats->corr_hcs));
+ printk("uncorr_hcs : %d\n", atomic_read(&stats->uncorr_hcs));
+ printk("tx_cells : %d\n", atomic_read(&stats->tx_cells));
+ printk("rx_cells : %d\n", atomic_read(&stats->rx_cells));
}
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
break;
case 0x9:
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
for (i = 1; i <= iadev->num_rx_desc; i++)
free_desc(_ia_dev[board], i);
writew( ~(RX_FREEQ_EMPT | RX_EXCP_RCVD),
iadev->reass_reg+REASS_MASK_REG);
iadev->rxing = 1;
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
break;
case 0xb:
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
IaFrontEndIntr(iadev);
break;
case 0xa:
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
{
- ia_cmds->status = 0;
- IADebugFlag = ia_cmds->maddr;
+ ia_cmds.status = 0;
+ IADebugFlag = ia_cmds.maddr;
printk("New debug option loaded\n");
}
break;
default:
- memcpy((char*)ia_cmds->buf, (char*)ia_cmds->maddr, ia_cmds->len);
- ia_cmds->status = 0;
+ ia_cmds.status = 0;
break;
}
}
@@ -2896,7 +2905,7 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
if (!iavcc->txing) {
printk("discard packet on closed VC\n");
if (vcc->pop) vcc->pop(vcc, skb);
- else dev_kfree_skb(skb);
+ else dev_kfree_skb_any(skb);
}
if (skb->len > iadev->tx_buf_sz - 8) {
@@ -2904,7 +2913,7 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
if (vcc->pop)
vcc->pop(vcc, skb);
else
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return 0;
}
if ((u32)skb->data & 3) {
@@ -2912,7 +2921,7 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
if (vcc->pop)
vcc->pop(vcc, skb);
else
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return 0;
}
/* Get a descriptor number from our free descriptor queue
@@ -2929,11 +2938,11 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
if ((desc == 0) || (desc > iadev->num_tx_desc))
{
IF_ERR(printk(DEV_LABEL "invalid desc for send: %d\n", desc);)
- vcc->stats->tx++;
+ atomic_inc(&vcc->stats->tx);
if (vcc->pop)
vcc->pop(vcc, skb);
else
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return 0; /* return SUCCESS */
}
@@ -3038,14 +3047,14 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
ATM_DESC(skb) = vcc->vci;
skb_queue_tail(&iadev->tx_dma_q, skb);
- vcc->stats->tx++;
+ atomic_inc(&vcc->stats->tx);
iadev->tx_pkt_cnt++;
/* Increment transaction counter */
writel(2, iadev->dma+IPHASE5575_TX_COUNTER);
#if 0
/* add flow control logic */
- if (vcc->stats->tx % 20 == 0) {
+ if (atomic_read(&vcc->stats->tx) % 20 == 0) {
if (iavcc->vc_desc_cnt > 10) {
vcc->tx_quota = vcc->tx_quota * 3 / 4;
printk("Tx1: vcc->tx_quota = %d \n", (u32)vcc->tx_quota );
@@ -3074,12 +3083,12 @@ static int ia_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
if (!skb)
printk(KERN_CRIT "null skb in ia_send\n");
- else dev_kfree_skb(skb);
+ else dev_kfree_skb_any(skb);
return -EINVAL;
}
spin_lock_irqsave(&iadev->tx_lock, flags);
- if ((vcc->flags & ATM_VF_READY) == 0){
- dev_kfree_skb(skb);
+ if (!test_bit(ATM_VF_READY,&vcc->flags)){
+ dev_kfree_skb_any(skb);
spin_unlock_irqrestore(&iadev->tx_lock, flags);
return -EINVAL;
}
@@ -3197,7 +3206,7 @@ __initfunc(int ia_detect(void))
IF_INIT(printk("ia detected at bus:%d dev: %d function:%d\n",
iadev->pci->bus->number, PCI_SLOT(iadev->pci->devfn),
PCI_FUNC(iadev->pci->devfn));)
- dev = atm_dev_register(DEV_LABEL, &ops, -1, 0);
+ dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
if (!dev) break;
IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n",
dev->number);)
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index 3e4930fdd..767fd75fb 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -37,8 +37,10 @@
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
+#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#include "nicstar.h"
#include "nicstarmac.h"
#ifdef CONFIG_ATM_NICSTAR_USE_SUNI
@@ -284,7 +286,7 @@ void cleanup_module(void)
card = cards[i];
#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105
- if (card->max_pcr == IDT_25_PCR) {
+ if (card->max_pcr == ATM_25_PCR) {
idt77105_stop(card->atmdev);
}
#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */
@@ -311,7 +313,7 @@ void cleanup_module(void)
PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count);
while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)
{
- kfree_skb(hb);
+ dev_kfree_skb_any(hb);
j++;
}
PRINTK("nicstar%d: %d huge buffers freed.\n", i, j);
@@ -319,14 +321,14 @@ void cleanup_module(void)
PRINTK("nicstar%d: freeing %d iovec buffers.\n", i, card->iovpool.count);
while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)
{
- kfree_skb(iovb);
+ dev_kfree_skb_any(iovb);
j++;
}
PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j);
while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
- kfree_skb(lb);
+ dev_kfree_skb_any(lb);
while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
- kfree_skb(sb);
+ dev_kfree_skb_any(sb);
free_scq(card->scq0, NULL);
for (j = 0; j < NS_FRSCD_NUM; j++)
{
@@ -547,7 +549,7 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
switch(data) {
case 0x00000009:
printk("nicstar%d: PHY seems to be 25 Mbps.\n", i);
- card->max_pcr = IDT_25_PCR;
+ card->max_pcr = ATM_25_PCR;
while(CMD_BUSY(card));
writel(0x00000008, card->membase + DR0);
writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD);
@@ -857,7 +859,7 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
card->efbie = 1;
/* Register device */
- card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, 0UL);
+ card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL);
if (card->atmdev == NULL)
{
printk("nicstar%d: can't register device.\n", i);
@@ -891,7 +893,7 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */
#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105
- if (card->max_pcr == IDT_25_PCR) {
+ if (card->max_pcr == ATM_25_PCR) {
idt77105_init(card->atmdev);
/* Note that for the IDT77105 PHY we don't need the awful
* module count hack that the SUNI needs because we can
@@ -936,26 +938,26 @@ static void ns_init_card_error(ns_dev *card, int error)
{
struct sk_buff *iovb;
while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)
- kfree_skb(iovb);
+ dev_kfree_skb_any(iovb);
}
if (error >= 15)
{
struct sk_buff *sb;
while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
- kfree_skb(sb);
+ dev_kfree_skb_any(sb);
free_scq(card->scq0, NULL);
}
if (error >= 14)
{
struct sk_buff *lb;
while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
- kfree_skb(lb);
+ dev_kfree_skb_any(lb);
}
if (error >= 13)
{
struct sk_buff *hb;
while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)
- kfree_skb(hb);
+ dev_kfree_skb_any(hb);
}
if (error >= 12)
{
@@ -1039,7 +1041,7 @@ static void free_scq(scq_info *scq, struct atm_vcc *vcc)
if (vcc->pop != NULL)
vcc->pop(vcc, scq->skb[i]);
else
- dev_kfree_skb(scq->skb[i]);
+ dev_kfree_skb_any(scq->skb[i]);
}
}
else /* vcc must be != NULL */
@@ -1048,7 +1050,7 @@ static void free_scq(scq_info *scq, struct atm_vcc *vcc)
{
printk("nicstar: free_scq() called with vcc == NULL for fixed rate scq.");
for (i = 0; i < scq->num_entries; i++)
- dev_kfree_skb(scq->skb[i]);
+ dev_kfree_skb_any(scq->skb[i]);
}
else
for (i = 0; i < scq->num_entries; i++)
@@ -1058,7 +1060,7 @@ static void free_scq(scq_info *scq, struct atm_vcc *vcc)
if (vcc->pop != NULL)
vcc->pop(vcc, scq->skb[i]);
else
- dev_kfree_skb(scq->skb[i]);
+ dev_kfree_skb_any(scq->skb[i]);
}
}
}
@@ -1130,9 +1132,9 @@ static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1,
if (card->sbfqc >= card->sbnr.max)
{
skb_unlink((struct sk_buff *) handle1);
- kfree_skb((struct sk_buff *) handle1);
+ dev_kfree_skb_any((struct sk_buff *) handle1);
skb_unlink((struct sk_buff *) handle2);
- kfree_skb((struct sk_buff *) handle2);
+ dev_kfree_skb_any((struct sk_buff *) handle2);
return;
}
else
@@ -1143,9 +1145,9 @@ static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1,
if (card->lbfqc >= card->lbnr.max)
{
skb_unlink((struct sk_buff *) handle1);
- kfree_skb((struct sk_buff *) handle1);
+ dev_kfree_skb_any((struct sk_buff *) handle1);
skb_unlink((struct sk_buff *) handle2);
- kfree_skb((struct sk_buff *) handle2);
+ dev_kfree_skb_any((struct sk_buff *) handle2);
return;
}
else
@@ -1420,16 +1422,16 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
return -EINVAL;
}
- vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&vcc->flags);
/* NOTE: You are not allowed to modify an open connection's QOS. To change
that, remove the ATM_VF_PARTIAL flag checking. There may be other changes
needed to do that. */
- if (!(vcc->flags & ATM_VF_PARTIAL))
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags))
{
scq_info *scq;
- vcc->flags |= ATM_VF_PARTIAL;
+ set_bit(ATM_VF_PARTIAL,&vcc->flags);
if (vcc->qos.txtp.traffic_class == ATM_CBR)
{
/* Check requested cell rate and availability of SCD */
@@ -1438,7 +1440,8 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
{
PRINTK("nicstar%d: trying to open a CBR vc with cell rate = 0 \n",
card->index);
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -EINVAL;
}
@@ -1461,7 +1464,8 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
if ((n = (card->tst_free_entries - NS_TST_RESERVED)) <= 0)
{
PRINTK("nicstar%d: no CBR bandwidth free.\n", card->index);
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -EINVAL;
}
}
@@ -1469,14 +1473,16 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
if (n == 0)
{
printk("nicstar%d: selected bandwidth < granularity.\n", card->index);
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -EINVAL;
}
if (n > (card->tst_free_entries - NS_TST_RESERVED))
{
PRINTK("nicstar%d: not enough free CBR bandwidth.\n", card->index);
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -EINVAL;
}
else
@@ -1495,7 +1501,8 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
{
PRINTK("nicstar%d: no SCD available for CBR channel.\n", card->index);
card->tst_free_entries += n;
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -EBUSY;
}
@@ -1507,7 +1514,8 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index);
card->scd2vc[frscdi] = NULL;
card->tst_free_entries += n;
- vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -ENOMEM;
}
vc->scq = scq;
@@ -1553,7 +1561,7 @@ static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
}
- vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&vcc->flags);
MOD_INC_USE_COUNT;
return 0;
}
@@ -1572,7 +1580,7 @@ static void ns_close(struct atm_vcc *vcc)
PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index,
(int) vcc->vpi, vcc->vci);
- vcc->flags &= ~(ATM_VF_READY);
+ clear_bit(ATM_VF_READY,&vcc->flags);
if (vcc->qos.rxtp.traffic_class != ATM_NONE)
{
@@ -1681,7 +1689,8 @@ static void ns_close(struct atm_vcc *vcc)
}
vcc->dev_data = NULL;
- vcc->flags &= ~(ATM_VF_PARTIAL | ATM_VF_ADDR);
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
MOD_DEC_USE_COUNT;
#ifdef RX_DEBUG
@@ -1778,32 +1787,32 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb)
if ((vc = (vc_map *) vcc->dev_data) == NULL)
{
printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n", card->index);
- vcc->stats->tx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
return -EINVAL;
}
if (!vc->tx)
{
printk("nicstar%d: Trying to transmit on a non-tx VC.\n", card->index);
- vcc->stats->tx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
return -EINVAL;
}
if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0)
{
printk("nicstar%d: Only AAL0 and AAL5 are supported.\n", card->index);
- vcc->stats->tx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
return -EINVAL;
}
if (ATM_SKB(skb)->iovcnt != 0)
{
printk("nicstar%d: No scatter-gather yet.\n", card->index);
- vcc->stats->tx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
return -EINVAL;
}
@@ -1847,11 +1856,11 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb)
if (push_scqe(card, vc, scq, &scqe, skb) != 0)
{
- vcc->stats->tx_err++;
- dev_kfree_skb(skb);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
return -EIO;
}
- vcc->stats->tx++;
+ atomic_inc(&vcc->stats->tx);
return 0;
}
@@ -2071,7 +2080,7 @@ static void drain_scq(ns_dev *card, scq_info *scq, int pos)
if (vcc->pop != NULL)
vcc->pop(vcc, skb);
else
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
scq->skb[i] = NULL;
}
if (++i == scq->num_entries)
@@ -2155,15 +2164,15 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
{
printk("nicstar%d: Can't allocate buffers for aal0.\n",
card->index);
- vcc->stats->rx_drop += i;
+ atomic_add(i,&vcc->stats->rx_drop);
break;
}
if (!atm_charge(vcc, sb->truesize))
{
RXPRINTK("nicstar%d: atm_charge() dropped aal0 packets.\n",
card->index);
- vcc->stats->rx_drop += i - 1; /* already increased by 1 */
- kfree_skb(sb);
+ atomic_add(i-1,&vcc->stats->rx_drop); /* already increased by 1 */
+ dev_kfree_skb_any(sb);
break;
}
/* Rebuild the header */
@@ -2177,7 +2186,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
ATM_SKB(sb)->vcc = vcc;
sb->stamp = xtime;
vcc->push(vcc, sb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
cell += ATM_CELL_PAYLOAD;
}
@@ -2196,7 +2205,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
if (iovb == NULL)
{
printk("nicstar%d: Out of iovec buffers.\n", card->index);
- vcc->stats->rx_drop++;
+ atomic_inc(&vcc->stats->rx_drop);
recycle_rx_buf(card, skb);
return;
}
@@ -2223,7 +2232,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
else if (ATM_SKB(iovb)->iovcnt >= NS_MAX_IOVECS)
{
printk("nicstar%d: received too big AAL5 SDU.\n", card->index);
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS);
ATM_SKB(iovb)->iovcnt = 0;
iovb->len = 0;
@@ -2242,7 +2251,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
printk("nicstar%d: Expected a small buffer, and this is not one.\n",
card->index);
which_list(card, skb);
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
recycle_rx_buf(card, skb);
vc->rx_iov = NULL;
recycle_iov_buf(card, iovb);
@@ -2256,7 +2265,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
printk("nicstar%d: Expected a large buffer, and this is not one.\n",
card->index);
which_list(card, skb);
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
ATM_SKB(iovb)->iovcnt);
vc->rx_iov = NULL;
@@ -2280,7 +2289,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
printk(" - PDU size mismatch.\n");
else
printk(".\n");
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
ATM_SKB(iovb)->iovcnt);
vc->rx_iov = NULL;
@@ -2308,7 +2317,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
ATM_SKB(skb)->vcc = vcc;
skb->stamp = xtime;
vcc->push(vcc, skb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
}
else if (ATM_SKB(iovb)->iovcnt == 2) /* One small plus one large buffer */
@@ -2335,7 +2344,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
ATM_SKB(sb)->vcc = vcc;
sb->stamp = xtime;
vcc->push(vcc, sb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
push_rxbufs(card, BUF_LG, (u32) skb,
@@ -2361,7 +2370,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
ATM_SKB(skb)->vcc = vcc;
skb->stamp = xtime;
vcc->push(vcc, skb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data),
@@ -2384,7 +2393,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
if (hb == NULL)
{
printk("nicstar%d: Out of huge buffers.\n", card->index);
- vcc->stats->rx_drop++;
+ atomic_inc(&vcc->stats->rx_drop);
recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
ATM_SKB(iovb)->iovcnt);
vc->rx_iov = NULL;
@@ -2431,7 +2440,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
card->hbpool.count++;
}
else
- kfree_skb(hb);
+ dev_kfree_skb_any(hb);
}
else
{
@@ -2467,7 +2476,7 @@ static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
#endif /* NS_USE_DESTRUCTORS */
hb->stamp = xtime;
vcc->push(vcc, hb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
}
@@ -2556,7 +2565,7 @@ static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb)
else
{
printk("nicstar%d: What kind of rx buffer is this?\n", card->index);
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
}
@@ -2578,7 +2587,7 @@ static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count)
else
{
printk("nicstar%d: What kind of rx buffer is this?\n", card->index);
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
}
}
@@ -2593,7 +2602,7 @@ static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb)
card->iovpool.count++;
}
else
- kfree_skb(iovb);
+ dev_kfree_skb_any(iovb);
}
@@ -2700,7 +2709,7 @@ static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page)
/* Dump 25.6 Mbps PHY registers */
/* Now there's a 25.6 Mbps PHY driver this code isn't needed. I left it
here just in case it's needed for debugging. */
- if (card->max_pcr == IDT_25_PCR && !left--)
+ if (card->max_pcr == ATM_25_PCR && !left--)
{
u32 phy_regs[4];
u32 i;
@@ -2787,7 +2796,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
return -EFAULT;
case NS_SETBUFLEV:
- if (!suser())
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (copy_from_user(&pl, (pool_levels *) arg, sizeof(pl)))
return -EFAULT;
@@ -2836,7 +2845,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
return 0;
case NS_ADJBUFLEV:
- if (!suser())
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
btype = (int) arg; /* an int is the same size as a pointer */
switch (btype)
@@ -2882,7 +2891,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
printk("nicstar%d: huge buffer count inconsistent.\n",
card->index);
else
- kfree_skb(hb);
+ dev_kfree_skb_any(hb);
}
while (card->hbpool.count < card->hbnr.init)
@@ -2912,7 +2921,7 @@ static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
printk("nicstar%d: iovec buffer count inconsistent.\n",
card->index);
else
- kfree_skb(iovb);
+ dev_kfree_skb_any(iovb);
}
while (card->iovpool.count < card->iovnr.init)
diff --git a/drivers/atm/nicstar.h b/drivers/atm/nicstar.h
index 61b89efe0..4e90650c0 100644
--- a/drivers/atm/nicstar.h
+++ b/drivers/atm/nicstar.h
@@ -100,8 +100,6 @@
#define NS_IOREMAP_SIZE 4096
-#define IDT_25_PCR ((25600000 / 8 - 8000) / 54)
-
#define BUF_SM 0x00000000 /* These two are used for push_rxbufs() */
#define BUF_LG 0x00000001 /* CMD, Write_FreeBufQ, LBUF bit */
diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c
index 7335bbb32..0de6e8ead 100644
--- a/drivers/atm/suni.c
+++ b/drivers/atm/suni.c
@@ -1,4 +1,4 @@
-/* drivers/atm/suni.c - PMC SUNI (PHY) driver */
+/* drivers/atm/suni.c - PMC PM5346 SUNI (PHY) driver */
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
@@ -18,6 +18,7 @@
#include <asm/system.h>
#include <asm/param.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#include "suni.h"
@@ -30,8 +31,8 @@
struct suni_priv {
- struct sonet_stats sonet_stats; /* link diagnostics */
- unsigned char loop_mode; /* loopback mode */
+ struct k_sonet_stats sonet_stats; /* link diagnostics */
+ int loop_mode; /* loopback mode */
struct atm_dev *dev; /* device back-pointer */
struct suni_priv *next; /* next SUNI */
};
@@ -46,69 +47,62 @@ struct suni_priv {
static struct timer_list poll_timer;
-static int start_timer = 1;
static struct suni_priv *sunis = NULL;
+static spinlock_t sunis_lock = SPIN_LOCK_UNLOCKED;
-static void suni_hz(unsigned long dummy)
+#define ADD_LIMITED(s,v) \
+ atomic_add((v),&stats->s); \
+ if (atomic_read(&stats->s) < 0) atomic_set(&stats->s,INT_MAX);
+
+
+static void suni_hz(unsigned long from_timer)
{
struct suni_priv *walk;
struct atm_dev *dev;
- struct sonet_stats *stats;
+ struct k_sonet_stats *stats;
for (walk = sunis; walk; walk = walk->next) {
dev = walk->dev;
stats = &walk->sonet_stats;
PUT(0,MRI); /* latch counters */
udelay(1);
- stats->section_bip += (GET(RSOP_SBL) & 0xff) |
- ((GET(RSOP_SBM) & 0xff) << 8);
- if (stats->section_bip < 0) stats->section_bip = LONG_MAX;
- stats->line_bip += (GET(RLOP_LBL) & 0xff) |
+ ADD_LIMITED(section_bip,(GET(RSOP_SBL) & 0xff) |
+ ((GET(RSOP_SBM) & 0xff) << 8));
+ ADD_LIMITED(line_bip,(GET(RLOP_LBL) & 0xff) |
((GET(RLOP_LB) & 0xff) << 8) |
- ((GET(RLOP_LBM) & 0xf) << 16);
- if (stats->line_bip < 0) stats->line_bip = LONG_MAX;
- stats->path_bip += (GET(RPOP_PBL) & 0xff) |
- ((GET(RPOP_PBM) & 0xff) << 8);
- if (stats->path_bip < 0) stats->path_bip = LONG_MAX;
- stats->line_febe += (GET(RLOP_LFL) & 0xff) |
+ ((GET(RLOP_LBM) & 0xf) << 16));
+ ADD_LIMITED(path_bip,(GET(RPOP_PBL) & 0xff) |
+ ((GET(RPOP_PBM) & 0xff) << 8));
+ ADD_LIMITED(line_febe,(GET(RLOP_LFL) & 0xff) |
((GET(RLOP_LF) & 0xff) << 8) |
- ((GET(RLOP_LFM) & 0xf) << 16);
- if (stats->line_febe < 0) stats->line_febe = LONG_MAX;
- stats->path_febe += (GET(RPOP_PFL) & 0xff) |
- ((GET(RPOP_PFM) & 0xff) << 8);
- if (stats->path_febe < 0) stats->path_febe = LONG_MAX;
- stats->corr_hcs += GET(RACP_CHEC) & 0xff;
- if (stats->corr_hcs < 0) stats->corr_hcs = LONG_MAX;
- stats->uncorr_hcs += GET(RACP_UHEC) & 0xff;
- if (stats->uncorr_hcs < 0) stats->uncorr_hcs = LONG_MAX;
- stats->rx_cells += (GET(RACP_RCCL) & 0xff) |
+ ((GET(RLOP_LFM) & 0xf) << 16));
+ ADD_LIMITED(path_febe,(GET(RPOP_PFL) & 0xff) |
+ ((GET(RPOP_PFM) & 0xff) << 8));
+ ADD_LIMITED(corr_hcs,GET(RACP_CHEC) & 0xff);
+ ADD_LIMITED(uncorr_hcs,GET(RACP_UHEC) & 0xff);
+ ADD_LIMITED(rx_cells,(GET(RACP_RCCL) & 0xff) |
((GET(RACP_RCC) & 0xff) << 8) |
- ((GET(RACP_RCCM) & 7) << 16);
- if (stats->rx_cells < 0) stats->rx_cells = LONG_MAX;
- stats->tx_cells += (GET(TACP_TCCL) & 0xff) |
+ ((GET(RACP_RCCM) & 7) << 16));
+ ADD_LIMITED(tx_cells,(GET(TACP_TCCL) & 0xff) |
((GET(TACP_TCC) & 0xff) << 8) |
- ((GET(TACP_TCCM) & 7) << 16);
- if (stats->tx_cells < 0) stats->tx_cells = LONG_MAX;
+ ((GET(TACP_TCCM) & 7) << 16));
}
- if (!start_timer) mod_timer(&poll_timer,jiffies+HZ);
+ if (from_timer) mod_timer(&poll_timer,jiffies+HZ);
}
+#undef ADD_LIMITED
+
+
static int fetch_stats(struct atm_dev *dev,struct sonet_stats *arg,int zero)
{
- unsigned long flags;
- int error;
-
- error = 0;
- save_flags(flags);
- cli();
- if (arg)
- error = copy_to_user(arg,&PRIV(dev)->sonet_stats,
- sizeof(struct sonet_stats));
- if (zero && !error)
- memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats));
- restore_flags(flags);
+ struct sonet_stats tmp;
+ int error = 0;
+
+ sonet_copy_stats(&PRIV(dev)->sonet_stats,&tmp);
+ if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp));
+ if (zero && !error) sonet_subtract_stats(&PRIV(dev)->sonet_stats,&tmp);
return error ? -EFAULT : 0;
}
@@ -158,6 +152,29 @@ static int get_diag(struct atm_dev *dev,void *arg)
}
+static int set_loopback(struct atm_dev *dev,int mode)
+{
+ unsigned char control;
+
+ control = GET(MCT) & ~(SUNI_MCT_DLE | SUNI_MCT_LLE);
+ switch (mode) {
+ case ATM_LM_NONE:
+ break;
+ case ATM_LM_LOC_PHY:
+ control |= SUNI_MCT_DLE;
+ break;
+ case ATM_LM_RMT_PHY:
+ control |= SUNI_MCT_LLE;
+ break;
+ default:
+ return -EINVAL;
+ }
+ PUT(control,MCT);
+ PRIV(dev)->loop_mode = mode;
+ return 0;
+}
+
+
static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
{
switch (cmd) {
@@ -172,7 +189,6 @@ static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
case SONET_GETDIAG:
return get_diag(dev,arg);
case SONET_SETFRAMING:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
if (arg != SONET_FRAME_SONET) return -EINVAL;
return 0;
case SONET_GETFRAMING:
@@ -180,23 +196,14 @@ static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
-EFAULT : 0;
case SONET_GETFRSENSE:
return -EINVAL;
- case SUNI_SETLOOP:
- {
- int int_arg = (int) (long) arg;
-
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- if (int_arg < 0 || int_arg > SUNI_LM_LOOP)
- return -EINVAL;
- PUT((GET(MCT) & ~(SUNI_MCT_DLE | SUNI_MCT_LLE))
- | (int_arg == SUNI_LM_DIAG ? SUNI_MCT_DLE :
- 0) | (int_arg == SUNI_LM_LOOP ?
- SUNI_MCT_LLE : 0),MCT);
- PRIV(dev)->loop_mode = int_arg;
- return 0;
- }
- case SUNI_GETLOOP:
+ case ATM_SETLOOP:
+ return set_loopback(dev,(int) (long) arg);
+ case ATM_GETLOOP:
return put_user(PRIV(dev)->loop_mode,(int *) arg) ?
-EFAULT : 0;
+ case ATM_QUERYLOOP:
+ return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY,
+ (int *) arg) ? -EFAULT : 0;
default:
return -ENOIOCTLCMD;
}
@@ -221,33 +228,31 @@ static void suni_int(struct atm_dev *dev)
static int suni_start(struct atm_dev *dev)
{
unsigned long flags;
+ int first;
if (!(PRIV(dev) = kmalloc(sizeof(struct suni_priv),GFP_KERNEL)))
return -ENOMEM;
PRIV(dev)->dev = dev;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&sunis_lock,flags);
+ first = !sunis;
PRIV(dev)->next = sunis;
sunis = PRIV(dev);
- restore_flags(flags);
- memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats));
+ spin_unlock_irqrestore(&sunis_lock,flags);
+ memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats));
PUT(GET(RSOP_CIE) | SUNI_RSOP_CIE_LOSE,RSOP_CIE);
/* interrupt on loss of signal */
poll_los(dev); /* ... and clear SUNI interrupts */
if (dev->signal == ATM_PHY_SIG_LOST)
printk(KERN_WARNING "%s(itf %d): no signal\n",dev->type,
dev->number);
- PRIV(dev)->loop_mode = SUNI_LM_NONE;
+ PRIV(dev)->loop_mode = ATM_LM_NONE;
suni_hz(0); /* clear SUNI counters */
(void) fetch_stats(dev,NULL,1); /* clear kernel counters */
- cli();
- if (!start_timer) restore_flags(flags);
- else {
- start_timer = 0;
- restore_flags(flags);
+ if (first) {
init_timer(&poll_timer);
poll_timer.expires = jiffies+HZ;
poll_timer.function = suni_hz;
+ poll_timer.data = 1;
#if 0
printk(KERN_DEBUG "[u] p=0x%lx,n=0x%lx\n",(unsigned long) poll_timer.prev,
(unsigned long) poll_timer.next);
@@ -258,10 +263,28 @@ printk(KERN_DEBUG "[u] p=0x%lx,n=0x%lx\n",(unsigned long) poll_timer.prev,
}
+static int suni_stop(struct atm_dev *dev)
+{
+ struct suni_priv **walk;
+ unsigned long flags;
+
+ /* let SAR driver worry about stopping interrupts */
+ spin_lock_irqsave(&sunis_lock,flags);
+ for (walk = &sunis; *walk != PRIV(dev);
+ walk = &PRIV((*walk)->dev)->next);
+ *walk = PRIV((*walk)->dev)->next;
+ if (!sunis) del_timer_sync(&poll_timer);
+ spin_unlock_irqrestore(&sunis_lock,flags);
+ kfree(PRIV(dev));
+ return 0;
+}
+
+
static const struct atmphy_ops suni_ops = {
- suni_start,
- suni_ioctl,
- suni_int
+ start: suni_start,
+ ioctl: suni_ioctl,
+ interrupt: suni_int,
+ stop: suni_stop,
};
diff --git a/drivers/atm/suni.h b/drivers/atm/suni.h
index f72cdc7be..ae6d39abb 100644
--- a/drivers/atm/suni.h
+++ b/drivers/atm/suni.h
@@ -1,6 +1,6 @@
-/* drivers/atm/suni.h - PMC SUNI (PHY) declarations */
+/* drivers/atm/suni.h - PMC PM5346 SUNI (PHY) declarations */
-/* Written 1995,1998 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef DRIVER_ATM_SUNI_H
diff --git a/drivers/atm/uPD98402.c b/drivers/atm/uPD98402.c
index 36fd70b17..7c5f57579 100644
--- a/drivers/atm/uPD98402.c
+++ b/drivers/atm/uPD98402.c
@@ -11,6 +11,7 @@
#include <linux/sonet.h>
#include <linux/init.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#include "uPD98402.h"
@@ -23,8 +24,9 @@
struct uPD98402_priv {
- struct sonet_stats sonet_stats; /* link diagnostics */
+ struct k_sonet_stats sonet_stats;/* link diagnostics */
unsigned char framing; /* SONET/SDH framing */
+ int loop_mode; /* loopback mode */
};
@@ -36,23 +38,18 @@ struct uPD98402_priv {
static int fetch_stats(struct atm_dev *dev,struct sonet_stats *arg,int zero)
{
- unsigned long flags;
- int error;
+ struct sonet_stats tmp;
+ int error = 0;
- error = 0;
- save_flags(flags);
- cli();
- PRIV(dev)->sonet_stats.uncorr_hcs += GET(HECCT);
- if (arg)
- error = copy_to_user(arg,&PRIV(dev)->sonet_stats,
- sizeof(struct sonet_stats));
+ atomic_add(GET(HECCT),&PRIV(dev)->sonet_stats.uncorr_hcs);
+ sonet_copy_stats(&PRIV(dev)->sonet_stats,&tmp);
+ if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp));
if (zero && !error) {
- memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats));
- PRIV(dev)->sonet_stats.corr_hcs = -1;
- PRIV(dev)->sonet_stats.tx_cells = -1;
- PRIV(dev)->sonet_stats.rx_cells = -1;
+ /* unused fields are reported as -1, but we must not "adjust"
+ them */
+ tmp.corr_hcs = tmp.tx_cells = tmp.rx_cells = 0;
+ sonet_subtract_stats(&PRIV(dev)->sonet_stats,&tmp);
}
- restore_flags(flags);
return error ? -EFAULT : 0;
}
@@ -102,6 +99,39 @@ static int get_sense(struct atm_dev *dev,u8 *arg)
}
+static int set_loopback(struct atm_dev *dev,int mode)
+{
+ unsigned char mode_reg;
+
+ mode_reg = GET(MDR) & ~(uPD98402_MDR_TPLP | uPD98402_MDR_ALP |
+ uPD98402_MDR_RPLP);
+ switch (__ATM_LM_XTLOC(mode)) {
+ case __ATM_LM_NONE:
+ break;
+ case __ATM_LM_PHY:
+ mode_reg |= uPD98402_MDR_TPLP;
+ break;
+ case __ATM_LM_ATM:
+ mode_reg |= uPD98402_MDR_ALP;
+ break;
+ default:
+ return -EINVAL;
+ }
+ switch (__ATM_LM_XTRMT(mode)) {
+ case __ATM_LM_NONE:
+ break;
+ case __ATM_LM_PHY:
+ mode_reg |= uPD98402_MDR_RPLP;
+ break;
+ default:
+ return -EINVAL;
+ }
+ PUT(mode_reg,MDR);
+ PRIV(dev)->loop_mode = mode;
+ return 0;
+}
+
+
static int uPD98402_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
{
switch (cmd) {
@@ -117,35 +147,42 @@ static int uPD98402_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
-EFAULT : 0;
case SONET_GETFRSENSE:
return get_sense(dev,arg);
+ case ATM_SETLOOP:
+ return set_loopback(dev,(int) (long) arg);
+ case ATM_GETLOOP:
+ return put_user(PRIV(dev)->loop_mode,(int *) arg) ?
+ -EFAULT : 0;
+ case ATM_QUERYLOOP:
+ return put_user(ATM_LM_LOC_PHY | ATM_LM_LOC_ATM |
+ ATM_LM_RMT_PHY,(int *) arg) ? -EFAULT : 0;
default:
- return -ENOIOCTLCMD;
+ return -ENOIOCTLCMD;
}
}
+#define ADD_LIMITED(s,v) \
+ { atomic_add(GET(v),&PRIV(dev)->sonet_stats.s); \
+ if (atomic_read(&PRIV(dev)->sonet_stats.s) < 0) \
+ atomic_set(&PRIV(dev)->sonet_stats.s,INT_MAX); }
+
+
static void stat_event(struct atm_dev *dev)
{
unsigned char events;
events = GET(PCR);
- if (events & uPD98402_PFM_PFEB)
- if ((PRIV(dev)->sonet_stats.path_febe += GET(PFECB)) < 0)
- PRIV(dev)->sonet_stats.path_febe = LONG_MAX;
- if (events & uPD98402_PFM_LFEB)
- if ((PRIV(dev)->sonet_stats.line_febe += GET(LECCT)) < 0)
- PRIV(dev)->sonet_stats.line_febe = LONG_MAX;
- if (events & uPD98402_PFM_B3E)
- if ((PRIV(dev)->sonet_stats.path_bip += GET(B3ECT)) < 0)
- PRIV(dev)->sonet_stats.path_bip = LONG_MAX;
- if (events & uPD98402_PFM_B2E)
- if ((PRIV(dev)->sonet_stats.line_bip += GET(B2ECT)) < 0)
- PRIV(dev)->sonet_stats.line_bip = LONG_MAX;
- if (events & uPD98402_PFM_B1E)
- if ((PRIV(dev)->sonet_stats.section_bip += GET(B1ECT)) < 0)
- PRIV(dev)->sonet_stats.section_bip = LONG_MAX;
+ if (events & uPD98402_PFM_PFEB) ADD_LIMITED(path_febe,PFECB);
+ if (events & uPD98402_PFM_LFEB) ADD_LIMITED(line_febe,LECCT);
+ if (events & uPD98402_PFM_B3E) ADD_LIMITED(path_bip,B3ECT);
+ if (events & uPD98402_PFM_B2E) ADD_LIMITED(line_bip,B2ECT);
+ if (events & uPD98402_PFM_B1E) ADD_LIMITED(section_bip,B1ECT);
}
+#undef ADD_LIMITED
+
+
static void uPD98402_int(struct atm_dev *dev)
{
static unsigned long silence = 0;
@@ -158,7 +195,8 @@ static void uPD98402_int(struct atm_dev *dev)
if (reason & uPD98402_INT_PFM) stat_event(dev);
if (reason & uPD98402_INT_PCO) {
(void) GET(PCOCR); /* clear interrupt cause */
- PRIV(dev)->sonet_stats.uncorr_hcs += GET(HECCT);
+ atomic_add(GET(HECCT),
+ &PRIV(dev)->sonet_stats.uncorr_hcs);
}
if ((reason & uPD98402_INT_RFO) &&
(time_after(jiffies, silence) || silence == 0)) {
@@ -172,10 +210,10 @@ static void uPD98402_int(struct atm_dev *dev)
static int uPD98402_start(struct atm_dev *dev)
{
-DPRINTK("phy_start\n");
+ DPRINTK("phy_start\n");
if (!(PRIV(dev) = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL)))
return -ENOMEM;
- memset(&PRIV(dev)->sonet_stats,0,sizeof(struct sonet_stats));
+ memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats));
(void) GET(PCR); /* clear performance events */
PUT(uPD98402_PFM_FJ,PCMR); /* ignore frequency adj */
(void) GET(PCOCR); /* clear overflows */
@@ -184,15 +222,26 @@ DPRINTK("phy_start\n");
PUT(~(uPD98402_INT_PFM | uPD98402_INT_ALM | uPD98402_INT_RFO |
uPD98402_INT_LOS),PIMR); /* enable them */
(void) fetch_stats(dev,NULL,1); /* clear kernel counters */
+ atomic_set(&PRIV(dev)->sonet_stats.corr_hcs,-1);
+ atomic_set(&PRIV(dev)->sonet_stats.tx_cells,-1);
+ atomic_set(&PRIV(dev)->sonet_stats.rx_cells,-1);
return 0;
}
+static int uPD98402_stop(struct atm_dev *dev)
+{
+ /* let SAR driver worry about stopping interrupts */
+ kfree(PRIV(dev));
+ return 0;
+}
+
static const struct atmphy_ops uPD98402_ops = {
- uPD98402_start,
- uPD98402_ioctl, /* no ioctl yet */
- uPD98402_int
+ start: uPD98402_start,
+ ioctl: uPD98402_ioctl,
+ interrupt: uPD98402_int,
+ stop: uPD98402_stop,
};
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index 26c8c9d90..1b68f5529 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -21,10 +21,12 @@
#include <linux/init.h>
#include <linux/atm_zatm.h>
#include <linux/capability.h>
+#include <linux/bitops.h>
#include <asm/byteorder.h>
#include <asm/system.h>
#include <asm/string.h>
#include <asm/io.h>
+#include <asm/atomic.h>
#include <asm/uaccess.h>
#include "uPD98401.h"
@@ -637,7 +639,7 @@ printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]);
}
if (!size) {
dev_kfree_skb_irq(skb);
- if (vcc) vcc->stats->rx_err++;
+ if (vcc) atomic_inc(&vcc->stats->rx_err);
continue;
}
if (!atm_charge(vcc,skb->truesize)) {
@@ -647,7 +649,7 @@ printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]);
skb->len = size;
ATM_SKB(skb)->vcc = vcc;
vcc->push(vcc,skb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
zout(pos & 0xffff,MTA(mbx));
#if 0 /* probably a stupid idea */
@@ -914,7 +916,7 @@ if (*ZATM_PRV_DSC(skb) != (uPD98401_TXPD_V | uPD98401_TXPD_DP |
skb_queue_head(&zatm_vcc->backlog,skb);
break;
}
- vcc->stats->tx++;
+ atomic_inc(&vcc->stats->tx);
wake_up(&zatm_vcc->tx_wait);
}
@@ -1537,7 +1539,7 @@ static void zatm_close(struct atm_vcc *vcc)
{
DPRINTK(">zatm_close\n");
if (!ZATM_VCC(vcc)) return;
- vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
close_rx(vcc);
EVENT("close_tx\n",0,0);
close_tx(vcc);
@@ -1545,7 +1547,7 @@ static void zatm_close(struct atm_vcc *vcc)
/* deallocate memory */
kfree(ZATM_VCC(vcc));
ZATM_VCC(vcc) = NULL;
- vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
}
@@ -1557,20 +1559,20 @@ static int zatm_open(struct atm_vcc *vcc,short vpi,int vci)
DPRINTK(">zatm_open\n");
zatm_dev = ZATM_DEV(vcc->dev);
- if (!(vcc->flags & ATM_VF_PARTIAL)) ZATM_VCC(vcc) = NULL;
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) ZATM_VCC(vcc) = NULL;
error = atm_find_ci(vcc,&vpi,&vci);
if (error) return error;
vcc->vpi = vpi;
vcc->vci = vci;
if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC)
- vcc->flags |= ATM_VF_ADDR;
+ set_bit(ATM_VF_ADDR,&vcc->flags);
if (vcc->qos.aal != ATM_AAL5) return -EINVAL; /* @@@ AAL0 */
DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi,
vcc->vci);
- if (!(vcc->flags & ATM_VF_PARTIAL)) {
+ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) {
zatm_vcc = kmalloc(sizeof(struct zatm_vcc),GFP_KERNEL);
if (!zatm_vcc) {
- vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
return -ENOMEM;
}
ZATM_VCC(vcc) = zatm_vcc;
@@ -1593,7 +1595,7 @@ static int zatm_open(struct atm_vcc *vcc,short vpi,int vci)
zatm_close(vcc);
return error;
}
- vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&vcc->flags);
return 0;
}
@@ -1733,7 +1735,7 @@ static int zatm_send(struct atm_vcc *vcc,struct sk_buff *skb)
int error;
EVENT(">zatm_send 0x%lx\n",(unsigned long) skb,0);
- if (!ZATM_VCC(vcc)->tx_chan || !(vcc->flags & ATM_VF_READY)) {
+ if (!ZATM_VCC(vcc)->tx_chan || !test_bit(ATM_VF_READY,&vcc->flags)) {
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb(skb);
return -EINVAL;
@@ -1809,7 +1811,7 @@ int __init zatm_detect(void)
while ((pci_dev = pci_find_device(PCI_VENDOR_ID_ZEITNET,type ?
PCI_DEVICE_ID_ZEITNET_1225 : PCI_DEVICE_ID_ZEITNET_1221,
pci_dev))) {
- dev = atm_dev_register(DEV_LABEL,&ops,-1,0);
+ dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL);
if (!dev) break;
zatm_dev->pci_dev = pci_dev;
ZATM_DEV(dev) = zatm_dev;