diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-03-27 23:54:12 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-03-27 23:54:12 +0000 |
commit | d3e71cb08747743fce908122bab08b479eb403a5 (patch) | |
tree | cbec6948fdbdee9af81cf3ecfb504070d2745d7b /drivers/atm | |
parent | fe7ff1706e323d0e5ed83972960a1ecc1ee538b3 (diff) |
Merge with Linux 2.3.99-pre3.
Diffstat (limited to 'drivers/atm')
-rw-r--r-- | drivers/atm/Makefile | 28 | ||||
-rw-r--r-- | drivers/atm/ambassador.c | 551 | ||||
-rw-r--r-- | drivers/atm/ambassador.h | 22 | ||||
-rw-r--r-- | drivers/atm/atmdev_init.c | 2 | ||||
-rw-r--r-- | drivers/atm/atmtcp.c | 61 | ||||
-rw-r--r-- | drivers/atm/eni.c | 271 | ||||
-rw-r--r-- | drivers/atm/eni.h | 3 | ||||
-rw-r--r-- | drivers/atm/fore200e.c | 174 | ||||
-rw-r--r-- | drivers/atm/fore200e.h | 33 | ||||
-rw-r--r-- | drivers/atm/horizon.c | 124 | ||||
-rw-r--r-- | drivers/atm/horizon.h | 2 | ||||
-rw-r--r-- | drivers/atm/idt77105.c | 64 | ||||
-rw-r--r-- | drivers/atm/iphase.c | 161 | ||||
-rw-r--r-- | drivers/atm/nicstar.c | 141 | ||||
-rw-r--r-- | drivers/atm/nicstar.h | 2 | ||||
-rw-r--r-- | drivers/atm/suni.c | 169 | ||||
-rw-r--r-- | drivers/atm/suni.h | 4 | ||||
-rw-r--r-- | drivers/atm/uPD98402.c | 123 | ||||
-rw-r--r-- | drivers/atm/zatm.c | 26 |
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 = ®s_local.ffredn; rfredn_t *rfL = ®s_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*)®s_local,sizeof(ia_regs_t)); + if (copy_to_user(ia_cmds.buf, ®s_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; |