S: 91054 Erlangen
S: Germany
+N: Giuliano Procida
+E: myxie@debian.org,gprocida@madge.com
+D: Madge Ambassador driver (Collage 155 Server ATM adapter)
+D: Madge Horizon driver (Collage 25 and 155 Client ATM adapters)
+P: 1024/93898735 D3 9E F4 F7 6D 8D 2F 3A 38 BA 06 7C 2B 33 43 7D
+S: Madge Networks
+S: Framewood Road
+S: Wexham SL3 6PJ
+S: United Kingdom
+
N: Daniel Quinlan
E: quinlan@pathname.com
W: http://www.pathname.com/~quinlan/
say M here and read Documentation/modules.txt. The module will be
called ohci1394.o.
-RAW IEEE 1394 I/O support
+Raw IEEE 1394 I/O support
CONFIG_IEEE1394_RAWIO
Say Y here if you want support for the raw device. This is generally
a good idea, so you should say Y here. The raw device enables
say M here and read Documentation/modules.txt. The module will be
called raw1394.o.
+Excessive debugging output
+CONFIG_IEEE1394_VERBOSEDEBUG
+ If you say Y here, you will get very verbose debugging logs from the
+ subsystem which includes a dump of the header of every sent and
+ received packet. This can amount to a high amount of data collected
+ in a very short time which is usually also saved to disk by the
+ system logging daemons.
+
+ Say Y if you really want or need the debugging output, everyone else
+ says N.
+
#
# m68k-specific kernel options
# Documented by Chris Lawrence <quango@themall.net> et al.
IEEE 1394 SUBSYSTEM
P: Andreas Bombe
M: andreas.bombe@munich.netsurf.de
-L: linux1394-devel@eclipt.uni-klu.ac.at
-W: http://eclipt.uni-klu.ac.at/ieee1394
+L: linux1394-devel@lists.sourceforge.net
+W: http://linux1394.sourceforge.net/
S: Maintained
IEEE 1394 AIC5800 DRIVER
P: Emanuel Pirker
M: epirker@edu.uni-klu.ac.at
L: linux1394-devel@eclipt.uni-klu.ac.at
-W: http://eclipt.uni-klu.ac.at/ieee1394
S: Maintained
IEEE 1394 OHCI DRIVER
P: Sebastien Rougeaux
M: sebastien.rougeaux@anu.edu.au
L: linux1394-devel@eclipt.uni-klu.ac.at
-W: http://eclipt.uni-klu.ac.at/ieee1394
S: Maintained
IEEE 1394 PCILYNX DRIVER
P: Andreas Bombe
M: andreas.bombe@munich.netsurf.de
L: linux1394-devel@eclipt.uni-klu.ac.at
-W: http://eclipt.uni-klu.ac.at/ieee1394
S: Maintained
IEEE 1394 RAW I/O DRIVER
P: Andreas Bombe
M: andreas.bombe@munich.netsurf.de
L: linux1394-devel@eclipt.uni-klu.ac.at
-W: http://eclipt.uni-klu.ac.at/ieee1394
S: Maintained
INTEL APIC/IOAPIC, LOWLEVEL X86 SMP SUPPORT
DRIVERS-$(CONFIG_TR) += drivers/net/tokenring/tr.a
DRIVERS-$(CONFIG_WAN) += drivers/net/wan/wan.a
DRIVERS-$(CONFIG_ARCNET) += drivers/net/arcnet/arcnet.a
-DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.a
+DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o
DRIVERS-$(CONFIG_IDE) += drivers/ide/ide.a
DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsi.a
DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394.a
-# $Id: Makefile,v 1.45 2000/01/29 01:08:48 anton Exp $
+# $Id: Makefile,v 1.46 2000/03/21 06:12:26 davem Exp $
# sparc/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
-# $Id: Makefile,v 1.42 2000/03/09 05:56:43 jj Exp $
+# $Id: Makefile,v 1.43 2000/03/21 06:12:28 davem Exp $
# sparc64/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
UNDECLARED_REGS := $(shell if $(CC) -c -x assembler /dev/null -Wa,--help | grep undeclared-regs > /dev/null; then echo y; else echo n; fi; )
+export NEW_GCC
+
ifneq ($(NEW_GAS),y)
AS = sparc64-linux-as
LD = sparc64-linux-ld
-# $Id: Makefile,v 1.51 2000/02/08 05:11:31 jj Exp $
+# $Id: Makefile,v 1.52 2000/03/19 07:00:29 ecd Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
#
binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c
-ifneq ($(IS_EGCS),y)
+ifneq ($(NEW_GCC),y)
CMODEL_CFLAG := -mmedlow
else
CMODEL_CFLAG := -mcmodel=medlow
-/* $Id: ioctl32.c,v 1.83 2000/03/14 07:31:25 jj Exp $
+/* $Id: ioctl32.c,v 1.84 2000/03/21 21:19:18 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
#define ATM_SETESIF32 _IOW('a', ATMIOC_ITF+13, struct atmif_sioc32)
#define ATM_GETSTAT32 _IOW('a', ATMIOC_SARCOM+0, struct atmif_sioc32)
#define ATM_GETSTATZ32 _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32)
+#define ATM_GETLOOP32 _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32)
+#define ATM_SETLOOP32 _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32)
static struct {
unsigned int cmd32;
{ ATM_SETESI32, ATM_SETESI },
{ ATM_SETESIF32, ATM_SETESIF },
{ ATM_GETSTAT32, ATM_GETSTAT },
- { ATM_GETSTATZ32, ATM_GETSTATZ }
+ { ATM_GETSTATZ32, ATM_GETSTATZ },
+ { ATM_GETLOOP32, ATM_GETLOOP },
+ { ATM_SETLOOP32, ATM_SETLOOP }
};
#define NR_ATM_IOCTL (sizeof(atm_ioctl_map)/sizeof(atm_ioctl_map[0]))
unsigned int cmd = 0;
switch (cmd32) {
- case SUNI_GETLOOP:
- case SUNI_SETLOOP:
case SONET_GETSTAT:
case SONET_GETSTATZ:
case SONET_GETDIAG:
return do_atmif_sioc(fd, cmd32, arg);
}
- if (cmd == 0) {
for (i = 0; i < NR_ATM_IOCTL; i++) {
if (cmd32 == atm_ioctl_map[i].cmd32) {
cmd = atm_ioctl_map[i].cmd;
if (i == NR_ATM_IOCTL) {
return -EINVAL;
}
- }
switch (cmd) {
case ATM_GETNAMES:
case ATM_SETESIF:
case ATM_GETSTAT:
case ATM_GETSTATZ:
+ case ATM_GETLOOP:
+ case ATM_SETLOOP:
return do_atmif_sioc(fd, cmd, arg);
}
HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl)
HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl)
HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl)
-HANDLE_IOCTL(SUNI_GETLOOP, do_atm_ioctl)
-HANDLE_IOCTL(SUNI_SETLOOP, do_atm_ioctl)
+HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl)
+HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl)
HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl)
HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl)
HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl)
-/* $Id: sys_sparc32.c,v 1.139 2000/03/16 20:37:57 davem Exp $
+/* $Id: sys_sparc32.c,v 1.140 2000/03/22 02:44:35 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
union nfsctl_res32 {
__u8 cr32_getfh[NFS_FHSIZE];
- u32 cr32_debug;
+ struct knfsd_fh cr32_getfs;
};
static int nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
return err;
}
+/* This really doesn't need translations, we are only passing
+ * back a union which contains opaque nfs file handle data.
+ */
static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
{
- int err;
-
- err = copy_to_user(&res32->cr32_getfh,
- &kres->cr_getfh,
- sizeof(res32->cr32_getfh));
- err |= __put_user(kres->cr_debug, &res32->cr32_debug);
- return err;
+ return copy_to_user(res32, kres, sizeof(*res32));
}
extern asmlinkage int sys_nfsservctl(int cmd, void *arg, void *resp);
# 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)
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
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
endif
ifeq ($(CONFIG_ATM_HORIZON),y)
-L_OBJS += horizon.o
+O_OBJS += horizon.o
else
ifeq ($(CONFIG_ATM_HORIZON),m)
M_OBJS += horizon.o
endif
ifeq ($(CONFIG_ATM_AMBASSADOR),y)
-L_OBJS += ambassador.o
+O_OBJS += ambassador.o
else
ifeq ($(CONFIG_ATM_AMBASSADOR),m)
M_OBJS += ambassador.o
endif
ifeq ($(CONFIG_ATM_TCP),y)
-L_OBJS += atmtcp.o
+O_OBJS += atmtcp.o
else
ifeq ($(CONFIG_ATM_TCP),m)
M_OBJS += atmtcp.o
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)
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)
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
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <asm/atomic.h>
#include <asm/io.h>
#include <asm/byteorder.h>
#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);
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
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) {
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;
}
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
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;
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);
}
}
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);
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);
} 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 {
dev->stats.rx.unused++;
}
- dev_kfree_skb (skb);
+ dev_kfree_skb_any (skb);
return;
}
// 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;
// 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
}
// 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();
}
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;
}
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
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;
/********** 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);
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;
}
#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;
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");
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));
}
}
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
// 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;
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;
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) {
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;
}
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;
return 0;
}
} else if (cmd == AMB_DONTPANIC) {
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
dont_panic (dev);
} else {
// moan
}
if (check_area (skb->data, skb->len)) {
- atm_vcc->stats->tx_err++;
+ atomic_inc(&atm_vcc->stats->tx_err);
return -ENOMEM; // ?
}
// 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);
}
// just do what the ATM layer would have done
- kfree_skb (skb);
+ dev_kfree_skb_any (skb);
return;
}
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);
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);
/********** 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,
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;
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 {
/* 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");
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");
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])) {
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 **********/
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;
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 {
}
// 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) {
/********** 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;
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;
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,
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);
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 {
}
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;
}
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) {
"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 */
show_version();
- // check arguments
amb_check_args();
// get the juice
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);
show_version();
- // check arguments
amb_check_args();
// get the juice
#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 */
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 */
( (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 {
devs = 0;
#ifdef CONFIG_ATM_ENI
- devs += eni_detect();
+// devs += eni_detect();
#endif
#ifdef CONFIG_ATM_ZATM
devs += zatm_detect();
#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 */
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;
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;
}
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",
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;
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);
}
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);
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));
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;
}
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));
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);
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 */
};
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;
}
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;
#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>
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 */
size);
}
eff = length = 0;
- vcc->stats->rx_err++;
+ atomic_inc(&vcc->stats->rx_err);
}
else {
size = (descr & MID_RED_COUNT)*(ATM_CELL_PAYLOAD >> 2);
"(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;
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)) {
if (rx_vcc(curr)) return;
eni_dev->slow = ENI_VCC(curr)->next;
ENI_VCC(curr)->next = ENI_VCC_NOS;
+ barrier();
ENI_VCC(curr)->servicing--;
}
}
vcc->push(vcc,skb);
pushed++;
}
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
wake_up(&eni_dev->rx_wait);
}
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;
/* 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;
* 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) */
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++;
}
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;
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 |
/*--------------------------------- 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 */
} })
-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;
#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;
}
-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;
}
-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;
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;
{
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();*/
}
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;
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;
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;
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;
}
* 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;
(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;
}
}
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;
}
};
-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
*/
}
-#endif
+
+module_init(eni_init);
+module_exit(eni_cleanup);
#include <linux/skbuff.h>
#include <linux/time.h>
#include <linux/pci.h>
+#include <linux/spinlock.h>
#include "midway.h"
};
struct eni_dev {
+ /*-------------------------------- spinlock */
+ spinlock_t lock; /* sync with interrupt */
/*-------------------------------- base pointers into Midway address
space */
unsigned long phy; /* PHY interface chip registers */
/*
- $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.
#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>
#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>
#define FORE200E_52BYTE_AAL0_SDU
#endif
-#define FORE200E_VERSION "0.2a"
+#define FORE200E_VERSION "0.2b"
#define FORE200E "fore200e: "
/* 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;
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)
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;
}
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);
}
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);
}
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;
chunk->alloc_addr,
chunk->dma_addr);
#else
- fore200e_pca_dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size);
-
fore200e_chunk_free(fore200e, chunk);
#endif
}
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);
*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);
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);
}
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)
/* 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;
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;
}
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);
}
}
vcc->push(vcc, skb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
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; "
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;
}
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;
}
}
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;
}
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;
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),
{
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
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);
*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);
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);
*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);
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;
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 */
/* 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;
}
/* 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);
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;
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"
mon960_release >> 16, mon960_release << 16 >> 16,
media_name[ media_index ],
oc3_revision,
- oc3_mode[ fore200e->loop_mode ]);
+ oc3_mode[ oc3_index ]);
}
if (!left--) {
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;
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);
} 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 {
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <asm/string.h>
#include <asm/byteorder.h>
#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);
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
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.
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)
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",
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);
}
}
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;
{
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);
#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
}
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;
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);
#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
}
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);
if (!channel) {
PRINTD (DBG_ERR|DBG_TX, "attempt to transmit on zero (rx_)channel");
+ hrz_kfree_skb (skb);
return -EIO;
}
#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)
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;
}
}
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();
// 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
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;
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;
// 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;
}
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
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 {
#define DRIVER_ATM_HORIZON_H
#include <linux/config.h>
-
#include <linux/version.h>
-
#ifdef CONFIG_ATM_HORIZON_DEBUG
#define DEBUG_HORIZON
#endif
}
+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;
}
/* 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;
}
#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>
#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 */
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;
}
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;
}
(long)skb1);)
}
else
- dev_kfree_skb(skb1);
+ dev_kfree_skb_any(skb1);
skb1 = skb_dequeue(&iavcc->txing_skb);
}
if (!skb1) {
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);
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");)
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;
}
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;
if (!skb->len)
{
printk("rx_dle_intr: skb len 0\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
else
{
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
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
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:
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) {
vcc->pop(vcc, skb);
}
else {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
}
else { /* Hold the rate-limited skb for flow control */
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) {
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);
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;
}
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;
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;
return error;
}
- vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&vcc->flags);
#ifndef MODULE
{
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;
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:
{
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;
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;
}
}
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) {
if (vcc->pop)
vcc->pop(vcc, skb);
else
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return 0;
}
if ((u32)skb->data & 3) {
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
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 */
}
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 );
{
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;
}
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);)
#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
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 */
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);
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++)
{
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);
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);
#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
{
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)
{
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 */
{
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++)
if (vcc->pop != NULL)
vcc->pop(vcc, scq->skb[i]);
else
- dev_kfree_skb(scq->skb[i]);
+ dev_kfree_skb_any(scq->skb[i]);
}
}
}
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
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
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 */
{
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;
}
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;
}
}
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
{
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;
}
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;
}
- vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&vcc->flags);
MOD_INC_USE_COUNT;
return 0;
}
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)
{
}
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
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;
}
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;
}
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)
{
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 */
ATM_SKB(sb)->vcc = vcc;
sb->stamp = xtime;
vcc->push(vcc, sb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
cell += ATM_CELL_PAYLOAD;
}
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;
}
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;
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);
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;
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;
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 */
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,
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),
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;
card->hbpool.count++;
}
else
- kfree_skb(hb);
+ dev_kfree_skb_any(hb);
}
else
{
#endif /* NS_USE_DESTRUCTORS */
hb->stamp = xtime;
vcc->push(vcc, hb);
- vcc->stats->rx++;
+ atomic_inc(&vcc->stats->rx);
}
}
else
{
printk("nicstar%d: What kind of rx buffer is this?\n", card->index);
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
}
else
{
printk("nicstar%d: What kind of rx buffer is this?\n", card->index);
- kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
}
}
card->iovpool.count++;
}
else
- kfree_skb(iovb);
+ dev_kfree_skb_any(iovb);
}
/* 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;
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;
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)
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)
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)
#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 */
-/* 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 */
#include <asm/system.h>
#include <asm/param.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#include "suni.h"
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 */
};
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;
}
}
+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) {
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:
-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;
}
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);
}
+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,
};
-/* 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
#include <linux/sonet.h>
#include <linux/init.h>
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#include "uPD98402.h"
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 */
};
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;
}
}
+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) {
-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;
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)) {
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 */
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,
};
#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"
}
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)) {
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 */
skb_queue_head(&zatm_vcc->backlog,skb);
break;
}
- vcc->stats->tx++;
+ atomic_inc(&vcc->stats->tx);
wake_up(&zatm_vcc->tx_wait);
}
{
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);
/* deallocate memory */
kfree(ZATM_VCC(vcc));
ZATM_VCC(vcc) = NULL;
- vcc->flags &= ~ATM_VF_ADDR;
+ clear_bit(ATM_VF_ADDR,&vcc->flags);
}
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;
zatm_close(vcc);
return error;
}
- vcc->flags |= ATM_VF_READY;
+ set_bit(ATM_VF_READY,&vcc->flags);
return 0;
}
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;
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;
* may race another module load of the same I/O
*/
- if (request_region(ATIXL_MSE_DATA_PORT, 3, "atixlmouse"))
+ if (!request_region(ATIXL_MSE_DATA_PORT, 3, "atixlmouse"))
return -EIO;
a = inb( ATIXL_MSE_SIGNATURE_PORT ); /* Get signature */
*/
/*#define BROKEN_MOUSE*/
-extern int sun_mouse_init(void);
-
struct busmouse_data {
struct miscdevice miscdev;
struct busmouse *ops;
return err;
}
-int __init bus_mouse_init(void)
-{
-#ifdef CONFIG_SUN_MOUSE
- sun_mouse_init();
-#endif
- return 0;
-}
-
EXPORT_SYMBOL(busmouse_add_movementbuttons);
EXPORT_SYMBOL(busmouse_add_movement);
EXPORT_SYMBOL(busmouse_add_buttons);
EXPORT_SYMBOL(register_busmouse);
EXPORT_SYMBOL(unregister_busmouse);
-
-#ifdef MODULE
-int init_module(void)
-{
- return bus_mouse_init();
-}
-
-void cleanup_module(void)
-{
-}
-#endif
extern int register_busmouse(struct busmouse *ops);
extern int unregister_busmouse(int mousedev);
-extern int bus_mouse_init(void);
-
#endif
int __init misc_init(void)
{
create_proc_read_entry("misc", 0, 0, misc_read_proc, NULL);
-#ifdef CONFIG_BUSMOUSE
- bus_mouse_init();
-#endif
#if defined CONFIG_82C710_MOUSE
qpmouse_init();
#endif
fi
dep_tristate 'Adaptec AIC-5800 (AHA-89xx) support' CONFIG_IEEE1394_AIC5800 $CONFIG_IEEE1394
-
+
dep_tristate 'OHCI (Open Host Controller Interface) support' CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394
dep_tristate 'Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394
+ bool 'Excessive debugging output' CONFIG_IEEE1394_VERBOSEDEBUG
fi
endmenu
fi
#include "highlevel.h"
+/* FIXME: this one won't work on little endian with big endian data */
static u16 csr_crc16(unsigned *data, int length)
{
int check=0, i;
host->csr.state &= ~0x100;
}
- host->csr.topology_map[1]++;
- host->csr.topology_map[2] = host->node_count << 16 | host->selfid_count;
- host->csr.topology_map[0] = (host->selfid_count + 2) << 16
- | csr_crc16(host->csr.topology_map + 1, host->selfid_count + 2);
-
- /* FIXME - generate speed map */
- host->csr.speed_map[0] = 0x3f1 << 16 | csr_crc16(host->csr.speed_map+1,
- 0x3f1);
+ host->csr.topology_map[1] =
+ cpu_to_be32(be32_to_cpu(host->csr.topology_map[1]) + 1);
+ host->csr.topology_map[2] = cpu_to_be32(host->node_count << 16
+ | host->selfid_count);
+ host->csr.topology_map[0] =
+ cpu_to_be32((host->selfid_count + 2) << 16
+ | csr_crc16(host->csr.topology_map + 1,
+ host->selfid_count + 2));
+
+ host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16
+ | csr_crc16(host->csr.speed_map+1,
+ 0x3f1));
}
/* Read topology / speed maps and configuration ROM */
-static int read_maps(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
- unsigned int length)
+static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+ u64 addr, unsigned int length)
{
int csraddr = addr - CSR_REGISTER_BASE;
const char *src;
return RCODE_COMPLETE;
}
-/* Read FCP register space */
-static int read_fcp(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
- unsigned int length)
-{
- int csraddr = addr - CSR_REGISTER_BASE;
- const char *src;
-
- if (csraddr + length > CSR_FCP_END) {
- return RCODE_ADDRESS_ERROR;
- }
- src = ((char *)host->csr.fcp_data) + csraddr - CSR_FCP_COMMAND;
-
- memcpy(buffer, src, length);
- return RCODE_COMPLETE;
-}
-
-/* Write FCP register space */
-static int write_fcp(struct hpsb_host *host, quadlet_t *data, u64 addr,
- unsigned int length)
-{
- int csraddr = addr - CSR_REGISTER_BASE;
- char *dest;
-
- if (csraddr + length > CSR_FCP_END) {
- return RCODE_ADDRESS_ERROR;
- }
- dest = ((char *)host->csr.fcp_data) + csraddr - CSR_FCP_COMMAND;
-
- memcpy(dest, data, length);
- return RCODE_COMPLETE;
-}
-
#define out if (--length == 0) break
-static int read_regs(struct hpsb_host *host, quadlet_t *buf, u64 addr,
- unsigned int length)
+static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
+ u64 addr, unsigned int length)
{
int csraddr = addr - CSR_REGISTER_BASE;
int oldcycle;
switch (csraddr) {
case CSR_STATE_CLEAR:
- *(buf++) = host->csr.state;
+ *(buf++) = cpu_to_be32(host->csr.state);
out;
case CSR_STATE_SET:
- *(buf++) = host->csr.state;
+ *(buf++) = cpu_to_be32(host->csr.state);
out;
case CSR_NODE_IDS:
- *(buf++) = host->csr.node_ids;
+ *(buf++) = cpu_to_be32(host->csr.node_ids);
out;
case CSR_RESET_START:
/* address gap - handled by default below */
case CSR_SPLIT_TIMEOUT_HI:
- *(buf++) = host->csr.split_timeout_hi;
+ *(buf++) = cpu_to_be32(host->csr.split_timeout_hi);
out;
case CSR_SPLIT_TIMEOUT_LO:
- *(buf++) = host->csr.split_timeout_lo;
+ *(buf++) = cpu_to_be32(host->csr.split_timeout_lo);
out;
/* address gap */
/* cycle time wrapped around */
host->csr.bus_time += 1 << 7;
}
- *(buf++) = host->csr.cycle_time;
+ *(buf++) = cpu_to_be32(host->csr.cycle_time);
out;
case CSR_BUS_TIME:
oldcycle = host->csr.cycle_time;
/* cycle time wrapped around */
host->csr.bus_time += (1 << 7);
}
- *(buf++) = host->csr.bus_time | (host->csr.cycle_time >> 25);
+ *(buf++) = cpu_to_be32(host->csr.bus_time
+ | (host->csr.cycle_time >> 25));
out;
/* address gap */
return RCODE_ADDRESS_ERROR;
case CSR_BUS_MANAGER_ID:
- *(buf++) = host->csr.bus_manager_id;
+ *(buf++) = cpu_to_be32(host->csr.bus_manager_id);
out;
case CSR_BANDWIDTH_AVAILABLE:
- *(buf++) = host->csr.bandwidth_available;
+ *(buf++) = cpu_to_be32(host->csr.bandwidth_available);
out;
case CSR_CHANNELS_AVAILABLE_HI:
- *(buf++) = host->csr.channels_available_hi;
+ *(buf++) = cpu_to_be32(host->csr.channels_available_hi);
out;
case CSR_CHANNELS_AVAILABLE_LO:
- *(buf++) = host->csr.channels_available_lo;
+ *(buf++) = cpu_to_be32(host->csr.channels_available_lo);
out;
/* address gap to end - fall through to default */
return RCODE_COMPLETE;
}
-static int write_regs(struct hpsb_host *host, quadlet_t *data, u64 addr,
- unsigned int length)
+static int write_regs(struct hpsb_host *host, int nodeid, quadlet_t *data,
+ u64 addr, unsigned int length)
{
int csraddr = addr - CSR_REGISTER_BASE;
case CSR_NODE_IDS:
host->csr.node_ids &= NODE_MASK << 16;
- host->csr.node_ids |= *(data++) & (BUS_MASK << 16);
+ host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16);
host->node_id = host->csr.node_ids >> 16;
host->template->devctl(host, SET_BUS_ID, host->node_id >> 6);
out;
return RCODE_ADDRESS_ERROR;
case CSR_SPLIT_TIMEOUT_HI:
- host->csr.split_timeout_hi = *(data++) & 0x00000007;
+ host->csr.split_timeout_hi =
+ be32_to_cpu(*(data++)) & 0x00000007;
out;
case CSR_SPLIT_TIMEOUT_LO:
- host->csr.split_timeout_lo = *(data++) & 0xfff80000;
+ host->csr.split_timeout_lo =
+ be32_to_cpu(*(data++)) & 0xfff80000;
out;
/* address gap */
case CSR_CYCLE_TIME:
/* should only be set by cycle start packet, automatically */
- host->csr.cycle_time = *data;
- host->template->devctl(host, SET_CYCLE_COUNTER, *(data++));
+ host->csr.cycle_time = be32_to_cpu(*data);
+ host->template->devctl(host, SET_CYCLE_COUNTER,
+ be32_to_cpu(*(data++)));
out;
case CSR_BUS_TIME:
- host->csr.bus_time = *(data++) & 0xffffff80;
+ host->csr.bus_time = be32_to_cpu(*(data++)) & 0xffffff80;
out;
/* address gap */
/* helper function for lock_regs */
inline static void compare_swap(quadlet_t *old, quadlet_t data, quadlet_t arg)
{
- if (*old == arg) {
- *old = data;
+ if (*old == be32_to_cpu(arg)) {
+ *old = be32_to_cpu(data);
}
}
-static int lock_regs(struct hpsb_host *host, quadlet_t *store, u64 addr,
- quadlet_t data, quadlet_t arg, int extcode)
+static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
+ u64 addr, quadlet_t data, quadlet_t arg, int extcode)
{
int csraddr = addr - CSR_REGISTER_BASE;
unsigned long flags;
switch (csraddr) {
case CSR_BUS_MANAGER_ID:
- *store = host->csr.bus_manager_id;
+ *store = cpu_to_be32(host->csr.bus_manager_id);
compare_swap(&host->csr.bus_manager_id,
data, arg);
break;
case CSR_BANDWIDTH_AVAILABLE:
- *store = host->csr.bandwidth_available;
+ *store = cpu_to_be32(host->
+ csr.bandwidth_available);
compare_swap(&host->csr.bandwidth_available,
data, arg);
break;
case CSR_CHANNELS_AVAILABLE_HI:
- *store = host->csr.channels_available_hi;
+ *store = cpu_to_be32(host->
+ csr.channels_available_hi);
compare_swap(&host->csr.channels_available_hi,
data, arg);
break;
case CSR_CHANNELS_AVAILABLE_LO:
- *store = host->csr.channels_available_lo;
+ *store = cpu_to_be32(host->
+ csr.channels_available_lo);
compare_swap(&host->csr.channels_available_lo,
data, arg);
break;
}
}
+static int write_fcp(struct hpsb_host *host, int nodeid, quadlet_t *data,
+ u64 addr, unsigned int length)
+{
+ int csraddr = addr - CSR_REGISTER_BASE;
+
+ if (length > 512) {
+ return RCODE_TYPE_ERROR;
+ }
+
+ switch (csraddr) {
+ case CSR_FCP_COMMAND:
+ highlevel_fcp_request(host, nodeid, 0, (u8 *)data, length);
+ break;
+ case CSR_FCP_RESPONSE:
+ highlevel_fcp_request(host, nodeid, 1, (u8 *)data, length);
+ break;
+ default:
+ return RCODE_TYPE_ERROR;
+ }
+
+ return RCODE_COMPLETE;
+}
+
struct hpsb_highlevel_ops csr_ops = {
- add_host,
- NULL,
- host_reset,
- NULL
+ add_host: add_host,
+ host_reset: host_reset,
};
struct hpsb_address_ops map_ops = {
- read_maps,
- NULL,
- NULL,
- NULL
+ read: read_maps,
};
struct hpsb_address_ops fcp_ops = {
- read_fcp,
- write_fcp,
- NULL,
- NULL
+ write: write_fcp,
};
struct hpsb_address_ops reg_ops = {
- read_regs,
- write_regs,
- lock_regs,
- NULL
+ read: read_regs,
+ write: write_regs,
+ lock: lock_regs,
};
quadlet_t topology_map[256];
quadlet_t speed_map[1024];
- quadlet_t fcp_data[1024];
};
read_unlock(&hl_drivers_lock);
}
+void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
+ u8 *data, unsigned int length)
+{
+ struct list_head *entry;
+ struct hpsb_highlevel *hl;
+ int cts = data[0];
+
+ read_lock(&hl_drivers_lock);
+ entry = hl_drivers.next;
+
+ while (entry != &hl_drivers) {
+ hl = list_entry(entry, struct hpsb_highlevel, hl_list);
+ if (hl->op->fcp_request) {
+ hl->op->fcp_request(host, nodeid, direction, cts, data,
+ length);
+ }
+ entry = entry->next;
+ }
+ read_unlock(&hl_drivers_lock);
+}
-int highlevel_read(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
- unsigned int length)
+int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+ u64 addr, unsigned int length)
{
struct hpsb_address_serve *as;
struct list_head *entry;
unsigned int partlength;
int rcode = RCODE_ADDRESS_ERROR;
- if ((addr | length) & 0x3) {
- /* Addresses or lengths not a multiple of a quadlet pose a big
- * problem on little endian machines because we always do this
- * in arch endian and swapping would mess it all up. So we
- * simply don't allow this at all. */
- return RCODE_TYPE_ERROR;
- }
-
read_lock(&addr_space_lock);
entry = addr_space.next;
length);
if (as->op->read != NULL) {
- rcode = as->op->read(host, buffer, addr,
+ rcode = as->op->read(host, nodeid, buffer, addr,
partlength);
} else {
rcode = RCODE_TYPE_ERROR;
return rcode;
}
-int highlevel_write(struct hpsb_host *host, quadlet_t *data, u64 addr,
- unsigned int length)
+int highlevel_write(struct hpsb_host *host, int nodeid, quadlet_t *data,
+ u64 addr, unsigned int length)
{
struct hpsb_address_serve *as;
struct list_head *entry;
unsigned int partlength;
int rcode = RCODE_ADDRESS_ERROR;
- if ((addr | length) & 0x3) {
- return RCODE_TYPE_ERROR;
- }
-
read_lock(&addr_space_lock);
entry = addr_space.next;
length);
if (as->op->write != NULL) {
- rcode = as->op->write(host, data, addr,
+ rcode = as->op->write(host, nodeid, data, addr,
partlength);
} else {
rcode = RCODE_TYPE_ERROR;
}
-int highlevel_lock(struct hpsb_host *host, quadlet_t *store, u64 addr,
- quadlet_t data, quadlet_t arg, int ext_tcode)
+int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
+ u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode)
{
struct hpsb_address_serve *as;
struct list_head *entry;
while (as->start <= addr) {
if (as->end > addr) {
if (as->op->lock != NULL) {
- rcode = as->op->lock(host, store, addr, data,
- arg, ext_tcode);
+ rcode = as->op->lock(host, nodeid, store, addr,
+ data, arg, ext_tcode);
} else {
rcode = RCODE_TYPE_ERROR;
}
return rcode;
}
-int highlevel_lock64(struct hpsb_host *host, octlet_t *store, u64 addr,
- octlet_t data, octlet_t arg, int ext_tcode)
+int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
+ u64 addr, octlet_t data, octlet_t arg, int ext_tcode)
{
struct hpsb_address_serve *as;
struct list_head *entry;
while (as->start <= addr) {
if (as->end > addr) {
if (as->op->lock64 != NULL) {
- rcode = as->op->lock64(host, store, addr, data,
- arg, ext_tcode);
+ rcode = as->op->lock64(host, nodeid, store,
+ addr, data, arg,
+ ext_tcode);
} else {
rcode = RCODE_TYPE_ERROR;
}
* for channel/host combinations you did not request. */
void (*iso_receive) (struct hpsb_host *host, int channel,
quadlet_t *data, unsigned int length);
+
+ /* A write request was received on either the FCP_COMMAND (direction =
+ * 0) or the FCP_RESPONSE (direction = 1) register. The cts arg
+ * contains the cts field (first byte of data).
+ */
+ void (*fcp_request) (struct hpsb_host *host, int nodeid, int direction,
+ int cts, u8 *data, unsigned int length);
};
struct hpsb_address_ops {
*/
/* These functions have to implement block reads for themselves. */
- int (*read) (struct hpsb_host *host, quadlet_t *buffer, u64 addr,
- unsigned int length);
- int (*write) (struct hpsb_host *host, quadlet_t *data, u64 addr,
- unsigned int length);
+ int (*read) (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+ u64 addr, unsigned int length);
+ int (*write) (struct hpsb_host *host, int nodeid, quadlet_t *data,
+ u64 addr, unsigned int length);
/* Lock transactions: write results of ext_tcode operation into
* *store. */
- int (*lock) (struct hpsb_host *host, quadlet_t *store, u64 addr,
- quadlet_t data, quadlet_t arg, int ext_tcode);
- int (*lock64) (struct hpsb_host *host, octlet_t *store, u64 addr,
- octlet_t data, octlet_t arg, int ext_tcode);
+ int (*lock) (struct hpsb_host *host, int nodeid, quadlet_t *store,
+ u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode);
+ int (*lock64) (struct hpsb_host *host, int nodeid, octlet_t *store,
+ u64 addr, octlet_t data, octlet_t arg, int ext_tcode);
};
void highlevel_remove_host(struct hpsb_host *host);
void highlevel_host_reset(struct hpsb_host *host);
-int highlevel_read(struct hpsb_host *host, quadlet_t *buffer, u64 addr,
- unsigned int length);
-int highlevel_write(struct hpsb_host *host, quadlet_t *data, u64 addr,
- unsigned int length);
-int highlevel_lock(struct hpsb_host *host, quadlet_t *store, u64 addr,
- quadlet_t data, quadlet_t arg, int ext_tcode);
-int highlevel_lock64(struct hpsb_host *host, octlet_t *store, u64 addr,
- octlet_t data, octlet_t arg, int ext_tcode);
+int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+ u64 addr, unsigned int length);
+int highlevel_write(struct hpsb_host *host, int nodeid, quadlet_t *data,
+ u64 addr, unsigned int length);
+int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
+ u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode);
+int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
+ u64 addr, octlet_t data, octlet_t arg, int ext_tcode);
void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
unsigned int length);
+void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
+ u8 *data, unsigned int length);
/*
#define SELFID_PORT_NCONN 0x1
#define SELFID_PORT_NONE 0x0
+
+#include <asm/byteorder.h>
+
+#ifdef __BIG_ENDIAN_BITFIELD
+
+struct selfid {
+ u32 packet_identifier:2; /* always binary 10 */
+ u32 phy_id:6;
+ /* byte */
+ u32 extended:1; /* if true is struct ext_selfid */
+ u32 link_active:1;
+ u32 gap_count:6;
+ /* byte */
+ u32 speed:2;
+ u32 phy_delay:2;
+ u32 contender:1;
+ u32 power_class:3;
+ /* byte */
+ u32 port0:2;
+ u32 port1:2;
+ u32 port2:2;
+ u32 initiated_reset:1;
+ u32 more_packets:1;
+} __attribute__((packed));
+
+struct ext_selfid {
+ u32 packet_identifier:2; /* always binary 10 */
+ u32 phy_id:6;
+ /* byte */
+ u32 extended:1; /* if false is struct selfid */
+ u32 seq_nr:3;
+ u32 reserved:2;
+ u32 porta:2;
+ /* byte */
+ u32 portb:2;
+ u32 portc:2;
+ u32 portd:2;
+ u32 porte:2;
+ /* byte */
+ u32 portf:2;
+ u32 portg:2;
+ u32 porth:2;
+ u32 reserved2:1;
+ u32 more_packets:1;
+} __attribute__((packed));
+
+#elif defined __LITTLE_ENDIAN_BITFIELD /* __BIG_ENDIAN_BITFIELD */
+
+/*
+ * Note: these mean to be bit fields of a big endian SelfID as seen on a little
+ * endian machine.
+ */
+
+struct selfid {
+ u32 phy_id:6;
+ u32 packet_identifier:2; /* always binary 10 */
+ /* byte */
+ u32 gap_count:6;
+ u32 link_active:1;
+ u32 extended:1; /* if true is struct ext_selfid */
+ /* byte */
+ u32 power_class:3;
+ u32 contender:1;
+ u32 phy_delay:2;
+ u32 speed:2;
+ /* byte */
+ u32 more_packets:1;
+ u32 initiated_reset:1;
+ u32 port2:2;
+ u32 port1:2;
+ u32 port0:2;
+} __attribute__((packed));
+
+struct ext_selfid {
+ u32 phy_id:6;
+ u32 packet_identifier:2; /* always binary 10 */
+ /* byte */
+ u32 porta:2;
+ u32 reserved:2;
+ u32 seq_nr:3;
+ u32 extended:1; /* if false is struct selfid */
+ /* byte */
+ u32 porte:2;
+ u32 portd:2;
+ u32 portc:2;
+ u32 portb:2;
+ /* byte */
+ u32 more_packets:1;
+ u32 reserved2:1;
+ u32 porth:2;
+ u32 portg:2;
+ u32 portf:2;
+} __attribute__((packed));
+
+#else
+#error What? PDP endian?
+#endif /* __BIG_ENDIAN_BITFIELD */
+
+
#endif /* _IEEE1394_IEEE1394_H */
* IEEE 1394 for Linux
*
* Core support: hpsb_packet management, packet handling and forwarding to
- * csr or lowlevel code
+ * highlevel or lowlevel code
*
* Copyright (C) 1999, 2000 Andreas E. Bombe
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/string.h>
packet->header = header;
if (data_size) {
- data = kmalloc(data_size + 4, kmflags);
+ data = kmalloc(data_size + 8, kmflags);
if (data == NULL) {
kfree(header);
kfree(packet);
}
packet->data = data;
- packet->data_size = data_size - 4;
+ packet->data_size = data_size;
}
INIT_LIST_HEAD(&packet->list);
sema_init(&packet->state_change, 0);
packet->state = unused;
packet->generation = get_hpsb_generation();
-
-#ifdef __BIG_ENDIAN
- /* set default */
packet->data_be = 1;
-#endif
return packet;
}
{
int nodeid = -1;
int rest_of_selfids = num_of_selfids;
- quadlet_t *sidp = host->topology_map;
- quadlet_t sid = *sidp;
+ struct selfid *sid = (struct selfid *)host->topology_map;
+ struct ext_selfid *esid;
int esid_seq = 23;
- int i;
while (rest_of_selfids--) {
- sid = *(sidp++);
-
- if (!(sid & 0x00800000) /* !extended */) {
+ if (!sid->extended) {
nodeid++;
esid_seq = 0;
-
- if (((sid >> 24) & NODE_MASK) != nodeid) {
+
+ if (sid->phy_id != nodeid) {
HPSB_INFO("SelfIDs failed monotony check with "
- "%d", (sid >> 24) & NODE_MASK);
+ "%d", sid->phy_id);
return 0;
}
-
- /* "if is contender and link active" */
- if ((sid & (1<<11)) && (sid & (1<<22))) {
- host->irm_id = LOCAL_BUS | ((sid >> 24)
- & NODE_MASK);
+
+ if (sid->contender && sid->link_active) {
+ host->irm_id = LOCAL_BUS | sid->phy_id;
}
} else {
- if ((((sid >> 24) & NODE_MASK) != nodeid)
- || (((sid >> 20) & 0x7) != esid_seq)) {
+ esid = (struct ext_selfid *)sid;
+
+ if ((esid->phy_id != nodeid)
+ || (esid->seq_nr != esid_seq)) {
HPSB_INFO("SelfIDs failed monotony check with "
- "%d/%d", (sid >> 24) & NODE_MASK,
- (sid >> 20) & 0x7);
+ "%d/%d", esid->phy_id, esid->seq_nr);
return 0;
}
esid_seq++;
}
- }
-
- sidp--;
- while (sid & 0x00800000 /* extended */) {
- /* check that no ports go to a parent */
- for (i = 2; i < 18; i += 2) {
- if ((sid & (0x3 << i)) == (0x2 << i)) {
+ sid++;
+ }
+
+ esid = (struct ext_selfid *)(sid - 1);
+ while (esid->extended) {
+ if ((esid->porta == 0x2) || (esid->portb == 0x2)
+ || (esid->portc == 0x2) || (esid->portd == 0x2)
+ || (esid->porte == 0x2) || (esid->portf == 0x2)
+ || (esid->portg == 0x2) || (esid->porth == 0x2)) {
HPSB_INFO("SelfIDs failed root check on "
"extended SelfID");
return 0;
- }
}
- sid = *(sidp--);
+ esid--;
}
- for (i = 2; i < 8; i += 2) {
- if ((sid & (0x3 << i)) == (0x2 << i)) {
+ sid = (struct selfid *)esid;
+ if ((sid->port0 == 0x2) || (sid->port1 == 0x2) || (sid->port2 == 0x2)) {
HPSB_INFO("SelfIDs failed root check");
return 0;
- }
}
return nodeid + 1;
char speedcap[nodecount];
char cldcnt[nodecount];
u8 *map = host->speed_map;
- quadlet_t *sidp;
+ struct selfid *sid;
+ struct ext_selfid *esid;
int i, j, n;
for (i = 0; i < (nodecount * 64); i += 64) {
}
/* find direct children count and speed */
- for (sidp = &host->topology_map[host->selfid_count-1],
+ for (sid = (struct selfid *)&host->topology_map[host->selfid_count-1],
n = nodecount - 1;
- sidp >= host->topology_map; sidp--) {
- if (*sidp & 0x00800000 /* extended */) {
- for (i = 2; i < 18; i += 2) {
- if ((*sidp & (0x3 << i)) == (0x3 << i)) {
- cldcnt[n]++;
- }
- }
+ (void *)sid >= (void *)host->topology_map; sid--) {
+ if (sid->extended) {
+ esid = (struct ext_selfid *)sid;
+
+ if (esid->porta == 0x3) cldcnt[n]++;
+ if (esid->portb == 0x3) cldcnt[n]++;
+ if (esid->portc == 0x3) cldcnt[n]++;
+ if (esid->portd == 0x3) cldcnt[n]++;
+ if (esid->porte == 0x3) cldcnt[n]++;
+ if (esid->portf == 0x3) cldcnt[n]++;
+ if (esid->portg == 0x3) cldcnt[n]++;
+ if (esid->porth == 0x3) cldcnt[n]++;
} else {
- for (i = 2; i < 8; i += 2) {
- if ((*sidp & (0x3 << i)) == (0x3 << i)) {
- cldcnt[n]++;
- }
- }
- speedcap[n] = (*sidp >> 14) & 0x3;
+ if (sid->port0 == 0x3) cldcnt[n]++;
+ if (sid->port1 == 0x3) cldcnt[n]++;
+ if (sid->port2 == 0x3) cldcnt[n]++;
+
+ speedcap[n] = sid->speed;
n--;
}
}
void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
{
if (host->in_bus_reset) {
- printk("including selfid 0x%x\n", sid);
+ HPSB_DEBUG("including selfid 0x%x", sid);
host->topology_map[host->selfid_count++] = sid;
} else {
/* FIXME - info on which host */
}
/* irm_id is kept up to date by check_selfids() */
- host->is_irm = (host->irm_id == host->node_id);
+ if (host->irm_id == host->node_id) {
+ host->is_irm = 1;
+ host->is_busmgr = 1;
+ host->busmgr_id = host->node_id;
+ host->csr.bus_manager_id = host->node_id;
+ }
host->reset_retries = 0;
inc_hpsb_generation();
packet->speed_code = host->speed_map[(host->node_id & NODE_MASK) * 64
+ (packet->node_id & NODE_MASK)];
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
switch (packet->speed_code) {
case 2:
dump_packet("send packet 400:", packet->header,
dump_packet("send packet 100:", packet->header,
packet->header_size);
}
+#endif
return host->template->transmit_packet(host, packet);
}
{
struct hpsb_packet *p;
+ dsize += (dsize % 4 ? 4 - (dsize % 4) : 0);
+
p = alloc_hpsb_packet(dsize);
if (p == NULL) {
/* FIXME - send data_error response */
return NULL;
}
-
+
p->type = async;
p->state = unused;
p->host = host;
p->tlabel = (data[0] >> 10) & 0x3f;
p->no_waiter = 1;
+ if (dsize % 4) {
+ p->data[dsize / 4] = 0;
+ }
+
return p;
}
packet = create_reply_packet(host, data, length); \
if (packet == NULL) break
-inline void swap_quadlets_on_le(quadlet_t *q)
-{
-#ifdef __LITTLE_ENDIAN
- quadlet_t saved = q[0];
- q[0] = q[1];
- q[1] = saved;
-#endif
-}
-
-
void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
size_t size)
{
struct hpsb_packet *packet;
int length, rcode, extcode;
+ int source = data[1] >> 16;
u64 addr;
/* big FIXME - no error checking is done for an out of bounds length */
switch (tcode) {
case TCODE_WRITEQ:
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_write(host, data+3, addr, 4);
+ rcode = highlevel_write(host, source, data+3, addr, 4);
if (((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
/* not a broadcast write, reply */
case TCODE_WRITEB:
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_write(host, data+4, addr, data[3]>>16);
+ rcode = highlevel_write(host, source, data+4, addr,
+ data[3]>>16);
if (((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
/* not a broadcast write, reply */
PREP_REPLY_PACKET(0);
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_read(host, data, addr, 4);
+ rcode = highlevel_read(host, source, data, addr, 4);
fill_async_readquad_resp(packet, rcode, *data);
send_packet_nocare(packet);
break;
PREP_REPLY_PACKET(length);
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_read(host, packet->data, addr, length);
+ rcode = highlevel_read(host, source, packet->data, addr,
+ length);
fill_async_readblock_resp(packet, rcode, length);
send_packet_nocare(packet);
break;
switch (length) {
case 4:
- rcode = highlevel_lock(host, packet->data, addr,
+ rcode = highlevel_lock(host, source, packet->data, addr,
data[4], 0, extcode);
fill_async_lock_resp(packet, rcode, extcode, 4);
break;
case 8:
if ((extcode != EXTCODE_FETCH_ADD)
&& (extcode != EXTCODE_LITTLE_ADD)) {
- rcode = highlevel_lock(host, packet->data, addr,
+ rcode = highlevel_lock(host, source,
+ packet->data, addr,
data[5], data[4],
extcode);
fill_async_lock_resp(packet, rcode, extcode, 4);
} else {
- swap_quadlets_on_le(data + 4);
- rcode = highlevel_lock64(host,
+ rcode = highlevel_lock64(host, source,
(octlet_t *)packet->data, addr,
*(octlet_t *)(data + 4), 0ULL,
extcode);
- swap_quadlets_on_le(packet->data);
fill_async_lock_resp(packet, rcode, extcode, 8);
}
break;
case 16:
- swap_quadlets_on_le(data + 4);
- swap_quadlets_on_le(data + 6);
- rcode = highlevel_lock64(host, (octlet_t *)packet->data,
- addr, *(octlet_t *)(data + 6),
+ rcode = highlevel_lock64(host, source,
+ (octlet_t *)packet->data, addr,
+ *(octlet_t *)(data + 6),
*(octlet_t *)(data + 4),
extcode);
- swap_quadlets_on_le(packet->data);
fill_async_lock_resp(packet, rcode, extcode, 8);
break;
default:
return;
}
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
dump_packet("received packet:", data, size);
+#endif
tcode = (data[0] >> 4) & 0xf;
unsigned no_waiter:1;
/* Data big endianness flag - may vary from request to request. The
- * header is always in machine byte order. */
+ * header is always in machine byte order.
+ * Not really used currently. */
unsigned data_be:1;
/* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */
unsigned speed_code:2;
- /* --- 16 bytes (one cacheline) --- */
-
- /* *header and *data are guaranteed to be 32-bit DMAable and may be
+ /*
+ * *header and *data are guaranteed to be 32-bit DMAable and may be
* overwritten to allow in-place byte swapping. Neither of these is
* CRCed (the sizes also don't include CRC), but contain space for at
* least one additional quadlet to allow in-place CRCing. The memory is
* also guaranteed to have physical mapping (virt_to_bus() is meaningful
* on these pointers).
- * NOTE: The 32-bit DMA guarantee is currently not enforced.
- * That's a Linux 2.3 issue.
*/
quadlet_t *header;
quadlet_t *data;
size_t header_size;
size_t data_size;
- /* --- 32 bytes --- */
struct hpsb_host *host;
unsigned int generation;
* for other cases (internal errors that don't justify a panic). Safe to call
* from within a transmit packet routine.
*/
-void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, int ackcode);
+void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
+ int ackcode);
/*
* Hand over received packet to the core. The contents of data are expected to
* be the full packet but with the CRCs left out (data block follows header
- * immediately) and in machine byte order. *data can be safely overwritten
+ * immediately), with the header (i.e. the first four quadlets) in machine byte
+ * order and the data block in big endian. *data can be safely overwritten
* after this call.
*/
void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size);
PREP_ASYNC_HEAD_RCODE(TCODE_READB_RESPONSE);
packet->header[3] = length << 16;
packet->header_size = 16;
- packet->data_size = length;
+ packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
}
void fill_async_writequad(struct hpsb_packet *packet, u64 addr, quadlet_t data)
PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEB);
packet->header[3] = length << 16;
packet->header_size = 16;
- packet->data_size = length;
packet->expect_response = 1;
+ packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
}
void fill_async_write_resp(struct hpsb_packet *packet, int rcode)
quadlet_t *buffer, size_t length)
{
if (host->node_id != node) return -1;
- return highlevel_read(host, buffer, addr, length);
+ return highlevel_read(host, node, buffer, addr, length);
}
struct hpsb_packet *hpsb_make_readqpacket(struct hpsb_host *host, nodeid_t node,
{
struct hpsb_packet *p;
- p = alloc_hpsb_packet(length);
+ p = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0));
if (!p) return NULL;
p->host = host;
{
struct hpsb_packet *p;
- p = alloc_hpsb_packet(length);
+ p = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0));
if (!p) return NULL;
+ if (length % 4) {
+ p->data[length / 4] = 0;
+ }
+
p->host = host;
p->tlabel = get_tlabel(host, node, 1);
p->node_id = node;
}
if (host->node_id == node) {
- switch(highlevel_read(host, buffer, addr, length)) {
+ switch(highlevel_read(host, node, buffer, addr, length)) {
case RCODE_COMPLETE:
return 0;
case RCODE_TYPE_ERROR:
}
}
- if (length & 0x3) {
- /* FIXME: Lengths not multiple of 4 are not implemented. Mainly
- * there is the problem with little endian machines because we
- * always swap to little endian on receive. If we read 5 bytes
- * 12345 we receive them as 12345000 and swap them to 43210005.
- * How should we copy that to the caller? Require *buffer to be
- * a full quadlet multiple in length? */
- return -EACCES;
- }
-
if (length == 4) {
packet = hpsb_make_readqpacket(host, node, addr);
} else {
}
if (host->node_id == node) {
- switch(highlevel_write(host, buffer, addr, length)) {
+ switch(highlevel_write(host, node, buffer, addr, length)) {
case RCODE_COMPLETE:
return 0;
case RCODE_TYPE_ERROR:
}
}
- if (length & 0x3) {
- /* FIXME: Lengths not multiple of 4 are not implemented. See function
- * hpsb_read for explanation, same reason, different direction. */
- return -EACCES;
- }
-
if (length == 4) {
packet = hpsb_make_writeqpacket(host, node, addr, *buffer);
} else {
int retval = 0, length;
if (host->node_id == node) {
- switch(highlevel_lock(host, data, addr, *data, arg, extcode)) {
+ switch(highlevel_lock(host, node, data, addr, *data, arg,
+ extcode)) {
case RCODE_COMPLETE:
return 0;
case RCODE_TYPE_ERROR:
#include <linux/types.h>
#include <linux/version.h>
#include <linux/list.h>
+#include <asm/byteorder.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
__list_add(new, head->prev, head);
}
+#define __constant_cpu_to_be32(x) __constant_htonl((x))
+
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18)
* . Config ROM
*
* Known bugs:
- * . Self-id are not received properly if card
- * is initialized with no other nodes on the
- * bus.
+ * . Self-id are sometimes not received properly
+ * if card is initialized with no other nodes
+ * on the bus
+ */
+
+/*
+ * Acknowledgments:
+ *
+ * Emilie Chung <emilie.chung@axis.com>
+ * .Tip on Async Request Filter
+ * Pascal Drolet <pascal.drolet@informission.ca>
+ * .Various tips for optimization and functionnalities
*/
#include <linux/config.h>
#include "ieee1394_core.h"
#include "ohci1394.h"
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+#define OHCI1394_DEBUG
+#endif
+
#ifdef DBGMSG
#undef DBGMSG
#endif
-#if OHCI1394_DEBUG
+#ifdef OHCI1394_DEBUG
#define DBGMSG(card, fmt, args...) \
printk(KERN_INFO "ohci1394_%d: " fmt "\n" , card , ## args)
#else
return 1;
int supported_chips[][2] = {
- { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394 },
- { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_2 },
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV22 },
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV23 },
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_LV26 },
{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_OHCI1394 },
{ PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_SONY_CXD3222 },
+ { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72862 },
+ { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72870 },
+ { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72871 },
{ -1, -1 }
};
if (q[0] == ~q[1]) {
PRINT(KERN_INFO, ohci->id, "selfid packet 0x%x rcvd",
q[0]);
- hpsb_selfid_received(host, q[0]);
+ hpsb_selfid_received(host, cpu_to_be32(q[0]));
if (((q[0]&0x3f000000)>>24)==phyid) {
lsid=q[0];
PRINT(KERN_INFO, ohci->id,
PRINT(KERN_INFO, ohci->id, "AT dma ctx=%d initialized", d->ctx);
}
+/* Count the number of available iso contexts */
+static int get_nb_iso_ctx(struct ti_ohci *ohci)
+{
+ int i,ctx=0;
+ u32 tmp;
+
+ reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0xffffffff);
+ tmp = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
+
+ /* Count the number of contexts */
+ for(i=0; i<32; i++) {
+ if(tmp & 1) ctx++;
+ tmp >>= 1;
+ }
+ return ctx;
+}
+
/* Global initialization */
static int ohci_initialize(struct hpsb_host *host)
{
virt_to_bus(ohci->csr_config_rom));
/* Write the config ROM header */
- reg_write(ohci, OHCI1394_ConfigROMhdr, ohci->csr_config_rom[0]);
+ reg_write(ohci, OHCI1394_ConfigROMhdr,
+ cpu_to_be32(ohci->csr_config_rom[0]));
/* Set bus options */
- reg_write(ohci, OHCI1394_BusOptions, ohci->csr_config_rom[2]);
-
- /* Write the GUID into the csr config rom */
- ohci->csr_config_rom[3] = reg_read(ohci, OHCI1394_GUIDHi);
- ohci->csr_config_rom[4] = reg_read(ohci, OHCI1394_GUIDLo);
+ reg_write(ohci, OHCI1394_BusOptions,
+ cpu_to_be32(ohci->csr_config_rom[2]));
+ /* Write the GUID into the csr config rom */
+ ohci->csr_config_rom[3] = be32_to_cpu(reg_read(ohci, OHCI1394_GUIDHi));
+ ohci->csr_config_rom[4] = be32_to_cpu(reg_read(ohci, OHCI1394_GUIDLo));
+
+ ohci->max_packet_size =
+ 1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
+ PRINT(KERN_INFO, ohci->id, "max packet size = %d bytes",
+ ohci->max_packet_size);
+
/* Don't accept phy packets into AR request context */
reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
/* Initialize IR dma */
- for (i=0;i<4;i++) { /* FIXME : how many contexts are available ? */
+ ohci->nb_iso_ctx = get_nb_iso_ctx(ohci);
+ PRINT(KERN_INFO, ohci->id, "%d iso contexts available",
+ ohci->nb_iso_ctx);
+ for (i=0;i<ohci->nb_iso_ctx;i++) {
reg_write(ohci, OHCI1394_IrRcvContextControlClear+32*i,
0xffffffff);
reg_write(ohci, OHCI1394_IrRcvContextMatch+32*i, 0);
* Accept AT requests from all nodes. This probably
* will have to be controlled from the subsystem
* on a per node basis.
- * (Tip by Emilie Chung <emilie.chung@axis.com>)
*/
reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000);
unsigned char tcode;
int i=50;
- if (packet->data_size >= 4096) {
- PRINT(KERN_ERR, ohci->id, "transmit packet data too big (%d)",
+ if (packet->data_size >= ohci->max_packet_size) {
+ PRINT(KERN_ERR, ohci->id,
+ "transmit packet size = %d too big",
packet->data_size);
return 0;
}
/* Decide wether we have a request or a response packet */
tcode = (packet->header[0]>>4)&0xf;
- if ((tcode==TCODE_READQ)||
- (tcode==TCODE_WRITEQ)||
- (tcode==TCODE_READB)||
- (tcode==TCODE_WRITEB)||
- (tcode==TCODE_LOCK_REQUEST))
- d = ohci->at_req_context;
-
- else if ((tcode==TCODE_WRITE_RESPONSE)||
- (tcode==TCODE_READQ_RESPONSE)||
- (tcode==TCODE_READB_RESPONSE)||
- (tcode==TCODE_LOCK_RESPONSE))
- d = ohci->at_resp_context;
-
- else {
- PRINT(KERN_ERR, ohci->id,
- "Unexpected packet tcode=%d in AT DMA", tcode);
- return 0;
- }
+ if (tcode & 0x02) d = ohci->at_resp_context;
+ else d = ohci->at_req_context;
spin_lock(&d->lock);
switch (cmd) {
case RESET_BUS:
+ host->attempt_root=1;
PRINT(KERN_INFO, ohci->id, "resetting bus on request%s",
(host->attempt_root ? " and attempting to become root"
: ""));
break;
case ACT_CYCLE_MASTER:
-#if 0
if (arg) {
- /* enable cycleTimer, cycleMaster, cycleSource */
- reg_write(ohci, OHCI1394_LinkControlSet, 0x00700000);
+ /* check if we are root and other nodes are present */
+ u32 nodeId = reg_read(ohci, OHCI1394_NodeID);
+ if ((nodeId & (1<<30)) && (nodeId & 0x3f)) {
+ /*
+ * enable cycleTimer cycleMaster cycleSource
+ */
+ DBGMSG(ohci->id, "Cycle master enabled");
+ reg_write(ohci, OHCI1394_LinkControlSet,
+ 0x00700000);
+ }
} else {
/* disable cycleTimer, cycleMaster, cycleSource */
reg_write(ohci, OHCI1394_LinkControlClear, 0x00700000);
- };
-#endif
+ }
break;
case CANCEL_REQUESTS:
struct hpsb_host *host = ohci->host;
int phyid = -1, isroot = 0;
+ /* read the interrupt event register */
event=reg_read(ohci, OHCI1394_IntEventSet);
+#if 0
+ /*
+ * clear the interrupt event register, except for the
+ * bus reset event interrupt (if any). This is an
+ * attempt to comply with ohci spec 7.2.3.2
+ */
+ reg_write(ohci, OHCI1394_IntEventClear, event & (~OHCI1394_busReset));
+#else
+ /* The above attempt doesn't work */
+ reg_write(ohci, OHCI1394_IntEventClear, event);
+#endif
if (event & OHCI1394_busReset) {
if (!host->in_bus_reset) {
PRINT(KERN_INFO, ohci->id, "Bus reset");
dma_trm_reset(ohci->at_req_context);
dma_trm_reset(ohci->at_resp_context);
+#if 0
+ /* clear the bus reset event */
+ reg_write(ohci, OHCI1394_IntEventClear,
+ OHCI1394_busReset);
+#endif
/* Subsystem call */
hpsb_bus_reset(ohci->host);
if (event & OHCI1394_selfIDComplete) {
if (host->in_bus_reset) {
node_id = reg_read(ohci, OHCI1394_NodeID);
- if (node_id & 0x8000000) { /* NodeID valid */
+ if (node_id & 0x80000000) { /* NodeID valid */
phyid = node_id & 0x0000003f;
isroot = (node_id & 0x40000000) != 0;
#endif
}
- /* clear the interrupt event register */
- reg_write(ohci, OHCI1394_IntEventClear, event);
}
/* Put the buffer back into the dma context */
return length;
}
-static int packet_length(struct dma_rcv_ctx *d, int idx,
- quadlet_t *buf_ptr, int offset)
+const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0,
+ -1, 0, -1, 0, -1, -1, 16, -1};
+
+/*
+ * Determine the length of a packet in the buffer
+ * Optimization suggested by Pascal Drolet <pascal.drolet@informission.ca>
+ */
+static int packet_length(struct dma_rcv_ctx *d, int idx, quadlet_t *buf_ptr,
+int offset)
{
- unsigned char tcode;
- int length;
+ unsigned char tcode;
+ int length = -1;
/* Let's see what kind of packet is in there */
- tcode = (buf_ptr[0]>>4)&0xf;
-
- if (d->ctx==0) { /* Async Receive Request */
- if (tcode==TCODE_READQ) return 16;
- else if (tcode==TCODE_WRITEQ ||
- tcode==TCODE_READB) return 20;
- else if (tcode==TCODE_WRITEB ||
- tcode==TCODE_LOCK_REQUEST) {
- return block_length(d, idx, buf_ptr, offset) + 20;
- }
- else if (tcode==0xE) { /* Phy packet */
- return 16;
- }
- else return -1;
- }
- else if (d->ctx==1) { /* Async Receive Response */
- if (tcode==TCODE_WRITE_RESPONSE) return 16;
- else if (tcode==TCODE_READQ_RESPONSE) return 20;
- else if (tcode==TCODE_READB_RESPONSE ||
- tcode==TCODE_LOCK_RESPONSE) {
- return block_length(d, idx, buf_ptr, offset) + 20;
- }
- else return -1;
+ tcode = (buf_ptr[0] >> 4) & 0xf;
+
+ if (d->ctx < 2) { /* Async Receive Response/Request */
+ length = TCODE_SIZE[tcode];
+ if (length == 0)
+ length = block_length(d, idx, buf_ptr, offset) + 20;
}
else if (d->ctx==2) { /* Iso receive */
/* Assumption: buffer fill mode with header/trailer */
length = (buf_ptr[0]>>16);
if (length % 4) length += 4 - (length % 4);
- return length+8;
+ length+=8;
}
- return -1;
+ return length;
}
/* Bottom half that processes dma receive buffers */
static int add_card(struct pci_dev *dev)
{
struct ti_ohci *ohci; /* shortcut to currently handled device */
+ int i;
if (num_of_cards == MAX_OHCI1394_CARDS) {
PRINT_G(KERN_WARNING, "cannot handle more than %d cards. "
return 1;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ pci_enable_device(dev);
+#endif
+
ohci = &cards[num_of_cards++];
ohci->id = num_of_cards-1;
if (ohci->csr_config_rom == NULL) {
FAIL("failed to allocate buffer config rom");
}
- memcpy(ohci->csr_config_rom, ohci_csr_rom, sizeof(ohci_csr_rom));
+ for (i=0;i<sizeof(ohci_csr_rom)/4;i++)
+ ohci->csr_config_rom[i] = cpu_to_be32(ohci_csr_rom[i]);
+
+ DBGMSG(ohci->id, "The 1st byte at offset 0x404 is: 0x%02x",
+ *((char *)ohci->csr_config_rom+4));
/* self-id dma buffer allocation */
ohci->self_id_buffer = kmalloc(2048, GFP_KERNEL);
#include "ieee1394_types.h"
-#define OHCI1394_DEBUG 1
-
#define OHCI1394_DRIVER_NAME "ohci1394"
-#ifndef PCI_DEVICE_ID_TI_OHCI1394
-#define PCI_DEVICE_ID_TI_OHCI1394 0x8009
-#endif
+#ifndef PCI_DEVICE_ID_TI_OHCI1394_LV22
+#define PCI_DEVICE_ID_TI_OHCI1394_LV22 0x8009
+#endif
+
+#ifndef PCI_DEVICE_ID_TI_OHCI1394_LV23
+#define PCI_DEVICE_ID_TI_OHCI1394_LV23 0x8019
+#endif
-#ifndef PCI_DEVICE_ID_TI_OHCI1394_2
-#define PCI_DEVICE_ID_TI_OHCI1394_2 0x8019
+#ifndef PCI_DEVICE_ID_TI_OHCI1394_LV26
+#define PCI_DEVICE_ID_TI_OHCI1394_LV26 0x8020
#endif
#ifndef PCI_DEVICE_ID_VIA_OHCI1394
#define PCI_DEVICE_ID_SONY_CXD3222 0x8039
#endif
+#ifndef PCI_DEVICE_ID_NEC_1394
+#define PCI_DEVICE_ID_NEC_1394 0x00cd
+#endif
+
+#ifndef PCI_DEVICE_ID_NEC_UPD72862
+#define PCI_DEVICE_ID_NEC_UPD72862 0x0063
+#endif
+
+#ifndef PCI_DEVICE_ID_NEC_UPD72870
+#define PCI_DEVICE_ID_NEC_UPD72870 0x00cd
+#endif
+
+#ifndef PCI_DEVICE_ID_NEC_UPD72871
+#define PCI_DEVICE_ID_NEC_UPD72871 0x00ce
+#endif
+
#define MAX_OHCI1394_CARDS 4
#define OHCI1394_MAX_AT_REQ_RETRIES 0x2
quadlet_t *self_id_buffer; /* dma buffer for self-id packets */
quadlet_t *csr_config_rom; /* buffer for csr config rom */
+ unsigned int max_packet_size;
+
/* async receive */
struct dma_rcv_ctx *ar_resp_context;
struct dma_rcv_ctx *ar_req_context;
struct dma_rcv_ctx *ir_context;
u64 IR_channel_usage;
spinlock_t IR_channel_lock;
+ int nb_iso_ctx;
/* IEEE-1394 part follows */
struct hpsb_host *host;
/* print card specific information */
#define PRINT(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args)
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+#define PRINT_GD(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)
+#define PRINTD(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args)
+#else
+#define PRINT_GD(level, fmt, args...)
+#define PRINTD(level, card, fmt, args...)
+#endif
static struct ti_lynx cards[MAX_PCILYNX_CARDS];
static int num_of_cards = 0;
}
}
- printk("-%d- generated own selfid 0x%x\n", lynx->id, lsid);
+ cpu_to_be32s(&lsid);
+ PRINT(KERN_DEBUG, lynx->id, "generated own selfid 0x%x", lsid);
return lsid;
}
quadlet_t *q = lynx->rcv_page;
int phyid, isroot;
quadlet_t lsid = 0;
+ int i;
+ i = (size > 16 ? 16 : size) / 4 - 1;
+ while (i >= 0) {
+ cpu_to_be32s(&q[i]);
+ i--;
+ }
+
if (!lynx->phyic.reg_1394a) {
lsid = generate_own_selfid(lynx, host);
}
}
while (size > 0) {
- if (!lynx->phyic.reg_1394a
- && (q[0] & 0x3f800000) == ((phyid + 1) << 24)) {
+ struct selfid *sid = (struct selfid *)q;
+
+ if (!lynx->phyic.reg_1394a && !sid->extended
+ && (sid->phy_id == (phyid + 1))) {
hpsb_selfid_received(host, lsid);
}
if (q[0] == ~q[1]) {
- printk("-%d- selfid packet 0x%x rcvd\n", lynx->id, q[0]);
+ PRINT(KERN_DEBUG, lynx->id, "selfid packet 0x%x rcvd",
+ q[0]);
hpsb_selfid_received(host, q[0]);
} else {
- printk("-%d- inconsistent selfid 0x%x/0x%x\n", lynx->id,
- q[0], q[1]);
+ PRINT(KERN_INFO, lynx->id,
+ "inconsistent selfid 0x%x/0x%x", q[0], q[1]);
}
q += 2;
size -= 8;
pcl.next = PCL_NEXT_INVALID;
pcl.async_error_next = PCL_NEXT_INVALID;
#ifdef __BIG_ENDIAN
- pcl.buffer[0].control = PCL_CMD_RCV | 2048;
- pcl.buffer[1].control = PCL_LAST_BUFF | 2048;
+ pcl.buffer[0].control = PCL_CMD_RCV | 16;
+ pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
#else
- pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 2048;
- pcl.buffer[1].control = PCL_LAST_BUFF | PCL_BIGENDIAN | 2048;
+ pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 16;
+ pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
#endif
pcl.buffer[0].pointer = virt_to_bus(lynx->rcv_page);
- pcl.buffer[1].pointer = virt_to_bus(lynx->rcv_page) + 2048;
+ pcl.buffer[1].pointer = virt_to_bus(lynx->rcv_page) + 16;
put_pcl(lynx, lynx->rcv_pcl, &pcl);
pcl.next = pcl_bus(lynx, lynx->async_pcl);
pcl.next = PCL_NEXT_INVALID;
pcl.async_error_next = PCL_NEXT_INVALID;
- pcl.buffer[0].control = PCL_CMD_RCV | PCL_LAST_BUFF | 2048;
+ pcl.buffer[0].control = PCL_CMD_RCV | 4;
#ifndef __BIG_ENDIAN
pcl.buffer[0].control |= PCL_BIGENDIAN;
#endif
+ pcl.buffer[1].control = PCL_LAST_BUFF | 2044;
for (i = 0; i < NUM_ISORCV_PCL; i++) {
int page = i / ISORCV_PER_PAGE;
pcl.buffer[0].pointer = virt_to_bus(lynx->iso_rcv.page[page])
+ sec * MAX_ISORCV_SIZE;
+ pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4;
put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);
}
}
packet->xnext = NULL;
+ if (packet->tcode == TCODE_WRITEQ
+ || packet->tcode == TCODE_READQ_RESPONSE) {
+ cpu_to_be32s(&packet->header[3]);
+ }
spin_lock_irqsave(&lynx->async_queue_lock, flags);
}
if (linkint & LINK_INT_PHY_REG_RCVD) {
if (!host->in_bus_reset) {
- printk("-%d- phy reg received without reset\n",
- lynx->id);
+ PRINT(KERN_INFO, lynx->id,
+ "phy reg received without reset");
}
}
if (linkint & LINK_INT_ISO_STUCK) {
}
if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_RCV)) {
- PRINT(KERN_INFO, lynx->id, "iso receive");
+ PRINTD(KERN_DEBUG, lynx->id, "iso receive");
spin_lock(&lynx->iso_rcv.lock);
if ((lynx->iso_rcv.next == lynx->iso_rcv.last)
|| !lynx->iso_rcv.chan_count) {
- printk("stopped\n");
+ PRINTD(KERN_DEBUG, lynx->id, "stopped");
reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
}
spin_unlock(&lynx->async_queue_lock);
if (ack & DMA_CHAN_STAT_SPECIALACK) {
- printk("-%d- special ack %d\n", lynx->id,
- (ack >> 15) & 0xf);
- ack = ACKX_SEND_ERROR;
+ ack = (ack >> 15) & 0xf;
+ PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
+ ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
} else {
ack = (ack >> 15) & 0xf;
}
/* general receive DMA completed */
int stat = reg_read(lynx, DMA1_CHAN_STAT);
- printk("-%d- received packet size %d\n", lynx->id,
+ PRINTD(KERN_DEBUG, lynx->id, "received packet size %d",
stat & 0x1fff);
if (stat & DMA_CHAN_STAT_SELFID) {
| LINK_CONTROL_TX_ASYNC_EN
| LINK_CONTROL_RX_ASYNC_EN);
} else {
- hpsb_packet_received(host, lynx->rcv_page,
- stat & 0x1fff);
+ quadlet_t *q_data = lynx->rcv_page;
+ if ((*q_data >> 4 & 0xf) == TCODE_READQ_RESPONSE
+ || (*q_data >> 4 & 0xf) == TCODE_WRITEQ) {
+ cpu_to_be32s(q_data + 3);
+ }
+ hpsb_packet_received(host, q_data, stat & 0x1fff);
}
run_pcl(lynx, lynx->rcv_pcl_start, 1);
}
if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) {
- PRINT_G(KERN_ERR, "allocation of char major number %d failed\n",
+ PRINT_G(KERN_ERR, "allocation of char major number %d failed",
PCILYNX_MAJOR);
return -EBUSY;
}
void cleanup_module(void)
{
hpsb_unregister_lowlevel(get_lynx_template());
- PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module\n");
+ PRINT_G(KERN_INFO, "removed " PCILYNX_DRIVER_NAME " module");
}
int init_module(void)
{
if (hpsb_register_lowlevel(get_lynx_template())) {
- PRINT_G(KERN_ERR, "registering failed\n");
+ PRINT_G(KERN_ERR, "registering failed");
return -ENXIO;
} else {
return 0;
-#include <linux/config.h>
#define PCILYNX_DRIVER_NAME "pcilynx"
#define PCILYNX_MAJOR 177
#define PCL_BIGENDIAN (1<<16)
+#define _(x) (__constant_cpu_to_be32(x))
+
quadlet_t lynx_csr_rom[] = {
/* bus info block */
- 0x04040000, /* info/CRC length, CRC */
- 0x31333934, /* 1394 magic number */
- 0xf064a000, /* misc. settings */
- 0x08002850, /* vendor ID, chip ID high */
- 0x0000ffff, /* chip ID low */
+ _(0x04040000), /* info/CRC length, CRC */
+ _(0x31333934), /* 1394 magic number */
+ _(0xf064a000), /* misc. settings */
+ _(0x08002850), /* vendor ID, chip ID high */
+ _(0x0000ffff), /* chip ID low */
/* root directory */
- 0x00090000, /* CRC length, CRC */
- 0x03080028, /* vendor ID (Texas Instr.) */
- 0x81000009, /* offset to textual ID */
- 0x0c000200, /* node capabilities */
- 0x8d00000e, /* offset to unique ID */
- 0xc7000010, /* offset to module independent info */
- 0x04000000, /* module hardware version */
- 0x81000026, /* offset to textual ID */
- 0x09000000, /* node hardware version */
- 0x81000026, /* offset to textual ID */
+ _(0x00090000), /* CRC length, CRC */
+ _(0x03080028), /* vendor ID (Texas Instr.) */
+ _(0x81000009), /* offset to textual ID */
+ _(0x0c000200), /* node capabilities */
+ _(0x8d00000e), /* offset to unique ID */
+ _(0xc7000010), /* offset to module independent info */
+ _(0x04000000), /* module hardware version */
+ _(0x81000026), /* offset to textual ID */
+ _(0x09000000), /* node hardware version */
+ _(0x81000026), /* offset to textual ID */
/* module vendor ID textual */
- 0x00080000, /* CRC length, CRC */
- 0x00000000,
- 0x00000000,
- 0x54455841, /* "Texas Instruments" */
- 0x5320494e,
- 0x53545255,
- 0x4d454e54,
- 0x53000000,
+ _(0x00080000), /* CRC length, CRC */
+ _(0x00000000),
+ _(0x00000000),
+ _(0x54455841), /* "Texas Instruments" */
+ _(0x5320494e),
+ _(0x53545255),
+ _(0x4d454e54),
+ _(0x53000000),
/* node unique ID leaf */
- 0x00020000, /* CRC length, CRC */
- 0x08002850, /* vendor ID, chip ID high */
- 0x0000ffff, /* chip ID low */
+ _(0x00020000), /* CRC length, CRC */
+ _(0x08002850), /* vendor ID, chip ID high */
+ _(0x0000ffff), /* chip ID low */
/* module dependent info */
- 0x00060000, /* CRC length, CRC */
- 0xb8000006, /* offset to module textual ID */
- 0x81000004, /* ??? textual descriptor */
- 0x39010000, /* SRAM size */
- 0x3a010000, /* AUXRAM size */
- 0x3b000000, /* AUX device */
+ _(0x00060000), /* CRC length, CRC */
+ _(0xb8000006), /* offset to module textual ID */
+ _(0x81000004), /* ??? textual descriptor */
+ _(0x39010000), /* SRAM size */
+ _(0x3a010000), /* AUXRAM size */
+ _(0x3b000000), /* AUX device */
/* module textual ID */
- 0x00050000, /* CRC length, CRC */
- 0x00000000,
- 0x00000000,
- 0x54534231, /* "TSB12LV21" */
- 0x324c5632,
- 0x31000000,
+ _(0x00050000), /* CRC length, CRC */
+ _(0x00000000),
+ _(0x00000000),
+ _(0x54534231), /* "TSB12LV21" */
+ _(0x324c5632),
+ _(0x31000000),
/* part number */
- 0x00060000, /* CRC length, CRC */
- 0x00000000,
- 0x00000000,
- 0x39383036, /* "9806000-0001" */
- 0x3030342d,
- 0x30303431,
- 0x20000001,
+ _(0x00060000), /* CRC length, CRC */
+ _(0x00000000),
+ _(0x00000000),
+ _(0x39383036), /* "9806000-0001" */
+ _(0x3030342d),
+ _(0x30303431),
+ _(0x20000001),
/* module hardware version textual */
- 0x00050000, /* CRC length, CRC */
- 0x00000000,
- 0x00000000,
- 0x5453424b, /* "TSBKPCITST" */
- 0x50434954,
- 0x53540000,
+ _(0x00050000), /* CRC length, CRC */
+ _(0x00000000),
+ _(0x00000000),
+ _(0x5453424b), /* "TSBKPCITST" */
+ _(0x50434954),
+ _(0x53540000),
/* node hardware version textual */
- 0x00050000, /* CRC length, CRC */
- 0x00000000,
- 0x00000000,
- 0x54534232, /* "TSB21LV03" */
- 0x313c5630,
- 0x33000000
+ _(0x00050000), /* CRC length, CRC */
+ _(0x00000000),
+ _(0x00000000),
+ _(0x54534232), /* "TSB21LV03" */
+ _(0x313c5630),
+ _(0x33000000)
};
+
+#undef _
{
if (req->ibs) {
if (atomic_dec_and_test(&req->ibs->refcount)) {
- atomic_sub((req->data[0] >> 16) + 4, &iso_buffer_size);
+ atomic_sub(req->ibs->data_size, &iso_buffer_size);
kfree(req->ibs);
}
} else if (req->free_data) {
}
free_tlabel(packet->host, packet->node_id, packet->tlabel);
+
queue_complete_req(req);
}
LIST_HEAD(reqs);
if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {
+ HPSB_INFO("dropped iso packet");
return;
}
continue;
}
+ req = __alloc_pending_request(SLAB_ATOMIC);
+ if (!req) break;
+
if (!ibs) {
ibs = kmalloc(sizeof(struct iso_block_store)
+ length, SLAB_ATOMIC);
- if (!ibs) break;
+ if (!ibs) {
+ kfree(req);
+ break;
+ }
atomic_add(length, &iso_buffer_size);
atomic_set(&ibs->refcount, 0);
+ ibs->data_size = length;
memcpy(ibs->data, data, length);
}
- req = __alloc_pending_request(SLAB_ATOMIC);
- if (!req) {
- kfree(ibs);
- break;
- }
-
atomic_inc(&ibs->refcount);
req->file_info = fi;
}
}
+static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
+ int cts, u8 *data, unsigned int length)
+{
+ unsigned long flags;
+ struct list_head *lh;
+ struct host_info *hi;
+ struct file_info *fi;
+ struct pending_request *req;
+ struct iso_block_store *ibs = NULL;
+ LIST_HEAD(reqs);
+
+ if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {
+ HPSB_INFO("dropped fcp request");
+ return;
+ }
+
+ spin_lock_irqsave(&host_info_lock, flags);
+ hi = find_host_info(host);
+
+ if (hi != NULL) {
+ for (lh = hi->file_info_list.next; lh != &hi->file_info_list;
+ lh = lh->next) {
+ fi = list_entry(lh, struct file_info, list);
+
+ if (!fi->fcp_buffer) {
+ continue;
+ }
+
+ req = __alloc_pending_request(SLAB_ATOMIC);
+ if (!req) break;
+
+ if (!ibs) {
+ ibs = kmalloc(sizeof(struct iso_block_store)
+ + length, SLAB_ATOMIC);
+ if (!ibs) {
+ kfree(req);
+ break;
+ }
+
+ atomic_add(length, &iso_buffer_size);
+ atomic_set(&ibs->refcount, 0);
+ ibs->data_size = length;
+ memcpy(ibs->data, data, length);
+ }
+
+ atomic_inc(&ibs->refcount);
+
+ req->file_info = fi;
+ req->ibs = ibs;
+ req->data = ibs->data;
+ req->req.type = RAW1394_REQ_FCP_REQUEST;
+ req->req.generation = get_hpsb_generation();
+ req->req.misc = nodeid | (direction << 16);
+ req->req.recvb = (quadlet_t *)fi->fcp_buffer;
+ req->req.length = length;
+
+ list_add_tail(&req->list, &reqs);
+ }
+ }
+ spin_unlock_irqrestore(&host_info_lock, flags);
+
+ lh = reqs.next;
+ while (lh != &reqs) {
+ req = list_entry(lh, struct pending_request, list);
+ lh = lh->next;
+ queue_complete_req(req);
+ }
+}
+
static int dev_read(struct file *file, char *buffer, size_t count,
loff_t *offset_is_ignored)
spin_unlock(&host_info_lock);
}
+static void handle_fcp_listen(struct file_info *fi, struct pending_request *req)
+{
+ if (req->req.misc) {
+ if (fi->fcp_buffer) {
+ req->req.error = RAW1394_ERROR_ALREADY;
+ } else {
+ fi->fcp_buffer = (u8 *)req->req.recvb;
+ }
+ } else {
+ if (!fi->fcp_buffer) {
+ req->req.error = RAW1394_ERROR_ALREADY;
+ } else {
+ fi->fcp_buffer = NULL;
+ }
+ }
+
+ req->req.length = 0;
+ queue_complete_req(req);
+}
+
static int handle_local_request(struct file_info *fi,
- struct pending_request *req)
+ struct pending_request *req, int node)
{
u64 addr = req->req.address & 0xffffffffffffULL;
switch (req->req.type) {
case RAW1394_REQ_ASYNC_READ:
- req->req.error = highlevel_read(fi->host, req->data, addr,
+ req->req.error = highlevel_read(fi->host, node, req->data, addr,
req->req.length);
break;
break;
}
- req->req.error = highlevel_write(fi->host, req->data, addr,
- req->req.length);
+ req->req.error = highlevel_write(fi->host, node, req->data,
+ addr, req->req.length);
req->req.length = 0;
break;
}
if (req->req.length == 8) {
- req->req.error = highlevel_lock(fi->host, req->data,
- addr, req->data[1],
+ req->req.error = highlevel_lock(fi->host, node,
+ req->data, addr,
+ req->data[1],
req->data[0],
req->req.misc);
req->req.length = 4;
} else {
- req->req.error = highlevel_lock(fi->host, req->data,
- addr, req->data[0], 0,
+ req->req.error = highlevel_lock(fi->host, node,
+ req->data, addr,
+ req->data[0], 0,
req->req.misc);
}
break;
if (!packet) return -ENOMEM;
req->data = &packet->header[3];
- } else if ((req->req.length % 4) == 0) {
+ } else {
packet = hpsb_make_readbpacket(fi->host, node, addr,
req->req.length);
if (!packet) return -ENOMEM;
req->data = packet->data;
- } else {
- req->req.error = RAW1394_ERROR_UNTIDY_LEN;
}
break;
case RAW1394_REQ_ASYNC_WRITE:
if (req->req.length == 4) {
- packet = hpsb_make_writeqpacket(fi->host, node, addr,
- 0);
- if (!packet) return -ENOMEM;
+ quadlet_t x;
- if (copy_from_user(&packet->header[3], req->req.sendb,
- 4)) {
+ if (copy_from_user(&x, req->req.sendb, 4)) {
req->req.error = RAW1394_ERROR_MEMFAULT;
}
- } else if ((req->req.length % 4) == 0) {
+
+ packet = hpsb_make_writeqpacket(fi->host, node, addr,
+ x);
+ if (!packet) return -ENOMEM;
+ } else {
packet = hpsb_make_writebpacket(fi->host, node, addr,
req->req.length);
if (!packet) return -ENOMEM;
req->req.length)) {
req->req.error = RAW1394_ERROR_MEMFAULT;
}
- } else {
- req->req.error = RAW1394_ERROR_UNTIDY_LEN;
}
req->req.length = 0;
break;
return sizeof(struct raw1394_request);
}
+ if (req->req.type == RAW1394_REQ_FCP_LISTEN) {
+ handle_fcp_listen(fi, req);
+ return sizeof(struct raw1394_request);
+ }
+
if (req->req.length == 0) {
req->req.error = RAW1394_ERROR_INVALID_ARG;
queue_complete_req(req);
}
if (fi->host->node_id == node) {
- return handle_local_request(fi, req);
+ return handle_local_request(fi, req, node);
}
return handle_remote_request(fi, req, node);
}
static struct hpsb_highlevel_ops hl_ops = {
- add_host,
- remove_host,
- host_reset,
- iso_receive
+ add_host: add_host,
+ remove_host: remove_host,
+ host_reset: host_reset,
+ iso_receive: iso_receive,
+ fcp_request: fcp_request,
};
static struct file_operations file_ops = {
#define RAW1394_DEVICE_MAJOR 171
#define RAW1394_DEVICE_NAME "raw1394"
-#define RAW1394_KERNELAPI_VERSION 1
+#define RAW1394_KERNELAPI_VERSION 2
/* state: opened */
#define RAW1394_REQ_INITIALIZE 1
#define RAW1394_REQ_LOCK64 103
#define RAW1394_REQ_ISO_LISTEN 200
+#define RAW1394_REQ_FCP_LISTEN 201
/* kernel to user */
#define RAW1394_REQ_BUS_RESET 10000
#define RAW1394_REQ_ISO_RECEIVE 10001
+#define RAW1394_REQ_FCP_REQUEST 10002
/* error codes */
#define RAW1394_ERROR_NONE 0
struct iso_block_store {
atomic_t refcount;
+ size_t data_size;
quadlet_t data[0];
};
spinlock_t reqlists_lock;
wait_queue_head_t poll_wait_complete;
+ u8 *fcp_buffer;
+
u64 listen_channels;
quadlet_t *iso_buffer;
size_t iso_buffer_length;
unsigned char prev_state; /* Previous button state */
int delta_x; /* Current delta-x */
int delta_y; /* Current delta-y */
- int present;
int ready; /* set if there if data is available */
int active; /* set if device is open */
int vuid_mode; /* VUID_NATIVE or VUID_FIRM_EVENT */
{
if(sunmouse.active++)
return 0;
- if(!sunmouse.present)
- return -EINVAL;
sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0;
sunmouse.button_state = 0x80;
sunmouse.vuid_mode = VUID_NATIVE;
SUN_MOUSE_MINOR, "sunmouse", &sun_mouse_fops
};
-int __init sun_mouse_init(void)
+void sun_mouse_zsinit(void)
{
- if (!sunmouse.present)
- return -ENODEV;
-
printk("Sun Mouse-Systems mouse driver version 1.00\n");
sunmouse.ready = sunmouse.active = 0;
sunmouse.button_state = 0x80;
init_waitqueue_head(&sunmouse.proc_list);
sunmouse.byte = 69;
- return 0;
-}
-
-void
-sun_mouse_zsinit(void)
-{
- sunmouse.present = 1;
}
-/* $Id: sunserial.c,v 1.74 1999/12/15 22:30:23 davem Exp $
+/* $Id: sunserial.c,v 1.75 2000/03/22 02:45:36 davem Exp $
* serial.c: Serial port driver infrastructure for the Sparc.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
return err;
}
+__initcall(rs_init);
+
void __init rs_kgdb_hook(int channel)
{
rs_ops.rs_kgdb_hook(channel);
*/
#include <linux/blk.h>
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
+++ /dev/null
-***************
-*** 399,405 ****
- /* @X@0001:mpu
- */
-
-- #ifdef CONFIG_MIDI
- if((mpu_dev = isapnp_find_dev(bus,
- ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL)))
- {
---- 361,366 ----
- /* @X@0001:mpu
- */
-
- if((mpu_dev = isapnp_find_dev(bus,
- ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL)))
- {
-***************
-*** 413,583 ****
- }
- else
- printk(KERN_ERR "sb: DT0197H panic: mpu not found\n");
-- #endif
--
--
-- /* @P@:Gameport
-- */
--
-- if((jp_dev = isapnp_find_dev(bus,
-- ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL)))
-- {
-- jp_dev->prepare(jp_dev);
--
-- if((jp_dev = activate_dev("DT0197H", "gameport", jp_dev)))
-- show_base("DT0197H", "gameport", &jp_dev->resource[0]);
-- }
-- else
-- printk(KERN_ERR "sb: DT0197H panic: gameport not found\n");
--
-- /* @H@0001:OPL3
-- */
--
-- #if defined(CONFIG_SOUND_YM3812) || defined(CONFIG_SOUND_YM3812_MODULE)
-- if((wss_dev = isapnp_find_dev(bus,
-- ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL)))
-- {
-- wss_dev->prepare(wss_dev);
--
-- /* Let's disable IRQ and DMA for WSS device */
--
-- wss_dev->irq_resource[0].flags = 0;
-- wss_dev->dma_resource[0].flags = 0;
--
-- if((wss_dev = activate_dev("DT0197H", "opl3", wss_dev)))
-- show_base("DT0197H", "opl3", &wss_dev->resource[0]);
-- }
-- else
-- printk(KERN_ERR "sb: DT0197H panic: opl3 not found\n");
-- #endif
-
- printk(KERN_INFO "sb: DT0197H mail reports to Torsten Werner <twerner@intercomm.de>\n");
-
- return(sb_dev);
- }
-
-- /* Specific support for awe will be dropped when:
-- * a) The new awe_wawe driver with PnP support will be introduced in the kernel
-- * b) The joystick driver will support PnP - a little patch is available from me....hint, hint :-)
-- */
--
-- static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
- {
-- /* CTL0042:Audio SB64
-- * CTL0031:Audio SB32
-- * CTL0045:Audio SB64
- */
-
-- if( (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), NULL)) ||
-- (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), NULL)) ||
-- (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), NULL)) )
- {
- sb_dev->prepare(sb_dev);
-
-- if((sb_dev = activate_dev("AWE", "sb", sb_dev)))
- {
- hw_config->io_base = sb_dev->resource[0].start;
- hw_config->irq = sb_dev->irq_resource[0].start;
-- hw_config->dma = sb_dev->dma_resource[0].start;
-- hw_config->dma2 = sb_dev->dma_resource[1].start;
--
-- mpu_config->io_base = sb_dev->resource[1].start;
-
-- show_base("AWE", "sb", &sb_dev->resource[0]);
-- show_base("AWE", "mpu", &sb_dev->resource[1]);
-- show_base("AWE", "opl3", &sb_dev->resource[2]);
- }
-- else
-- return(NULL);
-- }
-- else
-- printk(KERN_ERR "sb: AWE panic: sb base not found\n");
--
-
-- /* CTL7002:Game SB64
-- * CTL7001:Game SB32
-- */
--
-- if( (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL)) ||
-- (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7001), NULL)) )
-- {
-- jp_dev->prepare(jp_dev);
--
-- if((jp_dev = activate_dev("AWE", "gameport", jp_dev)))
-- show_base("AWE", "gameport", &jp_dev->resource[0]);
- }
- else
-- printk(KERN_ERR "sb: AWE panic: gameport not found\n");
--
-
-- /* CTL0022:WaveTable SB64
-- * CTL0021:WaveTable SB32
-- * CTL0023:WaveTable Sb64
- */
-
-- if( nosbwave == 0 &&
-- ( ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023), NULL)) ||
-- ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL)) ||
-- ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021), NULL)) ))
- {
-- wt_dev->prepare(wt_dev);
--
-- if((wt_dev = activate_dev("AWE", "wavetable", wt_dev)))
- {
-- show_base("AWE", "wavetable", &wt_dev->resource[0]);
-- show_base("AWE", "wavetable", &wt_dev->resource[1]);
-- show_base("AWE", "wavetable", &wt_dev->resource[2]);
- }
- }
- else
-- printk(KERN_ERR "sb: AWE panic: wavetable not found\n");
-
-- printk(KERN_INFO "sb: AWE mail reports to Alessandro Zummo <azummo@ita.flashnet.it>\n");
-
- return(sb_dev);
- }
-
-- #define SBF_DEV 0x01
--
-
- static struct { unsigned short vendor, function, flags; struct pci_dev * (*initfunc)(struct pci_bus *, struct pci_dev *, struct address_info *, struct address_info *); char *name; }
-- isapnp_sb_list[] __initdata = {
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
-- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), 0, &sb_init_awe, "Sound Blaster 32" },
-- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0039), 0, &sb_init_awe, "Sound Blaster AWE 32" },
-- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), 0, &sb_init_awe, "Sound Blaster AWE 64" },
-- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00C5), 0, &sb_init_awe, "Sound Blaster AWE 64" },
-- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00E4), 0, &sb_init_awe, "Sound Blaster AWE 64" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x0968), SBF_DEV, &sb_init_ess, "ESS 1688" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV, &sb_init_ess, "ESS 1868" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV, &sb_init_ess, "ESS 1868" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV, &sb_init_ess, "ESS 1869" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV, &sb_init_ess, "ESS 1878" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV, &sb_init_ess, "ESS 1879" },
-- {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" },
-- {ISAPNP_VENDOR('R','W','B'), ISAPNP_FUNCTION(0x1688), 0, &sb_init_diamond, "Diamond DT0197H" },
- {0}
- };
-
-- static int __init sb_init_isapnp(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot)
- {
- struct pci_dev *idev = NULL;
-
- /* You missed the init func? That's bad. */
-- if(isapnp_sb_list[slot].initfunc)
- {
-- char *busname = bus->name[0] ? bus->name : isapnp_sb_list[slot].name;
-
- printk(KERN_INFO "sb: %s detected\n", busname);
-
- /* Initialize this baby. */
-
-- if((idev = isapnp_sb_list[slot].initfunc(bus, card, hw_config, mpu_config)))
- {
- /* We got it. */
-
---- 374,473 ----
- }
- else
- printk(KERN_ERR "sb: DT0197H panic: mpu not found\n");
-
- printk(KERN_INFO "sb: DT0197H mail reports to Torsten Werner <twerner@intercomm.de>\n");
-
- return(sb_dev);
- }
-
-+ static struct pci_dev *sb_init_als(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
- {
-+ /*
-+ * ALS 100
-+ * very similar to both ones above
-+ */
-+
-+ /* @@@0001:Soundblaster.
- */
-
-+ if((sb_dev = isapnp_find_dev(bus,
-+ ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL)))
- {
- sb_dev->prepare(sb_dev);
-
-+ if((sb_dev = activate_dev("ALS100", "sb", sb_dev)))
- {
- hw_config->io_base = sb_dev->resource[0].start;
- hw_config->irq = sb_dev->irq_resource[0].start;
-+ hw_config->dma = sb_dev->dma_resource[1].start;
-+ hw_config->dma2 = sb_dev->dma_resource[0].start;
-
-+ show_base("ALS100", "sb", &sb_dev->resource[0]);
- }
-
-+ if(!sb_dev) return(NULL);
- }
- else
-+ printk(KERN_ERR "sb: ALS100 panic: sb base not found\n");
-
-+ /* @X@0001:mpu
- */
-
-+ if((mpu_dev = isapnp_find_dev(bus,
-+ ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL)))
- {
-+ mpu_dev->prepare(mpu_dev);
-+
-+ if((mpu_dev = activate_dev("ALS100", "mpu", mpu_dev)))
- {
-+ show_base("ALS100", "mpu", &mpu_dev->resource[0]);
-+ mpu_config->io_base = mpu_dev->resource[0].start;
- }
- }
- else
-+ printk(KERN_ERR "sb: ALS100 panic: mpu not found\n");
-
-+ printk(KERN_INFO "sb: ALS100 mail reports to Torsten Werner <twerner@intercomm.de>\n");
-
- return(sb_dev);
- }
-
-+ #define SBF_DEV 0x01 /* Please notice that cards without this flag set are on top in the list */
-
- static struct { unsigned short vendor, function, flags; struct pci_dev * (*initfunc)(struct pci_bus *, struct pci_dev *, struct address_info *, struct address_info *); char *name; }
-+ sb_isapnp_list[] __initdata = {
-+ {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" },
-+ {ISAPNP_VENDOR('R','W','B'), ISAPNP_FUNCTION(0x1688), 0, &sb_init_diamond, "Diamond DT0197H" },
-+ {ISAPNP_VENDOR('A','L','S'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_als, "ALS 100" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x0968), SBF_DEV, &sb_init_ess, "ESS 1688" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV, &sb_init_ess, "ESS 1868" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV, &sb_init_ess, "ESS 1868" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV, &sb_init_ess, "ESS 1869" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV, &sb_init_ess, "ESS 1878" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV, &sb_init_ess, "ESS 1879" },
- {0}
- };
-
-+ static int __init sb_isapnp_init(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot)
- {
- struct pci_dev *idev = NULL;
-
- /* You missed the init func? That's bad. */
-+ if(sb_isapnp_list[slot].initfunc)
- {
-+ char *busname = bus->name[0] ? bus->name : sb_isapnp_list[slot].name;
-
- printk(KERN_INFO "sb: %s detected\n", busname);
-
- /* Initialize this baby. */
-
-+ if((idev = sb_isapnp_list[slot].initfunc(bus, card, hw_config, mpu_config)))
- {
- /* We got it. */
-
-/* $Id: cgthreefb.c,v 1.8 1999/11/19 09:57:08 davem Exp $
+/* $Id: cgthreefb.c,v 1.9 2000/03/19 04:20:44 anton Exp $
* cgthreefb.c: CGthree frame buffer driver
*
* Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
u8 tmp;
spin_lock_irqsave(&fb->lock, flags);
- tmp = sbus_readl(&fb->s.cg3.regs->control);
+ tmp = sbus_readb(&fb->s.cg3.regs->control);
tmp &= ~CG3_CR_ENABLE_VIDEO;
- sbus_writel(tmp, &fb->s.cg3.regs->control);
+ sbus_writeb(tmp, &fb->s.cg3.regs->control);
spin_unlock_irqrestore(&fb->lock, flags);
}
u8 tmp;
spin_lock_irqsave(&fb->lock, flags);
- tmp = sbus_readl(&fb->s.cg3.regs->control);
+ tmp = sbus_readb(&fb->s.cg3.regs->control);
tmp |= CG3_CR_ENABLE_VIDEO;
- sbus_writel(tmp, &fb->s.cg3.regs->control);
+ sbus_writeb(tmp, &fb->s.cg3.regs->control);
spin_unlock_irqrestore(&fb->lock, flags);
}
* Copyright (C) 1999, 2000, Trond Myklebust <trond.myklebust@fys.uio.no>
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/malloc.h>
#include <linux/pagemap.h>
* Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de>
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/malloc.h>
#include <linux/swap.h>
/* Reading only -- no need for aquiring the semaphore. */
mask = POLLIN | POLLRDNORM;
- if (PIPE_FREE(*inode) >= PIPE_BUF)
+ if (PIPE_EMPTY(*inode))
mask = POLLOUT | POLLWRNORM;
if (!PIPE_WRITERS(*inode) && filp->f_version != PIPE_WCOUNTER(*inode))
mask |= POLLHUP;
#define ASIZ_task_cap_inheritable 0x00000004
#define AOFF_task_cap_permitted 0x000001c8
#define ASIZ_task_cap_permitted 0x00000004
-#define AOFF_task_user 0x000001cc
+#define AOFF_task_user 0x000001d0
#define ASIZ_task_user 0x00000004
-#define AOFF_task_rlim 0x000001d0
+#define AOFF_task_rlim 0x000001d4
#define ASIZ_task_rlim 0x00000050
-#define AOFF_task_used_math 0x00000220
+#define AOFF_task_used_math 0x00000224
#define ASIZ_task_used_math 0x00000002
-#define AOFF_task_comm 0x00000222
+#define AOFF_task_comm 0x00000226
#define ASIZ_task_comm 0x00000010
-#define AOFF_task_link_count 0x00000234
+#define AOFF_task_link_count 0x00000238
#define ASIZ_task_link_count 0x00000004
-#define AOFF_task_tty 0x00000238
+#define AOFF_task_tty 0x0000023c
#define ASIZ_task_tty 0x00000004
-#define AOFF_task_semundo 0x0000023c
+#define AOFF_task_semundo 0x00000240
#define ASIZ_task_semundo 0x00000004
-#define AOFF_task_semsleeping 0x00000240
+#define AOFF_task_semsleeping 0x00000244
#define ASIZ_task_semsleeping 0x00000004
#define AOFF_task_thread 0x00000248
#define ASIZ_task_thread 0x00000380
#define ASIZ_task_cap_inheritable 0x00000004
#define AOFF_task_cap_permitted 0x000002c4
#define ASIZ_task_cap_permitted 0x00000004
-#define AOFF_task_user 0x000002c8
+#define AOFF_task_user 0x000002cc
#define ASIZ_task_user 0x00000004
-#define AOFF_task_rlim 0x000002cc
+#define AOFF_task_rlim 0x000002d0
#define ASIZ_task_rlim 0x00000050
-#define AOFF_task_used_math 0x0000031c
+#define AOFF_task_used_math 0x00000320
#define ASIZ_task_used_math 0x00000002
-#define AOFF_task_comm 0x0000031e
+#define AOFF_task_comm 0x00000322
#define ASIZ_task_comm 0x00000010
-#define AOFF_task_link_count 0x00000330
+#define AOFF_task_link_count 0x00000334
#define ASIZ_task_link_count 0x00000004
-#define AOFF_task_tty 0x00000334
+#define AOFF_task_tty 0x00000338
#define ASIZ_task_tty 0x00000004
-#define AOFF_task_semundo 0x00000338
+#define AOFF_task_semundo 0x0000033c
#define ASIZ_task_semundo 0x00000004
-#define AOFF_task_semsleeping 0x0000033c
+#define AOFF_task_semsleeping 0x00000340
#define ASIZ_task_semsleeping 0x00000004
-#define AOFF_task_thread 0x00000340
+#define AOFF_task_thread 0x00000348
#define ASIZ_task_thread 0x00000380
-#define AOFF_task_fs 0x000006c0
+#define AOFF_task_fs 0x000006c8
#define ASIZ_task_fs 0x00000004
-#define AOFF_task_files 0x000006c4
+#define AOFF_task_files 0x000006cc
#define ASIZ_task_files 0x00000004
-#define AOFF_task_sigmask_lock 0x000006c8
+#define AOFF_task_sigmask_lock 0x000006d0
#define ASIZ_task_sigmask_lock 0x00000008
-#define AOFF_task_sig 0x000006d0
+#define AOFF_task_sig 0x000006d8
#define ASIZ_task_sig 0x00000004
-#define AOFF_task_signal 0x000006d4
+#define AOFF_task_signal 0x000006dc
#define ASIZ_task_signal 0x00000008
-#define AOFF_task_blocked 0x000006dc
+#define AOFF_task_blocked 0x000006e4
#define ASIZ_task_blocked 0x00000008
-#define AOFF_task_sigqueue 0x000006e4
+#define AOFF_task_sigqueue 0x000006ec
#define ASIZ_task_sigqueue 0x00000004
-#define AOFF_task_sigqueue_tail 0x000006e8
+#define AOFF_task_sigqueue_tail 0x000006f0
#define ASIZ_task_sigqueue_tail 0x00000004
-#define AOFF_task_sas_ss_sp 0x000006ec
+#define AOFF_task_sas_ss_sp 0x000006f4
#define ASIZ_task_sas_ss_sp 0x00000004
-#define AOFF_task_sas_ss_size 0x000006f0
+#define AOFF_task_sas_ss_size 0x000006f8
#define ASIZ_task_sas_ss_size 0x00000004
-#define AOFF_task_parent_exec_id 0x000006f4
+#define AOFF_task_parent_exec_id 0x000006fc
#define ASIZ_task_parent_exec_id 0x00000004
-#define AOFF_task_self_exec_id 0x000006f8
+#define AOFF_task_self_exec_id 0x00000700
#define ASIZ_task_self_exec_id 0x00000004
-#define AOFF_task_exit_sem 0x000006fc
+#define AOFF_task_exit_sem 0x00000704
#define ASIZ_task_exit_sem 0x00000024
#define AOFF_mm_mmap 0x00000000
#define ASIZ_mm_mmap 0x00000004
-/* $Id: pgtable.h,v 1.92 2000/03/02 20:37:37 davem Exp $ */
+/* $Id: pgtable.h,v 1.93 2000/03/21 01:04:53 anton Exp $ */
#ifndef _SPARC_PGTABLE_H
#define _SPARC_PGTABLE_H
#define VMALLOC_START (0xfe300000)
#define VMALLOC_END ~0x0UL
-#define pte_ERROR(e) __builtin_trap()
-#define pmd_ERROR(e) __builtin_trap()
-#define pgd_ERROR(e) __builtin_trap()
+#define pte_ERROR(e) \
+ printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pmd_ERROR(e) \
+ printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
BTFIXUPDEF_INT(page_none)
BTFIXUPDEF_INT(page_shared)
-/* $Id: page.h,v 1.32 2000/03/15 07:19:28 davem Exp $ */
+/* $Id: page.h,v 1.33 2000/03/22 02:48:04 davem Exp $ */
#ifndef _SPARC64_PAGE_H
#define _SPARC64_PAGE_H
#ifndef __ASSEMBLY__
/* Do prdele, look what happens to be in %g4... */
-register unsigned long page_offset asm("g4");
-#define PAGE_OFFSET page_offset
+register unsigned long PAGE_OFFSET asm("g4");
#else
#define PAGE_OFFSET 0xFFFFF80000000000
#endif
#include <asm/types.h>
#include <linux/atmioc.h>
+#include <linux/atmdev.h>
/*
* Structure for IDT77105_GETSTAT and IDT77105_GETSTATZ ioctls.
__u32 rx_hec_errors; /* Header Error Check errors on receive */
};
-#define IDT77105_GETLOOP _IOW('a',ATMIOC_PHYPRV,struct atmif_sioc) /* get loopback mode */
-#define IDT77105_SETLOOP _IOW('a',ATMIOC_PHYPRV+1,struct atmif_sioc) /* set loopback mode */
#define IDT77105_GETSTAT _IOW('a',ATMIOC_PHYPRV+2,struct atmif_sioc) /* get stats */
#define IDT77105_GETSTATZ _IOW('a',ATMIOC_PHYPRV+3,struct atmif_sioc) /* get stats and zero */
-
-/*
- * TODO: what we need is a global loopback mode get/set ioctl for
- * all devices, not these device-specific hacks -- Greg Banks
- */
-#define IDT77105_LM_NONE 0 /* no loopback */
-#define IDT77105_LM_DIAG 1 /* diagnostic (i.e. loop TX to RX)
- * (a.k.a. local loopback) */
-#define IDT77105_LM_LOOP 2 /* line (i.e. loop RX to TX)
- * (a.k.a. remote loopback) */
-
#endif
/* atm_suni.h - Driver-specific declarations of the SUNI driver (for use by
driver-specific utilities) */
-/* Written 1998 by Werner Almesberger, EPFL ICA */
+/* Written 1998,2000 by Werner Almesberger, EPFL ICA */
#ifndef LINUX_ATM_SUNI_H
#define LINUX_ATM_SUNI_H
-#include <linux/atmioc.h>
-
-#define SUNI_GETLOOP _IOR('a',ATMIOC_PHYPRV,int) /* get loopback mode */
-#define SUNI_SETLOOP _IO('a',ATMIOC_PHYPRV+1) /* set loopback mode */
-
-#define SUNI_LM_NONE 0 /* no loopback */
-#define SUNI_LM_DIAG 1 /* diagnostic (i.e. loop TX to RX) */
-#define SUNI_LM_LOOP 2 /* line (i.e. loop RX to TX) */
+/* everything obsoleted */
#endif
/* atmdev.h - ATM device driver declarations and various related items */
-/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef LINUX_ATMDEV_H
SONET overhead: /270*260 (9 section, 1 path)
bits per cell: /8/53
max cell rate: 353207.547 cells/sec */
+#define ATM_25_PCR ((25600000/8-8000)/54)
+ /* 25 Mbps ATM cell rate (59111) */
#define ATM_PDU_OVHD 0 /* number of bytes to charge against buffer
quota per PDU */
#define ATM_SD(s) ((s)->sk->protinfo.af_atm)
+#define __AAL_STAT_ITEMS \
+ __HANDLE_ITEM(tx); /* TX okay */ \
+ __HANDLE_ITEM(tx_err); /* TX errors */ \
+ __HANDLE_ITEM(rx); /* RX okay */ \
+ __HANDLE_ITEM(rx_err); /* RX errors */ \
+ __HANDLE_ITEM(rx_drop); /* RX out of memory */
+
struct atm_aal_stats {
- int tx,tx_err; /* TX okay and errors */
- int rx,rx_err; /* RX okay and errors */
- int rx_drop; /* RX out of memory */
+#define __HANDLE_ITEM(i) int i
+ __AAL_STAT_ITEMS
+#undef __HANDLE_ITEM
};
/* get AAL layer statistics */
#define ATM_GETSTATZ _IOW('a',ATMIOC_SARCOM+1,struct atmif_sioc)
/* get AAL layer statistics and zero */
+#define ATM_GETLOOP _IOW('a',ATMIOC_SARCOM+2,struct atmif_sioc)
+ /* get loopback mode */
+#define ATM_SETLOOP _IOW('a',ATMIOC_SARCOM+3,struct atmif_sioc)
+ /* set loopback mode */
+#define ATM_QUERYLOOP _IOW('a',ATMIOC_SARCOM+4,struct atmif_sioc)
+ /* query supported loopback modes */
#define ATM_SETSC _IOW('a',ATMIOC_SPECIAL+1,int)
/* enable or disable single-copy */
/* for ATM_GETTYPE */
#define ATM_ITFTYP_LEN 8 /* maximum length of interface type name */
+/*
+ * Loopback modes for ATM_{PHY,SAR}_{GET,SET}LOOP
+ */
+
+/* Point of loopback CPU-->SAR-->PHY-->line--> ... */
+#define __ATM_LM_NONE 0 /* no loop back ^ ^ ^ ^ */
+#define __ATM_LM_AAL 1 /* loop back PDUs --' | | | */
+#define __ATM_LM_ATM 2 /* loop back ATM cells ---' | | */
+/* RESERVED 4 loop back on PHY side ---' */
+#define __ATM_LM_PHY 8 /* loop back bits (digital) ----' | */
+#define __ATM_LM_ANALOG 16 /* loop back the analog signal --------' */
+
+/* Direction of loopback */
+#define __ATM_LM_MKLOC(n) ((n)) /* Local (i.e. loop TX to RX) */
+#define __ATM_LM_MKRMT(n) ((n) << 8) /* Remote (i.e. loop RX to TX) */
+
+#define __ATM_LM_XTLOC(n) ((n) & 0xff)
+#define __ATM_LM_XTRMT(n) (((n) >> 8) & 0xff)
+
+#define ATM_LM_NONE 0 /* no loopback */
+
+#define ATM_LM_LOC_AAL __ATM_LM_MKLOC(__ATM_LM_AAL)
+#define ATM_LM_LOC_ATM __ATM_LM_MKLOC(__ATM_LM_ATM)
+#define ATM_LM_LOC_PHY __ATM_LM_MKLOC(__ATM_LM_PHY)
+#define ATM_LM_LOC_ANALOG __ATM_LM_MKLOC(__ATM_LM_ANALOG)
+
+#define ATM_LM_RMT_AAL __ATM_LM_MKRMT(__ATM_LM_AAL)
+#define ATM_LM_RMT_ATM __ATM_LM_MKRMT(__ATM_LM_ATM)
+#define ATM_LM_RMT_PHY __ATM_LM_MKRMT(__ATM_LM_PHY)
+#define ATM_LM_RMT_ANALOG __ATM_LM_MKRMT(__ATM_LM_ANALOG)
+
+/*
+ * Note: ATM_LM_LOC_* and ATM_LM_RMT_* can be combined, provided that
+ * __ATM_LM_XTLOC(x) <= __ATM_LM_XTRMT(x)
+ */
struct atm_iobuf {
"SESSION", "HASSAP", "BOUND", "CLOSE"
-#ifdef __KERNEL__
+#ifndef __KERNEL__
+#undef __AAL_STAT_ITEMS
+#else
#include <linux/sched.h> /* wait_queue_head_t */
#include <linux/time.h> /* struct timeval */
#endif
-#define ATM_VF_ADDR 1 /* Address is in use. Set by anybody, cleared
+struct k_atm_aal_stats {
+#define __HANDLE_ITEM(i) atomic_t i
+ __AAL_STAT_ITEMS
+#undef __HANDLE_ITEM
+};
+
+
+struct k_atm_dev_stats {
+ struct k_atm_aal_stats aal0;
+ struct k_atm_aal_stats aal34;
+ struct k_atm_aal_stats aal5;
+};
+
+
+enum {
+ ATM_VF_ADDR, /* Address is in use. Set by anybody, cleared
by device driver. */
-#define ATM_VF_READY 2 /* VC is ready to transfer data. Set by device
+ ATM_VF_READY, /* VC is ready to transfer data. Set by device
driver, cleared by anybody. */
-#define ATM_VF_PARTIAL 4 /* resources are bound to PVC (partial PVC
+ ATM_VF_PARTIAL, /* resources are bound to PVC (partial PVC
setup), controlled by socket layer */
-#define ATM_VF_BOUND 16384 /* local SAP is set, controlled by SVC socket
- layer */
-#define ATM_VF_REGIS 8 /* registered with demon, controlled by SVC
+ ATM_VF_REGIS, /* registered with demon, controlled by SVC
socket layer */
-#define ATM_VF_RELEASED 16 /* demon has indicated/requested release,
+ ATM_VF_BOUND, /* local SAP is set, controlled by SVC socket
+ layer */
+ ATM_VF_RELEASED, /* demon has indicated/requested release,
controlled by SVC socket layer */
-#define ATM_VF_HASQOS 32 /* QOS parameters have been set */
-#define ATM_VF_LISTEN 64 /* socket is used for listening */
-#define ATM_VF_META 128 /* SVC socket isn't used for normal data
+ ATM_VF_HASQOS, /* QOS parameters have been set */
+ ATM_VF_LISTEN, /* socket is used for listening */
+ ATM_VF_META, /* SVC socket isn't used for normal data
traffic and doesn't depend on signaling
to be available */
- /* 256; unused */
- /* 512; unused */
- /* 1024; unused */
- /* 2048; unused */
-#define ATM_VF_SESSION 4096 /* VCC is p2mp session control descriptor */
-#define ATM_VF_HASSAP 8192 /* SAP has been set */
-#define ATM_VF_CLOSE 32768 /* asynchronous close - treat like VF_RELEASED*/
+ ATM_VF_SESSION, /* VCC is p2mp session control descriptor */
+ ATM_VF_HASSAP, /* SAP has been set */
+ ATM_VF_CLOSE, /* asynchronous close - treat like VF_RELEASED*/
+};
+
#define ATM_VF2VS(flags) \
- ((flags) & ATM_VF_READY ? ATM_VS_CONNECTED : \
- (flags) & ATM_VF_RELEASED ? ATM_VS_CLOSING : \
- (flags) & ATM_VF_LISTEN ? ATM_VS_LISTEN : \
- (flags) & ATM_VF_REGIS ? ATM_VS_INUSE : \
- (flags) & ATM_VF_BOUND ? ATM_VS_BOUND : ATM_VS_IDLE)
+ (test_bit(ATM_VF_READY,&(flags)) ? ATM_VS_CONNECTED : \
+ test_bit(ATM_VF_RELEASED,&(flags)) ? ATM_VS_CLOSING : \
+ test_bit(ATM_VF_LISTEN,&(flags)) ? ATM_VS_LISTEN : \
+ test_bit(ATM_VF_REGIS,&(flags)) ? ATM_VS_INUSE : \
+ test_bit(ATM_VF_BOUND,&(flags)) ? ATM_VS_BOUND : ATM_VS_IDLE)
+
+
+enum {
+ ATM_DF_CLOSE, /* close device when last VCC is closed */
+};
-#define ATM_DF_CLOSE 1 /* close device when last VCC is closed */
#define ATM_PHY_SIG_LOST 0 /* no carrier/light */
#define ATM_PHY_SIG_UNKNOWN 1 /* carrier/light status is unknown */
#define ATM_ATMOPT_CLP 1 /* set CLP bit */
+typedef struct { unsigned short bits; } atm_vcc_flags_t;
+
+
struct atm_vcc {
- unsigned short flags; /* VCC flags (ATM_VF_*) */
+ atm_vcc_flags_t flags; /* VCC flags (ATM_VF_*) */
unsigned char family; /* address family; 0 if unused */
short vpi; /* VPI and VCI (types must be equal */
/* with sockaddr) */
/* modified by protocol or by driver.*/
/* NOTE: this interface will change */
int (*push_oam)(struct atm_vcc *vcc,void *cell);
+ int (*send)(struct atm_vcc *vcc,struct sk_buff *skb);
void *dev_data; /* per-device data */
void *proto_data; /* per-protocol data */
struct timeval timestamp; /* AAL timestamps */
struct sk_buff_head recvq; /* receive queue */
- struct atm_aal_stats *stats; /* pointer to AAL stats group */
+ struct k_atm_aal_stats *stats; /* pointer to AAL stats group */
wait_queue_head_t sleep; /* if socket is busy */
wait_queue_head_t wsleep; /* if waiting for write buffer space */
struct sock *sk; /* socket backpointer */
};
+typedef struct { unsigned int bits; } atm_dev_flags_t;
+
+
struct atm_dev {
const struct atmdev_ops *ops; /* device operations; NULL if unused */
const struct atmphy_ops *phy; /* PHY operations, may be undefined */
struct atm_vcc *last; /* last VCC (or undefined) */
void *dev_data; /* per-device data */
void *phy_data; /* private PHY date */
- unsigned long flags; /* device flags (ATM_DF_*) */
+ atm_dev_flags_t flags; /* device flags (ATM_DF_*) */
struct atm_dev_addr *local; /* local ATM addresses */
unsigned char esi[ESI_LEN]; /* ESI ("MAC" addr) */
struct atm_cirange ci_range; /* VPI/VCI range */
- struct atm_dev_stats stats; /* statistics */
+ struct k_atm_dev_stats stats; /* statistics */
char signal; /* signal status (ATM_PHY_SIG_*) */
int link_rate; /* link rate (default: OC3) */
#ifdef CONFIG_PROC_FS
int (*start)(struct atm_dev *dev);
int (*ioctl)(struct atm_dev *dev,unsigned int cmd,void *arg);
void (*interrupt)(struct atm_dev *dev);
+ int (*stop)(struct atm_dev *dev);
};
struct atm_skb_data {
#define ATM_SKB(skb) (((struct atm_skb_data *) (skb)->cb))
struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
- int number,unsigned long flags); /* number == -1: pick first available */
+ int number,atm_dev_flags_t *flags); /* number == -1: pick first available */
struct atm_dev *atm_find_dev(int number);
void atm_dev_deregister(struct atm_dev *dev);
void shutdown_atm_dev(struct atm_dev *dev);
#define NET_XMIT_DROP 1 /* skb dropped */
#define NET_XMIT_CN 2 /* congestion notification */
#define NET_XMIT_POLICED 3 /* skb is shot by police */
+#define NET_XMIT_BYPASS 4 /* packet does not leave via dequeue;
+ (TC use only - dev_queue_xmit
+ returns this as NET_XMIT_SUCCESS) */
#define net_xmit_errno(e) ((e) != NET_XMIT_CN ? -ENOBUFS : 0)
#ifndef _LINUX_NFS_FS_H
#define _LINUX_NFS_FS_H
+#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/pagemap.h>
/* sonet.h - SONET/SHD physical layer control */
-/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef LINUX_SONET_H
#define LINUX_SONET_H
+#define __SONET_ITEMS \
+ __HANDLE_ITEM(section_bip); /* section parity errors (B1) */ \
+ __HANDLE_ITEM(line_bip); /* line parity errors (B2) */ \
+ __HANDLE_ITEM(path_bip); /* path parity errors (B3) */ \
+ __HANDLE_ITEM(line_febe); /* line parity errors at remote */ \
+ __HANDLE_ITEM(path_febe); /* path parity errors at remote */ \
+ __HANDLE_ITEM(corr_hcs); /* correctable header errors */ \
+ __HANDLE_ITEM(uncorr_hcs); /* uncorrectable header errors */ \
+ __HANDLE_ITEM(tx_cells); /* cells sent */ \
+ __HANDLE_ITEM(rx_cells); /* cells received */
+
struct sonet_stats {
- int section_bip; /* section parity errors (B1) */
- int line_bip; /* line parity errors (B2) */
- int path_bip; /* path parity errors (B3) */
- int line_febe; /* line parity errors at remote */
- int path_febe; /* path parity errors at remote */
- int corr_hcs; /* correctable header errors */
- int uncorr_hcs; /* uncorrectable header errors */
- int tx_cells; /* cells sent */
- int rx_cells; /* cells received */
+#define __HANDLE_ITEM(i) int i
+ __SONET_ITEMS
+#undef __HANDLE_ITEM
} __attribute__ ((packed));
+
#define SONET_GETSTAT _IOR('a',ATMIOC_PHYTYP,struct sonet_stats)
/* get statistics */
#define SONET_GETSTATZ _IOR('a',ATMIOC_PHYTYP+1,struct sonet_stats)
#define SONET_FRSENSE_SIZE 6 /* C1[3],H1[3] (0xff for unknown) */
+
+#ifndef __KERNEL__
+#undef __SONET_ITEMS
+#else
+
+#include <asm/atomic.h>
+
+struct k_sonet_stats {
+#define __HANDLE_ITEM(i) atomic_t i
+ __SONET_ITEMS
+#undef __HANDLE_ITEM
+};
+
+extern void sonet_copy_stats(struct k_sonet_stats *from,struct sonet_stats *to);
+extern void sonet_subtract_stats(struct k_sonet_stats *from,
+ struct sonet_stats *to);
+
+#endif
+
#endif
#ifdef CONFIG_BSD_PROCESS_ACCT
acct_process(code);
#endif
+ task_lock(tsk);
sem_exit();
__exit_mm(tsk);
__exit_files(tsk);
__exit_fs(tsk);
__exit_sighand(tsk);
- task_lock(tsk);
exit_thread();
tsk->state = TASK_ZOMBIE;
tsk->exit_code = code;
O_OBJS = addr.o pvc.o signaling.o svc.o
OX_OBJS = common.o atm_misc.o raw.o resources.o
-ifeq ($(CONFIG_MMU_HACKS),y)
-O_OBJS += mmuio.o
-endif
-
ifeq ($(CONFIG_ATM_CLIP),y)
O_OBJS += clip.o
NEED_IPCOM = ipcommon.o
endif
ifeq ($(CONFIG_ATM_LANE),y)
-O_OBJS += lec.o lane_mpoa_init.o
+O_OBJS += lec.o
+OX_OBJS += lane_mpoa_init.o
else
ifeq ($(CONFIG_ATM_LANE),m)
- O_OBJS += lane_mpoa_init.o
+ OX_OBJS += lane_mpoa_init.o
M_OBJS += lec.o
endif
endif
/* net/atm/addr.c - Local ATM address registry */
-/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#include <linux/atm.h>
#include <linux/atmdev.h>
-#include <linux/wait.h>
+#include <linux/sched.h>
#include <asm/uaccess.h>
#include "signaling.h"
* (which may involve page faults and therefore rescheduling)
*/
-
-static volatile int local_lock = 0;
-static wait_queue_head_t local_wait;
-
-
-static void lock_local(void)
-{
- while (local_lock) sleep_on(&local_wait);
- local_lock = 1;
-}
-
-
-static void unlock_local(void)
-{
- local_lock = 0;
- wake_up(&local_wait);
-}
+static DECLARE_MUTEX(local_lock);
static void notify_sigd(struct atm_dev *dev)
{
struct atm_dev_addr *this;
- lock_local();
+ down(&local_lock);
while (dev->local) {
this = dev->local;
dev->local = this->next;
kfree(this);
}
- unlock_local();
+ up(&local_lock);
notify_sigd(dev);
}
error = check_addr(addr);
if (error) return error;
- lock_local();
+ down(&local_lock);
for (walk = &dev->local; *walk; walk = &(*walk)->next)
if (identical(&(*walk)->addr,addr)) {
- unlock_local();
+ up(&local_lock);
return -EEXIST;
}
*walk = kmalloc(sizeof(struct atm_dev_addr),GFP_KERNEL);
if (!*walk) {
- unlock_local();
+ up(&local_lock);
return -ENOMEM;
}
(*walk)->addr = *addr;
(*walk)->next = NULL;
- unlock_local();
+ up(&local_lock);
notify_sigd(dev);
return 0;
}
error = check_addr(addr);
if (error) return error;
- lock_local();
+ down(&local_lock);
for (walk = &dev->local; *walk; walk = &(*walk)->next)
if (identical(&(*walk)->addr,addr)) break;
if (!*walk) {
- unlock_local();
+ up(&local_lock);
return -ENOENT;
}
this = *walk;
*walk = this->next;
kfree(this);
- unlock_local();
+ up(&local_lock);
notify_sigd(dev);
return 0;
}
struct atm_dev_addr *walk;
int total;
- lock_local();
+ down(&local_lock);
total = 0;
for (walk = dev->local; walk; walk = walk->next) {
total += sizeof(struct sockaddr_atmsvc);
if (total > size) {
- unlock_local();
+ up(&local_lock);
return -E2BIG;
}
if (copy_to_user(u_buf,&walk->addr,
sizeof(struct sockaddr_atmsvc))) {
- unlock_local();
+ up(&local_lock);
return -EFAULT;
}
u_buf++;
}
- unlock_local();
+ up(&local_lock);
return total;
}
-
-
-void init_addr(void)
-{
- init_waitqueue_head(&local_wait);
-}
/* net/atm/addr.h - Local ATM address registry */
-/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef NET_ATM_ADDR_H
int add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr);
int del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr);
int get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size);
-void init_addr(void);
#endif
/* net/atm/atm_misc.c - Various functions for use by ATM drivers */
-/* Written 1995-1999 by Werner Almesberger, EPFL ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL ICA */
#include <linux/module.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <linux/skbuff.h>
+#include <linux/sonet.h>
+#include <linux/bitops.h>
#include <asm/atomic.h>
#include <asm/errno.h>
atm_force_charge(vcc,truesize);
if (atomic_read(&vcc->rx_inuse) <= vcc->sk->rcvbuf) return 1;
atm_return(vcc,truesize);
- vcc->stats->rx_drop++;
+ atomic_inc(&vcc->stats->rx_drop);
return 0;
}
}
}
atm_return(vcc,guess);
- vcc->stats->rx_drop++;
+ atomic_inc(&vcc->stats->rx_drop);
return NULL;
}
struct atm_vcc *walk;
for (walk = vcc->dev->vccs; walk; walk = walk->next)
- if ((walk->flags & ATM_VF_ADDR) && walk->vpi == vpi &&
+ if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vpi == vpi &&
walk->vci == vci && ((walk->qos.txtp.traffic_class !=
ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) ||
(walk->qos.rxtp.traffic_class != ATM_NONE &&
}
+void sonet_copy_stats(struct k_sonet_stats *from,struct sonet_stats *to)
+{
+#define __HANDLE_ITEM(i) to->i = atomic_read(&from->i)
+ __SONET_ITEMS
+#undef __HANDLE_ITEM
+}
+
+
+void sonet_subtract_stats(struct k_sonet_stats *from,struct sonet_stats *to)
+{
+#define __HANDLE_ITEM(i) atomic_sub(to->i,&from->i)
+ __SONET_ITEMS
+#undef __HANDLE_ITEM
+}
+
+
EXPORT_SYMBOL(atm_charge);
EXPORT_SYMBOL(atm_alloc_charge);
EXPORT_SYMBOL(atm_find_ci);
EXPORT_SYMBOL(atm_pcr_goal);
+EXPORT_SYMBOL(sonet_copy_stats);
+EXPORT_SYMBOL(sonet_subtract_stats);
#include <linux/in.h> /* for struct sockaddr_in */
#include <linux/if.h> /* for IFF_UP */
#include <linux/inetdevice.h>
+#include <linux/bitops.h>
#include <net/route.h> /* for struct rtable and routing */
#include <net/icmp.h> /* icmp_send */
#include <asm/param.h> /* for HZ */
atm_return(vcc,skb->truesize);
skb->dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : clip_devs;
/* clip_vcc->entry == NULL if we don't have an IP address yet */
+ skb->rx_dev = NULL;
if (!skb->dev) {
kfree_skb(skb);
return;
}
clip_priv->stats.tx_packets++;
clip_priv->stats.tx_bytes += skb->len;
- (void) vcc->dev->ops->send(vcc,skb);
+ (void) vcc->send(vcc,skb);
if (atm_may_send(vcc,0)) {
entry->vccs->xoff = 0;
return 0;
struct clip_vcc *clip_vcc;
struct sk_buff_head copy;
struct sk_buff *skb;
- unsigned long flags;
if (!vcc->push) return -EBADFD;
clip_vcc = kmalloc(sizeof(struct clip_vcc),GFP_KERNEL);
clip_vcc->idle_timeout = timeout*HZ;
clip_vcc->old_push = vcc->push;
clip_vcc->old_pop = vcc->pop;
- save_flags(flags);
- cli();
vcc->push = clip_push;
vcc->pop = clip_pop;
skb_migrate(&vcc->recvq,©);
- restore_flags(flags);
/* re-process everything received between connection setup and MKIP */
while ((skb = skb_dequeue(©)))
if (!clip_devs) {
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 */
};
add_timer(&idle_timer);
}
atmarpd = vcc;
- vcc->flags |= ATM_VF_READY | ATM_VF_META;
+ set_bit(ATM_VF_META,&vcc->flags);
+ set_bit(ATM_VF_READY,&vcc->flags);
/* allow replies and avoid getting closed if signaling dies */
bind_vcc(vcc,&atmarpd_dev);
vcc->push = NULL;
#include <linux/sched.h>
#include <linux/time.h> /* struct timeval */
#include <linux/skbuff.h>
+#include <linux/bitops.h>
#include <net/sock.h> /* struct sock */
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#include <asm/poll.h>
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
if (sock->type == SOCK_STREAM) return -EINVAL;
if (!(sk = alloc_atm_vcc_sk(family))) return -ENOMEM;
vcc = sk->protinfo.af_atm;
- vcc->flags = 0;
+ memset(&vcc->flags,0,sizeof(vcc->flags));
vcc->dev = NULL;
vcc->family = sock->ops->family;
vcc->alloc_tx = alloc_tx;
struct sk_buff *skb;
vcc = sk->protinfo.af_atm;
- vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
if (vcc->dev) {
if (vcc->dev->ops->close) vcc->dev->ops->close(vcc);
if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */
void atm_async_release_vcc(struct atm_vcc *vcc,int reply)
{
- vcc->flags |= ATM_VF_CLOSE;
+ set_bit(ATM_VF_CLOSE,&vcc->flags);
vcc->reply = reply;
- /*vcc->flags &= ~ATM_VF_READY;*/
wake_up(&vcc->sleep);
}
if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE))
return -EPERM;
error = 0;
+ bind_vcc(vcc,dev);
switch (vcc->qos.aal) {
case ATM_AAL0:
error = atm_init_aal0(vcc);
}
if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->qos.aal);
if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal);
- if (error) return error;
- bind_vcc(vcc,dev);
+ if (error) {
+ bind_vcc(vcc,NULL);
+ return error;
+ }
DPRINTK("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal);
DPRINTK(" TX: %d, PCR %d..%d, SDU %d\n",vcc->qos.txtp.traffic_class,
vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu);
int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci)
{
if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC)
- vcc->flags &= ~ATM_VF_PARTIAL;
- else if (vcc->flags & ATM_VF_PARTIAL) return -EINVAL;
+ clear_bit(ATM_VF_PARTIAL,&vcc->flags);
+ else if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) return -EINVAL;
printk(KERN_DEBUG "atm_connect (TX: cl %d,bw %d-%d,sdu %d; "
"RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n",
vcc->qos.txtp.traffic_class,vcc->qos.txtp.min_pcr,
vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu,
vcc->qos.aal == ATM_AAL5 ? "" : vcc->qos.aal == ATM_AAL0 ? "" :
" ??? code ",vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal);
- if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD;
+ if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD;
if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
return -EINVAL;
if (!dev) return -ENODEV;
}
if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
- vcc->flags |= ATM_VF_PARTIAL;
+ set_bit(ATM_VF_PARTIAL,&vcc->flags);
return 0;
}
if (!(vpi || vci)) return -EINVAL;
error = atm_connect_vcc(ATM_SD(sock),itf,vpi,vci);
if (error) return error;
- if (ATM_SD(sock)->flags & ATM_VF_READY) sock->state = SS_CONNECTED;
+ if (test_bit(ATM_VF_READY,&ATM_SD(sock)->flags))
+ sock->state = SS_CONNECTED;
return 0;
}
int atm_recvmsg(struct socket *sock,struct msghdr *m,int total_len,
int flags,struct scm_cookie *scm)
{
+ DECLARE_WAITQUEUE(wait,current);
struct atm_vcc *vcc;
struct sk_buff *skb;
- unsigned long cpu_flags;
int eff_len,error;
-
void *buff;
int size;
buff = m->msg_iov->iov_base;
size = m->msg_iov->iov_len;
vcc = ATM_SD(sock);
- save_flags(cpu_flags);
- cli();
+ add_wait_queue(&vcc->sleep,&wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ error = 1; /* <= 0 is error */
while (!(skb = skb_dequeue(&vcc->recvq))) {
- if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE)) {
- restore_flags(cpu_flags);
- return vcc->reply;
+ if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
+ test_bit(ATM_VF_CLOSE,&vcc->flags)) {
+ error = vcc->reply;
+ break;
}
- if (!(vcc->flags & ATM_VF_READY)) {
- restore_flags(cpu_flags);
- return 0;
+ if (!test_bit(ATM_VF_READY,&vcc->flags)) {
+ error = 0;
+ break;
}
if (flags & MSG_DONTWAIT) {
- restore_flags(cpu_flags);
- return -EAGAIN;
+ error = -EAGAIN;
+ break;
}
- interruptible_sleep_on(&vcc->sleep);
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) {
- restore_flags(cpu_flags);
- return -ERESTARTSYS;
+ error = -ERESTARTSYS;
+ break;
}
}
- restore_flags(cpu_flags);
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&vcc->sleep,&wait);
+ if (error <= 0) return error;
vcc->timestamp = skb->stamp;
eff_len = skb->len > size ? size : skb->len;
if (vcc->dev->ops->feedback)
int atm_sendmsg(struct socket *sock,struct msghdr *m,int total_len,
struct scm_cookie *scm)
{
+ DECLARE_WAITQUEUE(wait,current);
struct atm_vcc *vcc;
struct sk_buff *skb;
int eff,error;
-
const void *buff;
int size;
buff = m->msg_iov->iov_base;
size = m->msg_iov->iov_len;
vcc = ATM_SD(sock);
- if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE)) return vcc->reply;
- if (!(vcc->flags & ATM_VF_READY)) return -EPIPE;
+ if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
+ test_bit(ATM_VF_CLOSE,&vcc->flags))
+ return vcc->reply;
+ if (!test_bit(ATM_VF_READY,&vcc->flags)) return -EPIPE;
if (!size) return 0;
/* verify_area is done by net/socket.c */
eff = (size+3) & ~3; /* align to word boundary */
+ add_wait_queue(&vcc->wsleep,&wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ error = 0;
while (!(skb = vcc->alloc_tx(vcc,eff))) {
- if (m->msg_flags & MSG_DONTWAIT) return -EAGAIN;
- interruptible_sleep_on(&vcc->wsleep);
- if (signal_pending(current)) return -ERESTARTSYS;
- if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE))
- return vcc->reply;
- if (!(vcc->flags & ATM_VF_READY)) return -EPIPE;
+ if (m->msg_flags & MSG_DONTWAIT) {
+ error = -EAGAIN;
+ break;
+ }
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (signal_pending(current)) {
+ error = -ERESTARTSYS;
+ break;
+ }
+ if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
+ test_bit(ATM_VF_CLOSE,&vcc->flags)) {
+ error = vcc->reply;
+ break;
+ }
+ if (!test_bit(ATM_VF_READY,&vcc->flags)) {
+ error = -EPIPE;
+ break;
+ }
}
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&vcc->wsleep,&wait);
+ if (error) return error;
skb->dev = NULL; /* for paths shared with net_device interfaces */
ATM_SKB(skb)->iovcnt = 0;
ATM_SKB(skb)->atm_options = vcc->atm_options;
mask = 0;
if (skb_peek(&vcc->recvq) || skb_peek(&vcc->listenq))
mask |= POLLIN | POLLRDNORM;
- if (vcc->flags & (ATM_VF_RELEASED | ATM_VF_CLOSE)) mask |= POLLHUP;
+ if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
+ test_bit(ATM_VF_CLOSE,&vcc->flags))
+ mask |= POLLHUP;
if (sock->state != SS_CONNECTING) {
if (vcc->qos.txtp.traffic_class != ATM_NONE &&
vcc->qos.txtp.max_sdu+atomic_read(&vcc->tx_inuse)+
}
-static int fetch_stats(struct atm_dev *dev,struct atm_dev_stats *arg,int zero)
+static void copy_aal_stats(struct k_atm_aal_stats *from,
+ struct atm_aal_stats *to)
{
- unsigned long flags;
- int error;
+#define __HANDLE_ITEM(i) to->i = atomic_read(&from->i)
+ __AAL_STAT_ITEMS
+#undef __HANDLE_ITEM
+}
- error = 0;
- save_flags(flags);
- cli();
- if (arg)
- error = copy_to_user(arg,&dev->stats,
- sizeof(struct atm_dev_stats));
- if (zero && !error)
- memset(&dev->stats,0,sizeof(struct atm_dev_stats));
- restore_flags(flags);
+
+static void subtract_aal_stats(struct k_atm_aal_stats *from,
+ struct atm_aal_stats *to)
+{
+#define __HANDLE_ITEM(i) atomic_sub(to->i,&from->i)
+ __AAL_STAT_ITEMS
+#undef __HANDLE_ITEM
+}
+
+
+static int fetch_stats(struct atm_dev *dev,struct atm_dev_stats *arg,int zero)
+{
+ struct atm_dev_stats tmp;
+ int error = 0;
+
+ copy_aal_stats(&dev->stats.aal0,&tmp.aal0);
+ copy_aal_stats(&dev->stats.aal34,&tmp.aal34);
+ copy_aal_stats(&dev->stats.aal5,&tmp.aal5);
+ if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp));
+ if (zero && !error) {
+ subtract_aal_stats(&dev->stats.aal0,&tmp.aal0);
+ subtract_aal_stats(&dev->stats.aal34,&tmp.aal34);
+ subtract_aal_stats(&dev->stats.aal5,&tmp.aal5);
+ }
return error ? -EFAULT : 0;
}
switch (cmd) {
case SIOCOUTQ:
if (sock->state != SS_CONNECTED ||
- !(vcc->flags & ATM_VF_READY)) return -EINVAL;
+ !test_bit(ATM_VF_READY,&vcc->flags))
+ return -EINVAL;
return put_user(vcc->sk->sndbuf-
atomic_read(&vcc->tx_inuse)-ATM_PDU_OVHD,
(int *) arg) ? -EFAULT : 0;
return 0;
case ATMSIGD_CTRL:
if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ /*
+ * The user/kernel protocol for exchanging signalling
+ * info uses kernel pointers as opaque references,
+ * so the holder of the file descriptor can scribble
+ * on the kernel... so we should make sure that we
+ * have the same privledges that /proc/kcore needs
+ */
+ if (!capable(CAP_SYS_RAWIO)) return -EPERM;
error = sigd_attach(vcc);
if (!error) sock->state = SS_CONNECTED;
return error;
write the length" */
return put_user(size,
&((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
+ case ATM_SETLOOP:
+ if (__ATM_LM_XTRMT((int) (long) buf) &&
+ __ATM_LM_XTLOC((int) (long) buf) >
+ __ATM_LM_XTRMT((int) (long) buf))
+ return -EINVAL;
+ /* fall through */
case ATM_SETCIRANGE:
case SONET_GETSTATZ:
case SONET_SETDIAG:
int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
{
+ /*
+ * Don't let the QoS change the already connected AAL type nor the
+ * traffic class.
+ */
+ if (qos->aal != vcc->qos.aal ||
+ qos->rxtp.traffic_class != vcc->qos.rxtp.traffic_class ||
+ qos->txtp.traffic_class != vcc->qos.txtp.traffic_class)
+ return -EINVAL;
if (!vcc->dev->ops->change_qos) return -EOPNOTSUPP;
if (vcc->family == AF_ATMPVC)
return vcc->dev->ops->change_qos(vcc,qos,ATM_MF_SET);
if (sock->state != SS_UNCONNECTED)
return -EBADFD;
vcc->qos = qos;
- vcc->flags |= ATM_VF_HASQOS;
+ set_bit(ATM_VF_HASQOS,&vcc->flags);
return 0;
}
case SO_SETCLP:
vcc = ATM_SD(sock);
switch (optname) {
case SO_ATMQOS:
- if (!(vcc->flags & ATM_VF_HASQOS)) return -EINVAL;
+ if (!test_bit(ATM_VF_HASQOS,&vcc->flags))
+ return -EINVAL;
return copy_to_user(optval,&vcc->qos,sizeof(vcc->qos)) ?
-EFAULT : 0;
case SO_SETCLP:
{
struct sockaddr_atmpvc pvc;
- if (!vcc->dev || !(vcc->flags & ATM_VF_ADDR))
+ if (!vcc->dev ||
+ !test_bit(ATM_VF_ADDR,&vcc->flags))
return -ENOTCONN;
pvc.sap_family = AF_ATMPVC;
pvc.sap_addr.itf = vcc->dev->number;
/* net/atm/ipcommon.c - Common items for all ways of doing IP over ATM */
-/* Written 1996,1997 by Werner Almesberger, EPFL LRC */
+/* Written 1996-2000 by Werner Almesberger, EPFL LRC/ICA */
#include <linux/string.h>
/*
* skb_migrate moves the list at FROM to TO, emptying FROM in the process.
- * This function should live in skbuff.c or skbuff.h. Note that skb_migrate
- * is not atomic, so turn off interrupts when using it.
+ * This function should live in skbuff.c or skbuff.h.
*/
void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to)
{
- struct sk_buff *skb,*prev;
+ struct sk_buff *skb;
+ unsigned long flags;
- for (skb = ((struct sk_buff *) from)->next;
- skb != (struct sk_buff *) from; skb = skb->next) skb->list = to;
- prev = from->prev;
- from->next->prev = (struct sk_buff *) to;
- prev->next = (struct sk_buff *) to;
+ spin_lock_irqsave(&from->lock,flags);
*to = *from;
- skb_queue_head_init(from);
+ from->prev = (struct sk_buff *) from;
+ from->next = (struct sk_buff *) from;
+ from->qlen = 0;
+ spin_unlock_irqrestore(&from->lock,flags);
+ spin_lock_init(&to->lock);
+ for (skb = ((struct sk_buff *) to)->next;
+ skb != (struct sk_buff *) from; skb = skb->next) skb->list = to;
+ if (to->next == (struct sk_buff *) from)
+ to->next = (struct sk_buff *) to;
+ to->next->prev = (struct sk_buff *) to;
+ to->prev->next = (struct sk_buff *) to;
}
/* net/atm/ipcommon.h - Common items for all ways of doing IP over ATM */
-/* Written 1996-1998 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1996-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef NET_ATM_IPCOMMON_H
extern struct net_device *clip_devs;
+/*
+ * Moves all skbs from "from" to "to". The operation is atomic for "from", but
+ * not for "to". "to" may only be accessed after skb_migrate finishes.
+ */
void skb_migrate(struct sk_buff_head *from,struct sk_buff_head *to);
#endif
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+rwlock_t lane_bridge_hook_lock = RW_LOCK_UNLOCKED;
+struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
+ unsigned char *addr) = NULL;
+void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent) = NULL;
+#if defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_BRIDGE_MODULE)
+EXPORT_SYMBOL(lane_bridge_hook_lock);
+EXPORT_SYMBOL(br_fdb_get_hook);
+EXPORT_SYMBOL(br_fdb_put_hook);
+#endif /* defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_BRIDGE_MODULE) */
+#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
+
void atm_lane_init(void)
{
#ifndef CONFIG_ATM_LANE_MODULE /* not module */
#include <linux/config.h>
#include <linux/kernel.h>
+#include <linux/bitops.h>
/* We are ethernet device */
#include <linux/if_ether.h>
#include <linux/atmdev.h>
#include <linux/atmlec.h>
-/* Bridge */
-#ifdef CONFIG_BRIDGE
-#include <net/br.h>
+/* Proxy LEC knows about bridging */
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+#include <linux/if_bridge.h>
+#include "../bridge/br_private.h"
+unsigned char bridge_ula[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
#endif
/* Modular too */
return &dev_lec[0];
}
-#ifdef CONFIG_BRIDGE
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
static void handle_bridge(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
char *buff;
struct lec_priv *priv;
- unsigned char bridge_ula[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
/* Check if this is a BPDU. If so, ask zeppelin to send
- * LE_TOPOLOGY_REQUEST with the value of Topology Change bit
- * in the Config BPDU*/
+ * LE_TOPOLOGY_REQUEST with the same value of Topology Change bit
+ * as the Config BPDU has */
eth = (struct ethhdr *)skb->data;
buff = skb->data + skb->dev->hard_header_len;
- if ((memcmp(eth->h_dest, bridge_ula, ETH_ALEN) == 0) &&
- *buff++ == BRIDGE_LLC1_DSAP &&
- *buff++ == BRIDGE_LLC1_SSAP &&
- *buff++ == BRIDGE_LLC1_CTRL) {
+ if (*buff++ == 0x42 && *buff++ == 0x42 && *buff++ == 0x03) {
struct sk_buff *skb2;
struct atmlec_msg *mesg;
skb2->len = sizeof(struct atmlec_msg);
mesg = (struct atmlec_msg *)skb2->data;
mesg->type = l_topology_change;
- mesg->content.normal.flag = *(skb->nh.raw + BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET) & TOPOLOGY_CHANGE;
+ buff += 4;
+ mesg->content.normal.flag = *buff & 0x01; /* 0x01 is topology change */
priv = (struct lec_priv *)dev->priv;
atm_force_charge(priv->lecd, skb2->truesize);
return;
}
-#endif /* CONFIG_BRIDGE */
+#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
/*
* Modelled after tr_type_trans
DPRINTK("skbuff head:%lx data:%lx tail:%lx end:%lx\n",
(long)skb->head, (long)skb->data, (long)skb->tail,
(long)skb->end);
-#ifdef CONFIG_BRIDGE
- if (skb->pkt_bridged == IS_BRIDGED)
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+ if (memcmp(skb->data, bridge_ula, sizeof(bridge_ula)) == 0)
handle_bridge(skb, dev);
-#endif /* CONFIG_BRIDGE */
+#endif
/* Make sure we have room for lec_id */
if (skb_headroom(skb) < 2) {
send_vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
DPRINTK("%s:send_vcc:%p vcc_flags:%x, entry:%p\n", dev->name,
send_vcc, send_vcc?send_vcc->flags:0, entry);
- if (!send_vcc || !(send_vcc->flags & ATM_VF_READY)) {
+ if (!send_vcc || !test_bit(ATM_VF_READY,&send_vcc->flags)) {
if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) {
DPRINTK("%s:lec_send_packet: queuing packet, ", dev->name);
DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
send_vcc->vpi, send_vcc->vci);
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb2->len;
- send_vcc->dev->ops->send(send_vcc, skb2);
+ send_vcc->send(send_vcc, skb2);
}
ATM_SKB(skb)->vcc = send_vcc;
ATM_SKB(skb)->atm_options = send_vcc->atm_options;
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb->len;
- send_vcc->dev->ops->send(send_vcc, skb);
+ send_vcc->send(send_vcc, skb);
#if 0
/* Should we wait for card's device driver to notify us? */
priv->lecid=(unsigned short)(0xffff&mesg->content.normal.flag);
break;
case l_should_bridge: {
-#ifdef CONFIG_BRIDGE
- struct fdb *f;
- extern Port_data port_info[];
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+ struct net_bridge_fdb_entry *f;
DPRINTK("%s: bridge zeppelin asks about 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
dev->name,
mesg->content.proxy.mac_addr[0], mesg->content.proxy.mac_addr[1],
mesg->content.proxy.mac_addr[2], mesg->content.proxy.mac_addr[3],
mesg->content.proxy.mac_addr[4], mesg->content.proxy.mac_addr[5]);
- f = br_avl_find_addr(mesg->content.proxy.mac_addr); /* bridge/br.c */
+
+ read_lock(&lane_bridge_hook_lock);
+ if (br_fdb_get_hook == NULL || dev->br_port == NULL) {
+ read_unlock(&lane_bridge_hook_lock);
+ break;
+ }
+
+ f = br_fdb_get_hook(dev->br_port->br, mesg->content.proxy.mac_addr);
if (f != NULL &&
- port_info[f->port].dev != dev &&
- port_info[f->port].state == Forwarding) {
+ f->dst->dev != dev &&
+ f->dst->state == BR_STATE_FORWARDING) {
/* hit from bridge table, send LE_ARP_RESPONSE */
struct sk_buff *skb2;
DPRINTK("%s: entry found, responding to zeppelin\n", dev->name);
skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
- if (skb2 == NULL) break;
+ if (skb2 == NULL) {
+ br_fdb_put_hook(f);
+ read_unlock(&lane_bridge_hook_lock);
+ break;
+ }
skb2->len = sizeof(struct atmlec_msg);
memcpy(skb2->data, mesg, sizeof(struct atmlec_msg));
atm_force_charge(priv->lecd, skb2->truesize);
skb_queue_tail(&priv->lecd->recvq, skb2);
wake_up(&priv->lecd->sleep);
}
-#endif /* CONFIG_BRIDGE */
+ if (f != NULL) br_fdb_put_hook(f);
+ read_unlock(&lane_bridge_hook_lock);
+#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
}
break;
default:
999, /*dummy device number*/
NULL,NULL, /*no VCCs*/
NULL,NULL, /*no data*/
- 0, /*no flags*/
+ { 0 }, /*no flags*/
NULL, /* no local address*/
{ 0 } /*no ESI or rest of the atm_dev struct things*/
};
lec_arp_check_empties(priv, vcc, skb);
}
skb->dev = dev;
+ skb->rx_dev = NULL;
skb->data += 2; /* skip lec_id */
#ifdef CONFIG_TR
if (priv->is_trdev) skb->protocol = tr_type_trans(skb, dev);
bind_vcc(vcc, &lecatm_dev);
vcc->proto_data = dev_lec[i];
- vcc->flags |= ATM_VF_READY | ATM_VF_META;
+ set_bit(ATM_VF_META,&vcc->flags);
+ set_bit(ATM_VF_READY,&vcc->flags);
/* Set default values to these variables */
priv->maximum_unknown_frame_count = 1;
if (entry->vcc) {
entry->vcc->push = entry->old_push;
#if 0 /* August 6, 1998 */
- entry->vcc->flags |= ATM_VF_RELEASED;
- entry->vcc->flags &= ~ATM_VF_READY;
+ set_bit(ATM_VF_RELEASED,&entry->vcc->flags);
+ clear_bit(ATM_VF_READY,&entry->vcc->flags);
entry->vcc->push(entry->vcc, NULL);
#endif
atm_async_release_vcc(entry->vcc, -EPIPE);
if (entry->recv_vcc) {
entry->recv_vcc->push = entry->old_recv_push;
#if 0
- entry->recv_vcc->flags |= ATM_VF_RELEASED;
- entry->recv_vcc->flags &= ~ATM_VF_READY;
+ set_bit(ATM_VF_RELEASED,&entry->vcc->flags);
+ clear_bit(ATM_VF_READY,&entry->vcc->flags);
entry->recv_vcc->push(entry->recv_vcc, NULL);
#endif
atm_async_release_vcc(entry->recv_vcc, -EPIPE);
#include <linux/netdevice.h>
#include <linux/atmlec.h>
+#if defined (CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+#include <linux/if_bridge.h>
+extern rwlock_t lane_bridge_hook_lock;
+struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
+ unsigned char *addr);
+void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
+#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
+
#define LEC_HEADER_LEN 16
struct lecdatahdr_8023 {
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/bitops.h>
/* We are an ethernet device */
#include <linux/if_ether.h>
atomic_add(skb->truesize, &entry->shortcut->tx_inuse);
ATM_SKB(skb)->iovcnt = 0; /* just to be safe ... */
ATM_SKB(skb)->atm_options = entry->shortcut->atm_options;
- entry->shortcut->dev->ops->send(entry->shortcut, skb);
+ entry->shortcut->send(entry->shortcut, skb);
entry->packets_fwded++;
return 0;
NULL, /* last VCC */
NULL, /* per-device data */
NULL, /* private PHY data */
- 0, /* device flags */
+ { 0 }, /* device flags */
NULL, /* local ATM address */
{ 0 } /* no ESI */
/* rest of the members will be 0 */
mpc->mpoad_vcc = vcc;
bind_vcc(vcc, &mpc_dev);
- vcc->flags |= ATM_VF_READY | ATM_VF_META;
+ set_bit(ATM_VF_META,&vcc->flags);
+ set_bit(ATM_VF_READY,&vcc->flags);
if (mpc->dev) {
char empty[ATM_ESA_LEN];
#include <linux/if_arp.h>
#include <linux/init.h> /* for __init */
#include <asm/uaccess.h>
+#include <asm/atomic.h>
#include <asm/param.h> /* for HZ */
#include "resources.h"
#include "common.h" /* atm_proc_init prototype */
};
static void add_stats(char *buf,const char *aal,
- const struct atm_aal_stats *stats)
+ const struct k_atm_aal_stats *stats)
{
- sprintf(strchr(buf,0),"%s ( %d %d %d %d %d )",aal,stats->tx,
- stats->tx_err,stats->rx,stats->rx_err,stats->rx_drop);
+ sprintf(strchr(buf,0),"%s ( %d %d %d %d %d )",aal,
+ atomic_read(&stats->tx),atomic_read(&stats->tx_err),
+ atomic_read(&stats->rx),atomic_read(&stats->rx_err),
+ atomic_read(&stats->rx_drop));
}
default:
here += sprintf(here,"%3d",vcc->family);
}
- here += sprintf(here," %04x %5d %7d/%7d %7d/%7d\n",vcc->flags,
+ here += sprintf(here," %04x %5d %7d/%7d %7d/%7d\n",vcc->flags.bits,
vcc->reply,
atomic_read(&vcc->tx_inuse),vcc->sk->sndbuf,
atomic_read(&vcc->rx_inuse),vcc->sk->rcvbuf);
struct proc_dir_entry *devices = NULL,*pvc = NULL,*svc = NULL;
struct proc_dir_entry *arp = NULL,*lec = NULL,*vc = NULL;
- atm_proc_root = proc_mkdir("atm", &proc_root);
+ atm_proc_root = proc_mkdir("net/atm",NULL);
if (!atm_proc_root)
return -ENOMEM;
CREATE_ENTRY(devices);
if (arp) remove_proc_entry("arp",atm_proc_root);
if (lec) remove_proc_entry("lec",atm_proc_root);
if (vc) remove_proc_entry("vc",atm_proc_root);
- remove_proc_entry("atm",&proc_root);
+ remove_proc_entry("net/atm",NULL);
return -ENOMEM;
}
/* net/atm/pvc.c - ATM PVC sockets */
-/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#include <linux/config.h>
#include <linux/kernel.h> /* printk */
#include <linux/init.h>
#include <linux/skbuff.h>
+#include <linux/bitops.h>
#include <net/sock.h> /* for sock_no_* */
#ifdef CONFIG_ATM_CLIP
#include <net/atmclip.h>
addr = (struct sockaddr_atmpvc *) sockaddr;
if (addr->sap_family != AF_ATMPVC) return -EAFNOSUPPORT;
vcc = ATM_SD(sock);
- if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD;
- if (vcc->flags & ATM_VF_PARTIAL) {
+ if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD;
+ if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) {
if (vcc->vpi != ATM_VPI_UNSPEC) addr->sap_addr.vpi = vcc->vpi;
if (vcc->vci != ATM_VCI_UNSPEC) addr->sap_addr.vci = vcc->vci;
}
struct sockaddr_atmpvc *addr;
struct atm_vcc *vcc = ATM_SD(sock);
- if (!vcc->dev || !(vcc->flags & ATM_VF_ADDR)) return -ENOTCONN;
+ if (!vcc->dev || !test_bit(ATM_VF_ADDR,&vcc->flags)) return -ENOTCONN;
*sockaddr_len = sizeof(struct sockaddr_atmpvc);
addr = (struct sockaddr_atmpvc *) sockaddr;
addr->sap_family = AF_ATMPVC;
{
DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->tx_inuse,skb->truesize);
atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
- dev_kfree_skb_irq(skb);
+ dev_kfree_skb_any(skb);
wake_up(&vcc->wsleep);
}
+static int atm_send_aal0(struct atm_vcc *vcc,struct sk_buff *skb)
+{
+ /*
+ * Note that if vpi/vci are _ANY or _UNSPEC the below will
+ * still work
+ */
+ if (!capable(CAP_NET_ADMIN) &&
+ (((u32 *) skb->data)[0] & (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)) !=
+ ((vcc->vpi << ATM_HDR_VPI_SHIFT) | (vcc->vci << ATM_HDR_VCI_SHIFT)))
+ {
+ kfree_skb(skb);
+ return -EADDRNOTAVAIL;
+ }
+ return vcc->dev->ops->send(vcc,skb);
+}
+
+
int atm_init_aal0(struct atm_vcc *vcc)
{
vcc->push = atm_push_raw;
vcc->pop = atm_pop_raw;
vcc->push_oam = NULL;
+ vcc->send = atm_send_aal0;
return 0;
}
vcc->push = atm_push_raw;
vcc->pop = atm_pop_raw;
vcc->push_oam = NULL;
+ vcc->send = vcc->dev->ops->send;
return 0;
}
vcc->push = atm_push_raw;
vcc->pop = atm_pop_raw;
vcc->push_oam = NULL;
+ vcc->send = vcc->dev->ops->send;
return 0;
}
/* net/atm/resources.c - Staticly allocated resources */
-/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#include <linux/config.h>
#include <linux/atmdev.h>
#include <linux/kernel.h> /* for barrier */
#include <linux/module.h>
+#include <linux/bitops.h>
#include <net/sock.h> /* for struct sock */
#include <asm/segment.h> /* for get_fs_long and put_fs_long */
struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
- int number,unsigned long flags)
+ int number,atm_dev_flags_t *flags)
{
struct atm_dev *dev;
dev->dev_data = NULL;
barrier();
dev->ops = ops;
- dev->flags = flags;
- memset((void *) &dev->stats,0,sizeof(struct atm_dev_stats));
+ if (flags) dev->flags = *flags;
+ else memset(&dev->flags,0,sizeof(dev->flags));
+ memset((void *) &dev->stats,0,sizeof(dev->stats));
#ifdef CONFIG_PROC_FS
if (ops->proc_read)
if (atm_proc_dev_register(dev) < 0) {
void shutdown_atm_dev(struct atm_dev *dev)
{
if (dev->vccs) {
- dev->flags |= ATM_DF_CLOSE;
+ set_bit(ATM_DF_CLOSE,&dev->flags);
return;
}
if (dev->ops->dev_close) dev->ops->dev_close(dev);
if (vcc->next) vcc->next->prev = vcc->prev;
else if (vcc->dev) vcc->dev->last = vcc->prev;
if (vcc->dev && vcc->dev != hold_dev && !vcc->dev->vccs &&
- (vcc->dev->flags & ATM_DF_CLOSE))
+ test_bit(ATM_DF_CLOSE,&vcc->dev->flags))
shutdown_atm_dev(vcc->dev);
}
#include <linux/atmsap.h>
#include <linux/atmsvc.h>
#include <linux/atmdev.h>
+#include <linux/bitops.h>
#include "resources.h"
#include "signaling.h"
struct atm_vcc *sigd = NULL;
-static wait_queue_head_t sigd_sleep;
+static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep);
static void sigd_put_skb(struct sk_buff *skb)
{
#ifdef WAIT_FOR_DEMON
static unsigned long silence = 0;
-#endif
+ DECLARE_WAITQUEUE(wait,current);
+ add_wait_queue(&sigd_sleep,&wait);
while (!sigd) {
-#ifdef WAIT_FOR_DEMON
+ set_current_state(TASK_UNINTERRUPTIBLE);
if (time_after(jiffies, silence) || silence == 0) {
printk(KERN_INFO "atmsvc: waiting for signaling demon "
"...\n");
silence = (jiffies+30*HZ)|1;
}
- sleep_on(&sigd_sleep);
+ schedule();
+ }
+ remove_wait_queue(&sigd_sleep,&wait);
#else
+ if (!sigd) {
printk(KERN_WARNING "atmsvc: no signaling demon\n");
kfree_skb(skb);
return;
-#endif
}
+#endif
atm_force_charge(sigd,skb->truesize);
skb_queue_tail(&sigd->recvq,skb);
wake_up(&sigd->sleep);
{
struct sk_buff *skb;
- if ((vcc->flags & ATM_VF_RELEASED) || !(vcc->flags & ATM_VF_READY))
+ if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
+ !test_bit(ATM_VF_READY,&vcc->flags))
return;
msg->type = as_error;
if (!vcc->dev->ops->change_qos) msg->reply = -EOPNOTSUPP;
session_vcc->qos = msg->qos;
break;
case as_error:
- vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_READY);
+ clear_bit(ATM_VF_REGIS,&vcc->flags);
+ clear_bit(ATM_VF_READY,&vcc->flags);
vcc->reply = msg->reply;
break;
case as_indicate:
}
return 0;
case as_close:
- vcc->flags |= ATM_VF_RELEASED;
- vcc->flags &= ~ATM_VF_READY;
+ set_bit(ATM_VF_RELEASED,&vcc->flags);
+ clear_bit(ATM_VF_READY,&vcc->flags);
vcc->reply = msg->reply;
break;
case as_modify:
if (!pvc) memset(&msg->pvc,0,sizeof(msg->pvc));
else msg->pvc = *pvc;
sigd_put_skb(skb);
- if (vcc) vcc->flags |= ATM_VF_REGIS;
+ if (vcc) set_bit(ATM_VF_REGIS,&vcc->flags);
}
{
while (vcc) {
if (vcc->family == PF_ATMSVC &&
- !(vcc->flags & ATM_VF_META)) {
- vcc->flags |= ATM_VF_RELEASED;
+ !test_bit(ATM_VF_META,&vcc->flags)) {
+ set_bit(ATM_VF_RELEASED,&vcc->flags);
vcc->reply = -EUNATCH;
wake_up(&vcc->sleep);
}
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 */
};
DPRINTK("sigd_attach\n");
sigd = vcc;
bind_vcc(vcc,&sigd_dev);
- vcc->flags |= ATM_VF_READY | ATM_VF_META;
+ set_bit(ATM_VF_META,&vcc->flags);
+ set_bit(ATM_VF_READY,&vcc->flags);
wake_up(&sigd_sleep);
return 0;
}
-
-
-void signaling_init(void)
-{
- init_waitqueue_head(&sigd_sleep);
-}
struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc,
const struct sockaddr_atmsvc *svc);
int sigd_attach(struct atm_vcc *vcc);
-void signaling_init(void);
#endif
#include <linux/atmsap.h>
#include <linux/atmsvc.h>
#include <linux/atmdev.h>
+#include <linux/bitops.h>
#include <net/sock.h> /* for sock_no_* */
#include <asm/uaccess.h>
static void svc_disconnect(struct atm_vcc *vcc)
{
+ DECLARE_WAITQUEUE(wait,current);
struct sk_buff *skb;
DPRINTK("svc_disconnect %p\n",vcc);
- if (vcc->flags & ATM_VF_REGIS) {
+ if (test_bit(ATM_VF_REGIS,&vcc->flags)) {
sigd_enq(vcc,as_close,NULL,NULL,NULL);
- while (!(vcc->flags & ATM_VF_RELEASED) && sigd)
- sleep_on(&vcc->sleep);
+ add_wait_queue(&vcc->sleep,&wait);
+ while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
+ }
+ remove_wait_queue(&vcc->sleep,&wait);
}
/* beware - socket is still in use by atmsigd until the last
as_indicate has been answered */
the reason */
dev_kfree_skb(skb);
}
- vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_RELEASED | ATM_VF_CLOSE);
- /* may retry later */
+ clear_bit(ATM_VF_REGIS,&vcc->flags);
+ clear_bit(ATM_VF_RELEASED,&vcc->flags);
+ clear_bit(ATM_VF_CLOSE,&vcc->flags);
+ /* ... may retry later */
}
if (!sock->sk) return 0;
vcc = ATM_SD(sock);
DPRINTK("svc_release %p\n",vcc);
- vcc->flags &= ~ATM_VF_READY;
+ clear_bit(ATM_VF_READY,&vcc->flags);
atm_release_vcc_sk(sock->sk,0);
svc_disconnect(vcc);
/* VCC pointer is used as a reference, so we must not free it
static int svc_bind(struct socket *sock,struct sockaddr *sockaddr,
int sockaddr_len)
{
+ DECLARE_WAITQUEUE(wait,current);
struct sockaddr_atmsvc *addr;
struct atm_vcc *vcc;
if (sock->state == SS_CONNECTED) return -EISCONN;
if (sock->state != SS_UNCONNECTED) return -EINVAL;
vcc = ATM_SD(sock);
- if (vcc->flags & ATM_VF_SESSION) return -EINVAL;
+ if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL;
addr = (struct sockaddr_atmsvc *) sockaddr;
if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT;
- vcc->flags &= ~ATM_VF_BOUND; /* failing rebind will kill old binding */
+ clear_bit(ATM_VF_BOUND,&vcc->flags);
+ /* failing rebind will kill old binding */
/* @@@ check memory (de)allocation on rebind */
- if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD;
+ if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD;
vcc->local = *addr;
vcc->reply = WAITING;
sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local);
- while (vcc->reply == WAITING && sigd) sleep_on(&vcc->sleep);
- vcc->flags &= ~ATM_VF_REGIS; /* doesn't count */
+ add_wait_queue(&vcc->sleep,&wait);
+ while (vcc->reply == WAITING && sigd) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
+ }
+ remove_wait_queue(&vcc->sleep,&wait);
+ clear_bit(ATM_VF_REGIS,&vcc->flags); /* doesn't count */
if (!sigd) return -EUNATCH;
- if (!vcc->reply) vcc->flags |= ATM_VF_BOUND;
+ if (!vcc->reply) set_bit(ATM_VF_BOUND,&vcc->flags);
return vcc->reply;
}
static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
int sockaddr_len,int flags)
{
+ DECLARE_WAITQUEUE(wait,current);
struct sockaddr_atmsvc *addr;
struct atm_vcc *vcc = ATM_SD(sock);
int error;
if (vcc->reply) return vcc->reply;
}
else {
+ int error;
+
if (sock->state != SS_UNCONNECTED) return -EINVAL;
- if (vcc->flags & ATM_VF_SESSION) return -EINVAL;
+ if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL;
addr = (struct sockaddr_atmsvc *) sockaddr;
if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT;
- if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD;
+ if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD;
if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
return -EINVAL;
sock->state = SS_CONNECTING;
return -EINPROGRESS;
}
+ add_wait_queue(&vcc->sleep,&wait);
+ error = 0;
while (vcc->reply == WAITING && sigd) {
- interruptible_sleep_on(&vcc->sleep);
- if (signal_pending(current)) {
- DPRINTK("*ABORT*\n");
- /*
- * This is tricky:
- * Kernel ---close--> Demon
- * Kernel <--close--- Demon
- * or
- * Kernel ---close--> Demon
- * Kernel <--error--- Demon
- * or
- * Kernel ---close--> Demon
- * Kernel <--okay---- Demon
- * Kernel <--close--- Demon
- */
- sigd_enq(vcc,as_close,NULL,NULL,NULL);
- while (vcc->reply == WAITING && sigd)
- sleep_on(&vcc->sleep);
- if (!vcc->reply)
- while (!(vcc->flags & ATM_VF_RELEASED)
- && sigd) sleep_on(&vcc->sleep);
- vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_RELEASED
- | ATM_VF_CLOSE);
- /* we're gone now but may connect later */
- return -EINTR;
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ if (!signal_pending(current)) continue;
+ DPRINTK("*ABORT*\n");
+ /*
+ * This is tricky:
+ * Kernel ---close--> Demon
+ * Kernel <--close--- Demon
+ * or
+ * Kernel ---close--> Demon
+ * Kernel <--error--- Demon
+ * or
+ * Kernel ---close--> Demon
+ * Kernel <--okay---- Demon
+ * Kernel <--close--- Demon
+ */
+ sigd_enq(vcc,as_close,NULL,NULL,NULL);
+ while (vcc->reply == WAITING && sigd) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
}
+ if (!vcc->reply)
+ while (!test_bit(ATM_VF_RELEASED,&vcc->flags)
+ && sigd) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
+ }
+ remove_wait_queue(&vcc->sleep,&wait);
+ clear_bit(ATM_VF_REGIS,&vcc->flags);
+ clear_bit(ATM_VF_RELEASED,&vcc->flags);
+ clear_bit(ATM_VF_CLOSE,&vcc->flags);
+ /* we're gone now but may connect later */
+ error = -EINTR;
+ break;
}
+ remove_wait_queue(&vcc->sleep,&wait);
+ if (error) return error;
if (!sigd) return -EUNATCH;
if (vcc->reply) return vcc->reply;
}
static int svc_listen(struct socket *sock,int backlog)
{
+ DECLARE_WAITQUEUE(wait,current);
struct atm_vcc *vcc = ATM_SD(sock);
DPRINTK("svc_listen %p\n",vcc);
/* let server handle listen on unbound sockets */
- if (vcc->flags & ATM_VF_SESSION) return -EINVAL;
+ if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL;
vcc->reply = WAITING;
sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local);
- while (vcc->reply == WAITING && sigd) sleep_on(&vcc->sleep);
+ add_wait_queue(&vcc->sleep,&wait);
+ while (vcc->reply == WAITING && sigd) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
+ }
+ remove_wait_queue(&vcc->sleep,&wait);
if (!sigd) return -EUNATCH;
- vcc->flags |= ATM_VF_LISTEN;
+ set_bit(ATM_VF_LISTEN,&vcc->flags);
vcc->backlog_quota = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT;
return vcc->reply;
}
DPRINTK("svc_accept %p -> %p\n",old_vcc,new_vcc);
while (1) {
+ DECLARE_WAITQUEUE(wait,current);
+
+ add_wait_queue(&old_vcc->sleep,&wait);
while (!(skb = skb_dequeue(&old_vcc->listenq)) && sigd) {
- if (old_vcc->flags & ATM_VF_RELEASED) break;
- if (old_vcc->flags & ATM_VF_CLOSE)
- return old_vcc->reply;
- if (flags & O_NONBLOCK) return -EAGAIN;
- interruptible_sleep_on(&old_vcc->sleep);
- if (signal_pending(current)) return -ERESTARTSYS;
+ if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break;
+ if (test_bit(ATM_VF_CLOSE,&old_vcc->flags)) {
+ error = old_vcc->reply;
+ break;
+ }
+ if (flags & O_NONBLOCK) {
+ error = -EAGAIN;
+ break;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ if (signal_pending(current)) {
+ error = -ERESTARTSYS;
+ break;
+ }
}
+ remove_wait_queue(&old_vcc->sleep,&wait);
+ if (error) return error;
if (!skb) return -EUNATCH;
msg = (struct atmsvc_msg *) skb->data;
new_vcc->qos = msg->qos;
- new_vcc->flags |= ATM_VF_HASQOS;
+ set_bit(ATM_VF_HASQOS,&new_vcc->flags);
new_vcc->remote = msg->svc;
new_vcc->local = msg->local;
new_vcc->sap = msg->sap;
/* wait should be short, so we ignore the non-blocking flag */
new_vcc->reply = WAITING;
sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL);
- while (new_vcc->reply == WAITING && sigd)
- sleep_on(&new_vcc->sleep);
+ add_wait_queue(&new_vcc->sleep,&wait);
+ while (new_vcc->reply == WAITING && sigd) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
+ }
+ remove_wait_queue(&new_vcc->sleep,&wait);
if (!sigd) return -EUNATCH;
if (!new_vcc->reply) break;
if (new_vcc->reply != -ERESTARTSYS) return new_vcc->reply;
int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
{
+ DECLARE_WAITQUEUE(wait,current);
struct atm_qos save_qos;
vcc->reply = WAITING;
vcc->qos = *qos;
sigd_enq(vcc,as_modify,NULL,NULL,&vcc->local);
vcc->qos = save_qos;
- while (vcc->reply == WAITING && !(vcc->flags & ATM_VF_RELEASED) &&
- sigd) sleep_on(&vcc->sleep);
+ add_wait_queue(&vcc->sleep,&wait);
+ while (vcc->reply == WAITING && !test_bit(ATM_VF_RELEASED,&vcc->flags)
+ && sigd) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule();
+ }
+ remove_wait_queue(&vcc->sleep,&wait);
if (!sigd) return -EUNATCH;
return vcc->reply;
}
return atm_setsockopt(sock,level,optname,optval,optlen);
vcc = ATM_SD(sock);
if (copy_from_user(&vcc->sap,optval,optlen)) return -EFAULT;
- vcc->flags |= ATM_VF_HASSAP;
+ set_bit(ATM_VF_HASSAP,&vcc->flags);
return 0;
}
printk(KERN_ERR "ATMSVC: can't register");
return;
}
- signaling_init();
- init_addr();
}
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br.c,v 1.39 2000/02/18 16:47:11 davem Exp $
+ * $Id: br.c,v 1.40 2000/03/21 21:08:47 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
#include <asm/uaccess.h>
#include "br_private.h"
+#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+#include "../atm/lec.h"
+#endif
+
void br_dec_use_count()
{
MOD_DEC_USE_COUNT;
br_handle_frame_hook = br_handle_frame;
br_ioctl_hook = br_ioctl_deviceless_stub;
+#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+ write_lock(&lane_bridge_hook_lock);
+ br_fdb_get_hook = br_fdb_get;
+ br_fdb_put_hook = br_fdb_put;
+ write_unlock(&lane_bridge_hook_lock);
+#endif
register_netdevice_notifier(&br_device_notifier);
return 0;
unregister_netdevice_notifier(&br_device_notifier);
br_call_ioctl_atomic(__br_clear_ioctl_hook);
net_call_rx_atomic(__br_clear_frame_hook);
+#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+ write_lock(&lane_bridge_hook_lock);
+ br_fdb_get_hook = NULL;
+ br_fdb_put_hook = NULL;
+ write_unlock(&lane_bridge_hook_lock);
+#endif
}
EXPORT_NO_SYMBOLS;
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_input.c,v 1.3 2000/02/24 19:48:06 davem Exp $
+ * $Id: br_input.c,v 1.4 2000/03/21 21:08:47 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
#include <linux/if_bridge.h>
#include "br_private.h"
-unsigned char bridge_ula[5] = { 0x01, 0x80, 0xc2, 0x00, 0x00 };
+unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
{
p->state == BR_STATE_DISABLED)
goto freeandout;
+ skb_push(skb, skb->data - skb->mac.raw);
+
if (br->dev.flags & IFF_PROMISC) {
struct sk_buff *skb2;
if (!memcmp(dest, bridge_ula, 5) && !(dest[5] & 0xF0))
goto handle_special_frame;
- skb_push(skb, skb->data - skb->mac.raw);
-
if (p->state == BR_STATE_LEARNING ||
p->state == BR_STATE_FORWARDING)
br_fdb_insert(br, p, skb->mac.ethernet->h_source, 0);
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_private.h,v 1.1 2000/02/18 16:47:12 davem Exp $
+ * $Id: br_private.h,v 1.2 2000/03/21 21:08:47 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
};
struct notifier_block br_device_notifier;
-unsigned char bridge_ula[5];
+unsigned char bridge_ula[6];
/* br.c */
void br_dec_use_count(void);
qdisc_run(dev);
spin_unlock_bh(&dev->queue_lock);
- return ret;
+ return ret == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : ret;
}
/* The device has no queue. Common case for software devices:
/*
* Linux NET3: IP/IP protocol decoder.
*
- * Version: $Id: ipip.c,v 1.31 2000/03/17 14:41:51 davem Exp $
+ * Version: $Id: ipip.c,v 1.32 2000/03/21 06:13:54 davem Exp $
*
* Authors:
* Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95
skb = netlink_build_message(e, &status);
if (skb == NULL)
return status;
- return netlink_unicast(nfnl, skb, nlq->peer.pid, 0);
+ return netlink_unicast(nfnl, skb, nlq->peer.pid, MSG_DONTWAIT);
}
static struct sk_buff *
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_input.c,v 1.189 2000/02/27 19:52:55 davem Exp $
+ * Version: $Id: tcp_input.c,v 1.190 2000/03/21 19:34:23 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
timer_expires = jiffies;
sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
- " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p %u %u %u %u",
+ " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u",
i, src, srcp, dest, destp, sp->state,
tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq,
timer_active, timer_expires-jiffies,
* Pedro Roque <roque@di.fc.ul.pt>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
*
- * $Id: sit.c,v 1.36 2000/03/17 14:42:08 davem Exp $
+ * $Id: sit.c,v 1.37 2000/03/21 06:14:00 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
goto err_out;
}
/* @@@ should check if the socket is really operational or we'll crash
- on vcc->dev->ops->send */
+ on vcc->send */
if (classid) {
if (TC_H_MAJ(classid ^ sch->handle)) {
DPRINTK("atm_tc_change: classid mismatch\n");
sch->stats.packets++;
flow->stats.bytes += skb->len;
flow->stats.packets++;
- sch->q.qlen++;
- return 0;
+ /*
+ * Okay, this may seem weird. We pretend we've dropped the packet if
+ * it goes via ATM. The reason for this is that the outer qdisc
+ * expects to be able to q->dequeue the packet later on if we return
+ * success at this place. Also, sch->q.qdisc needs to reflect whether
+ * there is a packet egligible for dequeuing or not. Note that the
+ * statistics of the outer qdisc are necessarily wrong because of all
+ * this. There's currently no correct solution for this.
+ */
+ if (flow == &p->link) {
+ sch->q.qlen++;
+ return 0;
+ }
+ tasklet_schedule(&p->task);
+ return NET_XMIT_BYPASS;
}
*/
while ((skb = flow->q->dequeue(flow->q))) {
if (!atm_may_send(flow->vcc,skb->truesize)) {
- if (flow->q->ops->requeue(skb,flow->q))
- sch->q.qlen--;
+ (void) flow->q->ops->requeue(skb,flow->q);
break;
}
- sch->q.qlen--;
D2PRINTK("atm_tc_deqeueue: sending on class %p\n",flow);
/* remove any LL header somebody else has attached */
skb_pull(skb,(char *) skb->nh.iph-(char *) skb->data);
atomic_add(skb->truesize,&flow->vcc->tx_inuse);
ATM_SKB(skb)->iovcnt = 0;
/* atm.atm_options are already set by atm_tc_enqueue */
- (void) flow->vcc->dev->ops->send(flow->vcc,skb);
+ (void) flow->vcc->send(flow->vcc,skb);
}
}