diff options
Diffstat (limited to 'drivers/net')
33 files changed, 3140 insertions, 432 deletions
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 2694dbb6c..a9ddfa475 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -65,7 +65,6 @@ static int max_interrupt_work = 20; #include <linux/malloc.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/bios32.h> #include <linux/timer.h> #include <asm/irq.h> /* For NR_IRQS only. */ #include <asm/bitops.h> @@ -113,6 +112,7 @@ static int max_interrupt_work = 20; #if LINUX_VERSION_CODE < 0x20115 #define test_and_set_bit(val, addr) set_bit(val, addr) +#include <linux/bios32.h> #elif defined(MODULE) MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>"); MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver"); @@ -532,12 +532,18 @@ static int vortex_scan(struct device *dev) be best done a central PCI probe dispatch, which wouldn't work well with the current structure. So instead we detect 3Com cards in slot order. */ - if (pcibios_present()) { + if (pci_present()) { static int pci_index = 0; unsigned char pci_bus, pci_device_fn; for (;pci_index < 0xff; pci_index++) { - unsigned char pci_irq_line, pci_latency; +#if LINUX_VERSION_CODE >= 0x20155 + unsigned int pci_irq_line; + struct pci_dev *pdev; +#else + unsigned char pci_irq_line; +#endif + unsigned char pci_latency; unsigned short pci_command, new_command, vendor, device; unsigned int pci_ioaddr; int board_index = 0; @@ -550,10 +556,16 @@ static int vortex_scan(struct device *dev) PCI_VENDOR_ID, &vendor); pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, &device); +#if LINUX_VERSION_CODE >= 0x20155 + pdev = pci_find_slot(pci_bus, pci_device_fn); + pci_irq_line = pdev->irq; + pci_ioaddr = pdev->base_address[0]; +#else pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pci_irq_line); pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0, &pci_ioaddr); +#endif pcibios_read_config_word(pci_bus, pci_device_fn, PCI_COMMAND, &pci_command); /* Remove I/O space marker in bit 0. */ diff --git a/drivers/net/Config.in b/drivers/net/Config.in index c3bcd09c5..dfe3ed200 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -42,7 +42,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then fi fi tristate '3c509/3c579 support' CONFIG_EL3 - tristate '3c590 series (592/595/597) "Vortex" support' CONFIG_VORTEX + tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX fi bool 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC @@ -103,8 +103,9 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'TI ThunderLAN support (EXPERIMENTAL)' CONFIG_TLAN tristate 'Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 + tristate 'SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100 + tristate 'TI ThunderLAN support (EXPERIMENTAL)' CONFIG_TLAN bool 'Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET fi fi diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 47738877f..3bd7f7280 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -581,6 +581,14 @@ else endif endif +ifeq ($(CONFIG_EPIC100),y) +L_OBJS += epic100.o +else + ifeq ($(CONFIG_EPIC100),m) + M_OBJS += epic100.o + endif +endif + # If anything built-in uses slhc, then build it into the kernel also. # If not, but a module uses it, build as a module. ifdef CONFIG_SLHC_BUILTIN diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 9d880aa4d..b01c6a8a8 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -94,6 +94,7 @@ extern int tlan_probe(struct device *); extern int mace_probe(struct device *); extern int cs89x0_probe(struct device *dev); extern int ethertap_probe(struct device *dev); +extern int epic100_probe(struct device *dev); /* Detachable devices ("pocket adaptors") */ extern int atp_init(struct device *); @@ -287,6 +288,9 @@ __initfunc(static int ethif_probe(struct device *dev)) #ifdef CONFIG_ARM_AM79C961A && am79c961_probe(dev) #endif +#ifdef CONFIG_EPIC100 + && epic100_probe(dev) +#endif && 1 ) { return 1; /* -ENODEV or -EAGAIN would be more accurate. */ } diff --git a/drivers/net/arcnet.c b/drivers/net/arcnet.c index 8a731a6e3..16795257e 100644 --- a/drivers/net/arcnet.c +++ b/drivers/net/arcnet.c @@ -18,6 +18,10 @@ ********************** + v3.01 (98/04/17) + - Interrupt handler now also checks dev->[se]dev are non-NULL + to avoid crashes in interrupts during card init. [dw] + v3.00 (97/11/09) - Minor cleanup of debugging messages. [mj] @@ -41,10 +45,10 @@ v2.80 ALPHA (97/08/01) - Split source into multiple files; generic arcnet support and - individual chipset drivers. <dwmw2@cam.ac.uk> + individual chipset drivers. <Dave@imladris.demon.co.uk> - v2.61 ALPHA (97/07/30) by David Woodhouse (dwmw2@cam.ac.uk) for - Nortel (Northern Telecom). + v2.61 ALPHA (97/07/30) by David Woodhouse (Dave@imladris.demon.co.uk) + for Nortel (Northern Telecom). - Added support for IO-mapped modes and for SMC COM20020 chipset. - Fixed (avoided) race condition in send_packet routines which was discovered when the buffer copy routines got slow (?). @@ -170,7 +174,7 @@ */ static const char *version = - "arcnet.c: v3.00 97/11/09 Avery Pennarun <apenwarr@bond.net> et al.\n"; + "arcnet.c: v3.01 98/04/24 Avery Pennarun <apenwarr@bond.net> et al.\n"; #include <linux/module.h> #include <linux/config.h> @@ -956,20 +960,24 @@ arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs) return; /* don't even try. */ } #ifdef CONFIG_ARCNET_1051 - lp->sdev->interrupt=1; + if (lp->sdev) + lp->sdev->interrupt=1; #endif #ifdef CONFIG_ARCNET_ETH - lp->edev->interrupt=1; + if (lp->edev) + lp->edev->interrupt=1; #endif /* Call the "real" interrupt handler. */ (*lp->inthandler)(dev); #ifdef CONFIG_ARCNET_ETH - lp->edev->interrupt=0; + if (lp->edev) + lp->edev->interrupt=0; #endif #ifdef CONFIG_ARCNET_1051 - lp->sdev->interrupt=0; + if (lp->sdev) + lp->sdev->interrupt=0; #endif if (!test_and_clear_bit(0, (int *)&dev->interrupt)) BUGMSG(D_NORMAL, "Someone cleared our dev->interrupt flag!\n"); diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c index 6bd5be8b7..c0c52d24f 100644 --- a/drivers/net/de4x5.c +++ b/drivers/net/de4x5.c @@ -213,7 +213,7 @@ insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'. - For a compiled in driver, at or above line 526, place e.g. + For a compiled in driver, somewhere in this file, place e.g. #define DE4X5_PARM "eth0:fdx autosense=AUI eth2:autosense=TP" Yes, I know full duplex isn't permissible on BNC or AUI; they're just @@ -380,6 +380,7 @@ static const char *version = "de4x5.c:V0.536 1998/3/5 davies@maniac.ultranet.com\n"; +#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> @@ -390,7 +391,6 @@ static const char *version = "de4x5.c:V0.536 1998/3/5 davies@maniac.ultranet.com #include <linux/errno.h> #include <linux/ioport.h> #include <linux/malloc.h> -#include <linux/bios32.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/init.h> @@ -929,7 +929,7 @@ static void SetMulticastFilter(struct device *dev); static int get_hw_addr(struct device *dev); static void srom_repair(struct device *dev, int card); static int test_bad_enet(struct device *dev, int status); -#ifndef __sparc_v9__ +#if !defined(__sparc_v9__) && !defined(__powerpc__) static void eisa_probe(struct device *dev, u_long iobase); #endif static void pci_probe(struct device *dev, u_long iobase); @@ -978,12 +978,15 @@ static int loading_module = 0; #endif /* MODULE */ static char name[DE4X5_NAME_LENGTH + 1]; -#ifndef __sparc_v9__ +#if !defined(__sparc_v9__) && !defined(__powerpc__) static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST; #endif static int num_de4x5s = 0; static int cfrv = 0, useSROM = 0; -static int lastEISA = 0, lastPCI = -1; +#if !defined(__sparc_v9__) && !defined(__powerpc__) +static int lastEISA = 0; +#endif +static int lastPCI = -1; static struct device *lastModule = NULL; /* @@ -1048,7 +1051,7 @@ de4x5_probe(struct device *dev)) { u_long iobase = dev->base_addr; -#ifndef __sparc_v9__ +#if !defined(__sparc_v9__) && !defined(__powerpc__) eisa_probe(dev, iobase); #endif pci_probe(dev, iobase); @@ -1305,9 +1308,8 @@ de4x5_open(struct device *dev) lp->state = OPEN; de4x5_dbg_open(dev); - if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ, - lp->adapter_name, dev)) { + lp->adapter_name, dev)) { printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq); if (request_irq(dev->irq, de4x5_interrupt, SA_INTERRUPT | SA_SHIRQ, lp->adapter_name, dev)) { @@ -1974,7 +1976,7 @@ SetMulticastFilter(struct device *dev) return; } -#ifndef __sparc_v9__ +#if !defined(__sparc_v9__) && !defined(__powerpc__) /* ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually ** the motherboard. Upto 15 EISA devices are supported. @@ -2063,15 +2065,14 @@ __initfunc(static void pci_probe(struct device *dev, u_long ioaddr)) { u_char pb, pbus, dev_num, dnum, dev_fn, timer; - u_short vendor, index, status; + u_short dev_id, vendor, index, status; u_int irq = 0, device, class = DE4X5_CLASS_CODE; u_long iobase = 0; /* Clear upper 32 bits in Alphas */ struct bus_type *lp = &bus; - struct pci_dev *pdev; if (lastPCI == NO_MORE_PCI) return; - if (!pcibios_present()) { + if (!pci_present()) { lastPCI = NO_MORE_PCI; return; /* No PCI bus in this machine! */ } @@ -2091,77 +2092,92 @@ pci_probe(struct device *dev, u_long ioaddr)) (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND); index++) { dev_num = PCI_SLOT(dev_fn); - if ((pbus || dnum) && ((pbus != pb) || (dnum != dev_num))) continue; - for (pdev = pci_devices; pdev; pdev = pdev->next) { - if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break; - } - - vendor = pdev->vendor; - device = pdev->device << 8; - if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue; + if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) { +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,85) + struct pci_dev *pdev = pci_find_slot(pb, dev_fn); +#else + u_char tirq; + u_int tmp; +#endif + device = 0; + pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor); + pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id); + device = dev_id; + device <<= 8; + if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) { + continue; + } - /* Search for an SROM on this bus */ - if (lp->bus_num != pb) { - lp->bus_num = pb; - srom_search(index); - } + /* Search for an SROM on this bus */ + if (lp->bus_num != pb) { + lp->bus_num = pb; + srom_search(index); + } - /* Get the chip configuration revision register */ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); + /* Get the chip configuration revision register */ + pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); - /* Set the device number information */ - lp->device = dev_num; - lp->bus_num = pb; + /* Set the device number information */ + lp->device = dev_num; + lp->bus_num = pb; - /* Set the chipset information */ - if (is_DC2114x) device |= (cfrv & CFRV_RN); - lp->chipset = device; + /* Set the chipset information */ + if (is_DC2114x) device |= (cfrv & CFRV_RN); + lp->chipset = device; - /* Get the board I/O address (64 bits on sparc64) */ - iobase = pdev->base_address[0] & CBIO_MASK; + /* Get the board I/O address and IRQ */ +#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,85) + pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp); + iobase = tmp; + pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &tirq); + irq = tirq; +#else + iobase = pdev->base_address[0]; + irq = pdev->irq; +#endif + iobase &= CBIO_MASK; - /* Fetch the IRQ to be used */ - irq = pdev->irq; - if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue; - - /* Check if I/O accesses and Bus Mastering are enabled */ - pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); -#ifdef __powerpc__ - if (!(status & PCI_COMMAND_IO)) { - status |= PCI_COMMAND_IO; - pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); + if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue; + + /* Check if I/O accesses and Bus Mastering are enabled */ pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); - } +#ifdef __powerpc__ + if (!(status & PCI_COMMAND_IO)) { + status |= PCI_COMMAND_IO; + pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); + pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); + } #endif /* __powerpc__ */ - if (!(status & PCI_COMMAND_IO)) continue; + if (!(status & PCI_COMMAND_IO)) continue; - if (!(status & PCI_COMMAND_MASTER)) { - status |= PCI_COMMAND_MASTER; - pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); - } - if (!(status & PCI_COMMAND_MASTER)) continue; + if (!(status & PCI_COMMAND_MASTER)) { + status |= PCI_COMMAND_MASTER; + pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); + pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); + } + if (!(status & PCI_COMMAND_MASTER)) continue; - /* Check the latency timer for values >= 0x60 */ - pcibios_read_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, &timer); - if (timer < 0x60) { - pcibios_write_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, 0x60); - } + /* Check the latency timer for values >= 0x60 */ + pcibios_read_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, &timer); + if (timer < 0x60) { + pcibios_write_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, 0x60); + } - DevicePresent(DE4X5_APROM); - if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) { - dev->irq = irq; - if ((status = de4x5_hw_init(dev, iobase)) == 0) { - num_de4x5s++; - if (loading_module) { - link_modules(lastModule, dev); - lastPCI = index; + DevicePresent(DE4X5_APROM); + if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) { + dev->irq = irq; + if ((status = de4x5_hw_init(dev, iobase)) == 0) { + num_de4x5s++; + if (loading_module) { + link_modules(lastModule, dev); + lastPCI = index; + } + return; } - return; + } else if (ioaddr != 0) { + printk("%s: region already allocated at 0x%04lx.\n", dev->name, + iobase); } - } else if (ioaddr != 0) { - printk("%s: region already allocated at 0x%04lx.\n", dev->name, - iobase); } } @@ -2180,26 +2196,35 @@ __initfunc(static void srom_search(int index)) { u_char pb, dev_fn; - u_short dev_num, vendor, status; + u_short dev_id, dev_num, vendor, status; u_int irq = 0, device, class = DE4X5_CLASS_CODE; u_long iobase = 0; /* Clear upper 32 bits in Alphas */ int i, j; struct bus_type *lp = &bus; - struct pci_dev *pdev; +#ifndef __sparc_v9__ + u_char tirq; + u_int tmp; +#endif for (; (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND); index++) { - - if (lp->bus_num != pb) return; - dev_num = PCI_SLOT(dev_fn); +#ifdef __sparc_v9__ + struct pci_dev *pdev; for (pdev = pci_devices; pdev; pdev = pdev->next) { if ((pdev->bus->number == pb) && (pdev->devfn == dev_fn)) break; } - - vendor = pdev->vendor; - device = pdev->device << 8; - if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue; +#endif + if (lp->bus_num != pb) return; + dev_num = PCI_SLOT(dev_fn); + device = 0; + pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor); + pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id); + device = dev_id; + device <<= 8; + if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) { + continue; + } /* Get the chip configuration revision register */ pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); @@ -2213,10 +2238,21 @@ srom_search(int index)) lp->chipset = device; /* Get the board I/O address (64 bits on sparc64) */ - iobase = pdev->base_address[0] & CBIO_MASK; +#ifndef __sparc_v9__ + pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp); + iobase = tmp; +#else + iobase = pdev->base_address[0]; +#endif + iobase &= CBIO_MASK; /* Fetch the IRQ to be used */ +#ifndef __sparc_v9__ + pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &tirq); + irq = tirq; +#else irq = pdev->irq; +#endif if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue; /* Check if I/O accesses are enabled */ @@ -4057,6 +4093,19 @@ get_hw_addr(struct device *dev) /* If possible, try to fix a broken card - SMC only so far */ srom_repair(dev, broken); +#ifdef CONFIG_PMAC + /* If the address starts with 00 a0, we have to bit-reverse + each byte of the address. */ + if (dev->dev_addr[0] == 0 && dev->dev_addr[1] == 0xa0) { + for (i = 0; i < ETH_ALEN; ++i) { + int x = dev->dev_addr[i]; + x = ((x & 0xf) << 4) + ((x & 0xf0) >> 4); + x = ((x & 0x33) << 2) + ((x & 0xcc) >> 2); + dev->dev_addr[i] = ((x & 0x55) << 1) + ((x & 0xaa) >> 1); + } + } +#endif /* CONFIG_PMAC */ + /* Test for a bad enet address */ status = test_bad_enet(dev, status); @@ -5717,32 +5766,30 @@ unlink_modules(struct device *p) static int count_adapters(void) { - int i, j=0; + int i, j; char name[DE4X5_STRLEN]; - u_char pb, dev_fn; - u_short vendor; + u_char pb, dev_fn, dev_num; + u_short dev_id, vendor; u_int class = DE4X5_CLASS_CODE; u_int device; - struct pci_dev *pdev; - -#ifndef __sparc_v9__ +#if !defined(__sparc_v9__) && !defined(__powerpc__) u_long iobase = 0x1000; - for (i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) { + for (j=0, i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) { if (EISA_signature(name, EISA_ID)) j++; } #endif - if (!pcibios_present()) return j; + if (!pci_present()) return j; for (i=0; (pcibios_find_class(class, i, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND); i++) { - for (pdev = pci_devices; pdev; pdev = pdev->next) { - if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break; - } - - vendor = pdev->vendor; - device = pdev->device << 8; + dev_num = PCI_SLOT(dev_fn); + device = 0; + pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor); + pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id); + device = dev_id; + device <<= 8; if (is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x) j++; } diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index 8c2cbd278..2faccc6fd 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -213,7 +213,6 @@ static const char *version = "defxx.c:v1.04 09/16/96 Lawrence V. Stefani (stefa #include <linux/malloc.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/bios32.h> #include <linux/delay.h> #include <linux/init.h> #include <asm/byteorder.h> @@ -455,9 +454,8 @@ __initfunc(int dfx_probe( int i; /* used in for loops */ int version_disp; /* was version info string already displayed? */ int port_len; /* length of port address range (in bytes) */ - u8 pci_bus; /* PCI bus number (0-255) */ - u8 pci_dev_fun; /* PCI device and function numbers (0-255) */ u16 port; /* temporary I/O (port) address */ + struct pci_dev * pdev = NULL; /* PCI device record */ u16 command; /* PCI Configuration space Command register val */ u32 slot_id; /* EISA hardware (slot) ID read from adapter */ DFX_board_t *bp; /* board pointer */ @@ -530,61 +528,58 @@ __initfunc(int dfx_probe( /* Scan for FDDI PCI controllers */ - if (pcibios_present()) /* is PCI BIOS even present? */ - for (i=0; i < DFX_MAX_NUM_BOARDS; i++) /* scan for up to 8 PCI cards */ - if (pcibios_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, i, &pci_bus, &pci_dev_fun) == 0) + if (pci_present()) /* is PCI even present? */ + while ((pdev = pci_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, pdev))) + { + if (!version_disp) /* display version info if adapter is found */ { - if (!version_disp) /* display version info if adapter is found */ - { - version_disp = 1; /* set display flag to TRUE so that */ - printk(version); /* we only display this string ONCE */ - } + version_disp = 1; /* set display flag to TRUE so that */ + printk(version); /* we only display this string ONCE */ + } - /* Verify that I/O enable bit is set (PCI slot is enabled) */ + /* Verify that I/O enable bit is set (PCI slot is enabled) */ - pcibios_read_config_word(pci_bus, pci_dev_fun, PCI_COMMAND, &command); - if ((command & PCI_COMMAND_IO) == 0) - printk("I/O enable bit not set! Verify that slot is enabled\n"); - else - { - /* Turn off memory mapped space and enable mastering */ + pci_read_config_word(pdev, PCI_COMMAND, &command); + if ((command & PCI_COMMAND_IO) == 0) + printk("I/O enable bit not set! Verify that slot is enabled\n"); + else + { + /* Turn off memory mapped space and enable mastering */ - command |= PCI_COMMAND_MASTER; - command &= ~PCI_COMMAND_MEMORY; - pcibios_write_config_word(pci_bus, pci_dev_fun, PCI_COMMAND, command); + command |= PCI_COMMAND_MASTER; + command &= ~PCI_COMMAND_MEMORY; + pci_write_config_word(pdev, PCI_COMMAND, command); - /* Read I/O base address from PCI Configuration Space */ - - pcibios_read_config_word(pci_bus, pci_dev_fun, PCI_BASE_ADDRESS_1, &port); - port &= PCI_BASE_ADDRESS_IO_MASK; /* clear I/O bit (bit 0) */ + /* Get I/O base address from PCI Configuration Space */ + + port = pdev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; - /* Verify port address range is not already being used */ + /* Verify port address range is not already being used */ + + port_len = PFI_K_CSR_IO_LEN; + if (check_region(port, port_len) == 0) + { + /* Allocate a new device structure for this adapter */ - port_len = PFI_K_CSR_IO_LEN; - if (check_region(port, port_len) == 0) + dev = dfx_alloc_device(dev, port); + if (dev != NULL) { - /* Allocate a new device structure for this adapter */ - - dev = dfx_alloc_device(dev, port); - if (dev != NULL) - { - /* Initialize board structure with bus-specific info */ - - bp = (DFX_board_t *) dev->priv; - bp->dev = dev; - bp->bus_type = DFX_BUS_TYPE_PCI; - bp->pci_bus = pci_bus; - bp->pci_dev_fun = pci_dev_fun; - if (dfx_driver_init(dev) == DFX_K_SUCCESS) - num_boards++; /* only increment global board count on success */ - else - dev->base_addr = 0; /* clear port address field in device structure on failure */ - } + /* Initialize board structure with bus-specific info */ + + bp = (DFX_board_t *) dev->priv; + bp->dev = dev; + bp->bus_type = DFX_BUS_TYPE_PCI; + bp->pci_dev = pdev; + if (dfx_driver_init(dev) == DFX_K_SUCCESS) + num_boards++; /* only increment global board count on success */ + else + dev->base_addr = 0; /* clear port address field in device structure on failure */ } - else - printk("I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1)); } + else + printk("I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1)); } + } /* * If we're at this point we're going through dfx_probe() for the first @@ -823,18 +818,19 @@ __initfunc(void dfx_bus_init( } else { + struct pci_dev *pdev = bp->pci_dev; + /* Get the interrupt level from the PCI Configuration Table */ - pcibios_read_config_byte(bp->pci_bus, bp->pci_dev_fun, PCI_INTERRUPT_LINE, &val); - dev->irq = val; /* save IRQ value in device table */ + dev->irq = pdev->irq; /* Check Latency Timer and set if less than minimal */ - pcibios_read_config_byte(bp->pci_bus, bp->pci_dev_fun, PCI_LATENCY_TIMER, &val); + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &val); if (val < PFI_K_LAT_TIMER_MIN) /* if less than min, override with default */ { val = PFI_K_LAT_TIMER_DEF; - pcibios_write_config_byte(bp->pci_bus, bp->pci_dev_fun, PCI_LATENCY_TIMER, val); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, val); } /* Enable interrupts at PCI bus interface chip (PFI) */ diff --git a/drivers/net/defxx.h b/drivers/net/defxx.h index 83d66456b..5707ad877 100644 --- a/drivers/net/defxx.h +++ b/drivers/net/defxx.h @@ -1754,8 +1754,7 @@ typedef struct DFX_board_tag struct device *dev; /* pointer to device structure */ u32 bus_type; /* bus type (0 == PCI, 1 == EISA) */ u16 base_addr; /* base I/O address (same as dev->base_addr) */ - u8 pci_bus; /* PCI bus number */ - u8 pci_dev_fun; /* PCI device and function numbers */ + struct pci_dev * pci_dev; u32 full_duplex_enb; /* FDDI Full Duplex enable (1 == on, 2 == off) */ u32 req_ttrt; /* requested TTRT value (in 80ns units) */ u32 burst_size; /* adapter burst size (enumerated) */ diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index e562446e8..c379b3a43 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -87,7 +87,6 @@ static char *version = "$Id: dgrs.c,v 1.12 1996/12/21 13:43:58 rick Exp $"; #include <linux/malloc.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/bios32.h> #include <linux/init.h> #include <asm/bitops.h> #include <asm/io.h> @@ -109,6 +108,7 @@ static char *version = "$Id: dgrs.c,v 1.12 1996/12/21 13:43:58 rick Exp $"; #define COPY_FROM_USER(DST,SRC,LEN) copy_from_user(DST,SRC,LEN) #define COPY_TO_USER(DST,SRC,LEN) copy_to_user(DST,SRC,LEN) #else + #include <linux/bios32.h> #define IOREMAP(ADDR, LEN) vremap(ADDR, LEN) #define IOUNMAP(ADDR) vfree(ADDR) #define COPY_FROM_USER(DST,SRC,LEN) memcpy_fromfs(DST,SRC,LEN) @@ -1373,14 +1373,19 @@ dgrs_scan(struct device *dev)) /* * First, check for PCI boards */ - if (pcibios_present()) + if (pci_present()) { int pci_index = 0; for (; pci_index < 8; pci_index++) { uchar pci_bus, pci_device_fn; +#if LINUX_VERSION_CODE < 0x20100 uchar pci_irq; +#else + uint pci_irq; + struct pci_dev *pdev; +#endif uchar pci_latency; ushort pci_command; @@ -1390,6 +1395,7 @@ dgrs_scan(struct device *dev)) &pci_device_fn)) break; +#if LINUX_VERSION_CODE < 0x20100 pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pci_irq); pcibios_read_config_dword(pci_bus, pci_device_fn, @@ -1398,6 +1404,13 @@ dgrs_scan(struct device *dev)) PCI_BASE_ADDRESS_1, &io); pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &mem); +#else + pdev = pci_find_slot(pci_bus, pci_device_fn); + pci_irq = pdev->irq; + plxreg = pdev->base_address[0]; + io = pdev->base_address[1]; + mem = pdev->base_address[2]; +#endif pcibios_read_config_dword(pci_bus, pci_device_fn, 0x30, &plxdma); irq = pci_irq; diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 156a07ba2..c896844b2 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -59,7 +59,6 @@ static int max_interrupt_work = 200; #include <linux/malloc.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/bios32.h> #include <linux/delay.h> #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/bitops.h> @@ -120,6 +119,7 @@ struct device *init_etherdev(struct device *dev, int sizeof_priv, #if (LINUX_VERSION_CODE < 0x20123) #define test_and_set_bit(val, addr) set_bit(val, addr) +#include <linux/bios32.h> #endif /* The total I/O port extent of the board. Nominally 0x18, but rounded up @@ -473,10 +473,16 @@ int eepro100_init(struct device *dev) { int cards_found = 0; - if (pcibios_present()) { + if (pci_present()) { static int pci_index = 0; for (; pci_index < 8; pci_index++) { - unsigned char pci_bus, pci_device_fn, pci_irq_line, pci_latency; + unsigned char pci_bus, pci_device_fn, pci_latency; +#if (LINUX_VERSION_CODE >= VERSION(2,1,85)) + unsigned int pci_irq_line; + struct pci_dev *pdev; +#else + unsigned char pci_irq_line; +#endif #if (LINUX_VERSION_CODE >= VERSION(1,3,44)) int pci_ioaddr; #else @@ -489,11 +495,17 @@ int eepro100_init(struct device *dev) pci_index, &pci_bus, &pci_device_fn)) break; +#if (LINUX_VERSION_CODE >= VERSION(2,1,85)) + pdev = pci_find_slot(pci_bus, pci_device_fn); + pci_irq_line = pdev->irq; + pci_ioaddr = pdev->base_address[1]; +#else pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pci_irq_line); /* Note: BASE_ADDRESS_0 is for memory-mapping the registers. */ pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &pci_ioaddr); +#endif /* Remove I/O space marker in bit 0. */ pci_ioaddr &= ~3; if (speedo_debug > 2) diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c new file mode 100644 index 000000000..b6fc14f55 --- /dev/null +++ b/drivers/net/epic100.c @@ -0,0 +1,1215 @@ +/* epic100.c: A SMC 83c170 EPIC/100 fast ethernet driver for Linux. */ +/* + NOTICE: THIS IS THE ALPHA TEST VERSION! + Written 1997 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + All other rights reserved. + + This driver is for the SMC EtherPower II 9432 PCI ethernet adapter based on + the SMC83c170. + + The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O + Center of Excellence in Space Data and Information Sciences + Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + + Support and updates available at + http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html +*/ + +static const char *version = +"epic100.c:v0.10 10/14/97 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html\n"; + +/* A few user-configurable values. */ + +/* Keep the ring sizes a power of two for efficiency. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority. + There are no ill effects from too-large receive rings. */ +#define TX_RING_SIZE 16 +#define RX_RING_SIZE 32 + +/* Set the copy breakpoint for the copy-only-tiny-frames scheme. + Setting to > 1518 effectively disables this feature. */ +static const int rx_copybreak = 200; + +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 10; + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT ((2000*HZ)/1000) + +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ + +/* Bytes transferred to chip before transmission starts. */ +#define TX_FIFO_THRESH 128 /* Rounded down to 4 byte units. */ +#define RX_FIFO_THRESH 1 /* 0-3, 0==32, 64,96, or 3==128 bytes */ + +#include <linux/config.h> +#ifdef MODULE +#ifdef MODVERSIONS +#include <linux/modversions.h> +#endif +#include <linux/module.h> +#include <linux/version.h> +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/ptrace.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/malloc.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/bios32.h> +#include <asm/processor.h> /* Processor type for cache alignment. */ +#include <asm/bitops.h> +#include <asm/io.h> +#include <asm/dma.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> + +/* Kernel compatibility defines, common to David Hind's PCMCIA package. + This is only in the support-all-kernels source code. */ +#include <linux/version.h> /* Evil, but neccessary */ + +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10300 +#define RUN_AT(x) (x) /* What to put in timer->expires. */ +#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC) +#define virt_to_bus(addr) ((unsigned long)addr) +#define bus_to_virt(addr) ((void*)addr) + +#else /* 1.3.0 and later */ +#define RUN_AT(x) (jiffies + (x)) +#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2) +#endif + +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10338 +#ifdef MODULE +#if !defined(CONFIG_MODVERSIONS) && !defined(__NO_VERSION__) +char kernel_version[] = UTS_RELEASE; +#endif +#else +#undef MOD_INC_USE_COUNT +#define MOD_INC_USE_COUNT +#undef MOD_DEC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif +#endif /* 1.3.38 */ + +#if (LINUX_VERSION_CODE >= 0x10344) +#define NEW_MULTICAST +#include <linux/delay.h> +#endif + +#ifdef SA_SHIRQ +#define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev) +#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance) +#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs) +#else +#define FREE_IRQ(irqnum, dev) free_irq(irqnum) +#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n) +#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs) +#endif + +#if (LINUX_VERSION_CODE < 0x20123) +#define test_and_set_bit(val, addr) set_bit(val, addr) +#else +#ifdef MODULE +MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>"); +MODULE_DESCRIPTION("SMC 82c170 EPIC series Ethernet driver"); +MODULE_PARM(debug, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(max_interrupt_work, "i"); +#endif +#endif + +/* The I/O extent. */ +#define EPIC_TOTAL_SIZE 0x100 + +#ifdef HAVE_DEVLIST +struct netdev_entry epic100_drv = +{"Epic100", epic100_pci_probe, EPIC_TOTAL_SIZE, NULL}; +#endif + +static int epic_debug = 1; + +/* + Theory of Operation + +I. Board Compatibility + +This device driver is designed for the SMC "EPCI/100", the SMC +single-chip ethernet controllers for PCI. This chip is used on +the SMC EtherPower II boards. + + +II. Board-specific settings + +PCI bus devices are configured by the system at boot time, so no jumpers +need to be set on the board. The system BIOS will assign the +PCI INTA signal to a (preferably otherwise unused) system IRQ line. +Note: Kernel versions earlier than 1.3.73 do not support shared PCI +interrupt lines. + +III. Driver operation + +IIIa. Ring buffers + +IVb. References + +http://www.smc.com/components/catalog/smc83c170.html +http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://www.national.com/pf/DP/DP83840.html + +IVc. Errata + +*/ + +#ifndef PCI_VENDOR_ID_SMC +#define PCI_VENDOR_ID_SMC 0x10B8 +#endif +#ifndef PCI_DEVICE_ID_SMC_EPIC100 +#define PCI_DEVICE_ID_SMC_EPIC100 0x0005 +#endif + +/* The rest of these values should never change. */ +/* Offsets to registers, using the (ugh) SMC names. */ +enum epic_registers { + COMMAND=0, INTSTAT=4, INTMASK=8, GENCTL=0x0C, NVCTL=0x10, EECTL=0x14, + TEST1=0x1C, CRCCNT=0x20, ALICNT=0x24, MPCNT=0x28, /* Rx error counters. */ + MIICtrl=0x30, MIIData=0x34, MIICfg=0x38, + LAN0=64, /* MAC address. */ + MC0=80, /* Multicast filter table. */ + RxCtrl=96, TxCtrl=112, TxSTAT=0x74, + PRxCDAR=0x84, RxSTAT=0xA4, EarlyRx=0xB0, PTxCDAR=0xC4, TxThresh=0xDC, +}; + +/* Interrupt register bits, using my own meaningful names. */ +enum IntrStatus { + TxIdle=0x40000, RxIdle=0x20000, + CntFull=0x0200, TxUnderrun=0x0100, + TxEmpty=0x0080, TxDone=0x0020, RxError=0x0010, + RxOverflow=0x0008, RxFull=0x0004, RxHeader=0x0002, RxDone=0x0001, +}; + +/* The EPIC100 Rx and Tx buffer descriptors. */ + +struct epic_tx_desc { + s16 status; + u16 txlength; + u32 bufaddr; + u16 buflength; + u16 control; + u32 next; +}; + +struct epic_rx_desc { + s16 status; + u16 rxlength; + u32 bufaddr; + u32 buflength; + u32 next; +}; + +struct epic_private { + char devname[8]; /* Used only for kernel debugging. */ + const char *product_name; + struct device *next_module; + struct epic_rx_desc rx_ring[RX_RING_SIZE]; + struct epic_tx_desc tx_ring[TX_RING_SIZE]; + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + /* The addresses of receive-in-place skbuffs. */ + struct sk_buff* rx_skbuff[RX_RING_SIZE]; + int chip_id; + int revision; + struct enet_statistics stats; + struct timer_list timer; /* Media selection timer. */ + unsigned int cur_rx, cur_tx; /* The next free ring entry */ + unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ + unsigned char mc_filter[8]; + signed char phys[4]; /* MII device addresses. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int default_port:4; /* Last dev->if_port value. */ + unsigned int media2:4; /* Secondary monitored media port. */ + unsigned int medialock:1; /* Don't sense media type. */ + unsigned int mediasense:1; /* Media sensing in progress. */ + int pad0, pad1; /* Used for 8-byte alignment */ +}; + +static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1}; +#ifdef MODULE +/* Used to pass the full-duplex flag, etc. */ +static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1}; +#endif + +static struct device *epic100_probe1(struct device *dev, int ioaddr, int irq, + int chip_id, int options, int card_idx); +static int epic_open(struct device *dev); +static int read_eeprom(int ioaddr, int location); +static int mii_read(int ioaddr, int phy_id, int location); +static void epic_timer(unsigned long data); +static void epic_tx_timeout(struct device *dev); +static void epic_init_ring(struct device *dev); +static int epic_start_xmit(struct sk_buff *skb, struct device *dev); +static int epic_rx(struct device *dev); +static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static int epic_close(struct device *dev); +static struct enet_statistics *epic_get_stats(struct device *dev); +#ifdef NEW_MULTICAST +static void set_rx_mode(struct device *dev); +#else +static void set_rx_mode(struct device *dev, int num_addrs, void *addrs); +#endif + + + +#ifdef MODULE +/* A list of all installed EPIC devices, for removing the driver module. */ +static struct device *root_epic_dev = NULL; +#endif + +int epic100_probe(struct device *dev) +{ + int cards_found = 0; + static int pci_index = 0; /* Static, for multiple probe calls. */ + + /* Ideally we would detect all network cards in slot order. That would + be best done a central PCI probe dispatch, which wouldn't work + well with the current structure. So instead we detect just the + Epic cards in slot order. */ + + if (pcibios_present()) { + unsigned char pci_bus, pci_device_fn; + + for (;pci_index < 0xff; pci_index++) { + unsigned char pci_irq_line, pci_latency; + unsigned short pci_command, vendor, device; + unsigned int pci_ioaddr, chip_idx = 0; + + if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, +#ifdef REVERSE_PROBE_ORDER + 0xff - pci_index, +#else + pci_index, +#endif + &pci_bus, &pci_device_fn) + != PCIBIOS_SUCCESSFUL) + break; + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_VENDOR_ID, &vendor); + if (vendor != PCI_VENDOR_ID_SMC) + continue; + + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_DEVICE_ID, &device); + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &pci_irq_line); + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &pci_ioaddr); + /* Remove I/O space marker in bit 0. */ + pci_ioaddr &= ~3; + + if (device != PCI_DEVICE_ID_SMC_EPIC100) { + printk("Unknown SMC PCI ethernet chip type %4.4x detected:" + " not configured.\n", device); + continue; + } + if (epic_debug > 2) + printk("Found SMC PCI EPIC/100 at I/O %#x, IRQ %d.\n", + pci_ioaddr, pci_irq_line); + + if (check_region(pci_ioaddr, EPIC_TOTAL_SIZE)) + continue; + +#ifdef MODULE + dev = epic100_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx, + options[cards_found], cards_found); +#else + dev = epic100_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx, + dev ? dev->mem_start : 0, -1); +#endif + + if (dev) { + /* Get and check the bus-master and latency values. */ + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, &pci_command); + if ( ! (pci_command & PCI_COMMAND_MASTER)) { + printk(" PCI Master Bit has not been set! Setting...\n"); + pci_command |= PCI_COMMAND_MASTER; + pcibios_write_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, pci_command); + } + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency < 10) { + printk(" PCI latency timer (CFLT) is unreasonably low at %d." + " Setting to 255 clocks.\n", pci_latency); + pcibios_write_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, 255); + } else if (epic_debug > 1) + printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency); + dev = 0; + cards_found++; + } + } + } + +#if defined (MODULE) + return cards_found; +#else + return cards_found ? 0 : -ENODEV; +#endif +} + +static struct device *epic100_probe1(struct device *dev, int ioaddr, int irq, + int chip_id, int options, int card_idx) +{ + static int did_version = 0; /* Already printed version info. */ + struct epic_private *tp; + int i; + + if (epic_debug > 0 && did_version++ == 0) + printk(version); + + dev = init_etherdev(dev, 0); + + printk("%s: SMC EPIC/100 at %#3x, IRQ %d, ", dev->name, ioaddr, irq); + + /* Bring the chip out of low-power mode. */ + outl(0x0200, ioaddr + GENCTL); + /* Magic?! If we don't set this bit the MII interface won't work. */ + outl(0x0008, ioaddr + TEST1); + + /* This could also be read from the EEPROM. */ + for (i = 0; i < 3; i++) + ((u16 *)dev->dev_addr)[i] = inw(ioaddr + LAN0 + i*4); + + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x.\n", dev->dev_addr[i]); + + if (epic_debug > 1) { + printk("%s: EEPROM contents\n", dev->name); + for (i = 0; i < 64; i++) + printk(" %4.4x%s", read_eeprom(ioaddr, i), i % 16 == 15 ? "\n" : ""); + } + + /* We do a request_region() to register /proc/ioports info. */ + request_region(ioaddr, EPIC_TOTAL_SIZE, "SMC EPIC/100"); + + dev->base_addr = ioaddr; + dev->irq = irq; + + /* The data structures must be quadword aligned. */ + tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA); + memset(tp, 0, sizeof(*tp)); + dev->priv = tp; + +#ifdef MODULE + tp->next_module = root_epic_dev; + root_epic_dev = dev; +#endif + + tp->chip_id = chip_id; + + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, but + takes too much time. */ + { + int phy, phy_idx; + for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); + phy++) { + int mii_status = mii_read(ioaddr, phy, 0); + if (mii_status != 0xffff && mii_status != 0x0000) { + tp->phys[phy_idx++] = phy; + printk("%s: MII transceiver found at address %d.\n", + dev->name, phy); + } + } + if (phy_idx == 0) { + printk("%s: ***WARNING***: No MII transceiver found!\n", + dev->name); + /* Use the known PHY address of the EPII. */ + tp->phys[0] = 3; + } + } + + /* Leave the chip in low-power mode. */ + outl(0x0008, ioaddr + GENCTL); + + /* The lower four bits are the media type. */ + if (options > 0) { + tp->full_duplex = (options & 16) ? 1 : 0; + tp->default_port = options & 15; + if (tp->default_port) + tp->medialock = 1; + } + if (card_idx >= 0) { + if (full_duplex[card_idx] >= 0) + tp->full_duplex = full_duplex[card_idx]; + } + + /* The Epic-specific entries in the device structure. */ + dev->open = &epic_open; + dev->hard_start_xmit = &epic_start_xmit; + dev->stop = &epic_close; + dev->get_stats = &epic_get_stats; + dev->set_multicast_list = &set_rx_mode; + + return dev; +} + +/* Serial EEPROM section. */ + +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ +#define EE_CS 0x02 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x08 /* EEPROM chip data in. */ +#define EE_WRITE_0 0x01 +#define EE_WRITE_1 0x09 +#define EE_DATA_READ 0x10 /* EEPROM chip data out. */ +#define EE_ENB (0x0001 | EE_CS) + +/* Delay between EEPROM clock transitions. + The 1.2 code is a "nasty" timing loop, but PC compatible machines are + *supposed* to delay an ISA-compatible period for the SLOW_DOWN_IO macro. */ +#ifdef _LINUX_DELAY_H +#define eeprom_delay(nanosec) udelay((nanosec + 999)/1000) +#else +#define eeprom_delay(nanosec) do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0) +#endif + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD (5 << 6) +#define EE_READ_CMD (6 << 6) +#define EE_ERASE_CMD (7 << 6) + +static int read_eeprom(int ioaddr, int location) +{ + int i; + int retval = 0; + int ee_addr = ioaddr + EECTL; + int read_cmd = location | EE_READ_CMD; + + outl(EE_ENB & ~EE_CS, ee_addr); + outl(EE_ENB, ee_addr); + + /* Shift the read command bits out. */ + for (i = 10; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + outl(EE_ENB | dataval, ee_addr); + eeprom_delay(100); + outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); + eeprom_delay(150); + outl(EE_ENB | dataval, ee_addr); /* Finish EEPROM a clock tick. */ + eeprom_delay(250); + } + outl(EE_ENB, ee_addr); + + for (i = 16; i > 0; i--) { + outl(EE_ENB | EE_SHIFT_CLK, ee_addr); + eeprom_delay(100); + retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); + outl(EE_ENB, ee_addr); + eeprom_delay(100); + } + + /* Terminate the EEPROM access. */ + outl(EE_ENB & ~EE_CS, ee_addr); + return retval; +} + +#define MII_READOP 1 +#define MII_WRITEOP 2 +static int mii_read(int ioaddr, int phy_id, int location) +{ + int i; + + outl((phy_id << 9) | (location << 4) | MII_READOP, ioaddr + MIICtrl); + /* Typical operation takes < 50 ticks. */ + for (i = 4000; i > 0; i--) + if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0) + break; + return inw(ioaddr + MIIData); +} + + +static int +epic_open(struct device *dev) +{ + struct epic_private *tp = (struct epic_private *)dev->priv; + int ioaddr = dev->base_addr; + int i; + int mii_reg5; + int full_duplex = 0; + + /* Soft reset the chip. */ + outl(0x0001, ioaddr + GENCTL); + +#ifdef SA_SHIRQ + if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, + "SMC EPIC/100", dev)) { + return -EAGAIN; + } +#else + if (irq2dev_map[dev->irq] != NULL + || (irq2dev_map[dev->irq] = dev) == NULL + || dev->irq == 0 + || request_irq(dev->irq, &epic_interrupt, 0, "SMC EPIC/100")) { + return -EAGAIN; + } +#endif + + MOD_INC_USE_COUNT; + + epic_init_ring(dev); + + /* This next line by Ken Yamaguchi.. ?? */ + outl(0x8, ioaddr + 0x1c); + + /* Pull the chip out of low-power mode, enable interrupts, and set for PCI read multiple. */ + outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); + + for (i = 0; i < 3; i++) + outl(((u16*)dev->dev_addr)[i], ioaddr + LAN0 + i*4); + + outl(TX_FIFO_THRESH, ioaddr + TxThresh); + full_duplex = tp->full_duplex; + + mii_reg5 = mii_read(ioaddr, tp->phys[0], 5); + if (mii_reg5 != 0xffff && (mii_reg5 & 0x0100)) { + full_duplex = 1; + if (epic_debug > 1) + printk("%s: Setting %s-duplex based on MII xcvr %d" + " register read of %4.4x.\n", dev->name, + full_duplex ? "full" : "half", tp->phys[0], + mii_read(ioaddr, tp->phys[0], 5)); + } + + outl(full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); + outl(virt_to_bus(tp->rx_ring), ioaddr + PRxCDAR); + outl(virt_to_bus(tp->tx_ring), ioaddr + PTxCDAR); + + /* Start the chip's Rx process. */ + set_rx_mode(dev); + outl(0x000A, ioaddr + COMMAND); + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + /* Enable interrupts by setting the interrupt mask. */ + outl(CntFull | TxUnderrun | TxDone + | RxError | RxOverflow | RxFull | RxHeader | RxDone, + ioaddr + INTMASK); + + if (epic_debug > 1) + printk("%s: epic_open() ioaddr %4.4x IRQ %d status %4.4x %s-duplex.\n", + dev->name, ioaddr, dev->irq, inl(ioaddr + GENCTL), + full_duplex ? "full" : "half"); + + /* Set the timer to switch to check for link beat and perhaps switch + to an alternate media type. */ + init_timer(&tp->timer); + tp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ + tp->timer.data = (unsigned long)dev; + tp->timer.function = &epic_timer; /* timer handler */ + add_timer(&tp->timer); + + return 0; +} + +static void epic_timer(unsigned long data) +{ + struct device *dev = (struct device *)data; + struct epic_private *tp = (struct epic_private *)dev->priv; + int ioaddr = dev->base_addr; + int next_tick = 0; + + if (epic_debug > 3) { + printk("%s: Media selection tick, Tx status %8.8x.\n", + dev->name, inl(ioaddr + TxSTAT)); + printk("%s: Other registers are IntMask %4.4x IntStatus %4.4x RxStatus" + " %4.4x.\n", + dev->name, inl(ioaddr + INTMASK), inl(ioaddr + INTSTAT), + inl(ioaddr + RxSTAT)); + } + + if (next_tick) { + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); + } +} + +static void epic_tx_timeout(struct device *dev) +{ + struct epic_private *tp = (struct epic_private *)dev->priv; + int ioaddr = dev->base_addr; + + if (epic_debug > 0) { + printk("%s: Transmit timeout using MII device, Tx status %4.4x.\n", + dev->name, inw(ioaddr + TxSTAT)); + if (epic_debug > 1) { + printk("%s: Tx indices: dirty_tx %d, cur_tx %d.\n", + dev->name, tp->dirty_tx, tp->cur_tx); + } + } + /* Perhaps stop and restart the chip's Tx processes . */ + /* Trigger a transmit demand. */ + outl(0x0004, dev->base_addr + COMMAND); + + dev->trans_start = jiffies; + tp->stats.tx_errors++; + return; +} + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void +epic_init_ring(struct device *dev) +{ + struct epic_private *tp = (struct epic_private *)dev->priv; + int i; + + tp->tx_full = 0; + tp->cur_rx = tp->cur_tx = 0; + tp->dirty_rx = tp->dirty_tx = 0; + + for (i = 0; i < RX_RING_SIZE; i++) { + tp->rx_ring[i].status = 0x8000; /* Owned by Epic chip */ + tp->rx_ring[i].buflength = PKT_BUF_SZ; + { + /* Note the receive buffer must be longword aligned. + dev_alloc_skb() provides 16 byte alignment. But do *not* + use skb_reserve() to align the IP header! */ + struct sk_buff *skb; + skb = DEV_ALLOC_SKB(PKT_BUF_SZ); + tp->rx_skbuff[i] = skb; + if (skb == NULL) + break; /* Bad news! */ + skb->dev = dev; /* Mark as being used by this device. */ +#if LINUX_VERSION_CODE > 0x10300 + skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ + tp->rx_ring[i].bufaddr = virt_to_bus(skb->tail); +#else + tp->rx_ring[i].bufaddr = virt_to_bus(skb->data); +#endif + } + tp->rx_ring[i].next = virt_to_bus(&tp->rx_ring[i+1]); + } + /* Mark the last entry as wrapping the ring. */ + tp->rx_ring[i-1].next = virt_to_bus(&tp->rx_ring[0]); + + /* The Tx buffer descriptor is filled in as needed, but we + do need to clear the ownership bit. */ + for (i = 0; i < TX_RING_SIZE; i++) { + tp->tx_skbuff[i] = 0; + tp->tx_ring[i].status = 0x0000; + tp->tx_ring[i].next = virt_to_bus(&tp->tx_ring[i+1]); + } + tp->tx_ring[i-1].next = virt_to_bus(&tp->tx_ring[0]); +} + +static int +epic_start_xmit(struct sk_buff *skb, struct device *dev) +{ + struct epic_private *tp = (struct epic_private *)dev->priv; + int entry; + u32 flag; + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + if (jiffies - dev->trans_start < TX_TIMEOUT) + return 1; + epic_tx_timeout(dev); + return 1; + } + + /* Caution: the write order is important here, set the base address + with the "ownership" bits last. */ + + /* Calculate the next Tx descriptor entry. */ + entry = tp->cur_tx % TX_RING_SIZE; + + tp->tx_skbuff[entry] = skb; + tp->tx_ring[entry].txlength = (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN); + tp->tx_ring[entry].bufaddr = virt_to_bus(skb->data); + tp->tx_ring[entry].buflength = skb->len; + + if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */ + flag = 0x10; /* No interrupt */ + dev->tbusy = 0; + } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) { + flag = 0x14; /* Tx-done intr. */ + dev->tbusy = 0; + } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) { + flag = 0x10; /* No Tx-done intr. */ + dev->tbusy = 0; + } else { + /* Leave room for two additional entries. */ + flag = 0x14; /* Tx-done intr. */ + tp->tx_full = 1; + } + + tp->tx_ring[entry].control = flag; + tp->tx_ring[entry].status = 0x8000; /* Pass ownership to the chip. */ + tp->cur_tx++; + /* Trigger an immediate transmit demand. */ + outl(0x0004, dev->base_addr + COMMAND); + + dev->trans_start = jiffies; + if (epic_debug > 4) + printk("%s: Queued Tx packet size %d to slot %d, " + "flag %2.2x Tx status %8.8x.\n", + dev->name, (int)skb->len, entry, flag, + inl(dev->base_addr + TxSTAT)); + + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void epic_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs) +{ +#ifdef SA_SHIRQ + struct device *dev = (struct device *)dev_instance; +#else + struct device *dev = (struct device *)(irq2dev_map[irq]); +#endif + struct epic_private *lp; + int status, ioaddr, boguscnt = max_interrupt_work; + + if (dev == NULL) { + printk ("epic_interrupt(): irq %d for unknown device.\n", irq); + return; + } + + ioaddr = dev->base_addr; + lp = (struct epic_private *)dev->priv; + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + + dev->interrupt = 1; + + do { + status = inl(ioaddr + INTSTAT); + /* Acknowledge all of the current interrupt sources ASAP. */ + outl(status & 0x00007fff, ioaddr + INTSTAT); + + if (epic_debug > 4) + printk("%s: interrupt interrupt=%#8.8x new intstat=%#8.8x.\n", + dev->name, status, inl(ioaddr + INTSTAT)); + + if ((status & (RxDone | TxEmpty | TxDone)) == 0) + break; + + if (status & RxDone) /* Rx interrupt */ + epic_rx(dev); + + if (status & (TxEmpty | TxDone)) { + int dirty_tx; + + for (dirty_tx = lp->dirty_tx; dirty_tx < lp->cur_tx; dirty_tx++) { + int entry = dirty_tx % TX_RING_SIZE; + int txstatus = lp->tx_ring[entry].status; + + if (txstatus < 0) + break; /* It still hasn't been Txed */ + + if ( ! (txstatus & 0x0001)) { + /* There was an major error, log it. */ +#ifndef final_version + if (epic_debug > 1) + printk("%s: Transmit error, Tx status %8.8x.\n", + dev->name, txstatus); +#endif + lp->stats.tx_errors++; + if (txstatus & 0x1050) lp->stats.tx_aborted_errors++; + if (txstatus & 0x0008) lp->stats.tx_carrier_errors++; + if (txstatus & 0x0040) lp->stats.tx_window_errors++; + if (txstatus & 0x0010) lp->stats.tx_fifo_errors++; +#ifdef ETHER_STATS + if (txstatus & 0x1000) lp->stats.collisions16++; +#endif + } else { +#ifdef ETHER_STATS + if ((txstatus & 0x0002) != 0) lp->stats.tx_deferred++; +#endif + lp->stats.collisions += (txstatus >> 8) & 15; + lp->stats.tx_packets++; + } + + /* Free the original skb. */ + dev_kfree_skb(lp->tx_skbuff[entry]); + lp->tx_skbuff[entry] = 0; + } + +#ifndef final_version + if (lp->cur_tx - dirty_tx > TX_RING_SIZE) { + printk("%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dev->name, dirty_tx, lp->cur_tx, lp->tx_full); + dirty_tx += TX_RING_SIZE; + } +#endif + + if (lp->tx_full && dev->tbusy + && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { + /* The ring is no longer full, clear tbusy. */ + lp->tx_full = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + } + + lp->dirty_tx = dirty_tx; + } + + /* Check uncommon events all at once. */ + if (status & (CntFull | TxUnderrun | RxOverflow)) { + /* Always update the error counts to avoid overhead later. */ + lp->stats.rx_missed_errors += inb(ioaddr + MPCNT); + lp->stats.rx_frame_errors += inb(ioaddr + ALICNT); + lp->stats.rx_crc_errors += inb(ioaddr + CRCCNT); + + if (status & TxUnderrun) { /* Tx FIFO underflow. */ + lp->stats.tx_fifo_errors++; + /* Restart the transmit process. */ + outl(0x0080, ioaddr + COMMAND); + } + if (status & RxOverflow) { /* Missed a Rx frame. */ + lp->stats.rx_errors++; + } + /* Clear all error sources. */ + outl(status & 0x7f18, ioaddr + INTSTAT); + } + if (--boguscnt < 0) { + printk("%s: Too much work at interrupt, IntrStatus=0x%8.8x.\n", + dev->name, status); + /* Clear all interrupt sources. */ + outl(0x0001ffff, ioaddr + INTSTAT); + break; + } + } while (1); + + if (epic_debug > 3) + printk("%s: exiting interrupt, intr_status=%#4.4x.\n", + dev->name, inl(ioaddr + INTSTAT)); + + /* Code that should never be run! Perhaps remove after testing.. */ + { + static int stopit = 10; + if (dev->start == 0 && --stopit < 0) { + printk("%s: Emergency stop, looping startup interrupt.\n", + dev->name); + FREE_IRQ(irq, dev); + } + } + + dev->interrupt = 0; + return; +} + +static int +epic_rx(struct device *dev) +{ + struct epic_private *lp = (struct epic_private *)dev->priv; + int entry = lp->cur_rx % RX_RING_SIZE; + + if (epic_debug > 4) + printk(" In epic_rx(), entry %d %8.8x.\n", entry, + lp->rx_ring[entry].status); + /* If we own the next entry, it's a new packet. Send it up. */ + while (lp->rx_ring[entry].status >= 0) { + int status = lp->rx_ring[entry].status; + + if (epic_debug > 4) + printk(" epic_rx() status was %8.8x.\n", status); + if (status & 0x2000) { + printk("%s: Oversized Ethernet frame spanned multiple buffers," + " status %4.4x!\n", dev->name, status); + lp->stats.rx_length_errors++; + } else if (status & 0x0006) { + /* Rx Frame errors are counted in hardware. */ + lp->stats.rx_errors++; + } else { + /* Malloc up new buffer, compatible with net-2e. */ + /* Omit the four octet CRC from the length. */ + short pkt_len = lp->rx_ring[entry].rxlength - 4; + struct sk_buff *skb; + int rx_in_place = 0; + + /* Check if the packet is long enough to just accept without + copying to a properly sized skbuff. */ + if (pkt_len > rx_copybreak) { + struct sk_buff *newskb; + char *temp; + + /* Pass up the skb already on the Rx ring. */ + skb = lp->rx_skbuff[entry]; + temp = skb_put(skb, pkt_len); + if (bus_to_virt(lp->rx_ring[entry].bufaddr) != temp) + printk("%s: Warning -- the skbuff addresses do not match" + " in epic_rx: %p vs. %p / %p.\n", dev->name, + bus_to_virt(lp->rx_ring[entry].bufaddr), + skb->head, temp); + /* Get a fresh skbuff to replace the filled one. */ + newskb = DEV_ALLOC_SKB(PKT_BUF_SZ); + if (newskb) { + rx_in_place = 1; + lp->rx_skbuff[entry] = newskb; + newskb->dev = dev; +#if LINUX_VERSION_CODE > 0x10300 + /* Align IP on 16 byte boundaries */ + skb_reserve(newskb, 2); + lp->rx_ring[entry].bufaddr = virt_to_bus(newskb->tail); +#else + lp->rx_ring[entry].bufaddr = virt_to_bus(newskb->data); +#endif + } else /* No memory, drop the packet. */ + skb = 0; + } else + skb = DEV_ALLOC_SKB(pkt_len + 2); + if (skb == NULL) { + int i; + printk("%s: Memory squeeze, deferring packet.\n", dev->name); + /* Check that at least two ring entries are free. + If not, free one and mark stats->rx_dropped++. */ + for (i = 0; i < RX_RING_SIZE; i++) + if (lp->rx_ring[(entry+i) % RX_RING_SIZE].status < 0) + break; + + if (i > RX_RING_SIZE -2) { + lp->stats.rx_dropped++; + lp->rx_ring[entry].status = 0x8000; + lp->cur_rx++; + } + break; + } + skb->dev = dev; + if (! rx_in_place) { + skb_reserve(skb, 2); /* 16 byte align the data fields */ + memcpy(skb_put(skb, pkt_len), + bus_to_virt(lp->rx_ring[entry].bufaddr), pkt_len); + } +#if LINUX_VERSION_CODE > 0x10300 + skb->protocol = eth_type_trans(skb, dev); +#else + skb->len = pkt_len; +#endif + netif_rx(skb); + lp->stats.rx_packets++; + } + + lp->rx_ring[entry].status = 0x8000; + entry = (++lp->cur_rx) % RX_RING_SIZE; + } + + return 0; +} + +static int +epic_close(struct device *dev) +{ + int ioaddr = dev->base_addr; + struct epic_private *tp = (struct epic_private *)dev->priv; + int i; + + dev->start = 0; + dev->tbusy = 1; + + if (epic_debug > 1) + printk("%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, inl(ioaddr + INTSTAT)); + + /* Disable interrupts by clearing the interrupt mask. */ + outl(0x00000000, ioaddr + INTMASK); + /* Stop the chip's Tx and Rx DMA processes. */ + outw(0x0061, ioaddr + COMMAND); + + /* Update the error counts. */ + tp->stats.rx_missed_errors += inb(ioaddr + MPCNT); + tp->stats.rx_frame_errors += inb(ioaddr + ALICNT); + tp->stats.rx_crc_errors += inb(ioaddr + CRCCNT); + + del_timer(&tp->timer); + +#ifdef SA_SHIRQ + free_irq(dev->irq, dev); +#else + free_irq(dev->irq); + irq2dev_map[dev->irq] = 0; +#endif + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = tp->rx_skbuff[i]; + tp->rx_skbuff[i] = 0; + tp->rx_ring[i].status = 0; /* Not owned by Epic chip. */ + tp->rx_ring[i].buflength = 0; + tp->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */ + if (skb) { +#if LINUX_VERSION_CODE < 0x20100 + skb->free = 1; +#endif + dev_kfree_skb(skb); + } + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (tp->tx_skbuff[i]) + dev_kfree_skb(tp->tx_skbuff[i]); + tp->tx_skbuff[i] = 0; + } + + + /* Green! Leave the chip in low-power mode. */ + outl(0x0008, ioaddr + GENCTL); + + MOD_DEC_USE_COUNT; + + return 0; +} + +static struct enet_statistics * +epic_get_stats(struct device *dev) +{ + struct epic_private *tp = (struct epic_private *)dev->priv; + int ioaddr = dev->base_addr; + + if (dev->start) { + /* Update the error counts. */ + tp->stats.rx_missed_errors += inb(ioaddr + MPCNT); + tp->stats.rx_frame_errors += inb(ioaddr + ALICNT); + tp->stats.rx_crc_errors += inb(ioaddr + CRCCNT); + } + + return &tp->stats; +} + +/* Set or clear the multicast filter for this adaptor. + Note that we only use exclusion around actually queueing the + new frame, not around filling tp->setup_frame. This is non-deterministic + when re-entered but still correct. */ + +/* The little-endian AUTODIN II ethernet CRC calculation. + N.B. Do not use for bulk data, use a table-based routine instead. + This is common code and should be moved to net/core/crc.c */ +static unsigned const ethernet_polynomial_le = 0xedb88320U; +static inline unsigned ether_crc_le(int length, unsigned char *data) +{ + unsigned int crc = 0xffffffff; /* Initial value. */ + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 8; --bit >= 0; current_octet >>= 1) { + if ((crc ^ current_octet) & 1) { + crc >>= 1; + crc ^= ethernet_polynomial_le; + } else + crc >>= 1; + } + } + return crc; +} + + +#ifdef NEW_MULTICAST +static void set_rx_mode(struct device *dev) +#else +static void set_rx_mode(struct device *dev, int num_addrs, void *addrs); +#endif +{ + int ioaddr = dev->base_addr; + struct epic_private *tp = (struct epic_private *)dev->priv; + unsigned char mc_filter[8]; /* Multicast hash filter */ + int i; + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + outl(0x002C, ioaddr + RxCtrl); + /* Unconditionally log net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + memset(mc_filter, 0xff, sizeof(mc_filter)); + } else if ((dev->mc_count > 0) || (dev->flags & IFF_ALLMULTI)) { + /* There is apparently a chip bug, so the multicast filter + is never enabled. */ + /* Too many to filter perfectly -- accept all multicasts. */ + memset(mc_filter, 0xff, sizeof(mc_filter)); + outl(0x000C, ioaddr + RxCtrl); + } else if (dev->mc_count == 0) { + outl(0x0004, ioaddr + RxCtrl); + return; + } else { /* Never executed, for now. */ + struct dev_mc_list *mclist; + + memset(mc_filter, 0, sizeof(mc_filter)); + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f, + mc_filter); + } + /* ToDo: perhaps we need to stop the Tx and Rx process here? */ + if (memcmp(mc_filter, tp->mc_filter, sizeof(mc_filter))) { + for (i = 0; i < 4; i++) + outw(((u16 *)mc_filter)[i], ioaddr + MC0 + i*4); + memcpy(tp->mc_filter, mc_filter, sizeof(mc_filter)); + } + return; +} + +#ifdef MODULE + +/* An additional parameter that may be passed in... */ +static int debug = -1; + +int +init_module(void) +{ + int cards_found; + + if (debug >= 0) + epic_debug = debug; + + root_epic_dev = NULL; + cards_found = epic100_probe(0); + + return cards_found ? 0 : -ENODEV; +} + +void +cleanup_module(void) +{ + struct device *next_dev; + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_epic_dev) { + next_dev = ((struct epic_private *)root_epic_dev->priv)->next_module; + unregister_netdev(root_epic_dev); + release_region(root_epic_dev->base_addr, EPIC_TOTAL_SIZE); + kfree(root_epic_dev); + root_epic_dev = next_dev; + } +} + +#endif /* MODULE */ + +/* + * Local variables: + * compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c epic100.c" + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c new file mode 100644 index 000000000..198ba1633 --- /dev/null +++ b/drivers/net/hamradio/6pack.c @@ -0,0 +1,1129 @@ +/* + * 6pack.c This module implements the 6pack protocol for kernel-based + * devices like TTY. It interfaces between a raw TTY and the + * kernel's AX.25 protocol layers. + * + * Version: @(#)6pack.c 0.3.0 04/07/98 + * + * Authors: Andreas Könsgen <ajk@iehk.rwth-aachen.de> + * + * Quite a lot of stuff "stolen" by Jörg Reuter from slip.c, written by + * + * Laurence Culhane, <loz@holmes.demon.co.uk> + * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> + * + */ + +#include <linux/config.h> +#include <linux/module.h> + +#include <asm/system.h> +#include <asm/uaccess.h> +#include <asm/bitops.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/tty.h> +#include <linux/errno.h> +#include <linux/netdevice.h> +#include <linux/timer.h> +#include <net/ax25.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/rtnetlink.h> +#include <linux/if_arp.h> +#include <linux/if_slip.h> +#include <linux/init.h> +#include <linux/ip.h> +#include <linux/tcp.h> +/* +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +*/ + +#include "6pack.h" + +typedef unsigned char byte; + + +typedef struct sixpack_ctrl { + char if_name[8]; /* "sp0\0" .. "sp99999\0" */ + struct sixpack ctrl; /* 6pack things */ + struct device dev; /* the device */ +} sixpack_ctrl_t; +static sixpack_ctrl_t **sixpack_ctrls = NULL; +int sixpack_maxdev = SIXP_NRUNIT; /* Can be overridden with insmod! */ + +static struct tty_ldisc sp_ldisc; + +static void sp_start_tx_timer(struct sixpack *); +static void sp_xmit_on_air(unsigned long); +static void resync_tnc(unsigned long); +void sixpack_decode(struct sixpack *, unsigned char[], int); +int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char); + +void decode_prio_command(byte, struct sixpack *); +void decode_std_command(byte, struct sixpack *); +void decode_data(byte, struct sixpack *); + +static int tnc_init(struct sixpack *); + +/* Find a free 6pack channel, and link in this `tty' line. */ +static inline struct sixpack * +sp_alloc(void) +{ + sixpack_ctrl_t *spp = NULL; + int i; + + if (sixpack_ctrls == NULL) return NULL; /* Master array missing ! */ + + for (i = 0; i < sixpack_maxdev; i++) + { + spp = sixpack_ctrls[i]; + + if (spp == NULL) + break; + + if (!test_and_set_bit(SIXPF_INUSE, &spp->ctrl.flags)) + break; + } + + /* Too many devices... */ + if (i >= sixpack_maxdev) + return NULL; + + /* If no channels are available, allocate one */ + if (!spp && + (sixpack_ctrls[i] = (sixpack_ctrl_t *)kmalloc(sizeof(sixpack_ctrl_t), + GFP_KERNEL)) != NULL) + { + spp = sixpack_ctrls[i]; + memset(spp, 0, sizeof(sixpack_ctrl_t)); + + /* Initialize channel control data */ + set_bit(SIXPF_INUSE, &spp->ctrl.flags); + spp->ctrl.tty = NULL; + sprintf(spp->if_name, "sp%d", i); + spp->dev.name = spp->if_name; + spp->dev.base_addr = i; + spp->dev.priv = (void*)&(spp->ctrl); + spp->dev.next = NULL; + spp->dev.init = sixpack_init; + } + + if (spp != NULL) + { + /* register device so that it can be ifconfig'ed */ + /* sixpack_init() will be called as a side-effect */ + /* SIDE-EFFECT WARNING: sixpack_init() CLEARS spp->ctrl ! */ + + if (register_netdev(&(spp->dev)) == 0) + { + set_bit(SIXPF_INUSE, &spp->ctrl.flags); + spp->ctrl.dev = &(spp->dev); + spp->dev.priv = (void*)&(spp->ctrl); + + return (&(spp->ctrl)); + } else { + clear_bit(SIXPF_INUSE,&(spp->ctrl.flags)); + printk(KERN_WARNING "sp_alloc() - register_netdev() failure.\n"); + } + } + + return NULL; +} + + +/* Free a 6pack channel. */ +static inline void +sp_free(struct sixpack *sp) +{ + /* Free all 6pack frame buffers. */ + if (sp->rbuff) + kfree(sp->rbuff); + sp->rbuff = NULL; + if (sp->xbuff) { + kfree(sp->xbuff); + } + sp->xbuff = NULL; + + if (!test_and_clear_bit(SIXPF_INUSE, &sp->flags)) + { + printk(KERN_WARNING "%s: sp_free for already free unit.\n", sp->dev->name); + } +} + + +/* Set the "sending" flag. */ +static inline void +sp_lock(struct sixpack *sp) +{ + if (test_and_set_bit(0, (void *) &sp->dev->tbusy)) + printk(KERN_WARNING "%s: trying to lock already locked device!\n", sp->dev->name); +} + + +/* Clear the "sending" flag. */ +static inline void +sp_unlock(struct sixpack *sp) +{ + if (!test_and_clear_bit(0, (void *)&sp->dev->tbusy)) + printk(KERN_WARNING "%s: trying to unlock already unlocked device!\n", sp->dev->name); +} + + +/* Send one completely decapsulated IP datagram to the IP layer. */ + +/* This is the routine that sends the received data to the kernel AX.25. + 'cmd' is the KISS command. For AX.25 data, it is zero. */ + +static void +sp_bump(struct sixpack *sp, char cmd) +{ + struct sk_buff *skb; + int count; + unsigned char *ptr; + + count = sp->rcount+1; + + sp->rx_bytes+=count; + + skb = dev_alloc_skb(count); + if (skb == NULL) + { + printk(KERN_DEBUG "%s: memory squeeze, dropping packet.\n", sp->dev->name); + sp->rx_dropped++; + return; + } + + skb->dev = sp->dev; + ptr = skb_put(skb, count); + *ptr++ = cmd; /* KISS command */ + + memcpy(ptr, (sp->cooked_buf)+1, count); + skb->mac.raw=skb->data; + skb->protocol=htons(ETH_P_AX25); + netif_rx(skb); + sp->rx_packets++; +} + + +/* ----------------------------------------------------------------------- */ + +/* Encapsulate one AX.25 frame and stuff into a TTY queue. */ +static void +sp_encaps(struct sixpack *sp, unsigned char *icp, int len) +{ + unsigned char *p; + int actual, count; + + if (len > sp->mtu) /* sp->mtu = AX25_MTU = max. PACLEN = 256 */ + { + len = sp->mtu; + printk(KERN_DEBUG "%s: truncating oversized transmit packet!\n", sp->dev->name); + sp->tx_dropped++; + sp_unlock(sp); + return; + } + + p = icp; + + if (p[0] > 5) + { + printk(KERN_DEBUG "%s: invalid KISS command -- dropped\n", sp->dev->name); + sp_unlock(sp); + return; + } + + if ((p[0] != 0) && (len > 2)) + { + printk(KERN_DEBUG "%s: KISS control packet too long -- dropped\n", sp->dev->name); + sp_unlock(sp); + return; + } + + if ((p[0] == 0) && (len < 15)) + { + printk(KERN_DEBUG "%s: bad AX.25 packet to transmit -- dropped\n", sp->dev->name); + sp_unlock(sp); + sp->tx_dropped++; + return; + } + + count = encode_sixpack(p, (unsigned char *) sp->xbuff, len, sp->tx_delay); + sp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + + switch(p[0]) + { + case 1: sp->tx_delay = p[1]; return; + case 2: sp->persistance = p[1]; return; + case 3: sp->slottime = p[1]; return; + case 4: /* ignored */ return; + case 5: sp->duplex = p[1]; return; + } + + if (p[0] == 0) { + /* in case of fullduplex or DAMA operation, we don't take care + about the state of the DCD or of any timers, as the determination + of the correct time to send is the job of the AX.25 layer. We send + immediately after data has arrived. */ + if (sp->duplex == 1){ + sp->led_state = 0x70; + sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1); + sp->tx_enable = 1; + actual = sp->tty->driver.write(sp->tty, 0, sp->xbuff, count); + sp->xleft = count - actual; + sp->xhead = sp->xbuff + actual; + sp->led_state = 0x60; + sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1); + } + else { + sp->xleft = count; + sp->xhead = sp->xbuff; + sp->status2 = count; + if (sp->duplex == 0) + sp_start_tx_timer(sp); + } + } +} + +/* + * Called by the TTY driver when there's room for more data. If we have + * more packets to send, we send them here. + */ +static void sixpack_write_wakeup(struct tty_struct *tty) +{ + int actual; + struct sixpack *sp = (struct sixpack *) tty->disc_data; + + /* First make sure we're connected. */ + if (!sp || sp->magic != SIXPACK_MAGIC || !sp->dev->start) { + return; + } + if (sp->xleft <= 0) { + /* Now serial buffer is almost free & we can start + * transmission of another packet */ + sp->tx_packets++; + tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + sp_unlock(sp); + sp->tx_enable = 0; + mark_bh(NET_BH); + return; + } + + if (sp->tx_enable == 1) { + actual = tty->driver.write(tty, 0, sp->xhead, sp->xleft); + sp->xleft -= actual; + sp->xhead += actual; + } +} + +/* ----------------------------------------------------------------------- */ + +/* Encapsulate an IP datagram and kick it into a TTY queue. */ + +static int +sp_xmit(struct sk_buff *skb, struct device *dev) +{ + struct sixpack *sp = (struct sixpack*)(dev->priv); + + if (!dev->start) + { + printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name); + return 1; + } + + if (dev->tbusy) + return 1; + + /* We were not busy, so we are now... :-) */ + if (skb != NULL) { + sp_lock(sp); + sp->tx_bytes+=skb->len; /*---2.1.x---*/ + sp_encaps(sp, skb->data, skb->len); + dev_kfree_skb(skb); + } + return 0; +} +/* #endif */ + + +/* perform the persistence/slottime algorithm for CSMA access. If the persistence + check was successful, write the data to the serial driver. Note that in case + of DAMA operation, the data is not sent here. */ + +static +void sp_xmit_on_air(unsigned long channel) +{ + struct sixpack *sp = (struct sixpack *) channel; + int actual; + static unsigned char random; + + random = random * 17 + 41; + + if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistance)) { + sp->led_state = 0x70; + sp->tty->driver.write(sp->tty, 0, &(sp->led_state),1); + sp->tx_enable = 1; + actual = sp->tty->driver.write(sp->tty, 0, sp->xbuff, sp->status2); + sp->xleft -= actual; + sp->xhead += actual; + sp->led_state = 0x60; + sp->tty->driver.write(sp->tty, 0, &(sp->led_state),1); + sp->status2 = 0; + } else + sp_start_tx_timer(sp); +} /* sp_xmit */ + +/* #if defined(CONFIG_6PACK) || defined(CONFIG_6PACK_MODULE) */ + +/* Return the frame type ID */ +static int sp_header(struct sk_buff *skb, struct device *dev, unsigned short type, + void *daddr, void *saddr, unsigned len) +{ +#ifdef CONFIG_INET + if (type != htons(ETH_P_AX25)) + return ax25_encapsulate(skb, dev, type, daddr, saddr, len); +#endif + return 0; +} + + +static int sp_rebuild_header(struct sk_buff *skb) +{ +#ifdef CONFIG_INET + return ax25_rebuild_header(skb); +#else + return 0; +#endif +} + +/* #endif */ /* CONFIG_{AX25,AX25_MODULE} */ + +/* Open the low-level part of the 6pack channel. */ +static int +sp_open(struct device *dev) +{ + struct sixpack *sp = (struct sixpack*)(dev->priv); + unsigned long len; + + if (sp->tty == NULL) + return -ENODEV; + + /* + * Allocate the 6pack frame buffers: + * + * rbuff Receive buffer. + * xbuff Transmit buffer. + * cbuff Temporary compression buffer. + */ + + /* !!! length of the buffers. MTU is IP MTU, not PACLEN! + */ + + len = dev->mtu * 2; + + sp->rbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL); + if (sp->rbuff == NULL) + return -ENOMEM; + + sp->xbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL); + if (sp->xbuff == NULL) + { + kfree(sp->rbuff); + return -ENOMEM; + } + + sp->mtu = AX25_MTU + 73; + sp->buffsize = len; + sp->rcount = 0; + sp->rx_count = 0; + sp->rx_count_cooked = 0; + sp->xleft = 0; + + sp->flags &= (1 << SIXPF_INUSE); /* Clear ESCAPE & ERROR flags */ + + sp->duplex = 0; + sp->tx_delay = SIXP_TXDELAY; + sp->persistance = SIXP_PERSIST; + sp->slottime = SIXP_SLOTTIME; + sp->led_state = 0x60; + sp->status = 1; + sp->status1 = 1; + sp->status2 = 0; + sp->tnc_ok = 0; + sp->tx_enable = 0; + + dev->tbusy = 0; + dev->start = 1; + + init_timer(&sp->tx_t); + init_timer(&sp->resync_t); + return 0; +} + + +/* Close the low-level part of the 6pack channel. */ +static int +sp_close(struct device *dev) +{ + struct sixpack *sp = (struct sixpack*)(dev->priv); + + if (sp->tty == NULL) { + return -EBUSY; + } + sp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + dev->tbusy = 1; + dev->start = 0; + + return 0; +} + +static int +sixpack_receive_room(struct tty_struct *tty) +{ + return 65536; /* We can handle an infinite amount of data. :-) */ +} + +/* !!! receive state machine */ + +/* + * Handle the 'receiver data ready' interrupt. + * This function is called by the 'tty_io' module in the kernel when + * a block of 6pack data has been received, which can now be decapsulated + * and sent on to some IP layer for further processing. + */ +static void +sixpack_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) +{ + unsigned char buf[512]; + unsigned long flags; + int count1; + + struct sixpack *sp = (struct sixpack *) tty->disc_data; + + if (!sp || sp->magic != SIXPACK_MAGIC || !sp->dev->start || !count) + return; + + save_flags(flags); + cli(); + memcpy(buf, cp, count<sizeof(buf)? count:sizeof(buf)); + restore_flags(flags); + + /* Read the characters out of the buffer */ + + count1 = count; + while(count) + { + count--; + if (fp && *fp++) + { + if (!test_and_set_bit(SIXPF_ERROR, &sp->flags)) { + sp->rx_errors++; + } + continue; + } + } + sixpack_decode(sp, buf, count1); +} + +/* + * Open the high-level part of the 6pack channel. + * This function is called by the TTY module when the + * 6pack line discipline is called for. Because we are + * sure the tty line exists, we only have to link it to + * a free 6pcack channel... + */ +static int +sixpack_open(struct tty_struct *tty) +{ + struct sixpack *sp = (struct sixpack *) tty->disc_data; + int err; + + /* First make sure we're not already connected. */ + + if (sp && sp->magic == SIXPACK_MAGIC) + return -EEXIST; + + /* OK. Find a free 6pack channel to use. */ + if ((sp = sp_alloc()) == NULL) + return -ENFILE; + sp->tty = tty; + tty->disc_data = sp; + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + + /* Restore default settings */ + sp->dev->type = ARPHRD_AX25; + + /* Perform the low-level 6pack initialization. */ + if ((err = sp_open(sp->dev))) + return err; + + MOD_INC_USE_COUNT; + + /* Done. We have linked the TTY line to a channel. */ + + tnc_init(sp); + + return sp->dev->base_addr; +} + + +/* + * Close down a 6pack channel. + * This means flushing out any pending queues, and then restoring the + * TTY line discipline to what it was before it got hooked to 6pack + * (which usually is TTY again). + */ +static void +sixpack_close(struct tty_struct *tty) +{ + struct sixpack *sp = (struct sixpack *) tty->disc_data; + + /* First make sure we're connected. */ + if (!sp || sp->magic != SIXPACK_MAGIC) + return; + + rtnl_lock(); + if (sp->dev->flags & IFF_UP) + (void) dev_close(sp->dev); + + del_timer(&(sp->tx_t)); + del_timer(&(sp->resync_t)); + + tty->disc_data = 0; + sp->tty = NULL; + /* VSV = very important to remove timers */ + + sp_free(sp); + unregister_netdev(sp->dev); + rtnl_unlock(); + MOD_DEC_USE_COUNT; +} + + +static struct net_device_stats * +sp_get_stats(struct device *dev) +{ + static struct net_device_stats stats; + struct sixpack *sp = (struct sixpack*)(dev->priv); + + memset(&stats, 0, sizeof(struct net_device_stats)); + + stats.rx_packets = sp->rx_packets; + stats.tx_packets = sp->tx_packets; + stats.rx_bytes = sp->rx_bytes; + stats.tx_bytes = sp->tx_bytes; + stats.rx_dropped = sp->rx_dropped; + stats.tx_dropped = sp->tx_dropped; + stats.tx_errors = sp->tx_errors; + stats.rx_errors = sp->rx_errors; + stats.rx_over_errors = sp->rx_over_errors; + return (&stats); +} + + +int +sp_set_mac_address(struct device *dev, void *addr) +{ + int err; + + err = verify_area(VERIFY_READ, addr, AX25_ADDR_LEN); + if (err) { + return err; + } + + copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN); /* addr is an AX.25 shifted ASCII mac address */ + + return 0; +} + +static int +sp_set_dev_mac_address(struct device *dev, void *addr) +{ + struct sockaddr *sa=addr; + memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN); + return 0; +} + + +/* Perform I/O control on an active 6pack channel. */ +static int +sixpack_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg) +{ + struct sixpack *sp = (struct sixpack *) tty->disc_data; + int err; + unsigned int tmp; + + /* First make sure we're connected. */ + if (!sp || sp->magic != SIXPACK_MAGIC) { + return -EINVAL; + } + + switch(cmd) { + case SIOCGIFNAME: + err = verify_area(VERIFY_WRITE, arg, strlen(sp->dev->name) + 1); + if (err) { + return err; + } + copy_to_user(arg, sp->dev->name, strlen(sp->dev->name) + 1); + return 0; + + case SIOCGIFENCAP: + err = verify_area(VERIFY_WRITE, arg, sizeof(int)); + if (err) { + return err; + } + put_user(0, (int *)arg); + return 0; + + case SIOCSIFENCAP: + err = verify_area(VERIFY_READ, arg, sizeof(int)); + if (err) { + return err; + } + get_user(tmp,(int *)arg); + + sp->mode = tmp; + sp->dev->addr_len = AX25_ADDR_LEN; /* sizeof an AX.25 addr */ + sp->dev->hard_header_len = AX25_KISS_HEADER_LEN + AX25_MAX_HEADER_LEN + 3; + sp->dev->type = ARPHRD_AX25; + + return 0; + + case SIOCSIFHWADDR: + return sp_set_mac_address(sp->dev, arg); + + /* Allow stty to read, but not set, the serial port */ + case TCGETS: + case TCGETA: + return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg); + + default: + return -ENOIOCTLCMD; + } +} + +static int sp_open_dev(struct device *dev) +{ + struct sixpack *sp = (struct sixpack*)(dev->priv); + if(sp->tty==NULL) + return -ENODEV; + return 0; +} + +/* Initialize 6pack control device -- register 6pack line discipline */ + +#ifdef MODULE +static int sixpack_init_ctrl_dev(void) +#else /* !MODULE */ +__initfunc sixpack_init_ctrl_dev(struct device *dummy) +#endif /* !MODULE */ +{ + int status; + + if (sixpack_maxdev < 4) sixpack_maxdev = 4; /* Sanity */ + + printk(KERN_INFO "6pack: %s (dynamic channels, max=%d)\n", + SIXPACK_VERSION, sixpack_maxdev); + + sixpack_ctrls = (sixpack_ctrl_t **) kmalloc(sizeof(void*)*sixpack_maxdev, GFP_KERNEL); + if (sixpack_ctrls == NULL) + { + printk(KERN_WARNING "6pack: Can't allocate sixpack_ctrls[] array! Uaargh! (-> No 6pack available)\n"); + return -ENOMEM; + } + + /* Clear the pointer array, we allocate devices when we need them */ + memset(sixpack_ctrls, 0, sizeof(void*)*sixpack_maxdev); /* Pointers */ + + + /* Fill in our line protocol discipline, and register it */ + memset(&sp_ldisc, 0, sizeof(sp_ldisc)); + sp_ldisc.magic = TTY_LDISC_MAGIC; + sp_ldisc.name = "6pack"; + sp_ldisc.flags = 0; + sp_ldisc.open = sixpack_open; + sp_ldisc.close = sixpack_close; + sp_ldisc.read = NULL; + sp_ldisc.write = NULL; + sp_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, + unsigned int, unsigned long)) sixpack_ioctl; + sp_ldisc.poll = NULL; + sp_ldisc.receive_buf = sixpack_receive_buf; + sp_ldisc.receive_room = sixpack_receive_room; + sp_ldisc.write_wakeup = sixpack_write_wakeup; + if ((status = tty_register_ldisc(N_6PACK, &sp_ldisc)) != 0) { + printk(KERN_WARNING "6pack: can't register line discipline (err = %d)\n", status); + } + +#ifdef MODULE + return status; +#else + /* Return "not found", so that dev_init() will unlink + * the placeholder device entry for us. + */ + return ENODEV; +#endif +} + +/* Initialize the 6pack driver. Called by DDI. */ +int +sixpack_init(struct device *dev) +{ + struct sixpack *sp = (struct sixpack*)(dev->priv); + + static char ax25_bcast[AX25_ADDR_LEN] = + {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; + static char ax25_test[AX25_ADDR_LEN] = + {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; + + if (sp == NULL) /* Allocation failed ?? */ + return -ENODEV; + + /* Set up the "6pack Control Block". (And clear statistics) */ + + memset(sp, 0, sizeof (struct sixpack)); + sp->magic = SIXPACK_MAGIC; + sp->dev = dev; + + /* Finish setting up the DEVICE info. */ + dev->mtu = SIXP_MTU; + dev->hard_start_xmit = sp_xmit; + dev->open = sp_open_dev; + dev->stop = sp_close; + dev->hard_header = sp_header; + dev->get_stats = sp_get_stats; + dev->set_mac_address = sp_set_dev_mac_address; + dev->hard_header_len = AX25_MAX_HEADER_LEN; + dev->addr_len = AX25_ADDR_LEN; + dev->type = ARPHRD_AX25; + dev->tx_queue_len = 10; + dev->rebuild_header = sp_rebuild_header; + + memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); /* Only activated in AX.25 mode */ + memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); /* "" "" "" "" */ + + dev_init_buffers(dev); + + /* New-style flags. */ + dev->flags = 0; + + return 0; +} + +#ifdef MODULE + +int +init_module(void) +{ + return sixpack_init_ctrl_dev(); +} + +void +cleanup_module(void) +{ + int i; + + if (sixpack_ctrls != NULL) + { + for (i = 0; i < sixpack_maxdev; i++) + { + if (sixpack_ctrls[i]) + { + /* + * VSV = if dev->start==0, then device + * unregistered while close proc. + */ + if (sixpack_ctrls[i]->dev.start) + unregister_netdev(&(sixpack_ctrls[i]->dev)); + + kfree(sixpack_ctrls[i]); + sixpack_ctrls[i] = NULL; + } + } + kfree(sixpack_ctrls); + sixpack_ctrls = NULL; + } + if ((i = tty_register_ldisc(N_6PACK, NULL))) + { + printk(KERN_WARNING "6pack: can't unregister line discipline (err = %d)\n", i); + } +} +#endif /* MODULE */ + +/* ----> 6pack timer interrupt handler and friends. <---- */ +static void +sp_start_tx_timer(struct sixpack *sp) +{ + int when = sp->slottime; + + del_timer(&(sp->tx_t)); + sp->tx_t.data = (unsigned long) sp; + sp->tx_t.function = sp_xmit_on_air; + sp->tx_t.expires = jiffies + ((when+1)*HZ)/100; + add_timer(&(sp->tx_t)); +} + + +/* encode an AX.25 packet into 6pack */ + +int encode_sixpack(byte *tx_buf, byte *tx_buf_raw, int length, byte tx_delay) +{ + int count = 0; + byte checksum = 0, buf[400]; + int raw_count = 0; + + tx_buf_raw[raw_count++] = SIXP_PRIO_CMD_MASK | SIXP_TX_MASK; + tx_buf_raw[raw_count++] = SIXP_SEOF; + + buf[0] = tx_delay; + for(count = 1; count < length; count++) + buf[count] = tx_buf[count]; + + for(count = 0; count < length; count++) + checksum += buf[count]; + buf[length] = (byte)0xff - checksum; + + for(count = 0; count <= length; count++) { + if((count % 3) == 0) { + tx_buf_raw[raw_count++] = (buf[count] & 0x3f); + tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x30); + } + else if((count % 3) == 1) { + tx_buf_raw[raw_count++] |= (buf[count] & 0x0f); + tx_buf_raw[raw_count] = + ((buf[count] >> 2) & 0x3c); + } else { + tx_buf_raw[raw_count++] |= (buf[count] & 0x03); + tx_buf_raw[raw_count++] = + (buf[count] >> 2); + } /* else */ + } /* for */ + if ((length % 3) != 2) + raw_count++; + tx_buf_raw[raw_count++] = SIXP_SEOF; + return(raw_count); +} + + +/* decode a 6pack packet */ + +void +sixpack_decode(struct sixpack *sp, unsigned char pre_rbuff[], int count) +{ + byte inbyte; + int count1; + + for (count1 = 0; count1 < count; count1++) { + inbyte = pre_rbuff[count1]; + if (inbyte == SIXP_FOUND_TNC) { + printk(KERN_INFO "6pack: TNC found.\n"); + sp->tnc_ok = 1; + del_timer(&(sp->resync_t)); + } + if((inbyte & SIXP_PRIO_CMD_MASK) != 0) + decode_prio_command(inbyte, sp); + else if((inbyte & SIXP_STD_CMD_MASK) != 0) + decode_std_command(inbyte, sp); + else { + if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK) + decode_data(inbyte, sp); + } /* else */ + } /* for */ +} + +static int +tnc_init(struct sixpack *sp) +{ + static byte inbyte; + + inbyte = 0xe8; + sp->tty->driver.write(sp->tty, 0, &inbyte, 1); + + del_timer(&(sp->resync_t)); + sp->resync_t.data = (unsigned long) sp; + sp->resync_t.function = resync_tnc; + sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT; + add_timer(&(sp->resync_t)); + + return 0; +} + + +/* identify and execute a 6pack priority command byte */ + +void decode_prio_command(byte cmd, struct sixpack *sp) +{ + byte channel; + int actual; + + channel = cmd & SIXP_CHN_MASK; + if ((cmd & SIXP_PRIO_DATA_MASK) != 0) { /* idle ? */ + + /* RX and DCD flags can only be set in the same prio command, + if the DCD flag has been set without the RX flag in the previous + prio command. If DCD has not been set before, something in the + transmission has gone wrong. In this case, RX and DCD are + cleared in order to prevent the decode_data routine from + reading further data that might be corrupt. */ + + if (((sp->status & SIXP_DCD_MASK) == 0) && + ((cmd & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)) { + if (sp->status != 1) + printk(KERN_DEBUG "6pack: protocol violation\n"); + else + sp->status = 0; + cmd &= !SIXP_RX_DCD_MASK; + } + sp->status = cmd & SIXP_PRIO_DATA_MASK; + } /* if */ + else { /* output watchdog char if idle */ + if ((sp->status2 != 0) && (sp->duplex == 1)) { + sp->led_state = 0x70; + sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1); + sp->tx_enable = 1; + actual = sp->tty->driver.write(sp->tty, 0, sp->xbuff, sp->status2); + sp->xleft -= actual; + sp->xhead += actual; + sp->led_state = 0x60; + sp->status2 = 0; + + } /* if */ + } /* else */ + + /* needed to trigger the TNC watchdog */ + sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1); + + /* if the state byte has been received, the TNC is present, + so the resync timer can be reset. */ + + if (sp->tnc_ok == 1) { + del_timer(&(sp->resync_t)); + sp->resync_t.data = (unsigned long) sp; + sp->resync_t.function = resync_tnc; + sp->resync_t.expires = jiffies + SIXP_INIT_RESYNC_TIMEOUT; + add_timer(&(sp->resync_t)); + } + + sp->status1 = cmd & SIXP_PRIO_DATA_MASK; +} + +/* try to resync the TNC. Called by the resync timer defined in + decode_prio_command */ + +static void +resync_tnc(unsigned long channel) +{ + static char resync_cmd = 0xe8; + struct sixpack *sp = (struct sixpack *) channel; + + printk(KERN_INFO "6pack: resyncing TNC\n"); + + /* clear any data that might have been received */ + + sp->rx_count = 0; + sp->rx_count_cooked = 0; + + /* reset state machine */ + + sp->status = 1; + sp->status1 = 1; + sp->status2 = 0; + sp->tnc_ok = 0; + + /* resync the TNC */ + + sp->led_state = 0x60; + sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1); + sp->tty->driver.write(sp->tty, 0, &resync_cmd, 1); + + + /* Start resync timer again -- the TNC might be still absent */ + + del_timer(&(sp->resync_t)); + sp->resync_t.data = (unsigned long) sp; + sp->resync_t.function = resync_tnc; + sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT; + add_timer(&(sp->resync_t)); +} + + + +/* identify and execute a standard 6pack command byte */ + +void decode_std_command(byte cmd, struct sixpack *sp) +{ + byte checksum = 0, rest = 0, channel; + short i; + + channel = cmd & SIXP_CHN_MASK; + switch(cmd & SIXP_CMD_MASK) { /* normal command */ + case SIXP_SEOF: + if ((sp->rx_count == 0) && (sp->rx_count_cooked == 0)) { + if ((sp->status & SIXP_RX_DCD_MASK) == + SIXP_RX_DCD_MASK) { + sp->led_state = 0x68; + sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1); + } /* if */ + } else { + sp->led_state = 0x60; + /* fill trailing bytes with zeroes */ + sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1); + rest = sp->rx_count; + if (rest != 0) + for(i=rest; i<=3; i++) + decode_data(0, sp); + if (rest == 2) + sp->rx_count_cooked -= 2; + else if (rest == 3) + sp->rx_count_cooked -= 1; + for (i=0; i<sp->rx_count_cooked; i++) + checksum+=sp->cooked_buf[i]; + if (checksum != SIXP_CHKSUM) { + printk(KERN_DEBUG "6pack: bad checksum %2.2x\n", checksum); + } else { + sp->rcount = sp->rx_count_cooked-2; + sp_bump(sp, 0); + } /* else */ + sp->rx_count_cooked = 0; + } /* else */ + break; + case SIXP_TX_URUN: printk(KERN_DEBUG "6pack: TX underrun\n"); + break; + case SIXP_RX_ORUN: printk(KERN_DEBUG "6pack: RX overrun\n"); + break; + case SIXP_RX_BUF_OVL: + printk(KERN_DEBUG "6pack: RX buffer overflow\n"); + } /* switch */ +} /* function */ + +/* decode 4 sixpack-encoded bytes into 3 data bytes */ + +void decode_data(byte inbyte, struct sixpack *sp) +{ + + unsigned char *buf; + + if (sp->rx_count != 3) + sp->raw_buf[sp->rx_count++] = inbyte; + else { + buf = sp->raw_buf; + sp->cooked_buf[sp->rx_count_cooked++] = + buf[0] | ((buf[1] << 2) & 0xc0); + sp->cooked_buf[sp->rx_count_cooked++] = + (buf[1] & 0x0f) | ((buf[2] << 2) & 0xf0); + sp->cooked_buf[sp->rx_count_cooked++] = + (buf[2] & 0x03) | (inbyte << 2); + sp->rx_count = 0; + } +} diff --git a/drivers/net/hamradio/6pack.h b/drivers/net/hamradio/6pack.h new file mode 100644 index 000000000..a5fe532f3 --- /dev/null +++ b/drivers/net/hamradio/6pack.h @@ -0,0 +1,135 @@ +/* + * 6pack.h Define the 6pack device driver interface and constants. + * + * NOTE: THIS FILE WILL BE MOVED TO THE LINUX INCLUDE DIRECTORY + * AS SOON AS POSSIBLE! + * + * Version: @(#)6pack.h 0.3.0 04/07/98 + * + * Fixes: + * + * Author: Andreas Könsgen <ajk@iehk.rwth-aachen.de> + * + * This file is derived from slip.h, written by + * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> + */ + +#ifndef _LINUX_6PACK_H +#define _LINUX_6PACK_H + +#define SIXPACK_VERSION "Revision: 0.3.0" + +#ifdef __KERNEL__ + +/* sixpack priority commands */ +#define SIXP_SEOF 0x40 /* start and end of a 6pack frame */ +#define SIXP_TX_URUN 0x48 /* transmit overrun */ +#define SIXP_RX_ORUN 0x50 /* receive overrun */ +#define SIXP_RX_BUF_OVL 0x58 /* receive buffer overflow */ + +#define SIXP_CHKSUM 0xFF /* valid checksum of a 6pack frame */ + +/* masks to get certain bits out of the status bytes sent by the TNC */ + +#define SIXP_CMD_MASK 0xC0 +#define SIXP_CHN_MASK 0x07 +#define SIXP_PRIO_CMD_MASK 0x80 +#define SIXP_STD_CMD_MASK 0x40 +#define SIXP_PRIO_DATA_MASK 0x38 +#define SIXP_TX_MASK 0x20 +#define SIXP_RX_MASK 0x10 +#define SIXP_RX_DCD_MASK 0x18 +#define SIXP_LEDS_ON 0x78 +#define SIXP_LEDS_OFF 0x60 +#define SIXP_CON 0x08 +#define SIXP_STA 0x10 + +#define SIXP_FOUND_TNC 0xe9 +#define SIXP_CON_ON 0x68 +#define SIXP_DCD_MASK 0x08 +#define SIXP_DAMA_OFF 0 + +/* default level 2 parameters */ +#define SIXP_TXDELAY 25 /* in 10 ms */ +#define SIXP_PERSIST 50 /* in 256ths */ +#define SIXP_SLOTTIME 10 /* in 10 ms */ +#define SIXP_INIT_RESYNC_TIMEOUT 150 /* in 10 ms */ +#define SIXP_RESYNC_TIMEOUT 500 /* in 10 ms */ + +/* 6pack configuration. */ +#define SIXP_NRUNIT 256 /* MAX number of 6pack channels */ +#define SIXP_MTU 256 /* Default MTU */ + +enum sixpack_flags { + SIXPF_INUSE, /* Channel in use */ + SIXPF_ERROR, /* Parity, etc. error */ +}; + +struct sixpack { + int magic; + + /* Various fields. */ + struct tty_struct *tty; /* ptr to TTY structure */ + struct device *dev; /* easy for intr handling */ + + /* These are pointers to the malloc()ed frame buffers. */ + unsigned char *rbuff; /* receiver buffer */ + int rcount; /* received chars counter */ + unsigned char *xbuff; /* transmitter buffer */ + unsigned char *xhead; /* pointer to next byte to XMIT */ + int xleft; /* bytes left in XMIT queue */ + + unsigned char raw_buf[4]; + unsigned char cooked_buf[400]; + + unsigned int rx_count; + unsigned int rx_count_cooked; + + /* 6pack interface statistics. */ + unsigned long rx_packets; /* inbound frames counter */ + unsigned long tx_packets; /* outbound frames counter */ + unsigned long rx_bytes; /* inbound bytes counter */ + unsigned long tx_bytes; /* outboud bytes counter */ + unsigned long rx_errors; /* Parity, etc. errors */ + unsigned long tx_errors; /* Planned stuff */ + unsigned long rx_dropped; /* No memory for skb */ + unsigned long tx_dropped; /* When MTU change */ + unsigned long rx_over_errors; /* Frame bigger then 6pack buf. */ + + /* Detailed 6pack statistics. */ + + int mtu; /* Our mtu (to spot changes!) */ + int buffsize; /* Max buffers sizes */ + + unsigned char flags; /* Flag values/ mode etc */ + unsigned char mode; /* 6pack mode */ + +/* 6pack stuff */ + + unsigned char tx_delay; + unsigned char persistance; + unsigned char slottime; + unsigned char duplex; + unsigned char led_state; + unsigned char status; + unsigned char status1; + unsigned char status2; + unsigned char tx_enable; + unsigned char tnc_ok; + +/* unsigned char retval; */ + + struct timer_list tx_t; + struct timer_list resync_t; +}; /* struct sixpack */ + + +/* should later be moved to include/net/ax25.h */ +#define AX25_6PACK_HEADER_LEN 0 +#define SIXPACK_MAGIC 0x5304 + +extern int sixpack_init(struct device *dev); + +#endif + +#endif /* _LINUX_6PACK.H */ diff --git a/drivers/net/hamradio/Config.in b/drivers/net/hamradio/Config.in index c0719608a..29e182fe9 100644 --- a/drivers/net/hamradio/Config.in +++ b/drivers/net/hamradio/Config.in @@ -1,7 +1,7 @@ comment 'AX.25 network device drivers' dep_tristate 'Serial port KISS driver' CONFIG_MKISS $CONFIG_AX25 -# dep_tristate 'Serial port 6PACK driver' CONFIG_6PACK $CONFIG_AX25 +dep_tristate 'Serial port 6PACK driver' CONFIG_6PACK $CONFIG_AX25 dep_tristate 'BPQ Ethernet driver' CONFIG_BPQETHER $CONFIG_AX25 dep_tristate 'High-speed (DMA) SCC driver for AX.25' CONFIG_DMASCC $CONFIG_AX25 diff --git a/drivers/net/hamradio/Makefile b/drivers/net/hamradio/Makefile index c247cee79..07e2aade5 100644 --- a/drivers/net/hamradio/Makefile +++ b/drivers/net/hamradio/Makefile @@ -45,6 +45,14 @@ else endif endif +ifeq ($(CONFIG_6PACK),y) +L_OBJS += 6pack.o +else + ifeq ($(CONFIG_6PACK),m) + M_OBJS += 6pack.o + endif +endif + ifeq ($(CONFIG_PI),y) L_OBJS += pi2.o else diff --git a/drivers/net/hamradio/soundmodem/gentbl.c b/drivers/net/hamradio/soundmodem/gentbl.c index 3f507d248..e67733831 100644 --- a/drivers/net/hamradio/soundmodem/gentbl.c +++ b/drivers/net/hamradio/soundmodem/gentbl.c @@ -681,7 +681,7 @@ int main(int argc, char *argv[]) gentbl_costab(f, 6); gentbl_afsk2400(f, 7372800); fclose(f); - return(0); + exit(0); } diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 0f1bdd3c7..bd97a51b3 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -2,7 +2,7 @@ ** hp100.c ** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters ** -** $Id: hp100.c,v 1.56 1998/03/04 15:23:59 perex Exp perex $ +** $Id: hp100.c,v 1.57 1998/04/10 16:27:23 perex Exp perex $ ** ** Based on the HP100 driver written by Jaroslav Kysela <perex@jcu.cz> ** Extended for new busmaster capable chipsets by @@ -31,10 +31,23 @@ ** - some updates for EISA version of card ** ** -** This source/code is public free; you can distribute it and/or modify -** it under terms of the GNU General Public License (published by the -** Free Software Foundation) either version two of this License, or any -** later version. +** This code 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. +** +** This code is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +** +** 1.56 -> 1.57 +** - updates for new PCI interface for 2.1 kernels ** ** 1.55 -> 1.56 ** - removed printk in misc. interrupt and update statistics to allow @@ -83,7 +96,6 @@ #include <linux/malloc.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/bios32.h> #include <asm/bitops.h> #include <asm/io.h> @@ -95,13 +107,15 @@ #include <linux/config.h> /* for CONFIG_PCI */ #include <linux/delay.h> -#if LINUX_VERSION_CODE < 0x020100 +#if LINUX_VERSION_CODE >= 0x020100 +#define LINUX_2_1 +typedef struct net_device_stats hp100_stats_t; +EXPORT_NO_SYMBOLS; +#else +#include <linux/bios32.h> #define ioremap vremap #define iounmap vfree typedef struct enet_statistics hp100_stats_t; -#else -#define LINUX_2_1 -typedef struct net_device_stats hp100_stats_t; #endif #ifndef __initfunc @@ -136,14 +150,14 @@ typedef struct net_device_stats hp100_stats_t; #define PCI_DEVICE_ID_COMPEX2_100VG 0x0005 #endif -#define HP100_REGION_SIZE 0x20 /* for ioports */ +#define HP100_REGION_SIZE 0x20 /* for ioports */ -#define HP100_MAX_PACKET_SIZE (1536+4) -#define HP100_MIN_PACKET_SIZE 60 +#define HP100_MAX_PACKET_SIZE (1536+4) +#define HP100_MIN_PACKET_SIZE 60 #ifndef HP100_DEFAULT_RX_RATIO /* default - 75% onboard memory on the card are used for RX packets */ -#define HP100_DEFAULT_RX_RATIO 75 +#define HP100_DEFAULT_RX_RATIO 75 #endif #ifndef HP100_DEFAULT_PRIORITY_TX @@ -176,8 +190,12 @@ struct hp100_private { u_short priority_tx; /* != 0 - priority tx */ u_short mode; /* PIO, Shared Mem or Busmaster */ u_char bus; +#ifndef LINUX_2_1 u_char pci_bus; u_char pci_device_fn; +#else + struct pci_dev *pci_dev; +#endif short mem_mapped; /* memory mapped access */ u_int *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */ u_int *mem_ptr_phys; /* physical memory mapped area */ @@ -282,7 +300,11 @@ MODULE_PARM( hp100_mode, "1i" ); * prototypes */ -static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn ); +#ifdef LINUX_2_1 +static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, struct pci_dev *pci_dev ); +#else +static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn ); +#endif static int hp100_open( struct device *dev ); static int hp100_close( struct device *dev ); static int hp100_start_xmit( struct sk_buff *skb, struct device *dev ); @@ -342,12 +364,24 @@ __initfunc(int hp100_probe( struct device *dev )) { if ( check_region( base_addr, HP100_REGION_SIZE ) ) return -EINVAL; if ( base_addr < 0x400 ) +#ifdef LINUX_2_1 + return hp100_probe1( dev, base_addr, HP100_BUS_ISA, NULL ); +#else return hp100_probe1( dev, base_addr, HP100_BUS_ISA, 0, 0 ); +#endif if ( EISA_bus && base_addr >= 0x1c38 && ( (base_addr - 0x1c38) & 0x3ff ) == 0 ) +#ifdef LINUX_2_1 + return hp100_probe1( dev, base_addr, HP100_BUS_EISA, NULL ); +#else return hp100_probe1( dev, base_addr, HP100_BUS_EISA, 0, 0 ); +#endif #ifdef CONFIG_PCI +#ifdef LINUX_2_1 + printk( "hp100: %s: You must specify card # in i/o address parameter for PCI bus...", dev->name ); +#else printk( "hp100: %s: You may specify card # in i/o address parameter for PCI bus...", dev->name ); return hp100_probe1( dev, base_addr, HP100_BUS_PCI, 0, 0 ); +#endif #else return -ENODEV; #endif @@ -366,10 +400,51 @@ __initfunc(int hp100_probe( struct device *dev )) if ( pcibios_present() ) { int pci_index; +#ifdef LINUX_2_1 + struct pci_dev *pci_dev = NULL; + int pci_id_index; + u_short pci_command; +#endif #ifdef HP100_DEBUG_PCI printk( "hp100: %s: PCI BIOS is present, checking for devices..\n", dev->name ); #endif +#ifdef LINUX_2_1 + pci_index = 0; + for ( pci_id_index = 0; pci_id_index < HP100_PCI_IDS_SIZE; pci_id_index++ ) { + while ( (pci_dev = pci_find_device( hp100_pci_ids[ pci_id_index ].vendor, + hp100_pci_ids[ pci_id_index ].device, + pci_dev )) != NULL ) { + if ( pci_index < (pci_start_index & 7) ) { + pci_index++; + continue; + } + /* found... */ + ioaddr = pci_dev -> base_address[ 0 ] & ~3; + if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; + pci_read_config_word( pci_dev, PCI_COMMAND, &pci_command ); + if ( !( pci_command & PCI_COMMAND_IO ) ) { +#ifdef HP100_DEBUG + printk( "hp100: %s: PCI I/O Bit has not been set. Setting...\n", dev->name ); +#endif + pci_command |= PCI_COMMAND_IO; + pci_write_config_word( pci_dev, PCI_COMMAND, pci_command ); + } + if ( !( pci_command & PCI_COMMAND_MASTER ) ) { +#ifdef HP100_DEBUG + printk( "hp100: %s: PCI Master Bit has not been set. Setting...\n", dev->name ); +#endif + pci_command |= PCI_COMMAND_MASTER; + pci_write_config_word( pci_dev, PCI_COMMAND, pci_command ); + } +#ifdef HP100_DEBUG + printk( "hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr ); +#endif + if ( hp100_probe1( dev, ioaddr, HP100_BUS_PCI, pci_dev ) == 0 ) + return 0; + } + } +#else /* old PCI interface */ for ( pci_index = pci_start_index & 7; pci_index < 8; pci_index++ ) { u_char pci_bus, pci_device_fn; @@ -417,6 +492,7 @@ __initfunc(int hp100_probe( struct device *dev )) if ( hp100_probe1( dev, ioaddr, HP100_BUS_PCI, pci_bus, pci_device_fn ) == 0 ) return 0; } +#endif } if ( pci_start_index > 0 ) return -ENODEV; #endif /* CONFIG_PCI */ @@ -425,21 +501,33 @@ __initfunc(int hp100_probe( struct device *dev )) for ( ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400 ) { if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; +#ifdef LINUX_2_1 + if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA, NULL ) == 0 ) return 0; +#else if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA, 0, 0 ) == 0 ) return 0; +#endif } /* Third Probe all ISA possible port regions */ for ( ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20 ) { if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; +#ifdef LINUX_2_1 + if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA, NULL ) == 0 ) return 0; +#else if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA, 0, 0 ) == 0 ) return 0; +#endif } return -ENODEV; } +#ifdef LINUX_2_1 +__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, struct pci_dev *pci_dev )) +#else __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn )) +#endif { int i; @@ -703,15 +791,19 @@ __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, /* Initialise the "private" data structure for this card. */ if ( (dev->priv=kmalloc(sizeof(struct hp100_private), GFP_KERNEL)) == NULL) return -ENOMEM; - memset( dev->priv, 0, sizeof(struct hp100_private) ); lp = (struct hp100_private *)dev->priv; + memset( lp, 0, sizeof( struct hp100_private ) ); lp->id = eid; lp->chip = chip; lp->mode = local_mode; - lp->pci_bus = pci_bus; lp->bus = bus; +#ifdef LINUX_2_1 + lp->pci_dev = pci_dev; +#else + lp->pci_bus = pci_bus; lp->pci_device_fn = pci_device_fn; +#endif lp->priority_tx = hp100_priority_tx; lp->rx_ratio = hp100_rx_ratio; lp->mem_ptr_phys = mem_ptr_phys; @@ -743,10 +835,18 @@ __initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, dev->set_multicast_list = &hp100_set_multicast_list; /* Ask the card for which IRQ line it is configured */ - hp100_page( HW_MAP ); - dev->irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQMASK; - if ( dev->irq == 2 ) - dev->irq = 9; +#ifdef LINUX_2_1 + if ( bus == HP100_BUS_PCI ) { + dev->irq = pci_dev->irq; + } else { +#endif + hp100_page( HW_MAP ); + dev->irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQMASK; + if ( dev->irq == 2 ) + dev->irq = 9; +#ifdef LINUX_2_1 + } +#endif if(lp->mode==1) /* busmaster */ dev->dma=4; diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 423b4a7ac..367654ea3 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -45,7 +45,6 @@ static const char *version = "lance.c:v1.09 Aug 20 1996 dplatt@3do.com, becker@c #include <linux/malloc.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/bios32.h> #include <linux/init.h> #include <asm/bitops.h> #include <asm/io.h> @@ -285,7 +284,7 @@ static struct lance_chip_type { enum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ISAP=2, PCNET_PCI=3, PCNET_VLB=4, PCNET_PCI_II=5, LANCE_UNKNOWN=6}; /* Non-zero only if the current card is a PCI with BIOS-set IRQ. */ -static unsigned char pci_irq_line = 0; +static unsigned int pci_irq_line = 0; /* Non-zero if lance_probe1() needs to allocate low-memory bounce buffers. Assume yes until we know the memory size. */ @@ -317,36 +316,26 @@ __initfunc(int lance_init(void)) lance_need_isa_bounce_buffers = 0; #if defined(CONFIG_PCI) && !defined(CONFIG_PCNET32) - if (pcibios_present()) { - int pci_index; + if (pci_present()) { + struct pci_dev *pdev = NULL; if (lance_debug > 1) - printk("lance.c: PCI bios is present, checking for devices...\n"); - for (pci_index = 0; pci_index < 8; pci_index++) { + printk("lance.c: PCI is present, checking for devices...\n"); + while (pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev)) { unsigned char pci_bus, pci_device_fn; unsigned int pci_ioaddr; unsigned short pci_command; - if (pcibios_find_device (PCI_VENDOR_ID_AMD, - PCI_DEVICE_ID_AMD_LANCE, pci_index, - &pci_bus, &pci_device_fn) != 0) - break; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &pci_ioaddr); - /* Remove I/O space marker in bit 0. */ - pci_ioaddr &= ~3; + pci_irq_line = pdev->irq; + pci_ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; /* PCI Spec 2.1 states that it is either the driver or PCI card's * responsibility to set the PCI Master Enable Bit if needed. * (From Mark Stockton <marks@schooner.sys.hou.compaq.com>) */ - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); if ( ! (pci_command & PCI_COMMAND_MASTER)) { printk("PCI Master Bit has not been set. Setting...\n"); pci_command |= PCI_COMMAND_MASTER; - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, pci_command); + pci_write_config_word(pdev, PCI_COMMAND, pci_command); } printk("Found PCnet/PCI at %#x, irq %d.\n", pci_ioaddr, pci_irq_line); diff --git a/drivers/net/mace.c b/drivers/net/mace.c index cf1e9e903..ea836aaa0 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -13,6 +13,7 @@ #include <asm/prom.h> #include <asm/dbdma.h> #include <asm/io.h> +#include <asm/pgtable.h> #include "mace.h" #define N_RX_RING 8 @@ -117,21 +118,22 @@ mace_probe(struct device *dev) mp = (struct mace_data *) dev->priv; dev->base_addr = maces->addrs[0].address; - mp->mace = (volatile struct mace *) maces->addrs[0].address; - dev->irq = maces->intrs[0]; + mp->mace = (volatile struct mace *) + ioremap(maces->addrs[0].address, 0x1000); + dev->irq = maces->intrs[0].line; if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) { printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq); return -EAGAIN; } - if (request_irq(maces->intrs[1], mace_txdma_intr, 0, "MACE-txdma", + if (request_irq(maces->intrs[1].line, mace_txdma_intr, 0, "MACE-txdma", dev)) { - printk(KERN_ERR "MACE: can't get irq %d\n", maces->intrs[1]); + printk(KERN_ERR "MACE: can't get irq %d\n", maces->intrs[1].line); return -EAGAIN; } - if (request_irq(maces->intrs[2], mace_rxdma_intr, 0, "MACE-rxdma", + if (request_irq(maces->intrs[2].line, mace_rxdma_intr, 0, "MACE-rxdma", dev)) { - printk(KERN_ERR "MACE: can't get irq %d\n", maces->intrs[2]); + printk(KERN_ERR "MACE: can't get irq %d\n", maces->intrs[2].line); return -EAGAIN; } @@ -155,10 +157,12 @@ mace_probe(struct device *dev) mp = (struct mace_data *) dev->priv; mp->maccc = ENXMT | ENRCV; - mp->tx_dma = (volatile struct dbdma_regs *) maces->addrs[1].address; - mp->tx_dma_intr = maces->intrs[1]; - mp->rx_dma = (volatile struct dbdma_regs *) maces->addrs[2].address; - mp->rx_dma_intr = maces->intrs[2]; + mp->tx_dma = (volatile struct dbdma_regs *) + ioremap(maces->addrs[1].address, 0x1000); + mp->tx_dma_intr = maces->intrs[1].line; + mp->rx_dma = (volatile struct dbdma_regs *) + ioremap(maces->addrs[2].address, 0x1000); + mp->rx_dma_intr = maces->intrs[2].line; mp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(mp + 1); mp->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1; @@ -169,8 +173,6 @@ mace_probe(struct device *dev) init_timer(&mp->tx_timeout); mp->timeout_active = 0; - mace_reset(dev); - dev->open = mace_open; dev->stop = mace_close; dev->hard_start_xmit = mace_xmit_start; @@ -260,6 +262,9 @@ static int mace_open(struct device *dev) struct sk_buff *skb; unsigned char *data; + /* reset the chip */ + mace_reset(dev); + /* initialize list of sk_buffs for receiving and set up recv dma */ memset((char *)mp->rx_cmds, 0, N_RX_RING * sizeof(struct dbdma_cmd)); cp = mp->rx_cmds; @@ -410,6 +415,10 @@ static int mace_xmit_start(struct sk_buff *skb, struct device *dev) ++mp->tx_active; mace_set_timeout(dev); } + if (++next >= N_TX_RING) + next = 0; + if (next == mp->tx_empty) + dev->tbusy = 1; restore_flags(flags); return 0; @@ -520,6 +529,8 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) i = mp->tx_empty; while (mb->pr & XMTSV) { + del_timer(&mp->tx_timeout); + mp->timeout_active = 0; /* * Clear any interrupt indication associated with this status * word. This appears to unlatch any error indication from @@ -533,8 +544,6 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) eieio(); mp->tx_bad_runt = 0; mb->xmtfc = AUTO_PAD_XMIT; - del_timer(&mp->tx_timeout); - mp->timeout_active = 0; continue; } dstat = ld_le32(&td->status); @@ -562,7 +571,8 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) } fs = mb->xmtfs; if ((fs & XMTSV) == 0) { - printk(KERN_ERR "mace: xmtfs not valid! (fs=%x xc=%d ds=%x)\n", fs, xcount, dstat); + printk(KERN_ERR "mace: xmtfs not valid! (fs=%x xc=%d ds=%x)\n", + fs, xcount, dstat); } cp = mp->tx_cmds + NCMDS_TX * i; stat = ld_le16(&cp->xfer_status); @@ -571,6 +581,7 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) * Check whether there were in fact 2 bytes written to * the transmit FIFO. */ + udelay(1); x = (mb->fifofc >> XMTFC_SH) & XMTFC_MASK; if (x != 0) { /* there were two bytes with an end-of-packet indication */ @@ -579,17 +590,21 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) } else { /* * Either there weren't the two bytes buffered up, or they - * didn't have an end-of-packet indication. Maybe we ought - * to flush the transmit FIFO just in case (by setting the + * didn't have an end-of-packet indication. + * We flush the transmit FIFO just in case (by setting the * XMTFWU bit with the transmitter disabled). */ - mb->xmtfc = AUTO_PAD_XMIT; - eieio(); + out_8(&mb->maccc, mb->maccc & ~ENXMT); + out_8(&mb->fifocc, mb->fifocc | XMTFWU); + udelay(1); + out_8(&mb->maccc, mb->maccc | ENXMT); + out_8(&mb->xmtfc, AUTO_PAD_XMIT); } } /* dma should have finished */ if (i == mp->tx_fill) { - printk(KERN_DEBUG "mace: tx ring ran out? (fs=%x xc=%d ds=%x)\n", fs, xcount, dstat); + printk(KERN_DEBUG "mace: tx ring ran out? (fs=%x xc=%d ds=%x)\n", + fs, xcount, dstat); continue; } /* Update stats */ @@ -607,11 +622,9 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) i = 0; mace_last_fs = fs; mace_last_xcount = xcount; - del_timer(&mp->tx_timeout); - mp->timeout_active = 0; } - if (i != mp->tx_empty && mp->tx_fullup) { + if (i != mp->tx_empty) { mp->tx_fullup = 0; dev->tbusy = 0; mark_bh(NET_BH); @@ -656,9 +669,6 @@ static void mace_tx_timeout(unsigned long data) mace_handle_misc_intrs(mp, mb->ir); cp = mp->tx_cmds + NCMDS_TX * mp->tx_empty; - printk(KERN_DEBUG "mace: tx dmastat=%x %x bad_runt=%d pr=%x fs=%x fc=%x\n", - ld_le32(&td->status), ld_le16(&cp->xfer_status), mp->tx_bad_runt, - mb->pr, mb->xmtfs, mb->fifofc); /* turn off both tx and rx and reset the chip */ mb->maccc = 0; @@ -685,11 +695,9 @@ static void mace_tx_timeout(unsigned long data) i = 0; mp->tx_empty = i; } - if (mp->tx_fullup) { - mp->tx_fullup = 0; - dev->tbusy = 0; - mark_bh(NET_BH); - } + mp->tx_fullup = 0; + dev->tbusy = 0; + mark_bh(NET_BH); if (i != mp->tx_fill) { cp = mp->tx_cmds + NCMDS_TX * i; out_le16(&cp->xfer_status, 0); diff --git a/drivers/net/mace.h b/drivers/net/mace.h index a397c83b4..30b7ec0ce 100644 --- a/drivers/net/mace.h +++ b/drivers/net/mace.h @@ -164,7 +164,7 @@ struct mace { /* Bits in UTR */ #define RTRE 0x80 /* reserved test register enable. DON'T SET. */ #define RTRD 0x40 /* reserved test register disable. Sticky */ -#define RPA 0x20 /* accept runt packets */ +#define RPAC 0x20 /* accept runt packets */ #define FCOLL 0x10 /* force collision */ #define RCVFCSE 0x08 /* receive FCS enable */ #define LOOP_NONE 0x00 /* no loopback */ diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 87b808754..10cf51941 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -40,7 +40,6 @@ static const char *version = #include <linux/sched.h> #include <linux/errno.h> #include <linux/pci.h> -#include <linux/bios32.h> #include <linux/init.h> #include <linux/delay.h> #include <asm/system.h> @@ -117,7 +116,7 @@ bad_clone_list[] __initdata = { #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ /* Non-zero only if the current card is a PCI with BIOS-set IRQ. */ -static unsigned char pci_irq_line = 0; +static unsigned int pci_irq_line = 0; int ne_probe(struct device *dev); static int ne_probe1(struct device *dev, int ioaddr); @@ -182,7 +181,7 @@ __initfunc(int ne_probe(struct device *dev)) #ifdef CONFIG_PCI /* Then look for any installed PCI clones */ - if (pcibios_present() && (ne_probe_pci(dev) == 0)) + if (pci_present() && (ne_probe_pci(dev) == 0)) return 0; #endif @@ -207,27 +206,19 @@ __initfunc(static int ne_probe_pci(struct device *dev)) int i; for (i = 0; pci_clone_list[i].vendor != 0; i++) { - unsigned char pci_bus, pci_device_fn; + struct pci_dev *pdev = NULL; unsigned int pci_ioaddr; - int pci_index; - - for (pci_index = 0; pci_index < 8; pci_index++) { - if (pcibios_find_device (pci_clone_list[i].vendor, - pci_clone_list[i].dev_id, pci_index, - &pci_bus, &pci_device_fn) != 0) - break; /* No more of these type of cards */ - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &pci_ioaddr); - /* Strip the I/O address out of the returned value */ - pci_ioaddr &= PCI_BASE_ADDRESS_IO_MASK; + + while ((pdev = pci_find_device(pci_clone_list[i].vendor, pci_clone_list[i].dev_id, pdev))) { + pci_ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; /* Avoid already found cards from previous calls */ if (check_region(pci_ioaddr, NE_IO_EXTENT)) continue; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); - break; /* Beauty -- got a valid card. */ + pci_irq_line = pdev->irq; + if (pci_irq_line) break; /* Found it */ } - if (pci_irq_line == 0) continue; /* Try next PCI ID */ + if (!pdev) + continue; printk("ne.c: PCI BIOS reports %s at i/o %#x, irq %d.\n", pci_clone_list[i].name, pci_ioaddr, pci_irq_line); diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 391714567..57d8cef9e 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -25,7 +25,6 @@ static const char *version = "pcnet32.c:v0.23 8.2.97 tsbogend@alpha.franken.de\n #include <linux/malloc.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/bios32.h> #include <linux/init.h> #include <asm/bitops.h> #ifdef __mips__ @@ -83,7 +82,7 @@ static int pcnet32_debug = 1; * in arch/i386/bios32.c * v0.21: added endian conversion for ppc, from work by cort@cs.nmt.edu * v0.22: added printing of status to ring dump - * v0.23: changed enet_statistics to net_devive_stats + * v0.23: changed enet_statistics to net_device_stats */ @@ -177,7 +176,7 @@ static void pcnet32_set_multicast_list(struct device *dev); __initfunc(int pcnet32_probe (struct device *dev)) { unsigned int ioaddr = dev ? dev->base_addr: 0; - unsigned char irq_line = dev ? dev->irq : 0; + unsigned int irq_line = dev ? dev->irq : 0; int *port; if (ioaddr > 0x1ff) @@ -186,30 +185,20 @@ __initfunc(int pcnet32_probe (struct device *dev)) return ENXIO; #if defined(CONFIG_PCI) - if (pcibios_present()) { - int pci_index; + if (pci_present()) { + struct pci_dev *pdev = NULL; printk("pcnet32.c: PCI bios is present, checking for devices...\n"); - for (pci_index = 0; pci_index < 8; pci_index++) { - unsigned char pci_bus, pci_device_fn; + while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev))) { unsigned short pci_command; - if (pcibios_find_device (PCI_VENDOR_ID_AMD, - PCI_DEVICE_ID_AMD_LANCE, pci_index, - &pci_bus, &pci_device_fn) != 0) - break; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &irq_line); - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &ioaddr); - /* Remove I/O space marker in bit 0. */ - ioaddr &= ~3; + irq_line = pdev->irq; + ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; /* PCI Spec 2.1 states that it is either the driver or PCI card's * responsibility to set the PCI Master Enable Bit if needed. * (From Mark Stockton <marks@schooner.sys.hou.compaq.com>) */ - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); /* Avoid already found cards from previous pcnet32_probe() calls */ if (check_region(ioaddr, PCNET32_TOTAL_SIZE)) @@ -218,8 +207,7 @@ __initfunc(int pcnet32_probe (struct device *dev)) if ( ! (pci_command & PCI_COMMAND_MASTER)) { printk("PCI Master Bit has not been set. Setting...\n"); pci_command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO; - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, pci_command); + pci_write_config_word(pdev, PCI_COMMAND, pci_command); } #ifdef __powerpc__ irq_line = 15; diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c index de70cd001..4db4094e2 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -8,7 +8,7 @@ * Dynamic PPP devices by Jim Freeman <jfree@caldera.com>. * ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se> * - * ==FILEVERSION 980123== + * ==FILEVERSION 980319== * * NOTE TO MAINTAINERS: * If you modify this file at all, please set the number above to the @@ -1326,6 +1326,10 @@ ppp_doframe (struct ppp *ppp) (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state, data, count); } + } else if (proto == PPP_COMP && (ppp->flags & SC_DEBUG)) { + printk(KERN_DEBUG "ppp: frame not decompressed: " + "flags=%x, count=%d, sc_rc_state=%p\n", + ppp->flags, count, ppp->sc_rc_state); } /* * Process the uncompressed frame. @@ -1659,6 +1663,9 @@ static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd) } break; } + if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "ppp_proto_ccp: %s code %d, flags=%x\n", + (rcvd? "rcvd": "sent"), CCP_CODE(dp), ppp->flags); restore_flags(flags); } @@ -1977,16 +1984,15 @@ ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf, (control == PPP_UI) && (proto != PPP_LCP) && (proto != PPP_CCP)) { - new_data = kmalloc (ppp->mtu, GFP_ATOMIC); + new_data = kmalloc (ppp->mtu + PPP_HDRLEN, GFP_ATOMIC); if (new_data == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_dev_xmit_frame: no memory\n"); + printk (KERN_ERR "ppp_dev_xmit_frame: no memory\n"); return 1; } new_count = (*ppp->sc_xcomp->compress) - (ppp->sc_xc_state, data, new_data, count, ppp->mtu); + (ppp->sc_xc_state, data, new_data, count, + ppp->mtu + PPP_HDRLEN); if (new_count > 0 && (ppp->flags & SC_CCP_UP)) { ppp_dev_xmit_lower (ppp, buf, new_data, new_count, 0); @@ -2153,7 +2159,7 @@ out: } /* - * Process the BSD compression IOCTL event for the tty device. + * Process the set-compression ioctl. */ static int @@ -2187,7 +2193,7 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp) save_flags(flags); cli(); - ppp->flags &= ~(SC_COMP_RUN | SC_DECOMP_RUN); + ppp->flags &= ~(data.transmit? SC_COMP_RUN: SC_DECOMP_RUN); restore_flags(flags); cp = find_compressor (ccp_option[0]); @@ -2257,8 +2263,9 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file, unsigned int param2, unsigned long param3) { struct ppp *ppp = tty2ppp (tty); - register int temp_i = 0; + register int temp_i = 0, oldflags; int error = 0; + unsigned long flags; /* * Verify the status of the PPP device. */ @@ -2308,16 +2315,18 @@ ppp_tty_ioctl (struct tty_struct *tty, struct file * file, if (error != 0) break; temp_i &= SC_MASK; - temp_i |= (ppp->flags & ~SC_MASK); - if ((ppp->flags & SC_CCP_OPEN) && - (temp_i & SC_CCP_OPEN) == 0) - ppp_ccp_closed (ppp); + if ((ppp->flags & SC_CCP_OPEN) && (temp_i & SC_CCP_OPEN) == 0) + ppp_ccp_closed(ppp); - if ((ppp->flags | temp_i) & SC_DEBUG) + save_flags(flags); + cli(); + oldflags = ppp->flags; + ppp->flags = temp_i |= (ppp->flags & ~SC_MASK); + restore_flags(flags); + if ((oldflags | temp_i) & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: set flags to %x\n", temp_i); - ppp->flags = temp_i; break; /* * Set the compression mode diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c index edb3d10f7..4862b9398 100644 --- a/drivers/net/ppp_deflate.c +++ b/drivers/net/ppp_deflate.c @@ -1,5 +1,5 @@ /* - * ==FILEVERSION 971001== + * ==FILEVERSION 980319== * * ppp_deflate.c - interface the zlib procedures for Deflate compression * and decompression (as used by gzip) to the PPP code. @@ -188,20 +188,21 @@ z_comp_alloc(options, opt_len) struct ppp_deflate_state *state; int w_size; - MOD_INC_USE_COUNT; - if (opt_len != CILEN_DEFLATE || options[0] != CI_DEFLATE + if (opt_len != CILEN_DEFLATE + || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) || options[1] != CILEN_DEFLATE || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL || options[3] != DEFLATE_CHK_SEQUENCE) - goto out_fail; + return NULL; w_size = DEFLATE_SIZE(options[2]); if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) - goto out_fail; + return NULL; state = (struct ppp_deflate_state *) kmalloc(sizeof(*state), GFP_KERNEL); if (state == NULL) - goto out_fail; + return NULL; + MOD_INC_USE_COUNT; memset (state, 0, sizeof (struct ppp_deflate_state)); state->strm.next_in = NULL; state->strm.zalloc = zalloc_init; @@ -217,7 +218,6 @@ z_comp_alloc(options, opt_len) out_free: z_comp_free(state); -out_fail: MOD_DEC_USE_COUNT; return NULL; } @@ -230,7 +230,8 @@ z_comp_init(arg, options, opt_len, unit, hdrlen, debug) { struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; - if (opt_len < CILEN_DEFLATE || options[0] != CI_DEFLATE + if (opt_len < CILEN_DEFLATE + || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) || options[1] != CILEN_DEFLATE || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL || DEFLATE_SIZE(options[2]) != state->w_size @@ -264,7 +265,7 @@ z_compress(arg, rptr, obuf, isize, osize) int isize, osize; { struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; - int r, proto, off, olen; + int r, proto, off, olen, oavail; unsigned char *wptr; /* @@ -291,9 +292,10 @@ z_compress(arg, rptr, obuf, isize, osize) wptr += PPP_HDRLEN; wptr[0] = state->seqno >> 8; wptr[1] = state->seqno; - wptr += 2; + wptr += DEFLATE_OVHD; + olen = PPP_HDRLEN + DEFLATE_OVHD; state->strm.next_out = wptr; - state->strm.avail_out = osize - (PPP_HDRLEN + 2); + state->strm.avail_out = oavail = osize - olen; ++state->seqno; off = (proto > 0xff) ? 2 : 3; /* skip 1st proto byte if 0 */ @@ -301,25 +303,23 @@ z_compress(arg, rptr, obuf, isize, osize) state->strm.next_in = rptr; state->strm.avail_in = (isize - off); - olen = 0; for (;;) { r = deflate(&state->strm, Z_PACKET_FLUSH); if (r != Z_OK) { if (state->debug) - printk(KERN_DEBUG "z_compress: deflate returned %d (%s)\n", - r, (state->strm.msg? state->strm.msg: "")); + printk(KERN_ERR + "z_compress: deflate returned %d\n", r); break; } if (state->strm.avail_out == 0) { - olen += osize; + olen += oavail; state->strm.next_out = NULL; - state->strm.avail_out = 1000000; + state->strm.avail_out = oavail = 1000000; } else { break; /* all done */ } } - if (olen < osize) - olen += osize - state->strm.avail_out; + olen += oavail - state->strm.avail_out; /* * See if we managed to reduce the size of the packet. @@ -372,19 +372,21 @@ z_decomp_alloc(options, opt_len) struct ppp_deflate_state *state; int w_size; - MOD_INC_USE_COUNT; - if (opt_len != CILEN_DEFLATE || options[0] != CI_DEFLATE + if (opt_len != CILEN_DEFLATE + || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) || options[1] != CILEN_DEFLATE || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL || options[3] != DEFLATE_CHK_SEQUENCE) - goto out_fail; + return NULL; w_size = DEFLATE_SIZE(options[2]); if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) - goto out_fail; + return NULL; state = (struct ppp_deflate_state *) kmalloc(sizeof(*state), GFP_KERNEL); if (state == NULL) - goto out_fail; + return NULL; + + MOD_INC_USE_COUNT; memset (state, 0, sizeof (struct ppp_deflate_state)); state->w_size = w_size; state->strm.next_out = NULL; @@ -398,7 +400,6 @@ z_decomp_alloc(options, opt_len) out_free: z_decomp_free(state); -out_fail: MOD_DEC_USE_COUNT; return NULL; } @@ -411,7 +412,8 @@ z_decomp_init(arg, options, opt_len, unit, hdrlen, mru, debug) { struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; - if (opt_len < CILEN_DEFLATE || options[0] != CI_DEFLATE + if (opt_len < CILEN_DEFLATE + || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) || options[1] != CILEN_DEFLATE || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL || DEFLATE_SIZE(options[2]) != state->w_size @@ -543,8 +545,12 @@ z_decompress(arg, ibuf, isize, obuf, osize) } } - if (decode_proto) + if (decode_proto) { + if (state->debug) + printk(KERN_DEBUG "z_decompress%d: didn't get proto\n", + state->unit); return DECOMP_ERROR; + } olen = osize + overflow - state->strm.avail_out; state->stats.unc_bytes += olen; @@ -634,6 +640,23 @@ struct compressor ppp_deflate = { z_comp_stats, /* decomp_stat */ }; +struct compressor ppp_deflate_draft = { + CI_DEFLATE_DRAFT, /* compress_proto */ + z_comp_alloc, /* comp_alloc */ + z_comp_free, /* comp_free */ + z_comp_init, /* comp_init */ + z_comp_reset, /* comp_reset */ + z_compress, /* compress */ + z_comp_stats, /* comp_stat */ + z_decomp_alloc, /* decomp_alloc */ + z_decomp_free, /* decomp_free */ + z_decomp_init, /* decomp_init */ + z_decomp_reset, /* decomp_reset */ + z_decompress, /* decompress */ + z_incomp, /* incomp */ + z_comp_stats, /* decomp_stat */ +}; + #ifdef MODULE /************************************************************* * Module support routines @@ -646,6 +669,7 @@ init_module(void) if (answer == 0) printk (KERN_INFO "PPP Deflate Compression module registered\n"); + ppp_register_compressor(&ppp_deflate_draft); return answer; } @@ -655,7 +679,9 @@ cleanup_module(void) if (MOD_IN_USE) printk (KERN_INFO "Deflate Compression module busy, remove delayed\n"); - else + else { ppp_unregister_compressor (&ppp_deflate); + ppp_unregister_compressor (&ppp_deflate_draft); + } } #endif diff --git a/drivers/net/sdla_fr.c b/drivers/net/sdla_fr.c index 9c1c65af8..79bd5d4ca 100644 --- a/drivers/net/sdla_fr.c +++ b/drivers/net/sdla_fr.c @@ -83,7 +83,6 @@ * Jan 02, 1997 Gene Kozin Initial version. *****************************************************************************/ -#include <linux/config.h> /* OS configuration options */ #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ diff --git a/drivers/net/sdla_ppp.c b/drivers/net/sdla_ppp.c index 32675d355..fa4f98d61 100644 --- a/drivers/net/sdla_ppp.c +++ b/drivers/net/sdla_ppp.c @@ -56,7 +56,6 @@ * Jan 06, 1997 Gene Kozin Initial version. *****************************************************************************/ -#include <linux/config.h> /* OS configuration options */ #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ diff --git a/drivers/net/sdla_x25.c b/drivers/net/sdla_x25.c index 6a649a2d2..6a1759040 100644 --- a/drivers/net/sdla_x25.c +++ b/drivers/net/sdla_x25.c @@ -42,7 +42,6 @@ #error This code MUST be compiled as a kernel module! #endif -#include <linux/config.h> /* OS configuration options */ #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index 7a4ceca36..79d6d8076 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -306,9 +306,9 @@ static int ultramca_close_card(struct device *dev) #define MAX_ULTRAMCA_CARDS 4 /* Max number of Ultra cards per module */ #define NAMELEN 8 /* # of chars for storing dev->name */ -static char namelist[NAMELEN * MAX_ULTRA_CARDS] = { 0, }; +static char namelist[NAMELEN * MAX_ULTRAMCA_CARDS] = { 0, }; -static struct device dev_ultra[MAX_ULTRA_CARDS] = +static struct device dev_ultra[MAX_ULTRAMCA_CARDS] = { { NULL, /* assign a chunk of namelist[] below */ @@ -318,11 +318,11 @@ static struct device dev_ultra[MAX_ULTRA_CARDS] = }, }; -static int io[MAX_ULTRA_CARDS] = { 0, }; -static int irq[MAX_ULTRA_CARDS] = { 0, }; +static int io[MAX_ULTRAMCA_CARDS] = { 0, }; +static int irq[MAX_ULTRAMCA_CARDS] = { 0, }; -MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ULTRA_CARDS) "i"); -MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ULTRA_CARDS) "i"); +MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i"); +MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i"); /* This is set up so that only a single autoprobe takes place per call. ISA device autoprobes on a running machine are not recommended. */ @@ -331,7 +331,7 @@ int init_module(void) { int this_dev, found = 0; - for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) + for (this_dev = 0; this_dev < MAX_ULTRAMCA_CARDS; this_dev++) { struct device *dev = &dev_ultra[this_dev]; dev->name = namelist+(NAMELEN*this_dev); @@ -360,7 +360,7 @@ void cleanup_module(void) { int this_dev; - for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) + for (this_dev = 0; this_dev < MAX_ULTRAMCA_CARDS; this_dev++) { struct device *dev = &dev_ultra[this_dev]; if (dev->priv != NULL) diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c index c4f6543a0..a3d3abebf 100644 --- a/drivers/net/smc-ultra32.c +++ b/drivers/net/smc-ultra32.c @@ -239,8 +239,9 @@ __initfunc(int ultra32_probe1(struct device *dev, int ioaddr)) static int ultra32_open(struct device *dev) { int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC addr */ + int irq_flags = (inb(ioaddr + ULTRA32_CFG5) & 0x08) ? 0 : SA_SHIRQ; - if (request_irq(dev->irq, ei_interrupt, 0, ei_status.name, dev)) + if (request_irq(dev->irq, ei_interrupt, irq_flags, ei_status.name, dev)) return -EAGAIN; outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */ diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 9ff5a4f11..ebe502604 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -45,7 +45,6 @@ static char *version = #ifdef CONFIG_PCI #include <linux/pci.h> -#include <linux/bios32.h> #include <asm/pbm.h> #endif @@ -55,7 +54,10 @@ static char *version = static struct happy_meal *root_happy_dev = NULL; #endif -/* #define HMEDEBUG */ +#undef HMEDEBUG +#undef SXDEBUG +#undef RXDEBUG +#undef TXDEBUG #ifdef HMEDEBUG #define HMD(x) printk x @@ -1406,27 +1408,15 @@ static int happy_meal_is_not_so_happy(struct happy_meal *hp, { int reset = 0; - printk("%s: Error interrupt for happy meal, status = %08lx\n", - hp->dev->name, status); - - if(status & - (GREG_STAT_RCNTEXP|GREG_STAT_ACNTEXP|GREG_STAT_CCNTEXP|GREG_STAT_LCNTEXP)) { - /* Some stupid counter expired, we should be not - * have interrupts for this enabled, but we check - * for it anyways. - */ - - printk("%s: Happy Meal counters expired [ ", hp->dev->name); - if(status & GREG_STAT_RCNTEXP) - printk("ReceiveFrame "); - if(status & GREG_STAT_ACNTEXP) - printk("AlignError "); - if(status & GREG_STAT_CCNTEXP) - printk("CrcError "); - if(status & GREG_STAT_LCNTEXP) - printk("LengthError "); - printk("]\n"); - } + /* Only print messages for non-counter related interrupts. */ + if(status & (GREG_STAT_RFIFOVF | GREG_STAT_STSTERR | GREG_STAT_TFIFO_UND | + GREG_STAT_MAXPKTERR | GREG_STAT_NORXD | GREG_STAT_RXERR | + GREG_STAT_RXPERR | GREG_STAT_RXTERR | GREG_STAT_EOPERR | + GREG_STAT_MIFIRQ | GREG_STAT_TXEACK | GREG_STAT_TXLERR | + GREG_STAT_TXPERR | GREG_STAT_TXTERR | GREG_STAT_SLVERR | + GREG_STAT_SLVPERR)) + printk("%s: Error interrupt for happy meal, status = %08lx\n", + hp->dev->name, status); if(status & GREG_STAT_RFIFOVF) { /* The receive FIFO overflowwed, usually a DMA error. */ @@ -1434,11 +1424,6 @@ static int happy_meal_is_not_so_happy(struct happy_meal *hp, reset = 1; } - if(status & GREG_STAT_CVCNTEXP) { - /* See above about counter expiration... */ - printk("%s: Code Violation error counter expired.\n", hp->dev->name); - } - if(status & GREG_STAT_STSTERR) { /* BigMAC SQE link test failed. */ printk("%s: Happy Meal BigMAC SQE test failed.\n", hp->dev->name); @@ -1460,32 +1445,6 @@ static int happy_meal_is_not_so_happy(struct happy_meal *hp, reset = 1; } - if(status & (GREG_STAT_NCNTEXP|GREG_STAT_ECNTEXP|GREG_STAT_LCCNTEXP| - GREG_STAT_FCNTEXP)) { - /* More stupid error counters... */ - printk("%s: Happy Meal counters expired [ ", hp->dev->name); - if(status & GREG_STAT_NCNTEXP) - printk("NormalCollision "); - if(status & GREG_STAT_ECNTEXP) - printk("ExcessCollision "); - if(status & GREG_STAT_LCCNTEXP) - printk("LateCollision "); - if(status & GREG_STAT_FCNTEXP) - printk("FirstCollision "); - printk("]\n"); - } - - if(status & GREG_STAT_DTIMEXP) { - /* Defer-timer expired. Probably means the happy meal needed - * to back off too much before it could transmit one frame. - */ -#if 0 /* XXX This isn't worth reporting and is in fact a normal condition. */ - printk("%s: Transmit defer timer expired, subnet congested?\n", - hp->dev->name); - reset = 1; -#endif - } - if(status & GREG_STAT_NORXD) { /* AIEEE, out of receive descriptors. Check out our drop * processing in happy_meal_rx to see how we try very hard @@ -1584,8 +1543,11 @@ static inline void happy_meal_mif_interrupt(struct happy_meal *hp, happy_meal_poll_stop(hp, tregs); } -/* #define TXD(x) printk x */ +#ifdef TXDEBUG +#define TXD(x) printk x +#else #define TXD(x) +#endif static inline void happy_meal_tx(struct happy_meal *hp) { @@ -1676,8 +1638,11 @@ static inline void sun4c_happy_meal_tx(struct happy_meal *hp) TXD((">")); } -/* #define RXD(x) printk x */ +#ifdef RXDEBUG +#define RXD(x) printk x +#else #define RXD(x) +#endif /* Originally I use to handle the allocation failure by just giving back just * that one ring buffer to the happy meal. Problem is that usually when that @@ -1705,7 +1670,7 @@ static inline void happy_meal_rx(struct happy_meal *hp, struct device *dev, /* Check for errors. */ if((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) { - RXD(("ERR(%08lx)]", flags)); + RXD(("ERR(%08x)]", flags)); hp->net_stats.rx_errors++; if(len < ETH_ZLEN) hp->net_stats.rx_length_errors++; @@ -1724,11 +1689,8 @@ static inline void happy_meal_rx(struct happy_meal *hp, struct device *dev, } skb = hp->rx_skbs[elem]; #ifdef NEED_DMA_SYNCHRONIZATION -#ifdef CONFIG_PCI - if(!(hp->happy_flags & HFLAG_PCI)) -#endif - mmu_sync_dma(kva_to_hva(hp, skb->data), - skb->len, hp->happy_sbus_dev->my_bus); + mmu_sync_dma(kva_to_hva(hp, skb->data), + skb->len, hp->happy_sbus_dev->my_bus); #endif if(len > RX_COPY_THRESHOLD) { struct sk_buff *new_skb; @@ -1819,7 +1781,7 @@ static inline void pci_happy_meal_rx(struct happy_meal *hp, struct device *dev, /* Check for errors. */ if((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) { - RXD(("ERR(%08lx)]", flags)); + RXD(("ERR(%08x)]", flags)); hp->net_stats.rx_errors++; if(len < ETH_ZLEN) hp->net_stats.rx_length_errors++; @@ -1926,7 +1888,7 @@ static inline void sun4c_happy_meal_rx(struct happy_meal *hp, struct device *dev /* Check for errors. */ if((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) { - RXD(("ERR(%08lx)]", flags)); + RXD(("ERR(%08x)]", flags)); hp->net_stats.rx_errors++; if(len < ETH_ZLEN) hp->net_stats.rx_length_errors++; @@ -1975,7 +1937,7 @@ static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs) struct hmeal_tcvregs *tregs = hp->tcvregs; unsigned int happy_status = hme_read32(hp, &gregs->stat); - HMD(("happy_meal_interrupt: status=%08lx ", happy_status)); + HMD(("happy_meal_interrupt: status=%08x ", happy_status)); dev->interrupt = 1; @@ -2020,7 +1982,7 @@ static void pci_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs struct hmeal_tcvregs *tregs = hp->tcvregs; unsigned int happy_status = readl((unsigned long)&gregs->stat); - HMD(("happy_meal_interrupt: status=%08lx ", happy_status)); + HMD(("happy_meal_interrupt: status=%08x ", happy_status)); dev->interrupt = 1; @@ -2065,7 +2027,7 @@ static void sun4c_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *re struct hmeal_tcvregs *tregs = hp->tcvregs; unsigned int happy_status = hme_read32(hp, &gregs->stat); - HMD(("happy_meal_interrupt: status=%08lx ", happy_status)); + HMD(("happy_meal_interrupt: status=%08x ", happy_status)); dev->interrupt = 1; @@ -2181,8 +2143,11 @@ static int happy_meal_close(struct device *dev) return 0; } -/* #define SXD(x) printk x */ +#ifdef SXDEBUG +#define SXD(x) printk x +#else #define SXD(x) +#endif static int happy_meal_start_xmit(struct sk_buff *skb, struct device *dev) { @@ -2700,19 +2665,20 @@ __initfunc(int happy_meal_probe(struct device *dev)) } } #ifdef CONFIG_PCI - if(pcibios_present()) { + if(pci_present()) { struct pci_dev *pdev; - for(pdev = pci_devices; pdev; pdev = pdev->next) { + pdev = pci_find_device(PCI_VENDOR_ID_SUN, + PCI_DEVICE_ID_SUN_HAPPYMEAL, 0); + while (pdev) { if(cards) dev = NULL; - if((pdev->vendor == PCI_VENDOR_ID_SUN) && - (pdev->device == PCI_DEVICE_ID_SUN_HAPPYMEAL)) { - cards++; - if((v = happy_meal_pci_init(dev, pdev))) - return v; - } - + cards++; + if((v = happy_meal_pci_init(dev, pdev))) + return v; + pdev = pci_find_device(PCI_VENDOR_ID_SUN, + PCI_DEVICE_ID_SUN_HAPPYMEAL, + pdev); } } #endif diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 093f7a181..4edbeba69 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.69 1998/01/09 16:42:52 jj Exp $ +/* $Id: sunlance.c,v 1.74 1998/02/12 07:37:25 davem Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza @@ -66,6 +66,7 @@ static char *version = static char *lancestr = "LANCE"; static char *lancedma = "LANCE DMA"; +#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> @@ -103,6 +104,9 @@ static char *lancedma = "LANCE DMA"; #include <linux/etherdevice.h> #include <linux/skbuff.h> +#include <asm/idprom.h> +#include <asm/machines.h> + /* Define: 2^4 Tx buffers and 2^4 Rx buffers */ #ifndef LANCE_LOG_TX_BUFFERS #define LANCE_LOG_TX_BUFFERS 4 @@ -1037,7 +1041,7 @@ sparc_lance_init (struct device *dev, struct linux_sbus_device *sdev, "busmaster-regval", (LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON)); - + lp->ll = ll; lp->name = lancestr; lp->ledma = ledma; @@ -1119,8 +1123,9 @@ no_link_test: dev->hard_start_xmit = &lance_start_xmit; dev->get_stats = &lance_get_stats; dev->set_multicast_list = &lance_set_multicast; - + dev->irq = (unsigned char) sdev->irqs [0].pri; + dev->dma = 0; ether_setup (dev); @@ -1144,6 +1149,31 @@ find_ledma (struct linux_sbus_device *dev) return 0; } +#ifdef CONFIG_SUN4 + +#include <asm/sun4paddr.h> + +/* Find all the lance cards on the system and initialize them */ +__initfunc(int sparc_lance_probe (struct device *dev)) +{ + static struct linux_sbus_device sdev; + static int called = 0; + + if(called) + return ENODEV; + called++; + + if (idprom->id_machtype == (SM_SUN4|SM_4_330)) { + memset (&sdev, 0, sizeof(sdev)); + sdev.reg_addrs[0].phys_addr = SUN4_300_ETH_PHYSADDR; + sdev.irqs[0].pri = 6; + return sparc_lance_init(dev, &sdev, 0, 0); + } + return ENODEV; +} + +#else /* !CONFIG_SUN4 */ + /* Find all the lance cards on the system and initialize them */ __initfunc(int sparc_lance_probe (struct device *dev)) { @@ -1152,10 +1182,11 @@ __initfunc(int sparc_lance_probe (struct device *dev)) struct Linux_SBus_DMA *ledma = 0; static int called = 0; int cards = 0, v; - + if(called) return ENODEV; called++; + for_each_sbus (bus) { for_each_sbusdev (sdev, bus) { if (cards) dev = NULL; @@ -1186,6 +1217,7 @@ __initfunc(int sparc_lance_probe (struct device *dev)) return ENODEV; return 0; } +#endif /* !CONFIG_SUN4 */ #ifdef MODULE diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index cef3f54a4..92d4b9e69 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -29,7 +29,6 @@ #include "tlan.h" -#include <linux/bios32.h> #include <linux/ioport.h> #include <linux/pci.h> #include <linux/etherdevice.h> @@ -96,7 +95,7 @@ static TLanPciId TLanDeviceList[] = { }; -static int TLan_PciProbe( u8 *, u8 *, u8 *, u8 *, u32 *, u32 * ); +static int TLan_PciProbe( u8 *, u8 *, int *, u8 *, u32 *, u32 * ); static int TLan_Init( struct device * ); static int TLan_Open(struct device *dev); static int TLan_StartTx(struct sk_buff *, struct device *); @@ -193,7 +192,7 @@ extern int init_module(void) int failed; int found; u32 io_base; - u8 irq; + int irq; u8 rev; printk( "TLAN driver, v%d.%d, (C) 1997 Caldera, Inc.\n", @@ -319,7 +318,8 @@ extern int tlan_probe( struct device *dev ) static int pad_allocated = 0; int found; TLanPrivateInfo *priv; - u8 bus, dfn, irq, rev; + u8 bus, dfn, rev; + int irq; u32 io_base, dl_ix; found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix ); @@ -398,7 +398,7 @@ extern int tlan_probe( struct device *dev ) * **************************************************************/ -int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix ) +int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, int *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix ) { static int dl_index = 0; static int pci_index = 0; @@ -409,7 +409,7 @@ int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_ int reg; - if ( ! pcibios_present() ) { + if ( ! pci_present() ) { printk( "TLAN: PCI Bios not present.\n" ); return 0; } @@ -425,6 +425,7 @@ int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_ ); if ( ! not_found ) { + struct pci_dev *pdev = pci_find_slot(*pci_bus, *pci_dfn); TLAN_DBG( TLAN_DEBUG_GNRL, @@ -433,19 +434,18 @@ int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_ TLanDeviceList[dl_index].deviceId ); - pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_REVISION_ID, pci_rev); - pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_INTERRUPT_LINE, pci_irq); - pcibios_read_config_word ( *pci_bus, *pci_dfn, PCI_COMMAND, &pci_command); - pcibios_read_config_dword( *pci_bus, *pci_dfn, PCI_BASE_ADDRESS_0, pci_io_base); - pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, &pci_latency); + pci_read_config_byte ( pdev, PCI_REVISION_ID, pci_rev); + *pci_irq = pdev->irq; + pci_read_config_word ( pdev, PCI_COMMAND, &pci_command); + pci_read_config_byte ( pdev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < 0x10) { - pcibios_write_config_byte( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, 0xff); + pci_write_config_byte( pdev, PCI_LATENCY_TIMER, 0xff); TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Setting latency timer to max.\n"); } - for ( reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg +=4 ) { - pcibios_read_config_dword( *pci_bus, *pci_dfn, reg, pci_io_base); + for ( reg = 0; reg <= 5; reg ++ ) { + *pci_io_base = pdev->base_address[reg]; if ((pci_command & PCI_COMMAND_IO) && (*pci_io_base & 0x3)) { *pci_io_base &= PCI_BASE_ADDRESS_IO_MASK; TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: IO mapping is available at %x.\n", *pci_io_base); diff --git a/drivers/net/tulip.c b/drivers/net/tulip.c index 035c47a5c..0abf814e5 100644 --- a/drivers/net/tulip.c +++ b/drivers/net/tulip.c @@ -82,7 +82,6 @@ static const rx_copybreak = 100; #include <linux/malloc.h> #include <linux/interrupt.h> #include <linux/pci.h> -#include <linux/bios32.h> #include <asm/processor.h> /* Processor type for cache alignment. */ #include <asm/bitops.h> #include <asm/io.h> @@ -125,8 +124,10 @@ char kernel_version[] = UTS_RELEASE; #include <linux/delay.h> #endif #if (LINUX_VERSION_CODE >= 0x20100) +#ifdef MODULE char kernel_version[] = UTS_RELEASE; #endif +#endif #ifdef SA_SHIRQ #define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs) #else @@ -135,6 +136,7 @@ char kernel_version[] = UTS_RELEASE; #if (LINUX_VERSION_CODE < 0x20123) #define test_and_set_bit(val, addr) set_bit(val, addr) +#include <linux/bios32.h> #endif /* This my implementation of shared IRQs, now only used for 1.2.13. */ @@ -453,11 +455,17 @@ int tulip_probe(struct device *dev) well with the current structure. So instead we detect just the Tulip cards in slot order. */ - if (pcibios_present()) { + if (pci_present()) { unsigned char pci_bus, pci_device_fn; for (;pci_index < 0xff; pci_index++) { - unsigned char pci_irq_line, pci_latency; + unsigned char pci_latency; +#if LINUX_VERSION_CODE >= 0x20155 + unsigned int pci_irq_line; + struct pci_dev *pdev; +#else + unsigned char pci_irq_line; +#endif unsigned short pci_command, vendor, device; unsigned int pci_ioaddr, chip_idx = 0; @@ -473,10 +481,16 @@ int tulip_probe(struct device *dev) PCI_VENDOR_ID, &vendor); pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, &device); +#if LINUX_VERSION_CODE >= 0x20155 + pdev = pci_find_slot(pci_bus, pci_device_fn); + pci_irq_line = pdev->irq; + pci_ioaddr = pdev->base_address[0]; +#else pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pci_irq_line); pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0, &pci_ioaddr); +#endif /* Remove I/O space marker in bit 0. */ pci_ioaddr &= ~3; |