From 1417ae0869472f4f3768779c51c3979faca20b2e Mon Sep 17 00:00:00 2001 From: Carl-Daniel Hailfinger Date: Tue, 4 Apr 2006 01:02:30 +0200 Subject: kbuild: fix unneeded rebuilds in drivers/net/chelsio after moving source tree This fixes some uneeded rebuilds under drivers/net/chelsio after moving the source tree. The makefiles used $(TOPDIR) for include paths, which is unnecessary. Changed to use relative paths. Compile tested, produces byte-identical code to the previous makefiles. Signed-off-by: Carl-Daniel Hailfinger Signed-off-by: Sam Ravnborg --- drivers/net/chelsio/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/chelsio/Makefile b/drivers/net/chelsio/Makefile index 91e9278..54c78d9 100644 --- a/drivers/net/chelsio/Makefile +++ b/drivers/net/chelsio/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_CHELSIO_T1) += cxgb.o -EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/chelsio $(DEBUG_FLAGS) +EXTRA_CFLAGS += -Idrivers/net/chelsio $(DEBUG_FLAGS) cxgb-objs := cxgb2.o espi.o pm3393.o sge.o subr.o mv88x201x.o -- cgit v1.1 From d938ab44c0c5418bb74a97b422a070e2cdccce22 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 4 Apr 2006 20:11:56 -0700 Subject: [NET] netconsole: set .name in struct console Set .name in netconsole's struct console to identify the struct's owner. Signed-off-by: Randy Dunlap Acked-by: Matt Mackall Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 75b35ad..66e74f7 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -87,6 +87,7 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) } static struct console netconsole = { + .name = "netcon", .flags = CON_ENABLED | CON_PRINTBUFFER, .write = write_msg }; -- cgit v1.1 From ad96b485b4224785bcca478cfba02d06c46ee575 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 5 Apr 2006 22:21:04 -0700 Subject: [TG3]: Fix a memory leak. This patch fixes a memory leak (buf wasn't freed) spotted by the Coverity checker. Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- drivers/net/tg3.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 0b53580..d6047bd 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8034,9 +8034,13 @@ static int tg3_test_nvram(struct tg3 *tp) for (i = 0; i < size; i++) csum8 += buf8[i]; - if (csum8 == 0) - return 0; - return -EIO; + if (csum8 == 0) { + err = 0; + goto out; + } + + err = -EIO; + goto out; } /* Bootstrap checksum at offset 0x10 */ -- cgit v1.1 From c1e14a6ea2ae34993f431d2eb9a0f228ac3574eb Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 5 Apr 2006 22:33:59 -0700 Subject: [IRDA]: smcinit merged into smsc-ircc driver This patch integrates the smcinit code into the smsc-ircc driver. Some laptops have their smsc-ircc chip not properly configured by the BIOS and needs some preconfiguration. Currently, this can be done from userspace with smcinit, a utility that comes with the irda-utils package. It messes with ioports and PCI settings, from userspace. Now with this patch, if we happen to be on one of the known to be faulty laptops, we preconfigure the chip from the driver. Patch from Linus Walleij Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/smsc-ircc2.c | 311 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 311 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index ec94ecd..bbcfc8e 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -11,6 +11,7 @@ * Copyright (c) 2002 Daniele Peri * All Rights Reserved. * Copyright (c) 2002 Jean Tourrilhes + * Copyright (c) 2006 Linus Walleij * * * Based on smc-ircc.c: @@ -61,6 +62,9 @@ #include #include +#ifdef CONFIG_PCI +#include +#endif #include #include @@ -100,6 +104,22 @@ MODULE_PARM_DESC(ircc_transceiver, "Transceiver type"); /* Types */ +#ifdef CONFIG_PCI +struct smsc_ircc_subsystem_configuration { + unsigned short vendor; /* PCI vendor ID */ + unsigned short device; /* PCI vendor ID */ + unsigned short subvendor; /* PCI subsystem vendor ID */ + unsigned short subdevice; /* PCI sybsystem device ID */ + unsigned short sir_io; /* I/O port for SIR */ + unsigned short fir_io; /* I/O port for FIR */ + unsigned char fir_irq; /* FIR IRQ */ + unsigned char fir_dma; /* FIR DMA */ + unsigned short cfg_base; /* I/O port for chip configuration */ + int (*preconfigure)(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); /* Preconfig function */ + const char *name; /* name shown as info */ +}; +#endif + struct smsc_transceiver { char *name; void (*set_for_speed)(int fir_base, u32 speed); @@ -202,6 +222,16 @@ static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned shor static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); static int __init smsc_superio_fdc(unsigned short cfg_base); static int __init smsc_superio_lpc(unsigned short cfg_base); +#ifdef CONFIG_PCI +static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); +static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, + unsigned short ircc_fir, + unsigned short ircc_sir, + unsigned char ircc_dma, + unsigned char ircc_irq); +#endif /* Transceivers specific functions */ @@ -353,6 +383,13 @@ static int __init smsc_ircc_init(void) return ret; } +#ifdef CONFIG_PCI + if (smsc_ircc_preconfigure_subsystems(ircc_cfg, ircc_fir, ircc_sir, ircc_dma, ircc_irq) < 0) { + /* Ignore errors from preconfiguration */ + IRDA_ERROR("%s, Preconfiguration failed !\n", driver_name); + } +#endif + dev_count = 0; if (ircc_fir > 0 && ircc_sir > 0) { @@ -2285,6 +2322,280 @@ static int __init smsc_superio_lpc(unsigned short cfg_base) return ret; } +/* + * Look for some specific subsystem setups that need + * pre-configuration not properly done by the BIOS (especially laptops) + * This code is based in part on smcinit.c, tosh1800-smcinit.c + * and tosh2450-smcinit.c. The table lists the device entries + * for ISA bridges with an LPC (Local Peripheral Configurator) + * that are in turn used to configure the SMSC device with default + * SIR and FIR I/O ports, DMA and IRQ. + */ +#ifdef CONFIG_PCI +#define PCIID_VENDOR_INTEL 0x8086 +#define PCIID_VENDOR_ALI 0x10b9 +static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __devinitdata = { + { + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ + .device = 0x24cc, + .subvendor = 0x103c, + .subdevice = 0x088c, + .sir_io = 0x02f8, /* Quite certain these are the same for nc8000 as for nc6000 */ + .fir_io = 0x0130, + .fir_irq = 0x09, + .fir_dma = 0x03, + .cfg_base = 0x004e, + .preconfigure = preconfigure_through_82801, + .name = "HP nc8000", + }, + { + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ + .device = 0x24cc, + .subvendor = 0x103c, + .subdevice = 0x0890, + .sir_io = 0x02f8, + .fir_io = 0x0130, + .fir_irq = 0x09, + .fir_dma = 0x03, + .cfg_base = 0x004e, + .preconfigure = preconfigure_through_82801, + .name = "HP nc6000", + }, + { + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ + .device = 0x24c0, + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ + .sir_io = 0x03f8, + .fir_io = 0x0130, + .fir_irq = 0x07, + .fir_dma = 0x01, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_82801, + .name = "Toshiba Satellite 2450", + }, + { + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */ + .device = 0x248c, /* Some use 24cc? */ + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ + .sir_io = 0x03f8, + .fir_io = 0x0130, + .fir_irq = 0x03, + .fir_dma = 0x03, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_82801, + .name = "Toshiba Satellite 5100/5200, Tecra 9100", + }, + { + .vendor = PCIID_VENDOR_ALI, /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ + .device = 0x1533, + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ + .sir_io = 0x02e8, + .fir_io = 0x02f8, + .fir_irq = 0x07, + .fir_dma = 0x03, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_ali, + .name = "Toshiba Satellite 1800", + }, + { } // Terminator +}; + + +/* + * This sets up the basic SMSC parameters (FIR port, SIR port, FIR DMA, FIR IRQ) + * through the chip configuration port. + */ +static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf) +{ + unsigned short iobase = conf->cfg_base; + unsigned char tmpbyte; + + outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state + outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID + tmpbyte = inb(iobase +1); // Read device ID + IRDA_DEBUG(0, "Detected Chip id: 0x%02x, setting up registers...\n",tmpbyte); + + /* Disable UART1 and set up SIR I/O port */ + outb(0x24, iobase); // select CR24 - UART1 base addr + outb(0x00, iobase + 1); // disable UART1 + outb(SMSCSIOFLAT_UART2BASEADDR_REG, iobase); // select CR25 - UART2 base addr + outb( (conf->sir_io >> 2), iobase + 1); // bits 2-9 of 0x3f8 + tmpbyte = inb(iobase + 1); + if (tmpbyte != (conf->sir_io >> 2) ) { + IRDA_WARNING("ERROR: could not configure SIR ioport.\n"); + return -ENXIO; + } + + /* Set up FIR IRQ channel for UART2 */ + outb(SMSCSIOFLAT_UARTIRQSELECT_REG, iobase); // select CR28 - UART1,2 IRQ select + tmpbyte = inb(iobase + 1); + tmpbyte &= SMSCSIOFLAT_UART1IRQSELECT_MASK; // Do not touch the UART1 portion + tmpbyte |= (conf->fir_irq & SMSCSIOFLAT_UART2IRQSELECT_MASK); + outb(tmpbyte, iobase + 1); + tmpbyte = inb(iobase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK; + if (tmpbyte != conf->fir_irq) { + IRDA_WARNING("ERROR: could not configure FIR IRQ channel.\n"); + return -ENXIO; + } + + /* Set up FIR I/O port */ + outb(SMSCSIOFLAT_FIRBASEADDR_REG, iobase); // CR2B - SCE (FIR) base addr + outb((conf->fir_io >> 3), iobase + 1); + tmpbyte = inb(iobase + 1); + if (tmpbyte != (conf->fir_io >> 3) ) { + IRDA_WARNING("ERROR: could not configure FIR I/O port.\n"); + return -ENXIO; + } + + /* Set up FIR DMA channel */ + outb(SMSCSIOFLAT_FIRDMASELECT_REG, iobase); // CR2C - SCE (FIR) DMA select + outb((conf->fir_dma & LPC47N227_FIRDMASELECT_MASK), iobase + 1); // DMA + tmpbyte = inb(iobase + 1) & LPC47N227_FIRDMASELECT_MASK; + if (tmpbyte != (conf->fir_dma & LPC47N227_FIRDMASELECT_MASK)) { + IRDA_WARNING("ERROR: could not configure FIR DMA channel.\n"); + return -ENXIO; + } + + outb(SMSCSIOFLAT_UARTMODE0C_REG, iobase); // CR0C - UART mode + tmpbyte = inb(iobase + 1); + tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | SMSCSIOFLAT_UART2MODE_VAL_IRDA; + outb(tmpbyte, iobase + 1); // enable IrDA (HPSIR) mode, high speed + + outb(LPC47N227_APMBOOTDRIVE_REG, iobase); // CR07 - Auto Pwr Mgt/boot drive sel + tmpbyte = inb(iobase + 1); + outb(tmpbyte | LPC47N227_UART2AUTOPWRDOWN_MASK, iobase + 1); // enable UART2 autopower down + + /* This one was not part of tosh1800 */ + outb(0x0a, iobase); // CR0a - ecp fifo / ir mux + tmpbyte = inb(iobase + 1); + outb(tmpbyte | 0x40, iobase + 1); // send active device to ir port + + outb(LPC47N227_UART12POWER_REG, iobase); // CR02 - UART 1,2 power + tmpbyte = inb(iobase + 1); + outb(tmpbyte | LPC47N227_UART2POWERDOWN_MASK, iobase + 1); // UART2 power up mode, UART1 power down + + outb(LPC47N227_FDCPOWERVALIDCONF_REG, iobase); // CR00 - FDC Power/valid config cycle + tmpbyte = inb(iobase + 1); + outb(tmpbyte | LPC47N227_VALID_MASK, iobase + 1); // valid config cycle done + + outb(LPC47N227_CFGEXITKEY, iobase); // Exit configuration + + return 0; +} + +/* 82801CAM registers */ +#define VID 0x00 +#define DID 0x02 +#define PIRQA_ROUT 0x60 +#define PCI_DMA_C 0x90 +#define COM_DEC 0xe0 +#define LPC_EN 0xe6 +#define GEN2_DEC 0xec +/* + * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge or + * Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. They all work the same way! + */ +static int __init preconfigure_through_82801(struct pci_dev *dev, + struct smsc_ircc_subsystem_configuration *conf) +{ + unsigned short tmpword; + int ret; + + IRDA_MESSAGE("Setting up the SMSC device via the 82801 controller.\n"); + pci_write_config_byte(dev, COM_DEC, 0x10); + + /* Enable LPC */ + pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */ + tmpword &= 0xfffd; /* mask bit 1 */ + tmpword |= 0x0001; /* set bit 0 : COMA addr range enable */ + pci_write_config_word(dev, LPC_EN, tmpword); + + /* Setup DMA */ + pci_write_config_word(dev, PCI_DMA_C, 0xc0c0); /* LPC I/F DMA on, channel 3 -- rtm (?? PCI DMA ?) */ + pci_write_config_word(dev, GEN2_DEC, 0x131); /* LPC I/F 2nd decode range */ + + /* Pre-configure chip */ + ret = preconfigure_smsc_chip(conf); + + /* Disable LPC */ + pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */ + tmpword &= 0xfffc; /* mask bit 1 and bit 0, COMA addr range disable */ + pci_write_config_word(dev, LPC_EN, tmpword); + return ret; +} + +static int __init preconfigure_through_ali(struct pci_dev *dev, + struct smsc_ircc_subsystem_configuration *conf) +{ + /* TODO: put in ALi 1533 configuration here. */ + IRDA_MESSAGE("SORRY: %s has an unsupported bridge controller (ALi): not pre-configured.\n", conf->name); + return -ENODEV; +} + +static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, + unsigned short ircc_fir, + unsigned short ircc_sir, + unsigned char ircc_dma, + unsigned char ircc_irq) +{ + struct pci_dev *dev = NULL; + unsigned short ss_vendor = 0x0000; + unsigned short ss_device = 0x0000; + int ret = 0; + + dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); + + while (dev != NULL) { + struct smsc_ircc_subsystem_configuration *conf; + + /* + * Cache the subsystem vendor/device: some manufacturers fail to set + * this for all components, so we save it in case there is just + * 0x0000 0x0000 on the device we want to check. + */ + if (dev->subsystem_vendor != 0x0000U) { + ss_vendor = dev->subsystem_vendor; + ss_device = dev->subsystem_device; + } + conf = subsystem_configurations; + for( ; conf->subvendor; conf++) { + if(conf->vendor == dev->vendor && + conf->device == dev->device && + conf->subvendor == ss_vendor && /* Sometimes these are cached values */ + (conf->subdevice == ss_device || conf->subdevice == 0xffff)) { + struct smsc_ircc_subsystem_configuration tmpconf; + + memcpy(&tmpconf, conf, sizeof(struct smsc_ircc_subsystem_configuration)); + + /* Override the default values with anything passed in as parameter */ + if (ircc_cfg != 0) + tmpconf.cfg_base = ircc_cfg; + if (ircc_fir != 0) + tmpconf.fir_io = ircc_fir; + if (ircc_sir != 0) + tmpconf.sir_io = ircc_sir; + if (ircc_dma != 0xff) + tmpconf.fir_dma = ircc_dma; + if (ircc_irq != 0xff) + tmpconf.fir_irq = ircc_irq; + + IRDA_MESSAGE("Detected unconfigured %s SMSC IrDA chip, pre-configuring device.\n", conf->name); + if (conf->preconfigure) + ret = conf->preconfigure(dev, &tmpconf); + else + ret = -ENODEV; + } + } + dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); + } + + return ret; +} +#endif // CONFIG_PCI + /************************************************ * * Transceivers specific functions -- cgit v1.1 From 137dc0233fba0bfa19679bdd96eb104f0e659c5a Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 5 Apr 2006 22:39:14 -0700 Subject: [IRDA]: Support for Sigmatel STIR421x chip This patch enables support for the Sigmatel's STIR421x IrDA chip. Once patched with Sigmatel's firmware, this chip "almost" follows the USB-IrDA spec. Thus this patch is against irda-usb.[ch]. The code has been tested by Nick Fedchik on an STIR4210 chipset based dongle. Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/irda-usb.c | 363 +++++++++++++++++++++++++++++++++++++++++--- drivers/net/irda/irda-usb.h | 43 ++++-- 2 files changed, 372 insertions(+), 34 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 6e2ec56..606243d 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -1,7 +1,7 @@ /***************************************************************************** * * Filename: irda-usb.c - * Version: 0.9b + * Version: 0.10 * Description: IrDA-USB Driver * Status: Experimental * Author: Dag Brattli @@ -9,6 +9,9 @@ * Copyright (C) 2000, Roman Weissgaerber * Copyright (C) 2001, Dag Brattli * Copyright (C) 2001, Jean Tourrilhes + * Copyright (C) 2004, SigmaTel, Inc. + * Copyright (C) 2005, Milan Beno + * Copyright (C) 2006, Nick Fedchik * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -61,6 +64,7 @@ #include #include #include +#include #include "irda-usb.h" @@ -78,8 +82,12 @@ static struct usb_device_id dongles[] = { { USB_DEVICE(0x50f, 0x180), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW }, /* Extended Systems, Inc., XTNDAccess IrDA USB (ESI-9685) */ { USB_DEVICE(0x8e9, 0x100), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW }, + /* SigmaTel STIR4210/4220/4116 USB IrDA (VFIR) Bridge */ + { USB_DEVICE(0x66f, 0x4210), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG }, + { USB_DEVICE(0x66f, 0x4220), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG }, + { USB_DEVICE(0x66f, 0x4116), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG }, { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | - USB_DEVICE_ID_MATCH_INT_SUBCLASS, + USB_DEVICE_ID_MATCH_INT_SUBCLASS, .bInterfaceClass = USB_CLASS_APP_SPEC, .bInterfaceSubClass = USB_CLASS_IRDA, .driver_info = IUC_DEFAULT, }, @@ -99,6 +107,7 @@ MODULE_DEVICE_TABLE(usb, dongles); /*------------------------------------------------------------------*/ +static void irda_usb_init_qos(struct irda_usb_cb *self) ; static struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf); static void irda_usb_disconnect(struct usb_interface *intf); static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self); @@ -141,7 +150,24 @@ static void irda_usb_build_header(struct irda_usb_cb *self, __u8 *header, int force) { - /* Set the negotiated link speed */ + /* Here we check if we have an STIR421x chip, + * and if either speed or xbofs (or both) needs + * to be changed. + */ + if (self->capability & IUC_STIR_4210 && + ((self->new_speed != -1) || (self->new_xbofs != -1))) { + + /* With STIR421x, speed and xBOFs must be set at the same + * time, even if only one of them changes. + */ + if (self->new_speed == -1) + self->new_speed = self->speed ; + + if (self->new_xbofs == -1) + self->new_xbofs = self->xbofs ; + } + + /* Set the link speed */ if (self->new_speed != -1) { /* Hum... Ugly hack :-( * Some device are not compliant with the spec and change @@ -191,7 +217,11 @@ static void irda_usb_build_header(struct irda_usb_cb *self, *header = SPEED_4000000; self->new_xbofs = 0; break; - } + case 16000000: + *header = SPEED_16000000; + self->new_xbofs = 0; + break; + } } else /* No change */ *header = 0; @@ -235,6 +265,32 @@ static void irda_usb_build_header(struct irda_usb_cb *self, } } +/* +* calculate turnaround time for SigmaTel header +*/ +static __u8 get_turnaround_time(struct sk_buff *skb) +{ + int turnaround_time = irda_get_mtt(skb); + + if ( turnaround_time == 0 ) + return 0; + else if ( turnaround_time <= 10 ) + return 1; + else if ( turnaround_time <= 50 ) + return 2; + else if ( turnaround_time <= 100 ) + return 3; + else if ( turnaround_time <= 500 ) + return 4; + else if ( turnaround_time <= 1000 ) + return 5; + else if ( turnaround_time <= 5000 ) + return 6; + else + return 7; +} + + /*------------------------------------------------------------------*/ /* * Send a command to change the speed of the dongle @@ -262,12 +318,18 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self) /* Set the new speed and xbofs in this fake frame */ irda_usb_build_header(self, frame, 1); + if ( self->capability & IUC_STIR_4210 ) { + if (frame[0] == 0) return ; // do nothing if no change + frame[1] = 0; // other parameters don't change here + frame[2] = 0; + } + /* Submit the 0 length IrDA frame to trigger new speed settings */ usb_fill_bulk_urb(urb, self->usbdev, usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), frame, IRDA_USB_SPEED_MTU, speed_bulk_callback, self); - urb->transfer_buffer_length = USB_IRDA_HEADER; + urb->transfer_buffer_length = self->header_length; urb->transfer_flags = 0; /* Irq disabled -> GFP_ATOMIC */ @@ -383,16 +445,35 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) * allocation will be done lower in skb_push(). * Also, we don't use directly skb_cow(), because it require * headroom >= 16, which force unnecessary copies - Jean II */ - if (skb_headroom(skb) < USB_IRDA_HEADER) { + if (skb_headroom(skb) < self->header_length) { IRDA_DEBUG(0, "%s(), Insuficient skb headroom.\n", __FUNCTION__); - if (skb_cow(skb, USB_IRDA_HEADER)) { + if (skb_cow(skb, self->header_length)) { IRDA_WARNING("%s(), failed skb_cow() !!!\n", __FUNCTION__); goto drop; } } /* Change setting for next frame */ - irda_usb_build_header(self, skb_push(skb, USB_IRDA_HEADER), 0); + + if ( self->capability & IUC_STIR_4210 ) { + __u8 turnaround_time; + __u8* frame; + turnaround_time = get_turnaround_time( skb ); + frame= skb_push(skb, self->header_length); + irda_usb_build_header(self, frame, 0); + frame[2] = turnaround_time; + if ((skb->len != 0) && + ((skb->len % 128) == 0) && + ((skb->len % 512) != 0)) { + /* add extra byte for special SigmaTel feature */ + frame[1] = 1; + skb_put(skb, 1); + } else { + frame[1] = 0; + } + } else { + irda_usb_build_header(self, skb_push(skb, self->header_length), 0); + } /* FIXME: Make macro out of this one */ ((struct irda_skb_cb *)skb->cb)->context = self; @@ -795,7 +876,7 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) } /* Check for empty frames */ - if (urb->actual_length <= USB_IRDA_HEADER) { + if (urb->actual_length <= self->header_length) { IRDA_WARNING("%s(), empty frame!\n", __FUNCTION__); goto done; } @@ -816,7 +897,11 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) docopy = (urb->actual_length < IRDA_RX_COPY_THRESHOLD); /* Allocate a new skb */ - newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU); + if ( self->capability & IUC_STIR_4210 ) + newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU + USB_IRDA_SIGMATEL_HEADER); + else + newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU); + if (!newskb) { self->stats.rx_dropped++; /* We could deliver the current skb, but this would stall @@ -845,7 +930,7 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) /* Set proper length on skb & remove USB-IrDA header */ skb_put(dataskb, urb->actual_length); - skb_pull(dataskb, USB_IRDA_HEADER); + skb_pull(dataskb, self->header_length); /* Ask the networking layer to queue the packet for the IrDA stack */ dataskb->dev = self->netdev; @@ -937,6 +1022,191 @@ static int irda_usb_is_receiving(struct irda_usb_cb *self) return 0; /* For now */ } + +#define STIR421X_PATCH_PRODUCT_VERSION_STR "Product Version: " +#define STIR421X_PATCH_COMPONENT_VERSION_STR "Component Version: " +#define STIR421X_PATCH_DATA_TAG_STR "STMP" +#define STIR421X_PATCH_FILE_VERSION_MAX_OFFSET 512 /* version info is before here */ +#define STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET 512 /* patch image starts before here */ +#define STIR421X_PATCH_FILE_END_OF_HEADER_TAG 0x1A /* marks end of patch file header (PC DOS text file EOF character) */ + +/* + * Known firmware patches for STIR421x dongles + */ +static char * stir421x_patches[] = { + "42101001.sb", + "42101002.sb", +}; + +static int stir421x_get_patch_version(unsigned char * patch, const unsigned long patch_len) +{ + unsigned int version_offset; + unsigned long version_major, version_minor, version_build; + unsigned char * version_start; + int version_found = 0; + + for (version_offset = 0; + version_offset < STIR421X_PATCH_FILE_END_OF_HEADER_TAG; + version_offset++) { + if (!memcmp(patch + version_offset, + STIR421X_PATCH_PRODUCT_VERSION_STR, + sizeof(STIR421X_PATCH_PRODUCT_VERSION_STR) - 1)) { + version_found = 1; + version_start = patch + + version_offset + + sizeof(STIR421X_PATCH_PRODUCT_VERSION_STR) - 1; + break; + } + } + + /* We couldn't find a product version on this patch */ + if (!version_found) + return -EINVAL; + + /* Let's check if the product version is dotted */ + if (version_start[3] != '.' || + version_start[7] != '.') + return -EINVAL; + + version_major = simple_strtoul(version_start, NULL, 10); + version_minor = simple_strtoul(version_start + 4, NULL, 10); + version_build = simple_strtoul(version_start + 8, NULL, 10); + + IRDA_DEBUG(2, "%s(), Major: %ld Minor: %ld Build: %ld\n", + __FUNCTION__, + version_major, version_minor, version_build); + + return (((version_major) << 12) + + ((version_minor) << 8) + + ((version_build / 10) << 4) + + (version_build % 10)); + +} + + +static int stir421x_upload_patch (struct irda_usb_cb *self, + unsigned char * patch, + const unsigned int patch_len) +{ + int retval = 0; + int actual_len; + unsigned int i = 0, download_amount = 0; + unsigned char * patch_chunk; + + IRDA_DEBUG (2, "%s(), Uploading STIR421x Patch\n", __FUNCTION__); + + patch_chunk = kzalloc(STIR421X_MAX_PATCH_DOWNLOAD_SIZE, GFP_KERNEL); + if (patch_chunk == NULL) + return -ENOMEM; + + /* break up patch into 1023-byte sections */ + for (i = 0; retval >= 0 && i < patch_len; i += download_amount) { + download_amount = patch_len - i; + if (download_amount > STIR421X_MAX_PATCH_DOWNLOAD_SIZE) + download_amount = STIR421X_MAX_PATCH_DOWNLOAD_SIZE; + + /* download the patch section */ + memcpy(patch_chunk, patch + i, download_amount); + + retval = usb_bulk_msg (self->usbdev, + usb_sndbulkpipe (self->usbdev, + self->bulk_out_ep), + patch_chunk, download_amount, + &actual_len, msecs_to_jiffies (500)); + IRDA_DEBUG (2, "%s(), Sent %u bytes\n", __FUNCTION__, + actual_len); + if (retval == 0) + mdelay(10); + } + + kfree(patch_chunk); + + if (i != patch_len) { + IRDA_ERROR ("%s(), Pushed %d bytes (!= patch_len (%d))\n", + __FUNCTION__, i, patch_len); + retval = -EIO; + } + + if (retval < 0) + /* todo - mark device as not ready */ + IRDA_ERROR ("%s(), STIR421x patch upload failed (%d)\n", + __FUNCTION__, retval); + + return retval; +} + + +static int stir421x_patch_device(struct irda_usb_cb *self) +{ + unsigned int i, patch_found = 0, data_found = 0, data_offset; + int patch_version, ret = 0; + const struct firmware *fw_entry; + + for (i = 0; i < ARRAY_SIZE(stir421x_patches); i++) { + if(request_firmware(&fw_entry, stir421x_patches[i], &self->usbdev->dev) != 0) { + IRDA_ERROR( "%s(), Patch %s is not available\n", __FUNCTION__, stir421x_patches[i]); + continue; + } + + /* We found a patch from userspace */ + patch_version = stir421x_get_patch_version (fw_entry->data, fw_entry->size); + + if (patch_version < 0) { + /* Couldn't fetch a version, let's move on to the next file */ + IRDA_ERROR("%s(), version parsing failed\n", __FUNCTION__); + ret = patch_version; + release_firmware(fw_entry); + continue; + } + + if (patch_version != self->usbdev->descriptor.bcdDevice) { + /* Patch version and device don't match */ + IRDA_ERROR ("%s(), wrong patch version (%d <-> %d)\n", + __FUNCTION__, + patch_version, self->usbdev->descriptor.bcdDevice); + ret = -EINVAL; + release_firmware(fw_entry); + continue; + } + + /* If we're here, we've found a correct patch */ + patch_found = 1; + break; + + } + + /* We couldn't find a valid firmware, let's leave */ + if (!patch_found) + return ret; + + /* The actual image starts after the "STMP" keyword */ + for (data_offset = 0; data_offset < STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET; data_offset++) { + if (!memcmp(fw_entry->data + data_offset, + STIR421X_PATCH_DATA_TAG_STR, + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET))) { + IRDA_DEBUG(2, "%s(), found patch data for STIR421x at offset %d\n", + __FUNCTION__, data_offset); + data_found = 1; + break; + } + } + + /* We couldn't find "STMP" from the header */ + if (!data_found) + return -EINVAL; + + /* Let's upload the patch to the target */ + ret = stir421x_upload_patch(self, + &fw_entry->data[data_offset + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET)], + fw_entry->size - (data_offset + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET))); + + release_firmware(fw_entry); + + return ret; + +} + + /********************** IRDA DEVICE CALLBACKS **********************/ /* * Main calls from the IrDA/Network subsystem. @@ -972,6 +1242,11 @@ static int irda_usb_net_open(struct net_device *netdev) return -1; } + if(self->needspatch) { + IRDA_WARNING("%s(), device needs patch\n", __FUNCTION__) ; + return -EIO ; + } + /* Initialise default speed and xbofs value * (IrLAP will change that soon) */ self->speed = -1; @@ -1050,7 +1325,7 @@ static int irda_usb_net_close(struct net_device *netdev) del_timer(&self->rx_defer_timer); /* Deallocate all the Rx path buffers (URBs and skb) */ - for (i = 0; i < IU_MAX_RX_URBS; i++) { + for (i = 0; i < self->max_rx_urb; i++) { struct urb *urb = self->rx_urb[i]; struct sk_buff *skb = (struct sk_buff *) urb->context; /* Cancel the receive command */ @@ -1426,8 +1701,22 @@ static int irda_usb_probe(struct usb_interface *intf, spin_lock_init(&self->lock); init_timer(&self->rx_defer_timer); + self->capability = id->driver_info; + self->needspatch = ((self->capability & IUC_STIR_4210) != 0) ; + /* Create all of the needed urbs */ - for (i = 0; i < IU_MAX_RX_URBS; i++) { + if (self->capability & IUC_STIR_4210) { + self->max_rx_urb = IU_SIGMATEL_MAX_RX_URBS; + self->header_length = USB_IRDA_SIGMATEL_HEADER; + } else { + self->max_rx_urb = IU_MAX_RX_URBS; + self->header_length = USB_IRDA_HEADER; + } + + self->rx_urb = kzalloc(self->max_rx_urb * sizeof(struct urb *), + GFP_KERNEL); + + for (i = 0; i < self->max_rx_urb; i++) { self->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL); if (!self->rx_urb[i]) { goto err_out_1; @@ -1479,17 +1768,28 @@ static int irda_usb_probe(struct usb_interface *intf, goto err_out_3; } + self->usbdev = dev; + /* Find IrDA class descriptor */ irda_desc = irda_usb_find_class_desc(intf); ret = -ENODEV; if (irda_desc == NULL) goto err_out_3; + if (self->needspatch) { + ret = usb_control_msg (self->usbdev, usb_sndctrlpipe (self->usbdev, 0), + 0x02, 0x40, 0, 0, 0, 0, msecs_to_jiffies(500)); + if (ret < 0) { + IRDA_DEBUG (0, "usb_control_msg failed %d\n", ret); + goto err_out_3; + } else { + mdelay(10); + } + } + self->irda_desc = irda_desc; self->present = 1; self->netopen = 0; - self->capability = id->driver_info; - self->usbdev = dev; self->usbintf = intf; /* Allocate the buffer for speed changes */ @@ -1508,6 +1808,28 @@ static int irda_usb_probe(struct usb_interface *intf, IRDA_MESSAGE("IrDA: Registered device %s\n", net->name); usb_set_intfdata(intf, self); + + if (self->needspatch) { + /* Now we fetch and upload the firmware patch */ + ret = stir421x_patch_device(self); + self->needspatch = (ret < 0); + if (ret < 0) { + printk("patch_device failed\n"); + goto err_out_4; + } + + /* replace IrDA class descriptor with what patched device is now reporting */ + irda_desc = irda_usb_find_class_desc (self->usbintf); + if (irda_desc == NULL) { + ret = -ENODEV; + goto err_out_4; + } + if (self->irda_desc) + kfree (self->irda_desc); + self->irda_desc = irda_desc; + irda_usb_init_qos(self); + } + return 0; err_out_4: @@ -1518,7 +1840,7 @@ err_out_3: err_out_2: usb_free_urb(self->tx_urb); err_out_1: - for (i = 0; i < IU_MAX_RX_URBS; i++) { + for (i = 0; i < self->max_rx_urb; i++) { if (self->rx_urb[i]) usb_free_urb(self->rx_urb[i]); } @@ -1571,7 +1893,7 @@ static void irda_usb_disconnect(struct usb_interface *intf) /*netif_device_detach(self->netdev);*/ netif_stop_queue(self->netdev); /* Stop all the receive URBs. Must be synchronous. */ - for (i = 0; i < IU_MAX_RX_URBS; i++) + for (i = 0; i < self->max_rx_urb; i++) usb_kill_urb(self->rx_urb[i]); /* Cancel Tx and speed URB. * Make sure it's synchronous to avoid races. */ @@ -1586,8 +1908,9 @@ static void irda_usb_disconnect(struct usb_interface *intf) self->usbintf = NULL; /* Clean up our urbs */ - for (i = 0; i < IU_MAX_RX_URBS; i++) + for (i = 0; i < self->max_rx_urb; i++) usb_free_urb(self->rx_urb[i]); + kfree(self->rx_urb); /* Clean up Tx and speed URB */ usb_free_urb(self->tx_urb); usb_free_urb(self->speed_urb); @@ -1648,6 +1971,6 @@ module_exit(usb_irda_cleanup); */ module_param(qos_mtt_bits, int, 0); MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); -MODULE_AUTHOR("Roman Weissgaerber , Dag Brattli and Jean Tourrilhes "); -MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); +MODULE_AUTHOR("Roman Weissgaerber , Dag Brattli , Jean Tourrilhes and Nick Fedchik "); +MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h index 4026af4..d833db5 100644 --- a/drivers/net/irda/irda-usb.h +++ b/drivers/net/irda/irda-usb.h @@ -1,7 +1,7 @@ /***************************************************************************** * * Filename: irda-usb.h - * Version: 0.9b + * Version: 0.10 * Description: IrDA-USB Driver * Status: Experimental * Author: Dag Brattli @@ -9,6 +9,9 @@ * Copyright (C) 2001, Roman Weissgaerber * Copyright (C) 2000, Dag Brattli * Copyright (C) 2001, Jean Tourrilhes + * Copyright (C) 2004, SigmaTel, Inc. + * Copyright (C) 2005, Milan Beno + * Copyright (C) 2006, Nick FEdchik * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,6 +34,9 @@ #include #include /* struct irlap_cb */ +#define PATCH_FILE_SIZE_MAX 65536 +#define PATCH_FILE_SIZE_MIN 80 + #define RX_COPY_THRESHOLD 200 #define IRDA_USB_MAX_MTU 2051 #define IRDA_USB_SPEED_MTU 64 /* Weird, but work like this */ @@ -79,15 +85,16 @@ /* Inbound header */ #define MEDIA_BUSY 0x80 -#define SPEED_2400 0x01 -#define SPEED_9600 0x02 -#define SPEED_19200 0x03 -#define SPEED_38400 0x04 -#define SPEED_57600 0x05 -#define SPEED_115200 0x06 -#define SPEED_576000 0x07 -#define SPEED_1152000 0x08 -#define SPEED_4000000 0x09 +#define SPEED_2400 0x01 +#define SPEED_9600 0x02 +#define SPEED_19200 0x03 +#define SPEED_38400 0x04 +#define SPEED_57600 0x05 +#define SPEED_115200 0x06 +#define SPEED_576000 0x07 +#define SPEED_1152000 0x08 +#define SPEED_4000000 0x09 +#define SPEED_16000000 0x0a /* Basic capabilities */ #define IUC_DEFAULT 0x00 /* Basic device compliant with 1.0 spec */ @@ -100,11 +107,14 @@ #define IUC_SMALL_PKT 0x10 /* Device doesn't behave with big Rx packets */ #define IUC_MAX_WINDOW 0x20 /* Device underestimate the Rx window */ #define IUC_MAX_XBOFS 0x40 /* Device need more xbofs than advertised */ +#define IUC_STIR_4210 0x80 /* SigmaTel 4210/4220/4116 VFIR */ /* USB class definitions */ -#define USB_IRDA_HEADER 0x01 -#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */ -#define USB_DT_IRDA 0x21 +#define USB_IRDA_HEADER 0x01 +#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */ +#define USB_DT_IRDA 0x21 +#define USB_IRDA_SIGMATEL_HEADER 0x03 +#define IU_SIGMATEL_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + USB_IRDA_SIGMATEL_HEADER) struct irda_class_desc { __u8 bLength; @@ -123,6 +133,7 @@ struct irda_class_desc { * (6.2.5, USB-IrDA class spec 1.0) */ #define IU_REQ_GET_CLASS_DESC 0x06 +#define STIR421X_MAX_PATCH_DOWNLOAD_SIZE 1023 struct irda_usb_cb { struct irda_class_desc *irda_desc; @@ -136,7 +147,8 @@ struct irda_usb_cb { __u16 bulk_out_mtu; /* Max Tx packet size in bytes */ __u8 bulk_int_ep; /* Interrupt Endpoint assignments */ - struct urb *rx_urb[IU_MAX_RX_URBS]; /* URBs used to receive data frames */ + __u8 max_rx_urb; + struct urb **rx_urb; /* URBs used to receive data frames */ struct urb *idle_rx_urb; /* Pointer to idle URB in Rx path */ struct urb *tx_urb; /* URB used to send data frames */ struct urb *speed_urb; /* URB used to send speed commands */ @@ -157,6 +169,9 @@ struct irda_usb_cb { __u32 speed; /* Current speed */ __s32 new_speed; /* speed we need to set */ + __u8 header_length; /* USB-IrDA frame header size */ + int needspatch; /* device needs firmware patch */ + struct timer_list rx_defer_timer; /* Wait for Rx error to clear */ }; -- cgit v1.1 From d2d746f83b74022a50d28f7f0f496842c9cde330 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 6 Apr 2006 21:45:39 -0700 Subject: [TG3]: Kill some less useful flags Kill the TG3_FLAG_NO_{TX|RX}_PSEUDO_CSUM flags because they are not very useful. This will free up some bits for new flags. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 21 ++++++++------------- drivers/net/tg3.h | 2 -- 2 files changed, 8 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index d6047bd..376d8e7 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5828,10 +5828,14 @@ static int tg3_reset_hw(struct tg3 *tp) GRC_MODE_NO_TX_PHDR_CSUM | GRC_MODE_NO_RX_PHDR_CSUM); tp->grc_mode |= GRC_MODE_HOST_SENDBDS; - if (tp->tg3_flags & TG3_FLAG_NO_TX_PSEUDO_CSUM) - tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM; - if (tp->tg3_flags & TG3_FLAG_NO_RX_PSEUDO_CSUM) - tp->grc_mode |= GRC_MODE_NO_RX_PHDR_CSUM; + + /* Pseudo-header checksum is done by hardware logic and not + * the offload processers, so make the chip do the pseudo- + * header checksums on receive. For transmit it is more + * convenient to do the pseudo-header checksum in software + * as Linux does that on transmit for us in all cases. + */ + tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM; tw32(GRC_MODE, tp->grc_mode | @@ -10303,15 +10307,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0) tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS; - /* Pseudo-header checksum is done by hardware logic and not - * the offload processers, so make the chip do the pseudo- - * header checksums on receive. For transmit it is more - * convenient to do the pseudo-header checksum in software - * as Linux does that on transmit for us in all cases. - */ - tp->tg3_flags |= TG3_FLAG_NO_TX_PSEUDO_CSUM; - tp->tg3_flags &= ~TG3_FLAG_NO_RX_PSEUDO_CSUM; - /* Derive initial jumbo mode from MTU assigned in * ether_setup() via the alloc_etherdev() call */ diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index c43cc32..b648442 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2171,8 +2171,6 @@ struct tg3 { #define TG3_FLAG_PCIX_MODE 0x00020000 #define TG3_FLAG_PCI_HIGH_SPEED 0x00040000 #define TG3_FLAG_PCI_32BIT 0x00080000 -#define TG3_FLAG_NO_TX_PSEUDO_CSUM 0x00100000 -#define TG3_FLAG_NO_RX_PSEUDO_CSUM 0x00200000 #define TG3_FLAG_SERDES_WOL_CAP 0x00400000 #define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000 #define TG3_FLAG_10_100_ONLY 0x01000000 -- cgit v1.1 From bbadf503d7c7e6efe0a4cd731f8855ba08276215 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 6 Apr 2006 21:46:34 -0700 Subject: [TG3]: Speed up SRAM access (2nd version) Speed up SRAM read and write functions if possible by using MMIO instead of config. cycles. With this change, the post reset signature done at the end of D3 power change must now be moved before the D3 power change. IBM reported a problem on powerpc blades during ethtool self test that was caused by the memory test taking excessively long. Config. cycles are very slow on powerpc and the memory test can take more than 10 seconds to complete using config. cycles. David Miller informed me that an earlier version of the patch caused problems on sparc64 systems with built-in tg3 chips. This version fixes the problem by excluding all SUN built-in tg3 chips from doing MMIO SRAM access. TG3_FLAG_EEPROM_WRITE_PROT is also set unconditionally when TG3_FLG2_SUN_570X is set. This should be sane as all SUN chips are built-in and do not require Vaux switching. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 69 +++++++++++++++++++++++++++++++++---------------------- drivers/net/tg3.h | 1 + 2 files changed, 43 insertions(+), 27 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 376d8e7..73e271e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -497,21 +497,20 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val) unsigned long flags; spin_lock_irqsave(&tp->indirect_lock, flags); - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); + if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) { + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); - /* Always leave this as zero. */ - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); - spin_unlock_irqrestore(&tp->indirect_lock, flags); -} + /* Always leave this as zero. */ + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); + } else { + tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off); + tw32_f(TG3PCI_MEM_WIN_DATA, val); -static void tg3_write_mem_fast(struct tg3 *tp, u32 off, u32 val) -{ - /* If no workaround is needed, write to mem space directly */ - if (tp->write32 != tg3_write_indirect_reg32) - tw32(NIC_SRAM_WIN_BASE + off, val); - else - tg3_write_mem(tp, off, val); + /* Always leave this as zero. */ + tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0); + } + spin_unlock_irqrestore(&tp->indirect_lock, flags); } static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) @@ -519,11 +518,19 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) unsigned long flags; spin_lock_irqsave(&tp->indirect_lock, flags); - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); - pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); + if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) { + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); + pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); - /* Always leave this as zero. */ - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); + /* Always leave this as zero. */ + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); + } else { + tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off); + *val = tr32(TG3PCI_MEM_WIN_DATA); + + /* Always leave this as zero. */ + tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0); + } spin_unlock_irqrestore(&tp->indirect_lock, flags); } @@ -1367,12 +1374,12 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) } } + tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN); + /* Finally, set the new power state. */ pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control); udelay(100); /* Delay after power state change */ - tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN); - return 0; } @@ -6539,11 +6546,11 @@ static void tg3_timer(unsigned long __opaque) if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { u32 val; - tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_MBOX, - FWCMD_NICDRV_ALIVE2); - tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, + FWCMD_NICDRV_ALIVE2); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); /* 5 seconds timeout */ - tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5); val = tr32(GRC_RX_CPU_EVENT); val |= (1 << 14); tw32(GRC_RX_CPU_EVENT, val); @@ -9539,8 +9546,11 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->led_ctrl = LED_CTRL_MODE_PHY_1; /* Do not even try poking around in here on Sun parts. */ - if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) + if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) { + /* All SUN chips are built-in LOMs. */ + tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT; return; + } tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); if (val == NIC_SRAM_DATA_SIG_MAGIC) { @@ -9638,9 +9648,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL) tp->led_ctrl = LED_CTRL_MODE_PHY_2; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) && - (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP)) + if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP) tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT; if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) { @@ -10265,6 +10273,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd); } + if (tp->write32 == tg3_write_indirect_reg32 || + ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) && + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) || + (tp->tg3_flags2 & TG3_FLG2_SUN_570X)) + tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG; + /* Get eeprom hw config before calling tg3_set_power_state(). * In particular, the TG3_FLAG_EEPROM_WRITE_PROT flag must be * determined before calling tg3_set_power_state() so that diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index b648442..8c8b987 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2171,6 +2171,7 @@ struct tg3 { #define TG3_FLAG_PCIX_MODE 0x00020000 #define TG3_FLAG_PCI_HIGH_SPEED 0x00040000 #define TG3_FLAG_PCI_32BIT 0x00080000 +#define TG3_FLAG_SRAM_USE_CONFIG 0x00100000 #define TG3_FLAG_SERDES_WOL_CAP 0x00400000 #define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000 #define TG3_FLAG_10_100_ONLY 0x01000000 -- cgit v1.1 From 8db60bcf3021921e2d10d158641792d640e52fe8 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 11 Apr 2006 17:28:33 -0700 Subject: [WAN]: Remove broken and unmaintained Sangoma drivers. The in-kernel Sangoma drivers are both not compiling and marked as BROKEN since at least kernel 2.6.0. Sangoma offers out-of-tree drivers, and David Mandelstam told me Sangoma does no longer maintain the in-kernel drivers and prefers to provide them as a separate installation package. This patch therefore removes these drivers. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/wan/Kconfig | 97 - drivers/net/wan/Makefile | 13 - drivers/net/wan/sdla_chdlc.c | 4428 ----------------------------- drivers/net/wan/sdla_fr.c | 5061 ---------------------------------- drivers/net/wan/sdla_ft1.c | 345 --- drivers/net/wan/sdla_ppp.c | 3430 ----------------------- drivers/net/wan/sdla_x25.c | 5497 ------------------------------------- drivers/net/wan/sdladrv.c | 2314 ---------------- drivers/net/wan/sdlamain.c | 1346 --------- drivers/net/wan/wanpipe_multppp.c | 2358 ---------------- 10 files changed, 24889 deletions(-) delete mode 100644 drivers/net/wan/sdla_chdlc.c delete mode 100644 drivers/net/wan/sdla_fr.c delete mode 100644 drivers/net/wan/sdla_ft1.c delete mode 100644 drivers/net/wan/sdla_ppp.c delete mode 100644 drivers/net/wan/sdla_x25.c delete mode 100644 drivers/net/wan/sdladrv.c delete mode 100644 drivers/net/wan/sdlamain.c delete mode 100644 drivers/net/wan/wanpipe_multppp.c (limited to 'drivers/net') diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 883cf7d..b5328b0 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -410,103 +410,6 @@ config WAN_ROUTER_DRIVERS If unsure, say N. -config VENDOR_SANGOMA - tristate "Sangoma WANPIPE(tm) multiprotocol cards" - depends on WAN_ROUTER_DRIVERS && WAN_ROUTER && (PCI || ISA) && BROKEN - ---help--- - Driver for S514-PCI/ISA Synchronous Data Link Adapters (SDLA). - - WANPIPE from Sangoma Technologies Inc. - is a family of intelligent multiprotocol WAN adapters with data - transfer rates up to 4Mbps. Cards support: - - - X.25, Frame Relay, PPP, Cisco HDLC protocols. - - - API for protocols like HDLC (LAPB), HDLC Streaming, X.25, - Frame Relay and BiSync. - - - Ethernet Bridging over Frame Relay protocol. - - - MULTILINK PPP - - - Async PPP (Modem Dialup) - - The next questions will ask you about the protocols you want - the driver to support. - - If you have one or more of these cards, say M to this option; - and read . - - To compile this driver as a module, choose M here: the - module will be called wanpipe. - -config WANPIPE_CHDLC - bool "WANPIPE Cisco HDLC support" - depends on VENDOR_SANGOMA - ---help--- - Connect a WANPIPE card to a leased line using the Cisco HDLC. - - - Supports Dual Port Cisco HDLC on the S514-PCI/S508-ISA cards - which allows user to build applications using the HDLC streaming API. - - - CHDLC Streaming MULTILINK PPP that can bind multiple WANPIPE T1 - cards into a single logical channel. - - Say Y and the Cisco HDLC support, HDLC streaming API and - MULTILINK PPP will be included in the driver. - -config WANPIPE_FR - bool "WANPIPE Frame Relay support" - depends on VENDOR_SANGOMA - help - Connect a WANPIPE card to a Frame Relay network, or use Frame Relay - API to develop custom applications. - - Contains the Ethernet Bridging over Frame Relay feature, where - a WANPIPE frame relay link can be directly connected to the Linux - kernel bridge. The Frame Relay option is supported on S514-PCI - and S508-ISA cards. - - Say Y and the Frame Relay support will be included in the driver. - -config WANPIPE_X25 - bool "WANPIPE X.25 support" - depends on VENDOR_SANGOMA - help - Connect a WANPIPE card to an X.25 network. - - Includes the X.25 API support for custom applications over the - X.25 protocol. The X.25 option is supported on S514-PCI and - S508-ISA cards. - - Say Y and the X.25 support will be included in the driver. - -config WANPIPE_PPP - bool "WANPIPE PPP support" - depends on VENDOR_SANGOMA - help - Connect a WANPIPE card to a leased line using Point-to-Point - Protocol (PPP). - - The PPP option is supported on S514-PCI/S508-ISA cards. - - Say Y and the PPP support will be included in the driver. - -config WANPIPE_MULTPPP - bool "WANPIPE Multi-Port PPP support" - depends on VENDOR_SANGOMA - help - Connect a WANPIPE card to a leased line using Point-to-Point - Protocol (PPP). - - Uses in-kernel SyncPPP protocol over the Sangoma HDLC Streaming - adapter. In this case each Sangoma adapter port can support an - independent PPP connection. For example, a single Quad-Port PCI - adapter can support up to four independent PPP links. The PPP - option is supported on S514-PCI/S508-ISA cards. - - Say Y and the Multi-Port PPP support will be included in the driver. - config CYCLADES_SYNC tristate "Cyclom 2X(tm) cards (EXPERIMENTAL)" depends on WAN_ROUTER_DRIVERS && (PCI || ISA) diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index ce6c56b..823c6d5 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -5,14 +5,6 @@ # Rewritten to use lists instead of if-statements. # -wanpipe-y := sdlamain.o sdla_ft1.o -wanpipe-$(CONFIG_WANPIPE_X25) += sdla_x25.o -wanpipe-$(CONFIG_WANPIPE_FR) += sdla_fr.o -wanpipe-$(CONFIG_WANPIPE_CHDLC) += sdla_chdlc.o -wanpipe-$(CONFIG_WANPIPE_PPP) += sdla_ppp.o -wanpipe-$(CONFIG_WANPIPE_MULTPPP) += wanpipe_multppp.o -wanpipe-objs := $(wanpipe-y) - cyclomx-y := cycx_main.o cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o cyclomx-objs := $(cyclomx-y) @@ -43,11 +35,6 @@ obj-$(CONFIG_LANMEDIA) += lmc/ obj-$(CONFIG_DLCI) += dlci.o obj-$(CONFIG_SDLA) += sdla.o -ifeq ($(CONFIG_WANPIPE_MULTPPP),y) - obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o syncppp.o -else - obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o -endif obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o obj-$(CONFIG_LAPBETHER) += lapbether.o obj-$(CONFIG_SBNI) += sbni.o diff --git a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c deleted file mode 100644 index 496d292..0000000 --- a/drivers/net/wan/sdla_chdlc.c +++ /dev/null @@ -1,4428 +0,0 @@ -/***************************************************************************** -* sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. -* -* Authors: Nenad Corbic -* Gideon Hack -* -* Copyright: (c) 1995-2001 Sangoma Technologies Inc. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version -* 2 of the License, or (at your option) any later version. -* ============================================================================ -* Feb 28, 2001 Nenad Corbic Updated if_tx_timeout() routine for -* 2.4.X kernels. -* Jan 25, 2001 Nenad Corbic Added a TTY Sync serial driver over the -* HDLC streaming protocol -* Added a TTY Async serial driver over the -* Async protocol. -* Dec 15, 2000 Nenad Corbic Updated for 2.4.X Kernel support -* Nov 13, 2000 Nenad Corbic Added true interface type encoding option. -* Tcpdump doesn't support CHDLC inteface -* types, to fix this "true type" option will set -* the interface type to RAW IP mode. -* Nov 07, 2000 Nenad Corbic Added security features for UDP debugging: -* Deny all and specify allowed requests. -* Jun 20, 2000 Nenad Corbic Fixed the API IP ERROR bug. Caused by the -* latest update. -* May 09, 2000 Nenad Corbic Option to bring down an interface -* upon disconnect. -* Mar 23, 2000 Nenad Corbic Improved task queue, bh handling. -* Mar 16, 2000 Nenad Corbic Fixed the SLARP Dynamic IP addressing. -* Mar 06, 2000 Nenad Corbic Bug Fix: corrupted mbox recovery. -* Feb 10, 2000 Gideon Hack Added ASYNC support. -* Feb 09, 2000 Nenad Corbic Fixed two shutdown bugs in update() and -* if_stats() functions. -* Jan 24, 2000 Nenad Corbic Fixed a startup wanpipe state racing, -* condition between if_open and isr. -* Jan 10, 2000 Nenad Corbic Added new socket API support. -* Dev 15, 1999 Nenad Corbic Fixed up header files for 2.0.X kernels -* Nov 20, 1999 Nenad Corbic Fixed zero length API bug. -* Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. -* Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing -* Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices. -* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. -* Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). -* Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. -* Aug 07, 1998 David Fong Initial version. -*****************************************************************************/ - -#include -#include /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include /* ARPHRD_* defines */ - - -#include -#include -#include - -#include /* sockaddr_in */ -#include -#include -#include /* htons(), etc. */ -#include -#include - -#include /* CHDLC firmware API definitions */ -#include /* CHDLC (async) API definitions */ - -#include /* Socket Driver common area */ -#include - -/* TTY Includes */ -#include -#include -#include - - -/****** Defines & Macros ****************************************************/ - -/* reasons for enabling the timer interrupt on the adapter */ -#define TMR_INT_ENABLED_UDP 0x01 -#define TMR_INT_ENABLED_UPDATE 0x02 -#define TMR_INT_ENABLED_CONFIG 0x10 - -#define MAX_IP_ERRORS 10 - -#define TTY_CHDLC_MAX_MTU 2000 -#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ -#define CHDLC_HDR_LEN 1 - -#define CHDLC_API 0x01 - -#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) -#define MAX_BH_BUFF 10 - -//#define PRINT_DEBUG -#ifdef PRINT_DEBUG -#define dbg_printk(format, a...) printk(format, ## a) -#else -#define dbg_printk(format, a...) -#endif - -/******Data Structures*****************************************************/ - -/* This structure is placed in the private data area of the device structure. - * The card structure used to occupy the private area but now the following - * structure will incorporate the card structure along with CHDLC specific data - */ - -typedef struct chdlc_private_area -{ - wanpipe_common_t common; - sdla_t *card; - int TracingEnabled; /* For enabling Tracing */ - unsigned long curr_trace_addr; /* Used for Tracing */ - unsigned long start_trace_addr; - unsigned long end_trace_addr; - unsigned long base_addr_trace_buffer; - unsigned long end_addr_trace_buffer; - unsigned short number_trace_elements; - unsigned available_buffer_space; - unsigned long router_start_time; - unsigned char route_status; - unsigned char route_removed; - unsigned long tick_counter; /* For 5s timeout counter */ - unsigned long router_up_time; - u32 IP_address; /* IP addressing */ - u32 IP_netmask; - u32 ip_local; - u32 ip_remote; - u32 ip_local_tmp; - u32 ip_remote_tmp; - u8 ip_error; - u8 config_chdlc; - u8 config_chdlc_timeout; - unsigned char mc; /* Mulitcast support on/off */ - unsigned short udp_pkt_lgth; /* udp packet processing */ - char udp_pkt_src; - char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; - unsigned short timer_int_enabled; - char update_comms_stats; /* updating comms stats */ - - bh_data_t *bh_head; /* Circular buffer for chdlc_bh */ - unsigned long tq_working; - volatile int bh_write; - volatile int bh_read; - atomic_t bh_buff_used; - - unsigned char interface_down; - - /* Polling work queue entry. Each interface - * has its own work queue entry, which is used - * to defer events from the interrupt */ - struct work_struct poll_work; - struct timer_list poll_delay_timer; - - u8 gateway; - u8 true_if_encoding; - //FIXME: add driver stats as per frame relay! - -} chdlc_private_area_t; - -/* Route Status options */ -#define NO_ROUTE 0x00 -#define ADD_ROUTE 0x01 -#define ROUTE_ADDED 0x02 -#define REMOVE_ROUTE 0x03 - - -/* variable for keeping track of enabling/disabling FT1 monitor status */ -static int rCount = 0; - -/* variable for tracking how many interfaces to open for WANPIPE on the - two ports */ - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/****** Function Prototypes *************************************************/ -/* WAN link driver entry points. These are called by the WAN router module. */ -static int update(struct wan_device* wandev); -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf); - -/* Network device interface */ -static int if_init(struct net_device* dev); -static int if_open(struct net_device* dev); -static int if_close(struct net_device* dev); -static int if_header(struct sk_buff* skb, struct net_device* dev, - unsigned short type, void* daddr, void* saddr, - unsigned len); - -static int if_rebuild_hdr (struct sk_buff *skb); -static struct net_device_stats* if_stats(struct net_device* dev); - -static int if_send(struct sk_buff* skb, struct net_device* dev); - -/* CHDLC Firmware interface functions */ -static int chdlc_configure (sdla_t* card, void* data); -static int chdlc_comm_enable (sdla_t* card); -static int chdlc_read_version (sdla_t* card, char* str); -static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); -static int chdlc_send (sdla_t* card, void* data, unsigned len); -static int chdlc_read_comm_err_stats (sdla_t* card); -static int chdlc_read_op_stats (sdla_t* card); -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); - - -static int chdlc_disable_comm_shutdown (sdla_t *card); -static void if_tx_timeout(struct net_device *dev); - -/* Miscellaneous CHDLC Functions */ -static int set_chdlc_config (sdla_t* card); -static void init_chdlc_tx_rx_buff( sdla_t* card); -static int process_chdlc_exception(sdla_t *card); -static int process_global_exception(sdla_t *card); -static int update_comms_stats(sdla_t* card, - chdlc_private_area_t* chdlc_priv_area); -static int configure_ip (sdla_t* card); -static int unconfigure_ip (sdla_t* card); -static void process_route(sdla_t *card); -static void port_set_state (sdla_t *card, int); -static int config_chdlc (sdla_t *card); -static void disable_comm (sdla_t *card); - -static void trigger_chdlc_poll(struct net_device *dev); -static void chdlc_poll(struct net_device *dev); -static void chdlc_poll_delay (unsigned long dev_ptr); - - -/* Miscellaneous asynchronous interface Functions */ -static int set_asy_config (sdla_t* card); -static int asy_comm_enable (sdla_t* card); - -/* Interrupt handlers */ -static void wpc_isr (sdla_t* card); -static void rx_intr (sdla_t* card); -static void timer_intr(sdla_t *); - -/* Bottom half handlers */ -static void chdlc_work(struct net_device *dev); -static int chdlc_work_cleanup(struct net_device *dev); -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb); - -/* Miscellaneous functions */ -static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev, - struct sk_buff *skb); -static int reply_udp( unsigned char *data, unsigned int mbox_len ); -static int intr_test( sdla_t* card); -static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area); -static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area); -static unsigned short calc_checksum (char *, int); -static void s508_lock (sdla_t *card, unsigned long *smp_flags); -static void s508_unlock (sdla_t *card, unsigned long *smp_flags); - - -static int Intr_test_counter; - -/* TTY Global Definitions */ - -#define NR_PORTS 4 -#define WAN_TTY_MAJOR 226 -#define WAN_TTY_MINOR 0 - -#define WAN_CARD(port) (tty_card_map[port]) -#define MIN_PORT 0 -#define MAX_PORT NR_PORTS-1 - -#define CRC_LENGTH 2 - -static int wanpipe_tty_init(sdla_t *card); -static void wanpipe_tty_receive(sdla_t *, unsigned, unsigned int); -static void wanpipe_tty_trigger_poll(sdla_t *card); - -static struct tty_driver serial_driver; -static int tty_init_cnt=0; - -static struct serial_state rs_table[NR_PORTS]; - -static char tty_driver_mode=WANOPT_TTY_SYNC; - -static char *opt_decode[] = {"NONE","CRTSCTS","XONXOFF-RX", - "CRTSCTS XONXOFF-RX","XONXOFF-TX", - "CRTSCTS XONXOFF-TX","CRTSCTS XONXOFF"}; -static char *p_decode[] = {"NONE","ODD","EVEN"}; - -static void* tty_card_map[NR_PORTS] = {NULL,NULL,NULL,NULL}; - - -/****** Public Functions ****************************************************/ - -/*============================================================================ - * Cisco HDLC protocol initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wpc_init (sdla_t* card, wandev_conf_t* conf) -{ - unsigned char port_num; - int err; - unsigned long max_permitted_baud = 0; - SHARED_MEMORY_INFO_STRUCT *flags; - - union - { - char str[80]; - } u; - volatile CHDLC_MAILBOX_STRUCT* mb; - CHDLC_MAILBOX_STRUCT* mb1; - unsigned long timeout; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_CHDLC) { - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - } - - /* Find out which Port to use */ - if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ - if (card->next){ - - if (conf->comm_port != card->next->u.c.comm_port){ - card->u.c.comm_port = conf->comm_port; - }else{ - printk(KERN_INFO "%s: ERROR - %s port used!\n", - card->wandev.name, PORT(conf->comm_port)); - return -EINVAL; - } - }else{ - card->u.c.comm_port = conf->comm_port; - } - }else{ - printk(KERN_INFO "%s: ERROR - Invalid Port Selected!\n", - card->wandev.name); - return -EINVAL; - } - - - /* Initialize protocol-specific fields */ - if(card->hw.type != SDLA_S514){ - - if (card->u.c.comm_port == WANOPT_PRI){ - card->mbox = (void *) card->hw.dpmbase; - }else{ - card->mbox = (void *) card->hw.dpmbase + - SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT; - } - }else{ - /* for a S514 adapter, set a pointer to the actual mailbox in the */ - /* allocated virtual memory area */ - if (card->u.c.comm_port == WANOPT_PRI){ - card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; - }else{ - card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT; - } - } - - mb = mb1 = card->mbox; - - if (!card->configured){ - - /* The board will place an 'I' in the return code to indicate that it is - ready to accept commands. We expect this to be completed in less - than 1 second. */ - - timeout = jiffies; - while (mb->return_code != 'I') /* Wait 1s for board to initialize */ - if ((jiffies - timeout) > 1*HZ) break; - - if (mb->return_code != 'I') { - printk(KERN_INFO - "%s: Initialization not completed by adapter\n", - card->devname); - printk(KERN_INFO "Please contact Sangoma representative.\n"); - return -EIO; - } - } - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - - if (chdlc_read_version(card, u.str)) - return -EIO; - - printk(KERN_INFO "%s: Running Cisco HDLC firmware v%s\n", - card->devname, u.str); - - card->isr = &wpc_isr; - card->poll = NULL; - card->exec = NULL; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = NULL; - card->wandev.udp_port = conf->udp_port; - card->disable_comm = &disable_comm; - card->wandev.new_if_cnt = 0; - - /* reset the number of times the 'update()' proc has been called */ - card->u.c.update_call_count = 0; - - card->wandev.ttl = conf->ttl; - card->wandev.interface = conf->interface; - - if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& - card->hw.type != SDLA_S514){ - printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", - card->devname, PORT(card->u.c.comm_port)); - return -EIO; - } - - card->wandev.clocking = conf->clocking; - - port_num = card->u.c.comm_port; - - /* in API mode, we can configure for "receive only" buffering */ - if(card->hw.type == SDLA_S514) { - card->u.c.receive_only = conf->receive_only; - if(conf->receive_only) { - printk(KERN_INFO - "%s: Configured for 'receive only' mode\n", - card->devname); - } - } - - /* Setup Port Bps */ - - if(card->wandev.clocking) { - if((port_num == WANOPT_PRI) || card->u.c.receive_only) { - /* For Primary Port 0 */ - max_permitted_baud = - (card->hw.type == SDLA_S514) ? - PRI_MAX_BAUD_RATE_S514 : - PRI_MAX_BAUD_RATE_S508; - - }else if(port_num == WANOPT_SEC) { - /* For Secondary Port 1 */ - max_permitted_baud = - (card->hw.type == SDLA_S514) ? - SEC_MAX_BAUD_RATE_S514 : - SEC_MAX_BAUD_RATE_S508; - } - - if(conf->bps > max_permitted_baud) { - conf->bps = max_permitted_baud; - printk(KERN_INFO "%s: Baud too high!\n", - card->wandev.name); - printk(KERN_INFO "%s: Baud rate set to %lu bps\n", - card->wandev.name, max_permitted_baud); - } - card->wandev.bps = conf->bps; - }else{ - card->wandev.bps = 0; - } - - /* Setup the Port MTU */ - if((port_num == WANOPT_PRI) || card->u.c.receive_only) { - - /* For Primary Port 0 */ - card->wandev.mtu = - (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? - min_t(unsigned int, conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) : - CHDLC_DFLT_DATA_LEN; - } else if(port_num == WANOPT_SEC) { - /* For Secondary Port 1 */ - card->wandev.mtu = - (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? - min_t(unsigned int, conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : - CHDLC_DFLT_DATA_LEN; - } - - /* Set up the interrupt status area */ - /* Read the CHDLC Configuration and obtain: - * Ptr to shared memory infor struct - * Use this pointer to calculate the value of card->u.c.flags ! - */ - mb1->buffer_length = 0; - mb1->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; - if(err != COMMAND_OK) { - if(card->hw.type != SDLA_S514) - enable_irq(card->hw.irq); - - chdlc_error(card, err, mb1); - return -EIO; - } - - if(card->hw.type == SDLA_S514){ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct)); - }else{ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); - } - - flags = card->u.c.flags; - - /* This is for the ports link state */ - card->wandev.state = WAN_DUALPORT; - card->u.c.state = WAN_DISCONNECTED; - - - if (!card->wandev.piggyback){ - int err; - - /* Perform interrupt testing */ - err = intr_test(card); - - if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk(KERN_INFO "%s: Interrupt test failed (%i)\n", - card->devname, Intr_test_counter); - printk(KERN_INFO "%s: Please choose another interrupt\n", - card->devname); - return -EIO; - } - - printk(KERN_INFO "%s: Interrupt test passed (%i)\n", - card->devname, Intr_test_counter); - card->configured = 1; - } - - if ((card->tty_opt=conf->tty) == WANOPT_YES){ - int err; - card->tty_minor = conf->tty_minor; - - /* On ASYNC connections internal clocking - * is mandatory */ - if ((card->u.c.async_mode = conf->tty_mode)){ - card->wandev.clocking = 1; - } - err=wanpipe_tty_init(card); - if (err){ - return err; - } - }else{ - - - if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ - printk (KERN_INFO "%s: " - "Failed to set interrupt triggers!\n", - card->devname); - return -EIO; - } - - /* Mask the Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TIMER; - } - - /* If we are using CHDLC in backup mode, this flag will - * indicate not to look for IP addresses in config_chdlc()*/ - card->u.c.backup = conf->backup; - - printk(KERN_INFO "\n"); - - return 0; -} - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Update device status & statistics - * This procedure is called when updating the PROC file system and returns - * various communications statistics. These statistics are accumulated from 3 - * different locations: - * 1) The 'if_stats' recorded for the device. - * 2) Communication error statistics on the adapter. - * 3) CHDLC operational statistics on the adapter. - * The board level statistics are read during a timer interrupt. Note that we - * read the error and operational statistics during consecitive timer ticks so - * as to minimize the time that we are inside the interrupt handler. - * - */ -static int update(struct wan_device* wandev) -{ - sdla_t* card = wandev->private; - struct net_device* dev; - volatile chdlc_private_area_t* chdlc_priv_area; - SHARED_MEMORY_INFO_STRUCT *flags; - unsigned long timeout; - - /* sanity checks */ - if((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - - if(wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - /* more sanity checks */ - if(!card->u.c.flags) - return -ENODEV; - - if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) - return -EAGAIN; - - if((dev=card->wandev.dev) == NULL) - return -ENODEV; - - if((chdlc_priv_area=dev->priv) == NULL) - return -ENODEV; - - flags = card->u.c.flags; - if(chdlc_priv_area->update_comms_stats){ - return -EAGAIN; - } - - /* we will need 2 timer interrupts to complete the */ - /* reading of the statistics */ - chdlc_priv_area->update_comms_stats = 2; - flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; - chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE; - - /* wait a maximum of 1 second for the statistics to be updated */ - timeout = jiffies; - for(;;) { - if(chdlc_priv_area->update_comms_stats == 0) - break; - if ((jiffies - timeout) > (1 * HZ)){ - chdlc_priv_area->update_comms_stats = 0; - chdlc_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - return -EAGAIN; - } - } - - return 0; -} - - -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. - * - * Return: 0 o.k. - * < 0 failure (channel will not be created) - */ -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf) -{ - sdla_t* card = wandev->private; - chdlc_private_area_t* chdlc_priv_area; - - - printk(KERN_INFO "%s: Configuring Interface: %s\n", - card->devname, conf->name); - - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - printk(KERN_INFO "%s: Invalid interface name!\n", - card->devname); - return -EINVAL; - } - - /* allocate and initialize private data */ - chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); - - if(chdlc_priv_area == NULL) - return -ENOMEM; - - memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); - - chdlc_priv_area->card = card; - chdlc_priv_area->common.sk = NULL; - chdlc_priv_area->common.func = NULL; - - /* initialize data */ - strcpy(card->u.c.if_name, conf->name); - - if(card->wandev.new_if_cnt > 0) { - kfree(chdlc_priv_area); - return -EEXIST; - } - - card->wandev.new_if_cnt++; - - chdlc_priv_area->TracingEnabled = 0; - chdlc_priv_area->route_status = NO_ROUTE; - chdlc_priv_area->route_removed = 0; - - card->u.c.async_mode = conf->async_mode; - - /* setup for asynchronous mode */ - if(conf->async_mode) { - printk(KERN_INFO "%s: Configuring for asynchronous mode\n", - wandev->name); - - if(card->u.c.comm_port == WANOPT_PRI) { - printk(KERN_INFO - "%s:Asynchronous mode on secondary port only\n", - wandev->name); - kfree(chdlc_priv_area); - return -EINVAL; - } - - if(strcmp(conf->usedby, "WANPIPE") == 0) { - printk(KERN_INFO - "%s: Running in WANIPE Async Mode\n", wandev->name); - card->u.c.usedby = WANPIPE; - }else{ - card->u.c.usedby = API; - } - - if(!card->wandev.clocking) { - printk(KERN_INFO - "%s: Asynch. clocking must be 'Internal'\n", - wandev->name); - kfree(chdlc_priv_area); - return -EINVAL; - } - - if((card->wandev.bps < MIN_ASY_BAUD_RATE) || - (card->wandev.bps > MAX_ASY_BAUD_RATE)) { - printk(KERN_INFO "%s: Selected baud rate is invalid.\n", - wandev->name); - printk(KERN_INFO "Must be between %u and %u bps.\n", - MIN_ASY_BAUD_RATE, MAX_ASY_BAUD_RATE); - kfree(chdlc_priv_area); - return -EINVAL; - } - - card->u.c.api_options = 0; - if (conf->asy_data_trans == WANOPT_YES) { - card->u.c.api_options |= ASY_RX_DATA_TRANSPARENT; - } - - card->u.c.protocol_options = 0; - if (conf->rts_hs_for_receive == WANOPT_YES) { - card->u.c.protocol_options |= ASY_RTS_HS_FOR_RX; - } - if (conf->xon_xoff_hs_for_receive == WANOPT_YES) { - card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_RX; - } - if (conf->xon_xoff_hs_for_transmit == WANOPT_YES) { - card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_TX; - } - if (conf->dcd_hs_for_transmit == WANOPT_YES) { - card->u.c.protocol_options |= ASY_DCD_HS_FOR_TX; - } - if (conf->cts_hs_for_transmit == WANOPT_YES) { - card->u.c.protocol_options |= ASY_CTS_HS_FOR_TX; - } - - card->u.c.tx_bits_per_char = conf->tx_bits_per_char; - card->u.c.rx_bits_per_char = conf->rx_bits_per_char; - card->u.c.stop_bits = conf->stop_bits; - card->u.c.parity = conf->parity; - card->u.c.break_timer = conf->break_timer; - card->u.c.inter_char_timer = conf->inter_char_timer; - card->u.c.rx_complete_length = conf->rx_complete_length; - card->u.c.xon_char = conf->xon_char; - - } else { /* setup for synchronous mode */ - - card->u.c.protocol_options = 0; - if (conf->ignore_dcd == WANOPT_YES){ - card->u.c.protocol_options |= IGNORE_DCD_FOR_LINK_STAT; - } - if (conf->ignore_cts == WANOPT_YES){ - card->u.c.protocol_options |= IGNORE_CTS_FOR_LINK_STAT; - } - - if (conf->ignore_keepalive == WANOPT_YES) { - card->u.c.protocol_options |= - IGNORE_KPALV_FOR_LINK_STAT; - card->u.c.kpalv_tx = MIN_Tx_KPALV_TIMER; - card->u.c.kpalv_rx = MIN_Rx_KPALV_TIMER; - card->u.c.kpalv_err = MIN_KPALV_ERR_TOL; - - } else { /* Do not ignore keepalives */ - card->u.c.kpalv_tx = - ((conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER) - >= 0) ? - min_t(unsigned int, conf->keepalive_tx_tmr,MAX_Tx_KPALV_TIMER) : - DEFAULT_Tx_KPALV_TIMER; - - card->u.c.kpalv_rx = - ((conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER) - >= 0) ? - min_t(unsigned int, conf->keepalive_rx_tmr,MAX_Rx_KPALV_TIMER) : - DEFAULT_Rx_KPALV_TIMER; - - card->u.c.kpalv_err = - ((conf->keepalive_err_margin-MIN_KPALV_ERR_TOL) - >= 0) ? - min_t(unsigned int, conf->keepalive_err_margin, - MAX_KPALV_ERR_TOL) : - DEFAULT_KPALV_ERR_TOL; - } - - /* Setup slarp timer to control delay between slarps */ - card->u.c.slarp_timer = - ((conf->slarp_timer - MIN_SLARP_REQ_TIMER) >= 0) ? - min_t(unsigned int, conf->slarp_timer, MAX_SLARP_REQ_TIMER) : - DEFAULT_SLARP_REQ_TIMER; - - if (conf->hdlc_streaming == WANOPT_YES) { - printk(KERN_INFO "%s: Enabling HDLC STREAMING Mode\n", - wandev->name); - card->u.c.protocol_options = HDLC_STREAMING_MODE; - } - - if ((chdlc_priv_area->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){ - printk(KERN_INFO - "%s: Enabling, true interface type encoding.\n", - card->devname); - } - - /* Setup wanpipe as a router (WANPIPE) or as an API */ - if( strcmp(conf->usedby, "WANPIPE") == 0) { - - printk(KERN_INFO "%s: Running in WANPIPE mode!\n", - wandev->name); - card->u.c.usedby = WANPIPE; - - /* Option to bring down the interface when - * the link goes down */ - if (conf->if_down){ - set_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down); - printk(KERN_INFO - "%s: Dynamic interface configuration enabled\n", - card->devname); - } - - } else if( strcmp(conf->usedby, "API") == 0) { - card->u.c.usedby = API; - printk(KERN_INFO "%s: Running in API mode !\n", - wandev->name); - } - } - - /* Tells us that if this interface is a - * gateway or not */ - if ((chdlc_priv_area->gateway = conf->gateway) == WANOPT_YES){ - printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", - card->devname,card->u.c.if_name); - } - - /* Get Multicast Information */ - chdlc_priv_area->mc = conf->mc; - - /* prepare network device data space for registration */ - strcpy(dev->name,card->u.c.if_name); - - dev->init = &if_init; - dev->priv = chdlc_priv_area; - - /* Initialize the polling work routine */ - INIT_WORK(&chdlc_priv_area->poll_work, (void*)(void*)chdlc_poll, dev); - - /* Initialize the polling delay timer */ - init_timer(&chdlc_priv_area->poll_delay_timer); - chdlc_priv_area->poll_delay_timer.data = (unsigned long)dev; - chdlc_priv_area->poll_delay_timer.function = chdlc_poll_delay; - - printk(KERN_INFO "\n"); - - return 0; -} - - -/****** Network Device Interface ********************************************/ - -/*============================================================================ - * Initialize Linux network interface. - * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. - */ -static int if_init(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - struct wan_device* wandev = &card->wandev; - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - dev->tx_timeout = &if_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - /* Initialize media-specific parameters */ - dev->flags |= IFF_POINTOPOINT; - dev->flags |= IFF_NOARP; - - /* Enable Mulitcasting if user selected */ - if (chdlc_priv_area->mc == WANOPT_YES){ - dev->flags |= IFF_MULTICAST; - } - - if (chdlc_priv_area->true_if_encoding){ - dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */ - }else{ - dev->type = ARPHRD_PPP; - } - - dev->mtu = card->wandev.mtu; - /* for API usage, add the API header size to the requested MTU size */ - if(card->u.c.usedby == API) { - dev->mtu += sizeof(api_tx_hdr_t); - } - - dev->hard_header_len = CHDLC_HDR_LEN; - - /* Initialize hardware parameters */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; - - /* Set transmit buffer queue length - * If too low packets will not be retransmitted - * by stack. - */ - dev->tx_queue_len = 100; - SET_MODULE_OWNER(dev); - - return 0; -} - -/*============================================================================ - * Open network interface. - * o enable communications and interrupts. - * o prevent module from unloading by incrementing use count - * - * Return 0 if O.k. or errno. - */ -static int if_open(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - struct timeval tv; - int err = 0; - - /* Only one open per interface is allowed */ - - if (netif_running(dev)) - return -EBUSY; - - /* Initialize the work queue entry */ - chdlc_priv_area->tq_working=0; - - INIT_WORK(&chdlc_priv_area->common.wanpipe_work, - (void *)(void *)chdlc_work, dev); - - /* Allocate and initialize BH circular buffer */ - /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */ - chdlc_priv_area->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC); - memset(chdlc_priv_area->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1))); - atomic_set(&chdlc_priv_area->bh_buff_used, 0); - - do_gettimeofday(&tv); - chdlc_priv_area->router_start_time = tv.tv_sec; - - netif_start_queue(dev); - - wanpipe_open(card); - - /* TTY is configured during wanpipe_set_termios - * call, not here */ - if (card->tty_opt) - return err; - - set_bit(0,&chdlc_priv_area->config_chdlc); - chdlc_priv_area->config_chdlc_timeout=jiffies; - - /* Start the CHDLC configuration after 1sec delay. - * This will give the interface initilization time - * to finish its configuration */ - mod_timer(&chdlc_priv_area->poll_delay_timer, jiffies + HZ); - return err; -} - -/*============================================================================ - * Close network interface. - * o if this is the last close, then disable communications and interrupts. - * o reset flags. - */ -static int if_close(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - - if (chdlc_priv_area->bh_head){ - int i; - struct sk_buff *skb; - - for (i=0; i<(MAX_BH_BUFF+1); i++){ - skb = ((bh_data_t *)&chdlc_priv_area->bh_head[i])->skb; - if (skb != NULL){ - dev_kfree_skb_any(skb); - } - } - kfree(chdlc_priv_area->bh_head); - chdlc_priv_area->bh_head=NULL; - } - - netif_stop_queue(dev); - wanpipe_close(card); - del_timer(&chdlc_priv_area->poll_delay_timer); - return 0; -} - -static void disable_comm (sdla_t *card) -{ - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - - if (card->u.c.comm_enabled){ - chdlc_disable_comm_shutdown (card); - }else{ - flags->interrupt_info_struct.interrupt_permission = 0; - } - - if (!tty_init_cnt) - return; - - if (card->tty_opt){ - struct serial_state * state; - if (!(--tty_init_cnt)){ - int e1; - serial_driver.refcount=0; - - if ((e1 = tty_unregister_driver(&serial_driver))) - printk("SERIAL: failed to unregister serial driver (%d)\n", - e1); - printk(KERN_INFO "%s: Unregistering TTY Driver, Major %i\n", - card->devname,WAN_TTY_MAJOR); - } - card->tty=NULL; - tty_card_map[card->tty_minor]=NULL; - state = &rs_table[card->tty_minor]; - memset(state, 0, sizeof(*state)); - } - return; -} - - -/*============================================================================ - * Build media header. - * - * The trick here is to put packet type (Ethertype) into 'protocol' field of - * the socket buffer, so that we don't forget it. If packet type is not - * supported, set skb->protocol to 0 and discard packet later. - * - * Return: media header length. - */ -static int if_header(struct sk_buff* skb, struct net_device* dev, - unsigned short type, void* daddr, void* saddr, - unsigned len) -{ - skb->protocol = htons(type); - - return CHDLC_HDR_LEN; -} - - -/*============================================================================ - * Handle transmit timeout event from netif watchdog - */ -static void if_tx_timeout(struct net_device *dev) -{ - chdlc_private_area_t* chan = dev->priv; - sdla_t *card = chan->card; - - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - - ++card->wandev.stats.collisions; - - printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); - netif_wake_queue (dev); -} - - - -/*============================================================================ - * Re-build media header. - * - * Return: 1 physical address resolved. - * 0 physical address not resolved - */ -static int if_rebuild_hdr (struct sk_buff *skb) -{ - return 1; -} - - -/*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission) to block a timer-based - * transmit from overlapping. - * o check link state. If link is not up, then drop the packet. - * o execute adapter send command. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. - */ -static int if_send(struct sk_buff* skb, struct net_device* dev) -{ - chdlc_private_area_t *chdlc_priv_area = dev->priv; - sdla_t *card = chdlc_priv_area->card; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; - int udp_type = 0; - unsigned long smp_flags; - int err=0; - - netif_stop_queue(dev); - - if (skb == NULL){ - /* If we get here, some higher layer thinks we've missed an - * tx-done interrupt. - */ - printk(KERN_INFO "%s: interface %s got kicked!\n", - card->devname, dev->name); - - netif_wake_queue(dev); - return 0; - } - - if (ntohs(skb->protocol) != htons(PVC_PROT)){ - - /* check the udp packet type */ - - udp_type = udp_pkt_type(skb, card); - - if (udp_type == UDP_CPIPE_TYPE){ - if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, - chdlc_priv_area)){ - chdlc_int->interrupt_permission |= - APP_INT_ON_TIMER; - } - netif_start_queue(dev); - return 0; - } - - /* check to see if the source IP address is a broadcast or */ - /* multicast IP address */ - if(chk_bcast_mcast_addr(card, dev, skb)){ - ++card->wandev.stats.tx_dropped; - dev_kfree_skb_any(skb); - netif_start_queue(dev); - return 0; - } - } - - /* Lock the 508 Card: SMP is supported */ - if(card->hw.type != SDLA_S514){ - s508_lock(card,&smp_flags); - } - - if(test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - - printk(KERN_INFO "%s: Critical in if_send: %lx\n", - card->wandev.name,card->wandev.critical); - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - goto if_send_exit_crit; - } - - if(card->u.c.state != WAN_CONNECTED){ - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - - }else if(!skb->protocol){ - ++card->wandev.stats.tx_errors; - netif_start_queue(dev); - - }else { - void* data = skb->data; - unsigned len = skb->len; - unsigned char attr; - - /* If it's an API packet pull off the API - * header. Also check that the packet size - * is larger than the API header - */ - if (card->u.c.usedby == API){ - api_tx_hdr_t* api_tx_hdr; - - /* discard the frame if we are configured for */ - /* 'receive only' mode or if there is no data */ - if (card->u.c.receive_only || - (len <= sizeof(api_tx_hdr_t))) { - - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - goto if_send_exit_crit; - } - - api_tx_hdr = (api_tx_hdr_t *)data; - attr = api_tx_hdr->attr; - data += sizeof(api_tx_hdr_t); - len -= sizeof(api_tx_hdr_t); - } - - if(chdlc_send(card, data, len)) { - netif_stop_queue(dev); - }else{ - ++card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += len; - - netif_start_queue(dev); - - dev->trans_start = jiffies; - } - } - -if_send_exit_crit: - - if (!(err=netif_queue_stopped(dev))) { - dev_kfree_skb_any(skb); - }else{ - chdlc_priv_area->tick_counter = jiffies; - chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; - } - - clear_bit(SEND_CRIT, (void*)&card->wandev.critical); - if(card->hw.type != SDLA_S514){ - s508_unlock(card,&smp_flags); - } - - return err; -} - - -/*============================================================================ - * Check to see if the packet to be transmitted contains a broadcast or - * multicast source IP address. - */ - -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, - struct sk_buff *skb) -{ - u32 src_ip_addr; - u32 broadcast_ip_addr = 0; - struct in_device *in_dev; - - /* read the IP source address from the outgoing packet */ - src_ip_addr = *(u32 *)(skb->data + 12); - - /* read the IP broadcast address for the device */ - in_dev = dev->ip_ptr; - if(in_dev != NULL) { - struct in_ifaddr *ifa= in_dev->ifa_list; - if(ifa != NULL) - broadcast_ip_addr = ifa->ifa_broadcast; - else - return 0; - } - - /* check if the IP Source Address is a Broadcast address */ - if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { - printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", - card->devname); - return 1; - } - - /* check if the IP Source Address is a Multicast address */ - if((ntohl(src_ip_addr) >= 0xE0000001) && - (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { - printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", - card->devname); - return 1; - } - - return 0; -} - - -/*============================================================================ - * Reply to UDP Management system. - * Return length of reply. - */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ) -{ - - unsigned short len, udp_length, temp, ip_length; - unsigned long ip_temp; - int even_bound = 0; - chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data; - - /* Set length of packet */ - len = sizeof(ip_pkt_t)+ - sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - sizeof(trace_info_t)+ - mbox_len; - - /* fill in UDP reply */ - c_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; - - /* fill in UDP length */ - udp_length = sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - sizeof(trace_info_t)+ - mbox_len; - - /* put it on an even boundary */ - if ( udp_length & 0x0001 ) { - udp_length += 1; - len += 1; - even_bound = 1; - } - - temp = (udp_length<<8)|(udp_length>>8); - c_udp_pkt->udp_pkt.udp_length = temp; - - /* swap UDP ports */ - temp = c_udp_pkt->udp_pkt.udp_src_port; - c_udp_pkt->udp_pkt.udp_src_port = - c_udp_pkt->udp_pkt.udp_dst_port; - c_udp_pkt->udp_pkt.udp_dst_port = temp; - - /* add UDP pseudo header */ - temp = 0x1100; - *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp; - temp = (udp_length<<8)|(udp_length>>8); - *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp; - - - /* calculate UDP checksum */ - c_udp_pkt->udp_pkt.udp_checksum = 0; - c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); - - /* fill in IP length */ - ip_length = len; - temp = (ip_length<<8)|(ip_length>>8); - c_udp_pkt->ip_pkt.total_length = temp; - - /* swap IP addresses */ - ip_temp = c_udp_pkt->ip_pkt.ip_src_address; - c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address; - c_udp_pkt->ip_pkt.ip_dst_address = ip_temp; - - /* fill in IP checksum */ - c_udp_pkt->ip_pkt.hdr_checksum = 0; - c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); - - return len; - -} /* reply_udp */ - -unsigned short calc_checksum (char *data, int len) -{ - unsigned short temp; - unsigned long sum=0; - int i; - - for( i = 0; i > 16 ) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - - temp = (unsigned short)sum; - temp = ~temp; - - if( temp == 0 ) - temp = 0xffff; - - return temp; -} - - -/*============================================================================ - * Get ethernet-style interface statistics. - * Return a pointer to struct enet_statistics. - */ -static struct net_device_stats* if_stats(struct net_device* dev) -{ - sdla_t *my_card; - chdlc_private_area_t* chdlc_priv_area; - - if ((chdlc_priv_area=dev->priv) == NULL) - return NULL; - - my_card = chdlc_priv_area->card; - return &my_card->wandev.stats; -} - - -/****** Cisco HDLC Firmware Interface Functions *******************************/ - -/*============================================================================ - * Read firmware code version. - * Put code version as ASCII string in str. - */ -static int chdlc_read_version (sdla_t* card, char* str) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int len; - char err; - mb->buffer_length = 0; - mb->command = READ_CHDLC_CODE_VERSION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - chdlc_error(card,err,mb); - } - else if (str) { /* is not null */ - len = mb->buffer_length; - memcpy(str, mb->data, len); - str[len] = '\0'; - } - return (err); -} - -/*----------------------------------------------------------------------------- - * Configure CHDLC firmware. - */ -static int chdlc_configure (sdla_t* card, void* data) -{ - int err; - CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; - int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); - - mailbox->buffer_length = data_length; - memcpy(mailbox->data, data, data_length); - mailbox->command = SET_CHDLC_CONFIGURATION; - err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; - - if (err != COMMAND_OK) chdlc_error (card, err, mailbox); - - return err; -} - - -/*============================================================================ - * Set interrupt mode -- HDLC Version. - */ - -static int chdlc_set_intr_mode (sdla_t* card, unsigned mode) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_INT_TRIGGERS_STRUCT* int_data = - (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; - int err; - - int_data->CHDLC_interrupt_triggers = mode; - int_data->IRQ = card->hw.irq; - int_data->interrupt_timer = 1; - - mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); - mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error (card, err, mb); - return err; -} - - -/*=========================================================== - * chdlc_disable_comm_shutdown - * - * Shutdown() disables the communications. We must - * have a sparate functions, because we must not - * call chdlc_error() hander since the private - * area has already been replaced */ - -static int chdlc_disable_comm_shutdown (sdla_t *card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_INT_TRIGGERS_STRUCT* int_data = - (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; - int err; - - /* Disable Interrutps */ - int_data->CHDLC_interrupt_triggers = 0; - int_data->IRQ = card->hw.irq; - int_data->interrupt_timer = 1; - - mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); - mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - /* Disable Communications */ - - if (card->u.c.async_mode) { - mb->command = DISABLE_ASY_COMMUNICATIONS; - }else{ - mb->command = DISABLE_CHDLC_COMMUNICATIONS; - } - - mb->buffer_length = 0; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - card->u.c.comm_enabled = 0; - - return 0; -} - -/*============================================================================ - * Enable communications. - */ - -static int chdlc_comm_enable (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = ENABLE_CHDLC_COMMUNICATIONS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card, err, mb); - else - card->u.c.comm_enabled = 1; - - return err; -} - -/*============================================================================ - * Read communication error statistics. - */ -static int chdlc_read_comm_err_stats (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = READ_COMMS_ERROR_STATS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - return err; -} - - -/*============================================================================ - * Read CHDLC operational statistics. - */ -static int chdlc_read_op_stats (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_OPERATIONAL_STATS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - return err; -} - - -/*============================================================================ - * Update communications error and general packet statistics. - */ -static int update_comms_stats(sdla_t* card, - chdlc_private_area_t* chdlc_priv_area) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - COMMS_ERROR_STATS_STRUCT* err_stats; - CHDLC_OPERATIONAL_STATS_STRUCT *op_stats; - - /* on the first timer interrupt, read the comms error statistics */ - if(chdlc_priv_area->update_comms_stats == 2) { - if(chdlc_read_comm_err_stats(card)) - return 1; - err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data; - card->wandev.stats.rx_over_errors = - err_stats->Rx_overrun_err_count; - card->wandev.stats.rx_crc_errors = - err_stats->CRC_err_count; - card->wandev.stats.rx_frame_errors = - err_stats->Rx_abort_count; - card->wandev.stats.rx_fifo_errors = - err_stats->Rx_dis_pri_bfrs_full_count; - card->wandev.stats.rx_missed_errors = - card->wandev.stats.rx_fifo_errors; - card->wandev.stats.tx_aborted_errors = - err_stats->sec_Tx_abort_count; - } - - /* on the second timer interrupt, read the operational statistics */ - else { - if(chdlc_read_op_stats(card)) - return 1; - op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data; - card->wandev.stats.rx_length_errors = - (op_stats->Rx_Data_discard_short_count + - op_stats->Rx_Data_discard_long_count); - } - - return 0; -} - -/*============================================================================ - * Send packet. - * Return: 0 - o.k. - * 1 - no transmit buffers available - */ -static int chdlc_send (sdla_t* card, void* data, unsigned len) -{ - CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf; - - if (txbuf->opp_flag) - return 1; - - sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len); - - txbuf->frame_length = len; - txbuf->opp_flag = 1; /* start transmission */ - - /* Update transmit buffer control fields */ - card->u.c.txbuf = ++txbuf; - - if ((void*)txbuf > card->u.c.txbuf_last) - card->u.c.txbuf = card->u.c.txbuf_base; - - return 0; -} - -/****** Firmware Error Handler **********************************************/ - -/*============================================================================ - * Firmware error handler. - * This routine is called whenever firmware command returns non-zero - * return code. - * - * Return zero if previous command has to be cancelled. - */ -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) -{ - unsigned cmd = mb->command; - - switch (err) { - - case CMD_TIMEOUT: - printk(KERN_INFO "%s: command 0x%02X timed out!\n", - card->devname, cmd); - break; - - case S514_BOTH_PORTS_SAME_CLK_MODE: - if(cmd == SET_CHDLC_CONFIGURATION) { - printk(KERN_INFO - "%s: Configure both ports for the same clock source\n", - card->devname); - break; - } - - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, cmd, err); - } - - return 0; -} - - -/********** Bottom Half Handlers ********************************************/ - -/* NOTE: There is no API, BH support for Kernels lower than 2.2.X. - * DO NOT INSERT ANY CODE HERE, NOTICE THE - * PREPROCESSOR STATEMENT ABOVE, UNLESS YOU KNOW WHAT YOU ARE - * DOING */ - -static void chdlc_work(struct net_device * dev) -{ - chdlc_private_area_t* chan = dev->priv; - sdla_t *card = chan->card; - struct sk_buff *skb; - - if (atomic_read(&chan->bh_buff_used) == 0){ - clear_bit(0, &chan->tq_working); - return; - } - - while (atomic_read(&chan->bh_buff_used)){ - - skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; - - if (skb != NULL){ - - if (chan->common.sk == NULL || chan->common.func == NULL){ - ++card->wandev.stats.rx_dropped; - dev_kfree_skb_any(skb); - chdlc_work_cleanup(dev); - continue; - } - - if (chan->common.func(skb,dev,chan->common.sk) != 0){ - /* Sock full cannot send, queue us for another - * try */ - atomic_set(&chan->common.receive_block,1); - return; - }else{ - chdlc_work_cleanup(dev); - } - }else{ - chdlc_work_cleanup(dev); - } - } - clear_bit(0, &chan->tq_working); - - return; -} - -static int chdlc_work_cleanup(struct net_device *dev) -{ - chdlc_private_area_t* chan = dev->priv; - - ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; - - if (chan->bh_read == MAX_BH_BUFF){ - chan->bh_read=0; - }else{ - ++chan->bh_read; - } - - atomic_dec(&chan->bh_buff_used); - return 0; -} - - - -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb) -{ - /* Check for full */ - chdlc_private_area_t* chan = dev->priv; - sdla_t *card = chan->card; - - if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ - ++card->wandev.stats.rx_dropped; - dev_kfree_skb_any(skb); - return 1; - } - - ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; - - if (chan->bh_write == MAX_BH_BUFF){ - chan->bh_write=0; - }else{ - ++chan->bh_write; - } - - atomic_inc(&chan->bh_buff_used); - - return 0; -} - -/* END OF API BH Support */ - - -/****** Interrupt Handlers **************************************************/ - -/*============================================================================ - * Cisco HDLC interrupt service routine. - */ -static void wpc_isr (sdla_t* card) -{ - struct net_device* dev; - SHARED_MEMORY_INFO_STRUCT* flags = NULL; - int i; - sdla_t *my_card; - - - /* Check for which port the interrupt has been generated - * Since Secondary Port is piggybacking on the Primary - * the check must be done here. - */ - - flags = card->u.c.flags; - if (!flags->interrupt_info_struct.interrupt_type){ - /* Check for a second port (piggybacking) */ - if ((my_card = card->next)){ - flags = my_card->u.c.flags; - if (flags->interrupt_info_struct.interrupt_type){ - card = my_card; - card->isr(card); - return; - } - } - } - - flags = card->u.c.flags; - card->in_isr = 1; - dev = card->wandev.dev; - - /* If we get an interrupt with no network device, stop the interrupts - * and issue an error */ - if (!card->tty_opt && !dev && - flags->interrupt_info_struct.interrupt_type != - COMMAND_COMPLETE_APP_INT_PEND){ - - goto isr_done; - } - - /* if critical due to peripheral operations - * ie. update() or getstats() then reset the interrupt and - * wait for the board to retrigger. - */ - if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { - printk(KERN_INFO "ISR CRIT TO PERI\n"); - goto isr_done; - } - - /* On a 508 Card, if critical due to if_send - * Major Error !!! */ - if(card->hw.type != SDLA_S514) { - if(test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - printk(KERN_INFO "%s: Critical while in ISR: %lx\n", - card->devname, card->wandev.critical); - card->in_isr = 0; - flags->interrupt_info_struct.interrupt_type = 0; - return; - } - } - - switch(flags->interrupt_info_struct.interrupt_type) { - - case RX_APP_INT_PEND: /* 0x01: receive interrupt */ - rx_intr(card); - break; - - case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TX_FRAME; - - if (card->tty_opt){ - wanpipe_tty_trigger_poll(card); - break; - } - - if (dev && netif_queue_stopped(dev)){ - if (card->u.c.usedby == API){ - netif_start_queue(dev); - wakeup_sk_bh(dev); - }else{ - netif_wake_queue(dev); - } - } - break; - - case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ - ++ Intr_test_counter; - break; - - case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ - process_chdlc_exception(card); - break; - - case GLOBAL_EXCEP_COND_APP_INT_PEND: - process_global_exception(card); - break; - - case TIMER_APP_INT_PEND: - timer_intr(card); - break; - - default: - printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", - card->devname, - flags->interrupt_info_struct.interrupt_type); - printk(KERN_INFO "Code name: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codename[i]); - printk(KERN_INFO "\nCode version: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codeversion[i]); - printk(KERN_INFO "\n"); - break; - } - -isr_done: - - card->in_isr = 0; - flags->interrupt_info_struct.interrupt_type = 0; - return; -} - -/*============================================================================ - * Receive interrupt handler. - */ -static void rx_intr (sdla_t* card) -{ - struct net_device *dev; - chdlc_private_area_t *chdlc_priv_area; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; - struct sk_buff *skb; - unsigned len; - unsigned addr = rxbuf->ptr_data_bfr; - void *buf; - int i,udp_type; - - if (rxbuf->opp_flag != 0x01) { - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned)rxbuf, rxbuf->opp_flag); - printk(KERN_INFO "Code name: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codename[i]); - printk(KERN_INFO "\nCode version: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codeversion[i]); - printk(KERN_INFO "\n"); - - - /* Bug Fix: Mar 6 2000 - * If we get a corrupted mailbox, it measn that driver - * is out of sync with the firmware. There is no recovery. - * If we don't turn off all interrupts for this card - * the machine will crash. - */ - printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); - printk(KERN_INFO "Please contact Sangoma Technologies !\n"); - chdlc_set_intr_mode(card,0); - return; - } - - len = rxbuf->frame_length; - - if (card->tty_opt){ - - if (rxbuf->error_flag){ - goto rx_exit; - } - - if (len <= CRC_LENGTH){ - goto rx_exit; - } - - if (!card->u.c.async_mode){ - len -= CRC_LENGTH; - } - - wanpipe_tty_receive(card,addr,len); - goto rx_exit; - } - - dev = card->wandev.dev; - - if (!dev){ - goto rx_exit; - } - - if (!netif_running(dev)) - goto rx_exit; - - chdlc_priv_area = dev->priv; - - - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); - - if (skb == NULL) { - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - ++card->wandev.stats.rx_dropped; - goto rx_exit; - } - - /* Copy data to the socket buffer */ - if((addr + len) > card->u.c.rx_top + 1) { - unsigned tmp = card->u.c.rx_top - addr + 1; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, addr, buf, tmp); - addr = card->u.c.rx_base; - len -= tmp; - } - - buf = skb_put(skb, len); - sdla_peek(&card->hw, addr, buf, len); - - skb->protocol = htons(ETH_P_IP); - - card->wandev.stats.rx_packets ++; - card->wandev.stats.rx_bytes += skb->len; - udp_type = udp_pkt_type( skb, card ); - - if(udp_type == UDP_CPIPE_TYPE) { - if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, - card, skb, dev, chdlc_priv_area)) { - flags->interrupt_info_struct. - interrupt_permission |= - APP_INT_ON_TIMER; - } - } else if(card->u.c.usedby == API) { - - api_rx_hdr_t* api_rx_hdr; - skb_push(skb, sizeof(api_rx_hdr_t)); - api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; - api_rx_hdr->error_flag = rxbuf->error_flag; - api_rx_hdr->time_stamp = rxbuf->time_stamp; - - skb->protocol = htons(PVC_PROT); - skb->mac.raw = skb->data; - skb->dev = dev; - skb->pkt_type = WAN_PACKET_DATA; - - bh_enqueue(dev, skb); - - if (!test_and_set_bit(0,&chdlc_priv_area->tq_working)) - wanpipe_queue_work(&chdlc_priv_area->common.wanpipe_work); - }else{ - /* FIXME: we should check to see if the received packet is a - multicast packet so that we can increment the multicast - statistic - ++ chdlc_priv_area->if_stats.multicast; - */ - /* Pass it up the protocol stack */ - - skb->dev = dev; - skb->mac.raw = skb->data; - netif_rx(skb); - dev->last_rx = jiffies; - } - -rx_exit: - /* Release buffer element and calculate a pointer to the next one */ - rxbuf->opp_flag = 0x00; - card->u.c.rxmb = ++ rxbuf; - if((void*)rxbuf > card->u.c.rxbuf_last){ - card->u.c.rxmb = card->u.c.rxbuf_base; - } -} - -/*============================================================================ - * Timer interrupt handler. - * The timer interrupt is used for two purposes: - * 1) Processing udp calls from 'cpipemon'. - * 2) Reading board-level statistics for updating the proc file system. - */ -void timer_intr(sdla_t *card) -{ - struct net_device* dev; - chdlc_private_area_t* chdlc_priv_area = NULL; - SHARED_MEMORY_INFO_STRUCT* flags = NULL; - - if ((dev = card->wandev.dev)==NULL){ - flags = card->u.c.flags; - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TIMER; - return; - } - - chdlc_priv_area = dev->priv; - - if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) { - if (!config_chdlc(card)){ - chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; - } - } - - /* process a udp call if pending */ - if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) { - process_udp_mgmt_pkt(card, dev, - chdlc_priv_area); - chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; - } - - /* read the communications statistics if required */ - if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) { - update_comms_stats(card, chdlc_priv_area); - if(!(-- chdlc_priv_area->update_comms_stats)) { - chdlc_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - } - } - - /* only disable the timer interrupt if there are no udp or statistic */ - /* updates pending */ - if(!chdlc_priv_area->timer_int_enabled) { - flags = card->u.c.flags; - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TIMER; - } -} - -/*------------------------------------------------------------------------------ - Miscellaneous Functions - - set_chdlc_config() used to set configuration options on the board -------------------------------------------------------------------------------*/ - -static int set_chdlc_config(sdla_t* card) -{ - CHDLC_CONFIGURATION_STRUCT cfg; - - memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); - - if(card->wandev.clocking){ - cfg.baud_rate = card->wandev.bps; - } - - cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? - INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; - - cfg.modem_config_options = 0; - cfg.modem_status_timer = 100; - - cfg.CHDLC_protocol_options = card->u.c.protocol_options; - - if (card->tty_opt){ - cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; - } - - cfg.percent_data_buffer_for_Tx = (card->u.c.receive_only) ? 0 : 50; - cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | - CHDLC_RX_DATA_BYTE_COUNT_STAT); - - if (card->tty_opt){ - card->wandev.mtu = TTY_CHDLC_MAX_MTU; - } - cfg.max_CHDLC_data_field_length = card->wandev.mtu; - cfg.transmit_keepalive_timer = card->u.c.kpalv_tx; - cfg.receive_keepalive_timer = card->u.c.kpalv_rx; - cfg.keepalive_error_tolerance = card->u.c.kpalv_err; - cfg.SLARP_request_timer = card->u.c.slarp_timer; - - if (cfg.SLARP_request_timer) { - cfg.IP_address = 0; - cfg.IP_netmask = 0; - - }else if (card->wandev.dev){ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area = dev->priv; - - struct in_device *in_dev = dev->ip_ptr; - - if(in_dev != NULL) { - struct in_ifaddr *ifa = in_dev->ifa_list; - - if (ifa != NULL ) { - cfg.IP_address = ntohl(ifa->ifa_local); - cfg.IP_netmask = ntohl(ifa->ifa_mask); - chdlc_priv_area->IP_address = ntohl(ifa->ifa_local); - chdlc_priv_area->IP_netmask = ntohl(ifa->ifa_mask); - } - } - - /* FIXME: We must re-think this message in next release - if((cfg.IP_address & 0x000000FF) > 2) { - printk(KERN_WARNING "\n"); - printk(KERN_WARNING " WARNING:%s configured with an\n", - card->devname); - printk(KERN_WARNING " invalid local IP address.\n"); - printk(KERN_WARNING " Slarp pragmatics will fail.\n"); - printk(KERN_WARNING " IP address should be of the\n"); - printk(KERN_WARNING " format A.B.C.1 or A.B.C.2.\n"); - } - */ - } - - return chdlc_configure(card, &cfg); -} - - -/*----------------------------------------------------------------------------- - set_asy_config() used to set asynchronous configuration options on the board -------------------------------------------------------------------------------*/ - -static int set_asy_config(sdla_t* card) -{ - - ASY_CONFIGURATION_STRUCT cfg; - CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; - int err; - - memset(&cfg, 0, sizeof(ASY_CONFIGURATION_STRUCT)); - - if(card->wandev.clocking) - cfg.baud_rate = card->wandev.bps; - - cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? - INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; - - cfg.modem_config_options = 0; - cfg.asy_API_options = card->u.c.api_options; - cfg.asy_protocol_options = card->u.c.protocol_options; - cfg.Tx_bits_per_char = card->u.c.tx_bits_per_char; - cfg.Rx_bits_per_char = card->u.c.rx_bits_per_char; - cfg.stop_bits = card->u.c.stop_bits; - cfg.parity = card->u.c.parity; - cfg.break_timer = card->u.c.break_timer; - cfg.asy_Rx_inter_char_timer = card->u.c.inter_char_timer; - cfg.asy_Rx_complete_length = card->u.c.rx_complete_length; - cfg.XON_char = card->u.c.xon_char; - cfg.XOFF_char = card->u.c.xoff_char; - cfg.asy_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | - CHDLC_RX_DATA_BYTE_COUNT_STAT); - - mailbox->buffer_length = sizeof(ASY_CONFIGURATION_STRUCT); - memcpy(mailbox->data, &cfg, mailbox->buffer_length); - mailbox->command = SET_ASY_CONFIGURATION; - err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error (card, err, mailbox); - return err; -} - -/*============================================================================ - * Enable asynchronous communications. - */ - -static int asy_comm_enable (sdla_t* card) -{ - - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = ENABLE_ASY_COMMUNICATIONS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK && card->wandev.dev) - chdlc_error(card, err, mb); - - if (!err) - card->u.c.comm_enabled = 1; - - return err; -} - -/*============================================================================ - * Process global exception condition - */ -static int process_global_exception(sdla_t *card) -{ - CHDLC_MAILBOX_STRUCT* mbox = card->mbox; - int err; - - mbox->buffer_length = 0; - mbox->command = READ_GLOBAL_EXCEPTION_CONDITION; - err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; - - if(err != CMD_TIMEOUT ){ - - switch(mbox->return_code) { - - case EXCEP_MODEM_STATUS_CHANGE: - - printk(KERN_INFO "%s: Modem status change\n", - card->devname); - - switch(mbox->data[0] & (DCD_HIGH | CTS_HIGH)) { - case (DCD_HIGH): - printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); - break; - case (CTS_HIGH): - printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); - break; - case ((DCD_HIGH | CTS_HIGH)): - printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); - break; - default: - printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); - break; - } - break; - - case EXCEP_TRC_DISABLED: - printk(KERN_INFO "%s: Line trace disabled\n", - card->devname); - break; - - case EXCEP_IRQ_TIMEOUT: - printk(KERN_INFO "%s: IRQ timeout occurred\n", - card->devname); - break; - - case 0x17: - if (card->tty_opt){ - if (card->tty && card->tty_open){ - printk(KERN_INFO - "%s: Modem Hangup Exception: Hanging Up!\n", - card->devname); - tty_hangup(card->tty); - } - break; - } - - /* If TTY is not used just drop throught */ - - default: - printk(KERN_INFO "%s: Global exception %x\n", - card->devname, mbox->return_code); - break; - } - } - return 0; -} - - -/*============================================================================ - * Process chdlc exception condition - */ -static int process_chdlc_exception(sdla_t *card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int err; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_EXCEPTION_CONDITION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if(err != CMD_TIMEOUT) { - - switch (err) { - - case EXCEP_LINK_ACTIVE: - port_set_state(card, WAN_CONNECTED); - trigger_chdlc_poll(card->wandev.dev); - break; - - case EXCEP_LINK_INACTIVE_MODEM: - port_set_state(card, WAN_DISCONNECTED); - unconfigure_ip(card); - trigger_chdlc_poll(card->wandev.dev); - break; - - case EXCEP_LINK_INACTIVE_KPALV: - port_set_state(card, WAN_DISCONNECTED); - printk(KERN_INFO "%s: Keepalive timer expired.\n", - card->devname); - unconfigure_ip(card); - trigger_chdlc_poll(card->wandev.dev); - break; - - case EXCEP_IP_ADDRESS_DISCOVERED: - if (configure_ip(card)) - return -1; - break; - - case EXCEP_LOOPBACK_CONDITION: - printk(KERN_INFO "%s: Loopback Condition Detected.\n", - card->devname); - break; - - case NO_CHDLC_EXCEP_COND_TO_REPORT: - printk(KERN_INFO "%s: No exceptions reported.\n", - card->devname); - break; - } - - } - return 0; -} - - -/*============================================================================ - * Configure IP from SLARP negotiation - * This adds dynamic routes when SLARP has provided valid addresses - */ - -static int configure_ip (sdla_t* card) -{ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area; - char err; - - if (!dev) - return 0; - - chdlc_priv_area = dev->priv; - - - /* set to discover */ - if(card->u.c.slarp_timer != 0x00) { - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_CONFIGURATION_STRUCT *cfg; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - chdlc_error(card,err,mb); - return -1; - } - - cfg = (CHDLC_CONFIGURATION_STRUCT *)mb->data; - chdlc_priv_area->IP_address = cfg->IP_address; - chdlc_priv_area->IP_netmask = cfg->IP_netmask; - - /* Set flag to add route */ - chdlc_priv_area->route_status = ADD_ROUTE; - - /* The idea here is to add the route in the poll routine. - This way, we aren't in interrupt context when adding routes */ - trigger_chdlc_poll(dev); - } - - return 0; -} - - -/*============================================================================ - * Un-Configure IP negotiated by SLARP - * This removes dynamic routes when the link becomes inactive. - */ - -static int unconfigure_ip (sdla_t* card) -{ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area; - - if (!dev) - return 0; - - chdlc_priv_area= dev->priv; - - if (chdlc_priv_area->route_status == ROUTE_ADDED) { - - /* Note: If this function is called, the - * port state has been DISCONNECTED. This state - * change will trigger a poll_disconnected - * function, that will check for this condition. - */ - chdlc_priv_area->route_status = REMOVE_ROUTE; - - } - return 0; -} - -/*============================================================================ - * Routine to add/remove routes - * Called like a polling routine when Routes are flagged to be added/removed. - */ - -static void process_route (sdla_t *card) -{ - struct net_device *dev = card->wandev.dev; - unsigned char port_num; - chdlc_private_area_t *chdlc_priv_area = NULL; - u32 local_IP_addr = 0; - u32 remote_IP_addr = 0; - u32 IP_netmask, IP_addr; - int err = 0; - struct in_device *in_dev; - mm_segment_t fs; - struct ifreq if_info; - struct sockaddr_in *if_data1, *if_data2; - - chdlc_priv_area = dev->priv; - port_num = card->u.c.comm_port; - - /* Bug Fix Mar 16 2000 - * AND the IP address to the Mask before checking - * the last two bits. */ - - if((chdlc_priv_area->route_status == ADD_ROUTE) && - ((chdlc_priv_area->IP_address & ~chdlc_priv_area->IP_netmask) > 2)) { - - printk(KERN_INFO "%s: Dynamic route failure.\n",card->devname); - - if(card->u.c.slarp_timer) { - u32 addr_net = htonl(chdlc_priv_area->IP_address); - - printk(KERN_INFO "%s: Bad IP address %u.%u.%u.%u received\n", - card->devname, - NIPQUAD(addr_net)); - printk(KERN_INFO "%s: from remote station.\n", - card->devname); - - }else{ - u32 addr_net = htonl(chdlc_priv_area->IP_address); - - printk(KERN_INFO "%s: Bad IP address %u.%u.%u.%u issued\n", - card->devname, - NIPQUAD(addr_net)); - printk(KERN_INFO "%s: to remote station. Local\n", - card->devname); - printk(KERN_INFO "%s: IP address must be A.B.C.1\n", - card->devname); - printk(KERN_INFO "%s: or A.B.C.2.\n",card->devname); - } - - /* remove the route due to the IP address error condition */ - chdlc_priv_area->route_status = REMOVE_ROUTE; - err = 1; - } - - /* If we are removing a route with bad IP addressing, then use the */ - /* locally configured IP addresses */ - if((chdlc_priv_area->route_status == REMOVE_ROUTE) && err) { - - /* do not remove a bad route that has already been removed */ - if(chdlc_priv_area->route_removed) { - return; - } - - in_dev = dev->ip_ptr; - - if(in_dev != NULL) { - struct in_ifaddr *ifa = in_dev->ifa_list; - if (ifa != NULL ) { - local_IP_addr = ifa->ifa_local; - IP_netmask = ifa->ifa_mask; - } - } - }else{ - /* According to Cisco HDLC, if the point-to-point address is - A.B.C.1, then we are the opposite (A.B.C.2), and vice-versa. - */ - IP_netmask = ntohl(chdlc_priv_area->IP_netmask); - remote_IP_addr = ntohl(chdlc_priv_area->IP_address); - - - /* If Netmask is 255.255.255.255 the local address - * calculation will fail. Default it back to 255.255.255.0 */ - if (IP_netmask == 0xffffffff) - IP_netmask &= 0x00ffffff; - - /* Bug Fix Mar 16 2000 - * AND the Remote IP address with IP netmask, instead - * of static netmask of 255.255.255.0 */ - local_IP_addr = (remote_IP_addr & IP_netmask) + - (~remote_IP_addr & ntohl(0x0003)); - - if(!card->u.c.slarp_timer) { - IP_addr = local_IP_addr; - local_IP_addr = remote_IP_addr; - remote_IP_addr = IP_addr; - } - } - - fs = get_fs(); /* Save file system */ - set_fs(get_ds()); /* Get user space block */ - - /* Setup a structure for adding/removing routes */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - - switch (chdlc_priv_area->route_status) { - - case ADD_ROUTE: - - if(!card->u.c.slarp_timer) { - if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data2->sin_addr.s_addr = remote_IP_addr; - if_data2->sin_family = AF_INET; - err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); - } else { - if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; - if_data1->sin_addr.s_addr = local_IP_addr; - if_data1->sin_family = AF_INET; - if(!(err = devinet_ioctl(SIOCSIFADDR, &if_info))){ - if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data2->sin_addr.s_addr = remote_IP_addr; - if_data2->sin_family = AF_INET; - err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); - } - } - - if(err) { - printk(KERN_INFO "%s: Add route %u.%u.%u.%u failed (%d)\n", - card->devname, NIPQUAD(remote_IP_addr), err); - } else { - ((chdlc_private_area_t *)dev->priv)->route_status = ROUTE_ADDED; - printk(KERN_INFO "%s: Dynamic route added.\n", - card->devname); - printk(KERN_INFO "%s: Local IP addr : %u.%u.%u.%u\n", - card->devname, NIPQUAD(local_IP_addr)); - printk(KERN_INFO "%s: Remote IP addr: %u.%u.%u.%u\n", - card->devname, NIPQUAD(remote_IP_addr)); - chdlc_priv_area->route_removed = 0; - } - break; - - - case REMOVE_ROUTE: - - /* Change the local ip address of the interface to 0. - * This will also delete the destination route. - */ - if(!card->u.c.slarp_timer) { - if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data2->sin_addr.s_addr = 0; - if_data2->sin_family = AF_INET; - err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); - } else { - if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; - if_data1->sin_addr.s_addr = 0; - if_data1->sin_family = AF_INET; - err = devinet_ioctl(SIOCSIFADDR,&if_info); - - } - if(err) { - printk(KERN_INFO - "%s: Remove route %u.%u.%u.%u failed, (err %d)\n", - card->devname, NIPQUAD(remote_IP_addr), - err); - } else { - ((chdlc_private_area_t *)dev->priv)->route_status = - NO_ROUTE; - printk(KERN_INFO "%s: Dynamic route removed: %u.%u.%u.%u\n", - card->devname, NIPQUAD(local_IP_addr)); - chdlc_priv_area->route_removed = 1; - } - break; - } - - set_fs(fs); /* Restore file system */ - -} - - -/*============================================================================= - * Store a UDP management packet for later processing. - */ - -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area) -{ - int udp_pkt_stored = 0; - - if(!chdlc_priv_area->udp_pkt_lgth && - (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { - chdlc_priv_area->udp_pkt_lgth = skb->len; - chdlc_priv_area->udp_pkt_src = udp_pkt_src; - memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len); - chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UDP; - udp_pkt_stored = 1; - } - - if(udp_pkt_src == UDP_PKT_FRM_STACK){ - dev_kfree_skb_any(skb); - }else{ - dev_kfree_skb_any(skb); - } - - return(udp_pkt_stored); -} - - -/*============================================================================= - * Process UDP management packet. - */ - -static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area ) -{ - unsigned char *buf; - unsigned int frames, len; - struct sk_buff *new_skb; - unsigned short buffer_length, real_len; - unsigned long data_ptr; - unsigned data_length; - int udp_mgmt_req_valid = 1; - CHDLC_MAILBOX_STRUCT *mb = card->mbox; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - chdlc_udp_pkt_t *chdlc_udp_pkt; - struct timeval tv; - int err; - char ut_char; - - chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data; - - if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ - - /* Only these commands are support for remote debugging. - * All others are not */ - switch(chdlc_udp_pkt->cblock.command) { - - case READ_GLOBAL_STATISTICS: - case READ_MODEM_STATUS: - case READ_CHDLC_LINK_STATUS: - case CPIPE_ROUTER_UP_TIME: - case READ_COMMS_ERROR_STATS: - case READ_CHDLC_OPERATIONAL_STATS: - - /* These two commands are executed for - * each request */ - case READ_CHDLC_CONFIGURATION: - case READ_CHDLC_CODE_VERSION: - udp_mgmt_req_valid = 1; - break; - default: - udp_mgmt_req_valid = 0; - break; - } - } - - if(!udp_mgmt_req_valid) { - - /* set length to 0 */ - chdlc_udp_pkt->cblock.buffer_length = 0; - - /* set return code */ - chdlc_udp_pkt->cblock.return_code = 0xCD; - - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Warning, Illegal UDP command attempted from network: %x\n", - card->devname,chdlc_udp_pkt->cblock.command); - } - - } else { - unsigned long trace_status_cfg_addr = 0; - TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; - TRACE_STATUS_ELEMENT_STRUCT trace_element_struct; - - switch(chdlc_udp_pkt->cblock.command) { - - case CPIPE_ENABLE_TRACING: - if (!chdlc_priv_area->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - - mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); - mb->command = SET_TRACE_CONFIGURATION; - - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_config = TRACE_ACTIVE; - /* Trace delay mode is not used because it slows - down transfer and results in a standoff situation - when there is a lot of data */ - - /* Configure the Trace based on user inputs */ - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->trace_config |= - chdlc_udp_pkt->data[0]; - - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_deactivation_timer = 4000; - - - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) { - chdlc_error(card,err,mb); - card->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = err; - mb->buffer_length = 0; - break; - } - - /* Get the base address of the trace element list */ - mb->buffer_length = 0; - mb->command = READ_TRACE_CONFIGURATION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if (err != COMMAND_OK) { - chdlc_error(card,err,mb); - chdlc_priv_area->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = err; - mb->buffer_length = 0; - break; - } - - trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *) - mb->data) -> ptr_trace_stat_el_cfg_struct; - - sdla_peek(&card->hw, trace_status_cfg_addr, - &trace_cfg_struct, sizeof(trace_cfg_struct)); - - chdlc_priv_area->start_trace_addr = trace_cfg_struct. - base_addr_trace_status_elements; - - chdlc_priv_area->number_trace_elements = - trace_cfg_struct.number_trace_status_elements; - - chdlc_priv_area->end_trace_addr = (unsigned long) - ((TRACE_STATUS_ELEMENT_STRUCT *) - chdlc_priv_area->start_trace_addr + - (chdlc_priv_area->number_trace_elements - 1)); - - chdlc_priv_area->base_addr_trace_buffer = - trace_cfg_struct.base_addr_trace_buffer; - - chdlc_priv_area->end_addr_trace_buffer = - trace_cfg_struct.end_addr_trace_buffer; - - chdlc_priv_area->curr_trace_addr = - trace_cfg_struct.next_trace_element_to_use; - - chdlc_priv_area->available_buffer_space = 2000 - - sizeof(ip_pkt_t) - - sizeof(udp_pkt_t) - - sizeof(wp_mgmt_t) - - sizeof(cblock_t) - - sizeof(trace_info_t); - } - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - mb->buffer_length = 0; - chdlc_priv_area->TracingEnabled = 1; - break; - - - case CPIPE_DISABLE_TRACING: - if (chdlc_priv_area->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); - mb->command = SET_TRACE_CONFIGURATION; - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_config = TRACE_INACTIVE; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - } - - chdlc_priv_area->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - mb->buffer_length = 0; - break; - - - case CPIPE_GET_TRACE_INFO: - - if (!chdlc_priv_area->TracingEnabled) { - chdlc_udp_pkt->cblock.return_code = 1; - mb->buffer_length = 0; - break; - } - - chdlc_udp_pkt->trace_info.ismoredata = 0x00; - buffer_length = 0; /* offset of packet already occupied */ - - for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){ - - trace_pkt_t *trace_pkt = (trace_pkt_t *) - &chdlc_udp_pkt->data[buffer_length]; - - sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr, - (unsigned char *)&trace_element_struct, - sizeof(TRACE_STATUS_ELEMENT_STRUCT)); - - if (trace_element_struct.opp_flag == 0x00) { - break; - } - - /* get pointer to real data */ - data_ptr = trace_element_struct.ptr_data_bfr; - - /* See if there is actual data on the trace buffer */ - if (data_ptr){ - data_length = trace_element_struct.trace_length; - }else{ - data_length = 0; - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - } - - if( (chdlc_priv_area->available_buffer_space - buffer_length) - < ( sizeof(trace_pkt_t) + data_length) ) { - - /* indicate there are more frames on board & exit */ - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - break; - } - - trace_pkt->status = trace_element_struct.trace_type; - - trace_pkt->time_stamp = - trace_element_struct.trace_time_stamp; - - trace_pkt->real_length = - trace_element_struct.trace_length; - - /* see if we can fit the frame into the user buffer */ - real_len = trace_pkt->real_length; - - if (data_ptr == 0) { - trace_pkt->data_avail = 0x00; - } else { - unsigned tmp = 0; - - /* get the data from circular buffer - must check for end of buffer */ - trace_pkt->data_avail = 0x01; - - if ((data_ptr + real_len) > - chdlc_priv_area->end_addr_trace_buffer + 1){ - - tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1; - sdla_peek(&card->hw, data_ptr, - trace_pkt->data,tmp); - data_ptr = chdlc_priv_area->base_addr_trace_buffer; - } - - sdla_peek(&card->hw, data_ptr, - &trace_pkt->data[tmp], real_len - tmp); - } - - /* zero the opp flag to show we got the frame */ - ut_char = 0x00; - sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &ut_char, 1); - - /* now move onto the next frame */ - chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT); - - /* check if we went over the last address */ - if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) { - chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; - } - - if(trace_pkt->data_avail == 0x01) { - buffer_length += real_len - 1; - } - - /* for the header */ - buffer_length += sizeof(trace_pkt_t); - - } /* For Loop */ - - if (frames == chdlc_priv_area->number_trace_elements){ - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - } - chdlc_udp_pkt->trace_info.num_frames = frames; - - mb->buffer_length = buffer_length; - chdlc_udp_pkt->cblock.buffer_length = buffer_length; - - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - - break; - - - case CPIPE_FT1_READ_STATUS: - ((unsigned char *)chdlc_udp_pkt->data )[0] = - flags->FT1_info_struct.parallel_port_A_input; - - ((unsigned char *)chdlc_udp_pkt->data )[1] = - flags->FT1_info_struct.parallel_port_B_input; - - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - chdlc_udp_pkt->cblock.buffer_length = 2; - mb->buffer_length = 2; - break; - - case CPIPE_ROUTER_UP_TIME: - do_gettimeofday( &tv ); - chdlc_priv_area->router_up_time = tv.tv_sec - - chdlc_priv_area->router_start_time; - *(unsigned long *)&chdlc_udp_pkt->data = - chdlc_priv_area->router_up_time; - mb->buffer_length = sizeof(unsigned long); - chdlc_udp_pkt->cblock.buffer_length = sizeof(unsigned long); - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - break; - - case FT1_MONITOR_STATUS_CTRL: - /* Enable FT1 MONITOR STATUS */ - if ((chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_STATUS) || - (chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_OP_STATS)) { - - if( rCount++ != 0 ) { - chdlc_udp_pkt->cblock. - return_code = COMMAND_OK; - mb->buffer_length = 1; - break; - } - } - - /* Disable FT1 MONITOR STATUS */ - if( chdlc_udp_pkt->data[0] == 0) { - - if( --rCount != 0) { - chdlc_udp_pkt->cblock. - return_code = COMMAND_OK; - mb->buffer_length = 1; - break; - } - } - goto dflt_1; - - default: -dflt_1: - /* it's a board command */ - mb->command = chdlc_udp_pkt->cblock.command; - mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length; - if (mb->buffer_length) { - memcpy(&mb->data, (unsigned char *) chdlc_udp_pkt-> - data, mb->buffer_length); - } - /* run the command on the board */ - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) { - break; - } - - /* copy the result back to our buffer */ - memcpy(&chdlc_udp_pkt->cblock, mb, sizeof(cblock_t)); - - if (mb->buffer_length) { - memcpy(&chdlc_udp_pkt->data, &mb->data, - mb->buffer_length); - } - - } /* end of switch */ - } /* end of else */ - - /* Fill UDP TTL */ - chdlc_udp_pkt->ip_pkt.ttl = card->wandev.ttl; - - len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length); - - - if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ - - /* Must check if we interrupted if_send() routine. The - * tx buffers might be used. If so drop the packet */ - if (!test_bit(SEND_CRIT,&card->wandev.critical)) { - - if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) { - ++ card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += len; - } - } - } else { - - /* Pass it up the stack - Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) { - /* copy data into new_skb */ - - buf = skb_put(new_skb, len); - memcpy(buf, chdlc_priv_area->udp_pkt_data, len); - - /* Decapsulate pkt and pass it up the protocol stack */ - new_skb->protocol = htons(ETH_P_IP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; - - netif_rx(new_skb); - dev->last_rx = jiffies; - } else { - - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - } - } - - chdlc_priv_area->udp_pkt_lgth = 0; - - return 0; -} - -/*============================================================================ - * Initialize Receive and Transmit Buffers. - */ - -static void init_chdlc_tx_rx_buff( sdla_t* card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; - CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config; - char err; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - if (card->wandev.dev){ - chdlc_error(card,err,mb); - } - return; - } - - if(card->hw.type == SDLA_S514) { - tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Tx_stat_el_cfg_struct)); - rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Rx_stat_el_cfg_struct)); - - /* Setup Head and Tails for buffers */ - card->u.c.txbuf_base = (void *)(card->hw.dpmbase + - tx_config->base_addr_Tx_status_elements); - card->u.c.txbuf_last = - (CHDLC_DATA_TX_STATUS_EL_STRUCT *) - card->u.c.txbuf_base + - (tx_config->number_Tx_status_elements - 1); - - card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + - rx_config->base_addr_Rx_status_elements); - card->u.c.rxbuf_last = - (CHDLC_DATA_RX_STATUS_EL_STRUCT *) - card->u.c.rxbuf_base + - (rx_config->number_Rx_status_elements - 1); - - /* Set up next pointer to be used */ - card->u.c.txbuf = (void *)(card->hw.dpmbase + - tx_config->next_Tx_status_element_to_use); - card->u.c.rxmb = (void *)(card->hw.dpmbase + - rx_config->next_Rx_status_element_to_use); - } - else { - tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); - - rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); - - /* Setup Head and Tails for buffers */ - card->u.c.txbuf_base = (void *)(card->hw.dpmbase + - (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE)); - card->u.c.txbuf_last = - (CHDLC_DATA_TX_STATUS_EL_STRUCT *)card->u.c.txbuf_base - + (tx_config->number_Tx_status_elements - 1); - card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + - (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE)); - card->u.c.rxbuf_last = - (CHDLC_DATA_RX_STATUS_EL_STRUCT *)card->u.c.rxbuf_base - + (rx_config->number_Rx_status_elements - 1); - - /* Set up next pointer to be used */ - card->u.c.txbuf = (void *)(card->hw.dpmbase + - (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE)); - card->u.c.rxmb = (void *)(card->hw.dpmbase + - (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE)); - } - - /* Setup Actual Buffer Start and end addresses */ - card->u.c.rx_base = rx_config->base_addr_Rx_buffer; - card->u.c.rx_top = rx_config->end_addr_Rx_buffer; - -} - -/*============================================================================= - * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR - * _TEST_COUNTER times. - */ -static int intr_test( sdla_t* card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int err,i; - - Intr_test_counter = 0; - - err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); - - if (err == CMD_OK) { - for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { - mb->buffer_length = 0; - mb->command = READ_CHDLC_CODE_VERSION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != CMD_OK) - chdlc_error(card, err, mb); - } - } - else { - return err; - } - - err = chdlc_set_intr_mode(card, 0); - - if (err != CMD_OK) - return err; - - return 0; -} - -/*============================================================================== - * Determine what type of UDP call it is. CPIPEAB ? - */ -static int udp_pkt_type(struct sk_buff *skb, sdla_t* card) -{ - chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data; - -#ifdef _WAN_UDP_DEBUG - printk(KERN_INFO "SIG %s = %s\n\ - UPP %x = %x\n\ - PRT %x = %x\n\ - REQ %i = %i\n\ - 36 th = %x 37th = %x\n", - chdlc_udp_pkt->wp_mgmt.signature, - UDPMGMT_SIGNATURE, - chdlc_udp_pkt->udp_pkt.udp_dst_port, - ntohs(card->wandev.udp_port), - chdlc_udp_pkt->ip_pkt.protocol, - UDPMGMT_UDP_PROTOCOL, - chdlc_udp_pkt->wp_mgmt.request_reply, - UDPMGMT_REQUEST, - skb->data[36], skb->data[37]); -#endif - - if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) && - (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && - (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && - (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { - - return UDP_CPIPE_TYPE; - - }else{ - return UDP_INVALID_TYPE; - } -} - -/*============================================================================ - * Set PORT state. - */ -static void port_set_state (sdla_t *card, int state) -{ - if (card->u.c.state != state) - { - switch (state) - { - case WAN_CONNECTED: - printk (KERN_INFO "%s: Link connected!\n", - card->devname); - break; - - case WAN_CONNECTING: - printk (KERN_INFO "%s: Link connecting...\n", - card->devname); - break; - - case WAN_DISCONNECTED: - printk (KERN_INFO "%s: Link disconnected!\n", - card->devname); - break; - } - - card->wandev.state = card->u.c.state = state; - if (card->wandev.dev){ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area = dev->priv; - chdlc_priv_area->common.state = state; - } - } -} - -/*=========================================================================== - * config_chdlc - * - * Configure the chdlc protocol and enable communications. - * - * The if_open() function binds this function to the poll routine. - * Therefore, this function will run every time the chdlc interface - * is brought up. We cannot run this function from the if_open - * because if_open does not have access to the remote IP address. - * - * If the communications are not enabled, proceed to configure - * the card and enable communications. - * - * If the communications are enabled, it means that the interface - * was shutdown by ether the user or driver. In this case, we - * have to check that the IP addresses have not changed. If - * the IP addresses have changed, we have to reconfigure the firmware - * and update the changed IP addresses. Otherwise, just exit. - * - */ - -static int config_chdlc (sdla_t *card) -{ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area = dev->priv; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - - if (card->u.c.comm_enabled){ - - /* Jun 20. 2000: NC - * IP addresses are not used in the API mode */ - - if ((chdlc_priv_area->ip_local_tmp != chdlc_priv_area->ip_local || - chdlc_priv_area->ip_remote_tmp != chdlc_priv_area->ip_remote) && - card->u.c.usedby == WANPIPE) { - - /* The IP addersses have changed, we must - * stop the communications and reconfigure - * the card. Reason: the firmware must know - * the local and remote IP addresses. */ - disable_comm(card); - port_set_state(card, WAN_DISCONNECTED); - printk(KERN_INFO - "%s: IP addresses changed!\n", - card->devname); - printk(KERN_INFO - "%s: Restarting communications ...\n", - card->devname); - }else{ - /* IP addresses are the same and the link is up, - * we don't have to do anything here. Therefore, exit */ - return 0; - } - } - - chdlc_priv_area->ip_local = chdlc_priv_area->ip_local_tmp; - chdlc_priv_area->ip_remote = chdlc_priv_area->ip_remote_tmp; - - - /* Setup the Board for asynchronous mode */ - if (card->u.c.async_mode){ - - if (set_asy_config(card)) { - printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n", - card->devname); - return 0; - } - }else{ - /* Setup the Board for CHDLC */ - if (set_chdlc_config(card)) { - printk (KERN_INFO "%s: Failed CHDLC configuration!\n", - card->devname); - return 0; - } - } - - /* Set interrupt mode and mask */ - if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | - APP_INT_ON_GLOBAL_EXCEP_COND | - APP_INT_ON_TX_FRAME | - APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ - printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", - card->devname); - return 0; - } - - - /* Mask the Transmit and Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); - - /* In TTY mode, receive interrupt will be enabled during - * wanpipe_tty_open() operation */ - if (card->tty_opt){ - flags->interrupt_info_struct.interrupt_permission &= ~APP_INT_ON_RX_FRAME; - } - - /* Enable communications */ - if (card->u.c.async_mode){ - if (asy_comm_enable(card) != 0) { - printk(KERN_INFO "%s: Failed to enable async commnunication!\n", - card->devname); - flags->interrupt_info_struct.interrupt_permission = 0; - card->u.c.comm_enabled=0; - chdlc_set_intr_mode(card,0); - return 0; - } - }else{ - if (chdlc_comm_enable(card) != 0) { - printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", - card->devname); - flags->interrupt_info_struct.interrupt_permission = 0; - card->u.c.comm_enabled=0; - chdlc_set_intr_mode(card,0); - return 0; - } - } - - /* Initialize Rx/Tx buffer control fields */ - init_chdlc_tx_rx_buff(card); - port_set_state(card, WAN_CONNECTING); - return 0; -} - - -/*============================================================ - * chdlc_poll - * - * Rationale: - * We cannot manipulate the routing tables, or - * ip addresses withing the interrupt. Therefore - * we must perform such actons outside an interrupt - * at a later time. - * - * Description: - * CHDLC polling routine, responsible for - * shutting down interfaces upon disconnect - * and adding/removing routes. - * - * Usage: - * This function is executed for each CHDLC - * interface through a tq_schedule bottom half. - * - * trigger_chdlc_poll() function is used to kick - * the chldc_poll routine. - */ - -static void chdlc_poll(struct net_device *dev) -{ - chdlc_private_area_t *chdlc_priv_area; - sdla_t *card; - u8 check_gateway=0; - SHARED_MEMORY_INFO_STRUCT* flags; - - - if (!dev || (chdlc_priv_area=dev->priv) == NULL) - return; - - card = chdlc_priv_area->card; - flags = card->u.c.flags; - - /* (Re)Configuraiton is in progress, stop what you are - * doing and get out */ - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - clear_bit(POLL_CRIT,&card->wandev.critical); - return; - } - - /* if_open() function has triggered the polling routine - * to determine the configured IP addresses. Once the - * addresses are found, trigger the chdlc configuration */ - if (test_bit(0,&chdlc_priv_area->config_chdlc)){ - - chdlc_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP); - chdlc_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); - - /* Jun 20. 2000 Bug Fix - * Only perform this check in WANPIPE mode, since - * IP addresses are not used in the API mode. */ - - if (chdlc_priv_area->ip_local_tmp == chdlc_priv_area->ip_remote_tmp && - card->u.c.slarp_timer == 0x00 && - !card->u.c.backup && - card->u.c.usedby == WANPIPE){ - - if (++chdlc_priv_area->ip_error > MAX_IP_ERRORS){ - printk(KERN_INFO "\n%s: --- WARNING ---\n", - card->devname); - printk(KERN_INFO - "%s: The local IP address is the same as the\n", - card->devname); - printk(KERN_INFO - "%s: Point-to-Point IP address.\n", - card->devname); - printk(KERN_INFO "%s: --- WARNING ---\n\n", - card->devname); - }else{ - clear_bit(POLL_CRIT,&card->wandev.critical); - chdlc_priv_area->poll_delay_timer.expires = jiffies+HZ; - add_timer(&chdlc_priv_area->poll_delay_timer); - return; - } - } - - clear_bit(0,&chdlc_priv_area->config_chdlc); - clear_bit(POLL_CRIT,&card->wandev.critical); - - chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; - flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; - return; - } - /* Dynamic interface implementation, as well as dynamic - * routing. */ - - switch (card->u.c.state){ - - case WAN_DISCONNECTED: - - /* If the dynamic interface configuration is on, and interface - * is up, then bring down the netowrk interface */ - - if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) && - !test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) && - card->wandev.dev->flags & IFF_UP){ - - printk(KERN_INFO "%s: Interface %s down.\n", - card->devname,card->wandev.dev->name); - change_dev_flags(card->wandev.dev,(card->wandev.dev->flags&~IFF_UP)); - set_bit(DEV_DOWN,&chdlc_priv_area->interface_down); - chdlc_priv_area->route_status = NO_ROUTE; - - }else{ - /* We need to check if the local IP address is - * zero. If it is, we shouldn't try to remove it. - */ - - if (card->wandev.dev->flags & IFF_UP && - get_ip_address(card->wandev.dev,WAN_LOCAL_IP) && - chdlc_priv_area->route_status != NO_ROUTE && - card->u.c.slarp_timer){ - - process_route(card); - } - } - break; - - case WAN_CONNECTED: - - /* In SMP machine this code can execute before the interface - * comes up. In this case, we must make sure that we do not - * try to bring up the interface before dev_open() is finished */ - - - /* DEV_DOWN will be set only when we bring down the interface - * for the very first time. This way we know that it was us - * that brought the interface down */ - - if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) && - test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) && - !(card->wandev.dev->flags & IFF_UP)){ - - printk(KERN_INFO "%s: Interface %s up.\n", - card->devname,card->wandev.dev->name); - change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP)); - clear_bit(DEV_DOWN,&chdlc_priv_area->interface_down); - check_gateway=1; - } - - if (chdlc_priv_area->route_status == ADD_ROUTE && - card->u.c.slarp_timer){ - - process_route(card); - check_gateway=1; - } - - if (chdlc_priv_area->gateway && check_gateway) - add_gateway(card,dev); - - break; - } - - clear_bit(POLL_CRIT,&card->wandev.critical); -} - -/*============================================================ - * trigger_chdlc_poll - * - * Description: - * Add a chdlc_poll() work entry into the keventd work queue - * for a specific dlci/interface. This will kick - * the fr_poll() routine at a later time. - * - * Usage: - * Interrupts use this to defer a taks to - * a polling routine. - * - */ -static void trigger_chdlc_poll(struct net_device *dev) -{ - chdlc_private_area_t *chdlc_priv_area; - sdla_t *card; - - if (!dev) - return; - - if ((chdlc_priv_area = dev->priv)==NULL) - return; - - card = chdlc_priv_area->card; - - if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ - return; - } - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - return; - } - schedule_work(&chdlc_priv_area->poll_work); -} - - -static void chdlc_poll_delay (unsigned long dev_ptr) -{ - struct net_device *dev = (struct net_device *)dev_ptr; - trigger_chdlc_poll(dev); -} - - -void s508_lock (sdla_t *card, unsigned long *smp_flags) -{ - spin_lock_irqsave(&card->wandev.lock, *smp_flags); - if (card->next){ - spin_lock(&card->next->wandev.lock); - } -} - -void s508_unlock (sdla_t *card, unsigned long *smp_flags) -{ - if (card->next){ - spin_unlock(&card->next->wandev.lock); - } - spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); -} - -//*********** TTY SECTION **************** - -static void wanpipe_tty_trigger_tx_irq(sdla_t *card) -{ - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; - chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; -} - -static void wanpipe_tty_trigger_poll(sdla_t *card) -{ - schedule_work(&card->tty_work); -} - -static void tty_poll_work (void* data) -{ - sdla_t *card = (sdla_t*)data; - struct tty_struct *tty; - - if ((tty=card->tty)==NULL) - return; - - tty_wakeup(tty); -#if defined(SERIAL_HAVE_POLL_WAIT) - wake_up_interruptible(&tty->poll_wait); -#endif - return; -} - -static void wanpipe_tty_close(struct tty_struct *tty, struct file * filp) -{ - sdla_t *card; - unsigned long smp_flags; - - if (!tty || !tty->driver_data){ - return; - } - - card = (sdla_t*)tty->driver_data; - - if (!card) - return; - - printk(KERN_INFO "%s: Closing TTY Driver!\n", - card->devname); - - /* Sanity Check */ - if (!card->tty_open) - return; - - wanpipe_close(card); - if (--card->tty_open == 0){ - - lock_adapter_irq(&card->wandev.lock,&smp_flags); - card->tty=NULL; - chdlc_disable_comm_shutdown(card); - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - - kfree(card->tty_buf); - card->tty_buf = NULL; - kfree(card->tty_rx); - card->tty_rx = NULL; - } - return; -} -static int wanpipe_tty_open(struct tty_struct *tty, struct file * filp) -{ - unsigned long smp_flags; - sdla_t *card; - - if (!tty){ - return -ENODEV; - } - - if (!tty->driver_data){ - int port; - port = tty->index; - if ((port < 0) || (port >= NR_PORTS)) - return -ENODEV; - - tty->driver_data = WAN_CARD(port); - if (!tty->driver_data) - return -ENODEV; - } - - card = (sdla_t*)tty->driver_data; - - if (!card){ - lock_adapter_irq(&card->wandev.lock,&smp_flags); - card->tty=NULL; - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - return -ENODEV; - } - - printk(KERN_INFO "%s: Opening TTY Driver!\n", - card->devname); - - if (card->tty_open == 0){ - lock_adapter_irq(&card->wandev.lock,&smp_flags); - card->tty=tty; - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - - if (!card->tty_buf){ - card->tty_buf = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL); - if (!card->tty_buf){ - card->tty_buf=NULL; - card->tty=NULL; - return -ENOMEM; - } - } - - if (!card->tty_rx){ - card->tty_rx = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL); - if (!card->tty_rx){ - /* Free the buffer above */ - kfree(card->tty_buf); - card->tty_buf=NULL; - card->tty=NULL; - return -ENOMEM; - } - } - } - - ++card->tty_open; - wanpipe_open(card); - return 0; -} - -static int wanpipe_tty_write(struct tty_struct * tty, const unsigned char *buf, int count) -{ - unsigned long smp_flags=0; - sdla_t *card=NULL; - - if (!tty){ - dbg_printk(KERN_INFO "NO TTY in Write\n"); - return -ENODEV; - } - - card = (sdla_t *)tty->driver_data; - - if (!card){ - dbg_printk(KERN_INFO "No Card in TTY Write\n"); - return -ENODEV; - } - - if (count > card->wandev.mtu){ - dbg_printk(KERN_INFO "Frame too big in Write %i Max: %i\n", - count,card->wandev.mtu); - return -EINVAL; - } - - if (card->wandev.state != WAN_CONNECTED){ - dbg_printk(KERN_INFO "Card not connected in TTY Write\n"); - return -EINVAL; - } - - /* Lock the 508 Card: SMP is supported */ - if(card->hw.type != SDLA_S514){ - s508_lock(card,&smp_flags); - } - - if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){ - printk(KERN_INFO "%s: Critical in TTY Write\n", - card->devname); - - /* Lock the 508 Card: SMP is supported */ - if(card->hw.type != SDLA_S514) - s508_unlock(card,&smp_flags); - - return -EINVAL; - } - - if (chdlc_send(card,(void*)buf,count)){ - dbg_printk(KERN_INFO "%s: Failed to send, retry later: kernel!\n", - card->devname); - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - - wanpipe_tty_trigger_tx_irq(card); - - if(card->hw.type != SDLA_S514) - s508_unlock(card,&smp_flags); - return 0; - } - dbg_printk(KERN_INFO "%s: Packet sent OK: %i\n",card->devname,count); - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - - if(card->hw.type != SDLA_S514) - s508_unlock(card,&smp_flags); - - return count; -} - -static void wanpipe_tty_receive(sdla_t *card, unsigned addr, unsigned int len) -{ - unsigned offset=0; - unsigned olen=len; - char fp=0; - struct tty_struct *tty; - int i; - struct tty_ldisc *ld; - - if (!card->tty_open){ - dbg_printk(KERN_INFO "%s: TTY not open during receive\n", - card->devname); - return; - } - - if ((tty=card->tty) == NULL){ - dbg_printk(KERN_INFO "%s: No TTY on receive\n", - card->devname); - return; - } - - if (!tty->driver_data){ - dbg_printk(KERN_INFO "%s: No Driver Data, or Flip on receive\n", - card->devname); - return; - } - - - if (card->u.c.async_mode){ - if ((tty->flip.count+len) >= TTY_FLIPBUF_SIZE){ - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Received packet size too big: %i bytes, Max: %i!\n", - card->devname,len,TTY_FLIPBUF_SIZE); - } - return; - } - - - if((addr + len) > card->u.c.rx_top + 1) { - offset = card->u.c.rx_top - addr + 1; - - sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, offset); - - addr = card->u.c.rx_base; - len -= offset; - - tty->flip.char_buf_ptr+=offset; - tty->flip.count+=offset; - for (i=0;iflip.flag_buf_ptr = 0; - tty->flip.flag_buf_ptr++; - } - } - - sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, len); - - tty->flip.char_buf_ptr+=len; - card->tty->flip.count+=len; - for (i=0;iflip.flag_buf_ptr = 0; - tty->flip.flag_buf_ptr++; - } - - tty->low_latency=1; - tty_flip_buffer_push(tty); - }else{ - if (!card->tty_rx){ - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Receive sync buffer not available!\n", - card->devname); - } - return; - } - - if (len > TTY_CHDLC_MAX_MTU){ - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Received packet size too big: %i bytes, Max: %i!\n", - card->devname,len,TTY_FLIPBUF_SIZE); - } - return; - } - - - if((addr + len) > card->u.c.rx_top + 1) { - offset = card->u.c.rx_top - addr + 1; - - sdla_peek(&card->hw, addr, card->tty_rx, offset); - - addr = card->u.c.rx_base; - len -= offset; - } - sdla_peek(&card->hw, addr, card->tty_rx+offset, len); - ld = tty_ldisc_ref(tty); - if (ld) { - if (ld->receive_buf) - ld->receive_buf(tty,card->tty_rx,&fp,olen); - tty_ldisc_deref(ld); - }else{ - if (net_ratelimit()){ - printk(KERN_INFO - "%s: NO TTY Sync line discipline!\n", - card->devname); - } - } - } - - dbg_printk(KERN_INFO "%s: Received Data %i\n",card->devname,olen); - return; -} - -#if 0 -static int wanpipe_tty_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - return -ENOIOCTLCMD; -} -#endif - -static void wanpipe_tty_stop(struct tty_struct *tty) -{ - return; -} - -static void wanpipe_tty_start(struct tty_struct *tty) -{ - return; -} - -static int config_tty (sdla_t *card) -{ - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - - /* Setup the Board for asynchronous mode */ - if (card->u.c.async_mode){ - - if (set_asy_config(card)) { - printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n", - card->devname); - return -EINVAL; - } - }else{ - /* Setup the Board for CHDLC */ - if (set_chdlc_config(card)) { - printk (KERN_INFO "%s: Failed CHDLC configuration!\n", - card->devname); - return -EINVAL; - } - } - - /* Set interrupt mode and mask */ - if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | - APP_INT_ON_GLOBAL_EXCEP_COND | - APP_INT_ON_TX_FRAME | - APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ - printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", - card->devname); - return -EINVAL; - } - - - /* Mask the Transmit and Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); - - - /* Enable communications */ - if (card->u.c.async_mode){ - if (asy_comm_enable(card) != 0) { - printk(KERN_INFO "%s: Failed to enable async commnunication!\n", - card->devname); - flags->interrupt_info_struct.interrupt_permission = 0; - card->u.c.comm_enabled=0; - chdlc_set_intr_mode(card,0); - return -EINVAL; - } - }else{ - if (chdlc_comm_enable(card) != 0) { - printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", - card->devname); - flags->interrupt_info_struct.interrupt_permission = 0; - card->u.c.comm_enabled=0; - chdlc_set_intr_mode(card,0); - return -EINVAL; - } - } - - /* Initialize Rx/Tx buffer control fields */ - init_chdlc_tx_rx_buff(card); - port_set_state(card, WAN_CONNECTING); - return 0; -} - - -static int change_speed(sdla_t *card, struct tty_struct *tty, - struct termios *old_termios) -{ - int baud, ret=0; - unsigned cflag; - int dbits,sbits,parity,handshaking; - - cflag = tty->termios->c_cflag; - - /* There is always one stop bit */ - sbits=WANOPT_ONE; - - /* Parity is defaulted to NONE */ - parity = WANOPT_NONE; - - handshaking=0; - - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: dbits = 5; break; - case CS6: dbits = 6; break; - case CS7: dbits = 7; break; - case CS8: dbits = 8; break; - /* Never happens, but GCC is too dumb to figure it out */ - default: dbits = 8; break; - } - - /* One more stop bit should be supported, thus increment - * the number of stop bits Max=2 */ - if (cflag & CSTOPB) { - sbits = WANOPT_TWO; - } - if (cflag & PARENB) { - parity = WANOPT_EVEN; - } - if (cflag & PARODD){ - parity = WANOPT_ODD; - } - - /* Determine divisor based on baud rate */ - baud = tty_get_baud_rate(tty); - - if (!baud) - baud = 9600; /* B0 transition handled in rs_set_termios */ - - if (cflag & CRTSCTS) { - handshaking|=ASY_RTS_HS_FOR_RX; - } - - if (I_IGNPAR(tty)) - parity = WANOPT_NONE; - - if (I_IXOFF(tty)){ - handshaking|=ASY_XON_XOFF_HS_FOR_RX; - handshaking|=ASY_XON_XOFF_HS_FOR_TX; - } - - if (I_IXON(tty)){ - handshaking|=ASY_XON_XOFF_HS_FOR_RX; - handshaking|=ASY_XON_XOFF_HS_FOR_TX; - } - - if (card->u.c.async_mode){ - if (card->wandev.bps != baud) - ret=1; - card->wandev.bps = baud; - } - - if (card->u.c.async_mode){ - if (card->u.c.protocol_options != handshaking) - ret=1; - card->u.c.protocol_options = handshaking; - - if (card->u.c.tx_bits_per_char != dbits) - ret=1; - card->u.c.tx_bits_per_char = dbits; - - if (card->u.c.rx_bits_per_char != dbits) - ret=1; - card->u.c.rx_bits_per_char = dbits; - - if (card->u.c.stop_bits != sbits) - ret=1; - card->u.c.stop_bits = sbits; - - if (card->u.c.parity != parity) - ret=1; - card->u.c.parity = parity; - - card->u.c.break_timer = 50; - card->u.c.inter_char_timer = 10; - card->u.c.rx_complete_length = 100; - card->u.c.xon_char = 0xFE; - }else{ - card->u.c.protocol_options = HDLC_STREAMING_MODE; - } - - return ret; -} - - -static void wanpipe_tty_set_termios(struct tty_struct *tty, struct termios *old_termios) -{ - sdla_t *card; - int err=1; - - if (!tty){ - return; - } - - card = (sdla_t *)tty->driver_data; - - if (!card) - return; - - if (change_speed(card, tty, old_termios) || !card->u.c.comm_enabled){ - unsigned long smp_flags; - - if (card->u.c.comm_enabled){ - lock_adapter_irq(&card->wandev.lock,&smp_flags); - chdlc_disable_comm_shutdown(card); - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - } - lock_adapter_irq(&card->wandev.lock,&smp_flags); - err = config_tty(card); - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - if (card->u.c.async_mode){ - printk(KERN_INFO "%s: TTY Async Configuration:\n" - " Baud =%i\n" - " Handshaking =%s\n" - " Tx Dbits =%i\n" - " Rx Dbits =%i\n" - " Parity =%s\n" - " Stop Bits =%i\n", - card->devname, - card->wandev.bps, - opt_decode[card->u.c.protocol_options], - card->u.c.tx_bits_per_char, - card->u.c.rx_bits_per_char, - p_decode[card->u.c.parity] , - card->u.c.stop_bits); - }else{ - printk(KERN_INFO "%s: TTY Sync Configuration:\n" - " Baud =%i\n" - " Protocol =HDLC_STREAMING\n", - card->devname,card->wandev.bps); - } - if (!err){ - port_set_state(card,WAN_CONNECTED); - }else{ - port_set_state(card,WAN_DISCONNECTED); - } - } - return; -} - -static void wanpipe_tty_put_char(struct tty_struct *tty, unsigned char ch) -{ - sdla_t *card; - unsigned long smp_flags=0; - - if (!tty){ - return; - } - - card = (sdla_t *)tty->driver_data; - - if (!card) - return; - - if (card->wandev.state != WAN_CONNECTED) - return; - - if(card->hw.type != SDLA_S514) - s508_lock(card,&smp_flags); - - if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){ - - wanpipe_tty_trigger_tx_irq(card); - - if(card->hw.type != SDLA_S514) - s508_unlock(card,&smp_flags); - return; - } - - if (chdlc_send(card,(void*)&ch,1)){ - wanpipe_tty_trigger_tx_irq(card); - dbg_printk("%s: Failed to TX char!\n",card->devname); - } - - dbg_printk("%s: Char TX OK\n",card->devname); - - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - - if(card->hw.type != SDLA_S514) - s508_unlock(card,&smp_flags); - - return; -} - -static void wanpipe_tty_flush_chars(struct tty_struct *tty) -{ - return; -} - -static void wanpipe_tty_flush_buffer(struct tty_struct *tty) -{ - if (!tty) - return; - -#if defined(SERIAL_HAVE_POLL_WAIT) - wake_up_interruptible(&tty->poll_wait); -#endif - tty_wakeup(tty); - return; -} - -/* - * This function is used to send a high-priority XON/XOFF character to - * the device - */ -static void wanpipe_tty_send_xchar(struct tty_struct *tty, char ch) -{ - return; -} - - -static int wanpipe_tty_chars_in_buffer(struct tty_struct *tty) -{ - return 0; -} - - -static int wanpipe_tty_write_room(struct tty_struct *tty) -{ - sdla_t *card; - - printk(KERN_INFO "TTY Write Room\n"); - - if (!tty){ - return 0; - } - - card = (sdla_t *)tty->driver_data; - if (!card) - return 0; - - if (card->wandev.state != WAN_CONNECTED) - return 0; - - return SEC_MAX_NO_DATA_BYTES_IN_FRAME; -} - - -static int set_modem_status(sdla_t *card, unsigned char data) -{ - CHDLC_MAILBOX_STRUCT *mb = card->mbox; - int err; - - mb->buffer_length=1; - mb->command=SET_MODEM_STATUS; - mb->data[0]=data; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error (card, err, mb); - - return err; -} - -static void wanpipe_tty_hangup(struct tty_struct *tty) -{ - sdla_t *card; - unsigned long smp_flags; - - printk(KERN_INFO "TTY Hangup!\n"); - - if (!tty){ - return; - } - - card = (sdla_t *)tty->driver_data; - if (!card) - return; - - lock_adapter_irq(&card->wandev.lock,&smp_flags); - set_modem_status(card,0); - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - return; -} - -static void wanpipe_tty_break(struct tty_struct *tty, int break_state) -{ - return; -} - -static void wanpipe_tty_wait_until_sent(struct tty_struct *tty, int timeout) -{ - return; -} - -static void wanpipe_tty_throttle(struct tty_struct * tty) -{ - return; -} - -static void wanpipe_tty_unthrottle(struct tty_struct * tty) -{ - return; -} - -int wanpipe_tty_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - return 0; -} - -/* - * The serial driver boot-time initialization code! - */ -int wanpipe_tty_init(sdla_t *card) -{ - struct serial_state * state; - - /* Initialize the tty_driver structure */ - - if (card->tty_minor < 0 || card->tty_minor > NR_PORTS){ - printk(KERN_INFO "%s: Illegal Minor TTY number (0-4): %i\n", - card->devname,card->tty_minor); - return -EINVAL; - } - - if (WAN_CARD(card->tty_minor)){ - printk(KERN_INFO "%s: TTY Minor %i, already in use\n", - card->devname,card->tty_minor); - return -EBUSY; - } - - if (tty_init_cnt==0){ - - printk(KERN_INFO "%s: TTY %s Driver Init: Major %i, Minor Range %i-%i\n", - card->devname, - card->u.c.async_mode ? "ASYNC" : "SYNC", - WAN_TTY_MAJOR,MIN_PORT,MAX_PORT); - - tty_driver_mode = card->u.c.async_mode; - - memset(&serial_driver, 0, sizeof(struct tty_driver)); - serial_driver.magic = TTY_DRIVER_MAGIC; - serial_driver.owner = THIS_MODULE; - serial_driver.driver_name = "wanpipe_tty"; - serial_driver.name = "ttyW"; - serial_driver.major = WAN_TTY_MAJOR; - serial_driver.minor_start = WAN_TTY_MINOR; - serial_driver.num = NR_PORTS; - serial_driver.type = TTY_DRIVER_TYPE_SERIAL; - serial_driver.subtype = SERIAL_TYPE_NORMAL; - - serial_driver.init_termios = tty_std_termios; - serial_driver.init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver.flags = TTY_DRIVER_REAL_RAW; - - serial_driver.refcount = 1; /* !@!@^#^&!! */ - - serial_driver.open = wanpipe_tty_open; - serial_driver.close = wanpipe_tty_close; - serial_driver.write = wanpipe_tty_write; - - serial_driver.put_char = wanpipe_tty_put_char; - serial_driver.flush_chars = wanpipe_tty_flush_chars; - serial_driver.write_room = wanpipe_tty_write_room; - serial_driver.chars_in_buffer = wanpipe_tty_chars_in_buffer; - serial_driver.flush_buffer = wanpipe_tty_flush_buffer; - //serial_driver.ioctl = wanpipe_tty_ioctl; - serial_driver.throttle = wanpipe_tty_throttle; - serial_driver.unthrottle = wanpipe_tty_unthrottle; - serial_driver.send_xchar = wanpipe_tty_send_xchar; - serial_driver.set_termios = wanpipe_tty_set_termios; - serial_driver.stop = wanpipe_tty_stop; - serial_driver.start = wanpipe_tty_start; - serial_driver.hangup = wanpipe_tty_hangup; - serial_driver.break_ctl = wanpipe_tty_break; - serial_driver.wait_until_sent = wanpipe_tty_wait_until_sent; - serial_driver.read_proc = wanpipe_tty_read_proc; - - if (tty_register_driver(&serial_driver)){ - printk(KERN_INFO "%s: Failed to register serial driver!\n", - card->devname); - } - } - - - /* The subsequent ports must comply to the initial configuration */ - if (tty_driver_mode != card->u.c.async_mode){ - printk(KERN_INFO "%s: Error: TTY Driver operation mode mismatch!\n", - card->devname); - printk(KERN_INFO "%s: The TTY driver is configured for %s!\n", - card->devname, tty_driver_mode ? "ASYNC" : "SYNC"); - return -EINVAL; - } - - tty_init_cnt++; - - printk(KERN_INFO "%s: Initializing TTY %s Driver Minor %i\n", - card->devname, - tty_driver_mode ? "ASYNC" : "SYNC", - card->tty_minor); - - tty_card_map[card->tty_minor] = card; - state = &rs_table[card->tty_minor]; - - state->magic = SSTATE_MAGIC; - state->line = 0; - state->type = PORT_UNKNOWN; - state->custom_divisor = 0; - state->close_delay = 5*HZ/10; - state->closing_wait = 30*HZ; - state->icount.cts = state->icount.dsr = - state->icount.rng = state->icount.dcd = 0; - state->icount.rx = state->icount.tx = 0; - state->icount.frame = state->icount.parity = 0; - state->icount.overrun = state->icount.brk = 0; - state->irq = card->wandev.irq; - - INIT_WORK(&card->tty_work, tty_poll_work, (void*)card); - return 0; -} - - -MODULE_LICENSE("GPL"); - -/****** End ****************************************************************/ diff --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c deleted file mode 100644 index 7f1ce9d..0000000 --- a/drivers/net/wan/sdla_fr.c +++ /dev/null @@ -1,5061 +0,0 @@ -/***************************************************************************** -* sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. -* -* Author(s): Nenad Corbic -* Gideon Hack -* -* Copyright: (c) 1995-2001 Sangoma Technologies Inc. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version -* 2 of the License, or (at your option) any later version. -* ============================================================================ -* Nov 23, 2000 Nenad Corbic o Added support for 2.4.X kernels -* Nov 15, 2000 David Rokavarg -* Nenad Corbic o Added frame relay bridging support. -* Original code from Mark Wells and Kristian Hoffmann has -* been integrated into the frame relay driver. -* Nov 13, 2000 Nenad Corbic o Added true interface type encoding option. -* Tcpdump doesn't support Frame Relay inteface -* types, to fix this true type option will set -* the interface type to RAW IP mode. -* Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging: -* Deny all and specify allowed requests. -* Nov 06, 2000 Nenad Corbic o Wanpipe interfaces conform to raw packet interfaces. -* Moved the if_header into the if_send() routine. -* The if_header() was breaking the libpcap -* support. i.e. support for tcpdump, ethereal ... -* Oct 12. 2000 Nenad Corbic o Added error message in fr_configure -* Jul 31, 2000 Nenad Corbic o Fixed the Router UP Time. -* Apr 28, 2000 Nenad Corbic o Added the option to shutdown an interface -* when the channel gets disconnected. -* Apr 28, 2000 Nenad Corbic o Added M.Grants patch: disallow duplicate -* interface setups. -* Apr 25, 2000 Nenad Corbic o Added M.Grants patch: dynamically add/remove -* new dlcis/interfaces. -* Mar 23, 2000 Nenad Corbic o Improved task queue, bh handling. -* Mar 16, 2000 Nenad Corbic o Added Inverse ARP support -* Mar 13, 2000 Nenad Corbic o Added new socket API support. -* Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. -* Feb 24, 2000 Nenad Corbic o Fixed up FT1 UDP debugging problem. -* Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels -* -* Nov 08, 1999 Nenad Corbic o Combined all debug UDP calls into one function -* o Removed the ARP support. This has to be done -* in the next version. -* o Only a Node can implement NO signalling. -* Initialize DLCI during if_open() if NO -* signalling. -* o Took out IPX support, implement in next -* version -* Sep 29, 1999 Nenad Corbic o Added SMP support and changed the update -* function to use timer interrupt. -* o Fixed the CIR bug: Set the value of BC -* to CIR when the CIR is enabled. -* o Updated comments, statistics and tracing. -* Jun 02, 1999 Gideon Hack o Updated for S514 support. -* Sep 18, 1998 Jaspreet Singh o Updated for 2.2.X kernels. -* Jul 31, 1998 Jaspreet Singh o Removed wpf_poll routine. The channel/DLCI -* status is received through an event interrupt. -* Jul 08, 1998 David Fong o Added inverse ARP support. -* Mar 26, 1997 Jaspreet Singh o Returning return codes for failed UDP cmds. -* Jan 28, 1997 Jaspreet Singh o Improved handling of inactive DLCIs. -* Dec 30, 1997 Jaspreet Singh o Replaced dev_tint() with mark_bh(NET_BH) -* Dec 16, 1997 Jaspreet Singh o Implemented Multiple IPX support. -* Nov 26, 1997 Jaspreet Singh o Improved load sharing with multiple boards -* o Added Cli() to protect enabling of interrupts -* while polling is called. -* Nov 24, 1997 Jaspreet Singh o Added counters to avoid enabling of interrupts -* when they have been disabled by another -* interface or routine (eg. wpf_poll). -* Nov 06, 1997 Jaspreet Singh o Added INTR_TEST_MODE to avoid polling -* routine disable interrupts during interrupt -* testing. -* Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time. -* Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow -* control by avoiding RACE conditions. The -* cli() and restore_flags() are taken out. -* The fr_channel structure is appended for -* Driver Statistics. -* Oct 15, 1997 Farhan Thawar o updated if_send() and receive for IPX -* Aug 29, 1997 Farhan Thawar o Removed most of the cli() and sti() -* o Abstracted the UDP management stuff -* o Now use tbusy and critical more intelligently -* Jul 21, 1997 Jaspreet Singh o Can configure T391, T392, N391, N392 & N393 -* through router.conf. -* o Protected calls to sdla_peek() by adDing -* save_flags(), cli() and restore_flags(). -* o Added error message for Inactive DLCIs in -* fr_event() and update_chan_state(). -* o Fixed freeing up of buffers using kfree() -* when packets are received. -* Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets -* o Added ability to discard multicast and -* broadcast source addressed packets -* Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities -* New case (0x44) statement in if_send routine -* Added a global variable rCount to keep track -* of FT1 status enabled on the board. -* May 29, 1997 Jaspreet Singh o Fixed major Flow Control Problem -* With multiple boards a problem was seen where -* the second board always stopped transmitting -* packet after running for a while. The code -* got into a stage where the interrupts were -* disabled and dev->tbusy was set to 1. -* This caused the If_send() routine to get into -* the if clause for it(0,dev->tbusy) -* forever. -* The code got into this stage due to an -* interrupt occurring within the if clause for -* set_bit(0,dev->tbusy). Since an interrupt -* disables furhter transmit interrupt and -* makes dev->tbusy = 0, this effect was undone -* by making dev->tbusy = 1 in the if clause. -* The Fix checks to see if Transmit interrupts -* are disabled then do not make dev->tbusy = 1 -* Introduced a global variable: int_occur and -* added tx_int_enabled in the wan_device -* structure. -* May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple -* boards. -* -* Apr 25, 1997 Farhan Thawar o added UDP Management stuff -* o fixed bug in if_send() and tx_intr() to -* sleep and wakeup all devices -* Mar 11, 1997 Farhan Thawar Version 3.1.1 -* o fixed (+1) bug in fr508_rx_intr() -* o changed if_send() to return 0 if -* wandev.critical() is true -* o free socket buffer in if_send() if -* returning 0 -* o added tx_intr() routine -* Jan 30, 1997 Gene Kozin Version 3.1.0 -* o implemented exec() entry point -* o fixed a bug causing driver configured as -* a FR switch to be stuck in WAN_ -* mode -* Jan 02, 1997 Gene Kozin Initial version. -*****************************************************************************/ - -#include -#include /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include -#include /* ARPHRD_* defines */ -#include /* htons(), etc. */ -#include /* for inb(), outb(), etc. */ -#include /* for do_gettimeofday */ -#include /* sockaddr_in */ -#include /* time_after() macro */ -#include - -#include -#include - -#include /* Wanpipe Socket */ -#include - -#include /* frame relay firmware API definitions */ - -#include -#include -#include - -#include /* Dynamic Route Creation */ -#include /* eth_type_trans() used for bridging */ -#include - -/****** Defines & Macros ****************************************************/ - -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ - -#define FR_HEADER_LEN 8 /* max encapsulation header size */ -#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ - -/* Q.922 frame types */ -#define Q922_UI 0x03 /* Unnumbered Info frame */ -#define Q922_XID 0xAF - -/* DLCI configured or not */ -#define DLCI_NOT_CONFIGURED 0x00 -#define DLCI_CONFIG_PENDING 0x01 -#define DLCI_CONFIGURED 0x02 - -/* CIR enabled or not */ -#define CIR_ENABLED 0x00 -#define CIR_DISABLED 0x01 - -#define FRAME_RELAY_API 1 -#define MAX_BH_BUFF 10 - -/* For handle_IPXWAN() */ -#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) - -/****** Data Structures *****************************************************/ - -/* This is an extention of the 'struct device' we create for each network - * interface to keep the rest of channel-specific data. - */ -typedef struct fr_channel -{ - wanpipe_common_t common; - char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ - unsigned dlci_configured ; /* check whether configured or not */ - unsigned cir_status; /* check whether CIR enabled or not */ - unsigned dlci; /* logical channel number */ - unsigned cir; /* committed information rate */ - unsigned bc; /* committed burst size */ - unsigned be; /* excess burst size */ - unsigned mc; /* multicast support on or off */ - unsigned tx_int_status; /* Transmit Interrupt Status */ - unsigned short pkt_length; /* Packet Length */ - unsigned long router_start_time;/* Router start time in seconds */ - unsigned long tick_counter; /* counter for transmit time out */ - char dev_pending_devtint; /* interface pending dev_tint() */ - void *dlci_int_interface; /* pointer to the DLCI Interface */ - unsigned long IB_addr; /* physical address of Interface Byte */ - unsigned long state_tick; /* time of the last state change */ - unsigned char enable_IPX; /* Enable/Disable the use of IPX */ - unsigned long network_number; /* Internal Network Number for IPX*/ - sdla_t *card; /* -> owner */ - unsigned route_flag; /* Add/Rem dest addr in route tables */ - unsigned inarp; /* Inverse Arp Request status */ - long inarp_ready; /* Ready to send requests */ - int inarp_interval; /* Time between InArp Requests */ - unsigned long inarp_tick; /* InArp jiffies tick counter */ - long interface_down; /* Bring interface down on disconnect */ - struct net_device_stats ifstats; /* interface statistics */ - if_send_stat_t drvstats_if_send; - rx_intr_stat_t drvstats_rx_intr; - pipe_mgmt_stat_t drvstats_gen; - unsigned long router_up_time; - - unsigned short transmit_length; - struct sk_buff *delay_skb; - - bh_data_t *bh_head; /* Circular buffer for chdlc_bh */ - unsigned long tq_working; - volatile int bh_write; - volatile int bh_read; - atomic_t bh_buff_used; - - /* Polling task queue. Each interface - * has its own task queue, which is used - * to defer events from the interrupt */ - struct work_struct fr_poll_work; - struct timer_list fr_arp_timer; - - u32 ip_local; - u32 ip_remote; - long config_dlci; - long unconfig_dlci; - - /* Whether this interface should be setup as a gateway. - * Used by dynamic route setup code */ - u8 gateway; - - /* True interface type */ - u8 true_if_encoding; - u8 fr_header[FR_HEADER_LEN]; - char fr_header_len; - -} fr_channel_t; - -/* Route Flag options */ -#define NO_ROUTE 0x00 -#define ADD_ROUTE 0x01 -#define ROUTE_ADDED 0x02 -#define REMOVE_ROUTE 0x03 -#define ARP_REQ 0x04 - -/* inarp options */ -#define INARP_NONE 0x00 -#define INARP_REQUEST 0x01 -#define INARP_CONFIGURED 0x02 - -/* reasons for enabling the timer interrupt on the adapter */ -#define TMR_INT_ENABLED_UDP 0x01 -#define TMR_INT_ENABLED_UPDATE 0x02 -#define TMR_INT_ENABLED_ARP 0x04 -#define TMR_INT_ENABLED_UPDATE_STATE 0x08 -#define TMR_INT_ENABLED_CONFIG 0x10 -#define TMR_INT_ENABLED_UNCONFIG 0x20 - - -typedef struct dlci_status -{ - unsigned short dlci PACKED; - unsigned char state PACKED; -} dlci_status_t; - -typedef struct dlci_IB_mapping -{ - unsigned short dlci PACKED; - unsigned long addr_value PACKED; -} dlci_IB_mapping_t; - -/* This structure is used for DLCI list Tx interrupt mode. It is used to - enable interrupt bit and set the packet length for transmission - */ -typedef struct fr_dlci_interface -{ - unsigned char gen_interrupt PACKED; - unsigned short packet_length PACKED; - unsigned char reserved PACKED; -} fr_dlci_interface_t; - -/* variable for keeping track of enabling/disabling FT1 monitor status */ -static int rCount = 0; - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/* variable for keeping track of number of interrupts generated during - * interrupt test routine - */ -static int Intr_test_counter; - -/****** Function Prototypes *************************************************/ - -/* WAN link driver entry points. These are called by the WAN router module. */ -static int update(struct wan_device *wandev); -static int new_if(struct wan_device *wandev, struct net_device *dev, - wanif_conf_t *conf); -static int del_if(struct wan_device *wandev, struct net_device *dev); -static void disable_comm (sdla_t *card); - -/* WANPIPE-specific entry points */ -static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data); - -/* Network device interface */ -static int if_init(struct net_device *dev); -static int if_open(struct net_device *dev); -static int if_close(struct net_device *dev); - -static void if_tx_timeout(struct net_device *dev); - -static int if_rebuild_hdr (struct sk_buff *skb); - -static int if_send(struct sk_buff *skb, struct net_device *dev); -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, - struct sk_buff *skb); -static struct net_device_stats *if_stats(struct net_device *dev); - -/* Interrupt handlers */ -static void fr_isr(sdla_t *card); -static void rx_intr(sdla_t *card); -static void tx_intr(sdla_t *card); -static void timer_intr(sdla_t *card); -static void spur_intr(sdla_t *card); - -/* Frame relay firmware interface functions */ -static int fr_read_version(sdla_t *card, char *str); -static int fr_configure(sdla_t *card, fr_conf_t *conf); -static int fr_dlci_configure(sdla_t *card, fr_dlc_conf_t *conf, unsigned dlci); -static int fr_init_dlci (sdla_t *card, fr_channel_t *chan); -static int fr_set_intr_mode (sdla_t *card, unsigned mode, unsigned mtu, unsigned short timeout); -static int fr_comm_enable(sdla_t *card); -static void fr_comm_disable(sdla_t *card); -static int fr_get_err_stats(sdla_t *card); -static int fr_get_stats(sdla_t *card); -static int fr_add_dlci(sdla_t *card, int dlci); -static int fr_activate_dlci(sdla_t *card, int dlci); -static int fr_delete_dlci (sdla_t* card, int dlci); -static int fr_issue_isf(sdla_t *card, int isf); -static int fr_send(sdla_t *card, int dlci, unsigned char attr, int len, - void *buf); -static int fr_send_data_header(sdla_t *card, int dlci, unsigned char attr, int len, - void *buf,unsigned char hdr_len); -static unsigned int fr_send_hdr(sdla_t *card, int dlci, unsigned int offset); - -static int check_dlci_config (sdla_t *card, fr_channel_t *chan); -static void initialize_rx_tx_buffers (sdla_t *card); - - -/* Firmware asynchronous event handlers */ -static int fr_event(sdla_t *card, int event, fr_mbox_t *mbox); -static int fr_modem_failure(sdla_t *card, fr_mbox_t *mbox); -static int fr_dlci_change(sdla_t *card, fr_mbox_t *mbox); - -/* Miscellaneous functions */ -static int update_chan_state(struct net_device *dev); -static void set_chan_state(struct net_device *dev, int state); -static struct net_device *find_channel(sdla_t *card, unsigned dlci); -static int is_tx_ready(sdla_t *card, fr_channel_t *chan); -static unsigned int dec_to_uint(unsigned char *str, int len); -static int reply_udp( unsigned char *data, unsigned int mbox_len ); - -static int intr_test( sdla_t* card ); -static void init_chan_statistics( fr_channel_t* chan ); -static void init_global_statistics( sdla_t* card ); -static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ); -static int setup_for_delayed_transmit(struct net_device* dev, - struct sk_buff *skb); - -struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev); -static int check_tx_status(sdla_t *card, struct net_device *dev); - -/* Frame Relay Socket API */ -static void trigger_fr_bh (fr_channel_t *); -static void fr_bh(struct net_device *dev); -static int fr_bh_cleanup(struct net_device *dev); -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb); - -static void trigger_fr_poll(struct net_device *dev); -static void fr_poll(struct net_device *dev); -//static void add_gateway(struct net_device *dev); - -static void trigger_unconfig_fr(struct net_device *dev); -static void unconfig_fr (sdla_t *); - -static void trigger_config_fr (sdla_t *); -static void config_fr (sdla_t *); - - -/* Inverse ARP and Dynamic routing functions */ -int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device *dev); -int is_arp(void *buf); -int send_inarp_request(sdla_t *card, struct net_device *dev); - -static void trigger_fr_arp(struct net_device *dev); -static void fr_arp (unsigned long data); - - -/* Udp management functions */ -static int process_udp_mgmt_pkt(sdla_t *card); -static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ); -static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, int dlci); - -/* IPX functions */ -static void switch_net_numbers(unsigned char *sendpacket, - unsigned long network_number, unsigned char incoming); - -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, - unsigned char enable_IPX, unsigned long network_number); - -/* Lock Functions: SMP supported */ -void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags); -void s508_s514_lock(sdla_t *card, unsigned long *smp_flags); - -unsigned short calc_checksum (char *, int); -static int setup_fr_header(struct sk_buff *skb, - struct net_device* dev, char op_mode); - - -/****** Public Functions ****************************************************/ - -/*============================================================================ - * Frame relay protocol initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wpf_init(sdla_t *card, wandev_conf_t *conf) -{ - - int err; - fr508_flags_t* flags; - - union - { - char str[80]; - fr_conf_t cfg; - } u; - - fr_buf_info_t* buf_info; - int i; - - - printk(KERN_INFO "\n"); - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_FR) { - - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - - } - - /* Initialize protocol-specific fields of adapter data space */ - switch (card->hw.fwid) { - - case SFID_FR508: - card->mbox = (void*)(card->hw.dpmbase + - FR508_MBOX_OFFS); - card->flags = (void*)(card->hw.dpmbase + - FR508_FLAG_OFFS); - if(card->hw.type == SDLA_S514) { - card->mbox += FR_MB_VECTOR; - card->flags += FR_MB_VECTOR; - } - card->isr = &fr_isr; - break; - - default: - return -EINVAL; - } - - flags = card->flags; - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - - if (fr_read_version(card, NULL) || fr_read_version(card, u.str)) - return -EIO; - - printk(KERN_INFO "%s: running frame relay firmware v%s\n", - card->devname, u.str); - - /* Adjust configuration */ - conf->mtu += FR_HEADER_LEN; - conf->mtu = (conf->mtu >= MIN_LGTH_FR_DATA_CFG) ? - min_t(unsigned int, conf->mtu, FR_MAX_NO_DATA_BYTES_IN_FRAME) : - FR_CHANNEL_MTU + FR_HEADER_LEN; - - conf->bps = min_t(unsigned int, conf->bps, 2048000); - - /* Initialze the configuration structure sent to the board to zero */ - memset(&u.cfg, 0, sizeof(u.cfg)); - - memset(card->u.f.dlci_to_dev_map, 0, sizeof(card->u.f.dlci_to_dev_map)); - - /* Configure adapter firmware */ - - u.cfg.mtu = conf->mtu; - u.cfg.kbps = conf->bps / 1000; - - u.cfg.cir_fwd = u.cfg.cir_bwd = 16; - u.cfg.bc_fwd = u.cfg.bc_bwd = 16; - - u.cfg.options = 0x0000; - printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname); - - switch (conf->u.fr.signalling) { - - case WANOPT_FR_ANSI: - u.cfg.options = 0x0000; - break; - - case WANOPT_FR_Q933: - u.cfg.options |= 0x0200; - break; - - case WANOPT_FR_LMI: - u.cfg.options |= 0x0400; - break; - - case WANOPT_NO: - u.cfg.options |= 0x0800; - break; - default: - printk(KERN_INFO "%s: Illegal Signalling option\n", - card->wandev.name); - return -EINVAL; - } - - - card->wandev.signalling = conf->u.fr.signalling; - - if (conf->station == WANOPT_CPE) { - - - if (conf->u.fr.signalling == WANOPT_NO){ - printk(KERN_INFO - "%s: ERROR - For NO signalling, station must be set to Node!", - card->devname); - return -EINVAL; - } - - u.cfg.station = 0; - u.cfg.options |= 0x8000; /* auto config DLCI */ - card->u.f.dlci_num = 0; - - } else { - - u.cfg.station = 1; /* switch emulation mode */ - - /* For switch emulation we have to create a list of dlci(s) - * that will be sent to be global SET_DLCI_CONFIGURATION - * command in fr_configure() routine. - */ - - card->u.f.dlci_num = min_t(unsigned int, max_t(unsigned int, conf->u.fr.dlci_num, 1), 100); - - for ( i = 0; i < card->u.f.dlci_num; i++) { - - card->u.f.node_dlci[i] = (unsigned short) - conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16; - - } - } - - if (conf->clocking == WANOPT_INTERNAL) - u.cfg.port |= 0x0001; - - if (conf->interface == WANOPT_RS232) - u.cfg.port |= 0x0002; - - if (conf->u.fr.t391) - u.cfg.t391 = min_t(unsigned int, conf->u.fr.t391, 30); - else - u.cfg.t391 = 5; - - if (conf->u.fr.t392) - u.cfg.t392 = min_t(unsigned int, conf->u.fr.t392, 30); - else - u.cfg.t392 = 15; - - if (conf->u.fr.n391) - u.cfg.n391 = min_t(unsigned int, conf->u.fr.n391, 255); - else - u.cfg.n391 = 2; - - if (conf->u.fr.n392) - u.cfg.n392 = min_t(unsigned int, conf->u.fr.n392, 10); - else - u.cfg.n392 = 3; - - if (conf->u.fr.n393) - u.cfg.n393 = min_t(unsigned int, conf->u.fr.n393, 10); - else - u.cfg.n393 = 4; - - if (fr_configure(card, &u.cfg)) - return -EIO; - - if (card->hw.type == SDLA_S514) { - - buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR + - FR508_RXBC_OFFS); - - card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase); - - card->u.f.rxmb_base = - (void*)(buf_info->rse_base + card->hw.dpmbase); - - card->u.f.rxmb_last = - (void*)(buf_info->rse_base + - (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + - card->hw.dpmbase); - }else{ - buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); - - card->rxmb = (void*)(buf_info->rse_next - - FR_MB_VECTOR + card->hw.dpmbase); - - card->u.f.rxmb_base = - (void*)(buf_info->rse_base - - FR_MB_VECTOR + card->hw.dpmbase); - - card->u.f.rxmb_last = - (void*)(buf_info->rse_base + - (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) - - FR_MB_VECTOR + card->hw.dpmbase); - } - - card->u.f.rx_base = buf_info->buf_base; - card->u.f.rx_top = buf_info->buf_top; - - card->u.f.tx_interrupts_pending = 0; - - card->wandev.mtu = conf->mtu; - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->poll = NULL; - card->exec = &wpf_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.state = WAN_DISCONNECTED; - card->wandev.ttl = conf->ttl; - card->wandev.udp_port = conf->udp_port; - card->disable_comm = &disable_comm; - card->u.f.arp_dev = NULL; - - /* Intialize global statistics for a card */ - init_global_statistics( card ); - - card->TracingEnabled = 0; - - /* Interrupt Test */ - Intr_test_counter = 0; - card->intr_mode = INTR_TEST_MODE; - err = intr_test( card ); - - printk(KERN_INFO "%s: End of Interrupt Test rc=0x%x count=%i\n", - card->devname,err,Intr_test_counter); - - if (err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk(KERN_ERR "%s: Interrupt Test Failed, Counter: %i\n", - card->devname, Intr_test_counter); - printk(KERN_ERR "Please choose another interrupt\n"); - err = -EIO; - return err; - } - - printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", - card->devname, Intr_test_counter); - - - /* Apr 28 2000. Nenad Corbic - * Enable commnunications here, not in if_open or new_if, since - * interfaces come down when the link is disconnected. - */ - - /* If you enable comms and then set ints, you get a Tx int as you - * perform the SET_INT_TRIGGERS command. So, we only set int - * triggers and then adjust the interrupt mask (to disable Tx ints) - * before enabling comms. - */ - if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY | - FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs) , - card->wandev.mtu, 0)) { - return -EIO; - } - - flags->imask &= ~(FR_INTR_TXRDY | FR_INTR_TIMER); - - if (fr_comm_enable(card)) { - return -EIO; - } - wanpipe_set_state(card, WAN_CONNECTED); - spin_lock_init(&card->u.f.if_send_lock); - - printk(KERN_INFO "\n"); - - return 0; -} - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Update device status & statistics. - */ -static int update(struct wan_device* wandev) -{ - volatile sdla_t* card; - unsigned long timeout; - fr508_flags_t* flags; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - - if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - card = wandev->private; - flags = card->flags; - - - card->u.f.update_comms_stats = 1; - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE; - flags->imask |= FR_INTR_TIMER; - timeout = jiffies; - for(;;) { - if(card->u.f.update_comms_stats == 0) - break; - if (time_after(jiffies, timeout + 1 * HZ)){ - card->u.f.update_comms_stats = 0; - return -EAGAIN; - } - } - - return 0; -} - -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. - * - * Return: 0 o.k. - * < 0 failure (channel will not be created) - */ -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf) -{ - sdla_t* card = wandev->private; - fr_channel_t* chan; - int dlci = 0; - int err = 0; - - - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - - printk(KERN_INFO "%s: Invalid interface name!\n", - card->devname); - return -EINVAL; - } - - /* allocate and initialize private data */ - chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL); - - if (chan == NULL) - return -ENOMEM; - - memset(chan, 0, sizeof(fr_channel_t)); - strcpy(chan->name, conf->name); - chan->card = card; - - /* verify media address */ - if (isdigit(conf->addr[0])) { - - dlci = dec_to_uint(conf->addr, 0); - - if (dlci && (dlci <= HIGHEST_VALID_DLCI)) { - - chan->dlci = dlci; - - } else { - - printk(KERN_ERR - "%s: Invalid DLCI %u on interface %s!\n", - wandev->name, dlci, chan->name); - err = -EINVAL; - } - - } else { - printk(KERN_ERR - "%s: Invalid media address on interface %s!\n", - wandev->name, chan->name); - err = -EINVAL; - } - - if ((chan->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){ - printk(KERN_INFO - "%s: Enabling, true interface type encoding.\n", - card->devname); - } - - - - /* Setup wanpipe as a router (WANPIPE) even if it is - * a bridged DLCI, or as an API - */ - if (strcmp(conf->usedby, "WANPIPE") == 0 || - strcmp(conf->usedby, "BRIDGE") == 0 || - strcmp(conf->usedby, "BRIDGE_N") == 0){ - - if(strcmp(conf->usedby, "WANPIPE") == 0){ - chan->common.usedby = WANPIPE; - - printk(KERN_INFO "%s: Running in WANPIPE mode.\n", - card->devname); - - }else if(strcmp(conf->usedby, "BRIDGE") == 0){ - - chan->common.usedby = BRIDGE; - - printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE) mode.\n", - card->devname); - }else if( strcmp(conf->usedby, "BRIDGE_N") == 0 ){ - - chan->common.usedby = BRIDGE_NODE; - - printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE_NODE) mode.\n", - card->devname); - } - - if (!err){ - /* Dynamic interface configuration option. - * On disconnect, if the options is selected, - * the interface will be brought down */ - if (conf->if_down == WANOPT_YES){ - set_bit(DYN_OPT_ON,&chan->interface_down); - printk(KERN_INFO - "%s: Dynamic interface configuration enabled.\n", - card->devname); - } - } - - } else if(strcmp(conf->usedby, "API") == 0){ - - chan->common.usedby = API; - printk(KERN_INFO "%s: Running in API mode.\n", - wandev->name); - } - - if (err) { - - kfree(chan); - return err; - } - - /* place cir,be,bc and other channel specific information into the - * chan structure - */ - if (conf->cir) { - - chan->cir = max_t(unsigned int, 1, - min_t(unsigned int, conf->cir, 512)); - chan->cir_status = CIR_ENABLED; - - - /* If CIR is enabled, force BC to equal CIR - * this solves number of potential problems if CIR is - * set and BC is not - */ - chan->bc = chan->cir; - - if (conf->be){ - chan->be = max_t(unsigned int, - 0, min_t(unsigned int, conf->be, 511)); - }else{ - conf->be = 0; - } - - printk (KERN_INFO "%s: CIR enabled for DLCI %i \n", - wandev->name,chan->dlci); - printk (KERN_INFO "%s: CIR = %i ; BC = %i ; BE = %i\n", - wandev->name,chan->cir,chan->bc,chan->be); - - - }else{ - chan->cir_status = CIR_DISABLED; - printk (KERN_INFO "%s: CIR disabled for DLCI %i\n", - wandev->name,chan->dlci); - } - - chan->mc = conf->mc; - - if (conf->inarp == WANOPT_YES){ - printk(KERN_INFO "%s: Inverse ARP Support Enabled\n",card->devname); - chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE; - chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10; - }else{ - printk(KERN_INFO "%s: Inverse ARP Support Disabled\n",card->devname); - chan->inarp = INARP_NONE; - chan->inarp_interval = 10; - } - - - chan->dlci_configured = DLCI_NOT_CONFIGURED; - - - /*FIXME: IPX disabled in this WANPIPE version */ - if (conf->enable_IPX == WANOPT_YES){ - printk(KERN_INFO "%s: ERROR - This version of WANPIPE doesn't support IPX\n", - card->devname); - kfree(chan); - return -EINVAL; - }else{ - chan->enable_IPX = WANOPT_NO; - } - - if (conf->network_number){ - chan->network_number = conf->network_number; - }else{ - chan->network_number = 0xDEADBEEF; - } - - chan->route_flag = NO_ROUTE; - - init_chan_statistics(chan); - - chan->transmit_length = 0; - - /* prepare network device data space for registration */ - strcpy(dev->name,chan->name); - - dev->init = &if_init; - dev->priv = chan; - - /* Initialize FR Polling Task Queue - * We need a poll routine for each network - * interface. - */ - INIT_WORK(&chan->fr_poll_work, (void *)fr_poll, dev); - - init_timer(&chan->fr_arp_timer); - chan->fr_arp_timer.data=(unsigned long)dev; - chan->fr_arp_timer.function = fr_arp; - - wandev->new_if_cnt++; - - /* Tells us that if this interface is a - * gateway or not */ - if ((chan->gateway = conf->gateway) == WANOPT_YES){ - printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", - card->devname,dev->name); - } - - /* M. Grant Patch Apr 28 2000 - * Disallow duplicate dlci configurations. */ - if (card->u.f.dlci_to_dev_map[chan->dlci] != NULL) { - kfree(chan); - return -EBUSY; - } - - /* Configure this dlci at a later date, when - * the interface comes up. i.e. when if_open() - * executes */ - set_bit(0,&chan->config_dlci); - - printk(KERN_INFO "\n"); - - return 0; -} - -/*============================================================================ - * Delete logical channel. - */ -static int del_if(struct wan_device* wandev, struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - unsigned long smp_flags=0; - - /* This interface is dead, make sure the - * ARP timer is stopped */ - del_timer(&chan->fr_arp_timer); - - /* If we are a NODE, we must unconfigure this DLCI - * Trigger an unconfigure command that will - * be executed in timer interrupt. We must wait - * for the command to complete. */ - trigger_unconfig_fr(dev); - - lock_adapter_irq(&wandev->lock, &smp_flags); - wandev->new_if_cnt--; - unlock_adapter_irq(&wandev->lock, &smp_flags); - - return 0; -} - - -/*===================================================================== - * disable_comm - * - * Description: - * Disable communications. - * This code runs in shutdown (sdlamain.c) - * under critical flag. Therefore it is not - * necessary to set a critical flag here - * - * Usage: - * Commnunications are disabled only on a card - * shutdown. - */ - -static void disable_comm (sdla_t *card) -{ - printk(KERN_INFO "%s: Disabling Communications!\n", - card->devname); - fr_comm_disable(card); -} - -/****** WANPIPE-specific entry points ***************************************/ - -/*============================================================================ - * Execute adapter interface command. - */ -static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err, len; - fr_cmd_t cmd; - - if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) - return -EFAULT; - - /* execute command */ - do - { - memcpy(&mbox->cmd, &cmd, sizeof(cmd)); - - if (cmd.length){ - if( copy_from_user((void*)&mbox->data, u_data, cmd.length)) - return -EFAULT; - } - - if (sdla_exec(mbox)) - err = mbox->cmd.result; - - else return -EIO; - - } while (err && retry-- && fr_event(card, err, mbox)); - - /* return result */ - if (copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t))) - return -EFAULT; - - len = mbox->cmd.length; - - if (len && u_data && !copy_to_user(u_data, (void*)&mbox->data, len)) - return -EFAULT; - return 0; -} - -/****** Network Device Interface ********************************************/ - -/*============================================================================ - * Initialize Linux network interface. - * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. - */ -static int if_init(struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - struct wan_device* wandev = &card->wandev; - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = NULL; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - dev->tx_timeout = &if_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - if (chan->common.usedby == WANPIPE || chan->common.usedby == API){ - - /* Initialize media-specific parameters */ - if (chan->true_if_encoding){ - dev->type = ARPHRD_DLCI; /* This breaks tcpdump */ - }else{ - dev->type = ARPHRD_PPP; /* ARP h/w type */ - } - - dev->flags |= IFF_POINTOPOINT; - dev->flags |= IFF_NOARP; - - /* Enable Multicast addressing */ - if (chan->mc == WANOPT_YES){ - dev->flags |= IFF_MULTICAST; - } - - dev->mtu = wandev->mtu - FR_HEADER_LEN; - /* For an API, the maximum number of bytes that the stack will pass - to the driver is (dev->mtu + dev->hard_header_len). So, adjust the - mtu so that a frame of maximum size can be transmitted by the API. - */ - if(chan->common.usedby == API) { - dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN); - } - - dev->hard_header_len = FR_HEADER_LEN;/* media header length */ - dev->addr_len = 2; /* hardware address length */ - *(unsigned short*)dev->dev_addr = htons(chan->dlci); - - /* Set transmit buffer queue length */ - dev->tx_queue_len = 100; - - }else{ - - /* Setup the interface for Bridging */ - int hw_addr=0; - ether_setup(dev); - - /* Use a random number to generate the MAC address */ - memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); - get_random_bytes(&hw_addr, sizeof(hw_addr)); - *(int *)(dev->dev_addr + 2) += hw_addr; - } - - /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; - SET_MODULE_OWNER(dev); - - return 0; -} - -/*============================================================================ - * Open network interface. - * o if this is the first open, then enable communications and interrupts. - * o prevent module from unloading by incrementing use count - * - * Return 0 if O.k. or errno. - */ -static int if_open(struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - int err = 0; - struct timeval tv; - - if (netif_running(dev)) - return -EBUSY; - - /* Initialize the task queue */ - chan->tq_working=0; - - INIT_WORK(&chan->common.wanpipe_work, (void *)fr_bh, dev); - - /* Allocate and initialize BH circular buffer */ - chan->bh_head = kmalloc((sizeof(bh_data_t)*MAX_BH_BUFF),GFP_ATOMIC); - memset(chan->bh_head,0,(sizeof(bh_data_t)*MAX_BH_BUFF)); - atomic_set(&chan->bh_buff_used, 0); - - netif_start_queue(dev); - - wanpipe_open(card); - do_gettimeofday( &tv ); - chan->router_start_time = tv.tv_sec; - - if (test_bit(0,&chan->config_dlci)){ - trigger_config_fr (card); - }else if (chan->inarp == INARP_REQUEST){ - trigger_fr_arp(dev); - } - - return err; -} - -/*============================================================================ - * Close network interface. - * o if this is the last open, then disable communications and interrupts. - * o reset flags. - */ -static int if_close(struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - if (chan->inarp == INARP_CONFIGURED) { - chan->inarp = INARP_REQUEST; - } - - netif_stop_queue(dev); - wanpipe_close(card); - - return 0; -} - -/*============================================================================ - * Re-build media header. - * - * Return: 1 physical address resolved. - * 0 physical address not resolved - */ -static int if_rebuild_hdr (struct sk_buff* skb) -{ - struct net_device *dev = skb->dev; - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); - return 1; -} - -/*============================================================================ - * Handle transmit timeout event from netif watchdog - */ -static void if_tx_timeout(struct net_device *dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - - chan->drvstats_if_send.if_send_tbusy++; - ++chan->ifstats.collisions; - - printk (KERN_INFO "%s: Transmit timed out on %s\n", - card->devname, dev->name); - chan->drvstats_if_send.if_send_tbusy_timeout++; - netif_wake_queue (dev); - -} - - -/*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission) to block a timer-based - * transmit from overlapping. - * o set critical flag when accessing board. - * o check link state. If link is not up, then drop the packet. - * o check channel status. If it's down then initiate a call. - * o pass a packet to corresponding WAN device. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * - * 2. Using netif_start_queue() and netif_stop_queue() - * will inhibit further transmit requests from the protocol stack - * and can be used for flow control with protocol layer. - */ -static int if_send(struct sk_buff* skb, struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - int err; - unsigned char *sendpacket; - fr508_flags_t* adptr_flags = card->flags; - int udp_type; - long delay_tx_queued = 0; - unsigned long smp_flags=0; - unsigned char attr = 0; - - chan->drvstats_if_send.if_send_entry++; - - netif_stop_queue(dev); - - if (skb == NULL) { - /* if we get here, some higher layer thinks we've missed an - * tx-done interrupt. - */ - printk(KERN_INFO "%s: interface %s got kicked!\n", - card->devname, dev->name); - chan->drvstats_if_send.if_send_skb_null ++; - - netif_wake_queue(dev); - return 0; - } - - /* If a peripheral task is running just drop packets */ - if (test_bit(PERI_CRIT, &card->wandev.critical)){ - - printk(KERN_INFO "%s: Critical in if_send(): Peripheral running!\n", - card->devname); - - dev_kfree_skb_any(skb); - netif_start_queue(dev); - return 0; - } - - /* We must set the 'tbusy' flag if we already have a packet queued for - transmission in the transmit interrupt handler. However, we must - ensure that the transmit interrupt does not reset the 'tbusy' flag - just before we set it, as this will result in a "transmit timeout". - */ - set_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); - if(chan->transmit_length) { - netif_stop_queue(dev); - chan->tick_counter = jiffies; - clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); - return 1; - } - clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); - - /* Move the if_header() code to here. By inserting frame - * relay header in if_header() we would break the - * tcpdump and other packet sniffers */ - chan->fr_header_len = setup_fr_header(skb,dev,chan->common.usedby); - if (chan->fr_header_len < 0 ){ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - - dev_kfree_skb_any(skb); - netif_start_queue(dev); - return 0; - } - - sendpacket = skb->data; - - udp_type = udp_pkt_type(skb, card); - - if(udp_type != UDP_INVALID_TYPE) { - if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb, - chan->dlci)) { - adptr_flags->imask |= FR_INTR_TIMER; - if (udp_type == UDP_FPIPE_TYPE){ - chan->drvstats_if_send. - if_send_PIPE_request ++; - } - } - netif_start_queue(dev); - return 0; - } - - //FIXME: can we do better than sendpacket[2]? - if ((chan->common.usedby == WANPIPE) && (sendpacket[2] == 0x45)) { - - /* check to see if the source IP address is a broadcast or */ - /* multicast IP address */ - if(chk_bcast_mcast_addr(card, dev, skb)){ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - dev_kfree_skb_any(skb); - netif_start_queue(dev); - return 0; - } - } - - - /* Lock the S514/S508 card: SMP Supported */ - s508_s514_lock(card,&smp_flags); - - if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - - chan->drvstats_if_send.if_send_critical_non_ISR ++; - chan->ifstats.tx_dropped ++; - printk(KERN_INFO "%s Critical in IF_SEND: if_send() already running!\n", - card->devname); - goto if_send_start_and_exit; - } - - /* API packet check: minimum packet size must be greater than - * 16 byte API header */ - if((chan->common.usedby == API) && (skb->len <= sizeof(api_tx_hdr_t))) { - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - - - goto if_send_start_and_exit; - - }else{ - /* During API transmission, get rid of the API header */ - if (chan->common.usedby == API) { - api_tx_hdr_t* api_tx_hdr; - api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00]; - attr = api_tx_hdr->attr; - skb_pull(skb,sizeof(api_tx_hdr_t)); - } - } - - if (card->wandev.state != WAN_CONNECTED) { - chan->drvstats_if_send.if_send_wan_disconnected ++; - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - - } else if (chan->common.state != WAN_CONNECTED) { - chan->drvstats_if_send.if_send_dlci_disconnected ++; - - /* Update the DLCI state in timer interrupt */ - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE_STATE; - adptr_flags->imask |= FR_INTR_TIMER; - - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - - } else if (!is_tx_ready(card, chan)) { - /* No tx buffers available, store for delayed transmit */ - if (!setup_for_delayed_transmit(dev, skb)){ - set_bit(1,&delay_tx_queued); - } - chan->drvstats_if_send.if_send_no_bfrs++; - - } else if (!skb->protocol) { - /* No protocols drop packet */ - chan->drvstats_if_send.if_send_protocol_error ++; - ++card->wandev.stats.tx_errors; - - } else if (test_bit(ARP_CRIT,&card->wandev.critical)){ - /* We are trying to send an ARP Packet, block IP data until - * ARP is sent */ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - - } else { - //FIXME: IPX is not implemented in this version of Frame Relay ? - if((chan->common.usedby == WANPIPE) && - sendpacket[1] == 0x00 && - sendpacket[2] == 0x80 && - sendpacket[6] == 0x81 && - sendpacket[7] == 0x37) { - - if( chan->enable_IPX ) { - switch_net_numbers(sendpacket, - chan->network_number, 0); - } else { - //FIXME: Take this out when IPX is fixed - printk(KERN_INFO - "%s: WARNING: Unsupported IPX data in send, packet dropped\n", - card->devname); - } - - }else{ - err = fr_send_data_header(card, chan->dlci, attr, skb->len, skb->data, chan->fr_header_len); - if (err) { - switch(err) { - case FRRES_CIR_OVERFLOW: - case FRRES_BUFFER_OVERFLOW: - if (!setup_for_delayed_transmit(dev, skb)){ - set_bit(1,&delay_tx_queued); - } - chan->drvstats_if_send. - if_send_adptr_bfrs_full ++; - break; - - case FRRES_TOO_LONG: - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Error: Frame too long, transmission failed %i\n", - card->devname, (unsigned int)skb->len); - } - /* Drop down to default */ - default: - chan->drvstats_if_send. - if_send_dlci_disconnected ++; - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - break; - } - } else { - chan->drvstats_if_send. - if_send_bfr_passed_to_adptr++; - ++chan->ifstats.tx_packets; - ++card->wandev.stats.tx_packets; - - chan->ifstats.tx_bytes += skb->len; - card->wandev.stats.tx_bytes += skb->len; - dev->trans_start = jiffies; - } - } - } - -if_send_start_and_exit: - - netif_start_queue(dev); - - /* If we queued the packet for transmission, we must not - * deallocate it. The packet is unlinked from the IP stack - * not copied. Therefore, we must keep the original packet */ - if (!test_bit(1,&delay_tx_queued)) { - dev_kfree_skb_any(skb); - }else{ - adptr_flags->imask |= FR_INTR_TXRDY; - card->u.f.tx_interrupts_pending ++; - } - - clear_bit(SEND_CRIT, (void*)&card->wandev.critical); - - s508_s514_unlock(card,&smp_flags); - - return 0; -} - - - -/*============================================================================ - * Setup so that a frame can be transmitted on the occurrence of a transmit - * interrupt. - */ -static int setup_for_delayed_transmit(struct net_device* dev, - struct sk_buff *skb) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - fr_dlci_interface_t* dlci_interface; - int len = skb->len; - - /* Check that the dlci is properly configured, - * before using tx interrupt */ - if (!chan->dlci_int_interface){ - if (net_ratelimit()){ - printk(KERN_INFO - "%s: ERROR on DLCI %i: Not configured properly !\n", - card->devname, chan->dlci); - printk(KERN_INFO "%s: Please contact Sangoma Technologies\n", - card->devname); - } - return 1; - } - - dlci_interface = chan->dlci_int_interface; - - if(chan->transmit_length) { - printk(KERN_INFO "%s: Big mess in setup_for_del...\n", - card->devname); - return 1; - } - - if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) { - //FIXME: increment some statistic */ - return 1; - } - - chan->transmit_length = len; - chan->delay_skb = skb; - - dlci_interface->gen_interrupt |= FR_INTR_TXRDY; - dlci_interface->packet_length = len; - - /* Turn on TX interrupt at the end of if_send */ - return 0; -} - - -/*============================================================================ - * Check to see if the packet to be transmitted contains a broadcast or - * multicast source IP address. - * Return 0 if not broadcast/multicast address, otherwise return 1. - */ - -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, - struct sk_buff *skb) -{ - u32 src_ip_addr; - u32 broadcast_ip_addr = 0; - struct in_device *in_dev; - fr_channel_t* chan = dev->priv; - - /* read the IP source address from the outgoing packet */ - src_ip_addr = *(u32 *)(skb->data + 14); - - /* read the IP broadcast address for the device */ - in_dev = dev->ip_ptr; - if(in_dev != NULL) { - struct in_ifaddr *ifa= in_dev->ifa_list; - if(ifa != NULL) - broadcast_ip_addr = ifa->ifa_broadcast; - else - return 0; - } - - /* check if the IP Source Address is a Broadcast address */ - if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { - printk(KERN_INFO - "%s: Broadcast Source Address silently discarded\n", - card->devname); - return 1; - } - - /* check if the IP Source Address is a Multicast address */ - if((chan->mc == WANOPT_NO) && (ntohl(src_ip_addr) >= 0xE0000001) && - (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { - printk(KERN_INFO - "%s: Multicast Source Address silently discarded\n", - card->devname); - return 1; - } - - return 0; -} - -/*============================================================================ - * Reply to UDP Management system. - * Return nothing. - */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ) -{ - unsigned short len, udp_length, temp, ip_length; - unsigned long ip_temp; - int even_bound = 0; - - - fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)data; - - /* Set length of packet */ - len = //sizeof(fr_encap_hdr_t)+ - sizeof(ip_pkt_t)+ - sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - - /* fill in UDP reply */ - fr_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; - - /* fill in UDP length */ - udp_length = sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - - /* put it on an even boundary */ - if ( udp_length & 0x0001 ) { - udp_length += 1; - len += 1; - even_bound = 1; - } - - temp = (udp_length<<8)|(udp_length>>8); - fr_udp_pkt->udp_pkt.udp_length = temp; - - /* swap UDP ports */ - temp = fr_udp_pkt->udp_pkt.udp_src_port; - fr_udp_pkt->udp_pkt.udp_src_port = - fr_udp_pkt->udp_pkt.udp_dst_port; - fr_udp_pkt->udp_pkt.udp_dst_port = temp; - - - - /* add UDP pseudo header */ - temp = 0x1100; - *((unsigned short *) - (fr_udp_pkt->data+mbox_len+even_bound)) = temp; - temp = (udp_length<<8)|(udp_length>>8); - *((unsigned short *) - (fr_udp_pkt->data+mbox_len+even_bound+2)) = temp; - - /* calculate UDP checksum */ - fr_udp_pkt->udp_pkt.udp_checksum = 0; - - fr_udp_pkt->udp_pkt.udp_checksum = - calc_checksum(&data[UDP_OFFSET/*+sizeof(fr_encap_hdr_t)*/], - udp_length+UDP_OFFSET); - - /* fill in IP length */ - ip_length = udp_length + sizeof(ip_pkt_t); - temp = (ip_length<<8)|(ip_length>>8); - fr_udp_pkt->ip_pkt.total_length = temp; - - /* swap IP addresses */ - ip_temp = fr_udp_pkt->ip_pkt.ip_src_address; - fr_udp_pkt->ip_pkt.ip_src_address = - fr_udp_pkt->ip_pkt.ip_dst_address; - fr_udp_pkt->ip_pkt.ip_dst_address = ip_temp; - - - /* fill in IP checksum */ - fr_udp_pkt->ip_pkt.hdr_checksum = 0; - fr_udp_pkt->ip_pkt.hdr_checksum = - calc_checksum(&data[/*sizeof(fr_encap_hdr_t)*/0], - sizeof(ip_pkt_t)); - - return len; -} /* reply_udp */ - -unsigned short calc_checksum (char *data, int len) -{ - unsigned short temp; - unsigned long sum=0; - int i; - - for( i = 0; i > 16 ) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - - temp = (unsigned short)sum; - temp = ~temp; - - if( temp == 0 ) - temp = 0xffff; - - return temp; -} - -/* - If incoming is 0 (outgoing)- if the net numbers is ours make it 0 - if incoming is 1 - if the net number is 0 make it ours - -*/ -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) -{ - unsigned long pnetwork_number; - - pnetwork_number = (unsigned long)((sendpacket[14] << 24) + - (sendpacket[15] << 16) + (sendpacket[16] << 8) + - sendpacket[17]); - - if (!incoming) { - /* If the destination network number is ours, make it 0 */ - if( pnetwork_number == network_number) { - sendpacket[14] = sendpacket[15] = sendpacket[16] = - sendpacket[17] = 0x00; - } - } else { - /* If the incoming network is 0, make it ours */ - if( pnetwork_number == 0) { - sendpacket[14] = (unsigned char)(network_number >> 24); - sendpacket[15] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[16] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[17] = (unsigned char)(network_number & - 0x000000FF); - } - } - - - pnetwork_number = (unsigned long)((sendpacket[26] << 24) + - (sendpacket[27] << 16) + (sendpacket[28] << 8) + - sendpacket[29]); - - if( !incoming ) { - /* If the source network is ours, make it 0 */ - if( pnetwork_number == network_number) { - sendpacket[26] = sendpacket[27] = sendpacket[28] = - sendpacket[29] = 0x00; - } - } else { - /* If the source network is 0, make it ours */ - if( pnetwork_number == 0 ) { - sendpacket[26] = (unsigned char)(network_number >> 24); - sendpacket[27] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[28] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[29] = (unsigned char)(network_number & - 0x000000FF); - } - } -} /* switch_net_numbers */ - -/*============================================================================ - * Get ethernet-style interface statistics. - * Return a pointer to struct enet_statistics. - */ -static struct net_device_stats *if_stats(struct net_device *dev) -{ - fr_channel_t* chan = dev->priv; - - if(chan == NULL) - return NULL; - - return &chan->ifstats; -} - -/****** Interrupt Handlers **************************************************/ - -/*============================================================================ - * fr_isr: S508 frame relay interrupt service routine. - * - * Description: - * Frame relay main interrupt service route. This - * function check the interrupt type and takes - * the appropriate action. - */ -static void fr_isr (sdla_t* card) -{ - fr508_flags_t* flags = card->flags; - char *ptr = &flags->iflag; - int i,err; - fr_mbox_t* mbox = card->mbox; - - /* This flag prevents nesting of interrupts. See sdla_isr() routine - * in sdlamain.c. */ - card->in_isr = 1; - - ++card->statistics.isr_entry; - - - /* All peripheral (configuraiton, re-configuration) events - * take presidence over the ISR. Thus, retrigger */ - if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { - ++card->statistics.isr_already_critical; - goto fr_isr_exit; - } - - if(card->hw.type != SDLA_S514) { - if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - printk(KERN_INFO "%s: Critical while in ISR: If Send Running!\n", - card->devname); - ++card->statistics.isr_already_critical; - goto fr_isr_exit; - } - } - - switch (flags->iflag) { - - case FR_INTR_RXRDY: /* receive interrupt */ - ++card->statistics.isr_rx; - rx_intr(card); - break; - - - case FR_INTR_TXRDY: /* transmit interrupt */ - ++ card->statistics.isr_tx; - tx_intr(card); - break; - - case FR_INTR_READY: - Intr_test_counter++; - ++card->statistics.isr_intr_test; - break; - - case FR_INTR_DLC: /* Event interrupt occurred */ - mbox->cmd.command = FR_READ_STATUS; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - fr_event(card, err, mbox); - break; - - case FR_INTR_TIMER: /* Timer interrupt */ - timer_intr(card); - break; - - default: - ++card->statistics.isr_spurious; - spur_intr(card); - printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", - card->devname, flags->iflag); - - printk(KERN_INFO "%s: ID Bytes = ",card->devname); - for(i = 0; i < 8; i ++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - - break; - } - -fr_isr_exit: - - card->in_isr = 0; - flags->iflag = 0; - return; -} - - - -/*=========================================================== - * rx_intr Receive interrupt handler. - * - * Description - * Upon receiveing an interrupt: - * 1. Check that the firmware is in sync with - * the driver. - * 2. Find an appropriate network interface - * based on the received dlci number. - * 3. Check that the netowrk interface exists - * and that it's setup properly. - * 4. Copy the data into an skb buffer. - * 5. Check the packet type and take - * appropriate acton: UPD, API, ARP or Data. - */ - -static void rx_intr (sdla_t* card) -{ - fr_rx_buf_ctl_t* frbuf = card->rxmb; - fr508_flags_t* flags = card->flags; - fr_channel_t* chan; - char *ptr = &flags->iflag; - struct sk_buff* skb; - struct net_device* dev; - void* buf; - unsigned dlci, len, offs, len_incl_hdr; - int i, udp_type; - - - /* Check that firmware buffers are in sync */ - if (frbuf->flag != 0x01) { - - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned)frbuf, frbuf->flag); - - printk(KERN_INFO "%s: ID Bytes = ",card->devname); - for(i = 0; i < 8; i ++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - - ++card->statistics.rx_intr_corrupt_rx_bfr; - - /* Bug Fix: Mar 6 2000 - * If we get a corrupted mailbox, it means that driver - * is out of sync with the firmware. There is no recovery. - * If we don't turn off all interrupts for this card - * the machine will crash. - */ - printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); - printk(KERN_INFO "Please contact Sangoma Technologies !\n"); - fr_set_intr_mode(card, 0, 0, 0); - return; - } - - len = frbuf->length; - dlci = frbuf->dlci; - offs = frbuf->offset; - - /* Find the network interface for this packet */ - dev = find_channel(card, dlci); - - - /* Check that the network interface is active and - * properly setup */ - if (dev == NULL) { - if( net_ratelimit()) { - printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", - card->devname, dlci); - } - ++card->statistics.rx_intr_on_orphaned_DLCI; - ++card->wandev.stats.rx_dropped; - goto rx_done; - } - - if ((chan = dev->priv) == NULL){ - if( net_ratelimit()) { - printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", - card->devname, dlci); - } - ++card->statistics.rx_intr_on_orphaned_DLCI; - ++card->wandev.stats.rx_dropped; - goto rx_done; - } - - skb = dev_alloc_skb(len); - - if (!netif_running(dev) || (skb == NULL)){ - - ++chan->ifstats.rx_dropped; - - if(skb == NULL) { - if (net_ratelimit()) { - printk(KERN_INFO - "%s: no socket buffers available!\n", - card->devname); - } - chan->drvstats_rx_intr.rx_intr_no_socket ++; - } - - if (!netif_running(dev)){ - chan->drvstats_rx_intr. - rx_intr_dev_not_started ++; - if (skb){ - dev_kfree_skb_any(skb); - } - } - goto rx_done; - } - - /* Copy data from the board into the socket buffer */ - if ((offs + len) > card->u.f.rx_top + 1) { - unsigned tmp = card->u.f.rx_top - offs + 1; - - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, offs, buf, tmp); - offs = card->u.f.rx_base; - len -= tmp; - } - - buf = skb_put(skb, len); - sdla_peek(&card->hw, offs, buf, len); - - - /* We got the packet from the bard. - * Check the packet type and take appropriate action */ - - udp_type = udp_pkt_type( skb, card ); - - if(udp_type != UDP_INVALID_TYPE) { - - /* UDP Debug packet received, store the - * packet and handle it in timer interrupt */ - - skb_pull(skb, 1); - if (wanrouter_type_trans(skb, dev)){ - if(store_udp_mgmt_pkt(udp_type,UDP_PKT_FRM_NETWORK,card,skb,dlci)){ - - flags->imask |= FR_INTR_TIMER; - - if (udp_type == UDP_FPIPE_TYPE){ - ++chan->drvstats_rx_intr.rx_intr_PIPE_request; - } - } - } - - }else if (chan->common.usedby == API) { - - /* We are in API mode. - * Add an API header to the RAW packet - * and queue it into a circular buffer. - * Then kick the fr_bh() bottom half handler */ - - api_rx_hdr_t* api_rx_hdr; - chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack ++; - chan->ifstats.rx_packets ++; - card->wandev.stats.rx_packets ++; - - chan->ifstats.rx_bytes += skb->len; - card->wandev.stats.rx_bytes += skb->len; - - skb_push(skb, sizeof(api_rx_hdr_t)); - api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; - api_rx_hdr->attr = frbuf->attr; - api_rx_hdr->time_stamp = frbuf->tmstamp; - - skb->protocol = htons(ETH_P_IP); - skb->mac.raw = skb->data; - skb->dev = dev; - skb->pkt_type = WAN_PACKET_DATA; - - bh_enqueue(dev, skb); - - trigger_fr_bh(chan); - - }else if (handle_IPXWAN(skb->data,chan->name,chan->enable_IPX, chan->network_number)){ - - //FIXME: Frame Relay IPX is not supported, Yet ! - //if (chan->enable_IPX) { - // fr_send(card, dlci, 0, skb->len,skb->data); - //} - dev_kfree_skb_any(skb); - - } else if (is_arp(skb->data)) { - - /* ARP support enabled Mar 16 2000 - * Process incoming ARP reply/request, setup - * dynamic routes. */ - - if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) { - if (net_ratelimit()){ - printk (KERN_INFO - "%s: Error processing ARP Packet.\n", - card->devname); - } - } - dev_kfree_skb_any(skb); - - } else if (skb->data[0] != 0x03) { - - if (net_ratelimit()) { - printk(KERN_INFO "%s: Non IETF packet discarded.\n", - card->devname); - } - dev_kfree_skb_any(skb); - - } else { - - len_incl_hdr = skb->len; - /* Decapsulate packet and pass it up the - protocol stack */ - skb->dev = dev; - - if (chan->common.usedby == BRIDGE || chan->common.usedby == BRIDGE_NODE){ - - /* Make sure it's an Ethernet frame, otherwise drop it */ - if (!memcmp(skb->data, "\x03\x00\x80\x00\x80\xC2\x00\x07", 8)) { - skb_pull(skb, 8); - skb->protocol=eth_type_trans(skb,dev); - }else{ - ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; - ++chan->ifstats.rx_errors; - ++card->wandev.stats.rx_errors; - goto rx_done; - } - }else{ - - /* remove hardware header */ - buf = skb_pull(skb, 1); - - if (!wanrouter_type_trans(skb, dev)) { - - /* can't decapsulate packet */ - dev_kfree_skb_any(skb); - - ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; - ++chan->ifstats.rx_errors; - ++card->wandev.stats.rx_errors; - goto rx_done; - } - skb->mac.raw = skb->data; - } - - - /* Send a packet up the IP stack */ - skb->dev->last_rx = jiffies; - netif_rx(skb); - ++chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack; - ++chan->ifstats.rx_packets; - ++card->wandev.stats.rx_packets; - - chan->ifstats.rx_bytes += len_incl_hdr; - card->wandev.stats.rx_bytes += len_incl_hdr; - } - -rx_done: - - /* Release buffer element and calculate a pointer to the next one */ - frbuf->flag = 0; - card->rxmb = ++frbuf; - if ((void*)frbuf > card->u.f.rxmb_last) - card->rxmb = card->u.f.rxmb_base; - -} - -/*================================================================== - * tx_intr: Transmit interrupt handler. - * - * Rationale: - * If the board is busy transmitting, if_send() will - * buffers a single packet and turn on - * the tx interrupt. Tx interrupt will be called - * by the board, once the firmware can send more - * data. Thus, no polling is required. - * - * Description: - * Tx interrupt is called for each - * configured dlci channel. Thus: - * 1. Obtain the netowrk interface based on the - * dlci number. - * 2. Check that network interface is up and - * properly setup. - * 3. Check for a buffered packet. - * 4. Transmit the packet. - * 5. If we are in WANPIPE mode, mark the - * NET_BH handler. - * 6. If we are in API mode, kick - * the AF_WANPIPE socket for more data. - * - */ -static void tx_intr(sdla_t *card) -{ - fr508_flags_t* flags = card->flags; - fr_tx_buf_ctl_t* bctl; - struct net_device* dev; - fr_channel_t* chan; - - if(card->hw.type == SDLA_S514){ - bctl = (void*)(flags->tse_offs + card->hw.dpmbase); - }else{ - bctl = (void*)(flags->tse_offs - FR_MB_VECTOR + - card->hw.dpmbase); - } - - /* Find the structure and make it unbusy */ - dev = find_channel(card, flags->dlci); - if (dev == NULL){ - printk(KERN_INFO "NO DEV IN TX Interrupt\n"); - goto end_of_tx_intr; - } - - if ((chan = dev->priv) == NULL){ - printk(KERN_INFO "NO CHAN IN TX Interrupt\n"); - goto end_of_tx_intr; - } - - if(!chan->transmit_length || !chan->delay_skb) { - printk(KERN_INFO "%s: tx int error - transmit length zero\n", - card->wandev.name); - goto end_of_tx_intr; - } - - /* If the 'if_send()' procedure is currently checking the 'tbusy' - status, then we cannot transmit. Instead, we configure the microcode - so as to re-issue this transmit interrupt at a later stage. - */ - if (test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { - - fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; - bctl->flag = 0xA0; - dlci_interface->gen_interrupt |= FR_INTR_TXRDY; - return; - - }else{ - bctl->dlci = flags->dlci; - bctl->length = chan->transmit_length+chan->fr_header_len; - sdla_poke(&card->hw, - fr_send_hdr(card,bctl->dlci,bctl->offset), - chan->delay_skb->data, - chan->delay_skb->len); - bctl->flag = 0xC0; - - ++chan->ifstats.tx_packets; - ++card->wandev.stats.tx_packets; - chan->ifstats.tx_bytes += chan->transmit_length; - card->wandev.stats.tx_bytes += chan->transmit_length; - - /* We must free an sk buffer, which we used - * for delayed transmission; Otherwise, the sock - * will run out of memory */ - dev_kfree_skb_any(chan->delay_skb); - - chan->delay_skb = NULL; - chan->transmit_length = 0; - - dev->trans_start = jiffies; - - if (netif_queue_stopped(dev)){ - /* If using API, than wakeup socket BH handler */ - if (chan->common.usedby == API){ - netif_start_queue(dev); - wakeup_sk_bh(dev); - }else{ - netif_wake_queue(dev); - } - } - } - -end_of_tx_intr: - - /* if any other interfaces have transmit interrupts pending, - * do not disable the global transmit interrupt */ - if(!(-- card->u.f.tx_interrupts_pending)) - flags->imask &= ~FR_INTR_TXRDY; - - -} - - -/*============================================================================ - * timer_intr: Timer interrupt handler. - * - * Rationale: - * All commans must be executed within the timer - * interrupt since no two commands should execute - * at the same time. - * - * Description: - * The timer interrupt is used to: - * 1. Processing udp calls from 'fpipemon'. - * 2. Processing update calls from /proc file system - * 3. Reading board-level statistics for - * updating the proc file system. - * 4. Sending inverse ARP request packets. - * 5. Configure a dlci/channel. - * 6. Unconfigure a dlci/channel. (Node only) - */ - -static void timer_intr(sdla_t *card) -{ - fr508_flags_t* flags = card->flags; - - /* UDP Debuging: fpipemon call */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) { - if(card->u.f.udp_type == UDP_FPIPE_TYPE) { - if(process_udp_mgmt_pkt(card)) { - card->u.f.timer_int_enabled &= - ~TMR_INT_ENABLED_UDP; - } - } - } - - /* /proc update call : triggered from update() */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) { - fr_get_err_stats(card); - fr_get_stats(card); - card->u.f.update_comms_stats = 0; - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; - } - - /* Update the channel state call. This is call is - * triggered by if_send() function */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE_STATE){ - struct net_device *dev; - if (card->wandev.state == WAN_CONNECTED){ - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)){ - fr_channel_t *chan = dev->priv; - if (chan->common.state != WAN_CONNECTED){ - update_chan_state(dev); - } - } - } - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE_STATE; - } - - /* configure a dlci/channel */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_CONFIG){ - config_fr(card); - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; - } - - /* unconfigure a dlci/channel */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG){ - unconfig_fr(card); - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG; - } - - - /* Transmit ARP packets */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_ARP){ - int i=0; - struct net_device *dev; - - if (card->u.f.arp_dev == NULL) - card->u.f.arp_dev = card->wandev.dev; - - dev = card->u.f.arp_dev; - - for (;;){ - - fr_channel_t *chan = dev->priv; - - /* If the interface is brought down cancel sending In-ARPs */ - if (!(dev->flags&IFF_UP)){ - clear_bit(0,&chan->inarp_ready); - } - - if (test_bit(0,&chan->inarp_ready)){ - - if (check_tx_status(card,dev)){ - set_bit(ARP_CRIT,&card->wandev.critical); - break; - } - - if (!send_inarp_request(card,dev)){ - trigger_fr_arp(dev); - chan->inarp_tick = jiffies; - } - - clear_bit(0,&chan->inarp_ready); - dev = move_dev_to_next(card,dev); - break; - } - dev = move_dev_to_next(card,dev); - - if (++i == card->wandev.new_if_cnt){ - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_ARP; - break; - } - } - card->u.f.arp_dev = dev; - } - - if(!card->u.f.timer_int_enabled) - flags->imask &= ~FR_INTR_TIMER; -} - - -/*============================================================================ - * spur_intr: Spurious interrupt handler. - * - * Description: - * We don't know this interrupt. - * Print a warning. - */ - -static void spur_intr (sdla_t* card) -{ - if (net_ratelimit()){ - printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); - } -} - - -//FIXME: Fix the IPX in next version -/*=========================================================================== - * Return 0 for non-IPXWAN packet - * 1 for IPXWAN packet or IPX is not enabled! - * FIXME: Use a IPX structure here not offsets - */ -static int handle_IPXWAN(unsigned char *sendpacket, - char *devname, unsigned char enable_IPX, - unsigned long network_number) -{ - int i; - - if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && - sendpacket[6] == 0x81 && sendpacket[7] == 0x37) { - - /* It's an IPX packet */ - if (!enable_IPX){ - /* Return 1 so we don't pass it up the stack. */ - //FIXME: Take this out when IPX is fixed - if (net_ratelimit()){ - printk (KERN_INFO - "%s: WARNING: Unsupported IPX packet received and dropped\n", - devname); - } - return 1; - } - } else { - /* It's not IPX so return and pass it up the stack. */ - return 0; - } - - if( sendpacket[24] == 0x90 && sendpacket[25] == 0x04){ - /* It's IPXWAN */ - - if( sendpacket[10] == 0x02 && sendpacket[42] == 0x00){ - - /* It's a timer request packet */ - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", - devname); - - /* Go through the routing options and answer no to every - * option except Unnumbered RIP/SAP - */ - for(i = 49; sendpacket[i] == 0x00; i += 5){ - /* 0x02 is the option for Unnumbered RIP/SAP */ - if( sendpacket[i + 4] != 0x02){ - sendpacket[i + 1] = 0; - } - } - - /* Skip over the extended Node ID option */ - if( sendpacket[i] == 0x04 ){ - i += 8; - } - - /* We also want to turn off all header compression opt. - */ - for(; sendpacket[i] == 0x80 ;){ - sendpacket[i + 1] = 0; - i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; - } - - /* Set the packet type to timer response */ - sendpacket[42] = 0x01; - - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", - devname); - - } else if( sendpacket[42] == 0x02 ){ - - /* This is an information request packet */ - printk(KERN_INFO - "%s: Received IPXWAN Information Request packet\n", - devname); - - /* Set the packet type to information response */ - sendpacket[42] = 0x03; - - /* Set the router name */ - sendpacket[59] = 'F'; - sendpacket[60] = 'P'; - sendpacket[61] = 'I'; - sendpacket[62] = 'P'; - sendpacket[63] = 'E'; - sendpacket[64] = '-'; - sendpacket[65] = CVHexToAscii(network_number >> 28); - sendpacket[66] = CVHexToAscii((network_number & 0x0F000000)>> 24); - sendpacket[67] = CVHexToAscii((network_number & 0x00F00000)>> 20); - sendpacket[68] = CVHexToAscii((network_number & 0x000F0000)>> 16); - sendpacket[69] = CVHexToAscii((network_number & 0x0000F000)>> 12); - sendpacket[70] = CVHexToAscii((network_number & 0x00000F00)>> 8); - sendpacket[71] = CVHexToAscii((network_number & 0x000000F0)>> 4); - sendpacket[72] = CVHexToAscii(network_number & 0x0000000F); - for(i = 73; i < 107; i+= 1) - { - sendpacket[i] = 0; - } - - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", - devname); - } else { - - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); - return 0; - } - - /* Set the WNodeID to our network address */ - sendpacket[43] = (unsigned char)(network_number >> 24); - sendpacket[44] = (unsigned char)((network_number & 0x00FF0000) >> 16); - sendpacket[45] = (unsigned char)((network_number & 0x0000FF00) >> 8); - sendpacket[46] = (unsigned char)(network_number & 0x000000FF); - - return 1; - } - - /* If we get here, it's an IPX-data packet so it'll get passed up the - * stack. - * switch the network numbers - */ - switch_net_numbers(sendpacket, network_number ,1); - return 0; -} -/*============================================================================ - * process_route - * - * Rationale: - * If the interface goes down, or we receive an ARP request, - * we have to change the network interface ip addresses. - * This cannot be done within the interrupt. - * - * Description: - * - * This routine is called as a polling routine to dynamically - * add/delete routes negotiated by inverse ARP. It is in this - * "task" because we don't want routes to be added while in - * interrupt context. - * - * Usage: - * This function is called by fr_poll() polling funtion. - */ - -static void process_route(struct net_device *dev) -{ - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - - struct ifreq if_info; - struct sockaddr_in *if_data; - mm_segment_t fs = get_fs(); - u32 ip_tmp; - int err; - - - switch(chan->route_flag){ - - case ADD_ROUTE: - - /* Set remote addresses */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - - set_fs(get_ds()); /* get user space block */ - - if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data->sin_addr.s_addr = chan->ip_remote; - if_data->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); - - set_fs(fs); /* restore old block */ - - if (err) { - printk(KERN_INFO - "%s: Route Add failed. Error: %d\n", - card->devname,err); - printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n", - chan->name, NIPQUAD(chan->ip_remote)); - - }else { - printk(KERN_INFO "%s: Route Added Successfully: %u.%u.%u.%u\n", - card->devname,NIPQUAD(chan->ip_remote)); - chan->route_flag = ROUTE_ADDED; - } - break; - - case REMOVE_ROUTE: - - /* Set remote addresses */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - - ip_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); - - set_fs(get_ds()); /* get user space block */ - - if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data->sin_addr.s_addr = 0; - if_data->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); - - set_fs(fs); - - if (err) { - printk(KERN_INFO - "%s: Deleting of route failed. Error: %d\n", - card->devname,err); - printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n", - dev->name,NIPQUAD(chan->ip_remote) ); - - } else { - printk(KERN_INFO "%s: Route Removed Sucessfuly: %u.%u.%u.%u\n", - card->devname,NIPQUAD(ip_tmp)); - chan->route_flag = NO_ROUTE; - } - break; - - } /* Case Statement */ - -} - - - -/****** Frame Relay Firmware-Specific Functions *****************************/ - -/*============================================================================ - * Read firmware code version. - * o fill string str with firmware version info. - */ -static int fr_read_version (sdla_t* card, char* str) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->cmd.command = FR_READ_CODE_VERSION; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err && str) { - int len = mbox->cmd.length; - memcpy(str, mbox->data, len); - str[len] = '\0'; - } - return err; -} - -/*============================================================================ - * Set global configuration. - */ -static int fr_configure (sdla_t* card, fr_conf_t *conf) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int dlci_num = card->u.f.dlci_num; - int err, i; - - do - { - memcpy(mbox->data, conf, sizeof(fr_conf_t)); - - if (dlci_num) for (i = 0; i < dlci_num; ++i) - ((fr_conf_t*)mbox->data)->dlci[i] = - card->u.f.node_dlci[i]; - - mbox->cmd.command = FR_SET_CONFIG; - mbox->cmd.length = - sizeof(fr_conf_t) + dlci_num * sizeof(short); - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && fr_event(card, err, mbox)); - - /*NC Oct 12 2000 */ - if (err != CMD_OK){ - printk(KERN_ERR "%s: Frame Relay Configuration Failed: rc=0x%x\n", - card->devname,err); - } - - return err; -} - -/*============================================================================ - * Set DLCI configuration. - */ -static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t)); - mbox->cmd.dlci = (unsigned short) dlci; - mbox->cmd.command = FR_SET_CONFIG; - mbox->cmd.length = sizeof(fr_dlc_conf_t); - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry--); - - return err; -} -/*============================================================================ - * Set interrupt mode. - */ -static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu, - unsigned short timeout) -{ - fr_mbox_t* mbox = card->mbox; - fr508_intr_ctl_t* ictl = (void*)mbox->data; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(ictl, 0, sizeof(fr508_intr_ctl_t)); - ictl->mode = mode; - ictl->tx_len = mtu; - ictl->irq = card->hw.irq; - - /* indicate timeout on timer */ - if (mode & 0x20) ictl->timeout = timeout; - - mbox->cmd.length = sizeof(fr508_intr_ctl_t); - mbox->cmd.command = FR_SET_INTR_MODE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - -/*============================================================================ - * Enable communications. - */ -static int fr_comm_enable (sdla_t* card) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->cmd.command = FR_COMM_ENABLE; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - -/*============================================================================ - * fr_comm_disable - * - * Warning: This functin is called by the shutdown() procedure. It is void - * since dev->priv are has already been deallocated and no - * error checking is possible using fr_event() function. - */ -static void fr_comm_disable (sdla_t* card) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do { - mbox->cmd.command = FR_SET_MODEM_STATUS; - mbox->cmd.length = 1; - mbox->data[0] = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry--); - - retry = MAX_CMD_RETRY; - - do - { - mbox->cmd.command = FR_COMM_DISABLE; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry--); - - return; -} - - - -/*============================================================================ - * Get communications error statistics. - */ -static int fr_get_err_stats (sdla_t* card) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - - do - { - mbox->cmd.command = FR_READ_ERROR_STATS; - mbox->cmd.length = 0; - mbox->cmd.dlci = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) { - fr_comm_stat_t* stats = (void*)mbox->data; - card->wandev.stats.rx_over_errors = stats->rx_overruns; - card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; - card->wandev.stats.rx_missed_errors = stats->rx_aborts; - card->wandev.stats.rx_length_errors = stats->rx_too_long; - card->wandev.stats.tx_aborted_errors = stats->tx_aborts; - - } - - return err; -} - -/*============================================================================ - * Get statistics. - */ -static int fr_get_stats (sdla_t* card) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - - do - { - mbox->cmd.command = FR_READ_STATISTICS; - mbox->cmd.length = 0; - mbox->cmd.dlci = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) { - fr_link_stat_t* stats = (void*)mbox->data; - card->wandev.stats.rx_frame_errors = stats->rx_bad_format; - card->wandev.stats.rx_dropped = - stats->rx_dropped + stats->rx_dropped2; - } - - return err; -} - -/*============================================================================ - * Add DLCI(s) (Access Node only!). - * This routine will perform the ADD_DLCIs command for the specified DLCI. - */ -static int fr_add_dlci (sdla_t* card, int dlci) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - unsigned short* dlci_list = (void*)mbox->data; - - mbox->cmd.length = sizeof(short); - dlci_list[0] = dlci; - mbox->cmd.command = FR_ADD_DLCI; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - -/*============================================================================ - * Activate DLCI(s) (Access Node only!). - * This routine will perform the ACTIVATE_DLCIs command with a DLCI number. - */ -static int fr_activate_dlci (sdla_t* card, int dlci) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - unsigned short* dlci_list = (void*)mbox->data; - - mbox->cmd.length = sizeof(short); - dlci_list[0] = dlci; - mbox->cmd.command = FR_ACTIVATE_DLCI; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - -/*============================================================================ - * Delete DLCI(s) (Access Node only!). - * This routine will perform the DELETE_DLCIs command with a DLCI number. - */ -static int fr_delete_dlci (sdla_t* card, int dlci) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - unsigned short* dlci_list = (void*)mbox->data; - - mbox->cmd.length = sizeof(short); - dlci_list[0] = dlci; - mbox->cmd.command = FR_DELETE_DLCI; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - - - -/*============================================================================ - * Issue in-channel signalling frame. - */ -static int fr_issue_isf (sdla_t* card, int isf) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->data[0] = isf; - mbox->cmd.length = 1; - mbox->cmd.command = FR_ISSUE_IS_FRAME; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - - -static unsigned int fr_send_hdr (sdla_t*card, int dlci, unsigned int offset) -{ - struct net_device *dev = find_channel(card,dlci); - fr_channel_t *chan; - - if (!dev || !(chan=dev->priv)) - return offset; - - if (chan->fr_header_len){ - sdla_poke(&card->hw, offset, chan->fr_header, chan->fr_header_len); - } - - return offset+chan->fr_header_len; -} - -/*============================================================================ - * Send a frame on a selected DLCI. - */ -static int fr_send_data_header (sdla_t* card, int dlci, unsigned char attr, int len, - void *buf, unsigned char hdr_len) -{ - fr_mbox_t* mbox = card->mbox + 0x800; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->cmd.dlci = dlci; - mbox->cmd.attr = attr; - mbox->cmd.length = len+hdr_len; - mbox->cmd.command = FR_WRITE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) { - fr_tx_buf_ctl_t* frbuf; - - if(card->hw.type == SDLA_S514) - frbuf = (void*)(*(unsigned long*)mbox->data + - card->hw.dpmbase); - else - frbuf = (void*)(*(unsigned long*)mbox->data - - FR_MB_VECTOR + card->hw.dpmbase); - - sdla_poke(&card->hw, fr_send_hdr(card,dlci,frbuf->offset), buf, len); - frbuf->flag = 0x01; - } - - return err; -} - -static int fr_send (sdla_t* card, int dlci, unsigned char attr, int len, - void *buf) -{ - fr_mbox_t* mbox = card->mbox + 0x800; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->cmd.dlci = dlci; - mbox->cmd.attr = attr; - mbox->cmd.length = len; - mbox->cmd.command = FR_WRITE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) { - fr_tx_buf_ctl_t* frbuf; - - if(card->hw.type == SDLA_S514) - frbuf = (void*)(*(unsigned long*)mbox->data + - card->hw.dpmbase); - else - frbuf = (void*)(*(unsigned long*)mbox->data - - FR_MB_VECTOR + card->hw.dpmbase); - - sdla_poke(&card->hw, frbuf->offset, buf, len); - frbuf->flag = 0x01; - } - - return err; -} - - -/****** Firmware Asynchronous Event Handlers ********************************/ - -/*============================================================================ - * Main asyncronous event/error handler. - * This routine is called whenever firmware command returns non-zero - * return code. - * - * Return zero if previous command has to be cancelled. - */ -static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox) -{ - fr508_flags_t* flags = card->flags; - char *ptr = &flags->iflag; - int i; - - switch (event) { - - case FRRES_MODEM_FAILURE: - return fr_modem_failure(card, mbox); - - case FRRES_CHANNEL_DOWN: { - struct net_device *dev; - - /* Remove all routes from associated DLCI's */ - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)) { - fr_channel_t *chan = dev->priv; - if (chan->route_flag == ROUTE_ADDED) { - chan->route_flag = REMOVE_ROUTE; - } - - if (chan->inarp == INARP_CONFIGURED) { - chan->inarp = INARP_REQUEST; - } - - /* If the link becomes disconnected then, - * all channels will be disconnected - * as well. - */ - set_chan_state(dev,WAN_DISCONNECTED); - } - - wanpipe_set_state(card, WAN_DISCONNECTED); - return 1; - } - - case FRRES_CHANNEL_UP: { - struct net_device *dev; - - /* FIXME: Only startup devices that are on the list */ - - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)) { - - set_chan_state(dev,WAN_CONNECTED); - } - - wanpipe_set_state(card, WAN_CONNECTED); - return 1; - } - - case FRRES_DLCI_CHANGE: - return fr_dlci_change(card, mbox); - - case FRRES_DLCI_MISMATCH: - printk(KERN_INFO "%s: DLCI list mismatch!\n", - card->devname); - return 1; - - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, mbox->cmd.command); - printk(KERN_INFO "%s: ID Bytes = ",card->devname); - for(i = 0; i < 8; i ++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x18 + i)); - printk(KERN_INFO "\n"); - - break; - - case FRRES_DLCI_INACTIVE: - break; - - case FRRES_CIR_OVERFLOW: - break; - - case FRRES_BUFFER_OVERFLOW: - break; - - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" - , card->devname, mbox->cmd.command, event); - } - - return 0; -} - -/*============================================================================ - * Handle modem error. - * - * Return zero if previous command has to be cancelled. - */ -static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox) -{ - printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n", - card->devname, mbox->data[0]); - - switch (mbox->cmd.command){ - case FR_WRITE: - - case FR_READ: - return 0; - } - - return 1; -} - -/*============================================================================ - * Handle DLCI status change. - * - * Return zero if previous command has to be cancelled. - */ -static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox) -{ - dlci_status_t* status = (void*)mbox->data; - int cnt = mbox->cmd.length / sizeof(dlci_status_t); - fr_channel_t *chan; - struct net_device* dev2; - - - for (; cnt; --cnt, ++status) { - - unsigned short dlci= status->dlci; - struct net_device* dev = find_channel(card, dlci); - - if (dev == NULL){ - printk(KERN_INFO - "%s: CPE contains unconfigured DLCI= %d\n", - card->devname, dlci); - - printk(KERN_INFO - "%s: unconfigured DLCI %d reported by network\n" - , card->devname, dlci); - - }else{ - if (status->state == FR_LINK_INOPER) { - printk(KERN_INFO - "%s: DLCI %u is inactive!\n", - card->devname, dlci); - - if (dev && netif_running(dev)) - set_chan_state(dev, WAN_DISCONNECTED); - } - - if (status->state & FR_DLCI_DELETED) { - - printk(KERN_INFO - "%s: DLCI %u has been deleted!\n", - card->devname, dlci); - - if (dev && netif_running(dev)){ - - fr_channel_t *chan = dev->priv; - - if (chan->route_flag == ROUTE_ADDED) { - chan->route_flag = REMOVE_ROUTE; - /* The state change will trigger - * the fr polling routine */ - } - - if (chan->inarp == INARP_CONFIGURED) { - chan->inarp = INARP_REQUEST; - } - - set_chan_state(dev, WAN_DISCONNECTED); - } - - } else if (status->state & FR_DLCI_ACTIVE) { - - chan = dev->priv; - - /* This flag is used for configuring specific - DLCI(s) when they become active. - */ - chan->dlci_configured = DLCI_CONFIG_PENDING; - - set_chan_state(dev, WAN_CONNECTED); - - } - } - } - - for (dev2 = card->wandev.dev; dev2; - dev2 = *((struct net_device **)dev2->priv)){ - - chan = dev2->priv; - - if (chan->dlci_configured == DLCI_CONFIG_PENDING) { - if (fr_init_dlci(card, chan)){ - return 1; - } - } - - } - return 1; -} - - -static int fr_init_dlci (sdla_t *card, fr_channel_t *chan) -{ - fr_dlc_conf_t cfg; - - memset(&cfg, 0, sizeof(cfg)); - - if ( chan->cir_status == CIR_DISABLED) { - - cfg.cir_fwd = cfg.cir_bwd = 16; - cfg.bc_fwd = cfg.bc_bwd = 16; - cfg.conf_flags = 0x0001; - - }else if (chan->cir_status == CIR_ENABLED) { - - cfg.cir_fwd = cfg.cir_bwd = chan->cir; - cfg.bc_fwd = cfg.bc_bwd = chan->bc; - cfg.be_fwd = cfg.be_bwd = chan->be; - cfg.conf_flags = 0x0000; - } - - if (fr_dlci_configure( card, &cfg , chan->dlci)){ - printk(KERN_INFO - "%s: DLCI Configure failed for %d\n", - card->devname, chan->dlci); - return 1; - } - - chan->dlci_configured = DLCI_CONFIGURED; - - /* Read the interface byte mapping into the channel - * structure. - */ - read_DLCI_IB_mapping( card, chan ); - - return 0; -} -/******* Miscellaneous ******************************************************/ - -/*============================================================================ - * Update channel state. - */ -static int update_chan_state(struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->cmd.command = FR_LIST_ACTIVE_DLCI; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) { - - unsigned short* list = (void*)mbox->data; - int cnt = mbox->cmd.length / sizeof(short); - - err=1; - - for (; cnt; --cnt, ++list) { - - if (*list == chan->dlci) { - set_chan_state(dev, WAN_CONNECTED); - - - /* May 23 2000. NC - * When a dlci is added or restarted, - * the dlci_int_interface pointer must - * be reinitialized. */ - if (!chan->dlci_int_interface){ - err=fr_init_dlci (card,chan); - } - break; - } - } - } - - return err; -} - -/*============================================================================ - * Set channel state. - */ -static void set_chan_state(struct net_device* dev, int state) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - if (chan->common.state != state) { - - switch (state) { - - case WAN_CONNECTED: - printk(KERN_INFO - "%s: Interface %s: DLCI %d connected\n", - card->devname, dev->name, chan->dlci); - - /* If the interface was previoulsy down, - * bring it up, since the channel is active */ - - trigger_fr_poll (dev); - trigger_fr_arp (dev); - break; - - case WAN_CONNECTING: - printk(KERN_INFO - "%s: Interface %s: DLCI %d connecting\n", - card->devname, dev->name, chan->dlci); - break; - - case WAN_DISCONNECTED: - printk (KERN_INFO - "%s: Interface %s: DLCI %d disconnected!\n", - card->devname, dev->name, chan->dlci); - - /* If the interface is up, bring it down, - * since the channel is now disconnected */ - trigger_fr_poll (dev); - break; - } - - chan->common.state = state; - } - - chan->state_tick = jiffies; -} - -/*============================================================================ - * Find network device by its channel number. - * - * We need this critical flag because we change - * the dlci_to_dev_map outside the interrupt. - * - * NOTE: del_if() functions updates this array, it uses - * the spin locks to avoid corruption. - */ -static struct net_device* find_channel(sdla_t* card, unsigned dlci) -{ - if(dlci > HIGHEST_VALID_DLCI) - return NULL; - - return(card->u.f.dlci_to_dev_map[dlci]); -} - -/*============================================================================ - * Check to see if a frame can be sent. If no transmit buffers available, - * enable transmit interrupts. - * - * Return: 1 - Tx buffer(s) available - * 0 - no buffers available - */ -static int is_tx_ready (sdla_t* card, fr_channel_t* chan) -{ - unsigned char sb; - - if(card->hw.type == SDLA_S514) - return 1; - - sb = inb(card->hw.port); - if (sb & 0x02) - return 1; - - return 0; -} - -/*============================================================================ - * Convert decimal string to unsigned integer. - * If len != 0 then only 'len' characters of the string are converted. - */ -static unsigned int dec_to_uint (unsigned char* str, int len) -{ - unsigned val; - - if (!len) - len = strlen(str); - - for (val = 0; len && isdigit(*str); ++str, --len) - val = (val * 10) + (*str - (unsigned)'0'); - - return val; -} - - - -/*============================================================================= - * Store a UDP management packet for later processing. - */ - -static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, int dlci) -{ - int udp_pkt_stored = 0; - - struct net_device *dev = find_channel(card, dlci); - fr_channel_t *chan; - - if (!dev || !(chan=dev->priv)) - return 1; - - if(!card->u.f.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ - card->u.f.udp_pkt_lgth = skb->len + chan->fr_header_len; - card->u.f.udp_type = udp_type; - card->u.f.udp_pkt_src = udp_pkt_src; - card->u.f.udp_dlci = dlci; - memcpy(card->u.f.udp_pkt_data, skb->data, skb->len); - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UDP; - udp_pkt_stored = 1; - - }else{ - printk(KERN_INFO "ERROR: UDP packet not stored for DLCI %d\n", - dlci); - } - - if(udp_pkt_src == UDP_PKT_FRM_STACK){ - dev_kfree_skb_any(skb); - }else{ - dev_kfree_skb_any(skb); - } - - return(udp_pkt_stored); -} - - -/*============================================================================== - * Process UDP call of type FPIPE8ND - */ -static int process_udp_mgmt_pkt(sdla_t* card) -{ - - int c_retry = MAX_CMD_RETRY; - unsigned char *buf; - unsigned char frames; - unsigned int len; - unsigned short buffer_length; - struct sk_buff *new_skb; - fr_mbox_t* mbox = card->mbox; - int err; - struct timeval tv; - int udp_mgmt_req_valid = 1; - struct net_device* dev; - fr_channel_t* chan; - fr_udp_pkt_t *fr_udp_pkt; - unsigned short num_trc_els; - fr_trc_el_t* ptr_trc_el; - fr_trc_el_t trc_el; - fpipemon_trc_t* fpipemon_trc; - - char udp_pkt_src = card->u.f.udp_pkt_src; - int dlci = card->u.f.udp_dlci; - - /* Find network interface for this packet */ - dev = find_channel(card, dlci); - if (!dev){ - card->u.f.udp_pkt_lgth = 0; - return 1; - } - if ((chan = dev->priv) == NULL){ - card->u.f.udp_pkt_lgth = 0; - return 1; - } - - /* If the UDP packet is from the network, we are going to have to - transmit a response. Before doing so, we must check to see that - we are not currently transmitting a frame (in 'if_send()') and - that we are not already in a 'delayed transmit' state. - */ - if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { - if (check_tx_status(card,dev)){ - card->u.f.udp_pkt_lgth = 0; - return 1; - } - } - - fr_udp_pkt = (fr_udp_pkt_t *)card->u.f.udp_pkt_data; - - if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - switch(fr_udp_pkt->cblock.command) { - - case FR_READ_MODEM_STATUS: - case FR_READ_STATUS: - case FPIPE_ROUTER_UP_TIME: - case FR_READ_ERROR_STATS: - case FPIPE_DRIVER_STAT_GEN: - case FR_READ_STATISTICS: - case FR_READ_ADD_DLC_STATS: - case FR_READ_CONFIG: - case FR_READ_CODE_VERSION: - udp_mgmt_req_valid = 1; - break; - default: - udp_mgmt_req_valid = 0; - break; - } - } - - if(!udp_mgmt_req_valid) { - /* set length to 0 */ - fr_udp_pkt->cblock.length = 0; - /* set return code */ - fr_udp_pkt->cblock.result = 0xCD; - - chan->drvstats_gen.UDP_PIPE_mgmt_direction_err ++; - - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Warning, Illegal UDP command attempted from network: %x\n", - card->devname,fr_udp_pkt->cblock.command); - } - - } else { - - switch(fr_udp_pkt->cblock.command) { - - case FPIPE_ENABLE_TRACING: - if(!card->TracingEnabled) { - do { - mbox->cmd.command = FR_SET_TRACE_CONFIG; - mbox->cmd.length = 1; - mbox->cmd.dlci = 0x00; - mbox->data[0] = fr_udp_pkt->data[0] | - RESET_TRC; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - } while (err && c_retry-- && fr_event(card, err, - mbox)); - - if(err) { - card->TracingEnabled = 0; - /* set the return code */ - fr_udp_pkt->cblock.result = - mbox->cmd.result; - mbox->cmd.length = 0; - break; - } - - sdla_peek(&card->hw, NO_TRC_ELEMENTS_OFF, - &num_trc_els, 2); - sdla_peek(&card->hw, BASE_TRC_ELEMENTS_OFF, - &card->u.f.trc_el_base, 4); - card->u.f.curr_trc_el = card->u.f.trc_el_base; - card->u.f.trc_el_last = card->u.f.curr_trc_el + - ((num_trc_els - 1) * - sizeof(fr_trc_el_t)); - - /* Calculate the maximum trace data area in */ - /* the UDP packet */ - card->u.f.trc_bfr_space=(MAX_LGTH_UDP_MGNT_PKT - - //sizeof(fr_encap_hdr_t) - - sizeof(ip_pkt_t) - - sizeof(udp_pkt_t) - - sizeof(wp_mgmt_t) - - sizeof(cblock_t)); - - /* set return code */ - fr_udp_pkt->cblock.result = 0; - - } else { - /* set return code to line trace already - enabled */ - fr_udp_pkt->cblock.result = 1; - } - - mbox->cmd.length = 0; - card->TracingEnabled = 1; - break; - - - case FPIPE_DISABLE_TRACING: - if(card->TracingEnabled) { - - do { - mbox->cmd.command = FR_SET_TRACE_CONFIG; - mbox->cmd.length = 1; - mbox->cmd.dlci = 0x00; - mbox->data[0] = ~ACTIVATE_TRC; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - } while (err && c_retry-- && fr_event(card, err, mbox)); - } - - /* set return code */ - fr_udp_pkt->cblock.result = 0; - mbox->cmd.length = 0; - card->TracingEnabled = 0; - break; - - case FPIPE_GET_TRACE_INFO: - - /* Line trace cannot be performed on the 502 */ - if(!card->TracingEnabled) { - /* set return code */ - fr_udp_pkt->cblock.result = 1; - mbox->cmd.length = 0; - break; - } - - ptr_trc_el = (void *)card->u.f.curr_trc_el; - - buffer_length = 0; - fr_udp_pkt->data[0x00] = 0x00; - - for(frames = 0; frames < MAX_FRMS_TRACED; frames ++) { - - sdla_peek(&card->hw, (unsigned long)ptr_trc_el, - (void *)&trc_el.flag, - sizeof(fr_trc_el_t)); - if(trc_el.flag == 0x00) { - break; - } - if((card->u.f.trc_bfr_space - buffer_length) - < sizeof(fpipemon_trc_hdr_t)) { - fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; - break; - } - - fpipemon_trc = - (fpipemon_trc_t *)&fr_udp_pkt->data[buffer_length]; - fpipemon_trc->fpipemon_trc_hdr.status = - trc_el.attr; - fpipemon_trc->fpipemon_trc_hdr.tmstamp = - trc_el.tmstamp; - fpipemon_trc->fpipemon_trc_hdr.length = - trc_el.length; - - if(!trc_el.offset || !trc_el.length) { - - fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; - - }else if((trc_el.length + sizeof(fpipemon_trc_hdr_t) + 1) > - (card->u.f.trc_bfr_space - buffer_length)){ - - fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; - fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; - - }else { - fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x01; - sdla_peek(&card->hw, trc_el.offset, - fpipemon_trc->data, - trc_el.length); - } - - trc_el.flag = 0x00; - sdla_poke(&card->hw, (unsigned long)ptr_trc_el, - &trc_el.flag, 1); - - ptr_trc_el ++; - if((void *)ptr_trc_el > card->u.f.trc_el_last) - ptr_trc_el = (void*)card->u.f.trc_el_base; - - buffer_length += sizeof(fpipemon_trc_hdr_t); - if(fpipemon_trc->fpipemon_trc_hdr.data_passed) { - buffer_length += trc_el.length; - } - - if(fr_udp_pkt->data[0x00] & MORE_TRC_DATA) { - break; - } - } - - if(frames == MAX_FRMS_TRACED) { - fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; - } - - card->u.f.curr_trc_el = (void *)ptr_trc_el; - - /* set the total number of frames passed */ - fr_udp_pkt->data[0x00] |= - ((frames << 1) & (MAX_FRMS_TRACED << 1)); - - /* set the data length and return code */ - fr_udp_pkt->cblock.length = mbox->cmd.length = buffer_length; - fr_udp_pkt->cblock.result = 0; - break; - - case FPIPE_FT1_READ_STATUS: - sdla_peek(&card->hw, 0xF020, - &fr_udp_pkt->data[0x00] , 2); - fr_udp_pkt->cblock.length = mbox->cmd.length = 2; - fr_udp_pkt->cblock.result = 0; - break; - - case FPIPE_FLUSH_DRIVER_STATS: - init_chan_statistics(chan); - init_global_statistics(card); - mbox->cmd.length = 0; - break; - - case FPIPE_ROUTER_UP_TIME: - do_gettimeofday(&tv); - chan->router_up_time = tv.tv_sec - - chan->router_start_time; - *(unsigned long *)&fr_udp_pkt->data = - chan->router_up_time; - mbox->cmd.length = fr_udp_pkt->cblock.length = 4; - fr_udp_pkt->cblock.result = 0; - break; - - case FPIPE_DRIVER_STAT_IFSEND: - memcpy(fr_udp_pkt->data, - &chan->drvstats_if_send.if_send_entry, - sizeof(if_send_stat_t)); - mbox->cmd.length = fr_udp_pkt->cblock.length =sizeof(if_send_stat_t); - fr_udp_pkt->cblock.result = 0; - break; - - case FPIPE_DRIVER_STAT_INTR: - - memcpy(fr_udp_pkt->data, - &card->statistics.isr_entry, - sizeof(global_stats_t)); - - memcpy(&fr_udp_pkt->data[sizeof(global_stats_t)], - &chan->drvstats_rx_intr.rx_intr_no_socket, - sizeof(rx_intr_stat_t)); - - mbox->cmd.length = fr_udp_pkt->cblock.length = - sizeof(global_stats_t) + - sizeof(rx_intr_stat_t); - fr_udp_pkt->cblock.result = 0; - break; - - case FPIPE_DRIVER_STAT_GEN: - memcpy(fr_udp_pkt->data, - &chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, - sizeof(pipe_mgmt_stat_t)); - - memcpy(&fr_udp_pkt->data[sizeof(pipe_mgmt_stat_t)], - &card->statistics, sizeof(global_stats_t)); - - mbox->cmd.length = fr_udp_pkt->cblock.length = sizeof(global_stats_t)+ - sizeof(rx_intr_stat_t); - fr_udp_pkt->cblock.result = 0; - break; - - - case FR_FT1_STATUS_CTRL: - if(fr_udp_pkt->data[0] == 1) { - if(rCount++ != 0 ){ - fr_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - - /* Disable FT1 MONITOR STATUS */ - if(fr_udp_pkt->data[0] == 0) { - if( --rCount != 0) { - fr_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - goto udp_mgmt_dflt; - - - default: -udp_mgmt_dflt: - do { - memcpy(&mbox->cmd, - &fr_udp_pkt->cblock.command, - sizeof(fr_cmd_t)); - if(mbox->cmd.length) { - memcpy(&mbox->data, - (char *)fr_udp_pkt->data, - mbox->cmd.length); - } - - err = sdla_exec(mbox) ? mbox->cmd.result : - CMD_TIMEOUT; - } while (err && c_retry-- && fr_event(card, err, mbox)); - - if(!err) - chan->drvstats_gen. - UDP_PIPE_mgmt_adptr_cmnd_OK ++; - else - chan->drvstats_gen. - UDP_PIPE_mgmt_adptr_cmnd_timeout ++; - - /* copy the result back to our buffer */ - memcpy(&fr_udp_pkt->cblock.command, - &mbox->cmd, sizeof(fr_cmd_t)); - - if(mbox->cmd.length) { - memcpy(&fr_udp_pkt->data, - &mbox->data, mbox->cmd.length); - } - } - } - - /* Fill UDP TTL */ - fr_udp_pkt->ip_pkt.ttl = card->wandev.ttl; - len = reply_udp(card->u.f.udp_pkt_data, mbox->cmd.length); - - if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - chan->fr_header_len=2; - chan->fr_header[0]=Q922_UI; - chan->fr_header[1]=NLPID_IP; - - err = fr_send_data_header(card, dlci, 0, len, - card->u.f.udp_pkt_data,chan->fr_header_len); - if (err){ - chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_passed ++; - }else{ - chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_failed ++; - } - - } else { - /* Allocate socket buffer */ - if((new_skb = dev_alloc_skb(len)) != NULL) { - - /* copy data into new_skb */ - buf = skb_put(new_skb, len); - memcpy(buf, card->u.f.udp_pkt_data, len); - - chan->drvstats_gen. - UDP_PIPE_mgmt_passed_to_stack ++; - new_skb->dev = dev; - new_skb->protocol = htons(ETH_P_IP); - new_skb->mac.raw = new_skb->data; - netif_rx(new_skb); - - } else { - chan->drvstats_gen.UDP_PIPE_mgmt_no_socket ++; - printk(KERN_INFO - "%s: UDP mgmt cmnd, no socket buffers available!\n", - card->devname); - } - } - - card->u.f.udp_pkt_lgth = 0; - - return 1; -} - -/*============================================================================== - * Send Inverse ARP Request - */ - -int send_inarp_request(sdla_t *card, struct net_device *dev) -{ - int err=0; - - arphdr_1490_t *ArpPacket; - arphdr_fr_t *arphdr; - fr_channel_t *chan = dev->priv; - struct in_device *in_dev; - - in_dev = dev->ip_ptr; - - if(in_dev != NULL ) { - - ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC); - /* SNAP Header indicating ARP */ - ArpPacket->control = 0x03; - ArpPacket->pad = 0x00; - ArpPacket->NLPID = 0x80; - ArpPacket->OUI[0] = 0; - ArpPacket->OUI[1] = 0; - ArpPacket->OUI[2] = 0; - ArpPacket->PID = 0x0608; - - arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet - - /* InARP request */ - arphdr->ar_hrd = 0x0F00; /* Frame Relay HW type */ - arphdr->ar_pro = 0x0008; /* IP Protocol */ - arphdr->ar_hln = 2; /* HW addr length */ - arphdr->ar_pln = 4; /* IP addr length */ - arphdr->ar_op = htons(0x08); /* InARP Request */ - arphdr->ar_sha = 0; /* src HW DLCI - Doesn't matter */ - if(in_dev->ifa_list != NULL) - arphdr->ar_sip = in_dev->ifa_list->ifa_local; /* Local Address */else - arphdr->ar_sip = 0; - arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */ - arphdr->ar_tip = 0; /* Remote Address -- what we want */ - - err = fr_send(card, chan->dlci, 0, sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), - (void *)ArpPacket); - - if (!err){ - printk(KERN_INFO "\n%s: Sending InARP request on DLCI %d.\n", - card->devname, chan->dlci); - clear_bit(ARP_CRIT,&card->wandev.critical); - } - - kfree(ArpPacket); - }else{ - printk(KERN_INFO "%s: INARP ERROR: %s doesn't have a local IP address!\n", - card->devname,dev->name); - return 1; - } - - return 0; -} - - -/*============================================================================== - * Check packet for ARP Type - */ - -int is_arp(void *buf) -{ - arphdr_1490_t *arphdr = (arphdr_1490_t *)buf; - - if (arphdr->pad == 0x00 && - arphdr->NLPID == 0x80 && - arphdr->PID == 0x0608) - return 1; - else return 0; -} - -/*============================================================================== - * Process ARP Packet Type - */ - -int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device* dev) -{ - - - arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */ - fr_rx_buf_ctl_t* frbuf = card->rxmb; - struct in_device *in_dev; - fr_channel_t *chan = dev->priv; - - /* Before we transmit ARP packet, we must check - * to see that we are not currently transmitting a - * frame (in 'if_send()') and that we are not - * already in a 'delayed transmit' state. */ - if (check_tx_status(card,dev)){ - if (net_ratelimit()){ - printk(KERN_INFO "%s: Disabling comminication to process ARP\n", - card->devname); - } - set_bit(ARP_CRIT,&card->wandev.critical); - return 0; - } - - in_dev = dev->ip_ptr; - - /* Check that IP addresses exist for our network address */ - if (in_dev == NULL || in_dev->ifa_list == NULL) - return -1; - - switch (ntohs(arphdr->ar_op)) { - - case 0x08: // Inverse ARP request -- Send Reply, add route. - - /* Check for valid Address */ - printk(KERN_INFO "%s: Recvd PtP addr -InArp Req: %u.%u.%u.%u\n", - card->devname, NIPQUAD(arphdr->ar_sip)); - - - /* Check that the network address is the same as ours, only - * if the netowrk mask is not 255.255.255.255. Otherwise - * this check would not make sense */ - - if (in_dev->ifa_list->ifa_mask != 0xFFFFFFFF && - (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != - (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)){ - printk(KERN_INFO - "%s: Invalid PtP address. %u.%u.%u.%u InARP ignored.\n", - card->devname,NIPQUAD(arphdr->ar_sip)); - - printk(KERN_INFO "%s: mask %u.%u.%u.%u\n", - card->devname, NIPQUAD(in_dev->ifa_list->ifa_mask)); - printk(KERN_INFO "%s: local %u.%u.%u.%u\n", - card->devname,NIPQUAD(in_dev->ifa_list->ifa_local)); - return -1; - } - - if (in_dev->ifa_list->ifa_local == arphdr->ar_sip){ - printk(KERN_INFO - "%s: Local addr = PtP addr. InARP ignored.\n", - card->devname); - return -1; - } - - arphdr->ar_op = htons(0x09); /* InARP Reply */ - - /* Set addresses */ - arphdr->ar_tip = arphdr->ar_sip; - arphdr->ar_sip = in_dev->ifa_list->ifa_local; - - chan->ip_local = in_dev->ifa_list->ifa_local; - chan->ip_remote = arphdr->ar_sip; - - fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket); - - if (test_bit(ARP_CRIT,&card->wandev.critical)){ - if (net_ratelimit()){ - printk(KERN_INFO "%s: ARP Processed Enabling Communication!\n", - card->devname); - } - } - clear_bit(ARP_CRIT,&card->wandev.critical); - - chan->ip_local = in_dev->ifa_list->ifa_local; - chan->ip_remote = arphdr->ar_sip; - - /* Add Route Flag */ - /* The route will be added in the polling routine so - that it is not interrupt context. */ - - chan->route_flag = ADD_ROUTE; - trigger_fr_poll (dev); - - break; - - case 0x09: // Inverse ARP reply - - /* Check for valid Address */ - printk(KERN_INFO "%s: Recvd PtP addr %u.%u.%u.%u -InArp Reply\n", - card->devname, NIPQUAD(arphdr->ar_sip)); - - - /* Compare network addresses, only if network mask - * is not 255.255.255.255 It would not make sense - * to perform this test if the mask was all 1's */ - - if (in_dev->ifa_list->ifa_mask != 0xffffffff && - (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != - (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { - - printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", - card->devname); - return -1; - } - - /* Make sure that the received IP address is not - * the same as our own local address */ - if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { - printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", - card->devname); - return -1; - } - - chan->ip_local = in_dev->ifa_list->ifa_local; - chan->ip_remote = arphdr->ar_sip; - - /* Add Route Flag */ - /* The route will be added in the polling routine so - that it is not interrupt context. */ - - chan->route_flag = ADD_ROUTE; - chan->inarp = INARP_CONFIGURED; - trigger_fr_poll(dev); - - break; - default: - break; // ARP's and RARP's -- Shouldn't happen. - } - - return 0; -} - - -/*============================================================ - * trigger_fr_arp - * - * Description: - * Add an fr_arp() task into a arp - * timer handler for a specific dlci/interface. - * This will kick the fr_arp() routine - * within the specified time interval. - * - * Usage: - * This timer is used to send ARP requests at - * certain time intervals. - * Called by an interrupt to request an action - * at a later date. - */ - -static void trigger_fr_arp(struct net_device *dev) -{ - fr_channel_t* chan = dev->priv; - - mod_timer(&chan->fr_arp_timer, jiffies + chan->inarp_interval * HZ); - return; -} - - - -/*============================================================================== - * ARP Request Action - * - * This funciton is called by timer interrupt to send an arp request - * to the remote end. - */ - -static void fr_arp (unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - fr_channel_t *chan = dev->priv; - volatile sdla_t *card = chan->card; - fr508_flags_t* flags = card->flags; - - /* Send ARP packets for all devs' until - * ARP state changes to CONFIGURED */ - - if (chan->inarp == INARP_REQUEST && - chan->common.state == WAN_CONNECTED && - card->wandev.state == WAN_CONNECTED){ - set_bit(0,&chan->inarp_ready); - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_ARP; - flags->imask |= FR_INTR_TIMER; - } - - return; -} - - -/*============================================================================== - * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_ - * TEST_COUNTER times. - */ -static int intr_test( sdla_t* card ) -{ - fr_mbox_t* mb = card->mbox; - int err,i; - - err = fr_set_intr_mode(card, FR_INTR_READY, card->wandev.mtu, 0 ); - - if (err == CMD_OK) { - - for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ ) { - /* Run command READ_CODE_VERSION */ - mb->cmd.length = 0; - mb->cmd.command = FR_READ_CODE_VERSION; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - fr_event(card, err, mb); - } - - } else { - return err; - } - - err = fr_set_intr_mode( card, 0, card->wandev.mtu, 0 ); - - if( err != CMD_OK ) - return err; - - return 0; -} - -/*============================================================================== - * Determine what type of UDP call it is. FPIPE8ND ? - */ -static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) -{ - fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)skb->data; - - /* Quick HACK */ - - - if((fr_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && - (fr_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && - (fr_udp_pkt->udp_pkt.udp_dst_port == - ntohs(card->wandev.udp_port)) && - (fr_udp_pkt->wp_mgmt.request_reply == - UDPMGMT_REQUEST)) { - if(!strncmp(fr_udp_pkt->wp_mgmt.signature, - UDPMGMT_FPIPE_SIGNATURE, 8)){ - return UDP_FPIPE_TYPE; - } - } - return UDP_INVALID_TYPE; -} - - -/*============================================================================== - * Initializes the Statistics values in the fr_channel structure. - */ -void init_chan_statistics( fr_channel_t* chan) -{ - memset(&chan->drvstats_if_send.if_send_entry, 0, - sizeof(if_send_stat_t)); - memset(&chan->drvstats_rx_intr.rx_intr_no_socket, 0, - sizeof(rx_intr_stat_t)); - memset(&chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, 0, - sizeof(pipe_mgmt_stat_t)); -} - -/*============================================================================== - * Initializes the Statistics values in the Sdla_t structure. - */ -void init_global_statistics( sdla_t* card ) -{ - /* Intialize global statistics for a card */ - memset(&card->statistics.isr_entry, 0, sizeof(global_stats_t)); -} - -static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - dlci_IB_mapping_t* result; - int err, counter, found; - - do { - mbox->cmd.command = FR_READ_DLCI_IB_MAPPING; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if( mbox->cmd.result != 0){ - printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", - chan->name); - } - - counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t); - result = (void *)mbox->data; - - found = 0; - for (; counter; --counter, ++result) { - if ( result->dlci == chan->dlci ) { - chan->IB_addr = result->addr_value; - if(card->hw.type == SDLA_S514){ - chan->dlci_int_interface = - (void*)(card->hw.dpmbase + - chan->IB_addr); - }else{ - chan->dlci_int_interface = - (void*)(card->hw.dpmbase + - (chan->IB_addr & 0x00001FFF)); - - } - found = 1; - break; - } - } - if (!found) - printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", - card->devname, chan->dlci); -} - - - -void s508_s514_lock(sdla_t *card, unsigned long *smp_flags) -{ - if (card->hw.type != SDLA_S514){ - - spin_lock_irqsave(&card->wandev.lock, *smp_flags); - }else{ - spin_lock(&card->u.f.if_send_lock); - } - return; -} - - -void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags) -{ - if (card->hw.type != SDLA_S514){ - - spin_unlock_irqrestore (&card->wandev.lock, *smp_flags); - }else{ - spin_unlock(&card->u.f.if_send_lock); - } - return; -} - - - -/*---------------------------------------------------------------------- - RECEIVE INTERRUPT: BOTTOM HALF HANDLERS - ----------------------------------------------------------------------*/ - - -/*======================================================== - * bh_enqueue - * - * Description: - * Insert a received packet into a circular - * rx queue. This packet will be picked up - * by fr_bh() and sent up the stack to the - * user. - * - * Usage: - * This function is called by rx interrupt, - * in API mode. - * - */ - -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb) -{ - /* Check for full */ - fr_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - - - if (atomic_read(&chan->bh_buff_used) == MAX_BH_BUFF){ - ++card->wandev.stats.rx_dropped; - dev_kfree_skb_any(skb); - return 1; - } - - ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; - - if (chan->bh_write == (MAX_BH_BUFF-1)){ - chan->bh_write=0; - }else{ - ++chan->bh_write; - } - - atomic_inc(&chan->bh_buff_used); - - return 0; -} - - -/*======================================================== - * trigger_fr_bh - * - * Description: - * Kick the fr_bh() handler - * - * Usage: - * rx interrupt calls this function during - * the API mode. - */ - -static void trigger_fr_bh (fr_channel_t *chan) -{ - if (!test_and_set_bit(0,&chan->tq_working)){ - wanpipe_queue_work(&chan->common.wanpipe_work); - } -} - - -/*======================================================== - * fr_bh - * - * Description: - * Frame relay receive BH handler. - * Dequeue data from the BH circular - * buffer and pass it up the API sock. - * - * Rationale: - * This fuction is used to offload the - * rx_interrupt during API operation mode. - * The fr_bh() function executes for each - * dlci/interface. - * - * Once receive interrupt copies data from the - * card into an skb buffer, the skb buffer - * is appended to a circular BH buffer. - * Then the interrupt kicks fr_bh() to finish the - * job at a later time (not within the interrupt). - * - * Usage: - * Interrupts use this to defer a task to - * a polling routine. - * - */ - -static void fr_bh(struct net_device * dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - struct sk_buff *skb; - - if (atomic_read(&chan->bh_buff_used) == 0){ - clear_bit(0, &chan->tq_working); - return; - } - - while (atomic_read(&chan->bh_buff_used)){ - - if (chan->common.sk == NULL || chan->common.func == NULL){ - clear_bit(0, &chan->tq_working); - return; - } - - skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; - - if (skb != NULL){ - - if (chan->common.sk == NULL || chan->common.func == NULL){ - ++card->wandev.stats.rx_dropped; - ++chan->ifstats.rx_dropped; - dev_kfree_skb_any(skb); - fr_bh_cleanup(dev); - continue; - } - - if (chan->common.func(skb,dev,chan->common.sk) != 0){ - /* Sock full cannot send, queue us for - * another try */ - atomic_set(&chan->common.receive_block,1); - return; - }else{ - fr_bh_cleanup(dev); - } - }else{ - fr_bh_cleanup(dev); - } - } - clear_bit(0, &chan->tq_working); - - return; -} - -static int fr_bh_cleanup(struct net_device *dev) -{ - fr_channel_t* chan = dev->priv; - - ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; - - if (chan->bh_read == (MAX_BH_BUFF-1)){ - chan->bh_read=0; - }else{ - ++chan->bh_read; - } - - atomic_dec(&chan->bh_buff_used); - return 0; -} - - -/*---------------------------------------------------------------------- - POLL BH HANDLERS AND KICK ROUTINES - ----------------------------------------------------------------------*/ - -/*============================================================ - * trigger_fr_poll - * - * Description: - * Add a fr_poll() task into a tq_scheduler bh handler - * for a specific dlci/interface. This will kick - * the fr_poll() routine at a later time. - * - * Usage: - * Interrupts use this to defer a taks to - * a polling routine. - * - */ -static void trigger_fr_poll(struct net_device *dev) -{ - fr_channel_t* chan = dev->priv; - schedule_work(&chan->fr_poll_work); - return; -} - - -/*============================================================ - * fr_poll - * - * Rationale: - * We cannot manipulate the routing tables, or - * ip addresses withing the interrupt. Therefore - * we must perform such actons outside an interrupt - * at a later time. - * - * Description: - * Frame relay polling routine, responsible for - * shutting down interfaces upon disconnect - * and adding/removing routes. - * - * Usage: - * This function is executed for each frame relay - * dlci/interface through a tq_schedule bottom half. - * - * trigger_fr_poll() function is used to kick - * the fr_poll routine. - */ - -static void fr_poll(struct net_device *dev) -{ - - fr_channel_t* chan; - sdla_t *card; - u8 check_gateway=0; - - if (!dev || (chan = dev->priv) == NULL) - return; - - card = chan->card; - - /* (Re)Configuraiton is in progress, stop what you are - * doing and get out */ - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - return; - } - - switch (chan->common.state){ - - case WAN_DISCONNECTED: - - if (test_bit(DYN_OPT_ON,&chan->interface_down) && - !test_bit(DEV_DOWN, &chan->interface_down) && - dev->flags&IFF_UP){ - - printk(KERN_INFO "%s: Interface %s is Down.\n", - card->devname,dev->name); - change_dev_flags(dev,dev->flags&~IFF_UP); - set_bit(DEV_DOWN, &chan->interface_down); - chan->route_flag = NO_ROUTE; - - }else{ - if (chan->inarp != INARP_NONE) - process_route(dev); - } - break; - - case WAN_CONNECTED: - - if (test_bit(DYN_OPT_ON,&chan->interface_down) && - test_bit(DEV_DOWN, &chan->interface_down) && - !(dev->flags&IFF_UP)){ - - printk(KERN_INFO "%s: Interface %s is Up.\n", - card->devname,dev->name); - - change_dev_flags(dev,dev->flags|IFF_UP); - clear_bit(DEV_DOWN, &chan->interface_down); - check_gateway=1; - } - - if (chan->inarp != INARP_NONE){ - process_route(dev); - check_gateway=1; - } - - if (chan->gateway && check_gateway) - add_gateway(card,dev); - - break; - - } - - return; -} - -/*============================================================== - * check_tx_status - * - * Rationale: - * We cannot transmit from an interrupt while - * the if_send is transmitting data. Therefore, - * we must check whether the tx buffers are - * begin used, before we transmit from an - * interrupt. - * - * Description: - * Checks whether it's safe to use the transmit - * buffers. - * - * Usage: - * ARP and UDP handling routines use this function - * because, they need to transmit data during - * an interrupt. - */ - -static int check_tx_status(sdla_t *card, struct net_device *dev) -{ - - if (card->hw.type == SDLA_S514){ - if (test_bit(SEND_CRIT, (void*)&card->wandev.critical) || - test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { - return 1; - } - } - - if (netif_queue_stopped(dev) || (card->u.f.tx_interrupts_pending)) - return 1; - - return 0; -} - -/*=============================================================== - * move_dev_to_next - * - * Description: - * Move the dev pointer to the next location in the - * link list. Check if we are at the end of the - * list, if so start from the begining. - * - * Usage: - * Timer interrupt uses this function to efficiently - * step through the devices that need to send ARP data. - * - */ - -struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev) -{ - if (card->wandev.new_if_cnt != 1){ - if (!*((struct net_device **)dev->priv)) - return card->wandev.dev; - else - return *((struct net_device **)dev->priv); - } - return dev; -} - -/*============================================================== - * trigger_config_fr - * - * Rationale: - * All commands must be performed inside of a - * interrupt. - * - * Description: - * Kick the config_fr() routine throught the - * timer interrupt. - */ - - -static void trigger_config_fr (sdla_t *card) -{ - fr508_flags_t* flags = card->flags; - - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_CONFIG; - flags->imask |= FR_INTR_TIMER; -} - - -/*============================================================== - * config_fr - * - * Rationale: - * All commands must be performed inside of a - * interrupt. - & - * Description: - * Configure a DLCI. This function is executed - * by a timer_interrupt. The if_open() function - * triggers it. - * - * Usage: - * new_if() collects all data necessary to - * configure the DLCI. It sets the chan->dlci_ready - * bit. When the if_open() function is executed - * it checks this bit, and if its set it triggers - * the timer interrupt to execute the config_fr() - * function. - */ - -static void config_fr (sdla_t *card) -{ - struct net_device *dev; - fr_channel_t *chan; - - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)) { - - if ((chan=dev->priv) == NULL) - continue; - - if (!test_bit(0,&chan->config_dlci)) - continue; - - clear_bit(0,&chan->config_dlci); - - /* If signalling is set to NO, then setup - * DLCI addresses right away. Don't have to wait for - * link to connect. - */ - if (card->wandev.signalling == WANOPT_NO){ - printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n", - card->wandev.name); - if (fr_init_dlci(card,chan)){ - printk(KERN_INFO "%s: ERROR: Failed to configure DLCI %i !\n", - card->devname, chan->dlci); - return; - } - } - - if (card->wandev.station == WANOPT_CPE) { - - update_chan_state(dev); - - /* CPE: issue full status enquiry */ - fr_issue_isf(card, FR_ISF_FSE); - - } else { - /* FR switch: activate DLCI(s) */ - - /* For Switch emulation we have to ADD and ACTIVATE - * the DLCI(s) that were configured with the SET_DLCI_ - * CONFIGURATION command. Add and Activate will fail if - * DLCI specified is not included in the list. - * - * Also If_open is called once for each interface. But - * it does not get in here for all the interface. So - * we have to pass the entire list of DLCI(s) to add - * activate routines. - */ - - if (!check_dlci_config (card, chan)){ - fr_add_dlci(card, chan->dlci); - fr_activate_dlci(card, chan->dlci); - } - } - - card->u.f.dlci_to_dev_map[chan->dlci] = dev; - } - return; -} - - -/*============================================================== - * config_fr - * - * Rationale: - * All commands must be executed during an interrupt. - * - * Description: - * Trigger uncofig_fr() function through - * the timer interrupt. - * - */ - -static void trigger_unconfig_fr(struct net_device *dev) -{ - fr_channel_t *chan = dev->priv; - volatile sdla_t *card = chan->card; - unsigned long timeout; - fr508_flags_t* flags = card->flags; - int reset_critical=0; - - if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ - clear_bit(PERI_CRIT,(void*)&card->wandev.critical); - reset_critical=1; - } - - /* run unconfig_dlci() function - * throught the timer interrupt */ - set_bit(0,(void*)&chan->unconfig_dlci); - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UNCONFIG; - flags->imask |= FR_INTR_TIMER; - - /* Wait for the command to complete */ - timeout = jiffies; - for(;;) { - - if(!(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG)) - break; - - if (time_after(jiffies, timeout + 1 * HZ)){ - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG; - printk(KERN_INFO "%s: Failed to delete DLCI %i\n", - card->devname,chan->dlci); - break; - } - } - - if (reset_critical){ - set_bit(PERI_CRIT,(void*)&card->wandev.critical); - } -} - -/*============================================================== - * unconfig_fr - * - * Rationale: - * All commands must be executed during an interrupt. - * - * Description: - * Remove the dlci from firmware. - * This funciton is used in NODE shutdown. - */ - -static void unconfig_fr (sdla_t *card) -{ - struct net_device *dev; - fr_channel_t *chan; - - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)){ - - if ((chan=dev->priv) == NULL) - continue; - - if (!test_bit(0,&chan->unconfig_dlci)) - continue; - - clear_bit(0,&chan->unconfig_dlci); - - if (card->wandev.station == WANOPT_NODE){ - printk(KERN_INFO "%s: Unconfiguring DLCI %i\n", - card->devname,chan->dlci); - fr_delete_dlci(card,chan->dlci); - } - card->u.f.dlci_to_dev_map[chan->dlci] = NULL; - } -} - -static int setup_fr_header(struct sk_buff *skb, struct net_device* dev, - char op_mode) -{ - fr_channel_t *chan=dev->priv; - - if (op_mode == WANPIPE) { - chan->fr_header[0]=Q922_UI; - - switch (htons(skb->protocol)){ - case ETH_P_IP: - chan->fr_header[1]=NLPID_IP; - break; - default: - return -EINVAL; - } - - return 2; - } - - /* If we are in bridging mode, we must apply - * an Ethernet header - */ - if (op_mode == BRIDGE || op_mode == BRIDGE_NODE) { - /* Encapsulate the packet as a bridged Ethernet frame. */ -#ifdef DEBUG - printk(KERN_INFO "%s: encapsulating skb for frame relay\n", - dev->name); -#endif - chan->fr_header[0] = 0x03; - chan->fr_header[1] = 0x00; - chan->fr_header[2] = 0x80; - chan->fr_header[3] = 0x00; - chan->fr_header[4] = 0x80; - chan->fr_header[5] = 0xC2; - chan->fr_header[6] = 0x00; - chan->fr_header[7] = 0x07; - - /* Yuck. */ - skb->protocol = ETH_P_802_3; - return 8; - } - - return 0; -} - - -static int check_dlci_config (sdla_t *card, fr_channel_t *chan) -{ - fr_mbox_t* mbox = card->mbox; - int err=0; - fr_conf_t *conf=NULL; - unsigned short dlci_num = chan->dlci; - int dlci_offset=0; - struct net_device *dev = NULL; - - mbox->cmd.command = FR_READ_CONFIG; - mbox->cmd.length = 0; - mbox->cmd.dlci = dlci_num; - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - if (err == CMD_OK){ - return 0; - } - - for (dev = card->wandev.dev; dev; - dev=*((struct net_device **)dev->priv)) - set_chan_state(dev,WAN_DISCONNECTED); - - printk(KERN_INFO "DLCI %i Not configured, configuring\n",dlci_num); - - mbox->cmd.command = FR_COMM_DISABLE; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK){ - fr_event(card, err, mbox); - return 2; - } - - printk(KERN_INFO "Disabled Communications \n"); - - mbox->cmd.command = FR_READ_CONFIG; - mbox->cmd.length = 0; - mbox->cmd.dlci = 0; - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK){ - fr_event(card, err, mbox); - return 2; - } - - conf = (fr_conf_t *)mbox->data; - - dlci_offset=0; - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)) { - fr_channel_t *chan_tmp = dev->priv; - conf->dlci[dlci_offset] = chan_tmp->dlci; - dlci_offset++; - } - - printk(KERN_INFO "Got Fr configuration Buffer Length is %x Dlci %i Dlci Off %i\n", - mbox->cmd.length, - mbox->cmd.length > 0x20 ? conf->dlci[0] : -1, - dlci_offset ); - - mbox->cmd.length = 0x20 + dlci_offset*2; - - mbox->cmd.command = FR_SET_CONFIG; - mbox->cmd.dlci = 0; - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK){ - fr_event(card, err, mbox); - return 2; - } - - initialize_rx_tx_buffers (card); - - - printk(KERN_INFO "Configuraiton Succeded for new DLCI %i\n",dlci_num); - - if (fr_comm_enable (card)){ - return 2; - } - - printk(KERN_INFO "Enabling Communications \n"); - - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)) { - fr_channel_t *chan_tmp = dev->priv; - fr_init_dlci(card,chan_tmp); - fr_add_dlci(card, chan_tmp->dlci); - fr_activate_dlci(card, chan_tmp->dlci); - } - - printk(KERN_INFO "END OF CONFIGURAITON %i\n",dlci_num); - - return 1; -} - -static void initialize_rx_tx_buffers (sdla_t *card) -{ - fr_buf_info_t* buf_info; - - if (card->hw.type == SDLA_S514) { - - buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR + - FR508_RXBC_OFFS); - - card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase); - - card->u.f.rxmb_base = - (void*)(buf_info->rse_base + card->hw.dpmbase); - - card->u.f.rxmb_last = - (void*)(buf_info->rse_base + - (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + - card->hw.dpmbase); - }else{ - buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); - - card->rxmb = (void*)(buf_info->rse_next - - FR_MB_VECTOR + card->hw.dpmbase); - - card->u.f.rxmb_base = - (void*)(buf_info->rse_base - - FR_MB_VECTOR + card->hw.dpmbase); - - card->u.f.rxmb_last = - (void*)(buf_info->rse_base + - (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) - - FR_MB_VECTOR + card->hw.dpmbase); - } - - card->u.f.rx_base = buf_info->buf_base; - card->u.f.rx_top = buf_info->buf_top; - - card->u.f.tx_interrupts_pending = 0; - - return; -} - - - -MODULE_LICENSE("GPL"); - -/****** End *****************************************************************/ diff --git a/drivers/net/wan/sdla_ft1.c b/drivers/net/wan/sdla_ft1.c deleted file mode 100644 index 9d6528a..0000000 --- a/drivers/net/wan/sdla_ft1.c +++ /dev/null @@ -1,345 +0,0 @@ -/***************************************************************************** -* sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. -* -* Authors: Nenad Corbic -* Gideon Hack -* -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version -* 2 of the License, or (at your option) any later version. -* ============================================================================ -* Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. -* Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing -* Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices. -* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. -* Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). -* Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. -* Aug 07, 1998 David Fong Initial version. -*****************************************************************************/ - -#include -#include /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include /* ARPHRD_* defines */ -#include /* time_after() macro */ - -#include -#include - -#include /* sockaddr_in */ -#include -#include -#include /* htons(), etc. */ -#include -#include - -#include /* CHDLC firmware API definitions */ - -/****** Defines & Macros ****************************************************/ - -/* reasons for enabling the timer interrupt on the adapter */ -#define TMR_INT_ENABLED_UDP 0x0001 -#define TMR_INT_ENABLED_UPDATE 0x0002 - -#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ -#define CHDLC_HDR_LEN 1 - -#define IFF_POINTTOPOINT 0x10 - -#define WANPIPE 0x00 -#define API 0x01 -#define CHDLC_API 0x01 - -#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) - - -/******Data Structures*****************************************************/ - -/* This structure is placed in the private data area of the device structure. - * The card structure used to occupy the private area but now the following - * structure will incorporate the card structure along with CHDLC specific data - */ - -typedef struct chdlc_private_area -{ - struct net_device *slave; - sdla_t *card; - int TracingEnabled; /* For enabling Tracing */ - unsigned long curr_trace_addr; /* Used for Tracing */ - unsigned long start_trace_addr; - unsigned long end_trace_addr; - unsigned long base_addr_trace_buffer; - unsigned long end_addr_trace_buffer; - unsigned short number_trace_elements; - unsigned available_buffer_space; - unsigned long router_start_time; - unsigned char route_status; - unsigned char route_removed; - unsigned long tick_counter; /* For 5s timeout counter */ - unsigned long router_up_time; - u32 IP_address; /* IP addressing */ - u32 IP_netmask; - unsigned char mc; /* Mulitcast support on/off */ - unsigned short udp_pkt_lgth; /* udp packet processing */ - char udp_pkt_src; - char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; - unsigned short timer_int_enabled; - char update_comms_stats; /* updating comms stats */ - //FIXME: add driver stats as per frame relay! - -} chdlc_private_area_t; - -/* Route Status options */ -#define NO_ROUTE 0x00 -#define ADD_ROUTE 0x01 -#define ROUTE_ADDED 0x02 -#define REMOVE_ROUTE 0x03 - - -/****** Function Prototypes *************************************************/ -/* WAN link driver entry points. These are called by the WAN router module. */ -static int wpft1_exec (struct sdla *card, void *u_cmd, void *u_data); -static int chdlc_read_version (sdla_t* card, char* str); -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); - -/****** Public Functions ****************************************************/ - -/*============================================================================ - * Cisco HDLC protocol initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wpft1_init (sdla_t* card, wandev_conf_t* conf) -{ - unsigned char port_num; - int err; - - union - { - char str[80]; - } u; - volatile CHDLC_MAILBOX_STRUCT* mb; - CHDLC_MAILBOX_STRUCT* mb1; - unsigned long timeout; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_CHDLC) { - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - } - - /* Use primary port */ - card->u.c.comm_port = 0; - - - /* Initialize protocol-specific fields */ - if(card->hw.type != SDLA_S514){ - card->mbox = (void *) card->hw.dpmbase; - }else{ - card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; - } - - mb = mb1 = card->mbox; - - if (!card->configured){ - - /* The board will place an 'I' in the return code to indicate that it is - ready to accept commands. We expect this to be completed in less - than 1 second. */ - - timeout = jiffies; - while (mb->return_code != 'I') /* Wait 1s for board to initialize */ - if (time_after(jiffies, timeout + 1*HZ)) break; - - if (mb->return_code != 'I') { - printk(KERN_INFO - "%s: Initialization not completed by adapter\n", - card->devname); - printk(KERN_INFO "Please contact Sangoma representative.\n"); - return -EIO; - } - } - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - - if (chdlc_read_version(card, u.str)) - return -EIO; - - printk(KERN_INFO "%s: Running FT1 Configuration firmware v%s\n", - card->devname, u.str); - - card->isr = NULL; - card->poll = NULL; - card->exec = &wpft1_exec; - card->wandev.update = NULL; - card->wandev.new_if = NULL; - card->wandev.del_if = NULL; - card->wandev.state = WAN_DUALPORT; - card->wandev.udp_port = conf->udp_port; - - card->wandev.new_if_cnt = 0; - - /* This is for the ports link state */ - card->u.c.state = WAN_DISCONNECTED; - - /* reset the number of times the 'update()' proc has been called */ - card->u.c.update_call_count = 0; - - card->wandev.ttl = 0x7F; - card->wandev.interface = 0; - - card->wandev.clocking = 0; - - port_num = card->u.c.comm_port; - - /* Setup Port Bps */ - - card->wandev.bps = 0; - - card->wandev.mtu = MIN_LGTH_CHDLC_DATA_CFG; - - /* Set up the interrupt status area */ - /* Read the CHDLC Configuration and obtain: - * Ptr to shared memory infor struct - * Use this pointer to calculate the value of card->u.c.flags ! - */ - mb1->buffer_length = 0; - mb1->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; - if(err != COMMAND_OK) { - chdlc_error(card, err, mb1); - return -EIO; - } - - if(card->hw.type == SDLA_S514){ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct)); - }else{ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); - } - - card->wandev.state = WAN_FT1_READY; - printk(KERN_INFO "%s: FT1 Config Ready !\n",card->devname); - - return 0; -} - -static int wpft1_exec(sdla_t *card, void *u_cmd, void *u_data) -{ - CHDLC_MAILBOX_STRUCT* mbox = card->mbox; - int len; - - if (copy_from_user((void*)&mbox->command, u_cmd, sizeof(ft1_exec_cmd_t))){ - return -EFAULT; - } - - len = mbox->buffer_length; - - if (len) { - if( copy_from_user((void*)&mbox->data, u_data, len)){ - return -EFAULT; - } - } - - /* execute command */ - if (!sdla_exec(mbox)){ - return -EIO; - } - - /* return result */ - if( copy_to_user(u_cmd, (void*)&mbox->command, sizeof(ft1_exec_cmd_t))){ - return -EFAULT; - } - - len = mbox->buffer_length; - - if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)){ - return -EFAULT; - } - - return 0; - -} - -/*============================================================================ - * Read firmware code version. - * Put code version as ASCII string in str. - */ -static int chdlc_read_version (sdla_t* card, char* str) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int len; - char err; - mb->buffer_length = 0; - mb->command = READ_CHDLC_CODE_VERSION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - chdlc_error(card,err,mb); - } - else if (str) { /* is not null */ - len = mb->buffer_length; - memcpy(str, mb->data, len); - str[len] = '\0'; - } - return (err); -} - -/*============================================================================ - * Firmware error handler. - * This routine is called whenever firmware command returns non-zero - * return code. - * - * Return zero if previous command has to be cancelled. - */ -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) -{ - unsigned cmd = mb->command; - - switch (err) { - - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - break; - - case S514_BOTH_PORTS_SAME_CLK_MODE: - if(cmd == SET_CHDLC_CONFIGURATION) { - printk(KERN_INFO - "%s: Configure both ports for the same clock source\n", - card->devname); - break; - } - - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, cmd, err); - } - - return 0; -} - -MODULE_LICENSE("GPL"); diff --git a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c deleted file mode 100644 index a4b489c..0000000 --- a/drivers/net/wan/sdla_ppp.c +++ /dev/null @@ -1,3430 +0,0 @@ -/***************************************************************************** -* sdla_ppp.c WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module. -* -* Author: Nenad Corbic -* -* Copyright: (c) 1995-2001 Sangoma Technologies Inc. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version -* 2 of the License, or (at your option) any later version. -* ============================================================================ -* Feb 28, 2001 Nenad Corbic o Updated if_tx_timeout() routine for -* 2.4.X kernels. -* Nov 29, 2000 Nenad Corbic o Added the 2.4.x kernel support: -* get_ip_address() function has moved -* into the ppp_poll() routine. It cannot -* be called from an interrupt. -* Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging: -* Deny all and specify allowed requests. -* May 02, 2000 Nenad Corbic o Added the dynamic interface shutdown -* option. When the link goes down, the -* network interface IFF_UP flag is reset. -* Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. -* Feb 25, 2000 Nenad Corbic o Fixed the FT1 UDP debugger problem. -* Feb 09, 2000 Nenad Coribc o Shutdown bug fix. update() was called -* with NULL dev pointer: no check. -* Jan 24, 2000 Nenad Corbic o Disabled use of CMD complete inter. -* Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels -* Oct 25, 1999 Nenad Corbic o Support for 2.0.X kernels -* Moved dynamic route processing into -* a polling routine. -* Oct 07, 1999 Nenad Corbic o Support for S514 PCI card. -* Gideon Hack o UPD and Updates executed using timer interrupt -* Sep 10, 1999 Nenad Corbic o Fixed up the /proc statistics -* Jul 20, 1999 Nenad Corbic o Remove the polling routines and use -* interrupts instead. -* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X Kernels. -* Aug 13, 1998 Jaspreet Singh o Improved Line Tracing. -* Jun 22, 1998 David Fong o Added remote IP address assignment -* Mar 15, 1998 Alan Cox o 2.1.8x basic port. -* Apr 16, 1998 Jaspreet Singh o using htons() for the IPX protocol. -* Dec 09, 1997 Jaspreet Singh o Added PAP and CHAP. -* o Implemented new routines like -* ppp_set_inbnd_auth(), ppp_set_outbnd_auth(), -* tokenize() and strstrip(). -* Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs -* while they have been disabled. -* Nov 24, 1997 Jaspreet Singh o Fixed another RACE condition caused by -* disabling and enabling of irqs. -* o Added new counters for stats on disable/enable -* IRQs. -* Nov 10, 1997 Jaspreet Singh o Initialized 'skb->mac.raw' to 'skb->data' -* before every netif_rx(). -* o Free up the device structure in del_if(). -* Nov 07, 1997 Jaspreet Singh o Changed the delay to zero for Line tracing -* command. -* Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time. -* Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow -* control by avoiding RACE conditions. The -* cli() and restore_flags() are taken out. -* A new structure, "ppp_private_area", is added -* to provide Driver Statistics. -* Jul 21, 1997 Jaspreet Singh o Protected calls to sdla_peek() by adding -* save_flags(), cli() and restore_flags(). -* Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets -* o Added ability to discard mulitcast and -* broacast source addressed packets. -* Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities -* New case (0x25) statement in if_send routine. -* Added a global variable rCount to keep track -* of FT1 status enabled on the board. -* May 22, 1997 Jaspreet Singh o Added change in the PPP_SET_CONFIG command for -* 508 card to reflect changes in the new -* ppp508.sfm for supporting:continous transmission -* of Configure-Request packets without receiving a -* reply -* OR-ed 0x300 to conf_flags -* o Changed connect_tmout from 900 to 0 -* May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple boards -* Apr 25, 1997 Farhan Thawar o added UDP Management stuff -* Mar 11, 1997 Farhan Thawar Version 3.1.1 -* o fixed (+1) bug in rx_intr() -* o changed if_send() to return 0 if -* wandev.critical() is true -* o free socket buffer in if_send() if -* returning 0 -* Jan 15, 1997 Gene Kozin Version 3.1.0 -* o implemented exec() entry point -* Jan 06, 1997 Gene Kozin Initial version. -*****************************************************************************/ - -#include -#include /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include /* ARPHRD_* defines */ -#include /* htons(), etc. */ -#include /* sockaddr_in */ -#include /* time_after() macro */ - - -#include -#include -#include - -#include -#include /* PPP firmware API definitions */ -#include /* S514 Type Definition */ -/****** Defines & Macros ****************************************************/ - -#define PPP_DFLT_MTU 1500 /* default MTU */ -#define PPP_MAX_MTU 4000 /* maximum MTU */ -#define PPP_HDR_LEN 1 - -#define MAX_IP_ERRORS 100 - -#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ -#define HOLD_DOWN_TIME (5*HZ) /* link hold down time : Changed from 30 to 5 */ - -/* For handle_IPXWAN() */ -#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) - -/* Macro for enabling/disabling debugging comments */ -//#define NEX_DEBUG -#ifdef NEX_DEBUG -#define NEX_PRINTK(format, a...) printk(format, ## a) -#else -#define NEX_PRINTK(format, a...) -#endif /* NEX_DEBUG */ - -#define DCD(a) ( a & 0x08 ? "HIGH" : "LOW" ) -#define CTS(a) ( a & 0x20 ? "HIGH" : "LOW" ) -#define LCP(a) ( a == 0x09 ? "OPEN" : "CLOSED" ) -#define IP(a) ( a == 0x09 ? "ENABLED" : "DISABLED" ) - -#define TMR_INT_ENABLED_UPDATE 0x01 -#define TMR_INT_ENABLED_PPP_EVENT 0x02 -#define TMR_INT_ENABLED_UDP 0x04 -#define TMR_INT_ENABLED_CONFIG 0x20 - -/* Set Configuraton Command Definitions */ -#define PERCENT_TX_BUFF 60 -#define TIME_BETWEEN_CONF_REQ 30 -#define TIME_BETWEEN_PAP_CHAP_REQ 30 -#define WAIT_PAP_CHAP_WITHOUT_REPLY 300 -#define WAIT_AFTER_DCD_CTS_LOW 5 -#define TIME_DCD_CTS_LOW_AFTER_LNK_DOWN 10 -#define WAIT_DCD_HIGH_AFTER_ENABLE_COMM 900 -#define MAX_CONF_REQ_WITHOUT_REPLY 10 -#define MAX_TERM_REQ_WITHOUT_REPLY 2 -#define NUM_CONF_NAK_WITHOUT_REPLY 5 -#define NUM_AUTH_REQ_WITHOUT_REPLY 10 - -#define END_OFFSET 0x1F0 - - -/******Data Structures*****************************************************/ - -/* This structure is placed in the private data area of the device structure. - * The card structure used to occupy the private area but now the following - * structure will incorporate the card structure along with PPP specific data - */ - -typedef struct ppp_private_area -{ - struct net_device *slave; - sdla_t* card; - unsigned long router_start_time; /*router start time in sec */ - unsigned long tick_counter; /*used for 5 second counter*/ - unsigned mc; /*multicast support on or off*/ - unsigned char enable_IPX; - unsigned long network_number; - unsigned char pap; - unsigned char chap; - unsigned char sysname[31]; /* system name for in-bnd auth*/ - unsigned char userid[511]; /* list of user ids */ - unsigned char passwd[511]; /* list of passwords */ - unsigned protocol; /* SKB Protocol */ - u32 ip_local; /* Local IP Address */ - u32 ip_remote; /* remote IP Address */ - - u32 ip_local_tmp; - u32 ip_remote_tmp; - - unsigned char timer_int_enabled; /* Who enabled the timer inter*/ - unsigned char update_comms_stats; /* Used by update function */ - unsigned long curr_trace_addr; /* Trace information */ - unsigned long start_trace_addr; - unsigned long end_trace_addr; - - unsigned char interface_down; /* Brind down interface when channel - goes down */ - unsigned long config_wait_timeout; /* After if_open() if in dynamic if mode, - wait a few seconds before configuring */ - - unsigned short udp_pkt_lgth; - char udp_pkt_src; - char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; - - /* PPP specific statistics */ - - if_send_stat_t if_send_stat; - rx_intr_stat_t rx_intr_stat; - pipe_mgmt_stat_t pipe_mgmt_stat; - - unsigned long router_up_time; - - /* Polling work queue entry. Each interface - * has its own work queue entry, which is used - * to defer events from the interrupt */ - struct work_struct poll_work; - struct timer_list poll_delay_timer; - - u8 gateway; - u8 config_ppp; - u8 ip_error; - -}ppp_private_area_t; - -/* variable for keeping track of enabling/disabling FT1 monitor status */ -static int rCount = 0; - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/****** Function Prototypes *************************************************/ - -/* WAN link driver entry points. These are called by the WAN router module. */ -static int update(struct wan_device *wandev); -static int new_if(struct wan_device *wandev, struct net_device *dev, - wanif_conf_t *conf); -static int del_if(struct wan_device *wandev, struct net_device *dev); - -/* WANPIPE-specific entry points */ -static int wpp_exec (struct sdla *card, void *u_cmd, void *u_data); - -/* Network device interface */ -static int if_init(struct net_device *dev); -static int if_open(struct net_device *dev); -static int if_close(struct net_device *dev); -static int if_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, - void *daddr, void *saddr, unsigned len); - -static void if_tx_timeout(struct net_device *dev); - -static int if_rebuild_hdr(struct sk_buff *skb); -static struct net_device_stats *if_stats(struct net_device *dev); -static int if_send(struct sk_buff *skb, struct net_device *dev); - - -/* PPP firmware interface functions */ -static int ppp_read_version(sdla_t *card, char *str); -static int ppp_set_outbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); -static int ppp_set_inbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); -static int ppp_configure(sdla_t *card, void *data); -static int ppp_set_intr_mode(sdla_t *card, unsigned char mode); -static int ppp_comm_enable(sdla_t *card); -static int ppp_comm_disable(sdla_t *card); -static int ppp_comm_disable_shutdown(sdla_t *card); -static int ppp_get_err_stats(sdla_t *card); -static int ppp_send(sdla_t *card, void *data, unsigned len, unsigned proto); -static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb); - -static void wpp_isr(sdla_t *card); -static void rx_intr(sdla_t *card); -static void event_intr(sdla_t *card); -static void timer_intr(sdla_t *card); - -/* Background polling routines */ -static void process_route(sdla_t *card); -static void retrigger_comm(sdla_t *card); - -/* Miscellaneous functions */ -static int read_info( sdla_t *card ); -static int read_connection_info (sdla_t *card); -static void remove_route( sdla_t *card ); -static int config508(struct net_device *dev, sdla_t *card); -static void show_disc_cause(sdla_t * card, unsigned cause); -static int reply_udp( unsigned char *data, unsigned int mbox_len ); -static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, - ppp_private_area_t *ppp_priv_area); -static void init_ppp_tx_rx_buff( sdla_t *card ); -static int intr_test( sdla_t *card ); -static int udp_pkt_type( struct sk_buff *skb , sdla_t *card); -static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area); -static void init_global_statistics( sdla_t *card ); -static int tokenize(char *str, char **tokens); -static char* strstrip(char *str, char *s); -static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev, - struct sk_buff *skb); - -static int config_ppp (sdla_t *); -static void ppp_poll(struct net_device *dev); -static void trigger_ppp_poll(struct net_device *dev); -static void ppp_poll_delay (unsigned long dev_ptr); - - -static int Read_connection_info; -static int Intr_test_counter; -static unsigned short available_buffer_space; - - -/* IPX functions */ -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, - unsigned char incoming); -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_PX, - unsigned long network_number, unsigned short proto); - -/* Lock Functions */ -static void s508_lock (sdla_t *card, unsigned long *smp_flags); -static void s508_unlock (sdla_t *card, unsigned long *smp_flags); - -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - ppp_private_area_t* ppp_priv_area ); -static unsigned short calc_checksum (char *data, int len); -static void disable_comm (sdla_t *card); -static int detect_and_fix_tx_bug (sdla_t *card); - -/****** Public Functions ****************************************************/ - -/*============================================================================ - * PPP protocol initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wpp_init(sdla_t *card, wandev_conf_t *conf) -{ - ppp_flags_t *flags; - union - { - char str[80]; - } u; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_PPP) { - - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - - } - - /* Initialize miscellaneous pointers to structures on the adapter */ - switch (card->hw.type) { - - case SDLA_S508: - card->mbox =(void*)(card->hw.dpmbase + PPP508_MB_OFFS); - card->flags=(void*)(card->hw.dpmbase + PPP508_FLG_OFFS); - break; - - case SDLA_S514: - card->mbox =(void*)(card->hw.dpmbase + PPP514_MB_OFFS); - card->flags=(void*)(card->hw.dpmbase + PPP514_FLG_OFFS); - break; - - default: - return -EINVAL; - - } - flags = card->flags; - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str)) - return -EIO; - - printk(KERN_INFO "%s: running PPP firmware v%s\n",card->devname, u.str); - /* Adjust configuration and set defaults */ - card->wandev.mtu = (conf->mtu) ? - min_t(unsigned int, conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU; - - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->isr = &wpp_isr; - card->poll = NULL; - card->exec = &wpp_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.udp_port = conf->udp_port; - card->wandev.ttl = conf->ttl; - card->wandev.state = WAN_DISCONNECTED; - card->disable_comm = &disable_comm; - card->irq_dis_if_send_count = 0; - card->irq_dis_poll_count = 0; - card->u.p.authenticator = conf->u.ppp.authenticator; - card->u.p.ip_mode = conf->u.ppp.ip_mode ? - conf->u.ppp.ip_mode : WANOPT_PPP_STATIC; - card->TracingEnabled = 0; - Read_connection_info = 1; - - /* initialize global statistics */ - init_global_statistics( card ); - - - - if (!card->configured){ - int err; - - Intr_test_counter = 0; - err = intr_test(card); - - if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk("%s: Interrupt Test Failed, Counter: %i\n", - card->devname, Intr_test_counter); - printk( "%s: Please choose another interrupt\n",card->devname); - return -EIO; - } - - printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", - card->devname, Intr_test_counter); - card->configured = 1; - } - - ppp_set_intr_mode(card, PPP_INTR_TIMER); - - /* Turn off the transmit and timer interrupt */ - flags->imask &= ~PPP_INTR_TIMER; - - printk(KERN_INFO "\n"); - - return 0; -} - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Update device status & statistics. - */ -static int update(struct wan_device *wandev) -{ - sdla_t* card = wandev->private; - struct net_device* dev; - volatile ppp_private_area_t *ppp_priv_area; - ppp_flags_t *flags = card->flags; - unsigned long timeout; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - - if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - /* Shutdown bug fix. This function can be - * called with NULL dev pointer during - * shutdown - */ - if ((dev=card->wandev.dev) == NULL){ - return -ENODEV; - } - - if ((ppp_priv_area=dev->priv) == NULL){ - return -ENODEV; - } - - ppp_priv_area->update_comms_stats = 2; - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UPDATE; - flags->imask |= PPP_INTR_TIMER; - - /* wait a maximum of 1 second for the statistics to be updated */ - timeout = jiffies; - for(;;) { - if(ppp_priv_area->update_comms_stats == 0){ - break; - } - if (time_after(jiffies, timeout + 1 * HZ)){ - ppp_priv_area->update_comms_stats = 0; - ppp_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - return -EAGAIN; - } - } - - return 0; -} - -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. - * - * Return: 0 o.k. - * < 0 failure (channel will not be created) - */ -static int new_if(struct wan_device *wandev, struct net_device *dev, - wanif_conf_t *conf) -{ - sdla_t *card = wandev->private; - ppp_private_area_t *ppp_priv_area; - - if (wandev->ndev) - return -EEXIST; - - - printk(KERN_INFO "%s: Configuring Interface: %s\n", - card->devname, conf->name); - - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - - printk(KERN_INFO "%s: Invalid interface name!\n", - card->devname); - return -EINVAL; - - } - - /* allocate and initialize private data */ - ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL); - - if( ppp_priv_area == NULL ) - return -ENOMEM; - - memset(ppp_priv_area, 0, sizeof(ppp_private_area_t)); - - ppp_priv_area->card = card; - - /* initialize data */ - strcpy(card->u.p.if_name, conf->name); - - /* initialize data in ppp_private_area structure */ - - init_ppp_priv_struct( ppp_priv_area ); - - ppp_priv_area->mc = conf->mc; - ppp_priv_area->pap = conf->pap; - ppp_priv_area->chap = conf->chap; - - /* Option to bring down the interface when - * the link goes down */ - if (conf->if_down){ - set_bit(DYN_OPT_ON,&ppp_priv_area->interface_down); - printk("%s: Dynamic interface configuration enabled\n", - card->devname); - } - - /* If no user ids are specified */ - if(!strlen(conf->userid) && (ppp_priv_area->pap||ppp_priv_area->chap)){ - kfree(ppp_priv_area); - return -EINVAL; - } - - /* If no passwords are specified */ - if(!strlen(conf->passwd) && (ppp_priv_area->pap||ppp_priv_area->chap)){ - kfree(ppp_priv_area); - return -EINVAL; - } - - if(strlen(conf->sysname) > 31){ - kfree(ppp_priv_area); - return -EINVAL; - } - - /* If no system name is specified */ - if(!strlen(conf->sysname) && (card->u.p.authenticator)){ - kfree(ppp_priv_area); - return -EINVAL; - } - - /* copy the data into the ppp private structure */ - memcpy(ppp_priv_area->userid, conf->userid, strlen(conf->userid)); - memcpy(ppp_priv_area->passwd, conf->passwd, strlen(conf->passwd)); - memcpy(ppp_priv_area->sysname, conf->sysname, strlen(conf->sysname)); - - - ppp_priv_area->enable_IPX = conf->enable_IPX; - if (conf->network_number){ - ppp_priv_area->network_number = conf->network_number; - }else{ - ppp_priv_area->network_number = 0xDEADBEEF; - } - - /* Tells us that if this interface is a - * gateway or not */ - if ((ppp_priv_area->gateway = conf->gateway) == WANOPT_YES){ - printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", - card->devname,card->u.p.if_name); - } - - /* prepare network device data space for registration */ - strcpy(dev->name,card->u.p.if_name); - - dev->init = &if_init; - dev->priv = ppp_priv_area; - dev->mtu = min_t(unsigned int, dev->mtu, card->wandev.mtu); - - /* Initialize the polling work routine */ - INIT_WORK(&ppp_priv_area->poll_work, (void*)(void*)ppp_poll, dev); - - /* Initialize the polling delay timer */ - init_timer(&ppp_priv_area->poll_delay_timer); - ppp_priv_area->poll_delay_timer.data = (unsigned long)dev; - ppp_priv_area->poll_delay_timer.function = ppp_poll_delay; - - - /* Since we start with dummy IP addresses we can say - * that route exists */ - printk(KERN_INFO "\n"); - - return 0; -} - -/*============================================================================ - * Delete logical channel. - */ -static int del_if(struct wan_device *wandev, struct net_device *dev) -{ - return 0; -} - -static void disable_comm (sdla_t *card) -{ - ppp_comm_disable_shutdown(card); - return; -} - -/****** WANPIPE-specific entry points ***************************************/ - -/*============================================================================ - * Execute adapter interface command. - */ - -//FIXME: Why do we need this ???? -static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data) -{ - ppp_mbox_t *mbox = card->mbox; - int len; - - if (copy_from_user((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t))) - return -EFAULT; - - len = mbox->cmd.length; - - if (len) { - - if( copy_from_user((void*)&mbox->data, u_data, len)) - return -EFAULT; - - } - - /* execute command */ - if (!sdla_exec(mbox)) - return -EIO; - - /* return result */ - if( copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(ppp_cmd_t))) - return -EFAULT; - len = mbox->cmd.length; - - if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) - return -EFAULT; - - return 0; -} - -/****** Network Device Interface ********************************************/ - -/*============================================================================ - * Initialize Linux network interface. - * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. - */ -static int if_init(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - struct wan_device *wandev = &card->wandev; - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - dev->tx_timeout = &if_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - /* Initialize media-specific parameters */ - dev->type = ARPHRD_PPP; /* ARP h/w type */ - dev->flags |= IFF_POINTOPOINT; - dev->flags |= IFF_NOARP; - - /* Enable Mulitcasting if specified by user*/ - if (ppp_priv_area->mc == WANOPT_YES){ - dev->flags |= IFF_MULTICAST; - } - - dev->mtu = wandev->mtu; - dev->hard_header_len = PPP_HDR_LEN; /* media header length */ - - /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; - - /* Set transmit buffer queue length */ - dev->tx_queue_len = 100; - SET_MODULE_OWNER(dev); - - return 0; -} - -/*============================================================================ - * Open network interface. - * o enable communications and interrupts. - * o prevent module from unloading by incrementing use count - * - * Return 0 if O.k. or errno. - */ -static int if_open(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - struct timeval tv; - //unsigned long smp_flags; - - if (netif_running(dev)) - return -EBUSY; - - wanpipe_open(card); - - netif_start_queue(dev); - - do_gettimeofday( &tv ); - ppp_priv_area->router_start_time = tv.tv_sec; - - /* We cannot configure the card here because we don't - * have access to the interface IP addresses. - * Once the interface initilization is complete, we will be - * able to access the IP addresses. Therefore, - * configure the ppp link in the poll routine */ - set_bit(0,&ppp_priv_area->config_ppp); - ppp_priv_area->config_wait_timeout=jiffies; - - /* Start the PPP configuration after 1sec delay. - * This will give the interface initilization time - * to finish its configuration */ - mod_timer(&ppp_priv_area->poll_delay_timer, jiffies + HZ); - return 0; -} - -/*============================================================================ - * Close network interface. - * o if this is the last open, then disable communications and interrupts. - * o reset flags. - */ -static int if_close(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - - netif_stop_queue(dev); - wanpipe_close(card); - - del_timer (&ppp_priv_area->poll_delay_timer); - return 0; -} - -/*============================================================================ - * Build media header. - * - * The trick here is to put packet type (Ethertype) into 'protocol' field of - * the socket buffer, so that we don't forget it. If packet type is not - * supported, set skb->protocol to 0 and discard packet later. - * - * Return: media header length. - */ -static int if_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - switch (type) - { - case ETH_P_IP: - case ETH_P_IPX: - skb->protocol = htons(type); - break; - - default: - skb->protocol = 0; - } - - return PPP_HDR_LEN; -} - -/*============================================================================ - * Re-build media header. - * - * Return: 1 physical address resolved. - * 0 physical address not resolved - */ -static int if_rebuild_hdr (struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - - printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); - return 1; -} - -/*============================================================================ - * Handle transmit timeout event from netif watchdog - */ -static void if_tx_timeout(struct net_device *dev) -{ - ppp_private_area_t* chan = dev->priv; - sdla_t *card = chan->card; - - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - - ++ chan->if_send_stat.if_send_tbusy; - ++card->wandev.stats.collisions; - - printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); - ++chan->if_send_stat.if_send_tbusy_timeout; - netif_wake_queue (dev); -} - - - -/*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission) to block a timer-based - * transmit from overlapping. - * o check link state. If link is not up, then drop the packet. - * o execute adapter send command. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. - */ -static int if_send (struct sk_buff *skb, struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - unsigned char *sendpacket; - unsigned long smp_flags; - ppp_flags_t *flags = card->flags; - int udp_type; - int err=0; - - ++ppp_priv_area->if_send_stat.if_send_entry; - - netif_stop_queue(dev); - - if (skb == NULL) { - - /* If we get here, some higher layer thinks we've missed an - * tx-done interrupt. - */ - printk(KERN_INFO "%s: interface %s got kicked!\n", - card->devname, dev->name); - - ++ppp_priv_area->if_send_stat.if_send_skb_null; - - netif_wake_queue(dev); - return 0; - } - - sendpacket = skb->data; - - udp_type = udp_pkt_type( skb, card ); - - - if (udp_type == UDP_PTPIPE_TYPE){ - if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, - ppp_priv_area)){ - flags->imask |= PPP_INTR_TIMER; - } - ++ppp_priv_area->if_send_stat.if_send_PIPE_request; - netif_start_queue(dev); - return 0; - } - - /* Check for broadcast and multicast addresses - * If found, drop (deallocate) a packet and return. - */ - if(chk_bcast_mcast_addr(card, dev, skb)){ - ++card->wandev.stats.tx_dropped; - dev_kfree_skb_any(skb); - netif_start_queue(dev); - return 0; - } - - - if(card->hw.type != SDLA_S514){ - s508_lock(card,&smp_flags); - } - - if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - - printk(KERN_INFO "%s: Critical in if_send: %lx\n", - card->wandev.name,card->wandev.critical); - - ++card->wandev.stats.tx_dropped; - ++ppp_priv_area->if_send_stat.if_send_critical_non_ISR; - netif_start_queue(dev); - goto if_send_exit_crit; - } - - if (card->wandev.state != WAN_CONNECTED) { - - ++ppp_priv_area->if_send_stat.if_send_wan_disconnected; - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - - } else if (!skb->protocol) { - ++ppp_priv_area->if_send_stat.if_send_protocol_error; - ++card->wandev.stats.tx_errors; - netif_start_queue(dev); - - } else { - - /*If it's IPX change the network numbers to 0 if they're ours.*/ - if( skb->protocol == htons(ETH_P_IPX) ) { - if(ppp_priv_area->enable_IPX) { - switch_net_numbers( skb->data, - ppp_priv_area->network_number, 0); - } else { - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - goto if_send_exit_crit; - } - } - - if (ppp_send(card, skb->data, skb->len, skb->protocol)) { - netif_stop_queue(dev); - ++ppp_priv_area->if_send_stat.if_send_adptr_bfrs_full; - ++ppp_priv_area->if_send_stat.if_send_tx_int_enabled; - } else { - ++ppp_priv_area->if_send_stat.if_send_bfr_passed_to_adptr; - ++card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += skb->len; - netif_start_queue(dev); - dev->trans_start = jiffies; - } - } - -if_send_exit_crit: - - if (!(err=netif_queue_stopped(dev))){ - dev_kfree_skb_any(skb); - }else{ - ppp_priv_area->tick_counter = jiffies; - flags->imask |= PPP_INTR_TXRDY; /* unmask Tx interrupts */ - } - - clear_bit(SEND_CRIT,&card->wandev.critical); - if(card->hw.type != SDLA_S514){ - s508_unlock(card,&smp_flags); - } - - return err; -} - - -/*============================================================================= - * Store a UDP management packet for later processing. - */ - -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - ppp_private_area_t* ppp_priv_area ) -{ - int udp_pkt_stored = 0; - - if(!ppp_priv_area->udp_pkt_lgth && (skb->len<=MAX_LGTH_UDP_MGNT_PKT)){ - ppp_priv_area->udp_pkt_lgth = skb->len; - ppp_priv_area->udp_pkt_src = udp_pkt_src; - memcpy(ppp_priv_area->udp_pkt_data, skb->data, skb->len); - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UDP; - ppp_priv_area->protocol = skb->protocol; - udp_pkt_stored = 1; - }else{ - if (skb->len > MAX_LGTH_UDP_MGNT_PKT){ - printk(KERN_INFO "%s: PIPEMON UDP request too long : %i\n", - card->devname, skb->len); - }else{ - printk(KERN_INFO "%s: PIPEMON UPD request already pending\n", - card->devname); - } - ppp_priv_area->udp_pkt_lgth = 0; - } - - if(udp_pkt_src == UDP_PKT_FRM_STACK){ - dev_kfree_skb_any(skb); - }else{ - dev_kfree_skb_any(skb); - } - - return(udp_pkt_stored); -} - - - -/*============================================================================ - * Reply to UDP Management system. - * Return length of reply. - */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ) -{ - unsigned short len, udp_length, temp, ip_length; - unsigned long ip_temp; - int even_bound = 0; - ppp_udp_pkt_t *p_udp_pkt = (ppp_udp_pkt_t *)data; - - /* Set length of packet */ - len = sizeof(ip_pkt_t)+ - sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - /* fill in UDP reply */ - p_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; - - /* fill in UDP length */ - udp_length = sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - - /* put it on an even boundary */ - if ( udp_length & 0x0001 ) { - udp_length += 1; - len += 1; - even_bound=1; - } - - temp = (udp_length<<8)|(udp_length>>8); - p_udp_pkt->udp_pkt.udp_length = temp; - - - /* swap UDP ports */ - temp = p_udp_pkt->udp_pkt.udp_src_port; - p_udp_pkt->udp_pkt.udp_src_port = - p_udp_pkt->udp_pkt.udp_dst_port; - p_udp_pkt->udp_pkt.udp_dst_port = temp; - - - /* add UDP pseudo header */ - temp = 0x1100; - *((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound)) = temp; - temp = (udp_length<<8)|(udp_length>>8); - *((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound+2)) = temp; - - /* calculate UDP checksum */ - p_udp_pkt->udp_pkt.udp_checksum = 0; - p_udp_pkt->udp_pkt.udp_checksum = - calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); - - /* fill in IP length */ - ip_length = udp_length + sizeof(ip_pkt_t); - temp = (ip_length<<8)|(ip_length>>8); - p_udp_pkt->ip_pkt.total_length = temp; - - /* swap IP addresses */ - ip_temp = p_udp_pkt->ip_pkt.ip_src_address; - p_udp_pkt->ip_pkt.ip_src_address = p_udp_pkt->ip_pkt.ip_dst_address; - p_udp_pkt->ip_pkt.ip_dst_address = ip_temp; - - /* fill in IP checksum */ - p_udp_pkt->ip_pkt.hdr_checksum = 0; - p_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); - - return len; - -} /* reply_udp */ - -unsigned short calc_checksum (char *data, int len) -{ - unsigned short temp; - unsigned long sum=0; - int i; - - for( i = 0; i > 16 ) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - - temp = (unsigned short)sum; - temp = ~temp; - - if( temp == 0 ) - temp = 0xffff; - - return temp; -} - -/* - If incoming is 0 (outgoing)- if the net numbers is ours make it 0 - if incoming is 1 - if the net number is 0 make it ours - -*/ -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) -{ - unsigned long pnetwork_number; - - pnetwork_number = (unsigned long)((sendpacket[6] << 24) + - (sendpacket[7] << 16) + (sendpacket[8] << 8) + - sendpacket[9]); - - if (!incoming) { - //If the destination network number is ours, make it 0 - if( pnetwork_number == network_number) { - sendpacket[6] = sendpacket[7] = sendpacket[8] = - sendpacket[9] = 0x00; - } - } else { - //If the incoming network is 0, make it ours - if( pnetwork_number == 0) { - sendpacket[6] = (unsigned char)(network_number >> 24); - sendpacket[7] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[8] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[9] = (unsigned char)(network_number & - 0x000000FF); - } - } - - - pnetwork_number = (unsigned long)((sendpacket[18] << 24) + - (sendpacket[19] << 16) + (sendpacket[20] << 8) + - sendpacket[21]); - - if( !incoming ) { - //If the source network is ours, make it 0 - if( pnetwork_number == network_number) { - sendpacket[18] = sendpacket[19] = sendpacket[20] = - sendpacket[21] = 0x00; - } - } else { - //If the source network is 0, make it ours - if( pnetwork_number == 0 ) { - sendpacket[18] = (unsigned char)(network_number >> 24); - sendpacket[19] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[20] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[21] = (unsigned char)(network_number & - 0x000000FF); - } - } -} /* switch_net_numbers */ - -/*============================================================================ - * Get ethernet-style interface statistics. - * Return a pointer to struct net_device_stats. - */ -static struct net_device_stats *if_stats(struct net_device *dev) -{ - - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t* card; - - if( ppp_priv_area == NULL ) - return NULL; - - card = ppp_priv_area->card; - return &card->wandev.stats; -} - -/****** PPP Firmware Interface Functions ************************************/ - -/*============================================================================ - * Read firmware code version. - * Put code version as ASCII string in str. - */ -static int ppp_read_version(sdla_t *card, char *str) -{ - ppp_mbox_t *mb = card->mbox; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_READ_CODE_VERSION; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - - ppp_error(card, err, mb); - - else if (str) { - - int len = mb->cmd.length; - - memcpy(str, mb->data, len); - str[len] = '\0'; - - } - - return err; -} -/*=========================================================================== - * Set Out-Bound Authentication. -*/ -static int ppp_set_outbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) -{ - ppp_mbox_t *mb = card->mbox; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - memset(&mb->data, 0, (strlen(ppp_priv_area->userid) + - strlen(ppp_priv_area->passwd) + 2 ) ); - memcpy(mb->data, ppp_priv_area->userid, strlen(ppp_priv_area->userid)); - memcpy((mb->data + strlen(ppp_priv_area->userid) + 1), - ppp_priv_area->passwd, strlen(ppp_priv_area->passwd)); - - mb->cmd.length = strlen(ppp_priv_area->userid) + - strlen(ppp_priv_area->passwd) + 2 ; - - mb->cmd.command = PPP_SET_OUTBOUND_AUTH; - - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - ppp_error(card, err, mb); - - return err; -} - -/*=========================================================================== - * Set In-Bound Authentication. -*/ -static int ppp_set_inbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) -{ - ppp_mbox_t *mb = card->mbox; - int err, i; - char* user_tokens[32]; - char* pass_tokens[32]; - int userids, passwds; - int add_ptr; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - memset(&mb->data, 0, 1008); - memcpy(mb->data, ppp_priv_area->sysname, - strlen(ppp_priv_area->sysname)); - - /* Parse the userid string and the password string and build a string - to copy it to the data area of the command structure. The string - will look like "SYS_NAMEUSER1PASS1USER2PASS2 - .... " - */ - userids = tokenize( ppp_priv_area->userid, user_tokens); - passwds = tokenize( ppp_priv_area->passwd, pass_tokens); - - if (userids != passwds){ - printk(KERN_INFO "%s: Number of passwords does not equal the number of user ids\n", card->devname); - return 1; - } - - add_ptr = strlen(ppp_priv_area->sysname) + 1; - for (i=0; idata + add_ptr), user_tokens[i], - strlen(user_tokens[i])); - memcpy((mb->data + add_ptr + strlen(user_tokens[i]) + 1), - pass_tokens[i], strlen(pass_tokens[i])); - add_ptr = add_ptr + strlen(user_tokens[i]) + 1 + - strlen(pass_tokens[i]) + 1; - } - - mb->cmd.length = add_ptr + 1; - mb->cmd.command = PPP_SET_INBOUND_AUTH; - - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - ppp_error(card, err, mb); - - return err; -} - - -/*============================================================================ - * Tokenize string. - * Parse a string of the following syntax: - * ,,... - * and fill array of tokens with pointers to string elements. - * - */ -static int tokenize (char *str, char **tokens) -{ - int cnt = 0; - - tokens[0] = strsep(&str, "/"); - while (tokens[cnt] && (cnt < 32 - 1)) - { - tokens[cnt] = strstrip(tokens[cnt], " \t"); - tokens[++cnt] = strsep(&str, "/"); - } - return cnt; -} - -/*============================================================================ - * Strip leading and trailing spaces off the string str. - */ -static char* strstrip (char *str, char* s) -{ - char *eos = str + strlen(str); /* -> end of string */ - - while (*str && strchr(s, *str)) - ++str /* strip leading spaces */ - ; - while ((eos > str) && strchr(s, *(eos - 1))) - --eos /* strip trailing spaces */ - ; - *eos = '\0'; - return str; -} -/*============================================================================ - * Configure PPP firmware. - */ -static int ppp_configure(sdla_t *card, void *data) -{ - ppp_mbox_t *mb = card->mbox; - int data_len = sizeof(ppp508_conf_t); - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - memcpy(mb->data, data, data_len); - mb->cmd.length = data_len; - mb->cmd.command = PPP_SET_CONFIG; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - ppp_error(card, err, mb); - - return err; -} - -/*============================================================================ - * Set interrupt mode. - */ -static int ppp_set_intr_mode(sdla_t *card, unsigned char mode) -{ - ppp_mbox_t *mb = card->mbox; - ppp_intr_info_t *ppp_intr_data = (ppp_intr_info_t *) &mb->data[0]; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - ppp_intr_data->i_enable = mode; - - ppp_intr_data->irq = card->hw.irq; - mb->cmd.length = 2; - - /* If timer has been enabled, set the timer delay to 1sec */ - if (mode & 0x80){ - ppp_intr_data->timer_len = 250; //5;//100; //250; - mb->cmd.length = 4; - } - - mb->cmd.command = PPP_SET_INTR_FLAGS; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - ppp_error(card, err, mb); - - - return err; -} - -/*============================================================================ - * Enable communications. - */ -static int ppp_comm_enable(sdla_t *card) -{ - ppp_mbox_t *mb = card->mbox; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_COMM_ENABLE; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - ppp_error(card, err, mb); - else - card->u.p.comm_enabled = 1; - - return err; -} - -/*============================================================================ - * Disable communications. - */ -static int ppp_comm_disable(sdla_t *card) -{ - ppp_mbox_t *mb = card->mbox; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_COMM_DISABLE; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - ppp_error(card, err, mb); - else - card->u.p.comm_enabled = 0; - - return err; -} - -static int ppp_comm_disable_shutdown(sdla_t *card) -{ - ppp_mbox_t *mb = card->mbox; - ppp_intr_info_t *ppp_intr_data; - int err; - - if (!mb){ - return 1; - } - - ppp_intr_data = (ppp_intr_info_t *) &mb->data[0]; - - /* Disable all interrupts */ - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - ppp_intr_data->i_enable = 0; - - ppp_intr_data->irq = card->hw.irq; - mb->cmd.length = 2; - - mb->cmd.command = PPP_SET_INTR_FLAGS; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - /* Disable communicatinons */ - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_COMM_DISABLE; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - card->u.p.comm_enabled = 0; - - return 0; -} - - - -/*============================================================================ - * Get communications error statistics. - */ -static int ppp_get_err_stats(sdla_t *card) -{ - ppp_mbox_t *mb = card->mbox; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_READ_ERROR_STATS; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err == CMD_OK) { - - ppp_err_stats_t* stats = (void*)mb->data; - card->wandev.stats.rx_over_errors = stats->rx_overrun; - card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; - card->wandev.stats.rx_missed_errors = stats->rx_abort; - card->wandev.stats.rx_length_errors = stats->rx_lost; - card->wandev.stats.tx_aborted_errors = stats->tx_abort; - - } else - ppp_error(card, err, mb); - - return err; -} - -/*============================================================================ - * Send packet. - * Return: 0 - o.k. - * 1 - no transmit buffers available - */ -static int ppp_send (sdla_t *card, void *data, unsigned len, unsigned proto) -{ - ppp_buf_ctl_t *txbuf = card->u.p.txbuf; - - if (txbuf->flag) - return 1; - - sdla_poke(&card->hw, txbuf->buf.ptr, data, len); - - txbuf->length = len; /* frame length */ - - if (proto == htons(ETH_P_IPX)) - txbuf->proto = 0x01; /* protocol ID */ - else - txbuf->proto = 0x00; /* protocol ID */ - - txbuf->flag = 1; /* start transmission */ - - /* Update transmit buffer control fields */ - card->u.p.txbuf = ++txbuf; - - if ((void*)txbuf > card->u.p.txbuf_last) - card->u.p.txbuf = card->u.p.txbuf_base; - - return 0; -} - -/****** Firmware Error Handler **********************************************/ - -/*============================================================================ - * Firmware error handler. - * This routine is called whenever firmware command returns non-zero - * return code. - * - * Return zero if previous command has to be cancelled. - */ -static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb) -{ - unsigned cmd = mb->cmd.command; - - switch (err) { - - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - break; - - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" - , card->devname, cmd, err); - } - - return 0; -} - -/****** Interrupt Handlers **************************************************/ - -/*============================================================================ - * PPP interrupt service routine. - */ -static void wpp_isr (sdla_t *card) -{ - ppp_flags_t *flags = card->flags; - char *ptr = &flags->iflag; - struct net_device *dev = card->wandev.dev; - int i; - - card->in_isr = 1; - ++card->statistics.isr_entry; - - if (!dev && flags->iflag != PPP_INTR_CMD){ - card->in_isr = 0; - flags->iflag = 0; - return; - } - - if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { - card->in_isr = 0; - flags->iflag = 0; - return; - } - - - if(card->hw.type != SDLA_S514){ - if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - ++card->statistics.isr_already_critical; - printk (KERN_INFO "%s: Critical while in ISR!\n", - card->devname); - card->in_isr = 0; - flags->iflag = 0; - return; - } - } - - switch (flags->iflag) { - - case PPP_INTR_RXRDY: /* receive interrupt 0x01 (bit 0)*/ - ++card->statistics.isr_rx; - rx_intr(card); - break; - - case PPP_INTR_TXRDY: /* transmit interrupt 0x02 (bit 1)*/ - ++card->statistics.isr_tx; - flags->imask &= ~PPP_INTR_TXRDY; - netif_wake_queue(dev); - break; - - case PPP_INTR_CMD: /* interface command completed */ - ++Intr_test_counter; - ++card->statistics.isr_intr_test; - break; - - case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/ - case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/ - case PPP_INTR_OPEN: /* Data link open 0x20 (bit 5)*/ - case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */ - event_intr(card); - break; - - case PPP_INTR_TIMER: - timer_intr(card); - break; - - default: /* unexpected interrupt */ - ++card->statistics.isr_spurious; - printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", - card->devname, flags->iflag); - printk(KERN_INFO "%s: ID Bytes = ",card->devname); - for(i = 0; i < 8; i ++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - } - - card->in_isr = 0; - flags->iflag = 0; - return; -} - -/*============================================================================ - * Receive interrupt handler. - */ -static void rx_intr(sdla_t *card) -{ - ppp_buf_ctl_t *rxbuf = card->rxmb; - struct net_device *dev = card->wandev.dev; - ppp_private_area_t *ppp_priv_area; - struct sk_buff *skb; - unsigned len; - void *buf; - int i; - ppp_flags_t *flags = card->flags; - char *ptr = &flags->iflag; - int udp_type; - - - if (rxbuf->flag != 0x01) { - - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned)rxbuf, rxbuf->flag); - - printk(KERN_INFO "%s: ID Bytes = ",card->devname); - - for(i = 0; i < 8; i ++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - - ++card->statistics.rx_intr_corrupt_rx_bfr; - - - /* Bug Fix: Mar 6 2000 - * If we get a corrupted mailbox, it means that driver - * is out of sync with the firmware. There is no recovery. - * If we don't turn off all interrupts for this card - * the machine will crash. - */ - printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); - printk(KERN_INFO "Please contact Sangoma Technologies !\n"); - ppp_set_intr_mode(card,0); - return; - } - - if (dev && netif_running(dev) && dev->priv){ - - len = rxbuf->length; - ppp_priv_area = dev->priv; - - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); - - if (skb != NULL) { - - /* Copy data to the socket buffer */ - unsigned addr = rxbuf->buf.ptr; - - if ((addr + len) > card->u.p.rx_top + 1) { - - unsigned tmp = card->u.p.rx_top - addr + 1; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, addr, buf, tmp); - addr = card->u.p.rx_base; - len -= tmp; - } - buf = skb_put(skb, len); - sdla_peek(&card->hw, addr, buf, len); - - /* Decapsulate packet */ - switch (rxbuf->proto) { - - case 0x00: - skb->protocol = htons(ETH_P_IP); - break; - - case 0x01: - skb->protocol = htons(ETH_P_IPX); - break; - } - - udp_type = udp_pkt_type( skb, card ); - - if (udp_type == UDP_PTPIPE_TYPE){ - - /* Handle a UDP Request in Timer Interrupt */ - if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb, dev, - ppp_priv_area)){ - flags->imask |= PPP_INTR_TIMER; - } - ++ppp_priv_area->rx_intr_stat.rx_intr_PIPE_request; - - - } else if (handle_IPXWAN(skb->data,card->devname, - ppp_priv_area->enable_IPX, - ppp_priv_area->network_number, - skb->protocol)) { - - /* Handle an IPXWAN packet */ - if( ppp_priv_area->enable_IPX) { - - /* Make sure we are not already sending */ - if (!test_bit(SEND_CRIT, &card->wandev.critical)){ - ppp_send(card, skb->data, skb->len, htons(ETH_P_IPX)); - } - dev_kfree_skb_any(skb); - - } else { - ++card->wandev.stats.rx_dropped; - } - } else { - /* Pass data up the protocol stack */ - skb->dev = dev; - skb->mac.raw = skb->data; - - ++card->wandev.stats.rx_packets; - card->wandev.stats.rx_bytes += skb->len; - ++ppp_priv_area->rx_intr_stat.rx_intr_bfr_passed_to_stack; - netif_rx(skb); - dev->last_rx = jiffies; - } - - } else { - - if (net_ratelimit()){ - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - } - ++card->wandev.stats.rx_dropped; - ++ppp_priv_area->rx_intr_stat.rx_intr_no_socket; - } - - } else { - ++card->statistics.rx_intr_dev_not_started; - } - - /* Release buffer element and calculate a pointer to the next one */ - rxbuf->flag = 0x00; - card->rxmb = ++rxbuf; - if ((void*)rxbuf > card->u.p.rxbuf_last) - card->rxmb = card->u.p.rxbuf_base; -} - - -void event_intr (sdla_t *card) -{ - - struct net_device* dev = card->wandev.dev; - ppp_private_area_t* ppp_priv_area = dev->priv; - volatile ppp_flags_t *flags = card->flags; - - switch (flags->iflag){ - - case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/ - - if (net_ratelimit()){ - printk (KERN_INFO "%s: Modem status: DCD=%s CTS=%s\n", - card->devname, DCD(flags->mstatus), CTS(flags->mstatus)); - } - break; - - case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/ - - NEX_PRINTK (KERN_INFO "Data link disconnected intr Cause %X\n", - flags->disc_cause); - - if (flags->disc_cause & - (PPP_LOCAL_TERMINATION | PPP_DCD_CTS_DROP | - PPP_REMOTE_TERMINATION)) { - - if (card->u.p.ip_mode == WANOPT_PPP_PEER) { - set_bit(0,&Read_connection_info); - } - wanpipe_set_state(card, WAN_DISCONNECTED); - - show_disc_cause(card, flags->disc_cause); - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; - flags->imask |= PPP_INTR_TIMER; - trigger_ppp_poll(dev); - } - break; - - case PPP_INTR_OPEN: /* Data link open 0x20 (bit 5)*/ - - NEX_PRINTK (KERN_INFO "%s: PPP Link Open, LCP=%s IP=%s\n", - card->devname,LCP(flags->lcp_state), - IP(flags->ip_state)); - - if (flags->lcp_state == 0x09 && - (flags->ip_state == 0x09 || flags->ipx_state == 0x09)){ - - /* Initialize the polling timer and set the state - * to WAN_CONNNECTED */ - - - /* BUG FIX: When the protocol restarts, during heavy - * traffic, board tx buffers and driver tx buffers - * can go out of sync. This checks the condition - * and if the tx buffers are out of sync, the - * protocols are restarted. - * I don't know why the board tx buffer is out - * of sync. It could be that a packets is tx - * while the link is down, but that is not - * possible. The other possiblility is that the - * firmware doesn't reinitialize properly. - * FIXME: A better fix should be found. - */ - if (detect_and_fix_tx_bug(card)){ - - ppp_comm_disable(card); - - wanpipe_set_state(card, WAN_DISCONNECTED); - - ppp_priv_area->timer_int_enabled |= - TMR_INT_ENABLED_PPP_EVENT; - flags->imask |= PPP_INTR_TIMER; - break; - } - - card->state_tick = jiffies; - wanpipe_set_state(card, WAN_CONNECTED); - - NEX_PRINTK(KERN_INFO "CON: L Tx: %lx B Tx: %lx || L Rx %lx B Rx %lx\n", - (unsigned long)card->u.p.txbuf, *card->u.p.txbuf_next, - (unsigned long)card->rxmb, *card->u.p.rxbuf_next); - - /* Tell timer interrupt that PPP event occurred */ - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; - flags->imask |= PPP_INTR_TIMER; - - /* If we are in PEER mode, we must first obtain the - * IP information and then go into the poll routine */ - if (card->u.p.ip_mode != WANOPT_PPP_PEER){ - trigger_ppp_poll(dev); - } - } - break; - - case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */ - - NEX_PRINTK(KERN_INFO "DTR Drop Timeout Interrrupt \n"); - - if (card->u.p.ip_mode == WANOPT_PPP_PEER) { - set_bit(0,&Read_connection_info); - } - - wanpipe_set_state(card, WAN_DISCONNECTED); - - show_disc_cause(card, flags->disc_cause); - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; - flags->imask |= PPP_INTR_TIMER; - trigger_ppp_poll(dev); - break; - - default: - printk(KERN_INFO "%s: Error, Invalid PPP Event\n",card->devname); - } -} - - - -/* TIMER INTERRUPT */ - -void timer_intr (sdla_t *card) -{ - - struct net_device* dev = card->wandev.dev; - ppp_private_area_t* ppp_priv_area = dev->priv; - ppp_flags_t *flags = card->flags; - - - if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG){ - if (!config_ppp(card)){ - ppp_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_CONFIG; - } - } - - /* Update statistics */ - if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE){ - ppp_get_err_stats(card); - if(!(--ppp_priv_area->update_comms_stats)){ - ppp_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - } - } - - /* PPIPEMON UDP request */ - - if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP){ - process_udp_mgmt_pkt(card,dev, ppp_priv_area); - ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; - } - - /* PPP Event */ - if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_PPP_EVENT){ - - if (card->wandev.state == WAN_DISCONNECTED){ - retrigger_comm(card); - } - - /* If the state is CONNECTING, it means that communicatins were - * enabled. When the remote side enables its comminication we - * should get an interrupt PPP_INTR_OPEN, thus turn off polling - */ - - else if (card->wandev.state == WAN_CONNECTING){ - /* Turn off the timer interrupt */ - ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT; - } - - /* If state is connected and we are in PEER mode - * poll for an IP address which will be provided by remote end. - */ - else if ((card->wandev.state == WAN_CONNECTED && - card->u.p.ip_mode == WANOPT_PPP_PEER) && - test_bit(0,&Read_connection_info)){ - - card->state_tick = jiffies; - if (read_connection_info (card)){ - printk(KERN_INFO "%s: Failed to read PEER IP Addresses\n", - card->devname); - }else{ - clear_bit(0,&Read_connection_info); - set_bit(1,&Read_connection_info); - trigger_ppp_poll(dev); - } - }else{ - //FIXME Put the comment back int - ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT; - } - - }/* End of PPP_EVENT */ - - - /* Only disable the timer interrupt if there are no udp, statistic */ - /* updates or events pending */ - if(!ppp_priv_area->timer_int_enabled) { - flags->imask &= ~PPP_INTR_TIMER; - } -} - - -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) -{ - int i; - - if( proto == htons(ETH_P_IPX) ) { - //It's an IPX packet - if(!enable_IPX) { - //Return 1 so we don't pass it up the stack. - return 1; - } - } else { - //It's not IPX so pass it up the stack. - return 0; - } - - if( sendpacket[16] == 0x90 && - sendpacket[17] == 0x04) - { - //It's IPXWAN - - if( sendpacket[2] == 0x02 && - sendpacket[34] == 0x00) - { - //It's a timer request packet - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); - - //Go through the routing options and answer no to every - //option except Unnumbered RIP/SAP - for(i = 41; sendpacket[i] == 0x00; i += 5) - { - //0x02 is the option for Unnumbered RIP/SAP - if( sendpacket[i + 4] != 0x02) - { - sendpacket[i + 1] = 0; - } - } - - //Skip over the extended Node ID option - if( sendpacket[i] == 0x04 ) - { - i += 8; - } - - //We also want to turn off all header compression opt. - for(; sendpacket[i] == 0x80 ;) - { - sendpacket[i + 1] = 0; - i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; - } - - //Set the packet type to timer response - sendpacket[34] = 0x01; - - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); - } - else if( sendpacket[34] == 0x02 ) - { - //This is an information request packet - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); - - //Set the packet type to information response - sendpacket[34] = 0x03; - - //Set the router name - sendpacket[51] = 'P'; - sendpacket[52] = 'T'; - sendpacket[53] = 'P'; - sendpacket[54] = 'I'; - sendpacket[55] = 'P'; - sendpacket[56] = 'E'; - sendpacket[57] = '-'; - sendpacket[58] = CVHexToAscii(network_number >> 28); - sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); - sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); - sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); - sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); - sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); - sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); - sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); - for(i = 66; i < 99; i+= 1) - { - sendpacket[i] = 0; - } - - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); - } - else - { - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); - return 0; - } - - //Set the WNodeID to our network address - sendpacket[35] = (unsigned char)(network_number >> 24); - sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); - sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); - sendpacket[38] = (unsigned char)(network_number & 0x000000FF); - - return 1; - } else { - //If we get here it's an IPX-data packet, so it'll get passed up the stack. - - //switch the network numbers - switch_net_numbers(sendpacket, network_number, 1); - return 0; - } -} - -/****** Background Polling Routines ****************************************/ - -/* All polling functions are invoked by the TIMER interrupt in the wpp_isr - * routine. - */ - -/*============================================================================ - * Monitor active link phase. - */ -static void process_route (sdla_t *card) -{ - ppp_flags_t *flags = card->flags; - struct net_device *dev = card->wandev.dev; - ppp_private_area_t *ppp_priv_area = dev->priv; - - if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && - (flags->ip_state == 0x09)){ - - /* We get ip_local from the firmware in PEER mode. - * Therefore, if ip_local is 0, we failed to obtain - * the remote IP address. */ - if (ppp_priv_area->ip_local == 0) - return; - - printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname); - if (read_info( card )) { - printk(KERN_INFO - "%s: An error occurred in IP assignment.\n", - card->devname); - } else { - struct in_device *in_dev = dev->ip_ptr; - if (in_dev != NULL ) { - struct in_ifaddr *ifa = in_dev->ifa_list; - - printk(KERN_INFO "%s: Assigned Lcl. Addr: %u.%u.%u.%u\n", - card->devname, NIPQUAD(ifa->ifa_local)); - printk(KERN_INFO "%s: Assigned Rmt. Addr: %u.%u.%u.%u\n", - card->devname, NIPQUAD(ifa->ifa_address)); - }else{ - printk(KERN_INFO - "%s: Error: Failed to add a route for PPP interface %s\n", - card->devname,dev->name); - } - } - } -} - -/*============================================================================ - * Monitor physical link disconnected phase. - * o if interface is up and the hold-down timeout has expired, then retry - * connection. - */ -static void retrigger_comm(sdla_t *card) -{ - struct net_device *dev = card->wandev.dev; - - if (dev && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) { - - wanpipe_set_state(card, WAN_CONNECTING); - - if(ppp_comm_enable(card) == CMD_OK){ - init_ppp_tx_rx_buff( card ); - } - } -} - -/****** Miscellaneous Functions *********************************************/ - -/*============================================================================ - * Configure S508 adapter. - */ -static int config508(struct net_device *dev, sdla_t *card) -{ - ppp508_conf_t cfg; - struct in_device *in_dev = dev->ip_ptr; - ppp_private_area_t *ppp_priv_area = dev->priv; - - /* Prepare PPP configuration structure */ - memset(&cfg, 0, sizeof(ppp508_conf_t)); - - if (card->wandev.clocking) - cfg.line_speed = card->wandev.bps; - - if (card->wandev.interface == WANOPT_RS232) - cfg.conf_flags |= INTERFACE_LEVEL_RS232; - - - cfg.conf_flags |= DONT_TERMINATE_LNK_MAX_CONFIG; /*send Configure-Request packets forever*/ - cfg.txbuf_percent = PERCENT_TX_BUFF; /* % of Tx bufs */ - cfg.mtu_local = card->wandev.mtu; - cfg.mtu_remote = card->wandev.mtu; /* Default */ - cfg.restart_tmr = TIME_BETWEEN_CONF_REQ; /* 30 = 3sec */ - cfg.auth_rsrt_tmr = TIME_BETWEEN_PAP_CHAP_REQ; /* 30 = 3sec */ - cfg.auth_wait_tmr = WAIT_PAP_CHAP_WITHOUT_REPLY; /* 300 = 30s */ - cfg.mdm_fail_tmr = WAIT_AFTER_DCD_CTS_LOW; /* 5 = 0.5s */ - cfg.dtr_drop_tmr = TIME_DCD_CTS_LOW_AFTER_LNK_DOWN; /* 10 = 1s */ - cfg.connect_tmout = WAIT_DCD_HIGH_AFTER_ENABLE_COMM; /* 900 = 90s */ - cfg.conf_retry = MAX_CONF_REQ_WITHOUT_REPLY; /* 10 = 1s */ - cfg.term_retry = MAX_TERM_REQ_WITHOUT_REPLY; /* 2 times */ - cfg.fail_retry = NUM_CONF_NAK_WITHOUT_REPLY; /* 5 times */ - cfg.auth_retry = NUM_AUTH_REQ_WITHOUT_REPLY; /* 10 times */ - - - if( !card->u.p.authenticator ) { - printk(KERN_INFO "%s: Device is not configured as an authenticator\n", - card->devname); - cfg.auth_options = NO_AUTHENTICATION; - }else{ - printk(KERN_INFO "%s: Device is configured as an authenticator\n", - card->devname); - cfg.auth_options = INBOUND_AUTH; - } - - if( ppp_priv_area->pap == WANOPT_YES){ - cfg.auth_options |=PAP_AUTH; - printk(KERN_INFO "%s: Pap enabled\n", card->devname); - } - if( ppp_priv_area->chap == WANOPT_YES){ - cfg.auth_options |= CHAP_AUTH; - printk(KERN_INFO "%s: Chap enabled\n", card->devname); - } - - - if (ppp_priv_area->enable_IPX == WANOPT_YES){ - printk(KERN_INFO "%s: Enabling IPX Protocol\n",card->devname); - cfg.ipx_options = ENABLE_IPX | ROUTING_PROT_DEFAULT; - }else{ - cfg.ipx_options = DISABLE_IPX; - } - - switch (card->u.p.ip_mode) { - - case WANOPT_PPP_STATIC: - - printk(KERN_INFO "%s: PPP IP Mode: STATIC\n",card->devname); - cfg.ip_options = L_AND_R_IP_NO_ASSIG | - ENABLE_IP; - cfg.ip_local = in_dev->ifa_list->ifa_local; - cfg.ip_remote = in_dev->ifa_list->ifa_address; - /* Debugging code used to check that IP addresses - * obtained from the kernel are correct */ - - NEX_PRINTK(KERN_INFO "Local %u.%u.%u.%u Remote %u.%u.%u.%u Name %s\n", - NIPQUAD(ip_local),NIPQUAD(ip_remote), dev->name); - break; - - case WANOPT_PPP_HOST: - - printk(KERN_INFO "%s: PPP IP Mode: HOST\n",card->devname); - cfg.ip_options = L_IP_LOCAL_ASSIG | - R_IP_LOCAL_ASSIG | - ENABLE_IP; - cfg.ip_local = in_dev->ifa_list->ifa_local; - cfg.ip_remote = in_dev->ifa_list->ifa_address; - /* Debugging code used to check that IP addresses - * obtained from the kernel are correct */ - NEX_PRINTK (KERN_INFO "Local %u.%u.%u.%u Remote %u.%u.%u.%u Name %s\n", - NIPQUAD(ip_local),NIPQUAD(ip_remote), dev->name); - - break; - - case WANOPT_PPP_PEER: - - printk(KERN_INFO "%s: PPP IP Mode: PEER\n",card->devname); - cfg.ip_options = L_IP_REMOTE_ASSIG | - R_IP_REMOTE_ASSIG | - ENABLE_IP; - cfg.ip_local = 0x00; - cfg.ip_remote = 0x00; - break; - - default: - printk(KERN_INFO "%s: ERROR: Unsupported PPP Mode Selected\n", - card->devname); - printk(KERN_INFO "%s: PPP IP Modes: STATIC, PEER or HOST\n", - card->devname); - return 1; - } - - return ppp_configure(card, &cfg); -} - -/*============================================================================ - * Show disconnection cause. - */ -static void show_disc_cause(sdla_t *card, unsigned cause) -{ - if (cause & 0x0802) - - printk(KERN_INFO "%s: link terminated by peer\n", - card->devname); - - else if (cause & 0x0004) - - printk(KERN_INFO "%s: link terminated by user\n", - card->devname); - - else if (cause & 0x0008) - - printk(KERN_INFO "%s: authentication failed\n", card->devname); - - else if (cause & 0x0010) - - printk(KERN_INFO - "%s: authentication protocol negotiation failed\n", - card->devname); - - else if (cause & 0x0020) - - printk(KERN_INFO - "%s: peer's request for authentication rejected\n", - card->devname); - - else if (cause & 0x0040) - - printk(KERN_INFO "%s: MRU option rejected by peer\n", - card->devname); - - else if (cause & 0x0080) - - printk(KERN_INFO "%s: peer's MRU was too small\n", - card->devname); - - else if (cause & 0x0100) - - printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n", - card->devname); - - else if (cause & 0x0200) - - printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n" - , card->devname); - - else if (cause & 0x0400) - - printk(KERN_INFO - "%s: failed to negotiate peer's IPXCP options\n", - card->devname); -} - -/*============================================================================= - * Process UDP call of type PTPIPEAB. - */ -static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, - ppp_private_area_t *ppp_priv_area ) -{ - unsigned char buf2[5]; - unsigned char *buf; - unsigned int frames, len; - struct sk_buff *new_skb; - unsigned short data_length, buffer_length, real_len; - unsigned long data_ptr; - int udp_mgmt_req_valid = 1; - ppp_mbox_t *mbox = card->mbox; - struct timeval tv; - int err; - ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t*)&ppp_priv_area->udp_pkt_data; - - memcpy(&buf2, &card->wandev.udp_port, 2 ); - - - if(ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - switch(ppp_udp_pkt->cblock.command) { - - case PPIPE_GET_IBA_DATA: - case PPP_READ_CONFIG: - case PPP_GET_CONNECTION_INFO: - case PPIPE_ROUTER_UP_TIME: - case PPP_READ_STATISTICS: - case PPP_READ_ERROR_STATS: - case PPP_READ_PACKET_STATS: - case PPP_READ_LCP_STATS: - case PPP_READ_IPCP_STATS: - case PPP_READ_IPXCP_STATS: - case PPP_READ_PAP_STATS: - case PPP_READ_CHAP_STATS: - case PPP_READ_CODE_VERSION: - udp_mgmt_req_valid = 1; - break; - - default: - udp_mgmt_req_valid = 0; - break; - } - } - - if(!udp_mgmt_req_valid) { - - /* set length to 0 */ - ppp_udp_pkt->cblock.length = 0x00; - - /* set return code */ - ppp_udp_pkt->cblock.result = 0xCD; - ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err; - - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Warning, Illegal UDP command attempted from network: %x\n", - card->devname,ppp_udp_pkt->cblock.command); - } - } else { - /* Initialize the trace element */ - trace_element_t trace_element; - - switch (ppp_udp_pkt->cblock.command){ - - /* PPIPE_ENABLE_TRACING */ - case PPIPE_ENABLE_TRACING: - if (!card->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - mbox->cmd.command = PPP_DATALINE_MONITOR; - mbox->cmd.length = 0x01; - mbox->data[0] = ppp_udp_pkt->data[0]; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) { - - ppp_error(card, err, mbox); - card->TracingEnabled = 0; - - /* set the return code */ - - ppp_udp_pkt->cblock.result = mbox->cmd.result; - mbox->cmd.length = 0; - break; - } - - sdla_peek(&card->hw, 0xC000, &buf2, 2); - - ppp_priv_area->curr_trace_addr = 0; - memcpy(&ppp_priv_area->curr_trace_addr, &buf2, 2); - ppp_priv_area->start_trace_addr = - ppp_priv_area->curr_trace_addr; - ppp_priv_area->end_trace_addr = - ppp_priv_area->start_trace_addr + END_OFFSET; - - /* MAX_SEND_BUFFER_SIZE - 28 (IP header) - - 32 (ppipemon CBLOCK) */ - available_buffer_space = MAX_LGTH_UDP_MGNT_PKT - - sizeof(ip_pkt_t)- - sizeof(udp_pkt_t)- - sizeof(wp_mgmt_t)- - sizeof(cblock_t); - } - ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 0; - card->TracingEnabled = 1; - break; - - /* PPIPE_DISABLE_TRACING */ - case PPIPE_DISABLE_TRACING: - - if(card->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - mbox->cmd.command = 0x33; - mbox->cmd.length = 1; - mbox->data[0] = 0x00; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - - } - - /*set return code*/ - ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 0; - card->TracingEnabled = 0; - break; - - /* PPIPE_GET_TRACE_INFO */ - case PPIPE_GET_TRACE_INFO: - - if(!card->TracingEnabled) { - /* set return code */ - ppp_udp_pkt->cblock.result = 1; - mbox->cmd.length = 0; - } - - buffer_length = 0; - - /* frames < 62, where 62 is the number of trace - information elements. There is in total 496 - bytes of space and each trace information - element is 8 bytes. - */ - for ( frames=0; frames<62; frames++) { - - trace_pkt_t *trace_pkt = (trace_pkt_t *) - &ppp_udp_pkt->data[buffer_length]; - - /* Read the whole trace packet */ - sdla_peek(&card->hw, ppp_priv_area->curr_trace_addr, - &trace_element, sizeof(trace_element_t)); - - /* no data on board so exit */ - if( trace_element.opp_flag == 0x00 ) - break; - - data_ptr = trace_element.trace_data_ptr; - - /* See if there is actual data on the trace buffer */ - if (data_ptr){ - data_length = trace_element.trace_length; - }else{ - data_length = 0; - ppp_udp_pkt->data[0] |= 0x02; - } - - //FIXME: Do we need this check - if ((available_buffer_space - buffer_length) - < (sizeof(trace_element_t)+1)){ - - /*indicate we have more frames - * on board and exit - */ - ppp_udp_pkt->data[0] |= 0x02; - break; - } - - trace_pkt->status = trace_element.trace_type; - trace_pkt->time_stamp = trace_element.trace_time_stamp; - trace_pkt->real_length = trace_element.trace_length; - - real_len = trace_element.trace_length; - - if(data_ptr == 0){ - trace_pkt->data_avail = 0x00; - }else{ - /* we can take it next time */ - if ((available_buffer_space - buffer_length)< - (real_len + sizeof(trace_pkt_t))){ - - ppp_udp_pkt->data[0] |= 0x02; - break; - } - trace_pkt->data_avail = 0x01; - - /* get the data */ - sdla_peek(&card->hw, data_ptr, - &trace_pkt->data, - real_len); - } - /* zero the opp flag to - show we got the frame */ - buf2[0] = 0x00; - sdla_poke(&card->hw, ppp_priv_area->curr_trace_addr, - &buf2, 1); - - /* now move onto the next - frame */ - ppp_priv_area->curr_trace_addr += 8; - - /* check if we passed the last address */ - if ( ppp_priv_area->curr_trace_addr >= - ppp_priv_area->end_trace_addr){ - - ppp_priv_area->curr_trace_addr = - ppp_priv_area->start_trace_addr; - } - - /* update buffer length and make sure its even */ - - if ( trace_pkt->data_avail == 0x01 ) { - buffer_length += real_len - 1; - } - - /* for the header */ - buffer_length += 8; - - if( buffer_length & 0x0001 ) - buffer_length += 1; - } - - /* ok now set the total number of frames passed - in the high 5 bits */ - ppp_udp_pkt->data[0] |= (frames << 2); - - /* set the data length */ - mbox->cmd.length = buffer_length; - ppp_udp_pkt->cblock.length = buffer_length; - - /* set return code */ - ppp_udp_pkt->cblock.result = 0; - break; - - /* PPIPE_GET_IBA_DATA */ - case PPIPE_GET_IBA_DATA: - - mbox->cmd.length = 0x09; - - sdla_peek(&card->hw, 0xF003, &ppp_udp_pkt->data, - mbox->cmd.length); - - /* set the length of the data */ - ppp_udp_pkt->cblock.length = 0x09; - - /* set return code */ - ppp_udp_pkt->cblock.result = 0x00; - ppp_udp_pkt->cblock.result = 0; - break; - - /* PPIPE_FT1_READ_STATUS */ - case PPIPE_FT1_READ_STATUS: - sdla_peek(&card->hw, 0xF020, &ppp_udp_pkt->data[0], 2); - ppp_udp_pkt->cblock.length = mbox->cmd.length = 2; - ppp_udp_pkt->cblock.result = 0; - break; - - case PPIPE_FLUSH_DRIVER_STATS: - init_ppp_priv_struct( ppp_priv_area ); - init_global_statistics( card ); - mbox->cmd.length = 0; - ppp_udp_pkt->cblock.result = 0; - break; - - - case PPIPE_ROUTER_UP_TIME: - - do_gettimeofday( &tv ); - ppp_priv_area->router_up_time = tv.tv_sec - - ppp_priv_area->router_start_time; - *(unsigned long *)&ppp_udp_pkt->data = ppp_priv_area->router_up_time; - mbox->cmd.length = 4; - ppp_udp_pkt->cblock.result = 0; - break; - - /* PPIPE_DRIVER_STATISTICS */ - case PPIPE_DRIVER_STAT_IFSEND: - memcpy(&ppp_udp_pkt->data, &ppp_priv_area->if_send_stat, - sizeof(if_send_stat_t)); - - - ppp_udp_pkt->cblock.result = 0; - ppp_udp_pkt->cblock.length = sizeof(if_send_stat_t); - mbox->cmd.length = sizeof(if_send_stat_t); - break; - - case PPIPE_DRIVER_STAT_INTR: - memcpy(&ppp_udp_pkt->data, &card->statistics, - sizeof(global_stats_t)); - - memcpy(&ppp_udp_pkt->data+sizeof(global_stats_t), - &ppp_priv_area->rx_intr_stat, - sizeof(rx_intr_stat_t)); - - ppp_udp_pkt->cblock.result = 0; - ppp_udp_pkt->cblock.length = sizeof(global_stats_t)+ - sizeof(rx_intr_stat_t); - mbox->cmd.length = ppp_udp_pkt->cblock.length; - break; - - case PPIPE_DRIVER_STAT_GEN: - memcpy( &ppp_udp_pkt->data, - &ppp_priv_area->pipe_mgmt_stat, - sizeof(pipe_mgmt_stat_t)); - - memcpy(&ppp_udp_pkt->data+sizeof(pipe_mgmt_stat_t), - &card->statistics, sizeof(global_stats_t)); - - ppp_udp_pkt->cblock.result = 0; - ppp_udp_pkt->cblock.length = sizeof(global_stats_t)+ - sizeof(rx_intr_stat_t); - mbox->cmd.length = ppp_udp_pkt->cblock.length; - break; - - - /* FT1 MONITOR STATUS */ - case FT1_MONITOR_STATUS_CTRL: - - /* Enable FT1 MONITOR STATUS */ - if( ppp_udp_pkt->data[0] == 1) { - - if( rCount++ != 0 ) { - ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - - /* Disable FT1 MONITOR STATUS */ - if( ppp_udp_pkt->data[0] == 0) { - - if( --rCount != 0) { - ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - goto udp_dflt_cmd; - - /* WARNING: FIXME: This should be fixed. - * The FT1 Status Ctrl doesn't have a break - * statment. Thus, no code must be inserted - * HERE: between default and above case statement */ - - default: -udp_dflt_cmd: - - /* it's a board command */ - mbox->cmd.command = ppp_udp_pkt->cblock.command; - mbox->cmd.length = ppp_udp_pkt->cblock.length; - - if(mbox->cmd.length) { - memcpy(&mbox->data,(unsigned char *)ppp_udp_pkt->data, - mbox->cmd.length); - } - - /* run the command on the board */ - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) { - - ppp_error(card, err, mbox); - ++ppp_priv_area->pipe_mgmt_stat. - UDP_PIPE_mgmt_adptr_cmnd_timeout; - break; - } - - ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK; - - /* copy the result back to our buffer */ - memcpy(&ppp_udp_pkt->cblock,mbox, sizeof(cblock_t)); - - if(mbox->cmd.length) { - memcpy(&ppp_udp_pkt->data,&mbox->data,mbox->cmd.length); - } - - } /* end of switch */ - } /* end of else */ - - /* Fill UDP TTL */ - ppp_udp_pkt->ip_pkt.ttl = card->wandev.ttl; - len = reply_udp(ppp_priv_area->udp_pkt_data, mbox->cmd.length); - - if (ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - /* Make sure we are not already sending */ - if (!test_bit(SEND_CRIT,&card->wandev.critical)){ - ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_adptr; - ppp_send(card,ppp_priv_area->udp_pkt_data,len,ppp_priv_area->protocol); - } - - } else { - - /* Pass it up the stack - Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) { - - /* copy data into new_skb */ - - buf = skb_put(new_skb, len); - memcpy(buf,ppp_priv_area->udp_pkt_data, len); - - ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack; - - /* Decapsulate packet and pass it up the protocol - stack */ - new_skb->protocol = htons(ETH_P_IP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; - netif_rx(new_skb); - dev->last_rx = jiffies; - - } else { - - ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket; - printk(KERN_INFO "no socket buffers available!\n"); - } - } - - ppp_priv_area->udp_pkt_lgth = 0; - - return; -} - -/*============================================================================= - * Initial the ppp_private_area structure. - */ -static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area ) -{ - - memset(&ppp_priv_area->if_send_stat, 0, sizeof(if_send_stat_t)); - memset(&ppp_priv_area->rx_intr_stat, 0, sizeof(rx_intr_stat_t)); - memset(&ppp_priv_area->pipe_mgmt_stat, 0, sizeof(pipe_mgmt_stat_t)); -} - -/*============================================================================ - * Initialize Global Statistics - */ -static void init_global_statistics( sdla_t *card ) -{ - memset(&card->statistics, 0, sizeof(global_stats_t)); -} - -/*============================================================================ - * Initialize Receive and Transmit Buffers. - */ -static void init_ppp_tx_rx_buff( sdla_t *card ) -{ - ppp508_buf_info_t* info; - - if (card->hw.type == SDLA_S514) { - - info = (void*)(card->hw.dpmbase + PPP514_BUF_OFFS); - - card->u.p.txbuf_base = (void*)(card->hw.dpmbase + - info->txb_ptr); - - card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + - (info->txb_num - 1); - - card->u.p.rxbuf_base = (void*)(card->hw.dpmbase + - info->rxb_ptr); - - card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + - (info->rxb_num - 1); - - } else { - - info = (void*)(card->hw.dpmbase + PPP508_BUF_OFFS); - - card->u.p.txbuf_base = (void*)(card->hw.dpmbase + - (info->txb_ptr - PPP508_MB_VECT)); - - card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + - (info->txb_num - 1); - - card->u.p.rxbuf_base = (void*)(card->hw.dpmbase + - (info->rxb_ptr - PPP508_MB_VECT)); - - card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + - (info->rxb_num - 1); - } - - card->u.p.txbuf_next = (unsigned long*)&info->txb_nxt; - card->u.p.rxbuf_next = (unsigned long*)&info->rxb1_ptr; - - card->u.p.rx_base = info->rxb_base; - card->u.p.rx_top = info->rxb_end; - - card->u.p.txbuf = card->u.p.txbuf_base; - card->rxmb = card->u.p.rxbuf_base; - -} - -/*============================================================================= - * Read Connection Information (ie for Remote IP address assginment). - * Called when ppp interface connected. - */ -static int read_info( sdla_t *card ) -{ - struct net_device *dev = card->wandev.dev; - ppp_private_area_t *ppp_priv_area = dev->priv; - int err; - - struct ifreq if_info; - struct sockaddr_in *if_data1, *if_data2; - mm_segment_t fs; - - /* Set Local and remote addresses */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - - - fs = get_fs(); - set_fs(get_ds()); /* get user space block */ - - /* Change the local and remote ip address of the interface. - * This will also add in the destination route. - */ - if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; - if_data1->sin_addr.s_addr = ppp_priv_area->ip_local; - if_data1->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFADDR, &if_info ); - if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data2->sin_addr.s_addr = ppp_priv_area->ip_remote; - if_data2->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); - - set_fs(fs); /* restore old block */ - - if (err) { - printk (KERN_INFO "%s: Adding of route failed: %i\n", - card->devname,err); - printk (KERN_INFO "%s: Local : %u.%u.%u.%u\n", - card->devname,NIPQUAD(ppp_priv_area->ip_local)); - printk (KERN_INFO "%s: Remote: %u.%u.%u.%u\n", - card->devname,NIPQUAD(ppp_priv_area->ip_remote)); - } - return err; -} - -/*============================================================================= - * Remove Dynamic Route. - * Called when ppp interface disconnected. - */ - -static void remove_route( sdla_t *card ) -{ - - struct net_device *dev = card->wandev.dev; - long ip_addr; - int err; - - mm_segment_t fs; - struct ifreq if_info; - struct sockaddr_in *if_data1; - struct in_device *in_dev = dev->ip_ptr; - struct in_ifaddr *ifa = in_dev->ifa_list; - - ip_addr = ifa->ifa_local; - - /* Set Local and remote addresses */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - - fs = get_fs(); - set_fs(get_ds()); /* get user space block */ - - /* Change the local ip address of the interface to 0. - * This will also delete the destination route. - */ - if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; - if_data1->sin_addr.s_addr = 0; - if_data1->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFADDR, &if_info ); - - set_fs(fs); /* restore old block */ - - - if (err) { - printk (KERN_INFO "%s: Deleting dynamic route failed %d!\n", - card->devname, err); - return; - }else{ - printk (KERN_INFO "%s: PPP Deleting dynamic route %u.%u.%u.%u successfuly\n", - card->devname, NIPQUAD(ip_addr)); - } - return; -} - -/*============================================================================= - * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR - * _TEST_COUNTER times. - */ -static int intr_test( sdla_t *card ) -{ - ppp_mbox_t *mb = card->mbox; - int err,i; - - err = ppp_set_intr_mode( card, 0x08 ); - - if (err == CMD_OK) { - - for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { - /* Run command READ_CODE_VERSION */ - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.length = 0; - mb->cmd.command = PPP_READ_CODE_VERSION; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - ppp_error(card, err, mb); - } - } - else return err; - - err = ppp_set_intr_mode( card, 0 ); - if (err != CMD_OK) - return err; - - return 0; -} - -/*============================================================================== - * Determine what type of UDP call it is. DRVSTATS or PTPIPEAB ? - */ -static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ) -{ - unsigned char *sendpacket; - unsigned char buf2[5]; - ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t *)skb->data; - - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - - if( ppp_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45 && /* IP packet */ - sendpacket[9] == 0x11 && /* UDP packet */ - sendpacket[22] == buf2[1] && /* UDP Port */ - sendpacket[23] == buf2[0] && - sendpacket[36] == 0x01 ) { - - if ( sendpacket[28] == 0x50 && /* PTPIPEAB: Signature */ - sendpacket[29] == 0x54 && - sendpacket[30] == 0x50 && - sendpacket[31] == 0x49 && - sendpacket[32] == 0x50 && - sendpacket[33] == 0x45 && - sendpacket[34] == 0x41 && - sendpacket[35] == 0x42 ){ - - return UDP_PTPIPE_TYPE; - - } else if(sendpacket[28] == 0x44 && /* DRVSTATS: Signature */ - sendpacket[29] == 0x52 && - sendpacket[30] == 0x56 && - sendpacket[31] == 0x53 && - sendpacket[32] == 0x54 && - sendpacket[33] == 0x41 && - sendpacket[34] == 0x54 && - sendpacket[35] == 0x53 ){ - - return UDP_DRVSTATS_TYPE; - - } else - return UDP_INVALID_TYPE; - - } else - return UDP_INVALID_TYPE; - -} - -/*============================================================================ - * Check to see if the packet to be transmitted contains a broadcast or - * multicast source IP address. - */ - -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, - struct sk_buff *skb) -{ - u32 src_ip_addr; - u32 broadcast_ip_addr = 0; - struct in_device *in_dev; - - /* read the IP source address from the outgoing packet */ - src_ip_addr = *(u32 *)(skb->data + 12); - - /* read the IP broadcast address for the device */ - in_dev = dev->ip_ptr; - if(in_dev != NULL) { - struct in_ifaddr *ifa= in_dev->ifa_list; - if(ifa != NULL) - broadcast_ip_addr = ifa->ifa_broadcast; - else - return 0; - } - - /* check if the IP Source Address is a Broadcast address */ - if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { - printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", - card->devname); - return 1; - } - - /* check if the IP Source Address is a Multicast address */ - if((ntohl(src_ip_addr) >= 0xE0000001) && - (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { - printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", - card->devname); - return 1; - } - - return 0; -} - -void s508_lock (sdla_t *card, unsigned long *smp_flags) -{ - spin_lock_irqsave(&card->wandev.lock, *smp_flags); -} - -void s508_unlock (sdla_t *card, unsigned long *smp_flags) -{ - spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); -} - -static int read_connection_info (sdla_t *card) -{ - ppp_mbox_t *mb = card->mbox; - struct net_device *dev = card->wandev.dev; - ppp_private_area_t *ppp_priv_area = dev->priv; - ppp508_connect_info_t *ppp508_connect_info; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.length = 0; - mb->cmd.command = PPP_GET_CONNECTION_INFO; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) { - ppp_error(card, err, mb); - ppp_priv_area->ip_remote = 0; - ppp_priv_area->ip_local = 0; - } - else { - ppp508_connect_info = (ppp508_connect_info_t *)mb->data; - ppp_priv_area->ip_remote = ppp508_connect_info->ip_remote; - ppp_priv_area->ip_local = ppp508_connect_info->ip_local; - - NEX_PRINTK(KERN_INFO "READ CONNECTION GOT IP ADDRESS %x, %x\n", - ppp_priv_area->ip_remote, - ppp_priv_area->ip_local); - } - - return err; -} - -/*=============================================================================== - * config_ppp - * - * Configure the ppp protocol and enable communications. - * - * The if_open function binds this function to the poll routine. - * Therefore, this function will run every time the ppp interface - * is brought up. - * - * If the communications are not enabled, proceed to configure - * the card and enable communications. - * - * If the communications are enabled, it means that the interface - * was shutdown by ether the user or driver. In this case, we - * have to check that the IP addresses have not changed. If - * the IP addresses changed, we have to reconfigure the firmware - * and update the changed IP addresses. Otherwise, just exit. - */ -static int config_ppp (sdla_t *card) -{ - - struct net_device *dev = card->wandev.dev; - ppp_flags_t *flags = card->flags; - ppp_private_area_t *ppp_priv_area = dev->priv; - - if (card->u.p.comm_enabled){ - - if (ppp_priv_area->ip_local_tmp != ppp_priv_area->ip_local || - ppp_priv_area->ip_remote_tmp != ppp_priv_area->ip_remote){ - - /* The IP addersses have changed, we must - * stop the communications and reconfigure - * the card. Reason: the firmware must know - * the local and remote IP addresses. */ - disable_comm(card); - wanpipe_set_state(card, WAN_DISCONNECTED); - printk(KERN_INFO - "%s: IP addresses changed!\n", - card->devname); - printk(KERN_INFO "%s: Restarting communications ...\n", - card->devname); - }else{ - /* IP addresses are the same and the link is up, - * we don't have to do anything here. Therefore, exit */ - return 0; - } - } - - /* Record the new IP addreses */ - ppp_priv_area->ip_local = ppp_priv_area->ip_local_tmp; - ppp_priv_area->ip_remote = ppp_priv_area->ip_remote_tmp; - - if (config508(dev, card)){ - printk(KERN_INFO "%s: Failed to configure PPP device\n", - card->devname); - return 0; - } - - if (ppp_set_intr_mode(card, PPP_INTR_RXRDY| - PPP_INTR_TXRDY| - PPP_INTR_MODEM| - PPP_INTR_DISC | - PPP_INTR_OPEN | - PPP_INTR_DROP_DTR | - PPP_INTR_TIMER)) { - - printk(KERN_INFO "%s: Failed to configure board interrupts !\n", - card->devname); - return 0; - } - - /* Turn off the transmit and timer interrupt */ - flags->imask &= ~(PPP_INTR_TXRDY | PPP_INTR_TIMER) ; - - - /* If you are not the authenticator and any one of the protocol is - * enabled then we call the set_out_bound_authentication. - */ - if ( !card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { - if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){ - printk(KERN_INFO "%s: Outbound authentication failed !\n", - card->devname); - return 0; - } - } - - /* If you are the authenticator and any one of the protocol is enabled - * then we call the set_in_bound_authentication. - */ - if (card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)){ - if (ppp_set_inbnd_auth(card, ppp_priv_area)){ - printk(KERN_INFO "%s: Inbound authentication failed !\n", - card->devname); - return 0; - } - } - - /* If we fail to enable communications here it's OK, - * since the DTR timer will cause a disconnected, which - * will retrigger communication in timer_intr() */ - if (ppp_comm_enable(card) == CMD_OK) { - wanpipe_set_state(card, WAN_CONNECTING); - init_ppp_tx_rx_buff(card); - } - - return 0; -} - -/*============================================================ - * ppp_poll - * - * Rationale: - * We cannot manipulate the routing tables, or - * ip addresses withing the interrupt. Therefore - * we must perform such actons outside an interrupt - * at a later time. - * - * Description: - * PPP polling routine, responsible for - * shutting down interfaces upon disconnect - * and adding/removing routes. - * - * Usage: - * This function is executed for each ppp - * interface through a tq_schedule bottom half. - * - * trigger_ppp_poll() function is used to kick - * the ppp_poll routine. - */ -static void ppp_poll(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area; - sdla_t *card; - u8 check_gateway=0; - ppp_flags_t *flags; - - if (!dev || (ppp_priv_area = dev->priv) == NULL) - return; - - card = ppp_priv_area->card; - flags = card->flags; - - /* Shutdown is in progress, stop what you are - * doing and get out */ - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - clear_bit(POLL_CRIT,&card->wandev.critical); - return; - } - - /* if_open() function has triggered the polling routine - * to determine the configured IP addresses. Once the - * addresses are found, trigger the chdlc configuration */ - if (test_bit(0,&ppp_priv_area->config_ppp)){ - - ppp_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP); - ppp_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); - - if (ppp_priv_area->ip_local_tmp == ppp_priv_area->ip_remote_tmp && - card->u.p.ip_mode == WANOPT_PPP_HOST){ - - if (++ppp_priv_area->ip_error > MAX_IP_ERRORS){ - printk(KERN_INFO "\n%s: --- WARNING ---\n", - card->devname); - printk(KERN_INFO "%s: The local IP address is the same as the\n", - card->devname); - printk(KERN_INFO "%s: Point-to-Point IP address.\n", - card->devname); - printk(KERN_INFO "%s: --- WARNING ---\n\n", - card->devname); - }else{ - clear_bit(POLL_CRIT,&card->wandev.critical); - ppp_priv_area->poll_delay_timer.expires = jiffies+HZ; - add_timer(&ppp_priv_area->poll_delay_timer); - return; - } - } - - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; - flags->imask |= PPP_INTR_TIMER; - ppp_priv_area->ip_error=0; - - clear_bit(0,&ppp_priv_area->config_ppp); - clear_bit(POLL_CRIT,&card->wandev.critical); - return; - } - - /* Dynamic interface implementation, as well as dynamic - * routing. */ - - switch (card->wandev.state) { - - case WAN_DISCONNECTED: - - /* If the dynamic interface configuration is on, and interface - * is up, then bring down the netowrk interface */ - - if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) && - !test_bit(DEV_DOWN,&ppp_priv_area->interface_down) && - card->wandev.dev->flags & IFF_UP){ - - printk(KERN_INFO "%s: Interface %s down.\n", - card->devname,card->wandev.dev->name); - change_dev_flags(card->wandev.dev, - (card->wandev.dev->flags&~IFF_UP)); - set_bit(DEV_DOWN,&ppp_priv_area->interface_down); - }else{ - /* We need to check if the local IP address is - * zero. If it is, we shouldn't try to remove it. - * For some reason the kernel crashes badly if - * we try to remove the route twice */ - - if (card->wandev.dev->flags & IFF_UP && - get_ip_address(card->wandev.dev,WAN_LOCAL_IP) && - card->u.p.ip_mode == WANOPT_PPP_PEER){ - - remove_route(card); - } - } - break; - - case WAN_CONNECTED: - - /* In SMP machine this code can execute before the interface - * comes up. In this case, we must make sure that we do not - * try to bring up the interface before dev_open() is finished */ - - - /* DEV_DOWN will be set only when we bring down the interface - * for the very first time. This way we know that it was us - * that brought the interface down */ - - if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) && - test_bit(DEV_DOWN, &ppp_priv_area->interface_down) && - !(card->wandev.dev->flags & IFF_UP)){ - - printk(KERN_INFO "%s: Interface %s up.\n", - card->devname,card->wandev.dev->name); - - change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP)); - clear_bit(DEV_DOWN,&ppp_priv_area->interface_down); - check_gateway=1; - } - - if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && - test_bit(1,&Read_connection_info)) { - - process_route(card); - clear_bit(1,&Read_connection_info); - check_gateway=1; - } - - if (ppp_priv_area->gateway && check_gateway) - add_gateway(card,dev); - - break; - } - clear_bit(POLL_CRIT,&card->wandev.critical); - return; -} - -/*============================================================ - * trigger_ppp_poll - * - * Description: - * Add a ppp_poll() task into a tq_scheduler bh handler - * for a specific interface. This will kick - * the ppp_poll() routine at a later time. - * - * Usage: - * Interrupts use this to defer a taks to - * a polling routine. - * - */ - -static void trigger_ppp_poll(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area; - if ((ppp_priv_area=dev->priv) != NULL){ - - sdla_t *card = ppp_priv_area->card; - - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - return; - } - - if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ - return; - } - - schedule_work(&ppp_priv_area->poll_work); - } - return; -} - -static void ppp_poll_delay (unsigned long dev_ptr) -{ - struct net_device *dev = (struct net_device *)dev_ptr; - trigger_ppp_poll(dev); -} - -/*============================================================ - * detect_and_fix_tx_bug - * - * Description: - * On connect, if the board tx buffer ptr is not the same - * as the driver tx buffer ptr, we found a firmware bug. - * Report the bug to the above layer. To fix the - * error restart communications again. - * - * Usage: - * - */ - -static int detect_and_fix_tx_bug (sdla_t *card) -{ - if (((unsigned long)card->u.p.txbuf_base&0xFFF) != ((*card->u.p.txbuf_next)&0xFFF)){ - NEX_PRINTK(KERN_INFO "Major Error, Fix the bug\n"); - return 1; - } - return 0; -} - -MODULE_LICENSE("GPL"); - -/****** End *****************************************************************/ diff --git a/drivers/net/wan/sdla_x25.c b/drivers/net/wan/sdla_x25.c deleted file mode 100644 index 63f846d..0000000 --- a/drivers/net/wan/sdla_x25.c +++ /dev/null @@ -1,5497 +0,0 @@ -/***************************************************************************** -* sdla_x25.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module. -* -* Author: Nenad Corbic -* -* Copyright: (c) 1995-2001 Sangoma Technologies Inc. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version -* 2 of the License, or (at your option) any later version. -* ============================================================================ -* Apr 03, 2001 Nenad Corbic o Fixed the rx_skb=NULL bug in x25 in rx_intr(). -* Dec 26, 2000 Nenad Corbic o Added a new polling routine, that uses -* a kernel timer (more efficient). -* Dec 25, 2000 Nenad Corbic o Updated for 2.4.X kernel -* Jul 26, 2000 Nenad Corbic o Increased the local packet buffering -* for API to 4096+header_size. -* Jul 17, 2000 Nenad Corbic o Fixed the x25 startup bug. Enable -* communications only after all interfaces -* come up. HIGH SVC/PVC is used to calculate -* the number of channels. -* Enable protocol only after all interfaces -* are enabled. -* Jul 10, 2000 Nenad Corbic o Fixed the M_BIT bug. -* Apr 25, 2000 Nenad Corbic o Pass Modem messages to the API. -* Disable idle timeout in X25 API. -* Apr 14, 2000 Nenad Corbic o Fixed: Large LCN number support. -* Maximum LCN number is 4095. -* Maximum number of X25 channels is 255. -* Apr 06, 2000 Nenad Corbic o Added SMP Support. -* Mar 29, 2000 Nenad Corbic o Added support for S514 PCI Card -* Mar 23, 2000 Nenad Corbic o Improved task queue, BH handling. -* Mar 14, 2000 Nenad Corbic o Updated Protocol Violation handling -* routines. Bug Fix. -* Mar 10, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. -* Mar 09, 2000 Nenad Corbic o Fixed the auto HDLC bug. -* Mar 08, 2000 Nenad Corbic o Fixed LAPB HDLC startup problems. -* Application must bring the link up -* before tx/rx, and bring the -* link down on close(). -* Mar 06, 2000 Nenad Corbic o Added an option for logging call setup -* information. -* Feb 29, 2000 Nenad Corbic o Added support for LAPB HDLC API -* Feb 25, 2000 Nenad Corbic o Fixed the modem failure handling. -* No Modem OOB message will be passed -* to the user. -* Feb 21, 2000 Nenad Corbic o Added Xpipemon Debug Support -* Dec 30, 1999 Nenad Corbic o Socket based X25API -* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X kernel -* Mar 15, 1998 Alan Cox o 2.1.x porting -* Dec 19, 1997 Jaspreet Singh o Added multi-channel IPX support -* Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs -* when they are disabled. -* Nov 17, 1997 Farhan Thawar o Added IPX support -* o Changed if_send() to now buffer packets when -* the board is busy -* o Removed queueing of packets via the polling -* routing -* o Changed if_send() critical flags to properly -* handle race conditions -* Nov 06, 1997 Farhan Thawar o Added support for SVC timeouts -* o Changed PVC encapsulation to ETH_P_IP -* Jul 21, 1997 Jaspreet Singh o Fixed freeing up of buffers using kfree() -* when packets are received. -* Mar 11, 1997 Farhan Thawar Version 3.1.1 -* o added support for V35 -* o changed if_send() to return 0 if -* wandev.critical() is true -* o free socket buffer in if_send() if -* returning 0 -* o added support for single '@' address to -* accept all incoming calls -* o fixed bug in set_chan_state() to disconnect -* Jan 15, 1997 Gene Kozin Version 3.1.0 -* o implemented exec() entry point -* Jan 07, 1997 Gene Kozin Initial version. -*****************************************************************************/ - -/*====================================================== - * Includes - *=====================================================*/ - -#include -#include /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include -#include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include -#include /* time_after() macro */ -#include /* htons(), etc. */ -#include -#include /* Experimental delay */ - -#include - -#include -#include -#include /* X.25 firmware API definitions */ -#include -#include - - -/*====================================================== - * Defines & Macros - *=====================================================*/ - - -#define CMD_OK 0 /* normal firmware return code */ -#define CMD_TIMEOUT 0xFF /* firmware command timed out */ -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ - -#define X25_CHAN_MTU 4096 /* unfragmented logical channel MTU */ -#define X25_HRDHDR_SZ 7 /* max encapsulation header size */ -#define X25_CONCT_TMOUT (90*HZ) /* link connection timeout */ -#define X25_RECON_TMOUT (10*HZ) /* link connection timeout */ -#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ -#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ -#define MAX_BH_BUFF 10 -#define M_BIT 0x01 - -//#define PRINT_DEBUG 1 -#ifdef PRINT_DEBUG -#define DBG_PRINTK(format, a...) printk(format, ## a) -#else -#define DBG_PRINTK(format, a...) -#endif - -#define TMR_INT_ENABLED_POLL_ACTIVE 0x01 -#define TMR_INT_ENABLED_POLL_CONNECT_ON 0x02 -#define TMR_INT_ENABLED_POLL_CONNECT_OFF 0x04 -#define TMR_INT_ENABLED_POLL_DISCONNECT 0x08 -#define TMR_INT_ENABLED_CMD_EXEC 0x10 -#define TMR_INT_ENABLED_UPDATE 0x20 -#define TMR_INT_ENABLED_UDP_PKT 0x40 - -#define MAX_X25_ADDR_SIZE 16 -#define MAX_X25_DATA_SIZE 129 -#define MAX_X25_FACL_SIZE 110 - -#define TRY_CMD_AGAIN 2 -#define DELAY_RESULT 1 -#define RETURN_RESULT 0 - -#define DCD(x) (x & 0x03 ? "HIGH" : "LOW") -#define CTS(x) (x & 0x05 ? "HIGH" : "LOW") - - -/* Driver will not write log messages about - * modem status if defined.*/ -#define MODEM_NOT_LOG 1 - -/*==================================================== - * For IPXWAN - *===================================================*/ - -#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) - - -/*==================================================== - * MEMORY DEBUGGING FUNCTION - *==================================================== - -#define KMEM_SAFETYZONE 8 - -static void * dbg_kmalloc(unsigned int size, int prio, int line) { - int i = 0; - void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); - char * c1 = v; - c1 += sizeof(unsigned int); - *((unsigned int *)v) = size; - - for (i = 0; i < KMEM_SAFETYZONE; i++) { - c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; - c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; - c1 += 8; - } - c1 += size; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; - c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; - c1 += 8; - } - v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; - printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); - return v; -} -static void dbg_kfree(void * v, int line) { - unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); - unsigned int size = *sp; - char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; - int i = 0; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' - || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { - printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); - printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, - c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); - } - c1 += 8; - } - c1 += size; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' - || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' - ) { - printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); - printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, - c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); - } - c1 += 8; - } - printk(KERN_INFO "line %d kfree(%p)\n",line,v); - v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); - kfree(v); -} - -#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) -#define kfree(x) dbg_kfree(x,__LINE__) - -==============================================================*/ - - - -/*=============================================== - * Data Structures - *===============================================*/ - - -/*======================================================== - * Name: x25_channel - * - * Purpose: To hold private informaton for each - * logical channel. - * - * Rationale: Per-channel debugging is possible if each - * channel has its own private area. - * - * Assumptions: - * - * Description: This is an extention of the struct net_device - * we create for each network interface to keep - * the rest of X.25 channel-specific data. - * - * Construct: Typedef - */ -typedef struct x25_channel -{ - wanpipe_common_t common; /* common area for x25api and socket */ - char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ - char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ - unsigned tx_pkt_size; - unsigned short protocol; /* ethertype, 0 - multiplexed */ - char drop_sequence; /* mark sequence for dropping */ - unsigned long state_tick; /* time of the last state change */ - unsigned idle_timeout; /* sec, before disconnecting */ - unsigned long i_timeout_sofar; /* # of sec's we've been idle */ - unsigned hold_timeout; /* sec, before re-connecting */ - unsigned long tick_counter; /* counter for transmit time out */ - char devtint; /* Weather we should dev_tint() */ - struct sk_buff* rx_skb; /* receive socket buffer */ - struct sk_buff* tx_skb; /* transmit socket buffer */ - - bh_data_t *bh_head; /* Circular buffer for x25api_bh */ - unsigned long tq_working; - volatile int bh_write; - volatile int bh_read; - atomic_t bh_buff_used; - - sdla_t* card; /* -> owner */ - struct net_device *dev; /* -> bound devce */ - - int ch_idx; - unsigned char enable_IPX; - unsigned long network_number; - struct net_device_stats ifstats; /* interface statistics */ - unsigned short transmit_length; - unsigned short tx_offset; - char transmit_buffer[X25_CHAN_MTU+sizeof(x25api_hdr_t)]; - - if_send_stat_t if_send_stat; - rx_intr_stat_t rx_intr_stat; - pipe_mgmt_stat_t pipe_mgmt_stat; - - unsigned long router_start_time; /* Router start time in seconds */ - unsigned long router_up_time; - -} x25_channel_t; - -/* FIXME Take this out */ - -#ifdef NEX_OLD_CALL_INFO -typedef struct x25_call_info -{ - char dest[17]; PACKED;/* ASCIIZ destination address */ - char src[17]; PACKED;/* ASCIIZ source address */ - char nuser; PACKED;/* number of user data bytes */ - unsigned char user[127]; PACKED;/* user data */ - char nfacil; PACKED;/* number of facilities */ - struct - { - unsigned char code; PACKED; - unsigned char parm; PACKED; - } facil[64]; /* facilities */ -} x25_call_info_t; -#else -typedef struct x25_call_info -{ - char dest[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ destination address */ - char src[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ source address */ - unsigned char nuser PACKED; - unsigned char user[MAX_X25_DATA_SIZE] PACKED;/* user data */ - unsigned char nfacil PACKED; - unsigned char facil[MAX_X25_FACL_SIZE] PACKED; - unsigned short lcn PACKED; -} x25_call_info_t; -#endif - - - -/*=============================================== - * Private Function Prototypes - *==============================================*/ - - -/*================================================= - * WAN link driver entry points. These are - * called by the WAN router module. - */ -static int update(struct wan_device* wandev); -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf); -static int del_if(struct wan_device* wandev, struct net_device* dev); -static void disable_comm (sdla_t* card); -static void disable_comm_shutdown(sdla_t *card); - - - -/*================================================= - * WANPIPE-specific entry points - */ -static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data); -static void x25api_bh(struct net_device *dev); -static int x25api_bh_cleanup(struct net_device *dev); -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb); - - -/*================================================= - * Network device interface - */ -static int if_init(struct net_device* dev); -static int if_open(struct net_device* dev); -static int if_close(struct net_device* dev); -static int if_header(struct sk_buff* skb, struct net_device* dev, - unsigned short type, void* daddr, void* saddr, unsigned len); -static int if_rebuild_hdr (struct sk_buff* skb); -static int if_send(struct sk_buff* skb, struct net_device* dev); -static struct net_device_stats *if_stats(struct net_device* dev); - -static void if_tx_timeout(struct net_device *dev); - -/*================================================= - * Interrupt handlers - */ -static void wpx_isr (sdla_t *); -static void rx_intr (sdla_t *); -static void tx_intr (sdla_t *); -static void status_intr (sdla_t *); -static void event_intr (sdla_t *); -static void spur_intr (sdla_t *); -static void timer_intr (sdla_t *); - -static int tx_intr_send(sdla_t *card, struct net_device *dev); -static struct net_device *move_dev_to_next(sdla_t *card, - struct net_device *dev); - -/*================================================= - * Background polling routines - */ -static void wpx_poll (sdla_t* card); -static void poll_disconnected (sdla_t* card); -static void poll_connecting (sdla_t* card); -static void poll_active (sdla_t* card); -static void trigger_x25_poll(sdla_t *card); -static void x25_timer_routine(unsigned long data); - - - -/*================================================= - * X.25 firmware interface functions - */ -static int x25_get_version (sdla_t* card, char* str); -static int x25_configure (sdla_t* card, TX25Config* conf); -static int hdlc_configure (sdla_t* card, TX25Config* conf); -static int set_hdlc_level (sdla_t* card); -static int x25_get_err_stats (sdla_t* card); -static int x25_get_stats (sdla_t* card); -static int x25_set_intr_mode (sdla_t* card, int mode); -static int x25_close_hdlc (sdla_t* card); -static int x25_open_hdlc (sdla_t* card); -static int x25_setup_hdlc (sdla_t* card); -static int x25_set_dtr (sdla_t* card, int dtr); -static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan); -static int x25_place_call (sdla_t* card, x25_channel_t* chan); -static int x25_accept_call (sdla_t* card, int lcn, int qdm); -static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn); -static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf); -static int x25_fetch_events (sdla_t* card); -static int x25_error (sdla_t* card, int err, int cmd, int lcn); - -/*================================================= - * X.25 asynchronous event handlers - */ -static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); - - -/*================================================= - * Miscellaneous functions - */ -static int connect (sdla_t* card); -static int disconnect (sdla_t* card); -static struct net_device* get_dev_by_lcn(struct wan_device* wandev, - unsigned lcn); -static int chan_connect(struct net_device* dev); -static int chan_disc(struct net_device* dev); -static void set_chan_state(struct net_device* dev, int state); -static int chan_send(struct net_device *dev, void* buff, unsigned data_len, - unsigned char tx_intr); -static unsigned char bps_to_speed_code (unsigned long bps); -static unsigned int dec_to_uint (unsigned char* str, int len); -static unsigned int hex_to_uint (unsigned char*, int); -static void parse_call_info (unsigned char*, x25_call_info_t*); -static struct net_device *find_channel(sdla_t *card, unsigned lcn); -static void bind_lcn_to_dev(sdla_t *card, struct net_device *dev, unsigned lcn); -static void setup_for_delayed_transmit(struct net_device *dev, - void *buf, unsigned len); - - -/*================================================= - * X25 API Functions - */ -static int wanpipe_pull_data_in_skb(sdla_t *card, struct net_device *dev, - struct sk_buff **); -static void timer_intr_exec(sdla_t *, unsigned char); -static int execute_delayed_cmd(sdla_t *card, struct net_device *dev, - mbox_cmd_t *usr_cmd, char bad_cmd); -static int api_incoming_call (sdla_t*, TX25Mbox *, int); -static int alloc_and_init_skb_buf (sdla_t *,struct sk_buff **, int); -static void send_delayed_cmd_result(sdla_t *card, struct net_device *dev, - TX25Mbox* mbox); -static int clear_confirm_event (sdla_t *, TX25Mbox*); -static void send_oob_msg (sdla_t *card, struct net_device *dev, TX25Mbox *mbox); -static int timer_intr_cmd_exec(sdla_t *card); -static void api_oob_event (sdla_t *card,TX25Mbox *mbox); -static int check_bad_command(sdla_t *card, struct net_device *dev); -static int channel_disconnect(sdla_t* card, struct net_device *dev); -static void hdlc_link_down (sdla_t*); - -/*================================================= - * XPIPEMON Functions - */ -static int process_udp_mgmt_pkt(sdla_t *); -static int udp_pkt_type( struct sk_buff *, sdla_t*); -static int reply_udp( unsigned char *, unsigned int); -static void init_x25_channel_struct( x25_channel_t *); -static void init_global_statistics( sdla_t *); -static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t *card, - struct net_device *dev, - struct sk_buff *skb, int lcn); -static unsigned short calc_checksum (char *, int); - - - -/*================================================= - * IPX functions - */ -static void switch_net_numbers(unsigned char *, unsigned long, unsigned char); -static int handle_IPXWAN(unsigned char *, char *, unsigned char , - unsigned long , unsigned short ); - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -static void S508_S514_lock(sdla_t *, unsigned long *); -static void S508_S514_unlock(sdla_t *, unsigned long *); - - -/*================================================= - * Global Variables - *=================================================*/ - - - -/*================================================= - * Public Functions - *=================================================*/ - - - - -/*=================================================================== - * wpx_init: X.25 Protocol Initialization routine. - * - * Purpose: To initialize the protocol/firmware. - * - * Rationale: This function is called by setup() function, in - * sdlamain.c, to dynamically setup the x25 protocol. - * This is the first protocol specific function, which - * executes once on startup. - * - * Description: This procedure initializes the x25 firmware and - * sets up the mailbox, transmit and receive buffer - * pointers. It also initializes all debugging structures - * and sets up the X25 environment. - * - * Sets up hardware options defined by user in [wanpipe#] - * section of wanpipe#.conf configuration file. - * - * At this point adapter is completely initialized - * and X.25 firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the - * adapter data space. - * - * Called by: setup() function in sdlamain.c - * - * Assumptions: None - * - * Warnings: None - * - * Return: 0 o.k. - * < 0 failure. - */ - -int wpx_init (sdla_t* card, wandev_conf_t* conf) -{ - union{ - char str[80]; - TX25Config cfg; - } u; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_X25){ - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id) - ; - return -EINVAL; - } - - /* Initialize protocol-specific fields */ - card->mbox = (void*)(card->hw.dpmbase + X25_MBOX_OFFS); - card->rxmb = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS); - card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS); - - /* Initialize for S514 Card */ - if(card->hw.type == SDLA_S514) { - card->mbox += X25_MB_VECTOR; - card->flags += X25_MB_VECTOR; - card->rxmb += X25_MB_VECTOR; - } - - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - if (x25_get_version(card, NULL) || x25_get_version(card, u.str)) - return -EIO; - - - /* X25 firmware can run ether in X25 or LAPB HDLC mode. - * Check the user defined option and configure accordingly */ - if (conf->u.x25.LAPB_hdlc_only == WANOPT_YES){ - if (set_hdlc_level(card) != CMD_OK){ - return -EIO; - }else{ - printk(KERN_INFO "%s: running LAP_B HDLC firmware v%s\n", - card->devname, u.str); - } - card->u.x.LAPB_hdlc = 1; - }else{ - printk(KERN_INFO "%s: running X.25 firmware v%s\n", - card->devname, u.str); - card->u.x.LAPB_hdlc = 0; - } - - /* Configure adapter. Here we set resonable defaults, then parse - * device configuration structure and set configuration options. - * Most configuration options are verified and corrected (if - * necessary) since we can't rely on the adapter to do so. - */ - memset(&u.cfg, 0, sizeof(u.cfg)); - u.cfg.t1 = 3; - u.cfg.n2 = 10; - u.cfg.autoHdlc = 1; /* automatic HDLC connection */ - u.cfg.hdlcWindow = 7; - u.cfg.pktWindow = 2; - u.cfg.station = 1; /* DTE */ - u.cfg.options = 0x0090; /* disable D-bit pragmatics */ - u.cfg.ccittCompat = 1988; - u.cfg.t10t20 = 30; - u.cfg.t11t21 = 30; - u.cfg.t12t22 = 30; - u.cfg.t13t23 = 30; - u.cfg.t16t26 = 30; - u.cfg.t28 = 30; - u.cfg.r10r20 = 5; - u.cfg.r12r22 = 5; - u.cfg.r13r23 = 5; - u.cfg.responseOpt = 1; /* RR's after every packet */ - - if (card->u.x.LAPB_hdlc){ - u.cfg.hdlcMTU = 1027; - } - - if (conf->u.x25.x25_conf_opt){ - u.cfg.options = conf->u.x25.x25_conf_opt; - } - - if (conf->clocking != WANOPT_EXTERNAL) - u.cfg.baudRate = bps_to_speed_code(conf->bps); - - if (conf->station != WANOPT_DTE){ - u.cfg.station = 0; /* DCE mode */ - } - - if (conf->interface != WANOPT_RS232 ){ - u.cfg.hdlcOptions |= 0x80; /* V35 mode */ - } - - /* adjust MTU */ - if (!conf->mtu || (conf->mtu >= 1024)) - card->wandev.mtu = 1024; - else if (conf->mtu >= 512) - card->wandev.mtu = 512; - else if (conf->mtu >= 256) - card->wandev.mtu = 256; - else if (conf->mtu >= 128) - card->wandev.mtu = 128; - else - card->wandev.mtu = 64; - - u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu; - - if (conf->u.x25.hi_pvc){ - card->u.x.hi_pvc = min_t(unsigned int, conf->u.x25.hi_pvc, MAX_LCN_NUM); - card->u.x.lo_pvc = min_t(unsigned int, conf->u.x25.lo_pvc, card->u.x.hi_pvc); - } - - if (conf->u.x25.hi_svc){ - card->u.x.hi_svc = min_t(unsigned int, conf->u.x25.hi_svc, MAX_LCN_NUM); - card->u.x.lo_svc = min_t(unsigned int, conf->u.x25.lo_svc, card->u.x.hi_svc); - } - - /* Figure out the total number of channels to configure */ - card->u.x.num_of_ch = 0; - if (card->u.x.hi_svc != 0){ - card->u.x.num_of_ch = (card->u.x.hi_svc - card->u.x.lo_svc) + 1; - } - if (card->u.x.hi_pvc != 0){ - card->u.x.num_of_ch += (card->u.x.hi_pvc - card->u.x.lo_pvc) + 1; - } - - if (card->u.x.num_of_ch == 0){ - printk(KERN_INFO "%s: ERROR, Minimum number of PVC/SVC channels is 1 !\n" - "%s: Please set the Lowest/Highest PVC/SVC values !\n", - card->devname,card->devname); - return -ECHRNG; - } - - u.cfg.loPVC = card->u.x.lo_pvc; - u.cfg.hiPVC = card->u.x.hi_pvc; - u.cfg.loTwoWaySVC = card->u.x.lo_svc; - u.cfg.hiTwoWaySVC = card->u.x.hi_svc; - - if (conf->u.x25.hdlc_window) - u.cfg.hdlcWindow = min_t(unsigned int, conf->u.x25.hdlc_window, 7); - if (conf->u.x25.pkt_window) - u.cfg.pktWindow = min_t(unsigned int, conf->u.x25.pkt_window, 7); - - if (conf->u.x25.t1) - u.cfg.t1 = min_t(unsigned int, conf->u.x25.t1, 30); - if (conf->u.x25.t2) - u.cfg.t2 = min_t(unsigned int, conf->u.x25.t2, 29); - if (conf->u.x25.t4) - u.cfg.t4 = min_t(unsigned int, conf->u.x25.t4, 240); - if (conf->u.x25.n2) - u.cfg.n2 = min_t(unsigned int, conf->u.x25.n2, 30); - - if (conf->u.x25.t10_t20) - u.cfg.t10t20 = min_t(unsigned int, conf->u.x25.t10_t20,255); - if (conf->u.x25.t11_t21) - u.cfg.t11t21 = min_t(unsigned int, conf->u.x25.t11_t21,255); - if (conf->u.x25.t12_t22) - u.cfg.t12t22 = min_t(unsigned int, conf->u.x25.t12_t22,255); - if (conf->u.x25.t13_t23) - u.cfg.t13t23 = min_t(unsigned int, conf->u.x25.t13_t23,255); - if (conf->u.x25.t16_t26) - u.cfg.t16t26 = min_t(unsigned int, conf->u.x25.t16_t26, 255); - if (conf->u.x25.t28) - u.cfg.t28 = min_t(unsigned int, conf->u.x25.t28, 255); - - if (conf->u.x25.r10_r20) - u.cfg.r10r20 = min_t(unsigned int, conf->u.x25.r10_r20,250); - if (conf->u.x25.r12_r22) - u.cfg.r12r22 = min_t(unsigned int, conf->u.x25.r12_r22,250); - if (conf->u.x25.r13_r23) - u.cfg.r13r23 = min_t(unsigned int, conf->u.x25.r13_r23,250); - - - if (conf->u.x25.ccitt_compat) - u.cfg.ccittCompat = conf->u.x25.ccitt_compat; - - /* initialize adapter */ - if (card->u.x.LAPB_hdlc){ - if (hdlc_configure(card, &u.cfg) != CMD_OK) - return -EIO; - }else{ - if (x25_configure(card, &u.cfg) != CMD_OK) - return -EIO; - } - - if ((x25_close_hdlc(card) != CMD_OK) || /* close HDLC link */ - (x25_set_dtr(card, 0) != CMD_OK)) /* drop DTR */ - return -EIO; - - /* Initialize protocol-specific fields of adapter data space */ - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->isr = &wpx_isr; - card->poll = NULL; //&wpx_poll; - card->disable_comm = &disable_comm; - card->exec = &wpx_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - - /* WARNING: This function cannot exit with an error - * after the change of state */ - card->wandev.state = WAN_DISCONNECTED; - - card->wandev.enable_tx_int = 0; - card->irq_dis_if_send_count = 0; - card->irq_dis_poll_count = 0; - card->u.x.tx_dev = NULL; - card->u.x.no_dev = 0; - - - /* Configure for S514 PCI Card */ - if (card->hw.type == SDLA_S514) { - card->u.x.hdlc_buf_status = - (volatile unsigned char *) - (card->hw.dpmbase + X25_MB_VECTOR+ X25_MISC_HDLC_BITS); - }else{ - card->u.x.hdlc_buf_status = - (volatile unsigned char *)(card->hw.dpmbase + X25_MISC_HDLC_BITS); - } - - card->u.x.poll_device=NULL; - card->wandev.udp_port = conf->udp_port; - - /* Enable or disable call setup logging */ - if (conf->u.x25.logging == WANOPT_YES){ - printk(KERN_INFO "%s: Enabling Call Logging.\n", - card->devname); - card->u.x.logging = 1; - }else{ - card->u.x.logging = 0; - } - - /* Enable or disable modem status reporting */ - if (conf->u.x25.oob_on_modem == WANOPT_YES){ - printk(KERN_INFO "%s: Enabling OOB on Modem change.\n", - card->devname); - card->u.x.oob_on_modem = 1; - }else{ - card->u.x.oob_on_modem = 0; - } - - init_global_statistics(card); - - INIT_WORK(&card->u.x.x25_poll_work, (void *)wpx_poll, card); - - init_timer(&card->u.x.x25_timer); - card->u.x.x25_timer.data = (unsigned long)card; - card->u.x.x25_timer.function = x25_timer_routine; - - return 0; -} - -/*========================================================= - * WAN Device Driver Entry Points - *========================================================*/ - -/*============================================================ - * Name: update(), Update device status & statistics. - * - * Purpose: To provide debugging and statitical - * information to the /proc file system. - * /proc/net/wanrouter/wanpipe# - * - * Rationale: The /proc file system is used to collect - * information about the kernel and drivers. - * Using the /proc file system the user - * can see exactly what the sangoma drivers are - * doing. And in what state they are in. - * - * Description: Collect all driver statistical information - * and pass it to the top laywer. - * - * Since we have to execute a debugging command, - * to obtain firmware statitics, we trigger a - * UPDATE function within the timer interrtup. - * We wait until the timer update is complete. - * Once complete return the appropriate return - * code to indicate that the update was successful. - * - * Called by: device_stat() in wanmain.c - * - * Assumptions: - * - * Warnings: This function will degrade the performance - * of the router, since it uses the mailbox. - * - * Return: 0 OK - * <0 Failed (or busy). - */ - -static int update(struct wan_device* wandev) -{ - volatile sdla_t* card; - TX25Status* status; - unsigned long timeout; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - - if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - if (test_bit(SEND_CRIT, (void*)&wandev->critical)) - return -EAGAIN; - - if (!wandev->dev) - return -ENODEV; - - card = wandev->private; - status = card->flags; - - card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UPDATE; - status->imask |= INTR_ON_TIMER; - timeout = jiffies; - - for (;;){ - if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE)){ - break; - } - if (time_after(jiffies, timeout + 1*HZ)){ - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; - return -EAGAIN; - } - } - return 0; -} - - -/*=================================================================== - * Name: new_if - * - * Purpose: To allocate and initialize resources for a - * new logical channel. - * - * Rationale: A new channel can be added dynamically via - * ioctl call. - * - * Description: Allocate a private channel structure, x25_channel_t. - * Parse the user interface options from wanpipe#.conf - * configuration file. - * Bind the private are into the network device private - * area pointer (dev->priv). - * Prepare the network device structure for registration. - * - * Called by: ROUTER_IFNEW Ioctl call, from wanrouter_ioctl() - * (wanmain.c) - * - * Assumptions: None - * - * Warnings: None - * - * Return: 0 Ok - * <0 Failed (channel will not be created) - */ -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf) -{ - sdla_t* card = wandev->private; - x25_channel_t* chan; - int err = 0; - - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)){ - printk(KERN_INFO "%s: invalid interface name!\n", - card->devname); - return -EINVAL; - } - - if(card->wandev.new_if_cnt++ > 0 && card->u.x.LAPB_hdlc) { - printk(KERN_INFO "%s: Error: Running LAPB HDLC Mode !\n", - card->devname); - printk(KERN_INFO - "%s: Maximum number of network interfaces must be one !\n", - card->devname); - return -EEXIST; - } - - /* allocate and initialize private data */ - chan = kmalloc(sizeof(x25_channel_t), GFP_ATOMIC); - if (chan == NULL){ - return -ENOMEM; - } - - memset(chan, 0, sizeof(x25_channel_t)); - - /* Bug Fix: Seg Err on PVC startup - * It must be here since bind_lcn_to_dev expects - * it bellow */ - dev->priv = chan; - - strcpy(chan->name, conf->name); - chan->card = card; - chan->dev = dev; - chan->common.sk = NULL; - chan->common.func = NULL; - chan->common.rw_bind = 0; - chan->tx_skb = chan->rx_skb = NULL; - - /* verify media address */ - if (conf->addr[0] == '@'){ /* SVC */ - chan->common.svc = 1; - strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ); - - /* Set channel timeouts (default if not specified) */ - chan->idle_timeout = (conf->idle_timeout) ? - conf->idle_timeout : 90; - chan->hold_timeout = (conf->hold_timeout) ? - conf->hold_timeout : 10; - - }else if (isdigit(conf->addr[0])){ /* PVC */ - int lcn = dec_to_uint(conf->addr, 0); - - if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)){ - bind_lcn_to_dev (card, dev, lcn); - }else{ - printk(KERN_ERR - "%s: PVC %u is out of range on interface %s!\n", - wandev->name, lcn, chan->name); - err = -EINVAL; - } - }else{ - printk(KERN_ERR - "%s: invalid media address on interface %s!\n", - wandev->name, chan->name); - err = -EINVAL; - } - - if(strcmp(conf->usedby, "WANPIPE") == 0){ - printk(KERN_INFO "%s: Running in WANPIPE mode %s\n", - wandev->name, chan->name); - chan->common.usedby = WANPIPE; - chan->protocol = htons(ETH_P_IP); - - }else if(strcmp(conf->usedby, "API") == 0){ - chan->common.usedby = API; - printk(KERN_INFO "%s: Running in API mode %s\n", - wandev->name, chan->name); - chan->protocol = htons(X25_PROT); - } - - - if (err){ - kfree(chan); - dev->priv = NULL; - return err; - } - - chan->enable_IPX = conf->enable_IPX; - - if (chan->enable_IPX) - chan->protocol = htons(ETH_P_IPX); - - if (conf->network_number) - chan->network_number = conf->network_number; - else - chan->network_number = 0xDEADBEEF; - - /* prepare network device data space for registration */ - strcpy(dev->name,chan->name); - - dev->init = &if_init; - - init_x25_channel_struct(chan); - - return 0; -} - -/*=================================================================== - * Name: del_if(), Remove a logical channel. - * - * Purpose: To dynamically remove a logical channel. - * - * Rationale: Each logical channel should be dynamically - * removable. This functin is called by an - * IOCTL_IFDEL ioctl call or shutdown(). - * - * Description: Do nothing. - * - * Called by: IOCTL_IFDEL : wanrouter_ioctl() from wanmain.c - * shutdown() from sdlamain.c - * - * Assumptions: - * - * Warnings: - * - * Return: 0 Ok. Void function. - */ - -//FIXME Del IF Should be taken out now. - -static int del_if(struct wan_device* wandev, struct net_device* dev) -{ - return 0; -} - - -/*============================================================ - * Name: wpx_exec - * - * Description: Execute adapter interface command. - * This option is currently dissabled. - *===========================================================*/ - -static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data) -{ - return 0; -} - -/*============================================================ - * Name: disable_comm - * - * Description: Disable communications during shutdown. - * Dont check return code because there is - * nothing we can do about it. - * - * Warning: Dev and private areas are gone at this point. - *===========================================================*/ - -static void disable_comm(sdla_t* card) -{ - disable_comm_shutdown(card); - del_timer(&card->u.x.x25_timer); - return; -} - - -/*============================================================ - * Network Device Interface - *===========================================================*/ - -/*=================================================================== - * Name: if_init(), Netowrk Interface Initialization - * - * Purpose: To initialize a network interface device structure. - * - * Rationale: During network interface startup, the if_init - * is called by the kernel to initialize the - * netowrk device structure. Thus a driver - * can customze a network device. - * - * Description: Initialize the netowrk device call back - * routines. This is where we tell the kernel - * which function to use when it wants to send - * via our interface. - * Furthermore, we initialize the device flags, - * MTU and physical address of the board. - * - * Called by: Kernel (/usr/src/linux/net/core/dev.c) - * (dev->init()) - * - * Assumptions: None - * - * Warnings: None - * - * Return: 0 Ok : Void function. - */ -static int if_init(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - struct wan_device* wandev = &card->wandev; - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - dev->tx_timeout = &if_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - /* Initialize media-specific parameters */ - dev->type = ARPHRD_PPP; /* ARP h/w type */ - dev->flags |= IFF_POINTOPOINT; - dev->flags |= IFF_NOARP; - - if (chan->common.usedby == API){ - dev->mtu = X25_CHAN_MTU+sizeof(x25api_hdr_t); - }else{ - dev->mtu = card->wandev.mtu; - } - - dev->hard_header_len = X25_HRDHDR_SZ; /* media header length */ - dev->addr_len = 2; /* hardware address length */ - - if (!chan->common.svc){ - *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); - } - - /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = (unsigned long)wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; - - /* Set transmit buffer queue length */ - dev->tx_queue_len = 100; - SET_MODULE_OWNER(dev); - - /* FIXME Why are we doing this */ - set_chan_state(dev, WAN_DISCONNECTED); - return 0; -} - - -/*=================================================================== - * Name: if_open(), Open/Bring up the Netowrk Interface - * - * Purpose: To bring up a network interface. - * - * Rationale: - * - * Description: Open network interface. - * o prevent module from unloading by incrementing use count - * o if link is disconnected then initiate connection - * - * Called by: Kernel (/usr/src/linux/net/core/dev.c) - * (dev->open()) - * - * Assumptions: None - * - * Warnings: None - * - * Return: 0 Ok - * <0 Failure: Interface will not come up. - */ - -static int if_open(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - struct timeval tv; - unsigned long smp_flags; - - if (netif_running(dev)) - return -EBUSY; - - chan->tq_working = 0; - - /* Initialize the workqueue */ - INIT_WORK(&chan->common.wanpipe_work, (void *)x25api_bh, dev); - - /* Allocate and initialize BH circular buffer */ - /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */ - chan->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC); - - if (chan->bh_head == NULL){ - printk(KERN_INFO "%s: ERROR, failed to allocate memory ! BH_BUFFERS !\n", - card->devname); - - return -ENOBUFS; - } - memset(chan->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1))); - atomic_set(&chan->bh_buff_used, 0); - - /* Increment the number of interfaces */ - ++card->u.x.no_dev; - - wanpipe_open(card); - - /* LAPB protocol only uses one interface, thus - * start the protocol after it comes up. */ - if (card->u.x.LAPB_hdlc){ - if (card->open_cnt == 1){ - TX25Status* status = card->flags; - S508_S514_lock(card, &smp_flags); - x25_set_intr_mode(card, INTR_ON_TIMER); - status->imask &= ~INTR_ON_TIMER; - S508_S514_unlock(card, &smp_flags); - } - }else{ - /* X25 can have multiple interfaces thus, start the - * protocol once all interfaces are up */ - - //FIXME: There is a bug here. If interface is - //brought down and up, it will try to enable comm. - if (card->open_cnt == card->u.x.num_of_ch){ - - S508_S514_lock(card, &smp_flags); - connect(card); - S508_S514_unlock(card, &smp_flags); - - mod_timer(&card->u.x.x25_timer, jiffies + HZ); - } - } - /* Device is not up until the we are in connected state */ - do_gettimeofday( &tv ); - chan->router_start_time = tv.tv_sec; - - netif_start_queue(dev); - - return 0; -} - -/*=================================================================== - * Name: if_close(), Close/Bring down the Netowrk Interface - * - * Purpose: To bring down a network interface. - * - * Rationale: - * - * Description: Close network interface. - * o decrement use module use count - * - * Called by: Kernel (/usr/src/linux/net/core/dev.c) - * (dev->close()) - * ifconfig down: will trigger the kernel - * which will call this function. - * - * Assumptions: None - * - * Warnings: None - * - * Return: 0 Ok - * <0 Failure: Interface will not exit properly. - */ -static int if_close(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - unsigned long smp_flags; - - netif_stop_queue(dev); - - if ((chan->common.state == WAN_CONNECTED) || - (chan->common.state == WAN_CONNECTING)){ - S508_S514_lock(card, &smp_flags); - chan_disc(dev); - S508_S514_unlock(card, &smp_flags); - } - - wanpipe_close(card); - - S508_S514_lock(card, &smp_flags); - if (chan->bh_head){ - int i; - struct sk_buff *skb; - - for (i=0; i<(MAX_BH_BUFF+1); i++){ - skb = ((bh_data_t *)&chan->bh_head[i])->skb; - if (skb != NULL){ - dev_kfree_skb_any(skb); - } - } - kfree(chan->bh_head); - chan->bh_head=NULL; - } - S508_S514_unlock(card, &smp_flags); - - /* If this is the last close, disconnect physical link */ - if (!card->open_cnt){ - S508_S514_lock(card, &smp_flags); - disconnect(card); - x25_set_intr_mode(card, 0); - S508_S514_unlock(card, &smp_flags); - } - - /* Decrement the number of interfaces */ - --card->u.x.no_dev; - return 0; -} - -/*====================================================================== - * Build media header. - * o encapsulate packet according to encapsulation type. - * - * The trick here is to put packet type (Ethertype) into 'protocol' - * field of the socket buffer, so that we don't forget it. - * If encapsulation fails, set skb->protocol to 0 and discard - * packet later. - * - * Return: media header length. - *======================================================================*/ - -static int if_header(struct sk_buff* skb, struct net_device* dev, - unsigned short type, void* daddr, void* saddr, - unsigned len) -{ - x25_channel_t* chan = dev->priv; - int hdr_len = dev->hard_header_len; - - skb->protocol = htons(type); - if (!chan->protocol){ - hdr_len = wanrouter_encapsulate(skb, dev, type); - if (hdr_len < 0){ - hdr_len = 0; - skb->protocol = htons(0); - } - } - return hdr_len; -} - -/*=============================================================== - * Re-build media header. - * - * Return: 1 physical address resolved. - * 0 physical address not resolved - *==============================================================*/ - -static int if_rebuild_hdr (struct sk_buff* skb) -{ - struct net_device *dev = skb->dev; - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); - return 1; -} - - -/*============================================================================ - * Handle transmit timeout event from netif watchdog - */ -static void if_tx_timeout(struct net_device *dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - - ++chan->if_send_stat.if_send_tbusy_timeout; - printk (KERN_INFO "%s: Transmit timed out on %s\n", - card->devname, dev->name); - netif_wake_queue (dev); -} - - -/*========================================================================= - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission). - * o check link state. If link is not up, then drop the packet. - * o check channel status. If it's down then initiate a call. - * o pass a packet to corresponding WAN device. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. - * - *========================================================================*/ - -static int if_send(struct sk_buff* skb, struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - TX25Status* status = card->flags; - int udp_type; - unsigned long smp_flags=0; - - ++chan->if_send_stat.if_send_entry; - - netif_stop_queue(dev); - - /* No need to check frame length, since socket code - * will perform the check for us */ - - chan->tick_counter = jiffies; - - /* Critical region starts here */ - S508_S514_lock(card, &smp_flags); - - if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ - printk(KERN_INFO "Hit critical in if_send()! %lx\n",card->wandev.critical); - goto if_send_crit_exit; - } - - udp_type = udp_pkt_type(skb, card); - - if(udp_type != UDP_INVALID_TYPE) { - - if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, dev, skb, - chan->common.lcn)) { - - status->imask |= INTR_ON_TIMER; - if (udp_type == UDP_XPIPE_TYPE){ - chan->if_send_stat.if_send_PIPE_request++; - } - } - netif_start_queue(dev); - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - S508_S514_unlock(card, &smp_flags); - return 0; - } - - if (chan->transmit_length){ - //FIXME: This check doesn't make sense any more - if (chan->common.state != WAN_CONNECTED){ - chan->transmit_length=0; - atomic_set(&chan->common.driver_busy,0); - }else{ - netif_stop_queue(dev); - ++card->u.x.tx_interrupts_pending; - status->imask |= INTR_ON_TX_FRAME; - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - S508_S514_unlock(card, &smp_flags); - return 1; - } - } - - if (card->wandev.state != WAN_CONNECTED){ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - ++chan->if_send_stat.if_send_wan_disconnected; - - }else if ( chan->protocol && (chan->protocol != skb->protocol)){ - printk(KERN_INFO - "%s: unsupported Ethertype 0x%04X on interface %s!\n", - chan->name, htons(skb->protocol), dev->name); - - printk(KERN_INFO "PROTO %Xn", htons(chan->protocol)); - ++chan->ifstats.tx_errors; - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - ++chan->if_send_stat.if_send_protocol_error; - - }else switch (chan->common.state){ - - case WAN_DISCONNECTED: - /* Try to establish connection. If succeded, then start - * transmission, else drop a packet. - */ - if (chan->common.usedby == API){ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - break; - }else{ - if (chan_connect(dev) != 0){ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - break; - } - } - /* fall through */ - - case WAN_CONNECTED: - if( skb->protocol == htons(ETH_P_IPX)) { - if(chan->enable_IPX) { - switch_net_numbers( skb->data, - chan->network_number, 0); - } else { - ++card->wandev.stats.tx_dropped; - ++chan->ifstats.tx_dropped; - ++chan->if_send_stat.if_send_protocol_error; - goto if_send_crit_exit; - } - } - /* We never drop here, if cannot send than, copy - * a packet into a transmit buffer - */ - chan_send(dev, skb->data, skb->len, 0); - break; - - default: - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - break; - } - - -if_send_crit_exit: - - dev_kfree_skb_any(skb); - - netif_start_queue(dev); - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - S508_S514_unlock(card, &smp_flags); - return 0; -} - -/*============================================================================ - * Setup so that a frame can be transmitted on the occurrence of a transmit - * interrupt. - *===========================================================================*/ - -static void setup_for_delayed_transmit(struct net_device* dev, void* buf, - unsigned len) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - TX25Status* status = card->flags; - - ++chan->if_send_stat.if_send_adptr_bfrs_full; - - if(chan->transmit_length) { - printk(KERN_INFO "%s: Error, transmit length set in delayed transmit!\n", - card->devname); - return; - } - - if (chan->common.usedby == API){ - if (len > X25_CHAN_MTU+sizeof(x25api_hdr_t)) { - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - printk(KERN_INFO "%s: Length is too big for delayed transmit\n", - card->devname); - return; - } - }else{ - if (len > X25_MAX_DATA) { - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - printk(KERN_INFO "%s: Length is too big for delayed transmit\n", - card->devname); - return; - } - } - - chan->transmit_length = len; - atomic_set(&chan->common.driver_busy,1); - memcpy(chan->transmit_buffer, buf, len); - - ++chan->if_send_stat.if_send_tx_int_enabled; - - /* Enable Transmit Interrupt */ - ++card->u.x.tx_interrupts_pending; - status->imask |= INTR_ON_TX_FRAME; -} - - -/*=============================================================== - * net_device_stats - * - * Get ethernet-style interface statistics. - * Return a pointer to struct enet_statistics. - * - *==============================================================*/ -static struct net_device_stats *if_stats(struct net_device* dev) -{ - x25_channel_t *chan = dev->priv; - - if(chan == NULL) - return NULL; - - return &chan->ifstats; -} - - -/* - * Interrupt Handlers - */ - -/* - * X.25 Interrupt Service Routine. - */ - -static void wpx_isr (sdla_t* card) -{ - TX25Status* status = card->flags; - - card->in_isr = 1; - ++card->statistics.isr_entry; - - if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ - card->in_isr=0; - status->iflags = 0; - return; - } - - if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)){ - - printk(KERN_INFO "%s: wpx_isr: wandev.critical set to 0x%02lx, int type = 0x%02x\n", - card->devname, card->wandev.critical, status->iflags); - card->in_isr = 0; - status->iflags = 0; - return; - } - - /* For all interrupts set the critical flag to CRITICAL_RX_INTR. - * If the if_send routine is called with this flag set it will set - * the enable transmit flag to 1. (for a delayed interrupt) - */ - switch (status->iflags){ - - case RX_INTR_PENDING: /* receive interrupt */ - rx_intr(card); - break; - - case TX_INTR_PENDING: /* transmit interrupt */ - tx_intr(card); - break; - - case MODEM_INTR_PENDING: /* modem status interrupt */ - status_intr(card); - break; - - case X25_ASY_TRANS_INTR_PENDING: /* network event interrupt */ - event_intr(card); - break; - - case TIMER_INTR_PENDING: - timer_intr(card); - break; - - default: /* unwanted interrupt */ - spur_intr(card); - } - - card->in_isr = 0; - status->iflags = 0; /* clear interrupt condition */ -} - -/* - * Receive interrupt handler. - * This routine handles fragmented IP packets using M-bit according to the - * RFC1356. - * o map ligical channel number to network interface. - * o allocate socket buffer or append received packet to the existing one. - * o if M-bit is reset (i.e. it's the last packet in a sequence) then - * decapsulate packet and pass socket buffer to the protocol stack. - * - * Notes: - * 1. When allocating a socket buffer, if M-bit is set then more data is - * coming and we have to allocate buffer for the maximum IP packet size - * expected on this channel. - * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no - * socket buffers available) the whole packet sequence must be discarded. - */ - -static void rx_intr (sdla_t* card) -{ - TX25Mbox* rxmb = card->rxmb; - unsigned lcn = rxmb->cmd.lcn; - struct net_device* dev = find_channel(card,lcn); - x25_channel_t* chan; - struct sk_buff* skb=NULL; - - if (dev == NULL){ - /* Invalid channel, discard packet */ - printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n", - card->devname, lcn); - return; - } - - chan = dev->priv; - chan->i_timeout_sofar = jiffies; - - - /* Copy the data from the board, into an - * skb buffer - */ - if (wanpipe_pull_data_in_skb(card,dev,&skb)){ - ++chan->ifstats.rx_dropped; - ++card->wandev.stats.rx_dropped; - ++chan->rx_intr_stat.rx_intr_no_socket; - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - return; - } - - dev->last_rx = jiffies; /* timestamp */ - - - /* ------------ API ----------------*/ - - if (chan->common.usedby == API){ - - if (bh_enqueue(dev, skb)){ - ++chan->ifstats.rx_dropped; - ++card->wandev.stats.rx_dropped; - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - dev_kfree_skb_any(skb); - return; - } - - ++chan->ifstats.rx_packets; - chan->ifstats.rx_bytes += skb->len; - - - chan->rx_skb = NULL; - if (!test_and_set_bit(0, &chan->tq_working)){ - wanpipe_queue_work(&chan->common.wanpipe_work); - } - return; - } - - - /* ------------- WANPIPE -------------------*/ - - /* set rx_skb to NULL so we won't access it later when kernel already owns it */ - chan->rx_skb=NULL; - - /* Decapsulate packet, if necessary */ - if (!skb->protocol && !wanrouter_type_trans(skb, dev)){ - /* can't decapsulate packet */ - dev_kfree_skb_any(skb); - ++chan->ifstats.rx_errors; - ++chan->ifstats.rx_dropped; - ++card->wandev.stats.rx_dropped; - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - - }else{ - if( handle_IPXWAN(skb->data, chan->name, - chan->enable_IPX, chan->network_number, - skb->protocol)){ - - if( chan->enable_IPX ){ - if(chan_send(dev, skb->data, skb->len,0)){ - chan->tx_skb = skb; - }else{ - dev_kfree_skb_any(skb); - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - } - }else{ - /* increment IPX packet dropped statistic */ - ++chan->ifstats.rx_dropped; - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - } - }else{ - skb->mac.raw = skb->data; - chan->ifstats.rx_bytes += skb->len; - ++chan->ifstats.rx_packets; - ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; - netif_rx(skb); - } - } - - return; -} - - -static int wanpipe_pull_data_in_skb(sdla_t *card, struct net_device *dev, - struct sk_buff **skb) -{ - void *bufptr; - TX25Mbox* rxmb = card->rxmb; - unsigned len = rxmb->cmd.length; /* packet length */ - unsigned qdm = rxmb->cmd.qdm; /* Q,D and M bits */ - x25_channel_t *chan = dev->priv; - struct sk_buff *new_skb = *skb; - - if (chan->common.usedby == WANPIPE){ - if (chan->drop_sequence){ - if (!(qdm & 0x01)){ - chan->drop_sequence = 0; - } - return 1; - } - new_skb = chan->rx_skb; - }else{ - /* Add on the API header to the received - * data - */ - len += sizeof(x25api_hdr_t); - } - - if (new_skb == NULL){ - int bufsize; - - if (chan->common.usedby == WANPIPE){ - bufsize = (qdm & 0x01) ? dev->mtu : len; - }else{ - bufsize = len; - } - - /* Allocate new socket buffer */ - new_skb = dev_alloc_skb(bufsize + dev->hard_header_len); - if (new_skb == NULL){ - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - chan->drop_sequence = 1; /* set flag */ - ++chan->ifstats.rx_dropped; - return 1; - } - } - - if (skb_tailroom(new_skb) < len){ - /* No room for the packet. Call off the whole thing! */ - dev_kfree_skb_any(new_skb); - if (chan->common.usedby == WANPIPE){ - chan->rx_skb = NULL; - if (qdm & 0x01){ - chan->drop_sequence = 1; - } - } - - printk(KERN_INFO "%s: unexpectedly long packet sequence " - "on interface %s!\n", card->devname, dev->name); - ++chan->ifstats.rx_length_errors; - return 1; - } - - bufptr = skb_put(new_skb,len); - - - if (chan->common.usedby == API){ - /* Fill in the x25api header - */ - x25api_t * api_data = (x25api_t*)bufptr; - api_data->hdr.qdm = rxmb->cmd.qdm; - api_data->hdr.cause = rxmb->cmd.cause; - api_data->hdr.diagn = rxmb->cmd.diagn; - api_data->hdr.length = rxmb->cmd.length; - memcpy(api_data->data, rxmb->data, rxmb->cmd.length); - }else{ - memcpy(bufptr, rxmb->data, len); - } - - new_skb->dev = dev; - - if (chan->common.usedby == API){ - new_skb->mac.raw = new_skb->data; - new_skb->protocol = htons(X25_PROT); - new_skb->pkt_type = WAN_PACKET_DATA; - }else{ - new_skb->protocol = chan->protocol; - chan->rx_skb = new_skb; - } - - /* If qdm bit is set, more data is coming - * thus, exit and wait for more data before - * sending the packet up. (Used by router only) - */ - if ((qdm & 0x01) && (chan->common.usedby == WANPIPE)) - return 1; - - *skb = new_skb; - - return 0; -} - -/*=============================================================== - * tx_intr - * - * Transmit interrupt handler. - * For each dev, check that there is something to send. - * If data available, transmit. - * - *===============================================================*/ - -static void tx_intr (sdla_t* card) -{ - struct net_device *dev; - TX25Status* status = card->flags; - unsigned char more_to_tx=0; - x25_channel_t *chan=NULL; - int i=0; - - if (card->u.x.tx_dev == NULL){ - card->u.x.tx_dev = card->wandev.dev; - } - - dev = card->u.x.tx_dev; - - for (;;){ - - chan = dev->priv; - if (chan->transmit_length){ - /* Device was set to transmit, check if the TX - * buffers are available - */ - if (chan->common.state != WAN_CONNECTED){ - chan->transmit_length = 0; - atomic_set(&chan->common.driver_busy,0); - chan->tx_offset=0; - if (netif_queue_stopped(dev)){ - if (chan->common.usedby == API){ - netif_start_queue(dev); - wakeup_sk_bh(dev); - }else{ - netif_wake_queue(dev); - } - } - dev = move_dev_to_next(card,dev); - break; - } - - if ((status->cflags[chan->ch_idx] & 0x40 || card->u.x.LAPB_hdlc) && - (*card->u.x.hdlc_buf_status & 0x40) ){ - /* Tx buffer available, we can send */ - - if (tx_intr_send(card, dev)){ - more_to_tx=1; - } - - /* If more than one interface present, move the - * device pointer to the next interface, so on the - * next TX interrupt we will try sending from it. - */ - dev = move_dev_to_next(card,dev); - break; - }else{ - /* Tx buffers not available, but device set - * the TX interrupt. Set more_to_tx and try - * to transmit for other devices. - */ - more_to_tx=1; - dev = move_dev_to_next(card,dev); - } - - }else{ - /* This device was not set to transmit, - * go to next - */ - dev = move_dev_to_next(card,dev); - } - - if (++i == card->u.x.no_dev){ - if (!more_to_tx){ - DBG_PRINTK(KERN_INFO "%s: Nothing to Send in TX INTR\n", - card->devname); - } - break; - } - - } //End of FOR - - card->u.x.tx_dev = dev; - - if (!more_to_tx){ - /* if any other interfaces have transmit interrupts pending, */ - /* do not disable the global transmit interrupt */ - if (!(--card->u.x.tx_interrupts_pending)){ - status->imask &= ~INTR_ON_TX_FRAME; - } - } - return; -} - -/*=============================================================== - * move_dev_to_next - * - * - *===============================================================*/ - - -struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev) -{ - if (card->u.x.no_dev != 1){ - if (!*((struct net_device **)dev->priv)) - return card->wandev.dev; - else - return *((struct net_device **)dev->priv); - } - return dev; -} - -/*=============================================================== - * tx_intr_send - * - * - *===============================================================*/ - -static int tx_intr_send(sdla_t *card, struct net_device *dev) -{ - x25_channel_t* chan = dev->priv; - - if (chan_send (dev,chan->transmit_buffer,chan->transmit_length,1)){ - - /* Packet was split up due to its size, do not disable - * tx_intr - */ - return 1; - } - - chan->transmit_length=0; - atomic_set(&chan->common.driver_busy,0); - chan->tx_offset=0; - - /* If we are in API mode, wakeup the - * sock BH handler, not the NET_BH */ - if (netif_queue_stopped(dev)){ - if (chan->common.usedby == API){ - netif_start_queue(dev); - wakeup_sk_bh(dev); - }else{ - netif_wake_queue(dev); - } - } - return 0; -} - - -/*=============================================================== - * timer_intr - * - * Timer interrupt handler. - * Check who called the timer interrupt and perform - * action accordingly. - * - *===============================================================*/ - -static void timer_intr (sdla_t *card) -{ - TX25Status* status = card->flags; - - if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC){ - - if (timer_intr_cmd_exec(card) == 0){ - card->u.x.timer_int_enabled &= - ~TMR_INT_ENABLED_CMD_EXEC; - } - - }else if(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UDP_PKT) { - - if ((*card->u.x.hdlc_buf_status & 0x40) && - card->u.x.udp_type == UDP_XPIPE_TYPE){ - - if(process_udp_mgmt_pkt(card)) { - card->u.x.timer_int_enabled &= - ~TMR_INT_ENABLED_UDP_PKT; - } - } - - }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_ACTIVE) { - - struct net_device *dev = card->u.x.poll_device; - x25_channel_t *chan = NULL; - - if (!dev){ - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; - return; - } - chan = dev->priv; - - printk(KERN_INFO - "%s: Closing down Idle link %s on LCN %d\n", - card->devname,chan->name,chan->common.lcn); - chan->i_timeout_sofar = jiffies; - chan_disc(dev); - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; - card->u.x.poll_device=NULL; - - }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_ON) { - - wanpipe_set_state(card, WAN_CONNECTED); - if (card->u.x.LAPB_hdlc){ - struct net_device *dev = card->wandev.dev; - set_chan_state(dev,WAN_CONNECTED); - send_delayed_cmd_result(card,dev,card->mbox); - } - - /* 0x8F enable all interrupts */ - x25_set_intr_mode(card, INTR_ON_RX_FRAME| - INTR_ON_TX_FRAME| - INTR_ON_MODEM_STATUS_CHANGE| - //INTR_ON_COMMAND_COMPLETE| - X25_ASY_TRANS_INTR_PENDING | - INTR_ON_TIMER | - DIRECT_RX_INTR_USAGE - ); - - status->imask &= ~INTR_ON_TX_FRAME; /* mask Tx interrupts */ - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_ON; - - }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_OFF) { - - //printk(KERN_INFO "Poll connect, Turning OFF\n"); - disconnect(card); - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_OFF; - - }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_DISCONNECT) { - - //printk(KERN_INFO "POll disconnect, trying to connect\n"); - connect(card); - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_DISCONNECT; - - }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE){ - - if (*card->u.x.hdlc_buf_status & 0x40){ - x25_get_err_stats(card); - x25_get_stats(card); - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; - } - } - - if(!card->u.x.timer_int_enabled){ - //printk(KERN_INFO "Turning Timer Off \n"); - status->imask &= ~INTR_ON_TIMER; - } -} - -/*==================================================================== - * Modem status interrupt handler. - *===================================================================*/ -static void status_intr (sdla_t* card) -{ - - /* Added to avoid Modem status message flooding */ - static TX25ModemStatus last_stat; - - TX25Mbox* mbox = card->mbox; - TX25ModemStatus *modem_status; - struct net_device *dev; - x25_channel_t *chan; - int err; - - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_READ_MODEM_STATUS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err){ - x25_error(card, err, X25_READ_MODEM_STATUS, 0); - }else{ - - modem_status = (TX25ModemStatus*)mbox->data; - - /* Check if the last status was the same - * if it was, do NOT print message again */ - - if (last_stat.status != modem_status->status){ - - printk(KERN_INFO "%s: Modem Status Change: DCD=%s, CTS=%s\n", - card->devname,DCD(modem_status->status),CTS(modem_status->status)); - - last_stat.status = modem_status->status; - - if (card->u.x.oob_on_modem){ - - mbox->cmd.pktType = mbox->cmd.command; - mbox->cmd.result = 0x08; - - /* Send a OOB to all connected sockets */ - for (dev = card->wandev.dev; dev; - dev = *((struct net_device**)dev->priv)) { - chan=dev->priv; - if (chan->common.usedby == API){ - send_oob_msg(card,dev,mbox); - } - } - - /* The modem OOB message will probably kill the - * the link. If we don't clear the flag here, - * a deadlock could occur */ - if (atomic_read(&card->u.x.command_busy)){ - atomic_set(&card->u.x.command_busy,0); - } - } - } - } - - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_LINK_STATUS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err){ - x25_error(card, err, X25_HDLC_LINK_STATUS, 0); - } - -} - -/*==================================================================== - * Network event interrupt handler. - *===================================================================*/ -static void event_intr (sdla_t* card) -{ - x25_fetch_events(card); -} - -/*==================================================================== - * Spurious interrupt handler. - * o print a warning - * o - *====================================================================*/ - -static void spur_intr (sdla_t* card) -{ - printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); -} - - -/* - * Background Polling Routines - */ - -/*==================================================================== - * Main polling routine. - * This routine is repeatedly called by the WANPIPE 'thread' to allow for - * time-dependent housekeeping work. - * - * Notes: - * 1. This routine may be called on interrupt context with all interrupts - * enabled. Beware! - *====================================================================*/ - -static void wpx_poll (sdla_t *card) -{ - if (!card->wandev.dev){ - goto wpx_poll_exit; - } - - if (card->open_cnt != card->u.x.num_of_ch){ - goto wpx_poll_exit; - } - - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - goto wpx_poll_exit; - } - - if (test_bit(SEND_CRIT,&card->wandev.critical)){ - goto wpx_poll_exit; - } - - switch(card->wandev.state){ - case WAN_CONNECTED: - poll_active(card); - break; - - case WAN_CONNECTING: - poll_connecting(card); - break; - - case WAN_DISCONNECTED: - poll_disconnected(card); - break; - } - -wpx_poll_exit: - clear_bit(POLL_CRIT,&card->wandev.critical); - return; -} - -static void trigger_x25_poll(sdla_t *card) -{ - schedule_work(&card->u.x.x25_poll_work); -} - -/*==================================================================== - * Handle physical link establishment phase. - * o if connection timed out, disconnect the link. - *===================================================================*/ - -static void poll_connecting (sdla_t* card) -{ - volatile TX25Status* status = card->flags; - - if (status->gflags & X25_HDLC_ABM){ - - timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_ON); - - }else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT){ - - timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_OFF); - - } -} - -/*==================================================================== - * Handle physical link disconnected phase. - * o if hold-down timeout has expired and there are open interfaces, - * connect link. - *===================================================================*/ - -static void poll_disconnected (sdla_t* card) -{ - struct net_device *dev; - x25_channel_t *chan; - TX25Status* status = card->flags; - - if (!card->u.x.LAPB_hdlc && card->open_cnt && - ((jiffies - card->state_tick) > HOLD_DOWN_TIME)){ - timer_intr_exec(card, TMR_INT_ENABLED_POLL_DISCONNECT); - } - - - if ((dev=card->wandev.dev) == NULL) - return; - - if ((chan=dev->priv) == NULL) - return; - - if (chan->common.usedby == API && - atomic_read(&chan->common.command) && - card->u.x.LAPB_hdlc){ - - if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) - card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; - - if (!(status->imask & INTR_ON_TIMER)) - status->imask |= INTR_ON_TIMER; - } - -} - -/*==================================================================== - * Handle active link phase. - * o fetch X.25 asynchronous events. - * o kick off transmission on all interfaces. - *===================================================================*/ - -static void poll_active (sdla_t* card) -{ - struct net_device* dev; - TX25Status* status = card->flags; - - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)){ - x25_channel_t* chan = dev->priv; - - /* If SVC has been idle long enough, close virtual circuit */ - if ( chan->common.svc && - chan->common.state == WAN_CONNECTED && - chan->common.usedby == WANPIPE ){ - - if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout ){ - /* Close svc */ - card->u.x.poll_device=dev; - timer_intr_exec (card, TMR_INT_ENABLED_POLL_ACTIVE); - } - } - -#ifdef PRINT_DEBUG - chan->ifstats.tx_compressed = atomic_read(&chan->common.command); - chan->ifstats.tx_errors = chan->common.state; - chan->ifstats.rx_fifo_errors = atomic_read(&card->u.x.command_busy); - ++chan->ifstats.tx_bytes; - - chan->ifstats.rx_fifo_errors=atomic_read(&chan->common.disconnect); - chan->ifstats.multicast=atomic_read(&chan->bh_buff_used); - chan->ifstats.rx_length_errors=*card->u.x.hdlc_buf_status; -#endif - - if (chan->common.usedby == API && - atomic_read(&chan->common.command) && - !card->u.x.LAPB_hdlc){ - - if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) - card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; - - if (!(status->imask & INTR_ON_TIMER)) - status->imask |= INTR_ON_TIMER; - } - - if ((chan->common.usedby == API) && - atomic_read(&chan->common.disconnect)){ - - if (chan->common.state == WAN_DISCONNECTED){ - atomic_set(&chan->common.disconnect,0); - return; - } - - atomic_set(&chan->common.command,X25_CLEAR_CALL); - if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) - card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; - - if (!(status->imask & INTR_ON_TIMER)) - status->imask |= INTR_ON_TIMER; - } - } -} - -static void timer_intr_exec(sdla_t *card, unsigned char TYPE) -{ - TX25Status* status = card->flags; - card->u.x.timer_int_enabled |= TYPE; - if (!(status->imask & INTR_ON_TIMER)) - status->imask |= INTR_ON_TIMER; -} - - -/*==================================================================== - * SDLA Firmware-Specific Functions - * - * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 - * asynchronous events' such as restart, interrupt, incoming call request, - * call clear request, etc. They can't be ignored and have to be delt with - * immediately. To tackle with this problem we execute each interface - * command in a loop until good return code is received or maximum number - * of retries is reached. Each interface command returns non-zero return - * code, an asynchronous event/error handler x25_error() is called. - *====================================================================*/ - -/*==================================================================== - * Read X.25 firmware version. - * Put code version as ASCII string in str. - *===================================================================*/ - -static int x25_get_version (sdla_t* card, char* str) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_READ_CODE_VERSION; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && - x25_error(card, err, X25_READ_CODE_VERSION, 0)); - - if (!err && str) - { - int len = mbox->cmd.length; - - memcpy(str, mbox->data, len); - str[len] = '\0'; - } - return err; -} - -/*==================================================================== - * Configure adapter. - *===================================================================*/ - -static int x25_configure (sdla_t* card, TX25Config* conf) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do{ - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); - mbox->cmd.length = sizeof(TX25Config); - mbox->cmd.command = X25_SET_CONFIGURATION; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0)); - return err; -} - -/*==================================================================== - * Configure adapter for HDLC only. - *===================================================================*/ - -static int hdlc_configure (sdla_t* card, TX25Config* conf) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do{ - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); - mbox->cmd.length = sizeof(TX25Config); - mbox->cmd.command = X25_HDLC_SET_CONFIG; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0)); - - return err; -} - -static int set_hdlc_level (sdla_t* card) -{ - - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do{ - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = SET_PROTOCOL_LEVEL; - mbox->cmd.length = 1; - mbox->data[0] = HDLC_LEVEL; //| DO_HDLC_LEVEL_ERROR_CHECKING; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, SET_PROTOCOL_LEVEL, 0)); - - return err; -} - - - -/*==================================================================== - * Get communications error statistics. - *====================================================================*/ - -static int x25_get_err_stats (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_READ_COMM_ERR; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0)); - - if (!err) - { - THdlcCommErr* stats = (void*)mbox->data; - - card->wandev.stats.rx_over_errors = stats->rxOverrun; - card->wandev.stats.rx_crc_errors = stats->rxBadCrc; - card->wandev.stats.rx_missed_errors = stats->rxAborted; - card->wandev.stats.tx_aborted_errors = stats->txAborted; - } - return err; -} - -/*==================================================================== - * Get protocol statistics. - *===================================================================*/ - -static int x25_get_stats (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_READ_STATISTICS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)) ; - - if (!err) - { - TX25Stats* stats = (void*)mbox->data; - - card->wandev.stats.rx_packets = stats->rxData; - card->wandev.stats.tx_packets = stats->txData; - } - return err; -} - -/*==================================================================== - * Close HDLC link. - *===================================================================*/ - -static int x25_close_hdlc (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_LINK_CLOSE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0)); - - return err; -} - - -/*==================================================================== - * Open HDLC link. - *===================================================================*/ - -static int x25_open_hdlc (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_LINK_OPEN; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0)); - - return err; -} - -/*===================================================================== - * Setup HDLC link. - *====================================================================*/ -static int x25_setup_hdlc (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_LINK_SETUP; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_SETUP, 0)); - - return err; -} - -/*==================================================================== - * Set (raise/drop) DTR. - *===================================================================*/ - -static int x25_set_dtr (sdla_t* card, int dtr) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->data[0] = 0; - mbox->data[2] = 0; - mbox->data[1] = dtr ? 0x02 : 0x01; - mbox->cmd.length = 3; - mbox->cmd.command = X25_SET_GLOBAL_VARS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0)); - - return err; -} - -/*==================================================================== - * Set interrupt mode. - *===================================================================*/ - -static int x25_set_intr_mode (sdla_t* card, int mode) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->data[0] = mode; - if (card->hw.fwid == SFID_X25_508){ - mbox->data[1] = card->hw.irq; - mbox->data[2] = 2; - mbox->cmd.length = 3; - }else { - mbox->cmd.length = 1; - } - mbox->cmd.command = X25_SET_INTERRUPT_MODE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)); - - return err; -} - -/*==================================================================== - * Read X.25 channel configuration. - *===================================================================*/ - -static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int lcn = chan->common.lcn; - int err; - - do{ - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.lcn = lcn; - mbox->cmd.command = X25_READ_CHANNEL_CONFIG; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn)); - - if (!err) - { - TX25Status* status = card->flags; - - /* calculate an offset into the array of status bytes */ - if (card->u.x.hi_svc <= X25_MAX_CHAN){ - - chan->ch_idx = lcn - 1; - - }else{ - int offset; - - /* FIX: Apr 14 2000 : Nenad Corbic - * The data field was being compared to 0x1F using - * '&&' instead of '&'. - * This caused X25API to fail for LCNs greater than 255. - */ - switch (mbox->data[0] & 0x1F) - { - case 0x01: - offset = status->pvc_map; break; - case 0x03: - offset = status->icc_map; break; - case 0x07: - offset = status->twc_map; break; - case 0x0B: - offset = status->ogc_map; break; - default: - offset = 0; - } - chan->ch_idx = lcn - 1 - offset; - } - - /* get actual transmit packet size on this channel */ - switch(mbox->data[1] & 0x38) - { - case 0x00: - chan->tx_pkt_size = 16; - break; - case 0x08: - chan->tx_pkt_size = 32; - break; - case 0x10: - chan->tx_pkt_size = 64; - break; - case 0x18: - chan->tx_pkt_size = 128; - break; - case 0x20: - chan->tx_pkt_size = 256; - break; - case 0x28: - chan->tx_pkt_size = 512; - break; - case 0x30: - chan->tx_pkt_size = 1024; - break; - } - if (card->u.x.logging) - printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n", - card->devname, lcn, chan->tx_pkt_size); - } - return err; -} - -/*==================================================================== - * Place X.25 call. - *====================================================================*/ - -static int x25_place_call (sdla_t* card, x25_channel_t* chan) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - char str[64]; - - - if (chan->protocol == htons(ETH_P_IP)){ - sprintf(str, "-d%s -uCC", chan->addr); - - }else if (chan->protocol == htons(ETH_P_IPX)){ - sprintf(str, "-d%s -u800000008137", chan->addr); - - } - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - strcpy(mbox->data, str); - mbox->cmd.length = strlen(str); - mbox->cmd.command = X25_PLACE_CALL; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_PLACE_CALL, 0)); - - if (!err){ - bind_lcn_to_dev (card, chan->dev, mbox->cmd.lcn); - } - return err; -} - -/*==================================================================== - * Accept X.25 call. - *====================================================================*/ - -static int x25_accept_call (sdla_t* card, int lcn, int qdm) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.lcn = lcn; - mbox->cmd.qdm = qdm; - mbox->cmd.command = X25_ACCEPT_CALL; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_ACCEPT_CALL, lcn)); - - return err; -} - -/*==================================================================== - * Clear X.25 call. - *====================================================================*/ - -static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.lcn = lcn; - mbox->cmd.cause = cause; - mbox->cmd.diagn = diagn; - mbox->cmd.command = X25_CLEAR_CALL; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_CLEAR_CALL, lcn)); - - return err; -} - -/*==================================================================== - * Send X.25 data packet. - *====================================================================*/ - -static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - unsigned char cmd; - - if (card->u.x.LAPB_hdlc) - cmd = X25_HDLC_WRITE; - else - cmd = X25_WRITE; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - memcpy(mbox->data, buf, len); - mbox->cmd.length = len; - mbox->cmd.lcn = lcn; - - if (card->u.x.LAPB_hdlc){ - mbox->cmd.pf = qdm; - }else{ - mbox->cmd.qdm = qdm; - } - - mbox->cmd.command = cmd; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, cmd , lcn)); - - - /* If buffers are busy the return code for LAPB HDLC is - * 1. The above functions are looking for return code - * of X25RES_NOT_READY if busy. */ - - if (card->u.x.LAPB_hdlc && err == 1){ - err = X25RES_NOT_READY; - } - - return err; -} - -/*==================================================================== - * Fetch X.25 asynchronous events. - *===================================================================*/ - -static int x25_fetch_events (sdla_t* card) -{ - TX25Status* status = card->flags; - TX25Mbox* mbox = card->mbox; - int err = 0; - - if (status->gflags & 0x20) - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_IS_DATA_AVAILABLE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); - } - return err; -} - -/*==================================================================== - * X.25 asynchronous event/error handler. - * This routine is called each time interface command returns - * non-zero return code to handle X.25 asynchronous events and - * common errors. Return non-zero to repeat command or zero to - * cancel it. - * - * Notes: - * 1. This function may be called recursively, as handling some of the - * asynchronous events (e.g. call request) requires execution of the - * interface command(s) that, in turn, may also return asynchronous - * events. To avoid re-entrancy problems we copy mailbox to dynamically - * allocated memory before processing events. - *====================================================================*/ - -static int x25_error (sdla_t* card, int err, int cmd, int lcn) -{ - int retry = 1; - unsigned dlen = ((TX25Mbox*)card->mbox)->cmd.length; - TX25Mbox* mb; - - mb = kmalloc(sizeof(TX25Mbox) + dlen, GFP_ATOMIC); - if (mb == NULL) - { - printk(KERN_ERR "%s: x25_error() out of memory!\n", - card->devname); - return 0; - } - memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen); - switch (err){ - - case X25RES_ASYNC_PACKET: /* X.25 asynchronous packet was received */ - - mb->data[dlen] = '\0'; - - switch (mb->cmd.pktType & 0x7F){ - - case ASE_CALL_RQST: /* incoming call */ - retry = incoming_call(card, cmd, lcn, mb); - break; - - case ASE_CALL_ACCEPTED: /* connected */ - retry = call_accepted(card, cmd, lcn, mb); - break; - - case ASE_CLEAR_RQST: /* call clear request */ - retry = call_cleared(card, cmd, lcn, mb); - break; - - case ASE_RESET_RQST: /* reset request */ - printk(KERN_INFO "%s: X.25 reset request on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, mb->cmd.cause, - mb->cmd.diagn); - api_oob_event (card,mb); - break; - - case ASE_RESTART_RQST: /* restart request */ - retry = restart_event(card, cmd, lcn, mb); - break; - - case ASE_CLEAR_CONFRM: - if (clear_confirm_event (card,mb)) - break; - - /* I use the goto statement here so if - * somebody inserts code between the - * case and default, we will not have - * ghost problems */ - - goto dflt_1; - - default: -dflt_1: - printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.pktType, - mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn); - } - break; - - case X25RES_PROTO_VIOLATION: /* X.25 protocol violation indication */ - - /* Bug Fix: Mar 14 2000 - * The Protocol violation error conditions were - * not handled previously */ - - switch (mb->cmd.pktType & 0x7F){ - - case PVE_CLEAR_RQST: /* Clear request */ - retry = call_cleared(card, cmd, lcn, mb); - break; - - case PVE_RESET_RQST: /* Reset request */ - printk(KERN_INFO "%s: X.25 reset request on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, mb->cmd.cause, - mb->cmd.diagn); - api_oob_event (card,mb); - break; - - case PVE_RESTART_RQST: /* Restart request */ - retry = restart_event(card, cmd, lcn, mb); - break; - - default : - printk(KERN_INFO - "%s: X.25 protocol violation on LCN %d! " - "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, - mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn); - api_oob_event(card,mb); - } - break; - - case 0x42: /* X.25 timeout */ - retry = timeout_event(card, cmd, lcn, mb); - break; - - case 0x43: /* X.25 retry limit exceeded */ - printk(KERN_INFO - "%s: exceeded X.25 retry limit on LCN %d! " - "Packet:0x%02X Diagn:0x%02X\n", card->devname, - mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn) - ; - break; - - case 0x08: /* modem failure */ -#ifndef MODEM_NOT_LOG - printk(KERN_INFO "%s: modem failure!\n", card->devname); -#endif /* MODEM_NOT_LOG */ - api_oob_event(card,mb); - break; - - case 0x09: /* N2 retry limit */ - printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", - card->devname); - api_oob_event(card,mb); - break; - - case 0x06: /* unnumbered frame was received while in ABM */ - printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", - card->devname, mb->data[0]); - api_oob_event(card,mb); - break; - - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd) - ; - retry = 0; /* abort command */ - break; - - case X25RES_NOT_READY: - retry = 1; - break; - - case 0x01: - if (card->u.x.LAPB_hdlc) - break; - - if (mb->cmd.command == 0x16) - break; - /* I use the goto statement here so if - * somebody inserts code between the - * case and default, we will not have - * ghost problems */ - goto dflt_2; - - default: -dflt_2: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X! Lcn %i\n", - card->devname, cmd, err, mb->cmd.lcn) - ; - retry = 0; /* abort command */ - } - kfree(mb); - return retry; -} - -/*==================================================================== - * X.25 Asynchronous Event Handlers - * These functions are called by the x25_error() and should return 0, if - * the command resulting in the asynchronous event must be aborted. - *====================================================================*/ - - - -/*==================================================================== - *Handle X.25 incoming call request. - * RFC 1356 establishes the following rules: - * 1. The first octet in the Call User Data (CUD) field of the call - * request packet contains NLPID identifying protocol encapsulation - * 2. Calls MUST NOT be accepted unless router supports requested - * protocol encapsulation. - * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used - * when clearing a call because protocol encapsulation is not - * supported. - * 4. If an incoming call is received while a call request is - * pending (i.e. call collision has occurred), the incoming call - * shall be rejected and call request shall be retried. - *====================================================================*/ - -static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - struct wan_device* wandev = &card->wandev; - int new_lcn = mb->cmd.lcn; - struct net_device* dev = get_dev_by_lcn(wandev, new_lcn); - x25_channel_t* chan = NULL; - int accept = 0; /* set to '1' if o.k. to accept call */ - unsigned int user_data; - x25_call_info_t* info; - - /* Make sure there is no call collision */ - if (dev != NULL) - { - printk(KERN_INFO - "%s: X.25 incoming call collision on LCN %d!\n", - card->devname, new_lcn); - - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } - - /* Make sure D bit is not set in call request */ -//FIXME: THIS IS NOT TURE !!!! TAKE IT OUT -// if (mb->cmd.qdm & 0x02) -// { -// printk(KERN_INFO -// "%s: X.25 incoming call on LCN %d with D-bit set!\n", -// card->devname, new_lcn); -// -// x25_clear_call(card, new_lcn, 0, 0); -// return 1; -// } - - /* Parse call request data */ - info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC); - if (info == NULL) - { - printk(KERN_ERR - "%s: not enough memory to parse X.25 incoming call " - "on LCN %d!\n", card->devname, new_lcn); - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } - - parse_call_info(mb->data, info); - - if (card->u.x.logging) - printk(KERN_INFO "\n%s: X.25 incoming call on LCN %d!\n", - card->devname, new_lcn); - - /* Conver the first two ASCII characters into an - * interger. Used to check the incoming protocol - */ - user_data = hex_to_uint(info->user,2); - - /* Find available channel */ - for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) { - chan = dev->priv; - - if (chan->common.usedby == API) - continue; - - if (!chan->common.svc || (chan->common.state != WAN_DISCONNECTED)) - continue; - - if (user_data == NLPID_IP && chan->protocol != htons(ETH_P_IP)){ - printk(KERN_INFO "IP packet but configured for IPX : %x, %x\n", - htons(chan->protocol), info->user[0]); - continue; - } - - if (user_data == NLPID_SNAP && chan->protocol != htons(ETH_P_IPX)){ - printk(KERN_INFO "IPX packet but configured for IP: %x\n", - htons(chan->protocol)); - continue; - } - if (strcmp(info->src, chan->addr) == 0) - break; - - /* If just an '@' is specified, accept all incoming calls */ - if (strcmp(chan->addr, "") == 0) - break; - } - - if (dev == NULL){ - - /* If the call is not for any WANPIPE interfaces - * check to see if there is an API listening queue - * waiting for data. If there is send the packet - * up the stack. - */ - if (card->sk != NULL && card->func != NULL){ - if (api_incoming_call(card,mb,new_lcn)){ - x25_clear_call(card, new_lcn, 0, 0); - } - accept = 0; - }else{ - printk(KERN_INFO "%s: no channels available!\n", - card->devname); - - x25_clear_call(card, new_lcn, 0, 0); - } - - }else if (info->nuser == 0){ - - printk(KERN_INFO - "%s: no user data in incoming call on LCN %d!\n", - card->devname, new_lcn) - ; - x25_clear_call(card, new_lcn, 0, 0); - - }else switch (info->user[0]){ - - case 0: /* multiplexed */ - chan->protocol = htons(0); - accept = 1; - break; - - case NLPID_IP: /* IP datagrams */ - accept = 1; - break; - - case NLPID_SNAP: /* IPX datagrams */ - accept = 1; - break; - - default: - printk(KERN_INFO - "%s: unsupported NLPID 0x%02X in incoming call " - "on LCN %d!\n", card->devname, info->user[0], new_lcn); - x25_clear_call(card, new_lcn, 0, 249); - } - - if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK)){ - - bind_lcn_to_dev (card, chan->dev, new_lcn); - - if (x25_get_chan_conf(card, chan) == CMD_OK) - set_chan_state(dev, WAN_CONNECTED); - else - x25_clear_call(card, new_lcn, 0, 0); - } - kfree(info); - return 1; -} - -/*==================================================================== - * Handle accepted call. - *====================================================================*/ - -static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - unsigned new_lcn = mb->cmd.lcn; - struct net_device* dev = find_channel(card, new_lcn); - x25_channel_t* chan; - - if (dev == NULL){ - printk(KERN_INFO - "%s: clearing orphaned connection on LCN %d!\n", - card->devname, new_lcn); - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } - - if (card->u.x.logging) - printk(KERN_INFO "%s: X.25 call accepted on Dev %s and LCN %d!\n", - card->devname, dev->name, new_lcn); - - /* Get channel configuration and notify router */ - chan = dev->priv; - if (x25_get_chan_conf(card, chan) != CMD_OK) - { - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } - - set_chan_state(dev, WAN_CONNECTED); - - if (chan->common.usedby == API){ - send_delayed_cmd_result(card,dev,mb); - bind_lcn_to_dev (card, dev, new_lcn); - } - - return 1; -} - -/*==================================================================== - * Handle cleared call. - *====================================================================*/ - -static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - unsigned new_lcn = mb->cmd.lcn; - struct net_device* dev = find_channel(card, new_lcn); - x25_channel_t *chan; - unsigned char old_state; - - if (card->u.x.logging){ - printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X " - "Diagn:0x%02X\n", - card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn); - } - - if (dev == NULL){ - printk(KERN_INFO "%s: X.25 clear request : No device for clear\n", - card->devname); - return 1; - } - - chan=dev->priv; - - old_state = chan->common.state; - - set_chan_state(dev, WAN_DISCONNECTED); - - if (chan->common.usedby == API){ - - switch (old_state){ - - case WAN_CONNECTING: - send_delayed_cmd_result(card,dev,mb); - break; - case WAN_CONNECTED: - send_oob_msg(card,dev,mb); - break; - } - } - - return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1; -} - -/*==================================================================== - * Handle X.25 restart event. - *====================================================================*/ - -static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - struct wan_device* wandev = &card->wandev; - struct net_device* dev; - x25_channel_t *chan; - unsigned char old_state; - - printk(KERN_INFO - "%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.cause, mb->cmd.diagn); - - /* down all logical channels */ - for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) { - chan=dev->priv; - old_state = chan->common.state; - - set_chan_state(dev, WAN_DISCONNECTED); - - if (chan->common.usedby == API){ - switch (old_state){ - - case WAN_CONNECTING: - send_delayed_cmd_result(card,dev,mb); - break; - case WAN_CONNECTED: - send_oob_msg(card,dev,mb); - break; - } - } - } - return (cmd == X25_WRITE) ? 0 : 1; -} - -/*==================================================================== - * Handle timeout event. - *====================================================================*/ - -static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - unsigned new_lcn = mb->cmd.lcn; - - if (mb->cmd.pktType == 0x05) /* call request time out */ - { - struct net_device* dev = find_channel(card,new_lcn); - - printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n", - card->devname, new_lcn); - - if (dev){ - x25_channel_t *chan = dev->priv; - set_chan_state(dev, WAN_DISCONNECTED); - - if (chan->common.usedby == API){ - send_delayed_cmd_result(card,dev,card->mbox); - } - } - }else{ - printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", - card->devname, mb->cmd.pktType, new_lcn); - } - return 1; -} - -/* - * Miscellaneous - */ - -/*==================================================================== - * Establish physical connection. - * o open HDLC and raise DTR - * - * Return: 0 connection established - * 1 connection is in progress - * <0 error - *===================================================================*/ - -static int connect (sdla_t* card) -{ - TX25Status* status = card->flags; - - if (x25_open_hdlc(card) || x25_setup_hdlc(card)) - return -EIO; - - wanpipe_set_state(card, WAN_CONNECTING); - - x25_set_intr_mode(card, INTR_ON_TIMER); - status->imask &= ~INTR_ON_TIMER; - - return 1; -} - -/* - * Tear down physical connection. - * o close HDLC link - * o drop DTR - * - * Return: 0 - * <0 error - */ - -static int disconnect (sdla_t* card) -{ - wanpipe_set_state(card, WAN_DISCONNECTED); - x25_set_intr_mode(card, INTR_ON_TIMER); /* disable all interrupt except timer */ - x25_close_hdlc(card); /* close HDLC link */ - x25_set_dtr(card, 0); /* drop DTR */ - return 0; -} - -/* - * Find network device by its channel number. - */ - -static struct net_device* get_dev_by_lcn(struct wan_device* wandev, - unsigned lcn) -{ - struct net_device* dev; - - for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) - if (((x25_channel_t*)dev->priv)->common.lcn == lcn) - break; - return dev; -} - -/* - * Initiate connection on the logical channel. - * o for PVC we just get channel configuration - * o for SVCs place an X.25 call - * - * Return: 0 connected - * >0 connection in progress - * <0 failure - */ - -static int chan_connect(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - if (chan->common.svc && chan->common.usedby == WANPIPE){ - if (!chan->addr[0]){ - printk(KERN_INFO "%s: No Destination Address\n", - card->devname); - return -EINVAL; /* no destination address */ - } - printk(KERN_INFO "%s: placing X.25 call to %s ...\n", - card->devname, chan->addr); - - if (x25_place_call(card, chan) != CMD_OK) - return -EIO; - - set_chan_state(dev, WAN_CONNECTING); - return 1; - }else{ - if (x25_get_chan_conf(card, chan) != CMD_OK) - return -EIO; - - set_chan_state(dev, WAN_CONNECTED); - } - return 0; -} - -/* - * Disconnect logical channel. - * o if SVC then clear X.25 call - */ - -static int chan_disc(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - - if (chan->common.svc){ - x25_clear_call(chan->card, chan->common.lcn, 0, 0); - - /* For API we disconnect on clear - * confirmation. - */ - if (chan->common.usedby == API) - return 0; - } - - set_chan_state(dev, WAN_DISCONNECTED); - - return 0; -} - -/* - * Set logical channel state. - */ - -static void set_chan_state(struct net_device* dev, int state) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - unsigned long flags; - - save_flags(flags); - cli(); - if (chan->common.state != state) - { - switch (state) - { - case WAN_CONNECTED: - if (card->u.x.logging){ - printk (KERN_INFO - "%s: interface %s connected, lcn %i !\n", - card->devname, dev->name,chan->common.lcn); - } - *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); - chan->i_timeout_sofar = jiffies; - - /* LAPB is PVC Based */ - if (card->u.x.LAPB_hdlc) - chan->common.svc=0; - break; - - case WAN_CONNECTING: - if (card->u.x.logging){ - printk (KERN_INFO - "%s: interface %s connecting, lcn %i ...\n", - card->devname, dev->name, chan->common.lcn); - } - break; - - case WAN_DISCONNECTED: - if (card->u.x.logging){ - printk (KERN_INFO - "%s: interface %s disconnected, lcn %i !\n", - card->devname, dev->name,chan->common.lcn); - } - atomic_set(&chan->common.disconnect,0); - - if (chan->common.svc) { - *(unsigned short*)dev->dev_addr = 0; - card->u.x.svc_to_dev_map[(chan->common.lcn%X25_MAX_CHAN)]=NULL; - chan->common.lcn = 0; - } - - if (chan->transmit_length){ - chan->transmit_length=0; - atomic_set(&chan->common.driver_busy,0); - chan->tx_offset=0; - if (netif_queue_stopped(dev)){ - netif_wake_queue(dev); - } - } - atomic_set(&chan->common.command,0); - break; - - case WAN_DISCONNECTING: - if (card->u.x.logging){ - printk (KERN_INFO - "\n%s: interface %s disconnecting, lcn %i ...\n", - card->devname, dev->name,chan->common.lcn); - } - atomic_set(&chan->common.disconnect,0); - break; - } - chan->common.state = state; - } - chan->state_tick = jiffies; - restore_flags(flags); -} - -/* - * Send packet on a logical channel. - * When this function is called, tx_skb field of the channel data - * space points to the transmit socket buffer. When transmission - * is complete, release socket buffer and reset 'tbusy' flag. - * - * Return: 0 - transmission complete - * 1 - busy - * - * Notes: - * 1. If packet length is greater than MTU for this channel, we'll fragment - * the packet into 'complete sequence' using M-bit. - * 2. When transmission is complete, an event notification should be issued - * to the router. - */ - -static int chan_send(struct net_device* dev, void* buff, unsigned data_len, - unsigned char tx_intr) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - TX25Status* status = card->flags; - unsigned len=0, qdm=0, res=0, orig_len = 0; - void *data; - - /* Check to see if channel is ready */ - if ((!(status->cflags[chan->ch_idx] & 0x40) && !card->u.x.LAPB_hdlc) || - !(*card->u.x.hdlc_buf_status & 0x40)){ - - if (!tx_intr){ - setup_for_delayed_transmit (dev, buff, data_len); - return 0; - }else{ - /* By returning 0 to tx_intr the packet will be dropped */ - ++card->wandev.stats.tx_dropped; - ++chan->ifstats.tx_dropped; - printk(KERN_INFO "%s: ERROR, Tx intr could not send, dropping %s:\n", - card->devname,dev->name); - ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; - return 0; - } - } - - if (chan->common.usedby == API){ - /* Remove the API Header */ - x25api_hdr_t *api_data = (x25api_hdr_t *)buff; - - /* Set the qdm bits from the packet header - * User has the option to set the qdm bits - */ - qdm = api_data->qdm; - - orig_len = len = data_len - sizeof(x25api_hdr_t); - data = (unsigned char*)buff + sizeof(x25api_hdr_t); - }else{ - data = buff; - orig_len = len = data_len; - } - - if (tx_intr){ - /* We are in tx_intr, minus the tx_offset from - * the total length. The tx_offset part of the - * data has already been sent. Also, move the - * data pointer to proper offset location. - */ - len -= chan->tx_offset; - data = (unsigned char*)data + chan->tx_offset; - } - - /* Check if the packet length is greater than MTU - * If YES: Cut the len to MTU and set the M bit - */ - if (len > chan->tx_pkt_size && !card->u.x.LAPB_hdlc){ - len = chan->tx_pkt_size; - qdm |= M_BIT; - } - - - /* Pass only first three bits of the qdm byte to the send - * routine. In case user sets any other bit which might - * cause errors. - */ - - switch(x25_send(card, chan->common.lcn, (qdm&0x07), len, data)){ - case 0x00: /* success */ - chan->i_timeout_sofar = jiffies; - - dev->trans_start=jiffies; - - if ((qdm & M_BIT) && !card->u.x.LAPB_hdlc){ - if (!tx_intr){ - /* The M bit was set, which means that part of the - * packet has been sent. Copy the packet into a buffer - * and set the offset to len, so on next tx_inter - * the packet will be sent using the below offset. - */ - chan->tx_offset += len; - - ++chan->ifstats.tx_packets; - chan->ifstats.tx_bytes += len; - - if (chan->tx_offset < orig_len){ - setup_for_delayed_transmit (dev, buff, data_len); - } - res=0; - }else{ - /* We are already in tx_inter, thus data is already - * in the buffer. Update the offset and wait for - * next tx_intr. We add on to the offset, since data can - * be X number of times larger than max data size. - */ - ++chan->ifstats.tx_packets; - chan->ifstats.tx_bytes += len; - - ++chan->if_send_stat.if_send_bfr_passed_to_adptr; - chan->tx_offset += len; - - /* The user can set the qdm bit as well. - * If the entire packet was sent and qdm is still - * set, than it's the user who has set the M bit. In that, - * case indicate that the packet was send by returning - * 0 and wait for a new packet. Otherwise, wait for next - * tx interrupt to send the rest of the packet */ - - if (chan->tx_offset < orig_len){ - res=1; - }else{ - res=0; - } - } - }else{ - ++chan->ifstats.tx_packets; - chan->ifstats.tx_bytes += len; - ++chan->if_send_stat.if_send_bfr_passed_to_adptr; - res=0; - } - break; - - case 0x33: /* Tx busy */ - if (tx_intr){ - printk(KERN_INFO "%s: Tx_intr: Big Error dropping packet %s\n", - card->devname,dev->name); - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; - res=0; - }else{ - DBG_PRINTK(KERN_INFO - "%s: Send: Big Error should have tx: storring %s\n", - card->devname,dev->name); - setup_for_delayed_transmit (dev, buff, data_len); - res=1; - } - break; - - default: /* failure */ - ++chan->ifstats.tx_errors; - if (tx_intr){ - printk(KERN_INFO "%s: Tx_intr: Failure to send, dropping %s\n", - card->devname,dev->name); - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; - res=0; - }else{ - DBG_PRINTK(KERN_INFO "%s: Send: Failure to send !!!, storing %s\n", - card->devname,dev->name); - setup_for_delayed_transmit (dev, buff, data_len); - res=1; - } - break; - } - return res; -} - - -/* - * Parse X.25 call request data and fill x25_call_info_t structure. - */ - -static void parse_call_info (unsigned char* str, x25_call_info_t* info) -{ - memset(info, 0, sizeof(x25_call_info_t)); - for (; *str; ++str) - { - int i; - unsigned char ch; - - if (*str == '-') switch (str[1]) { - - /* Take minus 2 off the maximum size so that - * last byte is 0. This way we can use string - * manipulaton functions on call information. - */ - - case 'd': /* destination address */ - for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ - ch = str[2+i]; - if (isspace(ch)) break; - info->dest[i] = ch; - } - break; - - case 's': /* source address */ - for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ - ch = str[2+i]; - if (isspace(ch)) break; - info->src[i] = ch; - } - break; - - case 'u': /* user data */ - for (i = 0; i < (MAX_X25_DATA_SIZE-2); ++i){ - ch = str[2+i]; - if (isspace(ch)) break; - info->user[i] = ch; - } - info->nuser = i; - break; - - case 'f': /* facilities */ - for (i = 0; i < (MAX_X25_FACL_SIZE-2); ++i){ - ch = str[2+i]; - if (isspace(ch)) break; - info->facil[i] = ch; - } - info->nfacil = i; - break; - } - } -} - -/* - * Convert line speed in bps to a number used by S502 code. - */ - -static unsigned char bps_to_speed_code (unsigned long bps) -{ - unsigned char number; - - if (bps <= 1200) number = 0x01; - else if (bps <= 2400) number = 0x02; - else if (bps <= 4800) number = 0x03; - else if (bps <= 9600) number = 0x04; - else if (bps <= 19200) number = 0x05; - else if (bps <= 38400) number = 0x06; - else if (bps <= 45000) number = 0x07; - else if (bps <= 56000) number = 0x08; - else if (bps <= 64000) number = 0x09; - else if (bps <= 74000) number = 0x0A; - else if (bps <= 112000) number = 0x0B; - else if (bps <= 128000) number = 0x0C; - else number = 0x0D; - - return number; -} - -/* - * Convert decimal string to unsigned integer. - * If len != 0 then only 'len' characters of the string are converted. - */ - -static unsigned int dec_to_uint (unsigned char* str, int len) -{ - unsigned val; - - if (!len) - len = strlen(str); - - for (val = 0; len && isdigit(*str); ++str, --len) - val = (val * 10) + (*str - (unsigned)'0'); - - return val; -} - -/* - * Convert hex string to unsigned integer. - * If len != 0 then only 'len' characters of the string are conferted. - */ - -static unsigned int hex_to_uint (unsigned char* str, int len) -{ - unsigned val, ch; - - if (!len) - len = strlen(str); - - for (val = 0; len; ++str, --len) - { - ch = *str; - if (isdigit(ch)) - val = (val << 4) + (ch - (unsigned)'0'); - else if (isxdigit(ch)) - val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10); - else break; - } - return val; -} - - -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) -{ - int i; - - if( proto == ETH_P_IPX) { - /* It's an IPX packet */ - if(!enable_IPX) { - /* Return 1 so we don't pass it up the stack. */ - return 1; - } - } else { - /* It's not IPX so pass it up the stack.*/ - return 0; - } - - if( sendpacket[16] == 0x90 && - sendpacket[17] == 0x04) - { - /* It's IPXWAN */ - - if( sendpacket[2] == 0x02 && - sendpacket[34] == 0x00) - { - /* It's a timer request packet */ - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); - - /* Go through the routing options and answer no to every - * option except Unnumbered RIP/SAP - */ - for(i = 41; sendpacket[i] == 0x00; i += 5) - { - /* 0x02 is the option for Unnumbered RIP/SAP */ - if( sendpacket[i + 4] != 0x02) - { - sendpacket[i + 1] = 0; - } - } - - /* Skip over the extended Node ID option */ - if( sendpacket[i] == 0x04 ) - { - i += 8; - } - - /* We also want to turn off all header compression opt. */ - for(; sendpacket[i] == 0x80 ;) - { - sendpacket[i + 1] = 0; - i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; - } - - /* Set the packet type to timer response */ - sendpacket[34] = 0x01; - - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); - } - else if( sendpacket[34] == 0x02 ) - { - /* This is an information request packet */ - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); - - /* Set the packet type to information response */ - sendpacket[34] = 0x03; - - /* Set the router name */ - sendpacket[51] = 'X'; - sendpacket[52] = 'T'; - sendpacket[53] = 'P'; - sendpacket[54] = 'I'; - sendpacket[55] = 'P'; - sendpacket[56] = 'E'; - sendpacket[57] = '-'; - sendpacket[58] = CVHexToAscii(network_number >> 28); - sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); - sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); - sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); - sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); - sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); - sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); - sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); - for(i = 66; i < 99; i+= 1) - { - sendpacket[i] = 0; - } - - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); - } - else - { - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); - return 0; - } - - /* Set the WNodeID to our network address */ - sendpacket[35] = (unsigned char)(network_number >> 24); - sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); - sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); - sendpacket[38] = (unsigned char)(network_number & 0x000000FF); - - return 1; - } else { - /*If we get here it's an IPX-data packet, so it'll get passed up the stack. - */ - /* switch the network numbers */ - switch_net_numbers(sendpacket, network_number, 1); - return 0; - } -} - -/* - * If incoming is 0 (outgoing)- if the net numbers is ours make it 0 - * if incoming is 1 - if the net number is 0 make it ours - */ - -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) -{ - unsigned long pnetwork_number; - - pnetwork_number = (unsigned long)((sendpacket[6] << 24) + - (sendpacket[7] << 16) + (sendpacket[8] << 8) + - sendpacket[9]); - - - if (!incoming) { - /*If the destination network number is ours, make it 0 */ - if( pnetwork_number == network_number) { - sendpacket[6] = sendpacket[7] = sendpacket[8] = - sendpacket[9] = 0x00; - } - } else { - /* If the incoming network is 0, make it ours */ - if( pnetwork_number == 0) { - sendpacket[6] = (unsigned char)(network_number >> 24); - sendpacket[7] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[8] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[9] = (unsigned char)(network_number & - 0x000000FF); - } - } - - - pnetwork_number = (unsigned long)((sendpacket[18] << 24) + - (sendpacket[19] << 16) + (sendpacket[20] << 8) + - sendpacket[21]); - - - if( !incoming ) { - /* If the source network is ours, make it 0 */ - if( pnetwork_number == network_number) { - sendpacket[18] = sendpacket[19] = sendpacket[20] = - sendpacket[21] = 0x00; - } - } else { - /* If the source network is 0, make it ours */ - if( pnetwork_number == 0 ) { - sendpacket[18] = (unsigned char)(network_number >> 24); - sendpacket[19] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[20] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[21] = (unsigned char)(network_number & - 0x000000FF); - } - } -} /* switch_net_numbers */ - - - - -/********************* X25API SPECIFIC FUNCTIONS ****************/ - - -/*=============================================================== - * find_channel - * - * Manages the lcn to device map. It increases performance - * because it eliminates the need to search through the link - * list for a device which is bounded to a specific lcn. - * - *===============================================================*/ - - -struct net_device *find_channel(sdla_t *card, unsigned lcn) -{ - if (card->u.x.LAPB_hdlc){ - - return card->wandev.dev; - - }else{ - /* We don't know whether the incoming lcn - * is a PVC or an SVC channel. But we do know that - * the lcn cannot be for both the PVC and the SVC - * channel. - - * If the lcn number is greater or equal to 255, - * take the modulo 255 of that number. We only have - * 255 locations, thus higher numbers must be mapped - * to a number between 0 and 245. - - * We must separate pvc's and svc's since two don't - * have to be contiguous. Meaning pvc's can start - * from 1 to 10 and svc's can start from 256 to 266. - * But 256%255 is 1, i.e. CONFLICT. - */ - - - /* Highest LCN number must be less or equal to 4096 */ - if ((lcn <= MAX_LCN_NUM) && (lcn > 0)){ - - if (lcn < X25_MAX_CHAN){ - if (card->u.x.svc_to_dev_map[lcn]) - return card->u.x.svc_to_dev_map[lcn]; - - if (card->u.x.pvc_to_dev_map[lcn]) - return card->u.x.pvc_to_dev_map[lcn]; - - }else{ - int new_lcn = lcn%X25_MAX_CHAN; - if (card->u.x.svc_to_dev_map[new_lcn]) - return card->u.x.svc_to_dev_map[new_lcn]; - - if (card->u.x.pvc_to_dev_map[new_lcn]) - return card->u.x.pvc_to_dev_map[new_lcn]; - } - } - return NULL; - } -} - -void bind_lcn_to_dev(sdla_t *card, struct net_device *dev, unsigned lcn) -{ - x25_channel_t *chan = dev->priv; - - /* Modulo the lcn number by X25_MAX_CHAN (255) - * because the lcn number can be greater than 255 - * - * We need to split svc and pvc since they don't have - * to be contigous. - */ - - if (chan->common.svc){ - card->u.x.svc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev; - }else{ - card->u.x.pvc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev; - } - chan->common.lcn = lcn; -} - - - -/*=============================================================== - * x25api_bh - * - * - *==============================================================*/ - -static void x25api_bh(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - struct sk_buff *skb; - - if (atomic_read(&chan->bh_buff_used) == 0){ - printk(KERN_INFO "%s: BH Buffer Empty in BH\n", - card->devname); - clear_bit(0, &chan->tq_working); - return; - } - - while (atomic_read(&chan->bh_buff_used)){ - - /* If the sock is in the process of unlinking the - * driver from the socket, we must get out. - * This never happends but is a sanity check. */ - if (test_bit(0,&chan->common.common_critical)){ - clear_bit(0, &chan->tq_working); - return; - } - - /* If LAPB HDLC, do not drop packets if socket is - * not connected. Let the buffer fill up and - * turn off rx interrupt */ - if (card->u.x.LAPB_hdlc){ - if (chan->common.sk == NULL || chan->common.func == NULL){ - clear_bit(0, &chan->tq_working); - return; - } - } - - skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; - - if (skb == NULL){ - printk(KERN_INFO "%s: BH Skb empty for read %i\n", - card->devname,chan->bh_read); - }else{ - - if (chan->common.sk == NULL || chan->common.func == NULL){ - printk(KERN_INFO "%s: BH: Socket disconnected, dropping\n", - card->devname); - dev_kfree_skb_any(skb); - x25api_bh_cleanup(dev); - ++chan->ifstats.rx_dropped; - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - continue; - } - - - if (chan->common.func(skb,dev,chan->common.sk) != 0){ - /* Sock full cannot send, queue us for another - * try - */ - printk(KERN_INFO "%s: BH: !!! Packet failed to send !!!!! \n", - card->devname); - atomic_set(&chan->common.receive_block,1); - return; - }else{ - x25api_bh_cleanup(dev); - ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; - } - } - } - clear_bit(0, &chan->tq_working); - - return; -} - -/*=============================================================== - * x25api_bh_cleanup - * - * - *==============================================================*/ - -static int x25api_bh_cleanup(struct net_device *dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - TX25Status* status = card->flags; - - - ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; - - if (chan->bh_read == MAX_BH_BUFF){ - chan->bh_read=0; - }else{ - ++chan->bh_read; - } - - /* If the Receive interrupt was off, it means - * that we filled up our circular buffer. Check - * that we have space in the buffer. If so - * turn the RX interrupt back on. - */ - if (!(status->imask & INTR_ON_RX_FRAME)){ - if (atomic_read(&chan->bh_buff_used) < (MAX_BH_BUFF+1)){ - printk(KERN_INFO "%s: BH: Turning on the interrupt\n", - card->devname); - status->imask |= INTR_ON_RX_FRAME; - } - } - - atomic_dec(&chan->bh_buff_used); - return 0; -} - - -/*=============================================================== - * bh_enqueue - * - * - *==============================================================*/ - -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb) -{ - x25_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - TX25Status* status = card->flags; - - if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ - printk(KERN_INFO "%s: Bottom half buffer FULL\n", - card->devname); - return 1; - } - - ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; - - if (chan->bh_write == MAX_BH_BUFF){ - chan->bh_write=0; - }else{ - ++chan->bh_write; - } - - atomic_inc(&chan->bh_buff_used); - - if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ - printk(KERN_INFO "%s: Buffer is now full, Turning off RX Intr\n", - card->devname); - status->imask &= ~INTR_ON_RX_FRAME; - } - - return 0; -} - - -/*=============================================================== - * timer_intr_cmd_exec - * - * Called by timer interrupt to execute a command - *===============================================================*/ - -static int timer_intr_cmd_exec (sdla_t* card) -{ - struct net_device *dev; - unsigned char more_to_exec=0; - volatile x25_channel_t *chan=NULL; - int i=0,bad_cmd=0,err=0; - - if (card->u.x.cmd_dev == NULL){ - card->u.x.cmd_dev = card->wandev.dev; - } - - dev = card->u.x.cmd_dev; - - for (;;){ - - chan = dev->priv; - - if (atomic_read(&chan->common.command)){ - - bad_cmd = check_bad_command(card,dev); - - if ((!chan->common.mbox || atomic_read(&chan->common.disconnect)) && - !bad_cmd){ - - /* Socket has died or exited, We must bring the - * channel down before anybody else tries to - * use it */ - err = channel_disconnect(card,dev); - }else{ - err = execute_delayed_cmd(card, dev, - (mbox_cmd_t*)chan->common.mbox, - bad_cmd); - } - - switch (err){ - - case RETURN_RESULT: - - /* Return the result to the socket without - * delay. NO_WAIT Command */ - atomic_set(&chan->common.command,0); - if (atomic_read(&card->u.x.command_busy)) - atomic_set(&card->u.x.command_busy,0); - - send_delayed_cmd_result(card,dev,card->mbox); - - more_to_exec=0; - break; - case DELAY_RESULT: - - /* Wait for the remote to respond, before - * sending the result up to the socket. - * WAIT command */ - if (atomic_read(&card->u.x.command_busy)) - atomic_set(&card->u.x.command_busy,0); - - atomic_set(&chan->common.command,0); - more_to_exec=0; - break; - default: - - /* If command could not be executed for - * some reason (i.e return code 0x33 busy) - * set the more_to_exec bit which will - * indicate that this command must be exectued - * again during next timer interrupt - */ - more_to_exec=1; - if (atomic_read(&card->u.x.command_busy) == 0) - atomic_set(&card->u.x.command_busy,1); - break; - } - - bad_cmd=0; - - /* If flags is set, there are no hdlc buffers, - * thus, wait for the next pass and try the - * same command again. Otherwise, start searching - * from next device on the next pass. - */ - if (!more_to_exec){ - dev = move_dev_to_next(card,dev); - } - break; - }else{ - /* This device has nothing to execute, - * go to next. - */ - if (atomic_read(&card->u.x.command_busy)) - atomic_set(&card->u.x.command_busy,0); - dev = move_dev_to_next(card,dev); - } - - if (++i == card->u.x.no_dev){ - if (!more_to_exec){ - DBG_PRINTK(KERN_INFO "%s: Nothing to execute in Timer\n", - card->devname); - if (atomic_read(&card->u.x.command_busy)){ - atomic_set(&card->u.x.command_busy,0); - } - } - break; - } - - } //End of FOR - - card->u.x.cmd_dev = dev; - - if (more_to_exec){ - /* If more commands are pending, do not turn off timer - * interrupt */ - return 1; - }else{ - /* No more commands, turn off timer interrupt */ - return 0; - } -} - -/*=============================================================== - * execute_delayed_cmd - * - * Execute an API command which was passed down from the - * sock. Sock is very limited in which commands it can - * execute. Wait and No Wait commands are supported. - * Place Call, Clear Call and Reset wait commands, where - * Accept Call is a no_wait command. - * - *===============================================================*/ - -static int execute_delayed_cmd(sdla_t* card, struct net_device *dev, - mbox_cmd_t *usr_cmd, char bad_cmd) -{ - TX25Mbox* mbox = card->mbox; - int err; - x25_channel_t *chan = dev->priv; - int delay=RETURN_RESULT; - - if (!(*card->u.x.hdlc_buf_status & 0x40) && !bad_cmd){ - return TRY_CMD_AGAIN; - } - - /* This way a command is guaranteed to be executed for - * a specific lcn, the network interface is bound to. */ - usr_cmd->cmd.lcn = chan->common.lcn; - - - /* If channel is pvc, instead of place call - * run x25_channel configuration. If running LAPB HDLC - * enable communications. - */ - if ((!chan->common.svc) && (usr_cmd->cmd.command == X25_PLACE_CALL)){ - - if (card->u.x.LAPB_hdlc){ - DBG_PRINTK(KERN_INFO "LAPB: Connecting\n"); - connect(card); - set_chan_state(dev,WAN_CONNECTING); - return DELAY_RESULT; - }else{ - DBG_PRINTK(KERN_INFO "%s: PVC is CONNECTING\n",card->devname); - if (x25_get_chan_conf(card, chan) == CMD_OK){ - set_chan_state(dev, WAN_CONNECTED); - }else{ - set_chan_state(dev, WAN_DISCONNECTED); - } - return RETURN_RESULT; - } - } - - /* Copy the socket mbox command onto the board */ - - memcpy(&mbox->cmd, &usr_cmd->cmd, sizeof(TX25Cmd)); - if (usr_cmd->cmd.length){ - memcpy(mbox->data, usr_cmd->data, usr_cmd->cmd.length); - } - - /* Check if command is bad. We need to copy the cmd into - * the buffer regardless since we return the, mbox to - * the user */ - if (bad_cmd){ - mbox->cmd.result=0x01; - return RETURN_RESULT; - } - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK && err != X25RES_NOT_READY) - x25_error(card, err, usr_cmd->cmd.command, usr_cmd->cmd.lcn); - - if (mbox->cmd.result == X25RES_NOT_READY){ - return TRY_CMD_AGAIN; - } - - switch (mbox->cmd.command){ - - case X25_PLACE_CALL: - - switch (mbox->cmd.result){ - - case CMD_OK: - - /* Check if Place call is a wait command or a - * no wait command */ - if (atomic_read(&chan->common.command) & 0x80) - delay=RETURN_RESULT; - else - delay=DELAY_RESULT; - - - DBG_PRINTK(KERN_INFO "\n%s: PLACE CALL Binding dev %s to lcn %i\n", - card->devname,dev->name, mbox->cmd.lcn); - - bind_lcn_to_dev (card, dev, mbox->cmd.lcn); - set_chan_state(dev, WAN_CONNECTING); - break; - - - default: - delay=RETURN_RESULT; - set_chan_state(dev, WAN_DISCONNECTED); - break; - } - break; - - case X25_ACCEPT_CALL: - - switch (mbox->cmd.result){ - - case CMD_OK: - - DBG_PRINTK(KERN_INFO "\n%s: ACCEPT Binding dev %s to lcn %i\n", - card->devname,dev->name,mbox->cmd.lcn); - - bind_lcn_to_dev (card, dev, mbox->cmd.lcn); - - if (x25_get_chan_conf(card, chan) == CMD_OK){ - - set_chan_state(dev, WAN_CONNECTED); - delay=RETURN_RESULT; - - }else{ - if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){ - /* if clear is successful, wait for clear confirm - */ - delay=DELAY_RESULT; - }else{ - /* Do not change the state here. If we fail - * the accept the return code is send up - *the stack, which will ether retry - * or clear the call - */ - DBG_PRINTK(KERN_INFO - "%s: ACCEPT: STATE MAY BE CURRUPTED 2 !!!!!\n", - card->devname); - delay=RETURN_RESULT; - } - } - break; - - - case X25RES_ASYNC_PACKET: - delay=TRY_CMD_AGAIN; - break; - - default: - DBG_PRINTK(KERN_INFO "%s: ACCEPT FAILED\n",card->devname); - if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){ - delay=DELAY_RESULT; - }else{ - /* Do not change the state here. If we fail the accept. The - * return code is send up the stack, which will ether retry - * or clear the call */ - DBG_PRINTK(KERN_INFO - "%s: ACCEPT: STATE MAY BE CORRUPTED 1 !!!!!\n", - card->devname); - delay=RETURN_RESULT; - } - } - break; - - case X25_CLEAR_CALL: - - switch (mbox->cmd.result){ - - case CMD_OK: - DBG_PRINTK(KERN_INFO - "CALL CLEAR OK: Dev %s Mbox Lcn %i Chan Lcn %i\n", - dev->name,mbox->cmd.lcn,chan->common.lcn); - set_chan_state(dev, WAN_DISCONNECTING); - delay = DELAY_RESULT; - break; - - case X25RES_CHANNEL_IN_USE: - case X25RES_ASYNC_PACKET: - delay = TRY_CMD_AGAIN; - break; - - case X25RES_LINK_NOT_IN_ABM: - case X25RES_INVAL_LCN: - case X25RES_INVAL_STATE: - set_chan_state(dev, WAN_DISCONNECTED); - delay = RETURN_RESULT; - break; - - default: - /* If command did not execute because of user - * fault, do not change the state. This will - * signal the socket that clear command failed. - * User can retry or close the socket. - * When socket gets killed, it will set the - * chan->disconnect which will signal - * driver to clear the call */ - printk(KERN_INFO "%s: Clear Command Failed, Rc %x\n", - card->devname,mbox->cmd.command); - delay = RETURN_RESULT; - } - break; - } - - return delay; -} - -/*=============================================================== - * api_incoming_call - * - * Pass an incoming call request up the listening - * sock. If the API sock is not listening reject the - * call. - * - *===============================================================*/ - -static int api_incoming_call (sdla_t* card, TX25Mbox *mbox, int lcn) -{ - struct sk_buff *skb; - int len = sizeof(TX25Cmd)+mbox->cmd.length; - - if (alloc_and_init_skb_buf(card, &skb, len)){ - printk(KERN_INFO "%s: API incoming call, no memory\n",card->devname); - return 1; - } - - memcpy(skb_put(skb,len),&mbox->cmd,len); - - skb->mac.raw = skb->data; - skb->protocol = htons(X25_PROT); - skb->pkt_type = WAN_PACKET_ASYNC; - - if (card->func(skb,card->sk) < 0){ - printk(KERN_INFO "%s: MAJOR ERROR: Failed to send up place call \n",card->devname); - dev_kfree_skb_any(skb); - return 1; - } - - return 0; -} - -/*=============================================================== - * send_delayed_cmd_result - * - * Wait commands like PLEACE CALL or CLEAR CALL must wait - * until the result arrives. This function passes - * the result to a waiting sock. - * - *===============================================================*/ -static void send_delayed_cmd_result(sdla_t *card, struct net_device *dev, - TX25Mbox* mbox) -{ - x25_channel_t *chan = dev->priv; - mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox; - struct sk_buff *skb; - int len=sizeof(unsigned char); - - atomic_set(&chan->common.command,0); - - /* If the sock is in the process of unlinking the - * driver from the socket, we must get out. - * This never happends but is a sanity check. */ - if (test_bit(0,&chan->common.common_critical)){ - return; - } - - if (!usr_cmd || !chan->common.sk || !chan->common.func){ - DBG_PRINTK(KERN_INFO "Delay result: Sock not bounded sk: %u, func: %u, mbox: %u\n", - (unsigned int)chan->common.sk, - (unsigned int)chan->common.func, - (unsigned int)usr_cmd); - return; - } - - memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd)); - if (mbox->cmd.length > 0){ - memcpy(usr_cmd->data, mbox->data, mbox->cmd.length); - } - - if (alloc_and_init_skb_buf(card,&skb,len)){ - printk(KERN_INFO "Delay result: No sock buffers\n"); - return; - } - - memcpy(skb_put(skb,len),&mbox->cmd.command,len); - - skb->mac.raw = skb->data; - skb->pkt_type = WAN_PACKET_CMD; - - chan->common.func(skb,dev,chan->common.sk); -} - -/*=============================================================== - * clear_confirm_event - * - * Pass the clear confirmation event up the sock. The - * API will disconnect only after the clear confirmation - * has been received. - * - * Depending on the state, clear confirmation could - * be an OOB event, or a result of an API command. - *===============================================================*/ - -static int clear_confirm_event (sdla_t *card, TX25Mbox* mb) -{ - struct net_device *dev; - x25_channel_t *chan; - unsigned char old_state; - - dev = find_channel(card,mb->cmd.lcn); - if (!dev){ - DBG_PRINTK(KERN_INFO "%s: *** GOT CLEAR BUT NO DEV %i\n", - card->devname,mb->cmd.lcn); - return 0; - } - - chan=dev->priv; - DBG_PRINTK(KERN_INFO "%s: GOT CLEAR CONFIRM %s: Mbox lcn %i Chan lcn %i\n", - card->devname, dev->name, mb->cmd.lcn, chan->common.lcn); - - /* If not API fall through to default. - * If API, send the result to a waiting - * socket. - */ - - old_state = chan->common.state; - set_chan_state(dev, WAN_DISCONNECTED); - - if (chan->common.usedby == API){ - switch (old_state) { - - case WAN_DISCONNECTING: - case WAN_CONNECTING: - send_delayed_cmd_result(card,dev,mb); - break; - case WAN_CONNECTED: - send_oob_msg(card,dev,mb); - break; - } - return 1; - } - - return 0; -} - -/*=============================================================== - * send_oob_msg - * - * Construct an NEM Message and pass it up the connected - * sock. If the sock is not bounded discard the NEM. - * - *===============================================================*/ - -static void send_oob_msg(sdla_t *card, struct net_device *dev, TX25Mbox *mbox) -{ - x25_channel_t *chan = dev->priv; - mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox; - struct sk_buff *skb; - int len=sizeof(x25api_hdr_t)+mbox->cmd.length; - x25api_t *api_hdr; - - /* If the sock is in the process of unlinking the - * driver from the socket, we must get out. - * This never happends but is a sanity check. */ - if (test_bit(0,&chan->common.common_critical)){ - return; - } - - if (!usr_cmd || !chan->common.sk || !chan->common.func){ - DBG_PRINTK(KERN_INFO "OOB MSG: Sock not bounded\n"); - return; - } - - memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd)); - if (mbox->cmd.length > 0){ - memcpy(usr_cmd->data, mbox->data, mbox->cmd.length); - } - - if (alloc_and_init_skb_buf(card,&skb,len)){ - printk(KERN_INFO "%s: OOB MSG: No sock buffers\n",card->devname); - return; - } - - api_hdr = (x25api_t*)skb_put(skb,len); - api_hdr->hdr.pktType = mbox->cmd.pktType & 0x7F; - api_hdr->hdr.qdm = mbox->cmd.qdm; - api_hdr->hdr.cause = mbox->cmd.cause; - api_hdr->hdr.diagn = mbox->cmd.diagn; - api_hdr->hdr.length = mbox->cmd.length; - api_hdr->hdr.result = mbox->cmd.result; - api_hdr->hdr.lcn = mbox->cmd.lcn; - - if (mbox->cmd.length > 0){ - memcpy(api_hdr->data,mbox->data,mbox->cmd.length); - } - - skb->mac.raw = skb->data; - skb->pkt_type = WAN_PACKET_ERR; - - if (chan->common.func(skb,dev,chan->common.sk) < 0){ - if (bh_enqueue(dev,skb)){ - printk(KERN_INFO "%s: Dropping OOB MSG\n",card->devname); - dev_kfree_skb_any(skb); - } - } - - DBG_PRINTK(KERN_INFO "%s: OOB MSG OK, %s, lcn %i\n", - card->devname, dev->name, mbox->cmd.lcn); -} - -/*=============================================================== - * alloc_and_init_skb_buf - * - * Allocate and initialize an skb buffer. - * - *===============================================================*/ - -static int alloc_and_init_skb_buf (sdla_t *card, struct sk_buff **skb, int len) -{ - struct sk_buff *new_skb = *skb; - - new_skb = dev_alloc_skb(len + X25_HRDHDR_SZ); - if (new_skb == NULL){ - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - return 1; - } - - if (skb_tailroom(new_skb) < len){ - /* No room for the packet. Call off the whole thing! */ - dev_kfree_skb_any(new_skb); - printk(KERN_INFO "%s: Listen: unexpectedly long packet sequence\n" - ,card->devname); - *skb = NULL; - return 1; - } - - *skb = new_skb; - return 0; - -} - -/*=============================================================== - * api_oob_event - * - * Send an OOB event up to the sock - * - *===============================================================*/ - -static void api_oob_event (sdla_t *card,TX25Mbox *mbox) -{ - struct net_device *dev = find_channel(card, mbox->cmd.lcn); - x25_channel_t *chan; - - if (!dev) - return; - - chan=dev->priv; - - if (chan->common.usedby == API) - send_oob_msg(card,dev,mbox); - -} - - - - -static int channel_disconnect(sdla_t* card, struct net_device *dev) -{ - - int err; - x25_channel_t *chan = dev->priv; - - DBG_PRINTK(KERN_INFO "%s: TIMER: %s, Device down disconnecting\n", - card->devname,dev->name); - - if (chan->common.svc){ - err = x25_clear_call(card,chan->common.lcn,0,0); - }else{ - /* If channel is PVC or LAPB HDLC, there is no call - * to be cleared, thus drop down to the default - * area - */ - err = 1; - } - - switch (err){ - - case X25RES_CHANNEL_IN_USE: - case X25RES_NOT_READY: - err = TRY_CMD_AGAIN; - break; - case CMD_OK: - DBG_PRINTK(KERN_INFO "CALL CLEAR OK: Dev %s Chan Lcn %i\n", - dev->name,chan->common.lcn); - - set_chan_state(dev,WAN_DISCONNECTING); - atomic_set(&chan->common.command,0); - err = DELAY_RESULT; - break; - default: - /* If LAPB HDLC protocol, bring the whole link down - * once the application terminates - */ - - set_chan_state(dev,WAN_DISCONNECTED); - - if (card->u.x.LAPB_hdlc){ - DBG_PRINTK(KERN_INFO "LAPB: Disconnecting Link\n"); - hdlc_link_down (card); - } - atomic_set(&chan->common.command,0); - err = RETURN_RESULT; - break; - } - - return err; -} - -static void hdlc_link_down (sdla_t *card) -{ - TX25Mbox* mbox = card->mbox; - int retry = 5; - int err=0; - - do { - memset(mbox,0,sizeof(TX25Mbox)); - mbox->cmd.command = X25_HDLC_LINK_DISC; - mbox->cmd.length = 1; - mbox->data[0]=0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_DISC, 0)); - - if (err) - printk(KERN_INFO "%s: Hdlc Link Down Failed %x\n",card->devname,err); - - disconnect (card); - -} - -static int check_bad_command(sdla_t* card, struct net_device *dev) -{ - x25_channel_t *chan = dev->priv; - int bad_cmd = 0; - - switch (atomic_read(&chan->common.command)&0x7F){ - - case X25_PLACE_CALL: - if (chan->common.state != WAN_DISCONNECTED) - bad_cmd=1; - break; - case X25_CLEAR_CALL: - if (chan->common.state == WAN_DISCONNECTED) - bad_cmd=1; - break; - case X25_ACCEPT_CALL: - if (chan->common.state != WAN_CONNECTING) - bad_cmd=1; - break; - case X25_RESET: - if (chan->common.state != WAN_CONNECTED) - bad_cmd=1; - break; - default: - bad_cmd=1; - break; - } - - if (bad_cmd){ - printk(KERN_INFO "%s: Invalid State, BAD Command %x, dev %s, lcn %i, st %i\n", - card->devname,atomic_read(&chan->common.command),dev->name, - chan->common.lcn, chan->common.state); - } - - return bad_cmd; -} - - - -/*************************** XPIPEMON FUNCTIONS **************************/ - -/*============================================================================== - * Process UDP call of type XPIPE - */ - -static int process_udp_mgmt_pkt(sdla_t *card) -{ - int c_retry = MAX_CMD_RETRY; - unsigned int len; - struct sk_buff *new_skb; - TX25Mbox *mbox = card->mbox; - int err; - int udp_mgmt_req_valid = 1; - struct net_device *dev; - x25_channel_t *chan; - unsigned short lcn; - struct timeval tv; - - - x25_udp_pkt_t *x25_udp_pkt; - x25_udp_pkt = (x25_udp_pkt_t *)card->u.x.udp_pkt_data; - - dev = card->u.x.udp_dev; - chan = dev->priv; - lcn = chan->common.lcn; - - switch(x25_udp_pkt->cblock.command) { - - /* XPIPE_ENABLE_TRACE */ - case XPIPE_ENABLE_TRACING: - - /* XPIPE_GET_TRACE_INFO */ - case XPIPE_GET_TRACE_INFO: - - /* SET FT1 MODE */ - case XPIPE_SET_FT1_MODE: - - if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err; - udp_mgmt_req_valid = 0; - break; - } - - /* XPIPE_FT1_READ_STATUS */ - case XPIPE_FT1_READ_STATUS: - - /* FT1 MONITOR STATUS */ - case XPIPE_FT1_STATUS_CTRL: - if(card->hw.fwid != SFID_X25_508) { - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_type_err; - udp_mgmt_req_valid = 0; - break; - } - default: - break; - } - - if(!udp_mgmt_req_valid) { - /* set length to 0 */ - x25_udp_pkt->cblock.length = 0; - /* set return code */ - x25_udp_pkt->cblock.result = (card->hw.fwid != SFID_X25_508) ? 0x1F : 0xCD; - - } else { - - switch (x25_udp_pkt->cblock.command) { - - - case XPIPE_FLUSH_DRIVER_STATS: - init_x25_channel_struct(chan); - init_global_statistics(card); - mbox->cmd.length = 0; - break; - - - case XPIPE_DRIVER_STAT_IFSEND: - memcpy(x25_udp_pkt->data, &chan->if_send_stat, sizeof(if_send_stat_t)); - mbox->cmd.length = sizeof(if_send_stat_t); - x25_udp_pkt->cblock.length = mbox->cmd.length; - break; - - case XPIPE_DRIVER_STAT_INTR: - memcpy(&x25_udp_pkt->data[0], &card->statistics, sizeof(global_stats_t)); - memcpy(&x25_udp_pkt->data[sizeof(global_stats_t)], - &chan->rx_intr_stat, sizeof(rx_intr_stat_t)); - - mbox->cmd.length = sizeof(global_stats_t) + - sizeof(rx_intr_stat_t); - x25_udp_pkt->cblock.length = mbox->cmd.length; - break; - - case XPIPE_DRIVER_STAT_GEN: - memcpy(x25_udp_pkt->data, - &chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err, - sizeof(pipe_mgmt_stat_t)); - - memcpy(&x25_udp_pkt->data[sizeof(pipe_mgmt_stat_t)], - &card->statistics, sizeof(global_stats_t)); - - x25_udp_pkt->cblock.result = 0; - x25_udp_pkt->cblock.length = sizeof(global_stats_t)+ - sizeof(rx_intr_stat_t); - mbox->cmd.length = x25_udp_pkt->cblock.length; - break; - - case XPIPE_ROUTER_UP_TIME: - do_gettimeofday(&tv); - chan->router_up_time = tv.tv_sec - chan->router_start_time; - *(unsigned long *)&x25_udp_pkt->data = chan->router_up_time; - x25_udp_pkt->cblock.length = mbox->cmd.length = 4; - x25_udp_pkt->cblock.result = 0; - break; - - default : - - do { - memcpy(&mbox->cmd, &x25_udp_pkt->cblock.command, sizeof(TX25Cmd)); - if(mbox->cmd.length){ - memcpy(&mbox->data, - (char *)x25_udp_pkt->data, - mbox->cmd.length); - } - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && c_retry-- && x25_error(card, err, mbox->cmd.command, 0)); - - - if ( err == CMD_OK || - (err == 1 && - (mbox->cmd.command == 0x06 || - mbox->cmd.command == 0x16) ) ){ - - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK; - } else { - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_timeout; - } - - /* copy the result back to our buffer */ - memcpy(&x25_udp_pkt->cblock.command, &mbox->cmd, sizeof(TX25Cmd)); - - if(mbox->cmd.length) { - memcpy(&x25_udp_pkt->data, &mbox->data, mbox->cmd.length); - } - break; - - } //switch - - } - - /* Fill UDP TTL */ - - x25_udp_pkt->ip_pkt.ttl = card->wandev.ttl; - len = reply_udp(card->u.x.udp_pkt_data, mbox->cmd.length); - - - if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - err = x25_send(card, lcn, 0, len, card->u.x.udp_pkt_data); - if (!err) - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_passed; - else - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_failed; - - } else { - - /* Allocate socket buffer */ - if((new_skb = dev_alloc_skb(len)) != NULL) { - void *buf; - - /* copy data into new_skb */ - buf = skb_put(new_skb, len); - memcpy(buf, card->u.x.udp_pkt_data, len); - - /* Decapsulate packet and pass it up the protocol - stack */ - new_skb->dev = dev; - - if (chan->common.usedby == API) - new_skb->protocol = htons(X25_PROT); - else - new_skb->protocol = htons(ETH_P_IP); - - new_skb->mac.raw = new_skb->data; - - netif_rx(new_skb); - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack; - - } else { - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket; - printk(KERN_INFO - "%s: UDP mgmt cmnd, no socket buffers available!\n", - card->devname); - } - } - - card->u.x.udp_pkt_lgth = 0; - - return 1; -} - - -/*============================================================================== - * Determine what type of UDP call it is. DRVSTATS or XPIPE8ND ? - */ -static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) -{ - x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)skb->data; - - if((x25_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && - (x25_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && - (x25_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && - (x25_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { - - if(!strncmp(x25_udp_pkt->wp_mgmt.signature, - UDPMGMT_XPIPE_SIGNATURE, 8)){ - return UDP_XPIPE_TYPE; - }else{ - printk(KERN_INFO "%s: UDP Packet, Failed Signature !\n", - card->devname); - } - } - - return UDP_INVALID_TYPE; -} - - -/*============================================================================ - * Reply to UDP Management system. - * Return nothing. - */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ) -{ - unsigned short len, udp_length, temp, ip_length; - unsigned long ip_temp; - int even_bound = 0; - - - x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)data; - - /* Set length of packet */ - len = sizeof(ip_pkt_t)+ - sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - - /* fill in UDP reply */ - x25_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; - - /* fill in UDP length */ - udp_length = sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - - /* put it on an even boundary */ - if ( udp_length & 0x0001 ) { - udp_length += 1; - len += 1; - even_bound = 1; - } - - temp = (udp_length<<8)|(udp_length>>8); - x25_udp_pkt->udp_pkt.udp_length = temp; - - /* swap UDP ports */ - temp = x25_udp_pkt->udp_pkt.udp_src_port; - x25_udp_pkt->udp_pkt.udp_src_port = - x25_udp_pkt->udp_pkt.udp_dst_port; - x25_udp_pkt->udp_pkt.udp_dst_port = temp; - - - - /* add UDP pseudo header */ - temp = 0x1100; - *((unsigned short *) - (x25_udp_pkt->data+mbox_len+even_bound)) = temp; - temp = (udp_length<<8)|(udp_length>>8); - *((unsigned short *) - (x25_udp_pkt->data+mbox_len+even_bound+2)) = temp; - - /* calculate UDP checksum */ - x25_udp_pkt->udp_pkt.udp_checksum = 0; - - x25_udp_pkt->udp_pkt.udp_checksum = - calc_checksum(&data[UDP_OFFSET], udp_length+UDP_OFFSET); - - /* fill in IP length */ - ip_length = len; - temp = (ip_length<<8)|(ip_length>>8); - x25_udp_pkt->ip_pkt.total_length = temp; - - /* swap IP addresses */ - ip_temp = x25_udp_pkt->ip_pkt.ip_src_address; - x25_udp_pkt->ip_pkt.ip_src_address = - x25_udp_pkt->ip_pkt.ip_dst_address; - x25_udp_pkt->ip_pkt.ip_dst_address = ip_temp; - - - /* fill in IP checksum */ - x25_udp_pkt->ip_pkt.hdr_checksum = 0; - x25_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data, sizeof(ip_pkt_t)); - - return len; -} /* reply_udp */ - -unsigned short calc_checksum (char *data, int len) -{ - unsigned short temp; - unsigned long sum=0; - int i; - - for( i = 0; i > 16 ) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - - temp = (unsigned short)sum; - temp = ~temp; - - if( temp == 0 ) - temp = 0xffff; - - return temp; -} - -/*============================================================================= - * Store a UDP management packet for later processing. - */ - -static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, - struct net_device *dev, struct sk_buff *skb, - int lcn) -{ - int udp_pkt_stored = 0; - - if(!card->u.x.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ - card->u.x.udp_pkt_lgth = skb->len; - card->u.x.udp_type = udp_type; - card->u.x.udp_pkt_src = udp_pkt_src; - card->u.x.udp_lcn = lcn; - card->u.x.udp_dev = dev; - memcpy(card->u.x.udp_pkt_data, skb->data, skb->len); - card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UDP_PKT; - udp_pkt_stored = 1; - - }else{ - printk(KERN_INFO "%s: ERROR: UDP packet not stored for LCN %d\n", - card->devname,lcn); - } - - if(udp_pkt_src == UDP_PKT_FRM_STACK){ - dev_kfree_skb_any(skb); - }else{ - dev_kfree_skb_any(skb); - } - - return(udp_pkt_stored); -} - - - -/*============================================================================= - * Initial the ppp_private_area structure. - */ -static void init_x25_channel_struct( x25_channel_t *chan ) -{ - memset(&chan->if_send_stat.if_send_entry,0,sizeof(if_send_stat_t)); - memset(&chan->rx_intr_stat.rx_intr_no_socket,0,sizeof(rx_intr_stat_t)); - memset(&chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err,0,sizeof(pipe_mgmt_stat_t)); -} - -/*============================================================================ - * Initialize Global Statistics - */ -static void init_global_statistics( sdla_t *card ) -{ - memset(&card->statistics.isr_entry,0,sizeof(global_stats_t)); -} - - -/*=============================================================== - * SMP Support - * ==============================================================*/ - -static void S508_S514_lock(sdla_t *card, unsigned long *smp_flags) -{ - spin_lock_irqsave(&card->wandev.lock, *smp_flags); -} -static void S508_S514_unlock(sdla_t *card, unsigned long *smp_flags) -{ - spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); -} - -/*=============================================================== - * x25_timer_routine - * - * A more efficient polling routine. Each half a second - * queue a polling task. We want to do the polling in a - * task not timer, because timer runs in interrupt time. - * - * FIXME Polling should be rethinked. - *==============================================================*/ - -static void x25_timer_routine(unsigned long data) -{ - sdla_t *card = (sdla_t*)data; - - if (!card->wandev.dev){ - printk(KERN_INFO "%s: Stopping the X25 Poll Timer: No Dev.\n", - card->devname); - return; - } - - if (card->open_cnt != card->u.x.num_of_ch){ - printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Interface down.\n", - card->devname); - return; - } - - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Shutting down.\n", - card->devname); - return; - } - - if (!test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ - trigger_x25_poll(card); - } - - card->u.x.x25_timer.expires=jiffies+(HZ>>1); - add_timer(&card->u.x.x25_timer); - return; -} - -void disable_comm_shutdown(sdla_t *card) -{ - TX25Mbox* mbox = card->mbox; - int err; - - /* Turn of interrutps */ - mbox->data[0] = 0; - if (card->hw.fwid == SFID_X25_508){ - mbox->data[1] = card->hw.irq; - mbox->data[2] = 2; - mbox->cmd.length = 3; - }else { - mbox->cmd.length = 1; - } - mbox->cmd.command = X25_SET_INTERRUPT_MODE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - printk(KERN_INFO "INTERRUPT OFF FAIED %x\n",err); - - /* Bring down HDLC */ - mbox->cmd.command = X25_HDLC_LINK_CLOSE; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - printk(KERN_INFO "LINK CLOSED FAILED %x\n",err); - - - /* Brind down DTR */ - mbox->data[0] = 0; - mbox->data[2] = 0; - mbox->data[1] = 0x01; - mbox->cmd.length = 3; - mbox->cmd.command = X25_SET_GLOBAL_VARS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - printk(KERN_INFO "DTR DOWN FAILED %x\n",err); - -} - -MODULE_LICENSE("GPL"); - -/****** End *****************************************************************/ diff --git a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c deleted file mode 100644 index 032c0f8..0000000 --- a/drivers/net/wan/sdladrv.c +++ /dev/null @@ -1,2314 +0,0 @@ -/***************************************************************************** -* sdladrv.c SDLA Support Module. Main module. -* -* This module is a library of common hardware-specific functions -* used by all Sangoma drivers. -* -* Author: Gideon Hack -* -* Copyright: (c) 1995-2000 Sangoma Technologies Inc. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version -* 2 of the License, or (at your option) any later version. -* ============================================================================ -* Mar 20, 2001 Nenad Corbic Added the auto_pci_cfg filed, to support -* the PCISLOT #0. -* Apr 04, 2000 Nenad Corbic Fixed the auto memory detection code. -* The memory test at address 0xC8000. -* Mar 09, 2000 Nenad Corbic Added Gideon's Bug Fix: clear pci -* interrupt flags on initial load. -* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. -* Updates for Linux 2.2.X kernels. -* Sep 17, 1998 Jaspreet Singh Updates for linux 2.2.X kernels -* Dec 20, 1996 Gene Kozin Version 3.0.0. Complete overhaul. -* Jul 12, 1996 Gene Kozin Changes for Linux 2.0 compatibility. -* Jun 12, 1996 Gene Kozin Added support for S503 card. -* Apr 30, 1996 Gene Kozin SDLA hardware interrupt is acknowledged before -* calling protocolspecific ISR. -* Register I/O ports with Linux kernel. -* Miscellaneous bug fixes. -* Dec 20, 1995 Gene Kozin Fixed a bug in interrupt routine. -* Oct 14, 1995 Gene Kozin Initial version. -*****************************************************************************/ - -/***************************************************************************** - * Notes: - * ------ - * 1. This code is ment to be system-independent (as much as possible). To - * achive this, various macros are used to hide system-specific interfaces. - * To compile this code, one of the following constants must be defined: - * - * Platform Define - * -------- ------ - * Linux _LINUX_ - * SCO Unix _SCO_UNIX_ - * - * 2. Supported adapter types: - * - * S502A - * ES502A (S502E) - * S503 - * S507 - * S508 (S509) - * - * 3. S502A Notes: - * - * There is no separate DPM window enable/disable control in S502A. It - * opens immediately after a window number it written to the HMCR - * register. To close the window, HMCR has to be written a value - * ????1111b (e.g. 0x0F or 0xFF). - * - * S502A DPM window cannot be located at offset E000 (e.g. 0xAE000). - * - * There should be a delay of ??? before reading back S502A status - * register. - * - * 4. S502E Notes: - * - * S502E has a h/w bug: although default IRQ line state is HIGH, enabling - * interrupts by setting bit 1 of the control register (BASE) to '1' - * causes it to go LOW! Therefore, disabling interrupts by setting that - * bit to '0' causes low-to-high transition on IRQ line (ghosty - * interrupt). The same occurs when disabling CPU by resetting bit 0 of - * CPU control register (BASE+3) - see the next note. - * - * S502E CPU and DPM control is limited: - * - * o CPU cannot be stopped independently. Resetting bit 0 of the CPUi - * control register (BASE+3) shuts the board down entirely, including - * DPM; - * - * o DPM access cannot be controlled dynamically. Ones CPU is started, - * bit 1 of the control register (BASE) is used to enable/disable IRQ, - * so that access to shared memory cannot be disabled while CPU is - * running. - ****************************************************************************/ - -#define _LINUX_ - -#if defined(_LINUX_) /****** Linux *******************************/ - -#include -#include /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* support for loadable modules */ -#include /* for jiffies, HZ, etc. */ -#include /* API definitions */ -#include /* SDLA firmware module definitions */ -#include /* SDLA PCI hardware definitions */ -#include /* PCI defines and function prototypes */ -#include /* for inb(), outb(), etc. */ - -#define _INB(port) (inb(port)) -#define _OUTB(port, byte) (outb((byte),(port))) -#define SYSTEM_TICK jiffies - -#include - - -#elif defined(_SCO_UNIX_) /****** SCO Unix ****************************/ - -#if !defined(INKERNEL) -#error This code MUST be compiled in kernel mode! -#endif -#include /* API definitions */ -#include /* SDLA firmware module definitions */ -#include /* for inb(), outb(), etc. */ -#define _INB(port) (inb(port)) -#define _OUTB(port, byte) (outb((port),(byte))) -#define SYSTEM_TICK lbolt - -#else -#error Unknown system type! -#endif - -#define MOD_VERSION 3 -#define MOD_RELEASE 0 - -#define SDLA_IODELAY 100 /* I/O Rd/Wr delay, 10 works for 486DX2-66 */ -#define EXEC_DELAY 20 /* shared memory access delay, mks */ -#define EXEC_TIMEOUT (HZ*2) /* command timeout, in ticks */ - -/* I/O port address range */ -#define S502A_IORANGE 3 -#define S502E_IORANGE 4 -#define S503_IORANGE 3 -#define S507_IORANGE 4 -#define S508_IORANGE 4 - -/* Maximum amount of memory */ -#define S502_MAXMEM 0x10000L -#define S503_MAXMEM 0x10000L -#define S507_MAXMEM 0x40000L -#define S508_MAXMEM 0x40000L - -/* Minimum amount of memory */ -#define S502_MINMEM 0x8000L -#define S503_MINMEM 0x8000L -#define S507_MINMEM 0x20000L -#define S508_MINMEM 0x20000L -#define NO_PORT -1 - - - - - -/****** Function Prototypes *************************************************/ - -/* Hardware-specific functions */ -static int sdla_detect (sdlahw_t* hw); -static int sdla_autodpm (sdlahw_t* hw); -static int sdla_setdpm (sdlahw_t* hw); -static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len); -static int sdla_init (sdlahw_t* hw); -static unsigned long sdla_memtest (sdlahw_t* hw); -static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo); -static unsigned char make_config_byte (sdlahw_t* hw); -static int sdla_start (sdlahw_t* hw, unsigned addr); - -static int init_s502a (sdlahw_t* hw); -static int init_s502e (sdlahw_t* hw); -static int init_s503 (sdlahw_t* hw); -static int init_s507 (sdlahw_t* hw); -static int init_s508 (sdlahw_t* hw); - -static int detect_s502a (int port); -static int detect_s502e (int port); -static int detect_s503 (int port); -static int detect_s507 (int port); -static int detect_s508 (int port); -static int detect_s514 (sdlahw_t* hw); -static int find_s514_adapter(sdlahw_t* hw, char find_first_S514_card); - -/* Miscellaneous functions */ -static void peek_by_4 (unsigned long src, void* buf, unsigned len); -static void poke_by_4 (unsigned long dest, void* buf, unsigned len); -static int calibrate_delay (int mks); -static int get_option_index (unsigned* optlist, unsigned optval); -static unsigned check_memregion (void* ptr, unsigned len); -static unsigned test_memregion (void* ptr, unsigned len); -static unsigned short checksum (unsigned char* buf, unsigned len); -static int init_pci_slot(sdlahw_t *); - -static int pci_probe(sdlahw_t *hw); - -/****** Global Data ********************************************************** - * Note: All data must be explicitly initialized!!! - */ - -static struct pci_device_id sdladrv_pci_tbl[] = { - { V3_VENDOR_ID, V3_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, sdladrv_pci_tbl); - -MODULE_LICENSE("GPL"); - -/* private data */ -static char modname[] = "sdladrv"; -static char fullname[] = "SDLA Support Module"; -static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc."; -static unsigned exec_idle; - -/* Hardware configuration options. - * These are arrays of configuration options used by verification routines. - * The first element of each array is its size (i.e. number of options). - */ -static unsigned s502_port_options[] = - { 4, 0x250, 0x300, 0x350, 0x360 } -; -static unsigned s503_port_options[] = - { 8, 0x250, 0x254, 0x300, 0x304, 0x350, 0x354, 0x360, 0x364 } -; -static unsigned s508_port_options[] = - { 8, 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390 } -; - -static unsigned s502a_irq_options[] = { 0 }; -static unsigned s502e_irq_options[] = { 4, 2, 3, 5, 7 }; -static unsigned s503_irq_options[] = { 5, 2, 3, 4, 5, 7 }; -static unsigned s508_irq_options[] = { 8, 3, 4, 5, 7, 10, 11, 12, 15 }; - -static unsigned s502a_dpmbase_options[] = -{ - 28, - 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, - 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, - 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, - 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, -}; -static unsigned s507_dpmbase_options[] = -{ - 32, - 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, - 0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000, - 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, - 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, -}; -static unsigned s508_dpmbase_options[] = /* incl. S502E and S503 */ -{ - 32, - 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, - 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, - 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000, - 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, -}; - -/* -static unsigned s502_dpmsize_options[] = { 2, 0x2000, 0x10000 }; -static unsigned s507_dpmsize_options[] = { 2, 0x2000, 0x4000 }; -static unsigned s508_dpmsize_options[] = { 1, 0x2000 }; -*/ - -static unsigned s502a_pclk_options[] = { 2, 3600, 7200 }; -static unsigned s502e_pclk_options[] = { 5, 3600, 5000, 7200, 8000, 10000 }; -static unsigned s503_pclk_options[] = { 3, 7200, 8000, 10000 }; -static unsigned s507_pclk_options[] = { 1, 12288 }; -static unsigned s508_pclk_options[] = { 1, 16000 }; - -/* Host memory control register masks */ -static unsigned char s502a_hmcr[] = -{ - 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, /* A0000 - AC000 */ - 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, /* C0000 - CC000 */ - 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, /* D0000 - DC000 */ - 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, /* E0000 - EC000 */ -}; -static unsigned char s502e_hmcr[] = -{ - 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, /* A0000 - AE000 */ - 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, /* C0000 - CE000 */ - 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* D0000 - DE000 */ - 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E, /* E0000 - EE000 */ -}; -static unsigned char s507_hmcr[] = -{ - 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* A0000 - AE000 */ - 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, /* B0000 - BE000 */ - 0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, /* C0000 - CE000 */ - 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, /* E0000 - EE000 */ -}; -static unsigned char s508_hmcr[] = -{ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* A0000 - AE000 */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* C0000 - CE000 */ - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* D0000 - DE000 */ - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* E0000 - EE000 */ -}; - -static unsigned char s507_irqmask[] = -{ - 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0 -}; - -static int pci_slot_ar[MAX_S514_CARDS]; - -/******* Kernel Loadable Module Entry Points ********************************/ - -/*============================================================================ - * Module 'insert' entry point. - * o print announcement - * o initialize static data - * o calibrate SDLA shared memory access delay. - * - * Return: 0 Ok - * < 0 error. - * Context: process - */ - -static int __init sdladrv_init(void) -{ - int i=0; - - printk(KERN_INFO "%s v%u.%u %s\n", - fullname, MOD_VERSION, MOD_RELEASE, copyright); - exec_idle = calibrate_delay(EXEC_DELAY); -#ifdef WANDEBUG - printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle); -#endif - - /* Initialize the PCI Card array, which - * will store flags, used to mark - * card initialization state */ - for (i=0; itype != SDLA_S514) - printk(KERN_INFO "%s: no SDLA card found at port 0x%X\n", - modname, hw->port); - return -EINVAL; - } - - if(hw->type != SDLA_S514) { - printk(KERN_INFO "%s: found S%04u card at port 0x%X.\n", - modname, hw->type, hw->port); - - hw->dpmsize = SDLA_WINDOWSIZE; - switch (hw->type) { - case SDLA_S502A: - hw->io_range = S502A_IORANGE; - irq_opt = s502a_irq_options; - dpmbase_opt = s502a_dpmbase_options; - pclk_opt = s502a_pclk_options; - break; - - case SDLA_S502E: - hw->io_range = S502E_IORANGE; - irq_opt = s502e_irq_options; - dpmbase_opt = s508_dpmbase_options; - pclk_opt = s502e_pclk_options; - break; - - case SDLA_S503: - hw->io_range = S503_IORANGE; - irq_opt = s503_irq_options; - dpmbase_opt = s508_dpmbase_options; - pclk_opt = s503_pclk_options; - break; - - case SDLA_S507: - hw->io_range = S507_IORANGE; - irq_opt = s508_irq_options; - dpmbase_opt = s507_dpmbase_options; - pclk_opt = s507_pclk_options; - break; - - case SDLA_S508: - hw->io_range = S508_IORANGE; - irq_opt = s508_irq_options; - dpmbase_opt = s508_dpmbase_options; - pclk_opt = s508_pclk_options; - break; - } - - /* Verify IRQ configuration options */ - if (!get_option_index(irq_opt, hw->irq)) { - printk(KERN_INFO "%s: IRQ %d is invalid!\n", - modname, hw->irq); - return -EINVAL; - } - - /* Verify CPU clock rate configuration options */ - if (hw->pclk == 0) - hw->pclk = pclk_opt[1]; /* use default */ - - else if (!get_option_index(pclk_opt, hw->pclk)) { - printk(KERN_INFO "%s: CPU clock %u is invalid!\n", - modname, hw->pclk); - return -EINVAL; - } - printk(KERN_INFO "%s: assuming CPU clock rate of %u kHz.\n", - modname, hw->pclk); - - /* Setup adapter dual-port memory window and test memory */ - if (hw->dpmbase == 0) { - err = sdla_autodpm(hw); - if (err) { - printk(KERN_INFO - "%s: can't find available memory region!\n", - modname); - return err; - } - } - else if (!get_option_index(dpmbase_opt, - virt_to_phys(hw->dpmbase))) { - printk(KERN_INFO - "%s: memory address 0x%lX is invalid!\n", - modname, virt_to_phys(hw->dpmbase)); - return -EINVAL; - } - else if (sdla_setdpm(hw)) { - printk(KERN_INFO - "%s: 8K memory region at 0x%lX is not available!\n", - modname, virt_to_phys(hw->dpmbase)); - return -EINVAL; - } - printk(KERN_INFO - "%s: dual-port memory window is set at 0x%lX.\n", - modname, virt_to_phys(hw->dpmbase)); - - - /* If we find memory in 0xE**** Memory region, - * warn the user to disable the SHADOW RAM. - * Since memory corruption can occur if SHADOW is - * enabled. This can causes random crashes ! */ - if (virt_to_phys(hw->dpmbase) >= 0xE0000){ - printk(KERN_WARNING "\n%s: !!!!!!!! WARNING !!!!!!!!\n",modname); - printk(KERN_WARNING "%s: WANPIPE is using 0x%lX memory region !!!\n", - modname, virt_to_phys(hw->dpmbase)); - printk(KERN_WARNING " Please disable the SHADOW RAM, otherwise\n"); - printk(KERN_WARNING " your system might crash randomly from time to time !\n"); - printk(KERN_WARNING "%s: !!!!!!!! WARNING !!!!!!!!\n\n",modname); - } - } - - else { - hw->memory = test_memregion((void*)hw->dpmbase, - MAX_SIZEOF_S514_MEMORY); - if(hw->memory < (256 * 1024)) { - printk(KERN_INFO - "%s: error in testing S514 memory (0x%lX)\n", - modname, hw->memory); - sdla_down(hw); - return -EINVAL; - } - } - - printk(KERN_INFO "%s: found %luK bytes of on-board memory\n", - modname, hw->memory / 1024); - - /* Load firmware. If loader fails then shut down adapter */ - err = sdla_load(hw, sfm, len); - if (err) sdla_down(hw); /* shutdown adapter */ - - return err; -} - -/*============================================================================ - * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc. - */ - -EXPORT_SYMBOL(sdla_down); - -int sdla_down (sdlahw_t* hw) -{ - unsigned port = hw->port; - int i; - unsigned char CPU_no; - u32 int_config, int_status; - - if(!port && (hw->type != SDLA_S514)) - return -EFAULT; - - switch (hw->type) { - case SDLA_S502A: - _OUTB(port, 0x08); /* halt CPU */ - _OUTB(port, 0x08); - _OUTB(port, 0x08); - hw->regs[0] = 0x08; - _OUTB(port + 1, 0xFF); /* close memory window */ - hw->regs[1] = 0xFF; - break; - - case SDLA_S502E: - _OUTB(port + 3, 0); /* stop CPU */ - _OUTB(port, 0); /* reset board */ - for (i = 0; i < S502E_IORANGE; ++i) - hw->regs[i] = 0 - ; - break; - - case SDLA_S503: - case SDLA_S507: - case SDLA_S508: - _OUTB(port, 0); /* reset board logic */ - hw->regs[0] = 0; - break; - - case SDLA_S514: - /* halt the adapter */ - *(char *)hw->vector = S514_CPU_HALT; - CPU_no = hw->S514_cpu_no[0]; - - /* disable the PCI IRQ and disable memory access */ - pci_read_config_dword(hw->pci_dev, PCI_INT_CONFIG, &int_config); - int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : ~PCI_DISABLE_IRQ_CPU_B; - pci_write_config_dword(hw->pci_dev, PCI_INT_CONFIG, int_config); - read_S514_int_stat(hw, &int_status); - S514_intack(hw, int_status); - if(CPU_no == S514_CPU_A) - pci_write_config_dword(hw->pci_dev, PCI_MAP0_DWORD, - PCI_CPU_A_MEM_DISABLE); - else - pci_write_config_dword(hw->pci_dev, PCI_MAP1_DWORD, - PCI_CPU_B_MEM_DISABLE); - - /* free up the allocated virtual memory */ - iounmap((void *)hw->dpmbase); - iounmap((void *)hw->vector); - break; - - - default: - return -EINVAL; - } - return 0; -} - -/*============================================================================ - * Map shared memory window into SDLA address space. - */ - -EXPORT_SYMBOL(sdla_mapmem); - -int sdla_mapmem (sdlahw_t* hw, unsigned long addr) -{ - unsigned port = hw->port; - register int tmp; - - switch (hw->type) { - case SDLA_S502A: - case SDLA_S502E: - if (addr < S502_MAXMEM) { /* verify parameter */ - tmp = addr >> 13; /* convert to register mask */ - _OUTB(port + 2, tmp); - hw->regs[2] = tmp; - } - else return -EINVAL; - break; - - case SDLA_S503: - if (addr < S503_MAXMEM) { /* verify parameter */ - tmp = (hw->regs[0] & 0x8F) | ((addr >> 9) & 0x70); - _OUTB(port, tmp); - hw->regs[0] = tmp; - } - else return -EINVAL; - break; - - case SDLA_S507: - if (addr < S507_MAXMEM) { - if (!(_INB(port) & 0x02)) - return -EIO; - tmp = addr >> 13; /* convert to register mask */ - _OUTB(port + 2, tmp); - hw->regs[2] = tmp; - } - else return -EINVAL; - break; - - case SDLA_S508: - if (addr < S508_MAXMEM) { - tmp = addr >> 13; /* convert to register mask */ - _OUTB(port + 2, tmp); - hw->regs[2] = tmp; - } - else return -EINVAL; - break; - - case SDLA_S514: - return 0; - - default: - return -EINVAL; - } - hw->vector = addr & 0xFFFFE000L; - return 0; -} - -/*============================================================================ - * Enable interrupt generation. - */ - -static int sdla_inten (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - switch (hw->type) { - case SDLA_S502E: - /* Note thar interrupt control operations on S502E are allowed - * only if CPU is enabled (bit 0 of status register is set). - */ - if (_INB(port) & 0x01) { - _OUTB(port, 0x02); /* bit1 = 1, bit2 = 0 */ - _OUTB(port, 0x06); /* bit1 = 1, bit2 = 1 */ - hw->regs[0] = 0x06; - } - else return -EIO; - break; - - case SDLA_S503: - tmp = hw->regs[0] | 0x04; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (!(_INB(port) & 0x02)) /* verify */ - return -EIO; - break; - - case SDLA_S508: - tmp = hw->regs[0] | 0x10; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (!(_INB(port + 1) & 0x10)) /* verify */ - return -EIO; - break; - - case SDLA_S502A: - case SDLA_S507: - break; - - case SDLA_S514: - break; - - default: - return -EINVAL; - - } - return 0; -} - -/*============================================================================ - * Disable interrupt generation. - */ - -#if 0 -int sdla_intde (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - switch (hw->type) { - case SDLA_S502E: - /* Notes: - * 1) interrupt control operations are allowed only if CPU is - * enabled (bit 0 of status register is set). - * 2) disabling interrupts using bit 1 of control register - * causes IRQ line go high, therefore we are going to use - * 0x04 instead: lower it to inhibit interrupts to PC. - */ - if (_INB(port) & 0x01) { - _OUTB(port, hw->regs[0] & ~0x04); - hw->regs[0] &= ~0x04; - } - else return -EIO; - break; - - case SDLA_S503: - tmp = hw->regs[0] & ~0x04; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) & 0x02) /* verify */ - return -EIO; - break; - - case SDLA_S508: - tmp = hw->regs[0] & ~0x10; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) & 0x10) /* verify */ - return -EIO; - break; - - case SDLA_S502A: - case SDLA_S507: - break; - - default: - return -EINVAL; - } - return 0; -} -#endif /* 0 */ - -/*============================================================================ - * Acknowledge SDLA hardware interrupt. - */ - -static int sdla_intack (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp; - - switch (hw->type) { - case SDLA_S502E: - /* To acknoledge hardware interrupt we have to toggle bit 3 of - * control register: \_/ - * Note that interrupt control operations on S502E are allowed - * only if CPU is enabled (bit 1 of status register is set). - */ - if (_INB(port) & 0x01) { - tmp = hw->regs[0] & ~0x04; - _OUTB(port, tmp); - tmp |= 0x04; - _OUTB(port, tmp); - hw->regs[0] = tmp; - } - else return -EIO; - break; - - case SDLA_S503: - if (_INB(port) & 0x04) { - tmp = hw->regs[0] & ~0x08; - _OUTB(port, tmp); - tmp |= 0x08; - _OUTB(port, tmp); - hw->regs[0] = tmp; - } - break; - - case SDLA_S502A: - case SDLA_S507: - case SDLA_S508: - break; - - default: - return -EINVAL; - } - return 0; -} - - -/*============================================================================ - * Acknowledge S514 hardware interrupt. - */ - -EXPORT_SYMBOL(S514_intack); - -void S514_intack (sdlahw_t* hw, u32 int_status) -{ - pci_write_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status); -} - - -/*============================================================================ - * Read the S514 hardware interrupt status. - */ - -EXPORT_SYMBOL(read_S514_int_stat); - -void read_S514_int_stat (sdlahw_t* hw, u32* int_status) -{ - pci_read_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status); -} - - -/*============================================================================ - * Generate an interrupt to adapter's CPU. - */ - -#if 0 -int sdla_intr (sdlahw_t* hw) -{ - unsigned port = hw->port; - - switch (hw->type) { - case SDLA_S502A: - if (!(_INB(port) & 0x40)) { - _OUTB(port, 0x10); /* issue NMI to CPU */ - hw->regs[0] = 0x10; - } - else return -EIO; - break; - - case SDLA_S507: - if ((_INB(port) & 0x06) == 0x06) { - _OUTB(port + 3, 0); - } - else return -EIO; - break; - - case SDLA_S508: - if (_INB(port + 1) & 0x02) { - _OUTB(port, 0x08); - } - else return -EIO; - break; - - case SDLA_S502E: - case SDLA_S503: - default: - return -EINVAL; - } - return 0; -} -#endif /* 0 */ - -/*============================================================================ - * Execute Adapter Command. - * o Set exec flag. - * o Busy-wait until flag is reset. - * o Return number of loops made, or 0 if command timed out. - */ - -EXPORT_SYMBOL(sdla_exec); - -int sdla_exec (void* opflag) -{ - volatile unsigned char* flag = opflag; - unsigned long tstop; - int nloops; - - if(readb(flag) != 0x00) { - printk(KERN_INFO - "WANPIPE: opp flag set on entry to sdla_exec\n"); - return 0; - } - - writeb(0x01, flag); - - tstop = SYSTEM_TICK + EXEC_TIMEOUT; - - for (nloops = 1; (readb(flag) == 0x01); ++ nloops) { - unsigned delay = exec_idle; - while (-- delay); /* delay */ - if (SYSTEM_TICK > tstop) return 0; /* time is up! */ - } - return nloops; -} - -/*============================================================================ - * Read absolute adapter memory. - * Transfer data from adapter's memory to data buffer. - * - * Note: - * Care should be taken when crossing dual-port memory window boundary. - * This function is not atomic, so caller must disable interrupt if - * interrupt routines are accessing adapter shared memory. - */ - -EXPORT_SYMBOL(sdla_peek); - -int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) -{ - - if (addr + len > hw->memory) /* verify arguments */ - return -EINVAL; - - if(hw->type == SDLA_S514) { /* copy data for the S514 adapter */ - peek_by_4 ((unsigned long)hw->dpmbase + addr, buf, len); - return 0; - } - - else { /* copy data for the S508 adapter */ - unsigned long oldvec = hw->vector; - unsigned winsize = hw->dpmsize; - unsigned curpos, curlen; /* current offset and block size */ - unsigned long curvec; /* current DPM window vector */ - int err = 0; - - while (len && !err) { - curpos = addr % winsize; /* current window offset */ - curvec = addr - curpos; /* current window vector */ - curlen = (len > (winsize - curpos)) ? - (winsize - curpos) : len; - /* Relocate window and copy block of data */ - err = sdla_mapmem(hw, curvec); - peek_by_4 ((unsigned long)hw->dpmbase + curpos, buf, - curlen); - addr += curlen; - buf = (char*)buf + curlen; - len -= curlen; - } - - /* Restore DPM window position */ - sdla_mapmem(hw, oldvec); - return err; - } -} - - -/*============================================================================ - * Read data from adapter's memory to a data buffer in 4-byte chunks. - * Note that we ensure that the SDLA memory address is on a 4-byte boundary - * before we begin moving the data in 4-byte chunks. -*/ - -static void peek_by_4 (unsigned long src, void* buf, unsigned len) -{ - - /* byte copy data until we get to a 4-byte boundary */ - while (len && (src & 0x03)) { - *(char *)buf ++ = readb(src ++); - len --; - } - - /* copy data in 4-byte chunks */ - while (len >= 4) { - *(unsigned long *)buf = readl(src); - buf += 4; - src += 4; - len -= 4; - } - - /* byte copy any remaining data */ - while (len) { - *(char *)buf ++ = readb(src ++); - len --; - } -} - - -/*============================================================================ - * Write Absolute Adapter Memory. - * Transfer data from data buffer to adapter's memory. - * - * Note: - * Care should be taken when crossing dual-port memory window boundary. - * This function is not atomic, so caller must disable interrupt if - * interrupt routines are accessing adapter shared memory. - */ - -EXPORT_SYMBOL(sdla_poke); - -int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) -{ - - if (addr + len > hw->memory) /* verify arguments */ - return -EINVAL; - - if(hw->type == SDLA_S514) { /* copy data for the S514 adapter */ - poke_by_4 ((unsigned long)hw->dpmbase + addr, buf, len); - return 0; - } - - else { /* copy data for the S508 adapter */ - unsigned long oldvec = hw->vector; - unsigned winsize = hw->dpmsize; - unsigned curpos, curlen; /* current offset and block size */ - unsigned long curvec; /* current DPM window vector */ - int err = 0; - - while (len && !err) { - curpos = addr % winsize; /* current window offset */ - curvec = addr - curpos; /* current window vector */ - curlen = (len > (winsize - curpos)) ? - (winsize - curpos) : len; - /* Relocate window and copy block of data */ - sdla_mapmem(hw, curvec); - poke_by_4 ((unsigned long)hw->dpmbase + curpos, buf, - curlen); - addr += curlen; - buf = (char*)buf + curlen; - len -= curlen; - } - - /* Restore DPM window position */ - sdla_mapmem(hw, oldvec); - return err; - } -} - - -/*============================================================================ - * Write from a data buffer to adapter's memory in 4-byte chunks. - * Note that we ensure that the SDLA memory address is on a 4-byte boundary - * before we begin moving the data in 4-byte chunks. -*/ - -static void poke_by_4 (unsigned long dest, void* buf, unsigned len) -{ - - /* byte copy data until we get to a 4-byte boundary */ - while (len && (dest & 0x03)) { - writeb (*(char *)buf ++, dest ++); - len --; - } - - /* copy data in 4-byte chunks */ - while (len >= 4) { - writel (*(unsigned long *)buf, dest); - dest += 4; - buf += 4; - len -= 4; - } - - /* byte copy any remaining data */ - while (len) { - writeb (*(char *)buf ++ , dest ++); - len --; - } -} - - -#ifdef DONT_COMPIPLE_THIS -#endif /* DONT_COMPIPLE_THIS */ - -/****** Hardware-Specific Functions *****************************************/ - -/*============================================================================ - * Detect adapter type. - * o if adapter type is specified then call detection routine for that adapter - * type. Otherwise call detection routines for every adapter types until - * adapter is detected. - * - * Notes: - * 1) Detection tests are destructive! Adapter will be left in shutdown state - * after the test. - */ -static int sdla_detect (sdlahw_t* hw) -{ - unsigned port = hw->port; - int err = 0; - - if (!port && (hw->type != SDLA_S514)) - return -EFAULT; - - switch (hw->type) { - case SDLA_S502A: - if (!detect_s502a(port)) err = -ENODEV; - break; - - case SDLA_S502E: - if (!detect_s502e(port)) err = -ENODEV; - break; - - case SDLA_S503: - if (!detect_s503(port)) err = -ENODEV; - break; - - case SDLA_S507: - if (!detect_s507(port)) err = -ENODEV; - break; - - case SDLA_S508: - if (!detect_s508(port)) err = -ENODEV; - break; - - case SDLA_S514: - if (!detect_s514(hw)) err = -ENODEV; - break; - - default: - if (detect_s502a(port)) - hw->type = SDLA_S502A; - else if (detect_s502e(port)) - hw->type = SDLA_S502E; - else if (detect_s503(port)) - hw->type = SDLA_S503; - else if (detect_s507(port)) - hw->type = SDLA_S507; - else if (detect_s508(port)) - hw->type = SDLA_S508; - else err = -ENODEV; - } - return err; -} - -/*============================================================================ - * Autoselect memory region. - * o try all available DMP address options from the top down until success. - */ -static int sdla_autodpm (sdlahw_t* hw) -{ - int i, err = -EINVAL; - unsigned* opt; - - switch (hw->type) { - case SDLA_S502A: - opt = s502a_dpmbase_options; - break; - - case SDLA_S502E: - case SDLA_S503: - case SDLA_S508: - opt = s508_dpmbase_options; - break; - - case SDLA_S507: - opt = s507_dpmbase_options; - break; - - default: - return -EINVAL; - } - - /* Start testing from 8th position, address - * 0xC8000 from the 508 address table. - * We don't want to test A**** addresses, since - * they are usually used for Video */ - for (i = 8; i <= opt[0] && err; i++) { - hw->dpmbase = phys_to_virt(opt[i]); - err = sdla_setdpm(hw); - } - return err; -} - -/*============================================================================ - * Set up adapter dual-port memory window. - * o shut down adapter - * o make sure that no physical memory exists in this region, i.e entire - * region reads 0xFF and is not writable when adapter is shut down. - * o initialize adapter hardware - * o make sure that region is usable with SDLA card, i.e. we can write to it - * when adapter is configured. - */ -static int sdla_setdpm (sdlahw_t* hw) -{ - int err; - - /* Shut down card and verify memory region */ - sdla_down(hw); - if (check_memregion(hw->dpmbase, hw->dpmsize)) - return -EINVAL; - - /* Initialize adapter and test on-board memory segment by segment. - * If memory size appears to be less than shared memory window size, - * assume that memory region is unusable. - */ - err = sdla_init(hw); - if (err) return err; - - if (sdla_memtest(hw) < hw->dpmsize) { /* less than window size */ - sdla_down(hw); - return -EIO; - } - sdla_mapmem(hw, 0L); /* set window vector at bottom */ - return 0; -} - -/*============================================================================ - * Load adapter from the memory image of the SDLA firmware module. - * o verify firmware integrity and compatibility - * o start adapter up - */ -static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len) -{ - - int i; - - /* Verify firmware signature */ - if (strcmp(sfm->signature, SFM_SIGNATURE)) { - printk(KERN_INFO "%s: not SDLA firmware!\n", - modname); - return -EINVAL; - } - - /* Verify firmware module format version */ - if (sfm->version != SFM_VERSION) { - printk(KERN_INFO - "%s: firmware format %u rejected! Expecting %u.\n", - modname, sfm->version, SFM_VERSION); - return -EINVAL; - } - - /* Verify firmware module length and checksum */ - if ((len - offsetof(sfm_t, image) != sfm->info.codesize) || - (checksum((void*)&sfm->info, - sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) { - printk(KERN_INFO "%s: firmware corrupted!\n", modname); - return -EINVAL; - } - - /* Announce */ - printk(KERN_INFO "%s: loading %s (ID=%u)...\n", modname, - (sfm->descr[0] != '\0') ? sfm->descr : "unknown firmware", - sfm->info.codeid); - - if(hw->type == SDLA_S514) - printk(KERN_INFO "%s: loading S514 adapter, CPU %c\n", - modname, hw->S514_cpu_no[0]); - - /* Scan through the list of compatible adapters and make sure our - * adapter type is listed. - */ - for (i = 0; - (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type); - ++i); - - if (i == SFM_MAX_SDLA) { - printk(KERN_INFO "%s: firmware is not compatible with S%u!\n", - modname, hw->type); - return -EINVAL; - } - - - /* Make sure there is enough on-board memory */ - if (hw->memory < sfm->info.memsize) { - printk(KERN_INFO - "%s: firmware needs %lu bytes of on-board memory!\n", - modname, sfm->info.memsize); - return -EINVAL; - } - - /* Move code onto adapter */ - if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) { - printk(KERN_INFO "%s: failed to load code segment!\n", - modname); - return -EIO; - } - - /* Prepare boot-time configuration data and kick-off CPU */ - sdla_bootcfg(hw, &sfm->info); - if (sdla_start(hw, sfm->info.startoffs)) { - printk(KERN_INFO "%s: Damn... Adapter won't start!\n", - modname); - return -EIO; - } - - /* position DPM window over the mailbox and enable interrupts */ - if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) { - printk(KERN_INFO "%s: adapter hardware failure!\n", - modname); - return -EIO; - } - hw->fwid = sfm->info.codeid; /* set firmware ID */ - return 0; -} - -/*============================================================================ - * Initialize SDLA hardware: setup memory window, IRQ, etc. - */ -static int sdla_init (sdlahw_t* hw) -{ - int i; - - for (i = 0; i < SDLA_MAXIORANGE; ++i) - hw->regs[i] = 0; - - switch (hw->type) { - case SDLA_S502A: return init_s502a(hw); - case SDLA_S502E: return init_s502e(hw); - case SDLA_S503: return init_s503(hw); - case SDLA_S507: return init_s507(hw); - case SDLA_S508: return init_s508(hw); - } - return -EINVAL; -} - -/*============================================================================ - * Test adapter on-board memory. - * o slide DPM window from the bottom up and test adapter memory segment by - * segment. - * Return adapter memory size. - */ -static unsigned long sdla_memtest (sdlahw_t* hw) -{ - unsigned long memsize; - unsigned winsize; - - for (memsize = 0, winsize = hw->dpmsize; - !sdla_mapmem(hw, memsize) && - (test_memregion(hw->dpmbase, winsize) == winsize) - ; - memsize += winsize) - ; - hw->memory = memsize; - return memsize; -} - -/*============================================================================ - * Prepare boot-time firmware configuration data. - * o position DPM window - * o initialize configuration data area - */ -static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo) -{ - unsigned char* data; - - if (!sfminfo->datasize) return 0; /* nothing to do */ - - if (sdla_mapmem(hw, sfminfo->dataoffs) != 0) - return -EIO; - - if(hw->type == SDLA_S514) - data = (void*)(hw->dpmbase + sfminfo->dataoffs); - else - data = (void*)((u8 *)hw->dpmbase + - (sfminfo->dataoffs - hw->vector)); - - memset_io (data, 0, sfminfo->datasize); - - writeb (make_config_byte(hw), &data[0x00]); - - switch (sfminfo->codeid) { - case SFID_X25_502: - case SFID_X25_508: - writeb (3, &data[0x01]); /* T1 timer */ - writeb (10, &data[0x03]); /* N2 */ - writeb (7, &data[0x06]); /* HDLC window size */ - writeb (1, &data[0x0B]); /* DTE */ - writeb (2, &data[0x0C]); /* X.25 packet window size */ - writew (128, &data[0x0D]); /* default X.25 data size */ - writew (128, &data[0x0F]); /* maximum X.25 data size */ - break; - } - return 0; -} - -/*============================================================================ - * Prepare configuration byte identifying adapter type and CPU clock rate. - */ -static unsigned char make_config_byte (sdlahw_t* hw) -{ - unsigned char byte = 0; - - switch (hw->pclk) { - case 5000: byte = 0x01; break; - case 7200: byte = 0x02; break; - case 8000: byte = 0x03; break; - case 10000: byte = 0x04; break; - case 16000: byte = 0x05; break; - } - - switch (hw->type) { - case SDLA_S502E: byte |= 0x80; break; - case SDLA_S503: byte |= 0x40; break; - } - return byte; -} - -/*============================================================================ - * Start adapter's CPU. - * o calculate a pointer to adapter's cold boot entry point - * o position DPM window - * o place boot instruction (jp addr) at cold boot entry point - * o start CPU - */ -static int sdla_start (sdlahw_t* hw, unsigned addr) -{ - unsigned port = hw->port; - unsigned char *bootp; - int err, tmp, i; - - if (!port && (hw->type != SDLA_S514)) return -EFAULT; - - switch (hw->type) { - case SDLA_S502A: - bootp = hw->dpmbase; - bootp += 0x66; - break; - - case SDLA_S502E: - case SDLA_S503: - case SDLA_S507: - case SDLA_S508: - case SDLA_S514: - bootp = hw->dpmbase; - break; - - default: - return -EINVAL; - } - - err = sdla_mapmem(hw, 0); - if (err) return err; - - writeb (0xC3, bootp); /* Z80: 'jp' opcode */ - bootp ++; - writew (addr, bootp); - - switch (hw->type) { - case SDLA_S502A: - _OUTB(port, 0x10); /* issue NMI to CPU */ - hw->regs[0] = 0x10; - break; - - case SDLA_S502E: - _OUTB(port + 3, 0x01); /* start CPU */ - hw->regs[3] = 0x01; - for (i = 0; i < SDLA_IODELAY; ++i); - if (_INB(port) & 0x01) { /* verify */ - /* - * Enabling CPU changes functionality of the - * control register, so we have to reset its - * mirror. - */ - _OUTB(port, 0); /* disable interrupts */ - hw->regs[0] = 0; - } - else return -EIO; - break; - - case SDLA_S503: - tmp = hw->regs[0] | 0x09; /* set bits 0 and 3 */ - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); - if (!(_INB(port) & 0x01)) /* verify */ - return -EIO; - break; - - case SDLA_S507: - tmp = hw->regs[0] | 0x02; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); - if (!(_INB(port) & 0x04)) /* verify */ - return -EIO; - break; - - case SDLA_S508: - tmp = hw->regs[0] | 0x02; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); - if (!(_INB(port + 1) & 0x02)) /* verify */ - return -EIO; - break; - - case SDLA_S514: - writeb (S514_CPU_START, hw->vector); - break; - - default: - return -EINVAL; - } - return 0; -} - -/*============================================================================ - * Initialize S502A adapter. - */ -static int init_s502a (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s502a(port)) - return -ENODEV; - - hw->regs[0] = 0x08; - hw->regs[1] = 0xFF; - - /* Verify configuration options */ - i = get_option_index(s502a_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL; - - tmp = s502a_hmcr[i - 1]; - switch (hw->dpmsize) { - case 0x2000: - tmp |= 0x01; - break; - - case 0x10000L: - break; - - default: - return -EINVAL; - } - - /* Setup dual-port memory window (this also enables memory access) */ - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - hw->regs[0] = 0x08; - return 0; -} - -/*============================================================================ - * Initialize S502E adapter. - */ -static int init_s502e (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s502e(port)) - return -ENODEV; - - /* Verify configuration options */ - i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL; - - tmp = s502e_hmcr[i - 1]; - switch (hw->dpmsize) { - case 0x2000: - tmp |= 0x01; - break; - - case 0x10000L: - break; - - default: - return -EINVAL; - } - - /* Setup dual-port memory window */ - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - - /* Enable memory access */ - _OUTB(port, 0x02); - hw->regs[0] = 0x02; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - return (_INB(port) & 0x02) ? 0 : -EIO; -} - -/*============================================================================ - * Initialize S503 adapter. - * --------------------------------------------------------------------------- - */ -static int init_s503 (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s503(port)) - return -ENODEV; - - /* Verify configuration options */ - i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL; - - tmp = s502e_hmcr[i - 1]; - switch (hw->dpmsize) { - case 0x2000: - tmp |= 0x01; - break; - - case 0x10000L: - break; - - default: - return -EINVAL; - } - - /* Setup dual-port memory window */ - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - - /* Enable memory access */ - _OUTB(port, 0x02); - hw->regs[0] = 0x02; /* update mirror */ - return 0; -} - -/*============================================================================ - * Initialize S507 adapter. - */ -static int init_s507 (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s507(port)) - return -ENODEV; - - /* Verify configuration options */ - i = get_option_index(s507_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL; - - tmp = s507_hmcr[i - 1]; - switch (hw->dpmsize) { - case 0x2000: - tmp |= 0x01; - break; - - case 0x10000L: - break; - - default: - return -EINVAL; - } - - /* Enable adapter's logic */ - _OUTB(port, 0x01); - hw->regs[0] = 0x01; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (!(_INB(port) & 0x20)) - return -EIO; - - /* Setup dual-port memory window */ - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - - /* Enable memory access */ - tmp = hw->regs[0] | 0x04; - if (hw->irq) { - i = get_option_index(s508_irq_options, hw->irq); - if (i) tmp |= s507_irqmask[i - 1]; - } - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - return (_INB(port) & 0x08) ? 0 : -EIO; -} - -/*============================================================================ - * Initialize S508 adapter. - */ -static int init_s508 (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s508(port)) - return -ENODEV; - - /* Verify configuration options */ - i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL; - - /* Setup memory configuration */ - tmp = s508_hmcr[i - 1]; - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - - /* Enable memory access */ - _OUTB(port, 0x04); - hw->regs[0] = 0x04; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - return (_INB(port + 1) & 0x04) ? 0 : -EIO; -} - -/*============================================================================ - * Detect S502A adapter. - * Following tests are used to detect S502A adapter: - * 1. All registers other than status (BASE) should read 0xFF - * 2. After writing 00001000b to control register, status register should - * read 01000000b. - * 3. After writing 0 to control register, status register should still - * read 01000000b. - * 4. After writing 00000100b to control register, status register should - * read 01000100b. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s502a (int port) -{ - int i, j; - - if (!get_option_index(s502_port_options, port)) - return 0; - - for (j = 1; j < SDLA_MAXIORANGE; ++j) { - if (_INB(port + j) != 0xFF) - return 0; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - } - - _OUTB(port, 0x08); /* halt CPU */ - _OUTB(port, 0x08); - _OUTB(port, 0x08); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0x40) - return 0; - _OUTB(port, 0x00); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0x40) - return 0; - _OUTB(port, 0x04); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0x44) - return 0; - - /* Reset adapter */ - _OUTB(port, 0x08); - _OUTB(port, 0x08); - _OUTB(port, 0x08); - _OUTB(port + 1, 0xFF); - return 1; -} - -/*============================================================================ - * Detect S502E adapter. - * Following tests are used to verify adapter presence: - * 1. All registers other than status (BASE) should read 0xFF. - * 2. After writing 0 to CPU control register (BASE+3), status register - * (BASE) should read 11111000b. - * 3. After writing 00000100b to port BASE (set bit 2), status register - * (BASE) should read 11111100b. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s502e (int port) -{ - int i, j; - - if (!get_option_index(s502_port_options, port)) - return 0; - for (j = 1; j < SDLA_MAXIORANGE; ++j) { - if (_INB(port + j) != 0xFF) - return 0; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - } - - _OUTB(port + 3, 0); /* CPU control reg. */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0xF8) /* read status */ - return 0; - _OUTB(port, 0x04); /* set bit 2 */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0xFC) /* verify */ - return 0; - - /* Reset adapter */ - _OUTB(port, 0); - return 1; -} - -/*============================================================================ - * Detect s503 adapter. - * Following tests are used to verify adapter presence: - * 1. All registers other than status (BASE) should read 0xFF. - * 2. After writing 0 to control register (BASE), status register (BASE) - * should read 11110000b. - * 3. After writing 00000100b (set bit 2) to control register (BASE), - * status register should read 11110010b. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s503 (int port) -{ - int i, j; - - if (!get_option_index(s503_port_options, port)) - return 0; - for (j = 1; j < SDLA_MAXIORANGE; ++j) { - if (_INB(port + j) != 0xFF) - return 0; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - } - - _OUTB(port, 0); /* reset control reg.*/ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0xF0) /* read status */ - return 0; - _OUTB(port, 0x04); /* set bit 2 */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0xF2) /* verify */ - return 0; - - /* Reset adapter */ - _OUTB(port, 0); - return 1; -} - -/*============================================================================ - * Detect s507 adapter. - * Following tests are used to detect s507 adapter: - * 1. All ports should read the same value. - * 2. After writing 0x00 to control register, status register should read - * ?011000?b. - * 3. After writing 0x01 to control register, status register should read - * ?011001?b. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s507 (int port) -{ - int tmp, i, j; - - if (!get_option_index(s508_port_options, port)) - return 0; - tmp = _INB(port); - for (j = 1; j < S507_IORANGE; ++j) { - if (_INB(port + j) != tmp) - return 0; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - } - - _OUTB(port, 0x00); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if ((_INB(port) & 0x7E) != 0x30) - return 0; - _OUTB(port, 0x01); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if ((_INB(port) & 0x7E) != 0x32) - return 0; - - /* Reset adapter */ - _OUTB(port, 0x00); - return 1; -} - -/*============================================================================ - * Detect s508 adapter. - * Following tests are used to detect s508 adapter: - * 1. After writing 0x00 to control register, status register should read - * ??000000b. - * 2. After writing 0x10 to control register, status register should read - * ??010000b - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s508 (int port) -{ - int i; - - if (!get_option_index(s508_port_options, port)) - return 0; - _OUTB(port, 0x00); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if ((_INB(port + 1) & 0x3F) != 0x00) - return 0; - _OUTB(port, 0x10); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if ((_INB(port + 1) & 0x3F) != 0x10) - return 0; - - /* Reset adapter */ - _OUTB(port, 0x00); - return 1; -} - -/*============================================================================ - * Detect s514 PCI adapter. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s514 (sdlahw_t* hw) -{ - unsigned char CPU_no, slot_no, auto_slot_cfg; - int number_S514_cards = 0; - u32 S514_mem_base_addr = 0; - u32 ut_u32; - struct pci_dev *pci_dev; - - -#ifndef CONFIG_PCI - printk(KERN_INFO "%s: Linux not compiled for PCI usage!\n", modname); - return 0; -#endif - - /* - The 'setup()' procedure in 'sdlamain.c' passes the CPU number and the - slot number defined in 'router.conf' via the 'port' definition. - */ - CPU_no = hw->S514_cpu_no[0]; - slot_no = hw->S514_slot_no; - auto_slot_cfg = hw->auto_pci_cfg; - - if (auto_slot_cfg){ - printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot=Auto\n", - modname, CPU_no); - - }else{ - printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot #%d\n", - modname, CPU_no, slot_no); - } - - /* check to see that CPU A or B has been selected in 'router.conf' */ - switch(CPU_no) { - case S514_CPU_A: - case S514_CPU_B: - break; - - default: - printk(KERN_INFO "%s: S514 CPU definition invalid.\n", - modname); - printk(KERN_INFO "Must be 'A' or 'B'\n"); - return 0; - } - - number_S514_cards = find_s514_adapter(hw, 0); - if(!number_S514_cards) - return 0; - - /* we are using a single S514 adapter with a slot of 0 so re-read the */ - /* location of this adapter */ - if((number_S514_cards == 1) && auto_slot_cfg) { - number_S514_cards = find_s514_adapter(hw, 1); - if(!number_S514_cards) { - printk(KERN_INFO "%s: Error finding PCI card\n", - modname); - return 0; - } - } - - pci_dev = hw->pci_dev; - /* read the physical memory base address */ - S514_mem_base_addr = (CPU_no == S514_CPU_A) ? - (pci_dev->resource[1].start) : - (pci_dev->resource[2].start); - - printk(KERN_INFO "%s: S514 PCI memory at 0x%X\n", - modname, S514_mem_base_addr); - if(!S514_mem_base_addr) { - if(CPU_no == S514_CPU_B) - printk(KERN_INFO "%s: CPU #B not present on the card\n", modname); - else - printk(KERN_INFO "%s: No PCI memory allocated to card\n", modname); - return 0; - } - - /* enable the PCI memory */ - pci_read_config_dword(pci_dev, - (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, - &ut_u32); - pci_write_config_dword(pci_dev, - (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, - (ut_u32 | PCI_MEMORY_ENABLE)); - - /* check the IRQ allocated and enable IRQ usage */ - if(!(hw->irq = pci_dev->irq)) { - printk(KERN_INFO "%s: IRQ not allocated to S514 adapter\n", - modname); - return 0; - } - - /* BUG FIX : Mar 6 2000 - * On a initial loading of the card, we must check - * and clear PCI interrupt bits, due to a reset - * problem on some other boards. i.e. An interrupt - * might be pending, even after system bootup, - * in which case, when starting wanrouter the machine - * would crash. - */ - if (init_pci_slot(hw)) - return 0; - - pci_read_config_dword(pci_dev, PCI_INT_CONFIG, &ut_u32); - ut_u32 |= (CPU_no == S514_CPU_A) ? - PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B; - pci_write_config_dword(pci_dev, PCI_INT_CONFIG, ut_u32); - - printk(KERN_INFO "%s: IRQ %d allocated to the S514 card\n", - modname, hw->irq); - - /* map the physical PCI memory to virtual memory */ - hw->dpmbase = ioremap((unsigned long)S514_mem_base_addr, - (unsigned long)MAX_SIZEOF_S514_MEMORY); - /* map the physical control register memory to virtual memory */ - hw->vector = (unsigned long)ioremap( - (unsigned long)(S514_mem_base_addr + S514_CTRL_REG_BYTE), - (unsigned long)16); - - if(!hw->dpmbase || !hw->vector) { - printk(KERN_INFO "%s: PCI virtual memory allocation failed\n", - modname); - return 0; - } - - /* halt the adapter */ - writeb (S514_CPU_HALT, hw->vector); - - return 1; -} - -/*============================================================================ - * Find the S514 PCI adapter in the PCI bus. - * Return the number of S514 adapters found (0 if no adapter found). - */ -static int find_s514_adapter(sdlahw_t* hw, char find_first_S514_card) -{ - unsigned char slot_no; - int number_S514_cards = 0; - char S514_found_in_slot = 0; - u16 PCI_subsys_vendor; - - struct pci_dev *pci_dev = NULL; - - slot_no = hw->S514_slot_no; - - while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) - != NULL) { - - pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD, - &PCI_subsys_vendor); - - if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) - continue; - - hw->pci_dev = pci_dev; - - if(find_first_S514_card) - return(1); - - number_S514_cards ++; - - printk(KERN_INFO - "%s: S514 card found, slot #%d (devfn 0x%X)\n", - modname, ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), - pci_dev->devfn); - - if (hw->auto_pci_cfg){ - hw->S514_slot_no = ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK); - slot_no = hw->S514_slot_no; - - }else if (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) == slot_no){ - S514_found_in_slot = 1; - break; - } - } - - /* if no S514 adapter has been found, then exit */ - if (!number_S514_cards) { - printk(KERN_INFO "%s: Error, no S514 adapters found\n", modname); - return 0; - } - /* if more than one S514 card has been found, then the user must have */ /* defined a slot number so that the correct adapter is used */ - else if ((number_S514_cards > 1) && hw->auto_pci_cfg) { - printk(KERN_INFO "%s: Error, PCI Slot autodetect Failed! \n" - "%s: More than one S514 adapter found.\n" - "%s: Disable the Autodetect feature and supply\n" - "%s: the PCISLOT numbers for each card.\n", - modname,modname,modname,modname); - return 0; - } - /* if the user has specified a slot number and the S514 adapter has */ - /* not been found in that slot, then exit */ - else if (!hw->auto_pci_cfg && !S514_found_in_slot) { - printk(KERN_INFO - "%s: Error, S514 card not found in specified slot #%d\n", - modname, slot_no); - return 0; - } - - return (number_S514_cards); -} - - - -/******* Miscellaneous ******************************************************/ - -/*============================================================================ - * Calibrate SDLA memory access delay. - * Count number of idle loops made within 1 second and then calculate the - * number of loops that should be made to achive desired delay. - */ -static int calibrate_delay (int mks) -{ - unsigned int delay; - unsigned long stop; - - for (delay = 0, stop = SYSTEM_TICK + HZ; SYSTEM_TICK < stop; ++delay); - return (delay/(1000000L/mks) + 1); -} - -/*============================================================================ - * Get option's index into the options list. - * Return option's index (1 .. N) or zero if option is invalid. - */ -static int get_option_index (unsigned* optlist, unsigned optval) -{ - int i; - - for (i = 1; i <= optlist[0]; ++i) - if ( optlist[i] == optval) - return i; - return 0; -} - -/*============================================================================ - * Check memory region to see if it's available. - * Return: 0 ok. - */ -static unsigned check_memregion (void* ptr, unsigned len) -{ - volatile unsigned char* p = ptr; - - for (; len && (readb (p) == 0xFF); --len, ++p) { - writeb (0, p); /* attempt to write 0 */ - if (readb(p) != 0xFF) { /* still has to read 0xFF */ - writeb (0xFF, p);/* restore original value */ - break; /* not good */ - } - } - - return len; -} - -/*============================================================================ - * Test memory region. - * Return: size of the region that passed the test. - * Note: Region size must be multiple of 2 ! - */ -static unsigned test_memregion (void* ptr, unsigned len) -{ - volatile unsigned short* w_ptr; - unsigned len_w = len >> 1; /* region len in words */ - unsigned i; - - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - writew (0xAA55, w_ptr); - - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - if (readw (w_ptr) != 0xAA55) { - len_w = i; - break; - } - - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - writew (0x55AA, w_ptr); - - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - if (readw(w_ptr) != 0x55AA) { - len_w = i; - break; - } - - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - writew (0, w_ptr); - - return len_w << 1; -} - -/*============================================================================ - * Calculate 16-bit CRC using CCITT polynomial. - */ -static unsigned short checksum (unsigned char* buf, unsigned len) -{ - unsigned short crc = 0; - unsigned mask, flag; - - for (; len; --len, ++buf) { - for (mask = 0x80; mask; mask >>= 1) { - flag = (crc & 0x8000); - crc <<= 1; - crc |= ((*buf & mask) ? 1 : 0); - if (flag) crc ^= 0x1021; - } - } - return crc; -} - -static int init_pci_slot(sdlahw_t *hw) -{ - - u32 int_status; - int volatile found=0; - int i=0; - - /* Check if this is a very first load for a specific - * pci card. If it is, clear the interrput bits, and - * set the flag indicating that this card was initialized. - */ - - for (i=0; (iS514_slot_no){ - found=1; - break; - } - if (pci_slot_ar[i] == 0xFF){ - break; - } - } - - if (!found){ - read_S514_int_stat(hw,&int_status); - S514_intack(hw,int_status); - if (i == MAX_S514_CARDS){ - printk(KERN_INFO "%s: Critical Error !!!\n",modname); - printk(KERN_INFO - "%s: Number of Sangoma PCI cards exceeded maximum limit.\n", - modname); - printk(KERN_INFO "Please contact Sangoma Technologies\n"); - return 1; - } - pci_slot_ar[i] = hw->S514_slot_no; - } - return 0; -} - -static int pci_probe(sdlahw_t *hw) -{ - - unsigned char slot_no; - int number_S514_cards = 0; - u16 PCI_subsys_vendor; - u16 PCI_card_type; - - struct pci_dev *pci_dev = NULL; - struct pci_bus *bus = NULL; - - slot_no = 0; - - while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) - != NULL) { - - pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD, - &PCI_subsys_vendor); - - if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) - continue; - - pci_read_config_word(pci_dev, PCI_CARD_TYPE, - &PCI_card_type); - - bus = pci_dev->bus; - - /* A dual cpu card can support up to 4 physical connections, - * where a single cpu card can support up to 2 physical - * connections. The FT1 card can only support a single - * connection, however we cannot distinguish between a Single - * CPU card and an FT1 card. */ - if (PCI_card_type == S514_DUAL_CPU){ - number_S514_cards += 4; - printk(KERN_INFO - "wanpipe: S514-PCI card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n", - bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), - pci_dev->irq); - }else{ - number_S514_cards += 2; - printk(KERN_INFO - "wanpipe: S514-PCI card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n", - bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), - pci_dev->irq); - } - } - - return number_S514_cards; - -} - - - -EXPORT_SYMBOL(wanpipe_hw_probe); - -unsigned wanpipe_hw_probe(void) -{ - sdlahw_t hw; - unsigned* opt = s508_port_options; - unsigned cardno=0; - int i; - - memset(&hw, 0, sizeof(hw)); - - for (i = 1; i <= opt[0]; i++) { - if (detect_s508(opt[i])){ - /* S508 card can support up to two physical links */ - cardno+=2; - printk(KERN_INFO "wanpipe: S508-ISA card found, port 0x%x\n",opt[i]); - } - } - - #ifdef CONFIG_PCI - hw.S514_slot_no = 0; - cardno += pci_probe(&hw); - #else - printk(KERN_INFO "wanpipe: Warning, Kernel not compiled for PCI support!\n"); - printk(KERN_INFO "wanpipe: PCI Hardware Probe Failed!\n"); - #endif - - return cardno; -} - -/****** End *****************************************************************/ diff --git a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c deleted file mode 100644 index 7a8b22a..0000000 --- a/drivers/net/wan/sdlamain.c +++ /dev/null @@ -1,1346 +0,0 @@ -/**************************************************************************** -* sdlamain.c WANPIPE(tm) Multiprotocol WAN Link Driver. Main module. -* -* Author: Nenad Corbic -* Gideon Hack -* -* Copyright: (c) 1995-2000 Sangoma Technologies Inc. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version -* 2 of the License, or (at your option) any later version. -* ============================================================================ -* Dec 22, 2000 Nenad Corbic Updated for 2.4.X kernels. -* Removed the polling routine. -* Nov 13, 2000 Nenad Corbic Added hw probing on module load and dynamic -* device allocation. -* Nov 7, 2000 Nenad Corbic Fixed the Multi-Port PPP for kernels -* 2.2.16 and above. -* Aug 2, 2000 Nenad Corbic Block the Multi-Port PPP from running on -* kernels 2.2.16 or greater. The SyncPPP -* has changed. -* Jul 25, 2000 Nenad Corbic Updated the Piggiback support for MultPPPP. -* Jul 13, 2000 Nenad Corbic Added Multi-PPP support. -* Feb 02, 2000 Nenad Corbic Fixed up piggyback probing and selection. -* Sep 23, 1999 Nenad Corbic Added support for SMP -* Sep 13, 1999 Nenad Corbic Each port is treated as a separate device. -* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. -* Updates for Linux 2.2.X kernels. -* Sep 17, 1998 Jaspreet Singh Updated for 2.1.121+ kernel -* Nov 28, 1997 Jaspreet Singh Changed DRV_RELEASE to 1 -* Nov 10, 1997 Jaspreet Singh Changed sti() to restore_flags(); -* Nov 06, 1997 Jaspreet Singh Changed DRV_VERSION to 4 and DRV_RELEASE to 0 -* Oct 20, 1997 Jaspreet Singh Modified sdla_isr routine so that card->in_isr -* assignments are taken out and placed in the -* sdla_ppp.c, sdla_fr.c and sdla_x25.c isr -* routines. Took out 'wandev->tx_int_enabled' and -* replaced it with 'wandev->enable_tx_int'. -* May 29, 1997 Jaspreet Singh Flow Control Problem -* added "wandev->tx_int_enabled=1" line in the -* init module. This line initializes the flag for -* preventing Interrupt disabled with device set to -* busy -* Jan 15, 1997 Gene Kozin Version 3.1.0 -* o added UDP management stuff -* Jan 02, 1997 Gene Kozin Initial version. -*****************************************************************************/ - -#include /* OS configuration options */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include -#include /* kmalloc(), kfree() */ -#include /* printk(), and other useful stuff */ -#include /* support for loadable modules */ -#include /* request_region(), release_region() */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include - -#include -#include /* phys_to_virt() */ -#include -#include -#include - -#include /* kernel <-> user copy */ -#include - -#include -#include - -#define KMEM_SAFETYZONE 8 - - -#ifndef CONFIG_WANPIPE_FR - #define wpf_init(a,b) (-EPROTONOSUPPORT) -#endif - -#ifndef CONFIG_WANPIPE_CHDLC - #define wpc_init(a,b) (-EPROTONOSUPPORT) -#endif - -#ifndef CONFIG_WANPIPE_X25 - #define wpx_init(a,b) (-EPROTONOSUPPORT) -#endif - -#ifndef CONFIG_WANPIPE_PPP - #define wpp_init(a,b) (-EPROTONOSUPPORT) -#endif - -#ifndef CONFIG_WANPIPE_MULTPPP - #define wsppp_init(a,b) (-EPROTONOSUPPORT) -#endif - - -/***********FOR DEBUGGING PURPOSES********************************************* -static void * dbg_kmalloc(unsigned int size, int prio, int line) { - int i = 0; - void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); - char * c1 = v; - c1 += sizeof(unsigned int); - *((unsigned int *)v) = size; - - for (i = 0; i < KMEM_SAFETYZONE; i++) { - c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; - c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; - c1 += 8; - } - c1 += size; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; - c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; - c1 += 8; - } - v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; - printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); - return v; -} -static void dbg_kfree(void * v, int line) { - unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); - unsigned int size = *sp; - char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; - int i = 0; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' - || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { - printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); - printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, - c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); - } - c1 += 8; - } - c1 += size; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' - || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' - ) { - printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); - printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, - c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); - } - c1 += 8; - } - printk(KERN_INFO "line %d kfree(%p)\n",line,v); - v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); - kfree(v); -} - -#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) -#define kfree(x) dbg_kfree(x,__LINE__) -******************************************************************************/ - - - -/****** Defines & Macros ****************************************************/ - -#ifdef _DEBUG_ -#define STATIC -#else -#define STATIC static -#endif - -#define DRV_VERSION 5 /* version number */ -#define DRV_RELEASE 0 /* release (minor version) number */ -#define MAX_CARDS 16 /* max number of adapters */ - -#ifndef CONFIG_WANPIPE_CARDS /* configurable option */ -#define CONFIG_WANPIPE_CARDS 1 -#endif - -#define CMD_OK 0 /* normal firmware return code */ -#define CMD_TIMEOUT 0xFF /* firmware command timed out */ -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ -/****** Function Prototypes *************************************************/ - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/* WAN link driver entry points */ -static int setup(struct wan_device* wandev, wandev_conf_t* conf); -static int shutdown(struct wan_device* wandev); -static int ioctl(struct wan_device* wandev, unsigned cmd, unsigned long arg); - -/* IOCTL handlers */ -static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump); -static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int); - -/* Miscellaneous functions */ -STATIC irqreturn_t sdla_isr (int irq, void* dev_id, struct pt_regs *regs); -static void release_hw (sdla_t *card); - -static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int*); -static int check_s514_conflicts (sdla_t* card,wandev_conf_t* conf, int*); - - -/****** Global Data ********************************************************** - * Note: All data must be explicitly initialized!!! - */ - -/* private data */ -static char drvname[] = "wanpipe"; -static char fullname[] = "WANPIPE(tm) Multiprotocol Driver"; -static char copyright[] = "(c) 1995-2000 Sangoma Technologies Inc."; -static int ncards; -static sdla_t* card_array; /* adapter data space */ - -/* Wanpipe's own workqueue, used for all API's. - * All protocol specific tasks will be inserted - * into the "wanpipe_wq" workqueue. - - * The kernel workqueue mechanism will execute - * all pending tasks in the "wanpipe_wq" workqueue. - */ - -struct workqueue_struct *wanpipe_wq; -DECLARE_WORK(wanpipe_work, NULL, NULL); - -static int wanpipe_bh_critical; - -/******* Kernel Loadable Module Entry Points ********************************/ - -/*============================================================================ - * Module 'insert' entry point. - * o print announcement - * o allocate adapter data space - * o initialize static data - * o register all cards with WAN router - * o calibrate SDLA shared memory access delay. - * - * Return: 0 Ok - * < 0 error. - * Context: process - */ - -static int __init wanpipe_init(void) -{ - int cnt, err = 0; - - printk(KERN_INFO "%s v%u.%u %s\n", - fullname, DRV_VERSION, DRV_RELEASE, copyright); - - wanpipe_wq = create_workqueue("wanpipe_wq"); - if (!wanpipe_wq) - return -ENOMEM; - - /* Probe for wanpipe cards and return the number found */ - printk(KERN_INFO "wanpipe: Probing for WANPIPE hardware.\n"); - ncards = wanpipe_hw_probe(); - if (ncards){ - printk(KERN_INFO "wanpipe: Allocating maximum %i devices: wanpipe%i - wanpipe%i.\n",ncards,1,ncards); - }else{ - printk(KERN_INFO "wanpipe: No S514/S508 cards found, unloading modules!\n"); - destroy_workqueue(wanpipe_wq); - return -ENODEV; - } - - /* Verify number of cards and allocate adapter data space */ - card_array = kmalloc(sizeof(sdla_t) * ncards, GFP_KERNEL); - if (card_array == NULL) { - destroy_workqueue(wanpipe_wq); - return -ENOMEM; - } - - memset(card_array, 0, sizeof(sdla_t) * ncards); - - /* Register adapters with WAN router */ - for (cnt = 0; cnt < ncards; ++ cnt) { - sdla_t* card = &card_array[cnt]; - struct wan_device* wandev = &card->wandev; - - card->next = NULL; - sprintf(card->devname, "%s%d", drvname, cnt + 1); - wandev->magic = ROUTER_MAGIC; - wandev->name = card->devname; - wandev->private = card; - wandev->enable_tx_int = 0; - wandev->setup = &setup; - wandev->shutdown = &shutdown; - wandev->ioctl = &ioctl; - err = register_wan_device(wandev); - if (err) { - printk(KERN_INFO - "%s: %s registration failed with error %d!\n", - drvname, card->devname, err); - break; - } - } - if (cnt){ - ncards = cnt; /* adjust actual number of cards */ - }else { - kfree(card_array); - destroy_workqueue(wanpipe_wq); - printk(KERN_INFO "IN Init Module: NO Cards registered\n"); - err = -ENODEV; - } - - return err; -} - -/*============================================================================ - * Module 'remove' entry point. - * o unregister all adapters from the WAN router - * o release all remaining system resources - */ -static void __exit wanpipe_cleanup(void) -{ - int i; - - if (!ncards) - return; - - for (i = 0; i < ncards; ++i) { - sdla_t* card = &card_array[i]; - unregister_wan_device(card->devname); - } - destroy_workqueue(wanpipe_wq); - kfree(card_array); - - printk(KERN_INFO "\nwanpipe: WANPIPE Modules Unloaded.\n"); -} - -module_init(wanpipe_init); -module_exit(wanpipe_cleanup); - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Setup/configure WAN link driver. - * o check adapter state - * o make sure firmware is present in configuration - * o make sure I/O port and IRQ are specified - * o make sure I/O region is available - * o allocate interrupt vector - * o setup SDLA hardware - * o call appropriate routine to perform protocol-specific initialization - * o mark I/O region as used - * o if this is the first active card, then schedule background task - * - * This function is called when router handles ROUTER_SETUP IOCTL. The - * configuration structure is in kernel memory (including extended data, if - * any). - */ - -static int setup(struct wan_device* wandev, wandev_conf_t* conf) -{ - sdla_t* card; - int err = 0; - int irq=0; - - /* Sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL)){ - printk(KERN_INFO - "%s: Failed Sdlamain Setup wandev %u, card %u, conf %u !\n", - wandev->name, - (unsigned int)wandev,(unsigned int)wandev->private, - (unsigned int)conf); - return -EFAULT; - } - - printk(KERN_INFO "%s: Starting WAN Setup\n", wandev->name); - - card = wandev->private; - if (wandev->state != WAN_UNCONFIGURED){ - printk(KERN_INFO "%s: failed sdlamain setup, busy!\n", - wandev->name); - return -EBUSY; /* already configured */ - } - - printk(KERN_INFO "\nProcessing WAN device %s...\n", wandev->name); - - /* Initialize the counters for each wandev - * Used for counting number of times new_if and - * del_if get called. - */ - wandev->del_if_cnt = 0; - wandev->new_if_cnt = 0; - wandev->config_id = conf->config_id; - - if (!conf->data_size || (conf->data == NULL)) { - printk(KERN_INFO - "%s: firmware not found in configuration data!\n", - wandev->name); - return -EINVAL; - } - - /* Check for resource conflicts and setup the - * card for piggibacking if necessary */ - if(!conf->S514_CPU_no[0]) { - if ((err=check_s508_conflicts(card,conf,&irq)) != 0){ - return err; - } - }else { - if ((err=check_s514_conflicts(card,conf,&irq)) != 0){ - return err; - } - } - - /* If the current card has already been configured - * or it's a piggyback card, do not try to allocate - * resources. - */ - if (!card->wandev.piggyback && !card->configured){ - - /* Configure hardware, load firmware, etc. */ - memset(&card->hw, 0, sizeof(sdlahw_t)); - - /* for an S514 adapter, pass the CPU number and the slot number read */ - /* from 'router.conf' to the 'sdla_setup()' function via the 'port' */ - /* parameter */ - if (conf->S514_CPU_no[0]){ - - card->hw.S514_cpu_no[0] = conf->S514_CPU_no[0]; - card->hw.S514_slot_no = conf->PCI_slot_no; - card->hw.auto_pci_cfg = conf->auto_pci_cfg; - - if (card->hw.auto_pci_cfg == WANOPT_YES){ - printk(KERN_INFO "%s: Setting CPU to %c and Slot to Auto\n", - card->devname, card->hw.S514_cpu_no[0]); - }else{ - printk(KERN_INFO "%s: Setting CPU to %c and Slot to %i\n", - card->devname, card->hw.S514_cpu_no[0], card->hw.S514_slot_no); - } - - }else{ - /* 508 Card io port and irq initialization */ - card->hw.port = conf->ioport; - card->hw.irq = (conf->irq == 9) ? 2 : conf->irq; - } - - - /* Compute the virtual address of the card in kernel space */ - if(conf->maddr){ - card->hw.dpmbase = phys_to_virt(conf->maddr); - }else{ - card->hw.dpmbase = (void *)conf->maddr; - } - - card->hw.dpmsize = SDLA_WINDOWSIZE; - - /* set the adapter type if using an S514 adapter */ - card->hw.type = (conf->S514_CPU_no[0]) ? SDLA_S514 : conf->hw_opt[0]; - card->hw.pclk = conf->hw_opt[1]; - - err = sdla_setup(&card->hw, conf->data, conf->data_size); - if (err){ - printk(KERN_INFO "%s: Hardware setup Failed %i\n", - card->devname,err); - return err; - } - - if(card->hw.type != SDLA_S514) - irq = (conf->irq == 2) ? 9 : conf->irq; /* IRQ2 -> IRQ9 */ - else - irq = card->hw.irq; - - /* request an interrupt vector - note that interrupts may be shared */ - /* when using the S514 PCI adapter */ - - if(request_irq(irq, sdla_isr, - (card->hw.type == SDLA_S514) ? SA_SHIRQ : 0, - wandev->name, card)){ - - printk(KERN_INFO "%s: Can't reserve IRQ %d!\n", wandev->name, irq); - return -EINVAL; - } - - }else{ - printk(KERN_INFO "%s: Card Configured %lu or Piggybacking %i!\n", - wandev->name,card->configured,card->wandev.piggyback); - } - - - if (!card->configured){ - - /* Initialize the Spin lock */ - printk(KERN_INFO "%s: Initializing for SMP\n",wandev->name); - - /* Piggyback spin lock has already been initialized, - * in check_s514/s508_conflicts() */ - if (!card->wandev.piggyback){ - spin_lock_init(&card->wandev.lock); - } - - /* Intialize WAN device data space */ - wandev->irq = irq; - wandev->dma = 0; - if(card->hw.type != SDLA_S514){ - wandev->ioport = card->hw.port; - }else{ - wandev->S514_cpu_no[0] = card->hw.S514_cpu_no[0]; - wandev->S514_slot_no = card->hw.S514_slot_no; - } - wandev->maddr = (unsigned long)card->hw.dpmbase; - wandev->msize = card->hw.dpmsize; - wandev->hw_opt[0] = card->hw.type; - wandev->hw_opt[1] = card->hw.pclk; - wandev->hw_opt[2] = card->hw.memory; - wandev->hw_opt[3] = card->hw.fwid; - } - - /* Protocol-specific initialization */ - switch (card->hw.fwid) { - - case SFID_X25_502: - case SFID_X25_508: - printk(KERN_INFO "%s: Starting X.25 Protocol Init.\n", - card->devname); - err = wpx_init(card, conf); - break; - case SFID_FR502: - case SFID_FR508: - printk(KERN_INFO "%s: Starting Frame Relay Protocol Init.\n", - card->devname); - err = wpf_init(card, conf); - break; - case SFID_PPP502: - case SFID_PPP508: - printk(KERN_INFO "%s: Starting PPP Protocol Init.\n", - card->devname); - err = wpp_init(card, conf); - break; - - case SFID_CHDLC508: - case SFID_CHDLC514: - if (conf->ft1){ - printk(KERN_INFO "%s: Starting FT1 CSU/DSU Config Driver.\n", - card->devname); - err = wpft1_init(card, conf); - break; - - }else if (conf->config_id == WANCONFIG_MPPP){ - printk(KERN_INFO "%s: Starting Multi-Port PPP Protocol Init.\n", - card->devname); - err = wsppp_init(card,conf); - break; - - }else{ - printk(KERN_INFO "%s: Starting CHDLC Protocol Init.\n", - card->devname); - err = wpc_init(card, conf); - break; - } - default: - printk(KERN_INFO "%s: Error, Firmware is not supported %X %X!\n", - wandev->name,card->hw.fwid,SFID_CHDLC508); - err = -EPROTONOSUPPORT; - } - - if (err != 0){ - if (err == -EPROTONOSUPPORT){ - printk(KERN_INFO - "%s: Error, Protocol selected has not been compiled!\n", - card->devname); - printk(KERN_INFO - "%s: Re-configure the kernel and re-build the modules!\n", - card->devname); - } - - release_hw(card); - wandev->state = WAN_UNCONFIGURED; - return err; - } - - - /* Reserve I/O region and schedule background task */ - if(card->hw.type != SDLA_S514 && !card->wandev.piggyback) - if (!request_region(card->hw.port, card->hw.io_range, - wandev->name)) { - printk(KERN_WARNING "port 0x%04x busy\n", card->hw.port); - release_hw(card); - wandev->state = WAN_UNCONFIGURED; - return -EBUSY; - } - - /* Only use the polling routine for the X25 protocol */ - - card->wandev.critical=0; - return 0; -} - -/*================================================================== - * configure_s508_card - * - * For a S508 adapter, check for a possible configuration error in that - * we are loading an adapter in the same IO port as a previously loaded S508 - * card. - */ - -static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int *irq) -{ - unsigned long smp_flags; - int i; - - if (conf->ioport <= 0) { - printk(KERN_INFO - "%s: can't configure without I/O port address!\n", - card->wandev.name); - return -EINVAL; - } - - if (conf->irq <= 0) { - printk(KERN_INFO "%s: can't configure without IRQ!\n", - card->wandev.name); - return -EINVAL; - } - - if (test_bit(0,&card->configured)) - return 0; - - - /* Check for already loaded card with the same IO port and IRQ - * If found, copy its hardware configuration and use its - * resources (i.e. piggybacking) - */ - - for (i = 0; i < ncards; i++) { - sdla_t *nxt_card = &card_array[i]; - - /* Skip the current card ptr */ - if (nxt_card == card) - continue; - - - /* Find a card that is already configured with the - * same IO Port */ - if ((nxt_card->hw.type == SDLA_S508) && - (nxt_card->hw.port == conf->ioport) && - (nxt_card->next == NULL)){ - - /* We found a card the card that has same configuration - * as us. This means, that we must setup this card in - * piggibacking mode. However, only CHDLC and MPPP protocol - * support this setup */ - - if ((conf->config_id == WANCONFIG_CHDLC || - conf->config_id == WANCONFIG_MPPP) && - (nxt_card->wandev.config_id == WANCONFIG_CHDLC || - nxt_card->wandev.config_id == WANCONFIG_MPPP)){ - - *irq = nxt_card->hw.irq; - memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); - - /* The master could already be running, we must - * set this as a critical area */ - lock_adapter_irq(&nxt_card->wandev.lock, &smp_flags); - - nxt_card->next = card; - card->next = nxt_card; - - card->wandev.piggyback = WANOPT_YES; - - /* We must initialise the piggiback spin lock here - * since isr will try to lock card->next if it - * exists */ - spin_lock_init(&card->wandev.lock); - - unlock_adapter_irq(&nxt_card->wandev.lock, &smp_flags); - break; - }else{ - /* Trying to run piggibacking with a wrong protocol */ - printk(KERN_INFO "%s: ERROR: Resource busy, ioport: 0x%x\n" - "%s: This protocol doesn't support\n" - "%s: multi-port operation!\n", - card->devname,nxt_card->hw.port, - card->devname,card->devname); - return -EEXIST; - } - } - } - - - /* Make sure I/O port region is available only if we are the - * master device. If we are running in piggybacking mode, - * we will use the resources of the master card. */ - if (!card->wandev.piggyback) { - struct resource *rr = - request_region(conf->ioport, SDLA_MAXIORANGE, "sdlamain"); - release_region(conf->ioport, SDLA_MAXIORANGE); - - if (!rr) { - printk(KERN_INFO - "%s: I/O region 0x%X - 0x%X is in use!\n", - card->wandev.name, conf->ioport, - conf->ioport + SDLA_MAXIORANGE - 1); - return -EINVAL; - } - } - - return 0; -} - -/*================================================================== - * configure_s514_card - * - * For a S514 adapter, check for a possible configuration error in that - * we are loading an adapter in the same slot as a previously loaded S514 - * card. - */ - - -static int check_s514_conflicts(sdla_t* card,wandev_conf_t* conf, int *irq) -{ - unsigned long smp_flags; - int i; - - if (test_bit(0,&card->configured)) - return 0; - - - /* Check for already loaded card with the same IO port and IRQ - * If found, copy its hardware configuration and use its - * resources (i.e. piggybacking) - */ - - for (i = 0; i < ncards; i ++) { - - sdla_t* nxt_card = &card_array[i]; - if(nxt_card == card) - continue; - - if((nxt_card->hw.type == SDLA_S514) && - (nxt_card->hw.S514_slot_no == conf->PCI_slot_no) && - (nxt_card->hw.S514_cpu_no[0] == conf->S514_CPU_no[0])&& - (nxt_card->next == NULL)){ - - - if ((conf->config_id == WANCONFIG_CHDLC || - conf->config_id == WANCONFIG_MPPP) && - (nxt_card->wandev.config_id == WANCONFIG_CHDLC || - nxt_card->wandev.config_id == WANCONFIG_MPPP)){ - - *irq = nxt_card->hw.irq; - memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); - - /* The master could already be running, we must - * set this as a critical area */ - lock_adapter_irq(&nxt_card->wandev.lock,&smp_flags); - nxt_card->next = card; - card->next = nxt_card; - - card->wandev.piggyback = WANOPT_YES; - - /* We must initialise the piggiback spin lock here - * since isr will try to lock card->next if it - * exists */ - spin_lock_init(&card->wandev.lock); - - unlock_adapter_irq(&nxt_card->wandev.lock,&smp_flags); - - }else{ - /* Trying to run piggibacking with a wrong protocol */ - printk(KERN_INFO "%s: ERROR: Resource busy: CPU %c PCISLOT %i\n" - "%s: This protocol doesn't support\n" - "%s: multi-port operation!\n", - card->devname, - conf->S514_CPU_no[0],conf->PCI_slot_no, - card->devname,card->devname); - return -EEXIST; - } - } - } - - return 0; -} - - - -/*============================================================================ - * Shut down WAN link driver. - * o shut down adapter hardware - * o release system resources. - * - * This function is called by the router when device is being unregistered or - * when it handles ROUTER_DOWN IOCTL. - */ -static int shutdown(struct wan_device* wandev) -{ - sdla_t *card; - int err=0; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)){ - return -EFAULT; - } - - if (wandev->state == WAN_UNCONFIGURED){ - return 0; - } - - card = wandev->private; - - if (card->tty_opt){ - if (card->tty_open){ - printk(KERN_INFO - "%s: Shutdown Failed: TTY is still open\n", - card->devname); - return -EBUSY; - } - } - - wandev->state = WAN_UNCONFIGURED; - - set_bit(PERI_CRIT,(void*)&wandev->critical); - - /* In case of piggibacking, make sure that - * we never try to shutdown both devices at the same - * time, because they depend on one another */ - - if (card->disable_comm){ - card->disable_comm(card); - } - - /* Release Resources */ - release_hw(card); - - /* only free the allocated I/O range if not an S514 adapter */ - if (wandev->hw_opt[0] != SDLA_S514 && !card->configured){ - release_region(card->hw.port, card->hw.io_range); - } - - if (!card->configured){ - memset(&card->hw, 0, sizeof(sdlahw_t)); - if (card->next){ - memset(&card->next->hw, 0, sizeof(sdlahw_t)); - } - } - - - clear_bit(PERI_CRIT,(void*)&wandev->critical); - return err; -} - -static void release_hw (sdla_t *card) -{ - sdla_t *nxt_card; - - - /* Check if next device exists */ - if (card->next){ - nxt_card = card->next; - /* If next device is down then release resources */ - if (nxt_card->wandev.state == WAN_UNCONFIGURED){ - if (card->wandev.piggyback){ - /* If this device is piggyback then use - * information of the master device - */ - printk(KERN_INFO "%s: Piggyback shutting down\n",card->devname); - sdla_down(&card->next->hw); - free_irq(card->wandev.irq, card->next); - card->configured = 0; - card->next->configured = 0; - card->wandev.piggyback = 0; - }else{ - /* Master device shutting down */ - printk(KERN_INFO "%s: Master shutting down\n",card->devname); - sdla_down(&card->hw); - free_irq(card->wandev.irq, card); - card->configured = 0; - card->next->configured = 0; - } - }else{ - printk(KERN_INFO "%s: Device still running %i\n", - nxt_card->devname,nxt_card->wandev.state); - - card->configured = 1; - } - }else{ - printk(KERN_INFO "%s: Master shutting down\n",card->devname); - sdla_down(&card->hw); - free_irq(card->wandev.irq, card); - card->configured = 0; - } - return; -} - - -/*============================================================================ - * Driver I/O control. - * o verify arguments - * o perform requested action - * - * This function is called when router handles one of the reserved user - * IOCTLs. Note that 'arg' stil points to user address space. - */ -static int ioctl(struct wan_device* wandev, unsigned cmd, unsigned long arg) -{ - sdla_t* card; - int err; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - card = wandev->private; - - if(card->hw.type != SDLA_S514){ - disable_irq(card->hw.irq); - } - - if (test_bit(SEND_CRIT, (void*)&wandev->critical)) { - return -EAGAIN; - } - - switch (cmd) { - case WANPIPE_DUMP: - err = ioctl_dump(wandev->private, (void*)arg); - break; - - case WANPIPE_EXEC: - err = ioctl_exec(wandev->private, (void*)arg, cmd); - break; - default: - err = -EINVAL; - } - - return err; -} - -/****** Driver IOCTL Handlers ***********************************************/ - -/*============================================================================ - * Dump adapter memory to user buffer. - * o verify request structure - * o copy request structure to kernel data space - * o verify length/offset - * o verify user buffer - * o copy adapter memory image to user buffer - * - * Note: when dumping memory, this routine switches curent dual-port memory - * vector, so care must be taken to avoid racing conditions. - */ -static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump) -{ - sdla_dump_t dump; - unsigned winsize; - unsigned long oldvec; /* DPM window vector */ - unsigned long smp_flags; - int err = 0; - - if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t))) - return -EFAULT; - - if ((dump.magic != WANPIPE_MAGIC) || - (dump.offset + dump.length > card->hw.memory)) - return -EINVAL; - - winsize = card->hw.dpmsize; - - if(card->hw.type != SDLA_S514) { - - lock_adapter_irq(&card->wandev.lock, &smp_flags); - - oldvec = card->hw.vector; - while (dump.length) { - /* current offset */ - unsigned pos = dump.offset % winsize; - /* current vector */ - unsigned long vec = dump.offset - pos; - unsigned len = (dump.length > (winsize - pos)) ? - (winsize - pos) : dump.length; - /* relocate window */ - if (sdla_mapmem(&card->hw, vec) != 0) { - err = -EIO; - break; - } - - if(copy_to_user((void *)dump.ptr, - (u8 *)card->hw.dpmbase + pos, len)){ - - unlock_adapter_irq(&card->wandev.lock, &smp_flags); - return -EFAULT; - } - - dump.length -= len; - dump.offset += len; - dump.ptr = (char*)dump.ptr + len; - } - - sdla_mapmem(&card->hw, oldvec);/* restore DPM window position */ - unlock_adapter_irq(&card->wandev.lock, &smp_flags); - - }else { - - if(copy_to_user((void *)dump.ptr, - (u8 *)card->hw.dpmbase + dump.offset, dump.length)){ - return -EFAULT; - } - } - - return err; -} - -/*============================================================================ - * Execute adapter firmware command. - * o verify request structure - * o copy request structure to kernel data space - * o call protocol-specific 'exec' function - */ -static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int cmd) -{ - sdla_exec_t exec; - int err=0; - - if (card->exec == NULL && cmd == WANPIPE_EXEC){ - return -ENODEV; - } - - if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t))) - return -EFAULT; - - if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL)) - return -EINVAL; - - switch (cmd) { - case WANPIPE_EXEC: - err = card->exec(card, exec.cmd, exec.data); - break; - } - return err; -} - -/******* Miscellaneous ******************************************************/ - -/*============================================================================ - * SDLA Interrupt Service Routine. - * o acknowledge SDLA hardware interrupt. - * o call protocol-specific interrupt service routine, if any. - */ -STATIC irqreturn_t sdla_isr (int irq, void* dev_id, struct pt_regs *regs) -{ -#define card ((sdla_t*)dev_id) - - if(card->hw.type == SDLA_S514) { /* handle interrrupt on S514 */ - u32 int_status; - unsigned char CPU_no = card->hw.S514_cpu_no[0]; - unsigned char card_found_for_IRQ; - u8 IRQ_count = 0; - - for(;;) { - - read_S514_int_stat(&card->hw, &int_status); - - /* check if the interrupt is for this device */ - if(!((unsigned char)int_status & - (IRQ_CPU_A | IRQ_CPU_B))) - return IRQ_HANDLED; - - /* if the IRQ is for both CPUs on the same adapter, */ - /* then alter the interrupt status so as to handle */ - /* one CPU at a time */ - if(((unsigned char)int_status & (IRQ_CPU_A | IRQ_CPU_B)) - == (IRQ_CPU_A | IRQ_CPU_B)) { - int_status &= (CPU_no == S514_CPU_A) ? - ~IRQ_CPU_B : ~IRQ_CPU_A; - } - - card_found_for_IRQ = 0; - - /* check to see that the CPU number for this device */ - /* corresponds to the interrupt status read */ - switch (CPU_no) { - case S514_CPU_A: - if((unsigned char)int_status & - IRQ_CPU_A) - card_found_for_IRQ = 1; - break; - - case S514_CPU_B: - if((unsigned char)int_status & - IRQ_CPU_B) - card_found_for_IRQ = 1; - break; - } - - /* exit if the interrupt is for another CPU on the */ - /* same IRQ */ - if(!card_found_for_IRQ) - return IRQ_HANDLED; - - if (!card || - (card->wandev.state == WAN_UNCONFIGURED && !card->configured)){ - printk(KERN_INFO - "Received IRQ %d for CPU #%c\n", - irq, CPU_no); - printk(KERN_INFO - "IRQ for unconfigured adapter\n"); - S514_intack(&card->hw, int_status); - return IRQ_HANDLED; - } - - if (card->in_isr) { - printk(KERN_INFO - "%s: interrupt re-entrancy on IRQ %d\n", - card->devname, card->wandev.irq); - S514_intack(&card->hw, int_status); - return IRQ_HANDLED; - } - - spin_lock(&card->wandev.lock); - if (card->next){ - spin_lock(&card->next->wandev.lock); - } - - S514_intack(&card->hw, int_status); - if (card->isr) - card->isr(card); - - if (card->next){ - spin_unlock(&card->next->wandev.lock); - } - spin_unlock(&card->wandev.lock); - - /* handle a maximum of two interrupts (one for each */ - /* CPU on the adapter) before returning */ - if((++ IRQ_count) == 2) - return IRQ_HANDLED; - } - } - - else { /* handle interrupt on S508 adapter */ - - if (!card || ((card->wandev.state == WAN_UNCONFIGURED) && !card->configured)) - return IRQ_HANDLED; - - if (card->in_isr) { - printk(KERN_INFO - "%s: interrupt re-entrancy on IRQ %d!\n", - card->devname, card->wandev.irq); - return IRQ_HANDLED; - } - - spin_lock(&card->wandev.lock); - if (card->next){ - spin_lock(&card->next->wandev.lock); - } - - sdla_intack(&card->hw); - if (card->isr) - card->isr(card); - - if (card->next){ - spin_unlock(&card->next->wandev.lock); - } - spin_unlock(&card->wandev.lock); - - } - return IRQ_HANDLED; -#undef card -} - -/*============================================================================ - * This routine is called by the protocol-specific modules when network - * interface is being open. The only reason we need this, is because we - * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's - * defined more than once into the same kernel module. - */ -void wanpipe_open (sdla_t* card) -{ - ++card->open_cnt; -} - -/*============================================================================ - * This routine is called by the protocol-specific modules when network - * interface is being closed. The only reason we need this, is because we - * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's - * defined more than once into the same kernel module. - */ -void wanpipe_close (sdla_t* card) -{ - --card->open_cnt; -} - -/*============================================================================ - * Set WAN device state. - */ -void wanpipe_set_state (sdla_t* card, int state) -{ - if (card->wandev.state != state) { - switch (state) { - case WAN_CONNECTED: - printk (KERN_INFO "%s: link connected!\n", - card->devname); - break; - - case WAN_CONNECTING: - printk (KERN_INFO "%s: link connecting...\n", - card->devname); - break; - - case WAN_DISCONNECTED: - printk (KERN_INFO "%s: link disconnected!\n", - card->devname); - break; - } - card->wandev.state = state; - } - card->state_tick = jiffies; -} - -sdla_t * wanpipe_find_card (char *name) -{ - int cnt; - for (cnt = 0; cnt < ncards; ++ cnt) { - sdla_t* card = &card_array[cnt]; - if (!strcmp(card->devname,name)) - return card; - } - return NULL; -} - -sdla_t * wanpipe_find_card_num (int num) -{ - if (num < 1 || num > ncards) - return NULL; - num--; - return &card_array[num]; -} - -/* - * @work_pointer: work_struct to be done; - * should already have PREPARE_WORK() or - * INIT_WORK() done on it by caller; - */ -void wanpipe_queue_work (struct work_struct *work_pointer) -{ - if (test_and_set_bit(1, (void*)&wanpipe_bh_critical)) - printk(KERN_INFO "CRITICAL IN QUEUING WORK\n"); - - queue_work(wanpipe_wq, work_pointer); - clear_bit(1,(void*)&wanpipe_bh_critical); -} - -void wakeup_sk_bh(struct net_device *dev) -{ - wanpipe_common_t *chan = dev->priv; - - if (test_bit(0,&chan->common_critical)) - return; - - if (chan->sk && chan->tx_timer){ - chan->tx_timer->expires=jiffies+1; - add_timer(chan->tx_timer); - } -} - -int change_dev_flags(struct net_device *dev, unsigned flags) -{ - struct ifreq if_info; - mm_segment_t fs = get_fs(); - int err; - - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - if_info.ifr_flags = flags; - - set_fs(get_ds()); /* get user space block */ - err = devinet_ioctl(SIOCSIFFLAGS, &if_info); - set_fs(fs); - - return err; -} - -unsigned long get_ip_address(struct net_device *dev, int option) -{ - - struct in_ifaddr *ifaddr; - struct in_device *in_dev; - unsigned long addr = 0; - - rcu_read_lock(); - if ((in_dev = __in_dev_get_rcu(dev)) == NULL){ - goto out; - } - - if ((ifaddr = in_dev->ifa_list)== NULL ){ - goto out; - } - - switch (option){ - - case WAN_LOCAL_IP: - addr = ifaddr->ifa_local; - break; - - case WAN_POINTOPOINT_IP: - addr = ifaddr->ifa_address; - break; - - case WAN_NETMASK_IP: - addr = ifaddr->ifa_mask; - break; - - case WAN_BROADCAST_IP: - addr = ifaddr->ifa_broadcast; - break; - default: - break; - } - -out: - rcu_read_unlock(); - return addr; -} - -void add_gateway(sdla_t *card, struct net_device *dev) -{ - mm_segment_t oldfs; - struct rtentry route; - int res; - - memset((char*)&route,0,sizeof(struct rtentry)); - - ((struct sockaddr_in *) - &(route.rt_dst))->sin_addr.s_addr = 0; - ((struct sockaddr_in *) - &(route.rt_dst))->sin_family = AF_INET; - - ((struct sockaddr_in *) - &(route.rt_genmask))->sin_addr.s_addr = 0; - ((struct sockaddr_in *) - &(route.rt_genmask)) ->sin_family = AF_INET; - - - route.rt_flags = 0; - route.rt_dev = dev->name; - - oldfs = get_fs(); - set_fs(get_ds()); - res = ip_rt_ioctl(SIOCADDRT,&route); - set_fs(oldfs); - - if (res == 0){ - printk(KERN_INFO "%s: Gateway added for %s\n", - card->devname,dev->name); - } - - return; -} - -MODULE_LICENSE("GPL"); - -/****** End *********************************************************/ diff --git a/drivers/net/wan/wanpipe_multppp.c b/drivers/net/wan/wanpipe_multppp.c deleted file mode 100644 index 812a118..0000000 --- a/drivers/net/wan/wanpipe_multppp.c +++ /dev/null @@ -1,2358 +0,0 @@ -/***************************************************************************** -* wanpipe_multppp.c Multi-Port PPP driver module. -* -* Authors: Nenad Corbic -* -* Copyright: (c) 1995-2001 Sangoma Technologies Inc. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version -* 2 of the License, or (at your option) any later version. -* ============================================================================ -* Dec 15 2000 Updated for 2.4.X kernel -* Nov 15 2000 Fixed the SyncPPP support for kernels 2.2.16 and higher. -* The pppstruct has changed. -* Jul 13 2000 Using the kernel Syncppp module on top of RAW Wanpipe CHDLC -* module. -*****************************************************************************/ - -#include -#include /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include /* ARPHRD_* defines */ -#include /* time_after() macro */ - -#include /* sockaddr_in */ -#include -#include -#include /* htons(), etc. */ -#include -#include - -#include /* CHDLC firmware API definitions */ -#include /* CHDLC (async) API definitions */ - -#include /* Socket Driver common area */ -#include - - -#include -#include - -#include - - -/****** Defines & Macros ****************************************************/ - -#ifdef _DEBUG_ -#define STATIC -#else -#define STATIC static -#endif - -/* reasons for enabling the timer interrupt on the adapter */ -#define TMR_INT_ENABLED_UDP 0x01 -#define TMR_INT_ENABLED_UPDATE 0x02 -#define TMR_INT_ENABLED_CONFIG 0x04 - -#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ -#define CHDLC_HDR_LEN 1 - -#define IFF_POINTTOPOINT 0x10 - -#define CHDLC_API 0x01 - -#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) -#define MAX_BH_BUFF 10 - -#define CRC_LENGTH 2 -#define PPP_HEADER_LEN 4 - -/******Data Structures*****************************************************/ - -/* This structure is placed in the private data area of the device structure. - * The card structure used to occupy the private area but now the following - * structure will incorporate the card structure along with CHDLC specific data - */ - -typedef struct chdlc_private_area -{ - void *if_ptr; /* General Pointer used by SPPP */ - wanpipe_common_t common; - sdla_t *card; - int TracingEnabled; /* For enabling Tracing */ - unsigned long curr_trace_addr; /* Used for Tracing */ - unsigned long start_trace_addr; - unsigned long end_trace_addr; - unsigned long base_addr_trace_buffer; - unsigned long end_addr_trace_buffer; - unsigned short number_trace_elements; - unsigned available_buffer_space; - unsigned long router_start_time; - unsigned char route_status; - unsigned char route_removed; - unsigned long tick_counter; /* For 5s timeout counter */ - unsigned long router_up_time; - u32 IP_address; /* IP addressing */ - u32 IP_netmask; - unsigned char mc; /* Mulitcast support on/off */ - unsigned short udp_pkt_lgth; /* udp packet processing */ - char udp_pkt_src; - char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; - unsigned short timer_int_enabled; - char update_comms_stats; /* updating comms stats */ - - //FIXME: add driver stats as per frame relay! - -} chdlc_private_area_t; - -/* Route Status options */ -#define NO_ROUTE 0x00 -#define ADD_ROUTE 0x01 -#define ROUTE_ADDED 0x02 -#define REMOVE_ROUTE 0x03 - - -/* variable for keeping track of enabling/disabling FT1 monitor status */ -static int rCount = 0; - -/* variable for tracking how many interfaces to open for WANPIPE on the - two ports */ - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/****** Function Prototypes *************************************************/ -/* WAN link driver entry points. These are called by the WAN router module. */ -static int update(struct wan_device* wandev); -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf); -static int del_if(struct wan_device* wandev, struct net_device* dev); - -/* Network device interface */ -static int if_init(struct net_device* dev); -static int if_open(struct net_device* dev); -static int if_close(struct net_device* dev); -static int if_send(struct sk_buff* skb, struct net_device* dev); -static struct net_device_stats* if_stats(struct net_device* dev); - -static void if_tx_timeout(struct net_device *dev); - -/* CHDLC Firmware interface functions */ -static int chdlc_configure (sdla_t* card, void* data); -static int chdlc_comm_enable (sdla_t* card); -static int chdlc_comm_disable (sdla_t* card); -static int chdlc_read_version (sdla_t* card, char* str); -static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); -static int chdlc_send (sdla_t* card, void* data, unsigned len); -static int chdlc_read_comm_err_stats (sdla_t* card); -static int chdlc_read_op_stats (sdla_t* card); -static int config_chdlc (sdla_t *card); - - -/* Miscellaneous CHDLC Functions */ -static int set_chdlc_config (sdla_t* card); -static void init_chdlc_tx_rx_buff(sdla_t* card, struct net_device *dev); -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); -static int process_chdlc_exception(sdla_t *card); -static int process_global_exception(sdla_t *card); -static int update_comms_stats(sdla_t* card, - chdlc_private_area_t* chdlc_priv_area); -static void port_set_state (sdla_t *card, int); - -/* Interrupt handlers */ -static void wsppp_isr (sdla_t* card); -static void rx_intr (sdla_t* card); -static void timer_intr(sdla_t *); - -/* Miscellaneous functions */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ); -static int intr_test( sdla_t* card); -static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area); -static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area); -static unsigned short calc_checksum (char *, int); -static void s508_lock (sdla_t *card, unsigned long *smp_flags); -static void s508_unlock (sdla_t *card, unsigned long *smp_flags); -static void send_ppp_term_request(struct net_device *dev); - - -static int Intr_test_counter; -/****** Public Functions ****************************************************/ - -/*============================================================================ - * Cisco HDLC protocol initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wsppp_init (sdla_t* card, wandev_conf_t* conf) -{ - unsigned char port_num; - int err; - unsigned long max_permitted_baud = 0; - SHARED_MEMORY_INFO_STRUCT *flags; - - union - { - char str[80]; - } u; - volatile CHDLC_MAILBOX_STRUCT* mb; - CHDLC_MAILBOX_STRUCT* mb1; - unsigned long timeout; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_MPPP) { - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - } - - /* Find out which Port to use */ - if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ - if (card->next){ - - if (conf->comm_port != card->next->u.c.comm_port){ - card->u.c.comm_port = conf->comm_port; - }else{ - printk(KERN_ERR "%s: ERROR - %s port used!\n", - card->wandev.name, PORT(conf->comm_port)); - return -EINVAL; - } - }else{ - card->u.c.comm_port = conf->comm_port; - } - }else{ - printk(KERN_ERR "%s: ERROR - Invalid Port Selected!\n", - card->wandev.name); - return -EINVAL; - } - - - /* Initialize protocol-specific fields */ - if(card->hw.type != SDLA_S514){ - - if (card->u.c.comm_port == WANOPT_PRI){ - card->mbox = (void *) card->hw.dpmbase; - }else{ - card->mbox = (void *) card->hw.dpmbase + - SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT; - } - }else{ - /* for a S514 adapter, set a pointer to the actual mailbox in the */ - /* allocated virtual memory area */ - if (card->u.c.comm_port == WANOPT_PRI){ - card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; - }else{ - card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT; - } - } - - mb = mb1 = card->mbox; - - if (!card->configured){ - - /* The board will place an 'I' in the return code to indicate that it is - ready to accept commands. We expect this to be completed in less - than 1 second. */ - - timeout = jiffies + 1 * HZ; - while (mb->return_code != 'I') /* Wait 1s for board to initialize */ - if (time_after(jiffies, timeout)) break; - - if (mb->return_code != 'I') { - printk(KERN_INFO - "%s: Initialization not completed by adapter\n", - card->devname); - printk(KERN_INFO "Please contact Sangoma representative.\n"); - return -EIO; - } - } - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - - if (chdlc_read_version(card, u.str)) - return -EIO; - - printk(KERN_INFO "%s: Running Raw CHDLC firmware v%s\n" - "%s: for Multi-Port PPP protocol.\n", - card->devname,u.str,card->devname); - - card->isr = &wsppp_isr; - card->poll = NULL; - card->exec = NULL; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.udp_port = conf->udp_port; - - card->wandev.new_if_cnt = 0; - - /* reset the number of times the 'update()' proc has been called */ - card->u.c.update_call_count = 0; - - card->wandev.ttl = conf->ttl; - card->wandev.interface = conf->interface; - - if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& - card->hw.type != SDLA_S514){ - printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", - card->devname, PORT(card->u.c.comm_port)); - return -EIO; - } - - - card->wandev.clocking = conf->clocking; - - port_num = card->u.c.comm_port; - - /* Setup Port Bps */ - - if(card->wandev.clocking) { - if((port_num == WANOPT_PRI) || card->u.c.receive_only) { - /* For Primary Port 0 */ - max_permitted_baud = - (card->hw.type == SDLA_S514) ? - PRI_MAX_BAUD_RATE_S514 : - PRI_MAX_BAUD_RATE_S508; - } - else if(port_num == WANOPT_SEC) { - /* For Secondary Port 1 */ - max_permitted_baud = - (card->hw.type == SDLA_S514) ? - SEC_MAX_BAUD_RATE_S514 : - SEC_MAX_BAUD_RATE_S508; - } - - if(conf->bps > max_permitted_baud) { - conf->bps = max_permitted_baud; - printk(KERN_INFO "%s: Baud too high!\n", - card->wandev.name); - printk(KERN_INFO "%s: Baud rate set to %lu bps\n", - card->wandev.name, max_permitted_baud); - } - - card->wandev.bps = conf->bps; - }else{ - card->wandev.bps = 0; - } - - /* Setup the Port MTU */ - if((port_num == WANOPT_PRI) || card->u.c.receive_only) { - - /* For Primary Port 0 */ - card->wandev.mtu = - (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? - min_t(unsigned int, conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) : - CHDLC_DFLT_DATA_LEN; - } else if(port_num == WANOPT_SEC) { - /* For Secondary Port 1 */ - card->wandev.mtu = - (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? - min_t(unsigned int, conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : - CHDLC_DFLT_DATA_LEN; - } - - /* Add on a PPP Header */ - card->wandev.mtu += PPP_HEADER_LEN; - - /* Set up the interrupt status area */ - /* Read the CHDLC Configuration and obtain: - * Ptr to shared memory infor struct - * Use this pointer to calculate the value of card->u.c.flags ! - */ - mb1->buffer_length = 0; - mb1->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; - if(err != COMMAND_OK) { - clear_bit(1, (void*)&card->wandev.critical); - - if(card->hw.type != SDLA_S514) - enable_irq(card->hw.irq); - - chdlc_error(card, err, mb1); - return -EIO; - } - - if(card->hw.type == SDLA_S514){ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct)); - }else{ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); - } - - flags = card->u.c.flags; - - /* This is for the ports link state */ - card->wandev.state = WAN_DUALPORT; - card->u.c.state = WAN_DISCONNECTED; - - - if (!card->wandev.piggyback){ - err = intr_test(card); - - if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk(KERN_ERR "%s: Interrupt test failed (%i)\n", - card->devname, Intr_test_counter); - printk(KERN_ERR "%s: Please choose another interrupt\n", - card->devname); - return -EIO; - } - - printk(KERN_INFO "%s: Interrupt test passed (%i)\n", - card->devname, Intr_test_counter); - } - - - if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ - printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", - card->devname); - return -EIO; - } - - /* Mask the Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TIMER; - - printk(KERN_INFO "\n"); - - return 0; -} - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Update device status & statistics - * This procedure is called when updating the PROC file system and returns - * various communications statistics. These statistics are accumulated from 3 - * different locations: - * 1) The 'if_stats' recorded for the device. - * 2) Communication error statistics on the adapter. - * 3) CHDLC operational statistics on the adapter. - * The board level statistics are read during a timer interrupt. Note that we - * read the error and operational statistics during consecitive timer ticks so - * as to minimize the time that we are inside the interrupt handler. - * - */ -static int update(struct wan_device* wandev) -{ - sdla_t* card = wandev->private; - struct net_device* dev; - volatile chdlc_private_area_t* chdlc_priv_area; - SHARED_MEMORY_INFO_STRUCT *flags; - unsigned long timeout; - - /* sanity checks */ - if((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - - if(wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - /* more sanity checks */ - if(!card->u.c.flags) - return -ENODEV; - - if((dev=card->wandev.dev) == NULL) - return -ENODEV; - - if((chdlc_priv_area=dev->priv) == NULL) - return -ENODEV; - - flags = card->u.c.flags; - - if(chdlc_priv_area->update_comms_stats){ - return -EAGAIN; - } - - /* we will need 2 timer interrupts to complete the */ - /* reading of the statistics */ - chdlc_priv_area->update_comms_stats = 2; - flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; - chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE; - - /* wait a maximum of 1 second for the statistics to be updated */ - timeout = jiffies + 1 * HZ; - for(;;) { - if(chdlc_priv_area->update_comms_stats == 0) - break; - if (time_after(jiffies, timeout)){ - chdlc_priv_area->update_comms_stats = 0; - chdlc_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - return -EAGAIN; - } - } - - return 0; -} - - -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. - * - * Return: 0 o.k. - * < 0 failure (channel will not be created) - */ -static int new_if(struct wan_device* wandev, struct net_device* pdev, - wanif_conf_t* conf) -{ - - struct ppp_device *pppdev = (struct ppp_device *)pdev; - struct net_device *dev = NULL; - struct sppp *sp; - sdla_t* card = wandev->private; - chdlc_private_area_t* chdlc_priv_area; - - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - printk(KERN_INFO "%s: invalid interface name!\n", - card->devname); - return -EINVAL; - } - - /* allocate and initialize private data */ - chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); - - if(chdlc_priv_area == NULL) - return -ENOMEM; - - memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); - - chdlc_priv_area->card = card; - - /* initialize data */ - strcpy(card->u.c.if_name, conf->name); - - if(card->wandev.new_if_cnt > 0) { - kfree(chdlc_priv_area); - return -EEXIST; - } - - card->wandev.new_if_cnt++; - - chdlc_priv_area->TracingEnabled = 0; - - //We don't need this any more - chdlc_priv_area->route_status = NO_ROUTE; - chdlc_priv_area->route_removed = 0; - - printk(KERN_INFO "%s: Firmware running in HDLC STREAMING Mode\n", - wandev->name); - - /* Setup wanpipe as a router (WANPIPE) or as an API */ - if( strcmp(conf->usedby, "WANPIPE") == 0) { - printk(KERN_INFO "%s: Driver running in WANPIPE mode!\n", - wandev->name); - card->u.c.usedby = WANPIPE; - } else { - printk(KERN_INFO - "%s: API Mode is not supported for SyncPPP!\n", - wandev->name); - kfree(chdlc_priv_area); - return -EINVAL; - } - - /* Get Multicast Information */ - chdlc_priv_area->mc = conf->mc; - - - chdlc_priv_area->if_ptr = pppdev; - - /* prepare network device data space for registration */ - - strcpy(dev->name,card->u.c.if_name); - - /* Attach PPP protocol layer to pppdev - * The sppp_attach() will initilize the dev structure - * and setup ppp layer protocols. - * All we have to do is to bind in: - * if_open(), if_close(), if_send() and get_stats() functions. - */ - sppp_attach(pppdev); - dev = pppdev->dev; - sp = &pppdev->sppp; - - /* Enable PPP Debugging */ - // FIXME Fix this up somehow - //sp->pp_flags |= PP_DEBUG; - sp->pp_flags &= ~PP_CISCO; - - dev->init = &if_init; - dev->priv = chdlc_priv_area; - - return 0; -} - - - - -/*============================================================================ - * Delete logical channel. - */ -static int del_if(struct wan_device* wandev, struct net_device* dev) -{ - chdlc_private_area_t *chdlc_priv_area = dev->priv; - sdla_t *card = chdlc_priv_area->card; - unsigned long smp_lock; - - /* Detach the PPP layer */ - printk(KERN_INFO "%s: Detaching SyncPPP Module from %s\n", - wandev->name,dev->name); - - lock_adapter_irq(&wandev->lock,&smp_lock); - - sppp_detach(dev); - chdlc_priv_area->if_ptr=NULL; - - chdlc_set_intr_mode(card, 0); - if (card->u.c.comm_enabled) - chdlc_comm_disable(card); - unlock_adapter_irq(&wandev->lock,&smp_lock); - - port_set_state(card, WAN_DISCONNECTED); - - return 0; -} - - -/****** Network Device Interface ********************************************/ - -/*============================================================================ - * Initialize Linux network interface. - * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. - */ -static int if_init(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - struct wan_device* wandev = &card->wandev; - - /* NOTE: Most of the dev initialization was - * done in sppp_attach(), called by new_if() - * function. All we have to do here is - * to link four major routines below. - */ - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - dev->tx_timeout = &if_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - - /* Initialize hardware parameters */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; - - /* Set transmit buffer queue length - * If we over fill this queue the packets will - * be droped by the kernel. - * sppp_attach() sets this to 10, but - * 100 will give us more room at low speeds. - */ - dev->tx_queue_len = 100; - - return 0; -} - - -/*============================================================================ - * Handle transmit timeout event from netif watchdog - */ -static void if_tx_timeout(struct net_device *dev) -{ - chdlc_private_area_t* chan = dev->priv; - sdla_t *card = chan->card; - - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - - ++card->wandev.stats.collisions; - - printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); - netif_wake_queue (dev); -} - - -/*============================================================================ - * Open network interface. - * o enable communications and interrupts. - * o prevent module from unloading by incrementing use count - * - * Return 0 if O.k. or errno. - */ -static int if_open(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - struct timeval tv; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - - /* Only one open per interface is allowed */ - if (netif_running(dev)) - return -EBUSY; - - /* Start PPP Layer */ - if (sppp_open(dev)){ - return -EIO; - } - - do_gettimeofday(&tv); - chdlc_priv_area->router_start_time = tv.tv_sec; - - netif_start_queue(dev); - - wanpipe_open(card); - - chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; - flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; - return 0; -} - -/*============================================================================ - * Close network interface. - * o if this is the last close, then disable communications and interrupts. - * o reset flags. - */ -static int if_close(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - - /* Stop the PPP Layer */ - sppp_close(dev); - netif_stop_queue(dev); - - wanpipe_close(card); - - return 0; -} - -/*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission) to block a timer-based - * transmit from overlapping. - * o check link state. If link is not up, then drop the packet. - * o execute adapter send command. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. - */ -static int if_send(struct sk_buff* skb, struct net_device* dev) -{ - chdlc_private_area_t *chdlc_priv_area = dev->priv; - sdla_t *card = chdlc_priv_area->card; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; - int udp_type = 0; - unsigned long smp_flags; - int err=0; - - netif_stop_queue(dev); - - - if (skb == NULL){ - /* If we get here, some higher layer thinks we've missed an - * tx-done interrupt. - */ - printk(KERN_INFO "%s: Received NULL skb buffer! interface %s got kicked!\n", - card->devname, dev->name); - - netif_wake_queue(dev); - return 0; - } - - if (ntohs(skb->protocol) != htons(PVC_PROT)){ - /* check the udp packet type */ - - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_CPIPE_TYPE){ - if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, - chdlc_priv_area)){ - chdlc_int->interrupt_permission |= - APP_INT_ON_TIMER; - } - netif_start_queue(dev); - return 0; - } - } - - /* Lock the 508 Card: SMP is supported */ - if(card->hw.type != SDLA_S514){ - s508_lock(card,&smp_flags); - } - - if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ - - printk(KERN_INFO "%s: Critical in if_send: %lx\n", - card->wandev.name,card->wandev.critical); - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - goto if_send_crit_exit; - } - - if (card->wandev.state != WAN_CONNECTED){ - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - goto if_send_crit_exit; - } - - if (chdlc_send(card, skb->data, skb->len)){ - netif_stop_queue(dev); - - }else{ - ++card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += skb->len; - dev->trans_start = jiffies; - netif_start_queue(dev); - } - -if_send_crit_exit: - if (!(err=netif_queue_stopped(dev))){ - dev_kfree_skb_any(skb); - }else{ - chdlc_priv_area->tick_counter = jiffies; - chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; - } - - clear_bit(SEND_CRIT, (void*)&card->wandev.critical); - if(card->hw.type != SDLA_S514){ - s508_unlock(card,&smp_flags); - } - - return err; -} - - -/*============================================================================ - * Reply to UDP Management system. - * Return length of reply. - */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ) -{ - - unsigned short len, udp_length, temp, ip_length; - unsigned long ip_temp; - int even_bound = 0; - chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data; - - /* Set length of packet */ - len = sizeof(ip_pkt_t)+ - sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - sizeof(trace_info_t)+ - mbox_len; - - /* fill in UDP reply */ - c_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; - - /* fill in UDP length */ - udp_length = sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - sizeof(trace_info_t)+ - mbox_len; - - /* put it on an even boundary */ - if ( udp_length & 0x0001 ) { - udp_length += 1; - len += 1; - even_bound = 1; - } - - temp = (udp_length<<8)|(udp_length>>8); - c_udp_pkt->udp_pkt.udp_length = temp; - - /* swap UDP ports */ - temp = c_udp_pkt->udp_pkt.udp_src_port; - c_udp_pkt->udp_pkt.udp_src_port = - c_udp_pkt->udp_pkt.udp_dst_port; - c_udp_pkt->udp_pkt.udp_dst_port = temp; - - /* add UDP pseudo header */ - temp = 0x1100; - *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp; - temp = (udp_length<<8)|(udp_length>>8); - *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp; - - - /* calculate UDP checksum */ - c_udp_pkt->udp_pkt.udp_checksum = 0; - c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); - - /* fill in IP length */ - ip_length = len; - temp = (ip_length<<8)|(ip_length>>8); - c_udp_pkt->ip_pkt.total_length = temp; - - /* swap IP addresses */ - ip_temp = c_udp_pkt->ip_pkt.ip_src_address; - c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address; - c_udp_pkt->ip_pkt.ip_dst_address = ip_temp; - - /* fill in IP checksum */ - c_udp_pkt->ip_pkt.hdr_checksum = 0; - c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); - - return len; - -} /* reply_udp */ - -unsigned short calc_checksum (char *data, int len) -{ - unsigned short temp; - unsigned long sum=0; - int i; - - for( i = 0; i > 16 ) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - - temp = (unsigned short)sum; - temp = ~temp; - - if( temp == 0 ) - temp = 0xffff; - - return temp; -} - - -/*============================================================================ - * Get ethernet-style interface statistics. - * Return a pointer to struct enet_statistics. - */ -static struct net_device_stats* if_stats(struct net_device* dev) -{ - sdla_t *my_card; - chdlc_private_area_t* chdlc_priv_area; - - /* Shutdown bug fix. In del_if() we kill - * dev->priv pointer. This function, gets - * called after del_if(), thus check - * if pointer has been deleted */ - if ((chdlc_priv_area=dev->priv) == NULL) - return NULL; - - my_card = chdlc_priv_area->card; - return &my_card->wandev.stats; -} - - -/****** Cisco HDLC Firmware Interface Functions *******************************/ - -/*============================================================================ - * Read firmware code version. - * Put code version as ASCII string in str. - */ -static int chdlc_read_version (sdla_t* card, char* str) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int len; - char err; - mb->buffer_length = 0; - mb->command = READ_CHDLC_CODE_VERSION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - chdlc_error(card,err,mb); - } - else if (str) { /* is not null */ - len = mb->buffer_length; - memcpy(str, mb->data, len); - str[len] = '\0'; - } - return (err); -} - -/*----------------------------------------------------------------------------- - * Configure CHDLC firmware. - */ -static int chdlc_configure (sdla_t* card, void* data) -{ - int err; - CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; - int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); - - mailbox->buffer_length = data_length; - memcpy(mailbox->data, data, data_length); - mailbox->command = SET_CHDLC_CONFIGURATION; - err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; - - if (err != COMMAND_OK) chdlc_error (card, err, mailbox); - - return err; -} - - -/*============================================================================ - * Set interrupt mode -- HDLC Version. - */ - -static int chdlc_set_intr_mode (sdla_t* card, unsigned mode) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_INT_TRIGGERS_STRUCT* int_data = - (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; - int err; - - int_data->CHDLC_interrupt_triggers = mode; - int_data->IRQ = card->hw.irq; - int_data->interrupt_timer = 1; - - mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); - mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error (card, err, mb); - return err; -} - - -/*============================================================================ - * Enable communications. - */ - -static int chdlc_comm_enable (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = ENABLE_CHDLC_COMMUNICATIONS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card, err, mb); - else - card->u.c.comm_enabled=1; - - return err; -} - -/*============================================================================ - * Disable communications and Drop the Modem lines (DCD and RTS). - */ -static int chdlc_comm_disable (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = DISABLE_CHDLC_COMMUNICATIONS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - - return err; -} - -/*============================================================================ - * Read communication error statistics. - */ -static int chdlc_read_comm_err_stats (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = READ_COMMS_ERROR_STATS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - return err; -} - - -/*============================================================================ - * Read CHDLC operational statistics. - */ -static int chdlc_read_op_stats (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_OPERATIONAL_STATS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - return err; -} - - -/*============================================================================ - * Update communications error and general packet statistics. - */ -static int update_comms_stats(sdla_t* card, - chdlc_private_area_t* chdlc_priv_area) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - COMMS_ERROR_STATS_STRUCT* err_stats; - CHDLC_OPERATIONAL_STATS_STRUCT *op_stats; - - /* on the first timer interrupt, read the comms error statistics */ - if(chdlc_priv_area->update_comms_stats == 2) { - if(chdlc_read_comm_err_stats(card)) - return 1; - err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data; - card->wandev.stats.rx_over_errors = - err_stats->Rx_overrun_err_count; - card->wandev.stats.rx_crc_errors = - err_stats->CRC_err_count; - card->wandev.stats.rx_frame_errors = - err_stats->Rx_abort_count; - card->wandev.stats.rx_fifo_errors = - err_stats->Rx_dis_pri_bfrs_full_count; - card->wandev.stats.rx_missed_errors = - card->wandev.stats.rx_fifo_errors; - card->wandev.stats.tx_aborted_errors = - err_stats->sec_Tx_abort_count; - } - - /* on the second timer interrupt, read the operational statistics */ - else { - if(chdlc_read_op_stats(card)) - return 1; - op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data; - card->wandev.stats.rx_length_errors = - (op_stats->Rx_Data_discard_short_count + - op_stats->Rx_Data_discard_long_count); - } - - return 0; -} - -/*============================================================================ - * Send packet. - * Return: 0 - o.k. - * 1 - no transmit buffers available - */ -static int chdlc_send (sdla_t* card, void* data, unsigned len) -{ - CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf; - - if (txbuf->opp_flag) - return 1; - - sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len); - - txbuf->frame_length = len; - txbuf->opp_flag = 1; /* start transmission */ - - /* Update transmit buffer control fields */ - card->u.c.txbuf = ++txbuf; - - if ((void*)txbuf > card->u.c.txbuf_last) - card->u.c.txbuf = card->u.c.txbuf_base; - - return 0; -} - -/****** Firmware Error Handler **********************************************/ - -/*============================================================================ - * Firmware error handler. - * This routine is called whenever firmware command returns non-zero - * return code. - * - * Return zero if previous command has to be cancelled. - */ -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) -{ - unsigned cmd = mb->command; - - switch (err) { - - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - break; - - case S514_BOTH_PORTS_SAME_CLK_MODE: - if(cmd == SET_CHDLC_CONFIGURATION) { - printk(KERN_INFO - "%s: Configure both ports for the same clock source\n", - card->devname); - break; - } - - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, cmd, err); - } - - return 0; -} - -/****** Interrupt Handlers **************************************************/ - -/*============================================================================ - * Cisco HDLC interrupt service routine. - */ -STATIC void wsppp_isr (sdla_t* card) -{ - struct net_device* dev; - SHARED_MEMORY_INFO_STRUCT* flags = NULL; - int i; - sdla_t *my_card; - - - /* Check for which port the interrupt has been generated - * Since Secondary Port is piggybacking on the Primary - * the check must be done here. - */ - - flags = card->u.c.flags; - if (!flags->interrupt_info_struct.interrupt_type){ - /* Check for a second port (piggybacking) */ - if((my_card = card->next)){ - flags = my_card->u.c.flags; - if (flags->interrupt_info_struct.interrupt_type){ - card = my_card; - card->isr(card); - return; - } - } - } - - dev = card->wandev.dev; - card->in_isr = 1; - flags = card->u.c.flags; - - /* If we get an interrupt with no network device, stop the interrupts - * and issue an error */ - if ((!dev || !dev->priv) && flags->interrupt_info_struct.interrupt_type != - COMMAND_COMPLETE_APP_INT_PEND){ - goto isr_done; - } - - - /* if critical due to peripheral operations - * ie. update() or getstats() then reset the interrupt and - * wait for the board to retrigger. - */ - if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { - flags->interrupt_info_struct. - interrupt_type = 0; - goto isr_done; - } - - - /* On a 508 Card, if critical due to if_send - * Major Error !!! - */ - if(card->hw.type != SDLA_S514) { - if(test_bit(0, (void*)&card->wandev.critical)) { - printk(KERN_INFO "%s: Critical while in ISR: %lx\n", - card->devname, card->wandev.critical); - goto isr_done; - } - } - - switch(flags->interrupt_info_struct.interrupt_type) { - - case RX_APP_INT_PEND: /* 0x01: receive interrupt */ - rx_intr(card); - break; - - case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TX_FRAME; - - netif_wake_queue(dev); - break; - - case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ - ++ Intr_test_counter; - break; - - case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ - process_chdlc_exception(card); - break; - - case GLOBAL_EXCEP_COND_APP_INT_PEND: - process_global_exception(card); - break; - - case TIMER_APP_INT_PEND: - timer_intr(card); - break; - - default: - printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", - card->devname, - flags->interrupt_info_struct.interrupt_type); - printk(KERN_INFO "Code name: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codename[i]); - printk(KERN_INFO "\nCode version: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codeversion[i]); - printk(KERN_INFO "\n"); - break; - } - -isr_done: - card->in_isr = 0; - flags->interrupt_info_struct.interrupt_type = 0; -} - -/*============================================================================ - * Receive interrupt handler. - */ -static void rx_intr (sdla_t* card) -{ - struct net_device *dev; - chdlc_private_area_t *chdlc_priv_area; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; - struct sk_buff *skb; - unsigned len; - unsigned addr = rxbuf->ptr_data_bfr; - void *buf; - int i,udp_type; - - if (rxbuf->opp_flag != 0x01) { - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned)rxbuf, rxbuf->opp_flag); - printk(KERN_INFO "Code name: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codename[i]); - printk(KERN_INFO "\nCode version: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codeversion[i]); - printk(KERN_INFO "\n"); - - - /* Bug Fix: Mar 6 2000 - * If we get a corrupted mailbox, it measn that driver - * is out of sync with the firmware. There is no recovery. - * If we don't turn off all interrupts for this card - * the machine will crash. - */ - printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); - printk(KERN_INFO "Please contact Sangoma Technologies !\n"); - chdlc_set_intr_mode(card,0); - return; - } - - dev = card->wandev.dev; - - if (!dev){ - goto rx_exit; - } - - if (!netif_running(dev)){ - goto rx_exit; - } - - chdlc_priv_area = dev->priv; - - if (rxbuf->error_flag){ - goto rx_exit; - } - /* Take off two CRC bytes */ - - if (rxbuf->frame_length < 7 || rxbuf->frame_length > 1506 ){ - goto rx_exit; - } - - len = rxbuf->frame_length - CRC_LENGTH; - - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); - - if (skb == NULL) { - if (net_ratelimit()){ - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - } - ++card->wandev.stats.rx_dropped; - goto rx_exit; - } - - /* Copy data to the socket buffer */ - if((addr + len) > card->u.c.rx_top + 1) { - unsigned tmp = card->u.c.rx_top - addr + 1; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, addr, buf, tmp); - addr = card->u.c.rx_base; - len -= tmp; - } - - buf = skb_put(skb, len); - sdla_peek(&card->hw, addr, buf, len); - - skb->protocol = htons(ETH_P_WAN_PPP); - - card->wandev.stats.rx_packets ++; - card->wandev.stats.rx_bytes += skb->len; - udp_type = udp_pkt_type( skb, card ); - - if(udp_type == UDP_CPIPE_TYPE) { - if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, - card, skb, dev, chdlc_priv_area)) { - flags->interrupt_info_struct. - interrupt_permission |= - APP_INT_ON_TIMER; - } - }else{ - /* Pass it up the protocol stack */ - skb->dev = dev; - skb->mac.raw = skb->data; - netif_rx(skb); - dev->last_rx = jiffies; - } - -rx_exit: - /* Release buffer element and calculate a pointer to the next one */ - rxbuf->opp_flag = 0x00; - card->u.c.rxmb = ++ rxbuf; - if((void*)rxbuf > card->u.c.rxbuf_last){ - card->u.c.rxmb = card->u.c.rxbuf_base; - } -} - -/*============================================================================ - * Timer interrupt handler. - * The timer interrupt is used for two purposes: - * 1) Processing udp calls from 'cpipemon'. - * 2) Reading board-level statistics for updating the proc file system. - */ -void timer_intr(sdla_t *card) -{ - struct net_device* dev; - chdlc_private_area_t* chdlc_priv_area = NULL; - SHARED_MEMORY_INFO_STRUCT* flags = NULL; - - dev = card->wandev.dev; - chdlc_priv_area = dev->priv; - - if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) { - if (!config_chdlc(card)){ - chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; - } - } - - /* process a udp call if pending */ - if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) { - process_udp_mgmt_pkt(card, dev, - chdlc_priv_area); - chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; - } - - - /* read the communications statistics if required */ - if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) { - update_comms_stats(card, chdlc_priv_area); - if(!(-- chdlc_priv_area->update_comms_stats)) { - chdlc_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - } - } - - /* only disable the timer interrupt if there are no udp or statistic */ - /* updates pending */ - if(!chdlc_priv_area->timer_int_enabled) { - flags = card->u.c.flags; - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TIMER; - } -} - -/*------------------------------------------------------------------------------ - Miscellaneous Functions - - set_chdlc_config() used to set configuration options on the board -------------------------------------------------------------------------------*/ - -static int set_chdlc_config(sdla_t* card) -{ - - CHDLC_CONFIGURATION_STRUCT cfg; - - memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); - - if(card->wandev.clocking) - cfg.baud_rate = card->wandev.bps; - - cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? - INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; - - cfg.modem_config_options = 0; - //API OPTIONS - cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; - cfg.modem_status_timer = 100; - cfg.CHDLC_protocol_options = HDLC_STREAMING_MODE; - cfg.percent_data_buffer_for_Tx = 50; - cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | - CHDLC_RX_DATA_BYTE_COUNT_STAT); - cfg.max_CHDLC_data_field_length = card->wandev.mtu; - - cfg.transmit_keepalive_timer = 0; - cfg.receive_keepalive_timer = 0; - cfg.keepalive_error_tolerance = 0; - cfg.SLARP_request_timer = 0; - - cfg.IP_address = 0; - cfg.IP_netmask = 0; - - return chdlc_configure(card, &cfg); -} - -/*============================================================================ - * Process global exception condition - */ -static int process_global_exception(sdla_t *card) -{ - CHDLC_MAILBOX_STRUCT* mbox = card->mbox; - int err; - - mbox->buffer_length = 0; - mbox->command = READ_GLOBAL_EXCEPTION_CONDITION; - err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; - - if(err != CMD_TIMEOUT ){ - - switch(mbox->return_code) { - - case EXCEP_MODEM_STATUS_CHANGE: - - printk(KERN_INFO "%s: Modem status change\n", - card->devname); - - switch(mbox->data[0] & (DCD_HIGH | CTS_HIGH)) { - case (DCD_HIGH): - printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); - break; - case (CTS_HIGH): - printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); - break; - case ((DCD_HIGH | CTS_HIGH)): - printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); - break; - default: - printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); - break; - } - - if (!(mbox->data[0] & DCD_HIGH) || !(mbox->data[0] & DCD_HIGH)){ - //printk(KERN_INFO "Sending TERM Request Manually !\n"); - send_ppp_term_request(card->wandev.dev); - } - break; - - case EXCEP_TRC_DISABLED: - printk(KERN_INFO "%s: Line trace disabled\n", - card->devname); - break; - - case EXCEP_IRQ_TIMEOUT: - printk(KERN_INFO "%s: IRQ timeout occurred\n", - card->devname); - break; - - default: - printk(KERN_INFO "%s: Global exception %x\n", - card->devname, mbox->return_code); - break; - } - } - return 0; -} - - -/*============================================================================ - * Process chdlc exception condition - */ -static int process_chdlc_exception(sdla_t *card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int err; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_EXCEPTION_CONDITION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if(err != CMD_TIMEOUT) { - - switch (err) { - - case EXCEP_LINK_ACTIVE: - port_set_state(card, WAN_CONNECTED); - break; - - case EXCEP_LINK_INACTIVE_MODEM: - port_set_state(card, WAN_DISCONNECTED); - break; - - case EXCEP_LOOPBACK_CONDITION: - printk(KERN_INFO "%s: Loopback Condition Detected.\n", - card->devname); - break; - - case NO_CHDLC_EXCEP_COND_TO_REPORT: - printk(KERN_INFO "%s: No exceptions reported.\n", - card->devname); - break; - default: - printk(KERN_INFO "%s: Exception Condition %x!\n", - card->devname,err); - break; - } - - } - return 0; -} - - -/*============================================================================= - * Store a UDP management packet for later processing. - */ - -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area ) -{ - int udp_pkt_stored = 0; - - if(!chdlc_priv_area->udp_pkt_lgth && - (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { - chdlc_priv_area->udp_pkt_lgth = skb->len; - chdlc_priv_area->udp_pkt_src = udp_pkt_src; - memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len); - chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UDP; - udp_pkt_stored = 1; - } - - if(udp_pkt_src == UDP_PKT_FRM_STACK) - dev_kfree_skb_any(skb); - else - dev_kfree_skb_any(skb); - - return(udp_pkt_stored); -} - - -/*============================================================================= - * Process UDP management packet. - */ - -static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area ) -{ - unsigned char *buf; - unsigned int frames, len; - struct sk_buff *new_skb; - unsigned short buffer_length, real_len; - unsigned long data_ptr; - unsigned data_length; - int udp_mgmt_req_valid = 1; - CHDLC_MAILBOX_STRUCT *mb = card->mbox; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - chdlc_udp_pkt_t *chdlc_udp_pkt; - struct timeval tv; - int err; - char ut_char; - - chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data; - - if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - switch(chdlc_udp_pkt->cblock.command) { - case READ_GLOBAL_STATISTICS: - case READ_MODEM_STATUS: - case READ_CHDLC_LINK_STATUS: - case CPIPE_ROUTER_UP_TIME: - case READ_COMMS_ERROR_STATS: - case READ_CHDLC_OPERATIONAL_STATS: - - /* These two commands are executed for - * each request */ - case READ_CHDLC_CONFIGURATION: - case READ_CHDLC_CODE_VERSION: - udp_mgmt_req_valid = 1; - break; - default: - udp_mgmt_req_valid = 0; - break; - } - } - - if(!udp_mgmt_req_valid) { - - /* set length to 0 */ - chdlc_udp_pkt->cblock.buffer_length = 0; - - /* set return code */ - chdlc_udp_pkt->cblock.return_code = 0xCD; - - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Warning, Illegal UDP command attempted from network: %x\n", - card->devname,chdlc_udp_pkt->cblock.command); - } - - } else { - unsigned long trace_status_cfg_addr = 0; - TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; - TRACE_STATUS_ELEMENT_STRUCT trace_element_struct; - - switch(chdlc_udp_pkt->cblock.command) { - - case CPIPE_ENABLE_TRACING: - if (!chdlc_priv_area->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - - mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); - mb->command = SET_TRACE_CONFIGURATION; - - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_config = TRACE_ACTIVE; - /* Trace delay mode is not used because it slows - down transfer and results in a standoff situation - when there is a lot of data */ - - /* Configure the Trace based on user inputs */ - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->trace_config |= - chdlc_udp_pkt->data[0]; - - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_deactivation_timer = 4000; - - - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) { - chdlc_error(card,err,mb); - card->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = err; - mb->buffer_length = 0; - break; - } - - /* Get the base address of the trace element list */ - mb->buffer_length = 0; - mb->command = READ_TRACE_CONFIGURATION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if (err != COMMAND_OK) { - chdlc_error(card,err,mb); - chdlc_priv_area->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = err; - mb->buffer_length = 0; - break; - } - - trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *) - mb->data) -> ptr_trace_stat_el_cfg_struct; - - sdla_peek(&card->hw, trace_status_cfg_addr, - &trace_cfg_struct, sizeof(trace_cfg_struct)); - - chdlc_priv_area->start_trace_addr = trace_cfg_struct. - base_addr_trace_status_elements; - - chdlc_priv_area->number_trace_elements = - trace_cfg_struct.number_trace_status_elements; - - chdlc_priv_area->end_trace_addr = (unsigned long) - ((TRACE_STATUS_ELEMENT_STRUCT *) - chdlc_priv_area->start_trace_addr + - (chdlc_priv_area->number_trace_elements - 1)); - - chdlc_priv_area->base_addr_trace_buffer = - trace_cfg_struct.base_addr_trace_buffer; - - chdlc_priv_area->end_addr_trace_buffer = - trace_cfg_struct.end_addr_trace_buffer; - - chdlc_priv_area->curr_trace_addr = - trace_cfg_struct.next_trace_element_to_use; - - chdlc_priv_area->available_buffer_space = 2000 - - sizeof(ip_pkt_t) - - sizeof(udp_pkt_t) - - sizeof(wp_mgmt_t) - - sizeof(cblock_t) - - sizeof(trace_info_t); - } - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - mb->buffer_length = 0; - chdlc_priv_area->TracingEnabled = 1; - break; - - - case CPIPE_DISABLE_TRACING: - if (chdlc_priv_area->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); - mb->command = SET_TRACE_CONFIGURATION; - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_config = TRACE_INACTIVE; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - } - - chdlc_priv_area->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - mb->buffer_length = 0; - break; - - - case CPIPE_GET_TRACE_INFO: - - if (!chdlc_priv_area->TracingEnabled) { - chdlc_udp_pkt->cblock.return_code = 1; - mb->buffer_length = 0; - break; - } - - chdlc_udp_pkt->trace_info.ismoredata = 0x00; - buffer_length = 0; /* offset of packet already occupied */ - - for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){ - - trace_pkt_t *trace_pkt = (trace_pkt_t *) - &chdlc_udp_pkt->data[buffer_length]; - - sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr, - (unsigned char *)&trace_element_struct, - sizeof(TRACE_STATUS_ELEMENT_STRUCT)); - - if (trace_element_struct.opp_flag == 0x00) { - break; - } - - /* get pointer to real data */ - data_ptr = trace_element_struct.ptr_data_bfr; - - /* See if there is actual data on the trace buffer */ - if (data_ptr){ - data_length = trace_element_struct.trace_length; - }else{ - data_length = 0; - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - } - - if( (chdlc_priv_area->available_buffer_space - buffer_length) - < ( sizeof(trace_pkt_t) + data_length) ) { - - /* indicate there are more frames on board & exit */ - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - break; - } - - trace_pkt->status = trace_element_struct.trace_type; - - trace_pkt->time_stamp = - trace_element_struct.trace_time_stamp; - - trace_pkt->real_length = - trace_element_struct.trace_length; - - /* see if we can fit the frame into the user buffer */ - real_len = trace_pkt->real_length; - - if (data_ptr == 0) { - trace_pkt->data_avail = 0x00; - } else { - unsigned tmp = 0; - - /* get the data from circular buffer - must check for end of buffer */ - trace_pkt->data_avail = 0x01; - - if ((data_ptr + real_len) > - chdlc_priv_area->end_addr_trace_buffer + 1){ - - tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1; - sdla_peek(&card->hw, data_ptr, - trace_pkt->data,tmp); - data_ptr = chdlc_priv_area->base_addr_trace_buffer; - } - - sdla_peek(&card->hw, data_ptr, - &trace_pkt->data[tmp], real_len - tmp); - } - - /* zero the opp flag to show we got the frame */ - ut_char = 0x00; - sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &ut_char, 1); - - /* now move onto the next frame */ - chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT); - - /* check if we went over the last address */ - if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) { - chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; - } - - if(trace_pkt->data_avail == 0x01) { - buffer_length += real_len - 1; - } - - /* for the header */ - buffer_length += sizeof(trace_pkt_t); - - } /* For Loop */ - - if (frames == chdlc_priv_area->number_trace_elements){ - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - } - chdlc_udp_pkt->trace_info.num_frames = frames; - - mb->buffer_length = buffer_length; - chdlc_udp_pkt->cblock.buffer_length = buffer_length; - - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - - break; - - - case CPIPE_FT1_READ_STATUS: - ((unsigned char *)chdlc_udp_pkt->data )[0] = - flags->FT1_info_struct.parallel_port_A_input; - - ((unsigned char *)chdlc_udp_pkt->data )[1] = - flags->FT1_info_struct.parallel_port_B_input; - - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - mb->buffer_length = 2; - break; - - case CPIPE_ROUTER_UP_TIME: - do_gettimeofday( &tv ); - chdlc_priv_area->router_up_time = tv.tv_sec - - chdlc_priv_area->router_start_time; - *(unsigned long *)&chdlc_udp_pkt->data = - chdlc_priv_area->router_up_time; - mb->buffer_length = sizeof(unsigned long); - break; - - case FT1_MONITOR_STATUS_CTRL: - /* Enable FT1 MONITOR STATUS */ - if ((chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_STATUS) || - (chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_OP_STATS)) { - - if( rCount++ != 0 ) { - chdlc_udp_pkt->cblock. - return_code = COMMAND_OK; - mb->buffer_length = 1; - break; - } - } - - /* Disable FT1 MONITOR STATUS */ - if( chdlc_udp_pkt->data[0] == 0) { - - if( --rCount != 0) { - chdlc_udp_pkt->cblock. - return_code = COMMAND_OK; - mb->buffer_length = 1; - break; - } - } - - default: - /* it's a board command */ - mb->command = chdlc_udp_pkt->cblock.command; - mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length; - if (mb->buffer_length) { - memcpy(&mb->data, (unsigned char *) chdlc_udp_pkt-> - data, mb->buffer_length); - } - /* run the command on the board */ - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) { - break; - } - - /* copy the result back to our buffer */ - memcpy(&chdlc_udp_pkt->cblock, mb, sizeof(cblock_t)); - - if (mb->buffer_length) { - memcpy(&chdlc_udp_pkt->data, &mb->data, - mb->buffer_length); - } - - } /* end of switch */ - } /* end of else */ - - /* Fill UDP TTL */ - chdlc_udp_pkt->ip_pkt.ttl = card->wandev.ttl; - - len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length); - - if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) { - ++ card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += len; - } - } else { - - /* Pass it up the stack - Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) { - /* copy data into new_skb */ - - buf = skb_put(new_skb, len); - memcpy(buf, chdlc_priv_area->udp_pkt_data, len); - - /* Decapsulate pkt and pass it up the protocol stack */ - new_skb->protocol = htons(ETH_P_IP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; - - netif_rx(new_skb); - dev->last_rx = jiffies; - } else { - - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - } - } - - chdlc_priv_area->udp_pkt_lgth = 0; - - return 0; -} - -/*============================================================================ - * Initialize Receive and Transmit Buffers. - */ - -static void init_chdlc_tx_rx_buff(sdla_t* card, struct net_device *dev) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; - CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config; - char err; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - chdlc_error(card,err,mb); - return; - } - - if(card->hw.type == SDLA_S514) { - tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Tx_stat_el_cfg_struct)); - rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Rx_stat_el_cfg_struct)); - - /* Setup Head and Tails for buffers */ - card->u.c.txbuf_base = (void *)(card->hw.dpmbase + - tx_config->base_addr_Tx_status_elements); - card->u.c.txbuf_last = - (CHDLC_DATA_TX_STATUS_EL_STRUCT *) - card->u.c.txbuf_base + - (tx_config->number_Tx_status_elements - 1); - - card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + - rx_config->base_addr_Rx_status_elements); - card->u.c.rxbuf_last = - (CHDLC_DATA_RX_STATUS_EL_STRUCT *) - card->u.c.rxbuf_base + - (rx_config->number_Rx_status_elements - 1); - - /* Set up next pointer to be used */ - card->u.c.txbuf = (void *)(card->hw.dpmbase + - tx_config->next_Tx_status_element_to_use); - card->u.c.rxmb = (void *)(card->hw.dpmbase + - rx_config->next_Rx_status_element_to_use); - } - else { - tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); - - rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); - - /* Setup Head and Tails for buffers */ - card->u.c.txbuf_base = (void *)(card->hw.dpmbase + - (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE)); - card->u.c.txbuf_last = - (CHDLC_DATA_TX_STATUS_EL_STRUCT *)card->u.c.txbuf_base - + (tx_config->number_Tx_status_elements - 1); - card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + - (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE)); - card->u.c.rxbuf_last = - (CHDLC_DATA_RX_STATUS_EL_STRUCT *)card->u.c.rxbuf_base - + (rx_config->number_Rx_status_elements - 1); - - /* Set up next pointer to be used */ - card->u.c.txbuf = (void *)(card->hw.dpmbase + - (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE)); - card->u.c.rxmb = (void *)(card->hw.dpmbase + - (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE)); - } - - /* Setup Actual Buffer Start and end addresses */ - card->u.c.rx_base = rx_config->base_addr_Rx_buffer; - card->u.c.rx_top = rx_config->end_addr_Rx_buffer; - -} - -/*============================================================================= - * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR - * _TEST_COUNTER times. - */ -static int intr_test( sdla_t* card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int err,i; - - Intr_test_counter = 0; - - /* The critical flag is unset because during initialization (if_open) - * we want the interrupts to be enabled so that when the wpc_isr is - * called it does not exit due to critical flag set. - */ - - err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); - - if (err == CMD_OK) { - for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { - mb->buffer_length = 0; - mb->command = READ_CHDLC_CODE_VERSION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - } - } - else { - return err; - } - - err = chdlc_set_intr_mode(card, 0); - - if (err != CMD_OK) - return err; - - return 0; -} - -/*============================================================================== - * Determine what type of UDP call it is. CPIPEAB ? - */ -static int udp_pkt_type(struct sk_buff *skb, sdla_t* card) -{ - chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data; - - if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) && - (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && - (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && - (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { - return UDP_CPIPE_TYPE; - } - else return UDP_INVALID_TYPE; -} - -/*============================================================================ - * Set PORT state. - */ -static void port_set_state (sdla_t *card, int state) -{ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area = dev->priv; - - if (card->u.c.state != state) - { - switch (state) - { - case WAN_CONNECTED: - printk (KERN_INFO "%s: HDLC link connected!\n", - card->devname); - break; - - case WAN_CONNECTING: - printk (KERN_INFO "%s: HDLC link connecting...\n", - card->devname); - break; - - case WAN_DISCONNECTED: - printk (KERN_INFO "%s: HDLC link disconnected!\n", - card->devname); - break; - } - - card->wandev.state = card->u.c.state = state; - chdlc_priv_area->common.state = state; - } -} - -void s508_lock (sdla_t *card, unsigned long *smp_flags) -{ - spin_lock_irqsave(&card->wandev.lock, *smp_flags); - if (card->next){ - /* It is ok to use spin_lock here, since we - * already turned off interrupts */ - spin_lock(&card->next->wandev.lock); - } -} - -void s508_unlock (sdla_t *card, unsigned long *smp_flags) -{ - if (card->next){ - spin_unlock(&card->next->wandev.lock); - } - spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); -} - - - -/*=========================================================================== - * config_chdlc - * - * Configure the chdlc protocol and enable communications. - * - * The if_open() function binds this function to the poll routine. - * Therefore, this function will run every time the chdlc interface - * is brought up. We cannot run this function from the if_open - * because if_open does not have access to the remote IP address. - * - * If the communications are not enabled, proceed to configure - * the card and enable communications. - * - * If the communications are enabled, it means that the interface - * was shutdown by ether the user or driver. In this case, we - * have to check that the IP addresses have not changed. If - * the IP addresses have changed, we have to reconfigure the firmware - * and update the changed IP addresses. Otherwise, just exit. - * - */ - -static int config_chdlc (sdla_t *card) -{ - struct net_device *dev = card->wandev.dev; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - - if (card->u.c.comm_enabled){ - chdlc_comm_disable(card); - port_set_state(card, WAN_DISCONNECTED); - } - - if (set_chdlc_config(card)) { - printk(KERN_INFO "%s: CHDLC Configuration Failed!\n", - card->devname); - return 0; - } - init_chdlc_tx_rx_buff(card, dev); - - /* Set interrupt mode and mask */ - if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | - APP_INT_ON_GLOBAL_EXCEP_COND | - APP_INT_ON_TX_FRAME | - APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ - printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", - card->devname); - return 0; - } - - - /* Mask the Transmit and Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); - - - if (chdlc_comm_enable(card) != 0) { - printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", - card->devname); - flags->interrupt_info_struct.interrupt_permission = 0; - card->u.c.comm_enabled=0; - chdlc_set_intr_mode(card,0); - return 0; - } - - /* Initialize Rx/Tx buffer control fields */ - port_set_state(card, WAN_CONNECTING); - return 0; -} - - -static void send_ppp_term_request(struct net_device *dev) -{ - struct sk_buff *new_skb; - unsigned char *buf; - - if ((new_skb = dev_alloc_skb(8)) != NULL) { - /* copy data into new_skb */ - - buf = skb_put(new_skb, 8); - sprintf(buf,"%c%c%c%c%c%c%c%c", 0xFF,0x03,0xC0,0x21,0x05,0x98,0x00,0x07); - - /* Decapsulate pkt and pass it up the protocol stack */ - new_skb->protocol = htons(ETH_P_WAN_PPP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; - - netif_rx(new_skb); - dev->last_rx = jiffies; - } -} - - -MODULE_LICENSE("GPL"); - -/****** End ****************************************************************/ -- cgit v1.1 From 5636f72794b42d31b2660064ef2c17f90816b3b1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 11 Apr 2006 10:28:21 -0700 Subject: [PATCH] dlink pci cards using wrong driver This patch fixes the problem of some Dlink cards picking the wrong driver. It looks like these cards use Yukon 1 chipset, not Yukon 2. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 2 ++ drivers/net/sky2.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 35dbf05..a70c2b0 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -78,6 +78,8 @@ static const struct pci_device_id skge_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) }, { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU) }, { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T), }, + { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) }, + { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b01) }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */ { PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) }, diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 68f9c20..4272e47 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -99,8 +99,6 @@ MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); static const struct pci_device_id sky2_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, - { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) }, - { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b01) }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) }, -- cgit v1.1 From ff768cd7139ab368bc2b97e7bd6fa592f20e1950 Mon Sep 17 00:00:00 2001 From: Komuro Date: Sun, 9 Apr 2006 11:21:10 +0900 Subject: [PATCH] network: axnet_cs.c: add missing 'PRIV' in ei_rx_overrun Signed-off-by: komurojun-mbn@nifty.com Signed-off-by: Jeff Garzik --- drivers/net/pcmcia/axnet_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 56233af..448a094 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -1560,7 +1560,7 @@ static void ei_receive(struct net_device *dev) static void ei_rx_overrun(struct net_device *dev) { - axnet_dev_t *info = (axnet_dev_t *)dev; + axnet_dev_t *info = PRIV(dev); long e8390_base = dev->base_addr; unsigned char was_txing, must_resend = 0; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); -- cgit v1.1 From 4be5de25259de21894df5e2fecc30da8252dee8c Mon Sep 17 00:00:00 2001 From: Roger Luethi Date: Tue, 4 Apr 2006 20:49:16 +0200 Subject: [PATCH] via-rhine: execute bounce buffers code on Rhine-I only Patch suggested by Yang Wu (pin xue ). Signed-off-by: Roger Luethi Signed-off-by: Jeff Garzik --- drivers/net/via-rhine.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index a9b2150..53dfc8c 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -469,7 +469,7 @@ struct rhine_private { struct sk_buff *tx_skbuff[TX_RING_SIZE]; dma_addr_t tx_skbuff_dma[TX_RING_SIZE]; - /* Tx bounce buffers */ + /* Tx bounce buffers (Rhine-I only) */ unsigned char *tx_buf[TX_RING_SIZE]; unsigned char *tx_bufs; dma_addr_t tx_bufs_dma; @@ -1043,7 +1043,8 @@ static void alloc_tbufs(struct net_device* dev) rp->tx_ring[i].desc_length = cpu_to_le32(TXDESC); next += sizeof(struct tx_desc); rp->tx_ring[i].next_desc = cpu_to_le32(next); - rp->tx_buf[i] = &rp->tx_bufs[i * PKT_BUF_SZ]; + if (rp->quirks & rqRhineI) + rp->tx_buf[i] = &rp->tx_bufs[i * PKT_BUF_SZ]; } rp->tx_ring[i-1].next_desc = cpu_to_le32(rp->tx_ring_dma); -- cgit v1.1 From 2b474cf53870abf1bbad631c3368b9efc9b5ba9d Mon Sep 17 00:00:00 2001 From: Gary Zambrano Date: Mon, 10 Apr 2006 12:02:21 -0700 Subject: [PATCH] b44: disable default tx pause Disable default tx pause frame support. The b44 controller has a bug that generates excessive tx pause frames. Signed-off-by: Gary Zambrano Signed-off-by: Jeff Garzik --- drivers/net/b44.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/b44.c b/drivers/net/b44.c index c4e12b5..a67d537 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -410,25 +410,18 @@ static void __b44_set_flow_ctrl(struct b44 *bp, u32 pause_flags) static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote) { - u32 pause_enab = bp->flags & (B44_FLAG_TX_PAUSE | - B44_FLAG_RX_PAUSE); - - if (local & ADVERTISE_PAUSE_CAP) { - if (local & ADVERTISE_PAUSE_ASYM) { - if (remote & LPA_PAUSE_CAP) - pause_enab |= (B44_FLAG_TX_PAUSE | - B44_FLAG_RX_PAUSE); - else if (remote & LPA_PAUSE_ASYM) - pause_enab |= B44_FLAG_RX_PAUSE; - } else { - if (remote & LPA_PAUSE_CAP) - pause_enab |= (B44_FLAG_TX_PAUSE | - B44_FLAG_RX_PAUSE); - } - } else if (local & ADVERTISE_PAUSE_ASYM) { - if ((remote & LPA_PAUSE_CAP) && - (remote & LPA_PAUSE_ASYM)) - pause_enab |= B44_FLAG_TX_PAUSE; + u32 pause_enab = 0; + + /* The driver supports only rx pause by default because + the b44 mac tx pause mechanism generates excessive + pause frames. + Use ethtool to turn on b44 tx pause if necessary. + */ + if ((local & ADVERTISE_PAUSE_CAP) && + (local & ADVERTISE_PAUSE_ASYM)){ + if ((remote & LPA_PAUSE_ASYM) && + !(remote & LPA_PAUSE_CAP)) + pause_enab |= B44_FLAG_RX_PAUSE; } __b44_set_flow_ctrl(bp, pause_enab); -- cgit v1.1 From 8056bfafb8a845f3035e7aae5ffe405df118bc12 Mon Sep 17 00:00:00 2001 From: Gary Zambrano Date: Mon, 10 Apr 2006 12:05:40 -0700 Subject: [PATCH] b44: increase version to 1.00 Signed-off-by: Jeff Garzik --- drivers/net/b44.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/b44.c b/drivers/net/b44.c index a67d537..aa1ef74 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -2,6 +2,7 @@ * * Copyright (C) 2002 David S. Miller (davem@redhat.com) * Fixed by Pekka Pietikainen (pp@ee.oulu.fi) + * Copyright (C) 2006 Broadcom Corporation. * * Distribute under GPL. */ @@ -28,8 +29,8 @@ #define DRV_MODULE_NAME "b44" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "0.97" -#define DRV_MODULE_RELDATE "Nov 30, 2005" +#define DRV_MODULE_VERSION "1.00" +#define DRV_MODULE_RELDATE "Apr 7, 2006" #define B44_DEF_MSG_ENABLE \ (NETIF_MSG_DRV | \ -- cgit v1.1 From 10badc215493a435e2dbdc691386f2650a1778de Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 12 Apr 2006 18:04:32 -0400 Subject: [netdrvr b44] trim trailing whitespace --- drivers/net/b44.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/b44.c b/drivers/net/b44.c index aa1ef74..3d30668 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -137,7 +137,7 @@ static inline unsigned long br32(const struct b44 *bp, unsigned long reg) return readl(bp->regs + reg); } -static inline void bw32(const struct b44 *bp, +static inline void bw32(const struct b44 *bp, unsigned long reg, unsigned long val) { writel(val, bp->regs + reg); @@ -287,13 +287,13 @@ static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index) val |= ((u32) data[4]) << 8; val |= ((u32) data[5]) << 0; bw32(bp, B44_CAM_DATA_LO, val); - val = (CAM_DATA_HI_VALID | + val = (CAM_DATA_HI_VALID | (((u32) data[0]) << 8) | (((u32) data[1]) << 0)); bw32(bp, B44_CAM_DATA_HI, val); bw32(bp, B44_CAM_CTRL, (CAM_CTRL_WRITE | (index << CAM_CTRL_INDEX_SHIFT))); - b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1); + b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1); } static inline void __b44_disable_ints(struct b44 *bp) @@ -411,15 +411,15 @@ static void __b44_set_flow_ctrl(struct b44 *bp, u32 pause_flags) static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote) { - u32 pause_enab = 0; + u32 pause_enab = 0; /* The driver supports only rx pause by default because - the b44 mac tx pause mechanism generates excessive - pause frames. + the b44 mac tx pause mechanism generates excessive + pause frames. Use ethtool to turn on b44 tx pause if necessary. */ if ((local & ADVERTISE_PAUSE_CAP) && - (local & ADVERTISE_PAUSE_ASYM)){ + (local & ADVERTISE_PAUSE_ASYM)){ if ((remote & LPA_PAUSE_ASYM) && !(remote & LPA_PAUSE_CAP)) pause_enab |= B44_FLAG_RX_PAUSE; @@ -1057,7 +1057,7 @@ static int b44_change_mtu(struct net_device *dev, int new_mtu) spin_unlock_irq(&bp->lock); b44_enable_ints(bp); - + return 0; } @@ -1375,7 +1375,7 @@ static void b44_init_hw(struct b44 *bp) bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset); bw32(bp, B44_DMARX_PTR, bp->rx_pending); - bp->rx_prod = bp->rx_pending; + bp->rx_prod = bp->rx_pending; bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); @@ -1547,9 +1547,9 @@ static void __b44_set_rx_mode(struct net_device *dev) val |= RXCONFIG_ALLMULTI; else i = __b44_load_mcast(bp, dev); - + for (; i < 64; i++) { - __b44_cam_write(bp, zero, i); + __b44_cam_write(bp, zero, i); } bw32(bp, B44_RXCONFIG, val); val = br32(bp, B44_CAM_CTRL); @@ -1731,7 +1731,7 @@ static int b44_set_ringparam(struct net_device *dev, spin_unlock_irq(&bp->lock); b44_enable_ints(bp); - + return 0; } @@ -1776,7 +1776,7 @@ static int b44_set_pauseparam(struct net_device *dev, spin_unlock_irq(&bp->lock); b44_enable_ints(bp); - + return 0; } @@ -1892,7 +1892,7 @@ static int __devinit b44_get_invariants(struct b44 *bp) bp->core_unit = ssb_core_unit(bp); bp->dma_offset = SB_PCI_DMA; - /* XXX - really required? + /* XXX - really required? bp->flags |= B44_FLAG_BUGGY_TXPTR; */ out: @@ -1940,7 +1940,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev, "aborting.\n"); goto err_out_free_res; } - + err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK); if (err) { printk(KERN_ERR PFX "No usable DMA configuration, " @@ -2035,9 +2035,9 @@ static int __devinit b44_init_one(struct pci_dev *pdev, pci_save_state(bp->pdev); - /* Chip reset provides power to the b44 MAC & PCI cores, which + /* Chip reset provides power to the b44 MAC & PCI cores, which * is necessary for MAC register access. - */ + */ b44_chip_reset(bp); printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name); @@ -2085,10 +2085,10 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state) del_timer_sync(&bp->timer); - spin_lock_irq(&bp->lock); + spin_lock_irq(&bp->lock); b44_halt(bp); - netif_carrier_off(bp->dev); + netif_carrier_off(bp->dev); netif_device_detach(bp->dev); b44_free_rings(bp); -- cgit v1.1 From 0761be4f5f9efb5f72a5f9771f2ed5845a974c46 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 10 Apr 2006 23:22:21 -0700 Subject: [PATCH] drivers/net/via-rhine.c: make a function static Signed-off-by: Adrian Bunk Signed-off-by: Roger Luethi Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/via-rhine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 53dfc8c..6a23964 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1092,7 +1092,7 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media) } /* Called after status of force_media possibly changed */ -void rhine_set_carrier(struct mii_if_info *mii) +static void rhine_set_carrier(struct mii_if_info *mii) { if (mii->force_media) { /* autoneg is off: Link is always assumed to be up */ -- cgit v1.1 From 037998d1e979e88a140ef32c5d28730f6ca8a96f Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 10 Apr 2006 23:22:07 -0700 Subject: [PATCH] remove drivers/net/hydra.h Remove drivers/net/hydra.h which is both unused and covered by a 4 clause BSD licence (not by the UCB). Signed-off-by: Adrian Bunk Acked-By: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/hydra.h | 177 ---------------------------------------------------- 1 file changed, 177 deletions(-) delete mode 100644 drivers/net/hydra.h (limited to 'drivers/net') diff --git a/drivers/net/hydra.h b/drivers/net/hydra.h deleted file mode 100644 index 3741414..0000000 --- a/drivers/net/hydra.h +++ /dev/null @@ -1,177 +0,0 @@ -/* $Linux: hydra.h,v 1.0 1994/10/26 02:03:47 cgd Exp $ */ - -/* - * Copyright (c) 1994 Timo Rossi - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Timo Rossi - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * The Hydra Systems card uses the National Semiconductor - * 8390 NIC (Network Interface Controller) chip, located - * at card base address + 0xffe1. NIC registers are accessible - * only at odd byte addresses, so the register offsets must - * be multiplied by two. - * - * Card address PROM is located at card base + 0xffc0 (even byte addresses) - * - * RAM starts at the card base address, and is 16K or 64K. - * The current Amiga NetBSD hydra driver is hardwired for 16K. - * It seems that the RAM should be accessed as words or longwords only. - * - */ - -/* adapted for Linux by Topi Kanerva 03/29/95 - with original author's permission */ - -#define HYDRA_NIC_BASE 0xffe1 - -/* Page0 registers */ - -#define NIC_CR 0 /* Command register */ -#define NIC_PSTART (1*2) /* Page start (write) */ -#define NIC_PSTOP (2*2) /* Page stop (write) */ -#define NIC_BNDRY (3*2) /* Boundary pointer */ -#define NIC_TSR (4*2) /* Transmit status (read) */ -#define NIC_TPSR (4*2) /* Transmit page start (write) */ -#define NIC_NCR (5*2) /* Number of collisions, read */ -#define NIC_TBCR0 (5*2) /* Transmit byte count low (write) */ -#define NIC_FIFO (6*2) /* FIFO reg. (read) */ -#define NIC_TBCR1 (6*2) /* Transmit byte count high (write) */ -#define NIC_ISR (7*2) /* Interrupt status register */ -#define NIC_RBCR0 (0xa*2) /* Remote byte count low (write) */ -#define NIC_RBCR1 (0xb*2) /* Remote byte count high (write) */ -#define NIC_RSR (0xc*2) /* Receive status (read) */ -#define NIC_RCR (0xc*2) /* Receive config (write) */ -#define NIC_CNTR0 (0xd*2) /* Frame alignment error count (read) */ -#define NIC_TCR (0xd*2) /* Transmit config (write) */ -#define NIC_CNTR1 (0xe*2) /* CRC error counter (read) */ -#define NIC_DCR (0xe*2) /* Data config (write) */ -#define NIC_CNTR2 (0xf*2) /* missed packet counter (read) */ -#define NIC_IMR (0xf*2) /* Interrupt mask reg. (write) */ - -/* Page1 registers */ - -#define NIC_PAR0 (1*2) /* Physical address */ -#define NIC_PAR1 (2*2) -#define NIC_PAR2 (3*2) -#define NIC_PAR3 (4*2) -#define NIC_PAR4 (5*2) -#define NIC_PAR5 (6*2) -#define NIC_CURR (7*2) /* Current RX ring-buffer page */ -#define NIC_MAR0 (8*2) /* Multicast address */ -#define NIC_MAR1 (9*2) -#define NIC_MAR2 (0xa*2) -#define NIC_MAR3 (0xb*2) -#define NIC_MAR4 (0xc*2) -#define NIC_MAR5 (0xd*2) -#define NIC_MAR6 (0xe*2) -#define NIC_MAR7 (0xf*2) - -/* Command register definitions */ - -#define CR_STOP 0x01 /* Stop -- software reset command */ -#define CR_START 0x02 /* Start */ -#define CR_TXP 0x04 /* Transmit packet */ - -#define CR_RD0 0x08 /* Remote DMA cmd */ -#define CR_RD1 0x10 -#define CR_RD2 0x20 - -#define CR_NODMA CR_RD2 - -#define CR_PS0 0x40 /* Page select */ -#define CR_PS1 0x80 - -#define CR_PAGE0 0 -#define CR_PAGE1 CR_PS0 -#define CR_PAGE2 CR_PS1 - -/* Interrupt status reg. definitions */ - -#define ISR_PRX 0x01 /* Packet received without errors */ -#define ISR_PTX 0x02 /* Packet transmitted without errors */ -#define ISR_RXE 0x04 /* Receive error */ -#define ISR_TXE 0x08 /* Transmit error */ -#define ISR_OVW 0x10 /* Ring buffer overrun */ -#define ISR_CNT 0x20 /* Counter overflow */ -#define ISR_RDC 0x40 /* Remote DMA compile */ -#define ISR_RST 0x80 /* Reset status */ - -/* Data config reg. definitions */ - -#define DCR_WTS 0x01 /* Word transfer select */ -#define DCR_BOS 0x02 /* Byte order select */ -#define DCR_LAS 0x04 /* Long address select */ -#define DCR_LS 0x08 /* Loopback select */ -#define DCR_AR 0x10 /* Auto-init remote */ -#define DCR_FT0 0x20 /* FIFO threshold select */ -#define DCR_FT1 0x40 - -/* Transmit config reg. definitions */ - -#define TCR_CRC 0x01 /* Inhibit CRC */ -#define TCR_LB0 0x02 /* Loopback control */ -#define TCR_LB1 0x04 -#define TCR_ATD 0x08 /* Auto transmit disable */ -#define TCR_OFST 0x10 /* Collision offset enable */ - -/* Transmit status reg. definitions */ - -#define TSR_PTX 0x01 /* Packet transmitted */ -#define TSR_COL 0x04 /* Transmit collided */ -#define TSR_ABT 0x08 /* Transmit aborted */ -#define TSR_CRS 0x10 /* Carrier sense lost */ -#define TSR_FU 0x20 /* FIFO underrun */ -#define TSR_CDH 0x40 /* CD Heartbeat */ -#define TSR_OWC 0x80 /* Out of Window Collision */ - -/* Receiver config register definitions */ - -#define RCR_SEP 0x01 /* Save errored packets */ -#define RCR_AR 0x02 /* Accept runt packets */ -#define RCR_AB 0x04 /* Accept broadcast */ -#define RCR_AM 0x08 /* Accept multicast */ -#define RCR_PRO 0x10 /* Promiscuous mode */ -#define RCR_MON 0x20 /* Monitor mode */ - -/* Receiver status register definitions */ - -#define RSR_PRX 0x01 /* Packet received without error */ -#define RSR_CRC 0x02 /* CRC error */ -#define RSR_FAE 0x04 /* Frame alignment error */ -#define RSR_FO 0x08 /* FIFO overrun */ -#define RSR_MPA 0x10 /* Missed packet */ -#define RSR_PHY 0x20 /* Physical address */ -#define RSR_DIS 0x40 /* Received disabled */ -#define RSR_DFR 0x80 /* Deferring (jabber) */ - -/* Hydra System card address PROM offset */ - -#define HYDRA_ADDRPROM 0xffc0 - - -- cgit v1.1 From e19360f2945f54eb44ae170ec9c33910d29834a2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 10 Apr 2006 23:22:06 -0700 Subject: [PATCH] net drivers: fix section attributes for gcc If CONFIG_HOTPLUG=n, gcc doesn't like some __initdata to be const (rodata) and other __initdata not const, so make the non-const __initdata const. gcc errors: drivers/net/bnx2.c:66: error: version causes a section type conflict drivers/net/starfire.c:338: error: version causes a section type conflict drivers/net/typhoon.c:137: error: version causes a section type conflict drivers/net/natsemi.c:241: error: version causes a section type conflict Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/bnx2.c | 2 +- drivers/net/natsemi.c | 2 +- drivers/net/starfire.c | 2 +- drivers/net/typhoon.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 2671da2..5ca99e2 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -63,7 +63,7 @@ /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (5*HZ) -static char version[] __devinitdata = +static const char version[] __devinitdata = "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("Michael Chan "); diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 7826afb..9062775 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -238,7 +238,7 @@ static int full_duplex[MAX_UNITS]; #define NATSEMI_RX_LIMIT 2046 /* maximum supported by hardware */ /* These identify the driver base version and may not be removed. */ -static char version[] __devinitdata = +static const char version[] __devinitdata = KERN_INFO DRV_NAME " dp8381x driver, version " DRV_VERSION ", " DRV_RELDATE "\n" KERN_INFO " originally by Donald Becker \n" diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 45ad036..9b7805b 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -335,7 +335,7 @@ do { \ /* These identify the driver base version and may not be removed. */ -static char version[] __devinitdata = +static const char version[] __devinitdata = KERN_INFO "starfire.c:v1.03 7/26/2000 Written by Donald Becker \n" KERN_INFO " (unofficial 2.2/2.4 kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n"; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index c1ce87a..d9258d4 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -134,7 +134,7 @@ static const int multicast_filter_limit = 32; #include "typhoon.h" #include "typhoon-firmware.h" -static char version[] __devinitdata = +static const char version[] __devinitdata = "typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("David Dillow "); -- cgit v1.1 From 5c5374087707d7848cb13f15e7c175daf346301c Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Tue, 11 Apr 2006 18:23:15 -0700 Subject: [PATCH] mv643xx_eth: Always free completed tx descs on tx interrupt Fix the tx interrupt handler to free completed tx descriptors even when NAPI is enabled. Otherwise, the tx queue would fill up resulting in poor performance and "NETDEV WATCHDOG: : transmit timed out" messages. Signed-off-by: Brent Cook Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 9f26613..85ac42c 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -552,9 +552,9 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, #else if (eth_int_cause & ETH_INT_CAUSE_RX) mv643xx_eth_receive_queue(dev, INT_MAX); +#endif if (eth_int_cause_ext & ETH_INT_CAUSE_TX) mv643xx_eth_free_completed_tx_descs(dev); -#endif /* * If no real interrupt occured, exit. -- cgit v1.1 From 94843566d7119e049a72618a3c939d5c2be022c7 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Tue, 11 Apr 2006 18:24:26 -0700 Subject: [PATCH] mv643xx_eth: Fix tx_timeout to only conditionally wake tx queue After resetting the hardware on a tx_timeout, call netif_wake_queue() only if we have free tx descriptors. Also, attempt to recover if mv643xx_eth_start_xmit() is called when there are fewer free tx descriptors than expected. The BUG_ON() call we are replacing was hit on a tx_timeout that called netif_wake_queue(), indirectly via netif_device_attach(), even though we did not have enough free tx descriptors. Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 85ac42c..ea62a3e 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -281,10 +281,16 @@ static void mv643xx_eth_tx_timeout_task(struct net_device *dev) { struct mv643xx_private *mp = netdev_priv(dev); - netif_device_detach(dev); + if (!netif_running(dev)) + return; + + netif_stop_queue(dev); + eth_port_reset(mp->port_num); eth_port_start(dev); - netif_device_attach(dev); + + if (mp->tx_ring_size - mp->tx_desc_count >= MAX_DESCS_PER_SKB) + netif_wake_queue(dev); } /** @@ -1186,7 +1192,12 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) BUG_ON(netif_queue_stopped(dev)); BUG_ON(skb == NULL); - BUG_ON(mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB); + + if (mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB) { + printk(KERN_ERR "%s: transmit with queue full\n", dev->name); + netif_stop_queue(dev); + return 1; + } if (has_tiny_unaligned_frags(skb)) { if ((skb_linearize(skb, GFP_ATOMIC) != 0)) { -- cgit v1.1 From 43f2f10444c008296cc8de68a72fd87b33b50452 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 5 Apr 2006 17:47:15 -0700 Subject: [PATCH] sky2: bad memory reference on dual port cards Sky2 driver will oops referencing bad memory if used on a dual port card. The problem is accessing past end of MIB counter space. Applies for both 2.6.17 and 2.6.16 (with fuzz) Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 4 ++-- drivers/net/sky2.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 4272e47..67b0eab 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -577,8 +577,8 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) reg = gma_read16(hw, port, GM_PHY_ADDR); gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR); - for (i = 0; i < GM_MIB_CNT_SIZE; i++) - gma_read16(hw, port, GM_MIB_CNT_BASE + 8 * i); + for (i = GM_MIB_CNT_BASE; i <= GM_MIB_CNT_END; i += 4) + gma_read16(hw, port, i); gma_write16(hw, port, GM_PHY_ADDR, reg); /* transmit control */ diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 62532b4..89dd18cd 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1375,7 +1375,7 @@ enum { GM_PHY_ADDR = 0x0088, /* 16 bit r/w GPHY Address Register */ /* MIB Counters */ GM_MIB_CNT_BASE = 0x0100, /* Base Address of MIB Counters */ - GM_MIB_CNT_SIZE = 256, + GM_MIB_CNT_END = 0x025C, /* Last MIB counter */ }; -- cgit v1.1 From c91e468a48a2afd2a2b0c2e29a35d6b8c51ea682 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Tue, 28 Mar 2006 18:10:38 +0200 Subject: [PATCH] Use pci_set_consistent_dma_mask in ixgb driver The ixgb driver is using pci_alloc_consistent, thus is should also use pci_set_consistent_dma_mask. This allows the driver to work on SGI systems. In case of an error during probing it should also disable the device again. Signed-off-by: Andreas Schwab Signed-off-by: Jeff Garzik --- drivers/net/ixgb/ixgb_main.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index f9f77e4..cfd67d8 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -357,18 +357,20 @@ ixgb_probe(struct pci_dev *pdev, if((err = pci_enable_device(pdev))) return err; - if(!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) { + if(!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) && + !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) { pci_using_dac = 1; } else { - if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) { + if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) || + (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) { IXGB_ERR("No usable DMA configuration, aborting\n"); - return err; + goto err_dma_mask; } pci_using_dac = 0; } if((err = pci_request_regions(pdev, ixgb_driver_name))) - return err; + goto err_request_regions; pci_set_master(pdev); @@ -502,6 +504,9 @@ err_ioremap: free_netdev(netdev); err_alloc_etherdev: pci_release_regions(pdev); +err_request_regions: +err_dma_mask: + pci_disable_device(pdev); return err; } -- cgit v1.1 From 269690ac164fc0a7c2de03e7e0d2f554104d1516 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 14 Apr 2006 16:02:07 -0700 Subject: [IRDA]: irda-usb, unregister netdev when patch upload fails In the STIR421x case, when the firmware upload fails, we need to unregister_netdev. Otherwise we hit a BUG on free_netdev(), if sysfs is enabled. Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/irda-usb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 606243d..96bdb73 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -1815,14 +1815,14 @@ static int irda_usb_probe(struct usb_interface *intf, self->needspatch = (ret < 0); if (ret < 0) { printk("patch_device failed\n"); - goto err_out_4; + goto err_out_5; } /* replace IrDA class descriptor with what patched device is now reporting */ irda_desc = irda_usb_find_class_desc (self->usbintf); if (irda_desc == NULL) { ret = -ENODEV; - goto err_out_4; + goto err_out_5; } if (self->irda_desc) kfree (self->irda_desc); @@ -1832,6 +1832,8 @@ static int irda_usb_probe(struct usb_interface *intf, return 0; +err_out_5: + unregister_netdev(self->netdev); err_out_4: kfree(self->speed_buff); err_out_3: -- cgit v1.1 From 08d099974a09faf4cb11ffc46da87073fa132fc0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 14 Apr 2006 16:03:33 -0700 Subject: [IRDA]: smsc-ircc2, smcinit support for ALi ISA bridges From: Linus Walleij This patch enables support for ALi ISA bridges when we run the smcinit code. It is needed to properly configure some Toshiba laptops. Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/smsc-ircc2.c | 316 +++++++++++++++++++++++++++++++++++------- 1 file changed, 264 insertions(+), 52 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index bbcfc8e..58f76ce 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -225,6 +225,8 @@ static int __init smsc_superio_lpc(unsigned short cfg_base); #ifdef CONFIG_PCI static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static void __init preconfigure_ali_port(struct pci_dev *dev, + unsigned short port); static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, unsigned short ircc_fir, @@ -2327,9 +2329,14 @@ static int __init smsc_superio_lpc(unsigned short cfg_base) * pre-configuration not properly done by the BIOS (especially laptops) * This code is based in part on smcinit.c, tosh1800-smcinit.c * and tosh2450-smcinit.c. The table lists the device entries - * for ISA bridges with an LPC (Local Peripheral Configurator) - * that are in turn used to configure the SMSC device with default - * SIR and FIR I/O ports, DMA and IRQ. + * for ISA bridges with an LPC (Low Pin Count) controller which + * handles the communication with the SMSC device. After the LPC + * controller is initialized through PCI, the SMSC device is initialized + * through a dedicated port in the ISA port-mapped I/O area, this latter + * area is used to configure the SMSC device with default + * SIR and FIR I/O ports, DMA and IRQ. Different vendors have + * used different sets of parameters and different control port + * addresses making a subsystem device table necessary. */ #ifdef CONFIG_PCI #define PCIID_VENDOR_INTEL 0x8086 @@ -2340,9 +2347,10 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __dev .device = 0x24cc, .subvendor = 0x103c, .subdevice = 0x088c, - .sir_io = 0x02f8, /* Quite certain these are the same for nc8000 as for nc6000 */ + /* Quite certain these are the same for nc8000 as for nc6000 */ + .sir_io = 0x02f8, .fir_io = 0x0130, - .fir_irq = 0x09, + .fir_irq = 0x05, .fir_dma = 0x03, .cfg_base = 0x004e, .preconfigure = preconfigure_through_82801, @@ -2355,60 +2363,79 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __dev .subdevice = 0x0890, .sir_io = 0x02f8, .fir_io = 0x0130, - .fir_irq = 0x09, + .fir_irq = 0x05, .fir_dma = 0x03, .cfg_base = 0x004e, .preconfigure = preconfigure_through_82801, .name = "HP nc6000", }, { - .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ + /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ + .vendor = PCIID_VENDOR_INTEL, .device = 0x24c0, .subvendor = 0x1179, - .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ + .subdevice = 0xffff, /* 0xffff is "any" */ .sir_io = 0x03f8, .fir_io = 0x0130, .fir_irq = 0x07, .fir_dma = 0x01, .cfg_base = 0x002e, .preconfigure = preconfigure_through_82801, - .name = "Toshiba Satellite 2450", + .name = "Toshiba laptop with Intel 82801DB/DBL LPC bridge", }, { .vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */ - .device = 0x248c, /* Some use 24cc? */ + .device = 0x248c, .subvendor = 0x1179, - .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ + .subdevice = 0xffff, /* 0xffff is "any" */ .sir_io = 0x03f8, .fir_io = 0x0130, .fir_irq = 0x03, .fir_dma = 0x03, .cfg_base = 0x002e, .preconfigure = preconfigure_through_82801, - .name = "Toshiba Satellite 5100/5200, Tecra 9100", + .name = "Toshiba laptop with Intel 82801CAM ISA bridge", }, { - .vendor = PCIID_VENDOR_ALI, /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ + /* 82801DBM (ICH4-M) LPC Interface Bridge */ + .vendor = PCIID_VENDOR_INTEL, + .device = 0x24cc, + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any" */ + .sir_io = 0x03f8, + .fir_io = 0x0130, + .fir_irq = 0x03, + .fir_dma = 0x03, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_82801, + .name = "Toshiba laptop with Intel 8281DBM LPC bridge", + }, + { + /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ + .vendor = PCIID_VENDOR_ALI, .device = 0x1533, .subvendor = 0x1179, - .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ + .subdevice = 0xffff, /* 0xffff is "any" */ .sir_io = 0x02e8, .fir_io = 0x02f8, .fir_irq = 0x07, .fir_dma = 0x03, .cfg_base = 0x002e, .preconfigure = preconfigure_through_ali, - .name = "Toshiba Satellite 1800", + .name = "Toshiba laptop with ALi ISA bridge", }, { } // Terminator }; /* - * This sets up the basic SMSC parameters (FIR port, SIR port, FIR DMA, FIR IRQ) + * This sets up the basic SMSC parameters + * (FIR port, SIR port, FIR DMA, FIR IRQ) * through the chip configuration port. */ -static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf) +static int __init preconfigure_smsc_chip(struct + smsc_ircc_subsystem_configuration + *conf) { unsigned short iobase = conf->cfg_base; unsigned char tmpbyte; @@ -2416,7 +2443,9 @@ static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuratio outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID tmpbyte = inb(iobase +1); // Read device ID - IRDA_DEBUG(0, "Detected Chip id: 0x%02x, setting up registers...\n",tmpbyte); + IRDA_DEBUG(0, + "Detected Chip id: 0x%02x, setting up registers...\n", + tmpbyte); /* Disable UART1 and set up SIR I/O port */ outb(0x24, iobase); // select CR24 - UART1 base addr @@ -2426,6 +2455,7 @@ static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuratio tmpbyte = inb(iobase + 1); if (tmpbyte != (conf->sir_io >> 2) ) { IRDA_WARNING("ERROR: could not configure SIR ioport.\n"); + IRDA_WARNING("Try to supply ircc_cfg argument.\n"); return -ENXIO; } @@ -2461,7 +2491,8 @@ static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuratio outb(SMSCSIOFLAT_UARTMODE0C_REG, iobase); // CR0C - UART mode tmpbyte = inb(iobase + 1); - tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | SMSCSIOFLAT_UART2MODE_VAL_IRDA; + tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | + SMSCSIOFLAT_UART2MODE_VAL_IRDA; outb(tmpbyte, iobase + 1); // enable IrDA (HPSIR) mode, high speed outb(LPC47N227_APMBOOTDRIVE_REG, iobase); // CR07 - Auto Pwr Mgt/boot drive sel @@ -2486,53 +2517,226 @@ static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuratio return 0; } -/* 82801CAM registers */ +/* 82801CAM generic registers */ #define VID 0x00 #define DID 0x02 -#define PIRQA_ROUT 0x60 +#define PIRQ_A_D_ROUT 0x60 +#define SIRQ_CNTL 0x64 +#define PIRQ_E_H_ROUT 0x68 #define PCI_DMA_C 0x90 +/* LPC-specific registers */ #define COM_DEC 0xe0 +#define GEN1_DEC 0xe4 #define LPC_EN 0xe6 #define GEN2_DEC 0xec /* - * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge or - * Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. They all work the same way! + * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge + * or Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. + * They all work the same way! */ static int __init preconfigure_through_82801(struct pci_dev *dev, - struct smsc_ircc_subsystem_configuration *conf) + struct + smsc_ircc_subsystem_configuration + *conf) { unsigned short tmpword; - int ret; + unsigned char tmpbyte; - IRDA_MESSAGE("Setting up the SMSC device via the 82801 controller.\n"); - pci_write_config_byte(dev, COM_DEC, 0x10); + IRDA_MESSAGE("Setting up Intel 82801 controller and SMSC device\n"); + /* + * Select the range for the COMA COM port (SIR) + * Register COM_DEC: + * Bit 7: reserved + * Bit 6-4, COMB decode range + * Bit 3: reserved + * Bit 2-0, COMA decode range + * + * Decode ranges: + * 000 = 0x3f8-0x3ff (COM1) + * 001 = 0x2f8-0x2ff (COM2) + * 010 = 0x220-0x227 + * 011 = 0x228-0x22f + * 100 = 0x238-0x23f + * 101 = 0x2e8-0x2ef (COM4) + * 110 = 0x338-0x33f + * 111 = 0x3e8-0x3ef (COM3) + */ + pci_read_config_byte(dev, COM_DEC, &tmpbyte); + tmpbyte &= 0xf8; /* mask COMA bits */ + switch(conf->sir_io) { + case 0x3f8: + tmpbyte |= 0x00; + break; + case 0x2f8: + tmpbyte |= 0x01; + break; + case 0x220: + tmpbyte |= 0x02; + break; + case 0x228: + tmpbyte |= 0x03; + break; + case 0x238: + tmpbyte |= 0x04; + break; + case 0x2e8: + tmpbyte |= 0x05; + break; + case 0x338: + tmpbyte |= 0x06; + break; + case 0x3e8: + tmpbyte |= 0x07; + break; + default: + tmpbyte |= 0x01; /* COM2 default */ + } + IRDA_DEBUG(1, "COM_DEC (write): 0x%02x\n", tmpbyte); + pci_write_config_byte(dev, COM_DEC, tmpbyte); - /* Enable LPC */ - pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */ - tmpword &= 0xfffd; /* mask bit 1 */ - tmpword |= 0x0001; /* set bit 0 : COMA addr range enable */ + /* Enable Low Pin Count interface */ + pci_read_config_word(dev, LPC_EN, &tmpword); + /* These seem to be set up at all times, + * just make sure it is properly set. + */ + switch(conf->cfg_base) { + case 0x04e: + tmpword |= 0x2000; + break; + case 0x02e: + tmpword |= 0x1000; + break; + case 0x062: + tmpword |= 0x0800; + break; + case 0x060: + tmpword |= 0x0400; + break; + default: + IRDA_WARNING("Uncommon I/O base address: 0x%04x\n", + conf->cfg_base); + break; + } + tmpword &= 0xfffd; /* disable LPC COMB */ + tmpword |= 0x0001; /* set bit 0 : enable LPC COMA addr range (GEN2) */ + IRDA_DEBUG(1, "LPC_EN (write): 0x%04x\n", tmpword); pci_write_config_word(dev, LPC_EN, tmpword); - /* Setup DMA */ - pci_write_config_word(dev, PCI_DMA_C, 0xc0c0); /* LPC I/F DMA on, channel 3 -- rtm (?? PCI DMA ?) */ - pci_write_config_word(dev, GEN2_DEC, 0x131); /* LPC I/F 2nd decode range */ + /* + * Configure LPC DMA channel + * PCI_DMA_C bits: + * Bit 15-14: DMA channel 7 select + * Bit 13-12: DMA channel 6 select + * Bit 11-10: DMA channel 5 select + * Bit 9-8: Reserved + * Bit 7-6: DMA channel 3 select + * Bit 5-4: DMA channel 2 select + * Bit 3-2: DMA channel 1 select + * Bit 1-0: DMA channel 0 select + * 00 = Reserved value + * 01 = PC/PCI DMA + * 10 = Reserved value + * 11 = LPC I/F DMA + */ + pci_read_config_word(dev, PCI_DMA_C, &tmpword); + switch(conf->fir_dma) { + case 0x07: + tmpword |= 0xc000; + break; + case 0x06: + tmpword |= 0x3000; + break; + case 0x05: + tmpword |= 0x0c00; + break; + case 0x03: + tmpword |= 0x00c0; + break; + case 0x02: + tmpword |= 0x0030; + break; + case 0x01: + tmpword |= 0x000c; + break; + case 0x00: + tmpword |= 0x0003; + break; + default: + break; /* do not change settings */ + } + IRDA_DEBUG(1, "PCI_DMA_C (write): 0x%04x\n", tmpword); + pci_write_config_word(dev, PCI_DMA_C, tmpword); + + /* + * GEN2_DEC bits: + * Bit 15-4: Generic I/O range + * Bit 3-1: reserved (read as 0) + * Bit 0: enable GEN2 range on LPC I/F + */ + tmpword = conf->fir_io & 0xfff8; + tmpword |= 0x0001; + IRDA_DEBUG(1, "GEN2_DEC (write): 0x%04x\n", tmpword); + pci_write_config_word(dev, GEN2_DEC, tmpword); /* Pre-configure chip */ - ret = preconfigure_smsc_chip(conf); + return preconfigure_smsc_chip(conf); +} - /* Disable LPC */ - pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */ - tmpword &= 0xfffc; /* mask bit 1 and bit 0, COMA addr range disable */ - pci_write_config_word(dev, LPC_EN, tmpword); - return ret; +/* + * Pre-configure a certain port on the ALi 1533 bridge. + * This is based on reverse-engineering since ALi does not + * provide any data sheet for the 1533 chip. + */ +static void __init preconfigure_ali_port(struct pci_dev *dev, + unsigned short port) +{ + unsigned char reg; + /* These bits obviously control the different ports */ + unsigned char mask; + unsigned char tmpbyte; + + switch(port) { + case 0x0130: + case 0x0178: + reg = 0xb0; + mask = 0x80; + break; + case 0x03f8: + reg = 0xb4; + mask = 0x80; + break; + case 0x02f8: + reg = 0xb4; + mask = 0x30; + break; + case 0x02e8: + reg = 0xb4; + mask = 0x08; + break; + default: + IRDA_ERROR("Failed to configure unsupported port on ALi 1533 bridge: 0x%04x\n", port); + return; + } + + pci_read_config_byte(dev, reg, &tmpbyte); + /* Turn on the right bits */ + tmpbyte |= mask; + pci_write_config_byte(dev, reg, tmpbyte); + IRDA_MESSAGE("Activated ALi 1533 ISA bridge port 0x%04x.\n", port); + return; } static int __init preconfigure_through_ali(struct pci_dev *dev, - struct smsc_ircc_subsystem_configuration *conf) + struct + smsc_ircc_subsystem_configuration + *conf) { - /* TODO: put in ALi 1533 configuration here. */ - IRDA_MESSAGE("SORRY: %s has an unsupported bridge controller (ALi): not pre-configured.\n", conf->name); - return -ENODEV; + /* Configure the two ports on the ALi 1533 */ + preconfigure_ali_port(dev, conf->sir_io); + preconfigure_ali_port(dev, conf->fir_io); + + /* Pre-configure chip */ + return preconfigure_smsc_chip(conf); } static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, @@ -2552,9 +2756,10 @@ static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, struct smsc_ircc_subsystem_configuration *conf; /* - * Cache the subsystem vendor/device: some manufacturers fail to set - * this for all components, so we save it in case there is just - * 0x0000 0x0000 on the device we want to check. + * Cache the subsystem vendor/device: + * some manufacturers fail to set this for all components, + * so we save it in case there is just 0x0000 0x0000 on the + * device we want to check. */ if (dev->subsystem_vendor != 0x0000U) { ss_vendor = dev->subsystem_vendor; @@ -2564,13 +2769,20 @@ static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, for( ; conf->subvendor; conf++) { if(conf->vendor == dev->vendor && conf->device == dev->device && - conf->subvendor == ss_vendor && /* Sometimes these are cached values */ - (conf->subdevice == ss_device || conf->subdevice == 0xffff)) { - struct smsc_ircc_subsystem_configuration tmpconf; + conf->subvendor == ss_vendor && + /* Sometimes these are cached values */ + (conf->subdevice == ss_device || + conf->subdevice == 0xffff)) { + struct smsc_ircc_subsystem_configuration + tmpconf; - memcpy(&tmpconf, conf, sizeof(struct smsc_ircc_subsystem_configuration)); + memcpy(&tmpconf, conf, + sizeof(struct smsc_ircc_subsystem_configuration)); - /* Override the default values with anything passed in as parameter */ + /* + * Override the default values with anything + * passed in as parameter + */ if (ircc_cfg != 0) tmpconf.cfg_base = ircc_cfg; if (ircc_fir != 0) -- cgit v1.1 From 6fcdf565ffb8c661749372115d28efdbe525aeba Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 31 Mar 2006 15:08:46 -0500 Subject: [PATCH] wireless/airo: clean up WEXT association and scan events Airo firmware versions >= 5.30.17 send re-association events to the driver that are currently unrecognized, causing spurious disassociation events to be sent to user space. Loss of sync due to scan requests also results in disassociation events sent to user space. This patch traps those two events; suppressing sync-loss on scan, and sending the correct association event on re-association notifications. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 46 +++++++++++++++++---------------------------- 1 file changed, 17 insertions(+), 29 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 108d9fe..00764dd 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -3139,6 +3139,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) } if ( status & EV_LINK ) { union iwreq_data wrqu; + int scan_forceloss = 0; /* The link status has changed, if you want to put a monitor hook in, do it here. (Remember that interrupts are still disabled!) @@ -3157,7 +3158,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) code) */ #define AUTHFAIL 0x0300 /* Authentication failure (low byte is reason code) */ -#define ASSOCIATED 0x0400 /* Assocatied */ +#define ASSOCIATED 0x0400 /* Associated */ +#define REASSOCIATED 0x0600 /* Reassociated? Only on firmware >= 5.30.17 */ #define RC_RESERVED 0 /* Reserved return code */ #define RC_NOREASON 1 /* Unspecified reason */ #define RC_AUTHINV 2 /* Previous authentication invalid */ @@ -3174,44 +3176,30 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) leaving BSS */ #define RC_NOAUTH 9 /* Station requesting (Re)Association is not Authenticated with the responding station */ - if (newStatus != ASSOCIATED) { - if (auto_wep && !apriv->expires) { - apriv->expires = RUN_AT(3*HZ); - wake_up_interruptible(&apriv->thr_wait); - } - } else { - struct task_struct *task = apriv->task; + if (newStatus == FORCELOSS && apriv->scan_timeout > 0) + scan_forceloss = 1; + if(newStatus == ASSOCIATED || newStatus == REASSOCIATED) { if (auto_wep) apriv->expires = 0; - if (task) - wake_up_process (task); + if (apriv->task) + wake_up_process (apriv->task); set_bit(FLAG_UPDATE_UNI, &apriv->flags); set_bit(FLAG_UPDATE_MULTI, &apriv->flags); - } - /* Question : is ASSOCIATED the only status - * that is valid ? We want to catch handover - * and reassociations as valid status - * Jean II */ - if(newStatus == ASSOCIATED) { -#if 0 - /* FIXME: Grabbing scan results here - * seems to be too early??? Just wait for - * timeout instead. */ - if (apriv->scan_timeout > 0) { - set_bit(JOB_SCAN_RESULTS, &apriv->flags); - wake_up_interruptible(&apriv->thr_wait); - } -#endif + if (down_trylock(&apriv->sem) != 0) { set_bit(JOB_EVENT, &apriv->flags); wake_up_interruptible(&apriv->thr_wait); } else airo_send_event(dev); - } else { - memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; + } else if (!scan_forceloss) { + if (auto_wep && !apriv->expires) { + apriv->expires = RUN_AT(3*HZ); + wake_up_interruptible(&apriv->thr_wait); + } /* Send event to user space */ + memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL); } } @@ -7136,10 +7124,10 @@ static int airo_set_scan(struct net_device *dev, goto out; /* Initiate a scan command */ + ai->scan_timeout = RUN_AT(3*HZ); memset(&cmd, 0, sizeof(cmd)); cmd.cmd=CMD_LISTBSS; issuecommand(ai, &cmd, &rsp); - ai->scan_timeout = RUN_AT(3*HZ); wake = 1; out: -- cgit v1.1 From 3a1af6ffe4941497071125d3a8bb3e1feee45df1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 31 Mar 2006 15:13:31 -0500 Subject: [PATCH] wireless/atmel: send WEXT scan completion events Send scan completion events to user space when a scan completes. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/atmel.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 87afa68..8606c88 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -3463,6 +3463,7 @@ static void atmel_command_irq(struct atmel_private *priv) u8 status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); u8 command = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET)); int fast_scan; + union iwreq_data wrqu; if (status == CMD_STATUS_IDLE || status == CMD_STATUS_IN_PROGRESS) @@ -3487,6 +3488,7 @@ static void atmel_command_irq(struct atmel_private *priv) atmel_scan(priv, 1); } else { int bss_index = retrieve_bss(priv); + int notify_scan_complete = 1; if (bss_index != -1) { atmel_join_bss(priv, bss_index); } else if (priv->operating_mode == IW_MODE_ADHOC && @@ -3495,8 +3497,14 @@ static void atmel_command_irq(struct atmel_private *priv) } else { priv->fast_scan = !fast_scan; atmel_scan(priv, 1); + notify_scan_complete = 0; } priv->site_survey_state = SITE_SURVEY_COMPLETED; + if (notify_scan_complete) { + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); + } } break; @@ -3509,6 +3517,9 @@ static void atmel_command_irq(struct atmel_private *priv) priv->site_survey_state = SITE_SURVEY_COMPLETED; if (priv->station_is_associated) { atmel_enter_state(priv, STATION_STATE_READY); + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); } else { atmel_scan(priv, 1); } -- cgit v1.1 From c1783454a31e05b94774951b0b5d1eb9075ebfb4 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Tue, 4 Apr 2006 15:59:46 -0700 Subject: [PATCH] Revert NET_RADIO Kconfig title change 2.6.17-rc1 changed the title for the entry CONFIG_NET_RADIO. I personally disagree with this change and want it reverted. Patch for 2.6.17-rc1. Rationale : WIRELESS_EXT is an invisible option. Therefore, the only way for a user to enable it is via NET_RADIO. Some users need to do that for out-of-tree drivers. Therefore it should be mentionned in the title of the option. Rationale2 : the option just below is called "Wireless Extension API over RtNetlink". Some users may confuse this option for the main "Wireless Extension" option. Therefore reverting this change help disambiguate the relation between those two options. Signed-off-by: Jean Tourrilhes Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index bad09eb..e0874cb 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -6,7 +6,7 @@ menu "Wireless LAN (non-hamradio)" depends on NETDEVICES config NET_RADIO - bool "Wireless LAN drivers (non-hamradio)" + bool "Wireless LAN drivers (non-hamradio) & Wireless Extensions" select WIRELESS_EXT ---help--- Support for wireless LANs and everything having to do with radio, -- cgit v1.1 From a208c4e1ea7a769042be071ae30ba2ad4c844954 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Fri, 7 Apr 2006 04:10:26 -0400 Subject: [PATCH] orinoco: fix truncating commsquality RID with the latest Symbol firmware Symbol firmware F3.91-71 has an additional word in the commsquality RID. Extend the receiving buffer by one word to accomodate it. Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 8dfdfbd..06523e2 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -390,7 +390,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) } } else { struct { - __le16 qual, signal, noise; + __le16 qual, signal, noise, unused; } __attribute__ ((packed)) cq; err = HERMES_READ_RECORD(hw, USER_BAP, -- cgit v1.1 From b79367a5ea28afe2ac659593970c15c9513f1d49 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 10 Apr 2006 02:39:54 +0200 Subject: [PATCH] bcm43xx: set trans_start on TX to prevent bogus timeouts Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index c37371f..23ad772 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3522,6 +3522,7 @@ static inline int bcm43xx_tx(struct bcm43xx_private *bcm, err = bcm43xx_pio_tx(bcm, txb); else err = bcm43xx_dma_tx(bcm, txb); + bcm->net_dev->trans_start = jiffies; return err; } -- cgit v1.1 From 4c6f749f74323518825476e3e5ca3b4f03c07873 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 11 Apr 2006 14:31:56 -0700 Subject: [PATCH] bcm43xx wireless: fix printk format warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix printk format warnings: drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c:456: warning: format ‘%u’ expects type ‘unsigned int’, but argument 3 has type ‘size_t’ drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c:460: warning: format ‘%08x’ expects type ‘unsigned int’, but argument 2 has type ‘size_t’ drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c:476: warning: format ‘%u’ expects type ‘unsigned int’, but argument 3 has type ‘size_t’ drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c:480: warning: format ‘%08x’ expects type ‘unsigned int’, but argument 2 has type ‘size_t’ drivers/net/wireless/bcm43xx/bcm43xx_dma.c:200: warning: format ‘%08x’ expects type ‘unsigned int’, but argument 2 has type ‘dma_addr_t’ drivers/net/wireless/bcm43xx/bcm43xx_dma.c:311: warning: format ‘%08x’ expects type ‘unsigned int’, but argument 2 has type ‘dma_addr_t’ drivers/net/wireless/bcm43xx/bcm43xx_dma.c:733: warning: format ‘%08x’ expects type ‘unsigned int’, but argument 2 has type ‘dma_addr_t’ Signed-off-by: Randy Dunlap Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 8 ++++---- drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 13 +++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index d2c3401..35a4fcb 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -452,12 +452,12 @@ void bcm43xx_printk_dump(const char *data, size_t i; char c; - printk(KERN_INFO PFX "Data dump (%s, %u bytes):", + printk(KERN_INFO PFX "Data dump (%s, %zd bytes):", description, size); for (i = 0; i < size; i++) { c = data[i]; if (i % 8 == 0) - printk("\n" KERN_INFO PFX "0x%08x: 0x%02x, ", i, c & 0xff); + printk("\n" KERN_INFO PFX "0x%08zx: 0x%02x, ", i, c & 0xff); else printk("0x%02x, ", c & 0xff); } @@ -472,12 +472,12 @@ void bcm43xx_printk_bitdump(const unsigned char *data, int j; const unsigned char *d; - printk(KERN_INFO PFX "*** Bitdump (%s, %u bytes, %s) ***", + printk(KERN_INFO PFX "*** Bitdump (%s, %zd bytes, %s) ***", description, bytes, msb_to_lsb ? "MSB to LSB" : "LSB to MSB"); for (i = 0; i < bytes; i++) { d = data + i; if (i % 8 == 0) - printk("\n" KERN_INFO PFX "0x%08x: ", i); + printk("\n" KERN_INFO PFX "0x%08zx: ", i); if (msb_to_lsb) { for (j = 7; j >= 0; j--) { if (*d & (1 << j)) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index c3681b8..bbecba0 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -196,8 +196,9 @@ static int alloc_ringmemory(struct bcm43xx_dmaring *ring) } if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) { printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G " - "(0x%08x, len: %lu)\n", - ring->dmabase, BCM43xx_DMA_RINGMEMSIZE); + "(0x%llx, len: %lu)\n", + (unsigned long long)ring->dmabase, + BCM43xx_DMA_RINGMEMSIZE); dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, ring->vbase, ring->dmabase); return -ENOMEM; @@ -307,8 +308,8 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); dev_kfree_skb_any(skb); printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G " - "(0x%08x, len: %u)\n", - dmaaddr, ring->rx_buffersize); + "(0x%llx, len: %u)\n", + (unsigned long long)dmaaddr, ring->rx_buffersize); return -ENOMEM; } meta->skb = skb; @@ -729,8 +730,8 @@ static int dma_tx_fragment(struct bcm43xx_dmaring *ring, if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) { return_slot(ring, slot); printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G " - "(0x%08x, len: %u)\n", - meta->dmaaddr, skb->len); + "(0x%llx, len: %u)\n", + (unsigned long long)meta->dmaaddr, skb->len); return -ENOMEM; } -- cgit v1.1 From 93fef7dda4002ac8b21a4a2090ca475dc40cc384 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 11 Apr 2006 14:32:53 -0700 Subject: [PATCH] bcm43xx: fix config menu alignment Use "depends on" to make all bcm43xx driver options be listed at the same level. Signed-off-by: Randy Dunlap Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/Kconfig | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig index 4184656..25ea474 100644 --- a/drivers/net/wireless/bcm43xx/Kconfig +++ b/drivers/net/wireless/bcm43xx/Kconfig @@ -17,8 +17,11 @@ config BCM43XX_DEBUG config BCM43XX_DMA bool + depends on BCM43XX + config BCM43XX_PIO bool + depends on BCM43XX choice prompt "BCM43xx data transfer mode" -- cgit v1.1 From 2230daa0fd50bf82303fd8da96b088310851d803 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 13 Apr 2006 02:27:49 +0200 Subject: [PATCH] bcm43xx: fix dyn tssi2dbm memleak This patch fixes a memory leak spotted by the Coverity checker. Signed-off-by: Adrian Bunk Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index 0a66f43..3313716 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -2151,6 +2151,7 @@ int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm) phy->tssi2dbm = NULL; printk(KERN_ERR PFX "Could not generate " "tssi2dBm table\n"); + kfree(dyn_tssi2dbm); return -ENODEV; } phy->tssi2dbm = dyn_tssi2dbm; -- cgit v1.1 From 8829d55e6b4957770de3f716bafab65ca3680110 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 13 Apr 2006 02:30:26 +0200 Subject: [PATCH] bcm43xx: fix pctl slowclock limit calculation This fixes coverity bug: http://marc.theaimsgroup.com/?l=linux-netdev&m=114417628413880&w=2 Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_power.c | 115 ++++++++++++++++----------- drivers/net/wireless/bcm43xx/bcm43xx_power.h | 9 +++ 2 files changed, 77 insertions(+), 47 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.c b/drivers/net/wireless/bcm43xx/bcm43xx_power.c index 3c92b62..6569da3 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_power.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_power.c @@ -35,77 +35,101 @@ #include "bcm43xx_main.h" +/* Get the Slow Clock Source */ +static int bcm43xx_pctl_get_slowclksrc(struct bcm43xx_private *bcm) +{ + u32 tmp; + int err; + + assert(bcm->current_core == &bcm->core_chipcommon); + if (bcm->current_core->rev < 6) { + if (bcm->bustype == BCM43xx_BUSTYPE_PCMCIA || + bcm->bustype == BCM43xx_BUSTYPE_SB) + return BCM43xx_PCTL_CLKSRC_XTALOS; + if (bcm->bustype == BCM43xx_BUSTYPE_PCI) { + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp); + assert(!err); + if (tmp & 0x10) + return BCM43xx_PCTL_CLKSRC_PCI; + return BCM43xx_PCTL_CLKSRC_XTALOS; + } + } + if (bcm->current_core->rev < 10) { + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); + tmp &= 0x7; + if (tmp == 0) + return BCM43xx_PCTL_CLKSRC_LOPWROS; + if (tmp == 1) + return BCM43xx_PCTL_CLKSRC_XTALOS; + if (tmp == 2) + return BCM43xx_PCTL_CLKSRC_PCI; + } + + return BCM43xx_PCTL_CLKSRC_XTALOS; +} + /* Get max/min slowclock frequency * as described in http://bcm-specs.sipsolutions.net/PowerControl */ static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm, int get_max) { - int limit = 0; + int limit; + int clocksrc; int divisor; - int selection; - int err; u32 tmp; - struct bcm43xx_coreinfo *old_core; - if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) - goto out; - old_core = bcm->current_core; - err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); - if (err) - goto out; + assert(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL); + assert(bcm->current_core == &bcm->core_chipcommon); + clocksrc = bcm43xx_pctl_get_slowclksrc(bcm); if (bcm->current_core->rev < 6) { - if ((bcm->bustype == BCM43xx_BUSTYPE_PCMCIA) || - (bcm->bustype == BCM43xx_BUSTYPE_SB)) { - selection = 1; + switch (clocksrc) { + case BCM43xx_PCTL_CLKSRC_PCI: + divisor = 64; + break; + case BCM43xx_PCTL_CLKSRC_XTALOS: divisor = 32; - } else { - err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp); - if (err) { - printk(KERN_ERR PFX "clockfreqlimit pcicfg read failure\n"); - goto out_switchback; - } - if (tmp & 0x10) { - /* PCI */ - selection = 2; - divisor = 64; - } else { - /* XTAL */ - selection = 1; - divisor = 32; - } + break; + default: + assert(0); + divisor = 1; } } else if (bcm->current_core->rev < 10) { - selection = (tmp & 0x07); - if (selection) { + switch (clocksrc) { + case BCM43xx_PCTL_CLKSRC_LOPWROS: + divisor = 1; + break; + case BCM43xx_PCTL_CLKSRC_XTALOS: + case BCM43xx_PCTL_CLKSRC_PCI: tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); - divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); - } else + divisor = ((tmp & 0xFFFF0000) >> 16) + 1; + divisor *= 4; + break; + default: + assert(0); divisor = 1; + } } else { tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL); - divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); - selection = 1; + divisor = ((tmp & 0xFFFF0000) >> 16) + 1; + divisor *= 4; } - - switch (selection) { - case 0: - /* LPO */ + + switch (clocksrc) { + case BCM43xx_PCTL_CLKSRC_LOPWROS: if (get_max) limit = 43000; else limit = 25000; break; - case 1: - /* XTAL */ + case BCM43xx_PCTL_CLKSRC_XTALOS: if (get_max) limit = 20200000; else limit = 19800000; break; - case 2: - /* PCI */ + case BCM43xx_PCTL_CLKSRC_PCI: if (get_max) limit = 34000000; else @@ -113,17 +137,14 @@ static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm, break; default: assert(0); + limit = 0; } limit /= divisor; -out_switchback: - err = bcm43xx_switch_core(bcm, old_core); - assert(err == 0); - -out: return limit; } + /* init power control * as described in http://bcm-specs.sipsolutions.net/PowerControl */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.h b/drivers/net/wireless/bcm43xx/bcm43xx_power.h index 5f63640..c966ab3 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_power.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_power.h @@ -33,6 +33,15 @@ #include +/* Clock sources */ +enum { + /* PCI clock */ + BCM43xx_PCTL_CLKSRC_PCI, + /* Crystal slow clock oscillator */ + BCM43xx_PCTL_CLKSRC_XTALOS, + /* Low power oscillator */ + BCM43xx_PCTL_CLKSRC_LOPWROS, +}; struct bcm43xx_private; -- cgit v1.1 From b35d649cb2110b4e782a8a7e9b625432c863cade Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 13 Apr 2006 02:32:58 +0200 Subject: [PATCH] bcm43xx: sysfs code cleanup This cleans up the bcm43xx sysfs code and makes it compliant with the unwritten sysfs rules (at least I hope so). Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 17 +++- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 1 + drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | 115 ++++++++++++++++----------- drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h | 16 ---- 4 files changed, 82 insertions(+), 67 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index dcadd29..2e83083 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -15,7 +15,6 @@ #include "bcm43xx_debugfs.h" #include "bcm43xx_leds.h" -#include "bcm43xx_sysfs.h" #define PFX KBUILD_MODNAME ": " @@ -638,8 +637,6 @@ struct bcm43xx_key { }; struct bcm43xx_private { - struct bcm43xx_sysfs sysfs; - struct ieee80211_device *ieee; struct ieee80211softmac_device *softmac; @@ -772,6 +769,20 @@ struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) return ieee80211softmac_priv(dev); } +struct device; + +static inline +struct bcm43xx_private * dev_to_bcm(struct device *dev) +{ + struct net_device *net_dev; + struct bcm43xx_private *bcm; + + net_dev = dev_get_drvdata(dev); + bcm = bcm43xx_priv(net_dev); + + return bcm; +} + /* Helper function, which returns a boolean. * TRUE, if PIO is used; FALSE, if DMA is used. diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 23ad772..9a06e61 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -52,6 +52,7 @@ #include "bcm43xx_wx.h" #include "bcm43xx_ethtool.h" #include "bcm43xx_xmit.h" +#include "bcm43xx_sysfs.h" MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver"); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c index c44d890..b438f48 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c @@ -71,14 +71,46 @@ static int get_boolean(const char *buf, size_t count) return -EINVAL; } +static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len) +{ + int i, pos = 0; + + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { + pos += snprintf(buf + pos, buf_len - pos - 1, + "%04X", swab16(sprom[i]) & 0xFFFF); + } + pos += snprintf(buf + pos, buf_len - pos - 1, "\n"); + + return pos + 1; +} + +static int hex2sprom(u16 *sprom, const char *dump, size_t len) +{ + char tmp[5] = { 0 }; + int cnt = 0; + unsigned long parsed; + + if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2) + return -EINVAL; + + while (cnt < BCM43xx_SPROM_SIZE) { + memcpy(tmp, dump, 4); + dump += 4; + parsed = simple_strtoul(tmp, NULL, 16); + sprom[cnt++] = swab16((u16)parsed); + } + + return 0; +} + static ssize_t bcm43xx_attr_sprom_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom); + struct bcm43xx_private *bcm = dev_to_bcm(dev); u16 *sprom; unsigned long flags; - int i, err; + int err; if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -91,55 +123,53 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev, bcm43xx_lock_mmio(bcm, flags); assert(bcm->initialized); err = bcm43xx_sprom_read(bcm, sprom); - if (!err) { - for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { - buf[i * 2] = sprom[i] & 0x00FF; - buf[i * 2 + 1] = (sprom[i] & 0xFF00) >> 8; - } - } + if (!err) + err = sprom2hex(sprom, buf, PAGE_SIZE); bcm43xx_unlock_mmio(bcm, flags); kfree(sprom); - return err ? err : BCM43xx_SPROM_SIZE * sizeof(u16); + return err; } static ssize_t bcm43xx_attr_sprom_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom); + struct bcm43xx_private *bcm = dev_to_bcm(dev); u16 *sprom; unsigned long flags; - int i, err; + int err; if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (count != BCM43xx_SPROM_SIZE * sizeof(u16)) - return -EINVAL; sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), GFP_KERNEL); if (!sprom) return -ENOMEM; - for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { - sprom[i] = buf[i * 2] & 0xFF; - sprom[i] |= ((u16)(buf[i * 2 + 1] & 0xFF)) << 8; - } + err = hex2sprom(sprom, buf, count); + if (err) + goto out_kfree; bcm43xx_lock_mmio(bcm, flags); assert(bcm->initialized); err = bcm43xx_sprom_write(bcm, sprom); bcm43xx_unlock_mmio(bcm, flags); +out_kfree: kfree(sprom); return err ? err : count; } +static DEVICE_ATTR(sprom, 0600, + bcm43xx_attr_sprom_show, + bcm43xx_attr_sprom_store); + static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode); + struct bcm43xx_private *bcm = dev_to_bcm(dev); unsigned long flags; int err; ssize_t count = 0; @@ -175,7 +205,7 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode); + struct bcm43xx_private *bcm = dev_to_bcm(dev); unsigned long flags; int err; int mode; @@ -215,11 +245,15 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, return err ? err : count; } +static DEVICE_ATTR(interference, 0644, + bcm43xx_attr_interfmode_show, + bcm43xx_attr_interfmode_store); + static ssize_t bcm43xx_attr_preamble_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble); + struct bcm43xx_private *bcm = dev_to_bcm(dev); unsigned long flags; int err; ssize_t count; @@ -245,7 +279,7 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble); + struct bcm43xx_private *bcm = dev_to_bcm(dev); unsigned long flags; int err; int value; @@ -267,56 +301,41 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev, return err ? err : count; } +static DEVICE_ATTR(shortpreamble, 0644, + bcm43xx_attr_preamble_show, + bcm43xx_attr_preamble_store); + int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) { struct device *dev = &bcm->pci_dev->dev; - struct bcm43xx_sysfs *sysfs = &bcm->sysfs; int err; assert(bcm->initialized); - sysfs->attr_sprom.attr.name = "sprom"; - sysfs->attr_sprom.attr.owner = THIS_MODULE; - sysfs->attr_sprom.attr.mode = 0600; - sysfs->attr_sprom.show = bcm43xx_attr_sprom_show; - sysfs->attr_sprom.store = bcm43xx_attr_sprom_store; - err = device_create_file(dev, &sysfs->attr_sprom); + err = device_create_file(dev, &dev_attr_sprom); if (err) goto out; - - sysfs->attr_interfmode.attr.name = "interference"; - sysfs->attr_interfmode.attr.owner = THIS_MODULE; - sysfs->attr_interfmode.attr.mode = 0600; - sysfs->attr_interfmode.show = bcm43xx_attr_interfmode_show; - sysfs->attr_interfmode.store = bcm43xx_attr_interfmode_store; - err = device_create_file(dev, &sysfs->attr_interfmode); + err = device_create_file(dev, &dev_attr_interference); if (err) goto err_remove_sprom; - - sysfs->attr_preamble.attr.name = "shortpreamble"; - sysfs->attr_preamble.attr.owner = THIS_MODULE; - sysfs->attr_preamble.attr.mode = 0600; - sysfs->attr_preamble.show = bcm43xx_attr_preamble_show; - sysfs->attr_preamble.store = bcm43xx_attr_preamble_store; - err = device_create_file(dev, &sysfs->attr_preamble); + err = device_create_file(dev, &dev_attr_shortpreamble); if (err) goto err_remove_interfmode; out: return err; err_remove_interfmode: - device_remove_file(dev, &sysfs->attr_interfmode); + device_remove_file(dev, &dev_attr_interference); err_remove_sprom: - device_remove_file(dev, &sysfs->attr_sprom); + device_remove_file(dev, &dev_attr_sprom); goto out; } void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm) { struct device *dev = &bcm->pci_dev->dev; - struct bcm43xx_sysfs *sysfs = &bcm->sysfs; - device_remove_file(dev, &sysfs->attr_preamble); - device_remove_file(dev, &sysfs->attr_interfmode); - device_remove_file(dev, &sysfs->attr_sprom); + device_remove_file(dev, &dev_attr_shortpreamble); + device_remove_file(dev, &dev_attr_interference); + device_remove_file(dev, &dev_attr_sprom); } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h index 57f1451..cc701df 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h @@ -1,22 +1,6 @@ #ifndef BCM43xx_SYSFS_H_ #define BCM43xx_SYSFS_H_ -#include - - -struct bcm43xx_sysfs { - struct device_attribute attr_sprom; - struct device_attribute attr_interfmode; - struct device_attribute attr_preamble; -}; - -#define devattr_to_bcm(attr, attr_name) ({ \ - struct bcm43xx_sysfs *__s; struct bcm43xx_private *__p; \ - __s = container_of((attr), struct bcm43xx_sysfs, attr_name); \ - __p = container_of(__s, struct bcm43xx_private, sysfs); \ - __p; \ - }) - struct bcm43xx_private; int bcm43xx_sysfs_register(struct bcm43xx_private *bcm); -- cgit v1.1 From a392149ee14d1631d8632060c1fc3082729f83c8 Mon Sep 17 00:00:00 2001 From: Erik Mouw Date: Thu, 13 Apr 2006 15:02:27 +0200 Subject: [PATCH] bcm43xx: iw_priv_args names should be <16 characters The room for the names in bcm43xx_priv_wx_args[] are IFNAMSIZ long and IFNAMSIZ is defined as 16, so the names in bcm43xx_priv_wx_args should be 15 characters (16 including the trailing \0). This patch fixes that for the "set_shortpreambl", "get_shortpreambl", "set_swencryption", and "get_swencryption" private calls. Patch is against 2.6.17-rc1. Signed-off-by: Erik Mouw Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index 3daee82..3edbb48 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -962,22 +962,22 @@ static const struct iw_priv_args bcm43xx_priv_wx_args[] = { { .cmd = PRIV_WX_SET_SHORTPREAMBLE, .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - .name = "set_shortpreambl", + .name = "set_shortpreamb", }, { .cmd = PRIV_WX_GET_SHORTPREAMBLE, .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, - .name = "get_shortpreambl", + .name = "get_shortpreamb", }, { .cmd = PRIV_WX_SET_SWENCRYPTION, .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - .name = "set_swencryption", + .name = "set_swencrypt", }, { .cmd = PRIV_WX_GET_SWENCRYPTION, .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, - .name = "get_swencryption", + .name = "get_swencrypt", }, { .cmd = PRIV_WX_SPROM_WRITE, -- cgit v1.1 From d47f3640fe2ac4da8a8e713a549e6eaf23ac2084 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Apr 2006 15:42:28 -0700 Subject: [SUNGEM]: Marvell PHY suspend. In a short discussion with Benjamin Herrenschmidt he mentioned that Marvell PHYs are powered down the same way as the other ones we currently handle. Thus actually do that, hopefully saving some power during suspend. Signed-off-by: Johannes Berg Acked-by: Benjamin Herrenschmidt Signed-off-by: David S. Miller --- drivers/net/sungem_phy.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c index cb0aba9..046371e 100644 --- a/drivers/net/sungem_phy.c +++ b/drivers/net/sungem_phy.c @@ -275,7 +275,7 @@ static int bcm5411_init(struct mii_phy* phy) return 0; } -static int bcm5411_suspend(struct mii_phy* phy) +static int generic_suspend(struct mii_phy* phy) { phy_write(phy, MII_BMCR, BMCR_PDOWN); @@ -738,7 +738,7 @@ static struct mii_phy_def bcm5401_phy_def = { /* Broadcom BCM 5411 */ static struct mii_phy_ops bcm5411_phy_ops = { .init = bcm5411_init, - .suspend = bcm5411_suspend, + .suspend = generic_suspend, .setup_aneg = bcm54xx_setup_aneg, .setup_forced = bcm54xx_setup_forced, .poll_link = genmii_poll_link, @@ -757,7 +757,7 @@ static struct mii_phy_def bcm5411_phy_def = { /* Broadcom BCM 5421 */ static struct mii_phy_ops bcm5421_phy_ops = { .init = bcm5421_init, - .suspend = bcm5411_suspend, + .suspend = generic_suspend, .setup_aneg = bcm54xx_setup_aneg, .setup_forced = bcm54xx_setup_forced, .poll_link = genmii_poll_link, @@ -776,7 +776,7 @@ static struct mii_phy_def bcm5421_phy_def = { /* Broadcom BCM 5421 built-in K2 */ static struct mii_phy_ops bcm5421k2_phy_ops = { .init = bcm5421_init, - .suspend = bcm5411_suspend, + .suspend = generic_suspend, .setup_aneg = bcm54xx_setup_aneg, .setup_forced = bcm54xx_setup_forced, .poll_link = genmii_poll_link, @@ -795,7 +795,7 @@ static struct mii_phy_def bcm5421k2_phy_def = { /* Broadcom BCM 5462 built-in Vesta */ static struct mii_phy_ops bcm5462V_phy_ops = { .init = bcm5421_init, - .suspend = bcm5411_suspend, + .suspend = generic_suspend, .setup_aneg = bcm54xx_setup_aneg, .setup_forced = bcm54xx_setup_forced, .poll_link = genmii_poll_link, @@ -816,6 +816,7 @@ static struct mii_phy_def bcm5462V_phy_def = { * would be useful here) --BenH. */ static struct mii_phy_ops marvell_phy_ops = { + .suspend = generic_suspend, .setup_aneg = marvell_setup_aneg, .setup_forced = marvell_setup_forced, .poll_link = genmii_poll_link, -- cgit v1.1 From 17c281ab3e33be63693687d3db7ac9cf2bbdfd66 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 16 Apr 2006 19:42:35 +0400 Subject: [PATCH] NEx000: fix RTL8019AS base address for RBTX4938 Correct the base address of the Realtek RTL8019AS chip on the Toshiba RBTX4938 board -- this should make the driver work at least when CONFIG_PCI is enabled. Signed-off-by: Yuri Shpilevsky Signed-off-by: Sergei Shtylyov Signed-off-by: Jeff Garzik --- drivers/net/ne.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 08b218c..93c494b 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -226,7 +226,7 @@ struct net_device * __init ne_probe(int unit) netdev_boot_setup_check(dev); #ifdef CONFIG_TOSHIBA_RBTX4938 - dev->base_addr = 0x07f20280; + dev->base_addr = RBTX4938_RTL_8019_BASE; dev->irq = RBTX4938_RTL_8019_IRQ; #endif err = do_ne_probe(dev); -- cgit v1.1