diff options
Diffstat (limited to 'drivers/net/tokenring/sktr.c')
-rw-r--r-- | drivers/net/tokenring/sktr.c | 2707 |
1 files changed, 0 insertions, 2707 deletions
diff --git a/drivers/net/tokenring/sktr.c b/drivers/net/tokenring/sktr.c index 81b2df4bc..e69de29bb 100644 --- a/drivers/net/tokenring/sktr.c +++ b/drivers/net/tokenring/sktr.c @@ -1,2707 +0,0 @@ -/* - * sktr.c: A network driver for the SysKonnect Token Ring ISA/PCI Adapters. - * - * Written 1997 by Christoph Goos - * - * A fine result of the Linux Systems Network Architecture Project. - * http://samba.anu.edu.au/linux-sna/ - * - * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. - * - * This device driver works with the following SysKonnect adapters: - * - SysKonnect TR4/16(+) ISA (SK-4190) - * - SysKonnect TR4/16(+) PCI (SK-4590) - * - SysKonnect TR4/16 PCI (SK-4591) - * - * Sources: - * - The hardware related parts of this driver are take from - * the SysKonnect Token Ring driver for Windows NT. - * - I used the IBM Token Ring driver 'ibmtr.c' as a base for this - * driver, as well as the 'skeleton.c' driver by Donald Becker. - * - Also various other drivers in the linux source tree were taken - * as samples for some tasks. - * - * Maintainer(s): - * JS Jay Schulist jschlst@samba.anu.edu.au - * CG Christoph Goos cgoos@syskonnect.de - * AF Adam Fritzler mid@auk.cx - * - * Modification History: - * 29-Aug-97 CG Created - * 04-Apr-98 CG Fixed problems caused by tok_timer_check - * 10-Apr-98 CG Fixed lockups at cable disconnection - * 27-May-98 JS Formated to Linux Kernel Format - * 31-May-98 JS Hacked in PCI support - * 16-Jun-98 JS Modulized for multiple cards with one driver - * 21-Sep-99 CG Fixed source routing issues for 2.2 kernels - * 21-Sep-99 AF Added multicast changes recommended by - * Jochen Friedrich <jochen@nwe.de> (untested) - * Added detection of compatible Compaq PCI card - * - * To do: - * 1. Selectable 16 Mbps or 4Mbps - * 2. Multi/Broadcast packet handling (might be done) - * - */ - -static const char *version = "sktr.c: v1.01 08/29/97 by Christoph Goos\n"; - -#ifdef MODULE -#include <linux/module.h> -#include <linux/version.h> -#endif - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/types.h> -#include <linux/fcntl.h> -#include <linux/interrupt.h> -#include <linux/ptrace.h> -#include <linux/ioport.h> -#include <linux/in.h> -#include <linux/malloc.h> -#include <linux/string.h> -#include <linux/time.h> -#include <asm/system.h> -#include <asm/bitops.h> -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/irq.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/pci.h> - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/trdevice.h> - -#include "sktr.h" /* Our Stuff */ -#include "sktr_firmware.h" /* SysKonnect adapter firmware */ - -/* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int sktr_portlist[] __initdata = { - 0x0A20, 0x1A20, 0x0B20, 0x1B20, 0x0980, 0x1980, 0x0900, 0x1900, - 0 -}; - -/* A zero-terminated list of IRQs to be probed. - * Used again after initial probe for sktr_chipset_init, called from sktr_open. - */ -static unsigned short sktr_irqlist[] = { - 3, 5, 9, 10, 11, 12, 15, - 0 -}; - -/* A zero-terminated list of DMAs to be probed. */ -static int sktr_dmalist[] __initdata = { - 5, 6, 7, - 0 -}; - -/* Card names */ -static char *pci_cardname = "SK NET TR 4/16 PCI\0"; -static char *isa_cardname = "SK NET TR 4/16 ISA\0"; -static char *AdapterName; - -/* Use 0 for production, 1 for verification, 2 for debug, and - * 3 for very verbose debug. - */ -#ifndef SKTR_DEBUG -#define SKTR_DEBUG 1 -#endif -static unsigned int sktr_debug = SKTR_DEBUG; - -/* The number of low I/O ports used by the tokencard. */ -#define SKTR_IO_EXTENT 32 - -/* Index to functions, as function prototypes. - * Alphabetical by function name. - */ - -/* "B" */ -static int sktr_bringup_diags(struct net_device *dev); -/* "C" */ -static void sktr_cancel_tx_queue(struct net_local* tp); -static int sktr_chipset_init(struct net_device *dev); -static void sktr_chk_irq(struct net_device *dev); -static unsigned char sktr_chk_frame(struct net_device *dev, unsigned char *Addr); -static void sktr_chk_outstanding_cmds(struct net_device *dev); -static void sktr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr); -static unsigned char sktr_chk_ssb(struct net_local *tp, unsigned short IrqType); -static int sktr_close(struct net_device *dev); -static void sktr_cmd_status_irq(struct net_device *dev); -/* "D" */ -static void sktr_disable_interrupts(struct net_device *dev); -static void sktr_dump(unsigned char *Data, int length); -/* "E" */ -static void sktr_enable_interrupts(struct net_device *dev); -static void sktr_exec_cmd(struct net_device *dev, unsigned short Command); -static void sktr_exec_sifcmd(struct net_device *dev, unsigned int WriteValue); -/* "F" */ -/* "G" */ -static struct enet_statistics *sktr_get_stats(struct net_device *dev); -/* "H" */ -static void sktr_hardware_send_packet(struct net_device *dev, - struct net_local* tp); -/* "I" */ -static int sktr_init_adapter(struct net_device *dev); -static int sktr_init_card(struct net_device *dev); -static void sktr_init_ipb(struct net_local *tp); -static void sktr_init_net_local(struct net_device *dev); -static void sktr_init_opb(struct net_local *tp); -static void sktr_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static int sktr_isa_chk_card(struct net_device *dev, int ioaddr); -static int sktr_isa_chk_ioaddr(int ioaddr); -/* "O" */ -static int sktr_open(struct net_device *dev); -static void sktr_open_adapter(struct net_device *dev); -/* "P" */ -static int sktr_pci_chk_card(struct net_device *dev); -int sktr_probe(struct net_device *dev); -static int sktr_probe1(struct net_device *dev, int ioaddr); -/* "R" */ -static void sktr_rcv_status_irq(struct net_device *dev); -static void sktr_read_addr(struct net_device *dev, unsigned char *Address); -static void sktr_read_ptr(struct net_device *dev); -static void sktr_read_ram(struct net_device *dev, unsigned char *Data, - unsigned short Address, int Length); -static int sktr_reset_adapter(struct net_device *dev); -static void sktr_reset_interrupt(struct net_device *dev); -static void sktr_ring_status_irq(struct net_device *dev); -/* "S" */ -static int sktr_send_packet(struct sk_buff *skb, struct net_device *dev); -static void sktr_set_multicast_list(struct net_device *dev); -/* "T" */ -static void sktr_timer_chk(unsigned long data); -static void sktr_timer_end_wait(unsigned long data); -static void sktr_tx_status_irq(struct net_device *dev); -/* "U" */ -static void sktr_update_rcv_stats(struct net_local *tp, - unsigned char DataPtr[], unsigned int Length); -/* "W" */ -static void sktr_wait(unsigned long time); -static void sktr_write_rpl_status(RPL *rpl, unsigned int Status); -static void sktr_write_tpl_status(TPL *tpl, unsigned int Status); - -/* - * Check for a network adapter of this type, and return '0' if one exists. - * If dev->base_addr == 0, probe all likely locations. - * If dev->base_addr == 1, always return failure. - */ -int __init sktr_probe(struct net_device *dev) -{ - int i; - int base_addr = dev ? dev->base_addr : 0; - - if(base_addr > 0x1ff) /* Check a single specified location. */ - return (sktr_probe1(dev, base_addr)); - else if(base_addr != 0) /* Don't probe at all. */ - return (-ENXIO); - - for(i = 0; sktr_portlist[i]; i++) - { - int ioaddr = sktr_portlist[i]; - if(check_region(ioaddr, SKTR_IO_EXTENT)) - continue; - if(sktr_probe1(dev, ioaddr)) - { -#ifndef MODULE - tr_freedev(dev); -#endif - } - else - return (0); - } - - return (-ENODEV); -} - -/* - * Detect and setup the PCI SysKonnect TR cards in slot order. - */ -static int __init sktr_pci_chk_card(struct net_device *dev) -{ - static int pci_index = 0; - unsigned char pci_bus, pci_device_fn; - - if(!pci_present()) - return (-1); /* No PCI present. */ - - for(; pci_index < 0xff; pci_index++) - { - unsigned int pci_irq_line; - struct pci_dev *pdev; - unsigned short pci_command, new_command, vendor, device; - unsigned int pci_ioaddr; - - if(pcibios_find_class(PCI_CLASS_NETWORK_TOKEN_RING << 8, - pci_index, &pci_bus, &pci_device_fn) - != PCIBIOS_SUCCESSFUL) - { - break; - } - - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_DEVICE_ID, &device); - - pdev = pci_find_slot(pci_bus, pci_device_fn); - pci_irq_line = pdev->irq; - pci_ioaddr = pdev->resource[0].start; - - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); - - /* Remove I/O space marker in bit 0. */ - pci_ioaddr &= ~3; - - if((vendor != PCI_VENDOR_ID_SK) && - (vendor != PCI_VENDOR_ID_COMPAQ)) - continue; - - if((vendor == PCI_VENDOR_ID_SK) && - (device != PCI_DEVICE_ID_SK_TR)) - continue; - else if((vendor == PCI_VENDOR_ID_COMPAQ) && - (device != PCI_DEVICE_ID_COMPAQ_TOKENRING)) - continue; - - if(check_region(pci_ioaddr, SKTR_IO_EXTENT)) - continue; - request_region(pci_ioaddr, SKTR_IO_EXTENT, pci_cardname); - if(request_irq(pdev->irq, sktr_interrupt, SA_SHIRQ, - pci_cardname, dev)) - return (-ENODEV); /* continue; ?? */ - - AdapterName = pci_cardname; - - new_command = (pci_command|PCI_COMMAND_MASTER|PCI_COMMAND_IO); - - if(pci_command != new_command) - { - printk("The PCI BIOS has not enabled this" - "device! Updating PCI command %4.4x->%4.4x.\n", - pci_command, new_command); - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, new_command); - } - - /* At this point we have found a valid PCI TR card. */ - dev->base_addr = pci_ioaddr; - dev->irq = pci_irq_line; - dev->dma = 0; - - printk("%s: %s found at %#4x, using IRQ %d.\n", - dev->name, AdapterName, pci_ioaddr, dev->irq); - - return (0); - } - - return (-1); -} - -/* - * Detect and setup the ISA SysKonnect TR cards. - */ -static int __init sktr_isa_chk_card(struct net_device *dev, int ioaddr) -{ - int i, err; - unsigned long flags; - - err = sktr_isa_chk_ioaddr(ioaddr); - if(err < 0) - return (-ENODEV); - - if(virt_to_bus((void*)((unsigned long)dev->priv+sizeof(struct net_local))) - > ISA_MAX_ADDRESS) - { - printk("%s: Memory not accessible for DMA\n", dev->name); - kfree(dev->priv); - return (-EAGAIN); - } - - AdapterName = isa_cardname; - - /* Grab the region so that no one else tries to probe our ioports. */ - request_region(ioaddr, SKTR_IO_EXTENT, AdapterName); - dev->base_addr = ioaddr; - - /* Autoselect IRQ and DMA if dev->irq == 0 */ - if(dev->irq == 0) - { - for(i = 0; sktr_irqlist[i] != 0; i++) - { - dev->irq = sktr_irqlist[i]; - err = request_irq(dev->irq, &sktr_interrupt, 0, AdapterName, dev); - if(!err) - break; - } - - if(sktr_irqlist[i] == 0) - { - printk("%s: AutoSelect no IRQ available\n", dev->name); - return (-EAGAIN); - } - } - else - { - err = request_irq(dev->irq, &sktr_interrupt, 0, AdapterName, dev); - if(err) - { - printk("%s: Selected IRQ not available\n", dev->name); - return (-EAGAIN); - } - } - - /* Always allocate the DMA channel after IRQ and clean up on failure */ - if(dev->dma == 0) - { - for(i = 0; sktr_dmalist[i] != 0; i++) - { - dev->dma = sktr_dmalist[i]; - err = request_dma(dev->dma, AdapterName); - if(!err) - break; - } - - if(dev->dma == 0) - { - printk("%s: AutoSelect no DMA available\n", dev->name); - free_irq(dev->irq, NULL); - return (-EAGAIN); - } - } - else - { - err = request_dma(dev->dma, AdapterName); - if(err) - { - printk("%s: Selected DMA not available\n", dev->name); - free_irq(dev->irq, NULL); - return (-EAGAIN); - } - } - - flags=claim_dma_lock(); - disable_dma(dev->dma); - set_dma_mode(dev->dma, DMA_MODE_CASCADE); - enable_dma(dev->dma); - release_dma_lock(flags); - - printk("%s: %s found at %#4x, using IRQ %d and DMA %d.\n", - dev->name, AdapterName, ioaddr, dev->irq, dev->dma); - - return (0); -} - -static int __init sktr_probe1(struct net_device *dev, int ioaddr) -{ - static unsigned version_printed = 0; - struct net_local *tp; - int DeviceType = SK_PCI; - int err; - - if(sktr_debug && version_printed++ == 0) - printk("%s", version); - -#ifndef MODULE - dev = init_trdev(dev, 0); - if(dev == NULL) - return (-ENOMEM); -#endif - - err = sktr_pci_chk_card(dev); - if(err < 0) - { - err = sktr_isa_chk_card(dev, ioaddr); - if(err < 0) - return (-ENODEV); - DeviceType = SK_ISA; - } - - /* Setup this devices private information structure */ - tp = (struct net_local *)kmalloc(sizeof(struct net_local), GFP_KERNEL | GFP_DMA); - if(tp == NULL) - return (-ENOMEM); - memset(tp, 0, sizeof(struct net_local)); - tp->DeviceType = DeviceType; - init_waitqueue_head(&tp->wait_for_tok_int); - - dev->priv = tp; - dev->init = sktr_init_card; - dev->open = sktr_open; - dev->stop = sktr_close; - dev->hard_start_xmit = sktr_send_packet; - dev->get_stats = sktr_get_stats; - dev->set_multicast_list = &sktr_set_multicast_list; - - return (0); -} - -/* Dummy function */ -static int __init sktr_init_card(struct net_device *dev) -{ - if(sktr_debug > 3) - printk("%s: sktr_init_card\n", dev->name); - - return (0); -} - -/* - * This function tests if an adapter is really installed at the - * given I/O address. Return negative if no adapter at IO addr. - */ -static int __init sktr_isa_chk_ioaddr(int ioaddr) -{ - unsigned char old, chk1, chk2; - - old = inb(ioaddr + SIFADR); /* Get the old SIFADR value */ - - chk1 = 0; /* Begin with check value 0 */ - do { - /* Write new SIFADR value */ - outb(chk1, ioaddr + SIFADR); - - /* Read, invert and write */ - chk2 = inb(ioaddr + SIFADD); - chk2 ^= 0x0FE; - outb(chk2, ioaddr + SIFADR); - - /* Read, invert and compare */ - chk2 = inb(ioaddr + SIFADD); - chk2 ^= 0x0FE; - - if(chk1 != chk2) - return (-1); /* No adapter */ - - chk1 -= 2; - } while(chk1 != 0); /* Repeat 128 times (all byte values) */ - - /* Restore the SIFADR value */ - outb(old, ioaddr + SIFADR); - - return (0); -} - -/* - * Open/initialize the board. This is called sometime after - * booting when the 'ifconfig' program is run. - * - * This routine should set everything up anew at each open, even - * registers that "should" only need to be set once at boot, so that - * there is non-reboot way to recover if something goes wrong. - */ -static int sktr_open(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - int err; - - /* Reset the hardware here. Don't forget to set the station address. */ - err = sktr_chipset_init(dev); - if(err) - { - printk(KERN_INFO "%s: Chipset initialization error\n", - dev->name); - return (-1); - } - - dev->addr_len = 6; - sktr_read_addr(dev, (unsigned char*)dev->dev_addr); - - init_timer(&tp->timer); - tp->timer.expires = jiffies + 30*HZ; - tp->timer.function = sktr_timer_end_wait; - tp->timer.data = (unsigned long)dev; - tp->timer.next = NULL; - tp->timer.prev = NULL; - add_timer(&tp->timer); - - sktr_read_ptr(dev); - sktr_enable_interrupts(dev); - sktr_open_adapter(dev); - - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 0; - - /* Wait for interrupt from hardware. If interrupt does not come, - * there will be a timeout from the timer. - */ - tp->Sleeping = 1; - interruptible_sleep_on(&tp->wait_for_tok_int); - del_timer(&tp->timer); - - /* If AdapterVirtOpenFlag is 1, the adapter is now open for use */ - if(tp->AdapterVirtOpenFlag == 0) - { - sktr_disable_interrupts(dev); - return (-1); - } - - dev->start = 1; - - tp->StartTime = jiffies; - - /* Start function control timer */ - tp->timer.expires = jiffies + 2*HZ; - tp->timer.function = sktr_timer_chk; - tp->timer.data = (unsigned long)dev; - add_timer(&tp->timer); - -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif - - return (0); -} - -/* - * Timeout function while waiting for event - */ -static void sktr_timer_end_wait(unsigned long data) -{ - struct net_device *dev = (struct net_device*)data; - struct net_local *tp = (struct net_local *)dev->priv; - - if(tp->Sleeping) - { - tp->Sleeping = 0; - wake_up_interruptible(&tp->wait_for_tok_int); - } - - return; -} - -/* - * Initialize the chipset - */ -static int sktr_chipset_init(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - unsigned char PosReg, Tmp; - int i, err; - - sktr_init_ipb(tp); - sktr_init_opb(tp); - sktr_init_net_local(dev); - - /* Set pos register: selects irq and dma channel. - * Only for ISA bus adapters. - */ - if(dev->dma > 0) - { - PosReg = 0; - for(i = 0; sktr_irqlist[i] != 0; i++) - { - if(sktr_irqlist[i] == dev->irq) - break; - } - - /* Choose default cycle time, 500 nsec */ - PosReg |= CYCLE_TIME << 2; - PosReg |= i << 4; - i = dev->dma - 5; - PosReg |= i; - - if(tp->DataRate == SPEED_4) - PosReg |= LINE_SPEED_BIT; - else - PosReg &= ~LINE_SPEED_BIT; - - outb(PosReg, dev->base_addr + POSREG); - Tmp = inb(dev->base_addr + POSREG); - if((Tmp & ~CYCLE_TIME) != (PosReg & ~CYCLE_TIME)) - printk(KERN_INFO "%s: POSREG error\n", dev->name); - } - - err = sktr_reset_adapter(dev); - if(err < 0) - return (-1); - - err = sktr_bringup_diags(dev); - if(err < 0) - return (-1); - - err = sktr_init_adapter(dev); - if(err < 0) - return (-1); - - return (0); -} - -/* - * Initializes the net_local structure. - */ -static void sktr_init_net_local(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - int i; - - tp->scb.CMD = 0; - tp->scb.Parm[0] = 0; - tp->scb.Parm[1] = 0; - - tp->ssb.STS = 0; - tp->ssb.Parm[0] = 0; - tp->ssb.Parm[1] = 0; - tp->ssb.Parm[2] = 0; - - tp->CMDqueue = 0; - - tp->AdapterOpenFlag = 0; - tp->AdapterVirtOpenFlag = 0; - tp->ScbInUse = 0; - tp->OpenCommandIssued = 0; - tp->ReOpenInProgress = 0; - tp->HaltInProgress = 0; - tp->TransmitHaltScheduled = 0; - tp->LobeWireFaultLogged = 0; - tp->LastOpenStatus = 0; - tp->MaxPacketSize = DEFAULT_PACKET_SIZE; - - skb_queue_head_init(&tp->SendSkbQueue); - tp->QueueSkb = MAX_TX_QUEUE; - - /* Create circular chain of transmit lists */ - for (i = 0; i < TPL_NUM; i++) - { - tp->Tpl[i].NextTPLAddr = htonl((unsigned long) virt_to_bus(&tp->Tpl[(i+1) % TPL_NUM])); - tp->Tpl[i].Status = 0; - tp->Tpl[i].FrameSize = 0; - tp->Tpl[i].FragList[0].DataCount = 0; - tp->Tpl[i].FragList[0].DataAddr = 0; - tp->Tpl[i].NextTPLPtr = &tp->Tpl[(i+1) % TPL_NUM]; - tp->Tpl[i].MData = NULL; - tp->Tpl[i].TPLIndex = i; - tp->Tpl[i].BusyFlag = 0; - } - - tp->TplFree = tp->TplBusy = &tp->Tpl[0]; - - /* Create circular chain of receive lists */ - for (i = 0; i < RPL_NUM; i++) - { - tp->Rpl[i].NextRPLAddr = htonl((unsigned long) virt_to_bus(&tp->Rpl[(i+1) % RPL_NUM])); - tp->Rpl[i].Status = (RX_VALID | RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ); - tp->Rpl[i].FrameSize = 0; - tp->Rpl[i].FragList[0].DataCount = SWAPB(tp->MaxPacketSize); - - /* Alloc skb and point adapter to data area */ - tp->Rpl[i].Skb = dev_alloc_skb(tp->MaxPacketSize); - - /* skb == NULL ? then use local buffer */ - if(tp->Rpl[i].Skb == NULL) - { - tp->Rpl[i].SkbStat = SKB_UNAVAILABLE; - tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i])); - tp->Rpl[i].MData = tp->LocalRxBuffers[i]; - } - else /* SKB != NULL */ - { - tp->Rpl[i].Skb->dev = dev; - skb_put(tp->Rpl[i].Skb, tp->MaxPacketSize); - - /* data unreachable for DMA ? then use local buffer */ - if(tp->DeviceType == SK_ISA && - virt_to_bus(tp->Rpl[i].Skb->data) + - tp->MaxPacketSize > ISA_MAX_ADDRESS) - { - tp->Rpl[i].SkbStat = SKB_DATA_COPY; - tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i])); - tp->Rpl[i].MData = tp->LocalRxBuffers[i]; - } - else /* DMA directly in skb->data */ - { - tp->Rpl[i].SkbStat = SKB_DMA_DIRECT; - tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->Rpl[i].Skb->data)); - tp->Rpl[i].MData = tp->Rpl[i].Skb->data; - } - } - - tp->Rpl[i].NextRPLPtr = &tp->Rpl[(i+1) % RPL_NUM]; - tp->Rpl[i].RPLIndex = i; - } - - tp->RplHead = &tp->Rpl[0]; - tp->RplTail = &tp->Rpl[RPL_NUM-1]; - tp->RplTail->Status = (RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ); - - return; -} - -/* - * Initializes the initialisation parameter block. - */ -static void sktr_init_ipb(struct net_local *tp) -{ - tp->ipb.Init_Options = BURST_MODE; - tp->ipb.CMD_Status_IV = 0; - tp->ipb.TX_IV = 0; - tp->ipb.RX_IV = 0; - tp->ipb.Ring_Status_IV = 0; - tp->ipb.SCB_Clear_IV = 0; - tp->ipb.Adapter_CHK_IV = 0; - tp->ipb.RX_Burst_Size = BURST_SIZE; - tp->ipb.TX_Burst_Size = BURST_SIZE; - tp->ipb.DMA_Abort_Thrhld = DMA_RETRIES; - tp->ipb.SCB_Addr = 0; - tp->ipb.SSB_Addr = 0; - - return; -} - -/* - * Initializes the open parameter block. - */ -static void sktr_init_opb(struct net_local *tp) -{ - unsigned long Addr; - unsigned short RplSize = RPL_SIZE; - unsigned short TplSize = TPL_SIZE; - unsigned short BufferSize = BUFFER_SIZE; - - tp->ocpl.OPENOptions = 0; - tp->ocpl.OPENOptions |= ENABLE_FULL_DUPLEX_SELECTION; -/* tp->ocpl.OPENOptions |= PAD_ROUTING_FIELD; no more needed */ - tp->ocpl.FullDuplex = 0; - tp->ocpl.FullDuplex |= OPEN_FULL_DUPLEX_OFF; - - /* Fixme: If mac address setable: - * for (i=0; i<LENGTH_OF_ADDRESS; i++) - * mac->Vam->ocpl.NodeAddr[i] = mac->CurrentAddress[i]; - */ - - tp->ocpl.GroupAddr = 0; - tp->ocpl.FunctAddr = 0; - tp->ocpl.RxListSize = SWAPB(RplSize); - tp->ocpl.TxListSize = SWAPB(TplSize); - tp->ocpl.BufSize = SWAPB(BufferSize); - tp->ocpl.Reserved = 0; - tp->ocpl.TXBufMin = TX_BUF_MIN; - tp->ocpl.TXBufMax = TX_BUF_MAX; - - Addr = htonl(virt_to_bus(tp->ProductID)); - - tp->ocpl.ProdIDAddr[0] = LOWORD(Addr); - tp->ocpl.ProdIDAddr[1] = HIWORD(Addr); - - return; -} - -/* - * Send OPEN command to adapter - */ -static void sktr_open_adapter(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - - if(tp->OpenCommandIssued) - return; - - tp->OpenCommandIssued = 1; - sktr_exec_cmd(dev, OC_OPEN); - - return; -} - -/* - * Clear the adapter's interrupt flag. Clear system interrupt enable - * (SINTEN): disable adapter to system interrupts. - */ -static void sktr_disable_interrupts(struct net_device *dev) -{ - outb(0, dev->base_addr + SIFACL); - - return; -} - -/* - * Set the adapter's interrupt flag. Set system interrupt enable - * (SINTEN): enable adapter to system interrupts. - */ -static void sktr_enable_interrupts(struct net_device *dev) -{ - outb(ACL_SINTEN, dev->base_addr + SIFACL); - - return; -} - -/* - * Put command in command queue, try to execute it. - */ -static void sktr_exec_cmd(struct net_device *dev, unsigned short Command) -{ - struct net_local *tp = (struct net_local *)dev->priv; - - tp->CMDqueue |= Command; - sktr_chk_outstanding_cmds(dev); - - return; -} - -/* - * Gets skb from system, queues it and checks if it can be sent - */ -static int sktr_send_packet(struct sk_buff *skb, struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - - if(dev->tbusy) - { - /* - * If we get here, some higher level has decided we are broken. - * There should really be a "kick me" function call instead. - * - * Resetting the token ring adapter takes a long time so just - * fake transmission time and go on trying. Our own timeout - * routine is in sktr_timer_chk() - */ - dev->tbusy = 0; - dev->trans_start = jiffies; - return (1); - } - - /* - * If some higher layer thinks we've missed an tx-done interrupt we - * are passed NULL. - */ - if(skb == NULL) - return (0); - - /* - * 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) - { - printk("%s: Transmitter access conflict.\n", dev->name); - return (1); - } - - if(tp->QueueSkb == 0) - return (1); /* Return with tbusy set: queue full */ - - tp->QueueSkb--; - skb_queue_tail(&tp->SendSkbQueue, skb); - sktr_hardware_send_packet(dev, tp); - if(tp->QueueSkb > 0) - dev->tbusy = 0; - - return (0); -} - -/* - * Move frames from internal skb queue into adapter tx queue - */ -static void sktr_hardware_send_packet(struct net_device *dev, struct net_local* tp) -{ - TPL *tpl; - short length; - unsigned char *buf, *newbuf; - struct sk_buff *skb; - int i; - - for(;;) - { - /* Try to get a free TPL from the chain. - * - * NOTE: We *must* always leave one unused TPL in the chain, - * because otherwise the adapter might send frames twice. - */ - if(tp->TplFree->NextTPLPtr->BusyFlag) /* No free TPL */ - { - printk(KERN_INFO "%s: No free TPL\n", dev->name); - return; - } - - /* Send first buffer from queue */ - skb = skb_dequeue(&tp->SendSkbQueue); - if(skb == NULL) - return; - - tp->QueueSkb++; - /* Is buffer reachable for Busmaster-DMA? */ - if(tp->DeviceType == SK_ISA && - virt_to_bus((void*)(((long) skb->data) + skb->len)) - > ISA_MAX_ADDRESS) - { - /* Copy frame to local buffer */ - i = tp->TplFree->TPLIndex; - length = skb->len; - buf = tp->LocalTxBuffers[i]; - memcpy(buf, skb->data, length); - newbuf = buf; - } - else - { - /* Send direct from skb->data */ - length = skb->len; - newbuf = skb->data; - } - - /* Source address in packet? */ - sktr_chk_src_addr(newbuf, dev->dev_addr); - - tp->LastSendTime = jiffies; - tpl = tp->TplFree; /* Get the "free" TPL */ - tpl->BusyFlag = 1; /* Mark TPL as busy */ - tp->TplFree = tpl->NextTPLPtr; - - /* Save the skb for delayed return of skb to system */ - tpl->Skb = skb; - tpl->FragList[0].DataCount = (unsigned short) SWAPB(length); - tpl->FragList[0].DataAddr = htonl(virt_to_bus(newbuf)); - - /* Write the data length in the transmit list. */ - tpl->FrameSize = (unsigned short) SWAPB(length); - tpl->MData = newbuf; - - /* Transmit the frame and set the status values. */ - sktr_write_tpl_status(tpl, TX_VALID | TX_START_FRAME - | TX_END_FRAME | TX_PASS_SRC_ADDR - | TX_FRAME_IRQ); - - /* Let adapter send the frame. */ - sktr_exec_sifcmd(dev, CMD_TX_VALID); - } - - return; -} - -/* - * Write the given value to the 'Status' field of the specified TPL. - * NOTE: This function should be used whenever the status of any TPL must be - * modified by the driver, because the compiler may otherwise change the - * order of instructions such that writing the TPL status may be executed at - * an undesireable time. When this function is used, the status is always - * written when the function is called. - */ -static void sktr_write_tpl_status(TPL *tpl, unsigned int Status) -{ - tpl->Status = Status; -} - -static void sktr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr) -{ - unsigned char SRBit; - - if((((unsigned long)frame[8]) & ~0x80) != 0) /* Compare 4 bytes */ - return; - if((unsigned short)frame[12] != 0) /* Compare 2 bytes */ - return; - - SRBit = frame[8] & 0x80; - memcpy(&frame[8], hw_addr, 6); - frame[8] |= SRBit; - - return; -} - -/* - * The timer routine: Check if adapter still open and working, reopen if not. - */ -static void sktr_timer_chk(unsigned long data) -{ - struct net_device *dev = (struct net_device*)data; - struct net_local *tp = (struct net_local*)dev->priv; - - if(tp->HaltInProgress) - return; - - sktr_chk_outstanding_cmds(dev); - if(time_before(tp->LastSendTime + SEND_TIMEOUT, jiffies) - && (tp->QueueSkb < MAX_TX_QUEUE || tp->TplFree != tp->TplBusy)) - { - /* Anything to send, but stalled to long */ - tp->LastSendTime = jiffies; - sktr_exec_cmd(dev, OC_CLOSE); /* Does reopen automatically */ - } - - tp->timer.expires = jiffies + 2*HZ; - add_timer(&tp->timer); - - if(tp->AdapterOpenFlag || tp->ReOpenInProgress) - return; - tp->ReOpenInProgress = 1; - sktr_open_adapter(dev); - - return; -} - -/* - * The typical workload of the driver: Handle the network interface interrupts. - */ -static void sktr_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = dev_id; - struct net_local *tp; - int ioaddr; - unsigned short irq_type; - - if(dev == NULL) - { - printk("%s: irq %d for unknown device.\n", dev->name, irq); - return; - } - - dev->interrupt = 1; - - ioaddr = dev->base_addr; - tp = (struct net_local *)dev->priv; - - irq_type = inw(ioaddr + SIFSTS); - - while(irq_type & STS_SYSTEM_IRQ) - { - irq_type &= STS_IRQ_MASK; - - if(!sktr_chk_ssb(tp, irq_type)) - { - printk(KERN_INFO "%s: DATA LATE occurred\n", dev->name); - break; - } - - switch(irq_type) - { - case STS_IRQ_RECEIVE_STATUS: - sktr_reset_interrupt(dev); - sktr_rcv_status_irq(dev); - break; - - case STS_IRQ_TRANSMIT_STATUS: - /* Check if TRANSMIT.HALT command is complete */ - if(tp->ssb.Parm[0] & COMMAND_COMPLETE) - { - tp->TransmitCommandActive = 0; - tp->TransmitHaltScheduled = 0; - - /* Issue a new transmit command. */ - sktr_exec_cmd(dev, OC_TRANSMIT); - } - - sktr_reset_interrupt(dev); - sktr_tx_status_irq(dev); - break; - - case STS_IRQ_COMMAND_STATUS: - /* The SSB contains status of last command - * other than receive/transmit. - */ - sktr_cmd_status_irq(dev); - break; - - case STS_IRQ_SCB_CLEAR: - /* The SCB is free for another command. */ - tp->ScbInUse = 0; - sktr_chk_outstanding_cmds(dev); - break; - - case STS_IRQ_RING_STATUS: - sktr_ring_status_irq(dev); - break; - - case STS_IRQ_ADAPTER_CHECK: - sktr_chk_irq(dev); - break; - - default: - printk(KERN_INFO "Unknown Token Ring IRQ\n"); - break; - } - - /* Reset system interrupt if not already done. */ - if(irq_type != STS_IRQ_TRANSMIT_STATUS - && irq_type != STS_IRQ_RECEIVE_STATUS) - { - sktr_reset_interrupt(dev); - } - - irq_type = inw(ioaddr + SIFSTS); - } - - dev->interrupt = 0; - - return; -} - -/* - * Reset the INTERRUPT SYSTEM bit and issue SSB CLEAR command. - */ -static void sktr_reset_interrupt(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - SSB *ssb = &tp->ssb; - - /* - * [Workaround for "Data Late"] - * Set all fields of the SSB to well-defined values so we can - * check if the adapter has written the SSB. - */ - - ssb->STS = (unsigned short) -1; - ssb->Parm[0] = (unsigned short) -1; - ssb->Parm[1] = (unsigned short) -1; - ssb->Parm[2] = (unsigned short) -1; - - /* Free SSB by issuing SSB_CLEAR command after reading IRQ code - * and clear STS_SYSTEM_IRQ bit: enable adapter for further interrupts. - */ - sktr_exec_sifcmd(dev, CMD_SSB_CLEAR | CMD_CLEAR_SYSTEM_IRQ); - - return; -} - -/* - * Check if the SSB has actually been written by the adapter. - */ -static unsigned char sktr_chk_ssb(struct net_local *tp, unsigned short IrqType) -{ - SSB *ssb = &tp->ssb; /* The address of the SSB. */ - - /* C 0 1 2 INTERRUPT CODE - * - - - - -------------- - * 1 1 1 1 TRANSMIT STATUS - * 1 1 1 1 RECEIVE STATUS - * 1 ? ? 0 COMMAND STATUS - * 0 0 0 0 SCB CLEAR - * 1 1 0 0 RING STATUS - * 0 0 0 0 ADAPTER CHECK - * - * 0 = SSB field not affected by interrupt - * 1 = SSB field is affected by interrupt - * - * C = SSB ADDRESS +0: COMMAND - * 0 = SSB ADDRESS +2: STATUS 0 - * 1 = SSB ADDRESS +4: STATUS 1 - * 2 = SSB ADDRESS +6: STATUS 2 - */ - - /* Check if this interrupt does use the SSB. */ - - if(IrqType != STS_IRQ_TRANSMIT_STATUS - && IrqType != STS_IRQ_RECEIVE_STATUS - && IrqType != STS_IRQ_COMMAND_STATUS - && IrqType != STS_IRQ_RING_STATUS) - { - return (1); /* SSB not involved. */ - } - - /* Note: All fields of the SSB have been set to all ones (-1) after it - * has last been used by the software (see DriverIsr()). - * - * Check if the affected SSB fields are still unchanged. - */ - - if(ssb->STS == (unsigned short) -1) - return (0); /* Command field not yet available. */ - if(IrqType == STS_IRQ_COMMAND_STATUS) - return (1); /* Status fields not always affected. */ - if(ssb->Parm[0] == (unsigned short) -1) - return (0); /* Status 1 field not yet available. */ - if(IrqType == STS_IRQ_RING_STATUS) - return (1); /* Status 2 & 3 fields not affected. */ - - /* Note: At this point, the interrupt is either TRANSMIT or RECEIVE. */ - if(ssb->Parm[1] == (unsigned short) -1) - return (0); /* Status 2 field not yet available. */ - if(ssb->Parm[2] == (unsigned short) -1) - return (0); /* Status 3 field not yet available. */ - - return (1); /* All SSB fields have been written by the adapter. */ -} - -/* - * Evaluates the command results status in the SSB status field. - */ -static void sktr_cmd_status_irq(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - unsigned short ssb_cmd, ssb_parm_0; - unsigned short ssb_parm_1; - char *open_err = "Open error -"; - char *code_err = "Open code -"; - - /* Copy the ssb values to local variables */ - ssb_cmd = tp->ssb.STS; - ssb_parm_0 = tp->ssb.Parm[0]; - ssb_parm_1 = tp->ssb.Parm[1]; - - if(ssb_cmd == OPEN) - { - tp->Sleeping = 0; - if(!tp->ReOpenInProgress) - wake_up_interruptible(&tp->wait_for_tok_int); - - tp->OpenCommandIssued = 0; - tp->ScbInUse = 0; - - if((ssb_parm_0 & 0x00FF) == GOOD_COMPLETION) - { - /* Success, the adapter is open. */ - tp->LobeWireFaultLogged = 0; - tp->AdapterOpenFlag = 1; - tp->AdapterVirtOpenFlag = 1; - tp->TransmitCommandActive = 0; - sktr_exec_cmd(dev, OC_TRANSMIT); - sktr_exec_cmd(dev, OC_RECEIVE); - - if(tp->ReOpenInProgress) - tp->ReOpenInProgress = 0; - - return; - } - else /* The adapter did not open. */ - { - if(ssb_parm_0 & NODE_ADDR_ERROR) - printk(KERN_INFO "%s: Node address error\n", - dev->name); - if(ssb_parm_0 & LIST_SIZE_ERROR) - printk(KERN_INFO "%s: List size error\n", - dev->name); - if(ssb_parm_0 & BUF_SIZE_ERROR) - printk(KERN_INFO "%s: Buffer size error\n", - dev->name); - if(ssb_parm_0 & TX_BUF_COUNT_ERROR) - printk(KERN_INFO "%s: Tx buffer count error\n", - dev->name); - if(ssb_parm_0 & INVALID_OPEN_OPTION) - printk(KERN_INFO "%s: Invalid open option\n", - dev->name); - if(ssb_parm_0 & OPEN_ERROR) - { - /* Show the open phase. */ - switch(ssb_parm_0 & OPEN_PHASES_MASK) - { - case LOBE_MEDIA_TEST: - if(!tp->LobeWireFaultLogged) - { - tp->LobeWireFaultLogged = 1; - printk(KERN_INFO "%s: %s Lobe wire fault (check cable !).\n", dev->name, open_err); - } - tp->ReOpenInProgress = 1; - tp->AdapterOpenFlag = 0; - tp->AdapterVirtOpenFlag = 1; - sktr_open_adapter(dev); - return; - - case PHYSICAL_INSERTION: - printk(KERN_INFO "%s: %s Physical insertion.\n", dev->name, open_err); - break; - - case ADDRESS_VERIFICATION: - printk(KERN_INFO "%s: %s Address verification.\n", dev->name, open_err); - break; - - case PARTICIPATION_IN_RING_POLL: - printk(KERN_INFO "%s: %s Participation in ring poll.\n", dev->name, open_err); - break; - - case REQUEST_INITIALISATION: - printk(KERN_INFO "%s: %s Request initialisation.\n", dev->name, open_err); - break; - - case FULLDUPLEX_CHECK: - printk(KERN_INFO "%s: %s Full duplex check.\n", dev->name, open_err); - break; - - default: - printk(KERN_INFO "%s: %s Unknown open phase\n", dev->name, open_err); - break; - } - - /* Show the open errors. */ - switch(ssb_parm_0 & OPEN_ERROR_CODES_MASK) - { - case OPEN_FUNCTION_FAILURE: - printk(KERN_INFO "%s: %s OPEN_FUNCTION_FAILURE", dev->name, code_err); - tp->LastOpenStatus = - OPEN_FUNCTION_FAILURE; - break; - - case OPEN_SIGNAL_LOSS: - printk(KERN_INFO "%s: %s OPEN_SIGNAL_LOSS\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_SIGNAL_LOSS; - break; - - case OPEN_TIMEOUT: - printk(KERN_INFO "%s: %s OPEN_TIMEOUT\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_TIMEOUT; - break; - - case OPEN_RING_FAILURE: - printk(KERN_INFO "%s: %s OPEN_RING_FAILURE\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_RING_FAILURE; - break; - - case OPEN_RING_BEACONING: - printk(KERN_INFO "%s: %s OPEN_RING_BEACONING\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_RING_BEACONING; - break; - - case OPEN_DUPLICATE_NODEADDR: - printk(KERN_INFO "%s: %s OPEN_DUPLICATE_NODEADDR\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_DUPLICATE_NODEADDR; - break; - - case OPEN_REQUEST_INIT: - printk(KERN_INFO "%s: %s OPEN_REQUEST_INIT\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_REQUEST_INIT; - break; - - case OPEN_REMOVE_RECEIVED: - printk(KERN_INFO "%s: %s OPEN_REMOVE_RECEIVED", dev->name, code_err); - tp->LastOpenStatus = - OPEN_REMOVE_RECEIVED; - break; - - case OPEN_FULLDUPLEX_SET: - printk(KERN_INFO "%s: %s OPEN_FULLDUPLEX_SET\n", dev->name, code_err); - tp->LastOpenStatus = - OPEN_FULLDUPLEX_SET; - break; - - default: - printk(KERN_INFO "%s: %s Unknown open err code", dev->name, code_err); - tp->LastOpenStatus = - OPEN_FUNCTION_FAILURE; - break; - } - } - - tp->AdapterOpenFlag = 0; - tp->AdapterVirtOpenFlag = 0; - - return; - } - } - else - { - if(ssb_cmd != READ_ERROR_LOG) - return; - - /* Add values from the error log table to the MAC - * statistics counters and update the errorlogtable - * memory. - */ - tp->MacStat.line_errors += tp->errorlogtable.Line_Error; - tp->MacStat.burst_errors += tp->errorlogtable.Burst_Error; - tp->MacStat.A_C_errors += tp->errorlogtable.ARI_FCI_Error; - tp->MacStat.lost_frames += tp->errorlogtable.Lost_Frame_Error; - tp->MacStat.recv_congest_count += tp->errorlogtable.Rx_Congest_Error; - tp->MacStat.rx_errors += tp->errorlogtable.Rx_Congest_Error; - tp->MacStat.frame_copied_errors += tp->errorlogtable.Frame_Copied_Error; - tp->MacStat.token_errors += tp->errorlogtable.Token_Error; - tp->MacStat.dummy1 += tp->errorlogtable.DMA_Bus_Error; - tp->MacStat.dummy1 += tp->errorlogtable.DMA_Parity_Error; - tp->MacStat.abort_delimiters += tp->errorlogtable.AbortDelimeters; - tp->MacStat.frequency_errors += tp->errorlogtable.Frequency_Error; - tp->MacStat.internal_errors += tp->errorlogtable.Internal_Error; - } - - return; -} - -/* - * The inverse routine to sktr_open(). - */ -static int sktr_close(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - - dev->tbusy = 1; - dev->start = 0; - - del_timer(&tp->timer); - - /* Flush the Tx and disable Rx here. */ - - tp->HaltInProgress = 1; - sktr_exec_cmd(dev, OC_CLOSE); - tp->timer.expires = jiffies + 1*HZ; - tp->timer.function = sktr_timer_end_wait; - tp->timer.data = (unsigned long)dev; - add_timer(&tp->timer); - - sktr_enable_interrupts(dev); - - tp->Sleeping = 1; - interruptible_sleep_on(&tp->wait_for_tok_int); - tp->TransmitCommandActive = 0; - - del_timer(&tp->timer); - sktr_disable_interrupts(dev); - - if(dev->dma > 0) - { - unsigned long flags=claim_dma_lock(); - disable_dma(dev->dma); - release_dma_lock(flags); - } - - outw(0xFF00, dev->base_addr + SIFCMD); - if(dev->dma > 0) - outb(0xff, dev->base_addr + POSREG); - -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif - - sktr_cancel_tx_queue(tp); - - return (0); -} - -/* - * Get the current statistics. This may be called with the card open - * or closed. - */ -static struct enet_statistics *sktr_get_stats(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - - return ((struct enet_statistics *)&tp->MacStat); -} - -/* - * Set or clear the multicast filter for this adapter. - */ -static void sktr_set_multicast_list(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - unsigned int OpenOptions; - - OpenOptions = tp->ocpl.OPENOptions & - ~(PASS_ADAPTER_MAC_FRAMES - | PASS_ATTENTION_FRAMES - | PASS_BEACON_MAC_FRAMES - | COPY_ALL_MAC_FRAMES - | COPY_ALL_NON_MAC_FRAMES); - - tp->ocpl.FunctAddr = 0; - - if(dev->flags & IFF_PROMISC) - /* Enable promiscuous mode */ - OpenOptions |= COPY_ALL_NON_MAC_FRAMES | - COPY_ALL_MAC_FRAMES; - else - { - if(dev->flags & IFF_ALLMULTI) - { - /* Disable promiscuous mode, use normal mode. */ - tp->ocpl.FunctAddr = 0xFFFFFFFF; - - } - else - { - int i; - struct dev_mc_list *mclist = dev->mc_list; - for (i=0; i< dev->mc_count; i++) - { - ((char *)(&tp->ocpl.FunctAddr))[0] |= - mclist->dmi_addr[2]; - ((char *)(&tp->ocpl.FunctAddr))[1] |= - mclist->dmi_addr[3]; - ((char *)(&tp->ocpl.FunctAddr))[2] |= - mclist->dmi_addr[4]; - ((char *)(&tp->ocpl.FunctAddr))[3] |= - mclist->dmi_addr[5]; - mclist = mclist->next; - } - } - sktr_exec_cmd(dev, OC_SET_FUNCT_ADDR); - } - - tp->ocpl.OPENOptions = OpenOptions; - sktr_exec_cmd(dev, OC_MODIFY_OPEN_PARMS); - return; -} - -/* - * Wait for some time (microseconds) - * - * udelay() is a bit harsh, but using a looser timer causes - * the bring-up-diags to stall indefinitly. - * - */ - -static void sktr_wait(unsigned long time) -{ - udelay(time); - return; -} - -/* - * Write a command value to the SIFCMD register - */ -static void sktr_exec_sifcmd(struct net_device *dev, unsigned int WriteValue) -{ - int ioaddr = dev->base_addr; - unsigned short cmd; - unsigned short SifStsValue; - unsigned long loop_counter; - - WriteValue = ((WriteValue ^ CMD_SYSTEM_IRQ) | CMD_INTERRUPT_ADAPTER); - cmd = (unsigned short)WriteValue; - loop_counter = 0,5 * 800000; - do { - SifStsValue = inw(ioaddr + SIFSTS); - } while((SifStsValue & CMD_INTERRUPT_ADAPTER) && loop_counter--); - outw(cmd, ioaddr + SIFCMD); - - return; -} - -/* - * Processes adapter hardware reset, halts adapter and downloads firmware, - * clears the halt bit. - */ -static int sktr_reset_adapter(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - unsigned short *fw_ptr = (unsigned short *)&sktr_code; - unsigned short count, c; - int ioaddr = dev->base_addr; - - /* Hardware adapter reset */ - outw(ACL_ARESET, ioaddr + SIFACL); - sktr_wait(40); - - c = inw(ioaddr + SIFACL); - sktr_wait(20); - - if(dev->dma == 0) /* For PCI adapters */ - { - c &= ~(ACL_SPEED4 | ACL_SPEED16); /* Clear bits */ - if(tp->DataRate == SPEED_4) - c |= ACL_SPEED4; /* Set 4Mbps */ - else - c |= ACL_SPEED16; /* Set 16Mbps */ - } - - /* In case a command is pending - forget it */ - tp->ScbInUse = 0; - - c &= ~ACL_ARESET; /* Clear adapter reset bit */ - c |= ACL_CPHALT; /* Halt adapter CPU, allow download */ - c &= ~ACL_PSDMAEN; /* Clear pseudo dma bit */ - outw(c, ioaddr + SIFACL); - sktr_wait(40); - - /* Download firmware via DIO interface: */ - do { - /* Download first address part */ - outw(*fw_ptr, ioaddr + SIFADX); - fw_ptr++; - - /* Download second address part */ - outw(*fw_ptr, ioaddr + SIFADD); - fw_ptr++; - - if((count = *fw_ptr) != 0) /* Load loop counter */ - { - fw_ptr++; /* Download block data */ - for(; count > 0; count--) - { - outw(*fw_ptr, ioaddr + SIFINC); - fw_ptr++; - } - } - else /* Stop, if last block downloaded */ - { - c = inw(ioaddr + SIFACL); - c &= (~ACL_CPHALT | ACL_SINTEN); - - /* Clear CPHALT and start BUD */ - outw(c, ioaddr + SIFACL); - return (1); - } - } while(count == 0); - - return (-1); -} - -/* - * Starts bring up diagnostics of token ring adapter and evaluates - * diagnostic results. - */ -static int sktr_bringup_diags(struct net_device *dev) -{ - int loop_cnt, retry_cnt; - unsigned short Status; - int ioaddr = dev->base_addr; - - sktr_wait(HALF_SECOND); - sktr_exec_sifcmd(dev, EXEC_SOFT_RESET); - sktr_wait(HALF_SECOND); - - retry_cnt = BUD_MAX_RETRIES; /* maximal number of retrys */ - - do { - retry_cnt--; - if(sktr_debug > 3) - printk(KERN_INFO "BUD-Status: \n"); - loop_cnt = BUD_MAX_LOOPCNT; /* maximum: three seconds*/ - do { /* Inspect BUD results */ - loop_cnt--; - sktr_wait(HALF_SECOND); - Status = inw(ioaddr + SIFSTS); - Status &= STS_MASK; - - if(sktr_debug > 3) - printk(KERN_INFO " %04X \n", Status); - /* BUD successfully completed */ - if(Status == STS_INITIALIZE) - return (1); - /* Unrecoverable hardware error, BUD not completed? */ - } while((loop_cnt > 0) && ((Status & (STS_ERROR | STS_TEST)) - != (STS_ERROR | STS_TEST))); - - /* Error preventing completion of BUD */ - if(retry_cnt > 0) - { - printk(KERN_INFO "%s: Adapter Software Reset.\n", - dev->name); - sktr_exec_sifcmd(dev, EXEC_SOFT_RESET); - sktr_wait(HALF_SECOND); - } - } while(retry_cnt > 0); - - Status = inw(ioaddr + SIFSTS); - Status &= STS_ERROR_MASK; /* Hardware error occurred! */ - - printk(KERN_INFO "%s: Bring Up Diagnostics Error (%04X) occurred\n", - dev->name, Status); - - return (-1); -} - -/* - * Copy initialisation data to adapter memory, beginning at address - * 1:0A00; Starting DMA test and evaluating result bits. - */ -static int sktr_init_adapter(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - - const unsigned char SCB_Test[6] = {0x00, 0x00, 0xC1, 0xE2, 0xD4, 0x8B}; - const unsigned char SSB_Test[8] = {0xFF, 0xFF, 0xD1, 0xD7, - 0xC5, 0xD9, 0xC3, 0xD4}; - void *ptr = (void *)&tp->ipb; - unsigned short *ipb_ptr = (unsigned short *)ptr; - unsigned char *cb_ptr = (unsigned char *) &tp->scb; - unsigned char *sb_ptr = (unsigned char *) &tp->ssb; - unsigned short Status; - int i, loop_cnt, retry_cnt; - int ioaddr = dev->base_addr; - - /* Normalize: byte order low/high, word order high/low! (only IPB!) */ - tp->ipb.SCB_Addr = SWAPW(virt_to_bus(&tp->scb)); - tp->ipb.SSB_Addr = SWAPW(virt_to_bus(&tp->ssb)); - - /* Maximum: three initialization retries */ - retry_cnt = INIT_MAX_RETRIES; - - do { - retry_cnt--; - - /* Transfer initialization block */ - outw(0x0001, ioaddr + SIFADX); - - /* To address 0001:0A00 of adapter RAM */ - outw(0x0A00, ioaddr + SIFADD); - - /* Write 11 words to adapter RAM */ - for(i = 0; i < 11; i++) - outw(ipb_ptr[i], ioaddr + SIFINC); - - /* Execute SCB adapter command */ - sktr_exec_sifcmd(dev, CMD_EXECUTE); - - loop_cnt = INIT_MAX_LOOPCNT; /* Maximum: 11 seconds */ - - /* While remaining retries, no error and not completed */ - do { - Status = 0; - loop_cnt--; - sktr_wait(HALF_SECOND); - - /* Mask interesting status bits */ - Status = inw(ioaddr + SIFSTS); - Status &= STS_MASK; - } while(((Status &(STS_INITIALIZE | STS_ERROR | STS_TEST)) != 0) - && ((Status & STS_ERROR) == 0) && (loop_cnt != 0)); - - if((Status & (STS_INITIALIZE | STS_ERROR | STS_TEST)) == 0) - { - /* Initialization completed without error */ - i = 0; - do { /* Test if contents of SCB is valid */ - if(SCB_Test[i] != *(cb_ptr + i)) - /* DMA data error: wrong data in SCB */ - return (-1); - i++; - } while(i < 6); - - i = 0; - do { /* Test if contents of SSB is valid */ - if(SSB_Test[i] != *(sb_ptr + i)) - /* DMA data error: wrong data in SSB */ - return (-1); - i++; - } while (i < 8); - - return (1); /* Adapter successfully initialized */ - } - else - { - if((Status & STS_ERROR) != 0) - { - /* Initialization error occurred */ - Status = inw(ioaddr + SIFSTS); - Status &= STS_ERROR_MASK; - /* ShowInitialisationErrorCode(Status); */ - return (-1); /* Unrecoverable error */ - } - else - { - if(retry_cnt > 0) - { - /* Reset adapter and try init again */ - sktr_exec_sifcmd(dev, EXEC_SOFT_RESET); - sktr_wait(HALF_SECOND); - } - } - } - } while(retry_cnt > 0); - - return (-1); -} - -/* - * Check for outstanding commands in command queue and tries to execute - * command immediately. Corresponding command flag in command queue is cleared. - */ -static void sktr_chk_outstanding_cmds(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - unsigned long Addr = 0; - unsigned char i = 0; - - if(tp->CMDqueue == 0) - return; /* No command execution */ - - /* If SCB in use: no command */ - if(tp->ScbInUse == 1) - return; - - /* Check if adapter is opened, avoiding COMMAND_REJECT - * interrupt by the adapter! - */ - if(tp->AdapterOpenFlag == 0) - { - if(tp->CMDqueue & OC_OPEN) - { - /* Execute OPEN command */ - tp->CMDqueue ^= OC_OPEN; - - /* Copy the 18 bytes of the product ID */ - while((AdapterName[i] != '\0') && (i < PROD_ID_SIZE)) - { - tp->ProductID[i] = AdapterName[i]; - i++; - } - - Addr = htonl(virt_to_bus(&tp->ocpl)); - tp->scb.Parm[0] = LOWORD(Addr); - tp->scb.Parm[1] = HIWORD(Addr); - tp->scb.CMD = OPEN; - } - else - /* No OPEN command queued, but adapter closed. Note: - * We'll try to re-open the adapter in DriverPoll() - */ - return; /* No adapter command issued */ - } - else - { - /* Adapter is open; evaluate command queue: try to execute - * outstanding commands (depending on priority!) CLOSE - * command queued - */ - if(tp->CMDqueue & OC_CLOSE) - { - tp->CMDqueue ^= OC_CLOSE; - tp->AdapterOpenFlag = 0; - tp->scb.Parm[0] = 0; /* Parm[0], Parm[1] are ignored */ - tp->scb.Parm[1] = 0; /* but should be set to zero! */ - tp->scb.CMD = CLOSE; - if(!tp->HaltInProgress) - tp->CMDqueue |= OC_OPEN; /* re-open adapter */ - else - tp->CMDqueue = 0; /* no more commands */ - } - else - { - if(tp->CMDqueue & OC_RECEIVE) - { - tp->CMDqueue ^= OC_RECEIVE; - Addr = htonl(virt_to_bus(tp->RplHead)); - tp->scb.Parm[0] = LOWORD(Addr); - tp->scb.Parm[1] = HIWORD(Addr); - tp->scb.CMD = RECEIVE; - } - else - { - if(tp->CMDqueue & OC_TRANSMIT_HALT) - { - /* NOTE: TRANSMIT.HALT must be checked - * before TRANSMIT. - */ - tp->CMDqueue ^= OC_TRANSMIT_HALT; - tp->scb.CMD = TRANSMIT_HALT; - - /* Parm[0] and Parm[1] are ignored - * but should be set to zero! - */ - tp->scb.Parm[0] = 0; - tp->scb.Parm[1] = 0; - } - else - { - if(tp->CMDqueue & OC_TRANSMIT) - { - /* NOTE: TRANSMIT must be - * checked after TRANSMIT.HALT - */ - if(tp->TransmitCommandActive) - { - if(!tp->TransmitHaltScheduled) - { - tp->TransmitHaltScheduled = 1; - sktr_exec_cmd(dev, OC_TRANSMIT_HALT) ; - } - tp->TransmitCommandActive = 0; - return; - } - - tp->CMDqueue ^= OC_TRANSMIT; - sktr_cancel_tx_queue(tp); - Addr = htonl(virt_to_bus(tp->TplBusy)); - tp->scb.Parm[0] = LOWORD(Addr); - tp->scb.Parm[1] = HIWORD(Addr); - tp->scb.CMD = TRANSMIT; - tp->TransmitCommandActive = 1; - } - else - { - if(tp->CMDqueue & OC_MODIFY_OPEN_PARMS) - { - tp->CMDqueue ^= OC_MODIFY_OPEN_PARMS; - tp->scb.Parm[0] = tp->ocpl.OPENOptions; /* new OPEN options*/ - tp->scb.Parm[0] |= ENABLE_FULL_DUPLEX_SELECTION; - tp->scb.Parm[1] = 0; /* is ignored but should be zero */ - tp->scb.CMD = MODIFY_OPEN_PARMS; - } - else - { - if(tp->CMDqueue & OC_SET_FUNCT_ADDR) - { - tp->CMDqueue ^= OC_SET_FUNCT_ADDR; - tp->scb.Parm[0] = LOWORD(tp->ocpl.FunctAddr); - tp->scb.Parm[1] = HIWORD(tp->ocpl.FunctAddr); - tp->scb.CMD = SET_FUNCT_ADDR; - } - else - { - if(tp->CMDqueue & OC_SET_GROUP_ADDR) - { - tp->CMDqueue ^= OC_SET_GROUP_ADDR; - tp->scb.Parm[0] = LOWORD(tp->ocpl.GroupAddr); - tp->scb.Parm[1] = HIWORD(tp->ocpl.GroupAddr); - tp->scb.CMD = SET_GROUP_ADDR; - } - else - { - if(tp->CMDqueue & OC_READ_ERROR_LOG) - { - tp->CMDqueue ^= OC_READ_ERROR_LOG; - Addr = htonl(virt_to_bus(&tp->errorlogtable)); - tp->scb.Parm[0] = LOWORD(Addr); - tp->scb.Parm[1] = HIWORD(Addr); - tp->scb.CMD = READ_ERROR_LOG; - } - else - { - printk(KERN_WARNING "CheckForOutstandingCommand: unknown Command\n"); - tp->CMDqueue = 0; - return; - } - } - } - } - } - } - } - } - } - - tp->ScbInUse = 1; /* Set semaphore: SCB in use. */ - - /* Execute SCB and generate IRQ when done. */ - sktr_exec_sifcmd(dev, CMD_EXECUTE | CMD_SCB_REQUEST); - - return; -} - -/* - * IRQ conditions: signal loss on the ring, transmit or receive of beacon - * frames (disabled if bit 1 of OPEN option is set); report error MAC - * frame transmit (disabled if bit 2 of OPEN option is set); open or short - * cirquit fault on the lobe is detected; remove MAC frame received; - * error counter overflow (255); opened adapter is the only station in ring. - * After some of the IRQs the adapter is closed! - */ -static void sktr_ring_status_irq(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - - tp->CurrentRingStatus = SWAPB(tp->ssb.Parm[0]); - - /* First: fill up statistics */ - if(tp->ssb.Parm[0] & SIGNAL_LOSS) - { - printk(KERN_INFO "%s: Signal Loss\n", dev->name); - tp->MacStat.line_errors++; - } - - /* Adapter is closed, but initialized */ - if(tp->ssb.Parm[0] & LOBE_WIRE_FAULT) - { - printk(KERN_INFO "%s: Lobe Wire Fault, Reopen Adapter\n", - dev->name); - tp->MacStat.line_errors++; - } - - if(tp->ssb.Parm[0] & RING_RECOVERY) - printk(KERN_INFO "%s: Ring Recovery\n", dev->name); - - /* Counter overflow: read error log */ - if(tp->ssb.Parm[0] & COUNTER_OVERFLOW) - { - printk(KERN_INFO "%s: Counter Overflow\n", dev->name); - sktr_exec_cmd(dev, OC_READ_ERROR_LOG); - } - - /* Adapter is closed, but initialized */ - if(tp->ssb.Parm[0] & REMOVE_RECEIVED) - printk(KERN_INFO "%s: Remove Received, Reopen Adapter\n", - dev->name); - - /* Adapter is closed, but initialized */ - if(tp->ssb.Parm[0] & AUTO_REMOVAL_ERROR) - printk(KERN_INFO "%s: Auto Removal Error, Reopen Adapter\n", - dev->name); - - if(tp->ssb.Parm[0] & HARD_ERROR) - printk(KERN_INFO "%s: Hard Error\n", dev->name); - - if(tp->ssb.Parm[0] & SOFT_ERROR) - printk(KERN_INFO "%s: Soft Error\n", dev->name); - - if(tp->ssb.Parm[0] & TRANSMIT_BEACON) - printk(KERN_INFO "%s: Transmit Beacon\n", dev->name); - - if(tp->ssb.Parm[0] & SINGLE_STATION) - printk(KERN_INFO "%s: Single Station\n", dev->name); - - /* Check if adapter has been closed */ - if(tp->ssb.Parm[0] & ADAPTER_CLOSED) - { - printk(KERN_INFO "%s: Adapter closed (Reopening)," - "QueueSkb %d, CurrentRingStat %x\n", - dev->name, tp->QueueSkb, tp->CurrentRingStatus); - tp->AdapterOpenFlag = 0; - sktr_open_adapter(dev); - } - - return; -} - -/* - * Issued if adapter has encountered an unrecoverable hardware - * or software error. - */ -static void sktr_chk_irq(struct net_device *dev) -{ - int i; - unsigned short AdapterCheckBlock[4]; - unsigned short ioaddr = dev->base_addr; - struct net_local *tp = (struct net_local *)dev->priv; - - tp->AdapterOpenFlag = 0; /* Adapter closed now */ - - /* Page number of adapter memory */ - outw(0x0001, ioaddr + SIFADX); - /* Address offset */ - outw(CHECKADDR, ioaddr + SIFADR); - - /* Reading 8 byte adapter check block. */ - for(i = 0; i < 4; i++) - AdapterCheckBlock[i] = inw(ioaddr + SIFINC); - - if(sktr_debug > 3) - { - printk("%s: AdapterCheckBlock: ", dev->name); - for (i = 0; i < 4; i++) - printk("%04X", AdapterCheckBlock[i]); - printk("\n"); - } - - switch(AdapterCheckBlock[0]) - { - case DIO_PARITY: - printk(KERN_INFO "%s: DIO parity error\n", dev->name); - break; - - case DMA_READ_ABORT: - printk(KERN_INFO "%s DMA read operation aborted:\n", - dev->name); - switch (AdapterCheckBlock[1]) - { - case 0: - printk(KERN_INFO "Timeout\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - case 1: - printk(KERN_INFO "Parity error\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - case 2: - printk(KERN_INFO "Bus error\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - default: - printk(KERN_INFO "Unknown error.\n"); - break; - } - break; - - case DMA_WRITE_ABORT: - printk(KERN_INFO "%s: DMA write operation aborted: \n", - dev->name); - switch (AdapterCheckBlock[1]) - { - case 0: - printk(KERN_INFO "Timeout\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - case 1: - printk(KERN_INFO "Parity error\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - case 2: - printk(KERN_INFO "Bus error\n"); - printk(KERN_INFO "Address: %04X %04X\n", - AdapterCheckBlock[2], - AdapterCheckBlock[3]); - break; - - default: - printk(KERN_INFO "Unknown error.\n"); - break; - } - break; - - case ILLEGAL_OP_CODE: - printk("%s: Illegal operation code in firmware\n", - dev->name); - /* Parm[0-3]: adapter internal register R13-R15 */ - break; - - case PARITY_ERRORS: - printk("%s: Adapter internal bus parity error\n", - dev->name); - /* Parm[0-3]: adapter internal register R13-R15 */ - break; - - case RAM_DATA_ERROR: - printk("%s: RAM data error\n", dev->name); - /* Parm[0-1]: MSW/LSW address of RAM location. */ - break; - - case RAM_PARITY_ERROR: - printk("%s: RAM parity error\n", dev->name); - /* Parm[0-1]: MSW/LSW address of RAM location. */ - break; - - case RING_UNDERRUN: - printk("%s: Internal DMA underrun detected\n", - dev->name); - break; - - case INVALID_IRQ: - printk("%s: Unrecognized interrupt detected\n", - dev->name); - /* Parm[0-3]: adapter internal register R13-R15 */ - break; - - case INVALID_ERROR_IRQ: - printk("%s: Unrecognized error interrupt detected\n", - dev->name); - /* Parm[0-3]: adapter internal register R13-R15 */ - break; - - case INVALID_XOP: - printk("%s: Unrecognized XOP request detected\n", - dev->name); - /* Parm[0-3]: adapter internal register R13-R15 */ - break; - - default: - printk("%s: Unknown status", dev->name); - break; - } - - if(sktr_chipset_init(dev) == 1) - { - /* Restart of firmware successful */ - tp->AdapterOpenFlag = 1; - } - - return; -} - -/* - * Internal adapter pointer to RAM data are copied from adapter into - * host system. - */ -static void sktr_read_ptr(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - unsigned short adapterram; - - sktr_read_ram(dev, (unsigned char *)&tp->intptrs.BurnedInAddrPtr, - ADAPTER_INT_PTRS, 16); - sktr_read_ram(dev, (unsigned char *)&adapterram, - (unsigned short)SWAPB(tp->intptrs.AdapterRAMPtr), 2); - - printk(KERN_INFO "%s: Adapter RAM size: %d K\n", - dev->name, SWAPB(adapterram)); - - return; -} - -/* - * Reads a number of bytes from adapter to system memory. - */ -static void sktr_read_ram(struct net_device *dev, unsigned char *Data, - unsigned short Address, int Length) -{ - int i; - unsigned short old_sifadx, old_sifadr, InWord; - unsigned short ioaddr = dev->base_addr; - - /* Save the current values */ - old_sifadx = inw(ioaddr + SIFADX); - old_sifadr = inw(ioaddr + SIFADR); - - /* Page number of adapter memory */ - outw(0x0001, ioaddr + SIFADX); - /* Address offset in adapter RAM */ - outw(Address, ioaddr + SIFADR); - - /* Copy len byte from adapter memory to system data area. */ - i = 0; - for(;;) - { - InWord = inw(ioaddr + SIFINC); - - *(Data + i) = HIBYTE(InWord); /* Write first byte */ - if(++i == Length) /* All is done break */ - break; - - *(Data + i) = LOBYTE(InWord); /* Write second byte */ - if (++i == Length) /* All is done break */ - break; - } - - /* Restore original values */ - outw(old_sifadx, ioaddr + SIFADX); - outw(old_sifadr, ioaddr + SIFADR); - - return; -} - -/* - * Reads MAC address from adapter ROM. - */ -static void sktr_read_addr(struct net_device *dev, unsigned char *Address) -{ - int i, In; - unsigned short ioaddr = dev->base_addr; - - /* Address: 0000:0000 */ - outw(0, ioaddr + SIFADX); - outw(0, ioaddr + SIFADR); - - /* Read six byte MAC address data */ - for(i = 0; i < 6; i++) - { - In = inw(ioaddr + SIFINC); - *(Address + i) = (unsigned char)(In >> 8); - } - - return; -} - -/* - * Cancel all queued packets in the transmission queue. - */ -static void sktr_cancel_tx_queue(struct net_local* tp) -{ - TPL *tpl; - struct sk_buff *skb; - - /* - * NOTE: There must not be an active TRANSMIT command pending, when - * this function is called. - */ - if(tp->TransmitCommandActive) - return; - - for(;;) - { - tpl = tp->TplBusy; - if(!tpl->BusyFlag) - break; - /* "Remove" TPL from busy list. */ - tp->TplBusy = tpl->NextTPLPtr; - sktr_write_tpl_status(tpl, 0); /* Clear VALID bit */ - tpl->BusyFlag = 0; /* "free" TPL */ - - printk(KERN_INFO "Cancel tx (%08lXh).\n", (unsigned long)tpl); - - dev_kfree_skb(tpl->Skb); - } - - for(;;) - { - skb = skb_dequeue(&tp->SendSkbQueue); - if(skb == NULL) - break; - tp->QueueSkb++; - dev_kfree_skb(skb); - } - - return; -} - -/* - * This function is called whenever a transmit interrupt is generated by the - * adapter. For a command complete interrupt, it is checked if we have to - * issue a new transmit command or not. - */ -static void sktr_tx_status_irq(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - unsigned char HighByte, HighAc, LowAc; - TPL *tpl; - - /* NOTE: At this point the SSB from TRANSMIT STATUS is no longer - * available, because the CLEAR SSB command has already been issued. - * - * Process all complete transmissions. - */ - - for(;;) - { - tpl = tp->TplBusy; - if(!tpl->BusyFlag || (tpl->Status - & (TX_VALID | TX_FRAME_COMPLETE)) - != TX_FRAME_COMPLETE) - { - break; - } - - /* "Remove" TPL from busy list. */ - tp->TplBusy = tpl->NextTPLPtr ; - - if(sktr_debug > 3) - sktr_dump(tpl->MData, SWAPB(tpl->FrameSize)); - - /* Check the transmit status field only for directed frames*/ - if(DIRECTED_FRAME(tpl) && (tpl->Status & TX_ERROR) == 0) - { - HighByte = GET_TRANSMIT_STATUS_HIGH_BYTE(tpl->Status); - HighAc = GET_FRAME_STATUS_HIGH_AC(HighByte); - LowAc = GET_FRAME_STATUS_LOW_AC(HighByte); - - if((HighAc != LowAc) || (HighAc == AC_NOT_RECOGNIZED)) - { - printk(KERN_INFO "%s: (DA=%08lX not recognized)", - dev->name, - *(unsigned long *)&tpl->MData[2+2]); - } - else - { - if(sktr_debug > 3) - printk("%s: Directed frame tx'd\n", - dev->name); - } - } - else - { - if(!DIRECTED_FRAME(tpl)) - { - if(sktr_debug > 3) - printk("%s: Broadcast frame tx'd\n", - dev->name); - } - } - - tp->MacStat.tx_packets++; - dev_kfree_skb(tpl->Skb); - tpl->BusyFlag = 0; /* "free" TPL */ - } - - dev->tbusy = 0; - if(tp->QueueSkb < MAX_TX_QUEUE) - sktr_hardware_send_packet(dev, tp); - - return; -} - -/* - * Called if a frame receive interrupt is generated by the adapter. - * Check if the frame is valid and indicate it to system. - */ -static void sktr_rcv_status_irq(struct net_device *dev) -{ - struct net_local *tp = (struct net_local *)dev->priv; - unsigned char *ReceiveDataPtr; - struct sk_buff *skb; - unsigned int Length, Length2; - RPL *rpl; - RPL *SaveHead; - - /* NOTE: At this point the SSB from RECEIVE STATUS is no longer - * available, because the CLEAR SSB command has already been issued. - * - * Process all complete receives. - */ - - for(;;) - { - rpl = tp->RplHead; - if(rpl->Status & RX_VALID) - break; /* RPL still in use by adapter */ - - /* Forward RPLHead pointer to next list. */ - SaveHead = tp->RplHead; - tp->RplHead = rpl->NextRPLPtr; - - /* Get the frame size (Byte swap for Intel). - * Do this early (see workaround comment below) - */ - Length = (unsigned short)SWAPB(rpl->FrameSize); - - /* Check if the Frame_Start, Frame_End and - * Frame_Complete bits are set. - */ - if((rpl->Status & VALID_SINGLE_BUFFER_FRAME) - == VALID_SINGLE_BUFFER_FRAME) - { - ReceiveDataPtr = rpl->MData; - - /* Workaround for delayed write of FrameSize on ISA - * (FrameSize is false but valid-bit is reset) - * Frame size is set to zero when the RPL is freed. - * Length2 is there because there have also been - * cases where the FrameSize was partially written - */ - Length2 = (unsigned short)SWAPB(rpl->FrameSize); - - if(Length == 0 || Length != Length2) - { - tp->RplHead = SaveHead; - break; /* Return to sktr_interrupt */ - } - - /* Drop frames sent by myself */ - if(sktr_chk_frame(dev, rpl->MData)) - { - if(rpl->Skb != NULL) - dev_kfree_skb(rpl->Skb); - } - else - { - sktr_update_rcv_stats(tp,ReceiveDataPtr,Length); - - if(sktr_debug > 3) - printk("%s: Packet Length %04X (%d)\n", - dev->name, Length, Length); - - /* Indicate the received frame to system. - * The source routing padding is no more - * necessary with 2.2.x kernel. - * See: OpenOptions in sktr_init_opb() - */ - skb = rpl->Skb; - if(rpl->SkbStat == SKB_UNAVAILABLE) - { - /* Try again to allocate skb */ - skb = dev_alloc_skb(tp->MaxPacketSize); - if(skb == NULL) - { - /* Update Stats ?? */ - } - else - { - skb->dev = dev; - skb_put(skb, tp->MaxPacketSize); - rpl->SkbStat = SKB_DATA_COPY; - ReceiveDataPtr = rpl->MData; - } - } - - if(rpl->SkbStat == SKB_DATA_COPY - || rpl->SkbStat == SKB_DMA_DIRECT) - { - if(rpl->SkbStat == SKB_DATA_COPY) - { - memmove(skb->data, ReceiveDataPtr, Length); - } - - /* Deliver frame to system */ - rpl->Skb = NULL; - skb_trim(skb,Length); - skb->dev = dev; - skb->protocol = tr_type_trans(skb,dev); - netif_rx(skb); - } - } - } - else /* Invalid frame */ - { - if(rpl->Skb != NULL) - dev_kfree_skb(rpl->Skb); - - /* Skip list. */ - if(rpl->Status & RX_START_FRAME) - /* Frame start bit is set -> overflow. */ - tp->MacStat.rx_errors++; - } - - /* Allocate new skb for rpl */ - rpl->Skb = dev_alloc_skb(tp->MaxPacketSize); - - /* skb == NULL ? then use local buffer */ - if(rpl->Skb == NULL) - { - rpl->SkbStat = SKB_UNAVAILABLE; - rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex])); - rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex]; - } - else /* skb != NULL */ - { - rpl->Skb->dev = dev; - skb_put(rpl->Skb, tp->MaxPacketSize); - - /* Data unreachable for DMA ? then use local buffer */ - if(tp->DeviceType == SK_ISA && - virt_to_bus(rpl->Skb->data) + tp->MaxPacketSize - > ISA_MAX_ADDRESS) - { - rpl->SkbStat = SKB_DATA_COPY; - rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex])); - rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex]; - } - else - { - /* DMA directly in skb->data */ - rpl->SkbStat = SKB_DMA_DIRECT; - rpl->FragList[0].DataAddr = htonl(virt_to_bus(rpl->Skb->data)); - rpl->MData = rpl->Skb->data; - } - } - - rpl->FragList[0].DataCount = SWAPB(tp->MaxPacketSize); - rpl->FrameSize = 0; - - /* Pass the last RPL back to the adapter */ - tp->RplTail->FrameSize = 0; - - /* Reset the CSTAT field in the list. */ - sktr_write_rpl_status(tp->RplTail, RX_VALID | RX_FRAME_IRQ); - - /* Current RPL becomes last one in list. */ - tp->RplTail = tp->RplTail->NextRPLPtr; - - /* Inform adapter about RPL valid. */ - sktr_exec_sifcmd(dev, CMD_RX_VALID); - } - - return; -} - -/* - * This function should be used whenever the status of any RPL must be - * modified by the driver, because the compiler may otherwise change the - * order of instructions such that writing the RPL status may be executed - * at an undesireable time. When this function is used, the status is - * always written when the function is called. - */ -static void sktr_write_rpl_status(RPL *rpl, unsigned int Status) -{ - rpl->Status = Status; - - return; -} - -/* - * The function updates the statistic counters in mac->MacStat. - * It differtiates between directed and broadcast/multicast ( ==functional) - * frames. - */ -static void sktr_update_rcv_stats(struct net_local *tp, unsigned char DataPtr[], - unsigned int Length) -{ - tp->MacStat.rx_packets++; - - /* Test functional bit */ - if(DataPtr[2] & GROUP_BIT) - tp->MacStat.multicast++; - - return; -} - -/* - * Check if it is a frame of myself. Compare source address with my current - * address in reverse direction, and mask out the TR_RII. - */ -static unsigned char sktr_chk_frame(struct net_device *dev, unsigned char *Addr) -{ - int i; - - for(i = 5; i > 0; i--) - { - if(Addr[8 + i] != dev->dev_addr[i]) - return (0); - } - - /* Mask out RIF bit. */ - if((Addr[8] & ~TR_RII) != (unsigned char)(dev->dev_addr[0])) - return (0); - - return (1); /* It is my frame. */ -} - -/* - * Dump Packet (data) - */ -static void sktr_dump(unsigned char *Data, int length) -{ - int i, j; - - for (i = 0, j = 0; i < length / 8; i++, j += 8) - { - printk(KERN_DEBUG "%02x %02x %02x %02x %02x %02x %02x %02x\n", - Data[j+0],Data[j+1],Data[j+2],Data[j+3], - Data[j+4],Data[j+5],Data[j+6],Data[j+7]); - } - - return; -} - -#ifdef MODULE - -static struct net_device* dev_sktr[SKTR_MAX_ADAPTERS]; -static int io[SKTR_MAX_ADAPTERS] = { 0, 0 }; -static int irq[SKTR_MAX_ADAPTERS] = { 0, 0 }; -static int mem[SKTR_MAX_ADAPTERS] = { 0, 0 }; - -MODULE_PARM(io, "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i"); -MODULE_PARM(irq, "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i"); -MODULE_PARM(mem, "1-" __MODULE_STRING(SKTR_MAX_ADAPTERS) "i"); - -int init_module(void) -{ - int i; - - for(i = 0; i < SKTR_MAX_ADAPTERS; i++) - { - irq[i] = 0; - mem[i] = 0; - dev_sktr[i] = NULL; - dev_sktr[i] = init_trdev(dev_sktr[i], 0); - if(dev_sktr[i] == NULL) - return (-ENOMEM); - - dev_sktr[i]->base_addr = io[i]; - dev_sktr[i]->irq = irq[i]; - dev_sktr[i]->mem_start = mem[i]; - dev_sktr[i]->init = &sktr_probe; - - if(register_trdev(dev_sktr[i]) != 0) - { - kfree_s(dev_sktr[i], sizeof(struct net_device)); - dev_sktr[i] = NULL; - if(i == 0) - { - printk("sktr: register_trdev() returned non-zero.\n"); - return (-EIO); - } - else - return (0); - } - } - - return (0); -} - -void cleanup_module(void) -{ - int i; - - for(i = 0; i < SKTR_MAX_ADAPTERS; i++) - { - if(dev_sktr[i]) - { - unregister_trdev(dev_sktr[i]); - release_region(dev_sktr[i]->base_addr, SKTR_IO_EXTENT); - if(dev_sktr[i]->irq) - free_irq(dev_sktr[i]->irq, dev_sktr[i]); - if(dev_sktr[i]->dma > 0) - free_dma(dev_sktr[i]->dma); - if(dev_sktr[i]->priv) - kfree_s(dev_sktr[i]->priv, sizeof(struct net_local)); - kfree_s(dev_sktr[i], sizeof(struct net_device)); - dev_sktr[i] = NULL; - } - } -} -#endif /* MODULE */ |