From 33f810b2036f13f1b123062a9e5c1794d400ce81 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Sun, 31 Jul 2011 00:06:29 -0700 Subject: fddi: Move the FDDI drivers Move the FDDI drivers into drivers/net/fddi/ and make the necessary Kconfig and Makefile changes. CC: "Maciej W. Rozycki" CC: Christoph Goos CC: Signed-off-by: Jeff Kirsher diff --git a/MAINTAINERS b/MAINTAINERS index d32e1ca..2777088 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2113,7 +2113,7 @@ F: net/decnet/ DEFXX FDDI NETWORK DRIVER M: "Maciej W. Rozycki" S: Maintained -F: drivers/net/defxx.* +F: drivers/net/fddi/defxx.* DELL LAPTOP DRIVER M: Matthew Garrett diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ef6b6be..7bdc22b 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -195,6 +195,8 @@ config SUNGEM_PHY source "drivers/net/ethernet/Kconfig" +source "drivers/net/fddi/Kconfig" + source "drivers/net/tokenring/Kconfig" source "drivers/net/wireless/Kconfig" @@ -268,76 +270,6 @@ config RIONET_RX_SIZE depends on RIONET default "128" -config FDDI - tristate "FDDI driver support" - depends on (PCI || EISA || TC) - help - Fiber Distributed Data Interface is a high speed local area network - design; essentially a replacement for high speed Ethernet. FDDI can - run over copper or fiber. If you are connected to such a network and - want a driver for the FDDI card in your computer, say Y here (and - then also Y to the driver for your FDDI card, below). Most people - will say N. - -config DEFXX - tristate "Digital DEFTA/DEFEA/DEFPA adapter support" - depends on FDDI && (PCI || EISA || TC) - ---help--- - This is support for the DIGITAL series of TURBOchannel (DEFTA), - EISA (DEFEA) and PCI (DEFPA) controllers which can connect you - to a local FDDI network. - - To compile this driver as a module, choose M here: the module - will be called defxx. If unsure, say N. - -config DEFXX_MMIO - bool - prompt "Use MMIO instead of PIO" if PCI || EISA - depends on DEFXX - default n if PCI || EISA - default y - ---help--- - This instructs the driver to use EISA or PCI memory-mapped I/O - (MMIO) as appropriate instead of programmed I/O ports (PIO). - Enabling this gives an improvement in processing time in parts - of the driver, but it may cause problems with EISA (DEFEA) - adapters. TURBOchannel does not have the concept of I/O ports, - so MMIO is always used for these (DEFTA) adapters. - - If unsure, say N. - -config SKFP - tristate "SysKonnect FDDI PCI support" - depends on FDDI && PCI - select BITREVERSE - ---help--- - Say Y here if you have a SysKonnect FDDI PCI adapter. - The following adapters are supported by this driver: - - SK-5521 (SK-NET FDDI-UP) - - SK-5522 (SK-NET FDDI-UP DAS) - - SK-5541 (SK-NET FDDI-FP) - - SK-5543 (SK-NET FDDI-LP) - - SK-5544 (SK-NET FDDI-LP DAS) - - SK-5821 (SK-NET FDDI-UP64) - - SK-5822 (SK-NET FDDI-UP64 DAS) - - SK-5841 (SK-NET FDDI-FP64) - - SK-5843 (SK-NET FDDI-LP64) - - SK-5844 (SK-NET FDDI-LP64 DAS) - - Netelligent 100 FDDI DAS Fibre SC - - Netelligent 100 FDDI SAS Fibre SC - - Netelligent 100 FDDI DAS UTP - - Netelligent 100 FDDI SAS UTP - - Netelligent 100 FDDI SAS Fibre MIC - - Read for information about - the driver. - - Questions concerning this driver can be addressed to: - - - To compile this driver as a module, choose M here: the module - will be called skfp. This is recommended. - config HIPPI bool "HIPPI driver support (EXPERIMENTAL)" depends on EXPERIMENTAL && INET && PCI diff --git a/drivers/net/Makefile b/drivers/net/Makefile index c33009b..3087b27 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -14,7 +14,6 @@ obj-$(CONFIG_VMXNET3) += vmxnet3/ # obj-$(CONFIG_PLIP) += plip.o obj-$(CONFIG_ROADRUNNER) += rrunner.o -obj-$(CONFIG_SKFP) += skfp/ obj-$(CONFIG_RIONET) += rionet.o # @@ -42,13 +41,13 @@ obj-$(CONFIG_DUMMY) += dummy.o obj-$(CONFIG_IFB) += ifb.o obj-$(CONFIG_MACVLAN) += macvlan.o obj-$(CONFIG_MACVTAP) += macvtap.o -obj-$(CONFIG_DEFXX) += defxx.o obj-$(CONFIG_EQUALIZER) += eql.o obj-$(CONFIG_TUN) += tun.o obj-$(CONFIG_VETH) += veth.o obj-$(CONFIG_DEV_APPLETALK) += appletalk/ obj-$(CONFIG_ETHERNET) += ethernet/ +obj-$(CONFIG_FDDI) += fddi/ obj-$(CONFIG_TR) += tokenring/ obj-$(CONFIG_WAN) += wan/ obj-$(CONFIG_ARCNET) += arcnet/ diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c deleted file mode 100644 index 4ad80f77..0000000 --- a/drivers/net/defxx.c +++ /dev/null @@ -1,3739 +0,0 @@ -/* - * File Name: - * defxx.c - * - * Copyright Information: - * Copyright Digital Equipment Corporation 1996. - * - * This software may be used and distributed according to the terms of - * the GNU General Public License, incorporated herein by reference. - * - * Abstract: - * A Linux device driver supporting the Digital Equipment Corporation - * FDDI TURBOchannel, EISA and PCI controller families. Supported - * adapters include: - * - * DEC FDDIcontroller/TURBOchannel (DEFTA) - * DEC FDDIcontroller/EISA (DEFEA) - * DEC FDDIcontroller/PCI (DEFPA) - * - * The original author: - * LVS Lawrence V. Stefani - * - * Maintainers: - * macro Maciej W. Rozycki - * - * Credits: - * I'd like to thank Patricia Cross for helping me get started with - * Linux, David Davies for a lot of help upgrading and configuring - * my development system and for answering many OS and driver - * development questions, and Alan Cox for recommendations and - * integration help on getting FDDI support into Linux. LVS - * - * Driver Architecture: - * The driver architecture is largely based on previous driver work - * for other operating systems. The upper edge interface and - * functions were largely taken from existing Linux device drivers - * such as David Davies' DE4X5.C driver and Donald Becker's TULIP.C - * driver. - * - * Adapter Probe - - * The driver scans for supported EISA adapters by reading the - * SLOT ID register for each EISA slot and making a match - * against the expected value. - * - * Bus-Specific Initialization - - * This driver currently supports both EISA and PCI controller - * families. While the custom DMA chip and FDDI logic is similar - * or identical, the bus logic is very different. After - * initialization, the only bus-specific differences is in how the - * driver enables and disables interrupts. Other than that, the - * run-time critical code behaves the same on both families. - * It's important to note that both adapter families are configured - * to I/O map, rather than memory map, the adapter registers. - * - * Driver Open/Close - - * In the driver open routine, the driver ISR (interrupt service - * routine) is registered and the adapter is brought to an - * operational state. In the driver close routine, the opposite - * occurs; the driver ISR is deregistered and the adapter is - * brought to a safe, but closed state. Users may use consecutive - * commands to bring the adapter up and down as in the following - * example: - * ifconfig fddi0 up - * ifconfig fddi0 down - * ifconfig fddi0 up - * - * Driver Shutdown - - * Apparently, there is no shutdown or halt routine support under - * Linux. This routine would be called during "reboot" or - * "shutdown" to allow the driver to place the adapter in a safe - * state before a warm reboot occurs. To be really safe, the user - * should close the adapter before shutdown (eg. ifconfig fddi0 down) - * to ensure that the adapter DMA engine is taken off-line. However, - * the current driver code anticipates this problem and always issues - * a soft reset of the adapter at the beginning of driver initialization. - * A future driver enhancement in this area may occur in 2.1.X where - * Alan indicated that a shutdown handler may be implemented. - * - * Interrupt Service Routine - - * The driver supports shared interrupts, so the ISR is registered for - * each board with the appropriate flag and the pointer to that board's - * device structure. This provides the context during interrupt - * processing to support shared interrupts and multiple boards. - * - * Interrupt enabling/disabling can occur at many levels. At the host - * end, you can disable system interrupts, or disable interrupts at the - * PIC (on Intel systems). Across the bus, both EISA and PCI adapters - * have a bus-logic chip interrupt enable/disable as well as a DMA - * controller interrupt enable/disable. - * - * The driver currently enables and disables adapter interrupts at the - * bus-logic chip and assumes that Linux will take care of clearing or - * acknowledging any host-based interrupt chips. - * - * Control Functions - - * Control functions are those used to support functions such as adding - * or deleting multicast addresses, enabling or disabling packet - * reception filters, or other custom/proprietary commands. Presently, - * the driver supports the "get statistics", "set multicast list", and - * "set mac address" functions defined by Linux. A list of possible - * enhancements include: - * - * - Custom ioctl interface for executing port interface commands - * - Custom ioctl interface for adding unicast addresses to - * adapter CAM (to support bridge functions). - * - Custom ioctl interface for supporting firmware upgrades. - * - * Hardware (port interface) Support Routines - - * The driver function names that start with "dfx_hw_" represent - * low-level port interface routines that are called frequently. They - * include issuing a DMA or port control command to the adapter, - * resetting the adapter, or reading the adapter state. Since the - * driver initialization and run-time code must make calls into the - * port interface, these routines were written to be as generic and - * usable as possible. - * - * Receive Path - - * The adapter DMA engine supports a 256 entry receive descriptor block - * of which up to 255 entries can be used at any given time. The - * architecture is a standard producer, consumer, completion model in - * which the driver "produces" receive buffers to the adapter, the - * adapter "consumes" the receive buffers by DMAing incoming packet data, - * and the driver "completes" the receive buffers by servicing the - * incoming packet, then "produces" a new buffer and starts the cycle - * again. Receive buffers can be fragmented in up to 16 fragments - * (descriptor entries). For simplicity, this driver posts - * single-fragment receive buffers of 4608 bytes, then allocates a - * sk_buff, copies the data, then reposts the buffer. To reduce CPU - * utilization, a better approach would be to pass up the receive - * buffer (no extra copy) then allocate and post a replacement buffer. - * This is a performance enhancement that should be looked into at - * some point. - * - * Transmit Path - - * Like the receive path, the adapter DMA engine supports a 256 entry - * transmit descriptor block of which up to 255 entries can be used at - * any given time. Transmit buffers can be fragmented in up to 255 - * fragments (descriptor entries). This driver always posts one - * fragment per transmit packet request. - * - * The fragment contains the entire packet from FC to end of data. - * Before posting the buffer to the adapter, the driver sets a three-byte - * packet request header (PRH) which is required by the Motorola MAC chip - * used on the adapters. The PRH tells the MAC the type of token to - * receive/send, whether or not to generate and append the CRC, whether - * synchronous or asynchronous framing is used, etc. Since the PRH - * definition is not necessarily consistent across all FDDI chipsets, - * the driver, rather than the common FDDI packet handler routines, - * sets these bytes. - * - * To reduce the amount of descriptor fetches needed per transmit request, - * the driver takes advantage of the fact that there are at least three - * bytes available before the skb->data field on the outgoing transmit - * request. This is guaranteed by having fddi_setup() in net_init.c set - * dev->hard_header_len to 24 bytes. 21 bytes accounts for the largest - * header in an 802.2 SNAP frame. The other 3 bytes are the extra "pad" - * bytes which we'll use to store the PRH. - * - * There's a subtle advantage to adding these pad bytes to the - * hard_header_len, it ensures that the data portion of the packet for - * an 802.2 SNAP frame is longword aligned. Other FDDI driver - * implementations may not need the extra padding and can start copying - * or DMAing directly from the FC byte which starts at skb->data. Should - * another driver implementation need ADDITIONAL padding, the net_init.c - * module should be updated and dev->hard_header_len should be increased. - * NOTE: To maintain the alignment on the data portion of the packet, - * dev->hard_header_len should always be evenly divisible by 4 and at - * least 24 bytes in size. - * - * Modification History: - * Date Name Description - * 16-Aug-96 LVS Created. - * 20-Aug-96 LVS Updated dfx_probe so that version information - * string is only displayed if 1 or more cards are - * found. Changed dfx_rcv_queue_process to copy - * 3 NULL bytes before FC to ensure that data is - * longword aligned in receive buffer. - * 09-Sep-96 LVS Updated dfx_ctl_set_multicast_list to enable - * LLC group promiscuous mode if multicast list - * is too large. LLC individual/group promiscuous - * mode is now disabled if IFF_PROMISC flag not set. - * dfx_xmt_queue_pkt no longer checks for NULL skb - * on Alan Cox recommendation. Added node address - * override support. - * 12-Sep-96 LVS Reset current address to factory address during - * device open. Updated transmit path to post a - * single fragment which includes PRH->end of data. - * Mar 2000 AC Did various cleanups for 2.3.x - * Jun 2000 jgarzik PCI and resource alloc cleanups - * Jul 2000 tjeerd Much cleanup and some bug fixes - * Sep 2000 tjeerd Fix leak on unload, cosmetic code cleanup - * Feb 2001 Skb allocation fixes - * Feb 2001 davej PCI enable cleanups. - * 04 Aug 2003 macro Converted to the DMA API. - * 14 Aug 2004 macro Fix device names reported. - * 14 Jun 2005 macro Use irqreturn_t. - * 23 Oct 2006 macro Big-endian host support. - * 14 Dec 2006 macro TURBOchannel support. - */ - -/* Include files */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "defxx.h" - -/* Version information string should be updated prior to each new release! */ -#define DRV_NAME "defxx" -#define DRV_VERSION "v1.10" -#define DRV_RELDATE "2006/12/14" - -static char version[] __devinitdata = - DRV_NAME ": " DRV_VERSION " " DRV_RELDATE - " Lawrence V. Stefani and others\n"; - -#define DYNAMIC_BUFFERS 1 - -#define SKBUFF_RX_COPYBREAK 200 -/* - * NEW_SKB_SIZE = PI_RCV_DATA_K_SIZE_MAX+128 to allow 128 byte - * alignment for compatibility with old EISA boards. - */ -#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128) - -#ifdef CONFIG_PCI -#define DFX_BUS_PCI(dev) (dev->bus == &pci_bus_type) -#else -#define DFX_BUS_PCI(dev) 0 -#endif - -#ifdef CONFIG_EISA -#define DFX_BUS_EISA(dev) (dev->bus == &eisa_bus_type) -#else -#define DFX_BUS_EISA(dev) 0 -#endif - -#ifdef CONFIG_TC -#define DFX_BUS_TC(dev) (dev->bus == &tc_bus_type) -#else -#define DFX_BUS_TC(dev) 0 -#endif - -#ifdef CONFIG_DEFXX_MMIO -#define DFX_MMIO 1 -#else -#define DFX_MMIO 0 -#endif - -/* Define module-wide (static) routines */ - -static void dfx_bus_init(struct net_device *dev); -static void dfx_bus_uninit(struct net_device *dev); -static void dfx_bus_config_check(DFX_board_t *bp); - -static int dfx_driver_init(struct net_device *dev, - const char *print_name, - resource_size_t bar_start); -static int dfx_adap_init(DFX_board_t *bp, int get_buffers); - -static int dfx_open(struct net_device *dev); -static int dfx_close(struct net_device *dev); - -static void dfx_int_pr_halt_id(DFX_board_t *bp); -static void dfx_int_type_0_process(DFX_board_t *bp); -static void dfx_int_common(struct net_device *dev); -static irqreturn_t dfx_interrupt(int irq, void *dev_id); - -static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev); -static void dfx_ctl_set_multicast_list(struct net_device *dev); -static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr); -static int dfx_ctl_update_cam(DFX_board_t *bp); -static int dfx_ctl_update_filters(DFX_board_t *bp); - -static int dfx_hw_dma_cmd_req(DFX_board_t *bp); -static int dfx_hw_port_ctrl_req(DFX_board_t *bp, PI_UINT32 command, PI_UINT32 data_a, PI_UINT32 data_b, PI_UINT32 *host_data); -static void dfx_hw_adap_reset(DFX_board_t *bp, PI_UINT32 type); -static int dfx_hw_adap_state_rd(DFX_board_t *bp); -static int dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type); - -static int dfx_rcv_init(DFX_board_t *bp, int get_buffers); -static void dfx_rcv_queue_process(DFX_board_t *bp); -static void dfx_rcv_flush(DFX_board_t *bp); - -static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, - struct net_device *dev); -static int dfx_xmt_done(DFX_board_t *bp); -static void dfx_xmt_flush(DFX_board_t *bp); - -/* Define module-wide (static) variables */ - -static struct pci_driver dfx_pci_driver; -static struct eisa_driver dfx_eisa_driver; -static struct tc_driver dfx_tc_driver; - - -/* - * ======================= - * = dfx_port_write_long = - * = dfx_port_read_long = - * ======================= - * - * Overview: - * Routines for reading and writing values from/to adapter - * - * Returns: - * None - * - * Arguments: - * bp - pointer to board information - * offset - register offset from base I/O address - * data - for dfx_port_write_long, this is a value to write; - * for dfx_port_read_long, this is a pointer to store - * the read value - * - * Functional Description: - * These routines perform the correct operation to read or write - * the adapter register. - * - * EISA port block base addresses are based on the slot number in which the - * controller is installed. For example, if the EISA controller is installed - * in slot 4, the port block base address is 0x4000. If the controller is - * installed in slot 2, the port block base address is 0x2000, and so on. - * This port block can be used to access PDQ, ESIC, and DEFEA on-board - * registers using the register offsets defined in DEFXX.H. - * - * PCI port block base addresses are assigned by the PCI BIOS or system - * firmware. There is one 128 byte port block which can be accessed. It - * allows for I/O mapping of both PDQ and PFI registers using the register - * offsets defined in DEFXX.H. - * - * Return Codes: - * None - * - * Assumptions: - * bp->base is a valid base I/O address for this adapter. - * offset is a valid register offset for this adapter. - * - * Side Effects: - * Rather than produce macros for these functions, these routines - * are defined using "inline" to ensure that the compiler will - * generate inline code and not waste a procedure call and return. - * This provides all the benefits of macros, but with the - * advantage of strict data type checking. - */ - -static inline void dfx_writel(DFX_board_t *bp, int offset, u32 data) -{ - writel(data, bp->base.mem + offset); - mb(); -} - -static inline void dfx_outl(DFX_board_t *bp, int offset, u32 data) -{ - outl(data, bp->base.port + offset); -} - -static void dfx_port_write_long(DFX_board_t *bp, int offset, u32 data) -{ - struct device __maybe_unused *bdev = bp->bus_dev; - int dfx_bus_tc = DFX_BUS_TC(bdev); - int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; - - if (dfx_use_mmio) - dfx_writel(bp, offset, data); - else - dfx_outl(bp, offset, data); -} - - -static inline void dfx_readl(DFX_board_t *bp, int offset, u32 *data) -{ - mb(); - *data = readl(bp->base.mem + offset); -} - -static inline void dfx_inl(DFX_board_t *bp, int offset, u32 *data) -{ - *data = inl(bp->base.port + offset); -} - -static void dfx_port_read_long(DFX_board_t *bp, int offset, u32 *data) -{ - struct device __maybe_unused *bdev = bp->bus_dev; - int dfx_bus_tc = DFX_BUS_TC(bdev); - int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; - - if (dfx_use_mmio) - dfx_readl(bp, offset, data); - else - dfx_inl(bp, offset, data); -} - - -/* - * ================ - * = dfx_get_bars = - * ================ - * - * Overview: - * Retrieves the address range used to access control and status - * registers. - * - * Returns: - * None - * - * Arguments: - * bdev - pointer to device information - * bar_start - pointer to store the start address - * bar_len - pointer to store the length of the area - * - * Assumptions: - * I am sure there are some. - * - * Side Effects: - * None - */ -static void dfx_get_bars(struct device *bdev, - resource_size_t *bar_start, resource_size_t *bar_len) -{ - int dfx_bus_pci = DFX_BUS_PCI(bdev); - int dfx_bus_eisa = DFX_BUS_EISA(bdev); - int dfx_bus_tc = DFX_BUS_TC(bdev); - int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; - - if (dfx_bus_pci) { - int num = dfx_use_mmio ? 0 : 1; - - *bar_start = pci_resource_start(to_pci_dev(bdev), num); - *bar_len = pci_resource_len(to_pci_dev(bdev), num); - } - if (dfx_bus_eisa) { - unsigned long base_addr = to_eisa_device(bdev)->base_addr; - resource_size_t bar; - - if (dfx_use_mmio) { - bar = inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_2); - bar <<= 8; - bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_1); - bar <<= 8; - bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_0); - bar <<= 16; - *bar_start = bar; - bar = inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_2); - bar <<= 8; - bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_1); - bar <<= 8; - bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_0); - bar <<= 16; - *bar_len = (bar | PI_MEM_ADD_MASK_M) + 1; - } else { - *bar_start = base_addr; - *bar_len = PI_ESIC_K_CSR_IO_LEN; - } - } - if (dfx_bus_tc) { - *bar_start = to_tc_dev(bdev)->resource.start + - PI_TC_K_CSR_OFFSET; - *bar_len = PI_TC_K_CSR_LEN; - } -} - -static const struct net_device_ops dfx_netdev_ops = { - .ndo_open = dfx_open, - .ndo_stop = dfx_close, - .ndo_start_xmit = dfx_xmt_queue_pkt, - .ndo_get_stats = dfx_ctl_get_stats, - .ndo_set_rx_mode = dfx_ctl_set_multicast_list, - .ndo_set_mac_address = dfx_ctl_set_mac_address, -}; - -/* - * ================ - * = dfx_register = - * ================ - * - * Overview: - * Initializes a supported FDDI controller - * - * Returns: - * Condition code - * - * Arguments: - * bdev - pointer to device information - * - * Functional Description: - * - * Return Codes: - * 0 - This device (fddi0, fddi1, etc) configured successfully - * -EBUSY - Failed to get resources, or dfx_driver_init failed. - * - * Assumptions: - * It compiles so it should work :-( (PCI cards do :-) - * - * Side Effects: - * Device structures for FDDI adapters (fddi0, fddi1, etc) are - * initialized and the board resources are read and stored in - * the device structure. - */ -static int __devinit dfx_register(struct device *bdev) -{ - static int version_disp; - int dfx_bus_pci = DFX_BUS_PCI(bdev); - int dfx_bus_tc = DFX_BUS_TC(bdev); - int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; - const char *print_name = dev_name(bdev); - struct net_device *dev; - DFX_board_t *bp; /* board pointer */ - resource_size_t bar_start = 0; /* pointer to port */ - resource_size_t bar_len = 0; /* resource length */ - int alloc_size; /* total buffer size used */ - struct resource *region; - int err = 0; - - 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 */ - } - - dev = alloc_fddidev(sizeof(*bp)); - if (!dev) { - printk(KERN_ERR "%s: Unable to allocate fddidev, aborting\n", - print_name); - return -ENOMEM; - } - - /* Enable PCI device. */ - if (dfx_bus_pci && pci_enable_device(to_pci_dev(bdev))) { - printk(KERN_ERR "%s: Cannot enable PCI device, aborting\n", - print_name); - goto err_out; - } - - SET_NETDEV_DEV(dev, bdev); - - bp = netdev_priv(dev); - bp->bus_dev = bdev; - dev_set_drvdata(bdev, dev); - - dfx_get_bars(bdev, &bar_start, &bar_len); - - if (dfx_use_mmio) - region = request_mem_region(bar_start, bar_len, print_name); - else - region = request_region(bar_start, bar_len, print_name); - if (!region) { - printk(KERN_ERR "%s: Cannot reserve I/O resource " - "0x%lx @ 0x%lx, aborting\n", - print_name, (long)bar_len, (long)bar_start); - err = -EBUSY; - goto err_out_disable; - } - - /* Set up I/O base address. */ - if (dfx_use_mmio) { - bp->base.mem = ioremap_nocache(bar_start, bar_len); - if (!bp->base.mem) { - printk(KERN_ERR "%s: Cannot map MMIO\n", print_name); - err = -ENOMEM; - goto err_out_region; - } - } else { - bp->base.port = bar_start; - dev->base_addr = bar_start; - } - - /* Initialize new device structure */ - dev->netdev_ops = &dfx_netdev_ops; - - if (dfx_bus_pci) - pci_set_master(to_pci_dev(bdev)); - - if (dfx_driver_init(dev, print_name, bar_start) != DFX_K_SUCCESS) { - err = -ENODEV; - goto err_out_unmap; - } - - err = register_netdev(dev); - if (err) - goto err_out_kfree; - - printk("%s: registered as %s\n", print_name, dev->name); - return 0; - -err_out_kfree: - alloc_size = sizeof(PI_DESCR_BLOCK) + - PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX + -#ifndef DYNAMIC_BUFFERS - (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) + -#endif - sizeof(PI_CONSUMER_BLOCK) + - (PI_ALIGN_K_DESC_BLK - 1); - if (bp->kmalloced) - dma_free_coherent(bdev, alloc_size, - bp->kmalloced, bp->kmalloced_dma); - -err_out_unmap: - if (dfx_use_mmio) - iounmap(bp->base.mem); - -err_out_region: - if (dfx_use_mmio) - release_mem_region(bar_start, bar_len); - else - release_region(bar_start, bar_len); - -err_out_disable: - if (dfx_bus_pci) - pci_disable_device(to_pci_dev(bdev)); - -err_out: - free_netdev(dev); - return err; -} - - -/* - * ================ - * = dfx_bus_init = - * ================ - * - * Overview: - * Initializes the bus-specific controller logic. - * - * Returns: - * None - * - * Arguments: - * dev - pointer to device information - * - * Functional Description: - * Determine and save adapter IRQ in device table, - * then perform bus-specific logic initialization. - * - * Return Codes: - * None - * - * Assumptions: - * bp->base has already been set with the proper - * base I/O address for this device. - * - * Side Effects: - * Interrupts are enabled at the adapter bus-specific logic. - * Note: Interrupts at the DMA engine (PDQ chip) are not - * enabled yet. - */ - -static void __devinit dfx_bus_init(struct net_device *dev) -{ - DFX_board_t *bp = netdev_priv(dev); - struct device *bdev = bp->bus_dev; - int dfx_bus_pci = DFX_BUS_PCI(bdev); - int dfx_bus_eisa = DFX_BUS_EISA(bdev); - int dfx_bus_tc = DFX_BUS_TC(bdev); - int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; - u8 val; - - DBG_printk("In dfx_bus_init...\n"); - - /* Initialize a pointer back to the net_device struct */ - bp->dev = dev; - - /* Initialize adapter based on bus type */ - - if (dfx_bus_tc) - dev->irq = to_tc_dev(bdev)->interrupt; - if (dfx_bus_eisa) { - unsigned long base_addr = to_eisa_device(bdev)->base_addr; - - /* Get the interrupt level from the ESIC chip. */ - val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); - val &= PI_CONFIG_STAT_0_M_IRQ; - val >>= PI_CONFIG_STAT_0_V_IRQ; - - switch (val) { - case PI_CONFIG_STAT_0_IRQ_K_9: - dev->irq = 9; - break; - - case PI_CONFIG_STAT_0_IRQ_K_10: - dev->irq = 10; - break; - - case PI_CONFIG_STAT_0_IRQ_K_11: - dev->irq = 11; - break; - - case PI_CONFIG_STAT_0_IRQ_K_15: - dev->irq = 15; - break; - } - - /* - * Enable memory decoding (MEMCS0) and/or port decoding - * (IOCS1/IOCS0) as appropriate in Function Control - * Register. One of the port chip selects seems to be - * used for the Burst Holdoff register, but this bit of - * documentation is missing and as yet it has not been - * determined which of the two. This is also the reason - * the size of the decoded port range is twice as large - * as one required by the PDQ. - */ - - /* Set the decode range of the board. */ - val = ((bp->base.port >> 12) << PI_IO_CMP_V_SLOT); - outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_1, val); - outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_0, 0); - outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_1, val); - outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_0, 0); - val = PI_ESIC_K_CSR_IO_LEN - 1; - outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_1, (val >> 8) & 0xff); - outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_0, val & 0xff); - outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_1, (val >> 8) & 0xff); - outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_0, val & 0xff); - - /* Enable the decoders. */ - val = PI_FUNCTION_CNTRL_M_IOCS1 | PI_FUNCTION_CNTRL_M_IOCS0; - if (dfx_use_mmio) - val |= PI_FUNCTION_CNTRL_M_MEMCS0; - outb(base_addr + PI_ESIC_K_FUNCTION_CNTRL, val); - - /* - * Enable access to the rest of the module - * (including PDQ and packet memory). - */ - val = PI_SLOT_CNTRL_M_ENB; - outb(base_addr + PI_ESIC_K_SLOT_CNTRL, val); - - /* - * Map PDQ registers into memory or port space. This is - * done with a bit in the Burst Holdoff register. - */ - val = inb(base_addr + PI_DEFEA_K_BURST_HOLDOFF); - if (dfx_use_mmio) - val |= PI_BURST_HOLDOFF_V_MEM_MAP; - else - val &= ~PI_BURST_HOLDOFF_V_MEM_MAP; - outb(base_addr + PI_DEFEA_K_BURST_HOLDOFF, val); - - /* Enable interrupts at EISA bus interface chip (ESIC) */ - val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); - val |= PI_CONFIG_STAT_0_M_INT_ENB; - outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val); - } - if (dfx_bus_pci) { - struct pci_dev *pdev = to_pci_dev(bdev); - - /* Get the interrupt level from the PCI Configuration Table */ - - dev->irq = pdev->irq; - - /* Check Latency Timer and set if less than minimal */ - - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &val); - if (val < PFI_K_LAT_TIMER_MIN) { - val = PFI_K_LAT_TIMER_DEF; - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, val); - } - - /* Enable interrupts at PCI bus interface chip (PFI) */ - val = PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB; - dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, val); - } -} - -/* - * ================== - * = dfx_bus_uninit = - * ================== - * - * Overview: - * Uninitializes the bus-specific controller logic. - * - * Returns: - * None - * - * Arguments: - * dev - pointer to device information - * - * Functional Description: - * Perform bus-specific logic uninitialization. - * - * Return Codes: - * None - * - * Assumptions: - * bp->base has already been set with the proper - * base I/O address for this device. - * - * Side Effects: - * Interrupts are disabled at the adapter bus-specific logic. - */ - -static void __devexit dfx_bus_uninit(struct net_device *dev) -{ - DFX_board_t *bp = netdev_priv(dev); - struct device *bdev = bp->bus_dev; - int dfx_bus_pci = DFX_BUS_PCI(bdev); - int dfx_bus_eisa = DFX_BUS_EISA(bdev); - u8 val; - - DBG_printk("In dfx_bus_uninit...\n"); - - /* Uninitialize adapter based on bus type */ - - if (dfx_bus_eisa) { - unsigned long base_addr = to_eisa_device(bdev)->base_addr; - - /* Disable interrupts at EISA bus interface chip (ESIC) */ - val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); - val &= ~PI_CONFIG_STAT_0_M_INT_ENB; - outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val); - } - if (dfx_bus_pci) { - /* Disable interrupts at PCI bus interface chip (PFI) */ - dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, 0); - } -} - - -/* - * ======================== - * = dfx_bus_config_check = - * ======================== - * - * Overview: - * Checks the configuration (burst size, full-duplex, etc.) If any parameters - * are illegal, then this routine will set new defaults. - * - * Returns: - * None - * - * Arguments: - * bp - pointer to board information - * - * Functional Description: - * For Revision 1 FDDI EISA, Revision 2 or later FDDI EISA with rev E or later - * PDQ, and all FDDI PCI controllers, all values are legal. - * - * Return Codes: - * None - * - * Assumptions: - * dfx_adap_init has NOT been called yet so burst size and other items have - * not been set. - * - * Side Effects: - * None - */ - -static void __devinit dfx_bus_config_check(DFX_board_t *bp) -{ - struct device __maybe_unused *bdev = bp->bus_dev; - int dfx_bus_eisa = DFX_BUS_EISA(bdev); - int status; /* return code from adapter port control call */ - u32 host_data; /* LW data returned from port control call */ - - DBG_printk("In dfx_bus_config_check...\n"); - - /* Configuration check only valid for EISA adapter */ - - if (dfx_bus_eisa) { - /* - * First check if revision 2 EISA controller. Rev. 1 cards used - * PDQ revision B, so no workaround needed in this case. Rev. 3 - * cards used PDQ revision E, so no workaround needed in this - * case, either. Only Rev. 2 cards used either Rev. D or E - * chips, so we must verify the chip revision on Rev. 2 cards. - */ - if (to_eisa_device(bdev)->id.driver_data == DEFEA_PROD_ID_2) { - /* - * Revision 2 FDDI EISA controller found, - * so let's check PDQ revision of adapter. - */ - status = dfx_hw_port_ctrl_req(bp, - PI_PCTRL_M_SUB_CMD, - PI_SUB_CMD_K_PDQ_REV_GET, - 0, - &host_data); - if ((status != DFX_K_SUCCESS) || (host_data == 2)) - { - /* - * Either we couldn't determine the PDQ revision, or - * we determined that it is at revision D. In either case, - * we need to implement the workaround. - */ - - /* Ensure that the burst size is set to 8 longwords or less */ - - switch (bp->burst_size) - { - case PI_PDATA_B_DMA_BURST_SIZE_32: - case PI_PDATA_B_DMA_BURST_SIZE_16: - bp->burst_size = PI_PDATA_B_DMA_BURST_SIZE_8; - break; - - default: - break; - } - - /* Ensure that full-duplex mode is not enabled */ - - bp->full_duplex_enb = PI_SNMP_K_FALSE; - } - } - } - } - - -/* - * =================== - * = dfx_driver_init = - * =================== - * - * Overview: - * Initializes remaining adapter board structure information - * and makes sure adapter is in a safe state prior to dfx_open(). - * - * Returns: - * Condition code - * - * Arguments: - * dev - pointer to device information - * print_name - printable device name - * - * Functional Description: - * This function allocates additional resources such as the host memory - * blocks needed by the adapter (eg. descriptor and consumer blocks). - * Remaining bus initialization steps are also completed. The adapter - * is also reset so that it is in the DMA_UNAVAILABLE state. The OS - * must call dfx_open() to open the adapter and bring it on-line. - * - * Return Codes: - * DFX_K_SUCCESS - initialization succeeded - * DFX_K_FAILURE - initialization failed - could not allocate memory - * or read adapter MAC address - * - * Assumptions: - * Memory allocated from pci_alloc_consistent() call is physically - * contiguous, locked memory. - * - * Side Effects: - * Adapter is reset and should be in DMA_UNAVAILABLE state before - * returning from this routine. - */ - -static int __devinit dfx_driver_init(struct net_device *dev, - const char *print_name, - resource_size_t bar_start) -{ - DFX_board_t *bp = netdev_priv(dev); - struct device *bdev = bp->bus_dev; - int dfx_bus_pci = DFX_BUS_PCI(bdev); - int dfx_bus_eisa = DFX_BUS_EISA(bdev); - int dfx_bus_tc = DFX_BUS_TC(bdev); - int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; - int alloc_size; /* total buffer size needed */ - char *top_v, *curr_v; /* virtual addrs into memory block */ - dma_addr_t top_p, curr_p; /* physical addrs into memory block */ - u32 data; /* host data register value */ - __le32 le32; - char *board_name = NULL; - - DBG_printk("In dfx_driver_init...\n"); - - /* Initialize bus-specific hardware registers */ - - dfx_bus_init(dev); - - /* - * Initialize default values for configurable parameters - * - * Note: All of these parameters are ones that a user may - * want to customize. It'd be nice to break these - * out into Space.c or someplace else that's more - * accessible/understandable than this file. - */ - - bp->full_duplex_enb = PI_SNMP_K_FALSE; - bp->req_ttrt = 8 * 12500; /* 8ms in 80 nanosec units */ - bp->burst_size = PI_PDATA_B_DMA_BURST_SIZE_DEF; - bp->rcv_bufs_to_post = RCV_BUFS_DEF; - - /* - * Ensure that HW configuration is OK - * - * Note: Depending on the hardware revision, we may need to modify - * some of the configurable parameters to workaround hardware - * limitations. We'll perform this configuration check AFTER - * setting the parameters to their default values. - */ - - dfx_bus_config_check(bp); - - /* Disable PDQ interrupts first */ - - dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); - - /* Place adapter in DMA_UNAVAILABLE state by resetting adapter */ - - (void) dfx_hw_dma_uninit(bp, PI_PDATA_A_RESET_M_SKIP_ST); - - /* Read the factory MAC address from the adapter then save it */ - - if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_LO, 0, - &data) != DFX_K_SUCCESS) { - printk("%s: Could not read adapter factory MAC address!\n", - print_name); - return DFX_K_FAILURE; - } - le32 = cpu_to_le32(data); - memcpy(&bp->factory_mac_addr[0], &le32, sizeof(u32)); - - if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_HI, 0, - &data) != DFX_K_SUCCESS) { - printk("%s: Could not read adapter factory MAC address!\n", - print_name); - return DFX_K_FAILURE; - } - le32 = cpu_to_le32(data); - memcpy(&bp->factory_mac_addr[4], &le32, sizeof(u16)); - - /* - * Set current address to factory address - * - * Note: Node address override support is handled through - * dfx_ctl_set_mac_address. - */ - - memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN); - if (dfx_bus_tc) - board_name = "DEFTA"; - if (dfx_bus_eisa) - board_name = "DEFEA"; - if (dfx_bus_pci) - board_name = "DEFPA"; - pr_info("%s: %s at %saddr = 0x%llx, IRQ = %d, Hardware addr = %pMF\n", - print_name, board_name, dfx_use_mmio ? "" : "I/O ", - (long long)bar_start, dev->irq, dev->dev_addr); - - /* - * Get memory for descriptor block, consumer block, and other buffers - * that need to be DMA read or written to by the adapter. - */ - - alloc_size = sizeof(PI_DESCR_BLOCK) + - PI_CMD_REQ_K_SIZE_MAX + - PI_CMD_RSP_K_SIZE_MAX + -#ifndef DYNAMIC_BUFFERS - (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) + -#endif - sizeof(PI_CONSUMER_BLOCK) + - (PI_ALIGN_K_DESC_BLK - 1); - bp->kmalloced = top_v = dma_alloc_coherent(bp->bus_dev, alloc_size, - &bp->kmalloced_dma, - GFP_ATOMIC); - if (top_v == NULL) { - printk("%s: Could not allocate memory for host buffers " - "and structures!\n", print_name); - return DFX_K_FAILURE; - } - memset(top_v, 0, alloc_size); /* zero out memory before continuing */ - top_p = bp->kmalloced_dma; /* get physical address of buffer */ - - /* - * To guarantee the 8K alignment required for the descriptor block, 8K - 1 - * plus the amount of memory needed was allocated. The physical address - * is now 8K aligned. By carving up the memory in a specific order, - * we'll guarantee the alignment requirements for all other structures. - * - * Note: If the assumptions change regarding the non-paged, non-cached, - * physically contiguous nature of the memory block or the address - * alignments, then we'll need to implement a different algorithm - * for allocating the needed memory. - */ - - curr_p = ALIGN(top_p, PI_ALIGN_K_DESC_BLK); - curr_v = top_v + (curr_p - top_p); - - /* Reserve space for descriptor block */ - - bp->descr_block_virt = (PI_DESCR_BLOCK *) curr_v; - bp->descr_block_phys = curr_p; - curr_v += sizeof(PI_DESCR_BLOCK); - curr_p += sizeof(PI_DESCR_BLOCK); - - /* Reserve space for command request buffer */ - - bp->cmd_req_virt = (PI_DMA_CMD_REQ *) curr_v; - bp->cmd_req_phys = curr_p; - curr_v += PI_CMD_REQ_K_SIZE_MAX; - curr_p += PI_CMD_REQ_K_SIZE_MAX; - - /* Reserve space for command response buffer */ - - bp->cmd_rsp_virt = (PI_DMA_CMD_RSP *) curr_v; - bp->cmd_rsp_phys = curr_p; - curr_v += PI_CMD_RSP_K_SIZE_MAX; - curr_p += PI_CMD_RSP_K_SIZE_MAX; - - /* Reserve space for the LLC host receive queue buffers */ - - bp->rcv_block_virt = curr_v; - bp->rcv_block_phys = curr_p; - -#ifndef DYNAMIC_BUFFERS - curr_v += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX); - curr_p += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX); -#endif - - /* Reserve space for the consumer block */ - - bp->cons_block_virt = (PI_CONSUMER_BLOCK *) curr_v; - bp->cons_block_phys = curr_p; - - /* Display virtual and physical addresses if debug driver */ - - DBG_printk("%s: Descriptor block virt = %0lX, phys = %0X\n", - print_name, - (long)bp->descr_block_virt, bp->descr_block_phys); - DBG_printk("%s: Command Request buffer virt = %0lX, phys = %0X\n", - print_name, (long)bp->cmd_req_virt, bp->cmd_req_phys); - DBG_printk("%s: Command Response buffer virt = %0lX, phys = %0X\n", - print_name, (long)bp->cmd_rsp_virt, bp->cmd_rsp_phys); - DBG_printk("%s: Receive buffer block virt = %0lX, phys = %0X\n", - print_name, (long)bp->rcv_block_virt, bp->rcv_block_phys); - DBG_printk("%s: Consumer block virt = %0lX, phys = %0X\n", - print_name, (long)bp->cons_block_virt, bp->cons_block_phys); - - return DFX_K_SUCCESS; -} - - -/* - * ================= - * = dfx_adap_init = - * ================= - * - * Overview: - * Brings the adapter to the link avail/link unavailable state. - * - * Returns: - * Condition code - * - * Arguments: - * bp - pointer to board information - * get_buffers - non-zero if buffers to be allocated - * - * Functional Description: - * Issues the low-level firmware/hardware calls necessary to bring - * the adapter up, or to properly reset and restore adapter during - * run-time. - * - * Return Codes: - * DFX_K_SUCCESS - Adapter brought up successfully - * DFX_K_FAILURE - Adapter initialization failed - * - * Assumptions: - * bp->reset_type should be set to a valid reset type value before - * calling this routine. - * - * Side Effects: - * Adapter should be in LINK_AVAILABLE or LINK_UNAVAILABLE state - * upon a successful return of this routine. - */ - -static int dfx_adap_init(DFX_board_t *bp, int get_buffers) - { - DBG_printk("In dfx_adap_init...\n"); - - /* Disable PDQ interrupts first */ - - dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); - - /* Place adapter in DMA_UNAVAILABLE state by resetting adapter */ - - if (dfx_hw_dma_uninit(bp, bp->reset_type) != DFX_K_SUCCESS) - { - printk("%s: Could not uninitialize/reset adapter!\n", bp->dev->name); - return DFX_K_FAILURE; - } - - /* - * When the PDQ is reset, some false Type 0 interrupts may be pending, - * so we'll acknowledge all Type 0 interrupts now before continuing. - */ - - dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, PI_HOST_INT_K_ACK_ALL_TYPE_0); - - /* - * Clear Type 1 and Type 2 registers before going to DMA_AVAILABLE state - * - * Note: We only need to clear host copies of these registers. The PDQ reset - * takes care of the on-board register values. - */ - - bp->cmd_req_reg.lword = 0; - bp->cmd_rsp_reg.lword = 0; - bp->rcv_xmt_reg.lword = 0; - - /* Clear consumer block before going to DMA_AVAILABLE state */ - - memset(bp->cons_block_virt, 0, sizeof(PI_CONSUMER_BLOCK)); - - /* Initialize the DMA Burst Size */ - - if (dfx_hw_port_ctrl_req(bp, - PI_PCTRL_M_SUB_CMD, - PI_SUB_CMD_K_BURST_SIZE_SET, - bp->burst_size, - NULL) != DFX_K_SUCCESS) - { - printk("%s: Could not set adapter burst size!\n", bp->dev->name); - return DFX_K_FAILURE; - } - - /* - * Set base address of Consumer Block - * - * Assumption: 32-bit physical address of consumer block is 64 byte - * aligned. That is, bits 0-5 of the address must be zero. - */ - - if (dfx_hw_port_ctrl_req(bp, - PI_PCTRL_M_CONS_BLOCK, - bp->cons_block_phys, - 0, - NULL) != DFX_K_SUCCESS) - { - printk("%s: Could not set consumer block address!\n", bp->dev->name); - return DFX_K_FAILURE; - } - - /* - * Set the base address of Descriptor Block and bring adapter - * to DMA_AVAILABLE state. - * - * Note: We also set the literal and data swapping requirements - * in this command. - * - * Assumption: 32-bit physical address of descriptor block - * is 8Kbyte aligned. - */ - if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_INIT, - (u32)(bp->descr_block_phys | - PI_PDATA_A_INIT_M_BSWAP_INIT), - 0, NULL) != DFX_K_SUCCESS) { - printk("%s: Could not set descriptor block address!\n", - bp->dev->name); - return DFX_K_FAILURE; - } - - /* Set transmit flush timeout value */ - - bp->cmd_req_virt->cmd_type = PI_CMD_K_CHARS_SET; - bp->cmd_req_virt->char_set.item[0].item_code = PI_ITEM_K_FLUSH_TIME; - bp->cmd_req_virt->char_set.item[0].value = 3; /* 3 seconds */ - bp->cmd_req_virt->char_set.item[0].item_index = 0; - bp->cmd_req_virt->char_set.item[1].item_code = PI_ITEM_K_EOL; - if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) - { - printk("%s: DMA command request failed!\n", bp->dev->name); - return DFX_K_FAILURE; - } - - /* Set the initial values for eFDXEnable and MACTReq MIB objects */ - - bp->cmd_req_virt->cmd_type = PI_CMD_K_SNMP_SET; - bp->cmd_req_virt->snmp_set.item[0].item_code = PI_ITEM_K_FDX_ENB_DIS; - bp->cmd_req_virt->snmp_set.item[0].value = bp->full_duplex_enb; - bp->cmd_req_virt->snmp_set.item[0].item_index = 0; - bp->cmd_req_virt->snmp_set.item[1].item_code = PI_ITEM_K_MAC_T_REQ; - bp->cmd_req_virt->snmp_set.item[1].value = bp->req_ttrt; - bp->cmd_req_virt->snmp_set.item[1].item_index = 0; - bp->cmd_req_virt->snmp_set.item[2].item_code = PI_ITEM_K_EOL; - if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) - { - printk("%s: DMA command request failed!\n", bp->dev->name); - return DFX_K_FAILURE; - } - - /* Initialize adapter CAM */ - - if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS) - { - printk("%s: Adapter CAM update failed!\n", bp->dev->name); - return DFX_K_FAILURE; - } - - /* Initialize adapter filters */ - - if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS) - { - printk("%s: Adapter filters update failed!\n", bp->dev->name); - return DFX_K_FAILURE; - } - - /* - * Remove any existing dynamic buffers (i.e. if the adapter is being - * reinitialized) - */ - - if (get_buffers) - dfx_rcv_flush(bp); - - /* Initialize receive descriptor block and produce buffers */ - - if (dfx_rcv_init(bp, get_buffers)) - { - printk("%s: Receive buffer allocation failed\n", bp->dev->name); - if (get_buffers) - dfx_rcv_flush(bp); - return DFX_K_FAILURE; - } - - /* Issue START command and bring adapter to LINK_(UN)AVAILABLE state */ - - bp->cmd_req_virt->cmd_type = PI_CMD_K_START; - if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) - { - printk("%s: Start command failed\n", bp->dev->name); - if (get_buffers) - dfx_rcv_flush(bp); - return DFX_K_FAILURE; - } - - /* Initialization succeeded, reenable PDQ interrupts */ - - dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_ENABLE_DEF_INTS); - return DFX_K_SUCCESS; - } - - -/* - * ============ - * = dfx_open = - * ============ - * - * Overview: - * Opens the adapter - * - * Returns: - * Condition code - * - * Arguments: - * dev - pointer to device information - * - * Functional Description: - * This function brings the adapter to an operational state. - * - * Return Codes: - * 0 - Adapter was successfully opened - * -EAGAIN - Could not register IRQ or adapter initialization failed - * - * Assumptions: - * This routine should only be called for a device that was - * initialized successfully. - * - * Side Effects: - * Adapter should be in LINK_AVAILABLE or LINK_UNAVAILABLE state - * if the open is successful. - */ - -static int dfx_open(struct net_device *dev) -{ - DFX_board_t *bp = netdev_priv(dev); - int ret; - - DBG_printk("In dfx_open...\n"); - - /* Register IRQ - support shared interrupts by passing device ptr */ - - ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name, - dev); - if (ret) { - printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq); - return ret; - } - - /* - * Set current address to factory MAC address - * - * Note: We've already done this step in dfx_driver_init. - * However, it's possible that a user has set a node - * address override, then closed and reopened the - * adapter. Unless we reset the device address field - * now, we'll continue to use the existing modified - * address. - */ - - memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN); - - /* Clear local unicast/multicast address tables and counts */ - - memset(bp->uc_table, 0, sizeof(bp->uc_table)); - memset(bp->mc_table, 0, sizeof(bp->mc_table)); - bp->uc_count = 0; - bp->mc_count = 0; - - /* Disable promiscuous filter settings */ - - bp->ind_group_prom = PI_FSTATE_K_BLOCK; - bp->group_prom = PI_FSTATE_K_BLOCK; - - spin_lock_init(&bp->lock); - - /* Reset and initialize adapter */ - - bp->reset_type = PI_PDATA_A_RESET_M_SKIP_ST; /* skip self-test */ - if (dfx_adap_init(bp, 1) != DFX_K_SUCCESS) - { - printk(KERN_ERR "%s: Adapter open failed!\n", dev->name); - free_irq(dev->irq, dev); - return -EAGAIN; - } - - /* Set device structure info */ - netif_start_queue(dev); - return 0; -} - - -/* - * ============= - * = dfx_close = - * ============= - * - * Overview: - * Closes the device/module. - * - * Returns: - * Condition code - * - * Arguments: - * dev - pointer to device information - * - * Functional Description: - * This routine closes the adapter and brings it to a safe state. - * The interrupt service routine is deregistered with the OS. - * The adapter can be opened again with another call to dfx_open(). - * - * Return Codes: - * Always return 0. - * - * Assumptions: - * No further requests for this adapter are made after this routine is - * called. dfx_open() can be called to reset and reinitialize the - * adapter. - * - * Side Effects: - * Adapter should be in DMA_UNAVAILABLE state upon completion of this - * routine. - */ - -static int dfx_close(struct net_device *dev) -{ - DFX_board_t *bp = netdev_priv(dev); - - DBG_printk("In dfx_close...\n"); - - /* Disable PDQ interrupts first */ - - dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); - - /* Place adapter in DMA_UNAVAILABLE state by resetting adapter */ - - (void) dfx_hw_dma_uninit(bp, PI_PDATA_A_RESET_M_SKIP_ST); - - /* - * Flush any pending transmit buffers - * - * Note: It's important that we flush the transmit buffers - * BEFORE we clear our copy of the Type 2 register. - * Otherwise, we'll have no idea how many buffers - * we need to free. - */ - - dfx_xmt_flush(bp); - - /* - * Clear Type 1 and Type 2 registers after adapter reset - * - * Note: Even though we're closing the adapter, it's - * possible that an interrupt will occur after - * dfx_close is called. Without some assurance to - * the contrary we want to make sure that we don't - * process receive and transmit LLC frames and update - * the Type 2 register with bad information. - */ - - bp->cmd_req_reg.lword = 0; - bp->cmd_rsp_reg.lword = 0; - bp->rcv_xmt_reg.lword = 0; - - /* Clear consumer block for the same reason given above */ - - memset(bp->cons_block_virt, 0, sizeof(PI_CONSUMER_BLOCK)); - - /* Release all dynamically allocate skb in the receive ring. */ - - dfx_rcv_flush(bp); - - /* Clear device structure flags */ - - netif_stop_queue(dev); - - /* Deregister (free) IRQ */ - - free_irq(dev->irq, dev); - - return 0; -} - - -/* - * ====================== - * = dfx_int_pr_halt_id = - * ====================== - * - * Overview: - * Displays halt id's in string form. - * - * Returns: - * None - * - * Arguments: - * bp - pointer to board information - * - * Functional Description: - * Determine current halt id and display appropriate string. - * - * Return Codes: - * None - * - * Assumptions: - * None - * - * Side Effects: - * None - */ - -static void dfx_int_pr_halt_id(DFX_board_t *bp) - { - PI_UINT32 port_status; /* PDQ port status register value */ - PI_UINT32 halt_id; /* PDQ port status halt ID */ - - /* Read the latest port status */ - - dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status); - - /* Display halt state transition information */ - - halt_id = (port_status & PI_PSTATUS_M_HALT_ID) >> PI_PSTATUS_V_HALT_ID; - switch (halt_id) - { - case PI_HALT_ID_K_SELFTEST_TIMEOUT: - printk("%s: Halt ID: Selftest Timeout\n", bp->dev->name); - break; - - case PI_HALT_ID_K_PARITY_ERROR: - printk("%s: Halt ID: Host Bus Parity Error\n", bp->dev->name); - break; - - case PI_HALT_ID_K_HOST_DIR_HALT: - printk("%s: Halt ID: Host-Directed Halt\n", bp->dev->name); - break; - - case PI_HALT_ID_K_SW_FAULT: - printk("%s: Halt ID: Adapter Software Fault\n", bp->dev->name); - break; - - case PI_HALT_ID_K_HW_FAULT: - printk("%s: Halt ID: Adapter Hardware Fault\n", bp->dev->name); - break; - - case PI_HALT_ID_K_PC_TRACE: - printk("%s: Halt ID: FDDI Network PC Trace Path Test\n", bp->dev->name); - break; - - case PI_HALT_ID_K_DMA_ERROR: - printk("%s: Halt ID: Adapter DMA Error\n", bp->dev->name); - break; - - case PI_HALT_ID_K_IMAGE_CRC_ERROR: - printk("%s: Halt ID: Firmware Image CRC Error\n", bp->dev->name); - break; - - case PI_HALT_ID_K_BUS_EXCEPTION: - printk("%s: Halt ID: 68000 Bus Exception\n", bp->dev->name); - break; - - default: - printk("%s: Halt ID: Unknown (code = %X)\n", bp->dev->name, halt_id); - break; - } - } - - -/* - * ========================== - * = dfx_int_type_0_process = - * ========================== - * - * Overview: - * Processes Type 0 interrupts. - * - * Returns: - * None - * - * Arguments: - * bp - pointer to board information - * - * Functional Description: - * Processes all enabled Type 0 interrupts. If the reason for the interrupt - * is a serious fault on the adapter, then an error message is displayed - * and the adapter is reset. - * - * One tricky potential timing window is the rapid succession of "link avail" - * "link unavail" state change interrupts. The acknowledgement of the Type 0 - * interrupt must be done before reading the state from the Port Status - * register. This is true because a state change could occur after reading - * the data, but before acknowledging the interrupt. If this state change - * does happen, it would be lost because the driver is using the old state, - * and it will never know about the new state because it subsequently - * acknowledges the state change interrupt. - * - * INCORRECT CORRECT - * read type 0 int reasons read type 0 int reasons - * read adapter state ack type 0 interrupts - * ack type 0 interrupts read adapter state - * ... process interrupt ... ... process interrupt ... - * - * Return Codes: - * None - * - * Assumptions: - * None - * - * Side Effects: - * An adapter reset may occur if the adapter has any Type 0 error interrupts - * or if the port status indicates that the adapter is halted. The driver - * is responsible for reinitializing the adapter with the current CAM - * contents and adapter filter settings. - */ - -static void dfx_int_type_0_process(DFX_board_t *bp) - - { - PI_UINT32 type_0_status; /* Host Interrupt Type 0 register */ - PI_UINT32 state; /* current adap state (from port status) */ - - /* - * Read host interrupt Type 0 register to determine which Type 0 - * interrupts are pending. Immediately write it back out to clear - * those interrupts. - */ - - dfx_port_read_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, &type_0_status); - dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, type_0_status); - - /* Check for Type 0 error interrupts */ - - if (type_0_status & (PI_TYPE_0_STAT_M_NXM | - PI_TYPE_0_STAT_M_PM_PAR_ERR | - PI_TYPE_0_STAT_M_BUS_PAR_ERR)) - { - /* Check for Non-Existent Memory error */ - - if (type_0_status & PI_TYPE_0_STAT_M_NXM) - printk("%s: Non-Existent Memory Access Error\n", bp->dev->name); - - /* Check for Packet Memory Parity error */ - - if (type_0_status & PI_TYPE_0_STAT_M_PM_PAR_ERR) - printk("%s: Packet Memory Parity Error\n", bp->dev->name); - - /* Check for Host Bus Parity error */ - - if (type_0_status & PI_TYPE_0_STAT_M_BUS_PAR_ERR) - printk("%s: Host Bus Parity Error\n", bp->dev->name); - - /* Reset adapter and bring it back on-line */ - - bp->link_available = PI_K_FALSE; /* link is no longer available */ - bp->reset_type = 0; /* rerun on-board diagnostics */ - printk("%s: Resetting adapter...\n", bp->dev->name); - if (dfx_adap_init(bp, 0) != DFX_K_SUCCESS) - { - printk("%s: Adapter reset failed! Disabling adapter interrupts.\n", bp->dev->name); - dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); - return; - } - printk("%s: Adapter reset successful!\n", bp->dev->name); - return; - } - - /* Check for transmit flush interrupt */ - - if (type_0_status & PI_TYPE_0_STAT_M_XMT_FLUSH) - { - /* Flush any pending xmt's and acknowledge the flush interrupt */ - - bp->link_available = PI_K_FALSE; /* link is no longer available */ - dfx_xmt_flush(bp); /* flush any outstanding packets */ - (void) dfx_hw_port_ctrl_req(bp, - PI_PCTRL_M_XMT_DATA_FLUSH_DONE, - 0, - 0, - NULL); - } - - /* Check for adapter state change */ - - if (type_0_status & PI_TYPE_0_STAT_M_STATE_CHANGE) - { - /* Get latest adapter state */ - - state = dfx_hw_adap_state_rd(bp); /* get adapter state */ - if (state == PI_STATE_K_HALTED) - { - /* - * Adapter has transitioned to HALTED state, try to reset - * adapter to bring it back on-line. If reset fails, - * leave the adapter in the broken state. - */ - - printk("%s: Controller has transitioned to HALTED state!\n", bp->dev->name); - dfx_int_pr_halt_id(bp); /* display halt id as string */ - - /* Reset adapter and bring it back on-line */ - - bp->link_available = PI_K_FALSE; /* link is no longer available */ - bp->reset_type = 0; /* rerun on-board diagnostics */ - printk("%s: Resetting adapter...\n", bp->dev->name); - if (dfx_adap_init(bp, 0) != DFX_K_SUCCESS) - { - printk("%s: Adapter reset failed! Disabling adapter interrupts.\n", bp->dev->name); - dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); - return; - } - printk("%s: Adapter reset successful!\n", bp->dev->name); - } - else if (state == PI_STATE_K_LINK_AVAIL) - { - bp->link_available = PI_K_TRUE; /* set link available flag */ - } - } - } - - -/* - * ================== - * = dfx_int_common = - * ================== - * - * Overview: - * Interrupt service routine (ISR) - * - * Returns: - * None - * - * Arguments: - * bp - pointer to board information - * - * Functional Description: - * This is the ISR which processes incoming adapter interrupts. - * - * Return Codes: - * None - * - * Assumptions: - * This routine assumes PDQ interrupts have not been disabled. - * When interrupts are disabled at the PDQ, the Port Status register - * is automatically cleared. This routine uses the Port Status - * register value to determine whether a Type 0 interrupt occurred, - * so it's important that adapter interrupts are not normally - * enabled/disabled at the PDQ. - * - * It's vital that this routine is NOT reentered for the - * same board and that the OS is not in another section of - * code (eg. dfx_xmt_queue_pkt) for the same board on a - * different thread. - * - * Side Effects: - * Pending interrupts are serviced. Depending on the type of - * interrupt, acknowledging and clearing the interrupt at the - * PDQ involves writing a register to clear the interrupt bit - * or updating completion indices. - */ - -static void dfx_int_common(struct net_device *dev) -{ - DFX_board_t *bp = netdev_priv(dev); - PI_UINT32 port_status; /* Port Status register */ - - /* Process xmt interrupts - frequent case, so always call this routine */ - - if(dfx_xmt_done(bp)) /* free consumed xmt packets */ - netif_wake_queue(dev); - - /* Process rcv interrupts - frequent case, so always call this routine */ - - dfx_rcv_queue_process(bp); /* service received LLC frames */ - - /* - * Transmit and receive producer and completion indices are updated on the - * adapter by writing to the Type 2 Producer register. Since the frequent - * case is that we'll be processing either LLC transmit or receive buffers, - * we'll optimize I/O writes by doing a single register write here. - */ - - dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); - - /* Read PDQ Port Status register to find out which interrupts need processing */ - - dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status); - - /* Process Type 0 interrupts (if any) - infrequent, so only call when needed */ - - if (port_status & PI_PSTATUS_M_TYPE_0_PENDING) - dfx_int_type_0_process(bp); /* process Type 0 interrupts */ - } - - -/* - * ================= - * = dfx_interrupt = - * ================= - * - * Overview: - * Interrupt processing routine - * - * Returns: - * Whether a valid interrupt was seen. - * - * Arguments: - * irq - interrupt vector - * dev_id - pointer to device information - * - * Functional Description: - * This routine calls the interrupt processing routine for this adapter. It - * disables and reenables adapter interrupts, as appropriate. We can support - * shared interrupts since the incoming dev_id pointer provides our device - * structure context. - * - * Return Codes: - * IRQ_HANDLED - an IRQ was handled. - * IRQ_NONE - no IRQ was handled. - * - * Assumptions: - * The interrupt acknowledgement at the hardware level (eg. ACKing the PIC - * on Intel-based systems) is done by the operating system outside this - * routine. - * - * System interrupts are enabled through this call. - * - * Side Effects: - * Interrupts are disabled, then reenabled at the adapter. - */ - -static irqreturn_t dfx_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - DFX_board_t *bp = netdev_priv(dev); - struct device *bdev = bp->bus_dev; - int dfx_bus_pci = DFX_BUS_PCI(bdev); - int dfx_bus_eisa = DFX_BUS_EISA(bdev); - int dfx_bus_tc = DFX_BUS_TC(bdev); - - /* Service adapter interrupts */ - - if (dfx_bus_pci) { - u32 status; - - dfx_port_read_long(bp, PFI_K_REG_STATUS, &status); - if (!(status & PFI_STATUS_M_PDQ_INT)) - return IRQ_NONE; - - spin_lock(&bp->lock); - - /* Disable PDQ-PFI interrupts at PFI */ - dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, - PFI_MODE_M_DMA_ENB); - - /* Call interrupt service routine for this adapter */ - dfx_int_common(dev); - - /* Clear PDQ interrupt status bit and reenable interrupts */ - dfx_port_write_long(bp, PFI_K_REG_STATUS, - PFI_STATUS_M_PDQ_INT); - dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, - (PFI_MODE_M_PDQ_INT_ENB | - PFI_MODE_M_DMA_ENB)); - - spin_unlock(&bp->lock); - } - if (dfx_bus_eisa) { - unsigned long base_addr = to_eisa_device(bdev)->base_addr; - u8 status; - - status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); - if (!(status & PI_CONFIG_STAT_0_M_PEND)) - return IRQ_NONE; - - spin_lock(&bp->lock); - - /* Disable interrupts at the ESIC */ - status &= ~PI_CONFIG_STAT_0_M_INT_ENB; - outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status); - - /* Call interrupt service routine for this adapter */ - dfx_int_common(dev); - - /* Reenable interrupts at the ESIC */ - status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); - status |= PI_CONFIG_STAT_0_M_INT_ENB; - outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status); - - spin_unlock(&bp->lock); - } - if (dfx_bus_tc) { - u32 status; - - dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &status); - if (!(status & (PI_PSTATUS_M_RCV_DATA_PENDING | - PI_PSTATUS_M_XMT_DATA_PENDING | - PI_PSTATUS_M_SMT_HOST_PENDING | - PI_PSTATUS_M_UNSOL_PENDING | - PI_PSTATUS_M_CMD_RSP_PENDING | - PI_PSTATUS_M_CMD_REQ_PENDING | - PI_PSTATUS_M_TYPE_0_PENDING))) - return IRQ_NONE; - - spin_lock(&bp->lock); - - /* Call interrupt service routine for this adapter */ - dfx_int_common(dev); - - spin_unlock(&bp->lock); - } - - return IRQ_HANDLED; -} - - -/* - * ===================== - * = dfx_ctl_get_stats = - * ===================== - * - * Overview: - * Get statistics for FDDI adapter - * - * Returns: - * Pointer to FDDI statistics structure - * - * Arguments: - * dev - pointer to device information - * - * Functional Description: - * Gets current MIB objects from adapter, then - * returns FDDI statistics structure as defined - * in if_fddi.h. - * - * Note: Since the FDDI statistics structure is - * still new and the device structure doesn't - * have an FDDI-specific get statistics handler, - * we'll return the FDDI statistics structure as - * a pointer to an Ethernet statistics structure. - * That way, at least the first part of the statistics - * structure can be decoded properly, and it allows - * "smart" applications to perform a second cast to - * decode the FDDI-specific statistics. - * - * We'll have to pay attention to this routine as the - * device structure becomes more mature and LAN media - * independent. - * - * Return Codes: - * None - * - * Assumptions: - * None - * - * Side Effects: - * None - */ - -static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev) - { - DFX_board_t *bp = netdev_priv(dev); - - /* Fill the bp->stats structure with driver-maintained counters */ - - bp->stats.gen.rx_packets = bp->rcv_total_frames; - bp->stats.gen.tx_packets = bp->xmt_total_frames; - bp->stats.gen.rx_bytes = bp->rcv_total_bytes; - bp->stats.gen.tx_bytes = bp->xmt_total_bytes; - bp->stats.gen.rx_errors = bp->rcv_crc_errors + - bp->rcv_frame_status_errors + - bp->rcv_length_errors; - bp->stats.gen.tx_errors = bp->xmt_length_errors; - bp->stats.gen.rx_dropped = bp->rcv_discards; - bp->stats.gen.tx_dropped = bp->xmt_discards; - bp->stats.gen.multicast = bp->rcv_multicast_frames; - bp->stats.gen.collisions = 0; /* always zero (0) for FDDI */ - - /* Get FDDI SMT MIB objects */ - - bp->cmd_req_virt->cmd_type = PI_CMD_K_SMT_MIB_GET; - if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) - return (struct net_device_stats *)&bp->stats; - - /* Fill the bp->stats structure with the SMT MIB object values */ - - memcpy(bp->stats.smt_station_id, &bp->cmd_rsp_virt->smt_mib_get.smt_station_id, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_station_id)); - bp->stats.smt_op_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_op_version_id; - bp->stats.smt_hi_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_hi_version_id; - bp->stats.smt_lo_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_lo_version_id; - memcpy(bp->stats.smt_user_data, &bp->cmd_rsp_virt->smt_mib_get.smt_user_data, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_user_data)); - bp->stats.smt_mib_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_mib_version_id; - bp->stats.smt_mac_cts = bp->cmd_rsp_virt->smt_mib_get.smt_mac_ct; - bp->stats.smt_non_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_non_master_ct; - bp->stats.smt_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_master_ct; - bp->stats.smt_available_paths = bp->cmd_rsp_virt->smt_mib_get.smt_available_paths; - bp->stats.smt_config_capabilities = bp->cmd_rsp_virt->smt_mib_get.smt_config_capabilities; - bp->stats.smt_config_policy = bp->cmd_rsp_virt->smt_mib_get.smt_config_policy; - bp->stats.smt_connection_policy = bp->cmd_rsp_virt->smt_mib_get.smt_connection_policy; - bp->stats.smt_t_notify = bp->cmd_rsp_virt->smt_mib_get.smt_t_notify; - bp->stats.smt_stat_rpt_policy = bp->cmd_rsp_virt->smt_mib_get.smt_stat_rpt_policy; - bp->stats.smt_trace_max_expiration = bp->cmd_rsp_virt->smt_mib_get.smt_trace_max_expiration; - bp->stats.smt_bypass_present = bp->cmd_rsp_virt->smt_mib_get.smt_bypass_present; - bp->stats.smt_ecm_state = bp->cmd_rsp_virt->smt_mib_get.smt_ecm_state; - bp->stats.smt_cf_state = bp->cmd_rsp_virt->smt_mib_get.smt_cf_state; - bp->stats.smt_remote_disconnect_flag = bp->cmd_rsp_virt->smt_mib_get.smt_remote_disconnect_flag; - bp->stats.smt_station_status = bp->cmd_rsp_virt->smt_mib_get.smt_station_status; - bp->stats.smt_peer_wrap_flag = bp->cmd_rsp_virt->smt_mib_get.smt_peer_wrap_flag; - bp->stats.smt_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_msg_time_stamp.ls; - bp->stats.smt_transition_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_transition_time_stamp.ls; - bp->stats.mac_frame_status_functions = bp->cmd_rsp_virt->smt_mib_get.mac_frame_status_functions; - bp->stats.mac_t_max_capability = bp->cmd_rsp_virt->smt_mib_get.mac_t_max_capability; - bp->stats.mac_tvx_capability = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_capability; - bp->stats.mac_available_paths = bp->cmd_rsp_virt->smt_mib_get.mac_available_paths; - bp->stats.mac_current_path = bp->cmd_rsp_virt->smt_mib_get.mac_current_path; - memcpy(bp->stats.mac_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_upstream_nbr, FDDI_K_ALEN); - memcpy(bp->stats.mac_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_downstream_nbr, FDDI_K_ALEN); - memcpy(bp->stats.mac_old_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_upstream_nbr, FDDI_K_ALEN); - memcpy(bp->stats.mac_old_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_downstream_nbr, FDDI_K_ALEN); - bp->stats.mac_dup_address_test = bp->cmd_rsp_virt->smt_mib_get.mac_dup_address_test; - bp->stats.mac_requested_paths = bp->cmd_rsp_virt->smt_mib_get.mac_requested_paths; - bp->stats.mac_downstream_port_type = bp->cmd_rsp_virt->smt_mib_get.mac_downstream_port_type; - memcpy(bp->stats.mac_smt_address, &bp->cmd_rsp_virt->smt_mib_get.mac_smt_address, FDDI_K_ALEN); - bp->stats.mac_t_req = bp->cmd_rsp_virt->smt_mib_get.mac_t_req; - bp->stats.mac_t_neg = bp->cmd_rsp_virt->smt_mib_get.mac_t_neg; - bp->stats.mac_t_max = bp->cmd_rsp_virt->smt_mib_get.mac_t_max; - bp->stats.mac_tvx_value = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_value; - bp->stats.mac_frame_error_threshold = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_threshold; - bp->stats.mac_frame_error_ratio = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_ratio; - bp->stats.mac_rmt_state = bp->cmd_rsp_virt->smt_mib_get.mac_rmt_state; - bp->stats.mac_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_da_flag; - bp->stats.mac_una_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_unda_flag; - bp->stats.mac_frame_error_flag = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_flag; - bp->stats.mac_ma_unitdata_available = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_available; - bp->stats.mac_hardware_present = bp->cmd_rsp_virt->smt_mib_get.mac_hardware_present; - bp->stats.mac_ma_unitdata_enable = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_enable; - bp->stats.path_tvx_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_tvx_lower_bound; - bp->stats.path_t_max_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_t_max_lower_bound; - bp->stats.path_max_t_req = bp->cmd_rsp_virt->smt_mib_get.path_max_t_req; - memcpy(bp->stats.path_configuration, &bp->cmd_rsp_virt->smt_mib_get.path_configuration, sizeof(bp->cmd_rsp_virt->smt_mib_get.path_configuration)); - bp->stats.port_my_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[0]; - bp->stats.port_my_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[1]; - bp->stats.port_neighbor_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[0]; - bp->stats.port_neighbor_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[1]; - bp->stats.port_connection_policies[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[0]; - bp->stats.port_connection_policies[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[1]; - bp->stats.port_mac_indicated[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[0]; - bp->stats.port_mac_indicated[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[1]; - bp->stats.port_current_path[0] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[0]; - bp->stats.port_current_path[1] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[1]; - memcpy(&bp->stats.port_requested_paths[0*3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[0], 3); - memcpy(&bp->stats.port_requested_paths[1*3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[1], 3); - bp->stats.port_mac_placement[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[0]; - bp->stats.port_mac_placement[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[1]; - bp->stats.port_available_paths[0] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[0]; - bp->stats.port_available_paths[1] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[1]; - bp->stats.port_pmd_class[0] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[0]; - bp->stats.port_pmd_class[1] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[1]; - bp->stats.port_connection_capabilities[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[0]; - bp->stats.port_connection_capabilities[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[1]; - bp->stats.port_bs_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[0]; - bp->stats.port_bs_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[1]; - bp->stats.port_ler_estimate[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[0]; - bp->stats.port_ler_estimate[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[1]; - bp->stats.port_ler_cutoff[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[0]; - bp->stats.port_ler_cutoff[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[1]; - bp->stats.port_ler_alarm[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[0]; - bp->stats.port_ler_alarm[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[1]; - bp->stats.port_connect_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[0]; - bp->stats.port_connect_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[1]; - bp->stats.port_pcm_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[0]; - bp->stats.port_pcm_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[1]; - bp->stats.port_pc_withhold[0] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[0]; - bp->stats.port_pc_withhold[1] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[1]; - bp->stats.port_ler_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[0]; - bp->stats.port_ler_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[1]; - bp->stats.port_hardware_present[0] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[0]; - bp->stats.port_hardware_present[1] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[1]; - - /* Get FDDI counters */ - - bp->cmd_req_virt->cmd_type = PI_CMD_K_CNTRS_GET; - if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) - return (struct net_device_stats *)&bp->stats; - - /* Fill the bp->stats structure with the FDDI counter values */ - - bp->stats.mac_frame_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.frame_cnt.ls; - bp->stats.mac_copied_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.copied_cnt.ls; - bp->stats.mac_transmit_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.transmit_cnt.ls; - bp->stats.mac_error_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.error_cnt.ls; - bp->stats.mac_lost_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.lost_cnt.ls; - bp->stats.port_lct_fail_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[0].ls; - bp->stats.port_lct_fail_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[1].ls; - bp->stats.port_lem_reject_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[0].ls; - bp->stats.port_lem_reject_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[1].ls; - bp->stats.port_lem_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[0].ls; - bp->stats.port_lem_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[1].ls; - - return (struct net_device_stats *)&bp->stats; - } - - -/* - * ============================== - * = dfx_ctl_set_multicast_list = - * ============================== - * - * Overview: - * Enable/Disable LLC frame promiscuous mode reception - * on the adapter and/or update multicast address table. - * - * Returns: - * None - * - * Arguments: - * dev - pointer to device information - * - * Functional Description: - * This routine follows a fairly simple algorithm for setting the - * adapter filters and CAM: - * - * if IFF_PROMISC flag is set - * enable LLC individual/group promiscuous mode - * else - * disable LLC individual/group promiscuous mode - * if number of incoming multicast addresses > - * (CAM max size - number of unicast addresses in CAM) - * enable LLC group promiscuous mode - * set driver-maintained multicast address count to zero - * else - * disable LLC group promiscuous mode - * set driver-maintained multicast address count to incoming count - * update adapter CAM - * update adapter filters - * - * Return Codes: - * None - * - * Assumptions: - * Multicast addresses are presented in canonical (LSB) format. - * - * Side Effects: - * On-board adapter CAM and filters are updated. - */ - -static void dfx_ctl_set_multicast_list(struct net_device *dev) -{ - DFX_board_t *bp = netdev_priv(dev); - int i; /* used as index in for loop */ - struct netdev_hw_addr *ha; - - /* Enable LLC frame promiscuous mode, if necessary */ - - if (dev->flags & IFF_PROMISC) - bp->ind_group_prom = PI_FSTATE_K_PASS; /* Enable LLC ind/group prom mode */ - - /* Else, update multicast address table */ - - else - { - bp->ind_group_prom = PI_FSTATE_K_BLOCK; /* Disable LLC ind/group prom mode */ - /* - * Check whether incoming multicast address count exceeds table size - * - * Note: The adapters utilize an on-board 64 entry CAM for - * supporting perfect filtering of multicast packets - * and bridge functions when adding unicast addresses. - * There is no hash function available. To support - * additional multicast addresses, the all multicast - * filter (LLC group promiscuous mode) must be enabled. - * - * The firmware reserves two CAM entries for SMT-related - * multicast addresses, which leaves 62 entries available. - * The following code ensures that we're not being asked - * to add more than 62 addresses to the CAM. If we are, - * the driver will enable the all multicast filter. - * Should the number of multicast addresses drop below - * the high water mark, the filter will be disabled and - * perfect filtering will be used. - */ - - if (netdev_mc_count(dev) > (PI_CMD_ADDR_FILTER_K_SIZE - bp->uc_count)) - { - bp->group_prom = PI_FSTATE_K_PASS; /* Enable LLC group prom mode */ - bp->mc_count = 0; /* Don't add mc addrs to CAM */ - } - else - { - bp->group_prom = PI_FSTATE_K_BLOCK; /* Disable LLC group prom mode */ - bp->mc_count = netdev_mc_count(dev); /* Add mc addrs to CAM */ - } - - /* Copy addresses to multicast address table, then update adapter CAM */ - - i = 0; - netdev_for_each_mc_addr(ha, dev) - memcpy(&bp->mc_table[i++ * FDDI_K_ALEN], - ha->addr, FDDI_K_ALEN); - - if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS) - { - DBG_printk("%s: Could not update multicast address table!\n", dev->name); - } - else - { - DBG_printk("%s: Multicast address table updated! Added %d addresses.\n", dev->name, bp->mc_count); - } - } - - /* Update adapter filters */ - - if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS) - { - DBG_printk("%s: Could not update adapter filters!\n", dev->name); - } - else - { - DBG_printk("%s: Adapter filters updated!\n", dev->name); - } - } - - -/* - * =========================== - * = dfx_ctl_set_mac_address = - * =========================== - * - * Overview: - * Add node address override (unicast address) to adapter - * CAM and update dev_addr field in device table. - * - * Returns: - * None - * - * Arguments: - * dev - pointer to device information - * addr - pointer to sockaddr structure containing unicast address to add - * - * Functional Description: - * The adapter supports node address overrides by adding one or more - * unicast addresses to the adapter CAM. This is similar to adding - * multicast addresses. In this routine we'll update the driver and - * device structures with the new address, then update the adapter CAM - * to ensure that the adapter will copy and strip frames destined and - * sourced by that address. - * - * Return Codes: - * Always returns zero. - * - * Assumptions: - * The address pointed to by addr->sa_data is a valid unicast - * address and is presented in canonical (LSB) format. - * - * Side Effects: - * On-board adapter CAM is updated. On-board adapter filters - * may be updated. - */ - -static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr) - { - struct sockaddr *p_sockaddr = (struct sockaddr *)addr; - DFX_board_t *bp = netdev_priv(dev); - - /* Copy unicast address to driver-maintained structs and update count */ - - memcpy(dev->dev_addr, p_sockaddr->sa_data, FDDI_K_ALEN); /* update device struct */ - memcpy(&bp->uc_table[0], p_sockaddr->sa_data, FDDI_K_ALEN); /* update driver struct */ - bp->uc_count = 1; - - /* - * Verify we're not exceeding the CAM size by adding unicast address - * - * Note: It's possible that before entering this routine we've - * already filled the CAM with 62 multicast addresses. - * Since we need to place the node address override into - * the CAM, we have to check to see that we're not - * exceeding the CAM size. If we are, we have to enable - * the LLC group (multicast) promiscuous mode filter as - * in dfx_ctl_set_multicast_list. - */ - - if ((bp->uc_count + bp->mc_count) > PI_CMD_ADDR_FILTER_K_SIZE) - { - bp->group_prom = PI_FSTATE_K_PASS; /* Enable LLC group prom mode */ - bp->mc_count = 0; /* Don't add mc addrs to CAM */ - - /* Update adapter filters */ - - if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS) - { - DBG_printk("%s: Could not update adapter filters!\n", dev->name); - } - else - { - DBG_printk("%s: Adapter filters updated!\n", dev->name); - } - } - - /* Update adapter CAM with new unicast address */ - - if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS) - { - DBG_printk("%s: Could not set new MAC address!\n", dev->name); - } - else - { - DBG_printk("%s: Adapter CAM updated with new MAC address\n", dev->name); - } - return 0; /* always return zero */ - } - - -/* - * ====================== - * = dfx_ctl_update_cam = - * ====================== - * - * Overview: - * Procedure to update adapter CAM (Content Addressable Memory) - * with desired unicast and multicast address entries. - * - * Returns: - * Condition code - * - * Arguments: - * bp - pointer to board information - * - * Functional Description: - * Updates adapter CAM with current contents of board structure - * unicast and multicast address tables. Since there are only 62 - * free entries in CAM, this routine ensures that the command - * request buffer is not overrun. - * - * Return Codes: - * DFX_K_SUCCESS - Request succeeded - * DFX_K_FAILURE - Request failed - * - * Assumptions: - * All addresses being added (unicast and multicast) are in canonical - * order. - * - * Side Effects: - * On-board adapter CAM is updated. - */ - -static int dfx_ctl_update_cam(DFX_board_t *bp) - { - int i; /* used as index */ - PI_LAN_ADDR *p_addr; /* pointer to CAM entry */ - - /* - * Fill in command request information - * - * Note: Even though both the unicast and multicast address - * table entries are stored as contiguous 6 byte entries, - * the firmware address filter set command expects each - * entry to be two longwords (8 bytes total). We must be - * careful to only copy the six bytes of each unicast and - * multicast table entry into each command entry. This - * is also why we must first clear the entire command - * request buffer. - */ - - memset(bp->cmd_req_virt, 0, PI_CMD_REQ_K_SIZE_MAX); /* first clear buffer */ - bp->cmd_req_virt->cmd_type = PI_CMD_K_ADDR_FILTER_SET; - p_addr = &bp->cmd_req_virt->addr_filter_set.entry[0]; - - /* Now add unicast addresses to command request buffer, if any */ - - for (i=0; i < (int)bp->uc_count; i++) - { - if (i < PI_CMD_ADDR_FILTER_K_SIZE) - { - memcpy(p_addr, &bp->uc_table[i*FDDI_K_ALEN], FDDI_K_ALEN); - p_addr++; /* point to next command entry */ - } - } - - /* Now add multicast addresses to command request buffer, if any */ - - for (i=0; i < (int)bp->mc_count; i++) - { - if ((i + bp->uc_count) < PI_CMD_ADDR_FILTER_K_SIZE) - { - memcpy(p_addr, &bp->mc_table[i*FDDI_K_ALEN], FDDI_K_ALEN); - p_addr++; /* point to next command entry */ - } - } - - /* Issue command to update adapter CAM, then return */ - - if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) - return DFX_K_FAILURE; - return DFX_K_SUCCESS; - } - - -/* - * ========================== - * = dfx_ctl_update_filters = - * ========================== - * - * Overview: - * Procedure to update adapter filters with desired - * filter settings. - * - * Returns: - * Condition code - * - * Arguments: - * bp - pointer to board information - * - * Functional Description: - * Enables or disables filter using current filter settings. - * - * Return Codes: - * DFX_K_SUCCESS - Request succeeded. - * DFX_K_FAILURE - Request failed. - * - * Assumptions: - * We must always pass up packets destined to the broadcast - * address (FF-FF-FF-FF-FF-FF), so we'll always keep the - * broadcast filter enabled. - * - * Side Effects: - * On-board adapter filters are updated. - */ - -static int dfx_ctl_update_filters(DFX_board_t *bp) - { - int i = 0; /* used as index */ - - /* Fill in command request information */ - - bp->cmd_req_virt->cmd_type = PI_CMD_K_FILTERS_SET; - - /* Initialize Broadcast filter - * ALWAYS ENABLED * */ - - bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_BROADCAST; - bp->cmd_req_virt->filter_set.item[i++].value = PI_FSTATE_K_PASS; - - /* Initialize LLC Individual/Group Promiscuous filter */ - - bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_IND_GROUP_PROM; - bp->cmd_req_virt->filter_set.item[i++].value = bp->ind_group_prom; - - /* Initialize LLC Group Promiscuous filter */ - - bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_GROUP_PROM; - bp->cmd_req_virt->filter_set.item[i++].value = bp->group_prom; - - /* Terminate the item code list */ - - bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_EOL; - - /* Issue command to update adapter filters, then return */ - - if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) - return DFX_K_FAILURE; - return DFX_K_SUCCESS; - } - - -/* - * ====================== - * = dfx_hw_dma_cmd_req = - * ====================== - * - * Overview: - * Sends PDQ DMA command to adapter firmware - * - * Returns: - * Condition code - * - * Arguments: - * bp - pointer to board information - * - * Functional Description: - * The command request and response buffers are posted to the adapter in the manner - * described in the PDQ Port Specification: - * - * 1. Command Response Buffer is posted to adapter. - * 2. Command Request Buffer is posted to adapter. - * 3. Command Request consumer index is polled until it indicates that request - * buffer has been DMA'd to adapter. - * 4. Command Response consumer index is polled until it indicates that response - * buffer has been DMA'd from adapter. - * - * This ordering ensures that a response buffer is already available for the firmware - * to use once it's done processing the request buffer. - * - * Return Codes: - * DFX_K_SUCCESS - DMA command succeeded - * DFX_K_OUTSTATE - Adapter is NOT in proper state - * DFX_K_HW_TIMEOUT - DMA command timed out - * - * Assumptions: - * Command request buffer has already been filled with desired DMA command. - * - * Side Effects: - * None - */ - -static int dfx_hw_dma_cmd_req(DFX_board_t *bp) - { - int status; /* adapter status */ - int timeout_cnt; /* used in for loops */ - - /* Make sure the adapter is in a state that we can issue the DMA command in */ - - status = dfx_hw_adap_state_rd(bp); - if ((status == PI_STATE_K_RESET) || - (status == PI_STATE_K_HALTED) || - (status == PI_STATE_K_DMA_UNAVAIL) || - (status == PI_STATE_K_UPGRADE)) - return DFX_K_OUTSTATE; - - /* Put response buffer on the command response queue */ - - bp->descr_block_virt->cmd_rsp[bp->cmd_rsp_reg.index.prod].long_0 = (u32) (PI_RCV_DESCR_M_SOP | - ((PI_CMD_RSP_K_SIZE_MAX / PI_ALIGN_K_CMD_RSP_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); - bp->descr_block_virt->cmd_rsp[bp->cmd_rsp_reg.index.prod].long_1 = bp->cmd_rsp_phys; - - /* Bump (and wrap) the producer index and write out to register */ - - bp->cmd_rsp_reg.index.prod += 1; - bp->cmd_rsp_reg.index.prod &= PI_CMD_RSP_K_NUM_ENTRIES-1; - dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_RSP_PROD, bp->cmd_rsp_reg.lword); - - /* Put request buffer on the command request queue */ - - bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_0 = (u32) (PI_XMT_DESCR_M_SOP | - PI_XMT_DESCR_M_EOP | (PI_CMD_REQ_K_SIZE_MAX << PI_XMT_DESCR_V_SEG_LEN)); - bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_1 = bp->cmd_req_phys; - - /* Bump (and wrap) the producer index and write out to register */ - - bp->cmd_req_reg.index.prod += 1; - bp->cmd_req_reg.index.prod &= PI_CMD_REQ_K_NUM_ENTRIES-1; - dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_REQ_PROD, bp->cmd_req_reg.lword); - - /* - * Here we wait for the command request consumer index to be equal - * to the producer, indicating that the adapter has DMAed the request. - */ - - for (timeout_cnt = 20000; timeout_cnt > 0; timeout_cnt--) - { - if (bp->cmd_req_reg.index.prod == (u8)(bp->cons_block_virt->cmd_req)) - break; - udelay(100); /* wait for 100 microseconds */ - } - if (timeout_cnt == 0) - return DFX_K_HW_TIMEOUT; - - /* Bump (and wrap) the completion index and write out to register */ - - bp->cmd_req_reg.index.comp += 1; - bp->cmd_req_reg.index.comp &= PI_CMD_REQ_K_NUM_ENTRIES-1; - dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_REQ_PROD, bp->cmd_req_reg.lword); - - /* - * Here we wait for the command response consumer index to be equal - * to the producer, indicating that the adapter has DMAed the response. - */ - - for (timeout_cnt = 20000; timeout_cnt > 0; timeout_cnt--) - { - if (bp->cmd_rsp_reg.index.prod == (u8)(bp->cons_block_virt->cmd_rsp)) - break; - udelay(100); /* wait for 100 microseconds */ - } - if (timeout_cnt == 0) - return DFX_K_HW_TIMEOUT; - - /* Bump (and wrap) the completion index and write out to register */ - - bp->cmd_rsp_reg.index.comp += 1; - bp->cmd_rsp_reg.index.comp &= PI_CMD_RSP_K_NUM_ENTRIES-1; - dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_RSP_PROD, bp->cmd_rsp_reg.lword); - return DFX_K_SUCCESS; - } - - -/* - * ======================== - * = dfx_hw_port_ctrl_req = - * ======================== - * - * Overview: - * Sends PDQ port control command to adapter firmware - * - * Returns: - * Host data register value in host_data if ptr is not NULL - * - * Arguments: - * bp - pointer to board information - * command - port control command - * data_a - port data A register value - * data_b - port data B register value - * host_data - ptr to host data register value - * - * Functional Description: - * Send generic port control command to adapter by writing - * to various PDQ port registers, then polling for completion. - * - * Return Codes: - * DFX_K_SUCCESS - port control command succeeded - * DFX_K_HW_TIMEOUT - port control command timed out - * - * Assumptions: - * None - * - * Side Effects: - * None - */ - -static int dfx_hw_port_ctrl_req( - DFX_board_t *bp, - PI_UINT32 command, - PI_UINT32 data_a, - PI_UINT32 data_b, - PI_UINT32 *host_data - ) - - { - PI_UINT32 port_cmd; /* Port Control command register value */ - int timeout_cnt; /* used in for loops */ - - /* Set Command Error bit in command longword */ - - port_cmd = (PI_UINT32) (command | PI_PCTRL_M_CMD_ERROR); - - /* Issue port command to the adapter */ - - dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_A, data_a); - dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_B, data_b); - dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_CTRL, port_cmd); - - /* Now wait for command to complete */ - - if (command == PI_PCTRL_M_BLAST_FLASH) - timeout_cnt = 600000; /* set command timeout count to 60 seconds */ - else - timeout_cnt = 20000; /* set command timeout count to 2 seconds */ - - for (; timeout_cnt > 0; timeout_cnt--) - { - dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_CTRL, &port_cmd); - if (!(port_cmd & PI_PCTRL_M_CMD_ERROR)) - break; - udelay(100); /* wait for 100 microseconds */ - } - if (timeout_cnt == 0) - return DFX_K_HW_TIMEOUT; - - /* - * If the address of host_data is non-zero, assume caller has supplied a - * non NULL pointer, and return the contents of the HOST_DATA register in - * it. - */ - - if (host_data != NULL) - dfx_port_read_long(bp, PI_PDQ_K_REG_HOST_DATA, host_data); - return DFX_K_SUCCESS; - } - - -/* - * ===================== - * = dfx_hw_adap_reset = - * ===================== - * - * Overview: - * Resets adapter - * - * Returns: - * None - * - * Arguments: - * bp - pointer to board information - * type - type of reset to perform - * - * Functional Description: - * Issue soft reset to adapter by writing to PDQ Port Reset - * register. Use incoming reset type to tell adapter what - * kind of reset operation to perform. - * - * Return Codes: - * None - * - * Assumptions: - * This routine merely issues a soft reset to the adapter. - * It is expected that after this routine returns, the caller - * will appropriately poll the Port Status register for the - * adapter to enter the proper state. - * - * Side Effects: - * Internal adapter registers are cleared. - */ - -static void dfx_hw_adap_reset( - DFX_board_t *bp, - PI_UINT32 type - ) - - { - /* Set Reset type and assert reset */ - - dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_A, type); /* tell adapter type of reset */ - dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, PI_RESET_M_ASSERT_RESET); - - /* Wait for at least 1 Microsecond according to the spec. We wait 20 just to be safe */ - - udelay(20); - - /* Deassert reset */ - - dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, 0); - } - - -/* - * ======================== - * = dfx_hw_adap_state_rd = - * ======================== - * - * Overview: - * Returns current adapter state - * - * Returns: - * Adapter state per PDQ Port Specification - * - * Arguments: - * bp - pointer to board information - * - * Functional Description: - * Reads PDQ Port Status register and returns adapter state. - * - * Return Codes: - * None - * - * Assumptions: - * None - * - * Side Effects: - * None - */ - -static int dfx_hw_adap_state_rd(DFX_board_t *bp) - { - PI_UINT32 port_status; /* Port Status register value */ - - dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status); - return (port_status & PI_PSTATUS_M_STATE) >> PI_PSTATUS_V_STATE; - } - - -/* - * ===================== - * = dfx_hw_dma_uninit = - * ===================== - * - * Overview: - * Brings adapter to DMA_UNAVAILABLE state - * - * Returns: - * Condition code - * - * Arguments: - * bp - pointer to board information - * type - type of reset to perform - * - * Functional Description: - * Bring adapter to DMA_UNAVAILABLE state by performing the following: - * 1. Set reset type bit in Port Data A Register then reset adapter. - * 2. Check that adapter is in DMA_UNAVAILABLE state. - * - * Return Codes: - * DFX_K_SUCCESS - adapter is in DMA_UNAVAILABLE state - * DFX_K_HW_TIMEOUT - adapter did not reset properly - * - * Assumptions: - * None - * - * Side Effects: - * Internal adapter registers are cleared. - */ - -static int dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type) - { - int timeout_cnt; /* used in for loops */ - - /* Set reset type bit and reset adapter */ - - dfx_hw_adap_reset(bp, type); - - /* Now wait for adapter to enter DMA_UNAVAILABLE state */ - - for (timeout_cnt = 100000; timeout_cnt > 0; timeout_cnt--) - { - if (dfx_hw_adap_state_rd(bp) == PI_STATE_K_DMA_UNAVAIL) - break; - udelay(100); /* wait for 100 microseconds */ - } - if (timeout_cnt == 0) - return DFX_K_HW_TIMEOUT; - return DFX_K_SUCCESS; - } - -/* - * Align an sk_buff to a boundary power of 2 - * - */ - -static void my_skb_align(struct sk_buff *skb, int n) -{ - unsigned long x = (unsigned long)skb->data; - unsigned long v; - - v = ALIGN(x, n); /* Where we want to be */ - - skb_reserve(skb, v - x); -} - - -/* - * ================ - * = dfx_rcv_init = - * ================ - * - * Overview: - * Produces buffers to adapter LLC Host receive descriptor block - * - * Returns: - * None - * - * Arguments: - * bp - pointer to board information - * get_buffers - non-zero if buffers to be allocated - * - * Functional Description: - * This routine can be called during dfx_adap_init() or during an adapter - * reset. It initializes the descriptor block and produces all allocated - * LLC Host queue receive buffers. - * - * Return Codes: - * Return 0 on success or -ENOMEM if buffer allocation failed (when using - * dynamic buffer allocation). If the buffer allocation failed, the - * already allocated buffers will not be released and the caller should do - * this. - * - * Assumptions: - * The PDQ has been reset and the adapter and driver maintained Type 2 - * register indices are cleared. - * - * Side Effects: - * Receive buffers are posted to the adapter LLC queue and the adapter - * is notified. - */ - -static int dfx_rcv_init(DFX_board_t *bp, int get_buffers) - { - int i, j; /* used in for loop */ - - /* - * Since each receive buffer is a single fragment of same length, initialize - * first longword in each receive descriptor for entire LLC Host descriptor - * block. Also initialize second longword in each receive descriptor with - * physical address of receive buffer. We'll always allocate receive - * buffers in powers of 2 so that we can easily fill the 256 entry descriptor - * block and produce new receive buffers by simply updating the receive - * producer index. - * - * Assumptions: - * To support all shipping versions of PDQ, the receive buffer size - * must be mod 128 in length and the physical address must be 128 byte - * aligned. In other words, bits 0-6 of the length and address must - * be zero for the following descriptor field entries to be correct on - * all PDQ-based boards. We guaranteed both requirements during - * driver initialization when we allocated memory for the receive buffers. - */ - - if (get_buffers) { -#ifdef DYNAMIC_BUFFERS - for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++) - for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) - { - struct sk_buff *newskb = __netdev_alloc_skb(bp->dev, NEW_SKB_SIZE, GFP_NOIO); - if (!newskb) - return -ENOMEM; - bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP | - ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); - /* - * align to 128 bytes for compatibility with - * the old EISA boards. - */ - - my_skb_align(newskb, 128); - bp->descr_block_virt->rcv_data[i + j].long_1 = - (u32)dma_map_single(bp->bus_dev, newskb->data, - NEW_SKB_SIZE, - DMA_FROM_DEVICE); - /* - * p_rcv_buff_va is only used inside the - * kernel so we put the skb pointer here. - */ - bp->p_rcv_buff_va[i+j] = (char *) newskb; - } -#else - for (i=0; i < (int)(bp->rcv_bufs_to_post); i++) - for (j=0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) - { - bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP | - ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); - bp->descr_block_virt->rcv_data[i+j].long_1 = (u32) (bp->rcv_block_phys + (i * PI_RCV_DATA_K_SIZE_MAX)); - bp->p_rcv_buff_va[i+j] = (char *) (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX)); - } -#endif - } - - /* Update receive producer and Type 2 register */ - - bp->rcv_xmt_reg.index.rcv_prod = bp->rcv_bufs_to_post; - dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); - return 0; - } - - -/* - * ========================= - * = dfx_rcv_queue_process = - * ========================= - * - * Overview: - * Process received LLC frames. - * - * Returns: - * None - * - * Arguments: - * bp - pointer to board information - * - * Functional Description: - * Received LLC frames are processed until there are no more consumed frames. - * Once all frames are processed, the receive buffers are returned to the - * adapter. Note that this algorithm fixes the length of time that can be spent - * in this routine, because there are a fixed number of receive buffers to - * process and buffers are not produced until this routine exits and returns - * to the ISR. - * - * Return Codes: - * None - * - * Assumptions: - * None - * - * Side Effects: - * None - */ - -static void dfx_rcv_queue_process( - DFX_board_t *bp - ) - - { - PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */ - char *p_buff; /* ptr to start of packet receive buffer (FMC descriptor) */ - u32 descr, pkt_len; /* FMC descriptor field and packet length */ - struct sk_buff *skb; /* pointer to a sk_buff to hold incoming packet data */ - - /* Service all consumed LLC receive frames */ - - p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data); - while (bp->rcv_xmt_reg.index.rcv_comp != p_type_2_cons->index.rcv_cons) - { - /* Process any errors */ - - int entry; - - entry = bp->rcv_xmt_reg.index.rcv_comp; -#ifdef DYNAMIC_BUFFERS - p_buff = (char *) (((struct sk_buff *)bp->p_rcv_buff_va[entry])->data); -#else - p_buff = (char *) bp->p_rcv_buff_va[entry]; -#endif - memcpy(&descr, p_buff + RCV_BUFF_K_DESCR, sizeof(u32)); - - if (descr & PI_FMC_DESCR_M_RCC_FLUSH) - { - if (descr & PI_FMC_DESCR_M_RCC_CRC) - bp->rcv_crc_errors++; - else - bp->rcv_frame_status_errors++; - } - else - { - int rx_in_place = 0; - - /* The frame was received without errors - verify packet length */ - - pkt_len = (u32)((descr & PI_FMC_DESCR_M_LEN) >> PI_FMC_DESCR_V_LEN); - pkt_len -= 4; /* subtract 4 byte CRC */ - if (!IN_RANGE(pkt_len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN)) - bp->rcv_length_errors++; - else{ -#ifdef DYNAMIC_BUFFERS - if (pkt_len > SKBUFF_RX_COPYBREAK) { - struct sk_buff *newskb; - - newskb = dev_alloc_skb(NEW_SKB_SIZE); - if (newskb){ - rx_in_place = 1; - - my_skb_align(newskb, 128); - skb = (struct sk_buff *)bp->p_rcv_buff_va[entry]; - dma_unmap_single(bp->bus_dev, - bp->descr_block_virt->rcv_data[entry].long_1, - NEW_SKB_SIZE, - DMA_FROM_DEVICE); - skb_reserve(skb, RCV_BUFF_K_PADDING); - bp->p_rcv_buff_va[entry] = (char *)newskb; - bp->descr_block_virt->rcv_data[entry].long_1 = - (u32)dma_map_single(bp->bus_dev, - newskb->data, - NEW_SKB_SIZE, - DMA_FROM_DEVICE); - } else - skb = NULL; - } else -#endif - skb = dev_alloc_skb(pkt_len+3); /* alloc new buffer to pass up, add room for PRH */ - if (skb == NULL) - { - printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); - bp->rcv_discards++; - break; - } - else { -#ifndef DYNAMIC_BUFFERS - if (! rx_in_place) -#endif - { - /* Receive buffer allocated, pass receive packet up */ - - skb_copy_to_linear_data(skb, - p_buff + RCV_BUFF_K_PADDING, - pkt_len + 3); - } - - skb_reserve(skb,3); /* adjust data field so that it points to FC byte */ - skb_put(skb, pkt_len); /* pass up packet length, NOT including CRC */ - skb->protocol = fddi_type_trans(skb, bp->dev); - bp->rcv_total_bytes += skb->len; - netif_rx(skb); - - /* Update the rcv counters */ - bp->rcv_total_frames++; - if (*(p_buff + RCV_BUFF_K_DA) & 0x01) - bp->rcv_multicast_frames++; - } - } - } - - /* - * Advance the producer (for recycling) and advance the completion - * (for servicing received frames). Note that it is okay to - * advance the producer without checking that it passes the - * completion index because they are both advanced at the same - * rate. - */ - - bp->rcv_xmt_reg.index.rcv_prod += 1; - bp->rcv_xmt_reg.index.rcv_comp += 1; - } - } - - -/* - * ===================== - * = dfx_xmt_queue_pkt = - * ===================== - * - * Overview: - * Queues packets for transmission - * - * Returns: - * Condition code - * - * Arguments: - * skb - pointer to sk_buff to queue for transmission - * dev - pointer to device information - * - * Functional Description: - * Here we assume that an incoming skb transmit request - * is contained in a single physically contiguous buffer - * in which the virtual address of the start of packet - * (skb->data) can be converted to a physical address - * by using pci_map_single(). - * - * Since the adapter architecture requires a three byte - * packet request header to prepend the start of packet, - * we'll write the three byte field immediately prior to - * the FC byte. This assumption is valid because we've - * ensured that dev->hard_header_len includes three pad - * bytes. By posting a single fragment to the adapter, - * we'll reduce the number of descriptor fetches and - * bus traffic needed to send the request. - * - * Also, we can't free the skb until after it's been DMA'd - * out by the adapter, so we'll queue it in the driver and - * return it in dfx_xmt_done. - * - * Return Codes: - * 0 - driver queued packet, link is unavailable, or skbuff was bad - * 1 - caller should requeue the sk_buff for later transmission - * - * Assumptions: - * First and foremost, we assume the incoming skb pointer - * is NOT NULL and is pointing to a valid sk_buff structure. - * - * The outgoing packet is complete, starting with the - * frame control byte including the last byte of data, - * but NOT including the 4 byte CRC. We'll let the - * adapter hardware generate and append the CRC. - * - * The entire packet is stored in one physically - * contiguous buffer which is not cached and whose - * 32-bit physical address can be determined. - * - * It's vital that this routine is NOT reentered for the - * same board and that the OS is not in another section of - * code (eg. dfx_int_common) for the same board on a - * different thread. - * - * Side Effects: - * None - */ - -static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, - struct net_device *dev) - { - DFX_board_t *bp = netdev_priv(dev); - u8 prod; /* local transmit producer index */ - PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */ - XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ - unsigned long flags; - - netif_stop_queue(dev); - - /* - * Verify that incoming transmit request is OK - * - * Note: The packet size check is consistent with other - * Linux device drivers, although the correct packet - * size should be verified before calling the - * transmit routine. - */ - - if (!IN_RANGE(skb->len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN)) - { - printk("%s: Invalid packet length - %u bytes\n", - dev->name, skb->len); - bp->xmt_length_errors++; /* bump error counter */ - netif_wake_queue(dev); - dev_kfree_skb(skb); - return NETDEV_TX_OK; /* return "success" */ - } - /* - * See if adapter link is available, if not, free buffer - * - * Note: If the link isn't available, free buffer and return 0 - * rather than tell the upper layer to requeue the packet. - * The methodology here is that by the time the link - * becomes available, the packet to be sent will be - * fairly stale. By simply dropping the packet, the - * higher layer protocols will eventually time out - * waiting for response packets which it won't receive. - */ - - if (bp->link_available == PI_K_FALSE) - { - if (dfx_hw_adap_state_rd(bp) == PI_STATE_K_LINK_AVAIL) /* is link really available? */ - bp->link_available = PI_K_TRUE; /* if so, set flag and continue */ - else - { - bp->xmt_discards++; /* bump error counter */ - dev_kfree_skb(skb); /* free sk_buff now */ - netif_wake_queue(dev); - return NETDEV_TX_OK; /* return "success" */ - } - } - - spin_lock_irqsave(&bp->lock, flags); - - /* Get the current producer and the next free xmt data descriptor */ - - prod = bp->rcv_xmt_reg.index.xmt_prod; - p_xmt_descr = &(bp->descr_block_virt->xmt_data[prod]); - - /* - * Get pointer to auxiliary queue entry to contain information - * for this packet. - * - * Note: The current xmt producer index will become the - * current xmt completion index when we complete this - * packet later on. So, we'll get the pointer to the - * next auxiliary queue entry now before we bump the - * producer index. - */ - - p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[prod++]); /* also bump producer index */ - - /* Write the three PRH bytes immediately before the FC byte */ - - skb_push(skb,3); - skb->data[0] = DFX_PRH0_BYTE; /* these byte values are defined */ - skb->data[1] = DFX_PRH1_BYTE; /* in the Motorola FDDI MAC chip */ - skb->data[2] = DFX_PRH2_BYTE; /* specification */ - - /* - * Write the descriptor with buffer info and bump producer - * - * Note: Since we need to start DMA from the packet request - * header, we'll add 3 bytes to the DMA buffer length, - * and we'll determine the physical address of the - * buffer from the PRH, not skb->data. - * - * Assumptions: - * 1. Packet starts with the frame control (FC) byte - * at skb->data. - * 2. The 4-byte CRC is not appended to the buffer or - * included in the length. - * 3. Packet length (skb->len) is from FC to end of - * data, inclusive. - * 4. The packet length does not exceed the maximum - * FDDI LLC frame length of 4491 bytes. - * 5. The entire packet is contained in a physically - * contiguous, non-cached, locked memory space - * comprised of a single buffer pointed to by - * skb->data. - * 6. The physical address of the start of packet - * can be determined from the virtual address - * by using pci_map_single() and is only 32-bits - * wide. - */ - - p_xmt_descr->long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len) << PI_XMT_DESCR_V_SEG_LEN)); - p_xmt_descr->long_1 = (u32)dma_map_single(bp->bus_dev, skb->data, - skb->len, DMA_TO_DEVICE); - - /* - * Verify that descriptor is actually available - * - * Note: If descriptor isn't available, return 1 which tells - * the upper layer to requeue the packet for later - * transmission. - * - * We need to ensure that the producer never reaches the - * completion, except to indicate that the queue is empty. - */ - - if (prod == bp->rcv_xmt_reg.index.xmt_comp) - { - skb_pull(skb,3); - spin_unlock_irqrestore(&bp->lock, flags); - return NETDEV_TX_BUSY; /* requeue packet for later */ - } - - /* - * Save info for this packet for xmt done indication routine - * - * Normally, we'd save the producer index in the p_xmt_drv_descr - * structure so that we'd have it handy when we complete this - * packet later (in dfx_xmt_done). However, since the current - * transmit architecture guarantees a single fragment for the - * entire packet, we can simply bump the completion index by - * one (1) for each completed packet. - * - * Note: If this assumption changes and we're presented with - * an inconsistent number of transmit fragments for packet - * data, we'll need to modify this code to save the current - * transmit producer index. - */ - - p_xmt_drv_descr->p_skb = skb; - - /* Update Type 2 register */ - - bp->rcv_xmt_reg.index.xmt_prod = prod; - dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); - spin_unlock_irqrestore(&bp->lock, flags); - netif_wake_queue(dev); - return NETDEV_TX_OK; /* packet queued to adapter */ - } - - -/* - * ================ - * = dfx_xmt_done = - * ================ - * - * Overview: - * Processes all frames that have been transmitted. - * - * Returns: - * None - * - * Arguments: - * bp - pointer to board information - * - * Functional Description: - * For all consumed transmit descriptors that have not - * yet been completed, we'll free the skb we were holding - * onto using dev_kfree_skb and bump the appropriate - * counters. - * - * Return Codes: - * None - * - * Assumptions: - * The Type 2 register is not updated in this routine. It is - * assumed that it will be updated in the ISR when dfx_xmt_done - * returns. - * - * Side Effects: - * None - */ - -static int dfx_xmt_done(DFX_board_t *bp) - { - XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ - PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */ - u8 comp; /* local transmit completion index */ - int freed = 0; /* buffers freed */ - - /* Service all consumed transmit frames */ - - p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data); - while (bp->rcv_xmt_reg.index.xmt_comp != p_type_2_cons->index.xmt_cons) - { - /* Get pointer to the transmit driver descriptor block information */ - - p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[bp->rcv_xmt_reg.index.xmt_comp]); - - /* Increment transmit counters */ - - bp->xmt_total_frames++; - bp->xmt_total_bytes += p_xmt_drv_descr->p_skb->len; - - /* Return skb to operating system */ - comp = bp->rcv_xmt_reg.index.xmt_comp; - dma_unmap_single(bp->bus_dev, - bp->descr_block_virt->xmt_data[comp].long_1, - p_xmt_drv_descr->p_skb->len, - DMA_TO_DEVICE); - dev_kfree_skb_irq(p_xmt_drv_descr->p_skb); - - /* - * Move to start of next packet by updating completion index - * - * Here we assume that a transmit packet request is always - * serviced by posting one fragment. We can therefore - * simplify the completion code by incrementing the - * completion index by one. This code will need to be - * modified if this assumption changes. See comments - * in dfx_xmt_queue_pkt for more details. - */ - - bp->rcv_xmt_reg.index.xmt_comp += 1; - freed++; - } - return freed; - } - - -/* - * ================= - * = dfx_rcv_flush = - * ================= - * - * Overview: - * Remove all skb's in the receive ring. - * - * Returns: - * None - * - * Arguments: - * bp - pointer to board information - * - * Functional Description: - * Free's all the dynamically allocated skb's that are - * currently attached to the device receive ring. This - * function is typically only used when the device is - * initialized or reinitialized. - * - * Return Codes: - * None - * - * Side Effects: - * None - */ -#ifdef DYNAMIC_BUFFERS -static void dfx_rcv_flush( DFX_board_t *bp ) - { - int i, j; - - for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++) - for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) - { - struct sk_buff *skb; - skb = (struct sk_buff *)bp->p_rcv_buff_va[i+j]; - if (skb) - dev_kfree_skb(skb); - bp->p_rcv_buff_va[i+j] = NULL; - } - - } -#else -static inline void dfx_rcv_flush( DFX_board_t *bp ) -{ -} -#endif /* DYNAMIC_BUFFERS */ - -/* - * ================= - * = dfx_xmt_flush = - * ================= - * - * Overview: - * Processes all frames whether they've been transmitted - * or not. - * - * Returns: - * None - * - * Arguments: - * bp - pointer to board information - * - * Functional Description: - * For all produced transmit descriptors that have not - * yet been completed, we'll free the skb we were holding - * onto using dev_kfree_skb and bump the appropriate - * counters. Of course, it's possible that some of - * these transmit requests actually did go out, but we - * won't make that distinction here. Finally, we'll - * update the consumer index to match the producer. - * - * Return Codes: - * None - * - * Assumptions: - * This routine does NOT update the Type 2 register. It - * is assumed that this routine is being called during a - * transmit flush interrupt, or a shutdown or close routine. - * - * Side Effects: - * None - */ - -static void dfx_xmt_flush( DFX_board_t *bp ) - { - u32 prod_cons; /* rcv/xmt consumer block longword */ - XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ - u8 comp; /* local transmit completion index */ - - /* Flush all outstanding transmit frames */ - - while (bp->rcv_xmt_reg.index.xmt_comp != bp->rcv_xmt_reg.index.xmt_prod) - { - /* Get pointer to the transmit driver descriptor block information */ - - p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[bp->rcv_xmt_reg.index.xmt_comp]); - - /* Return skb to operating system */ - comp = bp->rcv_xmt_reg.index.xmt_comp; - dma_unmap_single(bp->bus_dev, - bp->descr_block_virt->xmt_data[comp].long_1, - p_xmt_drv_descr->p_skb->len, - DMA_TO_DEVICE); - dev_kfree_skb(p_xmt_drv_descr->p_skb); - - /* Increment transmit error counter */ - - bp->xmt_discards++; - - /* - * Move to start of next packet by updating completion index - * - * Here we assume that a transmit packet request is always - * serviced by posting one fragment. We can therefore - * simplify the completion code by incrementing the - * completion index by one. This code will need to be - * modified if this assumption changes. See comments - * in dfx_xmt_queue_pkt for more details. - */ - - bp->rcv_xmt_reg.index.xmt_comp += 1; - } - - /* Update the transmit consumer index in the consumer block */ - - prod_cons = (u32)(bp->cons_block_virt->xmt_rcv_data & ~PI_CONS_M_XMT_INDEX); - prod_cons |= (u32)(bp->rcv_xmt_reg.index.xmt_prod << PI_CONS_V_XMT_INDEX); - bp->cons_block_virt->xmt_rcv_data = prod_cons; - } - -/* - * ================== - * = dfx_unregister = - * ================== - * - * Overview: - * Shuts down an FDDI controller - * - * Returns: - * Condition code - * - * Arguments: - * bdev - pointer to device information - * - * Functional Description: - * - * Return Codes: - * None - * - * Assumptions: - * It compiles so it should work :-( (PCI cards do :-) - * - * Side Effects: - * Device structures for FDDI adapters (fddi0, fddi1, etc) are - * freed. - */ -static void __devexit dfx_unregister(struct device *bdev) -{ - struct net_device *dev = dev_get_drvdata(bdev); - DFX_board_t *bp = netdev_priv(dev); - int dfx_bus_pci = DFX_BUS_PCI(bdev); - int dfx_bus_tc = DFX_BUS_TC(bdev); - int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; - resource_size_t bar_start = 0; /* pointer to port */ - resource_size_t bar_len = 0; /* resource length */ - int alloc_size; /* total buffer size used */ - - unregister_netdev(dev); - - alloc_size = sizeof(PI_DESCR_BLOCK) + - PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX + -#ifndef DYNAMIC_BUFFERS - (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) + -#endif - sizeof(PI_CONSUMER_BLOCK) + - (PI_ALIGN_K_DESC_BLK - 1); - if (bp->kmalloced) - dma_free_coherent(bdev, alloc_size, - bp->kmalloced, bp->kmalloced_dma); - - dfx_bus_uninit(dev); - - dfx_get_bars(bdev, &bar_start, &bar_len); - if (dfx_use_mmio) { - iounmap(bp->base.mem); - release_mem_region(bar_start, bar_len); - } else - release_region(bar_start, bar_len); - - if (dfx_bus_pci) - pci_disable_device(to_pci_dev(bdev)); - - free_netdev(dev); -} - - -static int __devinit __maybe_unused dfx_dev_register(struct device *); -static int __devexit __maybe_unused dfx_dev_unregister(struct device *); - -#ifdef CONFIG_PCI -static int __devinit dfx_pci_register(struct pci_dev *, - const struct pci_device_id *); -static void __devexit dfx_pci_unregister(struct pci_dev *); - -static DEFINE_PCI_DEVICE_TABLE(dfx_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI) }, - { } -}; -MODULE_DEVICE_TABLE(pci, dfx_pci_table); - -static struct pci_driver dfx_pci_driver = { - .name = "defxx", - .id_table = dfx_pci_table, - .probe = dfx_pci_register, - .remove = __devexit_p(dfx_pci_unregister), -}; - -static __devinit int dfx_pci_register(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - return dfx_register(&pdev->dev); -} - -static void __devexit dfx_pci_unregister(struct pci_dev *pdev) -{ - dfx_unregister(&pdev->dev); -} -#endif /* CONFIG_PCI */ - -#ifdef CONFIG_EISA -static struct eisa_device_id dfx_eisa_table[] = { - { "DEC3001", DEFEA_PROD_ID_1 }, - { "DEC3002", DEFEA_PROD_ID_2 }, - { "DEC3003", DEFEA_PROD_ID_3 }, - { "DEC3004", DEFEA_PROD_ID_4 }, - { } -}; -MODULE_DEVICE_TABLE(eisa, dfx_eisa_table); - -static struct eisa_driver dfx_eisa_driver = { - .id_table = dfx_eisa_table, - .driver = { - .name = "defxx", - .bus = &eisa_bus_type, - .probe = dfx_dev_register, - .remove = __devexit_p(dfx_dev_unregister), - }, -}; -#endif /* CONFIG_EISA */ - -#ifdef CONFIG_TC -static struct tc_device_id const dfx_tc_table[] = { - { "DEC ", "PMAF-FA " }, - { "DEC ", "PMAF-FD " }, - { "DEC ", "PMAF-FS " }, - { "DEC ", "PMAF-FU " }, - { } -}; -MODULE_DEVICE_TABLE(tc, dfx_tc_table); - -static struct tc_driver dfx_tc_driver = { - .id_table = dfx_tc_table, - .driver = { - .name = "defxx", - .bus = &tc_bus_type, - .probe = dfx_dev_register, - .remove = __devexit_p(dfx_dev_unregister), - }, -}; -#endif /* CONFIG_TC */ - -static int __devinit __maybe_unused dfx_dev_register(struct device *dev) -{ - int status; - - status = dfx_register(dev); - if (!status) - get_device(dev); - return status; -} - -static int __devexit __maybe_unused dfx_dev_unregister(struct device *dev) -{ - put_device(dev); - dfx_unregister(dev); - return 0; -} - - -static int __devinit dfx_init(void) -{ - int status; - - status = pci_register_driver(&dfx_pci_driver); - if (!status) - status = eisa_driver_register(&dfx_eisa_driver); - if (!status) - status = tc_register_driver(&dfx_tc_driver); - return status; -} - -static void __devexit dfx_cleanup(void) -{ - tc_unregister_driver(&dfx_tc_driver); - eisa_driver_unregister(&dfx_eisa_driver); - pci_unregister_driver(&dfx_pci_driver); -} - -module_init(dfx_init); -module_exit(dfx_cleanup); -MODULE_AUTHOR("Lawrence V. Stefani"); -MODULE_DESCRIPTION("DEC FDDIcontroller TC/EISA/PCI (DEFTA/DEFEA/DEFPA) driver " - DRV_VERSION " " DRV_RELDATE); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/defxx.h b/drivers/net/defxx.h deleted file mode 100644 index 19a6f64..0000000 --- a/drivers/net/defxx.h +++ /dev/null @@ -1,1801 +0,0 @@ -/* - * File Name: - * defxx.h - * - * Copyright Information: - * Copyright Digital Equipment Corporation 1996. - * - * This software may be used and distributed according to the terms of - * the GNU General Public License, incorporated herein by reference. - * - * Abstract: - * Contains all definitions specified by port specification and required - * by the defxx.c driver. - * - * The original author: - * LVS Lawrence V. Stefani - * - * Maintainers: - * macro Maciej W. Rozycki - * - * Modification History: - * Date Name Description - * 16-Aug-96 LVS Created. - * 09-Sep-96 LVS Added group_prom field. Moved read/write I/O - * macros to DEFXX.C. - * 12-Sep-96 LVS Removed packet request header pointers. - * 04 Aug 2003 macro Converted to the DMA API. - * 23 Oct 2006 macro Big-endian host support. - * 14 Dec 2006 macro TURBOchannel support. - */ - -#ifndef _DEFXX_H_ -#define _DEFXX_H_ - -/* Define basic types for unsigned chars, shorts, longs */ - -typedef u8 PI_UINT8; -typedef u16 PI_UINT16; -typedef u32 PI_UINT32; - -/* Define general structures */ - -typedef struct /* 64-bit counter */ - { - PI_UINT32 ms; - PI_UINT32 ls; - } PI_CNTR; - -typedef struct /* LAN address */ - { - PI_UINT32 lwrd_0; - PI_UINT32 lwrd_1; - } PI_LAN_ADDR; - -typedef struct /* Station ID address */ - { - PI_UINT32 octet_7_4; - PI_UINT32 octet_3_0; - } PI_STATION_ID; - - -/* Define general constants */ - -#define PI_ALIGN_K_DESC_BLK 8192 /* Descriptor block boundary */ -#define PI_ALIGN_K_CONS_BLK 64 /* Consumer block boundary */ -#define PI_ALIGN_K_CMD_REQ_BUFF 128 /* Xmt Command que buffer alignment */ -#define PI_ALIGN_K_CMD_RSP_BUFF 128 /* Rcv Command que buffer alignment */ -#define PI_ALIGN_K_UNSOL_BUFF 128 /* Unsol que buffer alignment */ -#define PI_ALIGN_K_XMT_DATA_BUFF 0 /* Xmt data que buffer alignment */ -#define PI_ALIGN_K_RCV_DATA_BUFF 128 /* Rcv que buffer alignment */ - -/* Define PHY index values */ - -#define PI_PHY_K_S 0 /* Index to S phy */ -#define PI_PHY_K_A 0 /* Index to A phy */ -#define PI_PHY_K_B 1 /* Index to B phy */ -#define PI_PHY_K_MAX 2 /* Max number of phys */ - -/* Define FMC descriptor fields */ - -#define PI_FMC_DESCR_V_SOP 31 -#define PI_FMC_DESCR_V_EOP 30 -#define PI_FMC_DESCR_V_FSC 27 -#define PI_FMC_DESCR_V_FSB_ERROR 26 -#define PI_FMC_DESCR_V_FSB_ADDR_RECOG 25 -#define PI_FMC_DESCR_V_FSB_ADDR_COPIED 24 -#define PI_FMC_DESCR_V_FSB 22 -#define PI_FMC_DESCR_V_RCC_FLUSH 21 -#define PI_FMC_DESCR_V_RCC_CRC 20 -#define PI_FMC_DESCR_V_RCC_RRR 17 -#define PI_FMC_DESCR_V_RCC_DD 15 -#define PI_FMC_DESCR_V_RCC_SS 13 -#define PI_FMC_DESCR_V_RCC 13 -#define PI_FMC_DESCR_V_LEN 0 - -#define PI_FMC_DESCR_M_SOP 0x80000000 -#define PI_FMC_DESCR_M_EOP 0x40000000 -#define PI_FMC_DESCR_M_FSC 0x38000000 -#define PI_FMC_DESCR_M_FSB_ERROR 0x04000000 -#define PI_FMC_DESCR_M_FSB_ADDR_RECOG 0x02000000 -#define PI_FMC_DESCR_M_FSB_ADDR_COPIED 0x01000000 -#define PI_FMC_DESCR_M_FSB 0x07C00000 -#define PI_FMC_DESCR_M_RCC_FLUSH 0x00200000 -#define PI_FMC_DESCR_M_RCC_CRC 0x00100000 -#define PI_FMC_DESCR_M_RCC_RRR 0x000E0000 -#define PI_FMC_DESCR_M_RCC_DD 0x00018000 -#define PI_FMC_DESCR_M_RCC_SS 0x00006000 -#define PI_FMC_DESCR_M_RCC 0x003FE000 -#define PI_FMC_DESCR_M_LEN 0x00001FFF - -#define PI_FMC_DESCR_K_RCC_FMC_INT_ERR 0x01AA - -#define PI_FMC_DESCR_K_RRR_SUCCESS 0x00 -#define PI_FMC_DESCR_K_RRR_SA_MATCH 0x01 -#define PI_FMC_DESCR_K_RRR_DA_MATCH 0x02 -#define PI_FMC_DESCR_K_RRR_FMC_ABORT 0x03 -#define PI_FMC_DESCR_K_RRR_LENGTH_BAD 0x04 -#define PI_FMC_DESCR_K_RRR_FRAGMENT 0x05 -#define PI_FMC_DESCR_K_RRR_FORMAT_ERR 0x06 -#define PI_FMC_DESCR_K_RRR_MAC_RESET 0x07 - -#define PI_FMC_DESCR_K_DD_NO_MATCH 0x0 -#define PI_FMC_DESCR_K_DD_PROMISCUOUS 0x1 -#define PI_FMC_DESCR_K_DD_CAM_MATCH 0x2 -#define PI_FMC_DESCR_K_DD_LOCAL_MATCH 0x3 - -#define PI_FMC_DESCR_K_SS_NO_MATCH 0x0 -#define PI_FMC_DESCR_K_SS_BRIDGE_MATCH 0x1 -#define PI_FMC_DESCR_K_SS_NOT_POSSIBLE 0x2 -#define PI_FMC_DESCR_K_SS_LOCAL_MATCH 0x3 - -/* Define some max buffer sizes */ - -#define PI_CMD_REQ_K_SIZE_MAX 512 -#define PI_CMD_RSP_K_SIZE_MAX 512 -#define PI_UNSOL_K_SIZE_MAX 512 -#define PI_SMT_HOST_K_SIZE_MAX 4608 /* 4 1/2 K */ -#define PI_RCV_DATA_K_SIZE_MAX 4608 /* 4 1/2 K */ -#define PI_XMT_DATA_K_SIZE_MAX 4608 /* 4 1/2 K */ - -/* Define adapter states */ - -#define PI_STATE_K_RESET 0 -#define PI_STATE_K_UPGRADE 1 -#define PI_STATE_K_DMA_UNAVAIL 2 -#define PI_STATE_K_DMA_AVAIL 3 -#define PI_STATE_K_LINK_AVAIL 4 -#define PI_STATE_K_LINK_UNAVAIL 5 -#define PI_STATE_K_HALTED 6 -#define PI_STATE_K_RING_MEMBER 7 -#define PI_STATE_K_NUMBER 8 - -/* Define codes for command type */ - -#define PI_CMD_K_START 0x00 -#define PI_CMD_K_FILTERS_SET 0x01 -#define PI_CMD_K_FILTERS_GET 0x02 -#define PI_CMD_K_CHARS_SET 0x03 -#define PI_CMD_K_STATUS_CHARS_GET 0x04 -#define PI_CMD_K_CNTRS_GET 0x05 -#define PI_CMD_K_CNTRS_SET 0x06 -#define PI_CMD_K_ADDR_FILTER_SET 0x07 -#define PI_CMD_K_ADDR_FILTER_GET 0x08 -#define PI_CMD_K_ERROR_LOG_CLEAR 0x09 -#define PI_CMD_K_ERROR_LOG_GET 0x0A -#define PI_CMD_K_FDDI_MIB_GET 0x0B -#define PI_CMD_K_DEC_EXT_MIB_GET 0x0C -#define PI_CMD_K_DEVICE_SPECIFIC_GET 0x0D -#define PI_CMD_K_SNMP_SET 0x0E -#define PI_CMD_K_UNSOL_TEST 0x0F -#define PI_CMD_K_SMT_MIB_GET 0x10 -#define PI_CMD_K_SMT_MIB_SET 0x11 -#define PI_CMD_K_MAX 0x11 /* Must match last */ - -/* Define item codes for Chars_Set and Filters_Set commands */ - -#define PI_ITEM_K_EOL 0x00 /* End-of-Item list */ -#define PI_ITEM_K_T_REQ 0x01 /* DECnet T_REQ */ -#define PI_ITEM_K_TVX 0x02 /* DECnet TVX */ -#define PI_ITEM_K_RESTRICTED_TOKEN 0x03 /* DECnet Restricted Token */ -#define PI_ITEM_K_LEM_THRESHOLD 0x04 /* DECnet LEM Threshold */ -#define PI_ITEM_K_RING_PURGER 0x05 /* DECnet Ring Purger Enable */ -#define PI_ITEM_K_CNTR_INTERVAL 0x06 /* Chars_Set */ -#define PI_ITEM_K_IND_GROUP_PROM 0x07 /* Filters_Set */ -#define PI_ITEM_K_GROUP_PROM 0x08 /* Filters_Set */ -#define PI_ITEM_K_BROADCAST 0x09 /* Filters_Set */ -#define PI_ITEM_K_SMT_PROM 0x0A /* Filters_Set */ -#define PI_ITEM_K_SMT_USER 0x0B /* Filters_Set */ -#define PI_ITEM_K_RESERVED 0x0C /* Filters_Set */ -#define PI_ITEM_K_IMPLEMENTOR 0x0D /* Filters_Set */ -#define PI_ITEM_K_LOOPBACK_MODE 0x0E /* Chars_Set */ -#define PI_ITEM_K_CONFIG_POLICY 0x10 /* SMTConfigPolicy */ -#define PI_ITEM_K_CON_POLICY 0x11 /* SMTConnectionPolicy */ -#define PI_ITEM_K_T_NOTIFY 0x12 /* SMTTNotify */ -#define PI_ITEM_K_STATION_ACTION 0x13 /* SMTStationAction */ -#define PI_ITEM_K_MAC_PATHS_REQ 0x15 /* MACPathsRequested */ -#define PI_ITEM_K_MAC_ACTION 0x17 /* MACAction */ -#define PI_ITEM_K_CON_POLICIES 0x18 /* PORTConnectionPolicies */ -#define PI_ITEM_K_PORT_PATHS_REQ 0x19 /* PORTPathsRequested */ -#define PI_ITEM_K_MAC_LOOP_TIME 0x1A /* PORTMACLoopTime */ -#define PI_ITEM_K_TB_MAX 0x1B /* PORTTBMax */ -#define PI_ITEM_K_LER_CUTOFF 0x1C /* PORTLerCutoff */ -#define PI_ITEM_K_LER_ALARM 0x1D /* PORTLerAlarm */ -#define PI_ITEM_K_PORT_ACTION 0x1E /* PORTAction */ -#define PI_ITEM_K_FLUSH_TIME 0x20 /* Chars_Set */ -#define PI_ITEM_K_MAC_T_REQ 0x29 /* MACTReq */ -#define PI_ITEM_K_EMAC_RING_PURGER 0x2A /* eMACRingPurgerEnable */ -#define PI_ITEM_K_EMAC_RTOKEN_TIMEOUT 0x2B /* eMACRestrictedTokenTimeout */ -#define PI_ITEM_K_FDX_ENB_DIS 0x2C /* eFDXEnable */ -#define PI_ITEM_K_MAX 0x2C /* Must equal high item */ - -/* Values for some of the items */ - -#define PI_K_FALSE 0 /* Generic false */ -#define PI_K_TRUE 1 /* Generic true */ - -#define PI_SNMP_K_TRUE 1 /* SNMP true/false values */ -#define PI_SNMP_K_FALSE 2 - -#define PI_FSTATE_K_BLOCK 0 /* Filter State */ -#define PI_FSTATE_K_PASS 1 - -/* Define command return codes */ - -#define PI_RSP_K_SUCCESS 0x00 -#define PI_RSP_K_FAILURE 0x01 -#define PI_RSP_K_WARNING 0x02 -#define PI_RSP_K_LOOP_MODE_BAD 0x03 -#define PI_RSP_K_ITEM_CODE_BAD 0x04 -#define PI_RSP_K_TVX_BAD 0x05 -#define PI_RSP_K_TREQ_BAD 0x06 -#define PI_RSP_K_TOKEN_BAD 0x07 -#define PI_RSP_K_NO_EOL 0x0C -#define PI_RSP_K_FILTER_STATE_BAD 0x0D -#define PI_RSP_K_CMD_TYPE_BAD 0x0E -#define PI_RSP_K_ADAPTER_STATE_BAD 0x0F -#define PI_RSP_K_RING_PURGER_BAD 0x10 -#define PI_RSP_K_LEM_THRESHOLD_BAD 0x11 -#define PI_RSP_K_LOOP_NOT_SUPPORTED 0x12 -#define PI_RSP_K_FLUSH_TIME_BAD 0x13 -#define PI_RSP_K_NOT_IMPLEMENTED 0x14 -#define PI_RSP_K_CONFIG_POLICY_BAD 0x15 -#define PI_RSP_K_STATION_ACTION_BAD 0x16 -#define PI_RSP_K_MAC_ACTION_BAD 0x17 -#define PI_RSP_K_CON_POLICIES_BAD 0x18 -#define PI_RSP_K_MAC_LOOP_TIME_BAD 0x19 -#define PI_RSP_K_TB_MAX_BAD 0x1A -#define PI_RSP_K_LER_CUTOFF_BAD 0x1B -#define PI_RSP_K_LER_ALARM_BAD 0x1C -#define PI_RSP_K_MAC_PATHS_REQ_BAD 0x1D -#define PI_RSP_K_MAC_T_REQ_BAD 0x1E -#define PI_RSP_K_EMAC_RING_PURGER_BAD 0x1F -#define PI_RSP_K_EMAC_RTOKEN_TIME_BAD 0x20 -#define PI_RSP_K_NO_SUCH_ENTRY 0x21 -#define PI_RSP_K_T_NOTIFY_BAD 0x22 -#define PI_RSP_K_TR_MAX_EXP_BAD 0x23 -#define PI_RSP_K_MAC_FRM_ERR_THR_BAD 0x24 -#define PI_RSP_K_MAX_T_REQ_BAD 0x25 -#define PI_RSP_K_FDX_ENB_DIS_BAD 0x26 -#define PI_RSP_K_ITEM_INDEX_BAD 0x27 -#define PI_RSP_K_PORT_ACTION_BAD 0x28 - -/* Commonly used structures */ - -typedef struct /* Item list */ - { - PI_UINT32 item_code; - PI_UINT32 value; - } PI_ITEM_LIST; - -typedef struct /* Response header */ - { - PI_UINT32 reserved; - PI_UINT32 cmd_type; - PI_UINT32 status; - } PI_RSP_HEADER; - - -/* Start Command */ - -typedef struct - { - PI_UINT32 cmd_type; - } PI_CMD_START_REQ; - -/* Start Response */ - -typedef struct - { - PI_RSP_HEADER header; - } PI_CMD_START_RSP; - -/* Filters_Set Request */ - -#define PI_CMD_FILTERS_SET_K_ITEMS_MAX 63 /* Fits in a 512 byte buffer */ - -typedef struct - { - PI_UINT32 cmd_type; - PI_ITEM_LIST item[PI_CMD_FILTERS_SET_K_ITEMS_MAX]; - } PI_CMD_FILTERS_SET_REQ; - -/* Filters_Set Response */ - -typedef struct - { - PI_RSP_HEADER header; - } PI_CMD_FILTERS_SET_RSP; - -/* Filters_Get Request */ - -typedef struct - { - PI_UINT32 cmd_type; - } PI_CMD_FILTERS_GET_REQ; - -/* Filters_Get Response */ - -typedef struct - { - PI_RSP_HEADER header; - PI_UINT32 ind_group_prom; - PI_UINT32 group_prom; - PI_UINT32 broadcast_all; - PI_UINT32 smt_all; - PI_UINT32 smt_user; - PI_UINT32 reserved_all; - PI_UINT32 implementor_all; - } PI_CMD_FILTERS_GET_RSP; - - -/* Chars_Set Request */ - -#define PI_CMD_CHARS_SET_K_ITEMS_MAX 42 /* Fits in a 512 byte buffer */ - -typedef struct - { - PI_UINT32 cmd_type; - struct /* Item list */ - { - PI_UINT32 item_code; - PI_UINT32 value; - PI_UINT32 item_index; - } item[PI_CMD_CHARS_SET_K_ITEMS_MAX]; - } PI_CMD_CHARS_SET_REQ; - -/* Chars_Set Response */ - -typedef struct - { - PI_RSP_HEADER header; - } PI_CMD_CHARS_SET_RSP; - - -/* SNMP_Set Request */ - -#define PI_CMD_SNMP_SET_K_ITEMS_MAX 42 /* Fits in a 512 byte buffer */ - -typedef struct - { - PI_UINT32 cmd_type; - struct /* Item list */ - { - PI_UINT32 item_code; - PI_UINT32 value; - PI_UINT32 item_index; - } item[PI_CMD_SNMP_SET_K_ITEMS_MAX]; - } PI_CMD_SNMP_SET_REQ; - -/* SNMP_Set Response */ - -typedef struct - { - PI_RSP_HEADER header; - } PI_CMD_SNMP_SET_RSP; - - -/* SMT_MIB_Set Request */ - -#define PI_CMD_SMT_MIB_SET_K_ITEMS_MAX 42 /* Max number of items */ - -typedef struct - { - PI_UINT32 cmd_type; - struct - { - PI_UINT32 item_code; - PI_UINT32 value; - PI_UINT32 item_index; - } item[PI_CMD_SMT_MIB_SET_K_ITEMS_MAX]; - } PI_CMD_SMT_MIB_SET_REQ; - -/* SMT_MIB_Set Response */ - -typedef struct - { - PI_RSP_HEADER header; - } PI_CMD_SMT_MIB_SET_RSP; - -/* SMT_MIB_Get Request */ - -typedef struct - { - PI_UINT32 cmd_type; - } PI_CMD_SMT_MIB_GET_REQ; - -/* SMT_MIB_Get Response */ - -typedef struct /* Refer to ANSI FDDI SMT Rev. 7.3 */ - { - PI_RSP_HEADER header; - - /* SMT GROUP */ - - PI_STATION_ID smt_station_id; - PI_UINT32 smt_op_version_id; - PI_UINT32 smt_hi_version_id; - PI_UINT32 smt_lo_version_id; - PI_UINT32 smt_user_data[8]; - PI_UINT32 smt_mib_version_id; - PI_UINT32 smt_mac_ct; - PI_UINT32 smt_non_master_ct; - PI_UINT32 smt_master_ct; - PI_UINT32 smt_available_paths; - PI_UINT32 smt_config_capabilities; - PI_UINT32 smt_config_policy; - PI_UINT32 smt_connection_policy; - PI_UINT32 smt_t_notify; - PI_UINT32 smt_stat_rpt_policy; - PI_UINT32 smt_trace_max_expiration; - PI_UINT32 smt_bypass_present; - PI_UINT32 smt_ecm_state; - PI_UINT32 smt_cf_state; - PI_UINT32 smt_remote_disconnect_flag; - PI_UINT32 smt_station_status; - PI_UINT32 smt_peer_wrap_flag; - PI_CNTR smt_msg_time_stamp; - PI_CNTR smt_transition_time_stamp; - - /* MAC GROUP */ - - PI_UINT32 mac_frame_status_functions; - PI_UINT32 mac_t_max_capability; - PI_UINT32 mac_tvx_capability; - PI_UINT32 mac_available_paths; - PI_UINT32 mac_current_path; - PI_LAN_ADDR mac_upstream_nbr; - PI_LAN_ADDR mac_downstream_nbr; - PI_LAN_ADDR mac_old_upstream_nbr; - PI_LAN_ADDR mac_old_downstream_nbr; - PI_UINT32 mac_dup_address_test; - PI_UINT32 mac_requested_paths; - PI_UINT32 mac_downstream_port_type; - PI_LAN_ADDR mac_smt_address; - PI_UINT32 mac_t_req; - PI_UINT32 mac_t_neg; - PI_UINT32 mac_t_max; - PI_UINT32 mac_tvx_value; - PI_UINT32 mac_frame_error_threshold; - PI_UINT32 mac_frame_error_ratio; - PI_UINT32 mac_rmt_state; - PI_UINT32 mac_da_flag; - PI_UINT32 mac_unda_flag; - PI_UINT32 mac_frame_error_flag; - PI_UINT32 mac_ma_unitdata_available; - PI_UINT32 mac_hardware_present; - PI_UINT32 mac_ma_unitdata_enable; - - /* PATH GROUP */ - - PI_UINT32 path_configuration[8]; - PI_UINT32 path_tvx_lower_bound; - PI_UINT32 path_t_max_lower_bound; - PI_UINT32 path_max_t_req; - - /* PORT GROUP */ - - PI_UINT32 port_my_type[PI_PHY_K_MAX]; - PI_UINT32 port_neighbor_type[PI_PHY_K_MAX]; - PI_UINT32 port_connection_policies[PI_PHY_K_MAX]; - PI_UINT32 port_mac_indicated[PI_PHY_K_MAX]; - PI_UINT32 port_current_path[PI_PHY_K_MAX]; - PI_UINT32 port_requested_paths[PI_PHY_K_MAX]; - PI_UINT32 port_mac_placement[PI_PHY_K_MAX]; - PI_UINT32 port_available_paths[PI_PHY_K_MAX]; - PI_UINT32 port_pmd_class[PI_PHY_K_MAX]; - PI_UINT32 port_connection_capabilities[PI_PHY_K_MAX]; - PI_UINT32 port_bs_flag[PI_PHY_K_MAX]; - PI_UINT32 port_ler_estimate[PI_PHY_K_MAX]; - PI_UINT32 port_ler_cutoff[PI_PHY_K_MAX]; - PI_UINT32 port_ler_alarm[PI_PHY_K_MAX]; - PI_UINT32 port_connect_state[PI_PHY_K_MAX]; - PI_UINT32 port_pcm_state[PI_PHY_K_MAX]; - PI_UINT32 port_pc_withhold[PI_PHY_K_MAX]; - PI_UINT32 port_ler_flag[PI_PHY_K_MAX]; - PI_UINT32 port_hardware_present[PI_PHY_K_MAX]; - - /* GROUP for things that were added later, so must be at the end. */ - - PI_CNTR path_ring_latency; - - } PI_CMD_SMT_MIB_GET_RSP; - - -/* - * Item and group code definitions for SMT 7.3 mandatory objects. These - * definitions are to be used as appropriate in SMT_MIB_SET commands and - * certain host-sent SMT frames such as PMF Get and Set requests. The - * codes have been taken from the MIB summary section of ANSI SMT 7.3. - */ - -#define PI_GRP_K_SMT_STATION_ID 0x100A -#define PI_ITEM_K_SMT_STATION_ID 0x100B -#define PI_ITEM_K_SMT_OP_VERS_ID 0x100D -#define PI_ITEM_K_SMT_HI_VERS_ID 0x100E -#define PI_ITEM_K_SMT_LO_VERS_ID 0x100F -#define PI_ITEM_K_SMT_USER_DATA 0x1011 -#define PI_ITEM_K_SMT_MIB_VERS_ID 0x1012 - -#define PI_GRP_K_SMT_STATION_CONFIG 0x1014 -#define PI_ITEM_K_SMT_MAC_CT 0x1015 -#define PI_ITEM_K_SMT_NON_MASTER_CT 0x1016 -#define PI_ITEM_K_SMT_MASTER_CT 0x1017 -#define PI_ITEM_K_SMT_AVAIL_PATHS 0x1018 -#define PI_ITEM_K_SMT_CONFIG_CAPS 0x1019 -#define PI_ITEM_K_SMT_CONFIG_POL 0x101A -#define PI_ITEM_K_SMT_CONN_POL 0x101B -#define PI_ITEM_K_SMT_T_NOTIFY 0x101D -#define PI_ITEM_K_SMT_STAT_POL 0x101E -#define PI_ITEM_K_SMT_TR_MAX_EXP 0x101F -#define PI_ITEM_K_SMT_PORT_INDEXES 0x1020 -#define PI_ITEM_K_SMT_MAC_INDEXES 0x1021 -#define PI_ITEM_K_SMT_BYPASS_PRESENT 0x1022 - -#define PI_GRP_K_SMT_STATUS 0x1028 -#define PI_ITEM_K_SMT_ECM_STATE 0x1029 -#define PI_ITEM_K_SMT_CF_STATE 0x102A -#define PI_ITEM_K_SMT_REM_DISC_FLAG 0x102C -#define PI_ITEM_K_SMT_STATION_STATUS 0x102D -#define PI_ITEM_K_SMT_PEER_WRAP_FLAG 0x102E - -#define PI_GRP_K_SMT_MIB_OPERATION 0x1032 -#define PI_ITEM_K_SMT_MSG_TIME_STAMP 0x1033 -#define PI_ITEM_K_SMT_TRN_TIME_STAMP 0x1034 - -#define PI_ITEM_K_SMT_STATION_ACT 0x103C - -#define PI_GRP_K_MAC_CAPABILITIES 0x200A -#define PI_ITEM_K_MAC_FRM_STAT_FUNC 0x200B -#define PI_ITEM_K_MAC_T_MAX_CAP 0x200D -#define PI_ITEM_K_MAC_TVX_CAP 0x200E - -#define PI_GRP_K_MAC_CONFIG 0x2014 -#define PI_ITEM_K_MAC_AVAIL_PATHS 0x2016 -#define PI_ITEM_K_MAC_CURRENT_PATH 0x2017 -#define PI_ITEM_K_MAC_UP_NBR 0x2018 -#define PI_ITEM_K_MAC_DOWN_NBR 0x2019 -#define PI_ITEM_K_MAC_OLD_UP_NBR 0x201A -#define PI_ITEM_K_MAC_OLD_DOWN_NBR 0x201B -#define PI_ITEM_K_MAC_DUP_ADDR_TEST 0x201D -#define PI_ITEM_K_MAC_REQ_PATHS 0x2020 -#define PI_ITEM_K_MAC_DOWN_PORT_TYPE 0x2021 -#define PI_ITEM_K_MAC_INDEX 0x2022 - -#define PI_GRP_K_MAC_ADDRESS 0x2028 -#define PI_ITEM_K_MAC_SMT_ADDRESS 0x2029 - -#define PI_GRP_K_MAC_OPERATION 0x2032 -#define PI_ITEM_K_MAC_TREQ 0x2033 -#define PI_ITEM_K_MAC_TNEG 0x2034 -#define PI_ITEM_K_MAC_TMAX 0x2035 -#define PI_ITEM_K_MAC_TVX_VALUE 0x2036 - -#define PI_GRP_K_MAC_COUNTERS 0x2046 -#define PI_ITEM_K_MAC_FRAME_CT 0x2047 -#define PI_ITEM_K_MAC_COPIED_CT 0x2048 -#define PI_ITEM_K_MAC_TRANSMIT_CT 0x2049 -#define PI_ITEM_K_MAC_ERROR_CT 0x2051 -#define PI_ITEM_K_MAC_LOST_CT 0x2052 - -#define PI_GRP_K_MAC_FRM_ERR_COND 0x205A -#define PI_ITEM_K_MAC_FRM_ERR_THR 0x205F -#define PI_ITEM_K_MAC_FRM_ERR_RAT 0x2060 - -#define PI_GRP_K_MAC_STATUS 0x206E -#define PI_ITEM_K_MAC_RMT_STATE 0x206F -#define PI_ITEM_K_MAC_DA_FLAG 0x2070 -#define PI_ITEM_K_MAC_UNDA_FLAG 0x2071 -#define PI_ITEM_K_MAC_FRM_ERR_FLAG 0x2072 -#define PI_ITEM_K_MAC_MA_UNIT_AVAIL 0x2074 -#define PI_ITEM_K_MAC_HW_PRESENT 0x2075 -#define PI_ITEM_K_MAC_MA_UNIT_ENAB 0x2076 - -#define PI_GRP_K_PATH_CONFIG 0x320A -#define PI_ITEM_K_PATH_INDEX 0x320B -#define PI_ITEM_K_PATH_CONFIGURATION 0x3212 -#define PI_ITEM_K_PATH_TVX_LB 0x3215 -#define PI_ITEM_K_PATH_T_MAX_LB 0x3216 -#define PI_ITEM_K_PATH_MAX_T_REQ 0x3217 - -#define PI_GRP_K_PORT_CONFIG 0x400A -#define PI_ITEM_K_PORT_MY_TYPE 0x400C -#define PI_ITEM_K_PORT_NBR_TYPE 0x400D -#define PI_ITEM_K_PORT_CONN_POLS 0x400E -#define PI_ITEM_K_PORT_MAC_INDICATED 0x400F -#define PI_ITEM_K_PORT_CURRENT_PATH 0x4010 -#define PI_ITEM_K_PORT_REQ_PATHS 0x4011 -#define PI_ITEM_K_PORT_MAC_PLACEMENT 0x4012 -#define PI_ITEM_K_PORT_AVAIL_PATHS 0x4013 -#define PI_ITEM_K_PORT_PMD_CLASS 0x4016 -#define PI_ITEM_K_PORT_CONN_CAPS 0x4017 -#define PI_ITEM_K_PORT_INDEX 0x401D - -#define PI_GRP_K_PORT_OPERATION 0x401E -#define PI_ITEM_K_PORT_BS_FLAG 0x4021 - -#define PI_GRP_K_PORT_ERR_CNTRS 0x4028 -#define PI_ITEM_K_PORT_LCT_FAIL_CT 0x402A - -#define PI_GRP_K_PORT_LER 0x4032 -#define PI_ITEM_K_PORT_LER_ESTIMATE 0x4033 -#define PI_ITEM_K_PORT_LEM_REJ_CT 0x4034 -#define PI_ITEM_K_PORT_LEM_CT 0x4035 -#define PI_ITEM_K_PORT_LER_CUTOFF 0x403A -#define PI_ITEM_K_PORT_LER_ALARM 0x403B - -#define PI_GRP_K_PORT_STATUS 0x403C -#define PI_ITEM_K_PORT_CONNECT_STATE 0x403D -#define PI_ITEM_K_PORT_PCM_STATE 0x403E -#define PI_ITEM_K_PORT_PC_WITHHOLD 0x403F -#define PI_ITEM_K_PORT_LER_FLAG 0x4040 -#define PI_ITEM_K_PORT_HW_PRESENT 0x4041 - -#define PI_ITEM_K_PORT_ACT 0x4046 - -/* Addr_Filter_Set Request */ - -#define PI_CMD_ADDR_FILTER_K_SIZE 62 - -typedef struct - { - PI_UINT32 cmd_type; - PI_LAN_ADDR entry[PI_CMD_ADDR_FILTER_K_SIZE]; - } PI_CMD_ADDR_FILTER_SET_REQ; - -/* Addr_Filter_Set Response */ - -typedef struct - { - PI_RSP_HEADER header; - } PI_CMD_ADDR_FILTER_SET_RSP; - -/* Addr_Filter_Get Request */ - -typedef struct - { - PI_UINT32 cmd_type; - } PI_CMD_ADDR_FILTER_GET_REQ; - -/* Addr_Filter_Get Response */ - -typedef struct - { - PI_RSP_HEADER header; - PI_LAN_ADDR entry[PI_CMD_ADDR_FILTER_K_SIZE]; - } PI_CMD_ADDR_FILTER_GET_RSP; - -/* Status_Chars_Get Request */ - -typedef struct - { - PI_UINT32 cmd_type; - } PI_CMD_STATUS_CHARS_GET_REQ; - -/* Status_Chars_Get Response */ - -typedef struct - { - PI_RSP_HEADER header; - PI_STATION_ID station_id; /* Station */ - PI_UINT32 station_type; - PI_UINT32 smt_ver_id; - PI_UINT32 smt_ver_id_max; - PI_UINT32 smt_ver_id_min; - PI_UINT32 station_state; - PI_LAN_ADDR link_addr; /* Link */ - PI_UINT32 t_req; - PI_UINT32 tvx; - PI_UINT32 token_timeout; - PI_UINT32 purger_enb; - PI_UINT32 link_state; - PI_UINT32 tneg; - PI_UINT32 dup_addr_flag; - PI_LAN_ADDR una; - PI_LAN_ADDR una_old; - PI_UINT32 un_dup_addr_flag; - PI_LAN_ADDR dna; - PI_LAN_ADDR dna_old; - PI_UINT32 purger_state; - PI_UINT32 fci_mode; - PI_UINT32 error_reason; - PI_UINT32 loopback; - PI_UINT32 ring_latency; - PI_LAN_ADDR last_dir_beacon_sa; - PI_LAN_ADDR last_dir_beacon_una; - PI_UINT32 phy_type[PI_PHY_K_MAX]; /* Phy */ - PI_UINT32 pmd_type[PI_PHY_K_MAX]; - PI_UINT32 lem_threshold[PI_PHY_K_MAX]; - PI_UINT32 phy_state[PI_PHY_K_MAX]; - PI_UINT32 nbor_phy_type[PI_PHY_K_MAX]; - PI_UINT32 link_error_est[PI_PHY_K_MAX]; - PI_UINT32 broken_reason[PI_PHY_K_MAX]; - PI_UINT32 reject_reason[PI_PHY_K_MAX]; - PI_UINT32 cntr_interval; /* Miscellaneous */ - PI_UINT32 module_rev; - PI_UINT32 firmware_rev; - PI_UINT32 mop_device_type; - PI_UINT32 phy_led[PI_PHY_K_MAX]; - PI_UINT32 flush_time; - } PI_CMD_STATUS_CHARS_GET_RSP; - -/* FDDI_MIB_Get Request */ - -typedef struct - { - PI_UINT32 cmd_type; - } PI_CMD_FDDI_MIB_GET_REQ; - -/* FDDI_MIB_Get Response */ - -typedef struct - { - PI_RSP_HEADER header; - - /* SMT GROUP */ - - PI_STATION_ID smt_station_id; - PI_UINT32 smt_op_version_id; - PI_UINT32 smt_hi_version_id; - PI_UINT32 smt_lo_version_id; - PI_UINT32 smt_mac_ct; - PI_UINT32 smt_non_master_ct; - PI_UINT32 smt_master_ct; - PI_UINT32 smt_paths_available; - PI_UINT32 smt_config_capabilities; - PI_UINT32 smt_config_policy; - PI_UINT32 smt_connection_policy; - PI_UINT32 smt_t_notify; - PI_UINT32 smt_status_reporting; - PI_UINT32 smt_ecm_state; - PI_UINT32 smt_cf_state; - PI_UINT32 smt_hold_state; - PI_UINT32 smt_remote_disconnect_flag; - PI_UINT32 smt_station_action; - - /* MAC GROUP */ - - PI_UINT32 mac_frame_status_capabilities; - PI_UINT32 mac_t_max_greatest_lower_bound; - PI_UINT32 mac_tvx_greatest_lower_bound; - PI_UINT32 mac_paths_available; - PI_UINT32 mac_current_path; - PI_LAN_ADDR mac_upstream_nbr; - PI_LAN_ADDR mac_old_upstream_nbr; - PI_UINT32 mac_dup_addr_test; - PI_UINT32 mac_paths_requested; - PI_UINT32 mac_downstream_port_type; - PI_LAN_ADDR mac_smt_address; - PI_UINT32 mac_t_req; - PI_UINT32 mac_t_neg; - PI_UINT32 mac_t_max; - PI_UINT32 mac_tvx_value; - PI_UINT32 mac_t_min; - PI_UINT32 mac_current_frame_status; - /* mac_frame_cts */ - /* mac_error_cts */ - /* mac_lost_cts */ - PI_UINT32 mac_frame_error_threshold; - PI_UINT32 mac_frame_error_ratio; - PI_UINT32 mac_rmt_state; - PI_UINT32 mac_da_flag; - PI_UINT32 mac_una_da_flag; - PI_UINT32 mac_frame_condition; - PI_UINT32 mac_chip_set; - PI_UINT32 mac_action; - - /* PATH GROUP => Does not need to be implemented */ - - /* PORT GROUP */ - - PI_UINT32 port_pc_type[PI_PHY_K_MAX]; - PI_UINT32 port_pc_neighbor[PI_PHY_K_MAX]; - PI_UINT32 port_connection_policies[PI_PHY_K_MAX]; - PI_UINT32 port_remote_mac_indicated[PI_PHY_K_MAX]; - PI_UINT32 port_ce_state[PI_PHY_K_MAX]; - PI_UINT32 port_paths_requested[PI_PHY_K_MAX]; - PI_UINT32 port_mac_placement[PI_PHY_K_MAX]; - PI_UINT32 port_available_paths[PI_PHY_K_MAX]; - PI_UINT32 port_mac_loop_time[PI_PHY_K_MAX]; - PI_UINT32 port_tb_max[PI_PHY_K_MAX]; - PI_UINT32 port_bs_flag[PI_PHY_K_MAX]; - /* port_lct_fail_cts[PI_PHY_K_MAX]; */ - PI_UINT32 port_ler_estimate[PI_PHY_K_MAX]; - /* port_lem_reject_cts[PI_PHY_K_MAX]; */ - /* port_lem_cts[PI_PHY_K_MAX]; */ - PI_UINT32 port_ler_cutoff[PI_PHY_K_MAX]; - PI_UINT32 port_ler_alarm[PI_PHY_K_MAX]; - PI_UINT32 port_connect_state[PI_PHY_K_MAX]; - PI_UINT32 port_pcm_state[PI_PHY_K_MAX]; - PI_UINT32 port_pc_withhold[PI_PHY_K_MAX]; - PI_UINT32 port_ler_condition[PI_PHY_K_MAX]; - PI_UINT32 port_chip_set[PI_PHY_K_MAX]; - PI_UINT32 port_action[PI_PHY_K_MAX]; - - /* ATTACHMENT GROUP */ - - PI_UINT32 attachment_class; - PI_UINT32 attachment_ob_present; - PI_UINT32 attachment_imax_expiration; - PI_UINT32 attachment_inserted_status; - PI_UINT32 attachment_insert_policy; - - /* CHIP SET GROUP => Does not need to be implemented */ - - } PI_CMD_FDDI_MIB_GET_RSP; - -/* DEC_Ext_MIB_Get Request */ - -typedef struct - { - PI_UINT32 cmd_type; - } PI_CMD_DEC_EXT_MIB_GET_REQ; - -/* DEC_Ext_MIB_Get (efddi and efdx groups only) Response */ - -typedef struct - { - PI_RSP_HEADER header; - - /* SMT GROUP */ - - PI_UINT32 esmt_station_type; - - /* MAC GROUP */ - - PI_UINT32 emac_link_state; - PI_UINT32 emac_ring_purger_state; - PI_UINT32 emac_ring_purger_enable; - PI_UINT32 emac_frame_strip_mode; - PI_UINT32 emac_ring_error_reason; - PI_UINT32 emac_up_nbr_dup_addr_flag; - PI_UINT32 emac_restricted_token_timeout; - - /* PORT GROUP */ - - PI_UINT32 eport_pmd_type[PI_PHY_K_MAX]; - PI_UINT32 eport_phy_state[PI_PHY_K_MAX]; - PI_UINT32 eport_reject_reason[PI_PHY_K_MAX]; - - /* FDX (Full-Duplex) GROUP */ - - PI_UINT32 efdx_enable; /* Valid only in SMT 7.3 */ - PI_UINT32 efdx_op; /* Valid only in SMT 7.3 */ - PI_UINT32 efdx_state; /* Valid only in SMT 7.3 */ - - } PI_CMD_DEC_EXT_MIB_GET_RSP; - -typedef struct - { - PI_CNTR traces_rcvd; /* Station */ - PI_CNTR frame_cnt; /* Link */ - PI_CNTR error_cnt; - PI_CNTR lost_cnt; - PI_CNTR octets_rcvd; - PI_CNTR octets_sent; - PI_CNTR pdus_rcvd; - PI_CNTR pdus_sent; - PI_CNTR mcast_octets_rcvd; - PI_CNTR mcast_octets_sent; - PI_CNTR mcast_pdus_rcvd; - PI_CNTR mcast_pdus_sent; - PI_CNTR xmt_underruns; - PI_CNTR xmt_failures; - PI_CNTR block_check_errors; - PI_CNTR frame_status_errors; - PI_CNTR pdu_length_errors; - PI_CNTR rcv_overruns; - PI_CNTR user_buff_unavailable; - PI_CNTR inits_initiated; - PI_CNTR inits_rcvd; - PI_CNTR beacons_initiated; - PI_CNTR dup_addrs; - PI_CNTR dup_tokens; - PI_CNTR purge_errors; - PI_CNTR fci_strip_errors; - PI_CNTR traces_initiated; - PI_CNTR directed_beacons_rcvd; - PI_CNTR emac_frame_alignment_errors; - PI_CNTR ebuff_errors[PI_PHY_K_MAX]; /* Phy */ - PI_CNTR lct_rejects[PI_PHY_K_MAX]; - PI_CNTR lem_rejects[PI_PHY_K_MAX]; - PI_CNTR link_errors[PI_PHY_K_MAX]; - PI_CNTR connections[PI_PHY_K_MAX]; - PI_CNTR copied_cnt; /* Valid only if using SMT 7.3 */ - PI_CNTR transmit_cnt; /* Valid only if using SMT 7.3 */ - PI_CNTR tokens; - } PI_CNTR_BLK; - -/* Counters_Get Request */ - -typedef struct - { - PI_UINT32 cmd_type; - } PI_CMD_CNTRS_GET_REQ; - -/* Counters_Get Response */ - -typedef struct - { - PI_RSP_HEADER header; - PI_CNTR time_since_reset; - PI_CNTR_BLK cntrs; - } PI_CMD_CNTRS_GET_RSP; - -/* Counters_Set Request */ - -typedef struct - { - PI_UINT32 cmd_type; - PI_CNTR_BLK cntrs; - } PI_CMD_CNTRS_SET_REQ; - -/* Counters_Set Response */ - -typedef struct - { - PI_RSP_HEADER header; - } PI_CMD_CNTRS_SET_RSP; - -/* Error_Log_Clear Request */ - -typedef struct - { - PI_UINT32 cmd_type; - } PI_CMD_ERROR_LOG_CLEAR_REQ; - -/* Error_Log_Clear Response */ - -typedef struct - { - PI_RSP_HEADER header; - } PI_CMD_ERROR_LOG_CLEAR_RSP; - -/* Error_Log_Get Request */ - -#define PI_LOG_ENTRY_K_INDEX_MIN 0 /* Minimum index for entry */ - -typedef struct - { - PI_UINT32 cmd_type; - PI_UINT32 entry_index; - } PI_CMD_ERROR_LOG_GET_REQ; - -/* Error_Log_Get Response */ - -#define PI_K_LOG_FW_SIZE 111 /* Max number of fw longwords */ -#define PI_K_LOG_DIAG_SIZE 6 /* Max number of diag longwords */ - -typedef struct - { - struct - { - PI_UINT32 fru_imp_mask; - PI_UINT32 test_id; - PI_UINT32 reserved[PI_K_LOG_DIAG_SIZE]; - } diag; - PI_UINT32 fw[PI_K_LOG_FW_SIZE]; - } PI_LOG_ENTRY; - -typedef struct - { - PI_RSP_HEADER header; - PI_UINT32 event_status; - PI_UINT32 caller_id; - PI_UINT32 timestamp_l; - PI_UINT32 timestamp_h; - PI_UINT32 write_count; - PI_LOG_ENTRY entry_info; - } PI_CMD_ERROR_LOG_GET_RSP; - -/* Define error log related constants and types. */ -/* Not all of the caller id's can occur. The only ones currently */ -/* implemented are: none, selftest, mfg, fw, console */ - -#define PI_LOG_EVENT_STATUS_K_VALID 0 /* Valid Event Status */ -#define PI_LOG_EVENT_STATUS_K_INVALID 1 /* Invalid Event Status */ -#define PI_LOG_CALLER_ID_K_NONE 0 /* No caller */ -#define PI_LOG_CALLER_ID_K_SELFTEST 1 /* Normal power-up selftest */ -#define PI_LOG_CALLER_ID_K_MFG 2 /* Mfg power-up selftest */ -#define PI_LOG_CALLER_ID_K_ONLINE 3 /* On-line diagnostics */ -#define PI_LOG_CALLER_ID_K_HW 4 /* Hardware */ -#define PI_LOG_CALLER_ID_K_FW 5 /* Firmware */ -#define PI_LOG_CALLER_ID_K_CNS_HW 6 /* CNS firmware */ -#define PI_LOG_CALLER_ID_K_CNS_FW 7 /* CNS hardware */ -#define PI_LOG_CALLER_ID_K_CONSOLE 8 /* Console Caller Id */ - -/* - * Place all DMA commands in the following request and response structures - * to simplify code. - */ - -typedef union - { - PI_UINT32 cmd_type; - PI_CMD_START_REQ start; - PI_CMD_FILTERS_SET_REQ filter_set; - PI_CMD_FILTERS_GET_REQ filter_get; - PI_CMD_CHARS_SET_REQ char_set; - PI_CMD_ADDR_FILTER_SET_REQ addr_filter_set; - PI_CMD_ADDR_FILTER_GET_REQ addr_filter_get; - PI_CMD_STATUS_CHARS_GET_REQ stat_char_get; - PI_CMD_CNTRS_GET_REQ cntrs_get; - PI_CMD_CNTRS_SET_REQ cntrs_set; - PI_CMD_ERROR_LOG_CLEAR_REQ error_log_clear; - PI_CMD_ERROR_LOG_GET_REQ error_log_read; - PI_CMD_SNMP_SET_REQ snmp_set; - PI_CMD_FDDI_MIB_GET_REQ fddi_mib_get; - PI_CMD_DEC_EXT_MIB_GET_REQ dec_mib_get; - PI_CMD_SMT_MIB_SET_REQ smt_mib_set; - PI_CMD_SMT_MIB_GET_REQ smt_mib_get; - char pad[PI_CMD_REQ_K_SIZE_MAX]; - } PI_DMA_CMD_REQ; - -typedef union - { - PI_RSP_HEADER header; - PI_CMD_START_RSP start; - PI_CMD_FILTERS_SET_RSP filter_set; - PI_CMD_FILTERS_GET_RSP filter_get; - PI_CMD_CHARS_SET_RSP char_set; - PI_CMD_ADDR_FILTER_SET_RSP addr_filter_set; - PI_CMD_ADDR_FILTER_GET_RSP addr_filter_get; - PI_CMD_STATUS_CHARS_GET_RSP stat_char_get; - PI_CMD_CNTRS_GET_RSP cntrs_get; - PI_CMD_CNTRS_SET_RSP cntrs_set; - PI_CMD_ERROR_LOG_CLEAR_RSP error_log_clear; - PI_CMD_ERROR_LOG_GET_RSP error_log_get; - PI_CMD_SNMP_SET_RSP snmp_set; - PI_CMD_FDDI_MIB_GET_RSP fddi_mib_get; - PI_CMD_DEC_EXT_MIB_GET_RSP dec_mib_get; - PI_CMD_SMT_MIB_SET_RSP smt_mib_set; - PI_CMD_SMT_MIB_GET_RSP smt_mib_get; - char pad[PI_CMD_RSP_K_SIZE_MAX]; - } PI_DMA_CMD_RSP; - -typedef union - { - PI_DMA_CMD_REQ request; - PI_DMA_CMD_RSP response; - } PI_DMA_CMD_BUFFER; - - -/* Define format of Consumer Block (resident in host memory) */ - -typedef struct - { - volatile PI_UINT32 xmt_rcv_data; - volatile PI_UINT32 reserved_1; - volatile PI_UINT32 smt_host; - volatile PI_UINT32 reserved_2; - volatile PI_UINT32 unsol; - volatile PI_UINT32 reserved_3; - volatile PI_UINT32 cmd_rsp; - volatile PI_UINT32 reserved_4; - volatile PI_UINT32 cmd_req; - volatile PI_UINT32 reserved_5; - } PI_CONSUMER_BLOCK; - -#define PI_CONS_M_RCV_INDEX 0x000000FF -#define PI_CONS_M_XMT_INDEX 0x00FF0000 -#define PI_CONS_V_RCV_INDEX 0 -#define PI_CONS_V_XMT_INDEX 16 - -/* Offsets into consumer block */ - -#define PI_CONS_BLK_K_XMT_RCV 0x00 -#define PI_CONS_BLK_K_SMT_HOST 0x08 -#define PI_CONS_BLK_K_UNSOL 0x10 -#define PI_CONS_BLK_K_CMD_RSP 0x18 -#define PI_CONS_BLK_K_CMD_REQ 0x20 - -/* Offsets into descriptor block */ - -#define PI_DESCR_BLK_K_RCV_DATA 0x0000 -#define PI_DESCR_BLK_K_XMT_DATA 0x0800 -#define PI_DESCR_BLK_K_SMT_HOST 0x1000 -#define PI_DESCR_BLK_K_UNSOL 0x1200 -#define PI_DESCR_BLK_K_CMD_RSP 0x1280 -#define PI_DESCR_BLK_K_CMD_REQ 0x1300 - -/* Define format of a rcv descr (Rcv Data, Cmd Rsp, Unsolicited, SMT Host) */ -/* Note a field has been added for later versions of the PDQ to allow for */ -/* finer granularity of the rcv buffer alignment. For backwards */ -/* compatibility, the two bits (which allow the rcv buffer to be longword */ -/* aligned) have been added at the MBZ bits. To support previous drivers, */ -/* the MBZ definition is left intact. */ - -typedef struct - { - PI_UINT32 long_0; - PI_UINT32 long_1; - } PI_RCV_DESCR; - -#define PI_RCV_DESCR_M_SOP 0x80000000 -#define PI_RCV_DESCR_M_SEG_LEN_LO 0x60000000 -#define PI_RCV_DESCR_M_MBZ 0x60000000 -#define PI_RCV_DESCR_M_SEG_LEN 0x1F800000 -#define PI_RCV_DESCR_M_SEG_LEN_HI 0x1FF00000 -#define PI_RCV_DESCR_M_SEG_CNT 0x000F0000 -#define PI_RCV_DESCR_M_BUFF_HI 0x0000FFFF - -#define PI_RCV_DESCR_V_SOP 31 -#define PI_RCV_DESCR_V_SEG_LEN_LO 29 -#define PI_RCV_DESCR_V_MBZ 29 -#define PI_RCV_DESCR_V_SEG_LEN 23 -#define PI_RCV_DESCR_V_SEG_LEN_HI 20 -#define PI_RCV_DESCR_V_SEG_CNT 16 -#define PI_RCV_DESCR_V_BUFF_HI 0 - -/* Define the format of a transmit descriptor (Xmt Data, Cmd Req) */ - -typedef struct - { - PI_UINT32 long_0; - PI_UINT32 long_1; - } PI_XMT_DESCR; - -#define PI_XMT_DESCR_M_SOP 0x80000000 -#define PI_XMT_DESCR_M_EOP 0x40000000 -#define PI_XMT_DESCR_M_MBZ 0x20000000 -#define PI_XMT_DESCR_M_SEG_LEN 0x1FFF0000 -#define PI_XMT_DESCR_M_BUFF_HI 0x0000FFFF - -#define PI_XMT_DESCR_V_SOP 31 -#define PI_XMT_DESCR_V_EOP 30 -#define PI_XMT_DESCR_V_MBZ 29 -#define PI_XMT_DESCR_V_SEG_LEN 16 -#define PI_XMT_DESCR_V_BUFF_HI 0 - -/* Define format of the Descriptor Block (resident in host memory) */ - -#define PI_RCV_DATA_K_NUM_ENTRIES 256 -#define PI_XMT_DATA_K_NUM_ENTRIES 256 -#define PI_SMT_HOST_K_NUM_ENTRIES 64 -#define PI_UNSOL_K_NUM_ENTRIES 16 -#define PI_CMD_RSP_K_NUM_ENTRIES 16 -#define PI_CMD_REQ_K_NUM_ENTRIES 16 - -typedef struct - { - PI_RCV_DESCR rcv_data[PI_RCV_DATA_K_NUM_ENTRIES]; - PI_XMT_DESCR xmt_data[PI_XMT_DATA_K_NUM_ENTRIES]; - PI_RCV_DESCR smt_host[PI_SMT_HOST_K_NUM_ENTRIES]; - PI_RCV_DESCR unsol[PI_UNSOL_K_NUM_ENTRIES]; - PI_RCV_DESCR cmd_rsp[PI_CMD_RSP_K_NUM_ENTRIES]; - PI_XMT_DESCR cmd_req[PI_CMD_REQ_K_NUM_ENTRIES]; - } PI_DESCR_BLOCK; - -/* Define Port Registers - offsets from PDQ Base address */ - -#define PI_PDQ_K_REG_PORT_RESET 0x00000000 -#define PI_PDQ_K_REG_HOST_DATA 0x00000004 -#define PI_PDQ_K_REG_PORT_CTRL 0x00000008 -#define PI_PDQ_K_REG_PORT_DATA_A 0x0000000C -#define PI_PDQ_K_REG_PORT_DATA_B 0x00000010 -#define PI_PDQ_K_REG_PORT_STATUS 0x00000014 -#define PI_PDQ_K_REG_TYPE_0_STATUS 0x00000018 -#define PI_PDQ_K_REG_HOST_INT_ENB 0x0000001C -#define PI_PDQ_K_REG_TYPE_2_PROD_NOINT 0x00000020 -#define PI_PDQ_K_REG_TYPE_2_PROD 0x00000024 -#define PI_PDQ_K_REG_CMD_RSP_PROD 0x00000028 -#define PI_PDQ_K_REG_CMD_REQ_PROD 0x0000002C -#define PI_PDQ_K_REG_SMT_HOST_PROD 0x00000030 -#define PI_PDQ_K_REG_UNSOL_PROD 0x00000034 - -/* Port Control Register - Command codes for primary commands */ - -#define PI_PCTRL_M_CMD_ERROR 0x8000 -#define PI_PCTRL_M_BLAST_FLASH 0x4000 -#define PI_PCTRL_M_HALT 0x2000 -#define PI_PCTRL_M_COPY_DATA 0x1000 -#define PI_PCTRL_M_ERROR_LOG_START 0x0800 -#define PI_PCTRL_M_ERROR_LOG_READ 0x0400 -#define PI_PCTRL_M_XMT_DATA_FLUSH_DONE 0x0200 -#define PI_PCTRL_M_INIT 0x0100 -#define PI_PCTRL_M_INIT_START 0x0080 -#define PI_PCTRL_M_CONS_BLOCK 0x0040 -#define PI_PCTRL_M_UNINIT 0x0020 -#define PI_PCTRL_M_RING_MEMBER 0x0010 -#define PI_PCTRL_M_MLA 0x0008 -#define PI_PCTRL_M_FW_REV_READ 0x0004 -#define PI_PCTRL_M_DEV_SPECIFIC 0x0002 -#define PI_PCTRL_M_SUB_CMD 0x0001 - -/* Define sub-commands accessed via the PI_PCTRL_M_SUB_CMD command */ - -#define PI_SUB_CMD_K_LINK_UNINIT 0x0001 -#define PI_SUB_CMD_K_BURST_SIZE_SET 0x0002 -#define PI_SUB_CMD_K_PDQ_REV_GET 0x0004 -#define PI_SUB_CMD_K_HW_REV_GET 0x0008 - -/* Define some Port Data B values */ - -#define PI_PDATA_B_DMA_BURST_SIZE_4 0 /* valid values for command */ -#define PI_PDATA_B_DMA_BURST_SIZE_8 1 -#define PI_PDATA_B_DMA_BURST_SIZE_16 2 -#define PI_PDATA_B_DMA_BURST_SIZE_32 3 /* not supported on PCI */ -#define PI_PDATA_B_DMA_BURST_SIZE_DEF PI_PDATA_B_DMA_BURST_SIZE_16 - -/* Port Data A Reset state */ - -#define PI_PDATA_A_RESET_M_UPGRADE 0x00000001 -#define PI_PDATA_A_RESET_M_SOFT_RESET 0x00000002 -#define PI_PDATA_A_RESET_M_SKIP_ST 0x00000004 - -/* Read adapter MLA address port control command constants */ - -#define PI_PDATA_A_MLA_K_LO 0 -#define PI_PDATA_A_MLA_K_HI 1 - -/* Byte Swap values for init command */ - -#define PI_PDATA_A_INIT_M_DESC_BLK_ADDR 0x0FFFFE000 -#define PI_PDATA_A_INIT_M_RESERVED 0x000001FFC -#define PI_PDATA_A_INIT_M_BSWAP_DATA 0x000000002 -#define PI_PDATA_A_INIT_M_BSWAP_LITERAL 0x000000001 - -#define PI_PDATA_A_INIT_V_DESC_BLK_ADDR 13 -#define PI_PDATA_A_INIT_V_RESERVED 3 -#define PI_PDATA_A_INIT_V_BSWAP_DATA 1 -#define PI_PDATA_A_INIT_V_BSWAP_LITERAL 0 - -/* Port Reset Register */ - -#define PI_RESET_M_ASSERT_RESET 1 - -/* Port Status register */ - -#define PI_PSTATUS_V_RCV_DATA_PENDING 31 -#define PI_PSTATUS_V_XMT_DATA_PENDING 30 -#define PI_PSTATUS_V_SMT_HOST_PENDING 29 -#define PI_PSTATUS_V_UNSOL_PENDING 28 -#define PI_PSTATUS_V_CMD_RSP_PENDING 27 -#define PI_PSTATUS_V_CMD_REQ_PENDING 26 -#define PI_PSTATUS_V_TYPE_0_PENDING 25 -#define PI_PSTATUS_V_RESERVED_1 16 -#define PI_PSTATUS_V_RESERVED_2 11 -#define PI_PSTATUS_V_STATE 8 -#define PI_PSTATUS_V_HALT_ID 0 - -#define PI_PSTATUS_M_RCV_DATA_PENDING 0x80000000 -#define PI_PSTATUS_M_XMT_DATA_PENDING 0x40000000 -#define PI_PSTATUS_M_SMT_HOST_PENDING 0x20000000 -#define PI_PSTATUS_M_UNSOL_PENDING 0x10000000 -#define PI_PSTATUS_M_CMD_RSP_PENDING 0x08000000 -#define PI_PSTATUS_M_CMD_REQ_PENDING 0x04000000 -#define PI_PSTATUS_M_TYPE_0_PENDING 0x02000000 -#define PI_PSTATUS_M_RESERVED_1 0x01FF0000 -#define PI_PSTATUS_M_RESERVED_2 0x0000F800 -#define PI_PSTATUS_M_STATE 0x00000700 -#define PI_PSTATUS_M_HALT_ID 0x000000FF - -/* Define Halt Id's */ -/* Do not insert into this list, only append. */ - -#define PI_HALT_ID_K_SELFTEST_TIMEOUT 0 -#define PI_HALT_ID_K_PARITY_ERROR 1 -#define PI_HALT_ID_K_HOST_DIR_HALT 2 -#define PI_HALT_ID_K_SW_FAULT 3 -#define PI_HALT_ID_K_HW_FAULT 4 -#define PI_HALT_ID_K_PC_TRACE 5 -#define PI_HALT_ID_K_DMA_ERROR 6 /* Host Data has error reg */ -#define PI_HALT_ID_K_IMAGE_CRC_ERROR 7 /* Image is bad, update it */ -#define PI_HALT_ID_K_BUS_EXCEPTION 8 /* 68K bus exception */ - -/* Host Interrupt Enable Register as seen by host */ - -#define PI_HOST_INT_M_XMT_DATA_ENB 0x80000000 /* Type 2 Enables */ -#define PI_HOST_INT_M_RCV_DATA_ENB 0x40000000 -#define PI_HOST_INT_M_SMT_HOST_ENB 0x10000000 /* Type 1 Enables */ -#define PI_HOST_INT_M_UNSOL_ENB 0x20000000 -#define PI_HOST_INT_M_CMD_RSP_ENB 0x08000000 -#define PI_HOST_INT_M_CMD_REQ_ENB 0x04000000 -#define PI_HOST_INT_M_TYPE_1_RESERVED 0x00FF0000 -#define PI_HOST_INT_M_TYPE_0_RESERVED 0x0000FF00 /* Type 0 Enables */ -#define PI_HOST_INT_M_1MS 0x00000080 -#define PI_HOST_INT_M_20MS 0x00000040 -#define PI_HOST_INT_M_CSR_CMD_DONE 0x00000020 -#define PI_HOST_INT_M_STATE_CHANGE 0x00000010 -#define PI_HOST_INT_M_XMT_FLUSH 0x00000008 -#define PI_HOST_INT_M_NXM 0x00000004 -#define PI_HOST_INT_M_PM_PAR_ERR 0x00000002 -#define PI_HOST_INT_M_BUS_PAR_ERR 0x00000001 - -#define PI_HOST_INT_V_XMT_DATA_ENB 31 /* Type 2 Enables */ -#define PI_HOST_INT_V_RCV_DATA_ENB 30 -#define PI_HOST_INT_V_SMT_HOST_ENB 29 /* Type 1 Enables */ -#define PI_HOST_INT_V_UNSOL_ENB 28 -#define PI_HOST_INT_V_CMD_RSP_ENB 27 -#define PI_HOST_INT_V_CMD_REQ_ENB 26 -#define PI_HOST_INT_V_TYPE_1_RESERVED 16 -#define PI_HOST_INT_V_TYPE_0_RESERVED 8 /* Type 0 Enables */ -#define PI_HOST_INT_V_1MS_ENB 7 -#define PI_HOST_INT_V_20MS_ENB 6 -#define PI_HOST_INT_V_CSR_CMD_DONE_ENB 5 -#define PI_HOST_INT_V_STATE_CHANGE_ENB 4 -#define PI_HOST_INT_V_XMT_FLUSH_ENB 3 -#define PI_HOST_INT_V_NXM_ENB 2 -#define PI_HOST_INT_V_PM_PAR_ERR_ENB 1 -#define PI_HOST_INT_V_BUS_PAR_ERR_ENB 0 - -#define PI_HOST_INT_K_ACK_ALL_TYPE_0 0x000000FF -#define PI_HOST_INT_K_DISABLE_ALL_INTS 0x00000000 -#define PI_HOST_INT_K_ENABLE_ALL_INTS 0xFFFFFFFF -#define PI_HOST_INT_K_ENABLE_DEF_INTS 0xC000001F - -/* Type 0 Interrupt Status Register */ - -#define PI_TYPE_0_STAT_M_1MS 0x00000080 -#define PI_TYPE_0_STAT_M_20MS 0x00000040 -#define PI_TYPE_0_STAT_M_CSR_CMD_DONE 0x00000020 -#define PI_TYPE_0_STAT_M_STATE_CHANGE 0x00000010 -#define PI_TYPE_0_STAT_M_XMT_FLUSH 0x00000008 -#define PI_TYPE_0_STAT_M_NXM 0x00000004 -#define PI_TYPE_0_STAT_M_PM_PAR_ERR 0x00000002 -#define PI_TYPE_0_STAT_M_BUS_PAR_ERR 0x00000001 - -#define PI_TYPE_0_STAT_V_1MS 7 -#define PI_TYPE_0_STAT_V_20MS 6 -#define PI_TYPE_0_STAT_V_CSR_CMD_DONE 5 -#define PI_TYPE_0_STAT_V_STATE_CHANGE 4 -#define PI_TYPE_0_STAT_V_XMT_FLUSH 3 -#define PI_TYPE_0_STAT_V_NXM 2 -#define PI_TYPE_0_STAT_V_PM_PAR_ERR 1 -#define PI_TYPE_0_STAT_V_BUS_PAR_ERR 0 - -/* Register definition structures are defined for both big and little endian systems */ - -#ifndef __BIG_ENDIAN - -/* Little endian format of Type 1 Producer register */ - -typedef union - { - PI_UINT32 lword; - struct - { - PI_UINT8 prod; - PI_UINT8 comp; - PI_UINT8 mbz_1; - PI_UINT8 mbz_2; - } index; - } PI_TYPE_1_PROD_REG; - -/* Little endian format of Type 2 Producer register */ - -typedef union - { - PI_UINT32 lword; - struct - { - PI_UINT8 rcv_prod; - PI_UINT8 xmt_prod; - PI_UINT8 rcv_comp; - PI_UINT8 xmt_comp; - } index; - } PI_TYPE_2_PROD_REG; - -/* Little endian format of Type 1 Consumer Block longword */ - -typedef union - { - PI_UINT32 lword; - struct - { - PI_UINT8 cons; - PI_UINT8 res0; - PI_UINT8 res1; - PI_UINT8 res2; - } index; - } PI_TYPE_1_CONSUMER; - -/* Little endian format of Type 2 Consumer Block longword */ - -typedef union - { - PI_UINT32 lword; - struct - { - PI_UINT8 rcv_cons; - PI_UINT8 res0; - PI_UINT8 xmt_cons; - PI_UINT8 res1; - } index; - } PI_TYPE_2_CONSUMER; - -/* Define swapping required by DMA transfers. */ -#define PI_PDATA_A_INIT_M_BSWAP_INIT \ - (PI_PDATA_A_INIT_M_BSWAP_DATA) - -#else /* __BIG_ENDIAN */ - -/* Big endian format of Type 1 Producer register */ - -typedef union - { - PI_UINT32 lword; - struct - { - PI_UINT8 mbz_2; - PI_UINT8 mbz_1; - PI_UINT8 comp; - PI_UINT8 prod; - } index; - } PI_TYPE_1_PROD_REG; - -/* Big endian format of Type 2 Producer register */ - -typedef union - { - PI_UINT32 lword; - struct - { - PI_UINT8 xmt_comp; - PI_UINT8 rcv_comp; - PI_UINT8 xmt_prod; - PI_UINT8 rcv_prod; - } index; - } PI_TYPE_2_PROD_REG; - -/* Big endian format of Type 1 Consumer Block longword */ - -typedef union - { - PI_UINT32 lword; - struct - { - PI_UINT8 res2; - PI_UINT8 res1; - PI_UINT8 res0; - PI_UINT8 cons; - } index; - } PI_TYPE_1_CONSUMER; - -/* Big endian format of Type 2 Consumer Block longword */ - -typedef union - { - PI_UINT32 lword; - struct - { - PI_UINT8 res1; - PI_UINT8 xmt_cons; - PI_UINT8 res0; - PI_UINT8 rcv_cons; - } index; - } PI_TYPE_2_CONSUMER; - -/* Define swapping required by DMA transfers. */ -#define PI_PDATA_A_INIT_M_BSWAP_INIT \ - (PI_PDATA_A_INIT_M_BSWAP_DATA | PI_PDATA_A_INIT_M_BSWAP_LITERAL) - -#endif /* __BIG_ENDIAN */ - -/* Define TC PDQ CSR offset and length */ - -#define PI_TC_K_CSR_OFFSET 0x100000 -#define PI_TC_K_CSR_LEN 0x40 /* 64 bytes */ - -/* Define EISA controller register offsets */ - -#define PI_ESIC_K_CSR_IO_LEN 0x80 /* 128 bytes */ - -#define PI_DEFEA_K_BURST_HOLDOFF 0x040 - -#define PI_ESIC_K_SLOT_ID 0xC80 -#define PI_ESIC_K_SLOT_CNTRL 0xC84 -#define PI_ESIC_K_MEM_ADD_CMP_0 0xC85 -#define PI_ESIC_K_MEM_ADD_CMP_1 0xC86 -#define PI_ESIC_K_MEM_ADD_CMP_2 0xC87 -#define PI_ESIC_K_MEM_ADD_HI_CMP_0 0xC88 -#define PI_ESIC_K_MEM_ADD_HI_CMP_1 0xC89 -#define PI_ESIC_K_MEM_ADD_HI_CMP_2 0xC8A -#define PI_ESIC_K_MEM_ADD_MASK_0 0xC8B -#define PI_ESIC_K_MEM_ADD_MASK_1 0xC8C -#define PI_ESIC_K_MEM_ADD_MASK_2 0xC8D -#define PI_ESIC_K_MEM_ADD_LO_CMP_0 0xC8E -#define PI_ESIC_K_MEM_ADD_LO_CMP_1 0xC8F -#define PI_ESIC_K_MEM_ADD_LO_CMP_2 0xC90 -#define PI_ESIC_K_IO_ADD_CMP_0_0 0xC91 -#define PI_ESIC_K_IO_ADD_CMP_0_1 0xC92 -#define PI_ESIC_K_IO_ADD_CMP_1_0 0xC93 -#define PI_ESIC_K_IO_ADD_CMP_1_1 0xC94 -#define PI_ESIC_K_IO_ADD_CMP_2_0 0xC95 -#define PI_ESIC_K_IO_ADD_CMP_2_1 0xC96 -#define PI_ESIC_K_IO_ADD_CMP_3_0 0xC97 -#define PI_ESIC_K_IO_ADD_CMP_3_1 0xC98 -#define PI_ESIC_K_IO_ADD_MASK_0_0 0xC99 -#define PI_ESIC_K_IO_ADD_MASK_0_1 0xC9A -#define PI_ESIC_K_IO_ADD_MASK_1_0 0xC9B -#define PI_ESIC_K_IO_ADD_MASK_1_1 0xC9C -#define PI_ESIC_K_IO_ADD_MASK_2_0 0xC9D -#define PI_ESIC_K_IO_ADD_MASK_2_1 0xC9E -#define PI_ESIC_K_IO_ADD_MASK_3_0 0xC9F -#define PI_ESIC_K_IO_ADD_MASK_3_1 0xCA0 -#define PI_ESIC_K_MOD_CONFIG_1 0xCA1 -#define PI_ESIC_K_MOD_CONFIG_2 0xCA2 -#define PI_ESIC_K_MOD_CONFIG_3 0xCA3 -#define PI_ESIC_K_MOD_CONFIG_4 0xCA4 -#define PI_ESIC_K_MOD_CONFIG_5 0xCA5 -#define PI_ESIC_K_MOD_CONFIG_6 0xCA6 -#define PI_ESIC_K_MOD_CONFIG_7 0xCA7 -#define PI_ESIC_K_DIP_SWITCH 0xCA8 -#define PI_ESIC_K_IO_CONFIG_STAT_0 0xCA9 -#define PI_ESIC_K_IO_CONFIG_STAT_1 0xCAA -#define PI_ESIC_K_DMA_CONFIG 0xCAB -#define PI_ESIC_K_INPUT_PORT 0xCAC -#define PI_ESIC_K_OUTPUT_PORT 0xCAD -#define PI_ESIC_K_FUNCTION_CNTRL 0xCAE - -/* Define the bits in the function control register. */ - -#define PI_FUNCTION_CNTRL_M_IOCS0 0x01 -#define PI_FUNCTION_CNTRL_M_IOCS1 0x02 -#define PI_FUNCTION_CNTRL_M_IOCS2 0x04 -#define PI_FUNCTION_CNTRL_M_IOCS3 0x08 -#define PI_FUNCTION_CNTRL_M_MEMCS0 0x10 -#define PI_FUNCTION_CNTRL_M_MEMCS1 0x20 -#define PI_FUNCTION_CNTRL_M_DMA 0x80 - -/* Define the bits in the slot control register. */ - -#define PI_SLOT_CNTRL_M_RESET 0x04 /* Don't use. */ -#define PI_SLOT_CNTRL_M_ERROR 0x02 /* Not implemented. */ -#define PI_SLOT_CNTRL_M_ENB 0x01 /* Must be set. */ - -/* Define the bits in the burst holdoff register. */ - -#define PI_BURST_HOLDOFF_M_HOLDOFF 0xFC -#define PI_BURST_HOLDOFF_M_RESERVED 0x02 -#define PI_BURST_HOLDOFF_M_MEM_MAP 0x01 - -#define PI_BURST_HOLDOFF_V_HOLDOFF 2 -#define PI_BURST_HOLDOFF_V_RESERVED 1 -#define PI_BURST_HOLDOFF_V_MEM_MAP 0 - -/* Define the implicit mask of the Memory Address Mask Register. */ - -#define PI_MEM_ADD_MASK_M 0x3ff - -/* - * Define the fields in the IO Compare registers. - * The driver must initialize the slot field with the slot ID shifted by the - * amount shown below. - */ - -#define PI_IO_CMP_V_SLOT 4 - -/* Define the fields in the Interrupt Channel Configuration and Status reg */ - -#define PI_CONFIG_STAT_0_M_PEND 0x80 -#define PI_CONFIG_STAT_0_M_RES_1 0x40 -#define PI_CONFIG_STAT_0_M_IREQ_OUT 0x20 -#define PI_CONFIG_STAT_0_M_IREQ_IN 0x10 -#define PI_CONFIG_STAT_0_M_INT_ENB 0x08 -#define PI_CONFIG_STAT_0_M_RES_0 0x04 -#define PI_CONFIG_STAT_0_M_IRQ 0x03 - -#define PI_CONFIG_STAT_0_V_PEND 7 -#define PI_CONFIG_STAT_0_V_RES_1 6 -#define PI_CONFIG_STAT_0_V_IREQ_OUT 5 -#define PI_CONFIG_STAT_0_V_IREQ_IN 4 -#define PI_CONFIG_STAT_0_V_INT_ENB 3 -#define PI_CONFIG_STAT_0_V_RES_0 2 -#define PI_CONFIG_STAT_0_V_IRQ 0 - -#define PI_CONFIG_STAT_0_IRQ_K_9 0 -#define PI_CONFIG_STAT_0_IRQ_K_10 1 -#define PI_CONFIG_STAT_0_IRQ_K_11 2 -#define PI_CONFIG_STAT_0_IRQ_K_15 3 - -/* Define DEC FDDIcontroller/EISA (DEFEA) EISA hardware ID's */ - -#define DEFEA_PRODUCT_ID 0x0030A310 /* DEC product 300 (no rev) */ -#define DEFEA_PROD_ID_1 0x0130A310 /* DEC product 300, rev 1 */ -#define DEFEA_PROD_ID_2 0x0230A310 /* DEC product 300, rev 2 */ -#define DEFEA_PROD_ID_3 0x0330A310 /* DEC product 300, rev 3 */ -#define DEFEA_PROD_ID_4 0x0430A310 /* DEC product 300, rev 4 */ - -/**********************************************/ -/* Digital PFI Specification v1.0 Definitions */ -/**********************************************/ - -/* PCI Configuration Space Constants */ - -#define PFI_K_LAT_TIMER_DEF 0x88 /* def max master latency timer */ -#define PFI_K_LAT_TIMER_MIN 0x20 /* min max master latency timer */ -#define PFI_K_CSR_MEM_LEN 0x80 /* 128 bytes */ -#define PFI_K_CSR_IO_LEN 0x80 /* 128 bytes */ -#define PFI_K_PKT_MEM_LEN 0x10000 /* 64K bytes */ - -/* PFI Register Offsets (starting at PDQ Register Base Address) */ - -#define PFI_K_REG_RESERVED_0 0X00000038 -#define PFI_K_REG_RESERVED_1 0X0000003C -#define PFI_K_REG_MODE_CTRL 0X00000040 -#define PFI_K_REG_STATUS 0X00000044 -#define PFI_K_REG_FIFO_WRITE 0X00000048 -#define PFI_K_REG_FIFO_READ 0X0000004C - -/* PFI Mode Control Register Constants */ - -#define PFI_MODE_M_RESERVED 0XFFFFFFF0 -#define PFI_MODE_M_TGT_ABORT_ENB 0X00000008 -#define PFI_MODE_M_PDQ_INT_ENB 0X00000004 -#define PFI_MODE_M_PFI_INT_ENB 0X00000002 -#define PFI_MODE_M_DMA_ENB 0X00000001 - -#define PFI_MODE_V_RESERVED 4 -#define PFI_MODE_V_TGT_ABORT_ENB 3 -#define PFI_MODE_V_PDQ_INT_ENB 2 -#define PFI_MODE_V_PFI_INT_ENB 1 -#define PFI_MODE_V_DMA_ENB 0 - -#define PFI_MODE_K_ALL_DISABLE 0X00000000 - -/* PFI Status Register Constants */ - -#define PFI_STATUS_M_RESERVED 0XFFFFFFC0 -#define PFI_STATUS_M_PFI_ERROR 0X00000020 /* only valid in rev 1 or later PFI */ -#define PFI_STATUS_M_PDQ_INT 0X00000010 -#define PFI_STATUS_M_PDQ_DMA_ABORT 0X00000008 -#define PFI_STATUS_M_FIFO_FULL 0X00000004 -#define PFI_STATUS_M_FIFO_EMPTY 0X00000002 -#define PFI_STATUS_M_DMA_IN_PROGRESS 0X00000001 - -#define PFI_STATUS_V_RESERVED 6 -#define PFI_STATUS_V_PFI_ERROR 5 /* only valid in rev 1 or later PFI */ -#define PFI_STATUS_V_PDQ_INT 4 -#define PFI_STATUS_V_PDQ_DMA_ABORT 3 -#define PFI_STATUS_V_FIFO_FULL 2 -#define PFI_STATUS_V_FIFO_EMPTY 1 -#define PFI_STATUS_V_DMA_IN_PROGRESS 0 - -#define DFX_FC_PRH2_PRH1_PRH0 0x54003820 /* Packet Request Header bytes + FC */ -#define DFX_PRH0_BYTE 0x20 /* Packet Request Header byte 0 */ -#define DFX_PRH1_BYTE 0x38 /* Packet Request Header byte 1 */ -#define DFX_PRH2_BYTE 0x00 /* Packet Request Header byte 2 */ - -/* Driver routine status (return) codes */ - -#define DFX_K_SUCCESS 0 /* routine succeeded */ -#define DFX_K_FAILURE 1 /* routine failed */ -#define DFX_K_OUTSTATE 2 /* bad state for command */ -#define DFX_K_HW_TIMEOUT 3 /* command timed out */ - -/* Define LLC host receive buffer min/max/default values */ - -#define RCV_BUFS_MIN 2 /* minimum pre-allocated receive buffers */ -#define RCV_BUFS_MAX 32 /* maximum pre-allocated receive buffers */ -#define RCV_BUFS_DEF 8 /* default pre-allocated receive buffers */ - -/* Define offsets into FDDI LLC or SMT receive frame buffers - used when indicating frames */ - -#define RCV_BUFF_K_DESCR 0 /* four byte FMC descriptor */ -#define RCV_BUFF_K_PADDING 4 /* three null bytes */ -#define RCV_BUFF_K_FC 7 /* one byte frame control */ -#define RCV_BUFF_K_DA 8 /* six byte destination address */ -#define RCV_BUFF_K_SA 14 /* six byte source address */ -#define RCV_BUFF_K_DATA 20 /* offset to start of packet data */ - -/* Define offsets into FDDI LLC transmit frame buffers - used when sending frames */ - -#define XMT_BUFF_K_FC 0 /* one byte frame control */ -#define XMT_BUFF_K_DA 1 /* six byte destination address */ -#define XMT_BUFF_K_SA 7 /* six byte source address */ -#define XMT_BUFF_K_DATA 13 /* offset to start of packet data */ - -/* Macro for checking a "value" is within a specific range */ - -#define IN_RANGE(value,low,high) ((value >= low) && (value <= high)) - -/* Only execute special print call when debug driver was built */ - -#ifdef DEFXX_DEBUG -#define DBG_printk(args...) printk(## args) -#else -#define DBG_printk(args...) -#endif - -/* Define constants for masking/unmasking interrupts */ - -#define DFX_MASK_INTERRUPTS 1 -#define DFX_UNMASK_INTERRUPTS 0 - -/* Define structure for driver transmit descriptor block */ - -typedef struct - { - struct sk_buff *p_skb; /* ptr to skb */ - } XMT_DRIVER_DESCR; - -typedef struct DFX_board_tag - { - /* Keep virtual and physical pointers to locked, physically contiguous memory */ - - char *kmalloced; /* pci_free_consistent this on unload */ - dma_addr_t kmalloced_dma; - /* DMA handle for the above */ - PI_DESCR_BLOCK *descr_block_virt; /* PDQ descriptor block virt address */ - dma_addr_t descr_block_phys; /* PDQ descriptor block phys address */ - PI_DMA_CMD_REQ *cmd_req_virt; /* Command request buffer virt address */ - dma_addr_t cmd_req_phys; /* Command request buffer phys address */ - PI_DMA_CMD_RSP *cmd_rsp_virt; /* Command response buffer virt address */ - dma_addr_t cmd_rsp_phys; /* Command response buffer phys address */ - char *rcv_block_virt; /* LLC host receive queue buf blk virt */ - dma_addr_t rcv_block_phys; /* LLC host receive queue buf blk phys */ - PI_CONSUMER_BLOCK *cons_block_virt; /* PDQ consumer block virt address */ - dma_addr_t cons_block_phys; /* PDQ consumer block phys address */ - - /* Keep local copies of Type 1 and Type 2 register data */ - - PI_TYPE_1_PROD_REG cmd_req_reg; /* Command Request register */ - PI_TYPE_1_PROD_REG cmd_rsp_reg; /* Command Response register */ - PI_TYPE_2_PROD_REG rcv_xmt_reg; /* Type 2 (RCV/XMT) register */ - - /* Storage for unicast and multicast address entries in adapter CAM */ - - u8 uc_table[1*FDDI_K_ALEN]; - u32 uc_count; /* number of unicast addresses */ - u8 mc_table[PI_CMD_ADDR_FILTER_K_SIZE*FDDI_K_ALEN]; - u32 mc_count; /* number of multicast addresses */ - - /* Current packet filter settings */ - - u32 ind_group_prom; /* LLC individual & group frame prom mode */ - u32 group_prom; /* LLC group (multicast) frame prom mode */ - - /* Link available flag needed to determine whether to drop outgoing packet requests */ - - u32 link_available; /* is link available? */ - - /* Resources to indicate reset type when resetting adapter */ - - u32 reset_type; /* skip or rerun diagnostics */ - - /* Store pointers to receive buffers for queue processing code */ - - char *p_rcv_buff_va[PI_RCV_DATA_K_NUM_ENTRIES]; - - /* Store pointers to transmit buffers for transmit completion code */ - - XMT_DRIVER_DESCR xmt_drv_descr_blk[PI_XMT_DATA_K_NUM_ENTRIES]; - - /* Transmit spinlocks */ - - spinlock_t lock; - - /* Store device, bus-specific, and parameter information for this adapter */ - - struct net_device *dev; /* pointer to device structure */ - union { - void __iomem *mem; - int port; - } base; /* base address */ - struct device *bus_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) */ - u32 rcv_bufs_to_post; /* receive buffers to post for LLC host queue */ - u8 factory_mac_addr[FDDI_K_ALEN]; /* factory (on-board) MAC address */ - - /* Common FDDI statistics structure and private counters */ - - struct fddi_statistics stats; - - u32 rcv_discards; - u32 rcv_crc_errors; - u32 rcv_frame_status_errors; - u32 rcv_length_errors; - u32 rcv_total_frames; - u32 rcv_multicast_frames; - u32 rcv_total_bytes; - - u32 xmt_discards; - u32 xmt_length_errors; - u32 xmt_total_frames; - u32 xmt_total_bytes; - } DFX_board_t; - -#endif /* #ifndef _DEFXX_H_ */ diff --git a/drivers/net/fddi/Kconfig b/drivers/net/fddi/Kconfig new file mode 100644 index 0000000..3a424c8 --- /dev/null +++ b/drivers/net/fddi/Kconfig @@ -0,0 +1,77 @@ +# +# FDDI network device configuration +# + +config FDDI + tristate "FDDI driver support" + depends on PCI || EISA || TC + ---help--- + Fiber Distributed Data Interface is a high speed local area network + design; essentially a replacement for high speed Ethernet. FDDI can + run over copper or fiber. If you are connected to such a network and + want a driver for the FDDI card in your computer, say Y here (and + then also Y to the driver for your FDDI card, below). Most people + will say N. + +if FDDI + +config DEFXX + tristate "Digital DEFTA/DEFEA/DEFPA adapter support" + depends on FDDI && (PCI || EISA || TC) + ---help--- + This is support for the DIGITAL series of TURBOchannel (DEFTA), + EISA (DEFEA) and PCI (DEFPA) controllers which can connect you + to a local FDDI network. + + To compile this driver as a module, choose M here: the module + will be called defxx. If unsure, say N. + +config DEFXX_MMIO + bool + prompt "Use MMIO instead of PIO" if PCI || EISA + depends on DEFXX + default n if PCI || EISA + default y + ---help--- + This instructs the driver to use EISA or PCI memory-mapped I/O + (MMIO) as appropriate instead of programmed I/O ports (PIO). + Enabling this gives an improvement in processing time in parts + of the driver, but it may cause problems with EISA (DEFEA) + adapters. TURBOchannel does not have the concept of I/O ports, + so MMIO is always used for these (DEFTA) adapters. + + If unsure, say N. + +config SKFP + tristate "SysKonnect FDDI PCI support" + depends on FDDI && PCI + select BITREVERSE + ---help--- + Say Y here if you have a SysKonnect FDDI PCI adapter. + The following adapters are supported by this driver: + - SK-5521 (SK-NET FDDI-UP) + - SK-5522 (SK-NET FDDI-UP DAS) + - SK-5541 (SK-NET FDDI-FP) + - SK-5543 (SK-NET FDDI-LP) + - SK-5544 (SK-NET FDDI-LP DAS) + - SK-5821 (SK-NET FDDI-UP64) + - SK-5822 (SK-NET FDDI-UP64 DAS) + - SK-5841 (SK-NET FDDI-FP64) + - SK-5843 (SK-NET FDDI-LP64) + - SK-5844 (SK-NET FDDI-LP64 DAS) + - Netelligent 100 FDDI DAS Fibre SC + - Netelligent 100 FDDI SAS Fibre SC + - Netelligent 100 FDDI DAS UTP + - Netelligent 100 FDDI SAS UTP + - Netelligent 100 FDDI SAS Fibre MIC + + Read for information about + the driver. + + Questions concerning this driver can be addressed to: + + + To compile this driver as a module, choose M here: the module + will be called skfp. This is recommended. + +endif # FDDI diff --git a/drivers/net/fddi/Makefile b/drivers/net/fddi/Makefile new file mode 100644 index 0000000..36da19c --- /dev/null +++ b/drivers/net/fddi/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the Linux FDDI network device drivers. +# + +obj-$(CONFIG_DEFXX) += defxx.o +obj-$(CONFIG_SKFP) += skfp/ diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c new file mode 100644 index 0000000..4ad80f77 --- /dev/null +++ b/drivers/net/fddi/defxx.c @@ -0,0 +1,3739 @@ +/* + * File Name: + * defxx.c + * + * Copyright Information: + * Copyright Digital Equipment Corporation 1996. + * + * This software may be used and distributed according to the terms of + * the GNU General Public License, incorporated herein by reference. + * + * Abstract: + * A Linux device driver supporting the Digital Equipment Corporation + * FDDI TURBOchannel, EISA and PCI controller families. Supported + * adapters include: + * + * DEC FDDIcontroller/TURBOchannel (DEFTA) + * DEC FDDIcontroller/EISA (DEFEA) + * DEC FDDIcontroller/PCI (DEFPA) + * + * The original author: + * LVS Lawrence V. Stefani + * + * Maintainers: + * macro Maciej W. Rozycki + * + * Credits: + * I'd like to thank Patricia Cross for helping me get started with + * Linux, David Davies for a lot of help upgrading and configuring + * my development system and for answering many OS and driver + * development questions, and Alan Cox for recommendations and + * integration help on getting FDDI support into Linux. LVS + * + * Driver Architecture: + * The driver architecture is largely based on previous driver work + * for other operating systems. The upper edge interface and + * functions were largely taken from existing Linux device drivers + * such as David Davies' DE4X5.C driver and Donald Becker's TULIP.C + * driver. + * + * Adapter Probe - + * The driver scans for supported EISA adapters by reading the + * SLOT ID register for each EISA slot and making a match + * against the expected value. + * + * Bus-Specific Initialization - + * This driver currently supports both EISA and PCI controller + * families. While the custom DMA chip and FDDI logic is similar + * or identical, the bus logic is very different. After + * initialization, the only bus-specific differences is in how the + * driver enables and disables interrupts. Other than that, the + * run-time critical code behaves the same on both families. + * It's important to note that both adapter families are configured + * to I/O map, rather than memory map, the adapter registers. + * + * Driver Open/Close - + * In the driver open routine, the driver ISR (interrupt service + * routine) is registered and the adapter is brought to an + * operational state. In the driver close routine, the opposite + * occurs; the driver ISR is deregistered and the adapter is + * brought to a safe, but closed state. Users may use consecutive + * commands to bring the adapter up and down as in the following + * example: + * ifconfig fddi0 up + * ifconfig fddi0 down + * ifconfig fddi0 up + * + * Driver Shutdown - + * Apparently, there is no shutdown or halt routine support under + * Linux. This routine would be called during "reboot" or + * "shutdown" to allow the driver to place the adapter in a safe + * state before a warm reboot occurs. To be really safe, the user + * should close the adapter before shutdown (eg. ifconfig fddi0 down) + * to ensure that the adapter DMA engine is taken off-line. However, + * the current driver code anticipates this problem and always issues + * a soft reset of the adapter at the beginning of driver initialization. + * A future driver enhancement in this area may occur in 2.1.X where + * Alan indicated that a shutdown handler may be implemented. + * + * Interrupt Service Routine - + * The driver supports shared interrupts, so the ISR is registered for + * each board with the appropriate flag and the pointer to that board's + * device structure. This provides the context during interrupt + * processing to support shared interrupts and multiple boards. + * + * Interrupt enabling/disabling can occur at many levels. At the host + * end, you can disable system interrupts, or disable interrupts at the + * PIC (on Intel systems). Across the bus, both EISA and PCI adapters + * have a bus-logic chip interrupt enable/disable as well as a DMA + * controller interrupt enable/disable. + * + * The driver currently enables and disables adapter interrupts at the + * bus-logic chip and assumes that Linux will take care of clearing or + * acknowledging any host-based interrupt chips. + * + * Control Functions - + * Control functions are those used to support functions such as adding + * or deleting multicast addresses, enabling or disabling packet + * reception filters, or other custom/proprietary commands. Presently, + * the driver supports the "get statistics", "set multicast list", and + * "set mac address" functions defined by Linux. A list of possible + * enhancements include: + * + * - Custom ioctl interface for executing port interface commands + * - Custom ioctl interface for adding unicast addresses to + * adapter CAM (to support bridge functions). + * - Custom ioctl interface for supporting firmware upgrades. + * + * Hardware (port interface) Support Routines - + * The driver function names that start with "dfx_hw_" represent + * low-level port interface routines that are called frequently. They + * include issuing a DMA or port control command to the adapter, + * resetting the adapter, or reading the adapter state. Since the + * driver initialization and run-time code must make calls into the + * port interface, these routines were written to be as generic and + * usable as possible. + * + * Receive Path - + * The adapter DMA engine supports a 256 entry receive descriptor block + * of which up to 255 entries can be used at any given time. The + * architecture is a standard producer, consumer, completion model in + * which the driver "produces" receive buffers to the adapter, the + * adapter "consumes" the receive buffers by DMAing incoming packet data, + * and the driver "completes" the receive buffers by servicing the + * incoming packet, then "produces" a new buffer and starts the cycle + * again. Receive buffers can be fragmented in up to 16 fragments + * (descriptor entries). For simplicity, this driver posts + * single-fragment receive buffers of 4608 bytes, then allocates a + * sk_buff, copies the data, then reposts the buffer. To reduce CPU + * utilization, a better approach would be to pass up the receive + * buffer (no extra copy) then allocate and post a replacement buffer. + * This is a performance enhancement that should be looked into at + * some point. + * + * Transmit Path - + * Like the receive path, the adapter DMA engine supports a 256 entry + * transmit descriptor block of which up to 255 entries can be used at + * any given time. Transmit buffers can be fragmented in up to 255 + * fragments (descriptor entries). This driver always posts one + * fragment per transmit packet request. + * + * The fragment contains the entire packet from FC to end of data. + * Before posting the buffer to the adapter, the driver sets a three-byte + * packet request header (PRH) which is required by the Motorola MAC chip + * used on the adapters. The PRH tells the MAC the type of token to + * receive/send, whether or not to generate and append the CRC, whether + * synchronous or asynchronous framing is used, etc. Since the PRH + * definition is not necessarily consistent across all FDDI chipsets, + * the driver, rather than the common FDDI packet handler routines, + * sets these bytes. + * + * To reduce the amount of descriptor fetches needed per transmit request, + * the driver takes advantage of the fact that there are at least three + * bytes available before the skb->data field on the outgoing transmit + * request. This is guaranteed by having fddi_setup() in net_init.c set + * dev->hard_header_len to 24 bytes. 21 bytes accounts for the largest + * header in an 802.2 SNAP frame. The other 3 bytes are the extra "pad" + * bytes which we'll use to store the PRH. + * + * There's a subtle advantage to adding these pad bytes to the + * hard_header_len, it ensures that the data portion of the packet for + * an 802.2 SNAP frame is longword aligned. Other FDDI driver + * implementations may not need the extra padding and can start copying + * or DMAing directly from the FC byte which starts at skb->data. Should + * another driver implementation need ADDITIONAL padding, the net_init.c + * module should be updated and dev->hard_header_len should be increased. + * NOTE: To maintain the alignment on the data portion of the packet, + * dev->hard_header_len should always be evenly divisible by 4 and at + * least 24 bytes in size. + * + * Modification History: + * Date Name Description + * 16-Aug-96 LVS Created. + * 20-Aug-96 LVS Updated dfx_probe so that version information + * string is only displayed if 1 or more cards are + * found. Changed dfx_rcv_queue_process to copy + * 3 NULL bytes before FC to ensure that data is + * longword aligned in receive buffer. + * 09-Sep-96 LVS Updated dfx_ctl_set_multicast_list to enable + * LLC group promiscuous mode if multicast list + * is too large. LLC individual/group promiscuous + * mode is now disabled if IFF_PROMISC flag not set. + * dfx_xmt_queue_pkt no longer checks for NULL skb + * on Alan Cox recommendation. Added node address + * override support. + * 12-Sep-96 LVS Reset current address to factory address during + * device open. Updated transmit path to post a + * single fragment which includes PRH->end of data. + * Mar 2000 AC Did various cleanups for 2.3.x + * Jun 2000 jgarzik PCI and resource alloc cleanups + * Jul 2000 tjeerd Much cleanup and some bug fixes + * Sep 2000 tjeerd Fix leak on unload, cosmetic code cleanup + * Feb 2001 Skb allocation fixes + * Feb 2001 davej PCI enable cleanups. + * 04 Aug 2003 macro Converted to the DMA API. + * 14 Aug 2004 macro Fix device names reported. + * 14 Jun 2005 macro Use irqreturn_t. + * 23 Oct 2006 macro Big-endian host support. + * 14 Dec 2006 macro TURBOchannel support. + */ + +/* Include files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "defxx.h" + +/* Version information string should be updated prior to each new release! */ +#define DRV_NAME "defxx" +#define DRV_VERSION "v1.10" +#define DRV_RELDATE "2006/12/14" + +static char version[] __devinitdata = + DRV_NAME ": " DRV_VERSION " " DRV_RELDATE + " Lawrence V. Stefani and others\n"; + +#define DYNAMIC_BUFFERS 1 + +#define SKBUFF_RX_COPYBREAK 200 +/* + * NEW_SKB_SIZE = PI_RCV_DATA_K_SIZE_MAX+128 to allow 128 byte + * alignment for compatibility with old EISA boards. + */ +#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128) + +#ifdef CONFIG_PCI +#define DFX_BUS_PCI(dev) (dev->bus == &pci_bus_type) +#else +#define DFX_BUS_PCI(dev) 0 +#endif + +#ifdef CONFIG_EISA +#define DFX_BUS_EISA(dev) (dev->bus == &eisa_bus_type) +#else +#define DFX_BUS_EISA(dev) 0 +#endif + +#ifdef CONFIG_TC +#define DFX_BUS_TC(dev) (dev->bus == &tc_bus_type) +#else +#define DFX_BUS_TC(dev) 0 +#endif + +#ifdef CONFIG_DEFXX_MMIO +#define DFX_MMIO 1 +#else +#define DFX_MMIO 0 +#endif + +/* Define module-wide (static) routines */ + +static void dfx_bus_init(struct net_device *dev); +static void dfx_bus_uninit(struct net_device *dev); +static void dfx_bus_config_check(DFX_board_t *bp); + +static int dfx_driver_init(struct net_device *dev, + const char *print_name, + resource_size_t bar_start); +static int dfx_adap_init(DFX_board_t *bp, int get_buffers); + +static int dfx_open(struct net_device *dev); +static int dfx_close(struct net_device *dev); + +static void dfx_int_pr_halt_id(DFX_board_t *bp); +static void dfx_int_type_0_process(DFX_board_t *bp); +static void dfx_int_common(struct net_device *dev); +static irqreturn_t dfx_interrupt(int irq, void *dev_id); + +static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev); +static void dfx_ctl_set_multicast_list(struct net_device *dev); +static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr); +static int dfx_ctl_update_cam(DFX_board_t *bp); +static int dfx_ctl_update_filters(DFX_board_t *bp); + +static int dfx_hw_dma_cmd_req(DFX_board_t *bp); +static int dfx_hw_port_ctrl_req(DFX_board_t *bp, PI_UINT32 command, PI_UINT32 data_a, PI_UINT32 data_b, PI_UINT32 *host_data); +static void dfx_hw_adap_reset(DFX_board_t *bp, PI_UINT32 type); +static int dfx_hw_adap_state_rd(DFX_board_t *bp); +static int dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type); + +static int dfx_rcv_init(DFX_board_t *bp, int get_buffers); +static void dfx_rcv_queue_process(DFX_board_t *bp); +static void dfx_rcv_flush(DFX_board_t *bp); + +static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, + struct net_device *dev); +static int dfx_xmt_done(DFX_board_t *bp); +static void dfx_xmt_flush(DFX_board_t *bp); + +/* Define module-wide (static) variables */ + +static struct pci_driver dfx_pci_driver; +static struct eisa_driver dfx_eisa_driver; +static struct tc_driver dfx_tc_driver; + + +/* + * ======================= + * = dfx_port_write_long = + * = dfx_port_read_long = + * ======================= + * + * Overview: + * Routines for reading and writing values from/to adapter + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * offset - register offset from base I/O address + * data - for dfx_port_write_long, this is a value to write; + * for dfx_port_read_long, this is a pointer to store + * the read value + * + * Functional Description: + * These routines perform the correct operation to read or write + * the adapter register. + * + * EISA port block base addresses are based on the slot number in which the + * controller is installed. For example, if the EISA controller is installed + * in slot 4, the port block base address is 0x4000. If the controller is + * installed in slot 2, the port block base address is 0x2000, and so on. + * This port block can be used to access PDQ, ESIC, and DEFEA on-board + * registers using the register offsets defined in DEFXX.H. + * + * PCI port block base addresses are assigned by the PCI BIOS or system + * firmware. There is one 128 byte port block which can be accessed. It + * allows for I/O mapping of both PDQ and PFI registers using the register + * offsets defined in DEFXX.H. + * + * Return Codes: + * None + * + * Assumptions: + * bp->base is a valid base I/O address for this adapter. + * offset is a valid register offset for this adapter. + * + * Side Effects: + * Rather than produce macros for these functions, these routines + * are defined using "inline" to ensure that the compiler will + * generate inline code and not waste a procedure call and return. + * This provides all the benefits of macros, but with the + * advantage of strict data type checking. + */ + +static inline void dfx_writel(DFX_board_t *bp, int offset, u32 data) +{ + writel(data, bp->base.mem + offset); + mb(); +} + +static inline void dfx_outl(DFX_board_t *bp, int offset, u32 data) +{ + outl(data, bp->base.port + offset); +} + +static void dfx_port_write_long(DFX_board_t *bp, int offset, u32 data) +{ + struct device __maybe_unused *bdev = bp->bus_dev; + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + + if (dfx_use_mmio) + dfx_writel(bp, offset, data); + else + dfx_outl(bp, offset, data); +} + + +static inline void dfx_readl(DFX_board_t *bp, int offset, u32 *data) +{ + mb(); + *data = readl(bp->base.mem + offset); +} + +static inline void dfx_inl(DFX_board_t *bp, int offset, u32 *data) +{ + *data = inl(bp->base.port + offset); +} + +static void dfx_port_read_long(DFX_board_t *bp, int offset, u32 *data) +{ + struct device __maybe_unused *bdev = bp->bus_dev; + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + + if (dfx_use_mmio) + dfx_readl(bp, offset, data); + else + dfx_inl(bp, offset, data); +} + + +/* + * ================ + * = dfx_get_bars = + * ================ + * + * Overview: + * Retrieves the address range used to access control and status + * registers. + * + * Returns: + * None + * + * Arguments: + * bdev - pointer to device information + * bar_start - pointer to store the start address + * bar_len - pointer to store the length of the area + * + * Assumptions: + * I am sure there are some. + * + * Side Effects: + * None + */ +static void dfx_get_bars(struct device *bdev, + resource_size_t *bar_start, resource_size_t *bar_len) +{ + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + + if (dfx_bus_pci) { + int num = dfx_use_mmio ? 0 : 1; + + *bar_start = pci_resource_start(to_pci_dev(bdev), num); + *bar_len = pci_resource_len(to_pci_dev(bdev), num); + } + if (dfx_bus_eisa) { + unsigned long base_addr = to_eisa_device(bdev)->base_addr; + resource_size_t bar; + + if (dfx_use_mmio) { + bar = inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_2); + bar <<= 8; + bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_1); + bar <<= 8; + bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_0); + bar <<= 16; + *bar_start = bar; + bar = inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_2); + bar <<= 8; + bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_1); + bar <<= 8; + bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_0); + bar <<= 16; + *bar_len = (bar | PI_MEM_ADD_MASK_M) + 1; + } else { + *bar_start = base_addr; + *bar_len = PI_ESIC_K_CSR_IO_LEN; + } + } + if (dfx_bus_tc) { + *bar_start = to_tc_dev(bdev)->resource.start + + PI_TC_K_CSR_OFFSET; + *bar_len = PI_TC_K_CSR_LEN; + } +} + +static const struct net_device_ops dfx_netdev_ops = { + .ndo_open = dfx_open, + .ndo_stop = dfx_close, + .ndo_start_xmit = dfx_xmt_queue_pkt, + .ndo_get_stats = dfx_ctl_get_stats, + .ndo_set_rx_mode = dfx_ctl_set_multicast_list, + .ndo_set_mac_address = dfx_ctl_set_mac_address, +}; + +/* + * ================ + * = dfx_register = + * ================ + * + * Overview: + * Initializes a supported FDDI controller + * + * Returns: + * Condition code + * + * Arguments: + * bdev - pointer to device information + * + * Functional Description: + * + * Return Codes: + * 0 - This device (fddi0, fddi1, etc) configured successfully + * -EBUSY - Failed to get resources, or dfx_driver_init failed. + * + * Assumptions: + * It compiles so it should work :-( (PCI cards do :-) + * + * Side Effects: + * Device structures for FDDI adapters (fddi0, fddi1, etc) are + * initialized and the board resources are read and stored in + * the device structure. + */ +static int __devinit dfx_register(struct device *bdev) +{ + static int version_disp; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + const char *print_name = dev_name(bdev); + struct net_device *dev; + DFX_board_t *bp; /* board pointer */ + resource_size_t bar_start = 0; /* pointer to port */ + resource_size_t bar_len = 0; /* resource length */ + int alloc_size; /* total buffer size used */ + struct resource *region; + int err = 0; + + 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 */ + } + + dev = alloc_fddidev(sizeof(*bp)); + if (!dev) { + printk(KERN_ERR "%s: Unable to allocate fddidev, aborting\n", + print_name); + return -ENOMEM; + } + + /* Enable PCI device. */ + if (dfx_bus_pci && pci_enable_device(to_pci_dev(bdev))) { + printk(KERN_ERR "%s: Cannot enable PCI device, aborting\n", + print_name); + goto err_out; + } + + SET_NETDEV_DEV(dev, bdev); + + bp = netdev_priv(dev); + bp->bus_dev = bdev; + dev_set_drvdata(bdev, dev); + + dfx_get_bars(bdev, &bar_start, &bar_len); + + if (dfx_use_mmio) + region = request_mem_region(bar_start, bar_len, print_name); + else + region = request_region(bar_start, bar_len, print_name); + if (!region) { + printk(KERN_ERR "%s: Cannot reserve I/O resource " + "0x%lx @ 0x%lx, aborting\n", + print_name, (long)bar_len, (long)bar_start); + err = -EBUSY; + goto err_out_disable; + } + + /* Set up I/O base address. */ + if (dfx_use_mmio) { + bp->base.mem = ioremap_nocache(bar_start, bar_len); + if (!bp->base.mem) { + printk(KERN_ERR "%s: Cannot map MMIO\n", print_name); + err = -ENOMEM; + goto err_out_region; + } + } else { + bp->base.port = bar_start; + dev->base_addr = bar_start; + } + + /* Initialize new device structure */ + dev->netdev_ops = &dfx_netdev_ops; + + if (dfx_bus_pci) + pci_set_master(to_pci_dev(bdev)); + + if (dfx_driver_init(dev, print_name, bar_start) != DFX_K_SUCCESS) { + err = -ENODEV; + goto err_out_unmap; + } + + err = register_netdev(dev); + if (err) + goto err_out_kfree; + + printk("%s: registered as %s\n", print_name, dev->name); + return 0; + +err_out_kfree: + alloc_size = sizeof(PI_DESCR_BLOCK) + + PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX + +#ifndef DYNAMIC_BUFFERS + (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) + +#endif + sizeof(PI_CONSUMER_BLOCK) + + (PI_ALIGN_K_DESC_BLK - 1); + if (bp->kmalloced) + dma_free_coherent(bdev, alloc_size, + bp->kmalloced, bp->kmalloced_dma); + +err_out_unmap: + if (dfx_use_mmio) + iounmap(bp->base.mem); + +err_out_region: + if (dfx_use_mmio) + release_mem_region(bar_start, bar_len); + else + release_region(bar_start, bar_len); + +err_out_disable: + if (dfx_bus_pci) + pci_disable_device(to_pci_dev(bdev)); + +err_out: + free_netdev(dev); + return err; +} + + +/* + * ================ + * = dfx_bus_init = + * ================ + * + * Overview: + * Initializes the bus-specific controller logic. + * + * Returns: + * None + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * Determine and save adapter IRQ in device table, + * then perform bus-specific logic initialization. + * + * Return Codes: + * None + * + * Assumptions: + * bp->base has already been set with the proper + * base I/O address for this device. + * + * Side Effects: + * Interrupts are enabled at the adapter bus-specific logic. + * Note: Interrupts at the DMA engine (PDQ chip) are not + * enabled yet. + */ + +static void __devinit dfx_bus_init(struct net_device *dev) +{ + DFX_board_t *bp = netdev_priv(dev); + struct device *bdev = bp->bus_dev; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + u8 val; + + DBG_printk("In dfx_bus_init...\n"); + + /* Initialize a pointer back to the net_device struct */ + bp->dev = dev; + + /* Initialize adapter based on bus type */ + + if (dfx_bus_tc) + dev->irq = to_tc_dev(bdev)->interrupt; + if (dfx_bus_eisa) { + unsigned long base_addr = to_eisa_device(bdev)->base_addr; + + /* Get the interrupt level from the ESIC chip. */ + val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); + val &= PI_CONFIG_STAT_0_M_IRQ; + val >>= PI_CONFIG_STAT_0_V_IRQ; + + switch (val) { + case PI_CONFIG_STAT_0_IRQ_K_9: + dev->irq = 9; + break; + + case PI_CONFIG_STAT_0_IRQ_K_10: + dev->irq = 10; + break; + + case PI_CONFIG_STAT_0_IRQ_K_11: + dev->irq = 11; + break; + + case PI_CONFIG_STAT_0_IRQ_K_15: + dev->irq = 15; + break; + } + + /* + * Enable memory decoding (MEMCS0) and/or port decoding + * (IOCS1/IOCS0) as appropriate in Function Control + * Register. One of the port chip selects seems to be + * used for the Burst Holdoff register, but this bit of + * documentation is missing and as yet it has not been + * determined which of the two. This is also the reason + * the size of the decoded port range is twice as large + * as one required by the PDQ. + */ + + /* Set the decode range of the board. */ + val = ((bp->base.port >> 12) << PI_IO_CMP_V_SLOT); + outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_1, val); + outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_0, 0); + outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_1, val); + outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_0, 0); + val = PI_ESIC_K_CSR_IO_LEN - 1; + outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_1, (val >> 8) & 0xff); + outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_0, val & 0xff); + outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_1, (val >> 8) & 0xff); + outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_0, val & 0xff); + + /* Enable the decoders. */ + val = PI_FUNCTION_CNTRL_M_IOCS1 | PI_FUNCTION_CNTRL_M_IOCS0; + if (dfx_use_mmio) + val |= PI_FUNCTION_CNTRL_M_MEMCS0; + outb(base_addr + PI_ESIC_K_FUNCTION_CNTRL, val); + + /* + * Enable access to the rest of the module + * (including PDQ and packet memory). + */ + val = PI_SLOT_CNTRL_M_ENB; + outb(base_addr + PI_ESIC_K_SLOT_CNTRL, val); + + /* + * Map PDQ registers into memory or port space. This is + * done with a bit in the Burst Holdoff register. + */ + val = inb(base_addr + PI_DEFEA_K_BURST_HOLDOFF); + if (dfx_use_mmio) + val |= PI_BURST_HOLDOFF_V_MEM_MAP; + else + val &= ~PI_BURST_HOLDOFF_V_MEM_MAP; + outb(base_addr + PI_DEFEA_K_BURST_HOLDOFF, val); + + /* Enable interrupts at EISA bus interface chip (ESIC) */ + val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); + val |= PI_CONFIG_STAT_0_M_INT_ENB; + outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val); + } + if (dfx_bus_pci) { + struct pci_dev *pdev = to_pci_dev(bdev); + + /* Get the interrupt level from the PCI Configuration Table */ + + dev->irq = pdev->irq; + + /* Check Latency Timer and set if less than minimal */ + + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &val); + if (val < PFI_K_LAT_TIMER_MIN) { + val = PFI_K_LAT_TIMER_DEF; + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, val); + } + + /* Enable interrupts at PCI bus interface chip (PFI) */ + val = PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB; + dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, val); + } +} + +/* + * ================== + * = dfx_bus_uninit = + * ================== + * + * Overview: + * Uninitializes the bus-specific controller logic. + * + * Returns: + * None + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * Perform bus-specific logic uninitialization. + * + * Return Codes: + * None + * + * Assumptions: + * bp->base has already been set with the proper + * base I/O address for this device. + * + * Side Effects: + * Interrupts are disabled at the adapter bus-specific logic. + */ + +static void __devexit dfx_bus_uninit(struct net_device *dev) +{ + DFX_board_t *bp = netdev_priv(dev); + struct device *bdev = bp->bus_dev; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + u8 val; + + DBG_printk("In dfx_bus_uninit...\n"); + + /* Uninitialize adapter based on bus type */ + + if (dfx_bus_eisa) { + unsigned long base_addr = to_eisa_device(bdev)->base_addr; + + /* Disable interrupts at EISA bus interface chip (ESIC) */ + val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); + val &= ~PI_CONFIG_STAT_0_M_INT_ENB; + outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val); + } + if (dfx_bus_pci) { + /* Disable interrupts at PCI bus interface chip (PFI) */ + dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, 0); + } +} + + +/* + * ======================== + * = dfx_bus_config_check = + * ======================== + * + * Overview: + * Checks the configuration (burst size, full-duplex, etc.) If any parameters + * are illegal, then this routine will set new defaults. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * For Revision 1 FDDI EISA, Revision 2 or later FDDI EISA with rev E or later + * PDQ, and all FDDI PCI controllers, all values are legal. + * + * Return Codes: + * None + * + * Assumptions: + * dfx_adap_init has NOT been called yet so burst size and other items have + * not been set. + * + * Side Effects: + * None + */ + +static void __devinit dfx_bus_config_check(DFX_board_t *bp) +{ + struct device __maybe_unused *bdev = bp->bus_dev; + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + int status; /* return code from adapter port control call */ + u32 host_data; /* LW data returned from port control call */ + + DBG_printk("In dfx_bus_config_check...\n"); + + /* Configuration check only valid for EISA adapter */ + + if (dfx_bus_eisa) { + /* + * First check if revision 2 EISA controller. Rev. 1 cards used + * PDQ revision B, so no workaround needed in this case. Rev. 3 + * cards used PDQ revision E, so no workaround needed in this + * case, either. Only Rev. 2 cards used either Rev. D or E + * chips, so we must verify the chip revision on Rev. 2 cards. + */ + if (to_eisa_device(bdev)->id.driver_data == DEFEA_PROD_ID_2) { + /* + * Revision 2 FDDI EISA controller found, + * so let's check PDQ revision of adapter. + */ + status = dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_SUB_CMD, + PI_SUB_CMD_K_PDQ_REV_GET, + 0, + &host_data); + if ((status != DFX_K_SUCCESS) || (host_data == 2)) + { + /* + * Either we couldn't determine the PDQ revision, or + * we determined that it is at revision D. In either case, + * we need to implement the workaround. + */ + + /* Ensure that the burst size is set to 8 longwords or less */ + + switch (bp->burst_size) + { + case PI_PDATA_B_DMA_BURST_SIZE_32: + case PI_PDATA_B_DMA_BURST_SIZE_16: + bp->burst_size = PI_PDATA_B_DMA_BURST_SIZE_8; + break; + + default: + break; + } + + /* Ensure that full-duplex mode is not enabled */ + + bp->full_duplex_enb = PI_SNMP_K_FALSE; + } + } + } + } + + +/* + * =================== + * = dfx_driver_init = + * =================== + * + * Overview: + * Initializes remaining adapter board structure information + * and makes sure adapter is in a safe state prior to dfx_open(). + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * print_name - printable device name + * + * Functional Description: + * This function allocates additional resources such as the host memory + * blocks needed by the adapter (eg. descriptor and consumer blocks). + * Remaining bus initialization steps are also completed. The adapter + * is also reset so that it is in the DMA_UNAVAILABLE state. The OS + * must call dfx_open() to open the adapter and bring it on-line. + * + * Return Codes: + * DFX_K_SUCCESS - initialization succeeded + * DFX_K_FAILURE - initialization failed - could not allocate memory + * or read adapter MAC address + * + * Assumptions: + * Memory allocated from pci_alloc_consistent() call is physically + * contiguous, locked memory. + * + * Side Effects: + * Adapter is reset and should be in DMA_UNAVAILABLE state before + * returning from this routine. + */ + +static int __devinit dfx_driver_init(struct net_device *dev, + const char *print_name, + resource_size_t bar_start) +{ + DFX_board_t *bp = netdev_priv(dev); + struct device *bdev = bp->bus_dev; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + int alloc_size; /* total buffer size needed */ + char *top_v, *curr_v; /* virtual addrs into memory block */ + dma_addr_t top_p, curr_p; /* physical addrs into memory block */ + u32 data; /* host data register value */ + __le32 le32; + char *board_name = NULL; + + DBG_printk("In dfx_driver_init...\n"); + + /* Initialize bus-specific hardware registers */ + + dfx_bus_init(dev); + + /* + * Initialize default values for configurable parameters + * + * Note: All of these parameters are ones that a user may + * want to customize. It'd be nice to break these + * out into Space.c or someplace else that's more + * accessible/understandable than this file. + */ + + bp->full_duplex_enb = PI_SNMP_K_FALSE; + bp->req_ttrt = 8 * 12500; /* 8ms in 80 nanosec units */ + bp->burst_size = PI_PDATA_B_DMA_BURST_SIZE_DEF; + bp->rcv_bufs_to_post = RCV_BUFS_DEF; + + /* + * Ensure that HW configuration is OK + * + * Note: Depending on the hardware revision, we may need to modify + * some of the configurable parameters to workaround hardware + * limitations. We'll perform this configuration check AFTER + * setting the parameters to their default values. + */ + + dfx_bus_config_check(bp); + + /* Disable PDQ interrupts first */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); + + /* Place adapter in DMA_UNAVAILABLE state by resetting adapter */ + + (void) dfx_hw_dma_uninit(bp, PI_PDATA_A_RESET_M_SKIP_ST); + + /* Read the factory MAC address from the adapter then save it */ + + if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_LO, 0, + &data) != DFX_K_SUCCESS) { + printk("%s: Could not read adapter factory MAC address!\n", + print_name); + return DFX_K_FAILURE; + } + le32 = cpu_to_le32(data); + memcpy(&bp->factory_mac_addr[0], &le32, sizeof(u32)); + + if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_HI, 0, + &data) != DFX_K_SUCCESS) { + printk("%s: Could not read adapter factory MAC address!\n", + print_name); + return DFX_K_FAILURE; + } + le32 = cpu_to_le32(data); + memcpy(&bp->factory_mac_addr[4], &le32, sizeof(u16)); + + /* + * Set current address to factory address + * + * Note: Node address override support is handled through + * dfx_ctl_set_mac_address. + */ + + memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN); + if (dfx_bus_tc) + board_name = "DEFTA"; + if (dfx_bus_eisa) + board_name = "DEFEA"; + if (dfx_bus_pci) + board_name = "DEFPA"; + pr_info("%s: %s at %saddr = 0x%llx, IRQ = %d, Hardware addr = %pMF\n", + print_name, board_name, dfx_use_mmio ? "" : "I/O ", + (long long)bar_start, dev->irq, dev->dev_addr); + + /* + * Get memory for descriptor block, consumer block, and other buffers + * that need to be DMA read or written to by the adapter. + */ + + alloc_size = sizeof(PI_DESCR_BLOCK) + + PI_CMD_REQ_K_SIZE_MAX + + PI_CMD_RSP_K_SIZE_MAX + +#ifndef DYNAMIC_BUFFERS + (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) + +#endif + sizeof(PI_CONSUMER_BLOCK) + + (PI_ALIGN_K_DESC_BLK - 1); + bp->kmalloced = top_v = dma_alloc_coherent(bp->bus_dev, alloc_size, + &bp->kmalloced_dma, + GFP_ATOMIC); + if (top_v == NULL) { + printk("%s: Could not allocate memory for host buffers " + "and structures!\n", print_name); + return DFX_K_FAILURE; + } + memset(top_v, 0, alloc_size); /* zero out memory before continuing */ + top_p = bp->kmalloced_dma; /* get physical address of buffer */ + + /* + * To guarantee the 8K alignment required for the descriptor block, 8K - 1 + * plus the amount of memory needed was allocated. The physical address + * is now 8K aligned. By carving up the memory in a specific order, + * we'll guarantee the alignment requirements for all other structures. + * + * Note: If the assumptions change regarding the non-paged, non-cached, + * physically contiguous nature of the memory block or the address + * alignments, then we'll need to implement a different algorithm + * for allocating the needed memory. + */ + + curr_p = ALIGN(top_p, PI_ALIGN_K_DESC_BLK); + curr_v = top_v + (curr_p - top_p); + + /* Reserve space for descriptor block */ + + bp->descr_block_virt = (PI_DESCR_BLOCK *) curr_v; + bp->descr_block_phys = curr_p; + curr_v += sizeof(PI_DESCR_BLOCK); + curr_p += sizeof(PI_DESCR_BLOCK); + + /* Reserve space for command request buffer */ + + bp->cmd_req_virt = (PI_DMA_CMD_REQ *) curr_v; + bp->cmd_req_phys = curr_p; + curr_v += PI_CMD_REQ_K_SIZE_MAX; + curr_p += PI_CMD_REQ_K_SIZE_MAX; + + /* Reserve space for command response buffer */ + + bp->cmd_rsp_virt = (PI_DMA_CMD_RSP *) curr_v; + bp->cmd_rsp_phys = curr_p; + curr_v += PI_CMD_RSP_K_SIZE_MAX; + curr_p += PI_CMD_RSP_K_SIZE_MAX; + + /* Reserve space for the LLC host receive queue buffers */ + + bp->rcv_block_virt = curr_v; + bp->rcv_block_phys = curr_p; + +#ifndef DYNAMIC_BUFFERS + curr_v += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX); + curr_p += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX); +#endif + + /* Reserve space for the consumer block */ + + bp->cons_block_virt = (PI_CONSUMER_BLOCK *) curr_v; + bp->cons_block_phys = curr_p; + + /* Display virtual and physical addresses if debug driver */ + + DBG_printk("%s: Descriptor block virt = %0lX, phys = %0X\n", + print_name, + (long)bp->descr_block_virt, bp->descr_block_phys); + DBG_printk("%s: Command Request buffer virt = %0lX, phys = %0X\n", + print_name, (long)bp->cmd_req_virt, bp->cmd_req_phys); + DBG_printk("%s: Command Response buffer virt = %0lX, phys = %0X\n", + print_name, (long)bp->cmd_rsp_virt, bp->cmd_rsp_phys); + DBG_printk("%s: Receive buffer block virt = %0lX, phys = %0X\n", + print_name, (long)bp->rcv_block_virt, bp->rcv_block_phys); + DBG_printk("%s: Consumer block virt = %0lX, phys = %0X\n", + print_name, (long)bp->cons_block_virt, bp->cons_block_phys); + + return DFX_K_SUCCESS; +} + + +/* + * ================= + * = dfx_adap_init = + * ================= + * + * Overview: + * Brings the adapter to the link avail/link unavailable state. + * + * Returns: + * Condition code + * + * Arguments: + * bp - pointer to board information + * get_buffers - non-zero if buffers to be allocated + * + * Functional Description: + * Issues the low-level firmware/hardware calls necessary to bring + * the adapter up, or to properly reset and restore adapter during + * run-time. + * + * Return Codes: + * DFX_K_SUCCESS - Adapter brought up successfully + * DFX_K_FAILURE - Adapter initialization failed + * + * Assumptions: + * bp->reset_type should be set to a valid reset type value before + * calling this routine. + * + * Side Effects: + * Adapter should be in LINK_AVAILABLE or LINK_UNAVAILABLE state + * upon a successful return of this routine. + */ + +static int dfx_adap_init(DFX_board_t *bp, int get_buffers) + { + DBG_printk("In dfx_adap_init...\n"); + + /* Disable PDQ interrupts first */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); + + /* Place adapter in DMA_UNAVAILABLE state by resetting adapter */ + + if (dfx_hw_dma_uninit(bp, bp->reset_type) != DFX_K_SUCCESS) + { + printk("%s: Could not uninitialize/reset adapter!\n", bp->dev->name); + return DFX_K_FAILURE; + } + + /* + * When the PDQ is reset, some false Type 0 interrupts may be pending, + * so we'll acknowledge all Type 0 interrupts now before continuing. + */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, PI_HOST_INT_K_ACK_ALL_TYPE_0); + + /* + * Clear Type 1 and Type 2 registers before going to DMA_AVAILABLE state + * + * Note: We only need to clear host copies of these registers. The PDQ reset + * takes care of the on-board register values. + */ + + bp->cmd_req_reg.lword = 0; + bp->cmd_rsp_reg.lword = 0; + bp->rcv_xmt_reg.lword = 0; + + /* Clear consumer block before going to DMA_AVAILABLE state */ + + memset(bp->cons_block_virt, 0, sizeof(PI_CONSUMER_BLOCK)); + + /* Initialize the DMA Burst Size */ + + if (dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_SUB_CMD, + PI_SUB_CMD_K_BURST_SIZE_SET, + bp->burst_size, + NULL) != DFX_K_SUCCESS) + { + printk("%s: Could not set adapter burst size!\n", bp->dev->name); + return DFX_K_FAILURE; + } + + /* + * Set base address of Consumer Block + * + * Assumption: 32-bit physical address of consumer block is 64 byte + * aligned. That is, bits 0-5 of the address must be zero. + */ + + if (dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_CONS_BLOCK, + bp->cons_block_phys, + 0, + NULL) != DFX_K_SUCCESS) + { + printk("%s: Could not set consumer block address!\n", bp->dev->name); + return DFX_K_FAILURE; + } + + /* + * Set the base address of Descriptor Block and bring adapter + * to DMA_AVAILABLE state. + * + * Note: We also set the literal and data swapping requirements + * in this command. + * + * Assumption: 32-bit physical address of descriptor block + * is 8Kbyte aligned. + */ + if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_INIT, + (u32)(bp->descr_block_phys | + PI_PDATA_A_INIT_M_BSWAP_INIT), + 0, NULL) != DFX_K_SUCCESS) { + printk("%s: Could not set descriptor block address!\n", + bp->dev->name); + return DFX_K_FAILURE; + } + + /* Set transmit flush timeout value */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_CHARS_SET; + bp->cmd_req_virt->char_set.item[0].item_code = PI_ITEM_K_FLUSH_TIME; + bp->cmd_req_virt->char_set.item[0].value = 3; /* 3 seconds */ + bp->cmd_req_virt->char_set.item[0].item_index = 0; + bp->cmd_req_virt->char_set.item[1].item_code = PI_ITEM_K_EOL; + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + { + printk("%s: DMA command request failed!\n", bp->dev->name); + return DFX_K_FAILURE; + } + + /* Set the initial values for eFDXEnable and MACTReq MIB objects */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_SNMP_SET; + bp->cmd_req_virt->snmp_set.item[0].item_code = PI_ITEM_K_FDX_ENB_DIS; + bp->cmd_req_virt->snmp_set.item[0].value = bp->full_duplex_enb; + bp->cmd_req_virt->snmp_set.item[0].item_index = 0; + bp->cmd_req_virt->snmp_set.item[1].item_code = PI_ITEM_K_MAC_T_REQ; + bp->cmd_req_virt->snmp_set.item[1].value = bp->req_ttrt; + bp->cmd_req_virt->snmp_set.item[1].item_index = 0; + bp->cmd_req_virt->snmp_set.item[2].item_code = PI_ITEM_K_EOL; + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + { + printk("%s: DMA command request failed!\n", bp->dev->name); + return DFX_K_FAILURE; + } + + /* Initialize adapter CAM */ + + if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS) + { + printk("%s: Adapter CAM update failed!\n", bp->dev->name); + return DFX_K_FAILURE; + } + + /* Initialize adapter filters */ + + if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS) + { + printk("%s: Adapter filters update failed!\n", bp->dev->name); + return DFX_K_FAILURE; + } + + /* + * Remove any existing dynamic buffers (i.e. if the adapter is being + * reinitialized) + */ + + if (get_buffers) + dfx_rcv_flush(bp); + + /* Initialize receive descriptor block and produce buffers */ + + if (dfx_rcv_init(bp, get_buffers)) + { + printk("%s: Receive buffer allocation failed\n", bp->dev->name); + if (get_buffers) + dfx_rcv_flush(bp); + return DFX_K_FAILURE; + } + + /* Issue START command and bring adapter to LINK_(UN)AVAILABLE state */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_START; + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + { + printk("%s: Start command failed\n", bp->dev->name); + if (get_buffers) + dfx_rcv_flush(bp); + return DFX_K_FAILURE; + } + + /* Initialization succeeded, reenable PDQ interrupts */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_ENABLE_DEF_INTS); + return DFX_K_SUCCESS; + } + + +/* + * ============ + * = dfx_open = + * ============ + * + * Overview: + * Opens the adapter + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This function brings the adapter to an operational state. + * + * Return Codes: + * 0 - Adapter was successfully opened + * -EAGAIN - Could not register IRQ or adapter initialization failed + * + * Assumptions: + * This routine should only be called for a device that was + * initialized successfully. + * + * Side Effects: + * Adapter should be in LINK_AVAILABLE or LINK_UNAVAILABLE state + * if the open is successful. + */ + +static int dfx_open(struct net_device *dev) +{ + DFX_board_t *bp = netdev_priv(dev); + int ret; + + DBG_printk("In dfx_open...\n"); + + /* Register IRQ - support shared interrupts by passing device ptr */ + + ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name, + dev); + if (ret) { + printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq); + return ret; + } + + /* + * Set current address to factory MAC address + * + * Note: We've already done this step in dfx_driver_init. + * However, it's possible that a user has set a node + * address override, then closed and reopened the + * adapter. Unless we reset the device address field + * now, we'll continue to use the existing modified + * address. + */ + + memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN); + + /* Clear local unicast/multicast address tables and counts */ + + memset(bp->uc_table, 0, sizeof(bp->uc_table)); + memset(bp->mc_table, 0, sizeof(bp->mc_table)); + bp->uc_count = 0; + bp->mc_count = 0; + + /* Disable promiscuous filter settings */ + + bp->ind_group_prom = PI_FSTATE_K_BLOCK; + bp->group_prom = PI_FSTATE_K_BLOCK; + + spin_lock_init(&bp->lock); + + /* Reset and initialize adapter */ + + bp->reset_type = PI_PDATA_A_RESET_M_SKIP_ST; /* skip self-test */ + if (dfx_adap_init(bp, 1) != DFX_K_SUCCESS) + { + printk(KERN_ERR "%s: Adapter open failed!\n", dev->name); + free_irq(dev->irq, dev); + return -EAGAIN; + } + + /* Set device structure info */ + netif_start_queue(dev); + return 0; +} + + +/* + * ============= + * = dfx_close = + * ============= + * + * Overview: + * Closes the device/module. + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This routine closes the adapter and brings it to a safe state. + * The interrupt service routine is deregistered with the OS. + * The adapter can be opened again with another call to dfx_open(). + * + * Return Codes: + * Always return 0. + * + * Assumptions: + * No further requests for this adapter are made after this routine is + * called. dfx_open() can be called to reset and reinitialize the + * adapter. + * + * Side Effects: + * Adapter should be in DMA_UNAVAILABLE state upon completion of this + * routine. + */ + +static int dfx_close(struct net_device *dev) +{ + DFX_board_t *bp = netdev_priv(dev); + + DBG_printk("In dfx_close...\n"); + + /* Disable PDQ interrupts first */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); + + /* Place adapter in DMA_UNAVAILABLE state by resetting adapter */ + + (void) dfx_hw_dma_uninit(bp, PI_PDATA_A_RESET_M_SKIP_ST); + + /* + * Flush any pending transmit buffers + * + * Note: It's important that we flush the transmit buffers + * BEFORE we clear our copy of the Type 2 register. + * Otherwise, we'll have no idea how many buffers + * we need to free. + */ + + dfx_xmt_flush(bp); + + /* + * Clear Type 1 and Type 2 registers after adapter reset + * + * Note: Even though we're closing the adapter, it's + * possible that an interrupt will occur after + * dfx_close is called. Without some assurance to + * the contrary we want to make sure that we don't + * process receive and transmit LLC frames and update + * the Type 2 register with bad information. + */ + + bp->cmd_req_reg.lword = 0; + bp->cmd_rsp_reg.lword = 0; + bp->rcv_xmt_reg.lword = 0; + + /* Clear consumer block for the same reason given above */ + + memset(bp->cons_block_virt, 0, sizeof(PI_CONSUMER_BLOCK)); + + /* Release all dynamically allocate skb in the receive ring. */ + + dfx_rcv_flush(bp); + + /* Clear device structure flags */ + + netif_stop_queue(dev); + + /* Deregister (free) IRQ */ + + free_irq(dev->irq, dev); + + return 0; +} + + +/* + * ====================== + * = dfx_int_pr_halt_id = + * ====================== + * + * Overview: + * Displays halt id's in string form. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Determine current halt id and display appropriate string. + * + * Return Codes: + * None + * + * Assumptions: + * None + * + * Side Effects: + * None + */ + +static void dfx_int_pr_halt_id(DFX_board_t *bp) + { + PI_UINT32 port_status; /* PDQ port status register value */ + PI_UINT32 halt_id; /* PDQ port status halt ID */ + + /* Read the latest port status */ + + dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status); + + /* Display halt state transition information */ + + halt_id = (port_status & PI_PSTATUS_M_HALT_ID) >> PI_PSTATUS_V_HALT_ID; + switch (halt_id) + { + case PI_HALT_ID_K_SELFTEST_TIMEOUT: + printk("%s: Halt ID: Selftest Timeout\n", bp->dev->name); + break; + + case PI_HALT_ID_K_PARITY_ERROR: + printk("%s: Halt ID: Host Bus Parity Error\n", bp->dev->name); + break; + + case PI_HALT_ID_K_HOST_DIR_HALT: + printk("%s: Halt ID: Host-Directed Halt\n", bp->dev->name); + break; + + case PI_HALT_ID_K_SW_FAULT: + printk("%s: Halt ID: Adapter Software Fault\n", bp->dev->name); + break; + + case PI_HALT_ID_K_HW_FAULT: + printk("%s: Halt ID: Adapter Hardware Fault\n", bp->dev->name); + break; + + case PI_HALT_ID_K_PC_TRACE: + printk("%s: Halt ID: FDDI Network PC Trace Path Test\n", bp->dev->name); + break; + + case PI_HALT_ID_K_DMA_ERROR: + printk("%s: Halt ID: Adapter DMA Error\n", bp->dev->name); + break; + + case PI_HALT_ID_K_IMAGE_CRC_ERROR: + printk("%s: Halt ID: Firmware Image CRC Error\n", bp->dev->name); + break; + + case PI_HALT_ID_K_BUS_EXCEPTION: + printk("%s: Halt ID: 68000 Bus Exception\n", bp->dev->name); + break; + + default: + printk("%s: Halt ID: Unknown (code = %X)\n", bp->dev->name, halt_id); + break; + } + } + + +/* + * ========================== + * = dfx_int_type_0_process = + * ========================== + * + * Overview: + * Processes Type 0 interrupts. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Processes all enabled Type 0 interrupts. If the reason for the interrupt + * is a serious fault on the adapter, then an error message is displayed + * and the adapter is reset. + * + * One tricky potential timing window is the rapid succession of "link avail" + * "link unavail" state change interrupts. The acknowledgement of the Type 0 + * interrupt must be done before reading the state from the Port Status + * register. This is true because a state change could occur after reading + * the data, but before acknowledging the interrupt. If this state change + * does happen, it would be lost because the driver is using the old state, + * and it will never know about the new state because it subsequently + * acknowledges the state change interrupt. + * + * INCORRECT CORRECT + * read type 0 int reasons read type 0 int reasons + * read adapter state ack type 0 interrupts + * ack type 0 interrupts read adapter state + * ... process interrupt ... ... process interrupt ... + * + * Return Codes: + * None + * + * Assumptions: + * None + * + * Side Effects: + * An adapter reset may occur if the adapter has any Type 0 error interrupts + * or if the port status indicates that the adapter is halted. The driver + * is responsible for reinitializing the adapter with the current CAM + * contents and adapter filter settings. + */ + +static void dfx_int_type_0_process(DFX_board_t *bp) + + { + PI_UINT32 type_0_status; /* Host Interrupt Type 0 register */ + PI_UINT32 state; /* current adap state (from port status) */ + + /* + * Read host interrupt Type 0 register to determine which Type 0 + * interrupts are pending. Immediately write it back out to clear + * those interrupts. + */ + + dfx_port_read_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, &type_0_status); + dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, type_0_status); + + /* Check for Type 0 error interrupts */ + + if (type_0_status & (PI_TYPE_0_STAT_M_NXM | + PI_TYPE_0_STAT_M_PM_PAR_ERR | + PI_TYPE_0_STAT_M_BUS_PAR_ERR)) + { + /* Check for Non-Existent Memory error */ + + if (type_0_status & PI_TYPE_0_STAT_M_NXM) + printk("%s: Non-Existent Memory Access Error\n", bp->dev->name); + + /* Check for Packet Memory Parity error */ + + if (type_0_status & PI_TYPE_0_STAT_M_PM_PAR_ERR) + printk("%s: Packet Memory Parity Error\n", bp->dev->name); + + /* Check for Host Bus Parity error */ + + if (type_0_status & PI_TYPE_0_STAT_M_BUS_PAR_ERR) + printk("%s: Host Bus Parity Error\n", bp->dev->name); + + /* Reset adapter and bring it back on-line */ + + bp->link_available = PI_K_FALSE; /* link is no longer available */ + bp->reset_type = 0; /* rerun on-board diagnostics */ + printk("%s: Resetting adapter...\n", bp->dev->name); + if (dfx_adap_init(bp, 0) != DFX_K_SUCCESS) + { + printk("%s: Adapter reset failed! Disabling adapter interrupts.\n", bp->dev->name); + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); + return; + } + printk("%s: Adapter reset successful!\n", bp->dev->name); + return; + } + + /* Check for transmit flush interrupt */ + + if (type_0_status & PI_TYPE_0_STAT_M_XMT_FLUSH) + { + /* Flush any pending xmt's and acknowledge the flush interrupt */ + + bp->link_available = PI_K_FALSE; /* link is no longer available */ + dfx_xmt_flush(bp); /* flush any outstanding packets */ + (void) dfx_hw_port_ctrl_req(bp, + PI_PCTRL_M_XMT_DATA_FLUSH_DONE, + 0, + 0, + NULL); + } + + /* Check for adapter state change */ + + if (type_0_status & PI_TYPE_0_STAT_M_STATE_CHANGE) + { + /* Get latest adapter state */ + + state = dfx_hw_adap_state_rd(bp); /* get adapter state */ + if (state == PI_STATE_K_HALTED) + { + /* + * Adapter has transitioned to HALTED state, try to reset + * adapter to bring it back on-line. If reset fails, + * leave the adapter in the broken state. + */ + + printk("%s: Controller has transitioned to HALTED state!\n", bp->dev->name); + dfx_int_pr_halt_id(bp); /* display halt id as string */ + + /* Reset adapter and bring it back on-line */ + + bp->link_available = PI_K_FALSE; /* link is no longer available */ + bp->reset_type = 0; /* rerun on-board diagnostics */ + printk("%s: Resetting adapter...\n", bp->dev->name); + if (dfx_adap_init(bp, 0) != DFX_K_SUCCESS) + { + printk("%s: Adapter reset failed! Disabling adapter interrupts.\n", bp->dev->name); + dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); + return; + } + printk("%s: Adapter reset successful!\n", bp->dev->name); + } + else if (state == PI_STATE_K_LINK_AVAIL) + { + bp->link_available = PI_K_TRUE; /* set link available flag */ + } + } + } + + +/* + * ================== + * = dfx_int_common = + * ================== + * + * Overview: + * Interrupt service routine (ISR) + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * This is the ISR which processes incoming adapter interrupts. + * + * Return Codes: + * None + * + * Assumptions: + * This routine assumes PDQ interrupts have not been disabled. + * When interrupts are disabled at the PDQ, the Port Status register + * is automatically cleared. This routine uses the Port Status + * register value to determine whether a Type 0 interrupt occurred, + * so it's important that adapter interrupts are not normally + * enabled/disabled at the PDQ. + * + * It's vital that this routine is NOT reentered for the + * same board and that the OS is not in another section of + * code (eg. dfx_xmt_queue_pkt) for the same board on a + * different thread. + * + * Side Effects: + * Pending interrupts are serviced. Depending on the type of + * interrupt, acknowledging and clearing the interrupt at the + * PDQ involves writing a register to clear the interrupt bit + * or updating completion indices. + */ + +static void dfx_int_common(struct net_device *dev) +{ + DFX_board_t *bp = netdev_priv(dev); + PI_UINT32 port_status; /* Port Status register */ + + /* Process xmt interrupts - frequent case, so always call this routine */ + + if(dfx_xmt_done(bp)) /* free consumed xmt packets */ + netif_wake_queue(dev); + + /* Process rcv interrupts - frequent case, so always call this routine */ + + dfx_rcv_queue_process(bp); /* service received LLC frames */ + + /* + * Transmit and receive producer and completion indices are updated on the + * adapter by writing to the Type 2 Producer register. Since the frequent + * case is that we'll be processing either LLC transmit or receive buffers, + * we'll optimize I/O writes by doing a single register write here. + */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); + + /* Read PDQ Port Status register to find out which interrupts need processing */ + + dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status); + + /* Process Type 0 interrupts (if any) - infrequent, so only call when needed */ + + if (port_status & PI_PSTATUS_M_TYPE_0_PENDING) + dfx_int_type_0_process(bp); /* process Type 0 interrupts */ + } + + +/* + * ================= + * = dfx_interrupt = + * ================= + * + * Overview: + * Interrupt processing routine + * + * Returns: + * Whether a valid interrupt was seen. + * + * Arguments: + * irq - interrupt vector + * dev_id - pointer to device information + * + * Functional Description: + * This routine calls the interrupt processing routine for this adapter. It + * disables and reenables adapter interrupts, as appropriate. We can support + * shared interrupts since the incoming dev_id pointer provides our device + * structure context. + * + * Return Codes: + * IRQ_HANDLED - an IRQ was handled. + * IRQ_NONE - no IRQ was handled. + * + * Assumptions: + * The interrupt acknowledgement at the hardware level (eg. ACKing the PIC + * on Intel-based systems) is done by the operating system outside this + * routine. + * + * System interrupts are enabled through this call. + * + * Side Effects: + * Interrupts are disabled, then reenabled at the adapter. + */ + +static irqreturn_t dfx_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + DFX_board_t *bp = netdev_priv(dev); + struct device *bdev = bp->bus_dev; + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + + /* Service adapter interrupts */ + + if (dfx_bus_pci) { + u32 status; + + dfx_port_read_long(bp, PFI_K_REG_STATUS, &status); + if (!(status & PFI_STATUS_M_PDQ_INT)) + return IRQ_NONE; + + spin_lock(&bp->lock); + + /* Disable PDQ-PFI interrupts at PFI */ + dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, + PFI_MODE_M_DMA_ENB); + + /* Call interrupt service routine for this adapter */ + dfx_int_common(dev); + + /* Clear PDQ interrupt status bit and reenable interrupts */ + dfx_port_write_long(bp, PFI_K_REG_STATUS, + PFI_STATUS_M_PDQ_INT); + dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, + (PFI_MODE_M_PDQ_INT_ENB | + PFI_MODE_M_DMA_ENB)); + + spin_unlock(&bp->lock); + } + if (dfx_bus_eisa) { + unsigned long base_addr = to_eisa_device(bdev)->base_addr; + u8 status; + + status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); + if (!(status & PI_CONFIG_STAT_0_M_PEND)) + return IRQ_NONE; + + spin_lock(&bp->lock); + + /* Disable interrupts at the ESIC */ + status &= ~PI_CONFIG_STAT_0_M_INT_ENB; + outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status); + + /* Call interrupt service routine for this adapter */ + dfx_int_common(dev); + + /* Reenable interrupts at the ESIC */ + status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); + status |= PI_CONFIG_STAT_0_M_INT_ENB; + outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status); + + spin_unlock(&bp->lock); + } + if (dfx_bus_tc) { + u32 status; + + dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &status); + if (!(status & (PI_PSTATUS_M_RCV_DATA_PENDING | + PI_PSTATUS_M_XMT_DATA_PENDING | + PI_PSTATUS_M_SMT_HOST_PENDING | + PI_PSTATUS_M_UNSOL_PENDING | + PI_PSTATUS_M_CMD_RSP_PENDING | + PI_PSTATUS_M_CMD_REQ_PENDING | + PI_PSTATUS_M_TYPE_0_PENDING))) + return IRQ_NONE; + + spin_lock(&bp->lock); + + /* Call interrupt service routine for this adapter */ + dfx_int_common(dev); + + spin_unlock(&bp->lock); + } + + return IRQ_HANDLED; +} + + +/* + * ===================== + * = dfx_ctl_get_stats = + * ===================== + * + * Overview: + * Get statistics for FDDI adapter + * + * Returns: + * Pointer to FDDI statistics structure + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * Gets current MIB objects from adapter, then + * returns FDDI statistics structure as defined + * in if_fddi.h. + * + * Note: Since the FDDI statistics structure is + * still new and the device structure doesn't + * have an FDDI-specific get statistics handler, + * we'll return the FDDI statistics structure as + * a pointer to an Ethernet statistics structure. + * That way, at least the first part of the statistics + * structure can be decoded properly, and it allows + * "smart" applications to perform a second cast to + * decode the FDDI-specific statistics. + * + * We'll have to pay attention to this routine as the + * device structure becomes more mature and LAN media + * independent. + * + * Return Codes: + * None + * + * Assumptions: + * None + * + * Side Effects: + * None + */ + +static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev) + { + DFX_board_t *bp = netdev_priv(dev); + + /* Fill the bp->stats structure with driver-maintained counters */ + + bp->stats.gen.rx_packets = bp->rcv_total_frames; + bp->stats.gen.tx_packets = bp->xmt_total_frames; + bp->stats.gen.rx_bytes = bp->rcv_total_bytes; + bp->stats.gen.tx_bytes = bp->xmt_total_bytes; + bp->stats.gen.rx_errors = bp->rcv_crc_errors + + bp->rcv_frame_status_errors + + bp->rcv_length_errors; + bp->stats.gen.tx_errors = bp->xmt_length_errors; + bp->stats.gen.rx_dropped = bp->rcv_discards; + bp->stats.gen.tx_dropped = bp->xmt_discards; + bp->stats.gen.multicast = bp->rcv_multicast_frames; + bp->stats.gen.collisions = 0; /* always zero (0) for FDDI */ + + /* Get FDDI SMT MIB objects */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_SMT_MIB_GET; + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + return (struct net_device_stats *)&bp->stats; + + /* Fill the bp->stats structure with the SMT MIB object values */ + + memcpy(bp->stats.smt_station_id, &bp->cmd_rsp_virt->smt_mib_get.smt_station_id, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_station_id)); + bp->stats.smt_op_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_op_version_id; + bp->stats.smt_hi_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_hi_version_id; + bp->stats.smt_lo_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_lo_version_id; + memcpy(bp->stats.smt_user_data, &bp->cmd_rsp_virt->smt_mib_get.smt_user_data, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_user_data)); + bp->stats.smt_mib_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_mib_version_id; + bp->stats.smt_mac_cts = bp->cmd_rsp_virt->smt_mib_get.smt_mac_ct; + bp->stats.smt_non_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_non_master_ct; + bp->stats.smt_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_master_ct; + bp->stats.smt_available_paths = bp->cmd_rsp_virt->smt_mib_get.smt_available_paths; + bp->stats.smt_config_capabilities = bp->cmd_rsp_virt->smt_mib_get.smt_config_capabilities; + bp->stats.smt_config_policy = bp->cmd_rsp_virt->smt_mib_get.smt_config_policy; + bp->stats.smt_connection_policy = bp->cmd_rsp_virt->smt_mib_get.smt_connection_policy; + bp->stats.smt_t_notify = bp->cmd_rsp_virt->smt_mib_get.smt_t_notify; + bp->stats.smt_stat_rpt_policy = bp->cmd_rsp_virt->smt_mib_get.smt_stat_rpt_policy; + bp->stats.smt_trace_max_expiration = bp->cmd_rsp_virt->smt_mib_get.smt_trace_max_expiration; + bp->stats.smt_bypass_present = bp->cmd_rsp_virt->smt_mib_get.smt_bypass_present; + bp->stats.smt_ecm_state = bp->cmd_rsp_virt->smt_mib_get.smt_ecm_state; + bp->stats.smt_cf_state = bp->cmd_rsp_virt->smt_mib_get.smt_cf_state; + bp->stats.smt_remote_disconnect_flag = bp->cmd_rsp_virt->smt_mib_get.smt_remote_disconnect_flag; + bp->stats.smt_station_status = bp->cmd_rsp_virt->smt_mib_get.smt_station_status; + bp->stats.smt_peer_wrap_flag = bp->cmd_rsp_virt->smt_mib_get.smt_peer_wrap_flag; + bp->stats.smt_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_msg_time_stamp.ls; + bp->stats.smt_transition_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_transition_time_stamp.ls; + bp->stats.mac_frame_status_functions = bp->cmd_rsp_virt->smt_mib_get.mac_frame_status_functions; + bp->stats.mac_t_max_capability = bp->cmd_rsp_virt->smt_mib_get.mac_t_max_capability; + bp->stats.mac_tvx_capability = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_capability; + bp->stats.mac_available_paths = bp->cmd_rsp_virt->smt_mib_get.mac_available_paths; + bp->stats.mac_current_path = bp->cmd_rsp_virt->smt_mib_get.mac_current_path; + memcpy(bp->stats.mac_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_upstream_nbr, FDDI_K_ALEN); + memcpy(bp->stats.mac_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_downstream_nbr, FDDI_K_ALEN); + memcpy(bp->stats.mac_old_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_upstream_nbr, FDDI_K_ALEN); + memcpy(bp->stats.mac_old_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_downstream_nbr, FDDI_K_ALEN); + bp->stats.mac_dup_address_test = bp->cmd_rsp_virt->smt_mib_get.mac_dup_address_test; + bp->stats.mac_requested_paths = bp->cmd_rsp_virt->smt_mib_get.mac_requested_paths; + bp->stats.mac_downstream_port_type = bp->cmd_rsp_virt->smt_mib_get.mac_downstream_port_type; + memcpy(bp->stats.mac_smt_address, &bp->cmd_rsp_virt->smt_mib_get.mac_smt_address, FDDI_K_ALEN); + bp->stats.mac_t_req = bp->cmd_rsp_virt->smt_mib_get.mac_t_req; + bp->stats.mac_t_neg = bp->cmd_rsp_virt->smt_mib_get.mac_t_neg; + bp->stats.mac_t_max = bp->cmd_rsp_virt->smt_mib_get.mac_t_max; + bp->stats.mac_tvx_value = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_value; + bp->stats.mac_frame_error_threshold = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_threshold; + bp->stats.mac_frame_error_ratio = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_ratio; + bp->stats.mac_rmt_state = bp->cmd_rsp_virt->smt_mib_get.mac_rmt_state; + bp->stats.mac_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_da_flag; + bp->stats.mac_una_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_unda_flag; + bp->stats.mac_frame_error_flag = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_flag; + bp->stats.mac_ma_unitdata_available = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_available; + bp->stats.mac_hardware_present = bp->cmd_rsp_virt->smt_mib_get.mac_hardware_present; + bp->stats.mac_ma_unitdata_enable = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_enable; + bp->stats.path_tvx_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_tvx_lower_bound; + bp->stats.path_t_max_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_t_max_lower_bound; + bp->stats.path_max_t_req = bp->cmd_rsp_virt->smt_mib_get.path_max_t_req; + memcpy(bp->stats.path_configuration, &bp->cmd_rsp_virt->smt_mib_get.path_configuration, sizeof(bp->cmd_rsp_virt->smt_mib_get.path_configuration)); + bp->stats.port_my_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[0]; + bp->stats.port_my_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[1]; + bp->stats.port_neighbor_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[0]; + bp->stats.port_neighbor_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[1]; + bp->stats.port_connection_policies[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[0]; + bp->stats.port_connection_policies[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[1]; + bp->stats.port_mac_indicated[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[0]; + bp->stats.port_mac_indicated[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[1]; + bp->stats.port_current_path[0] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[0]; + bp->stats.port_current_path[1] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[1]; + memcpy(&bp->stats.port_requested_paths[0*3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[0], 3); + memcpy(&bp->stats.port_requested_paths[1*3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[1], 3); + bp->stats.port_mac_placement[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[0]; + bp->stats.port_mac_placement[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[1]; + bp->stats.port_available_paths[0] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[0]; + bp->stats.port_available_paths[1] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[1]; + bp->stats.port_pmd_class[0] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[0]; + bp->stats.port_pmd_class[1] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[1]; + bp->stats.port_connection_capabilities[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[0]; + bp->stats.port_connection_capabilities[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[1]; + bp->stats.port_bs_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[0]; + bp->stats.port_bs_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[1]; + bp->stats.port_ler_estimate[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[0]; + bp->stats.port_ler_estimate[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[1]; + bp->stats.port_ler_cutoff[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[0]; + bp->stats.port_ler_cutoff[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[1]; + bp->stats.port_ler_alarm[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[0]; + bp->stats.port_ler_alarm[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[1]; + bp->stats.port_connect_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[0]; + bp->stats.port_connect_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[1]; + bp->stats.port_pcm_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[0]; + bp->stats.port_pcm_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[1]; + bp->stats.port_pc_withhold[0] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[0]; + bp->stats.port_pc_withhold[1] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[1]; + bp->stats.port_ler_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[0]; + bp->stats.port_ler_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[1]; + bp->stats.port_hardware_present[0] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[0]; + bp->stats.port_hardware_present[1] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[1]; + + /* Get FDDI counters */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_CNTRS_GET; + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + return (struct net_device_stats *)&bp->stats; + + /* Fill the bp->stats structure with the FDDI counter values */ + + bp->stats.mac_frame_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.frame_cnt.ls; + bp->stats.mac_copied_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.copied_cnt.ls; + bp->stats.mac_transmit_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.transmit_cnt.ls; + bp->stats.mac_error_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.error_cnt.ls; + bp->stats.mac_lost_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.lost_cnt.ls; + bp->stats.port_lct_fail_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[0].ls; + bp->stats.port_lct_fail_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[1].ls; + bp->stats.port_lem_reject_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[0].ls; + bp->stats.port_lem_reject_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[1].ls; + bp->stats.port_lem_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[0].ls; + bp->stats.port_lem_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[1].ls; + + return (struct net_device_stats *)&bp->stats; + } + + +/* + * ============================== + * = dfx_ctl_set_multicast_list = + * ============================== + * + * Overview: + * Enable/Disable LLC frame promiscuous mode reception + * on the adapter and/or update multicast address table. + * + * Returns: + * None + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This routine follows a fairly simple algorithm for setting the + * adapter filters and CAM: + * + * if IFF_PROMISC flag is set + * enable LLC individual/group promiscuous mode + * else + * disable LLC individual/group promiscuous mode + * if number of incoming multicast addresses > + * (CAM max size - number of unicast addresses in CAM) + * enable LLC group promiscuous mode + * set driver-maintained multicast address count to zero + * else + * disable LLC group promiscuous mode + * set driver-maintained multicast address count to incoming count + * update adapter CAM + * update adapter filters + * + * Return Codes: + * None + * + * Assumptions: + * Multicast addresses are presented in canonical (LSB) format. + * + * Side Effects: + * On-board adapter CAM and filters are updated. + */ + +static void dfx_ctl_set_multicast_list(struct net_device *dev) +{ + DFX_board_t *bp = netdev_priv(dev); + int i; /* used as index in for loop */ + struct netdev_hw_addr *ha; + + /* Enable LLC frame promiscuous mode, if necessary */ + + if (dev->flags & IFF_PROMISC) + bp->ind_group_prom = PI_FSTATE_K_PASS; /* Enable LLC ind/group prom mode */ + + /* Else, update multicast address table */ + + else + { + bp->ind_group_prom = PI_FSTATE_K_BLOCK; /* Disable LLC ind/group prom mode */ + /* + * Check whether incoming multicast address count exceeds table size + * + * Note: The adapters utilize an on-board 64 entry CAM for + * supporting perfect filtering of multicast packets + * and bridge functions when adding unicast addresses. + * There is no hash function available. To support + * additional multicast addresses, the all multicast + * filter (LLC group promiscuous mode) must be enabled. + * + * The firmware reserves two CAM entries for SMT-related + * multicast addresses, which leaves 62 entries available. + * The following code ensures that we're not being asked + * to add more than 62 addresses to the CAM. If we are, + * the driver will enable the all multicast filter. + * Should the number of multicast addresses drop below + * the high water mark, the filter will be disabled and + * perfect filtering will be used. + */ + + if (netdev_mc_count(dev) > (PI_CMD_ADDR_FILTER_K_SIZE - bp->uc_count)) + { + bp->group_prom = PI_FSTATE_K_PASS; /* Enable LLC group prom mode */ + bp->mc_count = 0; /* Don't add mc addrs to CAM */ + } + else + { + bp->group_prom = PI_FSTATE_K_BLOCK; /* Disable LLC group prom mode */ + bp->mc_count = netdev_mc_count(dev); /* Add mc addrs to CAM */ + } + + /* Copy addresses to multicast address table, then update adapter CAM */ + + i = 0; + netdev_for_each_mc_addr(ha, dev) + memcpy(&bp->mc_table[i++ * FDDI_K_ALEN], + ha->addr, FDDI_K_ALEN); + + if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS) + { + DBG_printk("%s: Could not update multicast address table!\n", dev->name); + } + else + { + DBG_printk("%s: Multicast address table updated! Added %d addresses.\n", dev->name, bp->mc_count); + } + } + + /* Update adapter filters */ + + if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS) + { + DBG_printk("%s: Could not update adapter filters!\n", dev->name); + } + else + { + DBG_printk("%s: Adapter filters updated!\n", dev->name); + } + } + + +/* + * =========================== + * = dfx_ctl_set_mac_address = + * =========================== + * + * Overview: + * Add node address override (unicast address) to adapter + * CAM and update dev_addr field in device table. + * + * Returns: + * None + * + * Arguments: + * dev - pointer to device information + * addr - pointer to sockaddr structure containing unicast address to add + * + * Functional Description: + * The adapter supports node address overrides by adding one or more + * unicast addresses to the adapter CAM. This is similar to adding + * multicast addresses. In this routine we'll update the driver and + * device structures with the new address, then update the adapter CAM + * to ensure that the adapter will copy and strip frames destined and + * sourced by that address. + * + * Return Codes: + * Always returns zero. + * + * Assumptions: + * The address pointed to by addr->sa_data is a valid unicast + * address and is presented in canonical (LSB) format. + * + * Side Effects: + * On-board adapter CAM is updated. On-board adapter filters + * may be updated. + */ + +static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr) + { + struct sockaddr *p_sockaddr = (struct sockaddr *)addr; + DFX_board_t *bp = netdev_priv(dev); + + /* Copy unicast address to driver-maintained structs and update count */ + + memcpy(dev->dev_addr, p_sockaddr->sa_data, FDDI_K_ALEN); /* update device struct */ + memcpy(&bp->uc_table[0], p_sockaddr->sa_data, FDDI_K_ALEN); /* update driver struct */ + bp->uc_count = 1; + + /* + * Verify we're not exceeding the CAM size by adding unicast address + * + * Note: It's possible that before entering this routine we've + * already filled the CAM with 62 multicast addresses. + * Since we need to place the node address override into + * the CAM, we have to check to see that we're not + * exceeding the CAM size. If we are, we have to enable + * the LLC group (multicast) promiscuous mode filter as + * in dfx_ctl_set_multicast_list. + */ + + if ((bp->uc_count + bp->mc_count) > PI_CMD_ADDR_FILTER_K_SIZE) + { + bp->group_prom = PI_FSTATE_K_PASS; /* Enable LLC group prom mode */ + bp->mc_count = 0; /* Don't add mc addrs to CAM */ + + /* Update adapter filters */ + + if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS) + { + DBG_printk("%s: Could not update adapter filters!\n", dev->name); + } + else + { + DBG_printk("%s: Adapter filters updated!\n", dev->name); + } + } + + /* Update adapter CAM with new unicast address */ + + if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS) + { + DBG_printk("%s: Could not set new MAC address!\n", dev->name); + } + else + { + DBG_printk("%s: Adapter CAM updated with new MAC address\n", dev->name); + } + return 0; /* always return zero */ + } + + +/* + * ====================== + * = dfx_ctl_update_cam = + * ====================== + * + * Overview: + * Procedure to update adapter CAM (Content Addressable Memory) + * with desired unicast and multicast address entries. + * + * Returns: + * Condition code + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Updates adapter CAM with current contents of board structure + * unicast and multicast address tables. Since there are only 62 + * free entries in CAM, this routine ensures that the command + * request buffer is not overrun. + * + * Return Codes: + * DFX_K_SUCCESS - Request succeeded + * DFX_K_FAILURE - Request failed + * + * Assumptions: + * All addresses being added (unicast and multicast) are in canonical + * order. + * + * Side Effects: + * On-board adapter CAM is updated. + */ + +static int dfx_ctl_update_cam(DFX_board_t *bp) + { + int i; /* used as index */ + PI_LAN_ADDR *p_addr; /* pointer to CAM entry */ + + /* + * Fill in command request information + * + * Note: Even though both the unicast and multicast address + * table entries are stored as contiguous 6 byte entries, + * the firmware address filter set command expects each + * entry to be two longwords (8 bytes total). We must be + * careful to only copy the six bytes of each unicast and + * multicast table entry into each command entry. This + * is also why we must first clear the entire command + * request buffer. + */ + + memset(bp->cmd_req_virt, 0, PI_CMD_REQ_K_SIZE_MAX); /* first clear buffer */ + bp->cmd_req_virt->cmd_type = PI_CMD_K_ADDR_FILTER_SET; + p_addr = &bp->cmd_req_virt->addr_filter_set.entry[0]; + + /* Now add unicast addresses to command request buffer, if any */ + + for (i=0; i < (int)bp->uc_count; i++) + { + if (i < PI_CMD_ADDR_FILTER_K_SIZE) + { + memcpy(p_addr, &bp->uc_table[i*FDDI_K_ALEN], FDDI_K_ALEN); + p_addr++; /* point to next command entry */ + } + } + + /* Now add multicast addresses to command request buffer, if any */ + + for (i=0; i < (int)bp->mc_count; i++) + { + if ((i + bp->uc_count) < PI_CMD_ADDR_FILTER_K_SIZE) + { + memcpy(p_addr, &bp->mc_table[i*FDDI_K_ALEN], FDDI_K_ALEN); + p_addr++; /* point to next command entry */ + } + } + + /* Issue command to update adapter CAM, then return */ + + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + return DFX_K_FAILURE; + return DFX_K_SUCCESS; + } + + +/* + * ========================== + * = dfx_ctl_update_filters = + * ========================== + * + * Overview: + * Procedure to update adapter filters with desired + * filter settings. + * + * Returns: + * Condition code + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Enables or disables filter using current filter settings. + * + * Return Codes: + * DFX_K_SUCCESS - Request succeeded. + * DFX_K_FAILURE - Request failed. + * + * Assumptions: + * We must always pass up packets destined to the broadcast + * address (FF-FF-FF-FF-FF-FF), so we'll always keep the + * broadcast filter enabled. + * + * Side Effects: + * On-board adapter filters are updated. + */ + +static int dfx_ctl_update_filters(DFX_board_t *bp) + { + int i = 0; /* used as index */ + + /* Fill in command request information */ + + bp->cmd_req_virt->cmd_type = PI_CMD_K_FILTERS_SET; + + /* Initialize Broadcast filter - * ALWAYS ENABLED * */ + + bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_BROADCAST; + bp->cmd_req_virt->filter_set.item[i++].value = PI_FSTATE_K_PASS; + + /* Initialize LLC Individual/Group Promiscuous filter */ + + bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_IND_GROUP_PROM; + bp->cmd_req_virt->filter_set.item[i++].value = bp->ind_group_prom; + + /* Initialize LLC Group Promiscuous filter */ + + bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_GROUP_PROM; + bp->cmd_req_virt->filter_set.item[i++].value = bp->group_prom; + + /* Terminate the item code list */ + + bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_EOL; + + /* Issue command to update adapter filters, then return */ + + if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) + return DFX_K_FAILURE; + return DFX_K_SUCCESS; + } + + +/* + * ====================== + * = dfx_hw_dma_cmd_req = + * ====================== + * + * Overview: + * Sends PDQ DMA command to adapter firmware + * + * Returns: + * Condition code + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * The command request and response buffers are posted to the adapter in the manner + * described in the PDQ Port Specification: + * + * 1. Command Response Buffer is posted to adapter. + * 2. Command Request Buffer is posted to adapter. + * 3. Command Request consumer index is polled until it indicates that request + * buffer has been DMA'd to adapter. + * 4. Command Response consumer index is polled until it indicates that response + * buffer has been DMA'd from adapter. + * + * This ordering ensures that a response buffer is already available for the firmware + * to use once it's done processing the request buffer. + * + * Return Codes: + * DFX_K_SUCCESS - DMA command succeeded + * DFX_K_OUTSTATE - Adapter is NOT in proper state + * DFX_K_HW_TIMEOUT - DMA command timed out + * + * Assumptions: + * Command request buffer has already been filled with desired DMA command. + * + * Side Effects: + * None + */ + +static int dfx_hw_dma_cmd_req(DFX_board_t *bp) + { + int status; /* adapter status */ + int timeout_cnt; /* used in for loops */ + + /* Make sure the adapter is in a state that we can issue the DMA command in */ + + status = dfx_hw_adap_state_rd(bp); + if ((status == PI_STATE_K_RESET) || + (status == PI_STATE_K_HALTED) || + (status == PI_STATE_K_DMA_UNAVAIL) || + (status == PI_STATE_K_UPGRADE)) + return DFX_K_OUTSTATE; + + /* Put response buffer on the command response queue */ + + bp->descr_block_virt->cmd_rsp[bp->cmd_rsp_reg.index.prod].long_0 = (u32) (PI_RCV_DESCR_M_SOP | + ((PI_CMD_RSP_K_SIZE_MAX / PI_ALIGN_K_CMD_RSP_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); + bp->descr_block_virt->cmd_rsp[bp->cmd_rsp_reg.index.prod].long_1 = bp->cmd_rsp_phys; + + /* Bump (and wrap) the producer index and write out to register */ + + bp->cmd_rsp_reg.index.prod += 1; + bp->cmd_rsp_reg.index.prod &= PI_CMD_RSP_K_NUM_ENTRIES-1; + dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_RSP_PROD, bp->cmd_rsp_reg.lword); + + /* Put request buffer on the command request queue */ + + bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_0 = (u32) (PI_XMT_DESCR_M_SOP | + PI_XMT_DESCR_M_EOP | (PI_CMD_REQ_K_SIZE_MAX << PI_XMT_DESCR_V_SEG_LEN)); + bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_1 = bp->cmd_req_phys; + + /* Bump (and wrap) the producer index and write out to register */ + + bp->cmd_req_reg.index.prod += 1; + bp->cmd_req_reg.index.prod &= PI_CMD_REQ_K_NUM_ENTRIES-1; + dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_REQ_PROD, bp->cmd_req_reg.lword); + + /* + * Here we wait for the command request consumer index to be equal + * to the producer, indicating that the adapter has DMAed the request. + */ + + for (timeout_cnt = 20000; timeout_cnt > 0; timeout_cnt--) + { + if (bp->cmd_req_reg.index.prod == (u8)(bp->cons_block_virt->cmd_req)) + break; + udelay(100); /* wait for 100 microseconds */ + } + if (timeout_cnt == 0) + return DFX_K_HW_TIMEOUT; + + /* Bump (and wrap) the completion index and write out to register */ + + bp->cmd_req_reg.index.comp += 1; + bp->cmd_req_reg.index.comp &= PI_CMD_REQ_K_NUM_ENTRIES-1; + dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_REQ_PROD, bp->cmd_req_reg.lword); + + /* + * Here we wait for the command response consumer index to be equal + * to the producer, indicating that the adapter has DMAed the response. + */ + + for (timeout_cnt = 20000; timeout_cnt > 0; timeout_cnt--) + { + if (bp->cmd_rsp_reg.index.prod == (u8)(bp->cons_block_virt->cmd_rsp)) + break; + udelay(100); /* wait for 100 microseconds */ + } + if (timeout_cnt == 0) + return DFX_K_HW_TIMEOUT; + + /* Bump (and wrap) the completion index and write out to register */ + + bp->cmd_rsp_reg.index.comp += 1; + bp->cmd_rsp_reg.index.comp &= PI_CMD_RSP_K_NUM_ENTRIES-1; + dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_RSP_PROD, bp->cmd_rsp_reg.lword); + return DFX_K_SUCCESS; + } + + +/* + * ======================== + * = dfx_hw_port_ctrl_req = + * ======================== + * + * Overview: + * Sends PDQ port control command to adapter firmware + * + * Returns: + * Host data register value in host_data if ptr is not NULL + * + * Arguments: + * bp - pointer to board information + * command - port control command + * data_a - port data A register value + * data_b - port data B register value + * host_data - ptr to host data register value + * + * Functional Description: + * Send generic port control command to adapter by writing + * to various PDQ port registers, then polling for completion. + * + * Return Codes: + * DFX_K_SUCCESS - port control command succeeded + * DFX_K_HW_TIMEOUT - port control command timed out + * + * Assumptions: + * None + * + * Side Effects: + * None + */ + +static int dfx_hw_port_ctrl_req( + DFX_board_t *bp, + PI_UINT32 command, + PI_UINT32 data_a, + PI_UINT32 data_b, + PI_UINT32 *host_data + ) + + { + PI_UINT32 port_cmd; /* Port Control command register value */ + int timeout_cnt; /* used in for loops */ + + /* Set Command Error bit in command longword */ + + port_cmd = (PI_UINT32) (command | PI_PCTRL_M_CMD_ERROR); + + /* Issue port command to the adapter */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_A, data_a); + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_B, data_b); + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_CTRL, port_cmd); + + /* Now wait for command to complete */ + + if (command == PI_PCTRL_M_BLAST_FLASH) + timeout_cnt = 600000; /* set command timeout count to 60 seconds */ + else + timeout_cnt = 20000; /* set command timeout count to 2 seconds */ + + for (; timeout_cnt > 0; timeout_cnt--) + { + dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_CTRL, &port_cmd); + if (!(port_cmd & PI_PCTRL_M_CMD_ERROR)) + break; + udelay(100); /* wait for 100 microseconds */ + } + if (timeout_cnt == 0) + return DFX_K_HW_TIMEOUT; + + /* + * If the address of host_data is non-zero, assume caller has supplied a + * non NULL pointer, and return the contents of the HOST_DATA register in + * it. + */ + + if (host_data != NULL) + dfx_port_read_long(bp, PI_PDQ_K_REG_HOST_DATA, host_data); + return DFX_K_SUCCESS; + } + + +/* + * ===================== + * = dfx_hw_adap_reset = + * ===================== + * + * Overview: + * Resets adapter + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * type - type of reset to perform + * + * Functional Description: + * Issue soft reset to adapter by writing to PDQ Port Reset + * register. Use incoming reset type to tell adapter what + * kind of reset operation to perform. + * + * Return Codes: + * None + * + * Assumptions: + * This routine merely issues a soft reset to the adapter. + * It is expected that after this routine returns, the caller + * will appropriately poll the Port Status register for the + * adapter to enter the proper state. + * + * Side Effects: + * Internal adapter registers are cleared. + */ + +static void dfx_hw_adap_reset( + DFX_board_t *bp, + PI_UINT32 type + ) + + { + /* Set Reset type and assert reset */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_A, type); /* tell adapter type of reset */ + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, PI_RESET_M_ASSERT_RESET); + + /* Wait for at least 1 Microsecond according to the spec. We wait 20 just to be safe */ + + udelay(20); + + /* Deassert reset */ + + dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, 0); + } + + +/* + * ======================== + * = dfx_hw_adap_state_rd = + * ======================== + * + * Overview: + * Returns current adapter state + * + * Returns: + * Adapter state per PDQ Port Specification + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Reads PDQ Port Status register and returns adapter state. + * + * Return Codes: + * None + * + * Assumptions: + * None + * + * Side Effects: + * None + */ + +static int dfx_hw_adap_state_rd(DFX_board_t *bp) + { + PI_UINT32 port_status; /* Port Status register value */ + + dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status); + return (port_status & PI_PSTATUS_M_STATE) >> PI_PSTATUS_V_STATE; + } + + +/* + * ===================== + * = dfx_hw_dma_uninit = + * ===================== + * + * Overview: + * Brings adapter to DMA_UNAVAILABLE state + * + * Returns: + * Condition code + * + * Arguments: + * bp - pointer to board information + * type - type of reset to perform + * + * Functional Description: + * Bring adapter to DMA_UNAVAILABLE state by performing the following: + * 1. Set reset type bit in Port Data A Register then reset adapter. + * 2. Check that adapter is in DMA_UNAVAILABLE state. + * + * Return Codes: + * DFX_K_SUCCESS - adapter is in DMA_UNAVAILABLE state + * DFX_K_HW_TIMEOUT - adapter did not reset properly + * + * Assumptions: + * None + * + * Side Effects: + * Internal adapter registers are cleared. + */ + +static int dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type) + { + int timeout_cnt; /* used in for loops */ + + /* Set reset type bit and reset adapter */ + + dfx_hw_adap_reset(bp, type); + + /* Now wait for adapter to enter DMA_UNAVAILABLE state */ + + for (timeout_cnt = 100000; timeout_cnt > 0; timeout_cnt--) + { + if (dfx_hw_adap_state_rd(bp) == PI_STATE_K_DMA_UNAVAIL) + break; + udelay(100); /* wait for 100 microseconds */ + } + if (timeout_cnt == 0) + return DFX_K_HW_TIMEOUT; + return DFX_K_SUCCESS; + } + +/* + * Align an sk_buff to a boundary power of 2 + * + */ + +static void my_skb_align(struct sk_buff *skb, int n) +{ + unsigned long x = (unsigned long)skb->data; + unsigned long v; + + v = ALIGN(x, n); /* Where we want to be */ + + skb_reserve(skb, v - x); +} + + +/* + * ================ + * = dfx_rcv_init = + * ================ + * + * Overview: + * Produces buffers to adapter LLC Host receive descriptor block + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * get_buffers - non-zero if buffers to be allocated + * + * Functional Description: + * This routine can be called during dfx_adap_init() or during an adapter + * reset. It initializes the descriptor block and produces all allocated + * LLC Host queue receive buffers. + * + * Return Codes: + * Return 0 on success or -ENOMEM if buffer allocation failed (when using + * dynamic buffer allocation). If the buffer allocation failed, the + * already allocated buffers will not be released and the caller should do + * this. + * + * Assumptions: + * The PDQ has been reset and the adapter and driver maintained Type 2 + * register indices are cleared. + * + * Side Effects: + * Receive buffers are posted to the adapter LLC queue and the adapter + * is notified. + */ + +static int dfx_rcv_init(DFX_board_t *bp, int get_buffers) + { + int i, j; /* used in for loop */ + + /* + * Since each receive buffer is a single fragment of same length, initialize + * first longword in each receive descriptor for entire LLC Host descriptor + * block. Also initialize second longword in each receive descriptor with + * physical address of receive buffer. We'll always allocate receive + * buffers in powers of 2 so that we can easily fill the 256 entry descriptor + * block and produce new receive buffers by simply updating the receive + * producer index. + * + * Assumptions: + * To support all shipping versions of PDQ, the receive buffer size + * must be mod 128 in length and the physical address must be 128 byte + * aligned. In other words, bits 0-6 of the length and address must + * be zero for the following descriptor field entries to be correct on + * all PDQ-based boards. We guaranteed both requirements during + * driver initialization when we allocated memory for the receive buffers. + */ + + if (get_buffers) { +#ifdef DYNAMIC_BUFFERS + for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++) + for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) + { + struct sk_buff *newskb = __netdev_alloc_skb(bp->dev, NEW_SKB_SIZE, GFP_NOIO); + if (!newskb) + return -ENOMEM; + bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP | + ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); + /* + * align to 128 bytes for compatibility with + * the old EISA boards. + */ + + my_skb_align(newskb, 128); + bp->descr_block_virt->rcv_data[i + j].long_1 = + (u32)dma_map_single(bp->bus_dev, newskb->data, + NEW_SKB_SIZE, + DMA_FROM_DEVICE); + /* + * p_rcv_buff_va is only used inside the + * kernel so we put the skb pointer here. + */ + bp->p_rcv_buff_va[i+j] = (char *) newskb; + } +#else + for (i=0; i < (int)(bp->rcv_bufs_to_post); i++) + for (j=0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) + { + bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP | + ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); + bp->descr_block_virt->rcv_data[i+j].long_1 = (u32) (bp->rcv_block_phys + (i * PI_RCV_DATA_K_SIZE_MAX)); + bp->p_rcv_buff_va[i+j] = (char *) (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX)); + } +#endif + } + + /* Update receive producer and Type 2 register */ + + bp->rcv_xmt_reg.index.rcv_prod = bp->rcv_bufs_to_post; + dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); + return 0; + } + + +/* + * ========================= + * = dfx_rcv_queue_process = + * ========================= + * + * Overview: + * Process received LLC frames. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Received LLC frames are processed until there are no more consumed frames. + * Once all frames are processed, the receive buffers are returned to the + * adapter. Note that this algorithm fixes the length of time that can be spent + * in this routine, because there are a fixed number of receive buffers to + * process and buffers are not produced until this routine exits and returns + * to the ISR. + * + * Return Codes: + * None + * + * Assumptions: + * None + * + * Side Effects: + * None + */ + +static void dfx_rcv_queue_process( + DFX_board_t *bp + ) + + { + PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */ + char *p_buff; /* ptr to start of packet receive buffer (FMC descriptor) */ + u32 descr, pkt_len; /* FMC descriptor field and packet length */ + struct sk_buff *skb; /* pointer to a sk_buff to hold incoming packet data */ + + /* Service all consumed LLC receive frames */ + + p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data); + while (bp->rcv_xmt_reg.index.rcv_comp != p_type_2_cons->index.rcv_cons) + { + /* Process any errors */ + + int entry; + + entry = bp->rcv_xmt_reg.index.rcv_comp; +#ifdef DYNAMIC_BUFFERS + p_buff = (char *) (((struct sk_buff *)bp->p_rcv_buff_va[entry])->data); +#else + p_buff = (char *) bp->p_rcv_buff_va[entry]; +#endif + memcpy(&descr, p_buff + RCV_BUFF_K_DESCR, sizeof(u32)); + + if (descr & PI_FMC_DESCR_M_RCC_FLUSH) + { + if (descr & PI_FMC_DESCR_M_RCC_CRC) + bp->rcv_crc_errors++; + else + bp->rcv_frame_status_errors++; + } + else + { + int rx_in_place = 0; + + /* The frame was received without errors - verify packet length */ + + pkt_len = (u32)((descr & PI_FMC_DESCR_M_LEN) >> PI_FMC_DESCR_V_LEN); + pkt_len -= 4; /* subtract 4 byte CRC */ + if (!IN_RANGE(pkt_len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN)) + bp->rcv_length_errors++; + else{ +#ifdef DYNAMIC_BUFFERS + if (pkt_len > SKBUFF_RX_COPYBREAK) { + struct sk_buff *newskb; + + newskb = dev_alloc_skb(NEW_SKB_SIZE); + if (newskb){ + rx_in_place = 1; + + my_skb_align(newskb, 128); + skb = (struct sk_buff *)bp->p_rcv_buff_va[entry]; + dma_unmap_single(bp->bus_dev, + bp->descr_block_virt->rcv_data[entry].long_1, + NEW_SKB_SIZE, + DMA_FROM_DEVICE); + skb_reserve(skb, RCV_BUFF_K_PADDING); + bp->p_rcv_buff_va[entry] = (char *)newskb; + bp->descr_block_virt->rcv_data[entry].long_1 = + (u32)dma_map_single(bp->bus_dev, + newskb->data, + NEW_SKB_SIZE, + DMA_FROM_DEVICE); + } else + skb = NULL; + } else +#endif + skb = dev_alloc_skb(pkt_len+3); /* alloc new buffer to pass up, add room for PRH */ + if (skb == NULL) + { + printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); + bp->rcv_discards++; + break; + } + else { +#ifndef DYNAMIC_BUFFERS + if (! rx_in_place) +#endif + { + /* Receive buffer allocated, pass receive packet up */ + + skb_copy_to_linear_data(skb, + p_buff + RCV_BUFF_K_PADDING, + pkt_len + 3); + } + + skb_reserve(skb,3); /* adjust data field so that it points to FC byte */ + skb_put(skb, pkt_len); /* pass up packet length, NOT including CRC */ + skb->protocol = fddi_type_trans(skb, bp->dev); + bp->rcv_total_bytes += skb->len; + netif_rx(skb); + + /* Update the rcv counters */ + bp->rcv_total_frames++; + if (*(p_buff + RCV_BUFF_K_DA) & 0x01) + bp->rcv_multicast_frames++; + } + } + } + + /* + * Advance the producer (for recycling) and advance the completion + * (for servicing received frames). Note that it is okay to + * advance the producer without checking that it passes the + * completion index because they are both advanced at the same + * rate. + */ + + bp->rcv_xmt_reg.index.rcv_prod += 1; + bp->rcv_xmt_reg.index.rcv_comp += 1; + } + } + + +/* + * ===================== + * = dfx_xmt_queue_pkt = + * ===================== + * + * Overview: + * Queues packets for transmission + * + * Returns: + * Condition code + * + * Arguments: + * skb - pointer to sk_buff to queue for transmission + * dev - pointer to device information + * + * Functional Description: + * Here we assume that an incoming skb transmit request + * is contained in a single physically contiguous buffer + * in which the virtual address of the start of packet + * (skb->data) can be converted to a physical address + * by using pci_map_single(). + * + * Since the adapter architecture requires a three byte + * packet request header to prepend the start of packet, + * we'll write the three byte field immediately prior to + * the FC byte. This assumption is valid because we've + * ensured that dev->hard_header_len includes three pad + * bytes. By posting a single fragment to the adapter, + * we'll reduce the number of descriptor fetches and + * bus traffic needed to send the request. + * + * Also, we can't free the skb until after it's been DMA'd + * out by the adapter, so we'll queue it in the driver and + * return it in dfx_xmt_done. + * + * Return Codes: + * 0 - driver queued packet, link is unavailable, or skbuff was bad + * 1 - caller should requeue the sk_buff for later transmission + * + * Assumptions: + * First and foremost, we assume the incoming skb pointer + * is NOT NULL and is pointing to a valid sk_buff structure. + * + * The outgoing packet is complete, starting with the + * frame control byte including the last byte of data, + * but NOT including the 4 byte CRC. We'll let the + * adapter hardware generate and append the CRC. + * + * The entire packet is stored in one physically + * contiguous buffer which is not cached and whose + * 32-bit physical address can be determined. + * + * It's vital that this routine is NOT reentered for the + * same board and that the OS is not in another section of + * code (eg. dfx_int_common) for the same board on a + * different thread. + * + * Side Effects: + * None + */ + +static netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, + struct net_device *dev) + { + DFX_board_t *bp = netdev_priv(dev); + u8 prod; /* local transmit producer index */ + PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */ + XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ + unsigned long flags; + + netif_stop_queue(dev); + + /* + * Verify that incoming transmit request is OK + * + * Note: The packet size check is consistent with other + * Linux device drivers, although the correct packet + * size should be verified before calling the + * transmit routine. + */ + + if (!IN_RANGE(skb->len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN)) + { + printk("%s: Invalid packet length - %u bytes\n", + dev->name, skb->len); + bp->xmt_length_errors++; /* bump error counter */ + netif_wake_queue(dev); + dev_kfree_skb(skb); + return NETDEV_TX_OK; /* return "success" */ + } + /* + * See if adapter link is available, if not, free buffer + * + * Note: If the link isn't available, free buffer and return 0 + * rather than tell the upper layer to requeue the packet. + * The methodology here is that by the time the link + * becomes available, the packet to be sent will be + * fairly stale. By simply dropping the packet, the + * higher layer protocols will eventually time out + * waiting for response packets which it won't receive. + */ + + if (bp->link_available == PI_K_FALSE) + { + if (dfx_hw_adap_state_rd(bp) == PI_STATE_K_LINK_AVAIL) /* is link really available? */ + bp->link_available = PI_K_TRUE; /* if so, set flag and continue */ + else + { + bp->xmt_discards++; /* bump error counter */ + dev_kfree_skb(skb); /* free sk_buff now */ + netif_wake_queue(dev); + return NETDEV_TX_OK; /* return "success" */ + } + } + + spin_lock_irqsave(&bp->lock, flags); + + /* Get the current producer and the next free xmt data descriptor */ + + prod = bp->rcv_xmt_reg.index.xmt_prod; + p_xmt_descr = &(bp->descr_block_virt->xmt_data[prod]); + + /* + * Get pointer to auxiliary queue entry to contain information + * for this packet. + * + * Note: The current xmt producer index will become the + * current xmt completion index when we complete this + * packet later on. So, we'll get the pointer to the + * next auxiliary queue entry now before we bump the + * producer index. + */ + + p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[prod++]); /* also bump producer index */ + + /* Write the three PRH bytes immediately before the FC byte */ + + skb_push(skb,3); + skb->data[0] = DFX_PRH0_BYTE; /* these byte values are defined */ + skb->data[1] = DFX_PRH1_BYTE; /* in the Motorola FDDI MAC chip */ + skb->data[2] = DFX_PRH2_BYTE; /* specification */ + + /* + * Write the descriptor with buffer info and bump producer + * + * Note: Since we need to start DMA from the packet request + * header, we'll add 3 bytes to the DMA buffer length, + * and we'll determine the physical address of the + * buffer from the PRH, not skb->data. + * + * Assumptions: + * 1. Packet starts with the frame control (FC) byte + * at skb->data. + * 2. The 4-byte CRC is not appended to the buffer or + * included in the length. + * 3. Packet length (skb->len) is from FC to end of + * data, inclusive. + * 4. The packet length does not exceed the maximum + * FDDI LLC frame length of 4491 bytes. + * 5. The entire packet is contained in a physically + * contiguous, non-cached, locked memory space + * comprised of a single buffer pointed to by + * skb->data. + * 6. The physical address of the start of packet + * can be determined from the virtual address + * by using pci_map_single() and is only 32-bits + * wide. + */ + + p_xmt_descr->long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len) << PI_XMT_DESCR_V_SEG_LEN)); + p_xmt_descr->long_1 = (u32)dma_map_single(bp->bus_dev, skb->data, + skb->len, DMA_TO_DEVICE); + + /* + * Verify that descriptor is actually available + * + * Note: If descriptor isn't available, return 1 which tells + * the upper layer to requeue the packet for later + * transmission. + * + * We need to ensure that the producer never reaches the + * completion, except to indicate that the queue is empty. + */ + + if (prod == bp->rcv_xmt_reg.index.xmt_comp) + { + skb_pull(skb,3); + spin_unlock_irqrestore(&bp->lock, flags); + return NETDEV_TX_BUSY; /* requeue packet for later */ + } + + /* + * Save info for this packet for xmt done indication routine + * + * Normally, we'd save the producer index in the p_xmt_drv_descr + * structure so that we'd have it handy when we complete this + * packet later (in dfx_xmt_done). However, since the current + * transmit architecture guarantees a single fragment for the + * entire packet, we can simply bump the completion index by + * one (1) for each completed packet. + * + * Note: If this assumption changes and we're presented with + * an inconsistent number of transmit fragments for packet + * data, we'll need to modify this code to save the current + * transmit producer index. + */ + + p_xmt_drv_descr->p_skb = skb; + + /* Update Type 2 register */ + + bp->rcv_xmt_reg.index.xmt_prod = prod; + dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); + spin_unlock_irqrestore(&bp->lock, flags); + netif_wake_queue(dev); + return NETDEV_TX_OK; /* packet queued to adapter */ + } + + +/* + * ================ + * = dfx_xmt_done = + * ================ + * + * Overview: + * Processes all frames that have been transmitted. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * For all consumed transmit descriptors that have not + * yet been completed, we'll free the skb we were holding + * onto using dev_kfree_skb and bump the appropriate + * counters. + * + * Return Codes: + * None + * + * Assumptions: + * The Type 2 register is not updated in this routine. It is + * assumed that it will be updated in the ISR when dfx_xmt_done + * returns. + * + * Side Effects: + * None + */ + +static int dfx_xmt_done(DFX_board_t *bp) + { + XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ + PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */ + u8 comp; /* local transmit completion index */ + int freed = 0; /* buffers freed */ + + /* Service all consumed transmit frames */ + + p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data); + while (bp->rcv_xmt_reg.index.xmt_comp != p_type_2_cons->index.xmt_cons) + { + /* Get pointer to the transmit driver descriptor block information */ + + p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[bp->rcv_xmt_reg.index.xmt_comp]); + + /* Increment transmit counters */ + + bp->xmt_total_frames++; + bp->xmt_total_bytes += p_xmt_drv_descr->p_skb->len; + + /* Return skb to operating system */ + comp = bp->rcv_xmt_reg.index.xmt_comp; + dma_unmap_single(bp->bus_dev, + bp->descr_block_virt->xmt_data[comp].long_1, + p_xmt_drv_descr->p_skb->len, + DMA_TO_DEVICE); + dev_kfree_skb_irq(p_xmt_drv_descr->p_skb); + + /* + * Move to start of next packet by updating completion index + * + * Here we assume that a transmit packet request is always + * serviced by posting one fragment. We can therefore + * simplify the completion code by incrementing the + * completion index by one. This code will need to be + * modified if this assumption changes. See comments + * in dfx_xmt_queue_pkt for more details. + */ + + bp->rcv_xmt_reg.index.xmt_comp += 1; + freed++; + } + return freed; + } + + +/* + * ================= + * = dfx_rcv_flush = + * ================= + * + * Overview: + * Remove all skb's in the receive ring. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Free's all the dynamically allocated skb's that are + * currently attached to the device receive ring. This + * function is typically only used when the device is + * initialized or reinitialized. + * + * Return Codes: + * None + * + * Side Effects: + * None + */ +#ifdef DYNAMIC_BUFFERS +static void dfx_rcv_flush( DFX_board_t *bp ) + { + int i, j; + + for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++) + for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) + { + struct sk_buff *skb; + skb = (struct sk_buff *)bp->p_rcv_buff_va[i+j]; + if (skb) + dev_kfree_skb(skb); + bp->p_rcv_buff_va[i+j] = NULL; + } + + } +#else +static inline void dfx_rcv_flush( DFX_board_t *bp ) +{ +} +#endif /* DYNAMIC_BUFFERS */ + +/* + * ================= + * = dfx_xmt_flush = + * ================= + * + * Overview: + * Processes all frames whether they've been transmitted + * or not. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * For all produced transmit descriptors that have not + * yet been completed, we'll free the skb we were holding + * onto using dev_kfree_skb and bump the appropriate + * counters. Of course, it's possible that some of + * these transmit requests actually did go out, but we + * won't make that distinction here. Finally, we'll + * update the consumer index to match the producer. + * + * Return Codes: + * None + * + * Assumptions: + * This routine does NOT update the Type 2 register. It + * is assumed that this routine is being called during a + * transmit flush interrupt, or a shutdown or close routine. + * + * Side Effects: + * None + */ + +static void dfx_xmt_flush( DFX_board_t *bp ) + { + u32 prod_cons; /* rcv/xmt consumer block longword */ + XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ + u8 comp; /* local transmit completion index */ + + /* Flush all outstanding transmit frames */ + + while (bp->rcv_xmt_reg.index.xmt_comp != bp->rcv_xmt_reg.index.xmt_prod) + { + /* Get pointer to the transmit driver descriptor block information */ + + p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[bp->rcv_xmt_reg.index.xmt_comp]); + + /* Return skb to operating system */ + comp = bp->rcv_xmt_reg.index.xmt_comp; + dma_unmap_single(bp->bus_dev, + bp->descr_block_virt->xmt_data[comp].long_1, + p_xmt_drv_descr->p_skb->len, + DMA_TO_DEVICE); + dev_kfree_skb(p_xmt_drv_descr->p_skb); + + /* Increment transmit error counter */ + + bp->xmt_discards++; + + /* + * Move to start of next packet by updating completion index + * + * Here we assume that a transmit packet request is always + * serviced by posting one fragment. We can therefore + * simplify the completion code by incrementing the + * completion index by one. This code will need to be + * modified if this assumption changes. See comments + * in dfx_xmt_queue_pkt for more details. + */ + + bp->rcv_xmt_reg.index.xmt_comp += 1; + } + + /* Update the transmit consumer index in the consumer block */ + + prod_cons = (u32)(bp->cons_block_virt->xmt_rcv_data & ~PI_CONS_M_XMT_INDEX); + prod_cons |= (u32)(bp->rcv_xmt_reg.index.xmt_prod << PI_CONS_V_XMT_INDEX); + bp->cons_block_virt->xmt_rcv_data = prod_cons; + } + +/* + * ================== + * = dfx_unregister = + * ================== + * + * Overview: + * Shuts down an FDDI controller + * + * Returns: + * Condition code + * + * Arguments: + * bdev - pointer to device information + * + * Functional Description: + * + * Return Codes: + * None + * + * Assumptions: + * It compiles so it should work :-( (PCI cards do :-) + * + * Side Effects: + * Device structures for FDDI adapters (fddi0, fddi1, etc) are + * freed. + */ +static void __devexit dfx_unregister(struct device *bdev) +{ + struct net_device *dev = dev_get_drvdata(bdev); + DFX_board_t *bp = netdev_priv(dev); + int dfx_bus_pci = DFX_BUS_PCI(bdev); + int dfx_bus_tc = DFX_BUS_TC(bdev); + int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; + resource_size_t bar_start = 0; /* pointer to port */ + resource_size_t bar_len = 0; /* resource length */ + int alloc_size; /* total buffer size used */ + + unregister_netdev(dev); + + alloc_size = sizeof(PI_DESCR_BLOCK) + + PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX + +#ifndef DYNAMIC_BUFFERS + (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) + +#endif + sizeof(PI_CONSUMER_BLOCK) + + (PI_ALIGN_K_DESC_BLK - 1); + if (bp->kmalloced) + dma_free_coherent(bdev, alloc_size, + bp->kmalloced, bp->kmalloced_dma); + + dfx_bus_uninit(dev); + + dfx_get_bars(bdev, &bar_start, &bar_len); + if (dfx_use_mmio) { + iounmap(bp->base.mem); + release_mem_region(bar_start, bar_len); + } else + release_region(bar_start, bar_len); + + if (dfx_bus_pci) + pci_disable_device(to_pci_dev(bdev)); + + free_netdev(dev); +} + + +static int __devinit __maybe_unused dfx_dev_register(struct device *); +static int __devexit __maybe_unused dfx_dev_unregister(struct device *); + +#ifdef CONFIG_PCI +static int __devinit dfx_pci_register(struct pci_dev *, + const struct pci_device_id *); +static void __devexit dfx_pci_unregister(struct pci_dev *); + +static DEFINE_PCI_DEVICE_TABLE(dfx_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI) }, + { } +}; +MODULE_DEVICE_TABLE(pci, dfx_pci_table); + +static struct pci_driver dfx_pci_driver = { + .name = "defxx", + .id_table = dfx_pci_table, + .probe = dfx_pci_register, + .remove = __devexit_p(dfx_pci_unregister), +}; + +static __devinit int dfx_pci_register(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + return dfx_register(&pdev->dev); +} + +static void __devexit dfx_pci_unregister(struct pci_dev *pdev) +{ + dfx_unregister(&pdev->dev); +} +#endif /* CONFIG_PCI */ + +#ifdef CONFIG_EISA +static struct eisa_device_id dfx_eisa_table[] = { + { "DEC3001", DEFEA_PROD_ID_1 }, + { "DEC3002", DEFEA_PROD_ID_2 }, + { "DEC3003", DEFEA_PROD_ID_3 }, + { "DEC3004", DEFEA_PROD_ID_4 }, + { } +}; +MODULE_DEVICE_TABLE(eisa, dfx_eisa_table); + +static struct eisa_driver dfx_eisa_driver = { + .id_table = dfx_eisa_table, + .driver = { + .name = "defxx", + .bus = &eisa_bus_type, + .probe = dfx_dev_register, + .remove = __devexit_p(dfx_dev_unregister), + }, +}; +#endif /* CONFIG_EISA */ + +#ifdef CONFIG_TC +static struct tc_device_id const dfx_tc_table[] = { + { "DEC ", "PMAF-FA " }, + { "DEC ", "PMAF-FD " }, + { "DEC ", "PMAF-FS " }, + { "DEC ", "PMAF-FU " }, + { } +}; +MODULE_DEVICE_TABLE(tc, dfx_tc_table); + +static struct tc_driver dfx_tc_driver = { + .id_table = dfx_tc_table, + .driver = { + .name = "defxx", + .bus = &tc_bus_type, + .probe = dfx_dev_register, + .remove = __devexit_p(dfx_dev_unregister), + }, +}; +#endif /* CONFIG_TC */ + +static int __devinit __maybe_unused dfx_dev_register(struct device *dev) +{ + int status; + + status = dfx_register(dev); + if (!status) + get_device(dev); + return status; +} + +static int __devexit __maybe_unused dfx_dev_unregister(struct device *dev) +{ + put_device(dev); + dfx_unregister(dev); + return 0; +} + + +static int __devinit dfx_init(void) +{ + int status; + + status = pci_register_driver(&dfx_pci_driver); + if (!status) + status = eisa_driver_register(&dfx_eisa_driver); + if (!status) + status = tc_register_driver(&dfx_tc_driver); + return status; +} + +static void __devexit dfx_cleanup(void) +{ + tc_unregister_driver(&dfx_tc_driver); + eisa_driver_unregister(&dfx_eisa_driver); + pci_unregister_driver(&dfx_pci_driver); +} + +module_init(dfx_init); +module_exit(dfx_cleanup); +MODULE_AUTHOR("Lawrence V. Stefani"); +MODULE_DESCRIPTION("DEC FDDIcontroller TC/EISA/PCI (DEFTA/DEFEA/DEFPA) driver " + DRV_VERSION " " DRV_RELDATE); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/fddi/defxx.h b/drivers/net/fddi/defxx.h new file mode 100644 index 0000000..19a6f64 --- /dev/null +++ b/drivers/net/fddi/defxx.h @@ -0,0 +1,1801 @@ +/* + * File Name: + * defxx.h + * + * Copyright Information: + * Copyright Digital Equipment Corporation 1996. + * + * This software may be used and distributed according to the terms of + * the GNU General Public License, incorporated herein by reference. + * + * Abstract: + * Contains all definitions specified by port specification and required + * by the defxx.c driver. + * + * The original author: + * LVS Lawrence V. Stefani + * + * Maintainers: + * macro Maciej W. Rozycki + * + * Modification History: + * Date Name Description + * 16-Aug-96 LVS Created. + * 09-Sep-96 LVS Added group_prom field. Moved read/write I/O + * macros to DEFXX.C. + * 12-Sep-96 LVS Removed packet request header pointers. + * 04 Aug 2003 macro Converted to the DMA API. + * 23 Oct 2006 macro Big-endian host support. + * 14 Dec 2006 macro TURBOchannel support. + */ + +#ifndef _DEFXX_H_ +#define _DEFXX_H_ + +/* Define basic types for unsigned chars, shorts, longs */ + +typedef u8 PI_UINT8; +typedef u16 PI_UINT16; +typedef u32 PI_UINT32; + +/* Define general structures */ + +typedef struct /* 64-bit counter */ + { + PI_UINT32 ms; + PI_UINT32 ls; + } PI_CNTR; + +typedef struct /* LAN address */ + { + PI_UINT32 lwrd_0; + PI_UINT32 lwrd_1; + } PI_LAN_ADDR; + +typedef struct /* Station ID address */ + { + PI_UINT32 octet_7_4; + PI_UINT32 octet_3_0; + } PI_STATION_ID; + + +/* Define general constants */ + +#define PI_ALIGN_K_DESC_BLK 8192 /* Descriptor block boundary */ +#define PI_ALIGN_K_CONS_BLK 64 /* Consumer block boundary */ +#define PI_ALIGN_K_CMD_REQ_BUFF 128 /* Xmt Command que buffer alignment */ +#define PI_ALIGN_K_CMD_RSP_BUFF 128 /* Rcv Command que buffer alignment */ +#define PI_ALIGN_K_UNSOL_BUFF 128 /* Unsol que buffer alignment */ +#define PI_ALIGN_K_XMT_DATA_BUFF 0 /* Xmt data que buffer alignment */ +#define PI_ALIGN_K_RCV_DATA_BUFF 128 /* Rcv que buffer alignment */ + +/* Define PHY index values */ + +#define PI_PHY_K_S 0 /* Index to S phy */ +#define PI_PHY_K_A 0 /* Index to A phy */ +#define PI_PHY_K_B 1 /* Index to B phy */ +#define PI_PHY_K_MAX 2 /* Max number of phys */ + +/* Define FMC descriptor fields */ + +#define PI_FMC_DESCR_V_SOP 31 +#define PI_FMC_DESCR_V_EOP 30 +#define PI_FMC_DESCR_V_FSC 27 +#define PI_FMC_DESCR_V_FSB_ERROR 26 +#define PI_FMC_DESCR_V_FSB_ADDR_RECOG 25 +#define PI_FMC_DESCR_V_FSB_ADDR_COPIED 24 +#define PI_FMC_DESCR_V_FSB 22 +#define PI_FMC_DESCR_V_RCC_FLUSH 21 +#define PI_FMC_DESCR_V_RCC_CRC 20 +#define PI_FMC_DESCR_V_RCC_RRR 17 +#define PI_FMC_DESCR_V_RCC_DD 15 +#define PI_FMC_DESCR_V_RCC_SS 13 +#define PI_FMC_DESCR_V_RCC 13 +#define PI_FMC_DESCR_V_LEN 0 + +#define PI_FMC_DESCR_M_SOP 0x80000000 +#define PI_FMC_DESCR_M_EOP 0x40000000 +#define PI_FMC_DESCR_M_FSC 0x38000000 +#define PI_FMC_DESCR_M_FSB_ERROR 0x04000000 +#define PI_FMC_DESCR_M_FSB_ADDR_RECOG 0x02000000 +#define PI_FMC_DESCR_M_FSB_ADDR_COPIED 0x01000000 +#define PI_FMC_DESCR_M_FSB 0x07C00000 +#define PI_FMC_DESCR_M_RCC_FLUSH 0x00200000 +#define PI_FMC_DESCR_M_RCC_CRC 0x00100000 +#define PI_FMC_DESCR_M_RCC_RRR 0x000E0000 +#define PI_FMC_DESCR_M_RCC_DD 0x00018000 +#define PI_FMC_DESCR_M_RCC_SS 0x00006000 +#define PI_FMC_DESCR_M_RCC 0x003FE000 +#define PI_FMC_DESCR_M_LEN 0x00001FFF + +#define PI_FMC_DESCR_K_RCC_FMC_INT_ERR 0x01AA + +#define PI_FMC_DESCR_K_RRR_SUCCESS 0x00 +#define PI_FMC_DESCR_K_RRR_SA_MATCH 0x01 +#define PI_FMC_DESCR_K_RRR_DA_MATCH 0x02 +#define PI_FMC_DESCR_K_RRR_FMC_ABORT 0x03 +#define PI_FMC_DESCR_K_RRR_LENGTH_BAD 0x04 +#define PI_FMC_DESCR_K_RRR_FRAGMENT 0x05 +#define PI_FMC_DESCR_K_RRR_FORMAT_ERR 0x06 +#define PI_FMC_DESCR_K_RRR_MAC_RESET 0x07 + +#define PI_FMC_DESCR_K_DD_NO_MATCH 0x0 +#define PI_FMC_DESCR_K_DD_PROMISCUOUS 0x1 +#define PI_FMC_DESCR_K_DD_CAM_MATCH 0x2 +#define PI_FMC_DESCR_K_DD_LOCAL_MATCH 0x3 + +#define PI_FMC_DESCR_K_SS_NO_MATCH 0x0 +#define PI_FMC_DESCR_K_SS_BRIDGE_MATCH 0x1 +#define PI_FMC_DESCR_K_SS_NOT_POSSIBLE 0x2 +#define PI_FMC_DESCR_K_SS_LOCAL_MATCH 0x3 + +/* Define some max buffer sizes */ + +#define PI_CMD_REQ_K_SIZE_MAX 512 +#define PI_CMD_RSP_K_SIZE_MAX 512 +#define PI_UNSOL_K_SIZE_MAX 512 +#define PI_SMT_HOST_K_SIZE_MAX 4608 /* 4 1/2 K */ +#define PI_RCV_DATA_K_SIZE_MAX 4608 /* 4 1/2 K */ +#define PI_XMT_DATA_K_SIZE_MAX 4608 /* 4 1/2 K */ + +/* Define adapter states */ + +#define PI_STATE_K_RESET 0 +#define PI_STATE_K_UPGRADE 1 +#define PI_STATE_K_DMA_UNAVAIL 2 +#define PI_STATE_K_DMA_AVAIL 3 +#define PI_STATE_K_LINK_AVAIL 4 +#define PI_STATE_K_LINK_UNAVAIL 5 +#define PI_STATE_K_HALTED 6 +#define PI_STATE_K_RING_MEMBER 7 +#define PI_STATE_K_NUMBER 8 + +/* Define codes for command type */ + +#define PI_CMD_K_START 0x00 +#define PI_CMD_K_FILTERS_SET 0x01 +#define PI_CMD_K_FILTERS_GET 0x02 +#define PI_CMD_K_CHARS_SET 0x03 +#define PI_CMD_K_STATUS_CHARS_GET 0x04 +#define PI_CMD_K_CNTRS_GET 0x05 +#define PI_CMD_K_CNTRS_SET 0x06 +#define PI_CMD_K_ADDR_FILTER_SET 0x07 +#define PI_CMD_K_ADDR_FILTER_GET 0x08 +#define PI_CMD_K_ERROR_LOG_CLEAR 0x09 +#define PI_CMD_K_ERROR_LOG_GET 0x0A +#define PI_CMD_K_FDDI_MIB_GET 0x0B +#define PI_CMD_K_DEC_EXT_MIB_GET 0x0C +#define PI_CMD_K_DEVICE_SPECIFIC_GET 0x0D +#define PI_CMD_K_SNMP_SET 0x0E +#define PI_CMD_K_UNSOL_TEST 0x0F +#define PI_CMD_K_SMT_MIB_GET 0x10 +#define PI_CMD_K_SMT_MIB_SET 0x11 +#define PI_CMD_K_MAX 0x11 /* Must match last */ + +/* Define item codes for Chars_Set and Filters_Set commands */ + +#define PI_ITEM_K_EOL 0x00 /* End-of-Item list */ +#define PI_ITEM_K_T_REQ 0x01 /* DECnet T_REQ */ +#define PI_ITEM_K_TVX 0x02 /* DECnet TVX */ +#define PI_ITEM_K_RESTRICTED_TOKEN 0x03 /* DECnet Restricted Token */ +#define PI_ITEM_K_LEM_THRESHOLD 0x04 /* DECnet LEM Threshold */ +#define PI_ITEM_K_RING_PURGER 0x05 /* DECnet Ring Purger Enable */ +#define PI_ITEM_K_CNTR_INTERVAL 0x06 /* Chars_Set */ +#define PI_ITEM_K_IND_GROUP_PROM 0x07 /* Filters_Set */ +#define PI_ITEM_K_GROUP_PROM 0x08 /* Filters_Set */ +#define PI_ITEM_K_BROADCAST 0x09 /* Filters_Set */ +#define PI_ITEM_K_SMT_PROM 0x0A /* Filters_Set */ +#define PI_ITEM_K_SMT_USER 0x0B /* Filters_Set */ +#define PI_ITEM_K_RESERVED 0x0C /* Filters_Set */ +#define PI_ITEM_K_IMPLEMENTOR 0x0D /* Filters_Set */ +#define PI_ITEM_K_LOOPBACK_MODE 0x0E /* Chars_Set */ +#define PI_ITEM_K_CONFIG_POLICY 0x10 /* SMTConfigPolicy */ +#define PI_ITEM_K_CON_POLICY 0x11 /* SMTConnectionPolicy */ +#define PI_ITEM_K_T_NOTIFY 0x12 /* SMTTNotify */ +#define PI_ITEM_K_STATION_ACTION 0x13 /* SMTStationAction */ +#define PI_ITEM_K_MAC_PATHS_REQ 0x15 /* MACPathsRequested */ +#define PI_ITEM_K_MAC_ACTION 0x17 /* MACAction */ +#define PI_ITEM_K_CON_POLICIES 0x18 /* PORTConnectionPolicies */ +#define PI_ITEM_K_PORT_PATHS_REQ 0x19 /* PORTPathsRequested */ +#define PI_ITEM_K_MAC_LOOP_TIME 0x1A /* PORTMACLoopTime */ +#define PI_ITEM_K_TB_MAX 0x1B /* PORTTBMax */ +#define PI_ITEM_K_LER_CUTOFF 0x1C /* PORTLerCutoff */ +#define PI_ITEM_K_LER_ALARM 0x1D /* PORTLerAlarm */ +#define PI_ITEM_K_PORT_ACTION 0x1E /* PORTAction */ +#define PI_ITEM_K_FLUSH_TIME 0x20 /* Chars_Set */ +#define PI_ITEM_K_MAC_T_REQ 0x29 /* MACTReq */ +#define PI_ITEM_K_EMAC_RING_PURGER 0x2A /* eMACRingPurgerEnable */ +#define PI_ITEM_K_EMAC_RTOKEN_TIMEOUT 0x2B /* eMACRestrictedTokenTimeout */ +#define PI_ITEM_K_FDX_ENB_DIS 0x2C /* eFDXEnable */ +#define PI_ITEM_K_MAX 0x2C /* Must equal high item */ + +/* Values for some of the items */ + +#define PI_K_FALSE 0 /* Generic false */ +#define PI_K_TRUE 1 /* Generic true */ + +#define PI_SNMP_K_TRUE 1 /* SNMP true/false values */ +#define PI_SNMP_K_FALSE 2 + +#define PI_FSTATE_K_BLOCK 0 /* Filter State */ +#define PI_FSTATE_K_PASS 1 + +/* Define command return codes */ + +#define PI_RSP_K_SUCCESS 0x00 +#define PI_RSP_K_FAILURE 0x01 +#define PI_RSP_K_WARNING 0x02 +#define PI_RSP_K_LOOP_MODE_BAD 0x03 +#define PI_RSP_K_ITEM_CODE_BAD 0x04 +#define PI_RSP_K_TVX_BAD 0x05 +#define PI_RSP_K_TREQ_BAD 0x06 +#define PI_RSP_K_TOKEN_BAD 0x07 +#define PI_RSP_K_NO_EOL 0x0C +#define PI_RSP_K_FILTER_STATE_BAD 0x0D +#define PI_RSP_K_CMD_TYPE_BAD 0x0E +#define PI_RSP_K_ADAPTER_STATE_BAD 0x0F +#define PI_RSP_K_RING_PURGER_BAD 0x10 +#define PI_RSP_K_LEM_THRESHOLD_BAD 0x11 +#define PI_RSP_K_LOOP_NOT_SUPPORTED 0x12 +#define PI_RSP_K_FLUSH_TIME_BAD 0x13 +#define PI_RSP_K_NOT_IMPLEMENTED 0x14 +#define PI_RSP_K_CONFIG_POLICY_BAD 0x15 +#define PI_RSP_K_STATION_ACTION_BAD 0x16 +#define PI_RSP_K_MAC_ACTION_BAD 0x17 +#define PI_RSP_K_CON_POLICIES_BAD 0x18 +#define PI_RSP_K_MAC_LOOP_TIME_BAD 0x19 +#define PI_RSP_K_TB_MAX_BAD 0x1A +#define PI_RSP_K_LER_CUTOFF_BAD 0x1B +#define PI_RSP_K_LER_ALARM_BAD 0x1C +#define PI_RSP_K_MAC_PATHS_REQ_BAD 0x1D +#define PI_RSP_K_MAC_T_REQ_BAD 0x1E +#define PI_RSP_K_EMAC_RING_PURGER_BAD 0x1F +#define PI_RSP_K_EMAC_RTOKEN_TIME_BAD 0x20 +#define PI_RSP_K_NO_SUCH_ENTRY 0x21 +#define PI_RSP_K_T_NOTIFY_BAD 0x22 +#define PI_RSP_K_TR_MAX_EXP_BAD 0x23 +#define PI_RSP_K_MAC_FRM_ERR_THR_BAD 0x24 +#define PI_RSP_K_MAX_T_REQ_BAD 0x25 +#define PI_RSP_K_FDX_ENB_DIS_BAD 0x26 +#define PI_RSP_K_ITEM_INDEX_BAD 0x27 +#define PI_RSP_K_PORT_ACTION_BAD 0x28 + +/* Commonly used structures */ + +typedef struct /* Item list */ + { + PI_UINT32 item_code; + PI_UINT32 value; + } PI_ITEM_LIST; + +typedef struct /* Response header */ + { + PI_UINT32 reserved; + PI_UINT32 cmd_type; + PI_UINT32 status; + } PI_RSP_HEADER; + + +/* Start Command */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_START_REQ; + +/* Start Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_START_RSP; + +/* Filters_Set Request */ + +#define PI_CMD_FILTERS_SET_K_ITEMS_MAX 63 /* Fits in a 512 byte buffer */ + +typedef struct + { + PI_UINT32 cmd_type; + PI_ITEM_LIST item[PI_CMD_FILTERS_SET_K_ITEMS_MAX]; + } PI_CMD_FILTERS_SET_REQ; + +/* Filters_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_FILTERS_SET_RSP; + +/* Filters_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_FILTERS_GET_REQ; + +/* Filters_Get Response */ + +typedef struct + { + PI_RSP_HEADER header; + PI_UINT32 ind_group_prom; + PI_UINT32 group_prom; + PI_UINT32 broadcast_all; + PI_UINT32 smt_all; + PI_UINT32 smt_user; + PI_UINT32 reserved_all; + PI_UINT32 implementor_all; + } PI_CMD_FILTERS_GET_RSP; + + +/* Chars_Set Request */ + +#define PI_CMD_CHARS_SET_K_ITEMS_MAX 42 /* Fits in a 512 byte buffer */ + +typedef struct + { + PI_UINT32 cmd_type; + struct /* Item list */ + { + PI_UINT32 item_code; + PI_UINT32 value; + PI_UINT32 item_index; + } item[PI_CMD_CHARS_SET_K_ITEMS_MAX]; + } PI_CMD_CHARS_SET_REQ; + +/* Chars_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_CHARS_SET_RSP; + + +/* SNMP_Set Request */ + +#define PI_CMD_SNMP_SET_K_ITEMS_MAX 42 /* Fits in a 512 byte buffer */ + +typedef struct + { + PI_UINT32 cmd_type; + struct /* Item list */ + { + PI_UINT32 item_code; + PI_UINT32 value; + PI_UINT32 item_index; + } item[PI_CMD_SNMP_SET_K_ITEMS_MAX]; + } PI_CMD_SNMP_SET_REQ; + +/* SNMP_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_SNMP_SET_RSP; + + +/* SMT_MIB_Set Request */ + +#define PI_CMD_SMT_MIB_SET_K_ITEMS_MAX 42 /* Max number of items */ + +typedef struct + { + PI_UINT32 cmd_type; + struct + { + PI_UINT32 item_code; + PI_UINT32 value; + PI_UINT32 item_index; + } item[PI_CMD_SMT_MIB_SET_K_ITEMS_MAX]; + } PI_CMD_SMT_MIB_SET_REQ; + +/* SMT_MIB_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_SMT_MIB_SET_RSP; + +/* SMT_MIB_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_SMT_MIB_GET_REQ; + +/* SMT_MIB_Get Response */ + +typedef struct /* Refer to ANSI FDDI SMT Rev. 7.3 */ + { + PI_RSP_HEADER header; + + /* SMT GROUP */ + + PI_STATION_ID smt_station_id; + PI_UINT32 smt_op_version_id; + PI_UINT32 smt_hi_version_id; + PI_UINT32 smt_lo_version_id; + PI_UINT32 smt_user_data[8]; + PI_UINT32 smt_mib_version_id; + PI_UINT32 smt_mac_ct; + PI_UINT32 smt_non_master_ct; + PI_UINT32 smt_master_ct; + PI_UINT32 smt_available_paths; + PI_UINT32 smt_config_capabilities; + PI_UINT32 smt_config_policy; + PI_UINT32 smt_connection_policy; + PI_UINT32 smt_t_notify; + PI_UINT32 smt_stat_rpt_policy; + PI_UINT32 smt_trace_max_expiration; + PI_UINT32 smt_bypass_present; + PI_UINT32 smt_ecm_state; + PI_UINT32 smt_cf_state; + PI_UINT32 smt_remote_disconnect_flag; + PI_UINT32 smt_station_status; + PI_UINT32 smt_peer_wrap_flag; + PI_CNTR smt_msg_time_stamp; + PI_CNTR smt_transition_time_stamp; + + /* MAC GROUP */ + + PI_UINT32 mac_frame_status_functions; + PI_UINT32 mac_t_max_capability; + PI_UINT32 mac_tvx_capability; + PI_UINT32 mac_available_paths; + PI_UINT32 mac_current_path; + PI_LAN_ADDR mac_upstream_nbr; + PI_LAN_ADDR mac_downstream_nbr; + PI_LAN_ADDR mac_old_upstream_nbr; + PI_LAN_ADDR mac_old_downstream_nbr; + PI_UINT32 mac_dup_address_test; + PI_UINT32 mac_requested_paths; + PI_UINT32 mac_downstream_port_type; + PI_LAN_ADDR mac_smt_address; + PI_UINT32 mac_t_req; + PI_UINT32 mac_t_neg; + PI_UINT32 mac_t_max; + PI_UINT32 mac_tvx_value; + PI_UINT32 mac_frame_error_threshold; + PI_UINT32 mac_frame_error_ratio; + PI_UINT32 mac_rmt_state; + PI_UINT32 mac_da_flag; + PI_UINT32 mac_unda_flag; + PI_UINT32 mac_frame_error_flag; + PI_UINT32 mac_ma_unitdata_available; + PI_UINT32 mac_hardware_present; + PI_UINT32 mac_ma_unitdata_enable; + + /* PATH GROUP */ + + PI_UINT32 path_configuration[8]; + PI_UINT32 path_tvx_lower_bound; + PI_UINT32 path_t_max_lower_bound; + PI_UINT32 path_max_t_req; + + /* PORT GROUP */ + + PI_UINT32 port_my_type[PI_PHY_K_MAX]; + PI_UINT32 port_neighbor_type[PI_PHY_K_MAX]; + PI_UINT32 port_connection_policies[PI_PHY_K_MAX]; + PI_UINT32 port_mac_indicated[PI_PHY_K_MAX]; + PI_UINT32 port_current_path[PI_PHY_K_MAX]; + PI_UINT32 port_requested_paths[PI_PHY_K_MAX]; + PI_UINT32 port_mac_placement[PI_PHY_K_MAX]; + PI_UINT32 port_available_paths[PI_PHY_K_MAX]; + PI_UINT32 port_pmd_class[PI_PHY_K_MAX]; + PI_UINT32 port_connection_capabilities[PI_PHY_K_MAX]; + PI_UINT32 port_bs_flag[PI_PHY_K_MAX]; + PI_UINT32 port_ler_estimate[PI_PHY_K_MAX]; + PI_UINT32 port_ler_cutoff[PI_PHY_K_MAX]; + PI_UINT32 port_ler_alarm[PI_PHY_K_MAX]; + PI_UINT32 port_connect_state[PI_PHY_K_MAX]; + PI_UINT32 port_pcm_state[PI_PHY_K_MAX]; + PI_UINT32 port_pc_withhold[PI_PHY_K_MAX]; + PI_UINT32 port_ler_flag[PI_PHY_K_MAX]; + PI_UINT32 port_hardware_present[PI_PHY_K_MAX]; + + /* GROUP for things that were added later, so must be at the end. */ + + PI_CNTR path_ring_latency; + + } PI_CMD_SMT_MIB_GET_RSP; + + +/* + * Item and group code definitions for SMT 7.3 mandatory objects. These + * definitions are to be used as appropriate in SMT_MIB_SET commands and + * certain host-sent SMT frames such as PMF Get and Set requests. The + * codes have been taken from the MIB summary section of ANSI SMT 7.3. + */ + +#define PI_GRP_K_SMT_STATION_ID 0x100A +#define PI_ITEM_K_SMT_STATION_ID 0x100B +#define PI_ITEM_K_SMT_OP_VERS_ID 0x100D +#define PI_ITEM_K_SMT_HI_VERS_ID 0x100E +#define PI_ITEM_K_SMT_LO_VERS_ID 0x100F +#define PI_ITEM_K_SMT_USER_DATA 0x1011 +#define PI_ITEM_K_SMT_MIB_VERS_ID 0x1012 + +#define PI_GRP_K_SMT_STATION_CONFIG 0x1014 +#define PI_ITEM_K_SMT_MAC_CT 0x1015 +#define PI_ITEM_K_SMT_NON_MASTER_CT 0x1016 +#define PI_ITEM_K_SMT_MASTER_CT 0x1017 +#define PI_ITEM_K_SMT_AVAIL_PATHS 0x1018 +#define PI_ITEM_K_SMT_CONFIG_CAPS 0x1019 +#define PI_ITEM_K_SMT_CONFIG_POL 0x101A +#define PI_ITEM_K_SMT_CONN_POL 0x101B +#define PI_ITEM_K_SMT_T_NOTIFY 0x101D +#define PI_ITEM_K_SMT_STAT_POL 0x101E +#define PI_ITEM_K_SMT_TR_MAX_EXP 0x101F +#define PI_ITEM_K_SMT_PORT_INDEXES 0x1020 +#define PI_ITEM_K_SMT_MAC_INDEXES 0x1021 +#define PI_ITEM_K_SMT_BYPASS_PRESENT 0x1022 + +#define PI_GRP_K_SMT_STATUS 0x1028 +#define PI_ITEM_K_SMT_ECM_STATE 0x1029 +#define PI_ITEM_K_SMT_CF_STATE 0x102A +#define PI_ITEM_K_SMT_REM_DISC_FLAG 0x102C +#define PI_ITEM_K_SMT_STATION_STATUS 0x102D +#define PI_ITEM_K_SMT_PEER_WRAP_FLAG 0x102E + +#define PI_GRP_K_SMT_MIB_OPERATION 0x1032 +#define PI_ITEM_K_SMT_MSG_TIME_STAMP 0x1033 +#define PI_ITEM_K_SMT_TRN_TIME_STAMP 0x1034 + +#define PI_ITEM_K_SMT_STATION_ACT 0x103C + +#define PI_GRP_K_MAC_CAPABILITIES 0x200A +#define PI_ITEM_K_MAC_FRM_STAT_FUNC 0x200B +#define PI_ITEM_K_MAC_T_MAX_CAP 0x200D +#define PI_ITEM_K_MAC_TVX_CAP 0x200E + +#define PI_GRP_K_MAC_CONFIG 0x2014 +#define PI_ITEM_K_MAC_AVAIL_PATHS 0x2016 +#define PI_ITEM_K_MAC_CURRENT_PATH 0x2017 +#define PI_ITEM_K_MAC_UP_NBR 0x2018 +#define PI_ITEM_K_MAC_DOWN_NBR 0x2019 +#define PI_ITEM_K_MAC_OLD_UP_NBR 0x201A +#define PI_ITEM_K_MAC_OLD_DOWN_NBR 0x201B +#define PI_ITEM_K_MAC_DUP_ADDR_TEST 0x201D +#define PI_ITEM_K_MAC_REQ_PATHS 0x2020 +#define PI_ITEM_K_MAC_DOWN_PORT_TYPE 0x2021 +#define PI_ITEM_K_MAC_INDEX 0x2022 + +#define PI_GRP_K_MAC_ADDRESS 0x2028 +#define PI_ITEM_K_MAC_SMT_ADDRESS 0x2029 + +#define PI_GRP_K_MAC_OPERATION 0x2032 +#define PI_ITEM_K_MAC_TREQ 0x2033 +#define PI_ITEM_K_MAC_TNEG 0x2034 +#define PI_ITEM_K_MAC_TMAX 0x2035 +#define PI_ITEM_K_MAC_TVX_VALUE 0x2036 + +#define PI_GRP_K_MAC_COUNTERS 0x2046 +#define PI_ITEM_K_MAC_FRAME_CT 0x2047 +#define PI_ITEM_K_MAC_COPIED_CT 0x2048 +#define PI_ITEM_K_MAC_TRANSMIT_CT 0x2049 +#define PI_ITEM_K_MAC_ERROR_CT 0x2051 +#define PI_ITEM_K_MAC_LOST_CT 0x2052 + +#define PI_GRP_K_MAC_FRM_ERR_COND 0x205A +#define PI_ITEM_K_MAC_FRM_ERR_THR 0x205F +#define PI_ITEM_K_MAC_FRM_ERR_RAT 0x2060 + +#define PI_GRP_K_MAC_STATUS 0x206E +#define PI_ITEM_K_MAC_RMT_STATE 0x206F +#define PI_ITEM_K_MAC_DA_FLAG 0x2070 +#define PI_ITEM_K_MAC_UNDA_FLAG 0x2071 +#define PI_ITEM_K_MAC_FRM_ERR_FLAG 0x2072 +#define PI_ITEM_K_MAC_MA_UNIT_AVAIL 0x2074 +#define PI_ITEM_K_MAC_HW_PRESENT 0x2075 +#define PI_ITEM_K_MAC_MA_UNIT_ENAB 0x2076 + +#define PI_GRP_K_PATH_CONFIG 0x320A +#define PI_ITEM_K_PATH_INDEX 0x320B +#define PI_ITEM_K_PATH_CONFIGURATION 0x3212 +#define PI_ITEM_K_PATH_TVX_LB 0x3215 +#define PI_ITEM_K_PATH_T_MAX_LB 0x3216 +#define PI_ITEM_K_PATH_MAX_T_REQ 0x3217 + +#define PI_GRP_K_PORT_CONFIG 0x400A +#define PI_ITEM_K_PORT_MY_TYPE 0x400C +#define PI_ITEM_K_PORT_NBR_TYPE 0x400D +#define PI_ITEM_K_PORT_CONN_POLS 0x400E +#define PI_ITEM_K_PORT_MAC_INDICATED 0x400F +#define PI_ITEM_K_PORT_CURRENT_PATH 0x4010 +#define PI_ITEM_K_PORT_REQ_PATHS 0x4011 +#define PI_ITEM_K_PORT_MAC_PLACEMENT 0x4012 +#define PI_ITEM_K_PORT_AVAIL_PATHS 0x4013 +#define PI_ITEM_K_PORT_PMD_CLASS 0x4016 +#define PI_ITEM_K_PORT_CONN_CAPS 0x4017 +#define PI_ITEM_K_PORT_INDEX 0x401D + +#define PI_GRP_K_PORT_OPERATION 0x401E +#define PI_ITEM_K_PORT_BS_FLAG 0x4021 + +#define PI_GRP_K_PORT_ERR_CNTRS 0x4028 +#define PI_ITEM_K_PORT_LCT_FAIL_CT 0x402A + +#define PI_GRP_K_PORT_LER 0x4032 +#define PI_ITEM_K_PORT_LER_ESTIMATE 0x4033 +#define PI_ITEM_K_PORT_LEM_REJ_CT 0x4034 +#define PI_ITEM_K_PORT_LEM_CT 0x4035 +#define PI_ITEM_K_PORT_LER_CUTOFF 0x403A +#define PI_ITEM_K_PORT_LER_ALARM 0x403B + +#define PI_GRP_K_PORT_STATUS 0x403C +#define PI_ITEM_K_PORT_CONNECT_STATE 0x403D +#define PI_ITEM_K_PORT_PCM_STATE 0x403E +#define PI_ITEM_K_PORT_PC_WITHHOLD 0x403F +#define PI_ITEM_K_PORT_LER_FLAG 0x4040 +#define PI_ITEM_K_PORT_HW_PRESENT 0x4041 + +#define PI_ITEM_K_PORT_ACT 0x4046 + +/* Addr_Filter_Set Request */ + +#define PI_CMD_ADDR_FILTER_K_SIZE 62 + +typedef struct + { + PI_UINT32 cmd_type; + PI_LAN_ADDR entry[PI_CMD_ADDR_FILTER_K_SIZE]; + } PI_CMD_ADDR_FILTER_SET_REQ; + +/* Addr_Filter_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_ADDR_FILTER_SET_RSP; + +/* Addr_Filter_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_ADDR_FILTER_GET_REQ; + +/* Addr_Filter_Get Response */ + +typedef struct + { + PI_RSP_HEADER header; + PI_LAN_ADDR entry[PI_CMD_ADDR_FILTER_K_SIZE]; + } PI_CMD_ADDR_FILTER_GET_RSP; + +/* Status_Chars_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_STATUS_CHARS_GET_REQ; + +/* Status_Chars_Get Response */ + +typedef struct + { + PI_RSP_HEADER header; + PI_STATION_ID station_id; /* Station */ + PI_UINT32 station_type; + PI_UINT32 smt_ver_id; + PI_UINT32 smt_ver_id_max; + PI_UINT32 smt_ver_id_min; + PI_UINT32 station_state; + PI_LAN_ADDR link_addr; /* Link */ + PI_UINT32 t_req; + PI_UINT32 tvx; + PI_UINT32 token_timeout; + PI_UINT32 purger_enb; + PI_UINT32 link_state; + PI_UINT32 tneg; + PI_UINT32 dup_addr_flag; + PI_LAN_ADDR una; + PI_LAN_ADDR una_old; + PI_UINT32 un_dup_addr_flag; + PI_LAN_ADDR dna; + PI_LAN_ADDR dna_old; + PI_UINT32 purger_state; + PI_UINT32 fci_mode; + PI_UINT32 error_reason; + PI_UINT32 loopback; + PI_UINT32 ring_latency; + PI_LAN_ADDR last_dir_beacon_sa; + PI_LAN_ADDR last_dir_beacon_una; + PI_UINT32 phy_type[PI_PHY_K_MAX]; /* Phy */ + PI_UINT32 pmd_type[PI_PHY_K_MAX]; + PI_UINT32 lem_threshold[PI_PHY_K_MAX]; + PI_UINT32 phy_state[PI_PHY_K_MAX]; + PI_UINT32 nbor_phy_type[PI_PHY_K_MAX]; + PI_UINT32 link_error_est[PI_PHY_K_MAX]; + PI_UINT32 broken_reason[PI_PHY_K_MAX]; + PI_UINT32 reject_reason[PI_PHY_K_MAX]; + PI_UINT32 cntr_interval; /* Miscellaneous */ + PI_UINT32 module_rev; + PI_UINT32 firmware_rev; + PI_UINT32 mop_device_type; + PI_UINT32 phy_led[PI_PHY_K_MAX]; + PI_UINT32 flush_time; + } PI_CMD_STATUS_CHARS_GET_RSP; + +/* FDDI_MIB_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_FDDI_MIB_GET_REQ; + +/* FDDI_MIB_Get Response */ + +typedef struct + { + PI_RSP_HEADER header; + + /* SMT GROUP */ + + PI_STATION_ID smt_station_id; + PI_UINT32 smt_op_version_id; + PI_UINT32 smt_hi_version_id; + PI_UINT32 smt_lo_version_id; + PI_UINT32 smt_mac_ct; + PI_UINT32 smt_non_master_ct; + PI_UINT32 smt_master_ct; + PI_UINT32 smt_paths_available; + PI_UINT32 smt_config_capabilities; + PI_UINT32 smt_config_policy; + PI_UINT32 smt_connection_policy; + PI_UINT32 smt_t_notify; + PI_UINT32 smt_status_reporting; + PI_UINT32 smt_ecm_state; + PI_UINT32 smt_cf_state; + PI_UINT32 smt_hold_state; + PI_UINT32 smt_remote_disconnect_flag; + PI_UINT32 smt_station_action; + + /* MAC GROUP */ + + PI_UINT32 mac_frame_status_capabilities; + PI_UINT32 mac_t_max_greatest_lower_bound; + PI_UINT32 mac_tvx_greatest_lower_bound; + PI_UINT32 mac_paths_available; + PI_UINT32 mac_current_path; + PI_LAN_ADDR mac_upstream_nbr; + PI_LAN_ADDR mac_old_upstream_nbr; + PI_UINT32 mac_dup_addr_test; + PI_UINT32 mac_paths_requested; + PI_UINT32 mac_downstream_port_type; + PI_LAN_ADDR mac_smt_address; + PI_UINT32 mac_t_req; + PI_UINT32 mac_t_neg; + PI_UINT32 mac_t_max; + PI_UINT32 mac_tvx_value; + PI_UINT32 mac_t_min; + PI_UINT32 mac_current_frame_status; + /* mac_frame_cts */ + /* mac_error_cts */ + /* mac_lost_cts */ + PI_UINT32 mac_frame_error_threshold; + PI_UINT32 mac_frame_error_ratio; + PI_UINT32 mac_rmt_state; + PI_UINT32 mac_da_flag; + PI_UINT32 mac_una_da_flag; + PI_UINT32 mac_frame_condition; + PI_UINT32 mac_chip_set; + PI_UINT32 mac_action; + + /* PATH GROUP => Does not need to be implemented */ + + /* PORT GROUP */ + + PI_UINT32 port_pc_type[PI_PHY_K_MAX]; + PI_UINT32 port_pc_neighbor[PI_PHY_K_MAX]; + PI_UINT32 port_connection_policies[PI_PHY_K_MAX]; + PI_UINT32 port_remote_mac_indicated[PI_PHY_K_MAX]; + PI_UINT32 port_ce_state[PI_PHY_K_MAX]; + PI_UINT32 port_paths_requested[PI_PHY_K_MAX]; + PI_UINT32 port_mac_placement[PI_PHY_K_MAX]; + PI_UINT32 port_available_paths[PI_PHY_K_MAX]; + PI_UINT32 port_mac_loop_time[PI_PHY_K_MAX]; + PI_UINT32 port_tb_max[PI_PHY_K_MAX]; + PI_UINT32 port_bs_flag[PI_PHY_K_MAX]; + /* port_lct_fail_cts[PI_PHY_K_MAX]; */ + PI_UINT32 port_ler_estimate[PI_PHY_K_MAX]; + /* port_lem_reject_cts[PI_PHY_K_MAX]; */ + /* port_lem_cts[PI_PHY_K_MAX]; */ + PI_UINT32 port_ler_cutoff[PI_PHY_K_MAX]; + PI_UINT32 port_ler_alarm[PI_PHY_K_MAX]; + PI_UINT32 port_connect_state[PI_PHY_K_MAX]; + PI_UINT32 port_pcm_state[PI_PHY_K_MAX]; + PI_UINT32 port_pc_withhold[PI_PHY_K_MAX]; + PI_UINT32 port_ler_condition[PI_PHY_K_MAX]; + PI_UINT32 port_chip_set[PI_PHY_K_MAX]; + PI_UINT32 port_action[PI_PHY_K_MAX]; + + /* ATTACHMENT GROUP */ + + PI_UINT32 attachment_class; + PI_UINT32 attachment_ob_present; + PI_UINT32 attachment_imax_expiration; + PI_UINT32 attachment_inserted_status; + PI_UINT32 attachment_insert_policy; + + /* CHIP SET GROUP => Does not need to be implemented */ + + } PI_CMD_FDDI_MIB_GET_RSP; + +/* DEC_Ext_MIB_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_DEC_EXT_MIB_GET_REQ; + +/* DEC_Ext_MIB_Get (efddi and efdx groups only) Response */ + +typedef struct + { + PI_RSP_HEADER header; + + /* SMT GROUP */ + + PI_UINT32 esmt_station_type; + + /* MAC GROUP */ + + PI_UINT32 emac_link_state; + PI_UINT32 emac_ring_purger_state; + PI_UINT32 emac_ring_purger_enable; + PI_UINT32 emac_frame_strip_mode; + PI_UINT32 emac_ring_error_reason; + PI_UINT32 emac_up_nbr_dup_addr_flag; + PI_UINT32 emac_restricted_token_timeout; + + /* PORT GROUP */ + + PI_UINT32 eport_pmd_type[PI_PHY_K_MAX]; + PI_UINT32 eport_phy_state[PI_PHY_K_MAX]; + PI_UINT32 eport_reject_reason[PI_PHY_K_MAX]; + + /* FDX (Full-Duplex) GROUP */ + + PI_UINT32 efdx_enable; /* Valid only in SMT 7.3 */ + PI_UINT32 efdx_op; /* Valid only in SMT 7.3 */ + PI_UINT32 efdx_state; /* Valid only in SMT 7.3 */ + + } PI_CMD_DEC_EXT_MIB_GET_RSP; + +typedef struct + { + PI_CNTR traces_rcvd; /* Station */ + PI_CNTR frame_cnt; /* Link */ + PI_CNTR error_cnt; + PI_CNTR lost_cnt; + PI_CNTR octets_rcvd; + PI_CNTR octets_sent; + PI_CNTR pdus_rcvd; + PI_CNTR pdus_sent; + PI_CNTR mcast_octets_rcvd; + PI_CNTR mcast_octets_sent; + PI_CNTR mcast_pdus_rcvd; + PI_CNTR mcast_pdus_sent; + PI_CNTR xmt_underruns; + PI_CNTR xmt_failures; + PI_CNTR block_check_errors; + PI_CNTR frame_status_errors; + PI_CNTR pdu_length_errors; + PI_CNTR rcv_overruns; + PI_CNTR user_buff_unavailable; + PI_CNTR inits_initiated; + PI_CNTR inits_rcvd; + PI_CNTR beacons_initiated; + PI_CNTR dup_addrs; + PI_CNTR dup_tokens; + PI_CNTR purge_errors; + PI_CNTR fci_strip_errors; + PI_CNTR traces_initiated; + PI_CNTR directed_beacons_rcvd; + PI_CNTR emac_frame_alignment_errors; + PI_CNTR ebuff_errors[PI_PHY_K_MAX]; /* Phy */ + PI_CNTR lct_rejects[PI_PHY_K_MAX]; + PI_CNTR lem_rejects[PI_PHY_K_MAX]; + PI_CNTR link_errors[PI_PHY_K_MAX]; + PI_CNTR connections[PI_PHY_K_MAX]; + PI_CNTR copied_cnt; /* Valid only if using SMT 7.3 */ + PI_CNTR transmit_cnt; /* Valid only if using SMT 7.3 */ + PI_CNTR tokens; + } PI_CNTR_BLK; + +/* Counters_Get Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_CNTRS_GET_REQ; + +/* Counters_Get Response */ + +typedef struct + { + PI_RSP_HEADER header; + PI_CNTR time_since_reset; + PI_CNTR_BLK cntrs; + } PI_CMD_CNTRS_GET_RSP; + +/* Counters_Set Request */ + +typedef struct + { + PI_UINT32 cmd_type; + PI_CNTR_BLK cntrs; + } PI_CMD_CNTRS_SET_REQ; + +/* Counters_Set Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_CNTRS_SET_RSP; + +/* Error_Log_Clear Request */ + +typedef struct + { + PI_UINT32 cmd_type; + } PI_CMD_ERROR_LOG_CLEAR_REQ; + +/* Error_Log_Clear Response */ + +typedef struct + { + PI_RSP_HEADER header; + } PI_CMD_ERROR_LOG_CLEAR_RSP; + +/* Error_Log_Get Request */ + +#define PI_LOG_ENTRY_K_INDEX_MIN 0 /* Minimum index for entry */ + +typedef struct + { + PI_UINT32 cmd_type; + PI_UINT32 entry_index; + } PI_CMD_ERROR_LOG_GET_REQ; + +/* Error_Log_Get Response */ + +#define PI_K_LOG_FW_SIZE 111 /* Max number of fw longwords */ +#define PI_K_LOG_DIAG_SIZE 6 /* Max number of diag longwords */ + +typedef struct + { + struct + { + PI_UINT32 fru_imp_mask; + PI_UINT32 test_id; + PI_UINT32 reserved[PI_K_LOG_DIAG_SIZE]; + } diag; + PI_UINT32 fw[PI_K_LOG_FW_SIZE]; + } PI_LOG_ENTRY; + +typedef struct + { + PI_RSP_HEADER header; + PI_UINT32 event_status; + PI_UINT32 caller_id; + PI_UINT32 timestamp_l; + PI_UINT32 timestamp_h; + PI_UINT32 write_count; + PI_LOG_ENTRY entry_info; + } PI_CMD_ERROR_LOG_GET_RSP; + +/* Define error log related constants and types. */ +/* Not all of the caller id's can occur. The only ones currently */ +/* implemented are: none, selftest, mfg, fw, console */ + +#define PI_LOG_EVENT_STATUS_K_VALID 0 /* Valid Event Status */ +#define PI_LOG_EVENT_STATUS_K_INVALID 1 /* Invalid Event Status */ +#define PI_LOG_CALLER_ID_K_NONE 0 /* No caller */ +#define PI_LOG_CALLER_ID_K_SELFTEST 1 /* Normal power-up selftest */ +#define PI_LOG_CALLER_ID_K_MFG 2 /* Mfg power-up selftest */ +#define PI_LOG_CALLER_ID_K_ONLINE 3 /* On-line diagnostics */ +#define PI_LOG_CALLER_ID_K_HW 4 /* Hardware */ +#define PI_LOG_CALLER_ID_K_FW 5 /* Firmware */ +#define PI_LOG_CALLER_ID_K_CNS_HW 6 /* CNS firmware */ +#define PI_LOG_CALLER_ID_K_CNS_FW 7 /* CNS hardware */ +#define PI_LOG_CALLER_ID_K_CONSOLE 8 /* Console Caller Id */ + +/* + * Place all DMA commands in the following request and response structures + * to simplify code. + */ + +typedef union + { + PI_UINT32 cmd_type; + PI_CMD_START_REQ start; + PI_CMD_FILTERS_SET_REQ filter_set; + PI_CMD_FILTERS_GET_REQ filter_get; + PI_CMD_CHARS_SET_REQ char_set; + PI_CMD_ADDR_FILTER_SET_REQ addr_filter_set; + PI_CMD_ADDR_FILTER_GET_REQ addr_filter_get; + PI_CMD_STATUS_CHARS_GET_REQ stat_char_get; + PI_CMD_CNTRS_GET_REQ cntrs_get; + PI_CMD_CNTRS_SET_REQ cntrs_set; + PI_CMD_ERROR_LOG_CLEAR_REQ error_log_clear; + PI_CMD_ERROR_LOG_GET_REQ error_log_read; + PI_CMD_SNMP_SET_REQ snmp_set; + PI_CMD_FDDI_MIB_GET_REQ fddi_mib_get; + PI_CMD_DEC_EXT_MIB_GET_REQ dec_mib_get; + PI_CMD_SMT_MIB_SET_REQ smt_mib_set; + PI_CMD_SMT_MIB_GET_REQ smt_mib_get; + char pad[PI_CMD_REQ_K_SIZE_MAX]; + } PI_DMA_CMD_REQ; + +typedef union + { + PI_RSP_HEADER header; + PI_CMD_START_RSP start; + PI_CMD_FILTERS_SET_RSP filter_set; + PI_CMD_FILTERS_GET_RSP filter_get; + PI_CMD_CHARS_SET_RSP char_set; + PI_CMD_ADDR_FILTER_SET_RSP addr_filter_set; + PI_CMD_ADDR_FILTER_GET_RSP addr_filter_get; + PI_CMD_STATUS_CHARS_GET_RSP stat_char_get; + PI_CMD_CNTRS_GET_RSP cntrs_get; + PI_CMD_CNTRS_SET_RSP cntrs_set; + PI_CMD_ERROR_LOG_CLEAR_RSP error_log_clear; + PI_CMD_ERROR_LOG_GET_RSP error_log_get; + PI_CMD_SNMP_SET_RSP snmp_set; + PI_CMD_FDDI_MIB_GET_RSP fddi_mib_get; + PI_CMD_DEC_EXT_MIB_GET_RSP dec_mib_get; + PI_CMD_SMT_MIB_SET_RSP smt_mib_set; + PI_CMD_SMT_MIB_GET_RSP smt_mib_get; + char pad[PI_CMD_RSP_K_SIZE_MAX]; + } PI_DMA_CMD_RSP; + +typedef union + { + PI_DMA_CMD_REQ request; + PI_DMA_CMD_RSP response; + } PI_DMA_CMD_BUFFER; + + +/* Define format of Consumer Block (resident in host memory) */ + +typedef struct + { + volatile PI_UINT32 xmt_rcv_data; + volatile PI_UINT32 reserved_1; + volatile PI_UINT32 smt_host; + volatile PI_UINT32 reserved_2; + volatile PI_UINT32 unsol; + volatile PI_UINT32 reserved_3; + volatile PI_UINT32 cmd_rsp; + volatile PI_UINT32 reserved_4; + volatile PI_UINT32 cmd_req; + volatile PI_UINT32 reserved_5; + } PI_CONSUMER_BLOCK; + +#define PI_CONS_M_RCV_INDEX 0x000000FF +#define PI_CONS_M_XMT_INDEX 0x00FF0000 +#define PI_CONS_V_RCV_INDEX 0 +#define PI_CONS_V_XMT_INDEX 16 + +/* Offsets into consumer block */ + +#define PI_CONS_BLK_K_XMT_RCV 0x00 +#define PI_CONS_BLK_K_SMT_HOST 0x08 +#define PI_CONS_BLK_K_UNSOL 0x10 +#define PI_CONS_BLK_K_CMD_RSP 0x18 +#define PI_CONS_BLK_K_CMD_REQ 0x20 + +/* Offsets into descriptor block */ + +#define PI_DESCR_BLK_K_RCV_DATA 0x0000 +#define PI_DESCR_BLK_K_XMT_DATA 0x0800 +#define PI_DESCR_BLK_K_SMT_HOST 0x1000 +#define PI_DESCR_BLK_K_UNSOL 0x1200 +#define PI_DESCR_BLK_K_CMD_RSP 0x1280 +#define PI_DESCR_BLK_K_CMD_REQ 0x1300 + +/* Define format of a rcv descr (Rcv Data, Cmd Rsp, Unsolicited, SMT Host) */ +/* Note a field has been added for later versions of the PDQ to allow for */ +/* finer granularity of the rcv buffer alignment. For backwards */ +/* compatibility, the two bits (which allow the rcv buffer to be longword */ +/* aligned) have been added at the MBZ bits. To support previous drivers, */ +/* the MBZ definition is left intact. */ + +typedef struct + { + PI_UINT32 long_0; + PI_UINT32 long_1; + } PI_RCV_DESCR; + +#define PI_RCV_DESCR_M_SOP 0x80000000 +#define PI_RCV_DESCR_M_SEG_LEN_LO 0x60000000 +#define PI_RCV_DESCR_M_MBZ 0x60000000 +#define PI_RCV_DESCR_M_SEG_LEN 0x1F800000 +#define PI_RCV_DESCR_M_SEG_LEN_HI 0x1FF00000 +#define PI_RCV_DESCR_M_SEG_CNT 0x000F0000 +#define PI_RCV_DESCR_M_BUFF_HI 0x0000FFFF + +#define PI_RCV_DESCR_V_SOP 31 +#define PI_RCV_DESCR_V_SEG_LEN_LO 29 +#define PI_RCV_DESCR_V_MBZ 29 +#define PI_RCV_DESCR_V_SEG_LEN 23 +#define PI_RCV_DESCR_V_SEG_LEN_HI 20 +#define PI_RCV_DESCR_V_SEG_CNT 16 +#define PI_RCV_DESCR_V_BUFF_HI 0 + +/* Define the format of a transmit descriptor (Xmt Data, Cmd Req) */ + +typedef struct + { + PI_UINT32 long_0; + PI_UINT32 long_1; + } PI_XMT_DESCR; + +#define PI_XMT_DESCR_M_SOP 0x80000000 +#define PI_XMT_DESCR_M_EOP 0x40000000 +#define PI_XMT_DESCR_M_MBZ 0x20000000 +#define PI_XMT_DESCR_M_SEG_LEN 0x1FFF0000 +#define PI_XMT_DESCR_M_BUFF_HI 0x0000FFFF + +#define PI_XMT_DESCR_V_SOP 31 +#define PI_XMT_DESCR_V_EOP 30 +#define PI_XMT_DESCR_V_MBZ 29 +#define PI_XMT_DESCR_V_SEG_LEN 16 +#define PI_XMT_DESCR_V_BUFF_HI 0 + +/* Define format of the Descriptor Block (resident in host memory) */ + +#define PI_RCV_DATA_K_NUM_ENTRIES 256 +#define PI_XMT_DATA_K_NUM_ENTRIES 256 +#define PI_SMT_HOST_K_NUM_ENTRIES 64 +#define PI_UNSOL_K_NUM_ENTRIES 16 +#define PI_CMD_RSP_K_NUM_ENTRIES 16 +#define PI_CMD_REQ_K_NUM_ENTRIES 16 + +typedef struct + { + PI_RCV_DESCR rcv_data[PI_RCV_DATA_K_NUM_ENTRIES]; + PI_XMT_DESCR xmt_data[PI_XMT_DATA_K_NUM_ENTRIES]; + PI_RCV_DESCR smt_host[PI_SMT_HOST_K_NUM_ENTRIES]; + PI_RCV_DESCR unsol[PI_UNSOL_K_NUM_ENTRIES]; + PI_RCV_DESCR cmd_rsp[PI_CMD_RSP_K_NUM_ENTRIES]; + PI_XMT_DESCR cmd_req[PI_CMD_REQ_K_NUM_ENTRIES]; + } PI_DESCR_BLOCK; + +/* Define Port Registers - offsets from PDQ Base address */ + +#define PI_PDQ_K_REG_PORT_RESET 0x00000000 +#define PI_PDQ_K_REG_HOST_DATA 0x00000004 +#define PI_PDQ_K_REG_PORT_CTRL 0x00000008 +#define PI_PDQ_K_REG_PORT_DATA_A 0x0000000C +#define PI_PDQ_K_REG_PORT_DATA_B 0x00000010 +#define PI_PDQ_K_REG_PORT_STATUS 0x00000014 +#define PI_PDQ_K_REG_TYPE_0_STATUS 0x00000018 +#define PI_PDQ_K_REG_HOST_INT_ENB 0x0000001C +#define PI_PDQ_K_REG_TYPE_2_PROD_NOINT 0x00000020 +#define PI_PDQ_K_REG_TYPE_2_PROD 0x00000024 +#define PI_PDQ_K_REG_CMD_RSP_PROD 0x00000028 +#define PI_PDQ_K_REG_CMD_REQ_PROD 0x0000002C +#define PI_PDQ_K_REG_SMT_HOST_PROD 0x00000030 +#define PI_PDQ_K_REG_UNSOL_PROD 0x00000034 + +/* Port Control Register - Command codes for primary commands */ + +#define PI_PCTRL_M_CMD_ERROR 0x8000 +#define PI_PCTRL_M_BLAST_FLASH 0x4000 +#define PI_PCTRL_M_HALT 0x2000 +#define PI_PCTRL_M_COPY_DATA 0x1000 +#define PI_PCTRL_M_ERROR_LOG_START 0x0800 +#define PI_PCTRL_M_ERROR_LOG_READ 0x0400 +#define PI_PCTRL_M_XMT_DATA_FLUSH_DONE 0x0200 +#define PI_PCTRL_M_INIT 0x0100 +#define PI_PCTRL_M_INIT_START 0x0080 +#define PI_PCTRL_M_CONS_BLOCK 0x0040 +#define PI_PCTRL_M_UNINIT 0x0020 +#define PI_PCTRL_M_RING_MEMBER 0x0010 +#define PI_PCTRL_M_MLA 0x0008 +#define PI_PCTRL_M_FW_REV_READ 0x0004 +#define PI_PCTRL_M_DEV_SPECIFIC 0x0002 +#define PI_PCTRL_M_SUB_CMD 0x0001 + +/* Define sub-commands accessed via the PI_PCTRL_M_SUB_CMD command */ + +#define PI_SUB_CMD_K_LINK_UNINIT 0x0001 +#define PI_SUB_CMD_K_BURST_SIZE_SET 0x0002 +#define PI_SUB_CMD_K_PDQ_REV_GET 0x0004 +#define PI_SUB_CMD_K_HW_REV_GET 0x0008 + +/* Define some Port Data B values */ + +#define PI_PDATA_B_DMA_BURST_SIZE_4 0 /* valid values for command */ +#define PI_PDATA_B_DMA_BURST_SIZE_8 1 +#define PI_PDATA_B_DMA_BURST_SIZE_16 2 +#define PI_PDATA_B_DMA_BURST_SIZE_32 3 /* not supported on PCI */ +#define PI_PDATA_B_DMA_BURST_SIZE_DEF PI_PDATA_B_DMA_BURST_SIZE_16 + +/* Port Data A Reset state */ + +#define PI_PDATA_A_RESET_M_UPGRADE 0x00000001 +#define PI_PDATA_A_RESET_M_SOFT_RESET 0x00000002 +#define PI_PDATA_A_RESET_M_SKIP_ST 0x00000004 + +/* Read adapter MLA address port control command constants */ + +#define PI_PDATA_A_MLA_K_LO 0 +#define PI_PDATA_A_MLA_K_HI 1 + +/* Byte Swap values for init command */ + +#define PI_PDATA_A_INIT_M_DESC_BLK_ADDR 0x0FFFFE000 +#define PI_PDATA_A_INIT_M_RESERVED 0x000001FFC +#define PI_PDATA_A_INIT_M_BSWAP_DATA 0x000000002 +#define PI_PDATA_A_INIT_M_BSWAP_LITERAL 0x000000001 + +#define PI_PDATA_A_INIT_V_DESC_BLK_ADDR 13 +#define PI_PDATA_A_INIT_V_RESERVED 3 +#define PI_PDATA_A_INIT_V_BSWAP_DATA 1 +#define PI_PDATA_A_INIT_V_BSWAP_LITERAL 0 + +/* Port Reset Register */ + +#define PI_RESET_M_ASSERT_RESET 1 + +/* Port Status register */ + +#define PI_PSTATUS_V_RCV_DATA_PENDING 31 +#define PI_PSTATUS_V_XMT_DATA_PENDING 30 +#define PI_PSTATUS_V_SMT_HOST_PENDING 29 +#define PI_PSTATUS_V_UNSOL_PENDING 28 +#define PI_PSTATUS_V_CMD_RSP_PENDING 27 +#define PI_PSTATUS_V_CMD_REQ_PENDING 26 +#define PI_PSTATUS_V_TYPE_0_PENDING 25 +#define PI_PSTATUS_V_RESERVED_1 16 +#define PI_PSTATUS_V_RESERVED_2 11 +#define PI_PSTATUS_V_STATE 8 +#define PI_PSTATUS_V_HALT_ID 0 + +#define PI_PSTATUS_M_RCV_DATA_PENDING 0x80000000 +#define PI_PSTATUS_M_XMT_DATA_PENDING 0x40000000 +#define PI_PSTATUS_M_SMT_HOST_PENDING 0x20000000 +#define PI_PSTATUS_M_UNSOL_PENDING 0x10000000 +#define PI_PSTATUS_M_CMD_RSP_PENDING 0x08000000 +#define PI_PSTATUS_M_CMD_REQ_PENDING 0x04000000 +#define PI_PSTATUS_M_TYPE_0_PENDING 0x02000000 +#define PI_PSTATUS_M_RESERVED_1 0x01FF0000 +#define PI_PSTATUS_M_RESERVED_2 0x0000F800 +#define PI_PSTATUS_M_STATE 0x00000700 +#define PI_PSTATUS_M_HALT_ID 0x000000FF + +/* Define Halt Id's */ +/* Do not insert into this list, only append. */ + +#define PI_HALT_ID_K_SELFTEST_TIMEOUT 0 +#define PI_HALT_ID_K_PARITY_ERROR 1 +#define PI_HALT_ID_K_HOST_DIR_HALT 2 +#define PI_HALT_ID_K_SW_FAULT 3 +#define PI_HALT_ID_K_HW_FAULT 4 +#define PI_HALT_ID_K_PC_TRACE 5 +#define PI_HALT_ID_K_DMA_ERROR 6 /* Host Data has error reg */ +#define PI_HALT_ID_K_IMAGE_CRC_ERROR 7 /* Image is bad, update it */ +#define PI_HALT_ID_K_BUS_EXCEPTION 8 /* 68K bus exception */ + +/* Host Interrupt Enable Register as seen by host */ + +#define PI_HOST_INT_M_XMT_DATA_ENB 0x80000000 /* Type 2 Enables */ +#define PI_HOST_INT_M_RCV_DATA_ENB 0x40000000 +#define PI_HOST_INT_M_SMT_HOST_ENB 0x10000000 /* Type 1 Enables */ +#define PI_HOST_INT_M_UNSOL_ENB 0x20000000 +#define PI_HOST_INT_M_CMD_RSP_ENB 0x08000000 +#define PI_HOST_INT_M_CMD_REQ_ENB 0x04000000 +#define PI_HOST_INT_M_TYPE_1_RESERVED 0x00FF0000 +#define PI_HOST_INT_M_TYPE_0_RESERVED 0x0000FF00 /* Type 0 Enables */ +#define PI_HOST_INT_M_1MS 0x00000080 +#define PI_HOST_INT_M_20MS 0x00000040 +#define PI_HOST_INT_M_CSR_CMD_DONE 0x00000020 +#define PI_HOST_INT_M_STATE_CHANGE 0x00000010 +#define PI_HOST_INT_M_XMT_FLUSH 0x00000008 +#define PI_HOST_INT_M_NXM 0x00000004 +#define PI_HOST_INT_M_PM_PAR_ERR 0x00000002 +#define PI_HOST_INT_M_BUS_PAR_ERR 0x00000001 + +#define PI_HOST_INT_V_XMT_DATA_ENB 31 /* Type 2 Enables */ +#define PI_HOST_INT_V_RCV_DATA_ENB 30 +#define PI_HOST_INT_V_SMT_HOST_ENB 29 /* Type 1 Enables */ +#define PI_HOST_INT_V_UNSOL_ENB 28 +#define PI_HOST_INT_V_CMD_RSP_ENB 27 +#define PI_HOST_INT_V_CMD_REQ_ENB 26 +#define PI_HOST_INT_V_TYPE_1_RESERVED 16 +#define PI_HOST_INT_V_TYPE_0_RESERVED 8 /* Type 0 Enables */ +#define PI_HOST_INT_V_1MS_ENB 7 +#define PI_HOST_INT_V_20MS_ENB 6 +#define PI_HOST_INT_V_CSR_CMD_DONE_ENB 5 +#define PI_HOST_INT_V_STATE_CHANGE_ENB 4 +#define PI_HOST_INT_V_XMT_FLUSH_ENB 3 +#define PI_HOST_INT_V_NXM_ENB 2 +#define PI_HOST_INT_V_PM_PAR_ERR_ENB 1 +#define PI_HOST_INT_V_BUS_PAR_ERR_ENB 0 + +#define PI_HOST_INT_K_ACK_ALL_TYPE_0 0x000000FF +#define PI_HOST_INT_K_DISABLE_ALL_INTS 0x00000000 +#define PI_HOST_INT_K_ENABLE_ALL_INTS 0xFFFFFFFF +#define PI_HOST_INT_K_ENABLE_DEF_INTS 0xC000001F + +/* Type 0 Interrupt Status Register */ + +#define PI_TYPE_0_STAT_M_1MS 0x00000080 +#define PI_TYPE_0_STAT_M_20MS 0x00000040 +#define PI_TYPE_0_STAT_M_CSR_CMD_DONE 0x00000020 +#define PI_TYPE_0_STAT_M_STATE_CHANGE 0x00000010 +#define PI_TYPE_0_STAT_M_XMT_FLUSH 0x00000008 +#define PI_TYPE_0_STAT_M_NXM 0x00000004 +#define PI_TYPE_0_STAT_M_PM_PAR_ERR 0x00000002 +#define PI_TYPE_0_STAT_M_BUS_PAR_ERR 0x00000001 + +#define PI_TYPE_0_STAT_V_1MS 7 +#define PI_TYPE_0_STAT_V_20MS 6 +#define PI_TYPE_0_STAT_V_CSR_CMD_DONE 5 +#define PI_TYPE_0_STAT_V_STATE_CHANGE 4 +#define PI_TYPE_0_STAT_V_XMT_FLUSH 3 +#define PI_TYPE_0_STAT_V_NXM 2 +#define PI_TYPE_0_STAT_V_PM_PAR_ERR 1 +#define PI_TYPE_0_STAT_V_BUS_PAR_ERR 0 + +/* Register definition structures are defined for both big and little endian systems */ + +#ifndef __BIG_ENDIAN + +/* Little endian format of Type 1 Producer register */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 prod; + PI_UINT8 comp; + PI_UINT8 mbz_1; + PI_UINT8 mbz_2; + } index; + } PI_TYPE_1_PROD_REG; + +/* Little endian format of Type 2 Producer register */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 rcv_prod; + PI_UINT8 xmt_prod; + PI_UINT8 rcv_comp; + PI_UINT8 xmt_comp; + } index; + } PI_TYPE_2_PROD_REG; + +/* Little endian format of Type 1 Consumer Block longword */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 cons; + PI_UINT8 res0; + PI_UINT8 res1; + PI_UINT8 res2; + } index; + } PI_TYPE_1_CONSUMER; + +/* Little endian format of Type 2 Consumer Block longword */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 rcv_cons; + PI_UINT8 res0; + PI_UINT8 xmt_cons; + PI_UINT8 res1; + } index; + } PI_TYPE_2_CONSUMER; + +/* Define swapping required by DMA transfers. */ +#define PI_PDATA_A_INIT_M_BSWAP_INIT \ + (PI_PDATA_A_INIT_M_BSWAP_DATA) + +#else /* __BIG_ENDIAN */ + +/* Big endian format of Type 1 Producer register */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 mbz_2; + PI_UINT8 mbz_1; + PI_UINT8 comp; + PI_UINT8 prod; + } index; + } PI_TYPE_1_PROD_REG; + +/* Big endian format of Type 2 Producer register */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 xmt_comp; + PI_UINT8 rcv_comp; + PI_UINT8 xmt_prod; + PI_UINT8 rcv_prod; + } index; + } PI_TYPE_2_PROD_REG; + +/* Big endian format of Type 1 Consumer Block longword */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 res2; + PI_UINT8 res1; + PI_UINT8 res0; + PI_UINT8 cons; + } index; + } PI_TYPE_1_CONSUMER; + +/* Big endian format of Type 2 Consumer Block longword */ + +typedef union + { + PI_UINT32 lword; + struct + { + PI_UINT8 res1; + PI_UINT8 xmt_cons; + PI_UINT8 res0; + PI_UINT8 rcv_cons; + } index; + } PI_TYPE_2_CONSUMER; + +/* Define swapping required by DMA transfers. */ +#define PI_PDATA_A_INIT_M_BSWAP_INIT \ + (PI_PDATA_A_INIT_M_BSWAP_DATA | PI_PDATA_A_INIT_M_BSWAP_LITERAL) + +#endif /* __BIG_ENDIAN */ + +/* Define TC PDQ CSR offset and length */ + +#define PI_TC_K_CSR_OFFSET 0x100000 +#define PI_TC_K_CSR_LEN 0x40 /* 64 bytes */ + +/* Define EISA controller register offsets */ + +#define PI_ESIC_K_CSR_IO_LEN 0x80 /* 128 bytes */ + +#define PI_DEFEA_K_BURST_HOLDOFF 0x040 + +#define PI_ESIC_K_SLOT_ID 0xC80 +#define PI_ESIC_K_SLOT_CNTRL 0xC84 +#define PI_ESIC_K_MEM_ADD_CMP_0 0xC85 +#define PI_ESIC_K_MEM_ADD_CMP_1 0xC86 +#define PI_ESIC_K_MEM_ADD_CMP_2 0xC87 +#define PI_ESIC_K_MEM_ADD_HI_CMP_0 0xC88 +#define PI_ESIC_K_MEM_ADD_HI_CMP_1 0xC89 +#define PI_ESIC_K_MEM_ADD_HI_CMP_2 0xC8A +#define PI_ESIC_K_MEM_ADD_MASK_0 0xC8B +#define PI_ESIC_K_MEM_ADD_MASK_1 0xC8C +#define PI_ESIC_K_MEM_ADD_MASK_2 0xC8D +#define PI_ESIC_K_MEM_ADD_LO_CMP_0 0xC8E +#define PI_ESIC_K_MEM_ADD_LO_CMP_1 0xC8F +#define PI_ESIC_K_MEM_ADD_LO_CMP_2 0xC90 +#define PI_ESIC_K_IO_ADD_CMP_0_0 0xC91 +#define PI_ESIC_K_IO_ADD_CMP_0_1 0xC92 +#define PI_ESIC_K_IO_ADD_CMP_1_0 0xC93 +#define PI_ESIC_K_IO_ADD_CMP_1_1 0xC94 +#define PI_ESIC_K_IO_ADD_CMP_2_0 0xC95 +#define PI_ESIC_K_IO_ADD_CMP_2_1 0xC96 +#define PI_ESIC_K_IO_ADD_CMP_3_0 0xC97 +#define PI_ESIC_K_IO_ADD_CMP_3_1 0xC98 +#define PI_ESIC_K_IO_ADD_MASK_0_0 0xC99 +#define PI_ESIC_K_IO_ADD_MASK_0_1 0xC9A +#define PI_ESIC_K_IO_ADD_MASK_1_0 0xC9B +#define PI_ESIC_K_IO_ADD_MASK_1_1 0xC9C +#define PI_ESIC_K_IO_ADD_MASK_2_0 0xC9D +#define PI_ESIC_K_IO_ADD_MASK_2_1 0xC9E +#define PI_ESIC_K_IO_ADD_MASK_3_0 0xC9F +#define PI_ESIC_K_IO_ADD_MASK_3_1 0xCA0 +#define PI_ESIC_K_MOD_CONFIG_1 0xCA1 +#define PI_ESIC_K_MOD_CONFIG_2 0xCA2 +#define PI_ESIC_K_MOD_CONFIG_3 0xCA3 +#define PI_ESIC_K_MOD_CONFIG_4 0xCA4 +#define PI_ESIC_K_MOD_CONFIG_5 0xCA5 +#define PI_ESIC_K_MOD_CONFIG_6 0xCA6 +#define PI_ESIC_K_MOD_CONFIG_7 0xCA7 +#define PI_ESIC_K_DIP_SWITCH 0xCA8 +#define PI_ESIC_K_IO_CONFIG_STAT_0 0xCA9 +#define PI_ESIC_K_IO_CONFIG_STAT_1 0xCAA +#define PI_ESIC_K_DMA_CONFIG 0xCAB +#define PI_ESIC_K_INPUT_PORT 0xCAC +#define PI_ESIC_K_OUTPUT_PORT 0xCAD +#define PI_ESIC_K_FUNCTION_CNTRL 0xCAE + +/* Define the bits in the function control register. */ + +#define PI_FUNCTION_CNTRL_M_IOCS0 0x01 +#define PI_FUNCTION_CNTRL_M_IOCS1 0x02 +#define PI_FUNCTION_CNTRL_M_IOCS2 0x04 +#define PI_FUNCTION_CNTRL_M_IOCS3 0x08 +#define PI_FUNCTION_CNTRL_M_MEMCS0 0x10 +#define PI_FUNCTION_CNTRL_M_MEMCS1 0x20 +#define PI_FUNCTION_CNTRL_M_DMA 0x80 + +/* Define the bits in the slot control register. */ + +#define PI_SLOT_CNTRL_M_RESET 0x04 /* Don't use. */ +#define PI_SLOT_CNTRL_M_ERROR 0x02 /* Not implemented. */ +#define PI_SLOT_CNTRL_M_ENB 0x01 /* Must be set. */ + +/* Define the bits in the burst holdoff register. */ + +#define PI_BURST_HOLDOFF_M_HOLDOFF 0xFC +#define PI_BURST_HOLDOFF_M_RESERVED 0x02 +#define PI_BURST_HOLDOFF_M_MEM_MAP 0x01 + +#define PI_BURST_HOLDOFF_V_HOLDOFF 2 +#define PI_BURST_HOLDOFF_V_RESERVED 1 +#define PI_BURST_HOLDOFF_V_MEM_MAP 0 + +/* Define the implicit mask of the Memory Address Mask Register. */ + +#define PI_MEM_ADD_MASK_M 0x3ff + +/* + * Define the fields in the IO Compare registers. + * The driver must initialize the slot field with the slot ID shifted by the + * amount shown below. + */ + +#define PI_IO_CMP_V_SLOT 4 + +/* Define the fields in the Interrupt Channel Configuration and Status reg */ + +#define PI_CONFIG_STAT_0_M_PEND 0x80 +#define PI_CONFIG_STAT_0_M_RES_1 0x40 +#define PI_CONFIG_STAT_0_M_IREQ_OUT 0x20 +#define PI_CONFIG_STAT_0_M_IREQ_IN 0x10 +#define PI_CONFIG_STAT_0_M_INT_ENB 0x08 +#define PI_CONFIG_STAT_0_M_RES_0 0x04 +#define PI_CONFIG_STAT_0_M_IRQ 0x03 + +#define PI_CONFIG_STAT_0_V_PEND 7 +#define PI_CONFIG_STAT_0_V_RES_1 6 +#define PI_CONFIG_STAT_0_V_IREQ_OUT 5 +#define PI_CONFIG_STAT_0_V_IREQ_IN 4 +#define PI_CONFIG_STAT_0_V_INT_ENB 3 +#define PI_CONFIG_STAT_0_V_RES_0 2 +#define PI_CONFIG_STAT_0_V_IRQ 0 + +#define PI_CONFIG_STAT_0_IRQ_K_9 0 +#define PI_CONFIG_STAT_0_IRQ_K_10 1 +#define PI_CONFIG_STAT_0_IRQ_K_11 2 +#define PI_CONFIG_STAT_0_IRQ_K_15 3 + +/* Define DEC FDDIcontroller/EISA (DEFEA) EISA hardware ID's */ + +#define DEFEA_PRODUCT_ID 0x0030A310 /* DEC product 300 (no rev) */ +#define DEFEA_PROD_ID_1 0x0130A310 /* DEC product 300, rev 1 */ +#define DEFEA_PROD_ID_2 0x0230A310 /* DEC product 300, rev 2 */ +#define DEFEA_PROD_ID_3 0x0330A310 /* DEC product 300, rev 3 */ +#define DEFEA_PROD_ID_4 0x0430A310 /* DEC product 300, rev 4 */ + +/**********************************************/ +/* Digital PFI Specification v1.0 Definitions */ +/**********************************************/ + +/* PCI Configuration Space Constants */ + +#define PFI_K_LAT_TIMER_DEF 0x88 /* def max master latency timer */ +#define PFI_K_LAT_TIMER_MIN 0x20 /* min max master latency timer */ +#define PFI_K_CSR_MEM_LEN 0x80 /* 128 bytes */ +#define PFI_K_CSR_IO_LEN 0x80 /* 128 bytes */ +#define PFI_K_PKT_MEM_LEN 0x10000 /* 64K bytes */ + +/* PFI Register Offsets (starting at PDQ Register Base Address) */ + +#define PFI_K_REG_RESERVED_0 0X00000038 +#define PFI_K_REG_RESERVED_1 0X0000003C +#define PFI_K_REG_MODE_CTRL 0X00000040 +#define PFI_K_REG_STATUS 0X00000044 +#define PFI_K_REG_FIFO_WRITE 0X00000048 +#define PFI_K_REG_FIFO_READ 0X0000004C + +/* PFI Mode Control Register Constants */ + +#define PFI_MODE_M_RESERVED 0XFFFFFFF0 +#define PFI_MODE_M_TGT_ABORT_ENB 0X00000008 +#define PFI_MODE_M_PDQ_INT_ENB 0X00000004 +#define PFI_MODE_M_PFI_INT_ENB 0X00000002 +#define PFI_MODE_M_DMA_ENB 0X00000001 + +#define PFI_MODE_V_RESERVED 4 +#define PFI_MODE_V_TGT_ABORT_ENB 3 +#define PFI_MODE_V_PDQ_INT_ENB 2 +#define PFI_MODE_V_PFI_INT_ENB 1 +#define PFI_MODE_V_DMA_ENB 0 + +#define PFI_MODE_K_ALL_DISABLE 0X00000000 + +/* PFI Status Register Constants */ + +#define PFI_STATUS_M_RESERVED 0XFFFFFFC0 +#define PFI_STATUS_M_PFI_ERROR 0X00000020 /* only valid in rev 1 or later PFI */ +#define PFI_STATUS_M_PDQ_INT 0X00000010 +#define PFI_STATUS_M_PDQ_DMA_ABORT 0X00000008 +#define PFI_STATUS_M_FIFO_FULL 0X00000004 +#define PFI_STATUS_M_FIFO_EMPTY 0X00000002 +#define PFI_STATUS_M_DMA_IN_PROGRESS 0X00000001 + +#define PFI_STATUS_V_RESERVED 6 +#define PFI_STATUS_V_PFI_ERROR 5 /* only valid in rev 1 or later PFI */ +#define PFI_STATUS_V_PDQ_INT 4 +#define PFI_STATUS_V_PDQ_DMA_ABORT 3 +#define PFI_STATUS_V_FIFO_FULL 2 +#define PFI_STATUS_V_FIFO_EMPTY 1 +#define PFI_STATUS_V_DMA_IN_PROGRESS 0 + +#define DFX_FC_PRH2_PRH1_PRH0 0x54003820 /* Packet Request Header bytes + FC */ +#define DFX_PRH0_BYTE 0x20 /* Packet Request Header byte 0 */ +#define DFX_PRH1_BYTE 0x38 /* Packet Request Header byte 1 */ +#define DFX_PRH2_BYTE 0x00 /* Packet Request Header byte 2 */ + +/* Driver routine status (return) codes */ + +#define DFX_K_SUCCESS 0 /* routine succeeded */ +#define DFX_K_FAILURE 1 /* routine failed */ +#define DFX_K_OUTSTATE 2 /* bad state for command */ +#define DFX_K_HW_TIMEOUT 3 /* command timed out */ + +/* Define LLC host receive buffer min/max/default values */ + +#define RCV_BUFS_MIN 2 /* minimum pre-allocated receive buffers */ +#define RCV_BUFS_MAX 32 /* maximum pre-allocated receive buffers */ +#define RCV_BUFS_DEF 8 /* default pre-allocated receive buffers */ + +/* Define offsets into FDDI LLC or SMT receive frame buffers - used when indicating frames */ + +#define RCV_BUFF_K_DESCR 0 /* four byte FMC descriptor */ +#define RCV_BUFF_K_PADDING 4 /* three null bytes */ +#define RCV_BUFF_K_FC 7 /* one byte frame control */ +#define RCV_BUFF_K_DA 8 /* six byte destination address */ +#define RCV_BUFF_K_SA 14 /* six byte source address */ +#define RCV_BUFF_K_DATA 20 /* offset to start of packet data */ + +/* Define offsets into FDDI LLC transmit frame buffers - used when sending frames */ + +#define XMT_BUFF_K_FC 0 /* one byte frame control */ +#define XMT_BUFF_K_DA 1 /* six byte destination address */ +#define XMT_BUFF_K_SA 7 /* six byte source address */ +#define XMT_BUFF_K_DATA 13 /* offset to start of packet data */ + +/* Macro for checking a "value" is within a specific range */ + +#define IN_RANGE(value,low,high) ((value >= low) && (value <= high)) + +/* Only execute special print call when debug driver was built */ + +#ifdef DEFXX_DEBUG +#define DBG_printk(args...) printk(## args) +#else +#define DBG_printk(args...) +#endif + +/* Define constants for masking/unmasking interrupts */ + +#define DFX_MASK_INTERRUPTS 1 +#define DFX_UNMASK_INTERRUPTS 0 + +/* Define structure for driver transmit descriptor block */ + +typedef struct + { + struct sk_buff *p_skb; /* ptr to skb */ + } XMT_DRIVER_DESCR; + +typedef struct DFX_board_tag + { + /* Keep virtual and physical pointers to locked, physically contiguous memory */ + + char *kmalloced; /* pci_free_consistent this on unload */ + dma_addr_t kmalloced_dma; + /* DMA handle for the above */ + PI_DESCR_BLOCK *descr_block_virt; /* PDQ descriptor block virt address */ + dma_addr_t descr_block_phys; /* PDQ descriptor block phys address */ + PI_DMA_CMD_REQ *cmd_req_virt; /* Command request buffer virt address */ + dma_addr_t cmd_req_phys; /* Command request buffer phys address */ + PI_DMA_CMD_RSP *cmd_rsp_virt; /* Command response buffer virt address */ + dma_addr_t cmd_rsp_phys; /* Command response buffer phys address */ + char *rcv_block_virt; /* LLC host receive queue buf blk virt */ + dma_addr_t rcv_block_phys; /* LLC host receive queue buf blk phys */ + PI_CONSUMER_BLOCK *cons_block_virt; /* PDQ consumer block virt address */ + dma_addr_t cons_block_phys; /* PDQ consumer block phys address */ + + /* Keep local copies of Type 1 and Type 2 register data */ + + PI_TYPE_1_PROD_REG cmd_req_reg; /* Command Request register */ + PI_TYPE_1_PROD_REG cmd_rsp_reg; /* Command Response register */ + PI_TYPE_2_PROD_REG rcv_xmt_reg; /* Type 2 (RCV/XMT) register */ + + /* Storage for unicast and multicast address entries in adapter CAM */ + + u8 uc_table[1*FDDI_K_ALEN]; + u32 uc_count; /* number of unicast addresses */ + u8 mc_table[PI_CMD_ADDR_FILTER_K_SIZE*FDDI_K_ALEN]; + u32 mc_count; /* number of multicast addresses */ + + /* Current packet filter settings */ + + u32 ind_group_prom; /* LLC individual & group frame prom mode */ + u32 group_prom; /* LLC group (multicast) frame prom mode */ + + /* Link available flag needed to determine whether to drop outgoing packet requests */ + + u32 link_available; /* is link available? */ + + /* Resources to indicate reset type when resetting adapter */ + + u32 reset_type; /* skip or rerun diagnostics */ + + /* Store pointers to receive buffers for queue processing code */ + + char *p_rcv_buff_va[PI_RCV_DATA_K_NUM_ENTRIES]; + + /* Store pointers to transmit buffers for transmit completion code */ + + XMT_DRIVER_DESCR xmt_drv_descr_blk[PI_XMT_DATA_K_NUM_ENTRIES]; + + /* Transmit spinlocks */ + + spinlock_t lock; + + /* Store device, bus-specific, and parameter information for this adapter */ + + struct net_device *dev; /* pointer to device structure */ + union { + void __iomem *mem; + int port; + } base; /* base address */ + struct device *bus_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) */ + u32 rcv_bufs_to_post; /* receive buffers to post for LLC host queue */ + u8 factory_mac_addr[FDDI_K_ALEN]; /* factory (on-board) MAC address */ + + /* Common FDDI statistics structure and private counters */ + + struct fddi_statistics stats; + + u32 rcv_discards; + u32 rcv_crc_errors; + u32 rcv_frame_status_errors; + u32 rcv_length_errors; + u32 rcv_total_frames; + u32 rcv_multicast_frames; + u32 rcv_total_bytes; + + u32 xmt_discards; + u32 xmt_length_errors; + u32 xmt_total_frames; + u32 xmt_total_bytes; + } DFX_board_t; + +#endif /* #ifndef _DEFXX_H_ */ diff --git a/drivers/net/fddi/skfp/Makefile b/drivers/net/fddi/skfp/Makefile new file mode 100644 index 0000000..b0be023 --- /dev/null +++ b/drivers/net/fddi/skfp/Makefile @@ -0,0 +1,20 @@ +# +# Makefile for the SysKonnect FDDI PCI adapter driver +# + +obj-$(CONFIG_SKFP) += skfp.o + +skfp-objs := skfddi.o hwmtm.o fplustm.o smt.o cfm.o \ + ecm.o pcmplc.o pmf.o queue.o rmt.o \ + smtdef.o smtinit.o smttimer.o srf.o hwt.o \ + drvfbi.o ess.o + +# NOTE: +# Compiling this driver produces some warnings (and some more are +# switched off below), but I did not fix this, because the Hardware +# Module source (see skfddi.c for details) is used for different +# drivers, and fixing it for Linux might bring problems on other +# projects. To keep the source common for all those drivers (and +# thus simplify fixes to it), please do not clean it up! + +ccflags-y := -Idrivers/net/skfp -DPCI -DMEM_MAPPED_IO -Wno-strict-prototypes diff --git a/drivers/net/fddi/skfp/cfm.c b/drivers/net/fddi/skfp/cfm.c new file mode 100644 index 0000000..e395ace --- /dev/null +++ b/drivers/net/fddi/skfp/cfm.c @@ -0,0 +1,627 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + SMT CFM + Configuration Management + DAS with single MAC +*/ + +/* + * Hardware independent state machine implemantation + * The following external SMT functions are referenced : + * + * queue_event() + * + * The following external HW dependent functions are referenced : + * config_mux() + * + * The following HW dependent events are required : + * NONE + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)cfm.c 2.18 98/10/06 (C) SK " ; +#endif + +/* + * FSM Macros + */ +#define AFLAG 0x10 +#define GO_STATE(x) (smc->mib.fddiSMTCF_State = (x)|AFLAG) +#define ACTIONS_DONE() (smc->mib.fddiSMTCF_State &= ~AFLAG) +#define ACTIONS(x) (x|AFLAG) + +#ifdef DEBUG +/* + * symbolic state names + */ +static const char * const cfm_states[] = { + "SC0_ISOLATED","CF1","CF2","CF3","CF4", + "SC1_WRAP_A","SC2_WRAP_B","SC5_TRHU_B","SC7_WRAP_S", + "SC9_C_WRAP_A","SC10_C_WRAP_B","SC11_C_WRAP_S","SC4_THRU_A" +} ; + +/* + * symbolic event names + */ +static const char * const cfm_events[] = { + "NONE","CF_LOOP_A","CF_LOOP_B","CF_JOIN_A","CF_JOIN_B" +} ; +#endif + +/* + * map from state to downstream port type + */ +static const unsigned char cf_to_ptype[] = { + TNONE,TNONE,TNONE,TNONE,TNONE, + TNONE,TB,TB,TS, + TA,TB,TS,TB +} ; + +/* + * CEM port states + */ +#define CEM_PST_DOWN 0 +#define CEM_PST_UP 1 +#define CEM_PST_HOLD 2 +/* define portstate array only for A and B port */ +/* Do this within the smc structure (use in multiple cards) */ + +/* + * all Globals are defined in smc.h + * struct s_cfm + */ + +/* + * function declarations + */ +static void cfm_fsm(struct s_smc *smc, int cmd); + +/* + init CFM state machine + clear all CFM vars and flags +*/ +void cfm_init(struct s_smc *smc) +{ + smc->mib.fddiSMTCF_State = ACTIONS(SC0_ISOLATED) ; + smc->r.rm_join = 0 ; + smc->r.rm_loop = 0 ; + smc->y[PA].scrub = 0 ; + smc->y[PB].scrub = 0 ; + smc->y[PA].cem_pst = CEM_PST_DOWN ; + smc->y[PB].cem_pst = CEM_PST_DOWN ; +} + +/* Some terms conditions used by the selection criteria */ +#define THRU_ENABLED(smc) (smc->y[PA].pc_mode != PM_TREE && \ + smc->y[PB].pc_mode != PM_TREE) +/* Selection criteria for the ports */ +static void selection_criteria (struct s_smc *smc, struct s_phy *phy) +{ + + switch (phy->mib->fddiPORTMy_Type) { + case TA: + if ( !THRU_ENABLED(smc) && smc->y[PB].cf_join ) { + phy->wc_flag = TRUE ; + } else { + phy->wc_flag = FALSE ; + } + + break; + case TB: + /* take precedence over PA */ + phy->wc_flag = FALSE ; + break; + case TS: + phy->wc_flag = FALSE ; + break; + case TM: + phy->wc_flag = FALSE ; + break; + } + +} + +void all_selection_criteria(struct s_smc *smc) +{ + struct s_phy *phy ; + int p ; + + for ( p = 0,phy = smc->y ; p < NUMPHYS; p++, phy++ ) { + /* Do the selection criteria */ + selection_criteria (smc,phy); + } +} + +static void cem_priv_state(struct s_smc *smc, int event) +/* State machine for private PORT states: used to optimize dual homing */ +{ + int np; /* Number of the port */ + int i; + + /* Do this only in a DAS */ + if (smc->s.sas != SMT_DAS ) + return ; + + np = event - CF_JOIN; + + if (np != PA && np != PB) { + return ; + } + /* Change the port state according to the event (portnumber) */ + if (smc->y[np].cf_join) { + smc->y[np].cem_pst = CEM_PST_UP ; + } else if (!smc->y[np].wc_flag) { + /* set the port to done only if it is not withheld */ + smc->y[np].cem_pst = CEM_PST_DOWN ; + } + + /* Don't set an hold port to down */ + + /* Check all ports of restart conditions */ + for (i = 0 ; i < 2 ; i ++ ) { + /* Check all port for PORT is on hold and no withhold is done */ + if ( smc->y[i].cem_pst == CEM_PST_HOLD && !smc->y[i].wc_flag ) { + smc->y[i].cem_pst = CEM_PST_DOWN; + queue_event(smc,(int)(EVENT_PCM+i),PC_START) ; + } + if ( smc->y[i].cem_pst == CEM_PST_UP && smc->y[i].wc_flag ) { + smc->y[i].cem_pst = CEM_PST_HOLD; + queue_event(smc,(int)(EVENT_PCM+i),PC_START) ; + } + if ( smc->y[i].cem_pst == CEM_PST_DOWN && smc->y[i].wc_flag ) { + /* + * The port must be restarted when the wc_flag + * will be reset. So set the port on hold. + */ + smc->y[i].cem_pst = CEM_PST_HOLD; + } + } + return ; +} + +/* + CFM state machine + called by dispatcher + + do + display state change + process event + until SM is stable +*/ +void cfm(struct s_smc *smc, int event) +{ + int state ; /* remember last state */ + int cond ; + int oldstate ; + + /* We will do the following: */ + /* - compute the variable WC_Flag for every port (This is where */ + /* we can extend the requested path checking !!) */ + /* - do the old (SMT 6.2 like) state machine */ + /* - do the resulting station states */ + + all_selection_criteria (smc); + + /* We will check now whether a state transition is allowed or not */ + /* - change the portstates */ + cem_priv_state (smc, event); + + oldstate = smc->mib.fddiSMTCF_State ; + do { + DB_CFM("CFM : state %s%s", + (smc->mib.fddiSMTCF_State & AFLAG) ? "ACTIONS " : "", + cfm_states[smc->mib.fddiSMTCF_State & ~AFLAG]) ; + DB_CFM(" event %s\n",cfm_events[event],0) ; + state = smc->mib.fddiSMTCF_State ; + cfm_fsm(smc,event) ; + event = 0 ; + } while (state != smc->mib.fddiSMTCF_State) ; + +#ifndef SLIM_SMT + /* + * check peer wrap condition + */ + cond = FALSE ; + if ( (smc->mib.fddiSMTCF_State == SC9_C_WRAP_A && + smc->y[PA].pc_mode == PM_PEER) || + (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B && + smc->y[PB].pc_mode == PM_PEER) || + (smc->mib.fddiSMTCF_State == SC11_C_WRAP_S && + smc->y[PS].pc_mode == PM_PEER && + smc->y[PS].mib->fddiPORTNeighborType != TS ) ) { + cond = TRUE ; + } + if (cond != smc->mib.fddiSMTPeerWrapFlag) + smt_srf_event(smc,SMT_COND_SMT_PEER_WRAP,0,cond) ; + +#if 0 + /* + * Don't send ever MAC_PATH_CHANGE events. Our MAC is hard-wired + * to the primary path. + */ + /* + * path change + */ + if (smc->mib.fddiSMTCF_State != oldstate) { + smt_srf_event(smc,SMT_EVENT_MAC_PATH_CHANGE,INDEX_MAC,0) ; + } +#endif +#endif /* no SLIM_SMT */ + + /* + * set MAC port type + */ + smc->mib.m[MAC0].fddiMACDownstreamPORTType = + cf_to_ptype[smc->mib.fddiSMTCF_State] ; + cfm_state_change(smc,(int)smc->mib.fddiSMTCF_State) ; +} + +/* + process CFM event +*/ +/*ARGSUSED1*/ +static void cfm_fsm(struct s_smc *smc, int cmd) +{ + switch(smc->mib.fddiSMTCF_State) { + case ACTIONS(SC0_ISOLATED) : + smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; + smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; + smc->mib.p[PA].fddiPORTMACPlacement = 0 ; + smc->mib.p[PB].fddiPORTMACPlacement = 0 ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ; + config_mux(smc,MUX_ISOLATE) ; /* configure PHY Mux */ + smc->r.rm_loop = FALSE ; + smc->r.rm_join = FALSE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + /* Don't do the WC-Flag changing here */ + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break; + case SC0_ISOLATED : + /*SC07*/ + /*SAS port can be PA or PB ! */ + if (smc->s.sas && (smc->y[PA].cf_join || smc->y[PA].cf_loop || + smc->y[PB].cf_join || smc->y[PB].cf_loop)) { + GO_STATE(SC11_C_WRAP_S) ; + break ; + } + /*SC01*/ + if ((smc->y[PA].cem_pst == CEM_PST_UP && smc->y[PA].cf_join && + !smc->y[PA].wc_flag) || smc->y[PA].cf_loop) { + GO_STATE(SC9_C_WRAP_A) ; + break ; + } + /*SC02*/ + if ((smc->y[PB].cem_pst == CEM_PST_UP && smc->y[PB].cf_join && + !smc->y[PB].wc_flag) || smc->y[PB].cf_loop) { + GO_STATE(SC10_C_WRAP_B) ; + break ; + } + break ; + case ACTIONS(SC9_C_WRAP_A) : + smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ; + smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; + smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ; + smc->mib.p[PB].fddiPORTMACPlacement = 0 ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ; + config_mux(smc,MUX_WRAPA) ; /* configure PHY mux */ + if (smc->y[PA].cf_loop) { + smc->r.rm_join = FALSE ; + smc->r.rm_loop = TRUE ; + queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */ + } + if (smc->y[PA].cf_join) { + smc->r.rm_loop = FALSE ; + smc->r.rm_join = TRUE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + } + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break ; + case SC9_C_WRAP_A : + /*SC10*/ + if ( (smc->y[PA].wc_flag || !smc->y[PA].cf_join) && + !smc->y[PA].cf_loop ) { + GO_STATE(SC0_ISOLATED) ; + break ; + } + /*SC12*/ + else if ( (smc->y[PB].cf_loop && smc->y[PA].cf_join && + smc->y[PA].cem_pst == CEM_PST_UP) || + ((smc->y[PB].cf_loop || + (smc->y[PB].cf_join && + smc->y[PB].cem_pst == CEM_PST_UP)) && + (smc->y[PA].pc_mode == PM_TREE || + smc->y[PB].pc_mode == PM_TREE))) { + smc->y[PA].scrub = TRUE ; + GO_STATE(SC10_C_WRAP_B) ; + break ; + } + /*SC14*/ + else if (!smc->s.attach_s && + smc->y[PA].cf_join && + smc->y[PA].cem_pst == CEM_PST_UP && + smc->y[PA].pc_mode == PM_PEER && smc->y[PB].cf_join && + smc->y[PB].cem_pst == CEM_PST_UP && + smc->y[PB].pc_mode == PM_PEER) { + smc->y[PA].scrub = TRUE ; + smc->y[PB].scrub = TRUE ; + GO_STATE(SC4_THRU_A) ; + break ; + } + /*SC15*/ + else if ( smc->s.attach_s && + smc->y[PA].cf_join && + smc->y[PA].cem_pst == CEM_PST_UP && + smc->y[PA].pc_mode == PM_PEER && + smc->y[PB].cf_join && + smc->y[PB].cem_pst == CEM_PST_UP && + smc->y[PB].pc_mode == PM_PEER) { + smc->y[PA].scrub = TRUE ; + smc->y[PB].scrub = TRUE ; + GO_STATE(SC5_THRU_B) ; + break ; + } + break ; + case ACTIONS(SC10_C_WRAP_B) : + smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; + smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ; + smc->mib.p[PA].fddiPORTMACPlacement = 0 ; + smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ; + config_mux(smc,MUX_WRAPB) ; /* configure PHY mux */ + if (smc->y[PB].cf_loop) { + smc->r.rm_join = FALSE ; + smc->r.rm_loop = TRUE ; + queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */ + } + if (smc->y[PB].cf_join) { + smc->r.rm_loop = FALSE ; + smc->r.rm_join = TRUE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + } + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break ; + case SC10_C_WRAP_B : + /*SC20*/ + if ( !smc->y[PB].cf_join && !smc->y[PB].cf_loop ) { + GO_STATE(SC0_ISOLATED) ; + break ; + } + /*SC21*/ + else if ( smc->y[PA].cf_loop && smc->y[PA].pc_mode == PM_PEER && + smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) { + smc->y[PB].scrub = TRUE ; + GO_STATE(SC9_C_WRAP_A) ; + break ; + } + /*SC24*/ + else if (!smc->s.attach_s && + smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER && + smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) { + smc->y[PA].scrub = TRUE ; + smc->y[PB].scrub = TRUE ; + GO_STATE(SC4_THRU_A) ; + break ; + } + /*SC25*/ + else if ( smc->s.attach_s && + smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER && + smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) { + smc->y[PA].scrub = TRUE ; + smc->y[PB].scrub = TRUE ; + GO_STATE(SC5_THRU_B) ; + break ; + } + break ; + case ACTIONS(SC4_THRU_A) : + smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ; + smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ; + smc->mib.p[PA].fddiPORTMACPlacement = 0 ; + smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ; + config_mux(smc,MUX_THRUA) ; /* configure PHY mux */ + smc->r.rm_loop = FALSE ; + smc->r.rm_join = TRUE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break ; + case SC4_THRU_A : + /*SC41*/ + if (smc->y[PB].wc_flag || !smc->y[PB].cf_join) { + smc->y[PA].scrub = TRUE ; + GO_STATE(SC9_C_WRAP_A) ; + break ; + } + /*SC42*/ + else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) { + smc->y[PB].scrub = TRUE ; + GO_STATE(SC10_C_WRAP_B) ; + break ; + } + /*SC45*/ + else if (smc->s.attach_s) { + smc->y[PB].scrub = TRUE ; + GO_STATE(SC5_THRU_B) ; + break ; + } + break ; + case ACTIONS(SC5_THRU_B) : + smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ; + smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ; + smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ; + smc->mib.p[PB].fddiPORTMACPlacement = 0 ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ; + config_mux(smc,MUX_THRUB) ; /* configure PHY mux */ + smc->r.rm_loop = FALSE ; + smc->r.rm_join = TRUE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break ; + case SC5_THRU_B : + /*SC51*/ + if (!smc->y[PB].cf_join || smc->y[PB].wc_flag) { + smc->y[PA].scrub = TRUE ; + GO_STATE(SC9_C_WRAP_A) ; + break ; + } + /*SC52*/ + else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) { + smc->y[PB].scrub = TRUE ; + GO_STATE(SC10_C_WRAP_B) ; + break ; + } + /*SC54*/ + else if (!smc->s.attach_s) { + smc->y[PA].scrub = TRUE ; + GO_STATE(SC4_THRU_A) ; + break ; + } + break ; + case ACTIONS(SC11_C_WRAP_S) : + smc->mib.p[PS].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ; + smc->mib.p[PS].fddiPORTMACPlacement = INDEX_MAC ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ; + config_mux(smc,MUX_WRAPS) ; /* configure PHY mux */ + if (smc->y[PA].cf_loop || smc->y[PB].cf_loop) { + smc->r.rm_join = FALSE ; + smc->r.rm_loop = TRUE ; + queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */ + } + if (smc->y[PA].cf_join || smc->y[PB].cf_join) { + smc->r.rm_loop = FALSE ; + smc->r.rm_join = TRUE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + } + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break ; + case SC11_C_WRAP_S : + /*SC70*/ + if ( !smc->y[PA].cf_join && !smc->y[PA].cf_loop && + !smc->y[PB].cf_join && !smc->y[PB].cf_loop) { + GO_STATE(SC0_ISOLATED) ; + break ; + } + break ; + default: + SMT_PANIC(smc,SMT_E0106, SMT_E0106_MSG) ; + break; + } +} + +/* + * get MAC's input Port + * return : + * PA or PB + */ +int cfm_get_mac_input(struct s_smc *smc) +{ + return (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B || + smc->mib.fddiSMTCF_State == SC5_THRU_B) ? PB : PA; +} + +/* + * get MAC's output Port + * return : + * PA or PB + */ +int cfm_get_mac_output(struct s_smc *smc) +{ + return (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B || + smc->mib.fddiSMTCF_State == SC4_THRU_A) ? PB : PA; +} + +static char path_iso[] = { + 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_ISO, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_ISO, + 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_ISO +} ; + +static char path_wrap_a[] = { + 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_PRIM, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM, + 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_ISO +} ; + +static char path_wrap_b[] = { + 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_PRIM, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM, + 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_ISO +} ; + +static char path_thru[] = { + 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_PRIM, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM, + 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_PRIM +} ; + +static char path_wrap_s[] = { + 0,0, 0,RES_PORT, 0,PS + INDEX_PORT, 0,PATH_PRIM, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM, +} ; + +static char path_iso_s[] = { + 0,0, 0,RES_PORT, 0,PS + INDEX_PORT, 0,PATH_ISO, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_ISO, +} ; + +int cem_build_path(struct s_smc *smc, char *to, int path_index) +{ + char *path ; + int len ; + + switch (smc->mib.fddiSMTCF_State) { + default : + case SC0_ISOLATED : + path = smc->s.sas ? path_iso_s : path_iso ; + len = smc->s.sas ? sizeof(path_iso_s) : sizeof(path_iso) ; + break ; + case SC9_C_WRAP_A : + path = path_wrap_a ; + len = sizeof(path_wrap_a) ; + break ; + case SC10_C_WRAP_B : + path = path_wrap_b ; + len = sizeof(path_wrap_b) ; + break ; + case SC4_THRU_A : + path = path_thru ; + len = sizeof(path_thru) ; + break ; + case SC11_C_WRAP_S : + path = path_wrap_s ; + len = sizeof(path_wrap_s) ; + break ; + } + memcpy(to,path,len) ; + + LINT_USE(path_index); + + return len; +} diff --git a/drivers/net/fddi/skfp/drvfbi.c b/drivers/net/fddi/skfp/drvfbi.c new file mode 100644 index 0000000..07da97c --- /dev/null +++ b/drivers/net/fddi/skfp/drvfbi.c @@ -0,0 +1,584 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * FBI board dependent Driver for SMT and LLC + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/supern_2.h" +#include "h/skfbiinc.h" +#include + +#ifndef lint +static const char ID_sccs[] = "@(#)drvfbi.c 1.63 99/02/11 (C) SK " ; +#endif + +/* + * PCM active state + */ +#define PC8_ACTIVE 8 + +#define LED_Y_ON 0x11 /* Used for ring up/down indication */ +#define LED_Y_OFF 0x10 + + +#define MS2BCLK(x) ((x)*12500L) + +/* + * valid configuration values are: + */ + +/* + * xPOS_ID:xxxx + * | \ / + * | \/ + * | --------------------- the patched POS_ID of the Adapter + * | xxxx = (Vendor ID low byte, + * | Vendor ID high byte, + * | Device ID low byte, + * | Device ID high byte) + * +------------------------------ the patched oem_id must be + * 'S' for SK or 'I' for IBM + * this is a short id for the driver. + */ +#ifndef MULT_OEM +#ifndef OEM_CONCEPT +const u_char oem_id[] = "xPOS_ID:xxxx" ; +#else /* OEM_CONCEPT */ +const u_char oem_id[] = OEM_ID ; +#endif /* OEM_CONCEPT */ +#define ID_BYTE0 8 +#define OEMID(smc,i) oem_id[ID_BYTE0 + i] +#else /* MULT_OEM */ +const struct s_oem_ids oem_ids[] = { +#include "oemids.h" +{0} +}; +#define OEMID(smc,i) smc->hw.oem_id->oi_id[i] +#endif /* MULT_OEM */ + +/* Prototypes of external functions */ +#ifdef AIX +extern int AIX_vpdReadByte() ; +#endif + + +/* Prototype of a local function. */ +static void smt_stop_watchdog(struct s_smc *smc); + +/* + * FDDI card reset + */ +static void card_start(struct s_smc *smc) +{ + int i ; +#ifdef PCI + u_char rev_id ; + u_short word; +#endif + + smt_stop_watchdog(smc) ; + +#ifdef PCI + /* + * make sure no transfer activity is pending + */ + outpw(FM_A(FM_MDREG1),FM_MINIT) ; + outp(ADDR(B0_CTRL), CTRL_HPI_SET) ; + hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ; + /* + * now reset everything + */ + outp(ADDR(B0_CTRL),CTRL_RST_SET) ; /* reset for all chips */ + i = (int) inp(ADDR(B0_CTRL)) ; /* do dummy read */ + SK_UNUSED(i) ; /* Make LINT happy. */ + outp(ADDR(B0_CTRL), CTRL_RST_CLR) ; + + /* + * Reset all bits in the PCI STATUS register + */ + outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_ON) ; /* enable for writes */ + word = inpw(PCI_C(PCI_STATUS)) ; + outpw(PCI_C(PCI_STATUS), word | PCI_ERRBITS) ; + outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_OFF) ; /* disable writes */ + + /* + * Release the reset of all the State machines + * Release Master_Reset + * Release HPI_SM_Reset + */ + outp(ADDR(B0_CTRL), CTRL_MRST_CLR|CTRL_HPI_CLR) ; + + /* + * determine the adapter type + * Note: Do it here, because some drivers may call card_start() once + * at very first before any other initialization functions is + * executed. + */ + rev_id = inp(PCI_C(PCI_REV_ID)) ; + if ((rev_id & 0xf0) == SK_ML_ID_1 || (rev_id & 0xf0) == SK_ML_ID_2) { + smc->hw.hw_is_64bit = TRUE ; + } else { + smc->hw.hw_is_64bit = FALSE ; + } + + /* + * Watermark initialization + */ + if (!smc->hw.hw_is_64bit) { + outpd(ADDR(B4_R1_F), RX_WATERMARK) ; + outpd(ADDR(B5_XA_F), TX_WATERMARK) ; + outpd(ADDR(B5_XS_F), TX_WATERMARK) ; + } + + outp(ADDR(B0_CTRL),CTRL_RST_CLR) ; /* clear the reset chips */ + outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_ON|LED_GB_OFF) ; /* ye LED on */ + + /* init the timer value for the watch dog 2,5 minutes */ + outpd(ADDR(B2_WDOG_INI),0x6FC23AC0) ; + + /* initialize the ISR mask */ + smc->hw.is_imask = ISR_MASK ; + smc->hw.hw_state = STOPPED ; +#endif + GET_PAGE(0) ; /* necessary for BOOT */ +} + +void card_stop(struct s_smc *smc) +{ + smt_stop_watchdog(smc) ; + smc->hw.mac_ring_is_up = 0 ; /* ring down */ + +#ifdef PCI + /* + * make sure no transfer activity is pending + */ + outpw(FM_A(FM_MDREG1),FM_MINIT) ; + outp(ADDR(B0_CTRL), CTRL_HPI_SET) ; + hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ; + /* + * now reset everything + */ + outp(ADDR(B0_CTRL),CTRL_RST_SET) ; /* reset for all chips */ + outp(ADDR(B0_CTRL),CTRL_RST_CLR) ; /* reset for all chips */ + outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_OFF|LED_GB_OFF) ; /* all LEDs off */ + smc->hw.hw_state = STOPPED ; +#endif +} +/*--------------------------- ISR handling ----------------------------------*/ + +void mac1_irq(struct s_smc *smc, u_short stu, u_short stl) +{ + int restart_tx = 0 ; +again: + + /* + * parity error: note encoding error is not possible in tag mode + */ + if (stl & (FM_SPCEPDS | /* parity err. syn.q.*/ + FM_SPCEPDA0 | /* parity err. a.q.0 */ + FM_SPCEPDA1)) { /* parity err. a.q.1 */ + SMT_PANIC(smc,SMT_E0134, SMT_E0134_MSG) ; + } + /* + * buffer underrun: can only occur if a tx threshold is specified + */ + if (stl & (FM_STBURS | /* tx buffer underrun syn.q.*/ + FM_STBURA0 | /* tx buffer underrun a.q.0 */ + FM_STBURA1)) { /* tx buffer underrun a.q.2 */ + SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ; + } + + if ( (stu & (FM_SXMTABT | /* transmit abort */ + FM_STXABRS | /* syn. tx abort */ + FM_STXABRA0)) || /* asyn. tx abort */ + (stl & (FM_SQLCKS | /* lock for syn. q. */ + FM_SQLCKA0)) ) { /* lock for asyn. q. */ + formac_tx_restart(smc) ; /* init tx */ + restart_tx = 1 ; + stu = inpw(FM_A(FM_ST1U)) ; + stl = inpw(FM_A(FM_ST1L)) ; + stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ; + if (stu || stl) + goto again ; + } + + if (stu & (FM_STEFRMA0 | /* end of asyn tx */ + FM_STEFRMS)) { /* end of sync tx */ + restart_tx = 1 ; + } + + if (restart_tx) + llc_restart_tx(smc) ; +} + +/* + * interrupt source= plc1 + * this function is called in nwfbisr.asm + */ +void plc1_irq(struct s_smc *smc) +{ + u_short st = inpw(PLC(PB,PL_INTR_EVENT)) ; + + plc_irq(smc,PB,st) ; +} + +/* + * interrupt source= plc2 + * this function is called in nwfbisr.asm + */ +void plc2_irq(struct s_smc *smc) +{ + u_short st = inpw(PLC(PA,PL_INTR_EVENT)) ; + + plc_irq(smc,PA,st) ; +} + + +/* + * interrupt source= timer + */ +void timer_irq(struct s_smc *smc) +{ + hwt_restart(smc); + smc->hw.t_stop = smc->hw.t_start; + smt_timer_done(smc) ; +} + +/* + * return S-port (PA or PB) + */ +int pcm_get_s_port(struct s_smc *smc) +{ + SK_UNUSED(smc) ; + return PS; +} + +/* + * Station Label = "FDDI-XYZ" where + * + * X = connector type + * Y = PMD type + * Z = port type + */ +#define STATION_LABEL_CONNECTOR_OFFSET 5 +#define STATION_LABEL_PMD_OFFSET 6 +#define STATION_LABEL_PORT_OFFSET 7 + +void read_address(struct s_smc *smc, u_char *mac_addr) +{ + char ConnectorType ; + char PmdType ; + int i ; + +#ifdef PCI + for (i = 0; i < 6; i++) { /* read mac address from board */ + smc->hw.fddi_phys_addr.a[i] = + bitrev8(inp(ADDR(B2_MAC_0+i))); + } +#endif + + ConnectorType = inp(ADDR(B2_CONN_TYP)) ; + PmdType = inp(ADDR(B2_PMD_TYP)) ; + + smc->y[PA].pmd_type[PMD_SK_CONN] = + smc->y[PB].pmd_type[PMD_SK_CONN] = ConnectorType ; + smc->y[PA].pmd_type[PMD_SK_PMD ] = + smc->y[PB].pmd_type[PMD_SK_PMD ] = PmdType ; + + if (mac_addr) { + for (i = 0; i < 6 ;i++) { + smc->hw.fddi_canon_addr.a[i] = mac_addr[i] ; + smc->hw.fddi_home_addr.a[i] = bitrev8(mac_addr[i]); + } + return ; + } + smc->hw.fddi_home_addr = smc->hw.fddi_phys_addr ; + + for (i = 0; i < 6 ;i++) { + smc->hw.fddi_canon_addr.a[i] = + bitrev8(smc->hw.fddi_phys_addr.a[i]); + } +} + +/* + * FDDI card soft reset + */ +void init_board(struct s_smc *smc, u_char *mac_addr) +{ + card_start(smc) ; + read_address(smc,mac_addr) ; + + if (!(inp(ADDR(B0_DAS)) & DAS_AVAIL)) + smc->s.sas = SMT_SAS ; /* Single att. station */ + else + smc->s.sas = SMT_DAS ; /* Dual att. station */ + + if (!(inp(ADDR(B0_DAS)) & DAS_BYP_ST)) + smc->mib.fddiSMTBypassPresent = 0 ; + /* without opt. bypass */ + else + smc->mib.fddiSMTBypassPresent = 1 ; + /* with opt. bypass */ +} + +/* + * insert or deinsert optical bypass (called by ECM) + */ +void sm_pm_bypass_req(struct s_smc *smc, int mode) +{ + DB_ECMN(1,"ECM : sm_pm_bypass_req(%s)\n",(mode == BP_INSERT) ? + "BP_INSERT" : "BP_DEINSERT",0) ; + + if (smc->s.sas != SMT_DAS) + return ; + +#ifdef PCI + switch(mode) { + case BP_INSERT : + outp(ADDR(B0_DAS),DAS_BYP_INS) ; /* insert station */ + break ; + case BP_DEINSERT : + outp(ADDR(B0_DAS),DAS_BYP_RMV) ; /* bypass station */ + break ; + } +#endif +} + +/* + * check if bypass connected + */ +int sm_pm_bypass_present(struct s_smc *smc) +{ + return (inp(ADDR(B0_DAS)) & DAS_BYP_ST) ? TRUE : FALSE; +} + +void plc_clear_irq(struct s_smc *smc, int p) +{ + SK_UNUSED(p) ; + + SK_UNUSED(smc) ; +} + + +/* + * led_indication called by rmt_indication() and + * pcm_state_change() + * + * Input: + * smc: SMT context + * led_event: + * 0 Only switch green LEDs according to their respective PCM state + * LED_Y_OFF just switch yellow LED off + * LED_Y_ON just switch yello LED on + */ +static void led_indication(struct s_smc *smc, int led_event) +{ + /* use smc->hw.mac_ring_is_up == TRUE + * as indication for Ring Operational + */ + u_short led_state ; + struct s_phy *phy ; + struct fddi_mib_p *mib_a ; + struct fddi_mib_p *mib_b ; + + phy = &smc->y[PA] ; + mib_a = phy->mib ; + phy = &smc->y[PB] ; + mib_b = phy->mib ; + +#ifdef PCI + led_state = 0 ; + + /* Ring up = yellow led OFF*/ + if (led_event == LED_Y_ON) { + led_state |= LED_MY_ON ; + } + else if (led_event == LED_Y_OFF) { + led_state |= LED_MY_OFF ; + } + else { /* PCM state changed */ + /* Link at Port A/S = green led A ON */ + if (mib_a->fddiPORTPCMState == PC8_ACTIVE) { + led_state |= LED_GA_ON ; + } + else { + led_state |= LED_GA_OFF ; + } + + /* Link at Port B = green led B ON */ + if (mib_b->fddiPORTPCMState == PC8_ACTIVE) { + led_state |= LED_GB_ON ; + } + else { + led_state |= LED_GB_OFF ; + } + } + + outp(ADDR(B0_LED), led_state) ; +#endif /* PCI */ + +} + + +void pcm_state_change(struct s_smc *smc, int plc, int p_state) +{ + /* + * the current implementation of pcm_state_change() in the driver + * parts must be renamed to drv_pcm_state_change() which will be called + * now after led_indication. + */ + DRV_PCM_STATE_CHANGE(smc,plc,p_state) ; + + led_indication(smc,0) ; +} + + +void rmt_indication(struct s_smc *smc, int i) +{ + /* Call a driver special function if defined */ + DRV_RMT_INDICATION(smc,i) ; + + led_indication(smc, i ? LED_Y_OFF : LED_Y_ON) ; +} + + +/* + * llc_recover_tx called by init_tx (fplus.c) + */ +void llc_recover_tx(struct s_smc *smc) +{ +#ifdef LOAD_GEN + extern int load_gen_flag ; + + load_gen_flag = 0 ; +#endif +#ifndef SYNC + smc->hw.n_a_send= 0 ; +#else + SK_UNUSED(smc) ; +#endif +} + +#ifdef MULT_OEM +static int is_equal_num(char comp1[], char comp2[], int num) +{ + int i ; + + for (i = 0 ; i < num ; i++) { + if (comp1[i] != comp2[i]) + return 0; + } + return 1; +} /* is_equal_num */ + + +/* + * set the OEM ID defaults, and test the contents of the OEM data base + * The default OEM is the first ACTIVE entry in the OEM data base + * + * returns: 0 success + * 1 error in data base + * 2 data base empty + * 3 no active entry + */ +int set_oi_id_def(struct s_smc *smc) +{ + int sel_id ; + int i ; + int act_entries ; + + i = 0 ; + sel_id = -1 ; + act_entries = FALSE ; + smc->hw.oem_id = 0 ; + smc->hw.oem_min_status = OI_STAT_ACTIVE ; + + /* check OEM data base */ + while (oem_ids[i].oi_status) { + switch (oem_ids[i].oi_status) { + case OI_STAT_ACTIVE: + act_entries = TRUE ; /* we have active IDs */ + if (sel_id == -1) + sel_id = i ; /* save the first active ID */ + case OI_STAT_VALID: + case OI_STAT_PRESENT: + i++ ; + break ; /* entry ok */ + default: + return 1; /* invalid oi_status */ + } + } + + if (i == 0) + return 2; + if (!act_entries) + return 3; + + /* ok, we have a valid OEM data base with an active entry */ + smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[sel_id] ; + return 0; +} +#endif /* MULT_OEM */ + +void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr) +{ + int i ; + + for (i = 0 ; i < 6 ; i++) + bia_addr->a[i] = bitrev8(smc->hw.fddi_phys_addr.a[i]); +} + +void smt_start_watchdog(struct s_smc *smc) +{ + SK_UNUSED(smc) ; /* Make LINT happy. */ + +#ifndef DEBUG + +#ifdef PCI + if (smc->hw.wdog_used) { + outpw(ADDR(B2_WDOG_CRTL),TIM_START) ; /* Start timer. */ + } +#endif + +#endif /* DEBUG */ +} + +static void smt_stop_watchdog(struct s_smc *smc) +{ + SK_UNUSED(smc) ; /* Make LINT happy. */ +#ifndef DEBUG + +#ifdef PCI + if (smc->hw.wdog_used) { + outpw(ADDR(B2_WDOG_CRTL),TIM_STOP) ; /* Stop timer. */ + } +#endif + +#endif /* DEBUG */ +} + +#ifdef PCI + +void mac_do_pci_fix(struct s_smc *smc) +{ + SK_UNUSED(smc) ; +} +#endif /* PCI */ + diff --git a/drivers/net/fddi/skfp/ecm.c b/drivers/net/fddi/skfp/ecm.c new file mode 100644 index 0000000..47d922c --- /dev/null +++ b/drivers/net/fddi/skfp/ecm.c @@ -0,0 +1,536 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + SMT ECM + Entity Coordination Management + Hardware independent state machine +*/ + +/* + * Hardware independent state machine implemantation + * The following external SMT functions are referenced : + * + * queue_event() + * smt_timer_start() + * smt_timer_stop() + * + * The following external HW dependent functions are referenced : + * sm_pm_bypass_req() + * sm_pm_ls_latch() + * sm_pm_get_ls() + * + * The following HW dependent events are required : + * NONE + * + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)ecm.c 2.7 99/08/05 (C) SK " ; +#endif + +/* + * FSM Macros + */ +#define AFLAG 0x10 +#define GO_STATE(x) (smc->mib.fddiSMTECMState = (x)|AFLAG) +#define ACTIONS_DONE() (smc->mib.fddiSMTECMState &= ~AFLAG) +#define ACTIONS(x) (x|AFLAG) + +#define EC0_OUT 0 /* not inserted */ +#define EC1_IN 1 /* inserted */ +#define EC2_TRACE 2 /* tracing */ +#define EC3_LEAVE 3 /* leaving the ring */ +#define EC4_PATH_TEST 4 /* performing path test */ +#define EC5_INSERT 5 /* bypass being turned on */ +#define EC6_CHECK 6 /* checking bypass */ +#define EC7_DEINSERT 7 /* bypass being turnde off */ + +#ifdef DEBUG +/* + * symbolic state names + */ +static const char * const ecm_states[] = { + "EC0_OUT","EC1_IN","EC2_TRACE","EC3_LEAVE","EC4_PATH_TEST", + "EC5_INSERT","EC6_CHECK","EC7_DEINSERT" +} ; + +/* + * symbolic event names + */ +static const char * const ecm_events[] = { + "NONE","EC_CONNECT","EC_DISCONNECT","EC_TRACE_PROP","EC_PATH_TEST", + "EC_TIMEOUT_TD","EC_TIMEOUT_TMAX", + "EC_TIMEOUT_IMAX","EC_TIMEOUT_INMAX","EC_TEST_DONE" +} ; +#endif + +/* + * all Globals are defined in smc.h + * struct s_ecm + */ + +/* + * function declarations + */ + +static void ecm_fsm(struct s_smc *smc, int cmd); +static void start_ecm_timer(struct s_smc *smc, u_long value, int event); +static void stop_ecm_timer(struct s_smc *smc); +static void prop_actions(struct s_smc *smc); + +/* + init ECM state machine + clear all ECM vars and flags +*/ +void ecm_init(struct s_smc *smc) +{ + smc->e.path_test = PT_PASSED ; + smc->e.trace_prop = 0 ; + smc->e.sb_flag = 0 ; + smc->mib.fddiSMTECMState = ACTIONS(EC0_OUT) ; + smc->e.ecm_line_state = FALSE ; +} + +/* + ECM state machine + called by dispatcher + + do + display state change + process event + until SM is stable +*/ +void ecm(struct s_smc *smc, int event) +{ + int state ; + + do { + DB_ECM("ECM : state %s%s", + (smc->mib.fddiSMTECMState & AFLAG) ? "ACTIONS " : "", + ecm_states[smc->mib.fddiSMTECMState & ~AFLAG]) ; + DB_ECM(" event %s\n",ecm_events[event],0) ; + state = smc->mib.fddiSMTECMState ; + ecm_fsm(smc,event) ; + event = 0 ; + } while (state != smc->mib.fddiSMTECMState) ; + ecm_state_change(smc,(int)smc->mib.fddiSMTECMState) ; +} + +/* + process ECM event +*/ +static void ecm_fsm(struct s_smc *smc, int cmd) +{ + int ls_a ; /* current line state PHY A */ + int ls_b ; /* current line state PHY B */ + int p ; /* ports */ + + + smc->mib.fddiSMTBypassPresent = sm_pm_bypass_present(smc) ; + if (cmd == EC_CONNECT) + smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ; + + /* For AIX event notification: */ + /* Is a disconnect command remotely issued ? */ + if (cmd == EC_DISCONNECT && + smc->mib.fddiSMTRemoteDisconnectFlag == TRUE) + AIX_EVENT (smc, (u_long) CIO_HARD_FAIL, (u_long) + FDDI_REMOTE_DISCONNECT, smt_get_event_word(smc), + smt_get_error_word(smc) ); + + /*jd 05-Aug-1999 Bug #10419 "Port Disconnect fails at Dup MAc Cond."*/ + if (cmd == EC_CONNECT) { + smc->e.DisconnectFlag = FALSE ; + } + else if (cmd == EC_DISCONNECT) { + smc->e.DisconnectFlag = TRUE ; + } + + switch(smc->mib.fddiSMTECMState) { + case ACTIONS(EC0_OUT) : + /* + * We do not perform a path test + */ + smc->e.path_test = PT_PASSED ; + smc->e.ecm_line_state = FALSE ; + stop_ecm_timer(smc) ; + ACTIONS_DONE() ; + break ; + case EC0_OUT: + /*EC01*/ + if (cmd == EC_CONNECT && !smc->mib.fddiSMTBypassPresent + && smc->e.path_test==PT_PASSED) { + GO_STATE(EC1_IN) ; + break ; + } + /*EC05*/ + else if (cmd == EC_CONNECT && (smc->e.path_test==PT_PASSED) && + smc->mib.fddiSMTBypassPresent && + (smc->s.sas == SMT_DAS)) { + GO_STATE(EC5_INSERT) ; + break ; + } + break; + case ACTIONS(EC1_IN) : + stop_ecm_timer(smc) ; + smc->e.trace_prop = 0 ; + sm_ma_control(smc,MA_TREQ) ; + for (p = 0 ; p < NUMPHYS ; p++) + if (smc->mib.p[p].fddiPORTHardwarePresent) + queue_event(smc,EVENT_PCMA+p,PC_START) ; + ACTIONS_DONE() ; + break ; + case EC1_IN: + /*EC12*/ + if (cmd == EC_TRACE_PROP) { + prop_actions(smc) ; + GO_STATE(EC2_TRACE) ; + break ; + } + /*EC13*/ + else if (cmd == EC_DISCONNECT) { + GO_STATE(EC3_LEAVE) ; + break ; + } + break; + case ACTIONS(EC2_TRACE) : + start_ecm_timer(smc,MIB2US(smc->mib.fddiSMTTrace_MaxExpiration), + EC_TIMEOUT_TMAX) ; + ACTIONS_DONE() ; + break ; + case EC2_TRACE : + /*EC22*/ + if (cmd == EC_TRACE_PROP) { + prop_actions(smc) ; + GO_STATE(EC2_TRACE) ; + break ; + } + /*EC23a*/ + else if (cmd == EC_DISCONNECT) { + smc->e.path_test = PT_EXITING ; + GO_STATE(EC3_LEAVE) ; + break ; + } + /*EC23b*/ + else if (smc->e.path_test == PT_PENDING) { + GO_STATE(EC3_LEAVE) ; + break ; + } + /*EC23c*/ + else if (cmd == EC_TIMEOUT_TMAX) { + /* Trace_Max is expired */ + /* -> send AIX_EVENT */ + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, + (u_long) FDDI_SMT_ERROR, (u_long) + FDDI_TRACE_MAX, smt_get_error_word(smc)); + smc->e.path_test = PT_PENDING ; + GO_STATE(EC3_LEAVE) ; + break ; + } + break ; + case ACTIONS(EC3_LEAVE) : + start_ecm_timer(smc,smc->s.ecm_td_min,EC_TIMEOUT_TD) ; + for (p = 0 ; p < NUMPHYS ; p++) + queue_event(smc,EVENT_PCMA+p,PC_STOP) ; + ACTIONS_DONE() ; + break ; + case EC3_LEAVE: + /*EC30*/ + if (cmd == EC_TIMEOUT_TD && !smc->mib.fddiSMTBypassPresent && + (smc->e.path_test != PT_PENDING)) { + GO_STATE(EC0_OUT) ; + break ; + } + /*EC34*/ + else if (cmd == EC_TIMEOUT_TD && + (smc->e.path_test == PT_PENDING)) { + GO_STATE(EC4_PATH_TEST) ; + break ; + } + /*EC31*/ + else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) { + GO_STATE(EC1_IN) ; + break ; + } + /*EC33*/ + else if (cmd == EC_DISCONNECT && + smc->e.path_test == PT_PENDING) { + smc->e.path_test = PT_EXITING ; + /* + * stay in state - state will be left via timeout + */ + } + /*EC37*/ + else if (cmd == EC_TIMEOUT_TD && + smc->mib.fddiSMTBypassPresent && + smc->e.path_test != PT_PENDING) { + GO_STATE(EC7_DEINSERT) ; + break ; + } + break ; + case ACTIONS(EC4_PATH_TEST) : + stop_ecm_timer(smc) ; + smc->e.path_test = PT_TESTING ; + start_ecm_timer(smc,smc->s.ecm_test_done,EC_TEST_DONE) ; + /* now perform path test ... just a simulation */ + ACTIONS_DONE() ; + break ; + case EC4_PATH_TEST : + /* path test done delay */ + if (cmd == EC_TEST_DONE) + smc->e.path_test = PT_PASSED ; + + if (smc->e.path_test == PT_FAILED) + RS_SET(smc,RS_PATHTEST) ; + + /*EC40a*/ + if (smc->e.path_test == PT_FAILED && + !smc->mib.fddiSMTBypassPresent) { + GO_STATE(EC0_OUT) ; + break ; + } + /*EC40b*/ + else if (cmd == EC_DISCONNECT && + !smc->mib.fddiSMTBypassPresent) { + GO_STATE(EC0_OUT) ; + break ; + } + /*EC41*/ + else if (smc->e.path_test == PT_PASSED) { + GO_STATE(EC1_IN) ; + break ; + } + /*EC47a*/ + else if (smc->e.path_test == PT_FAILED && + smc->mib.fddiSMTBypassPresent) { + GO_STATE(EC7_DEINSERT) ; + break ; + } + /*EC47b*/ + else if (cmd == EC_DISCONNECT && + smc->mib.fddiSMTBypassPresent) { + GO_STATE(EC7_DEINSERT) ; + break ; + } + break ; + case ACTIONS(EC5_INSERT) : + sm_pm_bypass_req(smc,BP_INSERT); + start_ecm_timer(smc,smc->s.ecm_in_max,EC_TIMEOUT_INMAX) ; + ACTIONS_DONE() ; + break ; + case EC5_INSERT : + /*EC56*/ + if (cmd == EC_TIMEOUT_INMAX) { + GO_STATE(EC6_CHECK) ; + break ; + } + /*EC57*/ + else if (cmd == EC_DISCONNECT) { + GO_STATE(EC7_DEINSERT) ; + break ; + } + break ; + case ACTIONS(EC6_CHECK) : + /* + * in EC6_CHECK, we *POLL* the line state ! + * check whether both bypass switches have switched. + */ + start_ecm_timer(smc,smc->s.ecm_check_poll,0) ; + smc->e.ecm_line_state = TRUE ; /* flag to pcm: report Q/HLS */ + (void) sm_pm_ls_latch(smc,PA,1) ; /* enable line state latch */ + (void) sm_pm_ls_latch(smc,PB,1) ; /* enable line state latch */ + ACTIONS_DONE() ; + break ; + case EC6_CHECK : + ls_a = sm_pm_get_ls(smc,PA) ; + ls_b = sm_pm_get_ls(smc,PB) ; + + /*EC61*/ + if (((ls_a == PC_QLS) || (ls_a == PC_HLS)) && + ((ls_b == PC_QLS) || (ls_b == PC_HLS)) ) { + smc->e.sb_flag = FALSE ; + smc->e.ecm_line_state = FALSE ; + GO_STATE(EC1_IN) ; + break ; + } + /*EC66*/ + else if (!smc->e.sb_flag && + (((ls_a == PC_ILS) && (ls_b == PC_QLS)) || + ((ls_a == PC_QLS) && (ls_b == PC_ILS)))){ + smc->e.sb_flag = TRUE ; + DB_ECMN(1,"ECM : EC6_CHECK - stuck bypass\n",0,0) ; + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_SMT_ERROR, (u_long) FDDI_BYPASS_STUCK, + smt_get_error_word(smc)); + } + /*EC67*/ + else if (cmd == EC_DISCONNECT) { + smc->e.ecm_line_state = FALSE ; + GO_STATE(EC7_DEINSERT) ; + break ; + } + else { + /* + * restart poll + */ + start_ecm_timer(smc,smc->s.ecm_check_poll,0) ; + } + break ; + case ACTIONS(EC7_DEINSERT) : + sm_pm_bypass_req(smc,BP_DEINSERT); + start_ecm_timer(smc,smc->s.ecm_i_max,EC_TIMEOUT_IMAX) ; + ACTIONS_DONE() ; + break ; + case EC7_DEINSERT: + /*EC70*/ + if (cmd == EC_TIMEOUT_IMAX) { + GO_STATE(EC0_OUT) ; + break ; + } + /*EC75*/ + else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) { + GO_STATE(EC5_INSERT) ; + break ; + } + break; + default: + SMT_PANIC(smc,SMT_E0107, SMT_E0107_MSG) ; + break; + } +} + +#ifndef CONCENTRATOR +/* + * trace propagation actions for SAS & DAS + */ +static void prop_actions(struct s_smc *smc) +{ + int port_in = 0 ; + int port_out = 0 ; + + RS_SET(smc,RS_EVENT) ; + switch (smc->s.sas) { + case SMT_SAS : + port_in = port_out = pcm_get_s_port(smc) ; + break ; + case SMT_DAS : + port_in = cfm_get_mac_input(smc) ; /* PA or PB */ + port_out = cfm_get_mac_output(smc) ; /* PA or PB */ + break ; + case SMT_NAC : + SMT_PANIC(smc,SMT_E0108, SMT_E0108_MSG) ; + return ; + } + + DB_ECM("ECM : prop_actions - trace_prop %d\n", smc->e.trace_prop,0) ; + DB_ECM("ECM : prop_actions - in %d out %d\n", port_in,port_out) ; + + if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) { + /* trace initiatior */ + DB_ECM("ECM : initiate TRACE on PHY %c\n",'A'+port_in-PA,0) ; + queue_event(smc,EVENT_PCM+port_in,PC_TRACE) ; + } + else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PA))) && + port_out != PA) { + /* trace propagate upstream */ + DB_ECM("ECM : propagate TRACE on PHY B\n",0,0) ; + queue_event(smc,EVENT_PCMB,PC_TRACE) ; + } + else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PB))) && + port_out != PB) { + /* trace propagate upstream */ + DB_ECM("ECM : propagate TRACE on PHY A\n",0,0) ; + queue_event(smc,EVENT_PCMA,PC_TRACE) ; + } + else { + /* signal trace termination */ + DB_ECM("ECM : TRACE terminated\n",0,0) ; + smc->e.path_test = PT_PENDING ; + } + smc->e.trace_prop = 0 ; +} +#else +/* + * trace propagation actions for Concentrator + */ +static void prop_actions(struct s_smc *smc) +{ + int initiator ; + int upstream ; + int p ; + + RS_SET(smc,RS_EVENT) ; + while (smc->e.trace_prop) { + DB_ECM("ECM : prop_actions - trace_prop %d\n", + smc->e.trace_prop,0) ; + + if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) { + initiator = ENTITY_MAC ; + smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_MAC) ; + DB_ECM("ECM: MAC initiates trace\n",0,0) ; + } + else { + for (p = NUMPHYS-1 ; p >= 0 ; p--) { + if (smc->e.trace_prop & + ENTITY_BIT(ENTITY_PHY(p))) + break ; + } + initiator = ENTITY_PHY(p) ; + smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_PHY(p)) ; + } + upstream = cem_get_upstream(smc,initiator) ; + + if (upstream == ENTITY_MAC) { + /* signal trace termination */ + DB_ECM("ECM : TRACE terminated\n",0,0) ; + smc->e.path_test = PT_PENDING ; + } + else { + /* trace propagate upstream */ + DB_ECM("ECM : propagate TRACE on PHY %d\n",upstream,0) ; + queue_event(smc,EVENT_PCM+upstream,PC_TRACE) ; + } + } +} +#endif + + +/* + * SMT timer interface + * start ECM timer + */ +static void start_ecm_timer(struct s_smc *smc, u_long value, int event) +{ + smt_timer_start(smc,&smc->e.ecm_timer,value,EV_TOKEN(EVENT_ECM,event)); +} + +/* + * SMT timer interface + * stop ECM timer + */ +static void stop_ecm_timer(struct s_smc *smc) +{ + if (smc->e.ecm_timer.tm_active) + smt_timer_stop(smc,&smc->e.ecm_timer) ; +} diff --git a/drivers/net/fddi/skfp/ess.c b/drivers/net/fddi/skfp/ess.c new file mode 100644 index 0000000..2fc5987 --- /dev/null +++ b/drivers/net/fddi/skfp/ess.c @@ -0,0 +1,720 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * ******************************************************************* + * This SBA code implements the Synchronous Bandwidth Allocation + * functions described in the "FDDI Synchronous Forum Implementer's + * Agreement" dated December 1th, 1993. + * ******************************************************************* + * + * PURPOSE: The purpose of this function is to control + * synchronous allocations on a single FDDI segment. + * Allocations are limited to the primary FDDI ring. + * The SBM provides recovery mechanisms to recover + * unused bandwidth also resolves T_Neg and + * reconfiguration changes. Many of the SBM state + * machine inputs are sourced by the underlying + * FDDI sub-system supporting the SBA application. + * + * ******************************************************************* + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/smt_p.h" + + +#ifndef SLIM_SMT + +#ifdef ESS + +#ifndef lint +static const char ID_sccs[] = "@(#)ess.c 1.10 96/02/23 (C) SK" ; +#define LINT_USE(x) +#else +#define LINT_USE(x) (x)=(x) +#endif +#define MS2BCLK(x) ((x)*12500L) + +/* + ------------------------------------------------------------- + LOCAL VARIABLES: + ------------------------------------------------------------- +*/ + +static const u_short plist_raf_alc_res[] = { SMT_P0012, SMT_P320B, SMT_P320F, + SMT_P3210, SMT_P0019, SMT_P001A, + SMT_P001D, 0 } ; + +static const u_short plist_raf_chg_req[] = { SMT_P320B, SMT_P320F, SMT_P3210, + SMT_P001A, 0 } ; + +static const struct fddi_addr smt_sba_da = {{0x80,0x01,0x43,0x00,0x80,0x0C}} ; +static const struct fddi_addr null_addr = {{0,0,0,0,0,0}} ; + +/* + ------------------------------------------------------------- + GLOBAL VARIABLES: + ------------------------------------------------------------- +*/ + + +/* + ------------------------------------------------------------- + LOCAL FUNCTIONS: + ------------------------------------------------------------- +*/ + +static void ess_send_response(struct s_smc *smc, struct smt_header *sm, + int sba_cmd); +static void ess_config_fifo(struct s_smc *smc); +static void ess_send_alc_req(struct s_smc *smc); +static void ess_send_frame(struct s_smc *smc, SMbuf *mb); + +/* + ------------------------------------------------------------- + EXTERNAL FUNCTIONS: + ------------------------------------------------------------- +*/ + +/* + ------------------------------------------------------------- + PUBLIC FUNCTIONS: + ------------------------------------------------------------- +*/ + +void ess_timer_poll(struct s_smc *smc); +void ess_para_change(struct s_smc *smc); +int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm, + int fs); +static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead); + + +/* + * -------------------------------------------------------------------------- + * End Station Support (ESS) + * -------------------------------------------------------------------------- + */ + +/* + * evaluate the RAF frame + */ +int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm, + int fs) +{ + void *p ; /* universal pointer */ + struct smt_p_0016 *cmd ; /* para: command for the ESS */ + SMbuf *db ; + u_long msg_res_type ; /* recource type */ + u_long payload, overhead ; + int local ; + int i ; + + /* + * Message Processing Code + */ + local = ((fs & L_INDICATOR) != 0) ; + + /* + * get the resource type + */ + if (!(p = (void *) sm_to_para(smc,sm,SMT_P0015))) { + DB_ESS("ESS: RAF frame error, parameter type not found\n",0,0) ; + return fs; + } + msg_res_type = ((struct smt_p_0015 *)p)->res_type ; + + /* + * get the pointer to the ESS command + */ + if (!(cmd = (struct smt_p_0016 *) sm_to_para(smc,sm,SMT_P0016))) { + /* + * error in frame: para ESS command was not found + */ + DB_ESS("ESS: RAF frame error, parameter command not found\n",0,0); + return fs; + } + + DB_ESSN(2,"fc %x ft %x\n",sm->smt_class,sm->smt_type) ; + DB_ESSN(2,"ver %x tran %lx\n",sm->smt_version,sm->smt_tid) ; + DB_ESSN(2,"stn_id %s\n",addr_to_string(&sm->smt_source),0) ; + + DB_ESSN(2,"infolen %x res %x\n",sm->smt_len, msg_res_type) ; + DB_ESSN(2,"sbacmd %x\n",cmd->sba_cmd,0) ; + + /* + * evaluate the ESS command + */ + switch (cmd->sba_cmd) { + + /* + * Process an ESS Allocation Request + */ + case REQUEST_ALLOCATION : + /* + * check for an RAF Request (Allocation Request) + */ + if (sm->smt_type == SMT_REQUEST) { + /* + * process the Allocation request only if the frame is + * local and no static allocation is used + */ + if (!local || smc->mib.fddiESSPayload) + return fs; + + p = (void *) sm_to_para(smc,sm,SMT_P0019) ; + for (i = 0; i < 5; i++) { + if (((struct smt_p_0019 *)p)->alloc_addr.a[i]) { + return fs; + } + } + + /* + * Note: The Application should send a LAN_LOC_FRAME. + * The ESS do not send the Frame to the network! + */ + smc->ess.alloc_trans_id = sm->smt_tid ; + DB_ESS("ESS: save Alloc Req Trans ID %lx\n",sm->smt_tid,0); + p = (void *) sm_to_para(smc,sm,SMT_P320F) ; + ((struct smt_p_320f *)p)->mib_payload = + smc->mib.a[PATH0].fddiPATHSbaPayload ; + p = (void *) sm_to_para(smc,sm,SMT_P3210) ; + ((struct smt_p_3210 *)p)->mib_overhead = + smc->mib.a[PATH0].fddiPATHSbaOverhead ; + sm->smt_dest = smt_sba_da ; + + if (smc->ess.local_sba_active) + return fs | I_INDICATOR; + + if (!(db = smt_get_mbuf(smc))) + return fs; + + db->sm_len = mb->sm_len ; + db->sm_off = mb->sm_off ; + memcpy(((char *)(db->sm_data+db->sm_off)),(char *)sm, + (int)db->sm_len) ; + dump_smt(smc, + (struct smt_header *)(db->sm_data+db->sm_off), + "RAF") ; + smt_send_frame(smc,db,FC_SMT_INFO,0) ; + return fs; + } + + /* + * The RAF frame is an Allocation Response ! + * check the parameters + */ + if (smt_check_para(smc,sm,plist_raf_alc_res)) { + DB_ESS("ESS: RAF with para problem, ignoring\n",0,0) ; + return fs; + } + + /* + * VERIFY THE FRAME IS WELL BUILT: + * + * 1. path index = primary ring only + * 2. resource type = sync bw only + * 3. trans action id = alloc_trans_id + * 4. reason code = success + * + * If any are violated, discard the RAF frame + */ + if ((((struct smt_p_320b *)sm_to_para(smc,sm,SMT_P320B))->path_index + != PRIMARY_RING) || + (msg_res_type != SYNC_BW) || + (((struct smt_p_reason *)sm_to_para(smc,sm,SMT_P0012))->rdf_reason + != SMT_RDF_SUCCESS) || + (sm->smt_tid != smc->ess.alloc_trans_id)) { + + DB_ESS("ESS: Allocation Response not accepted\n",0,0) ; + return fs; + } + + /* + * Extract message parameters + */ + p = (void *) sm_to_para(smc,sm,SMT_P320F) ; + if (!p) { + printk(KERN_ERR "ESS: sm_to_para failed"); + return fs; + } + payload = ((struct smt_p_320f *)p)->mib_payload ; + p = (void *) sm_to_para(smc,sm,SMT_P3210) ; + if (!p) { + printk(KERN_ERR "ESS: sm_to_para failed"); + return fs; + } + overhead = ((struct smt_p_3210 *)p)->mib_overhead ; + + DB_ESSN(2,"payload= %lx overhead= %lx\n",payload,overhead) ; + + /* + * process the bandwidth allocation + */ + (void)process_bw_alloc(smc,(long)payload,(long)overhead) ; + + return fs; + /* end of Process Allocation Request */ + + /* + * Process an ESS Change Request + */ + case CHANGE_ALLOCATION : + /* + * except only replies + */ + if (sm->smt_type != SMT_REQUEST) { + DB_ESS("ESS: Do not process Change Responses\n",0,0) ; + return fs; + } + + /* + * check the para for the Change Request + */ + if (smt_check_para(smc,sm,plist_raf_chg_req)) { + DB_ESS("ESS: RAF with para problem, ignoring\n",0,0) ; + return fs; + } + + /* + * Verify the path index and resource + * type are correct. If any of + * these are false, don't process this + * change request frame. + */ + if ((((struct smt_p_320b *)sm_to_para(smc,sm,SMT_P320B))->path_index + != PRIMARY_RING) || (msg_res_type != SYNC_BW)) { + DB_ESS("ESS: RAF frame with para problem, ignoring\n",0,0) ; + return fs; + } + + /* + * Extract message queue parameters + */ + p = (void *) sm_to_para(smc,sm,SMT_P320F) ; + payload = ((struct smt_p_320f *)p)->mib_payload ; + p = (void *) sm_to_para(smc,sm,SMT_P3210) ; + overhead = ((struct smt_p_3210 *)p)->mib_overhead ; + + DB_ESSN(2,"ESS: Change Request from %s\n", + addr_to_string(&sm->smt_source),0) ; + DB_ESSN(2,"payload= %lx overhead= %lx\n",payload,overhead) ; + + /* + * process the bandwidth allocation + */ + if(!process_bw_alloc(smc,(long)payload,(long)overhead)) + return fs; + + /* + * send an RAF Change Reply + */ + ess_send_response(smc,sm,CHANGE_ALLOCATION) ; + + return fs; + /* end of Process Change Request */ + + /* + * Process Report Response + */ + case REPORT_ALLOCATION : + /* + * except only requests + */ + if (sm->smt_type != SMT_REQUEST) { + DB_ESS("ESS: Do not process a Report Reply\n",0,0) ; + return fs; + } + + DB_ESSN(2,"ESS: Report Request from %s\n", + addr_to_string(&(sm->smt_source)),0) ; + + /* + * verify that the resource type is sync bw only + */ + if (msg_res_type != SYNC_BW) { + DB_ESS("ESS: ignoring RAF with para problem\n",0,0) ; + return fs; + } + + /* + * send an RAF Change Reply + */ + ess_send_response(smc,sm,REPORT_ALLOCATION) ; + + return fs; + /* end of Process Report Request */ + + default: + /* + * error in frame + */ + DB_ESS("ESS: ignoring RAF with bad sba_cmd\n",0,0) ; + break ; + } + + return fs; +} + +/* + * determines the synchronous bandwidth, set the TSYNC register and the + * mib variables SBAPayload, SBAOverhead and fddiMACT-NEG. + */ +static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead) +{ + /* + * determine the synchronous bandwidth (sync_bw) in bytes per T-NEG, + * if the payload is greater than zero. + * For the SBAPayload and the SBAOverhead we have the following + * unite quations + * _ _ + * | bytes | + * SBAPayload = | 8000 ------ | + * | s | + * - - + * _ _ + * | bytes | + * SBAOverhead = | ------ | + * | T-NEG | + * - - + * + * T-NEG is described by the equation: + * + * (-) fddiMACT-NEG + * T-NEG = ------------------- + * 12500000 1/s + * + * The number of bytes we are able to send is the payload + * plus the overhead. + * + * bytes T-NEG SBAPayload 8000 bytes/s + * sync_bw = SBAOverhead ------ + ----------------------------- + * T-NEG T-NEG + * + * + * 1 + * sync_bw = SBAOverhead + ---- (-)fddiMACT-NEG * SBAPayload + * 1562 + * + */ + + /* + * set the mib attributes fddiPATHSbaOverhead, fddiPATHSbaPayload + */ +/* if (smt_set_obj(smc,SMT_P320F,payload,S_SET)) { + DB_ESS("ESS: SMT does not accept the payload value\n",0,0) ; + return FALSE; + } + if (smt_set_obj(smc,SMT_P3210,overhead,S_SET)) { + DB_ESS("ESS: SMT does not accept the overhead value\n",0,0) ; + return FALSE; + } */ + + /* premliminary */ + if (payload > MAX_PAYLOAD || overhead > 5000) { + DB_ESS("ESS: payload / overhead not accepted\n",0,0) ; + return FALSE; + } + + /* + * start the iterative allocation process if the payload or the overhead + * are smaller than the parsed values + */ + if (smc->mib.fddiESSPayload && + ((u_long)payload != smc->mib.fddiESSPayload || + (u_long)overhead != smc->mib.fddiESSOverhead)) { + smc->ess.raf_act_timer_poll = TRUE ; + smc->ess.timer_count = 0 ; + } + + /* + * evulate the Payload + */ + if (payload) { + DB_ESSN(2,"ESS: turn SMT_ST_SYNC_SERVICE bit on\n",0,0) ; + smc->ess.sync_bw_available = TRUE ; + + smc->ess.sync_bw = overhead - + (long)smc->mib.m[MAC0].fddiMACT_Neg * + payload / 1562 ; + } + else { + DB_ESSN(2,"ESS: turn SMT_ST_SYNC_SERVICE bit off\n",0,0) ; + smc->ess.sync_bw_available = FALSE ; + smc->ess.sync_bw = 0 ; + overhead = 0 ; + } + + smc->mib.a[PATH0].fddiPATHSbaPayload = payload ; + smc->mib.a[PATH0].fddiPATHSbaOverhead = overhead ; + + + DB_ESSN(2,"tsync = %lx\n",smc->ess.sync_bw,0) ; + + ess_config_fifo(smc) ; + set_formac_tsync(smc,smc->ess.sync_bw) ; + return TRUE; +} + +static void ess_send_response(struct s_smc *smc, struct smt_header *sm, + int sba_cmd) +{ + struct smt_sba_chg *chg ; + SMbuf *mb ; + void *p ; + + /* + * get and initialize the response frame + */ + if (sba_cmd == CHANGE_ALLOCATION) { + if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REPLY, + sizeof(struct smt_sba_chg)))) + return ; + } + else { + if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REPLY, + sizeof(struct smt_sba_rep_res)))) + return ; + } + + chg = smtod(mb,struct smt_sba_chg *) ; + chg->smt.smt_tid = sm->smt_tid ; + chg->smt.smt_dest = sm->smt_source ; + + /* set P15 */ + chg->s_type.para.p_type = SMT_P0015 ; + chg->s_type.para.p_len = sizeof(struct smt_p_0015) - PARA_LEN ; + chg->s_type.res_type = SYNC_BW ; + + /* set P16 */ + chg->cmd.para.p_type = SMT_P0016 ; + chg->cmd.para.p_len = sizeof(struct smt_p_0016) - PARA_LEN ; + chg->cmd.sba_cmd = sba_cmd ; + + /* set P320B */ + chg->path.para.p_type = SMT_P320B ; + chg->path.para.p_len = sizeof(struct smt_p_320b) - PARA_LEN ; + chg->path.mib_index = SBAPATHINDEX ; + chg->path.path_pad = 0; + chg->path.path_index = PRIMARY_RING ; + + /* set P320F */ + chg->payload.para.p_type = SMT_P320F ; + chg->payload.para.p_len = sizeof(struct smt_p_320f) - PARA_LEN ; + chg->payload.mib_index = SBAPATHINDEX ; + chg->payload.mib_payload = smc->mib.a[PATH0].fddiPATHSbaPayload ; + + /* set P3210 */ + chg->overhead.para.p_type = SMT_P3210 ; + chg->overhead.para.p_len = sizeof(struct smt_p_3210) - PARA_LEN ; + chg->overhead.mib_index = SBAPATHINDEX ; + chg->overhead.mib_overhead = smc->mib.a[PATH0].fddiPATHSbaOverhead ; + + if (sba_cmd == CHANGE_ALLOCATION) { + /* set P1A */ + chg->cat.para.p_type = SMT_P001A ; + chg->cat.para.p_len = sizeof(struct smt_p_001a) - PARA_LEN ; + p = (void *) sm_to_para(smc,sm,SMT_P001A) ; + chg->cat.category = ((struct smt_p_001a *)p)->category ; + } + dump_smt(smc,(struct smt_header *)chg,"RAF") ; + ess_send_frame(smc,mb) ; +} + +void ess_timer_poll(struct s_smc *smc) +{ + if (!smc->ess.raf_act_timer_poll) + return ; + + DB_ESSN(2,"ESS: timer_poll\n",0,0) ; + + smc->ess.timer_count++ ; + if (smc->ess.timer_count == 10) { + smc->ess.timer_count = 0 ; + ess_send_alc_req(smc) ; + } +} + +static void ess_send_alc_req(struct s_smc *smc) +{ + struct smt_sba_alc_req *req ; + SMbuf *mb ; + + /* + * send never allocation request where the requested payload and + * overhead is zero or deallocate bandwidth when no bandwidth is + * parsed + */ + if (!smc->mib.fddiESSPayload) { + smc->mib.fddiESSOverhead = 0 ; + } + else { + if (!smc->mib.fddiESSOverhead) + smc->mib.fddiESSOverhead = DEFAULT_OV ; + } + + if (smc->mib.fddiESSOverhead == + smc->mib.a[PATH0].fddiPATHSbaOverhead && + smc->mib.fddiESSPayload == + smc->mib.a[PATH0].fddiPATHSbaPayload){ + smc->ess.raf_act_timer_poll = FALSE ; + smc->ess.timer_count = 7 ; /* next RAF alc req after 3 s */ + return ; + } + + /* + * get and initialize the response frame + */ + if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REQUEST, + sizeof(struct smt_sba_alc_req)))) + return ; + req = smtod(mb,struct smt_sba_alc_req *) ; + req->smt.smt_tid = smc->ess.alloc_trans_id = smt_get_tid(smc) ; + req->smt.smt_dest = smt_sba_da ; + + /* set P15 */ + req->s_type.para.p_type = SMT_P0015 ; + req->s_type.para.p_len = sizeof(struct smt_p_0015) - PARA_LEN ; + req->s_type.res_type = SYNC_BW ; + + /* set P16 */ + req->cmd.para.p_type = SMT_P0016 ; + req->cmd.para.p_len = sizeof(struct smt_p_0016) - PARA_LEN ; + req->cmd.sba_cmd = REQUEST_ALLOCATION ; + + /* + * set the parameter type and parameter length of all used + * parameters + */ + + /* set P320B */ + req->path.para.p_type = SMT_P320B ; + req->path.para.p_len = sizeof(struct smt_p_320b) - PARA_LEN ; + req->path.mib_index = SBAPATHINDEX ; + req->path.path_pad = 0; + req->path.path_index = PRIMARY_RING ; + + /* set P0017 */ + req->pl_req.para.p_type = SMT_P0017 ; + req->pl_req.para.p_len = sizeof(struct smt_p_0017) - PARA_LEN ; + req->pl_req.sba_pl_req = smc->mib.fddiESSPayload - + smc->mib.a[PATH0].fddiPATHSbaPayload ; + + /* set P0018 */ + req->ov_req.para.p_type = SMT_P0018 ; + req->ov_req.para.p_len = sizeof(struct smt_p_0018) - PARA_LEN ; + req->ov_req.sba_ov_req = smc->mib.fddiESSOverhead - + smc->mib.a[PATH0].fddiPATHSbaOverhead ; + + /* set P320F */ + req->payload.para.p_type = SMT_P320F ; + req->payload.para.p_len = sizeof(struct smt_p_320f) - PARA_LEN ; + req->payload.mib_index = SBAPATHINDEX ; + req->payload.mib_payload = smc->mib.a[PATH0].fddiPATHSbaPayload ; + + /* set P3210 */ + req->overhead.para.p_type = SMT_P3210 ; + req->overhead.para.p_len = sizeof(struct smt_p_3210) - PARA_LEN ; + req->overhead.mib_index = SBAPATHINDEX ; + req->overhead.mib_overhead = smc->mib.a[PATH0].fddiPATHSbaOverhead ; + + /* set P19 */ + req->a_addr.para.p_type = SMT_P0019 ; + req->a_addr.para.p_len = sizeof(struct smt_p_0019) - PARA_LEN ; + req->a_addr.sba_pad = 0; + req->a_addr.alloc_addr = null_addr ; + + /* set P1A */ + req->cat.para.p_type = SMT_P001A ; + req->cat.para.p_len = sizeof(struct smt_p_001a) - PARA_LEN ; + req->cat.category = smc->mib.fddiESSCategory ; + + /* set P1B */ + req->tneg.para.p_type = SMT_P001B ; + req->tneg.para.p_len = sizeof(struct smt_p_001b) - PARA_LEN ; + req->tneg.max_t_neg = smc->mib.fddiESSMaxTNeg ; + + /* set P1C */ + req->segm.para.p_type = SMT_P001C ; + req->segm.para.p_len = sizeof(struct smt_p_001c) - PARA_LEN ; + req->segm.min_seg_siz = smc->mib.fddiESSMinSegmentSize ; + + dump_smt(smc,(struct smt_header *)req,"RAF") ; + ess_send_frame(smc,mb) ; +} + +static void ess_send_frame(struct s_smc *smc, SMbuf *mb) +{ + /* + * check if the frame must be send to the own ESS + */ + if (smc->ess.local_sba_active) { + /* + * Send the Change Reply to the local SBA + */ + DB_ESS("ESS:Send to the local SBA\n",0,0) ; + if (!smc->ess.sba_reply_pend) + smc->ess.sba_reply_pend = mb ; + else { + DB_ESS("Frame is lost - another frame was pending\n",0,0); + smt_free_mbuf(smc,mb) ; + } + } + else { + /* + * Send the SBA RAF Change Reply to the network + */ + DB_ESS("ESS:Send to the network\n",0,0) ; + smt_send_frame(smc,mb,FC_SMT_INFO,0) ; + } +} + +void ess_para_change(struct s_smc *smc) +{ + (void)process_bw_alloc(smc,(long)smc->mib.a[PATH0].fddiPATHSbaPayload, + (long)smc->mib.a[PATH0].fddiPATHSbaOverhead) ; +} + +static void ess_config_fifo(struct s_smc *smc) +{ + /* + * if nothing to do exit + */ + if (smc->mib.a[PATH0].fddiPATHSbaPayload) { + if (smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON && + (smc->hw.fp.fifo.fifo_config_mode&SEND_ASYNC_AS_SYNC) == + smc->mib.fddiESSSynchTxMode) { + return ; + } + } + else { + if (!(smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON)) { + return ; + } + } + + /* + * split up the FIFO and reinitialize the queues + */ + formac_reinit_tx(smc) ; +} + +#endif /* ESS */ + +#endif /* no SLIM_SMT */ + diff --git a/drivers/net/fddi/skfp/fplustm.c b/drivers/net/fddi/skfp/fplustm.c new file mode 100644 index 0000000..a20ed1a --- /dev/null +++ b/drivers/net/fddi/skfp/fplustm.c @@ -0,0 +1,1491 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * FORMAC+ Driver for tag mode + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/supern_2.h" +#include + +#ifndef lint +static const char ID_sccs[] = "@(#)fplustm.c 1.32 99/02/23 (C) SK " ; +#endif + +#ifndef UNUSED +#ifdef lint +#define UNUSED(x) (x) = (x) +#else +#define UNUSED(x) +#endif +#endif + +#define FM_ADDRX (FM_ADDET|FM_EXGPA0|FM_EXGPA1) +#define MS2BCLK(x) ((x)*12500L) +#define US2BCLK(x) ((x)*1250L) + +/* + * prototypes for static function + */ +static void build_claim_beacon(struct s_smc *smc, u_long t_request); +static int init_mac(struct s_smc *smc, int all); +static void rtm_init(struct s_smc *smc); +static void smt_split_up_fifo(struct s_smc *smc); + +#if (!defined(NO_SMT_PANIC) || defined(DEBUG)) +static char write_mdr_warning [] = "E350 write_mdr() FM_SNPPND is set\n"; +static char cam_warning [] = "E_SMT_004: CAM still busy\n"; +#endif + +#define DUMMY_READ() smc->hw.mc_dummy = (u_short) inp(ADDR(B0_RAP)) + +#define CHECK_NPP() { unsigned k = 10000 ;\ + while ((inpw(FM_A(FM_STMCHN)) & FM_SNPPND) && k) k--;\ + if (!k) { \ + SMT_PANIC(smc,SMT_E0130, SMT_E0130_MSG) ; \ + } \ + } + +#define CHECK_CAM() { unsigned k = 10 ;\ + while (!(inpw(FM_A(FM_AFSTAT)) & FM_DONE) && k) k--;\ + if (!k) { \ + SMT_PANIC(smc,SMT_E0131, SMT_E0131_MSG) ; \ + } \ + } + +const struct fddi_addr fddi_broadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; +static const struct fddi_addr null_addr = {{0,0,0,0,0,0}}; +static const struct fddi_addr dbeacon_multi = {{0x01,0x80,0xc2,0x00,0x01,0x00}}; + +static const u_short my_said = 0xffff ; /* short address (n.u.) */ +static const u_short my_sagp = 0xffff ; /* short group address (n.u.) */ + +/* + * define my address + */ +#ifdef USE_CAN_ADDR +#define MA smc->hw.fddi_canon_addr +#else +#define MA smc->hw.fddi_home_addr +#endif + + +/* + * useful interrupt bits + */ +static const int mac_imsk1u = FM_STXABRS | FM_STXABRA0 | FM_SXMTABT ; +static const int mac_imsk1l = FM_SQLCKS | FM_SQLCKA0 | FM_SPCEPDS | FM_SPCEPDA0| + FM_STBURS | FM_STBURA0 ; + + /* delete FM_SRBFL after tests */ +static const int mac_imsk2u = FM_SERRSF | FM_SNFSLD | FM_SRCVOVR | FM_SRBFL | + FM_SMYCLM ; +static const int mac_imsk2l = FM_STRTEXR | FM_SDUPCLM | FM_SFRMCTR | + FM_SERRCTR | FM_SLSTCTR | + FM_STRTEXP | FM_SMULTDA | FM_SRNGOP ; + +static const int mac_imsk3u = FM_SRCVOVR2 | FM_SRBFL2 ; +static const int mac_imsk3l = FM_SRPERRQ2 | FM_SRPERRQ1 ; + +static const int mac_beacon_imsk2u = FM_SOTRBEC | FM_SMYBEC | FM_SBEC | + FM_SLOCLM | FM_SHICLM | FM_SMYCLM | FM_SCLM ; + + +static u_long mac_get_tneg(struct s_smc *smc) +{ + u_long tneg ; + + tneg = (u_long)((long)inpw(FM_A(FM_TNEG))<<5) ; + return (u_long)((tneg + ((inpw(FM_A(FM_TMRS))>>10)&0x1f)) | + 0xffe00000L) ; +} + +void mac_update_counter(struct s_smc *smc) +{ + smc->mib.m[MAC0].fddiMACFrame_Ct = + (smc->mib.m[MAC0].fddiMACFrame_Ct & 0xffff0000L) + + (u_short) inpw(FM_A(FM_FCNTR)) ; + smc->mib.m[MAC0].fddiMACLost_Ct = + (smc->mib.m[MAC0].fddiMACLost_Ct & 0xffff0000L) + + (u_short) inpw(FM_A(FM_LCNTR)) ; + smc->mib.m[MAC0].fddiMACError_Ct = + (smc->mib.m[MAC0].fddiMACError_Ct & 0xffff0000L) + + (u_short) inpw(FM_A(FM_ECNTR)) ; + smc->mib.m[MAC0].fddiMACT_Neg = mac_get_tneg(smc) ; +#ifdef SMT_REAL_TOKEN_CT + /* + * If the token counter is emulated it is updated in smt_event. + */ + TBD +#else + smt_emulate_token_ct( smc, MAC0 ); +#endif +} + +/* + * write long value into buffer memory over memory data register (MDR), + */ +static void write_mdr(struct s_smc *smc, u_long val) +{ + CHECK_NPP() ; + MDRW(val) ; +} + +#if 0 +/* + * read long value from buffer memory over memory data register (MDR), + */ +static u_long read_mdr(struct s_smc *smc, unsigned int addr) +{ + long p ; + CHECK_NPP() ; + MARR(addr) ; + outpw(FM_A(FM_CMDREG1),FM_IRMEMWO) ; + CHECK_NPP() ; /* needed for PCI to prevent from timeing violations */ +/* p = MDRR() ; */ /* bad read values if the workaround */ + /* smc->hw.mc_dummy = *((short volatile far *)(addr)))*/ + /* is used */ + p = (u_long)inpw(FM_A(FM_MDRU))<<16 ; + p += (u_long)inpw(FM_A(FM_MDRL)) ; + return p; +} +#endif + +/* + * clear buffer memory + */ +static void init_ram(struct s_smc *smc) +{ + u_short i ; + + smc->hw.fp.fifo.rbc_ram_start = 0 ; + smc->hw.fp.fifo.rbc_ram_end = + smc->hw.fp.fifo.rbc_ram_start + RBC_MEM_SIZE ; + CHECK_NPP() ; + MARW(smc->hw.fp.fifo.rbc_ram_start) ; + for (i = smc->hw.fp.fifo.rbc_ram_start; + i < (u_short) (smc->hw.fp.fifo.rbc_ram_end-1); i++) + write_mdr(smc,0L) ; + /* Erase the last byte too */ + write_mdr(smc,0L) ; +} + +/* + * set receive FIFO pointer + */ +static void set_recvptr(struct s_smc *smc) +{ + /* + * initialize the pointer for receive queue 1 + */ + outpw(FM_A(FM_RPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* RPR1 */ + outpw(FM_A(FM_SWPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* SWPR1 */ + outpw(FM_A(FM_WPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* WPR1 */ + outpw(FM_A(FM_EARV1),smc->hw.fp.fifo.tx_s_start-1) ; /* EARV1 */ + + /* + * initialize the pointer for receive queue 2 + */ + if (smc->hw.fp.fifo.rx2_fifo_size) { + outpw(FM_A(FM_RPR2),smc->hw.fp.fifo.rx2_fifo_start) ; + outpw(FM_A(FM_SWPR2),smc->hw.fp.fifo.rx2_fifo_start) ; + outpw(FM_A(FM_WPR2),smc->hw.fp.fifo.rx2_fifo_start) ; + outpw(FM_A(FM_EARV2),smc->hw.fp.fifo.rbc_ram_end-1) ; + } + else { + outpw(FM_A(FM_RPR2),smc->hw.fp.fifo.rbc_ram_end-1) ; + outpw(FM_A(FM_SWPR2),smc->hw.fp.fifo.rbc_ram_end-1) ; + outpw(FM_A(FM_WPR2),smc->hw.fp.fifo.rbc_ram_end-1) ; + outpw(FM_A(FM_EARV2),smc->hw.fp.fifo.rbc_ram_end-1) ; + } +} + +/* + * set transmit FIFO pointer + */ +static void set_txptr(struct s_smc *smc) +{ + outpw(FM_A(FM_CMDREG2),FM_IRSTQ) ; /* reset transmit queues */ + + /* + * initialize the pointer for asynchronous transmit queue + */ + outpw(FM_A(FM_RPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* RPXA0 */ + outpw(FM_A(FM_SWPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* SWPXA0 */ + outpw(FM_A(FM_WPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* WPXA0 */ + outpw(FM_A(FM_EAA0),smc->hw.fp.fifo.rx2_fifo_start-1) ; /* EAA0 */ + + /* + * initialize the pointer for synchronous transmit queue + */ + if (smc->hw.fp.fifo.tx_s_size) { + outpw(FM_A(FM_RPXS),smc->hw.fp.fifo.tx_s_start) ; + outpw(FM_A(FM_SWPXS),smc->hw.fp.fifo.tx_s_start) ; + outpw(FM_A(FM_WPXS),smc->hw.fp.fifo.tx_s_start) ; + outpw(FM_A(FM_EAS),smc->hw.fp.fifo.tx_a0_start-1) ; + } + else { + outpw(FM_A(FM_RPXS),smc->hw.fp.fifo.tx_a0_start-1) ; + outpw(FM_A(FM_SWPXS),smc->hw.fp.fifo.tx_a0_start-1) ; + outpw(FM_A(FM_WPXS),smc->hw.fp.fifo.tx_a0_start-1) ; + outpw(FM_A(FM_EAS),smc->hw.fp.fifo.tx_a0_start-1) ; + } +} + +/* + * init memory buffer management registers + */ +static void init_rbc(struct s_smc *smc) +{ + u_short rbc_ram_addr ; + + /* + * set unused pointers or permanent pointers + */ + rbc_ram_addr = smc->hw.fp.fifo.rx2_fifo_start - 1 ; + + outpw(FM_A(FM_RPXA1),rbc_ram_addr) ; /* a1-send pointer */ + outpw(FM_A(FM_WPXA1),rbc_ram_addr) ; + outpw(FM_A(FM_SWPXA1),rbc_ram_addr) ; + outpw(FM_A(FM_EAA1),rbc_ram_addr) ; + + set_recvptr(smc) ; + set_txptr(smc) ; +} + +/* + * init rx pointer + */ +static void init_rx(struct s_smc *smc) +{ + struct s_smt_rx_queue *queue ; + + /* + * init all tx data structures for receive queue 1 + */ + smc->hw.fp.rx[QUEUE_R1] = queue = &smc->hw.fp.rx_q[QUEUE_R1] ; + queue->rx_bmu_ctl = (HW_PTR) ADDR(B0_R1_CSR) ; + queue->rx_bmu_dsc = (HW_PTR) ADDR(B4_R1_DA) ; + + /* + * init all tx data structures for receive queue 2 + */ + smc->hw.fp.rx[QUEUE_R2] = queue = &smc->hw.fp.rx_q[QUEUE_R2] ; + queue->rx_bmu_ctl = (HW_PTR) ADDR(B0_R2_CSR) ; + queue->rx_bmu_dsc = (HW_PTR) ADDR(B4_R2_DA) ; +} + +/* + * set the TSYNC register of the FORMAC to regulate synchronous transmission + */ +void set_formac_tsync(struct s_smc *smc, long sync_bw) +{ + outpw(FM_A(FM_TSYNC),(unsigned int) (((-sync_bw) >> 5) & 0xffff) ) ; +} + +/* + * init all tx data structures + */ +static void init_tx(struct s_smc *smc) +{ + struct s_smt_tx_queue *queue ; + + /* + * init all tx data structures for the synchronous queue + */ + smc->hw.fp.tx[QUEUE_S] = queue = &smc->hw.fp.tx_q[QUEUE_S] ; + queue->tx_bmu_ctl = (HW_PTR) ADDR(B0_XS_CSR) ; + queue->tx_bmu_dsc = (HW_PTR) ADDR(B5_XS_DA) ; + +#ifdef ESS + set_formac_tsync(smc,smc->ess.sync_bw) ; +#endif + + /* + * init all tx data structures for the asynchronous queue 0 + */ + smc->hw.fp.tx[QUEUE_A0] = queue = &smc->hw.fp.tx_q[QUEUE_A0] ; + queue->tx_bmu_ctl = (HW_PTR) ADDR(B0_XA_CSR) ; + queue->tx_bmu_dsc = (HW_PTR) ADDR(B5_XA_DA) ; + + + llc_recover_tx(smc) ; +} + +static void mac_counter_init(struct s_smc *smc) +{ + int i ; + u_long *ec ; + + /* + * clear FORMAC+ frame-, lost- and error counter + */ + outpw(FM_A(FM_FCNTR),0) ; + outpw(FM_A(FM_LCNTR),0) ; + outpw(FM_A(FM_ECNTR),0) ; + /* + * clear internal error counter structure + */ + ec = (u_long *)&smc->hw.fp.err_stats ; + for (i = (sizeof(struct err_st)/sizeof(long)) ; i ; i--) + *ec++ = 0L ; + smc->mib.m[MAC0].fddiMACRingOp_Ct = 0 ; +} + +/* + * set FORMAC address, and t_request + */ +static void set_formac_addr(struct s_smc *smc) +{ + long t_requ = smc->mib.m[MAC0].fddiMACT_Req ; + + outpw(FM_A(FM_SAID),my_said) ; /* set short address */ + outpw(FM_A(FM_LAIL),(unsigned)((smc->hw.fddi_home_addr.a[4]<<8) + + smc->hw.fddi_home_addr.a[5])) ; + outpw(FM_A(FM_LAIC),(unsigned)((smc->hw.fddi_home_addr.a[2]<<8) + + smc->hw.fddi_home_addr.a[3])) ; + outpw(FM_A(FM_LAIM),(unsigned)((smc->hw.fddi_home_addr.a[0]<<8) + + smc->hw.fddi_home_addr.a[1])) ; + + outpw(FM_A(FM_SAGP),my_sagp) ; /* set short group address */ + + outpw(FM_A(FM_LAGL),(unsigned)((smc->hw.fp.group_addr.a[4]<<8) + + smc->hw.fp.group_addr.a[5])) ; + outpw(FM_A(FM_LAGC),(unsigned)((smc->hw.fp.group_addr.a[2]<<8) + + smc->hw.fp.group_addr.a[3])) ; + outpw(FM_A(FM_LAGM),(unsigned)((smc->hw.fp.group_addr.a[0]<<8) + + smc->hw.fp.group_addr.a[1])) ; + + /* set r_request regs. (MSW & LSW of TRT ) */ + outpw(FM_A(FM_TREQ1),(unsigned)(t_requ>>16)) ; + outpw(FM_A(FM_TREQ0),(unsigned)t_requ) ; +} + +static void set_int(char *p, int l) +{ + p[0] = (char)(l >> 24) ; + p[1] = (char)(l >> 16) ; + p[2] = (char)(l >> 8) ; + p[3] = (char)(l >> 0) ; +} + +/* + * copy TX descriptor to buffer mem + * append FC field and MAC frame + * if more bit is set in descr + * append pointer to descriptor (endless loop) + * else + * append 'end of chain' pointer + */ +static void copy_tx_mac(struct s_smc *smc, u_long td, struct fddi_mac *mac, + unsigned off, int len) +/* u_long td; transmit descriptor */ +/* struct fddi_mac *mac; mac frame pointer */ +/* unsigned off; start address within buffer memory */ +/* int len ; length of the frame including the FC */ +{ + int i ; + __le32 *p ; + + CHECK_NPP() ; + MARW(off) ; /* set memory address reg for writes */ + + p = (__le32 *) mac ; + for (i = (len + 3)/4 ; i ; i--) { + if (i == 1) { + /* last word, set the tag bit */ + outpw(FM_A(FM_CMDREG2),FM_ISTTB) ; + } + write_mdr(smc,le32_to_cpu(*p)) ; + p++ ; + } + + outpw(FM_A(FM_CMDREG2),FM_ISTTB) ; /* set the tag bit */ + write_mdr(smc,td) ; /* write over memory data reg to buffer */ +} + +/* + BEGIN_MANUAL_ENTRY(module;tests;3) + How to test directed beacon frames + ---------------------------------------------------------------- + + o Insert a break point in the function build_claim_beacon() + before calling copy_tx_mac() for building the claim frame. + o Modify the RM3_DETECT case so that the RM6_DETECT state + will always entered from the RM3_DETECT state (function rmt_fsm(), + rmt.c) + o Compile the driver. + o Set the parameter TREQ in the protocol.ini or net.cfg to a + small value to make sure your station will win the claim + process. + o Start the driver. + o When you reach the break point, modify the SA and DA address + of the claim frame (e.g. SA = DA = 10005affffff). + o When you see RM3_DETECT and RM6_DETECT, observe the direct + beacon frames on the UPPSLANA. + + END_MANUAL_ENTRY + */ +static void directed_beacon(struct s_smc *smc) +{ + SK_LOC_DECL(__le32,a[2]) ; + + /* + * set UNA in frame + * enable FORMAC to send endless queue of directed beacon + * important: the UNA starts at byte 1 (not at byte 0) + */ + * (char *) a = (char) ((long)DBEACON_INFO<<24L) ; + a[1] = 0 ; + memcpy((char *)a+1,(char *) &smc->mib.m[MAC0].fddiMACUpstreamNbr,6) ; + + CHECK_NPP() ; + /* set memory address reg for writes */ + MARW(smc->hw.fp.fifo.rbc_ram_start+DBEACON_FRAME_OFF+4) ; + write_mdr(smc,le32_to_cpu(a[0])) ; + outpw(FM_A(FM_CMDREG2),FM_ISTTB) ; /* set the tag bit */ + write_mdr(smc,le32_to_cpu(a[1])) ; + + outpw(FM_A(FM_SABC),smc->hw.fp.fifo.rbc_ram_start + DBEACON_FRAME_OFF) ; +} + +/* + setup claim & beacon pointer + NOTE : + special frame packets end with a pointer to their own + descriptor, and the MORE bit is set in the descriptor +*/ +static void build_claim_beacon(struct s_smc *smc, u_long t_request) +{ + u_int td ; + int len ; + struct fddi_mac_sf *mac ; + + /* + * build claim packet + */ + len = 17 ; + td = TX_DESCRIPTOR | ((((u_int)len-1)&3)<<27) ; + mac = &smc->hw.fp.mac_sfb ; + mac->mac_fc = FC_CLAIM ; + /* DA == SA in claim frame */ + mac->mac_source = mac->mac_dest = MA ; + /* 2's complement */ + set_int((char *)mac->mac_info,(int)t_request) ; + + copy_tx_mac(smc,td,(struct fddi_mac *)mac, + smc->hw.fp.fifo.rbc_ram_start + CLAIM_FRAME_OFF,len) ; + /* set CLAIM start pointer */ + outpw(FM_A(FM_SACL),smc->hw.fp.fifo.rbc_ram_start + CLAIM_FRAME_OFF) ; + + /* + * build beacon packet + */ + len = 17 ; + td = TX_DESCRIPTOR | ((((u_int)len-1)&3)<<27) ; + mac->mac_fc = FC_BEACON ; + mac->mac_source = MA ; + mac->mac_dest = null_addr ; /* DA == 0 in beacon frame */ + set_int((char *) mac->mac_info,((int)BEACON_INFO<<24) + 0 ) ; + + copy_tx_mac(smc,td,(struct fddi_mac *)mac, + smc->hw.fp.fifo.rbc_ram_start + BEACON_FRAME_OFF,len) ; + /* set beacon start pointer */ + outpw(FM_A(FM_SABC),smc->hw.fp.fifo.rbc_ram_start + BEACON_FRAME_OFF) ; + + /* + * build directed beacon packet + * contains optional UNA + */ + len = 23 ; + td = TX_DESCRIPTOR | ((((u_int)len-1)&3)<<27) ; + mac->mac_fc = FC_BEACON ; + mac->mac_source = MA ; + mac->mac_dest = dbeacon_multi ; /* multicast */ + set_int((char *) mac->mac_info,((int)DBEACON_INFO<<24) + 0 ) ; + set_int((char *) mac->mac_info+4,0) ; + set_int((char *) mac->mac_info+8,0) ; + + copy_tx_mac(smc,td,(struct fddi_mac *)mac, + smc->hw.fp.fifo.rbc_ram_start + DBEACON_FRAME_OFF,len) ; + + /* end of claim/beacon queue */ + outpw(FM_A(FM_EACB),smc->hw.fp.fifo.rx1_fifo_start-1) ; + + outpw(FM_A(FM_WPXSF),0) ; + outpw(FM_A(FM_RPXSF),0) ; +} + +static void formac_rcv_restart(struct s_smc *smc) +{ + /* enable receive function */ + SETMASK(FM_A(FM_MDREG1),smc->hw.fp.rx_mode,FM_ADDRX) ; + + outpw(FM_A(FM_CMDREG1),FM_ICLLR) ; /* clear receive lock */ +} + +void formac_tx_restart(struct s_smc *smc) +{ + outpw(FM_A(FM_CMDREG1),FM_ICLLS) ; /* clear s-frame lock */ + outpw(FM_A(FM_CMDREG1),FM_ICLLA0) ; /* clear a-frame lock */ +} + +static void enable_formac(struct s_smc *smc) +{ + /* set formac IMSK : 0 enables irq */ + outpw(FM_A(FM_IMSK1U),(unsigned short)~mac_imsk1u); + outpw(FM_A(FM_IMSK1L),(unsigned short)~mac_imsk1l); + outpw(FM_A(FM_IMSK2U),(unsigned short)~mac_imsk2u); + outpw(FM_A(FM_IMSK2L),(unsigned short)~mac_imsk2l); + outpw(FM_A(FM_IMSK3U),(unsigned short)~mac_imsk3u); + outpw(FM_A(FM_IMSK3L),(unsigned short)~mac_imsk3l); +} + +#if 0 /* Removed because the driver should use the ASICs TX complete IRQ. */ + /* The FORMACs tx complete IRQ should be used any longer */ + +/* + BEGIN_MANUAL_ENTRY(if,func;others;4) + + void enable_tx_irq(smc, queue) + struct s_smc *smc ; + u_short queue ; + +Function DOWNCALL (SMT, fplustm.c) + enable_tx_irq() enables the FORMACs transmit complete + interrupt of the queue. + +Para queue = QUEUE_S: synchronous queue + = QUEUE_A0: asynchronous queue + +Note After any ring operational change the transmit complete + interrupts are disabled. + The operating system dependent module must enable + the transmit complete interrupt of a queue, + - when it queues the first frame, + because of no transmit resources are beeing + available and + - when it escapes from the function llc_restart_tx + while some frames are still queued. + + END_MANUAL_ENTRY + */ +void enable_tx_irq(struct s_smc *smc, u_short queue) +/* u_short queue; 0 = synchronous queue, 1 = asynchronous queue 0 */ +{ + u_short imask ; + + imask = ~(inpw(FM_A(FM_IMSK1U))) ; + + if (queue == 0) { + outpw(FM_A(FM_IMSK1U),~(imask|FM_STEFRMS)) ; + } + if (queue == 1) { + outpw(FM_A(FM_IMSK1U),~(imask|FM_STEFRMA0)) ; + } +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;4) + + void disable_tx_irq(smc, queue) + struct s_smc *smc ; + u_short queue ; + +Function DOWNCALL (SMT, fplustm.c) + disable_tx_irq disables the FORMACs transmit complete + interrupt of the queue + +Para queue = QUEUE_S: synchronous queue + = QUEUE_A0: asynchronous queue + +Note The operating system dependent module should disable + the transmit complete interrupts if it escapes from the + function llc_restart_tx and no frames are queued. + + END_MANUAL_ENTRY + */ +void disable_tx_irq(struct s_smc *smc, u_short queue) +/* u_short queue; 0 = synchronous queue, 1 = asynchronous queue 0 */ +{ + u_short imask ; + + imask = ~(inpw(FM_A(FM_IMSK1U))) ; + + if (queue == 0) { + outpw(FM_A(FM_IMSK1U),~(imask&~FM_STEFRMS)) ; + } + if (queue == 1) { + outpw(FM_A(FM_IMSK1U),~(imask&~FM_STEFRMA0)) ; + } +} +#endif + +static void disable_formac(struct s_smc *smc) +{ + /* clear formac IMSK : 1 disables irq */ + outpw(FM_A(FM_IMSK1U),MW) ; + outpw(FM_A(FM_IMSK1L),MW) ; + outpw(FM_A(FM_IMSK2U),MW) ; + outpw(FM_A(FM_IMSK2L),MW) ; + outpw(FM_A(FM_IMSK3U),MW) ; + outpw(FM_A(FM_IMSK3L),MW) ; +} + + +static void mac_ring_up(struct s_smc *smc, int up) +{ + if (up) { + formac_rcv_restart(smc) ; /* enable receive function */ + smc->hw.mac_ring_is_up = TRUE ; + llc_restart_tx(smc) ; /* TX queue */ + } + else { + /* disable receive function */ + SETMASK(FM_A(FM_MDREG1),FM_MDISRCV,FM_ADDET) ; + + /* abort current transmit activity */ + outpw(FM_A(FM_CMDREG2),FM_IACTR) ; + + smc->hw.mac_ring_is_up = FALSE ; + } +} + +/*--------------------------- ISR handling ----------------------------------*/ +/* + * mac1_irq is in drvfbi.c + */ + +/* + * mac2_irq: status bits for the receive queue 1, and ring status + * ring status indication bits + */ +void mac2_irq(struct s_smc *smc, u_short code_s2u, u_short code_s2l) +{ + u_short change_s2l ; + u_short change_s2u ; + + /* (jd) 22-Feb-1999 + * Restart 2_DMax Timer after end of claiming or beaconing + */ + if (code_s2u & (FM_SCLM|FM_SHICLM|FM_SBEC|FM_SOTRBEC)) { + queue_event(smc,EVENT_RMT,RM_TX_STATE_CHANGE) ; + } + else if (code_s2l & (FM_STKISS)) { + queue_event(smc,EVENT_RMT,RM_TX_STATE_CHANGE) ; + } + + /* + * XOR current st bits with the last to avoid useless RMT event queuing + */ + change_s2l = smc->hw.fp.s2l ^ code_s2l ; + change_s2u = smc->hw.fp.s2u ^ code_s2u ; + + if ((change_s2l & FM_SRNGOP) || + (!smc->hw.mac_ring_is_up && ((code_s2l & FM_SRNGOP)))) { + if (code_s2l & FM_SRNGOP) { + mac_ring_up(smc,1) ; + queue_event(smc,EVENT_RMT,RM_RING_OP) ; + smc->mib.m[MAC0].fddiMACRingOp_Ct++ ; + } + else { + mac_ring_up(smc,0) ; + queue_event(smc,EVENT_RMT,RM_RING_NON_OP) ; + } + goto mac2_end ; + } + if (code_s2l & FM_SMISFRM) { /* missed frame */ + smc->mib.m[MAC0].fddiMACNotCopied_Ct++ ; + } + if (code_s2u & (FM_SRCVOVR | /* recv. FIFO overflow */ + FM_SRBFL)) { /* recv. buffer full */ + smc->hw.mac_ct.mac_r_restart_counter++ ; +/* formac_rcv_restart(smc) ; */ + smt_stat_counter(smc,1) ; +/* goto mac2_end ; */ + } + if (code_s2u & FM_SOTRBEC) + queue_event(smc,EVENT_RMT,RM_OTHER_BEACON) ; + if (code_s2u & FM_SMYBEC) + queue_event(smc,EVENT_RMT,RM_MY_BEACON) ; + if (change_s2u & code_s2u & FM_SLOCLM) { + DB_RMTN(2,"RMT : lower claim received\n",0,0) ; + } + if ((code_s2u & FM_SMYCLM) && !(code_s2l & FM_SDUPCLM)) { + /* + * This is my claim and that claim is not detected as a + * duplicate one. + */ + queue_event(smc,EVENT_RMT,RM_MY_CLAIM) ; + } + if (code_s2l & FM_SDUPCLM) { + /* + * If a duplicate claim frame (same SA but T_Bid != T_Req) + * this flag will be set. + * In the RMT state machine we need a RM_VALID_CLAIM event + * to do the appropriate state change. + * RM(34c) + */ + queue_event(smc,EVENT_RMT,RM_VALID_CLAIM) ; + } + if (change_s2u & code_s2u & FM_SHICLM) { + DB_RMTN(2,"RMT : higher claim received\n",0,0) ; + } + if ( (code_s2l & FM_STRTEXP) || + (code_s2l & FM_STRTEXR) ) + queue_event(smc,EVENT_RMT,RM_TRT_EXP) ; + if (code_s2l & FM_SMULTDA) { + /* + * The MAC has found a 2. MAC with the same address. + * Signal dup_addr_test = failed to RMT state machine. + * RM(25) + */ + smc->r.dup_addr_test = DA_FAILED ; + queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ; + } + if (code_s2u & FM_SBEC) + smc->hw.fp.err_stats.err_bec_stat++ ; + if (code_s2u & FM_SCLM) + smc->hw.fp.err_stats.err_clm_stat++ ; + if (code_s2l & FM_STVXEXP) + smc->mib.m[MAC0].fddiMACTvxExpired_Ct++ ; + if ((code_s2u & (FM_SBEC|FM_SCLM))) { + if (!(change_s2l & FM_SRNGOP) && (smc->hw.fp.s2l & FM_SRNGOP)) { + mac_ring_up(smc,0) ; + queue_event(smc,EVENT_RMT,RM_RING_NON_OP) ; + + mac_ring_up(smc,1) ; + queue_event(smc,EVENT_RMT,RM_RING_OP) ; + smc->mib.m[MAC0].fddiMACRingOp_Ct++ ; + } + } + if (code_s2l & FM_SPHINV) + smc->hw.fp.err_stats.err_phinv++ ; + if (code_s2l & FM_SSIFG) + smc->hw.fp.err_stats.err_sifg_det++ ; + if (code_s2l & FM_STKISS) + smc->hw.fp.err_stats.err_tkiss++ ; + if (code_s2l & FM_STKERR) + smc->hw.fp.err_stats.err_tkerr++ ; + if (code_s2l & FM_SFRMCTR) + smc->mib.m[MAC0].fddiMACFrame_Ct += 0x10000L ; + if (code_s2l & FM_SERRCTR) + smc->mib.m[MAC0].fddiMACError_Ct += 0x10000L ; + if (code_s2l & FM_SLSTCTR) + smc->mib.m[MAC0].fddiMACLost_Ct += 0x10000L ; + if (code_s2u & FM_SERRSF) { + SMT_PANIC(smc,SMT_E0114, SMT_E0114_MSG) ; + } +mac2_end: + /* notice old status */ + smc->hw.fp.s2l = code_s2l ; + smc->hw.fp.s2u = code_s2u ; + outpw(FM_A(FM_IMSK2U),~mac_imsk2u) ; +} + +/* + * mac3_irq: receive queue 2 bits and address detection bits + */ +void mac3_irq(struct s_smc *smc, u_short code_s3u, u_short code_s3l) +{ + UNUSED(code_s3l) ; + + if (code_s3u & (FM_SRCVOVR2 | /* recv. FIFO overflow */ + FM_SRBFL2)) { /* recv. buffer full */ + smc->hw.mac_ct.mac_r_restart_counter++ ; + smt_stat_counter(smc,1); + } + + + if (code_s3u & FM_SRPERRQ2) { /* parity error receive queue 2 */ + SMT_PANIC(smc,SMT_E0115, SMT_E0115_MSG) ; + } + if (code_s3u & FM_SRPERRQ1) { /* parity error receive queue 2 */ + SMT_PANIC(smc,SMT_E0116, SMT_E0116_MSG) ; + } +} + + +/* + * take formac offline + */ +static void formac_offline(struct s_smc *smc) +{ + outpw(FM_A(FM_CMDREG2),FM_IACTR) ;/* abort current transmit activity */ + + /* disable receive function */ + SETMASK(FM_A(FM_MDREG1),FM_MDISRCV,FM_ADDET) ; + + /* FORMAC+ 'Initialize Mode' */ + SETMASK(FM_A(FM_MDREG1),FM_MINIT,FM_MMODE) ; + + disable_formac(smc) ; + smc->hw.mac_ring_is_up = FALSE ; + smc->hw.hw_state = STOPPED ; +} + +/* + * bring formac online + */ +static void formac_online(struct s_smc *smc) +{ + enable_formac(smc) ; + SETMASK(FM_A(FM_MDREG1),FM_MONLINE | FM_SELRA | MDR1INIT | + smc->hw.fp.rx_mode, FM_MMODE | FM_SELRA | FM_ADDRX) ; +} + +/* + * FORMAC+ full init. (tx, rx, timer, counter, claim & beacon) + */ +int init_fplus(struct s_smc *smc) +{ + smc->hw.fp.nsa_mode = FM_MRNNSAFNMA ; + smc->hw.fp.rx_mode = FM_MDAMA ; + smc->hw.fp.group_addr = fddi_broadcast ; + smc->hw.fp.func_addr = 0 ; + smc->hw.fp.frselreg_init = 0 ; + + init_driver_fplus(smc) ; + if (smc->s.sas == SMT_DAS) + smc->hw.fp.mdr3init |= FM_MENDAS ; + + smc->hw.mac_ct.mac_nobuf_counter = 0 ; + smc->hw.mac_ct.mac_r_restart_counter = 0 ; + + smc->hw.fp.fm_st1u = (HW_PTR) ADDR(B0_ST1U) ; + smc->hw.fp.fm_st1l = (HW_PTR) ADDR(B0_ST1L) ; + smc->hw.fp.fm_st2u = (HW_PTR) ADDR(B0_ST2U) ; + smc->hw.fp.fm_st2l = (HW_PTR) ADDR(B0_ST2L) ; + smc->hw.fp.fm_st3u = (HW_PTR) ADDR(B0_ST3U) ; + smc->hw.fp.fm_st3l = (HW_PTR) ADDR(B0_ST3L) ; + + smc->hw.fp.s2l = smc->hw.fp.s2u = 0 ; + smc->hw.mac_ring_is_up = 0 ; + + mac_counter_init(smc) ; + + /* convert BCKL units to symbol time */ + smc->hw.mac_pa.t_neg = (u_long)0 ; + smc->hw.mac_pa.t_pri = (u_long)0 ; + + /* make sure all PCI settings are correct */ + mac_do_pci_fix(smc) ; + + return init_mac(smc, 1); + /* enable_formac(smc) ; */ +} + +static int init_mac(struct s_smc *smc, int all) +{ + u_short t_max,x ; + u_long time=0 ; + + /* + * clear memory + */ + outpw(FM_A(FM_MDREG1),FM_MINIT) ; /* FORMAC+ init mode */ + set_formac_addr(smc) ; + outpw(FM_A(FM_MDREG1),FM_MMEMACT) ; /* FORMAC+ memory activ mode */ + /* Note: Mode register 2 is set here, incase parity is enabled. */ + outpw(FM_A(FM_MDREG2),smc->hw.fp.mdr2init) ; + + if (all) { + init_ram(smc) ; + } + else { + /* + * reset the HPI, the Master and the BMUs + */ + outp(ADDR(B0_CTRL), CTRL_HPI_SET) ; + time = hwt_quick_read(smc) ; + } + + /* + * set all pointers, frames etc + */ + smt_split_up_fifo(smc) ; + + init_tx(smc) ; + init_rx(smc) ; + init_rbc(smc) ; + + build_claim_beacon(smc,smc->mib.m[MAC0].fddiMACT_Req) ; + + /* set RX threshold */ + /* see Errata #SN2 Phantom receive overflow */ + outpw(FM_A(FM_FRMTHR),14<<12) ; /* switch on */ + + /* set formac work mode */ + outpw(FM_A(FM_MDREG1),MDR1INIT | FM_SELRA | smc->hw.fp.rx_mode) ; + outpw(FM_A(FM_MDREG2),smc->hw.fp.mdr2init) ; + outpw(FM_A(FM_MDREG3),smc->hw.fp.mdr3init) ; + outpw(FM_A(FM_FRSELREG),smc->hw.fp.frselreg_init) ; + + /* set timer */ + /* + * errata #22 fplus: + * T_MAX must not be FFFE + * or one of FFDF, FFB8, FF91 (-0x27 etc..) + */ + t_max = (u_short)(smc->mib.m[MAC0].fddiMACT_Max/32) ; + x = t_max/0x27 ; + x *= 0x27 ; + if ((t_max == 0xfffe) || (t_max - x == 0x16)) + t_max-- ; + outpw(FM_A(FM_TMAX),(u_short)t_max) ; + + /* BugFix for report #10204 */ + if (smc->mib.m[MAC0].fddiMACTvxValue < (u_long) (- US2BCLK(52))) { + outpw(FM_A(FM_TVX), (u_short) (- US2BCLK(52))/255 & MB) ; + } else { + outpw(FM_A(FM_TVX), + (u_short)((smc->mib.m[MAC0].fddiMACTvxValue/255) & MB)) ; + } + + outpw(FM_A(FM_CMDREG1),FM_ICLLS) ; /* clear s-frame lock */ + outpw(FM_A(FM_CMDREG1),FM_ICLLA0) ; /* clear a-frame lock */ + outpw(FM_A(FM_CMDREG1),FM_ICLLR); /* clear receive lock */ + + /* Auto unlock receice threshold for receive queue 1 and 2 */ + outpw(FM_A(FM_UNLCKDLY),(0xff|(0xff<<8))) ; + + rtm_init(smc) ; /* RT-Monitor */ + + if (!all) { + /* + * after 10ms, reset the BMUs and repair the rings + */ + hwt_wait_time(smc,time,MS2BCLK(10)) ; + outpd(ADDR(B0_R1_CSR),CSR_SET_RESET) ; + outpd(ADDR(B0_XA_CSR),CSR_SET_RESET) ; + outpd(ADDR(B0_XS_CSR),CSR_SET_RESET) ; + outp(ADDR(B0_CTRL), CTRL_HPI_CLR) ; + outpd(ADDR(B0_R1_CSR),CSR_CLR_RESET) ; + outpd(ADDR(B0_XA_CSR),CSR_CLR_RESET) ; + outpd(ADDR(B0_XS_CSR),CSR_CLR_RESET) ; + if (!smc->hw.hw_is_64bit) { + outpd(ADDR(B4_R1_F), RX_WATERMARK) ; + outpd(ADDR(B5_XA_F), TX_WATERMARK) ; + outpd(ADDR(B5_XS_F), TX_WATERMARK) ; + } + smc->hw.hw_state = STOPPED ; + mac_drv_repair_descr(smc) ; + } + smc->hw.hw_state = STARTED ; + + return 0; +} + + +/* + * called by CFM + */ +void config_mux(struct s_smc *smc, int mux) +{ + plc_config_mux(smc,mux) ; + + SETMASK(FM_A(FM_MDREG1),FM_SELRA,FM_SELRA) ; +} + +/* + * called by RMT + * enable CLAIM/BEACON interrupts + * (only called if these events are of interest, e.g. in DETECT state + * the interrupt must not be permanently enabled + * RMT calls this function periodically (timer driven polling) + */ +void sm_mac_check_beacon_claim(struct s_smc *smc) +{ + /* set formac IMSK : 0 enables irq */ + outpw(FM_A(FM_IMSK2U),~(mac_imsk2u | mac_beacon_imsk2u)) ; + /* the driver must receive the directed beacons */ + formac_rcv_restart(smc) ; + process_receive(smc) ; +} + +/*-------------------------- interface functions ----------------------------*/ +/* + * control MAC layer (called by RMT) + */ +void sm_ma_control(struct s_smc *smc, int mode) +{ + switch(mode) { + case MA_OFFLINE : + /* Add to make the MAC offline in RM0_ISOLATED state */ + formac_offline(smc) ; + break ; + case MA_RESET : + (void)init_mac(smc,0) ; + break ; + case MA_BEACON : + formac_online(smc) ; + break ; + case MA_DIRECTED : + directed_beacon(smc) ; + break ; + case MA_TREQ : + /* + * no actions necessary, TREQ is already set + */ + break ; + } +} + +int sm_mac_get_tx_state(struct s_smc *smc) +{ + return (inpw(FM_A(FM_STMCHN))>>4) & 7; +} + +/* + * multicast functions + */ + +static struct s_fpmc* mac_get_mc_table(struct s_smc *smc, + struct fddi_addr *user, + struct fddi_addr *own, + int del, int can) +{ + struct s_fpmc *tb ; + struct s_fpmc *slot ; + u_char *p ; + int i ; + + /* + * set own = can(user) + */ + *own = *user ; + if (can) { + p = own->a ; + for (i = 0 ; i < 6 ; i++, p++) + *p = bitrev8(*p); + } + slot = NULL; + for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){ + if (!tb->n) { /* not used */ + if (!del && !slot) /* if !del save first free */ + slot = tb ; + continue ; + } + if (memcmp((char *)&tb->a,(char *)own,6)) + continue ; + return tb; + } + return slot; /* return first free or NULL */ +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;2) + + void mac_clear_multicast(smc) + struct s_smc *smc ; + +Function DOWNCALL (SMT, fplustm.c) + Clear all multicast entries + + END_MANUAL_ENTRY() + */ +void mac_clear_multicast(struct s_smc *smc) +{ + struct s_fpmc *tb ; + int i ; + + smc->hw.fp.os_slots_used = 0 ; /* note the SMT addresses */ + /* will not be deleted */ + for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){ + if (!tb->perm) { + tb->n = 0 ; + } + } +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;2) + + int mac_add_multicast(smc,addr,can) + struct s_smc *smc ; + struct fddi_addr *addr ; + int can ; + +Function DOWNCALL (SMC, fplustm.c) + Add an entry to the multicast table + +Para addr pointer to a multicast address + can = 0: the multicast address has the physical format + = 1: the multicast address has the canonical format + | 0x80 permanent + +Returns 0: success + 1: address table full + +Note After a 'driver reset' or a 'station set address' all + entries of the multicast table are cleared. + In this case the driver has to fill the multicast table again. + After the operating system dependent module filled + the multicast table it must call mac_update_multicast + to activate the new multicast addresses! + + END_MANUAL_ENTRY() + */ +int mac_add_multicast(struct s_smc *smc, struct fddi_addr *addr, int can) +{ + SK_LOC_DECL(struct fddi_addr,own) ; + struct s_fpmc *tb ; + + /* + * check if there are free table entries + */ + if (can & 0x80) { + if (smc->hw.fp.smt_slots_used >= SMT_MAX_MULTI) { + return 1; + } + } + else { + if (smc->hw.fp.os_slots_used >= FPMAX_MULTICAST-SMT_MAX_MULTI) { + return 1; + } + } + + /* + * find empty slot + */ + if (!(tb = mac_get_mc_table(smc,addr,&own,0,can & ~0x80))) + return 1; + tb->n++ ; + tb->a = own ; + tb->perm = (can & 0x80) ? 1 : 0 ; + + if (can & 0x80) + smc->hw.fp.smt_slots_used++ ; + else + smc->hw.fp.os_slots_used++ ; + + return 0; +} + +/* + * mode + */ + +#define RX_MODE_PROM 0x1 +#define RX_MODE_ALL_MULTI 0x2 + +/* + BEGIN_MANUAL_ENTRY(if,func;others;2) + + void mac_update_multicast(smc) + struct s_smc *smc ; + +Function DOWNCALL (SMT, fplustm.c) + Update FORMAC multicast registers + + END_MANUAL_ENTRY() + */ +void mac_update_multicast(struct s_smc *smc) +{ + struct s_fpmc *tb ; + u_char *fu ; + int i ; + + /* + * invalidate the CAM + */ + outpw(FM_A(FM_AFCMD),FM_IINV_CAM) ; + + /* + * set the functional address + */ + if (smc->hw.fp.func_addr) { + fu = (u_char *) &smc->hw.fp.func_addr ; + outpw(FM_A(FM_AFMASK2),0xffff) ; + outpw(FM_A(FM_AFMASK1),(u_short) ~((fu[0] << 8) + fu[1])) ; + outpw(FM_A(FM_AFMASK0),(u_short) ~((fu[2] << 8) + fu[3])) ; + outpw(FM_A(FM_AFPERS),FM_VALID|FM_DA) ; + outpw(FM_A(FM_AFCOMP2), 0xc000) ; + outpw(FM_A(FM_AFCOMP1), 0x0000) ; + outpw(FM_A(FM_AFCOMP0), 0x0000) ; + outpw(FM_A(FM_AFCMD),FM_IWRITE_CAM) ; + } + + /* + * set the mask and the personality register(s) + */ + outpw(FM_A(FM_AFMASK0),0xffff) ; + outpw(FM_A(FM_AFMASK1),0xffff) ; + outpw(FM_A(FM_AFMASK2),0xffff) ; + outpw(FM_A(FM_AFPERS),FM_VALID|FM_DA) ; + + for (i = 0, tb = smc->hw.fp.mc.table; i < FPMAX_MULTICAST; i++, tb++) { + if (tb->n) { + CHECK_CAM() ; + + /* + * write the multicast address into the CAM + */ + outpw(FM_A(FM_AFCOMP2), + (u_short)((tb->a.a[0]<<8)+tb->a.a[1])) ; + outpw(FM_A(FM_AFCOMP1), + (u_short)((tb->a.a[2]<<8)+tb->a.a[3])) ; + outpw(FM_A(FM_AFCOMP0), + (u_short)((tb->a.a[4]<<8)+tb->a.a[5])) ; + outpw(FM_A(FM_AFCMD),FM_IWRITE_CAM) ; + } + } +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;3) + + void mac_set_rx_mode(smc,mode) + struct s_smc *smc ; + int mode ; + +Function DOWNCALL/INTERN (SMT, fplustm.c) + This function enables / disables the selected receive. + Don't call this function if the hardware module is + used -- use mac_drv_rx_mode() instead of. + +Para mode = 1 RX_ENABLE_ALLMULTI enable all multicasts + 2 RX_DISABLE_ALLMULTI disable "enable all multicasts" + 3 RX_ENABLE_PROMISC enable promiscuous + 4 RX_DISABLE_PROMISC disable promiscuous + 5 RX_ENABLE_NSA enable reception of NSA frames + 6 RX_DISABLE_NSA disable reception of NSA frames + +Note The selected receive modes will be lost after 'driver reset' + or 'set station address' + + END_MANUAL_ENTRY + */ +void mac_set_rx_mode(struct s_smc *smc, int mode) +{ + switch (mode) { + case RX_ENABLE_ALLMULTI : + smc->hw.fp.rx_prom |= RX_MODE_ALL_MULTI ; + break ; + case RX_DISABLE_ALLMULTI : + smc->hw.fp.rx_prom &= ~RX_MODE_ALL_MULTI ; + break ; + case RX_ENABLE_PROMISC : + smc->hw.fp.rx_prom |= RX_MODE_PROM ; + break ; + case RX_DISABLE_PROMISC : + smc->hw.fp.rx_prom &= ~RX_MODE_PROM ; + break ; + case RX_ENABLE_NSA : + smc->hw.fp.nsa_mode = FM_MDAMA ; + smc->hw.fp.rx_mode = (smc->hw.fp.rx_mode & ~FM_ADDET) | + smc->hw.fp.nsa_mode ; + break ; + case RX_DISABLE_NSA : + smc->hw.fp.nsa_mode = FM_MRNNSAFNMA ; + smc->hw.fp.rx_mode = (smc->hw.fp.rx_mode & ~FM_ADDET) | + smc->hw.fp.nsa_mode ; + break ; + } + if (smc->hw.fp.rx_prom & RX_MODE_PROM) { + smc->hw.fp.rx_mode = FM_MLIMPROM ; + } + else if (smc->hw.fp.rx_prom & RX_MODE_ALL_MULTI) { + smc->hw.fp.rx_mode = smc->hw.fp.nsa_mode | FM_EXGPA0 ; + } + else + smc->hw.fp.rx_mode = smc->hw.fp.nsa_mode ; + SETMASK(FM_A(FM_MDREG1),smc->hw.fp.rx_mode,FM_ADDRX) ; + mac_update_multicast(smc) ; +} + +/* + BEGIN_MANUAL_ENTRY(module;tests;3) + How to test the Restricted Token Monitor + ---------------------------------------------------------------- + + o Insert a break point in the function rtm_irq() + o Remove all stations with a restricted token monitor from the + network. + o Connect a UPPS ISA or EISA station to the network. + o Give the FORMAC of UPPS station the command to send + restricted tokens until the ring becomes instable. + o Now connect your test test client. + o The restricted token monitor should detect the restricted token, + and your break point will be reached. + o You can ovserve how the station will clean the ring. + + END_MANUAL_ENTRY + */ +void rtm_irq(struct s_smc *smc) +{ + outpw(ADDR(B2_RTM_CRTL),TIM_CL_IRQ) ; /* clear IRQ */ + if (inpw(ADDR(B2_RTM_CRTL)) & TIM_RES_TOK) { + outpw(FM_A(FM_CMDREG1),FM_ICL) ; /* force claim */ + DB_RMT("RMT: fddiPATHT_Rmode expired\n",0,0) ; + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, + (u_long) FDDI_SMT_EVENT, + (u_long) FDDI_RTT, smt_get_event_word(smc)); + } + outpw(ADDR(B2_RTM_CRTL),TIM_START) ; /* enable RTM monitoring */ +} + +static void rtm_init(struct s_smc *smc) +{ + outpd(ADDR(B2_RTM_INI),0) ; /* timer = 0 */ + outpw(ADDR(B2_RTM_CRTL),TIM_START) ; /* enable IRQ */ +} + +void rtm_set_timer(struct s_smc *smc) +{ + /* + * MIB timer and hardware timer have the same resolution of 80nS + */ + DB_RMT("RMT: setting new fddiPATHT_Rmode, t = %d ns\n", + (int) smc->mib.a[PATH0].fddiPATHT_Rmode,0) ; + outpd(ADDR(B2_RTM_INI),smc->mib.a[PATH0].fddiPATHT_Rmode) ; +} + +static void smt_split_up_fifo(struct s_smc *smc) +{ + +/* + BEGIN_MANUAL_ENTRY(module;mem;1) + ------------------------------------------------------------- + RECEIVE BUFFER MEMORY DIVERSION + ------------------------------------------------------------- + + R1_RxD == SMT_R1_RXD_COUNT + R2_RxD == SMT_R2_RXD_COUNT + + SMT_R1_RXD_COUNT must be unequal zero + + | R1_RxD R2_RxD |R1_RxD R2_RxD | R1_RxD R2_RxD + | x 0 | x 1-3 | x < 3 + ---------------------------------------------------------------------- + | 63,75 kB | 54,75 | R1_RxD + rx queue 1 | RX_FIFO_SPACE | RX_LARGE_FIFO| ------------- * 63,75 kB + | | | R1_RxD+R2_RxD + ---------------------------------------------------------------------- + | | 9 kB | R2_RxD + rx queue 2 | 0 kB | RX_SMALL_FIFO| ------------- * 63,75 kB + | (not used) | | R1_RxD+R2_RxD + + END_MANUAL_ENTRY +*/ + + if (SMT_R1_RXD_COUNT == 0) { + SMT_PANIC(smc,SMT_E0117, SMT_E0117_MSG) ; + } + + switch(SMT_R2_RXD_COUNT) { + case 0: + smc->hw.fp.fifo.rx1_fifo_size = RX_FIFO_SPACE ; + smc->hw.fp.fifo.rx2_fifo_size = 0 ; + break ; + case 1: + case 2: + case 3: + smc->hw.fp.fifo.rx1_fifo_size = RX_LARGE_FIFO ; + smc->hw.fp.fifo.rx2_fifo_size = RX_SMALL_FIFO ; + break ; + default: /* this is not the real defaule */ + smc->hw.fp.fifo.rx1_fifo_size = RX_FIFO_SPACE * + SMT_R1_RXD_COUNT/(SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) ; + smc->hw.fp.fifo.rx2_fifo_size = RX_FIFO_SPACE * + SMT_R2_RXD_COUNT/(SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) ; + break ; + } + +/* + BEGIN_MANUAL_ENTRY(module;mem;1) + ------------------------------------------------------------- + TRANSMIT BUFFER MEMORY DIVERSION + ------------------------------------------------------------- + + + | no sync bw | sync bw available and | sync bw available and + | available | SynchTxMode = SPLIT | SynchTxMode = ALL + ----------------------------------------------------------------------- + sync tx | 0 kB | 32 kB | 55 kB + queue | | TX_MEDIUM_FIFO | TX_LARGE_FIFO + ----------------------------------------------------------------------- + async tx | 64 kB | 32 kB | 9 k + queue | TX_FIFO_SPACE| TX_MEDIUM_FIFO | TX_SMALL_FIFO + + END_MANUAL_ENTRY +*/ + + /* + * set the tx mode bits + */ + if (smc->mib.a[PATH0].fddiPATHSbaPayload) { +#ifdef ESS + smc->hw.fp.fifo.fifo_config_mode |= + smc->mib.fddiESSSynchTxMode | SYNC_TRAFFIC_ON ; +#endif + } + else { + smc->hw.fp.fifo.fifo_config_mode &= + ~(SEND_ASYNC_AS_SYNC|SYNC_TRAFFIC_ON) ; + } + + /* + * split up the FIFO + */ + if (smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON) { + if (smc->hw.fp.fifo.fifo_config_mode & SEND_ASYNC_AS_SYNC) { + smc->hw.fp.fifo.tx_s_size = TX_LARGE_FIFO ; + smc->hw.fp.fifo.tx_a0_size = TX_SMALL_FIFO ; + } + else { + smc->hw.fp.fifo.tx_s_size = TX_MEDIUM_FIFO ; + smc->hw.fp.fifo.tx_a0_size = TX_MEDIUM_FIFO ; + } + } + else { + smc->hw.fp.fifo.tx_s_size = 0 ; + smc->hw.fp.fifo.tx_a0_size = TX_FIFO_SPACE ; + } + + smc->hw.fp.fifo.rx1_fifo_start = smc->hw.fp.fifo.rbc_ram_start + + RX_FIFO_OFF ; + smc->hw.fp.fifo.tx_s_start = smc->hw.fp.fifo.rx1_fifo_start + + smc->hw.fp.fifo.rx1_fifo_size ; + smc->hw.fp.fifo.tx_a0_start = smc->hw.fp.fifo.tx_s_start + + smc->hw.fp.fifo.tx_s_size ; + smc->hw.fp.fifo.rx2_fifo_start = smc->hw.fp.fifo.tx_a0_start + + smc->hw.fp.fifo.tx_a0_size ; + + DB_SMT("FIFO split: mode = %x\n",smc->hw.fp.fifo.fifo_config_mode,0) ; + DB_SMT("rbc_ram_start = %x rbc_ram_end = %x\n", + smc->hw.fp.fifo.rbc_ram_start, smc->hw.fp.fifo.rbc_ram_end) ; + DB_SMT("rx1_fifo_start = %x tx_s_start = %x\n", + smc->hw.fp.fifo.rx1_fifo_start, smc->hw.fp.fifo.tx_s_start) ; + DB_SMT("tx_a0_start = %x rx2_fifo_start = %x\n", + smc->hw.fp.fifo.tx_a0_start, smc->hw.fp.fifo.rx2_fifo_start) ; +} + +void formac_reinit_tx(struct s_smc *smc) +{ + /* + * Split up the FIFO and reinitialize the MAC if synchronous + * bandwidth becomes available but no synchronous queue is + * configured. + */ + if (!smc->hw.fp.fifo.tx_s_size && smc->mib.a[PATH0].fddiPATHSbaPayload){ + (void)init_mac(smc,0) ; + } +} + diff --git a/drivers/net/fddi/skfp/h/cmtdef.h b/drivers/net/fddi/skfp/h/cmtdef.h new file mode 100644 index 0000000..5a6c612 --- /dev/null +++ b/drivers/net/fddi/skfp/h/cmtdef.h @@ -0,0 +1,756 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _CMTDEF_ +#define _CMTDEF_ + +/* **************************************************************** */ + +/* + * implementation specific constants + * MODIIFY THE FOLLOWING THREE DEFINES + */ +#define AMDPLC /* if Amd PLC chip used */ +#ifdef CONC +#define NUMPHYS 12 /* 2 for SAS or DAS, more for Concentrator */ +#else +#ifdef CONC_II +#define NUMPHYS 24 /* 2 for SAS or DAS, more for Concentrator */ +#else +#define NUMPHYS 2 /* 2 for SAS or DAS, more for Concentrator */ +#endif +#endif +#define NUMMACS 1 /* only 1 supported at the moment */ +#define NUMPATHS 2 /* primary and secondary path supported */ + +/* + * DO NOT MODIFY BEYOND THIS POINT + */ + +/* **************************************************************** */ + +#if NUMPHYS > 2 +#define CONCENTRATOR +#endif + +/* + * Definitions for comfortable LINT usage + */ +#ifdef lint +#define LINT_USE(x) (x)=(x) +#else +#define LINT_USE(x) +#endif + +#ifdef DEBUG +#define DB_PR(flag,a,b,c) { if (flag) printf(a,b,c) ; } +#else +#define DB_PR(flag,a,b,c) +#endif + +#ifdef DEBUG_BRD +#define DB_ECM(a,b,c) DB_PR((smc->debug.d_smt&1),a,b,c) +#define DB_ECMN(n,a,b,c) DB_PR((smc->debug.d_ecm >=(n)),a,b,c) +#define DB_RMT(a,b,c) DB_PR((smc->debug.d_smt&2),a,b,c) +#define DB_RMTN(n,a,b,c) DB_PR((smc->debug.d_rmt >=(n)),a,b,c) +#define DB_CFM(a,b,c) DB_PR((smc->debug.d_smt&4),a,b,c) +#define DB_CFMN(n,a,b,c) DB_PR((smc->debug.d_cfm >=(n)),a,b,c) +#define DB_PCM(a,b,c) DB_PR((smc->debug.d_smt&8),a,b,c) +#define DB_PCMN(n,a,b,c) DB_PR((smc->debug.d_pcm >=(n)),a,b,c) +#define DB_SMT(a,b,c) DB_PR((smc->debug.d_smtf),a,b,c) +#define DB_SMTN(n,a,b,c) DB_PR((smc->debug.d_smtf >=(n)),a,b,c) +#define DB_SBA(a,b,c) DB_PR((smc->debug.d_sba),a,b,c) +#define DB_SBAN(n,a,b,c) DB_PR((smc->debug.d_sba >=(n)),a,b,c) +#define DB_ESS(a,b,c) DB_PR((smc->debug.d_ess),a,b,c) +#define DB_ESSN(n,a,b,c) DB_PR((smc->debug.d_ess >=(n)),a,b,c) +#else +#define DB_ECM(a,b,c) DB_PR((debug.d_smt&1),a,b,c) +#define DB_ECMN(n,a,b,c) DB_PR((debug.d_ecm >=(n)),a,b,c) +#define DB_RMT(a,b,c) DB_PR((debug.d_smt&2),a,b,c) +#define DB_RMTN(n,a,b,c) DB_PR((debug.d_rmt >=(n)),a,b,c) +#define DB_CFM(a,b,c) DB_PR((debug.d_smt&4),a,b,c) +#define DB_CFMN(n,a,b,c) DB_PR((debug.d_cfm >=(n)),a,b,c) +#define DB_PCM(a,b,c) DB_PR((debug.d_smt&8),a,b,c) +#define DB_PCMN(n,a,b,c) DB_PR((debug.d_pcm >=(n)),a,b,c) +#define DB_SMT(a,b,c) DB_PR((debug.d_smtf),a,b,c) +#define DB_SMTN(n,a,b,c) DB_PR((debug.d_smtf >=(n)),a,b,c) +#define DB_SBA(a,b,c) DB_PR((debug.d_sba),a,b,c) +#define DB_SBAN(n,a,b,c) DB_PR((debug.d_sba >=(n)),a,b,c) +#define DB_ESS(a,b,c) DB_PR((debug.d_ess),a,b,c) +#define DB_ESSN(n,a,b,c) DB_PR((debug.d_ess >=(n)),a,b,c) +#endif + +#ifndef SS_NOT_DS +#define SK_LOC_DECL(type,var) type var +#else +#define SK_LOC_DECL(type,var) static type var +#endif +/* + * PHYs and PORTS + * Note: Don't touch the definition of PA and PB. Those might be used + * by some "for" loops. + */ +#define PA 0 +#define PB 1 +#if defined(SUPERNET_3) || defined(CONC_II) +/* + * The port indices have to be different, + * because the MAC output goes through the 2. PLC + * Conc II: It has to be the first port in the row. + */ +#define PS 0 /* Internal PLC which is the same as PA */ +#else +#define PS 1 +#endif +#define PM 2 /* PM .. PA+NUM_PHYS-1 */ + +/* + * PHY types - as in path descriptor 'fddiPHYType' + */ +#define TA 0 /* A port */ +#define TB 1 /* B port */ +#define TS 2 /* S port */ +#define TM 3 /* M port */ +#define TNONE 4 + + +/* + * indexes in MIB + */ +#define INDEX_MAC 1 +#define INDEX_PATH 1 +#define INDEX_PORT 1 + + +/* + * policies + */ +#define POLICY_AA (1<<0) /* reject AA */ +#define POLICY_AB (1<<1) /* reject AB */ +#define POLICY_AS (1<<2) /* reject AS */ +#define POLICY_AM (1<<3) /* reject AM */ +#define POLICY_BA (1<<4) /* reject BA */ +#define POLICY_BB (1<<5) /* reject BB */ +#define POLICY_BS (1<<6) /* reject BS */ +#define POLICY_BM (1<<7) /* reject BM */ +#define POLICY_SA (1<<8) /* reject SA */ +#define POLICY_SB (1<<9) /* reject SB */ +#define POLICY_SS (1<<10) /* reject SS */ +#define POLICY_SM (1<<11) /* reject SM */ +#define POLICY_MA (1<<12) /* reject MA */ +#define POLICY_MB (1<<13) /* reject MB */ +#define POLICY_MS (1<<14) /* reject MS */ +#define POLICY_MM (1<<15) /* reject MM */ + +/* + * commands + */ + +/* + * EVENTS + * event classes + */ +#define EVENT_ECM 1 /* event class ECM */ +#define EVENT_CFM 2 /* event class CFM */ +#define EVENT_RMT 3 /* event class RMT */ +#define EVENT_SMT 4 /* event class SMT */ +#define EVENT_PCM 5 /* event class PCM */ +#define EVENT_PCMA 5 /* event class PCMA */ +#define EVENT_PCMB 6 /* event class PCMB */ + +/* WARNING : + * EVENT_PCM* must be last in the above list + * if more than two ports are used, EVENT_PCM .. EVENT_PCMA+NUM_PHYS-1 + * are used ! + */ + +#define EV_TOKEN(class,event) (((u_long)(class)<<16L)|((u_long)(event))) +#define EV_T_CLASS(token) ((int)((token)>>16)&0xffff) +#define EV_T_EVENT(token) ((int)(token)&0xffff) + +/* + * ECM events + */ +#define EC_CONNECT 1 /* connect request */ +#define EC_DISCONNECT 2 /* disconnect request */ +#define EC_TRACE_PROP 3 /* trace propagation */ +#define EC_PATH_TEST 4 /* path test */ +#define EC_TIMEOUT_TD 5 /* timer TD_min */ +#define EC_TIMEOUT_TMAX 6 /* timer trace_max */ +#define EC_TIMEOUT_IMAX 7 /* timer I_max */ +#define EC_TIMEOUT_INMAX 8 /* timer IN_max */ +#define EC_TEST_DONE 9 /* path test done */ + +/* + * CFM events + */ +#define CF_LOOP 1 /* cf_loop flag from PCM */ +#define CF_LOOP_A 1 /* cf_loop flag from PCM */ +#define CF_LOOP_B 2 /* cf_loop flag from PCM */ +#define CF_JOIN 3 /* cf_join flag from PCM */ +#define CF_JOIN_A 3 /* cf_join flag from PCM */ +#define CF_JOIN_B 4 /* cf_join flag from PCM */ + +/* + * PCM events + */ +#define PC_START 1 +#define PC_STOP 2 +#define PC_LOOP 3 +#define PC_JOIN 4 +#define PC_SIGNAL 5 +#define PC_REJECT 6 +#define PC_MAINT 7 +#define PC_TRACE 8 +#define PC_PDR 9 +#define PC_ENABLE 10 +#define PC_DISABLE 11 + +/* + * must be ordered as in LineStateType + */ +#define PC_QLS 12 +#define PC_ILS 13 +#define PC_MLS 14 +#define PC_HLS 15 +#define PC_LS_PDR 16 +#define PC_LS_NONE 17 +#define LS2MIB(x) ((x)-PC_QLS) +#define MIB2LS(x) ((x)+PC_QLS) + +#define PC_TIMEOUT_TB_MAX 18 /* timer TB_max */ +#define PC_TIMEOUT_TB_MIN 19 /* timer TB_min */ +#define PC_TIMEOUT_C_MIN 20 /* timer C_Min */ +#define PC_TIMEOUT_T_OUT 21 /* timer T_Out */ +#define PC_TIMEOUT_TL_MIN 22 /* timer TL_Min */ +#define PC_TIMEOUT_T_NEXT 23 /* timer t_next[] */ +#define PC_TIMEOUT_LCT 24 +#define PC_NSE 25 /* NOISE hardware timer */ +#define PC_LEM 26 /* LEM done */ + +/* + * RMT events meaning from + */ +#define RM_RING_OP 1 /* ring operational MAC */ +#define RM_RING_NON_OP 2 /* ring not operational MAC */ +#define RM_MY_BEACON 3 /* recvd my beacon MAC */ +#define RM_OTHER_BEACON 4 /* recvd other beacon MAC */ +#define RM_MY_CLAIM 5 /* recvd my claim MAC */ +#define RM_TRT_EXP 6 /* TRT exp MAC */ +#define RM_VALID_CLAIM 7 /* claim from dup addr MAC */ +#define RM_JOIN 8 /* signal rm_join CFM */ +#define RM_LOOP 9 /* signal rm_loop CFM */ +#define RM_DUP_ADDR 10 /* dup_addr_test hange SMT-NIF */ +#define RM_ENABLE_FLAG 11 /* enable flag */ + +#define RM_TIMEOUT_NON_OP 12 /* timeout T_Non_OP */ +#define RM_TIMEOUT_T_STUCK 13 /* timeout T_Stuck */ +#define RM_TIMEOUT_ANNOUNCE 14 /* timeout T_Announce */ +#define RM_TIMEOUT_T_DIRECT 15 /* timeout T_Direct */ +#define RM_TIMEOUT_D_MAX 16 /* timeout D_Max */ +#define RM_TIMEOUT_POLL 17 /* claim/beacon poller */ +#define RM_TX_STATE_CHANGE 18 /* To restart timer for D_Max */ + +/* + * SMT events + */ +#define SM_TIMER 1 /* timer */ +#define SM_FAST 2 /* smt_force_irq */ + +/* PC modes */ +#define PM_NONE 0 +#define PM_PEER 1 +#define PM_TREE 2 + +/* + * PCM withhold codes + * MIB PC-WithholdType ENUM + */ +#define PC_WH_NONE 0 /* ok */ +#define PC_WH_M_M 1 /* M to M */ +#define PC_WH_OTHER 2 /* other incompatible phys */ +#define PC_WH_PATH 3 /* path not available */ +/* + * LCT duration + */ +#define LC_SHORT 1 /* short LCT */ +#define LC_MEDIUM 2 /* medium LCT */ +#define LC_LONG 3 /* long LCT */ +#define LC_EXTENDED 4 /* extended LCT */ + +/* + * path_test values + */ +#define PT_NONE 0 +#define PT_TESTING 1 /* test is running */ +#define PT_PASSED 2 /* test passed */ +#define PT_FAILED 3 /* test failed */ +#define PT_PENDING 4 /* path test follows */ +#define PT_EXITING 5 /* disconnected while in trace/leave */ + +/* + * duplicate address test + * MIB DupAddressTest ENUM + */ +#define DA_NONE 0 /* */ +#define DA_PASSED 1 /* test passed */ +#define DA_FAILED 2 /* test failed */ + + +/* + * optical bypass + */ +#define BP_DEINSERT 0 /* disable bypass */ +#define BP_INSERT 1 /* enable bypass */ + +/* + * ODL enable/disable + */ +#define PM_TRANSMIT_DISABLE 0 /* disable xmit */ +#define PM_TRANSMIT_ENABLE 1 /* enable xmit */ + +/* + * parameter for config_mux + * note : number is index in config_endec table ! + */ +#define MUX_THRUA 0 /* through A */ +#define MUX_THRUB 1 /* through B */ +#define MUX_WRAPA 2 /* wrap A */ +#define MUX_WRAPB 3 /* wrap B */ +#define MUX_ISOLATE 4 /* isolated */ +#define MUX_WRAPS 5 /* SAS */ + +/* + * MAC control + */ +#define MA_RESET 0 +#define MA_BEACON 1 +#define MA_CLAIM 2 +#define MA_DIRECTED 3 /* directed beacon */ +#define MA_TREQ 4 /* change T_Req */ +#define MA_OFFLINE 5 /* switch MAC to offline */ + + +/* + * trace prop + * bit map for trace propagation + */ +#define ENTITY_MAC (NUMPHYS) +#define ENTITY_PHY(p) (p) +#define ENTITY_BIT(m) (1<<(m)) + +/* + * Resource Tag Types + */ +#define PATH_ISO 0 /* isolated */ +#define PATH_PRIM 3 /* primary path */ +#define PATH_THRU 5 /* through path */ + +#define RES_MAC 2 /* resource type MAC */ +#define RES_PORT 4 /* resource type PORT */ + + +/* + * CFM state + * oops: MUST MATCH CF-StateType in SMT7.2 ! + */ +#define SC0_ISOLATED 0 /* isolated */ +#define SC1_WRAP_A 5 /* wrap A (not used) */ +#define SC2_WRAP_B 6 /* wrap B (not used) */ +#define SC4_THRU_A 12 /* through A */ +#define SC5_THRU_B 7 /* through B (used in SMT 6.2) */ +#define SC7_WRAP_S 8 /* SAS (not used) */ +#define SC9_C_WRAP_A 9 /* c wrap A */ +#define SC10_C_WRAP_B 10 /* c wrap B */ +#define SC11_C_WRAP_S 11 /* c wrap S */ + +/* + * convert MIB time in units of 80nS to uS + */ +#define MIB2US(t) ((t)/12) +#define SEC2MIB(s) ((s)*12500000L) +/* + * SMT timer + */ +struct smt_timer { + struct smt_timer *tm_next ; /* linked list */ + struct s_smc *tm_smc ; /* pointer to context */ + u_long tm_delta ; /* delta time */ + u_long tm_token ; /* token value */ + u_short tm_active ; /* flag : active/inactive */ + u_short tm_pad ; /* pad field */ +} ; + +/* + * communication structures + */ +struct mac_parameter { + u_long t_neg ; /* T_Neg parameter */ + u_long t_pri ; /* T_Pri register in MAC */ +} ; + +/* + * MAC counters + */ +struct mac_counter { + u_long mac_nobuf_counter ; /* MAC SW counter: no buffer */ + u_long mac_r_restart_counter ; /* MAC SW counter: rx restarted */ +} ; + +/* + * para struct context for SMT parameters + */ +struct s_pcon { + int pc_len ; + int pc_err ; + int pc_badset ; + void *pc_p ; +} ; + +/* + * link error monitor + */ +#define LEM_AVG 5 +struct lem_counter { +#ifdef AM29K + int lem_on ; + u_long lem_errors ; + u_long lem_symbols ; + u_long lem_tsymbols ; + int lem_s_count ; + int lem_n_s ; + int lem_values ; + int lem_index ; + int lem_avg_ber[LEM_AVG] ; + int lem_sum ; +#else + u_short lem_float_ber ; /* 10E-nn bit error rate */ + u_long lem_errors ; /* accumulated error count */ + u_short lem_on ; +#endif +} ; + +#define NUMBITS 10 + +#ifdef AMDPLC + +/* + * PLC state table + */ +struct s_plc { + u_short p_state ; /* current state */ + u_short p_bits ; /* number of bits to send */ + u_short p_start ; /* first bit pos */ + u_short p_pad ; /* padding for alignment */ + u_long soft_err ; /* error counter */ + u_long parity_err ; /* error counter */ + u_long ebuf_err ; /* error counter */ + u_long ebuf_cont ; /* continuous error counter */ + u_long phyinv ; /* error counter */ + u_long vsym_ctr ; /* error counter */ + u_long mini_ctr ; /* error counter */ + u_long tpc_exp ; /* error counter */ + u_long np_err ; /* error counter */ + u_long b_pcs ; /* error counter */ + u_long b_tpc ; /* error counter */ + u_long b_tne ; /* error counter */ + u_long b_qls ; /* error counter */ + u_long b_ils ; /* error counter */ + u_long b_hls ; /* error counter */ +} ; +#endif + +#ifdef PROTOTYP_INC +#include "fddi/driver.pro" +#else /* PROTOTYP_INC */ +/* + * function prototypes + */ +#include "h/mbuf.h" /* Type definitions for MBUFs */ +#include "h/smtstate.h" /* struct smt_state */ + +void hwt_restart(struct s_smc *smc); /* hwt.c */ +SMbuf *smt_build_frame(struct s_smc *smc, int class, int type, + int length); /* smt.c */ +SMbuf *smt_get_mbuf(struct s_smc *smc); /* drvsr.c */ +void *sm_to_para(struct s_smc *smc, struct smt_header *sm, + int para); /* smt.c */ + +#ifndef SK_UNUSED +#define SK_UNUSED(var) (void)(var) +#endif + +void queue_event(struct s_smc *smc, int class, int event); +void ecm(struct s_smc *smc, int event); +void ecm_init(struct s_smc *smc); +void rmt(struct s_smc *smc, int event); +void rmt_init(struct s_smc *smc); +void pcm(struct s_smc *smc, const int np, int event); +void pcm_init(struct s_smc *smc); +void cfm(struct s_smc *smc, int event); +void cfm_init(struct s_smc *smc); +void smt_timer_start(struct s_smc *smc, struct smt_timer *timer, u_long time, + u_long token); +void smt_timer_stop(struct s_smc *smc, struct smt_timer *timer); +void pcm_status_state(struct s_smc *smc, int np, int *type, int *state, + int *remote, int *mac); +void plc_config_mux(struct s_smc *smc, int mux); +void sm_lem_evaluate(struct s_smc *smc); +void mac_update_counter(struct s_smc *smc); +void sm_pm_ls_latch(struct s_smc *smc, int phy, int on_off); +void sm_ma_control(struct s_smc *smc, int mode); +void sm_mac_check_beacon_claim(struct s_smc *smc); +void config_mux(struct s_smc *smc, int mux); +void smt_agent_init(struct s_smc *smc); +void smt_timer_init(struct s_smc *smc); +void smt_received_pack(struct s_smc *smc, SMbuf *mb, int fs); +void smt_add_para(struct s_smc *smc, struct s_pcon *pcon, u_short para, + int index, int local); +void smt_swap_para(struct smt_header *sm, int len, int direction); +void ev_init(struct s_smc *smc); +void hwt_init(struct s_smc *smc); +u_long hwt_read(struct s_smc *smc); +void hwt_stop(struct s_smc *smc); +void hwt_start(struct s_smc *smc, u_long time); +void smt_send_mbuf(struct s_smc *smc, SMbuf *mb, int fc); +void smt_free_mbuf(struct s_smc *smc, SMbuf *mb); +void sm_pm_bypass_req(struct s_smc *smc, int mode); +void rmt_indication(struct s_smc *smc, int i); +void cfm_state_change(struct s_smc *smc, int c_state); + +#if defined(DEBUG) || !defined(NO_SMT_PANIC) +void smt_panic(struct s_smc *smc, char *text); +#else +#define smt_panic(smc,text) +#endif /* DEBUG || !NO_SMT_PANIC */ + +void smt_stat_counter(struct s_smc *smc, int stat); +void smt_timer_poll(struct s_smc *smc); +u_long smt_get_time(void); +u_long smt_get_tid(struct s_smc *smc); +void smt_timer_done(struct s_smc *smc); +void smt_fixup_mib(struct s_smc *smc); +void smt_reset_defaults(struct s_smc *smc, int level); +void smt_agent_task(struct s_smc *smc); +int smt_check_para(struct s_smc *smc, struct smt_header *sm, + const u_short list[]); +void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr); + +#ifdef SUPERNET_3 +void drv_reset_indication(struct s_smc *smc); +#endif /* SUPERNET_3 */ + +void smt_start_watchdog(struct s_smc *smc); +void smt_event(struct s_smc *smc, int event); +void timer_event(struct s_smc *smc, u_long token); +void ev_dispatcher(struct s_smc *smc); +void pcm_get_state(struct s_smc *smc, struct smt_state *state); +void ecm_state_change(struct s_smc *smc, int e_state); +int sm_pm_bypass_present(struct s_smc *smc); +void pcm_state_change(struct s_smc *smc, int plc, int p_state); +void rmt_state_change(struct s_smc *smc, int r_state); +int sm_pm_get_ls(struct s_smc *smc, int phy); +int pcm_get_s_port(struct s_smc *smc); +int pcm_rooted_station(struct s_smc *smc); +int cfm_get_mac_input(struct s_smc *smc); +int cfm_get_mac_output(struct s_smc *smc); +int cem_build_path(struct s_smc *smc, char *to, int path_index); +int sm_mac_get_tx_state(struct s_smc *smc); +char *get_pcmstate(struct s_smc *smc, int np); +int smt_action(struct s_smc *smc, int class, int code, int index); +u_short smt_online(struct s_smc *smc, int on); +void smt_force_irq(struct s_smc *smc); +void smt_pmf_received_pack(struct s_smc *smc, SMbuf *mb, int local); +void smt_send_frame(struct s_smc *smc, SMbuf *mb, int fc, int local); +void smt_set_timestamp(struct s_smc *smc, u_char *p); +void mac_set_rx_mode(struct s_smc *smc, int mode); +int mac_add_multicast(struct s_smc *smc, struct fddi_addr *addr, int can); +void mac_update_multicast(struct s_smc *smc); +void mac_clear_multicast(struct s_smc *smc); +void set_formac_tsync(struct s_smc *smc, long sync_bw); +void formac_reinit_tx(struct s_smc *smc); +void formac_tx_restart(struct s_smc *smc); +void process_receive(struct s_smc *smc); +void init_driver_fplus(struct s_smc *smc); +void rtm_irq(struct s_smc *smc); +void rtm_set_timer(struct s_smc *smc); +void ring_status_indication(struct s_smc *smc, u_long status); +void llc_recover_tx(struct s_smc *smc); +void llc_restart_tx(struct s_smc *smc); +void plc_clear_irq(struct s_smc *smc, int p); +void plc_irq(struct s_smc *smc, int np, unsigned int cmd); +int smt_set_mac_opvalues(struct s_smc *smc); + +#ifdef TAG_MODE +void mac_do_pci_fix(struct s_smc *smc); +void mac_drv_clear_tx_queue(struct s_smc *smc); +void mac_drv_repair_descr(struct s_smc *smc); +u_long hwt_quick_read(struct s_smc *smc); +void hwt_wait_time(struct s_smc *smc, u_long start, long duration); +#endif + +#ifdef SMT_PNMI +int pnmi_init(struct s_smc* smc); +int pnmi_process_ndis_id(struct s_smc *smc, u_long ndis_oid, void *buf, int len, + int *BytesAccessed, int *BytesNeeded, u_char action); +#endif + +#ifdef SBA +#ifndef _H2INC +void sba(); +#endif +void sba_raf_received_pack(); +void sba_timer_poll(); +void smt_init_sba(); +#endif + +#ifdef ESS +int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm, + int fs); +void ess_timer_poll(struct s_smc *smc); +void ess_para_change(struct s_smc *smc); +#endif + +#ifndef BOOT +void smt_init_evc(struct s_smc *smc); +void smt_srf_event(struct s_smc *smc, int code, int index, int cond); +#else +#define smt_init_evc(smc) +#define smt_srf_event(smc,code,index,cond) +#endif + +#ifndef SMT_REAL_TOKEN_CT +void smt_emulate_token_ct(struct s_smc *smc, int mac_index); +#endif + +#if defined(DEBUG) && !defined(BOOT) +void dump_smt(struct s_smc *smc, struct smt_header *sm, char *text); +#else +#define dump_smt(smc,sm,text) +#endif + +#ifdef DEBUG +char* addr_to_string(struct fddi_addr *addr); +void dump_hex(char *p, int len); +#endif + +#endif /* PROTOTYP_INC */ + +/* PNMI default defines */ +#ifndef PNMI_INIT +#define PNMI_INIT(smc) /* Nothing */ +#endif +#ifndef PNMI_GET_ID +#define PNMI_GET_ID( smc, ndis_oid, buf, len, BytesWritten, BytesNeeded ) \ + ( 1 ? (-1) : (-1) ) +#endif +#ifndef PNMI_SET_ID +#define PNMI_SET_ID( smc, ndis_oid, buf, len, BytesRead, BytesNeeded, \ + set_type) ( 1 ? (-1) : (-1) ) +#endif + +/* + * SMT_PANIC defines + */ +#ifndef SMT_PANIC +#define SMT_PANIC(smc,nr,msg) smt_panic (smc, msg) +#endif + +#ifndef SMT_ERR_LOG +#define SMT_ERR_LOG(smc,nr,msg) SMT_PANIC (smc, nr, msg) +#endif + +#ifndef SMT_EBASE +#define SMT_EBASE 100 +#endif + +#define SMT_E0100 SMT_EBASE + 0 +#define SMT_E0100_MSG "cfm FSM: invalid ce_type" +#define SMT_E0101 SMT_EBASE + 1 +#define SMT_E0101_MSG "CEM: case ???" +#define SMT_E0102 SMT_EBASE + 2 +#define SMT_E0102_MSG "CEM A: invalid state" +#define SMT_E0103 SMT_EBASE + 3 +#define SMT_E0103_MSG "CEM B: invalid state" +#define SMT_E0104 SMT_EBASE + 4 +#define SMT_E0104_MSG "CEM M: invalid state" +#define SMT_E0105 SMT_EBASE + 5 +#define SMT_E0105_MSG "CEM S: invalid state" +#define SMT_E0106 SMT_EBASE + 6 +#define SMT_E0106_MSG "CFM : invalid state" +#define SMT_E0107 SMT_EBASE + 7 +#define SMT_E0107_MSG "ECM : invalid state" +#define SMT_E0108 SMT_EBASE + 8 +#define SMT_E0108_MSG "prop_actions : NAC in DAS CFM" +#define SMT_E0109 SMT_EBASE + 9 +#define SMT_E0109_MSG "ST2U.FM_SERRSF error in special frame" +#define SMT_E0110 SMT_EBASE + 10 +#define SMT_E0110_MSG "ST2U.FM_SRFRCTOV recv. count. overflow" +#define SMT_E0111 SMT_EBASE + 11 +#define SMT_E0111_MSG "ST2U.FM_SNFSLD NP & FORMAC simult. load" +#define SMT_E0112 SMT_EBASE + 12 +#define SMT_E0112_MSG "ST2U.FM_SRCVFRM single-frame recv.-mode" +#define SMT_E0113 SMT_EBASE + 13 +#define SMT_E0113_MSG "FPLUS: Buffer Memory Error" +#define SMT_E0114 SMT_EBASE + 14 +#define SMT_E0114_MSG "ST2U.FM_SERRSF error in special frame" +#define SMT_E0115 SMT_EBASE + 15 +#define SMT_E0115_MSG "ST3L: parity error in receive queue 2" +#define SMT_E0116 SMT_EBASE + 16 +#define SMT_E0116_MSG "ST3L: parity error in receive queue 1" +#define SMT_E0117 SMT_EBASE + 17 +#define SMT_E0117_MSG "E_SMT_001: RxD count for receive queue 1 = 0" +#define SMT_E0118 SMT_EBASE + 18 +#define SMT_E0118_MSG "PCM : invalid state" +#define SMT_E0119 SMT_EBASE + 19 +#define SMT_E0119_MSG "smt_add_para" +#define SMT_E0120 SMT_EBASE + 20 +#define SMT_E0120_MSG "smt_set_para" +#define SMT_E0121 SMT_EBASE + 21 +#define SMT_E0121_MSG "invalid event in dispatcher" +#define SMT_E0122 SMT_EBASE + 22 +#define SMT_E0122_MSG "RMT : invalid state" +#define SMT_E0123 SMT_EBASE + 23 +#define SMT_E0123_MSG "SBA: state machine has invalid state" +#define SMT_E0124 SMT_EBASE + 24 +#define SMT_E0124_MSG "sba_free_session() called with NULL pointer" +#define SMT_E0125 SMT_EBASE + 25 +#define SMT_E0125_MSG "SBA : invalid session pointer" +#define SMT_E0126 SMT_EBASE + 26 +#define SMT_E0126_MSG "smt_free_mbuf() called with NULL pointer\n" +#define SMT_E0127 SMT_EBASE + 27 +#define SMT_E0127_MSG "sizeof evcs" +#define SMT_E0128 SMT_EBASE + 28 +#define SMT_E0128_MSG "evc->evc_cond_state = 0" +#define SMT_E0129 SMT_EBASE + 29 +#define SMT_E0129_MSG "evc->evc_multiple = 0" +#define SMT_E0130 SMT_EBASE + 30 +#define SMT_E0130_MSG write_mdr_warning +#define SMT_E0131 SMT_EBASE + 31 +#define SMT_E0131_MSG cam_warning +#define SMT_E0132 SMT_EBASE + 32 +#define SMT_E0132_MSG "ST1L.FM_SPCEPDx parity/coding error" +#define SMT_E0133 SMT_EBASE + 33 +#define SMT_E0133_MSG "ST1L.FM_STBURx tx buffer underrun" +#define SMT_E0134 SMT_EBASE + 34 +#define SMT_E0134_MSG "ST1L.FM_SPCEPDx parity error" +#define SMT_E0135 SMT_EBASE + 35 +#define SMT_E0135_MSG "RMT: duplicate MAC address detected. Ring left!" +#define SMT_E0136 SMT_EBASE + 36 +#define SMT_E0136_MSG "Elasticity Buffer hang-up" +#define SMT_E0137 SMT_EBASE + 37 +#define SMT_E0137_MSG "SMT: queue overrun" +#define SMT_E0138 SMT_EBASE + 38 +#define SMT_E0138_MSG "RMT: duplicate MAC address detected. Ring NOT left!" +#endif /* _CMTDEF_ */ diff --git a/drivers/net/fddi/skfp/h/fddi.h b/drivers/net/fddi/skfp/h/fddi.h new file mode 100644 index 0000000..c9a28a8 --- /dev/null +++ b/drivers/net/fddi/skfp/h/fddi.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _FDDI_ +#define _FDDI_ + +struct fddi_addr { + u_char a[6] ; +} ; + +#define GROUP_ADDR 0x80 /* MSB in a[0] */ + +struct fddi_mac { + struct fddi_addr mac_dest ; + struct fddi_addr mac_source ; + u_char mac_info[4478] ; +} ; + +#define FDDI_MAC_SIZE (12) +#define FDDI_RAW_MTU (4500-5) /* exl. Pr,SD, ED/FS */ +#define FDDI_RAW (4500) + +/* + * FC values + */ +#define FC_VOID 0x40 /* void frame */ +#define FC_TOKEN 0x80 /* token */ +#define FC_RES_TOKEN 0xc0 /* restricted token */ +#define FC_SMT_INFO 0x41 /* SMT Info frame */ +/* + * FC_SMT_LAN_LOC && FC_SMT_LOC are SK specific ! + */ +#define FC_SMT_LAN_LOC 0x42 /* local SMT Info frame */ +#define FC_SMT_LOC 0x43 /* local SMT Info frame */ +#define FC_SMT_NSA 0x4f /* SMT NSA frame */ +#define FC_MAC 0xc0 /* MAC frame */ +#define FC_BEACON 0xc2 /* MAC beacon frame */ +#define FC_CLAIM 0xc3 /* MAC claim frame */ +#define FC_SYNC_LLC 0xd0 /* sync. LLC frame */ +#define FC_ASYNC_LLC 0x50 /* async. LLC frame */ +#define FC_SYNC_BIT 0x80 /* sync. bit in FC */ + +#define FC_LLC_PRIOR 0x07 /* priority bits */ + +#define BEACON_INFO 0 /* beacon type */ +#define DBEACON_INFO 1 /* beacon type DIRECTED */ + + +/* + * indicator bits + */ +#define C_INDICATOR (1<<0) +#define A_INDICATOR (1<<1) +#define E_INDICATOR (1<<2) +#define I_INDICATOR (1<<6) /* SK specific */ +#define L_INDICATOR (1<<7) /* SK specific */ + +#endif /* _FDDI_ */ diff --git a/drivers/net/fddi/skfp/h/fddimib.h b/drivers/net/fddi/skfp/h/fddimib.h new file mode 100644 index 0000000..d1acdc7 --- /dev/null +++ b/drivers/net/fddi/skfp/h/fddimib.h @@ -0,0 +1,349 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * FDDI MIB + */ + +/* + * typedefs + */ + +typedef u_long Counter ; +typedef u_char TimeStamp[8] ; +typedef struct fddi_addr LongAddr ; +typedef u_long Timer_2 ; +typedef u_long Timer ; +typedef u_short ResId ; +typedef u_short SMTEnum ; +typedef u_char SMTFlag ; + +typedef struct { + Counter count ; + TimeStamp timestamp ; +} SetCountType ; + +/* + * bits for bit string "available_path" + */ +#define MIB_PATH_P (1<<0) +#define MIB_PATH_S (1<<1) +#define MIB_PATH_L (1<<2) + +/* + * bits for bit string PermittedPaths & RequestedPaths (SIZE(8)) + */ +#define MIB_P_PATH_LOCAL (1<<0) +#define MIB_P_PATH_SEC_ALTER (1<<1) +#define MIB_P_PATH_PRIM_ALTER (1<<2) +#define MIB_P_PATH_CON_ALTER (1<<3) +#define MIB_P_PATH_SEC_PREFER (1<<4) +#define MIB_P_PATH_PRIM_PREFER (1<<5) +#define MIB_P_PATH_CON_PREFER (1<<6) +#define MIB_P_PATH_THRU (1<<7) + +/* + * enum current path + */ +#define MIB_PATH_ISOLATED 0 +#define MIB_PATH_LOCAL 1 +#define MIB_PATH_SECONDARY 2 +#define MIB_PATH_PRIMARY 3 +#define MIB_PATH_CONCATENATED 4 +#define MIB_PATH_THRU 5 + +/* + * enum PMDClass + */ +#define MIB_PMDCLASS_MULTI 0 +#define MIB_PMDCLASS_SINGLE1 1 +#define MIB_PMDCLASS_SINGLE2 2 +#define MIB_PMDCLASS_SONET 3 +#define MIB_PMDCLASS_LCF 4 +#define MIB_PMDCLASS_TP 5 +#define MIB_PMDCLASS_UNKNOWN 6 +#define MIB_PMDCLASS_UNSPEC 7 + +/* + * enum SMTStationStatus + */ +#define MIB_SMT_STASTA_CON 0 +#define MIB_SMT_STASTA_SEPA 1 +#define MIB_SMT_STASTA_THRU 2 + + +struct fddi_mib { + /* + * private + */ + u_char fddiPRPMFPasswd[8] ; + struct smt_sid fddiPRPMFStation ; + +#ifdef ESS + /* + * private variables for static allocation of the + * End Station Support + */ + u_long fddiESSPayload ; /* payload for static alloc */ + u_long fddiESSOverhead ; /* frame ov for static alloc */ + u_long fddiESSMaxTNeg ; /* maximum of T-NEG */ + u_long fddiESSMinSegmentSize ; /* min size of the sync frames */ + u_long fddiESSCategory ; /* category for the Alloc req */ + short fddiESSSynchTxMode ; /* send all LLC frames as sync */ +#endif /* ESS */ +#ifdef SBA + /* + * private variables for the Synchronous Bandwidth Allocator + */ + char fddiSBACommand ; /* holds the parsed SBA cmd */ + u_char fddiSBAAvailable ; /* SBA allocatable value */ +#endif /* SBA */ + + /* + * SMT standard mib + */ + struct smt_sid fddiSMTStationId ; + u_short fddiSMTOpVersionId ; + u_short fddiSMTHiVersionId ; + u_short fddiSMTLoVersionId ; + u_char fddiSMTManufacturerData[32] ; + u_char fddiSMTUserData[32] ; + u_short fddiSMTMIBVersionId ; + + /* + * ConfigGrp + */ + u_char fddiSMTMac_Ct ; + u_char fddiSMTNonMaster_Ct ; + u_char fddiSMTMaster_Ct ; + u_char fddiSMTAvailablePaths ; + u_short fddiSMTConfigCapabilities ; + u_short fddiSMTConfigPolicy ; + u_short fddiSMTConnectionPolicy ; + u_short fddiSMTTT_Notify ; + u_char fddiSMTStatRptPolicy ; + u_long fddiSMTTrace_MaxExpiration ; + u_short fddiSMTPORTIndexes[NUMPHYS] ; + u_short fddiSMTMACIndexes ; + u_char fddiSMTBypassPresent ; + + /* + * StatusGrp + */ + SMTEnum fddiSMTECMState ; + SMTEnum fddiSMTCF_State ; + SMTEnum fddiSMTStationStatus ; + u_char fddiSMTRemoteDisconnectFlag ; + u_char fddiSMTPeerWrapFlag ; + + /* + * MIBOperationGrp + */ + TimeStamp fddiSMTTimeStamp ; + TimeStamp fddiSMTTransitionTimeStamp ; + SetCountType fddiSMTSetCount ; + struct smt_sid fddiSMTLastSetStationId ; + + struct fddi_mib_m { + u_short fddiMACFrameStatusFunctions ; + Timer_2 fddiMACT_MaxCapabilitiy ; + Timer_2 fddiMACTVXCapabilitiy ; + + /* ConfigGrp */ + u_char fddiMACMultiple_N ; /* private */ + u_char fddiMACMultiple_P ; /* private */ + u_char fddiMACDuplicateAddressCond ;/* private */ + u_char fddiMACAvailablePaths ; + u_short fddiMACCurrentPath ; + LongAddr fddiMACUpstreamNbr ; + LongAddr fddiMACDownstreamNbr ; + LongAddr fddiMACOldUpstreamNbr ; + LongAddr fddiMACOldDownstreamNbr ; + SMTEnum fddiMACDupAddressTest ; + u_short fddiMACRequestedPaths ; + SMTEnum fddiMACDownstreamPORTType ; + ResId fddiMACIndex ; + + /* AddressGrp */ + LongAddr fddiMACSMTAddress ; + + /* OperationGrp */ + Timer_2 fddiMACT_Min ; /* private */ + Timer_2 fddiMACT_ReqMIB ; + Timer_2 fddiMACT_Req ; /* private */ + Timer_2 fddiMACT_Neg ; + Timer_2 fddiMACT_MaxMIB ; + Timer_2 fddiMACT_Max ; /* private */ + Timer_2 fddiMACTvxValueMIB ; + Timer_2 fddiMACTvxValue ; /* private */ + Timer_2 fddiMACT_Pri0 ; + Timer_2 fddiMACT_Pri1 ; + Timer_2 fddiMACT_Pri2 ; + Timer_2 fddiMACT_Pri3 ; + Timer_2 fddiMACT_Pri4 ; + Timer_2 fddiMACT_Pri5 ; + Timer_2 fddiMACT_Pri6 ; + + /* CountersGrp */ + Counter fddiMACFrame_Ct ; + Counter fddiMACCopied_Ct ; + Counter fddiMACTransmit_Ct ; + Counter fddiMACToken_Ct ; + Counter fddiMACError_Ct ; + Counter fddiMACLost_Ct ; + Counter fddiMACTvxExpired_Ct ; + Counter fddiMACNotCopied_Ct ; + Counter fddiMACRingOp_Ct ; + + Counter fddiMACSMTCopied_Ct ; /* private */ + Counter fddiMACSMTTransmit_Ct ; /* private */ + + /* private for delta ratio */ + Counter fddiMACOld_Frame_Ct ; + Counter fddiMACOld_Copied_Ct ; + Counter fddiMACOld_Error_Ct ; + Counter fddiMACOld_Lost_Ct ; + Counter fddiMACOld_NotCopied_Ct ; + + /* FrameErrorConditionGrp */ + u_short fddiMACFrameErrorThreshold ; + u_short fddiMACFrameErrorRatio ; + + /* NotCopiedConditionGrp */ + u_short fddiMACNotCopiedThreshold ; + u_short fddiMACNotCopiedRatio ; + + /* StatusGrp */ + SMTEnum fddiMACRMTState ; + SMTFlag fddiMACDA_Flag ; + SMTFlag fddiMACUNDA_Flag ; + SMTFlag fddiMACFrameErrorFlag ; + SMTFlag fddiMACNotCopiedFlag ; + SMTFlag fddiMACMA_UnitdataAvailable ; + SMTFlag fddiMACHardwarePresent ; + SMTFlag fddiMACMA_UnitdataEnable ; + + } m[NUMMACS] ; +#define MAC0 0 + + struct fddi_mib_a { + ResId fddiPATHIndex ; + u_long fddiPATHSbaPayload ; + u_long fddiPATHSbaOverhead ; + /* fddiPATHConfiguration is built on demand */ + /* u_long fddiPATHConfiguration ; */ + Timer fddiPATHT_Rmode ; + u_long fddiPATHSbaAvailable ; + Timer_2 fddiPATHTVXLowerBound ; + Timer_2 fddiPATHT_MaxLowerBound ; + Timer_2 fddiPATHMaxT_Req ; + } a[NUMPATHS] ; +#define PATH0 0 + + struct fddi_mib_p { + /* ConfigGrp */ + SMTEnum fddiPORTMy_Type ; + SMTEnum fddiPORTNeighborType ; + u_char fddiPORTConnectionPolicies ; + struct { + u_char T_val ; + u_char R_val ; + } fddiPORTMacIndicated ; + SMTEnum fddiPORTCurrentPath ; + /* must be 4: is 32 bit in SMT format + * indices : + * 1 none + * 2 tree + * 3 peer + */ + u_char fddiPORTRequestedPaths[4] ; + u_short fddiPORTMACPlacement ; + u_char fddiPORTAvailablePaths ; + u_char fddiPORTConnectionCapabilities ; + SMTEnum fddiPORTPMDClass ; + ResId fddiPORTIndex ; + + /* OperationGrp */ + SMTEnum fddiPORTMaint_LS ; + SMTEnum fddiPORTPC_LS ; + u_char fddiPORTBS_Flag ; + + /* ErrorCtrsGrp */ + Counter fddiPORTLCTFail_Ct ; + Counter fddiPORTEBError_Ct ; + Counter fddiPORTOldEBError_Ct ; + + /* LerGrp */ + Counter fddiPORTLem_Reject_Ct ; + Counter fddiPORTLem_Ct ; + u_char fddiPORTLer_Estimate ; + u_char fddiPORTLer_Cutoff ; + u_char fddiPORTLer_Alarm ; + + /* StatusGrp */ + SMTEnum fddiPORTConnectState ; + SMTEnum fddiPORTPCMState ; /* real value */ + SMTEnum fddiPORTPCMStateX ; /* value for MIB */ + SMTEnum fddiPORTPC_Withhold ; + SMTFlag fddiPORTHardwarePresent ; + u_char fddiPORTLerFlag ; + + u_char fddiPORTMultiple_U ; /* private */ + u_char fddiPORTMultiple_P ; /* private */ + u_char fddiPORTEB_Condition ; /* private */ + } p[NUMPHYS] ; + struct { + Counter fddiPRIVECF_Req_Rx ; /* ECF req received */ + Counter fddiPRIVECF_Reply_Rx ; /* ECF repl received */ + Counter fddiPRIVECF_Req_Tx ; /* ECF req transm */ + Counter fddiPRIVECF_Reply_Tx ; /* ECF repl transm */ + Counter fddiPRIVPMF_Get_Rx ; /* PMF Get rec */ + Counter fddiPRIVPMF_Set_Rx ; /* PMF Set rec */ + Counter fddiPRIVRDF_Rx ; /* RDF received */ + Counter fddiPRIVRDF_Tx ; /* RDF transmitted */ + } priv ; +} ; + +/* + * OIDs for statistics + */ +#define SMT_OID_CF_STATE 1 /* fddiSMTCF_State */ +#define SMT_OID_PCM_STATE_A 2 /* fddiPORTPCMState port A */ +#define SMT_OID_PCM_STATE_B 17 /* fddiPORTPCMState port B */ +#define SMT_OID_RMT_STATE 3 /* fddiMACRMTState */ +#define SMT_OID_UNA 4 /* fddiMACUpstreamNbr */ +#define SMT_OID_DNA 5 /* fddiMACOldDownstreamNbr */ +#define SMT_OID_ERROR_CT 6 /* fddiMACError_Ct */ +#define SMT_OID_LOST_CT 7 /* fddiMACLost_Ct */ +#define SMT_OID_LEM_CT 8 /* fddiPORTLem_Ct */ +#define SMT_OID_LEM_CT_A 11 /* fddiPORTLem_Ct port A */ +#define SMT_OID_LEM_CT_B 12 /* fddiPORTLem_Ct port B */ +#define SMT_OID_LCT_FAIL_CT 9 /* fddiPORTLCTFail_Ct */ +#define SMT_OID_LCT_FAIL_CT_A 13 /* fddiPORTLCTFail_Ct port A */ +#define SMT_OID_LCT_FAIL_CT_B 14 /* fddiPORTLCTFail_Ct port B */ +#define SMT_OID_LEM_REJECT_CT 10 /* fddiPORTLem_Reject_Ct */ +#define SMT_OID_LEM_REJECT_CT_A 15 /* fddiPORTLem_Reject_Ct port A */ +#define SMT_OID_LEM_REJECT_CT_B 16 /* fddiPORTLem_Reject_Ct port B */ + +/* + * SK MIB + */ +#define SMT_OID_ECF_REQ_RX 20 /* ECF requests received */ +#define SMT_OID_ECF_REPLY_RX 21 /* ECF replies received */ +#define SMT_OID_ECF_REQ_TX 22 /* ECF requests transmitted */ +#define SMT_OID_ECF_REPLY_TX 23 /* ECF replies transmitted */ +#define SMT_OID_PMF_GET_RX 24 /* PMF get requests received */ +#define SMT_OID_PMF_SET_RX 25 /* PMF set requests received */ +#define SMT_OID_RDF_RX 26 /* RDF received */ +#define SMT_OID_RDF_TX 27 /* RDF transmitted */ diff --git a/drivers/net/fddi/skfp/h/fplustm.h b/drivers/net/fddi/skfp/h/fplustm.h new file mode 100644 index 0000000..d43191e --- /dev/null +++ b/drivers/net/fddi/skfp/h/fplustm.h @@ -0,0 +1,274 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * AMD Fplus in tag mode data structs + * defs for fplustm.c + */ + +#ifndef _FPLUS_ +#define _FPLUS_ + +#ifndef HW_PTR +#define HW_PTR void __iomem * +#endif + +/* + * fplus error statistic structure + */ +struct err_st { + u_long err_valid ; /* memory status valid */ + u_long err_abort ; /* memory status receive abort */ + u_long err_e_indicator ; /* error indicator */ + u_long err_crc ; /* error detected (CRC or length) */ + u_long err_llc_frame ; /* LLC frame */ + u_long err_mac_frame ; /* MAC frame */ + u_long err_smt_frame ; /* SMT frame */ + u_long err_imp_frame ; /* implementer frame */ + u_long err_no_buf ; /* no buffer available */ + u_long err_too_long ; /* longer than max. buffer */ + u_long err_bec_stat ; /* beacon state entered */ + u_long err_clm_stat ; /* claim state entered */ + u_long err_sifg_det ; /* short interframe gap detect */ + u_long err_phinv ; /* PHY invalid */ + u_long err_tkiss ; /* token issued */ + u_long err_tkerr ; /* token error */ +} ; + +/* + * Transmit Descriptor struct + */ +struct s_smt_fp_txd { + __le32 txd_tbctrl ; /* transmit buffer control */ + __le32 txd_txdscr ; /* transmit frame status word */ + __le32 txd_tbadr ; /* physical tx buffer address */ + __le32 txd_ntdadr ; /* physical pointer to the next TxD */ +#ifdef ENA_64BIT_SUP + __le32 txd_tbadr_hi ; /* physical tx buffer addr (high dword)*/ +#endif + char far *txd_virt ; /* virtual pointer to the data frag */ + /* virt pointer to the next TxD */ + struct s_smt_fp_txd volatile far *txd_next ; + struct s_txd_os txd_os ; /* OS - specific struct */ +} ; + +/* + * Receive Descriptor struct + */ +struct s_smt_fp_rxd { + __le32 rxd_rbctrl ; /* receive buffer control */ + __le32 rxd_rfsw ; /* receive frame status word */ + __le32 rxd_rbadr ; /* physical rx buffer address */ + __le32 rxd_nrdadr ; /* physical pointer to the next RxD */ +#ifdef ENA_64BIT_SUP + __le32 rxd_rbadr_hi ; /* physical tx buffer addr (high dword)*/ +#endif + char far *rxd_virt ; /* virtual pointer to the data frag */ + /* virt pointer to the next RxD */ + struct s_smt_fp_rxd volatile far *rxd_next ; + struct s_rxd_os rxd_os ; /* OS - specific struct */ +} ; + +/* + * Descriptor Union Definition + */ +union s_fp_descr { + struct s_smt_fp_txd t ; /* pointer to the TxD */ + struct s_smt_fp_rxd r ; /* pointer to the RxD */ +} ; + +/* + * TxD Ring Control struct + */ +struct s_smt_tx_queue { + struct s_smt_fp_txd volatile *tx_curr_put ; /* next free TxD */ + struct s_smt_fp_txd volatile *tx_prev_put ; /* shadow put pointer */ + struct s_smt_fp_txd volatile *tx_curr_get ; /* next TxD to release*/ + u_short tx_free ; /* count of free TxD's */ + u_short tx_used ; /* count of used TxD's */ + HW_PTR tx_bmu_ctl ; /* BMU addr for tx start */ + HW_PTR tx_bmu_dsc ; /* BMU addr for curr dsc. */ +} ; + +/* + * RxD Ring Control struct + */ +struct s_smt_rx_queue { + struct s_smt_fp_rxd volatile *rx_curr_put ; /* next RxD to queue into */ + struct s_smt_fp_rxd volatile *rx_prev_put ; /* shadow put pointer */ + struct s_smt_fp_rxd volatile *rx_curr_get ; /* next RxD to fill */ + u_short rx_free ; /* count of free RxD's */ + u_short rx_used ; /* count of used RxD's */ + HW_PTR rx_bmu_ctl ; /* BMU addr for rx start */ + HW_PTR rx_bmu_dsc ; /* BMU addr for curr dsc. */ +} ; + +#define VOID_FRAME_OFF 0x00 +#define CLAIM_FRAME_OFF 0x08 +#define BEACON_FRAME_OFF 0x10 +#define DBEACON_FRAME_OFF 0x18 +#define RX_FIFO_OFF 0x21 /* to get a prime number for */ + /* the RX_FIFO_SPACE */ + +#define RBC_MEM_SIZE 0x8000 +#define SEND_ASYNC_AS_SYNC 0x1 +#define SYNC_TRAFFIC_ON 0x2 + +/* big FIFO memory */ +#define RX_FIFO_SPACE 0x4000 - RX_FIFO_OFF +#define TX_FIFO_SPACE 0x4000 + +#define TX_SMALL_FIFO 0x0900 +#define TX_MEDIUM_FIFO TX_FIFO_SPACE / 2 +#define TX_LARGE_FIFO TX_FIFO_SPACE - TX_SMALL_FIFO + +#define RX_SMALL_FIFO 0x0900 +#define RX_LARGE_FIFO RX_FIFO_SPACE - RX_SMALL_FIFO + +struct s_smt_fifo_conf { + u_short rbc_ram_start ; /* FIFO start address */ + u_short rbc_ram_end ; /* FIFO size */ + u_short rx1_fifo_start ; /* rx queue start address */ + u_short rx1_fifo_size ; /* rx queue size */ + u_short rx2_fifo_start ; /* rx queue start address */ + u_short rx2_fifo_size ; /* rx queue size */ + u_short tx_s_start ; /* sync queue start address */ + u_short tx_s_size ; /* sync queue size */ + u_short tx_a0_start ; /* async queue A0 start address */ + u_short tx_a0_size ; /* async queue A0 size */ + u_short fifo_config_mode ; /* FIFO configuration mode */ +} ; + +#define FM_ADDRX (FM_ADDET|FM_EXGPA0|FM_EXGPA1) + +struct s_smt_fp { + u_short mdr2init ; /* mode register 2 init value */ + u_short mdr3init ; /* mode register 3 init value */ + u_short frselreg_init ; /* frame selection register init val */ + u_short rx_mode ; /* address mode broad/multi/promisc */ + u_short nsa_mode ; + u_short rx_prom ; + u_short exgpa ; + + struct err_st err_stats ; /* error statistics */ + + /* + * MAC buffers + */ + struct fddi_mac_sf { /* special frame build buffer */ + u_char mac_fc ; + struct fddi_addr mac_dest ; + struct fddi_addr mac_source ; + u_char mac_info[0x20] ; + } mac_sfb ; + + + /* + * queues + */ +#define QUEUE_S 0 +#define QUEUE_A0 1 +#define QUEUE_R1 0 +#define QUEUE_R2 1 +#define USED_QUEUES 2 + + /* + * queue pointers; points to the queue dependent variables + */ + struct s_smt_tx_queue *tx[USED_QUEUES] ; + struct s_smt_rx_queue *rx[USED_QUEUES] ; + + /* + * queue dependent variables + */ + struct s_smt_tx_queue tx_q[USED_QUEUES] ; + struct s_smt_rx_queue rx_q[USED_QUEUES] ; + + /* + * FIFO configuration struct + */ + struct s_smt_fifo_conf fifo ; + + /* last formac status */ + u_short s2u ; + u_short s2l ; + + /* calculated FORMAC+ reg.addr. */ + HW_PTR fm_st1u ; + HW_PTR fm_st1l ; + HW_PTR fm_st2u ; + HW_PTR fm_st2l ; + HW_PTR fm_st3u ; + HW_PTR fm_st3l ; + + + /* + * multicast table + */ +#define FPMAX_MULTICAST 32 +#define SMT_MAX_MULTI 4 + struct { + struct s_fpmc { + struct fddi_addr a ; /* mc address */ + u_char n ; /* usage counter */ + u_char perm ; /* flag: permanent */ + } table[FPMAX_MULTICAST] ; + } mc ; + struct fddi_addr group_addr ; + u_long func_addr ; /* functional address */ + int smt_slots_used ; /* count of table entries for the SMT */ + int os_slots_used ; /* count of table entries */ + /* used by the os-specific module */ +} ; + +/* + * modes for mac_set_rx_mode() + */ +#define RX_ENABLE_ALLMULTI 1 /* enable all multicasts */ +#define RX_DISABLE_ALLMULTI 2 /* disable "enable all multicasts" */ +#define RX_ENABLE_PROMISC 3 /* enable promiscuous */ +#define RX_DISABLE_PROMISC 4 /* disable promiscuous */ +#define RX_ENABLE_NSA 5 /* enable reception of NSA frames */ +#define RX_DISABLE_NSA 6 /* disable reception of NSA frames */ + + +/* + * support for byte reversal in AIX + * (descriptors and pointers must be byte reversed in memory + * CPU is big endian; M-Channel is little endian) + */ +#ifdef AIX +#define MDR_REV +#define AIX_REVERSE(x) ((((x)<<24L)&0xff000000L) + \ + (((x)<< 8L)&0x00ff0000L) + \ + (((x)>> 8L)&0x0000ff00L) + \ + (((x)>>24L)&0x000000ffL)) +#else +#ifndef AIX_REVERSE +#define AIX_REVERSE(x) (x) +#endif +#endif + +#ifdef MDR_REV +#define MDR_REVERSE(x) ((((x)<<24L)&0xff000000L) + \ + (((x)<< 8L)&0x00ff0000L) + \ + (((x)>> 8L)&0x0000ff00L) + \ + (((x)>>24L)&0x000000ffL)) +#else +#ifndef MDR_REVERSE +#define MDR_REVERSE(x) (x) +#endif +#endif + +#endif diff --git a/drivers/net/fddi/skfp/h/hwmtm.h b/drivers/net/fddi/skfp/h/hwmtm.h new file mode 100644 index 0000000..e1a7e5f --- /dev/null +++ b/drivers/net/fddi/skfp/h/hwmtm.h @@ -0,0 +1,399 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _HWM_ +#define _HWM_ + +#include "h/mbuf.h" + +/* + * MACRO for DMA synchronization: + * The descriptor 'desc' is flushed for the device 'flag'. + * Devices are the CPU (DDI_DMA_SYNC_FORCPU) and the + * adapter (DDI_DMA_SYNC_FORDEV). + * + * 'desc' Pointer to a Rx or Tx descriptor. + * 'flag' Flag for direction (view for CPU or DEVICE) that + * should be synchronized. + * + * Empty macros and defines are specified here. The real macro + * is os-specific and should be defined in osdef1st.h. + */ +#ifndef DRV_BUF_FLUSH +#define DRV_BUF_FLUSH(desc,flag) +#define DDI_DMA_SYNC_FORCPU +#define DDI_DMA_SYNC_FORDEV +#endif + + /* + * hardware modul dependent receive modes + */ +#define RX_ENABLE_PASS_SMT 21 +#define RX_DISABLE_PASS_SMT 22 +#define RX_ENABLE_PASS_NSA 23 +#define RX_DISABLE_PASS_NSA 24 +#define RX_ENABLE_PASS_DB 25 +#define RX_DISABLE_PASS_DB 26 +#define RX_DISABLE_PASS_ALL 27 +#define RX_DISABLE_LLC_PROMISC 28 +#define RX_ENABLE_LLC_PROMISC 29 + + +#ifndef DMA_RD +#define DMA_RD 1 /* memory -> hw */ +#endif +#ifndef DMA_WR +#define DMA_WR 2 /* hw -> memory */ +#endif +#define SMT_BUF 0x80 + + /* + * bits of the frame status byte + */ +#define EN_IRQ_EOF 0x02 /* get IRQ after end of frame transmission */ +#define LOC_TX 0x04 /* send frame to the local SMT */ +#define LAST_FRAG 0x08 /* last TxD of the frame */ +#define FIRST_FRAG 0x10 /* first TxD of the frame */ +#define LAN_TX 0x20 /* send frame to network if set */ +#define RING_DOWN 0x40 /* error: unable to send, ring down */ +#define OUT_OF_TXD 0x80 /* error: not enough TxDs available */ + + +#ifndef NULL +#define NULL 0 +#endif + +#ifdef LITTLE_ENDIAN +#define HWM_REVERSE(x) (x) +#else +#define HWM_REVERSE(x) ((((x)<<24L)&0xff000000L) + \ + (((x)<< 8L)&0x00ff0000L) + \ + (((x)>> 8L)&0x0000ff00L) + \ + (((x)>>24L)&0x000000ffL)) +#endif + +#define C_INDIC (1L<<25) +#define A_INDIC (1L<<26) +#define RD_FS_LOCAL 0x80 + + /* + * DEBUG FLAGS + */ +#define DEBUG_SMTF 1 +#define DEBUG_SMT 2 +#define DEBUG_ECM 3 +#define DEBUG_RMT 4 +#define DEBUG_CFM 5 +#define DEBUG_PCM 6 +#define DEBUG_SBA 7 +#define DEBUG_ESS 8 + +#define DB_HWM_RX 10 +#define DB_HWM_TX 11 +#define DB_HWM_GEN 12 + +struct s_mbuf_pool { +#ifndef MB_OUTSIDE_SMC + SMbuf mb[MAX_MBUF] ; /* mbuf pool */ +#endif + SMbuf *mb_start ; /* points to the first mb */ + SMbuf *mb_free ; /* free queue */ +} ; + +struct hwm_r { + /* + * hardware modul specific receive variables + */ + u_int len ; /* length of the whole frame */ + char *mb_pos ; /* SMbuf receive position */ +} ; + +struct hw_modul { + /* + * All hardware modul specific variables + */ + struct s_mbuf_pool mbuf_pool ; + struct hwm_r r ; + + union s_fp_descr volatile *descr_p ; /* points to the desriptor area */ + + u_short pass_SMT ; /* pass SMT frames */ + u_short pass_NSA ; /* pass all NSA frames */ + u_short pass_DB ; /* pass Direct Beacon Frames */ + u_short pass_llc_promisc ; /* pass all llc frames (default ON) */ + + SMbuf *llc_rx_pipe ; /* points to the first queued llc fr */ + SMbuf *llc_rx_tail ; /* points to the last queued llc fr */ + int queued_rx_frames ; /* number of queued frames */ + + SMbuf *txd_tx_pipe ; /* points to first mb in the txd ring */ + SMbuf *txd_tx_tail ; /* points to last mb in the txd ring */ + int queued_txd_mb ; /* number of SMT MBufs in txd ring */ + + int rx_break ; /* rev. was breaked because ind. off */ + int leave_isr ; /* leave fddi_isr immedeately if set */ + int isr_flag ; /* set, when HWM is entered from isr */ + /* + * variables for the current transmit frame + */ + struct s_smt_tx_queue *tx_p ; /* pointer to the transmit queue */ + u_long tx_descr ; /* tx descriptor for FORMAC+ */ + int tx_len ; /* tx frame length */ + SMbuf *tx_mb ; /* SMT tx MBuf pointer */ + char *tx_data ; /* data pointer to the SMT tx Mbuf */ + + int detec_count ; /* counter for out of RxD condition */ + u_long rx_len_error ; /* rx len FORMAC != sum of fragments */ +} ; + + +/* + * DEBUG structs and macros + */ + +#ifdef DEBUG +struct os_debug { + int hwm_rx ; + int hwm_tx ; + int hwm_gen ; +} ; +#endif + +#ifdef DEBUG +#ifdef DEBUG_BRD +#define DB_P smc->debug +#else +#define DB_P debug +#endif + +#define DB_RX(a,b,c,lev) if (DB_P.d_os.hwm_rx >= (lev)) printf(a,b,c) +#define DB_TX(a,b,c,lev) if (DB_P.d_os.hwm_tx >= (lev)) printf(a,b,c) +#define DB_GEN(a,b,c,lev) if (DB_P.d_os.hwm_gen >= (lev)) printf(a,b,c) +#else /* DEBUG */ +#define DB_RX(a,b,c,lev) +#define DB_TX(a,b,c,lev) +#define DB_GEN(a,b,c,lev) +#endif /* DEBUG */ + +#ifndef SK_BREAK +#define SK_BREAK() +#endif + + +/* + * HWM Macros + */ + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_TX_PHYS) + * u_long HWM_GET_TX_PHYS(txd) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to read + * the physical address of the specified TxD. + * + * para txd pointer to the TxD + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_TX_PHYS(txd) (u_long)AIX_REVERSE((txd)->txd_tbadr) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_TX_LEN) + * int HWM_GET_TX_LEN(txd) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to read + * the fragment length of the specified TxD + * + * para rxd pointer to the TxD + * + * return the length of the fragment in bytes + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_TX_LEN(txd) ((int)AIX_REVERSE((txd)->txd_tbctrl)& RD_LENGTH) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_TX_USED) + * txd *HWM_GET_TX_USED(smc,queue) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to get the + * number of used TxDs for the queue, specified by the index. + * + * para queue the number of the send queue: Can be specified by + * QUEUE_A0, QUEUE_S or (frame_status & QUEUE_A0) + * + * return number of used TxDs for this send queue + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_TX_USED(smc,queue) (int) (smc)->hw.fp.tx_q[queue].tx_used + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_CURR_TXD) + * txd *HWM_GET_CURR_TXD(smc,queue) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to get the + * pointer to the TxD which points to the current queue put + * position. + * + * para queue the number of the send queue: Can be specified by + * QUEUE_A0, QUEUE_S or (frame_status & QUEUE_A0) + * + * return pointer to the current TxD + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_CURR_TXD(smc,queue) (struct s_smt_fp_txd volatile *)\ + (smc)->hw.fp.tx_q[queue].tx_curr_put + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_RX_FRAG_LEN) + * int HWM_GET_RX_FRAG_LEN(rxd) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to read + * the fragment length of the specified RxD + * + * para rxd pointer to the RxD + * + * return the length of the fragment in bytes + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_RX_FRAG_LEN(rxd) ((int)AIX_REVERSE((rxd)->rxd_rbctrl)& \ + RD_LENGTH) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_RX_PHYS) + * u_long HWM_GET_RX_PHYS(rxd) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to read + * the physical address of the specified RxD. + * + * para rxd pointer to the RxD + * + * return the RxD's physical pointer to the data fragment + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_RX_PHYS(rxd) (u_long)AIX_REVERSE((rxd)->rxd_rbadr) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_RX_USED) + * int HWM_GET_RX_USED(smc) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to get + * the count of used RXDs in receive queue 1. + * + * return the used RXD count of receive queue 1 + * + * NOTE: Remember, because of an ASIC bug at least one RXD should be unused + * in the descriptor ring ! + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_RX_USED(smc) ((int)(smc)->hw.fp.rx_q[QUEUE_R1].rx_used) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_RX_FREE) + * int HWM_GET_RX_FREE(smc) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to get + * the rxd_free count of receive queue 1. + * + * return the rxd_free count of receive queue 1 + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_RX_FREE(smc) ((int)(smc)->hw.fp.rx_q[QUEUE_R1].rx_free-1) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_CURR_RXD) + * rxd *HWM_GET_CURR_RXD(smc) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to get the + * pointer to the RxD which points to the current queue put + * position. + * + * return pointer to the current RxD + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_CURR_RXD(smc) (struct s_smt_fp_rxd volatile *)\ + (smc)->hw.fp.rx_q[QUEUE_R1].rx_curr_put + +/* + * BEGIN_MANUAL_ENTRY(HWM_RX_CHECK) + * void HWM_RX_CHECK(smc,low_water) + * + * function MACRO (hardware module, hwmtm.h) + * This macro is invoked by the OS-specific before it left the + * function mac_drv_rx_complete. This macro calls mac_drv_fill_rxd + * if the number of used RxDs is equal or lower than the + * the given low water mark. + * + * para low_water low water mark of used RxD's + * + * END_MANUAL_ENTRY + */ +#ifndef HWM_NO_FLOW_CTL +#define HWM_RX_CHECK(smc,low_water) {\ + if ((low_water) >= (smc)->hw.fp.rx_q[QUEUE_R1].rx_used) {\ + mac_drv_fill_rxd(smc) ;\ + }\ +} +#else +#define HWM_RX_CHECK(smc,low_water) mac_drv_fill_rxd(smc) +#endif + +#ifndef HWM_EBASE +#define HWM_EBASE 500 +#endif + +#define HWM_E0001 HWM_EBASE + 1 +#define HWM_E0001_MSG "HWM: Wrong size of s_rxd_os struct" +#define HWM_E0002 HWM_EBASE + 2 +#define HWM_E0002_MSG "HWM: Wrong size of s_txd_os struct" +#define HWM_E0003 HWM_EBASE + 3 +#define HWM_E0003_MSG "HWM: smt_free_mbuf() called with NULL pointer" +#define HWM_E0004 HWM_EBASE + 4 +#define HWM_E0004_MSG "HWM: Parity error rx queue 1" +#define HWM_E0005 HWM_EBASE + 5 +#define HWM_E0005_MSG "HWM: Encoding error rx queue 1" +#define HWM_E0006 HWM_EBASE + 6 +#define HWM_E0006_MSG "HWM: Encoding error async tx queue" +#define HWM_E0007 HWM_EBASE + 7 +#define HWM_E0007_MSG "HWM: Encoding error sync tx queue" +#define HWM_E0008 HWM_EBASE + 8 +#define HWM_E0008_MSG "" +#define HWM_E0009 HWM_EBASE + 9 +#define HWM_E0009_MSG "HWM: Out of RxD condition detected" +#define HWM_E0010 HWM_EBASE + 10 +#define HWM_E0010_MSG "HWM: A protocol layer has tried to send a frame with an invalid frame control" +#define HWM_E0011 HWM_EBASE + 11 +#define HWM_E0011_MSG "HWM: mac_drv_clear_tx_queue was called although the hardware wasn't stopped" +#define HWM_E0012 HWM_EBASE + 12 +#define HWM_E0012_MSG "HWM: mac_drv_clear_rx_queue was called although the hardware wasn't stopped" +#define HWM_E0013 HWM_EBASE + 13 +#define HWM_E0013_MSG "HWM: mac_drv_repair_descr was called although the hardware wasn't stopped" + +#endif diff --git a/drivers/net/fddi/skfp/h/mbuf.h b/drivers/net/fddi/skfp/h/mbuf.h new file mode 100644 index 0000000..f2aadcd --- /dev/null +++ b/drivers/net/fddi/skfp/h/mbuf.h @@ -0,0 +1,50 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _MBUF_ +#define _MBUF_ + +#define M_SIZE 4504 + +#ifndef MAX_MBUF +#define MAX_MBUF 4 +#endif + +#ifndef NO_STD_MBUF +#define sm_next m_next +#define sm_off m_off +#define sm_len m_len +#define sm_data m_data +#define SMbuf Mbuf +#define mtod smtod +#define mtodoff smtodoff +#endif + +struct s_mbuf { + struct s_mbuf *sm_next ; /* low level linked list */ + short sm_off ; /* offset in m_data */ + u_int sm_len ; /* len of data */ +#ifdef PCI + int sm_use_count ; +#endif + char sm_data[M_SIZE] ; +} ; + +typedef struct s_mbuf SMbuf ; + +/* mbuf head, to typed data */ +#define smtod(x,t) ((t)((x)->sm_data + (x)->sm_off)) +#define smtodoff(x,t,o) ((t)((x)->sm_data + (o))) + +#endif /* _MBUF_ */ diff --git a/drivers/net/fddi/skfp/h/osdef1st.h b/drivers/net/fddi/skfp/h/osdef1st.h new file mode 100644 index 0000000..763ca18 --- /dev/null +++ b/drivers/net/fddi/skfp/h/osdef1st.h @@ -0,0 +1,125 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * Operating system-dependent definitions that have to be defined + * before any other header files are included. + */ + +// HWM (HardWare Module) Definitions +// ----------------------- + +#include + +#ifdef __LITTLE_ENDIAN +#define LITTLE_ENDIAN +#else +#define BIG_ENDIAN +#endif + +// this is set in the makefile +// #define PCI /* only PCI adapters supported by this driver */ +// #define MEM_MAPPED_IO /* use memory mapped I/O */ + + +#define USE_CAN_ADDR /* DA and SA in MAC header are canonical. */ + +#define MB_OUTSIDE_SMC /* SMT Mbufs outside of smc struct. */ + +// ----------------------- + + +// SMT Definitions +// ----------------------- +#define SYNC /* allow synchronous frames */ + +// #define SBA /* Synchronous Bandwidth Allocator support */ + /* not available as free source */ + +#define ESS /* SBA End Station Support */ + +#define SMT_PANIC(smc, nr, msg) printk(KERN_INFO "SMT PANIC: code: %d, msg: %s\n",nr,msg) + + +#ifdef DEBUG +#define printf(s,args...) printk(KERN_INFO s, ## args) +#endif + +// #define HW_PTR u_long +// ----------------------- + + + +// HWM and OS-specific buffer definitions +// ----------------------- + +// default number of receive buffers. +#define NUM_RECEIVE_BUFFERS 10 + +// default number of transmit buffers. +#define NUM_TRANSMIT_BUFFERS 10 + +// Number of SMT buffers (Mbufs). +#define NUM_SMT_BUF 4 + +// Number of TXDs for asynchronous transmit queue. +#define HWM_ASYNC_TXD_COUNT (NUM_TRANSMIT_BUFFERS + NUM_SMT_BUF) + +// Number of TXDs for synchronous transmit queue. +#define HWM_SYNC_TXD_COUNT HWM_ASYNC_TXD_COUNT + + +// Number of RXDs for receive queue #1. +// Note: Workaround for ASIC Errata #7: One extra RXD is required. +#if (NUM_RECEIVE_BUFFERS > 100) +#define SMT_R1_RXD_COUNT (1 + 100) +#else +#define SMT_R1_RXD_COUNT (1 + NUM_RECEIVE_BUFFERS) +#endif + +// Number of RXDs for receive queue #2. +#define SMT_R2_RXD_COUNT 0 // Not used. +// ----------------------- + + + +/* + * OS-specific part of the transmit/receive descriptor structure (TXD/RXD). + * + * Note: The size of these structures must follow this rule: + * + * sizeof(struct) + 2*sizeof(void*) == n * 16, n >= 1 + * + * We use the dma_addr fields under Linux to keep track of the + * DMA address of the packet data, for later pci_unmap_single. -DaveM + */ + +struct s_txd_os { // os-specific part of transmit descriptor + struct sk_buff *skb; + dma_addr_t dma_addr; +} ; + +struct s_rxd_os { // os-specific part of receive descriptor + struct sk_buff *skb; + dma_addr_t dma_addr; +} ; + + +/* + * So we do not need to make too many modifications to the generic driver + * parts, we take advantage of the AIX byte swapping macro interface. + */ + +#define AIX_REVERSE(x) ((u32)le32_to_cpu((u32)(x))) +#define MDR_REVERSE(x) ((u32)le32_to_cpu((u32)(x))) diff --git a/drivers/net/fddi/skfp/h/sba.h b/drivers/net/fddi/skfp/h/sba.h new file mode 100644 index 0000000..638cf02 --- /dev/null +++ b/drivers/net/fddi/skfp/h/sba.h @@ -0,0 +1,142 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * Synchronous Bandwidth Allocation (SBA) structs + */ + +#ifndef _SBA_ +#define _SBA_ + +#include "h/mbuf.h" +#include "h/sba_def.h" + +#ifdef SBA + +/* Timer Cell Template */ +struct timer_cell { + struct timer_cell *next_ptr ; + struct timer_cell *prev_ptr ; + u_long start_time ; + struct s_sba_node_vars *node_var ; +} ; + +/* + * Node variables + */ +struct s_sba_node_vars { + u_char change_resp_flag ; + u_char report_resp_flag ; + u_char change_req_flag ; + u_char report_req_flag ; + long change_amount ; + long node_overhead ; + long node_payload ; + u_long node_status ; + u_char deallocate_status ; + u_char timer_state ; + u_short report_cnt ; + long lastrep_req_tranid ; + struct fddi_addr mac_address ; + struct s_sba_sessions *node_sessions ; + struct timer_cell timer ; +} ; + +/* + * Session variables + */ +struct s_sba_sessions { + u_long deallocate_status ; + long session_overhead ; + u_long min_segment_size ; + long session_payload ; + u_long session_status ; + u_long sba_category ; + long lastchg_req_tranid ; + u_short session_id ; + u_char class ; + u_char fddi2 ; + u_long max_t_neg ; + struct s_sba_sessions *next_session ; +} ; + +struct s_sba { + + struct s_sba_node_vars node[MAX_NODES] ; + struct s_sba_sessions session[MAX_SESSIONS] ; + + struct s_sba_sessions *free_session ; /* points to the first */ + /* free session */ + + struct timer_cell *tail_timer ; /* points to the last timer cell */ + + /* + * variables for allocation actions + */ + long total_payload ; /* Total Payload */ + long total_overhead ; /* Total Overhead */ + long sba_allocatable ; /* allocatable sync bandwidth */ + + /* + * RAF message receive parameters + */ + long msg_path_index ; /* Path Type */ + long msg_sba_pl_req ; /* Payload Request */ + long msg_sba_ov_req ; /* Overhead Request */ + long msg_mib_pl ; /* Current Payload for this Path */ + long msg_mib_ov ; /* Current Overhead for this Path*/ + long msg_category ; /* Category of the Allocation */ + u_long msg_max_t_neg ; /* longest T_Neg acceptable */ + u_long msg_min_seg_siz ; /* minimum segement size */ + struct smt_header *sm ; /* points to the rec message */ + struct fddi_addr *msg_alloc_addr ; /* Allocation Address */ + + /* + * SBA variables + */ + u_long sba_t_neg ; /* holds the last T_NEG */ + long sba_max_alloc ; /* the parsed value of SBAAvailable */ + + /* + * SBA state machine variables + */ + short sba_next_state ; /* the next state of the SBA */ + char sba_command ; /* holds the execuded SBA cmd */ + u_char sba_available ; /* parsed value after possible check */ +} ; + +#endif /* SBA */ + + /* + * variables for the End Station Support + */ +struct s_ess { + + /* + * flags and counters + */ + u_char sync_bw_available ; /* is set if sync bw is allocated */ + u_char local_sba_active ; /* set when a local sba is available */ + char raf_act_timer_poll ; /* activate the timer to send allc req */ + char timer_count ; /* counts every timer function call */ + + SMbuf *sba_reply_pend ; /* local reply for the sba is pending */ + + /* + * variables for the ess bandwidth control + */ + long sync_bw ; /* holds the allocaed sync bw */ + u_long alloc_trans_id ; /* trans id of the last alloc req */ +} ; +#endif diff --git a/drivers/net/fddi/skfp/h/sba_def.h b/drivers/net/fddi/skfp/h/sba_def.h new file mode 100644 index 0000000..0459a09 --- /dev/null +++ b/drivers/net/fddi/skfp/h/sba_def.h @@ -0,0 +1,76 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#define PHYS 0 /* physical addr */ +#define PERM_ADDR 0x80 /* permanet address */ +#define SB_STATIC 0x00000001 +#define MAX_PAYLOAD 1562 +#define PRIMARY_RING 0x00000001 +#ifndef NULL +#define NULL 0x00 +#endif + +/*********************** SB_Input Variable Values ***********************/ +/* may be needed when ever the SBA state machine is called */ + +#define UNKNOWN_SYNC_SOURCE 0x0001 +#define REQ_ALLOCATION 0x0002 +#define REPORT_RESP 0x0003 +#define CHANGE_RESP 0x0004 +#define TNEG 0x0005 +#define NIF 0x0006 +#define SB_STOP 0x0007 +#define SB_START 0x0008 +#define REPORT_TIMER 0x0009 +#define CHANGE_REQUIRED 0x000A + +#define DEFAULT_OV 50 + +#ifdef SBA +/**************************** SBA STATES *****************************/ + +#define SBA_STANDBY 0x00000000 +#define SBA_ACTIVE 0x00000001 +#define SBA_RECOVERY 0x00000002 +#define SBA_REPORT 0x00000003 +#define SBA_CHANGE 0x00000004 + +/**************************** OTHERS *********************************/ + +#define FIFTY_PERCENT 50 /* bytes per second */ +#define MAX_SESSIONS 150 +#define TWO_MINUTES 13079 /* 9.175 ms/tick */ +#define FIFTY_BYTES 50 +#define SBA_DENIED 0x0000000D +#define I_NEED_ONE 0x00000000 +#define MAX_NODES 50 +/*#define T_REPORT 0x59682F00L*/ /* 120s/80ns in Hex */ +#define TWO_MIN 120 /* seconds */ +#define SBA_ST_UNKNOWN 0x00000002 +#define SBA_ST_ACTIVE 0x00000001 +#define S_CLEAR 0x00000000L +#define ZERO 0x00000000 +#define FULL 0x00000000 /* old: 0xFFFFFFFFF */ +#define S_SET 0x00000001L +#define LOW_PRIO 0x02 /* ??????? */ +#define OK 0x01 /* ??????? */ +#define NOT_OK 0x00 /* ??????? */ + +/****************************************/ +/* deallocate_status[ni][si] values */ +/****************************************/ +#define TX_CHANGE 0X00000001L +#define PENDING 0x00000002L +#define NONE 0X00000000L +#endif diff --git a/drivers/net/fddi/skfp/h/skfbi.h b/drivers/net/fddi/skfp/h/skfbi.h new file mode 100644 index 0000000..c1ba26c --- /dev/null +++ b/drivers/net/fddi/skfp/h/skfbi.h @@ -0,0 +1,1133 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _SKFBI_H_ +#define _SKFBI_H_ + +/* + * FDDI-Fx (x := {I(SA), P(CI)}) + * address calculation & function defines + */ + +/*--------------------------------------------------------------------------*/ +#ifdef PCI + +/* + * (DV) = only defined for Da Vinci + * (ML) = only defined for Monalisa + */ + +/* + * Configuration Space header + */ +#define PCI_VENDOR_ID 0x00 /* 16 bit Vendor ID */ +#define PCI_DEVICE_ID 0x02 /* 16 bit Device ID */ +#define PCI_COMMAND 0x04 /* 16 bit Command */ +#define PCI_STATUS 0x06 /* 16 bit Status */ +#define PCI_REV_ID 0x08 /* 8 bit Revision ID */ +#define PCI_CLASS_CODE 0x09 /* 24 bit Class Code */ +#define PCI_CACHE_LSZ 0x0c /* 8 bit Cache Line Size */ +#define PCI_LAT_TIM 0x0d /* 8 bit Latency Timer */ +#define PCI_HEADER_T 0x0e /* 8 bit Header Type */ +#define PCI_BIST 0x0f /* 8 bit Built-in selftest */ +#define PCI_BASE_1ST 0x10 /* 32 bit 1st Base address */ +#define PCI_BASE_2ND 0x14 /* 32 bit 2nd Base address */ +/* Byte 18..2b: Reserved */ +#define PCI_SUB_VID 0x2c /* 16 bit Subsystem Vendor ID */ +#define PCI_SUB_ID 0x2e /* 16 bit Subsystem ID */ +#define PCI_BASE_ROM 0x30 /* 32 bit Expansion ROM Base Address */ +/* Byte 34..33: Reserved */ +#define PCI_CAP_PTR 0x34 /* 8 bit (ML) Capabilities Ptr */ +/* Byte 35..3b: Reserved */ +#define PCI_IRQ_LINE 0x3c /* 8 bit Interrupt Line */ +#define PCI_IRQ_PIN 0x3d /* 8 bit Interrupt Pin */ +#define PCI_MIN_GNT 0x3e /* 8 bit Min_Gnt */ +#define PCI_MAX_LAT 0x3f /* 8 bit Max_Lat */ +/* Device Dependent Region */ +#define PCI_OUR_REG 0x40 /* 32 bit (DV) Our Register */ +#define PCI_OUR_REG_1 0x40 /* 32 bit (ML) Our Register 1 */ +#define PCI_OUR_REG_2 0x44 /* 32 bit (ML) Our Register 2 */ +/* Power Management Region */ +#define PCI_PM_CAP_ID 0x48 /* 8 bit (ML) Power Management Cap. ID */ +#define PCI_PM_NITEM 0x49 /* 8 bit (ML) Next Item Ptr */ +#define PCI_PM_CAP_REG 0x4a /* 16 bit (ML) Power Management Capabilities */ +#define PCI_PM_CTL_STS 0x4c /* 16 bit (ML) Power Manag. Control/Status */ +/* Byte 0x4e: Reserved */ +#define PCI_PM_DAT_REG 0x4f /* 8 bit (ML) Power Manag. Data Register */ +/* VPD Region */ +#define PCI_VPD_CAP_ID 0x50 /* 8 bit (ML) VPD Cap. ID */ +#define PCI_VPD_NITEM 0x51 /* 8 bit (ML) Next Item Ptr */ +#define PCI_VPD_ADR_REG 0x52 /* 16 bit (ML) VPD Address Register */ +#define PCI_VPD_DAT_REG 0x54 /* 32 bit (ML) VPD Data Register */ +/* Byte 58..ff: Reserved */ + +/* + * I2C Address (PCI Config) + * + * Note: The temperature and voltage sensors are relocated on a different + * I2C bus. + */ +#define I2C_ADDR_VPD 0xA0 /* I2C address for the VPD EEPROM */ + +/* + * Define Bits and Values of the registers + */ +/* PCI_VENDOR_ID 16 bit Vendor ID */ +/* PCI_DEVICE_ID 16 bit Device ID */ +/* Values for Vendor ID and Device ID shall be patched into the code */ +/* PCI_COMMAND 16 bit Command */ +#define PCI_FBTEN 0x0200 /* Bit 9: Fast Back-To-Back enable */ +#define PCI_SERREN 0x0100 /* Bit 8: SERR enable */ +#define PCI_ADSTEP 0x0080 /* Bit 7: Address Stepping */ +#define PCI_PERREN 0x0040 /* Bit 6: Parity Report Response enable */ +#define PCI_VGA_SNOOP 0x0020 /* Bit 5: VGA palette snoop */ +#define PCI_MWIEN 0x0010 /* Bit 4: Memory write an inv cycl ena */ +#define PCI_SCYCEN 0x0008 /* Bit 3: Special Cycle enable */ +#define PCI_BMEN 0x0004 /* Bit 2: Bus Master enable */ +#define PCI_MEMEN 0x0002 /* Bit 1: Memory Space Access enable */ +#define PCI_IOEN 0x0001 /* Bit 0: IO Space Access enable */ + +/* PCI_STATUS 16 bit Status */ +#define PCI_PERR 0x8000 /* Bit 15: Parity Error */ +#define PCI_SERR 0x4000 /* Bit 14: Signaled SERR */ +#define PCI_RMABORT 0x2000 /* Bit 13: Received Master Abort */ +#define PCI_RTABORT 0x1000 /* Bit 12: Received Target Abort */ +#define PCI_STABORT 0x0800 /* Bit 11: Sent Target Abort */ +#define PCI_DEVSEL 0x0600 /* Bit 10..9: DEVSEL Timing */ +#define PCI_DEV_FAST (0<<9) /* fast */ +#define PCI_DEV_MEDIUM (1<<9) /* medium */ +#define PCI_DEV_SLOW (2<<9) /* slow */ +#define PCI_DATAPERR 0x0100 /* Bit 8: DATA Parity error detected */ +#define PCI_FB2BCAP 0x0080 /* Bit 7: Fast Back-to-Back Capability */ +#define PCI_UDF 0x0040 /* Bit 6: User Defined Features */ +#define PCI_66MHZCAP 0x0020 /* Bit 5: 66 MHz PCI bus clock capable */ +#define PCI_NEWCAP 0x0010 /* Bit 4: New cap. list implemented */ + +#define PCI_ERRBITS (PCI_PERR|PCI_SERR|PCI_RMABORT|PCI_STABORT|PCI_DATAPERR) + +/* PCI_REV_ID 8 bit Revision ID */ +/* PCI_CLASS_CODE 24 bit Class Code */ +/* Byte 2: Base Class (02) */ +/* Byte 1: SubClass (02) */ +/* Byte 0: Programming Interface (00) */ + +/* PCI_CACHE_LSZ 8 bit Cache Line Size */ +/* Possible values: 0,2,4,8,16 */ + +/* PCI_LAT_TIM 8 bit Latency Timer */ + +/* PCI_HEADER_T 8 bit Header Type */ +#define PCI_HD_MF_DEV 0x80 /* Bit 7: 0= single, 1= multi-func dev */ +#define PCI_HD_TYPE 0x7f /* Bit 6..0: Header Layout 0= normal */ + +/* PCI_BIST 8 bit Built-in selftest */ +#define PCI_BIST_CAP 0x80 /* Bit 7: BIST Capable */ +#define PCI_BIST_ST 0x40 /* Bit 6: Start BIST */ +#define PCI_BIST_RET 0x0f /* Bit 3..0: Completion Code */ + +/* PCI_BASE_1ST 32 bit 1st Base address */ +#define PCI_MEMSIZE 0x800L /* use 2 kB Memory Base */ +#define PCI_MEMBASE_BITS 0xfffff800L /* Bit 31..11: Memory Base Address */ +#define PCI_MEMSIZE_BIIS 0x000007f0L /* Bit 10..4: Memory Size Req. */ +#define PCI_PREFEN 0x00000008L /* Bit 3: Prefetchable */ +#define PCI_MEM_TYP 0x00000006L /* Bit 2..1: Memory Type */ +#define PCI_MEM32BIT (0<<1) /* Base addr anywhere in 32 Bit range */ +#define PCI_MEM1M (1<<1) /* Base addr below 1 MegaByte */ +#define PCI_MEM64BIT (2<<1) /* Base addr anywhere in 64 Bit range */ +#define PCI_MEMSPACE 0x00000001L /* Bit 0: Memory Space Indic. */ + +/* PCI_BASE_2ND 32 bit 2nd Base address */ +#define PCI_IOBASE 0xffffff00L /* Bit 31..8: I/O Base address */ +#define PCI_IOSIZE 0x000000fcL /* Bit 7..2: I/O Size Requirements */ +#define PCI_IOSPACE 0x00000001L /* Bit 0: I/O Space Indicator */ + +/* PCI_SUB_VID 16 bit Subsystem Vendor ID */ +/* PCI_SUB_ID 16 bit Subsystem ID */ + +/* PCI_BASE_ROM 32 bit Expansion ROM Base Address */ +#define PCI_ROMBASE 0xfffe0000L /* Bit 31..17: ROM BASE address (1st) */ +#define PCI_ROMBASZ 0x0001c000L /* Bit 16..14: Treat as BASE or SIZE */ +#define PCI_ROMSIZE 0x00003800L /* Bit 13..11: ROM Size Requirements */ +#define PCI_ROMEN 0x00000001L /* Bit 0: Address Decode enable */ + +/* PCI_CAP_PTR 8 bit New Capabilities Pointers */ +/* PCI_IRQ_LINE 8 bit Interrupt Line */ +/* PCI_IRQ_PIN 8 bit Interrupt Pin */ +/* PCI_MIN_GNT 8 bit Min_Gnt */ +/* PCI_MAX_LAT 8 bit Max_Lat */ +/* Device Dependent Region */ +/* PCI_OUR_REG (DV) 32 bit Our Register */ +/* PCI_OUR_REG_1 (ML) 32 bit Our Register 1 */ + /* Bit 31..29: reserved */ +#define PCI_PATCH_DIR (3L<<27) /*(DV) Bit 28..27: Ext Patchs direction */ +#define PCI_PATCH_DIR_0 (1L<<27) /*(DV) Type of the pins EXT_PATCHS<1..0> */ +#define PCI_PATCH_DIR_1 (1L<<28) /* 0 = input */ + /* 1 = output */ +#define PCI_EXT_PATCHS (3L<<25) /*(DV) Bit 26..25: Extended Patches */ +#define PCI_EXT_PATCH_0 (1L<<25) /*(DV) */ +#define PCI_EXT_PATCH_1 (1L<<26) /* CLK for MicroWire (ML) */ +#define PCI_VIO (1L<<25) /*(ML) */ +#define PCI_EN_BOOT (1L<<24) /* Bit 24: Enable BOOT via ROM */ + /* 1 = Don't boot with ROM */ + /* 0 = Boot with ROM */ +#define PCI_EN_IO (1L<<23) /* Bit 23: Mapping to IO space */ +#define PCI_EN_FPROM (1L<<22) /* Bit 22: FLASH mapped to mem? */ + /* 1 = Map Flash to Memory */ + /* 0 = Disable all addr. decoding */ +#define PCI_PAGESIZE (3L<<20) /* Bit 21..20: FLASH Page Size */ +#define PCI_PAGE_16 (0L<<20) /* 16 k pages */ +#define PCI_PAGE_32K (1L<<20) /* 32 k pages */ +#define PCI_PAGE_64K (2L<<20) /* 64 k pages */ +#define PCI_PAGE_128K (3L<<20) /* 128 k pages */ + /* Bit 19: reserved (ML) and (DV) */ +#define PCI_PAGEREG (7L<<16) /* Bit 18..16: Page Register */ + /* Bit 15: reserved */ +#define PCI_FORCE_BE (1L<<14) /* Bit 14: Assert all BEs on MR */ +#define PCI_DIS_MRL (1L<<13) /* Bit 13: Disable Mem R Line */ +#define PCI_DIS_MRM (1L<<12) /* Bit 12: Disable Mem R multip */ +#define PCI_DIS_MWI (1L<<11) /* Bit 11: Disable Mem W & inv */ +#define PCI_DISC_CLS (1L<<10) /* Bit 10: Disc: cacheLsz bound */ +#define PCI_BURST_DIS (1L<<9) /* Bit 9: Burst Disable */ +#define PCI_BYTE_SWAP (1L<<8) /*(DV) Bit 8: Byte Swap in DATA */ +#define PCI_SKEW_DAS (0xfL<<4) /* Bit 7..4: Skew Ctrl, DAS Ext */ +#define PCI_SKEW_BASE (0xfL<<0) /* Bit 3..0: Skew Ctrl, Base */ + +/* PCI_OUR_REG_2 (ML) 32 bit Our Register 2 (Monalisa only) */ +#define PCI_VPD_WR_TH (0xffL<<24) /* Bit 24..31 VPD Write Threshold */ +#define PCI_DEV_SEL (0x7fL<<17) /* Bit 17..23 EEPROM Device Select */ +#define PCI_VPD_ROM_SZ (7L<<14) /* Bit 14..16 VPD ROM Size */ + /* Bit 12..13 reserved */ +#define PCI_PATCH_DIR2 (0xfL<<8) /* Bit 8..11 Ext Patchs dir 2..5 */ +#define PCI_PATCH_DIR_2 (1L<<8) /* Bit 8 CS for MicroWire */ +#define PCI_PATCH_DIR_3 (1L<<9) +#define PCI_PATCH_DIR_4 (1L<<10) +#define PCI_PATCH_DIR_5 (1L<<11) +#define PCI_EXT_PATCHS2 (0xfL<<4) /* Bit 4..7 Extended Patches */ +#define PCI_EXT_PATCH_2 (1L<<4) /* Bit 4 CS for MicroWire */ +#define PCI_EXT_PATCH_3 (1L<<5) +#define PCI_EXT_PATCH_4 (1L<<6) +#define PCI_EXT_PATCH_5 (1L<<7) +#define PCI_EN_DUMMY_RD (1L<<3) /* Bit 3 Enable Dummy Read */ +#define PCI_REV_DESC (1L<<2) /* Bit 2 Reverse Desc. Bytes */ +#define PCI_USEADDR64 (1L<<1) /* Bit 1 Use 64 Bit Addresse */ +#define PCI_USEDATA64 (1L<<0) /* Bit 0 Use 64 Bit Data bus ext*/ + +/* Power Management Region */ +/* PCI_PM_CAP_ID 8 bit (ML) Power Management Cap. ID */ +/* PCI_PM_NITEM 8 bit (ML) Next Item Ptr */ +/* PCI_PM_CAP_REG 16 bit (ML) Power Management Capabilities*/ +#define PCI_PME_SUP (0x1f<<11) /* Bit 11..15 PM Manag. Event Support*/ +#define PCI_PM_D2_SUB (1<<10) /* Bit 10 D2 Support Bit */ +#define PCI_PM_D1_SUB (1<<9) /* Bit 9 D1 Support Bit */ + /* Bit 6..8 reserved */ +#define PCI_PM_DSI (1<<5) /* Bit 5 Device Specific Init.*/ +#define PCI_PM_APS (1<<4) /* Bit 4 Auxialiary Power Src */ +#define PCI_PME_CLOCK (1<<3) /* Bit 3 PM Event Clock */ +#define PCI_PM_VER (7<<0) /* Bit 0..2 PM PCI Spec. version */ + +/* PCI_PM_CTL_STS 16 bit (ML) Power Manag. Control/Status */ +#define PCI_PME_STATUS (1<<15) /* Bit 15 PFA doesn't sup. PME#*/ +#define PCI_PM_DAT_SCL (3<<13) /* Bit 13..14 dat reg Scaling factor */ +#define PCI_PM_DAT_SEL (0xf<<9) /* Bit 9..12 PM data selector field */ + /* Bit 7.. 2 reserved */ +#define PCI_PM_STATE (3<<0) /* Bit 0.. 1 Power Management State */ +#define PCI_PM_STATE_D0 (0<<0) /* D0: Operational (default) */ +#define PCI_PM_STATE_D1 (1<<0) /* D1: not supported */ +#define PCI_PM_STATE_D2 (2<<0) /* D2: not supported */ +#define PCI_PM_STATE_D3 (3<<0) /* D3: HOT, Power Down and Reset */ + +/* PCI_PM_DAT_REG 8 bit (ML) Power Manag. Data Register */ +/* VPD Region */ +/* PCI_VPD_CAP_ID 8 bit (ML) VPD Cap. ID */ +/* PCI_VPD_NITEM 8 bit (ML) Next Item Ptr */ +/* PCI_VPD_ADR_REG 16 bit (ML) VPD Address Register */ +#define PCI_VPD_FLAG (1<<15) /* Bit 15 starts VPD rd/wd cycle*/ + +/* PCI_VPD_DAT_REG 32 bit (ML) VPD Data Register */ + +/* + * Control Register File: + * Bank 0 + */ +#define B0_RAP 0x0000 /* 8 bit register address port */ + /* 0x0001 - 0x0003: reserved */ +#define B0_CTRL 0x0004 /* 8 bit control register */ +#define B0_DAS 0x0005 /* 8 Bit control register (DAS) */ +#define B0_LED 0x0006 /* 8 Bit LED register */ +#define B0_TST_CTRL 0x0007 /* 8 bit test control register */ +#define B0_ISRC 0x0008 /* 32 bit Interrupt source register */ +#define B0_IMSK 0x000c /* 32 bit Interrupt mask register */ + +/* 0x0010 - 0x006b: formac+ (supernet_3) fequently used registers */ +#define B0_CMDREG1 0x0010 /* write command reg 1 instruction */ +#define B0_CMDREG2 0x0014 /* write command reg 2 instruction */ +#define B0_ST1U 0x0010 /* read upper 16-bit of status reg 1 */ +#define B0_ST1L 0x0014 /* read lower 16-bit of status reg 1 */ +#define B0_ST2U 0x0018 /* read upper 16-bit of status reg 2 */ +#define B0_ST2L 0x001c /* read lower 16-bit of status reg 2 */ + +#define B0_MARR 0x0020 /* r/w the memory read addr register */ +#define B0_MARW 0x0024 /* r/w the memory write addr register*/ +#define B0_MDRU 0x0028 /* r/w upper 16-bit of mem. data reg */ +#define B0_MDRL 0x002c /* r/w lower 16-bit of mem. data reg */ + +#define B0_MDREG3 0x0030 /* r/w Mode Register 3 */ +#define B0_ST3U 0x0034 /* read upper 16-bit of status reg 3 */ +#define B0_ST3L 0x0038 /* read lower 16-bit of status reg 3 */ +#define B0_IMSK3U 0x003c /* r/w upper 16-bit of IMSK reg 3 */ +#define B0_IMSK3L 0x0040 /* r/w lower 16-bit of IMSK reg 3 */ +#define B0_IVR 0x0044 /* read Interrupt Vector register */ +#define B0_IMR 0x0048 /* r/w Interrupt mask register */ +/* 0x4c Hidden */ + +#define B0_CNTRL_A 0x0050 /* control register A (r/w) */ +#define B0_CNTRL_B 0x0054 /* control register B (r/w) */ +#define B0_INTR_MASK 0x0058 /* interrupt mask (r/w) */ +#define B0_XMIT_VECTOR 0x005c /* transmit vector register (r/w) */ + +#define B0_STATUS_A 0x0060 /* status register A (read only) */ +#define B0_STATUS_B 0x0064 /* status register B (read only) */ +#define B0_CNTRL_C 0x0068 /* control register C (r/w) */ +#define B0_MDREG1 0x006c /* r/w Mode Register 1 */ + +#define B0_R1_CSR 0x0070 /* 32 bit BMU control/status reg (rec q 1) */ +#define B0_R2_CSR 0x0074 /* 32 bit BMU control/status reg (rec q 2)(DV)*/ +#define B0_XA_CSR 0x0078 /* 32 bit BMU control/status reg (a xmit q) */ +#define B0_XS_CSR 0x007c /* 32 bit BMU control/status reg (s xmit q) */ + +/* + * Bank 1 + * - completely empty (this is the RAP Block window) + * Note: if RAP = 1 this page is reserved + */ + +/* + * Bank 2 + */ +#define B2_MAC_0 0x0100 /* 8 bit MAC address Byte 0 */ +#define B2_MAC_1 0x0101 /* 8 bit MAC address Byte 1 */ +#define B2_MAC_2 0x0102 /* 8 bit MAC address Byte 2 */ +#define B2_MAC_3 0x0103 /* 8 bit MAC address Byte 3 */ +#define B2_MAC_4 0x0104 /* 8 bit MAC address Byte 4 */ +#define B2_MAC_5 0x0105 /* 8 bit MAC address Byte 5 */ +#define B2_MAC_6 0x0106 /* 8 bit MAC address Byte 6 (== 0) (DV) */ +#define B2_MAC_7 0x0107 /* 8 bit MAC address Byte 7 (== 0) (DV) */ + +#define B2_CONN_TYP 0x0108 /* 8 bit Connector type */ +#define B2_PMD_TYP 0x0109 /* 8 bit PMD type */ + /* 0x010a - 0x010b: reserved */ + /* Eprom registers are currently of no use */ +#define B2_E_0 0x010c /* 8 bit EPROM Byte 0 */ +#define B2_E_1 0x010d /* 8 bit EPROM Byte 1 */ +#define B2_E_2 0x010e /* 8 bit EPROM Byte 2 */ +#define B2_E_3 0x010f /* 8 bit EPROM Byte 3 */ +#define B2_FAR 0x0110 /* 32 bit Flash-Prom Address Register/Counter */ +#define B2_FDP 0x0114 /* 8 bit Flash-Prom Data Port */ + /* 0x0115 - 0x0117: reserved */ +#define B2_LD_CRTL 0x0118 /* 8 bit loader control */ +#define B2_LD_TEST 0x0119 /* 8 bit loader test */ + /* 0x011a - 0x011f: reserved */ +#define B2_TI_INI 0x0120 /* 32 bit Timer init value */ +#define B2_TI_VAL 0x0124 /* 32 bit Timer value */ +#define B2_TI_CRTL 0x0128 /* 8 bit Timer control */ +#define B2_TI_TEST 0x0129 /* 8 Bit Timer Test */ + /* 0x012a - 0x012f: reserved */ +#define B2_WDOG_INI 0x0130 /* 32 bit Watchdog init value */ +#define B2_WDOG_VAL 0x0134 /* 32 bit Watchdog value */ +#define B2_WDOG_CRTL 0x0138 /* 8 bit Watchdog control */ +#define B2_WDOG_TEST 0x0139 /* 8 Bit Watchdog Test */ + /* 0x013a - 0x013f: reserved */ +#define B2_RTM_INI 0x0140 /* 32 bit RTM init value */ +#define B2_RTM_VAL 0x0144 /* 32 bit RTM value */ +#define B2_RTM_CRTL 0x0148 /* 8 bit RTM control */ +#define B2_RTM_TEST 0x0149 /* 8 Bit RTM Test */ + +#define B2_TOK_COUNT 0x014c /* (ML) 32 bit Token Counter */ +#define B2_DESC_ADDR_H 0x0150 /* (ML) 32 bit Desciptor Base Addr Reg High */ +#define B2_CTRL_2 0x0154 /* (ML) 8 bit Control Register 2 */ +#define B2_IFACE_REG 0x0155 /* (ML) 8 bit Interface Register */ + /* 0x0156: reserved */ +#define B2_TST_CTRL_2 0x0157 /* (ML) 8 bit Test Control Register 2 */ +#define B2_I2C_CTRL 0x0158 /* (ML) 32 bit I2C Control Register */ +#define B2_I2C_DATA 0x015c /* (ML) 32 bit I2C Data Register */ + +#define B2_IRQ_MOD_INI 0x0160 /* (ML) 32 bit IRQ Moderation Timer Init Reg. */ +#define B2_IRQ_MOD_VAL 0x0164 /* (ML) 32 bit IRQ Moderation Timer Value */ +#define B2_IRQ_MOD_CTRL 0x0168 /* (ML) 8 bit IRQ Moderation Timer Control */ +#define B2_IRQ_MOD_TEST 0x0169 /* (ML) 8 bit IRQ Moderation Timer Test */ + /* 0x016a - 0x017f: reserved */ + +/* + * Bank 3 + */ +/* + * This is a copy of the Configuration register file (lower half) + */ +#define B3_CFG_SPC 0x180 + +/* + * Bank 4 + */ +#define B4_R1_D 0x0200 /* 4*32 bit current receive Descriptor */ +#define B4_R1_DA 0x0210 /* 32 bit current rec desc address */ +#define B4_R1_AC 0x0214 /* 32 bit current receive Address Count */ +#define B4_R1_BC 0x0218 /* 32 bit current receive Byte Counter */ +#define B4_R1_CSR 0x021c /* 32 bit BMU Control/Status Register */ +#define B4_R1_F 0x0220 /* 32 bit flag register */ +#define B4_R1_T1 0x0224 /* 32 bit Test Register 1 */ +#define B4_R1_T1_TR 0x0224 /* 8 bit Test Register 1 TR */ +#define B4_R1_T1_WR 0x0225 /* 8 bit Test Register 1 WR */ +#define B4_R1_T1_RD 0x0226 /* 8 bit Test Register 1 RD */ +#define B4_R1_T1_SV 0x0227 /* 8 bit Test Register 1 SV */ +#define B4_R1_T2 0x0228 /* 32 bit Test Register 2 */ +#define B4_R1_T3 0x022c /* 32 bit Test Register 3 */ +#define B4_R1_DA_H 0x0230 /* (ML) 32 bit Curr Rx Desc Address High */ +#define B4_R1_AC_H 0x0234 /* (ML) 32 bit Curr Addr Counter High dword */ + /* 0x0238 - 0x023f: reserved */ + /* Receive queue 2 is removed on Monalisa */ +#define B4_R2_D 0x0240 /* 4*32 bit current receive Descriptor (q2) */ +#define B4_R2_DA 0x0250 /* 32 bit current rec desc address (q2) */ +#define B4_R2_AC 0x0254 /* 32 bit current receive Address Count (q2) */ +#define B4_R2_BC 0x0258 /* 32 bit current receive Byte Counter (q2) */ +#define B4_R2_CSR 0x025c /* 32 bit BMU Control/Status Register (q2) */ +#define B4_R2_F 0x0260 /* 32 bit flag register (q2) */ +#define B4_R2_T1 0x0264 /* 32 bit Test Register 1 (q2) */ +#define B4_R2_T1_TR 0x0264 /* 8 bit Test Register 1 TR (q2) */ +#define B4_R2_T1_WR 0x0265 /* 8 bit Test Register 1 WR (q2) */ +#define B4_R2_T1_RD 0x0266 /* 8 bit Test Register 1 RD (q2) */ +#define B4_R2_T1_SV 0x0267 /* 8 bit Test Register 1 SV (q2) */ +#define B4_R2_T2 0x0268 /* 32 bit Test Register 2 (q2) */ +#define B4_R2_T3 0x026c /* 32 bit Test Register 3 (q2) */ + /* 0x0270 - 0x027c: reserved */ + +/* + * Bank 5 + */ +#define B5_XA_D 0x0280 /* 4*32 bit current transmit Descriptor (xa) */ +#define B5_XA_DA 0x0290 /* 32 bit current tx desc address (xa) */ +#define B5_XA_AC 0x0294 /* 32 bit current tx Address Count (xa) */ +#define B5_XA_BC 0x0298 /* 32 bit current tx Byte Counter (xa) */ +#define B5_XA_CSR 0x029c /* 32 bit BMU Control/Status Register (xa) */ +#define B5_XA_F 0x02a0 /* 32 bit flag register (xa) */ +#define B5_XA_T1 0x02a4 /* 32 bit Test Register 1 (xa) */ +#define B5_XA_T1_TR 0x02a4 /* 8 bit Test Register 1 TR (xa) */ +#define B5_XA_T1_WR 0x02a5 /* 8 bit Test Register 1 WR (xa) */ +#define B5_XA_T1_RD 0x02a6 /* 8 bit Test Register 1 RD (xa) */ +#define B5_XA_T1_SV 0x02a7 /* 8 bit Test Register 1 SV (xa) */ +#define B5_XA_T2 0x02a8 /* 32 bit Test Register 2 (xa) */ +#define B5_XA_T3 0x02ac /* 32 bit Test Register 3 (xa) */ +#define B5_XA_DA_H 0x02b0 /* (ML) 32 bit Curr Tx Desc Address High */ +#define B5_XA_AC_H 0x02b4 /* (ML) 32 bit Curr Addr Counter High dword */ + /* 0x02b8 - 0x02bc: reserved */ +#define B5_XS_D 0x02c0 /* 4*32 bit current transmit Descriptor (xs) */ +#define B5_XS_DA 0x02d0 /* 32 bit current tx desc address (xs) */ +#define B5_XS_AC 0x02d4 /* 32 bit current transmit Address Count(xs) */ +#define B5_XS_BC 0x02d8 /* 32 bit current transmit Byte Counter (xs) */ +#define B5_XS_CSR 0x02dc /* 32 bit BMU Control/Status Register (xs) */ +#define B5_XS_F 0x02e0 /* 32 bit flag register (xs) */ +#define B5_XS_T1 0x02e4 /* 32 bit Test Register 1 (xs) */ +#define B5_XS_T1_TR 0x02e4 /* 8 bit Test Register 1 TR (xs) */ +#define B5_XS_T1_WR 0x02e5 /* 8 bit Test Register 1 WR (xs) */ +#define B5_XS_T1_RD 0x02e6 /* 8 bit Test Register 1 RD (xs) */ +#define B5_XS_T1_SV 0x02e7 /* 8 bit Test Register 1 SV (xs) */ +#define B5_XS_T2 0x02e8 /* 32 bit Test Register 2 (xs) */ +#define B5_XS_T3 0x02ec /* 32 bit Test Register 3 (xs) */ +#define B5_XS_DA_H 0x02f0 /* (ML) 32 bit Curr Tx Desc Address High */ +#define B5_XS_AC_H 0x02f4 /* (ML) 32 bit Curr Addr Counter High dword */ + /* 0x02f8 - 0x02fc: reserved */ + +/* + * Bank 6 + */ +/* External PLC-S registers (SN2 compatibility for DV) */ +/* External registers (ML) */ +#define B6_EXT_REG 0x300 + +/* + * Bank 7 + */ +/* DAS PLC-S Registers */ + +/* + * Bank 8 - 15 + */ +/* IFCP registers */ + +/*---------------------------------------------------------------------------*/ +/* Definitions of the Bits in the registers */ + +/* B0_RAP 16 bit register address port */ +#define RAP_RAP 0x0f /* Bit 3..0: 0 = block0, .., f = block15 */ + +/* B0_CTRL 8 bit control register */ +#define CTRL_FDDI_CLR (1<<7) /* Bit 7: (ML) Clear FDDI Reset */ +#define CTRL_FDDI_SET (1<<6) /* Bit 6: (ML) Set FDDI Reset */ +#define CTRL_HPI_CLR (1<<5) /* Bit 5: Clear HPI SM reset */ +#define CTRL_HPI_SET (1<<4) /* Bit 4: Set HPI SM reset */ +#define CTRL_MRST_CLR (1<<3) /* Bit 3: Clear Master reset */ +#define CTRL_MRST_SET (1<<2) /* Bit 2: Set Master reset */ +#define CTRL_RST_CLR (1<<1) /* Bit 1: Clear Software reset */ +#define CTRL_RST_SET (1<<0) /* Bit 0: Set Software reset */ + +/* B0_DAS 8 Bit control register (DAS) */ +#define BUS_CLOCK (1<<7) /* Bit 7: (ML) Bus Clock 0/1 = 33/66MHz */ +#define BUS_SLOT_SZ (1<<6) /* Bit 6: (ML) Slot Size 0/1 = 32/64 bit slot*/ + /* Bit 5..4: reserved */ +#define DAS_AVAIL (1<<3) /* Bit 3: 1 = DAS, 0 = SAS */ +#define DAS_BYP_ST (1<<2) /* Bit 2: 1 = avail,SAS, 0 = not avail */ +#define DAS_BYP_INS (1<<1) /* Bit 1: 1 = insert Bypass */ +#define DAS_BYP_RMV (1<<0) /* Bit 0: 1 = remove Bypass */ + +/* B0_LED 8 Bit LED register */ + /* Bit 7..6: reserved */ +#define LED_2_ON (1<<5) /* Bit 5: 1 = switch LED_2 on (left,gn)*/ +#define LED_2_OFF (1<<4) /* Bit 4: 1 = switch LED_2 off */ +#define LED_1_ON (1<<3) /* Bit 3: 1 = switch LED_1 on (mid,yel)*/ +#define LED_1_OFF (1<<2) /* Bit 2: 1 = switch LED_1 off */ +#define LED_0_ON (1<<1) /* Bit 1: 1 = switch LED_0 on (rght,gn)*/ +#define LED_0_OFF (1<<0) /* Bit 0: 1 = switch LED_0 off */ +/* This hardware defines are very ugly therefore we define some others */ + +#define LED_GA_ON LED_2_ON /* S port = A port */ +#define LED_GA_OFF LED_2_OFF /* S port = A port */ +#define LED_MY_ON LED_1_ON +#define LED_MY_OFF LED_1_OFF +#define LED_GB_ON LED_0_ON +#define LED_GB_OFF LED_0_OFF + +/* B0_TST_CTRL 8 bit test control register */ +#define TST_FRC_DPERR_MR (1<<7) /* Bit 7: force DATAPERR on MST RE. */ +#define TST_FRC_DPERR_MW (1<<6) /* Bit 6: force DATAPERR on MST WR. */ +#define TST_FRC_DPERR_TR (1<<5) /* Bit 5: force DATAPERR on TRG RE. */ +#define TST_FRC_DPERR_TW (1<<4) /* Bit 4: force DATAPERR on TRG WR. */ +#define TST_FRC_APERR_M (1<<3) /* Bit 3: force ADDRPERR on MST */ +#define TST_FRC_APERR_T (1<<2) /* Bit 2: force ADDRPERR on TRG */ +#define TST_CFG_WRITE_ON (1<<1) /* Bit 1: ena configuration reg. WR */ +#define TST_CFG_WRITE_OFF (1<<0) /* Bit 0: dis configuration reg. WR */ + +/* B0_ISRC 32 bit Interrupt source register */ + /* Bit 31..28: reserved */ +#define IS_I2C_READY (1L<<27) /* Bit 27: (ML) IRQ on end of I2C tx */ +#define IS_IRQ_SW (1L<<26) /* Bit 26: (ML) SW forced IRQ */ +#define IS_EXT_REG (1L<<25) /* Bit 25: (ML) IRQ from external reg*/ +#define IS_IRQ_STAT (1L<<24) /* Bit 24: IRQ status exception */ + /* PERR, RMABORT, RTABORT DATAPERR */ +#define IS_IRQ_MST_ERR (1L<<23) /* Bit 23: IRQ master error */ + /* RMABORT, RTABORT, DATAPERR */ +#define IS_TIMINT (1L<<22) /* Bit 22: IRQ_TIMER */ +#define IS_TOKEN (1L<<21) /* Bit 21: IRQ_RTM */ +/* + * Note: The DAS is our First Port (!=PA) + */ +#define IS_PLINT1 (1L<<20) /* Bit 20: IRQ_PHY_DAS */ +#define IS_PLINT2 (1L<<19) /* Bit 19: IRQ_IFCP_4 */ +#define IS_MINTR3 (1L<<18) /* Bit 18: IRQ_IFCP_3/IRQ_PHY */ +#define IS_MINTR2 (1L<<17) /* Bit 17: IRQ_IFCP_2/IRQ_MAC_2 */ +#define IS_MINTR1 (1L<<16) /* Bit 16: IRQ_IFCP_1/IRQ_MAC_1 */ +/* Receive Queue 1 */ +#define IS_R1_P (1L<<15) /* Bit 15: Parity Error (q1) */ +#define IS_R1_B (1L<<14) /* Bit 14: End of Buffer (q1) */ +#define IS_R1_F (1L<<13) /* Bit 13: End of Frame (q1) */ +#define IS_R1_C (1L<<12) /* Bit 12: Encoding Error (q1) */ +/* Receive Queue 2 */ +#define IS_R2_P (1L<<11) /* Bit 11: (DV) Parity Error (q2) */ +#define IS_R2_B (1L<<10) /* Bit 10: (DV) End of Buffer (q2) */ +#define IS_R2_F (1L<<9) /* Bit 9: (DV) End of Frame (q2) */ +#define IS_R2_C (1L<<8) /* Bit 8: (DV) Encoding Error (q2) */ +/* Asynchronous Transmit queue */ + /* Bit 7: reserved */ +#define IS_XA_B (1L<<6) /* Bit 6: End of Buffer (xa) */ +#define IS_XA_F (1L<<5) /* Bit 5: End of Frame (xa) */ +#define IS_XA_C (1L<<4) /* Bit 4: Encoding Error (xa) */ +/* Synchronous Transmit queue */ + /* Bit 3: reserved */ +#define IS_XS_B (1L<<2) /* Bit 2: End of Buffer (xs) */ +#define IS_XS_F (1L<<1) /* Bit 1: End of Frame (xs) */ +#define IS_XS_C (1L<<0) /* Bit 0: Encoding Error (xs) */ + +/* + * Define all valid interrupt source Bits from GET_ISR () + */ +#define ALL_IRSR 0x01ffff77L /* (DV) */ +#define ALL_IRSR_ML 0x0ffff077L /* (ML) */ + + +/* B0_IMSK 32 bit Interrupt mask register */ +/* + * The Bit definnition of this register are the same as of the interrupt + * source register. These definition are directly derived from the Hardware + * spec. + */ + /* Bit 31..28: reserved */ +#define IRQ_I2C_READY (1L<<27) /* Bit 27: (ML) IRQ on end of I2C tx */ +#define IRQ_SW (1L<<26) /* Bit 26: (ML) SW forced IRQ */ +#define IRQ_EXT_REG (1L<<25) /* Bit 25: (ML) IRQ from external reg*/ +#define IRQ_STAT (1L<<24) /* Bit 24: IRQ status exception */ + /* PERR, RMABORT, RTABORT DATAPERR */ +#define IRQ_MST_ERR (1L<<23) /* Bit 23: IRQ master error */ + /* RMABORT, RTABORT, DATAPERR */ +#define IRQ_TIMER (1L<<22) /* Bit 22: IRQ_TIMER */ +#define IRQ_RTM (1L<<21) /* Bit 21: IRQ_RTM */ +#define IRQ_DAS (1L<<20) /* Bit 20: IRQ_PHY_DAS */ +#define IRQ_IFCP_4 (1L<<19) /* Bit 19: IRQ_IFCP_4 */ +#define IRQ_IFCP_3 (1L<<18) /* Bit 18: IRQ_IFCP_3/IRQ_PHY */ +#define IRQ_IFCP_2 (1L<<17) /* Bit 17: IRQ_IFCP_2/IRQ_MAC_2 */ +#define IRQ_IFCP_1 (1L<<16) /* Bit 16: IRQ_IFCP_1/IRQ_MAC_1 */ +/* Receive Queue 1 */ +#define IRQ_R1_P (1L<<15) /* Bit 15: Parity Error (q1) */ +#define IRQ_R1_B (1L<<14) /* Bit 14: End of Buffer (q1) */ +#define IRQ_R1_F (1L<<13) /* Bit 13: End of Frame (q1) */ +#define IRQ_R1_C (1L<<12) /* Bit 12: Encoding Error (q1) */ +/* Receive Queue 2 */ +#define IRQ_R2_P (1L<<11) /* Bit 11: (DV) Parity Error (q2) */ +#define IRQ_R2_B (1L<<10) /* Bit 10: (DV) End of Buffer (q2) */ +#define IRQ_R2_F (1L<<9) /* Bit 9: (DV) End of Frame (q2) */ +#define IRQ_R2_C (1L<<8) /* Bit 8: (DV) Encoding Error (q2) */ +/* Asynchronous Transmit queue */ + /* Bit 7: reserved */ +#define IRQ_XA_B (1L<<6) /* Bit 6: End of Buffer (xa) */ +#define IRQ_XA_F (1L<<5) /* Bit 5: End of Frame (xa) */ +#define IRQ_XA_C (1L<<4) /* Bit 4: Encoding Error (xa) */ +/* Synchronous Transmit queue */ + /* Bit 3: reserved */ +#define IRQ_XS_B (1L<<2) /* Bit 2: End of Buffer (xs) */ +#define IRQ_XS_F (1L<<1) /* Bit 1: End of Frame (xs) */ +#define IRQ_XS_C (1L<<0) /* Bit 0: Encoding Error (xs) */ + +/* 0x0010 - 0x006b: formac+ (supernet_3) fequently used registers */ +/* B0_R1_CSR 32 bit BMU control/status reg (rec q 1 ) */ +/* B0_R2_CSR 32 bit BMU control/status reg (rec q 2 ) */ +/* B0_XA_CSR 32 bit BMU control/status reg (a xmit q ) */ +/* B0_XS_CSR 32 bit BMU control/status reg (s xmit q ) */ +/* The registers are the same as B4_R1_CSR, B4_R2_CSR, B5_Xa_CSR, B5_XS_CSR */ + +/* B2_MAC_0 8 bit MAC address Byte 0 */ +/* B2_MAC_1 8 bit MAC address Byte 1 */ +/* B2_MAC_2 8 bit MAC address Byte 2 */ +/* B2_MAC_3 8 bit MAC address Byte 3 */ +/* B2_MAC_4 8 bit MAC address Byte 4 */ +/* B2_MAC_5 8 bit MAC address Byte 5 */ +/* B2_MAC_6 8 bit MAC address Byte 6 (== 0) (DV) */ +/* B2_MAC_7 8 bit MAC address Byte 7 (== 0) (DV) */ + +/* B2_CONN_TYP 8 bit Connector type */ +/* B2_PMD_TYP 8 bit PMD type */ +/* Values of connector and PMD type comply to SysKonnect internal std */ + +/* The EPROM register are currently of no use */ +/* B2_E_0 8 bit EPROM Byte 0 */ +/* B2_E_1 8 bit EPROM Byte 1 */ +/* B2_E_2 8 bit EPROM Byte 2 */ +/* B2_E_3 8 bit EPROM Byte 3 */ + +/* B2_FAR 32 bit Flash-Prom Address Register/Counter */ +#define FAR_ADDR 0x1ffffL /* Bit 16..0: FPROM Address mask */ + +/* B2_FDP 8 bit Flash-Prom Data Port */ + +/* B2_LD_CRTL 8 bit loader control */ +/* Bits are currently reserved */ + +/* B2_LD_TEST 8 bit loader test */ +#define LD_T_ON (1<<3) /* Bit 3: Loader Testmode on */ +#define LD_T_OFF (1<<2) /* Bit 2: Loader Testmode off */ +#define LD_T_STEP (1<<1) /* Bit 1: Decrement FPROM addr. Counter */ +#define LD_START (1<<0) /* Bit 0: Start loading FPROM */ + +/* B2_TI_INI 32 bit Timer init value */ +/* B2_TI_VAL 32 bit Timer value */ +/* B2_TI_CRTL 8 bit Timer control */ +/* B2_TI_TEST 8 Bit Timer Test */ +/* B2_WDOG_INI 32 bit Watchdog init value */ +/* B2_WDOG_VAL 32 bit Watchdog value */ +/* B2_WDOG_CRTL 8 bit Watchdog control */ +/* B2_WDOG_TEST 8 Bit Watchdog Test */ +/* B2_RTM_INI 32 bit RTM init value */ +/* B2_RTM_VAL 32 bit RTM value */ +/* B2_RTM_CRTL 8 bit RTM control */ +/* B2_RTM_TEST 8 Bit RTM Test */ +/* B2__CRTL 8 bit control */ +/* B2_IRQ_MOD_INI 32 bit IRQ Moderation Timer Init Reg. (ML) */ +/* B2_IRQ_MOD_VAL 32 bit IRQ Moderation Timer Value (ML) */ +/* B2_IRQ_MOD_CTRL 8 bit IRQ Moderation Timer Control (ML) */ +/* B2_IRQ_MOD_TEST 8 bit IRQ Moderation Timer Test (ML) */ +#define GET_TOK_CT (1<<4) /* Bit 4: Get the Token Counter (RTM) */ +#define TIM_RES_TOK (1<<3) /* Bit 3: RTM Status: 1 == restricted */ +#define TIM_ALARM (1<<3) /* Bit 3: Timer Alarm (WDOG) */ +#define TIM_START (1<<2) /* Bit 2: Start Timer (TI,WDOG,RTM,IRQ_MOD)*/ +#define TIM_STOP (1<<1) /* Bit 1: Stop Timer (TI,WDOG,RTM,IRQ_MOD) */ +#define TIM_CL_IRQ (1<<0) /* Bit 0: Clear Timer IRQ (TI,WDOG,RTM) */ +/* B2__TEST 8 Bit Test */ +#define TIM_T_ON (1<<2) /* Bit 2: Test mode on (TI,WDOG,RTM,IRQ_MOD) */ +#define TIM_T_OFF (1<<1) /* Bit 1: Test mode off (TI,WDOG,RTM,IRQ_MOD) */ +#define TIM_T_STEP (1<<0) /* Bit 0: Test step (TI,WDOG,RTM,IRQ_MOD) */ + +/* B2_TOK_COUNT 0x014c (ML) 32 bit Token Counter */ +/* B2_DESC_ADDR_H 0x0150 (ML) 32 bit Desciptor Base Addr Reg High */ +/* B2_CTRL_2 0x0154 (ML) 8 bit Control Register 2 */ + /* Bit 7..5: reserved */ +#define CTRL_CL_I2C_IRQ (1<<4) /* Bit 4: Clear I2C IRQ */ +#define CTRL_ST_SW_IRQ (1<<3) /* Bit 3: Set IRQ SW Request */ +#define CTRL_CL_SW_IRQ (1<<2) /* Bit 2: Clear IRQ SW Request */ +#define CTRL_STOP_DONE (1<<1) /* Bit 1: Stop Master is finished */ +#define CTRL_STOP_MAST (1<<0) /* Bit 0: Command Bit to stop the master*/ + +/* B2_IFACE_REG 0x0155 (ML) 8 bit Interface Register */ + /* Bit 7..3: reserved */ +#define IF_I2C_DATA_DIR (1<<2) /* Bit 2: direction of IF_I2C_DATA*/ +#define IF_I2C_DATA (1<<1) /* Bit 1: I2C Data Port */ +#define IF_I2C_CLK (1<<0) /* Bit 0: I2C Clock Port */ + + /* 0x0156: reserved */ +/* B2_TST_CTRL_2 0x0157 (ML) 8 bit Test Control Register 2 */ + /* Bit 7..4: reserved */ + /* force the following error on */ + /* the next master read/write */ +#define TST_FRC_DPERR_MR64 (1<<3) /* Bit 3: DataPERR RD 64 */ +#define TST_FRC_DPERR_MW64 (1<<2) /* Bit 2: DataPERR WR 64 */ +#define TST_FRC_APERR_1M64 (1<<1) /* Bit 1: AddrPERR on 1. phase */ +#define TST_FRC_APERR_2M64 (1<<0) /* Bit 0: AddrPERR on 2. phase */ + +/* B2_I2C_CTRL 0x0158 (ML) 32 bit I2C Control Register */ +#define I2C_FLAG (1L<<31) /* Bit 31: Start read/write if WR */ +#define I2C_ADDR (0x7fffL<<16) /* Bit 30..16: Addr to be read/written*/ +#define I2C_DEV_SEL (0x7fL<<9) /* Bit 9..15: I2C Device Select */ + /* Bit 5.. 8: reserved */ +#define I2C_BURST_LEN (1L<<4) /* Bit 4 Burst Len, 1/4 bytes */ +#define I2C_DEV_SIZE (7L<<1) /* Bit 1.. 3: I2C Device Size */ +#define I2C_025K_DEV (0L<<1) /* 0: 256 Bytes or smaller*/ +#define I2C_05K_DEV (1L<<1) /* 1: 512 Bytes */ +#define I2C_1K_DEV (2L<<1) /* 2: 1024 Bytes */ +#define I2C_2K_DEV (3L<<1) /* 3: 2048 Bytes */ +#define I2C_4K_DEV (4L<<1) /* 4: 4096 Bytes */ +#define I2C_8K_DEV (5L<<1) /* 5: 8192 Bytes */ +#define I2C_16K_DEV (6L<<1) /* 6: 16384 Bytes */ +#define I2C_32K_DEV (7L<<1) /* 7: 32768 Bytes */ +#define I2C_STOP_BIT (1<<0) /* Bit 0: Interrupt I2C transfer */ + +/* + * I2C Addresses + * + * The temperature sensor and the voltage sensor are on the same I2C bus. + * Note: The voltage sensor (Micorwire) will be selected by PCI_EXT_PATCH_1 + * in PCI_OUR_REG 1. + */ +#define I2C_ADDR_TEMP 0x90 /* I2C Address Temperature Sensor */ + +/* B2_I2C_DATA 0x015c (ML) 32 bit I2C Data Register */ + +/* B4_R1_D 4*32 bit current receive Descriptor (q1) */ +/* B4_R1_DA 32 bit current rec desc address (q1) */ +/* B4_R1_AC 32 bit current receive Address Count (q1) */ +/* B4_R1_BC 32 bit current receive Byte Counter (q1) */ +/* B4_R1_CSR 32 bit BMU Control/Status Register (q1) */ +/* B4_R1_F 32 bit flag register (q1) */ +/* B4_R1_T1 32 bit Test Register 1 (q1) */ +/* B4_R1_T2 32 bit Test Register 2 (q1) */ +/* B4_R1_T3 32 bit Test Register 3 (q1) */ +/* B4_R2_D 4*32 bit current receive Descriptor (q2) */ +/* B4_R2_DA 32 bit current rec desc address (q2) */ +/* B4_R2_AC 32 bit current receive Address Count (q2) */ +/* B4_R2_BC 32 bit current receive Byte Counter (q2) */ +/* B4_R2_CSR 32 bit BMU Control/Status Register (q2) */ +/* B4_R2_F 32 bit flag register (q2) */ +/* B4_R2_T1 32 bit Test Register 1 (q2) */ +/* B4_R2_T2 32 bit Test Register 2 (q2) */ +/* B4_R2_T3 32 bit Test Register 3 (q2) */ +/* B5_XA_D 4*32 bit current receive Descriptor (xa) */ +/* B5_XA_DA 32 bit current rec desc address (xa) */ +/* B5_XA_AC 32 bit current receive Address Count (xa) */ +/* B5_XA_BC 32 bit current receive Byte Counter (xa) */ +/* B5_XA_CSR 32 bit BMU Control/Status Register (xa) */ +/* B5_XA_F 32 bit flag register (xa) */ +/* B5_XA_T1 32 bit Test Register 1 (xa) */ +/* B5_XA_T2 32 bit Test Register 2 (xa) */ +/* B5_XA_T3 32 bit Test Register 3 (xa) */ +/* B5_XS_D 4*32 bit current receive Descriptor (xs) */ +/* B5_XS_DA 32 bit current rec desc address (xs) */ +/* B5_XS_AC 32 bit current receive Address Count (xs) */ +/* B5_XS_BC 32 bit current receive Byte Counter (xs) */ +/* B5_XS_CSR 32 bit BMU Control/Status Register (xs) */ +/* B5_XS_F 32 bit flag register (xs) */ +/* B5_XS_T1 32 bit Test Register 1 (xs) */ +/* B5_XS_T2 32 bit Test Register 2 (xs) */ +/* B5_XS_T3 32 bit Test Register 3 (xs) */ +/* B5__CSR 32 bit BMU Control/Status Register (xx) */ +#define CSR_DESC_CLEAR (1L<<21) /* Bit 21: Clear Reset for Descr */ +#define CSR_DESC_SET (1L<<20) /* Bit 20: Set Reset for Descr */ +#define CSR_FIFO_CLEAR (1L<<19) /* Bit 19: Clear Reset for FIFO */ +#define CSR_FIFO_SET (1L<<18) /* Bit 18: Set Reset for FIFO */ +#define CSR_HPI_RUN (1L<<17) /* Bit 17: Release HPI SM */ +#define CSR_HPI_RST (1L<<16) /* Bit 16: Reset HPI SM to Idle */ +#define CSR_SV_RUN (1L<<15) /* Bit 15: Release Supervisor SM */ +#define CSR_SV_RST (1L<<14) /* Bit 14: Reset Supervisor SM */ +#define CSR_DREAD_RUN (1L<<13) /* Bit 13: Release Descr Read SM */ +#define CSR_DREAD_RST (1L<<12) /* Bit 12: Reset Descr Read SM */ +#define CSR_DWRITE_RUN (1L<<11) /* Bit 11: Rel. Descr Write SM */ +#define CSR_DWRITE_RST (1L<<10) /* Bit 10: Reset Descr Write SM */ +#define CSR_TRANS_RUN (1L<<9) /* Bit 9: Release Transfer SM */ +#define CSR_TRANS_RST (1L<<8) /* Bit 8: Reset Transfer SM */ + /* Bit 7..5: reserved */ +#define CSR_START (1L<<4) /* Bit 4: Start Rec/Xmit Queue */ +#define CSR_IRQ_CL_P (1L<<3) /* Bit 3: Clear Parity IRQ, Rcv */ +#define CSR_IRQ_CL_B (1L<<2) /* Bit 2: Clear EOB IRQ */ +#define CSR_IRQ_CL_F (1L<<1) /* Bit 1: Clear EOF IRQ */ +#define CSR_IRQ_CL_C (1L<<0) /* Bit 0: Clear ERR IRQ */ + +#define CSR_SET_RESET (CSR_DESC_SET|CSR_FIFO_SET|CSR_HPI_RST|CSR_SV_RST|\ + CSR_DREAD_RST|CSR_DWRITE_RST|CSR_TRANS_RST) +#define CSR_CLR_RESET (CSR_DESC_CLEAR|CSR_FIFO_CLEAR|CSR_HPI_RUN|CSR_SV_RUN|\ + CSR_DREAD_RUN|CSR_DWRITE_RUN|CSR_TRANS_RUN) + + +/* B5__F 32 bit flag register (xx) */ + /* Bit 28..31: reserved */ +#define F_ALM_FULL (1L<<27) /* Bit 27: (ML) FIFO almost full */ +#define F_FIFO_EOF (1L<<26) /* Bit 26: (ML) Fag bit in FIFO */ +#define F_WM_REACHED (1L<<25) /* Bit 25: (ML) Watermark reached */ +#define F_UP_DW_USED (1L<<24) /* Bit 24: (ML) Upper Dword used (bug)*/ + /* Bit 23: reserved */ +#define F_FIFO_LEVEL (0x1fL<<16) /* Bit 16..22:(ML) # of Qwords in FIFO*/ + /* Bit 8..15: reserved */ +#define F_ML_WATER_M 0x0000ffL /* Bit 0.. 7:(ML) Watermark */ +#define FLAG_WATER 0x00001fL /* Bit 4..0:(DV) Level of req data tr.*/ + +/* B5__T1 32 bit Test Register 1 (xx) */ +/* Holds four State Machine control Bytes */ +#define SM_CRTL_SV (0xffL<<24) /* Bit 31..24: Control Supervisor SM */ +#define SM_CRTL_RD (0xffL<<16) /* Bit 23..16: Control Read Desc SM */ +#define SM_CRTL_WR (0xffL<<8) /* Bit 15..8: Control Write Desc SM */ +#define SM_CRTL_TR (0xffL<<0) /* Bit 7..0: Control Transfer SM */ + +/* B4__T1_TR 8 bit Test Register 1 TR (xx) */ +/* B4__T1_WR 8 bit Test Register 1 WR (xx) */ +/* B4__T1_RD 8 bit Test Register 1 RD (xx) */ +/* B4__T1_SV 8 bit Test Register 1 SV (xx) */ +/* The control status byte of each machine looks like ... */ +#define SM_STATE 0xf0 /* Bit 7..4: State which shall be loaded */ +#define SM_LOAD 0x08 /* Bit 3: Load the SM with SM_STATE */ +#define SM_TEST_ON 0x04 /* Bit 2: Switch on SM Test Mode */ +#define SM_TEST_OFF 0x02 /* Bit 1: Go off the Test Mode */ +#define SM_STEP 0x01 /* Bit 0: Step the State Machine */ + +/* The coding of the states */ +#define SM_SV_IDLE 0x0 /* Supervisor Idle Tr/Re */ +#define SM_SV_RES_START 0x1 /* Supervisor Res_Start Tr/Re */ +#define SM_SV_GET_DESC 0x3 /* Supervisor Get_Desc Tr/Re */ +#define SM_SV_CHECK 0x2 /* Supervisor Check Tr/Re */ +#define SM_SV_MOV_DATA 0x6 /* Supervisor Move_Data Tr/Re */ +#define SM_SV_PUT_DESC 0x7 /* Supervisor Put_Desc Tr/Re */ +#define SM_SV_SET_IRQ 0x5 /* Supervisor Set_Irq Tr/Re */ + +#define SM_RD_IDLE 0x0 /* Read Desc. Idle Tr/Re */ +#define SM_RD_LOAD 0x1 /* Read Desc. Load Tr/Re */ +#define SM_RD_WAIT_TC 0x3 /* Read Desc. Wait_TC Tr/Re */ +#define SM_RD_RST_EOF 0x6 /* Read Desc. Reset_EOF Re */ +#define SM_RD_WDONE_R 0x2 /* Read Desc. Wait_Done Re */ +#define SM_RD_WDONE_T 0x4 /* Read Desc. Wait_Done Tr */ + +#define SM_TR_IDLE 0x0 /* Trans. Data Idle Tr/Re */ +#define SM_TR_LOAD 0x3 /* Trans. Data Load Tr/Re */ +#define SM_TR_LOAD_R_ML 0x1 /* Trans. Data Load /Re (ML) */ +#define SM_TR_WAIT_TC 0x2 /* Trans. Data Wait_TC Tr/Re */ +#define SM_TR_WDONE 0x4 /* Trans. Data Wait_Done Tr/Re */ + +#define SM_WR_IDLE 0x0 /* Write Desc. Idle Tr/Re */ +#define SM_WR_ABLEN 0x1 /* Write Desc. Act_Buf_Length Tr/Re */ +#define SM_WR_LD_A4 0x2 /* Write Desc. Load_A4 Re */ +#define SM_WR_RES_OWN 0x2 /* Write Desc. Res_OWN Tr */ +#define SM_WR_WAIT_EOF 0x3 /* Write Desc. Wait_EOF Re */ +#define SM_WR_LD_N2C_R 0x4 /* Write Desc. Load_N2C Re */ +#define SM_WR_WAIT_TC_R 0x5 /* Write Desc. Wait_TC Re */ +#define SM_WR_WAIT_TC4 0x6 /* Write Desc. Wait_TC4 Re */ +#define SM_WR_LD_A_T 0x6 /* Write Desc. Load_A Tr */ +#define SM_WR_LD_A_R 0x7 /* Write Desc. Load_A Re */ +#define SM_WR_WAIT_TC_T 0x7 /* Write Desc. Wait_TC Tr */ +#define SM_WR_LD_N2C_T 0xc /* Write Desc. Load_N2C Tr */ +#define SM_WR_WDONE_T 0x9 /* Write Desc. Wait_Done Tr */ +#define SM_WR_WDONE_R 0xc /* Write Desc. Wait_Done Re */ +#define SM_WR_LD_D_AD 0xe /* Write Desc. Load_Dumr_A Re (ML) */ +#define SM_WR_WAIT_D_TC 0xf /* Write Desc. Wait_Dumr_TC Re (ML) */ + +/* B5__T2 32 bit Test Register 2 (xx) */ +/* Note: This register is only defined for the transmit queues */ + /* Bit 31..8: reserved */ +#define AC_TEST_ON (1<<7) /* Bit 7: Address Counter Test Mode on */ +#define AC_TEST_OFF (1<<6) /* Bit 6: Address Counter Test Mode off*/ +#define BC_TEST_ON (1<<5) /* Bit 5: Byte Counter Test Mode on */ +#define BC_TEST_OFF (1<<4) /* Bit 4: Byte Counter Test Mode off */ +#define TEST_STEP04 (1<<3) /* Bit 3: Inc AC/Dec BC by 4 */ +#define TEST_STEP03 (1<<2) /* Bit 2: Inc AC/Dec BC by 3 */ +#define TEST_STEP02 (1<<1) /* Bit 1: Inc AC/Dec BC by 2 */ +#define TEST_STEP01 (1<<0) /* Bit 0: Inc AC/Dec BC by 1 */ + +/* B5__T3 32 bit Test Register 3 (xx) */ +/* Note: This register is only defined for the transmit queues */ + /* Bit 31..8: reserved */ +#define T3_MUX_2 (1<<7) /* Bit 7: (ML) Mux position MSB */ +#define T3_VRAM_2 (1<<6) /* Bit 6: (ML) Virtual RAM buffer addr MSB */ +#define T3_LOOP (1<<5) /* Bit 5: Set Loopback (Xmit) */ +#define T3_UNLOOP (1<<4) /* Bit 4: Unset Loopback (Xmit) */ +#define T3_MUX (3<<2) /* Bit 3..2: Mux position */ +#define T3_VRAM (3<<0) /* Bit 1..0: Virtual RAM buffer Address */ + +/* PCI card IDs */ +/* + * Note: The following 4 byte definitions shall not be used! Use OEM Concept! + */ +#define PCI_VEND_ID0 0x48 /* PCI vendor ID (SysKonnect) */ +#define PCI_VEND_ID1 0x11 /* PCI vendor ID (SysKonnect) */ + /* (High byte) */ +#define PCI_DEV_ID0 0x00 /* PCI device ID */ +#define PCI_DEV_ID1 0x40 /* PCI device ID (High byte) */ + +/*#define PCI_CLASS 0x02*/ /* PCI class code: network device */ +#define PCI_NW_CLASS 0x02 /* PCI class code: network device */ +#define PCI_SUB_CLASS 0x02 /* PCI subclass ID: FDDI device */ +#define PCI_PROG_INTFC 0x00 /* PCI programming Interface (=0) */ + +/* + * address transmission from logical to physical offset address on board + */ +#define FMA(a) (0x0400|((a)<<2)) /* FORMAC+ (r/w) (SN3) */ +#define P1(a) (0x0380|((a)<<2)) /* PLC1 (r/w) (DAS) */ +#define P2(a) (0x0600|((a)<<2)) /* PLC2 (r/w) (covered by the SN3) */ +#define PRA(a) (B2_MAC_0 + (a)) /* configuration PROM (MAC address) */ + +/* + * FlashProm specification + */ +#define MAX_PAGES 0x20000L /* Every byte has a single page */ +#define MAX_FADDR 1 /* 1 byte per page */ + +/* + * Receive / Transmit Buffer Control word + */ +#define BMU_OWN (1UL<<31) /* OWN bit: 0 == host, 1 == adapter */ +#define BMU_STF (1L<<30) /* Start of Frame ? */ +#define BMU_EOF (1L<<29) /* End of Frame ? */ +#define BMU_EN_IRQ_EOB (1L<<28) /* Enable "End of Buffer" IRQ */ +#define BMU_EN_IRQ_EOF (1L<<27) /* Enable "End of Frame" IRQ */ +#define BMU_DEV_0 (1L<<26) /* RX: don't transfer to system mem */ +#define BMU_SMT_TX (1L<<25) /* TX: if set, buffer type SMT_MBuf */ +#define BMU_ST_BUF (1L<<25) /* RX: copy of start of frame */ +#define BMU_UNUSED (1L<<24) /* Set if the Descr is curr unused */ +#define BMU_SW (3L<<24) /* 2 Bits reserved for SW usage */ +#define BMU_CHECK 0x00550000L /* To identify the control word */ +#define BMU_BBC 0x0000FFFFL /* R/T Buffer Byte Count */ + +/* + * physical address offset + IO-Port base address + */ +#ifdef MEM_MAPPED_IO +#define ADDR(a) (char far *) smc->hw.iop+(a) +#define ADDRS(smc,a) (char far *) (smc)->hw.iop+(a) +#else +#define ADDR(a) (((a)>>7) ? (outp(smc->hw.iop+B0_RAP,(a)>>7), \ + (smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) : \ + (smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) +#define ADDRS(smc,a) (((a)>>7) ? (outp((smc)->hw.iop+B0_RAP,(a)>>7), \ + ((smc)->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) : \ + ((smc)->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) +#endif + +/* + * Define a macro to access the configuration space + */ +#define PCI_C(a) ADDR(B3_CFG_SPC + (a)) /* PCI Config Space */ + +#define EXT_R(a) ADDR(B6_EXT_REG + (a)) /* External Registers */ + +/* + * Define some values needed for the MAC address (PROM) + */ +#define SA_MAC (0) /* start addr. MAC_AD within the PROM */ +#define PRA_OFF (0) /* offset correction when 4th byte reading */ + +#define SKFDDI_PSZ 8 /* address PROM size */ + +#define FM_A(a) ADDR(FMA(a)) /* FORMAC Plus physical addr */ +#define P1_A(a) ADDR(P1(a)) /* PLC1 (r/w) */ +#define P2_A(a) ADDR(P2(a)) /* PLC2 (r/w) (DAS) */ +#define PR_A(a) ADDR(PRA(a)) /* config. PROM (MAC address) */ + +/* + * Macro to read the PROM + */ +#define READ_PROM(a) ((u_char)inp(a)) + +#define GET_PAGE(bank) outpd(ADDR(B2_FAR),bank) +#define VPP_ON() +#define VPP_OFF() + +/* + * Note: Values of the Interrupt Source Register are defined above + */ +#define ISR_A ADDR(B0_ISRC) +#define GET_ISR() inpd(ISR_A) +#define GET_ISR_SMP(iop) inpd((iop)+B0_ISRC) +#define CHECK_ISR() (inpd(ISR_A) & inpd(ADDR(B0_IMSK))) +#define CHECK_ISR_SMP(iop) (inpd((iop)+B0_ISRC) & inpd((iop)+B0_IMSK)) + +#define BUS_CHECK() + +/* + * CLI_FBI: Disable Board Interrupts + * STI_FBI: Enable Board Interrupts + */ +#ifndef UNIX +#define CLI_FBI() outpd(ADDR(B0_IMSK),0) +#else +#define CLI_FBI(smc) outpd(ADDRS((smc),B0_IMSK),0) +#endif + +#ifndef UNIX +#define STI_FBI() outpd(ADDR(B0_IMSK),smc->hw.is_imask) +#else +#define STI_FBI(smc) outpd(ADDRS((smc),B0_IMSK),(smc)->hw.is_imask) +#endif + +#define CLI_FBI_SMP(iop) outpd((iop)+B0_IMSK,0) +#define STI_FBI_SMP(smc,iop) outpd((iop)+B0_IMSK,(smc)->hw.is_imask) + +#endif /* PCI */ +/*--------------------------------------------------------------------------*/ + +/* + * 12 bit transfer (dword) counter: + * (ISA: 2*trc = number of byte) + * (EISA: 4*trc = number of byte) + * (MCA: 4*trc = number of byte) + */ +#define MAX_TRANS (0x0fff) + +/* + * PC PIC + */ +#define MST_8259 (0x20) +#define SLV_8259 (0xA0) + +#define TPS (18) /* ticks per second */ + +/* + * error timer defs + */ +#define TN (4) /* number of supported timer = TN+1 */ +#define SNPPND_TIME (5) /* buffer memory access over mem. data reg. */ + +#define MAC_AD 0x405a0000 + +#define MODR1 FM_A(FM_MDREG1) /* mode register 1 */ +#define MODR2 FM_A(FM_MDREG2) /* mode register 2 */ + +#define CMDR1 FM_A(FM_CMDREG1) /* command register 1 */ +#define CMDR2 FM_A(FM_CMDREG2) /* command register 2 */ + + +/* + * function defines + */ +#define CLEAR(io,mask) outpw((io),inpw(io)&(~(mask))) +#define SET(io,mask) outpw((io),inpw(io)|(mask)) +#define GET(io,mask) (inpw(io)&(mask)) +#define SETMASK(io,val,mask) outpw((io),(inpw(io) & ~(mask)) | (val)) + +/* + * PHY Port A (PA) = PLC 1 + * With SuperNet 3 PHY-A and PHY S are identical. + */ +#define PLC(np,reg) (((np) == PA) ? P2_A(reg) : P1_A(reg)) + +/* + * set memory address register for write and read + */ +#define MARW(ma) outpw(FM_A(FM_MARW),(unsigned int)(ma)) +#define MARR(ma) outpw(FM_A(FM_MARR),(unsigned int)(ma)) + +/* + * read/write from/to memory data register + */ +/* write double word */ +#define MDRW(dd) outpw(FM_A(FM_MDRU),(unsigned int)((dd)>>16)) ;\ + outpw(FM_A(FM_MDRL),(unsigned int)(dd)) + +#ifndef WINNT +/* read double word */ +#define MDRR() (((long)inpw(FM_A(FM_MDRU))<<16) + inpw(FM_A(FM_MDRL))) + +/* read FORMAC+ 32-bit status register */ +#define GET_ST1() (((long)inpw(FM_A(FM_ST1U))<<16) + inpw(FM_A(FM_ST1L))) +#define GET_ST2() (((long)inpw(FM_A(FM_ST2U))<<16) + inpw(FM_A(FM_ST2L))) +#ifdef SUPERNET_3 +#define GET_ST3() (((long)inpw(FM_A(FM_ST3U))<<16) + inpw(FM_A(FM_ST3L))) +#endif +#else +/* read double word */ +#define MDRR() inp2w((FM_A(FM_MDRU)),(FM_A(FM_MDRL))) + +/* read FORMAC+ 32-bit status register */ +#define GET_ST1() inp2w((FM_A(FM_ST1U)),(FM_A(FM_ST1L))) +#define GET_ST2() inp2w((FM_A(FM_ST2U)),(FM_A(FM_ST2L))) +#ifdef SUPERNET_3 +#define GET_ST3() inp2w((FM_A(FM_ST3U)),(FM_A(FM_ST3L))) +#endif +#endif + +/* Special timer macro for 82c54 */ + /* timer access over data bus bit 8..15 */ +#define OUT_82c54_TIMER(port,val) outpw(TI_A(port),(val)<<8) +#define IN_82c54_TIMER(port) ((inpw(TI_A(port))>>8) & 0xff) + + +#ifdef DEBUG +#define DB_MAC(mac,st) {if (debug_mac & 0x1)\ + printf("M") ;\ + if (debug_mac & 0x2)\ + printf("\tMAC %d status 0x%08lx\n",mac,st) ;\ + if (debug_mac & 0x4)\ + dp_mac(mac,st) ;\ +} + +#define DB_PLC(p,iev) { if (debug_plc & 0x1)\ + printf("P") ;\ + if (debug_plc & 0x2)\ + printf("\tPLC %s Int 0x%04x\n", \ + (p == PA) ? "A" : "B", iev) ;\ + if (debug_plc & 0x4)\ + dp_plc(p,iev) ;\ +} + +#define DB_TIMER() { if (debug_timer & 0x1)\ + printf("T") ;\ + if (debug_timer & 0x2)\ + printf("\tTimer ISR\n") ;\ +} + +#else /* no DEBUG */ + +#define DB_MAC(mac,st) +#define DB_PLC(p,iev) +#define DB_TIMER() + +#endif /* no DEBUG */ + +#define INC_PTR(sp,cp,ep) if (++cp == ep) cp = sp +/* + * timer defs + */ +#define COUNT(t) ((t)<<6) /* counter */ +#define RW_OP(o) ((o)<<4) /* read/write operation */ +#define TMODE(m) ((m)<<1) /* timer mode */ + +#endif diff --git a/drivers/net/fddi/skfp/h/skfbiinc.h b/drivers/net/fddi/skfp/h/skfbiinc.h new file mode 100644 index 0000000..ac2d719 --- /dev/null +++ b/drivers/net/fddi/skfp/h/skfbiinc.h @@ -0,0 +1,97 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _SKFBIINC_ +#define _SKFBIINC_ + +#include "h/supern_2.h" + +/* + * special defines for use into .asm files + */ +#define ERR_FLAGS (FS_MSRABT | FS_SEAC2 | FS_SFRMERR | FS_SFRMTY1) + +#ifdef PCI +#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \ + IS_MINTR2 | IS_MINTR3 | IS_R1_P | \ + IS_R1_C | IS_XA_C | IS_XS_C) +#endif + +#ifdef PCI +#define ISR_MASK (IS_MINTR1 | IS_R1_F | IS_XS_F| IS_XA_F | IMASK_FAST) +#else +#define ISR_MASK (IS_MINTR1 | IS_MINTR2 | IMASK_FAST) +#endif + +#define FMA_FM_CMDREG1 FMA(FM_CMDREG1) +#define FMA_FM_CMDREG2 FMA(FM_CMDREG2) +#define FMA_FM_STMCHN FMA(FM_STMCHN) +#define FMA_FM_RPR FMA(FM_RPR) +#define FMA_FM_WPXA0 FMA(FM_WPXA0) +#define FMA_FM_WPXA2 FMA(FM_WPXA2) +#define FMA_FM_MARR FMA(FM_MARR) +#define FMA_FM_MARW FMA(FM_MARW) +#define FMA_FM_MDRU FMA(FM_MDRU) +#define FMA_FM_MDRL FMA(FM_MDRL) +#define FMA_ST1L FMA(FM_ST1L) +#define FMA_ST1U FMA(FM_ST1U) +#define FMA_ST2L FMA(FM_ST2L) +#define FMA_ST2U FMA(FM_ST2U) +#ifdef SUPERNET_3 +#define FMA_ST3L FMA(FM_ST3L) +#define FMA_ST3U FMA(FM_ST3U) +#endif + +#define TMODE_RRQ RQ_RRQ +#define TMODE_WAQ2 RQ_WA2 +#define HSRA HSR(0) + + +#define FMA_FM_ST1L FMA_ST1L +#define FMA_FM_ST1U FMA_ST1U +#define FMA_FM_ST2L FMA_ST2L +#define FMA_FM_ST2U FMA_ST2U +#ifdef SUPERNET_3 +#define FMA_FM_ST3L FMA_ST3L +#define FMA_FM_ST3U FMA_ST3U +#endif + +#define FMA_FM_SWPR FMA(FM_SWPR) + +#define FMA_FM_RPXA0 FMA(FM_RPXA0) + +#define FMA_FM_RPXS FMA(FM_RPXS) +#define FMA_FM_WPXS FMA(FM_WPXS) + +#define FMA_FM_IMSK1U FMA(FM_IMSK1U) +#define FMA_FM_IMSK1L FMA(FM_IMSK1L) + +#define FMA_FM_EAS FMA(FM_EAS) +#define FMA_FM_EAA0 FMA(FM_EAA0) + +#define TMODE_WAQ0 RQ_WA0 +#define TMODE_WSQ RQ_WSQ + +/* Define default for DRV_PCM_STATE_CHANGE */ +#ifndef DRV_PCM_STATE_CHANGE +#define DRV_PCM_STATE_CHANGE(smc,plc,p_state) /* nothing */ +#endif + +/* Define default for DRV_RMT_INDICATION */ +#ifndef DRV_RMT_INDICATION +#define DRV_RMT_INDICATION(smc,i) /* nothing */ +#endif + +#endif /* n_SKFBIINC_ */ + diff --git a/drivers/net/fddi/skfp/h/smc.h b/drivers/net/fddi/skfp/h/smc.h new file mode 100644 index 0000000..c774a95 --- /dev/null +++ b/drivers/net/fddi/skfp/h/smc.h @@ -0,0 +1,488 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _SCMECM_ +#define _SCMECM_ + +#if defined(PCI) && !defined(OSDEF) +/* + * In the case of the PCI bus the file osdef1st.h must be present + */ +#define OSDEF +#endif + +#ifdef PCI +#ifndef SUPERNET_3 +#define SUPERNET_3 +#endif +#ifndef TAG_MODE +#define TAG_MODE +#endif +#endif + +/* + * include all other files in required order + * the following files must have been included before: + * types.h + * fddi.h + */ +#ifdef OSDEF +#include "h/osdef1st.h" +#endif /* OSDEF */ +#ifdef OEM_CONCEPT +#include "oemdef.h" +#endif /* OEM_CONCEPT */ +#include "h/smt.h" +#include "h/cmtdef.h" +#include "h/fddimib.h" +#include "h/targethw.h" /* all target hw dependencies */ +#include "h/targetos.h" /* all target os dependencies */ +#ifdef ESS +#include "h/sba.h" +#endif + +/* + * Event Queue + * queue.c + * events are class/value pairs + * class is addressee, e.g. RMT, PCM etc. + * value is command, e.g. line state change, ring op change etc. + */ +struct event_queue { + u_short class ; /* event class */ + u_short event ; /* event value */ +} ; + +/* + * define event queue as circular buffer + */ +#ifdef CONCENTRATOR +#define MAX_EVENT 128 +#else /* nCONCENTRATOR */ +#define MAX_EVENT 64 +#endif /* nCONCENTRATOR */ + +struct s_queue { + + struct event_queue ev_queue[MAX_EVENT]; + struct event_queue *ev_put ; + struct event_queue *ev_get ; +} ; + +/* + * ECM - Entity Coordination Management + * ecm.c + */ +struct s_ecm { + u_char path_test ; /* ECM path test variable */ + u_char sb_flag ; /* ECM stuck bypass */ + u_char DisconnectFlag ; /* jd 05-Aug-1999 Bug #10419 + * ECM disconnected */ + u_char ecm_line_state ; /* flag to dispatcher : line states */ + u_long trace_prop ; /* ECM Trace_Prop flag >= 16 bits !! */ + /* NUMPHYS note: + * this variable must have enough bits to hold all entiies in + * the station. So NUMPHYS may not be greater than 31. + */ + char ec_pad[2] ; + struct smt_timer ecm_timer ; /* timer */ +} ; + + +/* + * RMT - Ring Management + * rmt.c + */ +struct s_rmt { + u_char dup_addr_test ; /* state of dupl. addr. test */ + u_char da_flag ; /* flag : duplicate address det. */ + u_char loop_avail ; /* flag : MAC available for loopback */ + u_char sm_ma_avail ; /* flag : MAC available for SMT */ + u_char no_flag ; /* flag : ring not operational */ + u_char bn_flag ; /* flag : MAC reached beacon state */ + u_char jm_flag ; /* flag : jamming in NON_OP_DUP */ + u_char rm_join ; /* CFM flag RM_Join */ + u_char rm_loop ; /* CFM flag RM_Loop */ + + long fast_rm_join ; /* bit mask of active ports */ + /* + * timer and flags + */ + struct smt_timer rmt_timer0 ; /* timer 0 */ + struct smt_timer rmt_timer1 ; /* timer 1 */ + struct smt_timer rmt_timer2 ; /* timer 2 */ + u_char timer0_exp ; /* flag : timer 0 expired */ + u_char timer1_exp ; /* flag : timer 1 expired */ + u_char timer2_exp ; /* flag : timer 2 expired */ + + u_char rm_pad1[1] ; +} ; + +/* + * CFM - Configuration Management + * cfm.c + * used for SAS and DAS + */ +struct s_cfm { + u_char cf_state; /* CFM state machine current state */ + u_char cf_pad[3] ; +} ; + +/* + * CEM - Configuration Element Management + * cem.c + * used for Concentrator + */ +#ifdef CONCENTRATOR +struct s_cem { + int ce_state ; /* CEM state */ + int ce_port ; /* PA PB PM PM+1 .. */ + int ce_type ; /* TA TB TS TM */ +} ; + +/* + * linked list of CCEs in current token path + */ +struct s_c_ring { + struct s_c_ring *c_next ; + char c_entity ; +} ; + +struct mib_path_config { + u_long fddimibPATHConfigSMTIndex; + u_long fddimibPATHConfigPATHIndex; + u_long fddimibPATHConfigTokenOrder; + u_long fddimibPATHConfigResourceType; +#define SNMP_RES_TYPE_MAC 2 /* Resource is a MAC */ +#define SNMP_RES_TYPE_PORT 4 /* Resource is a PORT */ + u_long fddimibPATHConfigResourceIndex; + u_long fddimibPATHConfigCurrentPath; +#define SNMP_PATH_ISOLATED 1 /* Current path is isolated */ +#define SNMP_PATH_LOCAL 2 /* Current path is local */ +#define SNMP_PATH_SECONDARY 3 /* Current path is secondary */ +#define SNMP_PATH_PRIMARY 4 /* Current path is primary */ +#define SNMP_PATH_CONCATENATED 5 /* Current path is concatenated */ +#define SNMP_PATH_THRU 6 /* Current path is thru */ +}; + + +#endif + +/* + * PCM connect states + */ +#define PCM_DISABLED 0 +#define PCM_CONNECTING 1 +#define PCM_STANDBY 2 +#define PCM_ACTIVE 3 + +struct s_pcm { + u_char pcm_pad[3] ; +} ; + +/* + * PHY struct + * one per physical port + */ +struct s_phy { + /* Inter Module Globals */ + struct fddi_mib_p *mib ; + + u_char np ; /* index 0 .. NUMPHYS */ + u_char cf_join ; + u_char cf_loop ; + u_char wc_flag ; /* withhold connection flag */ + u_char pc_mode ; /* Holds the negotiated mode of the PCM */ + u_char pc_lem_fail ; /* flag : LCT failed */ + u_char lc_test ; + u_char scrub ; /* CFM flag Scrub -> PCM */ + char phy_name ; + u_char pmd_type[2] ; /* SK connector/transceiver type codes */ +#define PMD_SK_CONN 0 /* pmd_type[PMD_SK_CONN] = Connector */ +#define PMD_SK_PMD 1 /* pmd_type[PMD_SK_PMD] = Xver */ + u_char pmd_scramble ; /* scrambler on/off */ + + /* inner Module Globals */ + u_char curr_ls ; /* current line state */ + u_char ls_flag ; + u_char rc_flag ; + u_char tc_flag ; + u_char td_flag ; + u_char bitn ; + u_char tr_flag ; /* trace recvd while in active */ + u_char twisted ; /* flag to indicate an A-A or B-B connection */ + u_char t_val[NUMBITS] ; /* transmit bits for signaling */ + u_char r_val[NUMBITS] ; /* receive bits for signaling */ + u_long t_next[NUMBITS] ; + struct smt_timer pcm_timer0 ; + struct smt_timer pcm_timer1 ; + struct smt_timer pcm_timer2 ; + u_char timer0_exp ; + u_char timer1_exp ; + u_char timer2_exp ; + u_char pcm_pad1[1] ; + int cem_pst ; /* CEM privae state; used for dual homing */ + struct lem_counter lem ; +#ifdef AMDPLC + struct s_plc plc ; +#endif +} ; + +/* + * timer package + * smttimer.c + */ +struct s_timer { + struct smt_timer *st_queue ; + struct smt_timer st_fast ; +} ; + +/* + * SRF types and data + */ +#define SMT_EVENT_BASE 1 +#define SMT_EVENT_MAC_PATH_CHANGE (SMT_EVENT_BASE+0) +#define SMT_EVENT_MAC_NEIGHBOR_CHANGE (SMT_EVENT_BASE+1) +#define SMT_EVENT_PORT_PATH_CHANGE (SMT_EVENT_BASE+2) +#define SMT_EVENT_PORT_CONNECTION (SMT_EVENT_BASE+3) + +#define SMT_IS_CONDITION(x) ((x)>=SMT_COND_BASE) + +#define SMT_COND_BASE (SMT_EVENT_PORT_CONNECTION+1) +#define SMT_COND_SMT_PEER_WRAP (SMT_COND_BASE+0) +#define SMT_COND_SMT_HOLD (SMT_COND_BASE+1) +#define SMT_COND_MAC_FRAME_ERROR (SMT_COND_BASE+2) +#define SMT_COND_MAC_DUP_ADDR (SMT_COND_BASE+3) +#define SMT_COND_MAC_NOT_COPIED (SMT_COND_BASE+4) +#define SMT_COND_PORT_EB_ERROR (SMT_COND_BASE+5) +#define SMT_COND_PORT_LER (SMT_COND_BASE+6) + +#define SR0_WAIT 0 +#define SR1_HOLDOFF 1 +#define SR2_DISABLED 2 + +struct s_srf { + u_long SRThreshold ; /* threshold value */ + u_char RT_Flag ; /* report transmitted flag */ + u_char sr_state ; /* state-machine */ + u_char any_report ; /* any report required */ + u_long TSR ; /* timer */ + u_short ring_status ; /* IBM ring status */ +} ; + +/* + * IBM token ring status + */ +#define RS_RES15 (1<<15) /* reserved */ +#define RS_HARDERROR (1<<14) /* ring down */ +#define RS_SOFTERROR (1<<13) /* sent SRF */ +#define RS_BEACON (1<<12) /* transmitted beacon */ +#define RS_PATHTEST (1<<11) /* path test failed */ +#define RS_SELFTEST (1<<10) /* selftest required */ +#define RS_RES9 (1<< 9) /* reserved */ +#define RS_DISCONNECT (1<< 8) /* remote disconnect */ +#define RS_RES7 (1<< 7) /* reserved */ +#define RS_DUPADDR (1<< 6) /* duplicate address */ +#define RS_NORINGOP (1<< 5) /* no ring op */ +#define RS_VERSION (1<< 4) /* SMT version mismatch */ +#define RS_STUCKBYPASSS (1<< 3) /* stuck bypass */ +#define RS_EVENT (1<< 2) /* FDDI event occurred */ +#define RS_RINGOPCHANGE (1<< 1) /* ring op changed */ +#define RS_RES0 (1<< 0) /* reserved */ + +#define RS_SET(smc,bit) \ + ring_status_indication(smc,smc->srf.ring_status |= bit) +#define RS_CLEAR(smc,bit) \ + ring_status_indication(smc,smc->srf.ring_status &= ~bit) + +#define RS_CLEAR_EVENT (0xffff & ~(RS_NORINGOP)) + +/* Define the AIX-event-Notification as null function if it isn't defined */ +/* in the targetos.h file */ +#ifndef AIX_EVENT +#define AIX_EVENT(smc,opt0,opt1,opt2,opt3) /* nothing */ +#endif + +struct s_srf_evc { + u_char evc_code ; /* event code type */ + u_char evc_index ; /* index for mult. instances */ + u_char evc_rep_required ; /* report required */ + u_short evc_para ; /* SMT Para Number */ + u_char *evc_cond_state ; /* condition state */ + u_char *evc_multiple ; /* multiple occurrence */ +} ; + +/* + * Values used by frame based services + * smt.c + */ +#define SMT_MAX_TEST 5 +#define SMT_TID_NIF 0 /* pending NIF request */ +#define SMT_TID_NIF_TEST 1 /* pending NIF test */ +#define SMT_TID_ECF_UNA 2 /* pending ECF UNA test */ +#define SMT_TID_ECF_DNA 3 /* pending ECF DNA test */ +#define SMT_TID_ECF 4 /* pending ECF test */ + +struct smt_values { + u_long smt_tvu ; /* timer valid una */ + u_long smt_tvd ; /* timer valid dna */ + u_long smt_tid ; /* transaction id */ + u_long pend[SMT_MAX_TEST] ; /* TID of requests */ + u_long uniq_time ; /* unique time stamp */ + u_short uniq_ticks ; /* unique time stamp */ + u_short please_reconnect ; /* flag : reconnect */ + u_long smt_last_lem ; + u_long smt_last_notify ; + struct smt_timer smt_timer ; /* SMT NIF timer */ + u_long last_tok_time[NUMMACS]; /* token cnt emulation */ +} ; + +/* + * SMT/CMT configurable parameters + */ +#define SMT_DAS 0 /* dual attach */ +#define SMT_SAS 1 /* single attach */ +#define SMT_NAC 2 /* null attach concentrator */ + +struct smt_config { + u_char attach_s ; /* CFM attach to secondary path */ + u_char sas ; /* SMT_DAS/SAS/NAC */ + u_char build_ring_map ; /* build ringmap if TRUE */ + u_char numphys ; /* number of active phys */ + u_char sc_pad[1] ; + + u_long pcm_tb_min ; /* PCM : TB_Min timer value */ + u_long pcm_tb_max ; /* PCM : TB_Max timer value */ + u_long pcm_c_min ; /* PCM : C_Min timer value */ + u_long pcm_t_out ; /* PCM : T_Out timer value */ + u_long pcm_tl_min ; /* PCM : TL_min timer value */ + u_long pcm_lc_short ; /* PCM : LC_Short timer value */ + u_long pcm_lc_medium ; /* PCM : LC_Medium timer value */ + u_long pcm_lc_long ; /* PCM : LC_Long timer value */ + u_long pcm_lc_extended ; /* PCM : LC_Extended timer value */ + u_long pcm_t_next_9 ; /* PCM : T_Next[9] timer value */ + u_long pcm_ns_max ; /* PCM : NS_Max timer value */ + + u_long ecm_i_max ; /* ECM : I_Max timer value */ + u_long ecm_in_max ; /* ECM : IN_Max timer value */ + u_long ecm_td_min ; /* ECM : TD_Min timer */ + u_long ecm_test_done ; /* ECM : path test done timer */ + u_long ecm_check_poll ; /* ECM : check bypass poller */ + + u_long rmt_t_non_op ; /* RMT : T_Non_OP timer value */ + u_long rmt_t_stuck ; /* RMT : T_Stuck timer value */ + u_long rmt_t_direct ; /* RMT : T_Direct timer value */ + u_long rmt_t_jam ; /* RMT : T_Jam timer value */ + u_long rmt_t_announce ; /* RMT : T_Announce timer value */ + u_long rmt_t_poll ; /* RMT : claim/beacon poller */ + u_long rmt_dup_mac_behavior ; /* Flag for the beavior of SMT if + * a Duplicate MAC Address was detected. + * FALSE: SMT will leave finally the ring + * TRUE: SMT will reinstert into the ring + */ + u_long mac_d_max ; /* MAC : D_Max timer value */ + + u_long lct_short ; /* LCT : error threshold */ + u_long lct_medium ; /* LCT : error threshold */ + u_long lct_long ; /* LCT : error threshold */ + u_long lct_extended ; /* LCT : error threshold */ +} ; + +#ifdef DEBUG +/* + * Debugging struct sometimes used in smc + */ +struct smt_debug { + int d_smtf ; + int d_smt ; + int d_ecm ; + int d_rmt ; + int d_cfm ; + int d_pcm ; + int d_plc ; +#ifdef ESS + int d_ess ; +#endif +#ifdef SBA + int d_sba ; +#endif + struct os_debug d_os; /* Include specific OS DEBUG struct */ +} ; + +#ifndef DEBUG_BRD +/* all boards shall be debugged with one debug struct */ +extern struct smt_debug debug; /* Declaration of debug struct */ +#endif /* DEBUG_BRD */ + +#endif /* DEBUG */ + +/* + * the SMT Context Struct SMC + * this struct contains ALL global variables of SMT + */ +struct s_smc { + struct s_smt_os os ; /* os specific */ + struct s_smt_hw hw ; /* hardware */ + +/* + * NOTE: os and hw MUST BE the first two structs + * anything beyond hw WILL BE SET TO ZERO in smt_set_defaults() + */ + struct smt_config s ; /* smt constants */ + struct smt_values sm ; /* smt variables */ + struct s_ecm e ; /* ecm */ + struct s_rmt r ; /* rmt */ + struct s_cfm cf ; /* cfm/cem */ +#ifdef CONCENTRATOR + struct s_cem ce[NUMPHYS] ; /* cem */ + struct s_c_ring cr[NUMPHYS+NUMMACS] ; +#endif + struct s_pcm p ; /* pcm */ + struct s_phy y[NUMPHYS] ; /* phy */ + struct s_queue q ; /* queue */ + struct s_timer t ; /* timer */ + struct s_srf srf ; /* SRF */ + struct s_srf_evc evcs[6+NUMPHYS*4] ; + struct fddi_mib mib ; /* __THE_MIB__ */ +#ifdef SBA + struct s_sba sba ; /* SBA variables */ +#endif +#ifdef ESS + struct s_ess ess ; /* Ess variables */ +#endif +#if defined(DEBUG) && defined(DEBUG_BRD) + /* If you want all single board to be debugged separately */ + struct smt_debug debug; /* Declaration of debug struct */ +#endif /* DEBUG_BRD && DEBUG */ +} ; + +extern const struct fddi_addr fddi_broadcast; + +extern void all_selection_criteria(struct s_smc *smc); +extern void card_stop(struct s_smc *smc); +extern void init_board(struct s_smc *smc, u_char *mac_addr); +extern int init_fplus(struct s_smc *smc); +extern void init_plc(struct s_smc *smc); +extern int init_smt(struct s_smc *smc, u_char * mac_addr); +extern void mac1_irq(struct s_smc *smc, u_short stu, u_short stl); +extern void mac2_irq(struct s_smc *smc, u_short code_s2u, u_short code_s2l); +extern void mac3_irq(struct s_smc *smc, u_short code_s3u, u_short code_s3l); +extern int pcm_status_twisted(struct s_smc *smc); +extern void plc1_irq(struct s_smc *smc); +extern void plc2_irq(struct s_smc *smc); +extern void read_address(struct s_smc *smc, u_char * mac_addr); +extern void timer_irq(struct s_smc *smc); + +#endif /* _SCMECM_ */ + diff --git a/drivers/net/fddi/skfp/h/smt.h b/drivers/net/fddi/skfp/h/smt.h new file mode 100644 index 0000000..2030f9c --- /dev/null +++ b/drivers/net/fddi/skfp/h/smt.h @@ -0,0 +1,882 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * SMT 7.2 frame definitions + */ + +#ifndef _SMT_ +#define _SMT_ + +/* #define SMT5_10 */ +#define SMT6_10 +#define SMT7_20 + +#define OPT_PMF /* if parameter management is supported */ +#define OPT_SRF /* if status report is supported */ + +/* + * SMT frame version 5.1 + */ + +#define SMT_VID 0x0001 /* V 5.1 .. 6.1 */ +#define SMT_VID_2 0x0002 /* V 7.2 */ + +struct smt_sid { + u_char sid_oem[2] ; /* implementation spec. */ + struct fddi_addr sid_node ; /* node address */ +} ; + +typedef u_char t_station_id[8] ; + +/* + * note on alignment : + * sizeof(struct smt_header) = 32 + * all parameters are long aligned + * if struct smt_header starts at offset 0, all longs are aligned correctly + * (FC starts at offset 3) + */ +_packed struct smt_header { + struct fddi_addr smt_dest ; /* destination address */ + struct fddi_addr smt_source ; /* source address */ + u_char smt_class ; /* NIF, SIF ... */ + u_char smt_type ; /* req., response .. */ + u_short smt_version ; /* version id */ + u_int smt_tid ; /* transaction ID */ + struct smt_sid smt_sid ; /* station ID */ + u_short smt_pad ; /* pad with 0 */ + u_short smt_len ; /* length of info field */ +} ; +#define SWAP_SMTHEADER "662sl8ss" + +#if 0 +/* + * MAC FC values + */ +#define FC_SMT_INFO 0x41 /* SMT info */ +#define FC_SMT_NSA 0x4f /* SMT Next Station Addressing */ +#endif + + +/* + * type codes + */ +#define SMT_ANNOUNCE 0x01 /* announcement */ +#define SMT_REQUEST 0x02 /* request */ +#define SMT_REPLY 0x03 /* reply */ + +/* + * class codes + */ +#define SMT_NIF 0x01 /* neighbor information frames */ +#define SMT_SIF_CONFIG 0x02 /* station information configuration */ +#define SMT_SIF_OPER 0x03 /* station information operation */ +#define SMT_ECF 0x04 /* echo frames */ +#define SMT_RAF 0x05 /* resource allocation */ +#define SMT_RDF 0x06 /* request denied */ +#define SMT_SRF 0x07 /* status report */ +#define SMT_PMF_GET 0x08 /* parameter management get */ +#define SMT_PMF_SET 0x09 /* parameter management set */ +#define SMT_ESF 0xff /* extended service */ + +#define SMT_MAX_ECHO_LEN 4458 /* max length of SMT Echo */ +#if defined(CONC) || defined(CONC_II) +#define SMT_TEST_ECHO_LEN 50 /* test length of SMT Echo */ +#else +#define SMT_TEST_ECHO_LEN SMT_MAX_ECHO_LEN /* test length */ +#endif + +#define SMT_MAX_INFO_LEN (4352-20) /* max length for SMT info */ + + +/* + * parameter types + */ + +struct smt_para { + u_short p_type ; /* type */ + u_short p_len ; /* length of parameter */ +} ; + +#define PARA_LEN (sizeof(struct smt_para)) + +#define SMTSETPARA(p,t) (p)->para.p_type = (t),\ + (p)->para.p_len = sizeof(*(p)) - PARA_LEN + +/* + * P01 : Upstream Neighbor Address, UNA + */ +#define SMT_P_UNA 0x0001 /* upstream neighbor address */ +#define SWAP_SMT_P_UNA "s6" + +struct smt_p_una { + struct smt_para para ; /* generic parameter header */ + u_short una_pad ; + struct fddi_addr una_node ; /* node address, zero if unknown */ +} ; + +/* + * P02 : Station Descriptor + */ +#define SMT_P_SDE 0x0002 /* station descriptor */ +#define SWAP_SMT_P_SDE "1111" + +#define SMT_SDE_STATION 0 /* end node */ +#define SMT_SDE_CONCENTRATOR 1 /* concentrator */ + +struct smt_p_sde { + struct smt_para para ; /* generic parameter header */ + u_char sde_type ; /* station type */ + u_char sde_mac_count ; /* number of MACs */ + u_char sde_non_master ; /* number of A,B or S ports */ + u_char sde_master ; /* number of S ports on conc. */ +} ; + +/* + * P03 : Station State + */ +#define SMT_P_STATE 0x0003 /* station state */ +#define SWAP_SMT_P_STATE "scc" + +struct smt_p_state { + struct smt_para para ; /* generic parameter header */ + u_short st_pad ; + u_char st_topology ; /* topology */ + u_char st_dupl_addr ; /* duplicate address detected */ +} ; +#define SMT_ST_WRAPPED (1<<0) /* station wrapped */ +#define SMT_ST_UNATTACHED (1<<1) /* unattached concentrator */ +#define SMT_ST_TWISTED_A (1<<2) /* A-A connection, twisted ring */ +#define SMT_ST_TWISTED_B (1<<3) /* B-B connection, twisted ring */ +#define SMT_ST_ROOTED_S (1<<4) /* rooted station */ +#define SMT_ST_SRF (1<<5) /* SRF protocol supported */ +#define SMT_ST_SYNC_SERVICE (1<<6) /* use synchronous bandwidth */ + +#define SMT_ST_MY_DUPA (1<<0) /* my station detected dupl. */ +#define SMT_ST_UNA_DUPA (1<<1) /* my UNA detected duplicate */ + +/* + * P04 : timestamp + */ +#define SMT_P_TIMESTAMP 0x0004 /* time stamp */ +#define SWAP_SMT_P_TIMESTAMP "8" +struct smt_p_timestamp { + struct smt_para para ; /* generic parameter header */ + u_char ts_time[8] ; /* time, resolution 80nS, unique */ +} ; + +/* + * P05 : station policies + */ +#define SMT_P_POLICY 0x0005 /* station policies */ +#define SWAP_SMT_P_POLICY "ss" + +struct smt_p_policy { + struct smt_para para ; /* generic parameter header */ + u_short pl_config ; + u_short pl_connect ; /* bit string POLICY_AA ... */ +} ; +#define SMT_PL_HOLD 1 /* hold policy supported (Dual MAC) */ + +/* + * P06 : latency equivalent + */ +#define SMT_P_LATENCY 0x0006 /* latency */ +#define SWAP_SMT_P_LATENCY "ssss" + +/* + * note: latency has two phy entries by definition + * for a SAS, the 2nd one is null + */ +struct smt_p_latency { + struct smt_para para ; /* generic parameter header */ + u_short lt_phyout_idx1 ; /* index */ + u_short lt_latency1 ; /* latency , unit : byte clock */ + u_short lt_phyout_idx2 ; /* 0 if SAS */ + u_short lt_latency2 ; /* 0 if SAS */ +} ; + +/* + * P07 : MAC neighbors + */ +#define SMT_P_NEIGHBORS 0x0007 /* MAC neighbor description */ +#define SWAP_SMT_P_NEIGHBORS "ss66" + +struct smt_p_neighbor { + struct smt_para para ; /* generic parameter header */ + u_short nb_mib_index ; /* MIB index */ + u_short nb_mac_index ; /* n+1 .. n+m, m = #MACs, n = #PHYs */ + struct fddi_addr nb_una ; /* UNA , 0 for unknown */ + struct fddi_addr nb_dna ; /* DNA , 0 for unknown */ +} ; + +/* + * PHY record + */ +#define SMT_PHY_A 0 /* A port */ +#define SMT_PHY_B 1 /* B port */ +#define SMT_PHY_S 2 /* slave port */ +#define SMT_PHY_M 3 /* master port */ + +#define SMT_CS_DISABLED 0 /* connect state : disabled */ +#define SMT_CS_CONNECTING 1 /* connect state : connecting */ +#define SMT_CS_STANDBY 2 /* connect state : stand by */ +#define SMT_CS_ACTIVE 3 /* connect state : active */ + +#define SMT_RM_NONE 0 +#define SMT_RM_MAC 1 + +struct smt_phy_rec { + u_short phy_mib_index ; /* MIB index */ + u_char phy_type ; /* A/B/S/M */ + u_char phy_connect_state ; /* disabled/connecting/active */ + u_char phy_remote_type ; /* A/B/S/M */ + u_char phy_remote_mac ; /* none/remote */ + u_short phy_resource_idx ; /* 1 .. n */ +} ; + +/* + * MAC record + */ +struct smt_mac_rec { + struct fddi_addr mac_addr ; /* MAC address */ + u_short mac_resource_idx ; /* n+1 .. n+m */ +} ; + +/* + * P08 : path descriptors + * should be really an array ; however our environment has a fixed number of + * PHYs and MACs + */ +#define SMT_P_PATH 0x0008 /* path descriptor */ +#define SWAP_SMT_P_PATH "[6s]" + +struct smt_p_path { + struct smt_para para ; /* generic parameter header */ + struct smt_phy_rec pd_phy[2] ; /* PHY A */ + struct smt_mac_rec pd_mac ; /* MAC record */ +} ; + +/* + * P09 : MAC status + */ +#define SMT_P_MAC_STATUS 0x0009 /* MAC status */ +#define SWAP_SMT_P_MAC_STATUS "sslllllllll" + +struct smt_p_mac_status { + struct smt_para para ; /* generic parameter header */ + u_short st_mib_index ; /* MIB index */ + u_short st_mac_index ; /* n+1 .. n+m */ + u_int st_t_req ; /* T_Req */ + u_int st_t_neg ; /* T_Neg */ + u_int st_t_max ; /* T_Max */ + u_int st_tvx_value ; /* TVX_Value */ + u_int st_t_min ; /* T_Min */ + u_int st_sba ; /* synchr. bandwidth alloc */ + u_int st_frame_ct ; /* frame counter */ + u_int st_error_ct ; /* error counter */ + u_int st_lost_ct ; /* lost frames counter */ +} ; + +/* + * P0A : PHY link error rate monitoring + */ +#define SMT_P_LEM 0x000a /* link error monitor */ +#define SWAP_SMT_P_LEM "ssccccll" +/* + * units of lem_cutoff,lem_alarm,lem_estimate : 10**-x + */ +struct smt_p_lem { + struct smt_para para ; /* generic parameter header */ + u_short lem_mib_index ; /* MIB index */ + u_short lem_phy_index ; /* 1 .. n */ + u_char lem_pad2 ; /* be nice and make it even . */ + u_char lem_cutoff ; /* 0x4 .. 0xf, default 0x7 */ + u_char lem_alarm ; /* 0x4 .. 0xf, default 0x8 */ + u_char lem_estimate ; /* 0x0 .. 0xff */ + u_int lem_reject_ct ; /* 0x00000000 .. 0xffffffff */ + u_int lem_ct ; /* 0x00000000 .. 0xffffffff */ +} ; + +/* + * P0B : MAC frame counters + */ +#define SMT_P_MAC_COUNTER 0x000b /* MAC frame counters */ +#define SWAP_SMT_P_MAC_COUNTER "ssll" + +struct smt_p_mac_counter { + struct smt_para para ; /* generic parameter header */ + u_short mc_mib_index ; /* MIB index */ + u_short mc_index ; /* mac index */ + u_int mc_receive_ct ; /* receive counter */ + u_int mc_transmit_ct ; /* transmit counter */ +} ; + +/* + * P0C : MAC frame not copied counter + */ +#define SMT_P_MAC_FNC 0x000c /* MAC frame not copied counter */ +#define SWAP_SMT_P_MAC_FNC "ssl" + +struct smt_p_mac_fnc { + struct smt_para para ; /* generic parameter header */ + u_short nc_mib_index ; /* MIB index */ + u_short nc_index ; /* mac index */ + u_int nc_counter ; /* not copied counter */ +} ; + + +/* + * P0D : MAC priority values + */ +#define SMT_P_PRIORITY 0x000d /* MAC priority values */ +#define SWAP_SMT_P_PRIORITY "ssl" + +struct smt_p_priority { + struct smt_para para ; /* generic parameter header */ + u_short pr_mib_index ; /* MIB index */ + u_short pr_index ; /* mac index */ + u_int pr_priority[7] ; /* priority values */ +} ; + +/* + * P0E : PHY elasticity buffer status + */ +#define SMT_P_EB 0x000e /* PHY EB status */ +#define SWAP_SMT_P_EB "ssl" + +struct smt_p_eb { + struct smt_para para ; /* generic parameter header */ + u_short eb_mib_index ; /* MIB index */ + u_short eb_index ; /* phy index */ + u_int eb_error_ct ; /* # of eb overflows */ +} ; + +/* + * P0F : manufacturer field + */ +#define SMT_P_MANUFACTURER 0x000f /* manufacturer field */ +#define SWAP_SMT_P_MANUFACTURER "" + +struct smp_p_manufacturer { + struct smt_para para ; /* generic parameter header */ + u_char mf_data[32] ; /* OUI + arbitrary data */ +} ; + +/* + * P10 : user field + */ +#define SMT_P_USER 0x0010 /* manufacturer field */ +#define SWAP_SMT_P_USER "" + +struct smp_p_user { + struct smt_para para ; /* generic parameter header */ + u_char us_data[32] ; /* arbitrary data */ +} ; + + + +/* + * P11 : echo data + */ +#define SMT_P_ECHODATA 0x0011 /* echo data */ +#define SWAP_SMT_P_ECHODATA "" + +struct smt_p_echo { + struct smt_para para ; /* generic parameter header */ + u_char ec_data[SMT_MAX_ECHO_LEN-4] ; /* echo data */ +} ; + +/* + * P12 : reason code + */ +#define SMT_P_REASON 0x0012 /* reason code */ +#define SWAP_SMT_P_REASON "l" + +struct smt_p_reason { + struct smt_para para ; /* generic parameter header */ + u_int rdf_reason ; /* CLASS/VERSION */ +} ; +#define SMT_RDF_CLASS 0x00000001 /* class not supported */ +#define SMT_RDF_VERSION 0x00000002 /* version not supported */ +#define SMT_RDF_SUCCESS 0x00000003 /* success (PMF) */ +#define SMT_RDF_BADSET 0x00000004 /* bad set count (PMF) */ +#define SMT_RDF_ILLEGAL 0x00000005 /* read only (PMF) */ +#define SMT_RDF_NOPARAM 0x6 /* parameter not supported (PMF) */ +#define SMT_RDF_RANGE 0x8 /* out of range */ +#define SMT_RDF_AUTHOR 0x9 /* not autohorized */ +#define SMT_RDF_LENGTH 0x0a /* length error */ +#define SMT_RDF_TOOLONG 0x0b /* length error */ +#define SMT_RDF_SBA 0x0d /* SBA denied */ + +/* + * P13 : refused frame beginning + */ +#define SMT_P_REFUSED 0x0013 /* refused frame beginning */ +#define SWAP_SMT_P_REFUSED "l" + +struct smt_p_refused { + struct smt_para para ; /* generic parameter header */ + u_int ref_fc ; /* 3 bytes 0 + FC */ + struct smt_header ref_header ; /* refused header */ +} ; + +/* + * P14 : supported SMT versions + */ +#define SMT_P_VERSION 0x0014 /* SMT supported versions */ +#define SWAP_SMT_P_VERSION "sccss" + +struct smt_p_version { + struct smt_para para ; /* generic parameter header */ + u_short v_pad ; + u_char v_n ; /* 1 .. 0xff, #versions */ + u_char v_index ; /* 1 .. 0xff, index of op. v. */ + u_short v_version[1] ; /* list of min. 1 version */ + u_short v_pad2 ; /* pad if necessary */ +} ; + +/* + * P15 : Resource Type + */ +#define SWAP_SMT_P0015 "l" + +struct smt_p_0015 { + struct smt_para para ; /* generic parameter header */ + u_int res_type ; /* recsource type */ +} ; + +#define SYNC_BW 0x00000001L /* Synchronous Bandwidth */ + +/* + * P16 : SBA Command + */ +#define SWAP_SMT_P0016 "l" + +struct smt_p_0016 { + struct smt_para para ; /* generic parameter header */ + u_int sba_cmd ; /* command for the SBA */ +} ; + +#define REQUEST_ALLOCATION 0x1 /* req allocation of sync bandwidth */ +#define REPORT_ALLOCATION 0x2 /* rep of sync bandwidth allocation */ +#define CHANGE_ALLOCATION 0x3 /* forces a station using sync band-*/ + /* width to change its current allo-*/ + /* cation */ + +/* + * P17 : SBA Payload Request + */ +#define SWAP_SMT_P0017 "l" + +struct smt_p_0017 { + struct smt_para para ; /* generic parameter header */ + int sba_pl_req ; /* total sync bandwidth measured in */ +} ; /* bytes per 125 us */ + +/* + * P18 : SBA Overhead Request + */ +#define SWAP_SMT_P0018 "l" + +struct smt_p_0018 { + struct smt_para para ; /* generic parameter header */ + int sba_ov_req ; /* total sync bandwidth req for overhead*/ +} ; /* measuered in bytes per T_Neg */ + +/* + * P19 : SBA Allocation Address + */ +#define SWAP_SMT_P0019 "s6" + +struct smt_p_0019 { + struct smt_para para ; /* generic parameter header */ + u_short sba_pad ; + struct fddi_addr alloc_addr ; /* Allocation Address */ +} ; + +/* + * P1A : SBA Category + */ +#define SWAP_SMT_P001A "l" + +struct smt_p_001a { + struct smt_para para ; /* generic parameter header */ + u_int category ; /* Allocator defined classification */ +} ; + +/* + * P1B : Maximum T_Neg + */ +#define SWAP_SMT_P001B "l" + +struct smt_p_001b { + struct smt_para para ; /* generic parameter header */ + u_int max_t_neg ; /* longest T_NEG for the sync service*/ +} ; + +/* + * P1C : Minimum SBA Segment Size + */ +#define SWAP_SMT_P001C "l" + +struct smt_p_001c { + struct smt_para para ; /* generic parameter header */ + u_int min_seg_siz ; /* smallest number of bytes per frame*/ +} ; + +/* + * P1D : SBA Allocatable + */ +#define SWAP_SMT_P001D "l" + +struct smt_p_001d { + struct smt_para para ; /* generic parameter header */ + u_int allocatable ; /* total sync bw available for alloc */ +} ; + +/* + * P20 0B : frame status capabilities + * NOTE: not in swap table, is used by smt.c AND PMF table + */ +#define SMT_P_FSC 0x200b +/* #define SWAP_SMT_P_FSC "ssss" */ + +struct smt_p_fsc { + struct smt_para para ; /* generic parameter header */ + u_short fsc_pad0 ; + u_short fsc_mac_index ; /* mac index 1 .. ff */ + u_short fsc_pad1 ; + u_short fsc_value ; /* FSC_TYPE[0-2] */ +} ; + +#define FSC_TYPE0 0 /* "normal" node (A/C handling) */ +#define FSC_TYPE1 1 /* Special A/C indicator forwarding */ +#define FSC_TYPE2 2 /* Special A/C indicator forwarding */ + +/* + * P00 21 : user defined authoriziation (see pmf.c) + */ +#define SMT_P_AUTHOR 0x0021 + +/* + * notification parameters + */ +#define SWAP_SMT_P1048 "ll" +struct smt_p_1048 { + u_int p1048_flag ; + u_int p1048_cf_state ; +} ; + +/* + * NOTE: all 2xxx 3xxx and 4xxx must include the INDEX in the swap string, + * even so the INDEX is NOT part of the struct. + * INDEX is already swapped in pmf.c, format in string is '4' + */ +#define SWAP_SMT_P208C "4lss66" +struct smt_p_208c { + u_int p208c_flag ; + u_short p208c_pad ; + u_short p208c_dupcondition ; + struct fddi_addr p208c_fddilong ; + struct fddi_addr p208c_fddiunalong ; +} ; + +#define SWAP_SMT_P208D "4lllll" +struct smt_p_208d { + u_int p208d_flag ; + u_int p208d_frame_ct ; + u_int p208d_error_ct ; + u_int p208d_lost_ct ; + u_int p208d_ratio ; +} ; + +#define SWAP_SMT_P208E "4llll" +struct smt_p_208e { + u_int p208e_flag ; + u_int p208e_not_copied ; + u_int p208e_copied ; + u_int p208e_not_copied_ratio ; +} ; + +#define SWAP_SMT_P208F "4ll6666s6" + +struct smt_p_208f { + u_int p208f_multiple ; + u_int p208f_nacondition ; + struct fddi_addr p208f_old_una ; + struct fddi_addr p208f_new_una ; + struct fddi_addr p208f_old_dna ; + struct fddi_addr p208f_new_dna ; + u_short p208f_curren_path ; + struct fddi_addr p208f_smt_address ; +} ; + +#define SWAP_SMT_P2090 "4lssl" + +struct smt_p_2090 { + u_int p2090_multiple ; + u_short p2090_availablepaths ; + u_short p2090_currentpath ; + u_int p2090_requestedpaths ; +} ; + +/* + * NOTE: + * special kludge for parameters 320b,320f,3210 + * these parameters are part of RAF frames + * RAF frames are parsed in SBA.C and must be swapped + * PMF.C has special code to avoid double swapping + */ +#ifdef LITTLE_ENDIAN +#define SBAPATHINDEX (0x01000000L) +#else +#define SBAPATHINDEX (0x01L) +#endif + +#define SWAP_SMT_P320B "42s" + +struct smt_p_320b { + struct smt_para para ; /* generic parameter header */ + u_int mib_index ; + u_short path_pad ; + u_short path_index ; +} ; + +#define SWAP_SMT_P320F "4l" + +struct smt_p_320f { + struct smt_para para ; /* generic parameter header */ + u_int mib_index ; + u_int mib_payload ; +} ; + +#define SWAP_SMT_P3210 "4l" + +struct smt_p_3210 { + struct smt_para para ; /* generic parameter header */ + u_int mib_index ; + u_int mib_overhead ; +} ; + +#define SWAP_SMT_P4050 "4l1111ll" + +struct smt_p_4050 { + u_int p4050_flag ; + u_char p4050_pad ; + u_char p4050_cutoff ; + u_char p4050_alarm ; + u_char p4050_estimate ; + u_int p4050_reject_ct ; + u_int p4050_ct ; +} ; + +#define SWAP_SMT_P4051 "4lssss" +struct smt_p_4051 { + u_int p4051_multiple ; + u_short p4051_porttype ; + u_short p4051_connectstate ; + u_short p4051_pc_neighbor ; + u_short p4051_pc_withhold ; +} ; + +#define SWAP_SMT_P4052 "4ll" +struct smt_p_4052 { + u_int p4052_flag ; + u_int p4052_eberrorcount ; +} ; + +#define SWAP_SMT_P4053 "4lsslss" + +struct smt_p_4053 { + u_int p4053_multiple ; + u_short p4053_availablepaths ; + u_short p4053_currentpath ; + u_int p4053_requestedpaths ; + u_short p4053_mytype ; + u_short p4053_neighbortype ; +} ; + + +#define SMT_P_SETCOUNT 0x1035 +#define SWAP_SMT_P_SETCOUNT "l8" + +struct smt_p_setcount { + struct smt_para para ; /* generic parameter header */ + u_int count ; + u_char timestamp[8] ; +} ; + +/* + * SMT FRAMES + */ + +/* + * NIF : neighbor information frames + */ +struct smt_nif { + struct smt_header smt ; /* generic header */ + struct smt_p_una una ; /* UNA */ + struct smt_p_sde sde ; /* station descriptor */ + struct smt_p_state state ; /* station state */ +#ifdef SMT6_10 + struct smt_p_fsc fsc ; /* frame status cap. */ +#endif +} ; + +/* + * SIF : station information frames + */ +struct smt_sif_config { + struct smt_header smt ; /* generic header */ + struct smt_p_timestamp ts ; /* time stamp */ + struct smt_p_sde sde ; /* station descriptor */ + struct smt_p_version version ; /* supported versions */ + struct smt_p_state state ; /* station state */ + struct smt_p_policy policy ; /* station policy */ + struct smt_p_latency latency ; /* path latency */ + struct smt_p_neighbor neighbor ; /* neighbors, we have only one*/ +#ifdef OPT_PMF + struct smt_p_setcount setcount ; /* Set Count mandatory */ +#endif + /* WARNING : path MUST BE LAST FIELD !!! (see smt.c:smt_fill_path) */ + struct smt_p_path path ; /* path descriptor */ +} ; +#define SIZEOF_SMT_SIF_CONFIG (sizeof(struct smt_sif_config)- \ + sizeof(struct smt_p_path)) + +struct smt_sif_operation { + struct smt_header smt ; /* generic header */ + struct smt_p_timestamp ts ; /* time stamp */ + struct smt_p_mac_status status ; /* mac status */ + struct smt_p_mac_counter mc ; /* MAC counter */ + struct smt_p_mac_fnc fnc ; /* MAC frame not copied */ + struct smp_p_manufacturer man ; /* manufacturer field */ + struct smp_p_user user ; /* user field */ +#ifdef OPT_PMF + struct smt_p_setcount setcount ; /* Set Count mandatory */ +#endif + /* must be last */ + struct smt_p_lem lem[1] ; /* phy lem status */ +} ; +#define SIZEOF_SMT_SIF_OPERATION (sizeof(struct smt_sif_operation)- \ + sizeof(struct smt_p_lem)) + +/* + * ECF : echo frame + */ +struct smt_ecf { + struct smt_header smt ; /* generic header */ + struct smt_p_echo ec_echo ; /* echo parameter */ +} ; +#define SMT_ECF_LEN (sizeof(struct smt_header)+sizeof(struct smt_para)) + +/* + * RDF : request denied frame + */ +struct smt_rdf { + struct smt_header smt ; /* generic header */ + struct smt_p_reason reason ; /* reason code */ + struct smt_p_version version ; /* supported versions */ + struct smt_p_refused refused ; /* refused frame fragment */ +} ; + +/* + * SBA Request Allocation Response Frame + */ +struct smt_sba_alc_res { + struct smt_header smt ; /* generic header */ + struct smt_p_0015 s_type ; /* resource type */ + struct smt_p_0016 cmd ; /* SBA command */ + struct smt_p_reason reason ; /* reason code */ + struct smt_p_320b path ; /* path type */ + struct smt_p_320f payload ; /* current SBA payload */ + struct smt_p_3210 overhead ; /* current SBA overhead */ + struct smt_p_0019 a_addr ; /* Allocation Address */ + struct smt_p_001a cat ; /* Category - from the request */ + struct smt_p_001d alloc ; /* SBA Allocatable */ +} ; + +/* + * SBA Request Allocation Request Frame + */ +struct smt_sba_alc_req { + struct smt_header smt ; /* generic header */ + struct smt_p_0015 s_type ; /* resource type */ + struct smt_p_0016 cmd ; /* SBA command */ + struct smt_p_320b path ; /* path type */ + struct smt_p_0017 pl_req ; /* requested payload */ + struct smt_p_0018 ov_req ; /* requested SBA overhead */ + struct smt_p_320f payload ; /* current SBA payload */ + struct smt_p_3210 overhead ; /* current SBA overhead */ + struct smt_p_0019 a_addr ; /* Allocation Address */ + struct smt_p_001a cat ; /* Category - from the request */ + struct smt_p_001b tneg ; /* max T-NEG */ + struct smt_p_001c segm ; /* minimum segment size */ +} ; + +/* + * SBA Change Allocation Request Frame + */ +struct smt_sba_chg { + struct smt_header smt ; /* generic header */ + struct smt_p_0015 s_type ; /* resource type */ + struct smt_p_0016 cmd ; /* SBA command */ + struct smt_p_320b path ; /* path type */ + struct smt_p_320f payload ; /* current SBA payload */ + struct smt_p_3210 overhead ; /* current SBA overhead */ + struct smt_p_001a cat ; /* Category - from the request */ +} ; + +/* + * SBA Report Allocation Request Frame + */ +struct smt_sba_rep_req { + struct smt_header smt ; /* generic header */ + struct smt_p_0015 s_type ; /* resource type */ + struct smt_p_0016 cmd ; /* SBA command */ +} ; + +/* + * SBA Report Allocation Response Frame + */ +struct smt_sba_rep_res { + struct smt_header smt ; /* generic header */ + struct smt_p_0015 s_type ; /* resource type */ + struct smt_p_0016 cmd ; /* SBA command */ + struct smt_p_320b path ; /* path type */ + struct smt_p_320f payload ; /* current SBA payload */ + struct smt_p_3210 overhead ; /* current SBA overhead */ +} ; + +/* + * actions + */ +#define SMT_STATION_ACTION 1 +#define SMT_STATION_ACTION_CONNECT 0 +#define SMT_STATION_ACTION_DISCONNECT 1 +#define SMT_STATION_ACTION_PATHTEST 2 +#define SMT_STATION_ACTION_SELFTEST 3 +#define SMT_STATION_ACTION_DISABLE_A 4 +#define SMT_STATION_ACTION_DISABLE_B 5 +#define SMT_STATION_ACTION_DISABLE_M 6 + +#define SMT_PORT_ACTION 2 +#define SMT_PORT_ACTION_MAINT 0 +#define SMT_PORT_ACTION_ENABLE 1 +#define SMT_PORT_ACTION_DISABLE 2 +#define SMT_PORT_ACTION_START 3 +#define SMT_PORT_ACTION_STOP 4 + +#endif /* _SMT_ */ diff --git a/drivers/net/fddi/skfp/h/smt_p.h b/drivers/net/fddi/skfp/h/smt_p.h new file mode 100644 index 0000000..99f9be9 --- /dev/null +++ b/drivers/net/fddi/skfp/h/smt_p.h @@ -0,0 +1,326 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * defines for all SMT attributes + */ + +/* + * this boring file was produced by perl + * thanks Larry ! + */ +#define SMT_P0012 0x0012 + +#define SMT_P0015 0x0015 +#define SMT_P0016 0x0016 +#define SMT_P0017 0x0017 +#define SMT_P0018 0x0018 +#define SMT_P0019 0x0019 + +#define SMT_P001A 0x001a +#define SMT_P001B 0x001b +#define SMT_P001C 0x001c +#define SMT_P001D 0x001d + +#define SMT_P100A 0x100a +#define SMT_P100B 0x100b +#define SMT_P100C 0x100c +#define SMT_P100D 0x100d +#define SMT_P100E 0x100e +#define SMT_P100F 0x100f +#define SMT_P1010 0x1010 +#define SMT_P1011 0x1011 +#define SMT_P1012 0x1012 +#define SMT_P1013 0x1013 +#define SMT_P1014 0x1014 +#define SMT_P1015 0x1015 +#define SMT_P1016 0x1016 +#define SMT_P1017 0x1017 +#define SMT_P1018 0x1018 +#define SMT_P1019 0x1019 +#define SMT_P101A 0x101a +#define SMT_P101B 0x101b +#define SMT_P101C 0x101c +#define SMT_P101D 0x101d +#define SMT_P101E 0x101e +#define SMT_P101F 0x101f +#define SMT_P1020 0x1020 +#define SMT_P1021 0x1021 +#define SMT_P1022 0x1022 +#define SMT_P1023 0x1023 +#define SMT_P1024 0x1024 +#define SMT_P1025 0x1025 +#define SMT_P1026 0x1026 +#define SMT_P1027 0x1027 +#define SMT_P1028 0x1028 +#define SMT_P1029 0x1029 +#define SMT_P102A 0x102a +#define SMT_P102B 0x102b +#define SMT_P102C 0x102c +#define SMT_P102D 0x102d +#define SMT_P102E 0x102e +#define SMT_P102F 0x102f +#define SMT_P1030 0x1030 +#define SMT_P1031 0x1031 +#define SMT_P1032 0x1032 +#define SMT_P1033 0x1033 +#define SMT_P1034 0x1034 +#define SMT_P1035 0x1035 +#define SMT_P1036 0x1036 +#define SMT_P1037 0x1037 +#define SMT_P1038 0x1038 +#define SMT_P1039 0x1039 +#define SMT_P103A 0x103a +#define SMT_P103B 0x103b +#define SMT_P103C 0x103c +#define SMT_P103D 0x103d +#define SMT_P103E 0x103e +#define SMT_P103F 0x103f +#define SMT_P1040 0x1040 +#define SMT_P1041 0x1041 +#define SMT_P1042 0x1042 +#define SMT_P1043 0x1043 +#define SMT_P1044 0x1044 +#define SMT_P1045 0x1045 +#define SMT_P1046 0x1046 +#define SMT_P1047 0x1047 +#define SMT_P1048 0x1048 +#define SMT_P1049 0x1049 +#define SMT_P104A 0x104a +#define SMT_P104B 0x104b +#define SMT_P104C 0x104c +#define SMT_P104D 0x104d +#define SMT_P104E 0x104e +#define SMT_P104F 0x104f +#define SMT_P1050 0x1050 +#define SMT_P1051 0x1051 +#define SMT_P1052 0x1052 +#define SMT_P1053 0x1053 +#define SMT_P1054 0x1054 + +#define SMT_P10F0 0x10f0 +#define SMT_P10F1 0x10f1 +#ifdef ESS +#define SMT_P10F2 0x10f2 +#define SMT_P10F3 0x10f3 +#define SMT_P10F4 0x10f4 +#define SMT_P10F5 0x10f5 +#define SMT_P10F6 0x10f6 +#define SMT_P10F7 0x10f7 +#endif +#ifdef SBA +#define SMT_P10F8 0x10f8 +#define SMT_P10F9 0x10f9 +#endif + +#define SMT_P200A 0x200a +#define SMT_P200B 0x200b +#define SMT_P200C 0x200c +#define SMT_P200D 0x200d +#define SMT_P200E 0x200e +#define SMT_P200F 0x200f +#define SMT_P2010 0x2010 +#define SMT_P2011 0x2011 +#define SMT_P2012 0x2012 +#define SMT_P2013 0x2013 +#define SMT_P2014 0x2014 +#define SMT_P2015 0x2015 +#define SMT_P2016 0x2016 +#define SMT_P2017 0x2017 +#define SMT_P2018 0x2018 +#define SMT_P2019 0x2019 +#define SMT_P201A 0x201a +#define SMT_P201B 0x201b +#define SMT_P201C 0x201c +#define SMT_P201D 0x201d +#define SMT_P201E 0x201e +#define SMT_P201F 0x201f +#define SMT_P2020 0x2020 +#define SMT_P2021 0x2021 +#define SMT_P2022 0x2022 +#define SMT_P2023 0x2023 +#define SMT_P2024 0x2024 +#define SMT_P2025 0x2025 +#define SMT_P2026 0x2026 +#define SMT_P2027 0x2027 +#define SMT_P2028 0x2028 +#define SMT_P2029 0x2029 +#define SMT_P202A 0x202a +#define SMT_P202B 0x202b +#define SMT_P202C 0x202c +#define SMT_P202D 0x202d +#define SMT_P202E 0x202e +#define SMT_P202F 0x202f +#define SMT_P2030 0x2030 +#define SMT_P2031 0x2031 +#define SMT_P2032 0x2032 +#define SMT_P2033 0x2033 +#define SMT_P2034 0x2034 +#define SMT_P2035 0x2035 +#define SMT_P2036 0x2036 +#define SMT_P2037 0x2037 +#define SMT_P2038 0x2038 +#define SMT_P2039 0x2039 +#define SMT_P203A 0x203a +#define SMT_P203B 0x203b +#define SMT_P203C 0x203c +#define SMT_P203D 0x203d +#define SMT_P203E 0x203e +#define SMT_P203F 0x203f +#define SMT_P2040 0x2040 +#define SMT_P2041 0x2041 +#define SMT_P2042 0x2042 +#define SMT_P2043 0x2043 +#define SMT_P2044 0x2044 +#define SMT_P2045 0x2045 +#define SMT_P2046 0x2046 +#define SMT_P2047 0x2047 +#define SMT_P2048 0x2048 +#define SMT_P2049 0x2049 +#define SMT_P204A 0x204a +#define SMT_P204B 0x204b +#define SMT_P204C 0x204c +#define SMT_P204D 0x204d +#define SMT_P204E 0x204e +#define SMT_P204F 0x204f +#define SMT_P2050 0x2050 +#define SMT_P2051 0x2051 +#define SMT_P2052 0x2052 +#define SMT_P2053 0x2053 +#define SMT_P2054 0x2054 +#define SMT_P2055 0x2055 +#define SMT_P2056 0x2056 +#define SMT_P2057 0x2057 +#define SMT_P2058 0x2058 +#define SMT_P2059 0x2059 +#define SMT_P205A 0x205a +#define SMT_P205B 0x205b +#define SMT_P205C 0x205c +#define SMT_P205D 0x205d +#define SMT_P205E 0x205e +#define SMT_P205F 0x205f +#define SMT_P2060 0x2060 +#define SMT_P2061 0x2061 +#define SMT_P2062 0x2062 +#define SMT_P2063 0x2063 +#define SMT_P2064 0x2064 +#define SMT_P2065 0x2065 +#define SMT_P2066 0x2066 +#define SMT_P2067 0x2067 +#define SMT_P2068 0x2068 +#define SMT_P2069 0x2069 +#define SMT_P206A 0x206a +#define SMT_P206B 0x206b +#define SMT_P206C 0x206c +#define SMT_P206D 0x206d +#define SMT_P206E 0x206e +#define SMT_P206F 0x206f +#define SMT_P2070 0x2070 +#define SMT_P2071 0x2071 +#define SMT_P2072 0x2072 +#define SMT_P2073 0x2073 +#define SMT_P2074 0x2074 +#define SMT_P2075 0x2075 +#define SMT_P2076 0x2076 + +#define SMT_P208C 0x208c +#define SMT_P208D 0x208d +#define SMT_P208E 0x208e +#define SMT_P208F 0x208f +#define SMT_P2090 0x2090 + +#define SMT_P20F0 0x20F0 +#define SMT_P20F1 0x20F1 + +#define SMT_P320A 0x320a +#define SMT_P320B 0x320b +#define SMT_P320C 0x320c +#define SMT_P320D 0x320d +#define SMT_P320E 0x320e +#define SMT_P320F 0x320f +#define SMT_P3210 0x3210 +#define SMT_P3211 0x3211 +#define SMT_P3212 0x3212 +#define SMT_P3213 0x3213 +#define SMT_P3214 0x3214 +#define SMT_P3215 0x3215 +#define SMT_P3216 0x3216 +#define SMT_P3217 0x3217 + +#define SMT_P400A 0x400a +#define SMT_P400B 0x400b +#define SMT_P400C 0x400c +#define SMT_P400D 0x400d +#define SMT_P400E 0x400e +#define SMT_P400F 0x400f +#define SMT_P4010 0x4010 +#define SMT_P4011 0x4011 +#define SMT_P4012 0x4012 +#define SMT_P4013 0x4013 +#define SMT_P4014 0x4014 +#define SMT_P4015 0x4015 +#define SMT_P4016 0x4016 +#define SMT_P4017 0x4017 +#define SMT_P4018 0x4018 +#define SMT_P4019 0x4019 +#define SMT_P401A 0x401a +#define SMT_P401B 0x401b +#define SMT_P401C 0x401c +#define SMT_P401D 0x401d +#define SMT_P401E 0x401e +#define SMT_P401F 0x401f +#define SMT_P4020 0x4020 +#define SMT_P4021 0x4021 +#define SMT_P4022 0x4022 +#define SMT_P4023 0x4023 +#define SMT_P4024 0x4024 +#define SMT_P4025 0x4025 +#define SMT_P4026 0x4026 +#define SMT_P4027 0x4027 +#define SMT_P4028 0x4028 +#define SMT_P4029 0x4029 +#define SMT_P402A 0x402a +#define SMT_P402B 0x402b +#define SMT_P402C 0x402c +#define SMT_P402D 0x402d +#define SMT_P402E 0x402e +#define SMT_P402F 0x402f +#define SMT_P4030 0x4030 +#define SMT_P4031 0x4031 +#define SMT_P4032 0x4032 +#define SMT_P4033 0x4033 +#define SMT_P4034 0x4034 +#define SMT_P4035 0x4035 +#define SMT_P4036 0x4036 +#define SMT_P4037 0x4037 +#define SMT_P4038 0x4038 +#define SMT_P4039 0x4039 +#define SMT_P403A 0x403a +#define SMT_P403B 0x403b +#define SMT_P403C 0x403c +#define SMT_P403D 0x403d +#define SMT_P403E 0x403e +#define SMT_P403F 0x403f +#define SMT_P4040 0x4040 +#define SMT_P4041 0x4041 +#define SMT_P4042 0x4042 +#define SMT_P4043 0x4043 +#define SMT_P4044 0x4044 +#define SMT_P4045 0x4045 +#define SMT_P4046 0x4046 + +#define SMT_P4050 0x4050 +#define SMT_P4051 0x4051 +#define SMT_P4052 0x4052 +#define SMT_P4053 0x4053 diff --git a/drivers/net/fddi/skfp/h/smtstate.h b/drivers/net/fddi/skfp/h/smtstate.h new file mode 100644 index 0000000..62fe695 --- /dev/null +++ b/drivers/net/fddi/skfp/h/smtstate.h @@ -0,0 +1,106 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _SKFP_H_SMTSTATE_H_ +#define _SKFP_H_SMTSTATE_H_ + +/* + * SMT state definitions + */ + +#ifndef KERNEL +/* + * PCM states + */ +#define PC0_OFF 0 +#define PC1_BREAK 1 +#define PC2_TRACE 2 +#define PC3_CONNECT 3 +#define PC4_NEXT 4 +#define PC5_SIGNAL 5 +#define PC6_JOIN 6 +#define PC7_VERIFY 7 +#define PC8_ACTIVE 8 +#define PC9_MAINT 9 + +/* + * PCM modes + */ +#define PM_NONE 0 +#define PM_PEER 1 +#define PM_TREE 2 + +/* + * PCM type + */ +#define TA 0 +#define TB 1 +#define TS 2 +#define TM 3 +#define TNONE 4 + +/* + * CFM states + */ +#define SC0_ISOLATED 0 /* isolated */ +#define SC1_WRAP_A 5 /* wrap A */ +#define SC2_WRAP_B 6 /* wrap B */ +#define SC4_THRU_A 12 /* through A */ +#define SC5_THRU_B 7 /* through B (SMt 6.2) */ +#define SC7_WRAP_S 8 /* SAS */ + +/* + * ECM states + */ +#define EC0_OUT 0 +#define EC1_IN 1 +#define EC2_TRACE 2 +#define EC3_LEAVE 3 +#define EC4_PATH_TEST 4 +#define EC5_INSERT 5 +#define EC6_CHECK 6 +#define EC7_DEINSERT 7 + +/* + * RMT states + */ +#define RM0_ISOLATED 0 +#define RM1_NON_OP 1 /* not operational */ +#define RM2_RING_OP 2 /* ring operational */ +#define RM3_DETECT 3 /* detect dupl addresses */ +#define RM4_NON_OP_DUP 4 /* dupl. addr detected */ +#define RM5_RING_OP_DUP 5 /* ring oper. with dupl. addr */ +#define RM6_DIRECTED 6 /* sending directed beacons */ +#define RM7_TRACE 7 /* trace initiated */ +#endif + +struct pcm_state { + unsigned char pcm_type ; /* TA TB TS TM */ + unsigned char pcm_state ; /* state PC[0-9]_* */ + unsigned char pcm_mode ; /* PM_{NONE,PEER,TREE} */ + unsigned char pcm_neighbor ; /* TA TB TS TM */ + unsigned char pcm_bsf ; /* flag bs : TRUE/FALSE */ + unsigned char pcm_lsf ; /* flag ls : TRUE/FALSE */ + unsigned char pcm_lct_fail ; /* counter lct_fail */ + unsigned char pcm_ls_rx ; /* rx line state */ + short pcm_r_val ; /* signaling bits */ + short pcm_t_val ; /* signaling bits */ +} ; + +struct smt_state { + struct pcm_state pcm_state[NUMPHYS] ; /* port A & port B */ +} ; + +#endif + diff --git a/drivers/net/fddi/skfp/h/supern_2.h b/drivers/net/fddi/skfp/h/supern_2.h new file mode 100644 index 0000000..0b73690 --- /dev/null +++ b/drivers/net/fddi/skfp/h/supern_2.h @@ -0,0 +1,1059 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + defines for AMD Supernet II chip set + the chips are referred to as + FPLUS Formac Plus + PLC Physical Layer + + added defines for AMD Supernet III chip set + added comments on differences between Supernet II and Supernet III + added defines for the Motorola ELM (MOT_ELM) +*/ + +#ifndef _SUPERNET_ +#define _SUPERNET_ + +/* + * Define Supernet 3 when used + */ +#ifdef PCI +#ifndef SUPERNET_3 +#define SUPERNET_3 +#endif +#define TAG +#endif + +#define MB 0xff +#define MW 0xffff +#define MD 0xffffffff + +/* + * FORMAC frame status (rx_msext) + */ +#define FS_EI (1<<2) +#define FS_AI (1<<1) +#define FS_CI (1<<0) + +#define FS_MSVALID (1<<15) /* end of queue */ +#define FS_MSRABT (1<<14) /* frame was aborted during reception*/ +#define FS_SSRCRTG (1<<12) /* if SA has set MSB (source-routing)*/ +#define FS_SEAC2 (FS_EI<<9) /* error indicator */ +#define FS_SEAC1 (FS_AI<<9) /* address indicator */ +#define FS_SEAC0 (FS_CI<<9) /* copy indicator */ +#define FS_SFRMERR (1<<8) /* error detected (CRC or length) */ +#define FS_SADRRG (1<<7) /* address recognized */ +#define FS_SFRMTY2 (1<<6) /* frame-class bit */ +#define FS_SFRMTY1 (1<<5) /* frame-type bit (impementor) */ +#define FS_SFRMTY0 (1<<4) /* frame-type bit (LLC) */ +#define FS_ERFBB1 (1<<1) /* byte offset (depends on LSB bit) */ +#define FS_ERFBB0 (1<<0) /* - " - */ + +/* + * status frame type + */ +#define FRM_SMT (0) /* asynchr. frames */ +#define FRM_LLCA (1) +#define FRM_IMPA (2) +#define FRM_MAC (4) /* synchr. frames */ +#define FRM_LLCS (5) +#define FRM_IMPS (6) + +/* + * bits in rx_descr.i (receive frame status word) + */ +#define RX_MSVALID ((long)1<<31) /* memory status valid */ +#define RX_MSRABT ((long)1<<30) /* memory status receive abort */ +#define RX_FS_E ((long)FS_SEAC2<<16) /* error indicator */ +#define RX_FS_A ((long)FS_SEAC1<<16) /* address indicator */ +#define RX_FS_C ((long)FS_SEAC0<<16) /* copy indicator */ +#define RX_FS_CRC ((long)FS_SFRMERR<<16)/* error detected */ +#define RX_FS_ADDRESS ((long)FS_SADRRG<<16) /* address recognized */ +#define RX_FS_MAC ((long)FS_SFRMTY2<<16)/* MAC frame */ +#define RX_FS_SMT ((long)0<<16) /* SMT frame */ +#define RX_FS_IMPL ((long)FS_SFRMTY1<<16)/* implementer frame */ +#define RX_FS_LLC ((long)FS_SFRMTY0<<16)/* LLC frame */ + +/* + * receive frame descriptor + */ +union rx_descr { + struct { +#ifdef LITTLE_ENDIAN + unsigned rx_length :16 ; /* frame length lower/upper byte */ + unsigned rx_erfbb :2 ; /* received frame byte boundary */ + unsigned rx_reserv2:2 ; /* reserved */ + unsigned rx_sfrmty :3 ; /* frame type bits */ + unsigned rx_sadrrg :1 ; /* DA == MA or broad-/multicast */ + unsigned rx_sfrmerr:1 ; /* received frame not valid */ + unsigned rx_seac0 :1 ; /* frame-copied C-indicator */ + unsigned rx_seac1 :1 ; /* address-match A-indicator */ + unsigned rx_seac2 :1 ; /* frame-error E-indicator */ + unsigned rx_ssrcrtg:1 ; /* == 1 SA has MSB set */ + unsigned rx_reserv1:1 ; /* reserved */ + unsigned rx_msrabt :1 ; /* memory status receive abort */ + unsigned rx_msvalid:1 ; /* memory status valid */ +#else + unsigned rx_msvalid:1 ; /* memory status valid */ + unsigned rx_msrabt :1 ; /* memory status receive abort */ + unsigned rx_reserv1:1 ; /* reserved */ + unsigned rx_ssrcrtg:1 ; /* == 1 SA has MSB set */ + unsigned rx_seac2 :1 ; /* frame-error E-indicator */ + unsigned rx_seac1 :1 ; /* address-match A-indicator */ + unsigned rx_seac0 :1 ; /* frame-copied C-indicator */ + unsigned rx_sfrmerr:1 ; /* received frame not valid */ + unsigned rx_sadrrg :1 ; /* DA == MA or broad-/multicast */ + unsigned rx_sfrmty :3 ; /* frame type bits */ + unsigned rx_erfbb :2 ; /* received frame byte boundary */ + unsigned rx_reserv2:2 ; /* reserved */ + unsigned rx_length :16 ; /* frame length lower/upper byte */ +#endif + } r ; + long i ; +} ; + +/* defines for Receive Frame Descriptor access */ +#define RD_S_ERFBB 0x00030000L /* received frame byte boundary */ +#define RD_S_RES2 0x000c0000L /* reserved */ +#define RD_S_SFRMTY 0x00700000L /* frame type bits */ +#define RD_S_SADRRG 0x00800000L /* DA == MA or broad-/multicast */ +#define RD_S_SFRMERR 0x01000000L /* received frame not valid */ +#define RD_S_SEAC 0x0e000000L /* frame status indicators */ +#define RD_S_SEAC0 0x02000000L /* frame-copied case-indicator */ +#define RD_S_SEAC1 0x04000000L /* address-match A-indicator */ +#define RD_S_SEAC2 0x08000000L /* frame-error E-indicator */ +#define RD_S_SSRCRTG 0x10000000L /* == 1 SA has MSB set */ +#define RD_S_RES1 0x20000000L /* reserved */ +#define RD_S_MSRABT 0x40000000L /* memory status receive abort */ +#define RD_S_MSVALID 0x80000000L /* memory status valid */ + +#define RD_STATUS 0xffff0000L +#define RD_LENGTH 0x0000ffffL + +/* defines for Receive Frames Status Word values */ +/*RD_S_SFRMTY*/ +#define RD_FRM_SMT (unsigned long)(0<<20) /* asynchr. frames */ +#define RD_FRM_LLCA (unsigned long)(1<<20) +#define RD_FRM_IMPA (unsigned long)(2<<20) +#define RD_FRM_MAC (unsigned long)(4<<20) /* synchr. frames */ +#define RD_FRM_LLCS (unsigned long)(5<<20) +#define RD_FRM_IMPS (unsigned long)(6<<20) + +#define TX_DESCRIPTOR 0x40000000L +#define TX_OFFSET_3 0x18000000L + +#define TXP1 2 + +/* + * transmit frame descriptor + */ +union tx_descr { + struct { +#ifdef LITTLE_ENDIAN + unsigned tx_length:16 ; /* frame length lower/upper byte */ + unsigned tx_res :8 ; /* reserved (bit 16..23) */ + unsigned tx_xmtabt:1 ; /* transmit abort */ + unsigned tx_nfcs :1 ; /* no frame check sequence */ + unsigned tx_xdone :1 ; /* give up token */ + unsigned tx_rpxm :2 ; /* byte offset */ + unsigned tx_pat1 :2 ; /* must be TXP1 */ + unsigned tx_more :1 ; /* more frame in chain */ +#else + unsigned tx_more :1 ; /* more frame in chain */ + unsigned tx_pat1 :2 ; /* must be TXP1 */ + unsigned tx_rpxm :2 ; /* byte offset */ + unsigned tx_xdone :1 ; /* give up token */ + unsigned tx_nfcs :1 ; /* no frame check sequence */ + unsigned tx_xmtabt:1 ; /* transmit abort */ + unsigned tx_res :8 ; /* reserved (bit 16..23) */ + unsigned tx_length:16 ; /* frame length lower/upper byte */ +#endif + } t ; + long i ; +} ; + +/* defines for Transmit Descriptor access */ +#define TD_C_MORE 0x80000000L /* more frame in chain */ +#define TD_C_DESCR 0x60000000L /* must be TXP1 */ +#define TD_C_TXFBB 0x18000000L /* byte offset */ +#define TD_C_XDONE 0x04000000L /* give up token */ +#define TD_C_NFCS 0x02000000L /* no frame check sequence */ +#define TD_C_XMTABT 0x01000000L /* transmit abort */ + +#define TD_C_LNCNU 0x0000ff00L +#define TD_C_LNCNL 0x000000ffL +#define TD_C_LNCN 0x0000ffffL /* frame length lower/upper byte */ + +/* + * transmit pointer + */ +union tx_pointer { + struct t { +#ifdef LITTLE_ENDIAN + unsigned tp_pointer:16 ; /* pointer to tx_descr (low/high) */ + unsigned tp_res :8 ; /* reserved (bit 16..23) */ + unsigned tp_pattern:8 ; /* fixed pattern (bit 24..31) */ +#else + unsigned tp_pattern:8 ; /* fixed pattern (bit 24..31) */ + unsigned tp_res :8 ; /* reserved (bit 16..23) */ + unsigned tp_pointer:16 ; /* pointer to tx_descr (low/high) */ +#endif + } t ; + long i ; +} ; + +/* defines for Nontag Mode Pointer access */ +#define TD_P_CNTRL 0xff000000L +#define TD_P_RPXU 0x0000ff00L +#define TD_P_RPXL 0x000000ffL +#define TD_P_RPX 0x0000ffffL + + +#define TX_PATTERN 0xa0 +#define TX_POINTER_END 0xa0000000L +#define TX_INT_PATTERN 0xa0000000L + +struct tx_queue { + struct tx_queue *tq_next ; + u_short tq_pack_offset ; /* offset buffer memory */ + u_char tq_pad[2] ; +} ; + +/* + defines for FORMAC Plus (Am79C830) +*/ + +/* + * FORMAC+ read/write (r/w) registers + */ +#define FM_CMDREG1 0x00 /* write command reg 1 instruction */ +#define FM_CMDREG2 0x01 /* write command reg 2 instruction */ +#define FM_ST1U 0x00 /* read upper 16-bit of status reg 1 */ +#define FM_ST1L 0x01 /* read lower 16-bit of status reg 1 */ +#define FM_ST2U 0x02 /* read upper 16-bit of status reg 2 */ +#define FM_ST2L 0x03 /* read lower 16-bit of status reg 2 */ +#define FM_IMSK1U 0x04 /* r/w upper 16-bit of IMSK 1 */ +#define FM_IMSK1L 0x05 /* r/w lower 16-bit of IMSK 1 */ +#define FM_IMSK2U 0x06 /* r/w upper 16-bit of IMSK 2 */ +#define FM_IMSK2L 0x07 /* r/w lower 16-bit of IMSK 2 */ +#define FM_SAID 0x08 /* r/w short addr.-individual */ +#define FM_LAIM 0x09 /* r/w long addr.-ind. (MSW of LAID) */ +#define FM_LAIC 0x0a /* r/w long addr.-ind. (middle)*/ +#define FM_LAIL 0x0b /* r/w long addr.-ind. (LSW) */ +#define FM_SAGP 0x0c /* r/w short address-group */ +#define FM_LAGM 0x0d /* r/w long addr.-gr. (MSW of LAGP) */ +#define FM_LAGC 0x0e /* r/w long addr.-gr. (middle) */ +#define FM_LAGL 0x0f /* r/w long addr.-gr. (LSW) */ +#define FM_MDREG1 0x10 /* r/w 16-bit mode reg 1 */ +#define FM_STMCHN 0x11 /* read state-machine reg */ +#define FM_MIR1 0x12 /* read upper 16-bit of MAC Info Reg */ +#define FM_MIR0 0x13 /* read lower 16-bit of MAC Info Reg */ +#define FM_TMAX 0x14 /* r/w 16-bit TMAX reg */ +#define FM_TVX 0x15 /* write 8-bit TVX reg with NP7-0 + read TVX on NP7-0, timer on NP15-8*/ +#define FM_TRT 0x16 /* r/w upper 16-bit of TRT timer */ +#define FM_THT 0x17 /* r/w upper 16-bit of THT timer */ +#define FM_TNEG 0x18 /* read upper 16-bit of TNEG (TTRT) */ +#define FM_TMRS 0x19 /* read lower 5-bit of TNEG,TRT,THT */ + /* F E D C B A 9 8 7 6 5 4 3 2 1 0 + x |-TNEG4-0| |-TRT4-0-| |-THT4-0-| (x-late count) */ +#define FM_TREQ0 0x1a /* r/w 16-bit TREQ0 reg (LSW of TRT) */ +#define FM_TREQ1 0x1b /* r/w 16-bit TREQ1 reg (MSW of TRT) */ +#define FM_PRI0 0x1c /* r/w priority r. for asyn.-queue 0 */ +#define FM_PRI1 0x1d /* r/w priority r. for asyn.-queue 1 */ +#define FM_PRI2 0x1e /* r/w priority r. for asyn.-queue 2 */ +#define FM_TSYNC 0x1f /* r/w 16-bit of the TSYNC register */ +#define FM_MDREG2 0x20 /* r/w 16-bit mode reg 2 */ +#define FM_FRMTHR 0x21 /* r/w the frame threshold register */ +#define FM_EACB 0x22 /* r/w end addr of claim/beacon area */ +#define FM_EARV 0x23 /* r/w end addr of receive queue */ +/* Supernet 3 */ +#define FM_EARV1 FM_EARV + +#define FM_EAS 0x24 /* r/w end addr of synchr. queue */ +#define FM_EAA0 0x25 /* r/w end addr of asyn. queue 0 */ +#define FM_EAA1 0x26 /* r/w end addr of asyn. queue 1 */ +#define FM_EAA2 0x27 /* r/w end addr of asyn. queue 2 */ +#define FM_SACL 0x28 /* r/w start addr of claim frame */ +#define FM_SABC 0x29 /* r/w start addr of beacon frame */ +#define FM_WPXSF 0x2a /* r/w the write ptr. for special fr.*/ +#define FM_RPXSF 0x2b /* r/w the read ptr. for special fr. */ +#define FM_RPR 0x2d /* r/w the read ptr. for receive qu. */ +#define FM_WPR 0x2e /* r/w the write ptr. for receive qu.*/ +#define FM_SWPR 0x2f /* r/w the shadow wr.-ptr. for rec.q.*/ +/* Supernet 3 */ +#define FM_RPR1 FM_RPR +#define FM_WPR1 FM_WPR +#define FM_SWPR1 FM_SWPR + +#define FM_WPXS 0x30 /* r/w the write ptr. for synchr. qu.*/ +#define FM_WPXA0 0x31 /* r/w the write ptr. for asyn. qu.0 */ +#define FM_WPXA1 0x32 /* r/w the write ptr. for asyn. qu.1 */ +#define FM_WPXA2 0x33 /* r/w the write ptr. for asyn. qu.2 */ +#define FM_SWPXS 0x34 /* r/w the shadow wr.-ptr. for syn.q.*/ +#define FM_SWPXA0 0x35 /* r/w the shad. wr.-ptr. for asyn.q0*/ +#define FM_SWPXA1 0x36 /* r/w the shad. wr.-ptr. for asyn.q1*/ +#define FM_SWPXA2 0x37 /* r/w the shad. wr.-ptr. for asyn.q2*/ +#define FM_RPXS 0x38 /* r/w the read ptr. for synchr. qu. */ +#define FM_RPXA0 0x39 /* r/w the read ptr. for asyn. qu. 0 */ +#define FM_RPXA1 0x3a /* r/w the read ptr. for asyn. qu. 1 */ +#define FM_RPXA2 0x3b /* r/w the read ptr. for asyn. qu. 2 */ +#define FM_MARR 0x3c /* r/w the memory read addr register */ +#define FM_MARW 0x3d /* r/w the memory write addr register*/ +#define FM_MDRU 0x3e /* r/w upper 16-bit of mem. data reg */ +#define FM_MDRL 0x3f /* r/w lower 16-bit of mem. data reg */ + +/* following instructions relate to MAC counters and timer */ +#define FM_TMSYNC 0x40 /* r/w upper 16 bits of TMSYNC timer */ +#define FM_FCNTR 0x41 /* r/w the 16-bit frame counter */ +#define FM_LCNTR 0x42 /* r/w the 16-bit lost counter */ +#define FM_ECNTR 0x43 /* r/w the 16-bit error counter */ + +/* Supernet 3: extensions to old register block */ +#define FM_FSCNTR 0x44 /* r/? Frame Strip Counter */ +#define FM_FRSELREG 0x45 /* r/w Frame Selection Register */ + +/* Supernet 3: extensions for 2. receive queue etc. */ +#define FM_MDREG3 0x60 /* r/w Mode Register 3 */ +#define FM_ST3U 0x61 /* read upper 16-bit of status reg 3 */ +#define FM_ST3L 0x62 /* read lower 16-bit of status reg 3 */ +#define FM_IMSK3U 0x63 /* r/w upper 16-bit of IMSK reg 3 */ +#define FM_IMSK3L 0x64 /* r/w lower 16-bit of IMSK reg 3 */ +#define FM_IVR 0x65 /* read Interrupt Vector register */ +#define FM_IMR 0x66 /* r/w Interrupt mask register */ +/* 0x67 Hidden */ +#define FM_RPR2 0x68 /* r/w the read ptr. for rec. qu. 2 */ +#define FM_WPR2 0x69 /* r/w the write ptr. for rec. qu. 2 */ +#define FM_SWPR2 0x6a /* r/w the shadow wptr. for rec. q. 2 */ +#define FM_EARV2 0x6b /* r/w end addr of rec. qu. 2 */ +#define FM_UNLCKDLY 0x6c /* r/w Auto Unlock Delay register */ + /* Bit 15-8: RECV2 unlock threshold */ + /* Bit 7-0: RECV1 unlock threshold */ +/* 0x6f-0x73 Hidden */ +#define FM_LTDPA1 0x79 /* r/w Last Trans desc ptr for A1 qu. */ +/* 0x80-0x9a PLCS registers of built-in PLCS (Supernet 3 only) */ + +/* Supernet 3: Adderss Filter Registers */ +#define FM_AFCMD 0xb0 /* r/w Address Filter Command Reg */ +#define FM_AFSTAT 0xb2 /* r/w Address Filter Status Reg */ +#define FM_AFBIST 0xb4 /* r/w Address Filter BIST signature */ +#define FM_AFCOMP2 0xb6 /* r/w Address Filter Comparand 2 */ +#define FM_AFCOMP1 0xb8 /* r/w Address Filter Comparand 1 */ +#define FM_AFCOMP0 0xba /* r/w Address Filter Comparand 0 */ +#define FM_AFMASK2 0xbc /* r/w Address Filter Mask 2 */ +#define FM_AFMASK1 0xbe /* r/w Address Filter Mask 1 */ +#define FM_AFMASK0 0xc0 /* r/w Address Filter Mask 0 */ +#define FM_AFPERS 0xc2 /* r/w Address Filter Personality Reg */ + +/* Supernet 3: Orion (PDX?) Registers */ +#define FM_ORBIST 0xd0 /* r/w Orion BIST signature */ +#define FM_ORSTAT 0xd2 /* r/w Orion Status Register */ + + +/* + * Mode Register 1 (MDREG1) + */ +#define FM_RES0 0x0001 /* reserved */ + /* SN3: other definition */ +#define FM_XMTINH_HOLD 0x0002 /* transmit-inhibit/hold bit */ + /* SN3: other definition */ +#define FM_HOFLXI 0x0003 /* SN3: Hold / Flush / Inhibit */ +#define FM_FULL_HALF 0x0004 /* full-duplex/half-duplex bit */ +#define FM_LOCKTX 0x0008 /* lock-transmit-asynchr.-queues bit */ +#define FM_EXGPA0 0x0010 /* extended-group-addressing bit 0 */ +#define FM_EXGPA1 0x0020 /* extended-group-addressing bit 1 */ +#define FM_DISCRY 0x0040 /* disable-carry bit */ + /* SN3: reserved */ +#define FM_SELRA 0x0080 /* select input from PHY (1=RA,0=RB) */ + +#define FM_ADDET 0x0700 /* address detection */ +#define FM_MDAMA (0<<8) /* address detection : DA = MA */ +#define FM_MDASAMA (1<<8) /* address detection : DA=MA||SA=MA */ +#define FM_MRNNSAFNMA (2<<8) /* rec. non-NSA frames DA=MA&&SA!=MA */ +#define FM_MRNNSAF (3<<8) /* rec. non-NSA frames DA = MA */ +#define FM_MDISRCV (4<<8) /* disable receive function */ +#define FM_MRES0 (5<<8) /* reserve */ +#define FM_MLIMPROM (6<<8) /* limited-promiscuous mode */ +#define FM_MPROMISCOUS (7<<8) /* address detection : promiscuous */ + +#define FM_SELSA 0x0800 /* select-short-address bit */ + +#define FM_MMODE 0x7000 /* mode select */ +#define FM_MINIT (0<<12) /* initialize */ +#define FM_MMEMACT (1<<12) /* memory activate */ +#define FM_MONLINESP (2<<12) /* on-line special */ +#define FM_MONLINE (3<<12) /* on-line (FDDI operational mode) */ +#define FM_MILOOP (4<<12) /* internal loopback */ +#define FM_MRES1 (5<<12) /* reserved */ +#define FM_MRES2 (6<<12) /* reserved */ +#define FM_MELOOP (7<<12) /* external loopback */ + +#define FM_SNGLFRM 0x8000 /* single-frame-receive mode */ + /* SN3: reserved */ + +#define MDR1INIT (FM_MINIT | FM_MDAMA) + +/* + * Mode Register 2 (MDREG2) + */ +#define FM_AFULL 0x000f /* 4-bit value (empty loc.in txqueue)*/ +#define FM_RCVERR 0x0010 /* rec.-errored-frames bit */ +#define FM_SYMCTL 0x0020 /* sysmbol-control bit */ + /* SN3: reserved */ +#define FM_SYNPRQ 0x0040 /* synchron.-NP-DMA-request bit */ +#define FM_ENNPRQ 0x0080 /* enable-NP-DMA-request bit */ +#define FM_ENHSRQ 0x0100 /* enable-host-request bit */ +#define FM_RXFBB01 0x0600 /* rec. frame byte boundary bit0 & 1 */ +#define FM_LSB 0x0800 /* determ. ordering of bytes in buffer*/ +#define FM_PARITY 0x1000 /* 1 = even, 0 = odd */ +#define FM_CHKPAR 0x2000 /* 1 = parity of 32-bit buffer BD-bus*/ +#define FM_STRPFCS 0x4000 /* 1 = strips FCS field of rec.frame */ +#define FM_BMMODE 0x8000 /* Buffer-Memory-Mode (1 = tag mode) */ + /* SN3: 1 = tag, 0 = modified tag */ + +/* + * Status Register 1, Upper 16 Bits (ST1U) + */ +#define FM_STEFRMS 0x0001 /* transmit end of frame: synchr. qu.*/ +#define FM_STEFRMA0 0x0002 /* transmit end of frame: asyn. qu.0 */ +#define FM_STEFRMA1 0x0004 /* transmit end of frame: asyn. qu.1 */ +#define FM_STEFRMA2 0x0008 /* transmit end of frame: asyn. qu.2 */ + /* SN3: reserved */ +#define FM_STECFRMS 0x0010 /* transmit end of chain of syn. qu. */ + /* SN3: reserved */ +#define FM_STECFRMA0 0x0020 /* transmit end of chain of asyn. q0 */ + /* SN3: reserved */ +#define FM_STECFRMA1 0x0040 /* transmit end of chain of asyn. q1 */ + /* SN3: STECMDA1 */ +#define FM_STECMDA1 0x0040 /* SN3: 'no description' */ +#define FM_STECFRMA2 0x0080 /* transmit end of chain of asyn. q2 */ + /* SN3: reserved */ +#define FM_STEXDONS 0x0100 /* transmit until XDONE in syn. qu. */ +#define FM_STBFLA 0x0200 /* asynchr.-queue trans. buffer full */ +#define FM_STBFLS 0x0400 /* synchr.-queue transm. buffer full */ +#define FM_STXABRS 0x0800 /* synchr. queue transmit-abort */ +#define FM_STXABRA0 0x1000 /* asynchr. queue 0 transmit-abort */ +#define FM_STXABRA1 0x2000 /* asynchr. queue 1 transmit-abort */ +#define FM_STXABRA2 0x4000 /* asynchr. queue 2 transmit-abort */ + /* SN3: reserved */ +#define FM_SXMTABT 0x8000 /* transmit abort */ + +/* + * Status Register 1, Lower 16 Bits (ST1L) + */ +#define FM_SQLCKS 0x0001 /* queue lock for synchr. queue */ +#define FM_SQLCKA0 0x0002 /* queue lock for asynchr. queue 0 */ +#define FM_SQLCKA1 0x0004 /* queue lock for asynchr. queue 1 */ +#define FM_SQLCKA2 0x0008 /* queue lock for asynchr. queue 2 */ + /* SN3: reserved */ +#define FM_STXINFLS 0x0010 /* transmit instruction full: syn. */ + /* SN3: reserved */ +#define FM_STXINFLA0 0x0020 /* transmit instruction full: asyn.0 */ + /* SN3: reserved */ +#define FM_STXINFLA1 0x0040 /* transmit instruction full: asyn.1 */ + /* SN3: reserved */ +#define FM_STXINFLA2 0x0080 /* transmit instruction full: asyn.2 */ + /* SN3: reserved */ +#define FM_SPCEPDS 0x0100 /* parity/coding error: syn. queue */ +#define FM_SPCEPDA0 0x0200 /* parity/coding error: asyn. queue0 */ +#define FM_SPCEPDA1 0x0400 /* parity/coding error: asyn. queue1 */ +#define FM_SPCEPDA2 0x0800 /* parity/coding error: asyn. queue2 */ + /* SN3: reserved */ +#define FM_STBURS 0x1000 /* transmit buffer underrun: syn. q. */ +#define FM_STBURA0 0x2000 /* transmit buffer underrun: asyn.0 */ +#define FM_STBURA1 0x4000 /* transmit buffer underrun: asyn.1 */ +#define FM_STBURA2 0x8000 /* transmit buffer underrun: asyn.2 */ + /* SN3: reserved */ + +/* + * Status Register 2, Upper 16 Bits (ST2U) + */ +#define FM_SOTRBEC 0x0001 /* other beacon received */ +#define FM_SMYBEC 0x0002 /* my beacon received */ +#define FM_SBEC 0x0004 /* beacon state entered */ +#define FM_SLOCLM 0x0008 /* low claim received */ +#define FM_SHICLM 0x0010 /* high claim received */ +#define FM_SMYCLM 0x0020 /* my claim received */ +#define FM_SCLM 0x0040 /* claim state entered */ +#define FM_SERRSF 0x0080 /* error in special frame */ +#define FM_SNFSLD 0x0100 /* NP and FORMAC+ simultaneous load */ +#define FM_SRFRCTOV 0x0200 /* receive frame counter overflow */ + /* SN3: reserved */ +#define FM_SRCVFRM 0x0400 /* receive frame */ + /* SN3: reserved */ +#define FM_SRCVOVR 0x0800 /* receive FIFO overflow */ +#define FM_SRBFL 0x1000 /* receive buffer full */ +#define FM_SRABT 0x2000 /* receive abort */ +#define FM_SRBMT 0x4000 /* receive buffer empty */ +#define FM_SRCOMP 0x8000 /* receive complete. Nontag mode */ + +/* + * Status Register 2, Lower 16 Bits (ST2L) + * Attention: SN3 docu shows these bits the other way around + */ +#define FM_SRES0 0x0001 /* reserved */ +#define FM_SESTRIPTK 0x0001 /* SN3: 'no description' */ +#define FM_STRTEXR 0x0002 /* TRT expired in claim | beacon st. */ +#define FM_SDUPCLM 0x0004 /* duplicate claim received */ +#define FM_SSIFG 0x0008 /* short interframe gap */ +#define FM_SFRMCTR 0x0010 /* frame counter overflow */ +#define FM_SERRCTR 0x0020 /* error counter overflow */ +#define FM_SLSTCTR 0x0040 /* lost counter overflow */ +#define FM_SPHINV 0x0080 /* PHY invalid */ +#define FM_SADET 0x0100 /* address detect */ +#define FM_SMISFRM 0x0200 /* missed frame */ +#define FM_STRTEXP 0x0400 /* TRT expired and late count > 0 */ +#define FM_STVXEXP 0x0800 /* TVX expired */ +#define FM_STKISS 0x1000 /* token issued */ +#define FM_STKERR 0x2000 /* token error */ +#define FM_SMULTDA 0x4000 /* multiple destination address */ +#define FM_SRNGOP 0x8000 /* ring operational */ + +/* + * Supernet 3: + * Status Register 3, Upper 16 Bits (ST3U) + */ +#define FM_SRQUNLCK1 0x0001 /* receive queue unlocked queue 1 */ +#define FM_SRQUNLCK2 0x0002 /* receive queue unlocked queue 2 */ +#define FM_SRPERRQ1 0x0004 /* receive parity error rx queue 1 */ +#define FM_SRPERRQ2 0x0008 /* receive parity error rx queue 2 */ + /* Bit 4-10: reserved */ +#define FM_SRCVOVR2 0x0800 /* receive FIFO overfull rx queue 2 */ +#define FM_SRBFL2 0x1000 /* receive buffer full rx queue 2 */ +#define FM_SRABT2 0x2000 /* receive abort rx queue 2 */ +#define FM_SRBMT2 0x4000 /* receive buf empty rx queue 2 */ +#define FM_SRCOMP2 0x8000 /* receive comp rx queue 2 */ + +/* + * Supernet 3: + * Status Register 3, Lower 16 Bits (ST3L) + */ +#define FM_AF_BIST_DONE 0x0001 /* Address Filter BIST is done */ +#define FM_PLC_BIST_DONE 0x0002 /* internal PLC Bist is done */ +#define FM_PDX_BIST_DONE 0x0004 /* PDX BIST is done */ + /* Bit 3: reserved */ +#define FM_SICAMDAMAT 0x0010 /* Status internal CAM DA match */ +#define FM_SICAMDAXACT 0x0020 /* Status internal CAM DA exact match */ +#define FM_SICAMSAMAT 0x0040 /* Status internal CAM SA match */ +#define FM_SICAMSAXACT 0x0080 /* Status internal CAM SA exact match */ + +/* + * MAC State-Machine Register FM_STMCHN + */ +#define FM_MDRTAG 0x0004 /* tag bit of long word read */ +#define FM_SNPPND 0x0008 /* r/w from buffer mem. is pending */ +#define FM_TXSTAT 0x0070 /* transmitter state machine state */ +#define FM_RCSTAT 0x0380 /* receiver state machine state */ +#define FM_TM01 0x0c00 /* indicate token mode */ +#define FM_SIM 0x1000 /* indicate send immediate-mode */ +#define FM_REV 0xe000 /* FORMAC Plus revision number */ + +/* + * Supernet 3 + * Mode Register 3 + */ +#define FM_MENRS 0x0001 /* Ena enhanced rec status encoding */ +#define FM_MENXS 0x0002 /* Ena enhanced xmit status encoding */ +#define FM_MENXCT 0x0004 /* Ena EXACT/INEXACT matching */ +#define FM_MENAFULL 0x0008 /* Ena enh QCTRL encoding for AFULL */ +#define FM_MEIND 0x0030 /* Ena enh A,C indicator settings */ +#define FM_MENQCTRL 0x0040 /* Ena enh QCTRL encoding */ +#define FM_MENRQAUNLCK 0x0080 /* Ena rec q auto unlock */ +#define FM_MENDAS 0x0100 /* Ena DAS connections by cntr MUX */ +#define FM_MENPLCCST 0x0200 /* Ena Counter Segm test in PLC blck */ +#define FM_MENSGLINT 0x0400 /* Ena Vectored Interrupt reading */ +#define FM_MENDRCV 0x0800 /* Ena dual receive queue operation */ +#define FM_MENFCLOC 0x3000 /* Ena FC location within frm data */ +#define FM_MENTRCMD 0x4000 /* Ena ASYNC1 xmit only after command */ +#define FM_MENTDLPBK 0x8000 /* Ena TDAT to RDAT lkoopback */ + +/* + * Supernet 3 + * Frame Selection Register + */ +#define FM_RECV1 0x000f /* options for receive queue 1 */ +#define FM_RCV1_ALL (0<<0) /* receive all frames */ +#define FM_RCV1_LLC (1<<0) /* rec all LLC frames */ +#define FM_RCV1_SMT (2<<0) /* rec all SMT frames */ +#define FM_RCV1_NSMT (3<<0) /* rec non-SMT frames */ +#define FM_RCV1_IMP (4<<0) /* rec Implementor frames */ +#define FM_RCV1_MAC (5<<0) /* rec all MAC frames */ +#define FM_RCV1_SLLC (6<<0) /* rec all sync LLC frames */ +#define FM_RCV1_ALLC (7<<0) /* rec all async LLC frames */ +#define FM_RCV1_VOID (8<<0) /* rec all void frames */ +#define FM_RCV1_ALSMT (9<<0) /* rec all async LLC & SMT frames */ +#define FM_RECV2 0x00f0 /* options for receive queue 2 */ +#define FM_RCV2_ALL (0<<4) /* receive all other frames */ +#define FM_RCV2_LLC (1<<4) /* rec all LLC frames */ +#define FM_RCV2_SMT (2<<4) /* rec all SMT frames */ +#define FM_RCV2_NSMT (3<<4) /* rec non-SMT frames */ +#define FM_RCV2_IMP (4<<4) /* rec Implementor frames */ +#define FM_RCV2_MAC (5<<4) /* rec all MAC frames */ +#define FM_RCV2_SLLC (6<<4) /* rec all sync LLC frames */ +#define FM_RCV2_ALLC (7<<4) /* rec all async LLC frames */ +#define FM_RCV2_VOID (8<<4) /* rec all void frames */ +#define FM_RCV2_ALSMT (9<<4) /* rec all async LLC & SMT frames */ +#define FM_ENXMTADSWAP 0x4000 /* enh rec addr swap (phys -> can) */ +#define FM_ENRCVADSWAP 0x8000 /* enh tx addr swap (can -> phys) */ + +/* + * Supernet 3: + * Address Filter Command Register (AFCMD) + */ +#define FM_INST 0x0007 /* Address Filter Operation */ +#define FM_IINV_CAM (0<<0) /* Invalidate CAM */ +#define FM_IWRITE_CAM (1<<0) /* Write CAM */ +#define FM_IREAD_CAM (2<<0) /* Read CAM */ +#define FM_IRUN_BIST (3<<0) /* Run BIST */ +#define FM_IFIND (4<<0) /* Find */ +#define FM_IINV (5<<0) /* Invalidate */ +#define FM_ISKIP (6<<0) /* Skip */ +#define FM_ICL_SKIP (7<<0) /* Clear all SKIP bits */ + +/* + * Supernet 3: + * Address Filter Status Register (AFSTAT) + */ + /* Bit 0-4: reserved */ +#define FM_REV_NO 0x00e0 /* Revision Number of Address Filter */ +#define FM_BIST_DONE 0x0100 /* BIST complete */ +#define FM_EMPTY 0x0200 /* CAM empty */ +#define FM_ERROR 0x0400 /* Error (improper operation) */ +#define FM_MULT 0x0800 /* Multiple Match */ +#define FM_EXACT 0x1000 /* Exact Match */ +#define FM_FOUND 0x2000 /* Comparand found in CAM */ +#define FM_FULL 0x4000 /* CAM full */ +#define FM_DONE 0x8000 /* DONE indicator */ + +/* + * Supernet 3: + * BIST Signature Register (AFBIST) + */ +#define AF_BIST_SIGNAT 0x0553 /* Address Filter BIST Signature */ + +/* + * Supernet 3: + * Personality Register (AFPERS) + */ +#define FM_VALID 0x0001 /* CAM Entry Valid */ +#define FM_DA 0x0002 /* Destination Address */ +#define FM_DAX 0x0004 /* Destination Address Exact */ +#define FM_SA 0x0008 /* Source Address */ +#define FM_SAX 0x0010 /* Source Address Exact */ +#define FM_SKIP 0x0020 /* Skip this entry */ + +/* + * instruction set for command register 1 (NPADDR6-0 = 0x00) + */ +#define FM_IRESET 0x01 /* software reset */ +#define FM_IRMEMWI 0x02 /* load Memory Data Reg., inc MARR */ +#define FM_IRMEMWO 0x03 /* load MDR from buffer memory, n.i. */ +#define FM_IIL 0x04 /* idle/listen */ +#define FM_ICL 0x05 /* claim/listen */ +#define FM_IBL 0x06 /* beacon/listen */ +#define FM_ILTVX 0x07 /* load TVX timer from TVX reg */ +#define FM_INRTM 0x08 /* nonrestricted token mode */ +#define FM_IENTM 0x09 /* enter nonrestricted token mode */ +#define FM_IERTM 0x0a /* enter restricted token mode */ +#define FM_IRTM 0x0b /* restricted token mode */ +#define FM_ISURT 0x0c /* send unrestricted token */ +#define FM_ISRT 0x0d /* send restricted token */ +#define FM_ISIM 0x0e /* enter send-immediate mode */ +#define FM_IESIM 0x0f /* exit send-immediate mode */ +#define FM_ICLLS 0x11 /* clear synchronous queue lock */ +#define FM_ICLLA0 0x12 /* clear asynchronous queue 0 lock */ +#define FM_ICLLA1 0x14 /* clear asynchronous queue 1 lock */ +#define FM_ICLLA2 0x18 /* clear asynchronous queue 2 lock */ + /* SN3: reserved */ +#define FM_ICLLR 0x20 /* clear receive queue (SN3:1) lock */ +#define FM_ICLLR2 0x21 /* SN3: clear receive queue 2 lock */ +#define FM_ITRXBUS 0x22 /* SN3: Tristate X-Bus (SAS only) */ +#define FM_IDRXBUS 0x23 /* SN3: drive X-Bus */ +#define FM_ICLLAL 0x3f /* clear all queue locks */ + +/* + * instruction set for command register 2 (NPADDR6-0 = 0x01) + */ +#define FM_ITRS 0x01 /* transmit synchronous queue */ + /* SN3: reserved */ +#define FM_ITRA0 0x02 /* transmit asynchronous queue 0 */ + /* SN3: reserved */ +#define FM_ITRA1 0x04 /* transmit asynchronous queue 1 */ + /* SN3: reserved */ +#define FM_ITRA2 0x08 /* transmit asynchronous queue 2 */ + /* SN3: reserved */ +#define FM_IACTR 0x10 /* abort current transmit activity */ +#define FM_IRSTQ 0x20 /* reset transmit queues */ +#define FM_ISTTB 0x30 /* set tag bit */ +#define FM_IERSF 0x40 /* enable receive single frame */ + /* SN3: reserved */ +#define FM_ITR 0x50 /* SN3: Transmit Command */ + + +/* + * defines for PLC (Am79C864) + */ + +/* + * PLC read/write (r/w) registers + */ +#define PL_CNTRL_A 0x00 /* control register A (r/w) */ +#define PL_CNTRL_B 0x01 /* control register B (r/w) */ +#define PL_INTR_MASK 0x02 /* interrupt mask (r/w) */ +#define PL_XMIT_VECTOR 0x03 /* transmit vector register (r/w) */ +#define PL_VECTOR_LEN 0x04 /* transmit vector length (r/w) */ +#define PL_LE_THRESHOLD 0x05 /* link error event threshold (r/w) */ +#define PL_C_MIN 0x06 /* minimum connect state time (r/w) */ +#define PL_TL_MIN 0x07 /* min. line state transmit t. (r/w) */ +#define PL_TB_MIN 0x08 /* minimum break time (r/w) */ +#define PL_T_OUT 0x09 /* signal timeout (r/w) */ +#define PL_CNTRL_C 0x0a /* control register C (r/w) */ +#define PL_LC_LENGTH 0x0b /* link confidence test time (r/w) */ +#define PL_T_SCRUB 0x0c /* scrub time = MAC TVX (r/w) */ +#define PL_NS_MAX 0x0d /* max. noise time before break (r/w)*/ +#define PL_TPC_LOAD_V 0x0e /* TPC timer load value (write only) */ +#define PL_TNE_LOAD_V 0x0f /* TNE timer load value (write only) */ +#define PL_STATUS_A 0x10 /* status register A (read only) */ +#define PL_STATUS_B 0x11 /* status register B (read only) */ +#define PL_TPC 0x12 /* timer for PCM (ro) [20.48 us] */ +#define PL_TNE 0x13 /* time of noise event [0.32 us] */ +#define PL_CLK_DIV 0x14 /* TNE clock divider (read only) */ +#define PL_BIST_SIGNAT 0x15 /* built in self test signature (ro)*/ +#define PL_RCV_VECTOR 0x16 /* receive vector reg. (read only) */ +#define PL_INTR_EVENT 0x17 /* interrupt event reg. (read only) */ +#define PL_VIOL_SYM_CTR 0x18 /* violation symbol count. (read o) */ +#define PL_MIN_IDLE_CTR 0x19 /* minimum idle counter (read only) */ +#define PL_LINK_ERR_CTR 0x1a /* link error event ctr.(read only) */ +#ifdef MOT_ELM +#define PL_T_FOT_ASS 0x1e /* FOTOFF Assert Timer */ +#define PL_T_FOT_DEASS 0x1f /* FOTOFF Deassert Timer */ +#endif /* MOT_ELM */ + +#ifdef MOT_ELM +/* + * Special Quad-Elm Registers. + * A Quad-ELM consists of for ELMs and these additional registers. + */ +#define QELM_XBAR_W 0x80 /* Crossbar Control ELM W */ +#define QELM_XBAR_X 0x81 /* Crossbar Control ELM X */ +#define QELM_XBAR_Y 0x82 /* Crossbar Control ELM Y */ +#define QELM_XBAR_Z 0x83 /* Crossbar Control ELM Z */ +#define QELM_XBAR_P 0x84 /* Crossbar Control Bus P */ +#define QELM_XBAR_S 0x85 /* Crossbar Control Bus S */ +#define QELM_XBAR_R 0x86 /* Crossbar Control Bus R */ +#define QELM_WR_XBAR 0x87 /* Write the Crossbar now (write) */ +#define QELM_CTR_W 0x88 /* Counter W */ +#define QELM_CTR_X 0x89 /* Counter X */ +#define QELM_CTR_Y 0x8a /* Counter Y */ +#define QELM_CTR_Z 0x8b /* Counter Z */ +#define QELM_INT_MASK 0x8c /* Interrupt mask register */ +#define QELM_INT_DATA 0x8d /* Interrupt data (event) register */ +#define QELM_ELMB 0x00 /* Elm base */ +#define QELM_ELM_SIZE 0x20 /* ELM size */ +#endif /* MOT_ELM */ +/* + * PLC control register A (PL_CNTRL_A: log. addr. 0x00) + * It is used for timer configuration, specification of PCM MAINT state option, + * counter interrupt frequency, PLC data path config. and Built In Self Test. + */ +#define PL_RUN_BIST 0x0001 /* begin running its Built In Self T.*/ +#define PL_RF_DISABLE 0x0002 /* disable the Repeat Filter state m.*/ +#define PL_SC_REM_LOOP 0x0004 /* remote loopback path */ +#define PL_SC_BYPASS 0x0008 /* by providing a physical bypass */ +#define PL_LM_LOC_LOOP 0x0010 /* loop path just after elastic buff.*/ +#define PL_EB_LOC_LOOP 0x0020 /* loop path just prior to PDT/PDR IF*/ +#define PL_FOT_OFF 0x0040 /* assertion of /FOTOFF pin of PLC */ +#define PL_LOOPBACK 0x0080 /* it cause the /LPBCK pin ass. low */ +#define PL_MINI_CTR_INT 0x0100 /* partially contr. when bit is ass. */ +#define PL_VSYM_CTR_INT 0x0200 /* controls when int bit is asserted */ +#define PL_ENA_PAR_CHK 0x0400 /* enable parity check */ +#define PL_REQ_SCRUB 0x0800 /* limited access to scrub capability*/ +#define PL_TPC_16BIT 0x1000 /* causes the TPC as a 16 bit timer */ +#define PL_TNE_16BIT 0x2000 /* causes the TNE as a 16 bit timer */ +#define PL_NOISE_TIMER 0x4000 /* allows the noise timing function */ + +/* + * PLC control register B (PL_CNTRL_B: log. addr. 0x01) + * It contains signals and requeste to direct the process of PCM and it is also + * used to control the Line State Match interrupt. + */ +#define PL_PCM_CNTRL 0x0003 /* control PCM state machine */ +#define PL_PCM_NAF (0) /* state is not affected */ +#define PL_PCM_START (1) /* goes to the BREAK state */ +#define PL_PCM_TRACE (2) /* goes to the TRACE state */ +#define PL_PCM_STOP (3) /* goes to the OFF state */ + +#define PL_MAINT 0x0004 /* if OFF state --> MAINT state */ +#define PL_LONG 0x0008 /* perf. a long Link Confid.Test(LCT)*/ +#define PL_PC_JOIN 0x0010 /* if NEXT state --> JOIN state */ + +#define PL_PC_LOOP 0x0060 /* loopback used in the LCT */ +#define PL_NOLCT (0<<5) /* no LCT is performed */ +#define PL_TPDR (1<<5) /* PCM asserts transmit PDR */ +#define PL_TIDLE (2<<5) /* PCM asserts transmit idle */ +#define PL_RLBP (3<<5) /* trans. PDR & remote loopb. path */ + +#define PL_CLASS_S 0x0080 /* signif. that single att. station */ + +#define PL_MAINT_LS 0x0700 /* line state while in the MAINT st. */ +#define PL_M_QUI0 (0<<8) /* transmit QUIET line state */ +#define PL_M_IDLE (1<<8) /* transmit IDLE line state */ +#define PL_M_HALT (2<<8) /* transmit HALT line state */ +#define PL_M_MASTR (3<<8) /* transmit MASTER line state */ +#define PL_M_QUI1 (4<<8) /* transmit QUIET line state */ +#define PL_M_QUI2 (5<<8) /* transmit QUIET line state */ +#define PL_M_TPDR (6<<8) /* tr. PHY_DATA requ.-symbol is tr.ed*/ +#define PL_M_QUI3 (7<<8) /* transmit QUIET line state */ + +#define PL_MATCH_LS 0x7800 /* line state to be comp. with curr.*/ +#define PL_I_ANY (0<<11) /* Int. on any change in *_LINE_ST */ +#define PL_I_IDLE (1<<11) /* Interrupt on IDLE line state */ +#define PL_I_HALT (2<<11) /* Interrupt on HALT line state */ +#define PL_I_MASTR (4<<11) /* Interrupt on MASTER line state */ +#define PL_I_QUIET (8<<11) /* Interrupt on QUIET line state */ + +#define PL_CONFIG_CNTRL 0x8000 /* control over scrub, byp. & loopb.*/ + +/* + * PLC control register C (PL_CNTRL_C: log. addr. 0x0a) + * It contains the scrambling control registers (PLC-S only) + */ +#define PL_C_CIPHER_ENABLE (1<<0) /* enable scrambler */ +#define PL_C_CIPHER_LPBCK (1<<1) /* loopback scrambler */ +#define PL_C_SDOFF_ENABLE (1<<6) /* enable SDOFF timer */ +#define PL_C_SDON_ENABLE (1<<7) /* enable SDON timer */ +#ifdef MOT_ELM +#define PL_C_FOTOFF_CTRL (3<<2) /* FOTOFF timer control */ +#define PL_C_FOTOFF_TIM (0<<2) /* FOTOFF use timer for (de)-assert */ +#define PL_C_FOTOFF_INA (2<<2) /* FOTOFF forced inactive */ +#define PL_C_FOTOFF_ACT (3<<2) /* FOTOFF forced active */ +#define PL_C_FOTOFF_SRCE (1<<4) /* FOTOFF source is PCM state != OFF */ +#define PL_C_RXDATA_EN (1<<5) /* Rec scr data forced to 0 */ +#define PL_C_SDNRZEN (1<<8) /* Monitor rec descr. data for act */ +#else /* nMOT_ELM */ +#define PL_C_FOTOFF_CTRL (3<<8) /* FOTOFF timer control */ +#define PL_C_FOTOFF_0 (0<<8) /* timer off */ +#define PL_C_FOTOFF_30 (1<<8) /* 30uS */ +#define PL_C_FOTOFF_50 (2<<8) /* 50uS */ +#define PL_C_FOTOFF_NEVER (3<<8) /* never */ +#define PL_C_SDON_TIMER (3<<10) /* SDON timer control */ +#define PL_C_SDON_084 (0<<10) /* 0.84 uS */ +#define PL_C_SDON_132 (1<<10) /* 1.32 uS */ +#define PL_C_SDON_252 (2<<10) /* 2.52 uS */ +#define PL_C_SDON_512 (3<<10) /* 5.12 uS */ +#define PL_C_SOFF_TIMER (3<<12) /* SDOFF timer control */ +#define PL_C_SOFF_076 (0<<12) /* 0.76 uS */ +#define PL_C_SOFF_132 (1<<12) /* 1.32 uS */ +#define PL_C_SOFF_252 (2<<12) /* 2.52 uS */ +#define PL_C_SOFF_512 (3<<12) /* 5.12 uS */ +#define PL_C_TSEL (3<<14) /* scrambler path select */ +#endif /* nMOT_ELM */ + +/* + * PLC status register A (PL_STATUS_A: log. addr. 0x10) + * It is used to report status information to the Node Processor about the + * Line State Machine (LSM). + */ +#ifdef MOT_ELM +#define PLC_INT_MASK 0xc000 /* ELM integration bits in status A */ +#define PLC_INT_C 0x0000 /* ELM Revision Band C */ +#define PLC_INT_CAMEL 0x4000 /* ELM integrated into CAMEL */ +#define PLC_INT_QE 0x8000 /* ELM integrated into Quad ELM */ +#define PLC_REV_MASK 0x3800 /* revision bits in status A */ +#define PLC_REVISION_B 0x0000 /* rev bits for ELM Rev B */ +#define PLC_REVISION_QA 0x0800 /* rev bits for ELM core in QELM-A */ +#else /* nMOT_ELM */ +#define PLC_REV_MASK 0xf800 /* revision bits in status A */ +#define PLC_REVISION_A 0x0000 /* revision bits for PLC */ +#define PLC_REVISION_S 0xf800 /* revision bits for PLC-S */ +#define PLC_REV_SN3 0x7800 /* revision bits for PLC-S in IFCP */ +#endif /* nMOT_ELM */ +#define PL_SYM_PR_CTR 0x0007 /* contains the LSM symbol pair Ctr. */ +#define PL_UNKN_LINE_ST 0x0008 /* unknown line state bit from LSM */ +#define PL_LSM_STATE 0x0010 /* state bit of LSM */ + +#define PL_LINE_ST 0x00e0 /* contains recogn. line state of LSM*/ +#define PL_L_NLS (0<<5) /* noise line state */ +#define PL_L_ALS (1<<5) /* activ line state */ +#define PL_L_UND (2<<5) /* undefined */ +#define PL_L_ILS4 (3<<5) /* idle l. s. (after 4 idle symbols) */ +#define PL_L_QLS (4<<5) /* quiet line state */ +#define PL_L_MLS (5<<5) /* master line state */ +#define PL_L_HLS (6<<5) /* halt line state */ +#define PL_L_ILS16 (7<<5) /* idle line state (after 16 idle s.)*/ + +#define PL_PREV_LINE_ST 0x0300 /* value of previous line state */ +#define PL_P_QLS (0<<8) /* quiet line state */ +#define PL_P_MLS (1<<8) /* master line state */ +#define PL_P_HLS (2<<8) /* halt line state */ +#define PL_P_ILS16 (3<<8) /* idle line state (after 16 idle s.)*/ + +#define PL_SIGNAL_DET 0x0400 /* 1=that signal detect is deasserted*/ + + +/* + * PLC status register B (PL_STATUS_B: log. addr. 0x11) + * It contains signals and status from the repeat filter and PCM state machine. + */ +#define PL_BREAK_REASON 0x0007 /* reason for PCM state mach.s to br.*/ +#define PL_B_NOT (0) /* PCM SM has not gone to BREAK state*/ +#define PL_B_PCS (1) /* PC_Start issued */ +#define PL_B_TPC (2) /* TPC timer expired after T_OUT */ +#define PL_B_TNE (3) /* TNE timer expired after NS_MAX */ +#define PL_B_QLS (4) /* quit line state detected */ +#define PL_B_ILS (5) /* idle line state detected */ +#define PL_B_HLS (6) /* halt line state detected */ + +#define PL_TCF 0x0008 /* transmit code flag (start exec.) */ +#define PL_RCF 0x0010 /* receive code flag (start exec.) */ +#define PL_LSF 0x0020 /* line state flag (l.s. has been r.)*/ +#define PL_PCM_SIGNAL 0x0040 /* indic. that XMIT_VECTOR hb.written*/ + +#define PL_PCM_STATE 0x0780 /* state bits of PCM state machine */ +#define PL_PC0 (0<<7) /* OFF - when /RST or PCM_CNTRL */ +#define PL_PC1 (1<<7) /* BREAK - entry point in start PCM*/ +#define PL_PC2 (2<<7) /* TRACE - to localize stuck Beacon*/ +#define PL_PC3 (3<<7) /* CONNECT - synchronize ends of conn*/ +#define PL_PC4 (4<<7) /* NEXT - to separate the signalng*/ +#define PL_PC5 (5<<7) /* SIGNAL - PCM trans/rec. bit infos*/ +#define PL_PC6 (6<<7) /* JOIN - 1. state to activ conn. */ +#define PL_PC7 (7<<7) /* VERIFY - 2. - " - (3. ACTIVE) */ +#define PL_PC8 (8<<7) /* ACTIVE - PHY has been incorporated*/ +#define PL_PC9 (9<<7) /* MAINT - for test purposes or so + that PCM op. completely in softw. */ + +#define PL_PCI_SCRUB 0x0800 /* scrubbing function is being exec. */ + +#define PL_PCI_STATE 0x3000 /* Physical Connect. Insertion SM */ +#define PL_CI_REMV (0<<12) /* REMOVED */ +#define PL_CI_ISCR (1<<12) /* INSERT_SCRUB */ +#define PL_CI_RSCR (2<<12) /* REMOVE_SCRUB */ +#define PL_CI_INS (3<<12) /* INSERTED */ + +#define PL_RF_STATE 0xc000 /* state bit of repeate filter SM */ +#define PL_RF_REPT (0<<14) /* REPEAT */ +#define PL_RF_IDLE (1<<14) /* IDLE */ +#define PL_RF_HALT1 (2<<14) /* HALT1 */ +#define PL_RF_HALT2 (3<<14) /* HALT2 */ + + +/* + * PLC interrupt event register (PL_INTR_EVENT: log. addr. 0x17) + * It is read only and is clearde whenever it is read! + * It is used by the PLC to report events to the node processor. + */ +#define PL_PARITY_ERR 0x0001 /* p. error h.b.detected on TX9-0 inp*/ +#define PL_LS_MATCH 0x0002 /* l.s.== l.s. PLC_CNTRL_B's MATCH_LS*/ +#define PL_PCM_CODE 0x0004 /* transmit&receive | LCT complete */ +#define PL_TRACE_PROP 0x0008 /* master l.s. while PCM ACTIV|TRACE */ +#define PL_SELF_TEST 0x0010 /* QUIET|HALT while PCM in TRACE st. */ +#define PL_PCM_BREAK 0x0020 /* PCM has entered the BREAK state */ +#define PL_PCM_ENABLED 0x0040 /* asserted SC_JOIN, scrub. & ACTIV */ +#define PL_TPC_EXPIRED 0x0080 /* TPC timer reached zero */ +#define PL_TNE_EXPIRED 0x0100 /* TNE timer reached zero */ +#define PL_EBUF_ERR 0x0200 /* elastic buff. det. over-|underflow*/ +#define PL_PHYINV 0x0400 /* physical layer invalid signal */ +#define PL_VSYM_CTR 0x0800 /* violation symbol counter has incr.*/ +#define PL_MINI_CTR 0x1000 /* dep. on PLC_CNTRL_A's MINI_CTR_INT*/ +#define PL_LE_CTR 0x2000 /* link error event counter */ +#define PL_LSDO 0x4000 /* SDO input pin changed to a 1 */ +#define PL_NP_ERR 0x8000 /* NP has requested to r/w an inv. r.*/ + +/* + * The PLC interrupt mask register (PL_INTR_MASK: log. addr. 0x02) constr. is + * equal PL_INTR_EVENT register. + * For each set bit, the setting of corresponding bit generate an int to NP. + */ + +#ifdef MOT_ELM +/* + * Quad ELM Crosbar Control register values (QELM_XBAR_?) + */ +#define QELM_XOUT_IDLE 0x0000 /* Idles/Passthrough */ +#define QELM_XOUT_P 0x0001 /* Output to: Bus P */ +#define QELM_XOUT_S 0x0002 /* Output to: Bus S */ +#define QELM_XOUT_R 0x0003 /* Output to: Bus R */ +#define QELM_XOUT_W 0x0004 /* Output to: ELM W */ +#define QELM_XOUT_X 0x0005 /* Output to: ELM X */ +#define QELM_XOUT_Y 0x0006 /* Output to: ELM Y */ +#define QELM_XOUT_Z 0x0007 /* Output to: ELM Z */ + +/* + * Quad ELM Interrupt data and event registers. + */ +#define QELM_NP_ERR (1<<15) /* Node Processor Error */ +#define QELM_COUNT_Z (1<<7) /* Counter Z Interrupt */ +#define QELM_COUNT_Y (1<<6) /* Counter Y Interrupt */ +#define QELM_COUNT_X (1<<5) /* Counter X Interrupt */ +#define QELM_COUNT_W (1<<4) /* Counter W Interrupt */ +#define QELM_ELM_Z (1<<3) /* ELM Z Interrupt */ +#define QELM_ELM_Y (1<<2) /* ELM Y Interrupt */ +#define QELM_ELM_X (1<<1) /* ELM X Interrupt */ +#define QELM_ELM_W (1<<0) /* ELM W Interrupt */ +#endif /* MOT_ELM */ +/* + * PLC Timing Parameters + */ +#define TP_C_MIN 0xff9c /* 2 ms */ +#define TP_TL_MIN 0xfff0 /* 0.3 ms */ +#define TP_TB_MIN 0xff10 /* 5 ms */ +#define TP_T_OUT 0xd9db /* 200 ms */ +#define TP_LC_LENGTH 0xf676 /* 50 ms */ +#define TP_LC_LONGLN 0xa0a2 /* 500 ms */ +#define TP_T_SCRUB 0xff6d /* 3.5 ms */ +#define TP_NS_MAX 0xf021 /* 1.3 ms */ + +/* + * BIST values + */ +#define PLC_BIST 0x6ecd /* BIST signature for PLC */ +#define PLCS_BIST 0x5b6b /* BIST signature for PLC-S */ +#define PLC_ELM_B_BIST 0x6ecd /* BIST signature of ELM Rev. B */ +#define PLC_ELM_D_BIST 0x5b6b /* BIST signature of ELM Rev. D */ +#define PLC_CAM_A_BIST 0x9e75 /* BIST signature of CAMEL Rev. A */ +#define PLC_CAM_B_BIST 0x5b6b /* BIST signature of CAMEL Rev. B */ +#define PLC_IFD_A_BIST 0x9e75 /* BIST signature of IFDDI Rev. A */ +#define PLC_IFD_B_BIST 0x5b6b /* BIST signature of IFDDI Rev. B */ +#define PLC_QELM_A_BIST 0x5b6b /* BIST signature of QELM Rev. A */ + +/* + FDDI board recources + */ + +/* + * request register array (log. addr: RQA_A + a<<1 {a=0..7}) write only. + * It specifies to FORMAC+ the type of buffer memory access the host requires. + */ +#define RQ_NOT 0 /* not request */ +#define RQ_RES 1 /* reserved */ +#define RQ_SFW 2 /* special frame write */ +#define RQ_RRQ 3 /* read request: receive queue */ +#define RQ_WSQ 4 /* write request: synchronous queue */ +#define RQ_WA0 5 /* write requ.: asynchronous queue 0 */ +#define RQ_WA1 6 /* write requ.: asynchronous queue 1 */ +#define RQ_WA2 7 /* write requ.: asynchronous queue 2 */ + +#define SZ_LONG (sizeof(long)) + +/* + * FDDI defaults + * NOTE : In the ANSI docs, times are specified in units of "symbol time". + * AMD chips use BCLK as unit. 1 BCKL == 2 symbols + */ +#define COMPLREF ((u_long)32*256*256) /* two's complement 21 bit */ +#define MSTOBCLK(x) ((u_long)(x)*12500L) +#define MSTOTVX(x) (((u_long)(x)*1000L)/80/255) + +#endif /* _SUPERNET_ */ diff --git a/drivers/net/fddi/skfp/h/targethw.h b/drivers/net/fddi/skfp/h/targethw.h new file mode 100644 index 0000000..626dc72 --- /dev/null +++ b/drivers/net/fddi/skfp/h/targethw.h @@ -0,0 +1,138 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _TARGETHW_ +#define _TARGETHW_ + + /* + * PCI Watermark definition + */ +#ifdef PCI +#define RX_WATERMARK 24 +#define TX_WATERMARK 24 +#define SK_ML_ID_1 0x20 +#define SK_ML_ID_2 0x30 +#endif + +#include "h/skfbi.h" +#ifndef TAG_MODE +#include "h/fplus.h" +#else +#include "h/fplustm.h" +#endif + +#ifndef HW_PTR +#define HW_PTR void __iomem * +#endif + +#ifdef MULT_OEM +#define OI_STAT_LAST 0 /* end of OEM data base */ +#define OI_STAT_PRESENT 1 /* entry present but not empty */ +#define OI_STAT_VALID 2 /* holds valid ID, but is not active */ +#define OI_STAT_ACTIVE 3 /* holds valid ID, entry is active */ + /* active = adapter is supported */ + +/* Memory representation of IDs must match representation in adapter. */ +struct s_oem_ids { + u_char oi_status ; /* Stat: last, present, valid, active */ + u_char oi_mark[5] ; /* "PID00" .. "PID07" .. */ + u_char oi_id[4] ; /* id bytes, representation as */ + /* defined by hardware, */ +#ifdef PCI + u_char oi_sub_id[4] ; /* sub id bytes, representation as */ + /* defined by hardware, */ +#endif +} ; +#endif /* MULT_OEM */ + + +struct s_smt_hw { + /* + * global + */ + HW_PTR iop ; /* IO base address */ + short dma ; /* DMA channel */ + short irq ; /* IRQ level */ + short eprom ; /* FLASH prom */ + +#ifndef SYNC + u_short n_a_send ; /* pending send requests */ +#endif + +#if defined(PCI) + short slot ; /* slot number */ + short max_slots ; /* maximum number of slots */ + short wdog_used ; /* TRUE if the watch dog is used */ +#endif + +#ifdef PCI + u_short pci_handle ; /* handle to access the BIOS func */ + u_long is_imask ; /* int maske for the int source reg */ + u_long phys_mem_addr ; /* physical memory address */ + u_short mc_dummy ; /* work around for MC compiler bug */ + /* + * state of the hardware + */ + u_short hw_state ; /* started or stopped */ + +#define STARTED 1 +#define STOPPED 0 + + int hw_is_64bit ; /* does we have a 64 bit adapter */ +#endif + +#ifdef TAG_MODE + u_long pci_fix_value ; /* value parsed by PCIFIX */ +#endif + + /* + * hwt.c + */ + u_long t_start ; /* HWT start */ + u_long t_stop ; /* HWT stop */ + u_short timer_activ ; /* HWT timer active */ + + /* + * PIC + */ + u_char pic_a1 ; + u_char pic_21 ; + + /* + * GENERIC ; do not modify beyond this line + */ + + /* + * physical and canonical address + */ + struct fddi_addr fddi_home_addr ; + struct fddi_addr fddi_canon_addr ; + struct fddi_addr fddi_phys_addr ; + + /* + * mac variables + */ + struct mac_parameter mac_pa ; /* tmin, tmax, tvx, treq .. */ + struct mac_counter mac_ct ; /* recv., lost, error */ + u_short mac_ring_is_up ; /* ring is up flag */ + + struct s_smt_fp fp ; /* formac+ */ + +#ifdef MULT_OEM + struct s_oem_ids *oem_id ; /* pointer to selected id */ + int oem_min_status ; /* IDs to take care of */ +#endif /* MULT_OEM */ + +} ; +#endif diff --git a/drivers/net/fddi/skfp/h/targetos.h b/drivers/net/fddi/skfp/h/targetos.h new file mode 100644 index 0000000..5d940e7 --- /dev/null +++ b/drivers/net/fddi/skfp/h/targetos.h @@ -0,0 +1,165 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * Operating system specific definitions for driver and + * hardware module. + */ + +#ifndef TARGETOS_H +#define TARGETOS_H + + +//-------- those should go into include/linux/pci.h +#define PCI_VENDOR_ID_SK 0x1148 +#define PCI_DEVICE_ID_SK_FP 0x4000 +//-------- + + + +//-------- those should go into include/linux/if_fddi.h +#define FDDI_MAC_HDR_LEN 13 + +#define FDDI_RII 0x01 /* routing information bit */ +#define FDDI_RCF_DIR_BIT 0x80 +#define FDDI_RCF_LEN_MASK 0x1f +#define FDDI_RCF_BROADCAST 0x8000 +#define FDDI_RCF_LIMITED_BROADCAST 0xA000 +#define FDDI_RCF_FRAME2K 0x20 +#define FDDI_RCF_FRAME4K 0x30 +//-------- + + +#undef ADDR + +#include +#include +#include +#include +#include +#include + +// is redefined by linux, but we need our definition +#undef ADDR +#ifdef MEM_MAPPED_IO +#define ADDR(a) (smc->hw.iop+(a)) +#else +#define ADDR(a) (((a)>>7) ? (outp(smc->hw.iop+B0_RAP,(a)>>7), (smc->hw.iop+( ((a)&0x7F) | ((a)>>7 ? 0x80:0)) )) : (smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) +#endif + +#include "h/hwmtm.h" + +#define TRUE 1 +#define FALSE 0 + +// HWM Definitions +// ----------------------- +#define FDDI_TRACE(string, arg1, arg2, arg3) // Performance analysis. +#ifdef PCI +#define NDD_TRACE(string, arg1, arg2, arg3) // Performance analysis. +#endif // PCI +#define SMT_PAGESIZE PAGE_SIZE // Size of a memory page (power of 2). +// ----------------------- + + +// SMT Definitions +// ----------------------- +#define TICKS_PER_SECOND HZ +#define SMC_VERSION 1 +// ----------------------- + + +// OS-Driver Definitions +// ----------------------- +#define NO_ADDRESS 0xffe0 /* No Device (I/O) Address */ +#define SKFP_MAX_NUM_BOARDS 8 /* maximum number of PCI boards */ + +#define SK_BUS_TYPE_PCI 0 +#define SK_BUS_TYPE_EISA 1 + +#define FP_IO_LEN 256 /* length of IO area used */ + +#define u8 unsigned char +#define u16 unsigned short +#define u32 unsigned int + +#define MAX_TX_QUEUE_LEN 20 // number of packets queued by driver +#define MAX_FRAME_SIZE 4550 + +#define RX_LOW_WATERMARK NUM_RECEIVE_BUFFERS / 2 +#define TX_LOW_WATERMARK NUM_TRANSMIT_BUFFERS - 2 + +/* +** Include the IOCTL stuff +*/ +#include + +#define SKFPIOCTL SIOCDEVPRIVATE + +struct s_skfp_ioctl { + unsigned short cmd; /* Command to run */ + unsigned short len; /* Length of the data buffer */ + unsigned char __user *data; /* Pointer to the data buffer */ +}; + +/* +** Recognised ioctl commands for the driver +*/ +#define SKFP_GET_STATS 0x05 /* Get the driver statistics */ +#define SKFP_CLR_STATS 0x06 /* Zero out the driver statistics */ + +// The per-adapter driver structure +struct s_smt_os { + struct net_device *dev; + struct net_device *next_module; + u32 bus_type; /* bus type (0 == PCI, 1 == EISA) */ + struct pci_dev pdev; /* PCI device structure */ + + unsigned long base_addr; + unsigned char factory_mac_addr[8]; + ulong SharedMemSize; + ulong SharedMemHeap; + void* SharedMemAddr; + dma_addr_t SharedMemDMA; + + ulong QueueSkb; + struct sk_buff_head SendSkbQueue; + + ulong MaxFrameSize; + u8 ResetRequested; + + // MAC statistics structure + struct fddi_statistics MacStat; + + // receive into this local buffer if no skb available + // data will be not valid, because multiple RxDs can + // point here at the same time, it must be at least + // MAX_FRAME_SIZE bytes in size + unsigned char *LocalRxBuffer; + dma_addr_t LocalRxBufferDMA; + + // Version (required by SMT module). + u_long smc_version ; + + // Required by Hardware Module (HWM). + struct hw_modul hwm ; + + // For SMP-savety + spinlock_t DriverLock; + +}; + +typedef struct s_smt_os skfddi_priv; + +#endif // _TARGETOS_ diff --git a/drivers/net/fddi/skfp/h/types.h b/drivers/net/fddi/skfp/h/types.h new file mode 100644 index 0000000..5a3bf83 --- /dev/null +++ b/drivers/net/fddi/skfp/h/types.h @@ -0,0 +1,39 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#include +/* + ---------------------- + Basic SMT system types + ---------------------- +*/ +#ifndef _TYPES_ +#define _TYPES_ + +#define _packed +#ifndef far +#define far +#endif +#ifndef _far +#define _far +#endif + +#define inp(p) ioread8(p) +#define inpw(p) ioread16(p) +#define inpd(p) ioread32(p) +#define outp(p,c) iowrite8(c,p) +#define outpw(p,s) iowrite16(s,p) +#define outpd(p,l) iowrite32(l,p) + +#endif /* _TYPES_ */ diff --git a/drivers/net/fddi/skfp/hwmtm.c b/drivers/net/fddi/skfp/hwmtm.c new file mode 100644 index 0000000..e26398b --- /dev/null +++ b/drivers/net/fddi/skfp/hwmtm.c @@ -0,0 +1,2178 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef lint +static char const ID_sccs[] = "@(#)hwmtm.c 1.40 99/05/31 (C) SK" ; +#endif + +#define HWMTM + +#ifndef FDDI +#define FDDI +#endif + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/supern_2.h" +#include "h/skfbiinc.h" + +/* + ------------------------------------------------------------- + DOCUMENTATION + ------------------------------------------------------------- + BEGIN_MANUAL_ENTRY(DOCUMENTATION) + + T B D + + END_MANUAL_ENTRY +*/ +/* + ------------------------------------------------------------- + LOCAL VARIABLES: + ------------------------------------------------------------- +*/ +#ifdef COMMON_MB_POOL +static SMbuf *mb_start = 0 ; +static SMbuf *mb_free = 0 ; +static int mb_init = FALSE ; +static int call_count = 0 ; +#endif + +/* + ------------------------------------------------------------- + EXTERNE VARIABLES: + ------------------------------------------------------------- +*/ + +#ifdef DEBUG +#ifndef DEBUG_BRD +extern struct smt_debug debug ; +#endif +#endif + +#ifdef NDIS_OS2 +extern u_char offDepth ; +extern u_char force_irq_pending ; +#endif + +/* + ------------------------------------------------------------- + LOCAL FUNCTIONS: + ------------------------------------------------------------- +*/ + +static void queue_llc_rx(struct s_smc *smc, SMbuf *mb); +static void smt_to_llc(struct s_smc *smc, SMbuf *mb); +static void init_txd_ring(struct s_smc *smc); +static void init_rxd_ring(struct s_smc *smc); +static void queue_txd_mb(struct s_smc *smc, SMbuf *mb); +static u_long init_descr_ring(struct s_smc *smc, union s_fp_descr volatile *start, + int count); +static u_long repair_txd_ring(struct s_smc *smc, struct s_smt_tx_queue *queue); +static u_long repair_rxd_ring(struct s_smc *smc, struct s_smt_rx_queue *queue); +static SMbuf* get_llc_rx(struct s_smc *smc); +static SMbuf* get_txd_mb(struct s_smc *smc); +static void mac_drv_clear_txd(struct s_smc *smc); + +/* + ------------------------------------------------------------- + EXTERNAL FUNCTIONS: + ------------------------------------------------------------- +*/ +/* The external SMT functions are listed in cmtdef.h */ + +extern void* mac_drv_get_space(struct s_smc *smc, unsigned int size); +extern void* mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size); +extern void mac_drv_fill_rxd(struct s_smc *smc); +extern void mac_drv_tx_complete(struct s_smc *smc, + volatile struct s_smt_fp_txd *txd); +extern void mac_drv_rx_complete(struct s_smc *smc, + volatile struct s_smt_fp_rxd *rxd, + int frag_count, int len); +extern void mac_drv_requeue_rxd(struct s_smc *smc, + volatile struct s_smt_fp_rxd *rxd, + int frag_count); +extern void mac_drv_clear_rxd(struct s_smc *smc, + volatile struct s_smt_fp_rxd *rxd, int frag_count); + +#ifdef USE_OS_CPY +extern void hwm_cpy_rxd2mb(void); +extern void hwm_cpy_txd2mb(void); +#endif + +#ifdef ALL_RX_COMPLETE +extern void mac_drv_all_receives_complete(void); +#endif + +extern u_long mac_drv_virt2phys(struct s_smc *smc, void *virt); +extern u_long dma_master(struct s_smc *smc, void *virt, int len, int flag); + +#ifdef NDIS_OS2 +extern void post_proc(void); +#else +extern void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr, + int flag); +#endif + +extern int mac_drv_rx_init(struct s_smc *smc, int len, int fc, char *look_ahead, + int la_len); + +/* + ------------------------------------------------------------- + PUBLIC FUNCTIONS: + ------------------------------------------------------------- +*/ +void process_receive(struct s_smc *smc); +void fddi_isr(struct s_smc *smc); +void smt_free_mbuf(struct s_smc *smc, SMbuf *mb); +void init_driver_fplus(struct s_smc *smc); +void mac_drv_rx_mode(struct s_smc *smc, int mode); +void init_fddi_driver(struct s_smc *smc, u_char *mac_addr); +void mac_drv_clear_tx_queue(struct s_smc *smc); +void mac_drv_clear_rx_queue(struct s_smc *smc); +void hwm_tx_frag(struct s_smc *smc, char far *virt, u_long phys, int len, + int frame_status); +void hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len, + int frame_status); + +int mac_drv_init(struct s_smc *smc); +int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, int frame_len, + int frame_status); + +u_int mac_drv_check_space(void); + +SMbuf* smt_get_mbuf(struct s_smc *smc); + +#ifdef DEBUG + void mac_drv_debug_lev(void); +#endif + +/* + ------------------------------------------------------------- + MACROS: + ------------------------------------------------------------- +*/ +#ifndef UNUSED +#ifdef lint +#define UNUSED(x) (x) = (x) +#else +#define UNUSED(x) +#endif +#endif + +#ifdef USE_CAN_ADDR +#define MA smc->hw.fddi_canon_addr.a +#define GROUP_ADDR_BIT 0x01 +#else +#define MA smc->hw.fddi_home_addr.a +#define GROUP_ADDR_BIT 0x80 +#endif + +#define RXD_TXD_COUNT (HWM_ASYNC_TXD_COUNT+HWM_SYNC_TXD_COUNT+\ + SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) + +#ifdef MB_OUTSIDE_SMC +#define EXT_VIRT_MEM ((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd) +\ + MAX_MBUF*sizeof(SMbuf)) +#define EXT_VIRT_MEM_2 ((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)) +#else +#define EXT_VIRT_MEM ((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)) +#endif + + /* + * define critical read for 16 Bit drivers + */ +#if defined(NDIS_OS2) || defined(ODI2) +#define CR_READ(var) ((var) & 0xffff0000 | ((var) & 0xffff)) +#else +#define CR_READ(var) (__le32)(var) +#endif + +#define IMASK_SLOW (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \ + IS_MINTR1 | IS_MINTR2 | IS_MINTR3 | IS_R1_P | \ + IS_R1_C | IS_XA_C | IS_XS_C) + +/* + ------------------------------------------------------------- + INIT- AND SMT FUNCTIONS: + ------------------------------------------------------------- +*/ + + +/* + * BEGIN_MANUAL_ENTRY(mac_drv_check_space) + * u_int mac_drv_check_space() + * + * function DOWNCALL (drvsr.c) + * This function calculates the needed non virtual + * memory for MBufs, RxD and TxD descriptors etc. + * needed by the driver. + * + * return u_int memory in bytes + * + * END_MANUAL_ENTRY + */ +u_int mac_drv_check_space(void) +{ +#ifdef MB_OUTSIDE_SMC +#ifdef COMMON_MB_POOL + call_count++ ; + if (call_count == 1) { + return EXT_VIRT_MEM; + } + else { + return EXT_VIRT_MEM_2; + } +#else + return EXT_VIRT_MEM; +#endif +#else + return 0; +#endif +} + +/* + * BEGIN_MANUAL_ENTRY(mac_drv_init) + * void mac_drv_init(smc) + * + * function DOWNCALL (drvsr.c) + * In this function the hardware module allocates it's + * memory. + * The operating system dependent module should call + * mac_drv_init once, after the adatper is detected. + * END_MANUAL_ENTRY + */ +int mac_drv_init(struct s_smc *smc) +{ + if (sizeof(struct s_smt_fp_rxd) % 16) { + SMT_PANIC(smc,HWM_E0001,HWM_E0001_MSG) ; + } + if (sizeof(struct s_smt_fp_txd) % 16) { + SMT_PANIC(smc,HWM_E0002,HWM_E0002_MSG) ; + } + + /* + * get the required memory for the RxDs and TxDs + */ + if (!(smc->os.hwm.descr_p = (union s_fp_descr volatile *) + mac_drv_get_desc_mem(smc,(u_int) + (RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)))) { + return 1; /* no space the hwm modul can't work */ + } + + /* + * get the memory for the SMT MBufs + */ +#ifndef MB_OUTSIDE_SMC + smc->os.hwm.mbuf_pool.mb_start=(SMbuf *)(&smc->os.hwm.mbuf_pool.mb[0]) ; +#else +#ifndef COMMON_MB_POOL + if (!(smc->os.hwm.mbuf_pool.mb_start = (SMbuf *) mac_drv_get_space(smc, + MAX_MBUF*sizeof(SMbuf)))) { + return 1; /* no space the hwm modul can't work */ + } +#else + if (!mb_start) { + if (!(mb_start = (SMbuf *) mac_drv_get_space(smc, + MAX_MBUF*sizeof(SMbuf)))) { + return 1; /* no space the hwm modul can't work */ + } + } +#endif +#endif + return 0; +} + +/* + * BEGIN_MANUAL_ENTRY(init_driver_fplus) + * init_driver_fplus(smc) + * + * Sets hardware modul specific values for the mode register 2 + * (e.g. the byte alignment for the received frames, the position of the + * least significant byte etc.) + * END_MANUAL_ENTRY + */ +void init_driver_fplus(struct s_smc *smc) +{ + smc->hw.fp.mdr2init = FM_LSB | FM_BMMODE | FM_ENNPRQ | FM_ENHSRQ | 3 ; + +#ifdef PCI + smc->hw.fp.mdr2init |= FM_CHKPAR | FM_PARITY ; +#endif + smc->hw.fp.mdr3init = FM_MENRQAUNLCK | FM_MENRS ; + +#ifdef USE_CAN_ADDR + /* enable address bit swapping */ + smc->hw.fp.frselreg_init = FM_ENXMTADSWAP | FM_ENRCVADSWAP ; +#endif +} + +static u_long init_descr_ring(struct s_smc *smc, + union s_fp_descr volatile *start, + int count) +{ + int i ; + union s_fp_descr volatile *d1 ; + union s_fp_descr volatile *d2 ; + u_long phys ; + + DB_GEN("descr ring starts at = %x ",(void *)start,0,3) ; + for (i=count-1, d1=start; i ; i--) { + d2 = d1 ; + d1++ ; /* descr is owned by the host */ + d2->r.rxd_rbctrl = cpu_to_le32(BMU_CHECK) ; + d2->r.rxd_next = &d1->r ; + phys = mac_drv_virt2phys(smc,(void *)d1) ; + d2->r.rxd_nrdadr = cpu_to_le32(phys) ; + } + DB_GEN("descr ring ends at = %x ",(void *)d1,0,3) ; + d1->r.rxd_rbctrl = cpu_to_le32(BMU_CHECK) ; + d1->r.rxd_next = &start->r ; + phys = mac_drv_virt2phys(smc,(void *)start) ; + d1->r.rxd_nrdadr = cpu_to_le32(phys) ; + + for (i=count, d1=start; i ; i--) { + DRV_BUF_FLUSH(&d1->r,DDI_DMA_SYNC_FORDEV) ; + d1++; + } + return phys; +} + +static void init_txd_ring(struct s_smc *smc) +{ + struct s_smt_fp_txd volatile *ds ; + struct s_smt_tx_queue *queue ; + u_long phys ; + + /* + * initialize the transmit descriptors + */ + ds = (struct s_smt_fp_txd volatile *) ((char *)smc->os.hwm.descr_p + + SMT_R1_RXD_COUNT*sizeof(struct s_smt_fp_rxd)) ; + queue = smc->hw.fp.tx[QUEUE_A0] ; + DB_GEN("Init async TxD ring, %d TxDs ",HWM_ASYNC_TXD_COUNT,0,3) ; + (void)init_descr_ring(smc,(union s_fp_descr volatile *)ds, + HWM_ASYNC_TXD_COUNT) ; + phys = le32_to_cpu(ds->txd_ntdadr) ; + ds++ ; + queue->tx_curr_put = queue->tx_curr_get = ds ; + ds-- ; + queue->tx_free = HWM_ASYNC_TXD_COUNT ; + queue->tx_used = 0 ; + outpd(ADDR(B5_XA_DA),phys) ; + + ds = (struct s_smt_fp_txd volatile *) ((char *)ds + + HWM_ASYNC_TXD_COUNT*sizeof(struct s_smt_fp_txd)) ; + queue = smc->hw.fp.tx[QUEUE_S] ; + DB_GEN("Init sync TxD ring, %d TxDs ",HWM_SYNC_TXD_COUNT,0,3) ; + (void)init_descr_ring(smc,(union s_fp_descr volatile *)ds, + HWM_SYNC_TXD_COUNT) ; + phys = le32_to_cpu(ds->txd_ntdadr) ; + ds++ ; + queue->tx_curr_put = queue->tx_curr_get = ds ; + queue->tx_free = HWM_SYNC_TXD_COUNT ; + queue->tx_used = 0 ; + outpd(ADDR(B5_XS_DA),phys) ; +} + +static void init_rxd_ring(struct s_smc *smc) +{ + struct s_smt_fp_rxd volatile *ds ; + struct s_smt_rx_queue *queue ; + u_long phys ; + + /* + * initialize the receive descriptors + */ + ds = (struct s_smt_fp_rxd volatile *) smc->os.hwm.descr_p ; + queue = smc->hw.fp.rx[QUEUE_R1] ; + DB_GEN("Init RxD ring, %d RxDs ",SMT_R1_RXD_COUNT,0,3) ; + (void)init_descr_ring(smc,(union s_fp_descr volatile *)ds, + SMT_R1_RXD_COUNT) ; + phys = le32_to_cpu(ds->rxd_nrdadr) ; + ds++ ; + queue->rx_curr_put = queue->rx_curr_get = ds ; + queue->rx_free = SMT_R1_RXD_COUNT ; + queue->rx_used = 0 ; + outpd(ADDR(B4_R1_DA),phys) ; +} + +/* + * BEGIN_MANUAL_ENTRY(init_fddi_driver) + * void init_fddi_driver(smc,mac_addr) + * + * initializes the driver and it's variables + * + * END_MANUAL_ENTRY + */ +void init_fddi_driver(struct s_smc *smc, u_char *mac_addr) +{ + SMbuf *mb ; + int i ; + + init_board(smc,mac_addr) ; + (void)init_fplus(smc) ; + + /* + * initialize the SMbufs for the SMT + */ +#ifndef COMMON_MB_POOL + mb = smc->os.hwm.mbuf_pool.mb_start ; + smc->os.hwm.mbuf_pool.mb_free = (SMbuf *)NULL ; + for (i = 0; i < MAX_MBUF; i++) { + mb->sm_use_count = 1 ; + smt_free_mbuf(smc,mb) ; + mb++ ; + } +#else + mb = mb_start ; + if (!mb_init) { + mb_free = 0 ; + for (i = 0; i < MAX_MBUF; i++) { + mb->sm_use_count = 1 ; + smt_free_mbuf(smc,mb) ; + mb++ ; + } + mb_init = TRUE ; + } +#endif + + /* + * initialize the other variables + */ + smc->os.hwm.llc_rx_pipe = smc->os.hwm.llc_rx_tail = (SMbuf *)NULL ; + smc->os.hwm.txd_tx_pipe = smc->os.hwm.txd_tx_tail = NULL ; + smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = smc->os.hwm.pass_DB = 0 ; + smc->os.hwm.pass_llc_promisc = TRUE ; + smc->os.hwm.queued_rx_frames = smc->os.hwm.queued_txd_mb = 0 ; + smc->os.hwm.detec_count = 0 ; + smc->os.hwm.rx_break = 0 ; + smc->os.hwm.rx_len_error = 0 ; + smc->os.hwm.isr_flag = FALSE ; + + /* + * make sure that the start pointer is 16 byte aligned + */ + i = 16 - ((long)smc->os.hwm.descr_p & 0xf) ; + if (i != 16) { + DB_GEN("i = %d",i,0,3) ; + smc->os.hwm.descr_p = (union s_fp_descr volatile *) + ((char *)smc->os.hwm.descr_p+i) ; + } + DB_GEN("pt to descr area = %x",(void *)smc->os.hwm.descr_p,0,3) ; + + init_txd_ring(smc) ; + init_rxd_ring(smc) ; + mac_drv_fill_rxd(smc) ; + + init_plc(smc) ; +} + + +SMbuf *smt_get_mbuf(struct s_smc *smc) +{ + register SMbuf *mb ; + +#ifndef COMMON_MB_POOL + mb = smc->os.hwm.mbuf_pool.mb_free ; +#else + mb = mb_free ; +#endif + if (mb) { +#ifndef COMMON_MB_POOL + smc->os.hwm.mbuf_pool.mb_free = mb->sm_next ; +#else + mb_free = mb->sm_next ; +#endif + mb->sm_off = 8 ; + mb->sm_use_count = 1 ; + } + DB_GEN("get SMbuf: mb = %x",(void *)mb,0,3) ; + return mb; /* May be NULL */ +} + +void smt_free_mbuf(struct s_smc *smc, SMbuf *mb) +{ + + if (mb) { + mb->sm_use_count-- ; + DB_GEN("free_mbuf: sm_use_count = %d",mb->sm_use_count,0,3) ; + /* + * If the use_count is != zero the MBuf is queued + * more than once and must not queued into the + * free MBuf queue + */ + if (!mb->sm_use_count) { + DB_GEN("free SMbuf: mb = %x",(void *)mb,0,3) ; +#ifndef COMMON_MB_POOL + mb->sm_next = smc->os.hwm.mbuf_pool.mb_free ; + smc->os.hwm.mbuf_pool.mb_free = mb ; +#else + mb->sm_next = mb_free ; + mb_free = mb ; +#endif + } + } + else + SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; +} + + +/* + * BEGIN_MANUAL_ENTRY(mac_drv_repair_descr) + * void mac_drv_repair_descr(smc) + * + * function called from SMT (HWM / hwmtm.c) + * The BMU is idle when this function is called. + * Mac_drv_repair_descr sets up the physical address + * for all receive and transmit queues where the BMU + * should continue. + * It may be that the BMU was reseted during a fragmented + * transfer. In this case there are some fragments which will + * never completed by the BMU. The OWN bit of this fragments + * must be switched to be owned by the host. + * + * Give a start command to the receive BMU. + * Start the transmit BMUs if transmit frames pending. + * + * END_MANUAL_ENTRY + */ +void mac_drv_repair_descr(struct s_smc *smc) +{ + u_long phys ; + + if (smc->hw.hw_state != STOPPED) { + SK_BREAK() ; + SMT_PANIC(smc,HWM_E0013,HWM_E0013_MSG) ; + return ; + } + + /* + * repair tx queues: don't start + */ + phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_A0]) ; + outpd(ADDR(B5_XA_DA),phys) ; + if (smc->hw.fp.tx_q[QUEUE_A0].tx_used) { + outpd(ADDR(B0_XA_CSR),CSR_START) ; + } + phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_S]) ; + outpd(ADDR(B5_XS_DA),phys) ; + if (smc->hw.fp.tx_q[QUEUE_S].tx_used) { + outpd(ADDR(B0_XS_CSR),CSR_START) ; + } + + /* + * repair rx queues + */ + phys = repair_rxd_ring(smc,smc->hw.fp.rx[QUEUE_R1]) ; + outpd(ADDR(B4_R1_DA),phys) ; + outpd(ADDR(B0_R1_CSR),CSR_START) ; +} + +static u_long repair_txd_ring(struct s_smc *smc, struct s_smt_tx_queue *queue) +{ + int i ; + int tx_used ; + u_long phys ; + u_long tbctrl ; + struct s_smt_fp_txd volatile *t ; + + SK_UNUSED(smc) ; + + t = queue->tx_curr_get ; + tx_used = queue->tx_used ; + for (i = tx_used+queue->tx_free-1 ; i ; i-- ) { + t = t->txd_next ; + } + phys = le32_to_cpu(t->txd_ntdadr) ; + + t = queue->tx_curr_get ; + while (tx_used) { + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ; + tbctrl = le32_to_cpu(t->txd_tbctrl) ; + + if (tbctrl & BMU_OWN) { + if (tbctrl & BMU_STF) { + break ; /* exit the loop */ + } + else { + /* + * repair the descriptor + */ + t->txd_tbctrl &= ~cpu_to_le32(BMU_OWN) ; + } + } + phys = le32_to_cpu(t->txd_ntdadr) ; + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + t = t->txd_next ; + tx_used-- ; + } + return phys; +} + +/* + * Repairs the receive descriptor ring and returns the physical address + * where the BMU should continue working. + * + * o The physical address where the BMU was stopped has to be + * determined. This is the next RxD after rx_curr_get with an OWN + * bit set. + * o The BMU should start working at beginning of the next frame. + * RxDs with an OWN bit set but with a reset STF bit should be + * skipped and owned by the driver (OWN = 0). + */ +static u_long repair_rxd_ring(struct s_smc *smc, struct s_smt_rx_queue *queue) +{ + int i ; + int rx_used ; + u_long phys ; + u_long rbctrl ; + struct s_smt_fp_rxd volatile *r ; + + SK_UNUSED(smc) ; + + r = queue->rx_curr_get ; + rx_used = queue->rx_used ; + for (i = SMT_R1_RXD_COUNT-1 ; i ; i-- ) { + r = r->rxd_next ; + } + phys = le32_to_cpu(r->rxd_nrdadr) ; + + r = queue->rx_curr_get ; + while (rx_used) { + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + rbctrl = le32_to_cpu(r->rxd_rbctrl) ; + + if (rbctrl & BMU_OWN) { + if (rbctrl & BMU_STF) { + break ; /* exit the loop */ + } + else { + /* + * repair the descriptor + */ + r->rxd_rbctrl &= ~cpu_to_le32(BMU_OWN) ; + } + } + phys = le32_to_cpu(r->rxd_nrdadr) ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; + r = r->rxd_next ; + rx_used-- ; + } + return phys; +} + + +/* + ------------------------------------------------------------- + INTERRUPT SERVICE ROUTINE: + ------------------------------------------------------------- +*/ + +/* + * BEGIN_MANUAL_ENTRY(fddi_isr) + * void fddi_isr(smc) + * + * function DOWNCALL (drvsr.c) + * interrupt service routine, handles the interrupt requests + * generated by the FDDI adapter. + * + * NOTE: The operating system dependent module must guarantee that the + * interrupts of the adapter are disabled when it calls fddi_isr. + * + * About the USE_BREAK_ISR mechanismn: + * + * The main requirement of this mechanismn is to force an timer IRQ when + * leaving process_receive() with leave_isr set. process_receive() may + * be called at any time from anywhere! + * To be sure we don't miss such event we set 'force_irq' per default. + * We have to force and Timer IRQ if 'smc->os.hwm.leave_isr' AND + * 'force_irq' are set. 'force_irq' may be reset if a receive complete + * IRQ is pending. + * + * END_MANUAL_ENTRY + */ +void fddi_isr(struct s_smc *smc) +{ + u_long is ; /* ISR source */ + u_short stu, stl ; + SMbuf *mb ; + +#ifdef USE_BREAK_ISR + int force_irq ; +#endif + +#ifdef ODI2 + if (smc->os.hwm.rx_break) { + mac_drv_fill_rxd(smc) ; + if (smc->hw.fp.rx_q[QUEUE_R1].rx_used > 0) { + smc->os.hwm.rx_break = 0 ; + process_receive(smc) ; + } + else { + smc->os.hwm.detec_count = 0 ; + smt_force_irq(smc) ; + } + } +#endif + smc->os.hwm.isr_flag = TRUE ; + +#ifdef USE_BREAK_ISR + force_irq = TRUE ; + if (smc->os.hwm.leave_isr) { + smc->os.hwm.leave_isr = FALSE ; + process_receive(smc) ; + } +#endif + + while ((is = GET_ISR() & ISR_MASK)) { + NDD_TRACE("CH0B",is,0,0) ; + DB_GEN("ISA = 0x%x",is,0,7) ; + + if (is & IMASK_SLOW) { + NDD_TRACE("CH1b",is,0,0) ; + if (is & IS_PLINT1) { /* PLC1 */ + plc1_irq(smc) ; + } + if (is & IS_PLINT2) { /* PLC2 */ + plc2_irq(smc) ; + } + if (is & IS_MINTR1) { /* FORMAC+ STU1(U/L) */ + stu = inpw(FM_A(FM_ST1U)) ; + stl = inpw(FM_A(FM_ST1L)) ; + DB_GEN("Slow transmit complete",0,0,6) ; + mac1_irq(smc,stu,stl) ; + } + if (is & IS_MINTR2) { /* FORMAC+ STU2(U/L) */ + stu= inpw(FM_A(FM_ST2U)) ; + stl= inpw(FM_A(FM_ST2L)) ; + DB_GEN("Slow receive complete",0,0,6) ; + DB_GEN("stl = %x : stu = %x",stl,stu,7) ; + mac2_irq(smc,stu,stl) ; + } + if (is & IS_MINTR3) { /* FORMAC+ STU3(U/L) */ + stu= inpw(FM_A(FM_ST3U)) ; + stl= inpw(FM_A(FM_ST3L)) ; + DB_GEN("FORMAC Mode Register 3",0,0,6) ; + mac3_irq(smc,stu,stl) ; + } + if (is & IS_TIMINT) { /* Timer 82C54-2 */ + timer_irq(smc) ; +#ifdef NDIS_OS2 + force_irq_pending = 0 ; +#endif + /* + * out of RxD detection + */ + if (++smc->os.hwm.detec_count > 4) { + /* + * check out of RxD condition + */ + process_receive(smc) ; + } + } + if (is & IS_TOKEN) { /* Restricted Token Monitor */ + rtm_irq(smc) ; + } + if (is & IS_R1_P) { /* Parity error rx queue 1 */ + /* clear IRQ */ + outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_P) ; + SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; + } + if (is & IS_R1_C) { /* Encoding error rx queue 1 */ + /* clear IRQ */ + outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_C) ; + SMT_PANIC(smc,HWM_E0005,HWM_E0005_MSG) ; + } + if (is & IS_XA_C) { /* Encoding error async tx q */ + /* clear IRQ */ + outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_C) ; + SMT_PANIC(smc,HWM_E0006,HWM_E0006_MSG) ; + } + if (is & IS_XS_C) { /* Encoding error sync tx q */ + /* clear IRQ */ + outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_C) ; + SMT_PANIC(smc,HWM_E0007,HWM_E0007_MSG) ; + } + } + + /* + * Fast Tx complete Async/Sync Queue (BMU service) + */ + if (is & (IS_XS_F|IS_XA_F)) { + DB_GEN("Fast tx complete queue",0,0,6) ; + /* + * clear IRQ, Note: no IRQ is lost, because + * we always service both queues + */ + outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_F) ; + outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_F) ; + mac_drv_clear_txd(smc) ; + llc_restart_tx(smc) ; + } + + /* + * Fast Rx Complete (BMU service) + */ + if (is & IS_R1_F) { + DB_GEN("Fast receive complete",0,0,6) ; + /* clear IRQ */ +#ifndef USE_BREAK_ISR + outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ; + process_receive(smc) ; +#else + process_receive(smc) ; + if (smc->os.hwm.leave_isr) { + force_irq = FALSE ; + } else { + outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ; + process_receive(smc) ; + } +#endif + } + +#ifndef NDIS_OS2 + while ((mb = get_llc_rx(smc))) { + smt_to_llc(smc,mb) ; + } +#else + if (offDepth) + post_proc() ; + + while (!offDepth && (mb = get_llc_rx(smc))) { + smt_to_llc(smc,mb) ; + } + + if (!offDepth && smc->os.hwm.rx_break) { + process_receive(smc) ; + } +#endif + if (smc->q.ev_get != smc->q.ev_put) { + NDD_TRACE("CH2a",0,0,0) ; + ev_dispatcher(smc) ; + } +#ifdef NDIS_OS2 + post_proc() ; + if (offDepth) { /* leave fddi_isr because */ + break ; /* indications not allowed */ + } +#endif +#ifdef USE_BREAK_ISR + if (smc->os.hwm.leave_isr) { + break ; /* leave fddi_isr */ + } +#endif + + /* NOTE: when the isr is left, no rx is pending */ + } /* end of interrupt source polling loop */ + +#ifdef USE_BREAK_ISR + if (smc->os.hwm.leave_isr && force_irq) { + smt_force_irq(smc) ; + } +#endif + smc->os.hwm.isr_flag = FALSE ; + NDD_TRACE("CH0E",0,0,0) ; +} + + +/* + ------------------------------------------------------------- + RECEIVE FUNCTIONS: + ------------------------------------------------------------- +*/ + +#ifndef NDIS_OS2 +/* + * BEGIN_MANUAL_ENTRY(mac_drv_rx_mode) + * void mac_drv_rx_mode(smc,mode) + * + * function DOWNCALL (fplus.c) + * Corresponding to the parameter mode, the operating system + * dependent module can activate several receive modes. + * + * para mode = 1: RX_ENABLE_ALLMULTI enable all multicasts + * = 2: RX_DISABLE_ALLMULTI disable "enable all multicasts" + * = 3: RX_ENABLE_PROMISC enable promiscuous + * = 4: RX_DISABLE_PROMISC disable promiscuous + * = 5: RX_ENABLE_NSA enable rec. of all NSA frames + * (disabled after 'driver reset' & 'set station address') + * = 6: RX_DISABLE_NSA disable rec. of all NSA frames + * + * = 21: RX_ENABLE_PASS_SMT ( see description ) + * = 22: RX_DISABLE_PASS_SMT ( " " ) + * = 23: RX_ENABLE_PASS_NSA ( " " ) + * = 24: RX_DISABLE_PASS_NSA ( " " ) + * = 25: RX_ENABLE_PASS_DB ( " " ) + * = 26: RX_DISABLE_PASS_DB ( " " ) + * = 27: RX_DISABLE_PASS_ALL ( " " ) + * = 28: RX_DISABLE_LLC_PROMISC ( " " ) + * = 29: RX_ENABLE_LLC_PROMISC ( " " ) + * + * + * RX_ENABLE_PASS_SMT / RX_DISABLE_PASS_SMT + * + * If the operating system dependent module activates the + * mode RX_ENABLE_PASS_SMT, the hardware module + * duplicates all SMT frames with the frame control + * FC_SMT_INFO and passes them to the LLC receive channel + * by calling mac_drv_rx_init. + * The SMT Frames which are sent by the local SMT and the NSA + * frames whose A- and C-Indicator is not set are also duplicated + * and passed. + * The receive mode RX_DISABLE_PASS_SMT disables the passing + * of SMT frames. + * + * RX_ENABLE_PASS_NSA / RX_DISABLE_PASS_NSA + * + * If the operating system dependent module activates the + * mode RX_ENABLE_PASS_NSA, the hardware module + * duplicates all NSA frames with frame control FC_SMT_NSA + * and a set A-Indicator and passed them to the LLC + * receive channel by calling mac_drv_rx_init. + * All NSA Frames which are sent by the local SMT + * are also duplicated and passed. + * The receive mode RX_DISABLE_PASS_NSA disables the passing + * of NSA frames with the A- or C-Indicator set. + * + * NOTE: For fear that the hardware module receives NSA frames with + * a reset A-Indicator, the operating system dependent module + * has to call mac_drv_rx_mode with the mode RX_ENABLE_NSA + * before activate the RX_ENABLE_PASS_NSA mode and after every + * 'driver reset' and 'set station address'. + * + * RX_ENABLE_PASS_DB / RX_DISABLE_PASS_DB + * + * If the operating system dependent module activates the + * mode RX_ENABLE_PASS_DB, direct BEACON frames + * (FC_BEACON frame control) are passed to the LLC receive + * channel by mac_drv_rx_init. + * The receive mode RX_DISABLE_PASS_DB disables the passing + * of direct BEACON frames. + * + * RX_DISABLE_PASS_ALL + * + * Disables all special receives modes. It is equal to + * call mac_drv_set_rx_mode successively with the + * parameters RX_DISABLE_NSA, RX_DISABLE_PASS_SMT, + * RX_DISABLE_PASS_NSA and RX_DISABLE_PASS_DB. + * + * RX_ENABLE_LLC_PROMISC + * + * (default) all received LLC frames and all SMT/NSA/DBEACON + * frames depending on the attitude of the flags + * PASS_SMT/PASS_NSA/PASS_DBEACON will be delivered to the + * LLC layer + * + * RX_DISABLE_LLC_PROMISC + * + * all received SMT/NSA/DBEACON frames depending on the + * attitude of the flags PASS_SMT/PASS_NSA/PASS_DBEACON + * will be delivered to the LLC layer. + * all received LLC frames with a directed address, Multicast + * or Broadcast address will be delivered to the LLC + * layer too. + * + * END_MANUAL_ENTRY + */ +void mac_drv_rx_mode(struct s_smc *smc, int mode) +{ + switch(mode) { + case RX_ENABLE_PASS_SMT: + smc->os.hwm.pass_SMT = TRUE ; + break ; + case RX_DISABLE_PASS_SMT: + smc->os.hwm.pass_SMT = FALSE ; + break ; + case RX_ENABLE_PASS_NSA: + smc->os.hwm.pass_NSA = TRUE ; + break ; + case RX_DISABLE_PASS_NSA: + smc->os.hwm.pass_NSA = FALSE ; + break ; + case RX_ENABLE_PASS_DB: + smc->os.hwm.pass_DB = TRUE ; + break ; + case RX_DISABLE_PASS_DB: + smc->os.hwm.pass_DB = FALSE ; + break ; + case RX_DISABLE_PASS_ALL: + smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = FALSE ; + smc->os.hwm.pass_DB = FALSE ; + smc->os.hwm.pass_llc_promisc = TRUE ; + mac_set_rx_mode(smc,RX_DISABLE_NSA) ; + break ; + case RX_DISABLE_LLC_PROMISC: + smc->os.hwm.pass_llc_promisc = FALSE ; + break ; + case RX_ENABLE_LLC_PROMISC: + smc->os.hwm.pass_llc_promisc = TRUE ; + break ; + case RX_ENABLE_ALLMULTI: + case RX_DISABLE_ALLMULTI: + case RX_ENABLE_PROMISC: + case RX_DISABLE_PROMISC: + case RX_ENABLE_NSA: + case RX_DISABLE_NSA: + default: + mac_set_rx_mode(smc,mode) ; + break ; + } +} +#endif /* ifndef NDIS_OS2 */ + +/* + * process receive queue + */ +void process_receive(struct s_smc *smc) +{ + int i ; + int n ; + int frag_count ; /* number of RxDs of the curr rx buf */ + int used_frags ; /* number of RxDs of the curr frame */ + struct s_smt_rx_queue *queue ; /* points to the queue ctl struct */ + struct s_smt_fp_rxd volatile *r ; /* rxd pointer */ + struct s_smt_fp_rxd volatile *rxd ; /* first rxd of rx frame */ + u_long rbctrl ; /* receive buffer control word */ + u_long rfsw ; /* receive frame status word */ + u_short rx_used ; + u_char far *virt ; + char far *data ; + SMbuf *mb ; + u_char fc ; /* Frame control */ + int len ; /* Frame length */ + + smc->os.hwm.detec_count = 0 ; + queue = smc->hw.fp.rx[QUEUE_R1] ; + NDD_TRACE("RHxB",0,0,0) ; + for ( ; ; ) { + r = queue->rx_curr_get ; + rx_used = queue->rx_used ; + frag_count = 0 ; + +#ifdef USE_BREAK_ISR + if (smc->os.hwm.leave_isr) { + goto rx_end ; + } +#endif +#ifdef NDIS_OS2 + if (offDepth) { + smc->os.hwm.rx_break = 1 ; + goto rx_end ; + } + smc->os.hwm.rx_break = 0 ; +#endif +#ifdef ODI2 + if (smc->os.hwm.rx_break) { + goto rx_end ; + } +#endif + n = 0 ; + do { + DB_RX("Check RxD %x for OWN and EOF",(void *)r,0,5) ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + rbctrl = le32_to_cpu(CR_READ(r->rxd_rbctrl)); + + if (rbctrl & BMU_OWN) { + NDD_TRACE("RHxE",r,rfsw,rbctrl) ; + DB_RX("End of RxDs",0,0,4) ; + goto rx_end ; + } + /* + * out of RxD detection + */ + if (!rx_used) { + SK_BREAK() ; + SMT_PANIC(smc,HWM_E0009,HWM_E0009_MSG) ; + /* Either we don't have an RxD or all + * RxDs are filled. Therefore it's allowed + * for to set the STOPPED flag */ + smc->hw.hw_state = STOPPED ; + mac_drv_clear_rx_queue(smc) ; + smc->hw.hw_state = STARTED ; + mac_drv_fill_rxd(smc) ; + smc->os.hwm.detec_count = 0 ; + goto rx_end ; + } + rfsw = le32_to_cpu(r->rxd_rfsw) ; + if ((rbctrl & BMU_STF) != ((rbctrl & BMU_ST_BUF) <<5)) { + /* + * The BMU_STF bit is deleted, 1 frame is + * placed into more than 1 rx buffer + * + * skip frame by setting the rx len to 0 + * + * if fragment count == 0 + * The missing STF bit belongs to the + * current frame, search for the + * EOF bit to complete the frame + * else + * the fragment belongs to the next frame, + * exit the loop and process the frame + */ + SK_BREAK() ; + rfsw = 0 ; + if (frag_count) { + break ; + } + } + n += rbctrl & 0xffff ; + r = r->rxd_next ; + frag_count++ ; + rx_used-- ; + } while (!(rbctrl & BMU_EOF)) ; + used_frags = frag_count ; + DB_RX("EOF set in RxD, used_frags = %d ",used_frags,0,5) ; + + /* may be next 2 DRV_BUF_FLUSH() can be skipped, because */ + /* BMU_ST_BUF will not be changed by the ASIC */ + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + while (rx_used && !(r->rxd_rbctrl & cpu_to_le32(BMU_ST_BUF))) { + DB_RX("Check STF bit in %x",(void *)r,0,5) ; + r = r->rxd_next ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + frag_count++ ; + rx_used-- ; + } + DB_RX("STF bit found",0,0,5) ; + + /* + * The received frame is finished for the process receive + */ + rxd = queue->rx_curr_get ; + queue->rx_curr_get = r ; + queue->rx_free += frag_count ; + queue->rx_used = rx_used ; + + /* + * ASIC Errata no. 7 (STF - Bit Bug) + */ + rxd->rxd_rbctrl &= cpu_to_le32(~BMU_STF) ; + + for (r=rxd, i=frag_count ; i ; r=r->rxd_next, i--){ + DB_RX("dma_complete for RxD %x",(void *)r,0,5) ; + dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR); + } + smc->hw.fp.err_stats.err_valid++ ; + smc->mib.m[MAC0].fddiMACCopied_Ct++ ; + + /* the length of the data including the FC */ + len = (rfsw & RD_LENGTH) - 4 ; + + DB_RX("frame length = %d",len,0,4) ; + /* + * check the frame_length and all error flags + */ + if (rfsw & (RX_MSRABT|RX_FS_E|RX_FS_CRC|RX_FS_IMPL)){ + if (rfsw & RD_S_MSRABT) { + DB_RX("Frame aborted by the FORMAC",0,0,2) ; + smc->hw.fp.err_stats.err_abort++ ; + } + /* + * check frame status + */ + if (rfsw & RD_S_SEAC2) { + DB_RX("E-Indicator set",0,0,2) ; + smc->hw.fp.err_stats.err_e_indicator++ ; + } + if (rfsw & RD_S_SFRMERR) { + DB_RX("CRC error",0,0,2) ; + smc->hw.fp.err_stats.err_crc++ ; + } + if (rfsw & RX_FS_IMPL) { + DB_RX("Implementer frame",0,0,2) ; + smc->hw.fp.err_stats.err_imp_frame++ ; + } + goto abort_frame ; + } + if (len > FDDI_RAW_MTU-4) { + DB_RX("Frame too long error",0,0,2) ; + smc->hw.fp.err_stats.err_too_long++ ; + goto abort_frame ; + } + /* + * SUPERNET 3 Bug: FORMAC delivers status words + * of aborded frames to the BMU + */ + if (len <= 4) { + DB_RX("Frame length = 0",0,0,2) ; + goto abort_frame ; + } + + if (len != (n-4)) { + DB_RX("BMU: rx len differs: [%d:%d]",len,n,4); + smc->os.hwm.rx_len_error++ ; + goto abort_frame ; + } + + /* + * Check SA == MA + */ + virt = (u_char far *) rxd->rxd_virt ; + DB_RX("FC = %x",*virt,0,2) ; + if (virt[12] == MA[5] && + virt[11] == MA[4] && + virt[10] == MA[3] && + virt[9] == MA[2] && + virt[8] == MA[1] && + (virt[7] & ~GROUP_ADDR_BIT) == MA[0]) { + goto abort_frame ; + } + + /* + * test if LLC frame + */ + if (rfsw & RX_FS_LLC) { + /* + * if pass_llc_promisc is disable + * if DA != Multicast or Broadcast or DA!=MA + * abort the frame + */ + if (!smc->os.hwm.pass_llc_promisc) { + if(!(virt[1] & GROUP_ADDR_BIT)) { + if (virt[6] != MA[5] || + virt[5] != MA[4] || + virt[4] != MA[3] || + virt[3] != MA[2] || + virt[2] != MA[1] || + virt[1] != MA[0]) { + DB_RX("DA != MA and not multi- or broadcast",0,0,2) ; + goto abort_frame ; + } + } + } + + /* + * LLC frame received + */ + DB_RX("LLC - receive",0,0,4) ; + mac_drv_rx_complete(smc,rxd,frag_count,len) ; + } + else { + if (!(mb = smt_get_mbuf(smc))) { + smc->hw.fp.err_stats.err_no_buf++ ; + DB_RX("No SMbuf; receive terminated",0,0,4) ; + goto abort_frame ; + } + data = smtod(mb,char *) - 1 ; + + /* + * copy the frame into a SMT_MBuf + */ +#ifdef USE_OS_CPY + hwm_cpy_rxd2mb(rxd,data,len) ; +#else + for (r=rxd, i=used_frags ; i ; r=r->rxd_next, i--){ + n = le32_to_cpu(r->rxd_rbctrl) & RD_LENGTH ; + DB_RX("cp SMT frame to mb: len = %d",n,0,6) ; + memcpy(data,r->rxd_virt,n) ; + data += n ; + } + data = smtod(mb,char *) - 1 ; +#endif + fc = *(char *)mb->sm_data = *data ; + mb->sm_len = len - 1 ; /* len - fc */ + data++ ; + + /* + * SMT frame received + */ + switch(fc) { + case FC_SMT_INFO : + smc->hw.fp.err_stats.err_smt_frame++ ; + DB_RX("SMT frame received ",0,0,5) ; + + if (smc->os.hwm.pass_SMT) { + DB_RX("pass SMT frame ",0,0,5) ; + mac_drv_rx_complete(smc, rxd, + frag_count,len) ; + } + else { + DB_RX("requeue RxD",0,0,5) ; + mac_drv_requeue_rxd(smc,rxd,frag_count); + } + + smt_received_pack(smc,mb,(int)(rfsw>>25)) ; + break ; + case FC_SMT_NSA : + smc->hw.fp.err_stats.err_smt_frame++ ; + DB_RX("SMT frame received ",0,0,5) ; + + /* if pass_NSA set pass the NSA frame or */ + /* pass_SMT set and the A-Indicator */ + /* is not set, pass the NSA frame */ + if (smc->os.hwm.pass_NSA || + (smc->os.hwm.pass_SMT && + !(rfsw & A_INDIC))) { + DB_RX("pass SMT frame ",0,0,5) ; + mac_drv_rx_complete(smc, rxd, + frag_count,len) ; + } + else { + DB_RX("requeue RxD",0,0,5) ; + mac_drv_requeue_rxd(smc,rxd,frag_count); + } + + smt_received_pack(smc,mb,(int)(rfsw>>25)) ; + break ; + case FC_BEACON : + if (smc->os.hwm.pass_DB) { + DB_RX("pass DB frame ",0,0,5) ; + mac_drv_rx_complete(smc, rxd, + frag_count,len) ; + } + else { + DB_RX("requeue RxD",0,0,5) ; + mac_drv_requeue_rxd(smc,rxd,frag_count); + } + smt_free_mbuf(smc,mb) ; + break ; + default : + /* + * unknown FC abord the frame + */ + DB_RX("unknown FC error",0,0,2) ; + smt_free_mbuf(smc,mb) ; + DB_RX("requeue RxD",0,0,5) ; + mac_drv_requeue_rxd(smc,rxd,frag_count) ; + if ((fc & 0xf0) == FC_MAC) + smc->hw.fp.err_stats.err_mac_frame++ ; + else + smc->hw.fp.err_stats.err_imp_frame++ ; + + break ; + } + } + + DB_RX("next RxD is %x ",queue->rx_curr_get,0,3) ; + NDD_TRACE("RHx1",queue->rx_curr_get,0,0) ; + + continue ; + /*--------------------------------------------------------------------*/ +abort_frame: + DB_RX("requeue RxD",0,0,5) ; + mac_drv_requeue_rxd(smc,rxd,frag_count) ; + + DB_RX("next RxD is %x ",queue->rx_curr_get,0,3) ; + NDD_TRACE("RHx2",queue->rx_curr_get,0,0) ; + } +rx_end: +#ifdef ALL_RX_COMPLETE + mac_drv_all_receives_complete(smc) ; +#endif + return ; /* lint bug: needs return detect end of function */ +} + +static void smt_to_llc(struct s_smc *smc, SMbuf *mb) +{ + u_char fc ; + + DB_RX("send a queued frame to the llc layer",0,0,4) ; + smc->os.hwm.r.len = mb->sm_len ; + smc->os.hwm.r.mb_pos = smtod(mb,char *) ; + fc = *smc->os.hwm.r.mb_pos ; + (void)mac_drv_rx_init(smc,(int)mb->sm_len,(int)fc, + smc->os.hwm.r.mb_pos,(int)mb->sm_len) ; + smt_free_mbuf(smc,mb) ; +} + +/* + * BEGIN_MANUAL_ENTRY(hwm_rx_frag) + * void hwm_rx_frag(smc,virt,phys,len,frame_status) + * + * function MACRO (hardware module, hwmtm.h) + * This function calls dma_master for preparing the + * system hardware for the DMA transfer and initializes + * the current RxD with the length and the physical and + * virtual address of the fragment. Furthermore, it sets the + * STF and EOF bits depending on the frame status byte, + * switches the OWN flag of the RxD, so that it is owned by the + * adapter and issues an rx_start. + * + * para virt virtual pointer to the fragment + * len the length of the fragment + * frame_status status of the frame, see design description + * + * NOTE: It is possible to call this function with a fragment length + * of zero. + * + * END_MANUAL_ENTRY + */ +void hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len, + int frame_status) +{ + struct s_smt_fp_rxd volatile *r ; + __le32 rbctrl; + + NDD_TRACE("RHfB",virt,len,frame_status) ; + DB_RX("hwm_rx_frag: len = %d, frame_status = %x\n",len,frame_status,2) ; + r = smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put ; + r->rxd_virt = virt ; + r->rxd_rbadr = cpu_to_le32(phys) ; + rbctrl = cpu_to_le32( (((__u32)frame_status & + (FIRST_FRAG|LAST_FRAG))<<26) | + (((u_long) frame_status & FIRST_FRAG) << 21) | + BMU_OWN | BMU_CHECK | BMU_EN_IRQ_EOF | len) ; + r->rxd_rbctrl = rbctrl ; + + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; + outpd(ADDR(B0_R1_CSR),CSR_START) ; + smc->hw.fp.rx_q[QUEUE_R1].rx_free-- ; + smc->hw.fp.rx_q[QUEUE_R1].rx_used++ ; + smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put = r->rxd_next ; + NDD_TRACE("RHfE",r,le32_to_cpu(r->rxd_rbadr),0) ; +} + +/* + * BEGINN_MANUAL_ENTRY(mac_drv_clear_rx_queue) + * + * void mac_drv_clear_rx_queue(smc) + * struct s_smc *smc ; + * + * function DOWNCALL (hardware module, hwmtm.c) + * mac_drv_clear_rx_queue is called by the OS-specific module + * after it has issued a card_stop. + * In this case, the frames in the receive queue are obsolete and + * should be removed. For removing mac_drv_clear_rx_queue + * calls dma_master for each RxD and mac_drv_clear_rxd for each + * receive buffer. + * + * NOTE: calling sequence card_stop: + * CLI_FBI(), card_stop(), + * mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(), + * + * NOTE: The caller is responsible that the BMUs are idle + * when this function is called. + * + * END_MANUAL_ENTRY + */ +void mac_drv_clear_rx_queue(struct s_smc *smc) +{ + struct s_smt_fp_rxd volatile *r ; + struct s_smt_fp_rxd volatile *next_rxd ; + struct s_smt_rx_queue *queue ; + int frag_count ; + int i ; + + if (smc->hw.hw_state != STOPPED) { + SK_BREAK() ; + SMT_PANIC(smc,HWM_E0012,HWM_E0012_MSG) ; + return ; + } + + queue = smc->hw.fp.rx[QUEUE_R1] ; + DB_RX("clear_rx_queue",0,0,5) ; + + /* + * dma_complete and mac_drv_clear_rxd for all RxDs / receive buffers + */ + r = queue->rx_curr_get ; + while (queue->rx_used) { + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + DB_RX("switch OWN bit of RxD 0x%x ",r,0,5) ; + r->rxd_rbctrl &= ~cpu_to_le32(BMU_OWN) ; + frag_count = 1 ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; + r = r->rxd_next ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + while (r != queue->rx_curr_put && + !(r->rxd_rbctrl & cpu_to_le32(BMU_ST_BUF))) { + DB_RX("Check STF bit in %x",(void *)r,0,5) ; + r->rxd_rbctrl &= ~cpu_to_le32(BMU_OWN) ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; + r = r->rxd_next ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + frag_count++ ; + } + DB_RX("STF bit found",0,0,5) ; + next_rxd = r ; + + for (r=queue->rx_curr_get,i=frag_count; i ; r=r->rxd_next,i--){ + DB_RX("dma_complete for RxD %x",(void *)r,0,5) ; + dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR); + } + + DB_RX("mac_drv_clear_rxd: RxD %x frag_count %d ", + (void *)queue->rx_curr_get,frag_count,5) ; + mac_drv_clear_rxd(smc,queue->rx_curr_get,frag_count) ; + + queue->rx_curr_get = next_rxd ; + queue->rx_used -= frag_count ; + queue->rx_free += frag_count ; + } +} + + +/* + ------------------------------------------------------------- + SEND FUNCTIONS: + ------------------------------------------------------------- +*/ + +/* + * BEGIN_MANUAL_ENTRY(hwm_tx_init) + * int hwm_tx_init(smc,fc,frag_count,frame_len,frame_status) + * + * function DOWN_CALL (hardware module, hwmtm.c) + * hwm_tx_init checks if the frame can be sent through the + * corresponding send queue. + * + * para fc the frame control. To determine through which + * send queue the frame should be transmitted. + * 0x50 - 0x57: asynchronous LLC frame + * 0xD0 - 0xD7: synchronous LLC frame + * 0x41, 0x4F: SMT frame to the network + * 0x42: SMT frame to the network and to the local SMT + * 0x43: SMT frame to the local SMT + * frag_count count of the fragments for this frame + * frame_len length of the frame + * frame_status status of the frame, the send queue bit is already + * specified + * + * return frame_status + * + * END_MANUAL_ENTRY + */ +int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, int frame_len, + int frame_status) +{ + NDD_TRACE("THiB",fc,frag_count,frame_len) ; + smc->os.hwm.tx_p = smc->hw.fp.tx[frame_status & QUEUE_A0] ; + smc->os.hwm.tx_descr = TX_DESCRIPTOR | (((u_long)(frame_len-1)&3)<<27) ; + smc->os.hwm.tx_len = frame_len ; + DB_TX("hwm_tx_init: fc = %x, len = %d",fc,frame_len,3) ; + if ((fc & ~(FC_SYNC_BIT|FC_LLC_PRIOR)) == FC_ASYNC_LLC) { + frame_status |= LAN_TX ; + } + else { + switch (fc) { + case FC_SMT_INFO : + case FC_SMT_NSA : + frame_status |= LAN_TX ; + break ; + case FC_SMT_LOC : + frame_status |= LOC_TX ; + break ; + case FC_SMT_LAN_LOC : + frame_status |= LAN_TX | LOC_TX ; + break ; + default : + SMT_PANIC(smc,HWM_E0010,HWM_E0010_MSG) ; + } + } + if (!smc->hw.mac_ring_is_up) { + frame_status &= ~LAN_TX ; + frame_status |= RING_DOWN ; + DB_TX("Ring is down: terminate LAN_TX",0,0,2) ; + } + if (frag_count > smc->os.hwm.tx_p->tx_free) { +#ifndef NDIS_OS2 + mac_drv_clear_txd(smc) ; + if (frag_count > smc->os.hwm.tx_p->tx_free) { + DB_TX("Out of TxDs, terminate LAN_TX",0,0,2) ; + frame_status &= ~LAN_TX ; + frame_status |= OUT_OF_TXD ; + } +#else + DB_TX("Out of TxDs, terminate LAN_TX",0,0,2) ; + frame_status &= ~LAN_TX ; + frame_status |= OUT_OF_TXD ; +#endif + } + DB_TX("frame_status = %x",frame_status,0,3) ; + NDD_TRACE("THiE",frame_status,smc->os.hwm.tx_p->tx_free,0) ; + return frame_status; +} + +/* + * BEGIN_MANUAL_ENTRY(hwm_tx_frag) + * void hwm_tx_frag(smc,virt,phys,len,frame_status) + * + * function DOWNCALL (hardware module, hwmtm.c) + * If the frame should be sent to the LAN, this function calls + * dma_master, fills the current TxD with the virtual and the + * physical address, sets the STF and EOF bits dependent on + * the frame status, and requests the BMU to start the + * transmit. + * If the frame should be sent to the local SMT, an SMT_MBuf + * is allocated if the FIRST_FRAG bit is set in the frame_status. + * The fragment of the frame is copied into the SMT MBuf. + * The function smt_received_pack is called if the LAST_FRAG + * bit is set in the frame_status word. + * + * para virt virtual pointer to the fragment + * len the length of the fragment + * frame_status status of the frame, see design description + * + * return nothing returned, no parameter is modified + * + * NOTE: It is possible to invoke this macro with a fragment length + * of zero. + * + * END_MANUAL_ENTRY + */ +void hwm_tx_frag(struct s_smc *smc, char far *virt, u_long phys, int len, + int frame_status) +{ + struct s_smt_fp_txd volatile *t ; + struct s_smt_tx_queue *queue ; + __le32 tbctrl ; + + queue = smc->os.hwm.tx_p ; + + NDD_TRACE("THfB",virt,len,frame_status) ; + /* Bug fix: AF / May 31 1999 (#missing) + * snmpinfo problem reported by IBM is caused by invalid + * t-pointer (txd) if LAN_TX is not set but LOC_TX only. + * Set: t = queue->tx_curr_put here ! + */ + t = queue->tx_curr_put ; + + DB_TX("hwm_tx_frag: len = %d, frame_status = %x ",len,frame_status,2) ; + if (frame_status & LAN_TX) { + /* '*t' is already defined */ + DB_TX("LAN_TX: TxD = %x, virt = %x ",t,virt,3) ; + t->txd_virt = virt ; + t->txd_txdscr = cpu_to_le32(smc->os.hwm.tx_descr) ; + t->txd_tbadr = cpu_to_le32(phys) ; + tbctrl = cpu_to_le32((((__u32)frame_status & + (FIRST_FRAG|LAST_FRAG|EN_IRQ_EOF))<< 26) | + BMU_OWN|BMU_CHECK |len) ; + t->txd_tbctrl = tbctrl ; + +#ifndef AIX + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + outpd(queue->tx_bmu_ctl,CSR_START) ; +#else /* ifndef AIX */ + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + if (frame_status & QUEUE_A0) { + outpd(ADDR(B0_XA_CSR),CSR_START) ; + } + else { + outpd(ADDR(B0_XS_CSR),CSR_START) ; + } +#endif + queue->tx_free-- ; + queue->tx_used++ ; + queue->tx_curr_put = t->txd_next ; + if (frame_status & LAST_FRAG) { + smc->mib.m[MAC0].fddiMACTransmit_Ct++ ; + } + } + if (frame_status & LOC_TX) { + DB_TX("LOC_TX: ",0,0,3) ; + if (frame_status & FIRST_FRAG) { + if(!(smc->os.hwm.tx_mb = smt_get_mbuf(smc))) { + smc->hw.fp.err_stats.err_no_buf++ ; + DB_TX("No SMbuf; transmit terminated",0,0,4) ; + } + else { + smc->os.hwm.tx_data = + smtod(smc->os.hwm.tx_mb,char *) - 1 ; +#ifdef USE_OS_CPY +#ifdef PASS_1ST_TXD_2_TX_COMP + hwm_cpy_txd2mb(t,smc->os.hwm.tx_data, + smc->os.hwm.tx_len) ; +#endif +#endif + } + } + if (smc->os.hwm.tx_mb) { +#ifndef USE_OS_CPY + DB_TX("copy fragment into MBuf ",0,0,3) ; + memcpy(smc->os.hwm.tx_data,virt,len) ; + smc->os.hwm.tx_data += len ; +#endif + if (frame_status & LAST_FRAG) { +#ifdef USE_OS_CPY +#ifndef PASS_1ST_TXD_2_TX_COMP + /* + * hwm_cpy_txd2mb(txd,data,len) copies 'len' + * bytes from the virtual pointer in 'rxd' + * to 'data'. The virtual pointer of the + * os-specific tx-buffer should be written + * in the LAST txd. + */ + hwm_cpy_txd2mb(t,smc->os.hwm.tx_data, + smc->os.hwm.tx_len) ; +#endif /* nPASS_1ST_TXD_2_TX_COMP */ +#endif /* USE_OS_CPY */ + smc->os.hwm.tx_data = + smtod(smc->os.hwm.tx_mb,char *) - 1 ; + *(char *)smc->os.hwm.tx_mb->sm_data = + *smc->os.hwm.tx_data ; + smc->os.hwm.tx_data++ ; + smc->os.hwm.tx_mb->sm_len = + smc->os.hwm.tx_len - 1 ; + DB_TX("pass LLC frame to SMT ",0,0,3) ; + smt_received_pack(smc,smc->os.hwm.tx_mb, + RD_FS_LOCAL) ; + } + } + } + NDD_TRACE("THfE",t,queue->tx_free,0) ; +} + + +/* + * queues a receive for later send + */ +static void queue_llc_rx(struct s_smc *smc, SMbuf *mb) +{ + DB_GEN("queue_llc_rx: mb = %x",(void *)mb,0,4) ; + smc->os.hwm.queued_rx_frames++ ; + mb->sm_next = (SMbuf *)NULL ; + if (smc->os.hwm.llc_rx_pipe == NULL) { + smc->os.hwm.llc_rx_pipe = mb ; + } + else { + smc->os.hwm.llc_rx_tail->sm_next = mb ; + } + smc->os.hwm.llc_rx_tail = mb ; + + /* + * force an timer IRQ to receive the data + */ + if (!smc->os.hwm.isr_flag) { + smt_force_irq(smc) ; + } +} + +/* + * get a SMbuf from the llc_rx_queue + */ +static SMbuf *get_llc_rx(struct s_smc *smc) +{ + SMbuf *mb ; + + if ((mb = smc->os.hwm.llc_rx_pipe)) { + smc->os.hwm.queued_rx_frames-- ; + smc->os.hwm.llc_rx_pipe = mb->sm_next ; + } + DB_GEN("get_llc_rx: mb = 0x%x",(void *)mb,0,4) ; + return mb; +} + +/* + * queues a transmit SMT MBuf during the time were the MBuf is + * queued the TxD ring + */ +static void queue_txd_mb(struct s_smc *smc, SMbuf *mb) +{ + DB_GEN("_rx: queue_txd_mb = %x",(void *)mb,0,4) ; + smc->os.hwm.queued_txd_mb++ ; + mb->sm_next = (SMbuf *)NULL ; + if (smc->os.hwm.txd_tx_pipe == NULL) { + smc->os.hwm.txd_tx_pipe = mb ; + } + else { + smc->os.hwm.txd_tx_tail->sm_next = mb ; + } + smc->os.hwm.txd_tx_tail = mb ; +} + +/* + * get a SMbuf from the txd_tx_queue + */ +static SMbuf *get_txd_mb(struct s_smc *smc) +{ + SMbuf *mb ; + + if ((mb = smc->os.hwm.txd_tx_pipe)) { + smc->os.hwm.queued_txd_mb-- ; + smc->os.hwm.txd_tx_pipe = mb->sm_next ; + } + DB_GEN("get_txd_mb: mb = 0x%x",(void *)mb,0,4) ; + return mb; +} + +/* + * SMT Send function + */ +void smt_send_mbuf(struct s_smc *smc, SMbuf *mb, int fc) +{ + char far *data ; + int len ; + int n ; + int i ; + int frag_count ; + int frame_status ; + SK_LOC_DECL(char far,*virt[3]) ; + int frag_len[3] ; + struct s_smt_tx_queue *queue ; + struct s_smt_fp_txd volatile *t ; + u_long phys ; + __le32 tbctrl; + + NDD_TRACE("THSB",mb,fc,0) ; + DB_TX("smt_send_mbuf: mb = 0x%x, fc = 0x%x",mb,fc,4) ; + + mb->sm_off-- ; /* set to fc */ + mb->sm_len++ ; /* + fc */ + data = smtod(mb,char *) ; + *data = fc ; + if (fc == FC_SMT_LOC) + *data = FC_SMT_INFO ; + + /* + * determine the frag count and the virt addresses of the frags + */ + frag_count = 0 ; + len = mb->sm_len ; + while (len) { + n = SMT_PAGESIZE - ((long)data & (SMT_PAGESIZE-1)) ; + if (n >= len) { + n = len ; + } + DB_TX("frag: virt/len = 0x%x/%d ",(void *)data,n,5) ; + virt[frag_count] = data ; + frag_len[frag_count] = n ; + frag_count++ ; + len -= n ; + data += n ; + } + + /* + * determine the frame status + */ + queue = smc->hw.fp.tx[QUEUE_A0] ; + if (fc == FC_BEACON || fc == FC_SMT_LOC) { + frame_status = LOC_TX ; + } + else { + frame_status = LAN_TX ; + if ((smc->os.hwm.pass_NSA &&(fc == FC_SMT_NSA)) || + (smc->os.hwm.pass_SMT &&(fc == FC_SMT_INFO))) + frame_status |= LOC_TX ; + } + + if (!smc->hw.mac_ring_is_up || frag_count > queue->tx_free) { + frame_status &= ~LAN_TX; + if (frame_status) { + DB_TX("Ring is down: terminate LAN_TX",0,0,2) ; + } + else { + DB_TX("Ring is down: terminate transmission",0,0,2) ; + smt_free_mbuf(smc,mb) ; + return ; + } + } + DB_TX("frame_status = 0x%x ",frame_status,0,5) ; + + if ((frame_status & LAN_TX) && (frame_status & LOC_TX)) { + mb->sm_use_count = 2 ; + } + + if (frame_status & LAN_TX) { + t = queue->tx_curr_put ; + frame_status |= FIRST_FRAG ; + for (i = 0; i < frag_count; i++) { + DB_TX("init TxD = 0x%x",(void *)t,0,5) ; + if (i == frag_count-1) { + frame_status |= LAST_FRAG ; + t->txd_txdscr = cpu_to_le32(TX_DESCRIPTOR | + (((__u32)(mb->sm_len-1)&3) << 27)) ; + } + t->txd_virt = virt[i] ; + phys = dma_master(smc, (void far *)virt[i], + frag_len[i], DMA_RD|SMT_BUF) ; + t->txd_tbadr = cpu_to_le32(phys) ; + tbctrl = cpu_to_le32((((__u32)frame_status & + (FIRST_FRAG|LAST_FRAG)) << 26) | + BMU_OWN | BMU_CHECK | BMU_SMT_TX |frag_len[i]) ; + t->txd_tbctrl = tbctrl ; +#ifndef AIX + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + outpd(queue->tx_bmu_ctl,CSR_START) ; +#else + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + outpd(ADDR(B0_XA_CSR),CSR_START) ; +#endif + frame_status &= ~FIRST_FRAG ; + queue->tx_curr_put = t = t->txd_next ; + queue->tx_free-- ; + queue->tx_used++ ; + } + smc->mib.m[MAC0].fddiMACTransmit_Ct++ ; + queue_txd_mb(smc,mb) ; + } + + if (frame_status & LOC_TX) { + DB_TX("pass Mbuf to LLC queue",0,0,5) ; + queue_llc_rx(smc,mb) ; + } + + /* + * We need to unqueue the free SMT_MBUFs here, because it may + * be that the SMT want's to send more than 1 frame for one down call + */ + mac_drv_clear_txd(smc) ; + NDD_TRACE("THSE",t,queue->tx_free,frag_count) ; +} + +/* BEGIN_MANUAL_ENTRY(mac_drv_clear_txd) + * void mac_drv_clear_txd(smc) + * + * function DOWNCALL (hardware module, hwmtm.c) + * mac_drv_clear_txd searches in both send queues for TxD's + * which were finished by the adapter. It calls dma_complete + * for each TxD. If the last fragment of an LLC frame is + * reached, it calls mac_drv_tx_complete to release the + * send buffer. + * + * return nothing + * + * END_MANUAL_ENTRY + */ +static void mac_drv_clear_txd(struct s_smc *smc) +{ + struct s_smt_tx_queue *queue ; + struct s_smt_fp_txd volatile *t1 ; + struct s_smt_fp_txd volatile *t2 = NULL ; + SMbuf *mb ; + u_long tbctrl ; + int i ; + int frag_count ; + int n ; + + NDD_TRACE("THcB",0,0,0) ; + for (i = QUEUE_S; i <= QUEUE_A0; i++) { + queue = smc->hw.fp.tx[i] ; + t1 = queue->tx_curr_get ; + DB_TX("clear_txd: QUEUE = %d (0=sync/1=async)",i,0,5) ; + + for ( ; ; ) { + frag_count = 0 ; + + do { + DRV_BUF_FLUSH(t1,DDI_DMA_SYNC_FORCPU) ; + DB_TX("check OWN/EOF bit of TxD 0x%x",t1,0,5) ; + tbctrl = le32_to_cpu(CR_READ(t1->txd_tbctrl)); + + if (tbctrl & BMU_OWN || !queue->tx_used){ + DB_TX("End of TxDs queue %d",i,0,4) ; + goto free_next_queue ; /* next queue */ + } + t1 = t1->txd_next ; + frag_count++ ; + } while (!(tbctrl & BMU_EOF)) ; + + t1 = queue->tx_curr_get ; + for (n = frag_count; n; n--) { + tbctrl = le32_to_cpu(t1->txd_tbctrl) ; + dma_complete(smc, + (union s_fp_descr volatile *) t1, + (int) (DMA_RD | + ((tbctrl & BMU_SMT_TX) >> 18))) ; + t2 = t1 ; + t1 = t1->txd_next ; + } + + if (tbctrl & BMU_SMT_TX) { + mb = get_txd_mb(smc) ; + smt_free_mbuf(smc,mb) ; + } + else { +#ifndef PASS_1ST_TXD_2_TX_COMP + DB_TX("mac_drv_tx_comp for TxD 0x%x",t2,0,4) ; + mac_drv_tx_complete(smc,t2) ; +#else + DB_TX("mac_drv_tx_comp for TxD 0x%x", + queue->tx_curr_get,0,4) ; + mac_drv_tx_complete(smc,queue->tx_curr_get) ; +#endif + } + queue->tx_curr_get = t1 ; + queue->tx_free += frag_count ; + queue->tx_used -= frag_count ; + } +free_next_queue: ; + } + NDD_TRACE("THcE",0,0,0) ; +} + +/* + * BEGINN_MANUAL_ENTRY(mac_drv_clear_tx_queue) + * + * void mac_drv_clear_tx_queue(smc) + * struct s_smc *smc ; + * + * function DOWNCALL (hardware module, hwmtm.c) + * mac_drv_clear_tx_queue is called from the SMT when + * the RMT state machine has entered the ISOLATE state. + * This function is also called by the os-specific module + * after it has called the function card_stop(). + * In this case, the frames in the send queues are obsolete and + * should be removed. + * + * note calling sequence: + * CLI_FBI(), card_stop(), + * mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(), + * + * NOTE: The caller is responsible that the BMUs are idle + * when this function is called. + * + * END_MANUAL_ENTRY + */ +void mac_drv_clear_tx_queue(struct s_smc *smc) +{ + struct s_smt_fp_txd volatile *t ; + struct s_smt_tx_queue *queue ; + int tx_used ; + int i ; + + if (smc->hw.hw_state != STOPPED) { + SK_BREAK() ; + SMT_PANIC(smc,HWM_E0011,HWM_E0011_MSG) ; + return ; + } + + for (i = QUEUE_S; i <= QUEUE_A0; i++) { + queue = smc->hw.fp.tx[i] ; + DB_TX("clear_tx_queue: QUEUE = %d (0=sync/1=async)",i,0,5) ; + + /* + * switch the OWN bit of all pending frames to the host + */ + t = queue->tx_curr_get ; + tx_used = queue->tx_used ; + while (tx_used) { + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ; + DB_TX("switch OWN bit of TxD 0x%x ",t,0,5) ; + t->txd_tbctrl &= ~cpu_to_le32(BMU_OWN) ; + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + t = t->txd_next ; + tx_used-- ; + } + } + + /* + * release all TxD's for both send queues + */ + mac_drv_clear_txd(smc) ; + + for (i = QUEUE_S; i <= QUEUE_A0; i++) { + queue = smc->hw.fp.tx[i] ; + t = queue->tx_curr_get ; + + /* + * write the phys pointer of the NEXT descriptor into the + * BMU's current address descriptor pointer and set + * tx_curr_get and tx_curr_put to this position + */ + if (i == QUEUE_S) { + outpd(ADDR(B5_XS_DA),le32_to_cpu(t->txd_ntdadr)) ; + } + else { + outpd(ADDR(B5_XA_DA),le32_to_cpu(t->txd_ntdadr)) ; + } + + queue->tx_curr_put = queue->tx_curr_get->txd_next ; + queue->tx_curr_get = queue->tx_curr_put ; + } +} + + +/* + ------------------------------------------------------------- + TEST FUNCTIONS: + ------------------------------------------------------------- +*/ + +#ifdef DEBUG +/* + * BEGIN_MANUAL_ENTRY(mac_drv_debug_lev) + * void mac_drv_debug_lev(smc,flag,lev) + * + * function DOWNCALL (drvsr.c) + * To get a special debug info the user can assign a debug level + * to any debug flag. + * + * para flag debug flag, possible values are: + * = 0: reset all debug flags (the defined level is + * ignored) + * = 1: debug.d_smtf + * = 2: debug.d_smt + * = 3: debug.d_ecm + * = 4: debug.d_rmt + * = 5: debug.d_cfm + * = 6: debug.d_pcm + * + * = 10: debug.d_os.hwm_rx (hardware module receive path) + * = 11: debug.d_os.hwm_tx(hardware module transmit path) + * = 12: debug.d_os.hwm_gen(hardware module general flag) + * + * lev debug level + * + * END_MANUAL_ENTRY + */ +void mac_drv_debug_lev(struct s_smc *smc, int flag, int lev) +{ + switch(flag) { + case (int)NULL: + DB_P.d_smtf = DB_P.d_smt = DB_P.d_ecm = DB_P.d_rmt = 0 ; + DB_P.d_cfm = 0 ; + DB_P.d_os.hwm_rx = DB_P.d_os.hwm_tx = DB_P.d_os.hwm_gen = 0 ; +#ifdef SBA + DB_P.d_sba = 0 ; +#endif +#ifdef ESS + DB_P.d_ess = 0 ; +#endif + break ; + case DEBUG_SMTF: + DB_P.d_smtf = lev ; + break ; + case DEBUG_SMT: + DB_P.d_smt = lev ; + break ; + case DEBUG_ECM: + DB_P.d_ecm = lev ; + break ; + case DEBUG_RMT: + DB_P.d_rmt = lev ; + break ; + case DEBUG_CFM: + DB_P.d_cfm = lev ; + break ; + case DEBUG_PCM: + DB_P.d_pcm = lev ; + break ; + case DEBUG_SBA: +#ifdef SBA + DB_P.d_sba = lev ; +#endif + break ; + case DEBUG_ESS: +#ifdef ESS + DB_P.d_ess = lev ; +#endif + break ; + case DB_HWM_RX: + DB_P.d_os.hwm_rx = lev ; + break ; + case DB_HWM_TX: + DB_P.d_os.hwm_tx = lev ; + break ; + case DB_HWM_GEN: + DB_P.d_os.hwm_gen = lev ; + break ; + default: + break ; + } +} +#endif diff --git a/drivers/net/fddi/skfp/hwt.c b/drivers/net/fddi/skfp/hwt.c new file mode 100644 index 0000000..c0798fd --- /dev/null +++ b/drivers/net/fddi/skfp/hwt.c @@ -0,0 +1,269 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * Timer Driver for FBI board (timer chip 82C54) + */ + +/* + * Modifications: + * + * 28-Jun-1994 sw Edit v1.6. + * MCA: Added support for the SK-NET FDDI-FM2 adapter. The + * following functions have been added(+) or modified(*): + * hwt_start(*), hwt_stop(*), hwt_restart(*), hwt_read(*) + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)hwt.c 1.13 97/04/23 (C) SK " ; +#endif + +/* + * Prototypes of local functions. + */ +/* 28-Jun-1994 sw - Note: hwt_restart() is also used in module 'drvfbi.c'. */ +/*static void hwt_restart() ; */ + +/************************ + * + * hwt_start + * + * Start hardware timer (clock ticks are 16us). + * + * void hwt_start( + * struct s_smc *smc, + * u_long time) ; + * In + * smc - A pointer to the SMT Context structure. + * + * time - The time in units of 16us to load the timer with. + * Out + * Nothing. + * + ************************/ +#define HWT_MAX (65000) + +void hwt_start(struct s_smc *smc, u_long time) +{ + u_short cnt ; + + if (time > HWT_MAX) + time = HWT_MAX ; + + smc->hw.t_start = time ; + smc->hw.t_stop = 0L ; + + cnt = (u_short)time ; + /* + * if time < 16 us + * time = 16 us + */ + if (!cnt) + cnt++ ; + + outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ; /* Load timer value. */ + outpw(ADDR(B2_TI_CRTL), TIM_START) ; /* Start timer. */ + + smc->hw.timer_activ = TRUE ; +} + +/************************ + * + * hwt_stop + * + * Stop hardware timer. + * + * void hwt_stop( + * struct s_smc *smc) ; + * In + * smc - A pointer to the SMT Context structure. + * Out + * Nothing. + * + ************************/ +void hwt_stop(struct s_smc *smc) +{ + outpw(ADDR(B2_TI_CRTL), TIM_STOP) ; + outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ; + + smc->hw.timer_activ = FALSE ; +} + +/************************ + * + * hwt_init + * + * Initialize hardware timer. + * + * void hwt_init( + * struct s_smc *smc) ; + * In + * smc - A pointer to the SMT Context structure. + * Out + * Nothing. + * + ************************/ +void hwt_init(struct s_smc *smc) +{ + smc->hw.t_start = 0 ; + smc->hw.t_stop = 0 ; + smc->hw.timer_activ = FALSE ; + + hwt_restart(smc) ; +} + +/************************ + * + * hwt_restart + * + * Clear timer interrupt. + * + * void hwt_restart( + * struct s_smc *smc) ; + * In + * smc - A pointer to the SMT Context structure. + * Out + * Nothing. + * + ************************/ +void hwt_restart(struct s_smc *smc) +{ + hwt_stop(smc) ; +} + +/************************ + * + * hwt_read + * + * Stop hardware timer and read time elapsed since last start. + * + * u_long hwt_read(smc) ; + * In + * smc - A pointer to the SMT Context structure. + * Out + * The elapsed time since last start in units of 16us. + * + ************************/ +u_long hwt_read(struct s_smc *smc) +{ + u_short tr ; + u_long is ; + + if (smc->hw.timer_activ) { + hwt_stop(smc) ; + tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ; + + is = GET_ISR() ; + /* Check if timer expired (or wraparound). */ + if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) { + hwt_restart(smc) ; + smc->hw.t_stop = smc->hw.t_start ; + } + else + smc->hw.t_stop = smc->hw.t_start - tr ; + } + return smc->hw.t_stop; +} + +#ifdef PCI +/************************ + * + * hwt_quick_read + * + * Stop hardware timer and read timer value and start the timer again. + * + * u_long hwt_read(smc) ; + * In + * smc - A pointer to the SMT Context structure. + * Out + * current timer value in units of 80ns. + * + ************************/ +u_long hwt_quick_read(struct s_smc *smc) +{ + u_long interval ; + u_long time ; + + interval = inpd(ADDR(B2_TI_INI)) ; + outpw(ADDR(B2_TI_CRTL), TIM_STOP) ; + time = inpd(ADDR(B2_TI_VAL)) ; + outpd(ADDR(B2_TI_INI),time) ; + outpw(ADDR(B2_TI_CRTL), TIM_START) ; + outpd(ADDR(B2_TI_INI),interval) ; + + return time; +} + +/************************ + * + * hwt_wait_time(smc,start,duration) + * + * This function returnes after the amount of time is elapsed + * since the start time. + * + * para start start time + * duration time to wait + * + * NOTE: The function will return immediately, if the timer is not + * started + ************************/ +void hwt_wait_time(struct s_smc *smc, u_long start, long int duration) +{ + long diff ; + long interval ; + int wrapped ; + + /* + * check if timer is running + */ + if (smc->hw.timer_activ == FALSE || + hwt_quick_read(smc) == hwt_quick_read(smc)) { + return ; + } + + interval = inpd(ADDR(B2_TI_INI)) ; + if (interval > duration) { + do { + diff = (long)(start - hwt_quick_read(smc)) ; + if (diff < 0) { + diff += interval ; + } + } while (diff <= duration) ; + } + else { + diff = interval ; + wrapped = 0 ; + do { + if (!wrapped) { + if (hwt_quick_read(smc) >= start) { + diff += interval ; + wrapped = 1 ; + } + } + else { + if (hwt_quick_read(smc) < start) { + wrapped = 0 ; + } + } + } while (diff <= duration) ; + } +} +#endif + diff --git a/drivers/net/fddi/skfp/pcmplc.c b/drivers/net/fddi/skfp/pcmplc.c new file mode 100644 index 0000000..88d02d0 --- /dev/null +++ b/drivers/net/fddi/skfp/pcmplc.c @@ -0,0 +1,2014 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + PCM + Physical Connection Management +*/ + +/* + * Hardware independent state machine implemantation + * The following external SMT functions are referenced : + * + * queue_event() + * smt_timer_start() + * smt_timer_stop() + * + * The following external HW dependent functions are referenced : + * sm_pm_control() + * sm_ph_linestate() + * sm_pm_ls_latch() + * + * The following HW dependent events are required : + * PC_QLS + * PC_ILS + * PC_HLS + * PC_MLS + * PC_NSE + * PC_LEM + * + */ + + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/supern_2.h" +#define KERNEL +#include "h/smtstate.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)pcmplc.c 2.55 99/08/05 (C) SK " ; +#endif + +#ifdef FDDI_MIB +extern int snmp_fddi_trap( +#ifdef ANSIC +struct s_smc * smc, int type, int index +#endif +); +#endif +#ifdef CONCENTRATOR +extern int plc_is_installed( +#ifdef ANSIC +struct s_smc *smc , +int p +#endif +) ; +#endif +/* + * FSM Macros + */ +#define AFLAG (0x20) +#define GO_STATE(x) (mib->fddiPORTPCMState = (x)|AFLAG) +#define ACTIONS_DONE() (mib->fddiPORTPCMState &= ~AFLAG) +#define ACTIONS(x) (x|AFLAG) + +/* + * PCM states + */ +#define PC0_OFF 0 +#define PC1_BREAK 1 +#define PC2_TRACE 2 +#define PC3_CONNECT 3 +#define PC4_NEXT 4 +#define PC5_SIGNAL 5 +#define PC6_JOIN 6 +#define PC7_VERIFY 7 +#define PC8_ACTIVE 8 +#define PC9_MAINT 9 + +#ifdef DEBUG +/* + * symbolic state names + */ +static const char * const pcm_states[] = { + "PC0_OFF","PC1_BREAK","PC2_TRACE","PC3_CONNECT","PC4_NEXT", + "PC5_SIGNAL","PC6_JOIN","PC7_VERIFY","PC8_ACTIVE","PC9_MAINT" +} ; + +/* + * symbolic event names + */ +static const char * const pcm_events[] = { + "NONE","PC_START","PC_STOP","PC_LOOP","PC_JOIN","PC_SIGNAL", + "PC_REJECT","PC_MAINT","PC_TRACE","PC_PDR", + "PC_ENABLE","PC_DISABLE", + "PC_QLS","PC_ILS","PC_MLS","PC_HLS","PC_LS_PDR","PC_LS_NONE", + "PC_TIMEOUT_TB_MAX","PC_TIMEOUT_TB_MIN", + "PC_TIMEOUT_C_MIN","PC_TIMEOUT_T_OUT", + "PC_TIMEOUT_TL_MIN","PC_TIMEOUT_T_NEXT","PC_TIMEOUT_LCT", + "PC_NSE","PC_LEM" +} ; +#endif + +#ifdef MOT_ELM +/* + * PCL-S control register + * this register in the PLC-S controls the scrambling parameters + */ +#define PLCS_CONTROL_C_U 0 +#define PLCS_CONTROL_C_S (PL_C_SDOFF_ENABLE | PL_C_SDON_ENABLE | \ + PL_C_CIPHER_ENABLE) +#define PLCS_FASSERT_U 0 +#define PLCS_FASSERT_S 0xFd76 /* 52.0 us */ +#define PLCS_FDEASSERT_U 0 +#define PLCS_FDEASSERT_S 0 +#else /* nMOT_ELM */ +/* + * PCL-S control register + * this register in the PLC-S controls the scrambling parameters + * can be patched for ANSI compliance if standard changes + */ +static const u_char plcs_control_c_u[17] = "PLC_CNTRL_C_U=\0\0" ; +static const u_char plcs_control_c_s[17] = "PLC_CNTRL_C_S=\01\02" ; + +#define PLCS_CONTROL_C_U (plcs_control_c_u[14] | (plcs_control_c_u[15]<<8)) +#define PLCS_CONTROL_C_S (plcs_control_c_s[14] | (plcs_control_c_s[15]<<8)) +#endif /* nMOT_ELM */ + +/* + * external vars + */ +/* struct definition see 'cmtdef.h' (also used by CFM) */ + +#define PS_OFF 0 +#define PS_BIT3 1 +#define PS_BIT4 2 +#define PS_BIT7 3 +#define PS_LCT 4 +#define PS_BIT8 5 +#define PS_JOIN 6 +#define PS_ACTIVE 7 + +#define LCT_LEM_MAX 255 + +/* + * PLC timing parameter + */ + +#define PLC_MS(m) ((int)((0x10000L-(m*100000L/2048)))) +#define SLOW_TL_MIN PLC_MS(6) +#define SLOW_C_MIN PLC_MS(10) + +static const struct plt { + int timer ; /* relative plc timer address */ + int para ; /* default timing parameters */ +} pltm[] = { + { PL_C_MIN, SLOW_C_MIN }, /* min t. to remain Connect State */ + { PL_TL_MIN, SLOW_TL_MIN }, /* min t. to transmit a Line State */ + { PL_TB_MIN, TP_TB_MIN }, /* min break time */ + { PL_T_OUT, TP_T_OUT }, /* Signaling timeout */ + { PL_LC_LENGTH, TP_LC_LENGTH }, /* Link Confidence Test Time */ + { PL_T_SCRUB, TP_T_SCRUB }, /* Scrub Time == MAC TVX time ! */ + { PL_NS_MAX, TP_NS_MAX }, /* max t. that noise is tolerated */ + { 0,0 } +} ; + +/* + * interrupt mask + */ +#ifdef SUPERNET_3 +/* + * Do we need the EBUF error during signaling, too, to detect SUPERNET_3 + * PLL bug? + */ +static const int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | + PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR; +#else /* SUPERNET_3 */ +/* + * We do NOT need the elasticity buffer error during signaling. + */ +static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | + PL_PCM_ENABLED | PL_SELF_TEST ; +#endif /* SUPERNET_3 */ +static const int plc_imsk_act = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | + PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR; + +/* internal functions */ +static void pcm_fsm(struct s_smc *smc, struct s_phy *phy, int cmd); +static void pc_rcode_actions(struct s_smc *smc, int bit, struct s_phy *phy); +static void pc_tcode_actions(struct s_smc *smc, const int bit, struct s_phy *phy); +static void reset_lem_struct(struct s_phy *phy); +static void plc_init(struct s_smc *smc, int p); +static void sm_ph_lem_start(struct s_smc *smc, int np, int threshold); +static void sm_ph_lem_stop(struct s_smc *smc, int np); +static void sm_ph_linestate(struct s_smc *smc, int phy, int ls); +static void real_init_plc(struct s_smc *smc); + +/* + * SMT timer interface + * start PCM timer 0 + */ +static void start_pcm_timer0(struct s_smc *smc, u_long value, int event, + struct s_phy *phy) +{ + phy->timer0_exp = FALSE ; /* clear timer event flag */ + smt_timer_start(smc,&phy->pcm_timer0,value, + EV_TOKEN(EVENT_PCM+phy->np,event)) ; +} +/* + * SMT timer interface + * stop PCM timer 0 + */ +static void stop_pcm_timer0(struct s_smc *smc, struct s_phy *phy) +{ + if (phy->pcm_timer0.tm_active) + smt_timer_stop(smc,&phy->pcm_timer0) ; +} + +/* + init PCM state machine (called by driver) + clear all PCM vars and flags +*/ +void pcm_init(struct s_smc *smc) +{ + int i ; + int np ; + struct s_phy *phy ; + struct fddi_mib_p *mib ; + + for (np = 0,phy = smc->y ; np < NUMPHYS ; np++,phy++) { + /* Indicates the type of PHY being used */ + mib = phy->mib ; + mib->fddiPORTPCMState = ACTIONS(PC0_OFF) ; + phy->np = np ; + switch (smc->s.sas) { +#ifdef CONCENTRATOR + case SMT_SAS : + mib->fddiPORTMy_Type = (np == PS) ? TS : TM ; + break ; + case SMT_DAS : + mib->fddiPORTMy_Type = (np == PA) ? TA : + (np == PB) ? TB : TM ; + break ; + case SMT_NAC : + mib->fddiPORTMy_Type = TM ; + break; +#else + case SMT_SAS : + mib->fddiPORTMy_Type = (np == PS) ? TS : TNONE ; + mib->fddiPORTHardwarePresent = (np == PS) ? TRUE : + FALSE ; +#ifndef SUPERNET_3 + smc->y[PA].mib->fddiPORTPCMState = PC0_OFF ; +#else + smc->y[PB].mib->fddiPORTPCMState = PC0_OFF ; +#endif + break ; + case SMT_DAS : + mib->fddiPORTMy_Type = (np == PB) ? TB : TA ; + break ; +#endif + } + /* + * set PMD-type + */ + phy->pmd_scramble = 0 ; + switch (phy->pmd_type[PMD_SK_PMD]) { + case 'P' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ; + break ; + case 'L' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_LCF ; + break ; + case 'D' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; + break ; + case 'S' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; + phy->pmd_scramble = TRUE ; + break ; + case 'U' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; + phy->pmd_scramble = TRUE ; + break ; + case '1' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ; + break ; + case '2' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ; + break ; + case '3' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ; + break ; + case '4' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ; + break ; + case 'H' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ; + break ; + case 'I' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; + break ; + case 'G' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; + break ; + default: + mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ; + break ; + } + /* + * A and B port can be on primary and secondary path + */ + switch (mib->fddiPORTMy_Type) { + case TA : + mib->fddiPORTAvailablePaths |= MIB_PATH_S ; + mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; + mib->fddiPORTRequestedPaths[2] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_CON_ALTER | + MIB_P_PATH_SEC_PREFER ; + mib->fddiPORTRequestedPaths[3] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_CON_ALTER | + MIB_P_PATH_SEC_PREFER | + MIB_P_PATH_THRU ; + break ; + case TB : + mib->fddiPORTAvailablePaths |= MIB_PATH_S ; + mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; + mib->fddiPORTRequestedPaths[2] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_PRIM_PREFER ; + mib->fddiPORTRequestedPaths[3] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_PRIM_PREFER | + MIB_P_PATH_CON_PREFER | + MIB_P_PATH_THRU ; + break ; + case TS : + mib->fddiPORTAvailablePaths |= MIB_PATH_S ; + mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; + mib->fddiPORTRequestedPaths[2] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_CON_ALTER | + MIB_P_PATH_PRIM_PREFER ; + mib->fddiPORTRequestedPaths[3] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_CON_ALTER | + MIB_P_PATH_PRIM_PREFER ; + break ; + case TM : + mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; + mib->fddiPORTRequestedPaths[2] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_SEC_ALTER | + MIB_P_PATH_PRIM_ALTER ; + mib->fddiPORTRequestedPaths[3] = 0 ; + break ; + } + + phy->pc_lem_fail = FALSE ; + mib->fddiPORTPCMStateX = mib->fddiPORTPCMState ; + mib->fddiPORTLCTFail_Ct = 0 ; + mib->fddiPORTBS_Flag = 0 ; + mib->fddiPORTCurrentPath = MIB_PATH_ISOLATED ; + mib->fddiPORTNeighborType = TNONE ; + phy->ls_flag = 0 ; + phy->rc_flag = 0 ; + phy->tc_flag = 0 ; + phy->td_flag = 0 ; + if (np >= PM) + phy->phy_name = '0' + np - PM ; + else + phy->phy_name = 'A' + np ; + phy->wc_flag = FALSE ; /* set by SMT */ + memset((char *)&phy->lem,0,sizeof(struct lem_counter)) ; + reset_lem_struct(phy) ; + memset((char *)&phy->plc,0,sizeof(struct s_plc)) ; + phy->plc.p_state = PS_OFF ; + for (i = 0 ; i < NUMBITS ; i++) { + phy->t_next[i] = 0 ; + } + } + real_init_plc(smc) ; +} + +void init_plc(struct s_smc *smc) +{ + SK_UNUSED(smc) ; + + /* + * dummy + * this is an obsolete public entry point that has to remain + * for compat. It is used by various drivers. + * the work is now done in real_init_plc() + * which is called from pcm_init() ; + */ +} + +static void real_init_plc(struct s_smc *smc) +{ + int p ; + + for (p = 0 ; p < NUMPHYS ; p++) + plc_init(smc,p) ; +} + +static void plc_init(struct s_smc *smc, int p) +{ + int i ; +#ifndef MOT_ELM + int rev ; /* Revision of PLC-x */ +#endif /* MOT_ELM */ + + /* transit PCM state machine to MAINT state */ + outpw(PLC(p,PL_CNTRL_B),0) ; + outpw(PLC(p,PL_CNTRL_B),PL_PCM_STOP) ; + outpw(PLC(p,PL_CNTRL_A),0) ; + + /* + * if PLC-S then set control register C + */ +#ifndef MOT_ELM + rev = inpw(PLC(p,PL_STATUS_A)) & PLC_REV_MASK ; + if (rev != PLC_REVISION_A) +#endif /* MOT_ELM */ + { + if (smc->y[p].pmd_scramble) { + outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_S) ; +#ifdef MOT_ELM + outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_S) ; + outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_S) ; +#endif /* MOT_ELM */ + } + else { + outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_U) ; +#ifdef MOT_ELM + outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_U) ; + outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_U) ; +#endif /* MOT_ELM */ + } + } + + /* + * set timer register + */ + for ( i = 0 ; pltm[i].timer; i++) /* set timer parameter reg */ + outpw(PLC(p,pltm[i].timer),pltm[i].para) ; + + (void)inpw(PLC(p,PL_INTR_EVENT)) ; /* clear interrupt event reg */ + plc_clear_irq(smc,p) ; + outpw(PLC(p,PL_INTR_MASK),plc_imsk_na); /* enable non active irq's */ + + /* + * if PCM is configured for class s, it will NOT go to the + * REMOVE state if offline (page 3-36;) + * in the concentrator, all inactive PHYS always must be in + * the remove state + * there's no real need to use this feature at all .. + */ +#ifndef CONCENTRATOR + if ((smc->s.sas == SMT_SAS) && (p == PS)) { + outpw(PLC(p,PL_CNTRL_B),PL_CLASS_S) ; + } +#endif +} + +/* + * control PCM state machine + */ +static void plc_go_state(struct s_smc *smc, int p, int state) +{ + HW_PTR port ; + int val ; + + SK_UNUSED(smc) ; + + port = (HW_PTR) (PLC(p,PL_CNTRL_B)) ; + val = inpw(port) & ~(PL_PCM_CNTRL | PL_MAINT) ; + outpw(port,val) ; + outpw(port,val | state) ; +} + +/* + * read current line state (called by ECM & PCM) + */ +int sm_pm_get_ls(struct s_smc *smc, int phy) +{ + int state ; + +#ifdef CONCENTRATOR + if (!plc_is_installed(smc,phy)) + return PC_QLS; +#endif + + state = inpw(PLC(phy,PL_STATUS_A)) & PL_LINE_ST ; + switch(state) { + case PL_L_QLS: + state = PC_QLS ; + break ; + case PL_L_MLS: + state = PC_MLS ; + break ; + case PL_L_HLS: + state = PC_HLS ; + break ; + case PL_L_ILS4: + case PL_L_ILS16: + state = PC_ILS ; + break ; + case PL_L_ALS: + state = PC_LS_PDR ; + break ; + default : + state = PC_LS_NONE ; + } + return state; +} + +static int plc_send_bits(struct s_smc *smc, struct s_phy *phy, int len) +{ + int np = phy->np ; /* PHY index */ + int n ; + int i ; + + SK_UNUSED(smc) ; + + /* create bit vector */ + for (i = len-1,n = 0 ; i >= 0 ; i--) { + n = (n<<1) | phy->t_val[phy->bitn+i] ; + } + if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) { +#if 0 + printf("PL_PCM_SIGNAL is set\n") ; +#endif + return 1; + } + /* write bit[n] & length = 1 to regs */ + outpw(PLC(np,PL_VECTOR_LEN),len-1) ; /* len=nr-1 */ + outpw(PLC(np,PL_XMIT_VECTOR),n) ; +#ifdef DEBUG +#if 1 +#ifdef DEBUG_BRD + if (smc->debug.d_plc & 0x80) +#else + if (debug.d_plc & 0x80) +#endif + printf("SIGNALING bit %d .. %d\n",phy->bitn,phy->bitn+len-1) ; +#endif +#endif + return 0; +} + +/* + * config plc muxes + */ +void plc_config_mux(struct s_smc *smc, int mux) +{ + if (smc->s.sas != SMT_DAS) + return ; + if (mux == MUX_WRAPB) { + SETMASK(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ; + SETMASK(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP,PL_SC_REM_LOOP) ; + } + else { + CLEAR(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL) ; + CLEAR(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP) ; + } + CLEAR(PLC(PB,PL_CNTRL_B),PL_CONFIG_CNTRL) ; + CLEAR(PLC(PB,PL_CNTRL_A),PL_SC_REM_LOOP) ; +} + +/* + PCM state machine + called by dispatcher & fddi_init() (driver) + do + display state change + process event + until SM is stable +*/ +void pcm(struct s_smc *smc, const int np, int event) +{ + int state ; + int oldstate ; + struct s_phy *phy ; + struct fddi_mib_p *mib ; + +#ifndef CONCENTRATOR + /* + * ignore 2nd PHY if SAS + */ + if ((np != PS) && (smc->s.sas == SMT_SAS)) + return ; +#endif + phy = &smc->y[np] ; + mib = phy->mib ; + oldstate = mib->fddiPORTPCMState ; + do { + DB_PCM("PCM %c: state %s", + phy->phy_name, + (mib->fddiPORTPCMState & AFLAG) ? "ACTIONS " : "") ; + DB_PCM("%s, event %s\n", + pcm_states[mib->fddiPORTPCMState & ~AFLAG], + pcm_events[event]) ; + state = mib->fddiPORTPCMState ; + pcm_fsm(smc,phy,event) ; + event = 0 ; + } while (state != mib->fddiPORTPCMState) ; + /* + * because the PLC does the bit signaling for us, + * we're always in SIGNAL state + * the MIB want's to see CONNECT + * we therefore fake an entry in the MIB + */ + if (state == PC5_SIGNAL) + mib->fddiPORTPCMStateX = PC3_CONNECT ; + else + mib->fddiPORTPCMStateX = state ; + +#ifndef SLIM_SMT + /* + * path change + */ + if ( mib->fddiPORTPCMState != oldstate && + ((oldstate == PC8_ACTIVE) || (mib->fddiPORTPCMState == PC8_ACTIVE))) { + smt_srf_event(smc,SMT_EVENT_PORT_PATH_CHANGE, + (int) (INDEX_PORT+ phy->np),0) ; + } +#endif + +#ifdef FDDI_MIB + /* check whether a snmp-trap has to be sent */ + + if ( mib->fddiPORTPCMState != oldstate ) { + /* a real state change took place */ + DB_SNMP ("PCM from %d to %d\n", oldstate, mib->fddiPORTPCMState); + if ( mib->fddiPORTPCMState == PC0_OFF ) { + /* send first trap */ + snmp_fddi_trap (smc, 1, (int) mib->fddiPORTIndex ); + } else if ( oldstate == PC0_OFF ) { + /* send second trap */ + snmp_fddi_trap (smc, 2, (int) mib->fddiPORTIndex ); + } else if ( mib->fddiPORTPCMState != PC2_TRACE && + oldstate == PC8_ACTIVE ) { + /* send third trap */ + snmp_fddi_trap (smc, 3, (int) mib->fddiPORTIndex ); + } else if ( mib->fddiPORTPCMState == PC8_ACTIVE ) { + /* send fourth trap */ + snmp_fddi_trap (smc, 4, (int) mib->fddiPORTIndex ); + } + } +#endif + + pcm_state_change(smc,np,state) ; +} + +/* + * PCM state machine + */ +static void pcm_fsm(struct s_smc *smc, struct s_phy *phy, int cmd) +{ + int i ; + int np = phy->np ; /* PHY index */ + struct s_plc *plc ; + struct fddi_mib_p *mib ; +#ifndef MOT_ELM + u_short plc_rev ; /* Revision of the plc */ +#endif /* nMOT_ELM */ + + plc = &phy->plc ; + mib = phy->mib ; + + /* + * general transitions independent of state + */ + switch (cmd) { + case PC_STOP : + /*PC00-PC80*/ + if (mib->fddiPORTPCMState != PC9_MAINT) { + GO_STATE(PC0_OFF) ; + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_PORT_EVENT, (u_long) FDDI_PORT_STOP, + smt_get_port_event_word(smc)); + } + return ; + case PC_START : + /*PC01-PC81*/ + if (mib->fddiPORTPCMState != PC9_MAINT) + GO_STATE(PC1_BREAK) ; + return ; + case PC_DISABLE : + /* PC09-PC99 */ + GO_STATE(PC9_MAINT) ; + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_PORT_EVENT, (u_long) FDDI_PORT_DISABLED, + smt_get_port_event_word(smc)); + return ; + case PC_TIMEOUT_LCT : + /* if long or extended LCT */ + stop_pcm_timer0(smc,phy) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; + /* end of LCT is indicate by PCM_CODE (initiate PCM event) */ + return ; + } + + switch(mib->fddiPORTPCMState) { + case ACTIONS(PC0_OFF) : + stop_pcm_timer0(smc,phy) ; + outpw(PLC(np,PL_CNTRL_A),0) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; + sm_ph_lem_stop(smc,np) ; /* disable LEM */ + phy->cf_loop = FALSE ; + phy->cf_join = FALSE ; + queue_event(smc,EVENT_CFM,CF_JOIN+np) ; + plc_go_state(smc,np,PL_PCM_STOP) ; + mib->fddiPORTConnectState = PCM_DISABLED ; + ACTIONS_DONE() ; + break ; + case PC0_OFF: + /*PC09*/ + if (cmd == PC_MAINT) { + GO_STATE(PC9_MAINT) ; + break ; + } + break ; + case ACTIONS(PC1_BREAK) : + /* Stop the LCT timer if we came from Signal state */ + stop_pcm_timer0(smc,phy) ; + ACTIONS_DONE() ; + plc_go_state(smc,np,0) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; + sm_ph_lem_stop(smc,np) ; /* disable LEM */ + /* + * if vector is already loaded, go to OFF to clear PCM_SIGNAL + */ +#if 0 + if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) { + plc_go_state(smc,np,PL_PCM_STOP) ; + /* TB_MIN ? */ + } +#endif + /* + * Go to OFF state in any case. + */ + plc_go_state(smc,np,PL_PCM_STOP) ; + + if (mib->fddiPORTPC_Withhold == PC_WH_NONE) + mib->fddiPORTConnectState = PCM_CONNECTING ; + phy->cf_loop = FALSE ; + phy->cf_join = FALSE ; + queue_event(smc,EVENT_CFM,CF_JOIN+np) ; + phy->ls_flag = FALSE ; + phy->pc_mode = PM_NONE ; /* needed by CFM */ + phy->bitn = 0 ; /* bit signaling start bit */ + for (i = 0 ; i < 3 ; i++) + pc_tcode_actions(smc,i,phy) ; + + /* Set the non-active interrupt mask register */ + outpw(PLC(np,PL_INTR_MASK),plc_imsk_na) ; + + /* + * If the LCT was stopped. There might be a + * PCM_CODE interrupt event present. + * This must be cleared. + */ + (void)inpw(PLC(np,PL_INTR_EVENT)) ; +#ifndef MOT_ELM + /* Get the plc revision for revision dependent code */ + plc_rev = inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK ; + + if (plc_rev != PLC_REV_SN3) +#endif /* MOT_ELM */ + { + /* + * No supernet III PLC, so set Xmit verctor and + * length BEFORE starting the state machine. + */ + if (plc_send_bits(smc,phy,3)) { + return ; + } + } + + /* + * Now give the Start command. + * - The start command shall be done before setting the bits + * to be signaled. (In PLC-S description and PLCS in SN3. + * - The start command shall be issued AFTER setting the + * XMIT vector and the XMIT length register. + * + * We do it exactly according this specs for the old PLC and + * the new PLCS inside the SN3. + * For the usual PLCS we try it the way it is done for the + * old PLC and set the XMIT registers again, if the PLC is + * not in SIGNAL state. This is done according to an PLCS + * errata workaround. + */ + + plc_go_state(smc,np,PL_PCM_START) ; + + /* + * workaround for PLC-S eng. sample errata + */ +#ifdef MOT_ELM + if (!(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL)) +#else /* nMOT_ELM */ + if (((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) != + PLC_REVISION_A) && + !(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL)) +#endif /* nMOT_ELM */ + { + /* + * Set register again (PLCS errata) or the first time + * (new SN3 PLCS). + */ + (void) plc_send_bits(smc,phy,3) ; + } + /* + * end of workaround + */ + + GO_STATE(PC5_SIGNAL) ; + plc->p_state = PS_BIT3 ; + plc->p_bits = 3 ; + plc->p_start = 0 ; + + break ; + case PC1_BREAK : + break ; + case ACTIONS(PC2_TRACE) : + plc_go_state(smc,np,PL_PCM_TRACE) ; + ACTIONS_DONE() ; + break ; + case PC2_TRACE : + break ; + + case PC3_CONNECT : /* these states are done by hardware */ + case PC4_NEXT : + break ; + + case ACTIONS(PC5_SIGNAL) : + ACTIONS_DONE() ; + case PC5_SIGNAL : + if ((cmd != PC_SIGNAL) && (cmd != PC_TIMEOUT_LCT)) + break ; + switch (plc->p_state) { + case PS_BIT3 : + for (i = 0 ; i <= 2 ; i++) + pc_rcode_actions(smc,i,phy) ; + pc_tcode_actions(smc,3,phy) ; + plc->p_state = PS_BIT4 ; + plc->p_bits = 1 ; + plc->p_start = 3 ; + phy->bitn = 3 ; + if (plc_send_bits(smc,phy,1)) { + return ; + } + break ; + case PS_BIT4 : + pc_rcode_actions(smc,3,phy) ; + for (i = 4 ; i <= 6 ; i++) + pc_tcode_actions(smc,i,phy) ; + plc->p_state = PS_BIT7 ; + plc->p_bits = 3 ; + plc->p_start = 4 ; + phy->bitn = 4 ; + if (plc_send_bits(smc,phy,3)) { + return ; + } + break ; + case PS_BIT7 : + for (i = 3 ; i <= 6 ; i++) + pc_rcode_actions(smc,i,phy) ; + plc->p_state = PS_LCT ; + plc->p_bits = 0 ; + plc->p_start = 7 ; + phy->bitn = 7 ; + sm_ph_lem_start(smc,np,(int)smc->s.lct_short) ; /* enable LEM */ + /* start LCT */ + i = inpw(PLC(np,PL_CNTRL_B)) & ~PL_PC_LOOP ; + outpw(PLC(np,PL_CNTRL_B),i) ; /* must be cleared */ + outpw(PLC(np,PL_CNTRL_B),i | PL_RLBP) ; + break ; + case PS_LCT : + /* check for local LCT failure */ + pc_tcode_actions(smc,7,phy) ; + /* + * set tval[7] + */ + plc->p_state = PS_BIT8 ; + plc->p_bits = 1 ; + plc->p_start = 7 ; + phy->bitn = 7 ; + if (plc_send_bits(smc,phy,1)) { + return ; + } + break ; + case PS_BIT8 : + /* check for remote LCT failure */ + pc_rcode_actions(smc,7,phy) ; + if (phy->t_val[7] || phy->r_val[7]) { + plc_go_state(smc,np,PL_PCM_STOP) ; + GO_STATE(PC1_BREAK) ; + break ; + } + for (i = 8 ; i <= 9 ; i++) + pc_tcode_actions(smc,i,phy) ; + plc->p_state = PS_JOIN ; + plc->p_bits = 2 ; + plc->p_start = 8 ; + phy->bitn = 8 ; + if (plc_send_bits(smc,phy,2)) { + return ; + } + break ; + case PS_JOIN : + for (i = 8 ; i <= 9 ; i++) + pc_rcode_actions(smc,i,phy) ; + plc->p_state = PS_ACTIVE ; + GO_STATE(PC6_JOIN) ; + break ; + } + break ; + + case ACTIONS(PC6_JOIN) : + /* + * prevent mux error when going from WRAP_A to WRAP_B + */ + if (smc->s.sas == SMT_DAS && np == PB && + (smc->y[PA].pc_mode == PM_TREE || + smc->y[PB].pc_mode == PM_TREE)) { + SETMASK(PLC(np,PL_CNTRL_A), + PL_SC_REM_LOOP,PL_SC_REM_LOOP) ; + SETMASK(PLC(np,PL_CNTRL_B), + PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ; + } + SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ; + SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ; + ACTIONS_DONE() ; + cmd = 0 ; + /* fall thru */ + case PC6_JOIN : + switch (plc->p_state) { + case PS_ACTIVE: + /*PC88b*/ + if (!phy->cf_join) { + phy->cf_join = TRUE ; + queue_event(smc,EVENT_CFM,CF_JOIN+np) ; + } + if (cmd == PC_JOIN) + GO_STATE(PC8_ACTIVE) ; + /*PC82*/ + if (cmd == PC_TRACE) { + GO_STATE(PC2_TRACE) ; + break ; + } + break ; + } + break ; + + case PC7_VERIFY : + break ; + + case ACTIONS(PC8_ACTIVE) : + /* + * start LEM for SMT + */ + sm_ph_lem_start(smc,(int)phy->np,LCT_LEM_MAX) ; + + phy->tr_flag = FALSE ; + mib->fddiPORTConnectState = PCM_ACTIVE ; + + /* Set the active interrupt mask register */ + outpw(PLC(np,PL_INTR_MASK),plc_imsk_act) ; + + ACTIONS_DONE() ; + break ; + case PC8_ACTIVE : + /*PC81 is done by PL_TNE_EXPIRED irq */ + /*PC82*/ + if (cmd == PC_TRACE) { + GO_STATE(PC2_TRACE) ; + break ; + } + /*PC88c: is done by TRACE_PROP irq */ + + break ; + case ACTIONS(PC9_MAINT) : + stop_pcm_timer0(smc,phy) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; + CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ; /* disable LEM int. */ + sm_ph_lem_stop(smc,np) ; /* disable LEM */ + phy->cf_loop = FALSE ; + phy->cf_join = FALSE ; + queue_event(smc,EVENT_CFM,CF_JOIN+np) ; + plc_go_state(smc,np,PL_PCM_STOP) ; + mib->fddiPORTConnectState = PCM_DISABLED ; + SETMASK(PLC(np,PL_CNTRL_B),PL_MAINT,PL_MAINT) ; + sm_ph_linestate(smc,np,(int) MIB2LS(mib->fddiPORTMaint_LS)) ; + outpw(PLC(np,PL_CNTRL_A),PL_SC_BYPASS) ; + ACTIONS_DONE() ; + break ; + case PC9_MAINT : + DB_PCMN(1,"PCM %c : MAINT\n",phy->phy_name,0) ; + /*PC90*/ + if (cmd == PC_ENABLE) { + GO_STATE(PC0_OFF) ; + break ; + } + break ; + + default: + SMT_PANIC(smc,SMT_E0118, SMT_E0118_MSG) ; + break ; + } +} + +/* + * force line state on a PHY output (only in MAINT state) + */ +static void sm_ph_linestate(struct s_smc *smc, int phy, int ls) +{ + int cntrl ; + + SK_UNUSED(smc) ; + + cntrl = (inpw(PLC(phy,PL_CNTRL_B)) & ~PL_MAINT_LS) | + PL_PCM_STOP | PL_MAINT ; + switch(ls) { + case PC_QLS: /* Force Quiet */ + cntrl |= PL_M_QUI0 ; + break ; + case PC_MLS: /* Force Master */ + cntrl |= PL_M_MASTR ; + break ; + case PC_HLS: /* Force Halt */ + cntrl |= PL_M_HALT ; + break ; + default : + case PC_ILS: /* Force Idle */ + cntrl |= PL_M_IDLE ; + break ; + case PC_LS_PDR: /* Enable repeat filter */ + cntrl |= PL_M_TPDR ; + break ; + } + outpw(PLC(phy,PL_CNTRL_B),cntrl) ; +} + +static void reset_lem_struct(struct s_phy *phy) +{ + struct lem_counter *lem = &phy->lem ; + + phy->mib->fddiPORTLer_Estimate = 15 ; + lem->lem_float_ber = 15 * 100 ; +} + +/* + * link error monitor + */ +static void lem_evaluate(struct s_smc *smc, struct s_phy *phy) +{ + int ber ; + u_long errors ; + struct lem_counter *lem = &phy->lem ; + struct fddi_mib_p *mib ; + int cond ; + + mib = phy->mib ; + + if (!lem->lem_on) + return ; + + errors = inpw(PLC(((int) phy->np),PL_LINK_ERR_CTR)) ; + lem->lem_errors += errors ; + mib->fddiPORTLem_Ct += errors ; + + errors = lem->lem_errors ; + /* + * calculation is called on a intervall of 8 seconds + * -> this means, that one error in 8 sec. is one of 8*125*10E6 + * the same as BER = 10E-9 + * Please note: + * -> 9 errors in 8 seconds mean: + * BER = 9 * 10E-9 and this is + * < 10E-8, so the limit of 10E-8 is not reached! + */ + + if (!errors) ber = 15 ; + else if (errors <= 9) ber = 9 ; + else if (errors <= 99) ber = 8 ; + else if (errors <= 999) ber = 7 ; + else if (errors <= 9999) ber = 6 ; + else if (errors <= 99999) ber = 5 ; + else if (errors <= 999999) ber = 4 ; + else if (errors <= 9999999) ber = 3 ; + else if (errors <= 99999999) ber = 2 ; + else if (errors <= 999999999) ber = 1 ; + else ber = 0 ; + + /* + * weighted average + */ + ber *= 100 ; + lem->lem_float_ber = lem->lem_float_ber * 7 + ber * 3 ; + lem->lem_float_ber /= 10 ; + mib->fddiPORTLer_Estimate = lem->lem_float_ber / 100 ; + if (mib->fddiPORTLer_Estimate < 4) { + mib->fddiPORTLer_Estimate = 4 ; + } + + if (lem->lem_errors) { + DB_PCMN(1,"LEM %c :\n",phy->np == PB? 'B' : 'A',0) ; + DB_PCMN(1,"errors : %ld\n",lem->lem_errors,0) ; + DB_PCMN(1,"sum_errors : %ld\n",mib->fddiPORTLem_Ct,0) ; + DB_PCMN(1,"current BER : 10E-%d\n",ber/100,0) ; + DB_PCMN(1,"float BER : 10E-(%d/100)\n",lem->lem_float_ber,0) ; + DB_PCMN(1,"avg. BER : 10E-%d\n", + mib->fddiPORTLer_Estimate,0) ; + } + + lem->lem_errors = 0L ; + +#ifndef SLIM_SMT + cond = (mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Alarm) ? + TRUE : FALSE ; +#ifdef SMT_EXT_CUTOFF + smt_ler_alarm_check(smc,phy,cond) ; +#endif /* nSMT_EXT_CUTOFF */ + if (cond != mib->fddiPORTLerFlag) { + smt_srf_event(smc,SMT_COND_PORT_LER, + (int) (INDEX_PORT+ phy->np) ,cond) ; + } +#endif + + if ( mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Cutoff) { + phy->pc_lem_fail = TRUE ; /* flag */ + mib->fddiPORTLem_Reject_Ct++ ; + /* + * "forgive 10e-2" if we cutoff so we can come + * up again .. + */ + lem->lem_float_ber += 2*100 ; + + /*PC81b*/ +#ifdef CONCENTRATOR + DB_PCMN(1,"PCM: LER cutoff on port %d cutoff %d\n", + phy->np, mib->fddiPORTLer_Cutoff) ; +#endif +#ifdef SMT_EXT_CUTOFF + smt_port_off_event(smc,phy->np); +#else /* nSMT_EXT_CUTOFF */ + queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ; +#endif /* nSMT_EXT_CUTOFF */ + } +} + +/* + * called by SMT to calculate LEM bit error rate + */ +void sm_lem_evaluate(struct s_smc *smc) +{ + int np ; + + for (np = 0 ; np < NUMPHYS ; np++) + lem_evaluate(smc,&smc->y[np]) ; +} + +static void lem_check_lct(struct s_smc *smc, struct s_phy *phy) +{ + struct lem_counter *lem = &phy->lem ; + struct fddi_mib_p *mib ; + int errors ; + + mib = phy->mib ; + + phy->pc_lem_fail = FALSE ; /* flag */ + errors = inpw(PLC(((int)phy->np),PL_LINK_ERR_CTR)) ; + lem->lem_errors += errors ; + mib->fddiPORTLem_Ct += errors ; + if (lem->lem_errors) { + switch(phy->lc_test) { + case LC_SHORT: + if (lem->lem_errors >= smc->s.lct_short) + phy->pc_lem_fail = TRUE ; + break ; + case LC_MEDIUM: + if (lem->lem_errors >= smc->s.lct_medium) + phy->pc_lem_fail = TRUE ; + break ; + case LC_LONG: + if (lem->lem_errors >= smc->s.lct_long) + phy->pc_lem_fail = TRUE ; + break ; + case LC_EXTENDED: + if (lem->lem_errors >= smc->s.lct_extended) + phy->pc_lem_fail = TRUE ; + break ; + } + DB_PCMN(1," >>errors : %d\n",lem->lem_errors,0) ; + } + if (phy->pc_lem_fail) { + mib->fddiPORTLCTFail_Ct++ ; + mib->fddiPORTLem_Reject_Ct++ ; + } + else + mib->fddiPORTLCTFail_Ct = 0 ; +} + +/* + * LEM functions + */ +static void sm_ph_lem_start(struct s_smc *smc, int np, int threshold) +{ + struct lem_counter *lem = &smc->y[np].lem ; + + lem->lem_on = 1 ; + lem->lem_errors = 0L ; + + /* Do NOT reset mib->fddiPORTLer_Estimate here. It is called too + * often. + */ + + outpw(PLC(np,PL_LE_THRESHOLD),threshold) ; + (void)inpw(PLC(np,PL_LINK_ERR_CTR)) ; /* clear error counter */ + + /* enable LE INT */ + SETMASK(PLC(np,PL_INTR_MASK),PL_LE_CTR,PL_LE_CTR) ; +} + +static void sm_ph_lem_stop(struct s_smc *smc, int np) +{ + struct lem_counter *lem = &smc->y[np].lem ; + + lem->lem_on = 0 ; + CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ; +} + +/* ARGSUSED */ +void sm_pm_ls_latch(struct s_smc *smc, int phy, int on_off) +/* int on_off; en- or disable ident. ls */ +{ + SK_UNUSED(smc) ; + + phy = phy ; on_off = on_off ; +} + + +/* + * PCM pseudo code + * receive actions are called AFTER the bit n is received, + * i.e. if pc_rcode_actions(5) is called, bit 6 is the next bit to be received + */ + +/* + * PCM pseudo code 5.1 .. 6.1 + */ +static void pc_rcode_actions(struct s_smc *smc, int bit, struct s_phy *phy) +{ + struct fddi_mib_p *mib ; + + mib = phy->mib ; + + DB_PCMN(1,"SIG rec %x %x:\n", bit,phy->r_val[bit] ) ; + bit++ ; + + switch(bit) { + case 0: + case 1: + case 2: + break ; + case 3 : + if (phy->r_val[1] == 0 && phy->r_val[2] == 0) + mib->fddiPORTNeighborType = TA ; + else if (phy->r_val[1] == 0 && phy->r_val[2] == 1) + mib->fddiPORTNeighborType = TB ; + else if (phy->r_val[1] == 1 && phy->r_val[2] == 0) + mib->fddiPORTNeighborType = TS ; + else if (phy->r_val[1] == 1 && phy->r_val[2] == 1) + mib->fddiPORTNeighborType = TM ; + break ; + case 4: + if (mib->fddiPORTMy_Type == TM && + mib->fddiPORTNeighborType == TM) { + DB_PCMN(1,"PCM %c : E100 withhold M-M\n", + phy->phy_name,0) ; + mib->fddiPORTPC_Withhold = PC_WH_M_M ; + RS_SET(smc,RS_EVENT) ; + } + else if (phy->t_val[3] || phy->r_val[3]) { + mib->fddiPORTPC_Withhold = PC_WH_NONE ; + if (mib->fddiPORTMy_Type == TM || + mib->fddiPORTNeighborType == TM) + phy->pc_mode = PM_TREE ; + else + phy->pc_mode = PM_PEER ; + + /* reevaluate the selection criteria (wc_flag) */ + all_selection_criteria (smc); + + if (phy->wc_flag) { + mib->fddiPORTPC_Withhold = PC_WH_PATH ; + } + } + else { + mib->fddiPORTPC_Withhold = PC_WH_OTHER ; + RS_SET(smc,RS_EVENT) ; + DB_PCMN(1,"PCM %c : E101 withhold other\n", + phy->phy_name,0) ; + } + phy->twisted = ((mib->fddiPORTMy_Type != TS) && + (mib->fddiPORTMy_Type != TM) && + (mib->fddiPORTNeighborType == + mib->fddiPORTMy_Type)) ; + if (phy->twisted) { + DB_PCMN(1,"PCM %c : E102 !!! TWISTED !!!\n", + phy->phy_name,0) ; + } + break ; + case 5 : + break ; + case 6: + if (phy->t_val[4] || phy->r_val[4]) { + if ((phy->t_val[4] && phy->t_val[5]) || + (phy->r_val[4] && phy->r_val[5]) ) + phy->lc_test = LC_EXTENDED ; + else + phy->lc_test = LC_LONG ; + } + else if (phy->t_val[5] || phy->r_val[5]) + phy->lc_test = LC_MEDIUM ; + else + phy->lc_test = LC_SHORT ; + switch (phy->lc_test) { + case LC_SHORT : /* 50ms */ + outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LENGTH ) ; + phy->t_next[7] = smc->s.pcm_lc_short ; + break ; + case LC_MEDIUM : /* 500ms */ + outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LONGLN ) ; + phy->t_next[7] = smc->s.pcm_lc_medium ; + break ; + case LC_LONG : + SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ; + phy->t_next[7] = smc->s.pcm_lc_long ; + break ; + case LC_EXTENDED : + SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ; + phy->t_next[7] = smc->s.pcm_lc_extended ; + break ; + } + if (phy->t_next[7] > smc->s.pcm_lc_medium) { + start_pcm_timer0(smc,phy->t_next[7],PC_TIMEOUT_LCT,phy); + } + DB_PCMN(1,"LCT timer = %ld us\n", phy->t_next[7], 0) ; + phy->t_next[9] = smc->s.pcm_t_next_9 ; + break ; + case 7: + if (phy->t_val[6]) { + phy->cf_loop = TRUE ; + } + phy->td_flag = TRUE ; + break ; + case 8: + if (phy->t_val[7] || phy->r_val[7]) { + DB_PCMN(1,"PCM %c : E103 LCT fail %s\n", + phy->phy_name,phy->t_val[7]? "local":"remote") ; + queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ; + } + break ; + case 9: + if (phy->t_val[8] || phy->r_val[8]) { + if (phy->t_val[8]) + phy->cf_loop = TRUE ; + phy->td_flag = TRUE ; + } + break ; + case 10: + if (phy->r_val[9]) { + /* neighbor intends to have MAC on output */ ; + mib->fddiPORTMacIndicated.R_val = TRUE ; + } + else { + /* neighbor does not intend to have MAC on output */ ; + mib->fddiPORTMacIndicated.R_val = FALSE ; + } + break ; + } +} + +/* + * PCM pseudo code 5.1 .. 6.1 + */ +static void pc_tcode_actions(struct s_smc *smc, const int bit, struct s_phy *phy) +{ + int np = phy->np ; + struct fddi_mib_p *mib ; + + mib = phy->mib ; + + switch(bit) { + case 0: + phy->t_val[0] = 0 ; /* no escape used */ + break ; + case 1: + if (mib->fddiPORTMy_Type == TS || mib->fddiPORTMy_Type == TM) + phy->t_val[1] = 1 ; + else + phy->t_val[1] = 0 ; + break ; + case 2 : + if (mib->fddiPORTMy_Type == TB || mib->fddiPORTMy_Type == TM) + phy->t_val[2] = 1 ; + else + phy->t_val[2] = 0 ; + break ; + case 3: + { + int type,ne ; + int policy ; + + type = mib->fddiPORTMy_Type ; + ne = mib->fddiPORTNeighborType ; + policy = smc->mib.fddiSMTConnectionPolicy ; + + phy->t_val[3] = 1 ; /* Accept connection */ + switch (type) { + case TA : + if ( + ((policy & POLICY_AA) && ne == TA) || + ((policy & POLICY_AB) && ne == TB) || + ((policy & POLICY_AS) && ne == TS) || + ((policy & POLICY_AM) && ne == TM) ) + phy->t_val[3] = 0 ; /* Reject */ + break ; + case TB : + if ( + ((policy & POLICY_BA) && ne == TA) || + ((policy & POLICY_BB) && ne == TB) || + ((policy & POLICY_BS) && ne == TS) || + ((policy & POLICY_BM) && ne == TM) ) + phy->t_val[3] = 0 ; /* Reject */ + break ; + case TS : + if ( + ((policy & POLICY_SA) && ne == TA) || + ((policy & POLICY_SB) && ne == TB) || + ((policy & POLICY_SS) && ne == TS) || + ((policy & POLICY_SM) && ne == TM) ) + phy->t_val[3] = 0 ; /* Reject */ + break ; + case TM : + if ( ne == TM || + ((policy & POLICY_MA) && ne == TA) || + ((policy & POLICY_MB) && ne == TB) || + ((policy & POLICY_MS) && ne == TS) || + ((policy & POLICY_MM) && ne == TM) ) + phy->t_val[3] = 0 ; /* Reject */ + break ; + } +#ifndef SLIM_SMT + /* + * detect undesirable connection attempt event + */ + if ( (type == TA && ne == TA ) || + (type == TA && ne == TS ) || + (type == TB && ne == TB ) || + (type == TB && ne == TS ) || + (type == TS && ne == TA ) || + (type == TS && ne == TB ) ) { + smt_srf_event(smc,SMT_EVENT_PORT_CONNECTION, + (int) (INDEX_PORT+ phy->np) ,0) ; + } +#endif + } + break ; + case 4: + if (mib->fddiPORTPC_Withhold == PC_WH_NONE) { + if (phy->pc_lem_fail) { + phy->t_val[4] = 1 ; /* long */ + phy->t_val[5] = 0 ; + } + else { + phy->t_val[4] = 0 ; + if (mib->fddiPORTLCTFail_Ct > 0) + phy->t_val[5] = 1 ; /* medium */ + else + phy->t_val[5] = 0 ; /* short */ + + /* + * Implementers choice: use medium + * instead of short when undesired + * connection attempt is made. + */ + if (phy->wc_flag) + phy->t_val[5] = 1 ; /* medium */ + } + mib->fddiPORTConnectState = PCM_CONNECTING ; + } + else { + mib->fddiPORTConnectState = PCM_STANDBY ; + phy->t_val[4] = 1 ; /* extended */ + phy->t_val[5] = 1 ; + } + break ; + case 5: + break ; + case 6: + /* we do NOT have a MAC for LCT */ + phy->t_val[6] = 0 ; + break ; + case 7: + phy->cf_loop = FALSE ; + lem_check_lct(smc,phy) ; + if (phy->pc_lem_fail) { + DB_PCMN(1,"PCM %c : E104 LCT failed\n", + phy->phy_name,0) ; + phy->t_val[7] = 1 ; + } + else + phy->t_val[7] = 0 ; + break ; + case 8: + phy->t_val[8] = 0 ; /* Don't request MAC loopback */ + break ; + case 9: + phy->cf_loop = 0 ; + if ((mib->fddiPORTPC_Withhold != PC_WH_NONE) || + ((smc->s.sas == SMT_DAS) && (phy->wc_flag))) { + queue_event(smc,EVENT_PCM+np,PC_START) ; + break ; + } + phy->t_val[9] = FALSE ; + switch (smc->s.sas) { + case SMT_DAS : + /* + * MAC intended on output + */ + if (phy->pc_mode == PM_TREE) { + if ((np == PB) || ((np == PA) && + (smc->y[PB].mib->fddiPORTConnectState != + PCM_ACTIVE))) + phy->t_val[9] = TRUE ; + } + else { + if (np == PB) + phy->t_val[9] = TRUE ; + } + break ; + case SMT_SAS : + if (np == PS) + phy->t_val[9] = TRUE ; + break ; +#ifdef CONCENTRATOR + case SMT_NAC : + /* + * MAC intended on output + */ + if (np == PB) + phy->t_val[9] = TRUE ; + break ; +#endif + } + mib->fddiPORTMacIndicated.T_val = phy->t_val[9] ; + break ; + } + DB_PCMN(1,"SIG snd %x %x:\n", bit,phy->t_val[bit] ) ; +} + +/* + * return status twisted (called by SMT) + */ +int pcm_status_twisted(struct s_smc *smc) +{ + int twist = 0 ; + if (smc->s.sas != SMT_DAS) + return 0; + if (smc->y[PA].twisted && (smc->y[PA].mib->fddiPORTPCMState == PC8_ACTIVE)) + twist |= 1 ; + if (smc->y[PB].twisted && (smc->y[PB].mib->fddiPORTPCMState == PC8_ACTIVE)) + twist |= 2 ; + return twist; +} + +/* + * return status (called by SMT) + * type + * state + * remote phy type + * remote mac yes/no + */ +void pcm_status_state(struct s_smc *smc, int np, int *type, int *state, + int *remote, int *mac) +{ + struct s_phy *phy = &smc->y[np] ; + struct fddi_mib_p *mib ; + + mib = phy->mib ; + + /* remote PHY type and MAC - set only if active */ + *mac = 0 ; + *type = mib->fddiPORTMy_Type ; /* our PHY type */ + *state = mib->fddiPORTConnectState ; + *remote = mib->fddiPORTNeighborType ; + + switch(mib->fddiPORTPCMState) { + case PC8_ACTIVE : + *mac = mib->fddiPORTMacIndicated.R_val ; + break ; + } +} + +/* + * return rooted station status (called by SMT) + */ +int pcm_rooted_station(struct s_smc *smc) +{ + int n ; + + for (n = 0 ; n < NUMPHYS ; n++) { + if (smc->y[n].mib->fddiPORTPCMState == PC8_ACTIVE && + smc->y[n].mib->fddiPORTNeighborType == TM) + return 0; + } + return 1; +} + +/* + * Interrupt actions for PLC & PCM events + */ +void plc_irq(struct s_smc *smc, int np, unsigned int cmd) +/* int np; PHY index */ +{ + struct s_phy *phy = &smc->y[np] ; + struct s_plc *plc = &phy->plc ; + int n ; +#ifdef SUPERNET_3 + int corr_mask ; +#endif /* SUPERNET_3 */ + int i ; + + if (np >= smc->s.numphys) { + plc->soft_err++ ; + return ; + } + if (cmd & PL_EBUF_ERR) { /* elastic buff. det. over-|underflow*/ + /* + * Check whether the SRF Condition occurred. + */ + if (!plc->ebuf_cont && phy->mib->fddiPORTPCMState == PC8_ACTIVE){ + /* + * This is the real Elasticity Error. + * More than one in a row are treated as a + * single one. + * Only count this in the active state. + */ + phy->mib->fddiPORTEBError_Ct ++ ; + + } + + plc->ebuf_err++ ; + if (plc->ebuf_cont <= 1000) { + /* + * Prevent counter from being wrapped after + * hanging years in that interrupt. + */ + plc->ebuf_cont++ ; /* Ebuf continuous error */ + } + +#ifdef SUPERNET_3 + if (plc->ebuf_cont == 1000 && + ((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) == + PLC_REV_SN3)) { + /* + * This interrupt remeained high for at least + * 1000 consecutive interrupt calls. + * + * This is caused by a hardware error of the + * ORION part of the Supernet III chipset. + * + * Disable this bit from the mask. + */ + corr_mask = (plc_imsk_na & ~PL_EBUF_ERR) ; + outpw(PLC(np,PL_INTR_MASK),corr_mask); + + /* + * Disconnect from the ring. + * Call the driver with the reset indication. + */ + queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; + + /* + * Make an error log entry. + */ + SMT_ERR_LOG(smc,SMT_E0136, SMT_E0136_MSG) ; + + /* + * Indicate the Reset. + */ + drv_reset_indication(smc) ; + } +#endif /* SUPERNET_3 */ + } else { + /* Reset the continuous error variable */ + plc->ebuf_cont = 0 ; /* reset Ebuf continuous error */ + } + if (cmd & PL_PHYINV) { /* physical layer invalid signal */ + plc->phyinv++ ; + } + if (cmd & PL_VSYM_CTR) { /* violation symbol counter has incr.*/ + plc->vsym_ctr++ ; + } + if (cmd & PL_MINI_CTR) { /* dep. on PLC_CNTRL_A's MINI_CTR_INT*/ + plc->mini_ctr++ ; + } + if (cmd & PL_LE_CTR) { /* link error event counter */ + int j ; + + /* + * note: PL_LINK_ERR_CTR MUST be read to clear it + */ + j = inpw(PLC(np,PL_LE_THRESHOLD)) ; + i = inpw(PLC(np,PL_LINK_ERR_CTR)) ; + + if (i < j) { + /* wrapped around */ + i += 256 ; + } + + if (phy->lem.lem_on) { + /* Note: Lem errors shall only be counted when + * link is ACTIVE or LCT is active. + */ + phy->lem.lem_errors += i ; + phy->mib->fddiPORTLem_Ct += i ; + } + } + if (cmd & PL_TPC_EXPIRED) { /* TPC timer reached zero */ + if (plc->p_state == PS_LCT) { + /* + * end of LCT + */ + ; + } + plc->tpc_exp++ ; + } + if (cmd & PL_LS_MATCH) { /* LS == LS in PLC_CNTRL_B's MATCH_LS*/ + switch (inpw(PLC(np,PL_CNTRL_B)) & PL_MATCH_LS) { + case PL_I_IDLE : phy->curr_ls = PC_ILS ; break ; + case PL_I_HALT : phy->curr_ls = PC_HLS ; break ; + case PL_I_MASTR : phy->curr_ls = PC_MLS ; break ; + case PL_I_QUIET : phy->curr_ls = PC_QLS ; break ; + } + } + if (cmd & PL_PCM_BREAK) { /* PCM has entered the BREAK state */ + int reason; + + reason = inpw(PLC(np,PL_STATUS_B)) & PL_BREAK_REASON ; + + switch (reason) { + case PL_B_PCS : plc->b_pcs++ ; break ; + case PL_B_TPC : plc->b_tpc++ ; break ; + case PL_B_TNE : plc->b_tne++ ; break ; + case PL_B_QLS : plc->b_qls++ ; break ; + case PL_B_ILS : plc->b_ils++ ; break ; + case PL_B_HLS : plc->b_hls++ ; break ; + } + + /*jd 05-Aug-1999 changed: Bug #10419 */ + DB_PCMN(1,"PLC %d: MDcF = %x\n", np, smc->e.DisconnectFlag); + if (smc->e.DisconnectFlag == FALSE) { + DB_PCMN(1,"PLC %d: restart (reason %x)\n", np, reason); + queue_event(smc,EVENT_PCM+np,PC_START) ; + } + else { + DB_PCMN(1,"PLC %d: NO!! restart (reason %x)\n", np, reason); + } + return ; + } + /* + * If both CODE & ENABLE are set ignore enable + */ + if (cmd & PL_PCM_CODE) { /* receive last sign.-bit | LCT complete */ + queue_event(smc,EVENT_PCM+np,PC_SIGNAL) ; + n = inpw(PLC(np,PL_RCV_VECTOR)) ; + for (i = 0 ; i < plc->p_bits ; i++) { + phy->r_val[plc->p_start+i] = n & 1 ; + n >>= 1 ; + } + } + else if (cmd & PL_PCM_ENABLED) { /* asserted SC_JOIN, scrub.completed*/ + queue_event(smc,EVENT_PCM+np,PC_JOIN) ; + } + if (cmd & PL_TRACE_PROP) { /* MLS while PC8_ACTIV || PC2_TRACE */ + /*PC22b*/ + if (!phy->tr_flag) { + DB_PCMN(1,"PCM : irq TRACE_PROP %d %d\n", + np,smc->mib.fddiSMTECMState) ; + phy->tr_flag = TRUE ; + smc->e.trace_prop |= ENTITY_BIT(ENTITY_PHY(np)) ; + queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ; + } + } + /* + * filter PLC glitch ??? + * QLS || HLS only while in PC2_TRACE state + */ + if ((cmd & PL_SELF_TEST) && (phy->mib->fddiPORTPCMState == PC2_TRACE)) { + /*PC22a*/ + if (smc->e.path_test == PT_PASSED) { + DB_PCMN(1,"PCM : state = %s %d\n", get_pcmstate(smc,np), + phy->mib->fddiPORTPCMState) ; + + smc->e.path_test = PT_PENDING ; + queue_event(smc,EVENT_ECM,EC_PATH_TEST) ; + } + } + if (cmd & PL_TNE_EXPIRED) { /* TNE: length of noise events */ + /* break_required (TNE > NS_Max) */ + if (phy->mib->fddiPORTPCMState == PC8_ACTIVE) { + if (!phy->tr_flag) { + DB_PCMN(1,"PCM %c : PC81 %s\n",phy->phy_name,"NSE"); + queue_event(smc,EVENT_PCM+np,PC_START) ; + return ; + } + } + } +#if 0 + if (cmd & PL_NP_ERR) { /* NP has requested to r/w an inv reg*/ + /* + * It's a bug by AMD + */ + plc->np_err++ ; + } + /* pin inactiv (GND) */ + if (cmd & PL_PARITY_ERR) { /* p. error dedected on TX9-0 inp */ + plc->parity_err++ ; + } + if (cmd & PL_LSDO) { /* carrier detected */ + ; + } +#endif +} + +#ifdef DEBUG +/* + * fill state struct + */ +void pcm_get_state(struct s_smc *smc, struct smt_state *state) +{ + struct s_phy *phy ; + struct pcm_state *pcs ; + int i ; + int ii ; + short rbits ; + short tbits ; + struct fddi_mib_p *mib ; + + for (i = 0, phy = smc->y, pcs = state->pcm_state ; i < NUMPHYS ; + i++ , phy++, pcs++ ) { + mib = phy->mib ; + pcs->pcm_type = (u_char) mib->fddiPORTMy_Type ; + pcs->pcm_state = (u_char) mib->fddiPORTPCMState ; + pcs->pcm_mode = phy->pc_mode ; + pcs->pcm_neighbor = (u_char) mib->fddiPORTNeighborType ; + pcs->pcm_bsf = mib->fddiPORTBS_Flag ; + pcs->pcm_lsf = phy->ls_flag ; + pcs->pcm_lct_fail = (u_char) mib->fddiPORTLCTFail_Ct ; + pcs->pcm_ls_rx = LS2MIB(sm_pm_get_ls(smc,i)) ; + for (ii = 0, rbits = tbits = 0 ; ii < NUMBITS ; ii++) { + rbits <<= 1 ; + tbits <<= 1 ; + if (phy->r_val[NUMBITS-1-ii]) + rbits |= 1 ; + if (phy->t_val[NUMBITS-1-ii]) + tbits |= 1 ; + } + pcs->pcm_r_val = rbits ; + pcs->pcm_t_val = tbits ; + } +} + +int get_pcm_state(struct s_smc *smc, int np) +{ + int pcs ; + + SK_UNUSED(smc) ; + + switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) { + case PL_PC0 : pcs = PC_STOP ; break ; + case PL_PC1 : pcs = PC_START ; break ; + case PL_PC2 : pcs = PC_TRACE ; break ; + case PL_PC3 : pcs = PC_SIGNAL ; break ; + case PL_PC4 : pcs = PC_SIGNAL ; break ; + case PL_PC5 : pcs = PC_SIGNAL ; break ; + case PL_PC6 : pcs = PC_JOIN ; break ; + case PL_PC7 : pcs = PC_JOIN ; break ; + case PL_PC8 : pcs = PC_ENABLE ; break ; + case PL_PC9 : pcs = PC_MAINT ; break ; + default : pcs = PC_DISABLE ; break ; + } + return pcs; +} + +char *get_linestate(struct s_smc *smc, int np) +{ + char *ls = "" ; + + SK_UNUSED(smc) ; + + switch (inpw(PLC(np,PL_STATUS_A)) & PL_LINE_ST) { + case PL_L_NLS : ls = "NOISE" ; break ; + case PL_L_ALS : ls = "ACTIV" ; break ; + case PL_L_UND : ls = "UNDEF" ; break ; + case PL_L_ILS4: ls = "ILS 4" ; break ; + case PL_L_QLS : ls = "QLS" ; break ; + case PL_L_MLS : ls = "MLS" ; break ; + case PL_L_HLS : ls = "HLS" ; break ; + case PL_L_ILS16:ls = "ILS16" ; break ; +#ifdef lint + default: ls = "unknown" ; break ; +#endif + } + return ls; +} + +char *get_pcmstate(struct s_smc *smc, int np) +{ + char *pcs ; + + SK_UNUSED(smc) ; + + switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) { + case PL_PC0 : pcs = "OFF" ; break ; + case PL_PC1 : pcs = "BREAK" ; break ; + case PL_PC2 : pcs = "TRACE" ; break ; + case PL_PC3 : pcs = "CONNECT"; break ; + case PL_PC4 : pcs = "NEXT" ; break ; + case PL_PC5 : pcs = "SIGNAL" ; break ; + case PL_PC6 : pcs = "JOIN" ; break ; + case PL_PC7 : pcs = "VERIFY" ; break ; + case PL_PC8 : pcs = "ACTIV" ; break ; + case PL_PC9 : pcs = "MAINT" ; break ; + default : pcs = "UNKNOWN" ; break ; + } + return pcs; +} + +void list_phy(struct s_smc *smc) +{ + struct s_plc *plc ; + int np ; + + for (np = 0 ; np < NUMPHYS ; np++) { + plc = &smc->y[np].plc ; + printf("PHY %d:\tERRORS\t\t\tBREAK_REASONS\t\tSTATES:\n",np) ; + printf("\tsoft_error: %ld \t\tPC_Start : %ld\n", + plc->soft_err,plc->b_pcs); + printf("\tparity_err: %ld \t\tTPC exp. : %ld\t\tLine: %s\n", + plc->parity_err,plc->b_tpc,get_linestate(smc,np)) ; + printf("\tebuf_error: %ld \t\tTNE exp. : %ld\n", + plc->ebuf_err,plc->b_tne) ; + printf("\tphyinvalid: %ld \t\tQLS det. : %ld\t\tPCM : %s\n", + plc->phyinv,plc->b_qls,get_pcmstate(smc,np)) ; + printf("\tviosym_ctr: %ld \t\tILS det. : %ld\n", + plc->vsym_ctr,plc->b_ils) ; + printf("\tmingap_ctr: %ld \t\tHLS det. : %ld\n", + plc->mini_ctr,plc->b_hls) ; + printf("\tnodepr_err: %ld\n",plc->np_err) ; + printf("\tTPC_exp : %ld\n",plc->tpc_exp) ; + printf("\tLEM_err : %ld\n",smc->y[np].lem.lem_errors) ; + } +} + + +#ifdef CONCENTRATOR +void pcm_lem_dump(struct s_smc *smc) +{ + int i ; + struct s_phy *phy ; + struct fddi_mib_p *mib ; + + char *entostring() ; + + printf("PHY errors BER\n") ; + printf("----------------------\n") ; + for (i = 0,phy = smc->y ; i < NUMPHYS ; i++,phy++) { + if (!plc_is_installed(smc,i)) + continue ; + mib = phy->mib ; + printf("%s\t%ld\t10E-%d\n", + entostring(smc,ENTITY_PHY(i)), + mib->fddiPORTLem_Ct, + mib->fddiPORTLer_Estimate) ; + } +} +#endif +#endif diff --git a/drivers/net/fddi/skfp/pmf.c b/drivers/net/fddi/skfp/pmf.c new file mode 100644 index 0000000..9ac4665 --- /dev/null +++ b/drivers/net/fddi/skfp/pmf.c @@ -0,0 +1,1663 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + Parameter Management Frame processing for SMT 7.2 +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/smt_p.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef SLIM_SMT + +#ifndef lint +static const char ID_sccs[] = "@(#)pmf.c 1.37 97/08/04 (C) SK " ; +#endif + +static int smt_authorize(struct s_smc *smc, struct smt_header *sm); +static int smt_check_set_count(struct s_smc *smc, struct smt_header *sm); +static const struct s_p_tab* smt_get_ptab(u_short para); +static int smt_mib_phys(struct s_smc *smc); +static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index, + int local, int set); +void smt_add_para(struct s_smc *smc, struct s_pcon *pcon, u_short para, + int index, int local); +static SMbuf *smt_build_pmf_response(struct s_smc *smc, struct smt_header *req, + int set, int local); +static int port_to_mib(struct s_smc *smc, int p); + +#define MOFFSS(e) offsetof(struct fddi_mib, e) +#define MOFFMS(e) offsetof(struct fddi_mib_m, e) +#define MOFFAS(e) offsetof(struct fddi_mib_a, e) +#define MOFFPS(e) offsetof(struct fddi_mib_p, e) + + +#define AC_G 0x01 /* Get */ +#define AC_GR 0x02 /* Get/Set */ +#define AC_S 0x04 /* Set */ +#define AC_NA 0x08 +#define AC_GROUP 0x10 /* Group */ +#define MS2BCLK(x) ((x)*12500L) +/* + F LFag (byte) + B byte + S u_short 16 bit + C Counter 32 bit + L Long 32 bit + T Timer_2 32 bit + P TimeStamp ; + A LongAddress (6 byte) + E Enum 16 bit + R ResId 16 Bit +*/ +static const struct s_p_tab { + u_short p_num ; /* parameter code */ + u_char p_access ; /* access rights */ + u_short p_offset ; /* offset in mib */ + char p_swap[3] ; /* format string */ +} p_tab[] = { + /* StationIdGrp */ + { SMT_P100A,AC_GROUP } , + { SMT_P100B,AC_G, MOFFSS(fddiSMTStationId), "8" } , + { SMT_P100D,AC_G, MOFFSS(fddiSMTOpVersionId), "S" } , + { SMT_P100E,AC_G, MOFFSS(fddiSMTHiVersionId), "S" } , + { SMT_P100F,AC_G, MOFFSS(fddiSMTLoVersionId), "S" } , + { SMT_P1010,AC_G, MOFFSS(fddiSMTManufacturerData), "D" } , + { SMT_P1011,AC_GR, MOFFSS(fddiSMTUserData), "D" } , + { SMT_P1012,AC_G, MOFFSS(fddiSMTMIBVersionId), "S" } , + + /* StationConfigGrp */ + { SMT_P1014,AC_GROUP } , + { SMT_P1015,AC_G, MOFFSS(fddiSMTMac_Ct), "B" } , + { SMT_P1016,AC_G, MOFFSS(fddiSMTNonMaster_Ct), "B" } , + { SMT_P1017,AC_G, MOFFSS(fddiSMTMaster_Ct), "B" } , + { SMT_P1018,AC_G, MOFFSS(fddiSMTAvailablePaths), "B" } , + { SMT_P1019,AC_G, MOFFSS(fddiSMTConfigCapabilities),"S" } , + { SMT_P101A,AC_GR, MOFFSS(fddiSMTConfigPolicy), "wS" } , + { SMT_P101B,AC_GR, MOFFSS(fddiSMTConnectionPolicy),"wS" } , + { SMT_P101D,AC_GR, MOFFSS(fddiSMTTT_Notify), "wS" } , + { SMT_P101E,AC_GR, MOFFSS(fddiSMTStatRptPolicy), "bB" } , + { SMT_P101F,AC_GR, MOFFSS(fddiSMTTrace_MaxExpiration),"lL" } , + { SMT_P1020,AC_G, MOFFSS(fddiSMTPORTIndexes), "II" } , + { SMT_P1021,AC_G, MOFFSS(fddiSMTMACIndexes), "I" } , + { SMT_P1022,AC_G, MOFFSS(fddiSMTBypassPresent), "F" } , + + /* StatusGrp */ + { SMT_P1028,AC_GROUP } , + { SMT_P1029,AC_G, MOFFSS(fddiSMTECMState), "E" } , + { SMT_P102A,AC_G, MOFFSS(fddiSMTCF_State), "E" } , + { SMT_P102C,AC_G, MOFFSS(fddiSMTRemoteDisconnectFlag),"F" } , + { SMT_P102D,AC_G, MOFFSS(fddiSMTStationStatus), "E" } , + { SMT_P102E,AC_G, MOFFSS(fddiSMTPeerWrapFlag), "F" } , + + /* MIBOperationGrp */ + { SMT_P1032,AC_GROUP } , + { SMT_P1033,AC_G, MOFFSS(fddiSMTTimeStamp),"P" } , + { SMT_P1034,AC_G, MOFFSS(fddiSMTTransitionTimeStamp),"P" } , + /* NOTE : SMT_P1035 is already swapped ! SMT_P_SETCOUNT */ + { SMT_P1035,AC_G, MOFFSS(fddiSMTSetCount),"4P" } , + { SMT_P1036,AC_G, MOFFSS(fddiSMTLastSetStationId),"8" } , + + { SMT_P103C,AC_S, 0, "wS" } , + + /* + * PRIVATE EXTENSIONS + * only accessible locally to get/set passwd + */ + { SMT_P10F0,AC_GR, MOFFSS(fddiPRPMFPasswd), "8" } , + { SMT_P10F1,AC_GR, MOFFSS(fddiPRPMFStation), "8" } , +#ifdef ESS + { SMT_P10F2,AC_GR, MOFFSS(fddiESSPayload), "lL" } , + { SMT_P10F3,AC_GR, MOFFSS(fddiESSOverhead), "lL" } , + { SMT_P10F4,AC_GR, MOFFSS(fddiESSMaxTNeg), "lL" } , + { SMT_P10F5,AC_GR, MOFFSS(fddiESSMinSegmentSize), "lL" } , + { SMT_P10F6,AC_GR, MOFFSS(fddiESSCategory), "lL" } , + { SMT_P10F7,AC_GR, MOFFSS(fddiESSSynchTxMode), "wS" } , +#endif +#ifdef SBA + { SMT_P10F8,AC_GR, MOFFSS(fddiSBACommand), "bF" } , + { SMT_P10F9,AC_GR, MOFFSS(fddiSBAAvailable), "bF" } , +#endif + /* MAC Attributes */ + { SMT_P200A,AC_GROUP } , + { SMT_P200B,AC_G, MOFFMS(fddiMACFrameStatusFunctions),"S" } , + { SMT_P200D,AC_G, MOFFMS(fddiMACT_MaxCapabilitiy),"T" } , + { SMT_P200E,AC_G, MOFFMS(fddiMACTVXCapabilitiy),"T" } , + + /* ConfigGrp */ + { SMT_P2014,AC_GROUP } , + { SMT_P2016,AC_G, MOFFMS(fddiMACAvailablePaths), "B" } , + { SMT_P2017,AC_G, MOFFMS(fddiMACCurrentPath), "S" } , + { SMT_P2018,AC_G, MOFFMS(fddiMACUpstreamNbr), "A" } , + { SMT_P2019,AC_G, MOFFMS(fddiMACDownstreamNbr), "A" } , + { SMT_P201A,AC_G, MOFFMS(fddiMACOldUpstreamNbr), "A" } , + { SMT_P201B,AC_G, MOFFMS(fddiMACOldDownstreamNbr),"A" } , + { SMT_P201D,AC_G, MOFFMS(fddiMACDupAddressTest), "E" } , + { SMT_P2020,AC_GR, MOFFMS(fddiMACRequestedPaths), "wS" } , + { SMT_P2021,AC_G, MOFFMS(fddiMACDownstreamPORTType),"E" } , + { SMT_P2022,AC_G, MOFFMS(fddiMACIndex), "S" } , + + /* AddressGrp */ + { SMT_P2028,AC_GROUP } , + { SMT_P2029,AC_G, MOFFMS(fddiMACSMTAddress), "A" } , + + /* OperationGrp */ + { SMT_P2032,AC_GROUP } , + { SMT_P2033,AC_G, MOFFMS(fddiMACT_Req), "T" } , + { SMT_P2034,AC_G, MOFFMS(fddiMACT_Neg), "T" } , + { SMT_P2035,AC_G, MOFFMS(fddiMACT_Max), "T" } , + { SMT_P2036,AC_G, MOFFMS(fddiMACTvxValue), "T" } , + { SMT_P2038,AC_G, MOFFMS(fddiMACT_Pri0), "T" } , + { SMT_P2039,AC_G, MOFFMS(fddiMACT_Pri1), "T" } , + { SMT_P203A,AC_G, MOFFMS(fddiMACT_Pri2), "T" } , + { SMT_P203B,AC_G, MOFFMS(fddiMACT_Pri3), "T" } , + { SMT_P203C,AC_G, MOFFMS(fddiMACT_Pri4), "T" } , + { SMT_P203D,AC_G, MOFFMS(fddiMACT_Pri5), "T" } , + { SMT_P203E,AC_G, MOFFMS(fddiMACT_Pri6), "T" } , + + + /* CountersGrp */ + { SMT_P2046,AC_GROUP } , + { SMT_P2047,AC_G, MOFFMS(fddiMACFrame_Ct), "C" } , + { SMT_P2048,AC_G, MOFFMS(fddiMACCopied_Ct), "C" } , + { SMT_P2049,AC_G, MOFFMS(fddiMACTransmit_Ct), "C" } , + { SMT_P204A,AC_G, MOFFMS(fddiMACToken_Ct), "C" } , + { SMT_P2051,AC_G, MOFFMS(fddiMACError_Ct), "C" } , + { SMT_P2052,AC_G, MOFFMS(fddiMACLost_Ct), "C" } , + { SMT_P2053,AC_G, MOFFMS(fddiMACTvxExpired_Ct), "C" } , + { SMT_P2054,AC_G, MOFFMS(fddiMACNotCopied_Ct), "C" } , + { SMT_P2056,AC_G, MOFFMS(fddiMACRingOp_Ct), "C" } , + + /* FrameErrorConditionGrp */ + { SMT_P205A,AC_GROUP } , + { SMT_P205F,AC_GR, MOFFMS(fddiMACFrameErrorThreshold),"wS" } , + { SMT_P2060,AC_G, MOFFMS(fddiMACFrameErrorRatio), "S" } , + + /* NotCopiedConditionGrp */ + { SMT_P2064,AC_GROUP } , + { SMT_P2067,AC_GR, MOFFMS(fddiMACNotCopiedThreshold),"wS" } , + { SMT_P2069,AC_G, MOFFMS(fddiMACNotCopiedRatio), "S" } , + + /* StatusGrp */ + { SMT_P206E,AC_GROUP } , + { SMT_P206F,AC_G, MOFFMS(fddiMACRMTState), "S" } , + { SMT_P2070,AC_G, MOFFMS(fddiMACDA_Flag), "F" } , + { SMT_P2071,AC_G, MOFFMS(fddiMACUNDA_Flag), "F" } , + { SMT_P2072,AC_G, MOFFMS(fddiMACFrameErrorFlag), "F" } , + { SMT_P2073,AC_G, MOFFMS(fddiMACNotCopiedFlag), "F" } , + { SMT_P2074,AC_G, MOFFMS(fddiMACMA_UnitdataAvailable),"F" } , + { SMT_P2075,AC_G, MOFFMS(fddiMACHardwarePresent), "F" } , + { SMT_P2076,AC_GR, MOFFMS(fddiMACMA_UnitdataEnable),"bF" } , + + /* + * PRIVATE EXTENSIONS + * only accessible locally to get/set TMIN + */ + { SMT_P20F0,AC_NA } , + { SMT_P20F1,AC_GR, MOFFMS(fddiMACT_Min), "lT" } , + + /* Path Attributes */ + /* + * DON't swap 320B,320F,3210: they are already swapped in swap_para() + */ + { SMT_P320A,AC_GROUP } , + { SMT_P320B,AC_G, MOFFAS(fddiPATHIndex), "r" } , + { SMT_P320F,AC_GR, MOFFAS(fddiPATHSbaPayload), "l4" } , + { SMT_P3210,AC_GR, MOFFAS(fddiPATHSbaOverhead), "l4" } , + /* fddiPATHConfiguration */ + { SMT_P3212,AC_G, 0, "" } , + { SMT_P3213,AC_GR, MOFFAS(fddiPATHT_Rmode), "lT" } , + { SMT_P3214,AC_GR, MOFFAS(fddiPATHSbaAvailable), "lL" } , + { SMT_P3215,AC_GR, MOFFAS(fddiPATHTVXLowerBound), "lT" } , + { SMT_P3216,AC_GR, MOFFAS(fddiPATHT_MaxLowerBound),"lT" } , + { SMT_P3217,AC_GR, MOFFAS(fddiPATHMaxT_Req), "lT" } , + + /* Port Attributes */ + /* ConfigGrp */ + { SMT_P400A,AC_GROUP } , + { SMT_P400C,AC_G, MOFFPS(fddiPORTMy_Type), "E" } , + { SMT_P400D,AC_G, MOFFPS(fddiPORTNeighborType), "E" } , + { SMT_P400E,AC_GR, MOFFPS(fddiPORTConnectionPolicies),"bB" } , + { SMT_P400F,AC_G, MOFFPS(fddiPORTMacIndicated), "2" } , + { SMT_P4010,AC_G, MOFFPS(fddiPORTCurrentPath), "E" } , + { SMT_P4011,AC_GR, MOFFPS(fddiPORTRequestedPaths), "l4" } , + { SMT_P4012,AC_G, MOFFPS(fddiPORTMACPlacement), "S" } , + { SMT_P4013,AC_G, MOFFPS(fddiPORTAvailablePaths), "B" } , + { SMT_P4016,AC_G, MOFFPS(fddiPORTPMDClass), "E" } , + { SMT_P4017,AC_G, MOFFPS(fddiPORTConnectionCapabilities), "B"} , + { SMT_P401D,AC_G, MOFFPS(fddiPORTIndex), "R" } , + + /* OperationGrp */ + { SMT_P401E,AC_GROUP } , + { SMT_P401F,AC_GR, MOFFPS(fddiPORTMaint_LS), "wE" } , + { SMT_P4021,AC_G, MOFFPS(fddiPORTBS_Flag), "F" } , + { SMT_P4022,AC_G, MOFFPS(fddiPORTPC_LS), "E" } , + + /* ErrorCtrsGrp */ + { SMT_P4028,AC_GROUP } , + { SMT_P4029,AC_G, MOFFPS(fddiPORTEBError_Ct), "C" } , + { SMT_P402A,AC_G, MOFFPS(fddiPORTLCTFail_Ct), "C" } , + + /* LerGrp */ + { SMT_P4032,AC_GROUP } , + { SMT_P4033,AC_G, MOFFPS(fddiPORTLer_Estimate), "F" } , + { SMT_P4034,AC_G, MOFFPS(fddiPORTLem_Reject_Ct), "C" } , + { SMT_P4035,AC_G, MOFFPS(fddiPORTLem_Ct), "C" } , + { SMT_P403A,AC_GR, MOFFPS(fddiPORTLer_Cutoff), "bB" } , + { SMT_P403B,AC_GR, MOFFPS(fddiPORTLer_Alarm), "bB" } , + + /* StatusGrp */ + { SMT_P403C,AC_GROUP } , + { SMT_P403D,AC_G, MOFFPS(fddiPORTConnectState), "E" } , + { SMT_P403E,AC_G, MOFFPS(fddiPORTPCMStateX), "E" } , + { SMT_P403F,AC_G, MOFFPS(fddiPORTPC_Withhold), "E" } , + { SMT_P4040,AC_G, MOFFPS(fddiPORTLerFlag), "F" } , + { SMT_P4041,AC_G, MOFFPS(fddiPORTHardwarePresent),"F" } , + + { SMT_P4046,AC_S, 0, "wS" } , + + { 0, AC_GROUP } , + { 0 } +} ; + +void smt_pmf_received_pack(struct s_smc *smc, SMbuf *mb, int local) +{ + struct smt_header *sm ; + SMbuf *reply ; + + sm = smtod(mb,struct smt_header *) ; + DB_SMT("SMT: processing PMF frame at %x len %d\n",sm,mb->sm_len) ; +#ifdef DEBUG + dump_smt(smc,sm,"PMF Received") ; +#endif + /* + * Start the watchdog: It may be a long, long packet and + * maybe the watchdog occurs ... + */ + smt_start_watchdog(smc) ; + + if (sm->smt_class == SMT_PMF_GET || + sm->smt_class == SMT_PMF_SET) { + reply = smt_build_pmf_response(smc,sm, + sm->smt_class == SMT_PMF_SET,local) ; + if (reply) { + sm = smtod(reply,struct smt_header *) ; +#ifdef DEBUG + dump_smt(smc,sm,"PMF Reply") ; +#endif + smt_send_frame(smc,reply,FC_SMT_INFO,local) ; + } + } +} + +static SMbuf *smt_build_pmf_response(struct s_smc *smc, struct smt_header *req, + int set, int local) +{ + SMbuf *mb ; + struct smt_header *smt ; + struct smt_para *pa ; + struct smt_p_reason *res ; + const struct s_p_tab *pt ; + int len ; + int index ; + int idx_end ; + int error ; + int range ; + SK_LOC_DECL(struct s_pcon,pcon) ; + SK_LOC_DECL(struct s_pcon,set_pcon) ; + + /* + * build SMT header + */ + if (!(mb = smt_get_mbuf(smc))) + return mb; + + smt = smtod(mb, struct smt_header *) ; + smt->smt_dest = req->smt_source ; /* DA == source of request */ + smt->smt_class = req->smt_class ; /* same class (GET/SET) */ + smt->smt_type = SMT_REPLY ; + smt->smt_version = SMT_VID_2 ; + smt->smt_tid = req->smt_tid ; /* same TID */ + smt->smt_pad = 0 ; + smt->smt_len = 0 ; + + /* + * setup parameter status + */ + pcon.pc_len = SMT_MAX_INFO_LEN ; /* max para length */ + pcon.pc_err = 0 ; /* no error */ + pcon.pc_badset = 0 ; /* no bad set count */ + pcon.pc_p = (void *) (smt + 1) ; /* paras start here */ + + /* + * check authoriziation and set count + */ + error = 0 ; + if (set) { + if (!local && smt_authorize(smc,req)) + error = SMT_RDF_AUTHOR ; + else if (smt_check_set_count(smc,req)) + pcon.pc_badset = SMT_RDF_BADSET ; + } + /* + * add reason code and all mandatory parameters + */ + res = (struct smt_p_reason *) pcon.pc_p ; + smt_add_para(smc,&pcon,(u_short) SMT_P_REASON,0,0) ; + smt_add_para(smc,&pcon,(u_short) SMT_P1033,0,0) ; + /* update 1035 and 1036 later if set */ + set_pcon = pcon ; + smt_add_para(smc,&pcon,(u_short) SMT_P1035,0,0) ; + smt_add_para(smc,&pcon,(u_short) SMT_P1036,0,0) ; + + pcon.pc_err = error ; + len = req->smt_len ; + pa = (struct smt_para *) (req + 1) ; + /* + * process list of paras + */ + while (!pcon.pc_err && len > 0 ) { + if (((u_short)len < pa->p_len + PARA_LEN) || (pa->p_len & 3)) { + pcon.pc_err = SMT_RDF_LENGTH ; + break ; + } + + if (((range = (pa->p_type & 0xf000)) == 0x2000) || + range == 0x3000 || range == 0x4000) { + /* + * get index for PART,MAC ad PATH group + */ + index = *((u_char *)pa + PARA_LEN + 3) ;/* index */ + idx_end = index ; + if (!set && (pa->p_len != 4)) { + pcon.pc_err = SMT_RDF_LENGTH ; + break ; + } + if (!index && !set) { + switch (range) { + case 0x2000 : + index = INDEX_MAC ; + idx_end = index - 1 + NUMMACS ; + break ; + case 0x3000 : + index = INDEX_PATH ; + idx_end = index - 1 + NUMPATHS ; + break ; + case 0x4000 : + index = INDEX_PORT ; + idx_end = index - 1 + NUMPHYS ; +#ifndef CONCENTRATOR + if (smc->s.sas == SMT_SAS) + idx_end = INDEX_PORT ; +#endif + break ; + } + } + } + else { + /* + * smt group has no index + */ + if (!set && (pa->p_len != 0)) { + pcon.pc_err = SMT_RDF_LENGTH ; + break ; + } + index = 0 ; + idx_end = 0 ; + } + while (index <= idx_end) { + /* + * if group + * add all paras of group + */ + pt = smt_get_ptab(pa->p_type) ; + if (pt && pt->p_access == AC_GROUP && !set) { + pt++ ; + while (pt->p_access == AC_G || + pt->p_access == AC_GR) { + smt_add_para(smc,&pcon,pt->p_num, + index,local); + pt++ ; + } + } + /* + * ignore + * AUTHORIZATION in get/set + * SET COUNT in set + */ + else if (pa->p_type != SMT_P_AUTHOR && + (!set || (pa->p_type != SMT_P1035))) { + int st ; + if (pcon.pc_badset) { + smt_add_para(smc,&pcon,pa->p_type, + index,local) ; + } + else if (set) { + st = smt_set_para(smc,pa,index,local,1); + /* + * return para even if error + */ + smt_add_para(smc,&pcon,pa->p_type, + index,local) ; + pcon.pc_err = st ; + } + else { + if (pt && pt->p_access == AC_S) { + pcon.pc_err = + SMT_RDF_ILLEGAL ; + } + smt_add_para(smc,&pcon,pa->p_type, + index,local) ; + } + } + if (pcon.pc_err) + break ; + index++ ; + } + len -= pa->p_len + PARA_LEN ; + pa = (struct smt_para *) ((char *)pa + pa->p_len + PARA_LEN) ; + } + smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ; + mb->sm_len = smt->smt_len + sizeof(struct smt_header) ; + + /* update reason code */ + res->rdf_reason = pcon.pc_badset ? pcon.pc_badset : + pcon.pc_err ? pcon.pc_err : SMT_RDF_SUCCESS ; + if (set && (res->rdf_reason == SMT_RDF_SUCCESS)) { + /* + * increment set count + * set time stamp + * store station id of last set + */ + smc->mib.fddiSMTSetCount.count++ ; + smt_set_timestamp(smc,smc->mib.fddiSMTSetCount.timestamp) ; + smc->mib.fddiSMTLastSetStationId = req->smt_sid ; + smt_add_para(smc,&set_pcon,(u_short) SMT_P1035,0,0) ; + smt_add_para(smc,&set_pcon,(u_short) SMT_P1036,0,0) ; + } + return mb; +} + +static int smt_authorize(struct s_smc *smc, struct smt_header *sm) +{ + struct smt_para *pa ; + int i ; + char *p ; + + /* + * check source station id if not zero + */ + p = (char *) &smc->mib.fddiPRPMFStation ; + for (i = 0 ; i < 8 && !p[i] ; i++) + ; + if (i != 8) { + if (memcmp((char *) &sm->smt_sid, + (char *) &smc->mib.fddiPRPMFStation,8)) + return 1; + } + /* + * check authoriziation parameter if passwd not zero + */ + p = (char *) smc->mib.fddiPRPMFPasswd ; + for (i = 0 ; i < 8 && !p[i] ; i++) + ; + if (i != 8) { + pa = (struct smt_para *) sm_to_para(smc,sm,SMT_P_AUTHOR) ; + if (!pa) + return 1; + if (pa->p_len != 8) + return 1; + if (memcmp((char *)(pa+1),(char *)smc->mib.fddiPRPMFPasswd,8)) + return 1; + } + return 0; +} + +static int smt_check_set_count(struct s_smc *smc, struct smt_header *sm) +{ + struct smt_para *pa ; + struct smt_p_setcount *sc ; + + pa = (struct smt_para *) sm_to_para(smc,sm,SMT_P1035) ; + if (pa) { + sc = (struct smt_p_setcount *) pa ; + if ((smc->mib.fddiSMTSetCount.count != sc->count) || + memcmp((char *) smc->mib.fddiSMTSetCount.timestamp, + (char *)sc->timestamp,8)) + return 1; + } + return 0; +} + +void smt_add_para(struct s_smc *smc, struct s_pcon *pcon, u_short para, + int index, int local) +{ + struct smt_para *pa ; + const struct s_p_tab *pt ; + struct fddi_mib_m *mib_m = NULL; + struct fddi_mib_p *mib_p = NULL; + int len ; + int plen ; + char *from ; + char *to ; + const char *swap ; + char c ; + int range ; + char *mib_addr ; + int mac ; + int path ; + int port ; + int sp_len ; + + /* + * skip if error + */ + if (pcon->pc_err) + return ; + + /* + * actions don't have a value + */ + pt = smt_get_ptab(para) ; + if (pt && pt->p_access == AC_S) + return ; + + to = (char *) (pcon->pc_p) ; /* destination pointer */ + len = pcon->pc_len ; /* free space */ + plen = len ; /* remember start length */ + pa = (struct smt_para *) to ; /* type/length pointer */ + to += PARA_LEN ; /* skip smt_para */ + len -= PARA_LEN ; + /* + * set index if required + */ + if (((range = (para & 0xf000)) == 0x2000) || + range == 0x3000 || range == 0x4000) { + if (len < 4) + goto wrong_error ; + to[0] = 0 ; + to[1] = 0 ; + to[2] = 0 ; + to[3] = index ; + len -= 4 ; + to += 4 ; + } + mac = index - INDEX_MAC ; + path = index - INDEX_PATH ; + port = index - INDEX_PORT ; + /* + * get pointer to mib + */ + switch (range) { + case 0x1000 : + default : + mib_addr = (char *) (&smc->mib) ; + break ; + case 0x2000 : + if (mac < 0 || mac >= NUMMACS) { + pcon->pc_err = SMT_RDF_NOPARAM ; + return ; + } + mib_addr = (char *) (&smc->mib.m[mac]) ; + mib_m = (struct fddi_mib_m *) mib_addr ; + break ; + case 0x3000 : + if (path < 0 || path >= NUMPATHS) { + pcon->pc_err = SMT_RDF_NOPARAM ; + return ; + } + mib_addr = (char *) (&smc->mib.a[path]) ; + break ; + case 0x4000 : + if (port < 0 || port >= smt_mib_phys(smc)) { + pcon->pc_err = SMT_RDF_NOPARAM ; + return ; + } + mib_addr = (char *) (&smc->mib.p[port_to_mib(smc,port)]) ; + mib_p = (struct fddi_mib_p *) mib_addr ; + break ; + } + /* + * check special paras + */ + swap = NULL; + switch (para) { + case SMT_P10F0 : + case SMT_P10F1 : +#ifdef ESS + case SMT_P10F2 : + case SMT_P10F3 : + case SMT_P10F4 : + case SMT_P10F5 : + case SMT_P10F6 : + case SMT_P10F7 : +#endif +#ifdef SBA + case SMT_P10F8 : + case SMT_P10F9 : +#endif + case SMT_P20F1 : + if (!local) { + pcon->pc_err = SMT_RDF_NOPARAM ; + return ; + } + break ; + case SMT_P2034 : + case SMT_P2046 : + case SMT_P2047 : + case SMT_P204A : + case SMT_P2051 : + case SMT_P2052 : + mac_update_counter(smc) ; + break ; + case SMT_P4022: + mib_p->fddiPORTPC_LS = LS2MIB( + sm_pm_get_ls(smc,port_to_mib(smc,port))) ; + break ; + case SMT_P_REASON : + * (u_long *) to = 0 ; + sp_len = 4 ; + goto sp_done ; + case SMT_P1033 : /* time stamp */ + smt_set_timestamp(smc,smc->mib.fddiSMTTimeStamp) ; + break ; + + case SMT_P1020: /* port indexes */ +#if NUMPHYS == 12 + swap = "IIIIIIIIIIII" ; +#else +#if NUMPHYS == 2 + if (smc->s.sas == SMT_SAS) + swap = "I" ; + else + swap = "II" ; +#else +#if NUMPHYS == 24 + swap = "IIIIIIIIIIIIIIIIIIIIIIII" ; +#else + ???? +#endif +#endif +#endif + break ; + case SMT_P3212 : + { + sp_len = cem_build_path(smc,to,path) ; + goto sp_done ; + } + case SMT_P1048 : /* peer wrap condition */ + { + struct smt_p_1048 *sp ; + sp = (struct smt_p_1048 *) to ; + sp->p1048_flag = smc->mib.fddiSMTPeerWrapFlag ; + sp->p1048_cf_state = smc->mib.fddiSMTCF_State ; + sp_len = sizeof(struct smt_p_1048) ; + goto sp_done ; + } + case SMT_P208C : + { + struct smt_p_208c *sp ; + sp = (struct smt_p_208c *) to ; + sp->p208c_flag = + smc->mib.m[MAC0].fddiMACDuplicateAddressCond ; + sp->p208c_dupcondition = + (mib_m->fddiMACDA_Flag ? SMT_ST_MY_DUPA : 0) | + (mib_m->fddiMACUNDA_Flag ? SMT_ST_UNA_DUPA : 0); + sp->p208c_fddilong = + mib_m->fddiMACSMTAddress ; + sp->p208c_fddiunalong = + mib_m->fddiMACUpstreamNbr ; + sp->p208c_pad = 0 ; + sp_len = sizeof(struct smt_p_208c) ; + goto sp_done ; + } + case SMT_P208D : /* frame error condition */ + { + struct smt_p_208d *sp ; + sp = (struct smt_p_208d *) to ; + sp->p208d_flag = + mib_m->fddiMACFrameErrorFlag ; + sp->p208d_frame_ct = + mib_m->fddiMACFrame_Ct ; + sp->p208d_error_ct = + mib_m->fddiMACError_Ct ; + sp->p208d_lost_ct = + mib_m->fddiMACLost_Ct ; + sp->p208d_ratio = + mib_m->fddiMACFrameErrorRatio ; + sp_len = sizeof(struct smt_p_208d) ; + goto sp_done ; + } + case SMT_P208E : /* not copied condition */ + { + struct smt_p_208e *sp ; + sp = (struct smt_p_208e *) to ; + sp->p208e_flag = + mib_m->fddiMACNotCopiedFlag ; + sp->p208e_not_copied = + mib_m->fddiMACNotCopied_Ct ; + sp->p208e_copied = + mib_m->fddiMACCopied_Ct ; + sp->p208e_not_copied_ratio = + mib_m->fddiMACNotCopiedRatio ; + sp_len = sizeof(struct smt_p_208e) ; + goto sp_done ; + } + case SMT_P208F : /* neighbor change event */ + { + struct smt_p_208f *sp ; + sp = (struct smt_p_208f *) to ; + sp->p208f_multiple = + mib_m->fddiMACMultiple_N ; + sp->p208f_nacondition = + mib_m->fddiMACDuplicateAddressCond ; + sp->p208f_old_una = + mib_m->fddiMACOldUpstreamNbr ; + sp->p208f_new_una = + mib_m->fddiMACUpstreamNbr ; + sp->p208f_old_dna = + mib_m->fddiMACOldDownstreamNbr ; + sp->p208f_new_dna = + mib_m->fddiMACDownstreamNbr ; + sp->p208f_curren_path = + mib_m->fddiMACCurrentPath ; + sp->p208f_smt_address = + mib_m->fddiMACSMTAddress ; + sp_len = sizeof(struct smt_p_208f) ; + goto sp_done ; + } + case SMT_P2090 : + { + struct smt_p_2090 *sp ; + sp = (struct smt_p_2090 *) to ; + sp->p2090_multiple = + mib_m->fddiMACMultiple_P ; + sp->p2090_availablepaths = + mib_m->fddiMACAvailablePaths ; + sp->p2090_currentpath = + mib_m->fddiMACCurrentPath ; + sp->p2090_requestedpaths = + mib_m->fddiMACRequestedPaths ; + sp_len = sizeof(struct smt_p_2090) ; + goto sp_done ; + } + case SMT_P4050 : + { + struct smt_p_4050 *sp ; + sp = (struct smt_p_4050 *) to ; + sp->p4050_flag = + mib_p->fddiPORTLerFlag ; + sp->p4050_pad = 0 ; + sp->p4050_cutoff = + mib_p->fddiPORTLer_Cutoff ; + sp->p4050_alarm = + mib_p->fddiPORTLer_Alarm ; + sp->p4050_estimate = + mib_p->fddiPORTLer_Estimate ; + sp->p4050_reject_ct = + mib_p->fddiPORTLem_Reject_Ct ; + sp->p4050_ct = + mib_p->fddiPORTLem_Ct ; + sp_len = sizeof(struct smt_p_4050) ; + goto sp_done ; + } + + case SMT_P4051 : + { + struct smt_p_4051 *sp ; + sp = (struct smt_p_4051 *) to ; + sp->p4051_multiple = + mib_p->fddiPORTMultiple_U ; + sp->p4051_porttype = + mib_p->fddiPORTMy_Type ; + sp->p4051_connectstate = + mib_p->fddiPORTConnectState ; + sp->p4051_pc_neighbor = + mib_p->fddiPORTNeighborType ; + sp->p4051_pc_withhold = + mib_p->fddiPORTPC_Withhold ; + sp_len = sizeof(struct smt_p_4051) ; + goto sp_done ; + } + case SMT_P4052 : + { + struct smt_p_4052 *sp ; + sp = (struct smt_p_4052 *) to ; + sp->p4052_flag = + mib_p->fddiPORTEB_Condition ; + sp->p4052_eberrorcount = + mib_p->fddiPORTEBError_Ct ; + sp_len = sizeof(struct smt_p_4052) ; + goto sp_done ; + } + case SMT_P4053 : + { + struct smt_p_4053 *sp ; + sp = (struct smt_p_4053 *) to ; + sp->p4053_multiple = + mib_p->fddiPORTMultiple_P ; + sp->p4053_availablepaths = + mib_p->fddiPORTAvailablePaths ; + sp->p4053_currentpath = + mib_p->fddiPORTCurrentPath ; + memcpy( (char *) &sp->p4053_requestedpaths, + (char *) mib_p->fddiPORTRequestedPaths,4) ; + sp->p4053_mytype = + mib_p->fddiPORTMy_Type ; + sp->p4053_neighbortype = + mib_p->fddiPORTNeighborType ; + sp_len = sizeof(struct smt_p_4053) ; + goto sp_done ; + } + default : + break ; + } + /* + * in table ? + */ + if (!pt) { + pcon->pc_err = (para & 0xff00) ? SMT_RDF_NOPARAM : + SMT_RDF_ILLEGAL ; + return ; + } + /* + * check access rights + */ + switch (pt->p_access) { + case AC_G : + case AC_GR : + break ; + default : + pcon->pc_err = SMT_RDF_ILLEGAL ; + return ; + } + from = mib_addr + pt->p_offset ; + if (!swap) + swap = pt->p_swap ; /* pointer to swap string */ + + /* + * copy values + */ + while ((c = *swap++)) { + switch(c) { + case 'b' : + case 'w' : + case 'l' : + break ; + case 'S' : + case 'E' : + case 'R' : + case 'r' : + if (len < 4) + goto len_error ; + to[0] = 0 ; + to[1] = 0 ; +#ifdef LITTLE_ENDIAN + if (c == 'r') { + to[2] = *from++ ; + to[3] = *from++ ; + } + else { + to[3] = *from++ ; + to[2] = *from++ ; + } +#else + to[2] = *from++ ; + to[3] = *from++ ; +#endif + to += 4 ; + len -= 4 ; + break ; + case 'I' : /* for SET of port indexes */ + if (len < 2) + goto len_error ; +#ifdef LITTLE_ENDIAN + to[1] = *from++ ; + to[0] = *from++ ; +#else + to[0] = *from++ ; + to[1] = *from++ ; +#endif + to += 2 ; + len -= 2 ; + break ; + case 'F' : + case 'B' : + if (len < 4) + goto len_error ; + len -= 4 ; + to[0] = 0 ; + to[1] = 0 ; + to[2] = 0 ; + to[3] = *from++ ; + to += 4 ; + break ; + case 'C' : + case 'T' : + case 'L' : + if (len < 4) + goto len_error ; +#ifdef LITTLE_ENDIAN + to[3] = *from++ ; + to[2] = *from++ ; + to[1] = *from++ ; + to[0] = *from++ ; +#else + to[0] = *from++ ; + to[1] = *from++ ; + to[2] = *from++ ; + to[3] = *from++ ; +#endif + len -= 4 ; + to += 4 ; + break ; + case '2' : /* PortMacIndicated */ + if (len < 4) + goto len_error ; + to[0] = 0 ; + to[1] = 0 ; + to[2] = *from++ ; + to[3] = *from++ ; + len -= 4 ; + to += 4 ; + break ; + case '4' : + if (len < 4) + goto len_error ; + to[0] = *from++ ; + to[1] = *from++ ; + to[2] = *from++ ; + to[3] = *from++ ; + len -= 4 ; + to += 4 ; + break ; + case 'A' : + if (len < 8) + goto len_error ; + to[0] = 0 ; + to[1] = 0 ; + memcpy((char *) to+2,(char *) from,6) ; + to += 8 ; + from += 8 ; + len -= 8 ; + break ; + case '8' : + if (len < 8) + goto len_error ; + memcpy((char *) to,(char *) from,8) ; + to += 8 ; + from += 8 ; + len -= 8 ; + break ; + case 'D' : + if (len < 32) + goto len_error ; + memcpy((char *) to,(char *) from,32) ; + to += 32 ; + from += 32 ; + len -= 32 ; + break ; + case 'P' : /* timestamp is NOT swapped */ + if (len < 8) + goto len_error ; + to[0] = *from++ ; + to[1] = *from++ ; + to[2] = *from++ ; + to[3] = *from++ ; + to[4] = *from++ ; + to[5] = *from++ ; + to[6] = *from++ ; + to[7] = *from++ ; + to += 8 ; + len -= 8 ; + break ; + default : + SMT_PANIC(smc,SMT_E0119, SMT_E0119_MSG) ; + break ; + } + } + +done: + /* + * make it even (in case of 'I' encoding) + * note: len is DECREMENTED + */ + if (len & 3) { + to[0] = 0 ; + to[1] = 0 ; + to += 4 - (len & 3 ) ; + len = len & ~ 3 ; + } + + /* set type and length */ + pa->p_type = para ; + pa->p_len = plen - len - PARA_LEN ; + /* return values */ + pcon->pc_p = (void *) to ; + pcon->pc_len = len ; + return ; + +sp_done: + len -= sp_len ; + to += sp_len ; + goto done ; + +len_error: + /* parameter does not fit in frame */ + pcon->pc_err = SMT_RDF_TOOLONG ; + return ; + +wrong_error: + pcon->pc_err = SMT_RDF_LENGTH ; +} + +/* + * set parameter + */ +static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index, + int local, int set) +{ +#define IFSET(x) if (set) (x) + + const struct s_p_tab *pt ; + int len ; + char *from ; + char *to ; + const char *swap ; + char c ; + char *mib_addr ; + struct fddi_mib *mib ; + struct fddi_mib_m *mib_m = NULL; + struct fddi_mib_a *mib_a = NULL; + struct fddi_mib_p *mib_p = NULL; + int mac ; + int path ; + int port ; + SK_LOC_DECL(u_char,byte_val) ; + SK_LOC_DECL(u_short,word_val) ; + SK_LOC_DECL(u_long,long_val) ; + + mac = index - INDEX_MAC ; + path = index - INDEX_PATH ; + port = index - INDEX_PORT ; + len = pa->p_len ; + from = (char *) (pa + 1 ) ; + + mib = &smc->mib ; + switch (pa->p_type & 0xf000) { + case 0x1000 : + default : + mib_addr = (char *) mib ; + break ; + case 0x2000 : + if (mac < 0 || mac >= NUMMACS) { + return SMT_RDF_NOPARAM; + } + mib_m = &smc->mib.m[mac] ; + mib_addr = (char *) mib_m ; + from += 4 ; /* skip index */ + len -= 4 ; + break ; + case 0x3000 : + if (path < 0 || path >= NUMPATHS) { + return SMT_RDF_NOPARAM; + } + mib_a = &smc->mib.a[path] ; + mib_addr = (char *) mib_a ; + from += 4 ; /* skip index */ + len -= 4 ; + break ; + case 0x4000 : + if (port < 0 || port >= smt_mib_phys(smc)) { + return SMT_RDF_NOPARAM; + } + mib_p = &smc->mib.p[port_to_mib(smc,port)] ; + mib_addr = (char *) mib_p ; + from += 4 ; /* skip index */ + len -= 4 ; + break ; + } + switch (pa->p_type) { + case SMT_P10F0 : + case SMT_P10F1 : +#ifdef ESS + case SMT_P10F2 : + case SMT_P10F3 : + case SMT_P10F4 : + case SMT_P10F5 : + case SMT_P10F6 : + case SMT_P10F7 : +#endif +#ifdef SBA + case SMT_P10F8 : + case SMT_P10F9 : +#endif + case SMT_P20F1 : + if (!local) + return SMT_RDF_NOPARAM; + break ; + } + pt = smt_get_ptab(pa->p_type) ; + if (!pt) + return (pa->p_type & 0xff00) ? SMT_RDF_NOPARAM : + SMT_RDF_ILLEGAL; + switch (pt->p_access) { + case AC_GR : + case AC_S : + break ; + default : + return SMT_RDF_ILLEGAL; + } + to = mib_addr + pt->p_offset ; + swap = pt->p_swap ; /* pointer to swap string */ + + while (swap && (c = *swap++)) { + switch(c) { + case 'b' : + to = (char *) &byte_val ; + break ; + case 'w' : + to = (char *) &word_val ; + break ; + case 'l' : + to = (char *) &long_val ; + break ; + case 'S' : + case 'E' : + case 'R' : + case 'r' : + if (len < 4) { + goto len_error ; + } + if (from[0] | from[1]) + goto val_error ; +#ifdef LITTLE_ENDIAN + if (c == 'r') { + to[0] = from[2] ; + to[1] = from[3] ; + } + else { + to[1] = from[2] ; + to[0] = from[3] ; + } +#else + to[0] = from[2] ; + to[1] = from[3] ; +#endif + from += 4 ; + to += 2 ; + len -= 4 ; + break ; + case 'F' : + case 'B' : + if (len < 4) { + goto len_error ; + } + if (from[0] | from[1] | from[2]) + goto val_error ; + to[0] = from[3] ; + len -= 4 ; + from += 4 ; + to += 4 ; + break ; + case 'C' : + case 'T' : + case 'L' : + if (len < 4) { + goto len_error ; + } +#ifdef LITTLE_ENDIAN + to[3] = *from++ ; + to[2] = *from++ ; + to[1] = *from++ ; + to[0] = *from++ ; +#else + to[0] = *from++ ; + to[1] = *from++ ; + to[2] = *from++ ; + to[3] = *from++ ; +#endif + len -= 4 ; + to += 4 ; + break ; + case 'A' : + if (len < 8) + goto len_error ; + if (set) + memcpy((char *) to,(char *) from+2,6) ; + to += 8 ; + from += 8 ; + len -= 8 ; + break ; + case '4' : + if (len < 4) + goto len_error ; + if (set) + memcpy((char *) to,(char *) from,4) ; + to += 4 ; + from += 4 ; + len -= 4 ; + break ; + case '8' : + if (len < 8) + goto len_error ; + if (set) + memcpy((char *) to,(char *) from,8) ; + to += 8 ; + from += 8 ; + len -= 8 ; + break ; + case 'D' : + if (len < 32) + goto len_error ; + if (set) + memcpy((char *) to,(char *) from,32) ; + to += 32 ; + from += 32 ; + len -= 32 ; + break ; + case 'P' : /* timestamp is NOT swapped */ + if (set) { + to[0] = *from++ ; + to[1] = *from++ ; + to[2] = *from++ ; + to[3] = *from++ ; + to[4] = *from++ ; + to[5] = *from++ ; + to[6] = *from++ ; + to[7] = *from++ ; + } + to += 8 ; + len -= 8 ; + break ; + default : + SMT_PANIC(smc,SMT_E0120, SMT_E0120_MSG) ; + return SMT_RDF_ILLEGAL; + } + } + /* + * actions and internal updates + */ + switch (pa->p_type) { + case SMT_P101A: /* fddiSMTConfigPolicy */ + if (word_val & ~1) + goto val_error ; + IFSET(mib->fddiSMTConfigPolicy = word_val) ; + break ; + case SMT_P101B : /* fddiSMTConnectionPolicy */ + if (!(word_val & POLICY_MM)) + goto val_error ; + IFSET(mib->fddiSMTConnectionPolicy = word_val) ; + break ; + case SMT_P101D : /* fddiSMTTT_Notify */ + if (word_val < 2 || word_val > 30) + goto val_error ; + IFSET(mib->fddiSMTTT_Notify = word_val) ; + break ; + case SMT_P101E : /* fddiSMTStatRptPolicy */ + if (byte_val & ~1) + goto val_error ; + IFSET(mib->fddiSMTStatRptPolicy = byte_val) ; + break ; + case SMT_P101F : /* fddiSMTTrace_MaxExpiration */ + /* + * note: lower limit trace_max = 6.001773... s + * NO upper limit + */ + if (long_val < (long)0x478bf51L) + goto val_error ; + IFSET(mib->fddiSMTTrace_MaxExpiration = long_val) ; + break ; +#ifdef ESS + case SMT_P10F2 : /* fddiESSPayload */ + if (long_val > 1562) + goto val_error ; + if (set && smc->mib.fddiESSPayload != long_val) { + smc->ess.raf_act_timer_poll = TRUE ; + smc->mib.fddiESSPayload = long_val ; + } + break ; + case SMT_P10F3 : /* fddiESSOverhead */ + if (long_val < 50 || long_val > 5000) + goto val_error ; + if (set && smc->mib.fddiESSPayload && + smc->mib.fddiESSOverhead != long_val) { + smc->ess.raf_act_timer_poll = TRUE ; + smc->mib.fddiESSOverhead = long_val ; + } + break ; + case SMT_P10F4 : /* fddiESSMaxTNeg */ + if (long_val > -MS2BCLK(5) || long_val < -MS2BCLK(165)) + goto val_error ; + IFSET(mib->fddiESSMaxTNeg = long_val) ; + break ; + case SMT_P10F5 : /* fddiESSMinSegmentSize */ + if (long_val < 1 || long_val > 4478) + goto val_error ; + IFSET(mib->fddiESSMinSegmentSize = long_val) ; + break ; + case SMT_P10F6 : /* fddiESSCategory */ + if ((long_val & 0xffff) != 1) + goto val_error ; + IFSET(mib->fddiESSCategory = long_val) ; + break ; + case SMT_P10F7 : /* fddiESSSyncTxMode */ + if (word_val > 1) + goto val_error ; + IFSET(mib->fddiESSSynchTxMode = word_val) ; + break ; +#endif +#ifdef SBA + case SMT_P10F8 : /* fddiSBACommand */ + if (byte_val != SB_STOP && byte_val != SB_START) + goto val_error ; + IFSET(mib->fddiSBACommand = byte_val) ; + break ; + case SMT_P10F9 : /* fddiSBAAvailable */ + if (byte_val > 100) + goto val_error ; + IFSET(mib->fddiSBAAvailable = byte_val) ; + break ; +#endif + case SMT_P2020 : /* fddiMACRequestedPaths */ + if ((word_val & (MIB_P_PATH_PRIM_PREFER | + MIB_P_PATH_PRIM_ALTER)) == 0 ) + goto val_error ; + IFSET(mib_m->fddiMACRequestedPaths = word_val) ; + break ; + case SMT_P205F : /* fddiMACFrameErrorThreshold */ + /* 0 .. ffff acceptable */ + IFSET(mib_m->fddiMACFrameErrorThreshold = word_val) ; + break ; + case SMT_P2067 : /* fddiMACNotCopiedThreshold */ + /* 0 .. ffff acceptable */ + IFSET(mib_m->fddiMACNotCopiedThreshold = word_val) ; + break ; + case SMT_P2076: /* fddiMACMA_UnitdataEnable */ + if (byte_val & ~1) + goto val_error ; + if (set) { + mib_m->fddiMACMA_UnitdataEnable = byte_val ; + queue_event(smc,EVENT_RMT,RM_ENABLE_FLAG) ; + } + break ; + case SMT_P20F1 : /* fddiMACT_Min */ + IFSET(mib_m->fddiMACT_Min = long_val) ; + break ; + case SMT_P320F : + if (long_val > 1562) + goto val_error ; + IFSET(mib_a->fddiPATHSbaPayload = long_val) ; +#ifdef ESS + if (set) + ess_para_change(smc) ; +#endif + break ; + case SMT_P3210 : + if (long_val > 5000) + goto val_error ; + + if (long_val != 0 && mib_a->fddiPATHSbaPayload == 0) + goto val_error ; + + IFSET(mib_a->fddiPATHSbaOverhead = long_val) ; +#ifdef ESS + if (set) + ess_para_change(smc) ; +#endif + break ; + case SMT_P3213: /* fddiPATHT_Rmode */ + /* no limit : + * 0 .. 343.597 => 0 .. 2e32 * 80nS + */ + if (set) { + mib_a->fddiPATHT_Rmode = long_val ; + rtm_set_timer(smc) ; + } + break ; + case SMT_P3214 : /* fddiPATHSbaAvailable */ + if (long_val > 0x00BEBC20L) + goto val_error ; +#ifdef SBA + if (set && mib->fddiSBACommand == SB_STOP) + goto val_error ; +#endif + IFSET(mib_a->fddiPATHSbaAvailable = long_val) ; + break ; + case SMT_P3215 : /* fddiPATHTVXLowerBound */ + IFSET(mib_a->fddiPATHTVXLowerBound = long_val) ; + goto change_mac_para ; + case SMT_P3216 : /* fddiPATHT_MaxLowerBound */ + IFSET(mib_a->fddiPATHT_MaxLowerBound = long_val) ; + goto change_mac_para ; + case SMT_P3217 : /* fddiPATHMaxT_Req */ + IFSET(mib_a->fddiPATHMaxT_Req = long_val) ; + +change_mac_para: + if (set && smt_set_mac_opvalues(smc)) { + RS_SET(smc,RS_EVENT) ; + smc->sm.please_reconnect = 1 ; + queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; + } + break ; + case SMT_P400E : /* fddiPORTConnectionPolicies */ + if (byte_val > 1) + goto val_error ; + IFSET(mib_p->fddiPORTConnectionPolicies = byte_val) ; + break ; + case SMT_P4011 : /* fddiPORTRequestedPaths */ + /* all 3*8 bits allowed */ + IFSET(memcpy((char *)mib_p->fddiPORTRequestedPaths, + (char *)&long_val,4)) ; + break ; + case SMT_P401F: /* fddiPORTMaint_LS */ + if (word_val > 4) + goto val_error ; + IFSET(mib_p->fddiPORTMaint_LS = word_val) ; + break ; + case SMT_P403A : /* fddiPORTLer_Cutoff */ + if (byte_val < 4 || byte_val > 15) + goto val_error ; + IFSET(mib_p->fddiPORTLer_Cutoff = byte_val) ; + break ; + case SMT_P403B : /* fddiPORTLer_Alarm */ + if (byte_val < 4 || byte_val > 15) + goto val_error ; + IFSET(mib_p->fddiPORTLer_Alarm = byte_val) ; + break ; + + /* + * Actions + */ + case SMT_P103C : /* fddiSMTStationAction */ + if (smt_action(smc,SMT_STATION_ACTION, (int) word_val, 0)) + goto val_error ; + break ; + case SMT_P4046: /* fddiPORTAction */ + if (smt_action(smc,SMT_PORT_ACTION, (int) word_val, + port_to_mib(smc,port))) + goto val_error ; + break ; + default : + break ; + } + return 0; + +val_error: + /* parameter value in frame is out of range */ + return SMT_RDF_RANGE; + +len_error: + /* parameter value in frame is too short */ + return SMT_RDF_LENGTH; + +#if 0 +no_author_error: + /* parameter not setable, because the SBA is not active + * Please note: we give the return code 'not authorizeed + * because SBA denied is not a valid return code in the + * PMF protocol. + */ + return SMT_RDF_AUTHOR; +#endif +} + +static const struct s_p_tab *smt_get_ptab(u_short para) +{ + const struct s_p_tab *pt ; + for (pt = p_tab ; pt->p_num && pt->p_num != para ; pt++) + ; + return pt->p_num ? pt : NULL; +} + +static int smt_mib_phys(struct s_smc *smc) +{ +#ifdef CONCENTRATOR + SK_UNUSED(smc) ; + + return NUMPHYS; +#else + if (smc->s.sas == SMT_SAS) + return 1; + return NUMPHYS; +#endif +} + +static int port_to_mib(struct s_smc *smc, int p) +{ +#ifdef CONCENTRATOR + SK_UNUSED(smc) ; + + return p; +#else + if (smc->s.sas == SMT_SAS) + return PS; + return p; +#endif +} + + +#ifdef DEBUG +#ifndef BOOT +void dump_smt(struct s_smc *smc, struct smt_header *sm, char *text) +{ + int len ; + struct smt_para *pa ; + char *c ; + int n ; + int nn ; +#ifdef LITTLE_ENDIAN + int smtlen ; +#endif + + SK_UNUSED(smc) ; + +#ifdef DEBUG_BRD + if (smc->debug.d_smtf < 2) +#else + if (debug.d_smtf < 2) +#endif + return ; +#ifdef LITTLE_ENDIAN + smtlen = sm->smt_len + sizeof(struct smt_header) ; +#endif + printf("SMT Frame [%s]:\nDA ",text) ; + dump_hex((char *) &sm->smt_dest,6) ; + printf("\tSA ") ; + dump_hex((char *) &sm->smt_source,6) ; + printf(" Class %x Type %x Version %x\n", + sm->smt_class,sm->smt_type,sm->smt_version) ; + printf("TID %lx\t\tSID ",sm->smt_tid) ; + dump_hex((char *) &sm->smt_sid,8) ; + printf(" LEN %x\n",sm->smt_len) ; + + len = sm->smt_len ; + pa = (struct smt_para *) (sm + 1) ; + while (len > 0 ) { + int plen ; +#ifdef UNIX + printf("TYPE %x LEN %x VALUE\t",pa->p_type,pa->p_len) ; +#else + printf("TYPE %04x LEN %2x VALUE\t",pa->p_type,pa->p_len) ; +#endif + n = pa->p_len ; + if ( (n < 0 ) || (n > (int)(len - PARA_LEN))) { + n = len - PARA_LEN ; + printf(" BAD LENGTH\n") ; + break ; + } +#ifdef LITTLE_ENDIAN + smt_swap_para(sm,smtlen,0) ; +#endif + if (n < 24) { + dump_hex((char *)(pa+1),(int) n) ; + printf("\n") ; + } + else { + int first = 0 ; + c = (char *)(pa+1) ; + dump_hex(c,16) ; + printf("\n") ; + n -= 16 ; + c += 16 ; + while (n > 0) { + nn = (n > 16) ? 16 : n ; + if (n > 64) { + if (first == 0) + printf("\t\t\t...\n") ; + first = 1 ; + } + else { + printf("\t\t\t") ; + dump_hex(c,nn) ; + printf("\n") ; + } + n -= nn ; + c += 16 ; + } + } +#ifdef LITTLE_ENDIAN + smt_swap_para(sm,smtlen,1) ; +#endif + plen = (pa->p_len + PARA_LEN + 3) & ~3 ; + len -= plen ; + pa = (struct smt_para *)((char *)pa + plen) ; + } + printf("-------------------------------------------------\n\n") ; +} + +void dump_hex(char *p, int len) +{ + int n = 0 ; + while (len--) { + n++ ; +#ifdef UNIX + printf("%x%s",*p++ & 0xff,len ? ( (n & 7) ? " " : "-") : "") ; +#else + printf("%02x%s",*p++ & 0xff,len ? ( (n & 7) ? " " : "-") : "") ; +#endif + } +} +#endif /* no BOOT */ +#endif /* DEBUG */ + + +#endif /* no SLIM_SMT */ diff --git a/drivers/net/fddi/skfp/queue.c b/drivers/net/fddi/skfp/queue.c new file mode 100644 index 0000000..c1a0df4 --- /dev/null +++ b/drivers/net/fddi/skfp/queue.c @@ -0,0 +1,173 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + SMT Event Queue Management +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)queue.c 2.9 97/08/04 (C) SK " ; +#endif + +#define PRINTF(a,b,c) + +/* + * init event queue management + */ +void ev_init(struct s_smc *smc) +{ + smc->q.ev_put = smc->q.ev_get = smc->q.ev_queue ; +} + +/* + * add event to queue + */ +void queue_event(struct s_smc *smc, int class, int event) +{ + PRINTF("queue class %d event %d\n",class,event) ; + smc->q.ev_put->class = class ; + smc->q.ev_put->event = event ; + if (++smc->q.ev_put == &smc->q.ev_queue[MAX_EVENT]) + smc->q.ev_put = smc->q.ev_queue ; + + if (smc->q.ev_put == smc->q.ev_get) { + SMT_ERR_LOG(smc,SMT_E0137, SMT_E0137_MSG) ; + } +} + +/* + * timer_event is called from HW timer package. + */ +void timer_event(struct s_smc *smc, u_long token) +{ + PRINTF("timer event class %d token %d\n", + EV_T_CLASS(token), + EV_T_EVENT(token)) ; + queue_event(smc,EV_T_CLASS(token),EV_T_EVENT(token)); +} + +/* + * event dispatcher + * while event queue is not empty + * get event from queue + * send command to state machine + * end + */ +void ev_dispatcher(struct s_smc *smc) +{ + struct event_queue *ev ; /* pointer into queue */ + int class ; + + ev = smc->q.ev_get ; + PRINTF("dispatch get %x put %x\n",ev,smc->q.ev_put) ; + while (ev != smc->q.ev_put) { + PRINTF("dispatch class %d event %d\n",ev->class,ev->event) ; + switch(class = ev->class) { + case EVENT_ECM : /* Entity Corordination Man. */ + ecm(smc,(int)ev->event) ; + break ; + case EVENT_CFM : /* Configuration Man. */ + cfm(smc,(int)ev->event) ; + break ; + case EVENT_RMT : /* Ring Man. */ + rmt(smc,(int)ev->event) ; + break ; + case EVENT_SMT : + smt_event(smc,(int)ev->event) ; + break ; +#ifdef CONCENTRATOR + case 99 : + timer_test_event(smc,(int)ev->event) ; + break ; +#endif + case EVENT_PCMA : /* PHY A */ + case EVENT_PCMB : /* PHY B */ + default : + if (class >= EVENT_PCMA && + class < EVENT_PCMA + NUMPHYS) { + pcm(smc,class - EVENT_PCMA,(int)ev->event) ; + break ; + } + SMT_PANIC(smc,SMT_E0121, SMT_E0121_MSG) ; + return ; + } + + if (++ev == &smc->q.ev_queue[MAX_EVENT]) + ev = smc->q.ev_queue ; + + /* Renew get: it is used in queue_events to detect overruns */ + smc->q.ev_get = ev; + } +} + +/* + * smt_online connects to or disconnects from the ring + * MUST be called to initiate connection establishment + * + * on 0 disconnect + * on 1 connect + */ +u_short smt_online(struct s_smc *smc, int on) +{ + queue_event(smc,EVENT_ECM,on ? EC_CONNECT : EC_DISCONNECT) ; + ev_dispatcher(smc) ; + return smc->mib.fddiSMTCF_State; +} + +/* + * set SMT flag to value + * flag flag name + * value flag value + * dump current flag setting + */ +#ifdef CONCENTRATOR +void do_smt_flag(struct s_smc *smc, char *flag, int value) +{ +#ifdef DEBUG + struct smt_debug *deb; + + SK_UNUSED(smc) ; + +#ifdef DEBUG_BRD + deb = &smc->debug; +#else + deb = &debug; +#endif + if (!strcmp(flag,"smt")) + deb->d_smt = value ; + else if (!strcmp(flag,"smtf")) + deb->d_smtf = value ; + else if (!strcmp(flag,"pcm")) + deb->d_pcm = value ; + else if (!strcmp(flag,"rmt")) + deb->d_rmt = value ; + else if (!strcmp(flag,"cfm")) + deb->d_cfm = value ; + else if (!strcmp(flag,"ecm")) + deb->d_ecm = value ; + printf("smt %d\n",deb->d_smt) ; + printf("smtf %d\n",deb->d_smtf) ; + printf("pcm %d\n",deb->d_pcm) ; + printf("rmt %d\n",deb->d_rmt) ; + printf("cfm %d\n",deb->d_cfm) ; + printf("ecm %d\n",deb->d_ecm) ; +#endif /* DEBUG */ +} +#endif diff --git a/drivers/net/fddi/skfp/rmt.c b/drivers/net/fddi/skfp/rmt.c new file mode 100644 index 0000000..ef8d567 --- /dev/null +++ b/drivers/net/fddi/skfp/rmt.c @@ -0,0 +1,654 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + SMT RMT + Ring Management +*/ + +/* + * Hardware independent state machine implemantation + * The following external SMT functions are referenced : + * + * queue_event() + * smt_timer_start() + * smt_timer_stop() + * + * The following external HW dependent functions are referenced : + * sm_ma_control() + * sm_mac_check_beacon_claim() + * + * The following HW dependent events are required : + * RM_RING_OP + * RM_RING_NON_OP + * RM_MY_BEACON + * RM_OTHER_BEACON + * RM_MY_CLAIM + * RM_TRT_EXP + * RM_VALID_CLAIM + * + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)rmt.c 2.13 99/07/02 (C) SK " ; +#endif + +/* + * FSM Macros + */ +#define AFLAG 0x10 +#define GO_STATE(x) (smc->mib.m[MAC0].fddiMACRMTState = (x)|AFLAG) +#define ACTIONS_DONE() (smc->mib.m[MAC0].fddiMACRMTState &= ~AFLAG) +#define ACTIONS(x) (x|AFLAG) + +#define RM0_ISOLATED 0 +#define RM1_NON_OP 1 /* not operational */ +#define RM2_RING_OP 2 /* ring operational */ +#define RM3_DETECT 3 /* detect dupl addresses */ +#define RM4_NON_OP_DUP 4 /* dupl. addr detected */ +#define RM5_RING_OP_DUP 5 /* ring oper. with dupl. addr */ +#define RM6_DIRECTED 6 /* sending directed beacons */ +#define RM7_TRACE 7 /* trace initiated */ + +#ifdef DEBUG +/* + * symbolic state names + */ +static const char * const rmt_states[] = { + "RM0_ISOLATED","RM1_NON_OP","RM2_RING_OP","RM3_DETECT", + "RM4_NON_OP_DUP","RM5_RING_OP_DUP","RM6_DIRECTED", + "RM7_TRACE" +} ; + +/* + * symbolic event names + */ +static const char * const rmt_events[] = { + "NONE","RM_RING_OP","RM_RING_NON_OP","RM_MY_BEACON", + "RM_OTHER_BEACON","RM_MY_CLAIM","RM_TRT_EXP","RM_VALID_CLAIM", + "RM_JOIN","RM_LOOP","RM_DUP_ADDR","RM_ENABLE_FLAG", + "RM_TIMEOUT_NON_OP","RM_TIMEOUT_T_STUCK", + "RM_TIMEOUT_ANNOUNCE","RM_TIMEOUT_T_DIRECT", + "RM_TIMEOUT_D_MAX","RM_TIMEOUT_POLL","RM_TX_STATE_CHANGE" +} ; +#endif + +/* + * Globals + * in struct s_rmt + */ + + +/* + * function declarations + */ +static void rmt_fsm(struct s_smc *smc, int cmd); +static void start_rmt_timer0(struct s_smc *smc, u_long value, int event); +static void start_rmt_timer1(struct s_smc *smc, u_long value, int event); +static void start_rmt_timer2(struct s_smc *smc, u_long value, int event); +static void stop_rmt_timer0(struct s_smc *smc); +static void stop_rmt_timer1(struct s_smc *smc); +static void stop_rmt_timer2(struct s_smc *smc); +static void rmt_dup_actions(struct s_smc *smc); +static void rmt_reinsert_actions(struct s_smc *smc); +static void rmt_leave_actions(struct s_smc *smc); +static void rmt_new_dup_actions(struct s_smc *smc); + +#ifndef SUPERNET_3 +extern void restart_trt_for_dbcn() ; +#endif /*SUPERNET_3*/ + +/* + init RMT state machine + clear all RMT vars and flags +*/ +void rmt_init(struct s_smc *smc) +{ + smc->mib.m[MAC0].fddiMACRMTState = ACTIONS(RM0_ISOLATED) ; + smc->r.dup_addr_test = DA_NONE ; + smc->r.da_flag = 0 ; + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + smc->r.sm_ma_avail = FALSE ; + smc->r.loop_avail = 0 ; + smc->r.bn_flag = 0 ; + smc->r.jm_flag = 0 ; + smc->r.no_flag = TRUE ; +} + +/* + RMT state machine + called by dispatcher + + do + display state change + process event + until SM is stable +*/ +void rmt(struct s_smc *smc, int event) +{ + int state ; + + do { + DB_RMT("RMT : state %s%s", + (smc->mib.m[MAC0].fddiMACRMTState & AFLAG) ? "ACTIONS " : "", + rmt_states[smc->mib.m[MAC0].fddiMACRMTState & ~AFLAG]) ; + DB_RMT(" event %s\n",rmt_events[event],0) ; + state = smc->mib.m[MAC0].fddiMACRMTState ; + rmt_fsm(smc,event) ; + event = 0 ; + } while (state != smc->mib.m[MAC0].fddiMACRMTState) ; + rmt_state_change(smc,(int)smc->mib.m[MAC0].fddiMACRMTState) ; +} + +/* + process RMT event +*/ +static void rmt_fsm(struct s_smc *smc, int cmd) +{ + /* + * RM00-RM70 : from all states + */ + if (!smc->r.rm_join && !smc->r.rm_loop && + smc->mib.m[MAC0].fddiMACRMTState != ACTIONS(RM0_ISOLATED) && + smc->mib.m[MAC0].fddiMACRMTState != RM0_ISOLATED) { + RS_SET(smc,RS_NORINGOP) ; + rmt_indication(smc,0) ; + GO_STATE(RM0_ISOLATED) ; + return ; + } + + switch(smc->mib.m[MAC0].fddiMACRMTState) { + case ACTIONS(RM0_ISOLATED) : + stop_rmt_timer0(smc) ; + stop_rmt_timer1(smc) ; + stop_rmt_timer2(smc) ; + + /* + * Disable MAC. + */ + sm_ma_control(smc,MA_OFFLINE) ; + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + smc->r.loop_avail = FALSE ; + smc->r.sm_ma_avail = FALSE ; + smc->r.no_flag = TRUE ; + DB_RMTN(1,"RMT : ISOLATED\n",0,0) ; + ACTIONS_DONE() ; + break ; + case RM0_ISOLATED : + /*RM01*/ + if (smc->r.rm_join || smc->r.rm_loop) { + /* + * According to the standard the MAC must be reset + * here. The FORMAC will be initialized and Claim + * and Beacon Frames will be uploaded to the MAC. + * So any change of Treq will take effect NOW. + */ + sm_ma_control(smc,MA_RESET) ; + GO_STATE(RM1_NON_OP) ; + break ; + } + break ; + case ACTIONS(RM1_NON_OP) : + start_rmt_timer0(smc,smc->s.rmt_t_non_op,RM_TIMEOUT_NON_OP) ; + stop_rmt_timer1(smc) ; + stop_rmt_timer2(smc) ; + sm_ma_control(smc,MA_BEACON) ; + DB_RMTN(1,"RMT : RING DOWN\n",0,0) ; + RS_SET(smc,RS_NORINGOP) ; + smc->r.sm_ma_avail = FALSE ; + rmt_indication(smc,0) ; + ACTIONS_DONE() ; + break ; + case RM1_NON_OP : + /*RM12*/ + if (cmd == RM_RING_OP) { + RS_SET(smc,RS_RINGOPCHANGE) ; + GO_STATE(RM2_RING_OP) ; + break ; + } + /*RM13*/ + else if (cmd == RM_TIMEOUT_NON_OP) { + smc->r.bn_flag = FALSE ; + smc->r.no_flag = TRUE ; + GO_STATE(RM3_DETECT) ; + break ; + } + break ; + case ACTIONS(RM2_RING_OP) : + stop_rmt_timer0(smc) ; + stop_rmt_timer1(smc) ; + stop_rmt_timer2(smc) ; + smc->r.no_flag = FALSE ; + if (smc->r.rm_loop) + smc->r.loop_avail = TRUE ; + if (smc->r.rm_join) { + smc->r.sm_ma_avail = TRUE ; + if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable) + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ; + else + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + } + DB_RMTN(1,"RMT : RING UP\n",0,0) ; + RS_CLEAR(smc,RS_NORINGOP) ; + RS_SET(smc,RS_RINGOPCHANGE) ; + rmt_indication(smc,1) ; + smt_stat_counter(smc,0) ; + ACTIONS_DONE() ; + break ; + case RM2_RING_OP : + /*RM21*/ + if (cmd == RM_RING_NON_OP) { + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + smc->r.loop_avail = FALSE ; + RS_SET(smc,RS_RINGOPCHANGE) ; + GO_STATE(RM1_NON_OP) ; + break ; + } + /*RM22a*/ + else if (cmd == RM_ENABLE_FLAG) { + if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable) + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ; + else + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + } + /*RM25*/ + else if (smc->r.dup_addr_test == DA_FAILED) { + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + smc->r.loop_avail = FALSE ; + smc->r.da_flag = TRUE ; + GO_STATE(RM5_RING_OP_DUP) ; + break ; + } + break ; + case ACTIONS(RM3_DETECT) : + start_rmt_timer0(smc,smc->s.mac_d_max*2,RM_TIMEOUT_D_MAX) ; + start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ; + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ; + sm_mac_check_beacon_claim(smc) ; + DB_RMTN(1,"RMT : RM3_DETECT\n",0,0) ; + ACTIONS_DONE() ; + break ; + case RM3_DETECT : + if (cmd == RM_TIMEOUT_POLL) { + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL); + sm_mac_check_beacon_claim(smc) ; + break ; + } + if (cmd == RM_TIMEOUT_D_MAX) { + smc->r.timer0_exp = TRUE ; + } + /* + *jd(22-Feb-1999) + * We need a time ">= 2*mac_d_max" since we had finished + * Claim or Beacon state. So we will restart timer0 at + * every state change. + */ + if (cmd == RM_TX_STATE_CHANGE) { + start_rmt_timer0(smc, + smc->s.mac_d_max*2, + RM_TIMEOUT_D_MAX) ; + } + /*RM32*/ + if (cmd == RM_RING_OP) { + GO_STATE(RM2_RING_OP) ; + break ; + } + /*RM33a*/ + else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) + && smc->r.bn_flag) { + smc->r.bn_flag = FALSE ; + } + /*RM33b*/ + else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) { + int tx ; + /* + * set bn_flag only if in state T4 or T5: + * only if we're the beaconer should we start the + * trace ! + */ + if ((tx = sm_mac_get_tx_state(smc)) == 4 || tx == 5) { + DB_RMTN(2,"RMT : DETECT && TRT_EXPIRED && T4/T5\n",0,0); + smc->r.bn_flag = TRUE ; + /* + * If one of the upstream stations beaconed + * and the link to the upstream neighbor is + * lost we need to restart the stuck timer to + * check the "stuck beacon" condition. + */ + start_rmt_timer1(smc,smc->s.rmt_t_stuck, + RM_TIMEOUT_T_STUCK) ; + } + /* + * We do NOT need to clear smc->r.bn_flag in case of + * not being in state T4 or T5, because the flag + * must be cleared in order to get in this condition. + */ + + DB_RMTN(2, + "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n", + tx,smc->r.bn_flag) ; + } + /*RM34a*/ + else if (cmd == RM_MY_CLAIM && smc->r.timer0_exp) { + rmt_new_dup_actions(smc) ; + GO_STATE(RM4_NON_OP_DUP) ; + break ; + } + /*RM34b*/ + else if (cmd == RM_MY_BEACON && smc->r.timer0_exp) { + rmt_new_dup_actions(smc) ; + GO_STATE(RM4_NON_OP_DUP) ; + break ; + } + /*RM34c*/ + else if (cmd == RM_VALID_CLAIM) { + rmt_new_dup_actions(smc) ; + GO_STATE(RM4_NON_OP_DUP) ; + break ; + } + /*RM36*/ + else if (cmd == RM_TIMEOUT_T_STUCK && + smc->r.rm_join && smc->r.bn_flag) { + GO_STATE(RM6_DIRECTED) ; + break ; + } + break ; + case ACTIONS(RM4_NON_OP_DUP) : + start_rmt_timer0(smc,smc->s.rmt_t_announce,RM_TIMEOUT_ANNOUNCE); + start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ; + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ; + sm_mac_check_beacon_claim(smc) ; + DB_RMTN(1,"RMT : RM4_NON_OP_DUP\n",0,0) ; + ACTIONS_DONE() ; + break ; + case RM4_NON_OP_DUP : + if (cmd == RM_TIMEOUT_POLL) { + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL); + sm_mac_check_beacon_claim(smc) ; + break ; + } + /*RM41*/ + if (!smc->r.da_flag) { + GO_STATE(RM1_NON_OP) ; + break ; + } + /*RM44a*/ + else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) && + smc->r.bn_flag) { + smc->r.bn_flag = FALSE ; + } + /*RM44b*/ + else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) { + int tx ; + /* + * set bn_flag only if in state T4 or T5: + * only if we're the beaconer should we start the + * trace ! + */ + if ((tx = sm_mac_get_tx_state(smc)) == 4 || tx == 5) { + DB_RMTN(2,"RMT : NOPDUP && TRT_EXPIRED && T4/T5\n",0,0); + smc->r.bn_flag = TRUE ; + /* + * If one of the upstream stations beaconed + * and the link to the upstream neighbor is + * lost we need to restart the stuck timer to + * check the "stuck beacon" condition. + */ + start_rmt_timer1(smc,smc->s.rmt_t_stuck, + RM_TIMEOUT_T_STUCK) ; + } + /* + * We do NOT need to clear smc->r.bn_flag in case of + * not being in state T4 or T5, because the flag + * must be cleared in order to get in this condition. + */ + + DB_RMTN(2, + "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n", + tx,smc->r.bn_flag) ; + } + /*RM44c*/ + else if (cmd == RM_TIMEOUT_ANNOUNCE && !smc->r.bn_flag) { + rmt_dup_actions(smc) ; + } + /*RM45*/ + else if (cmd == RM_RING_OP) { + smc->r.no_flag = FALSE ; + GO_STATE(RM5_RING_OP_DUP) ; + break ; + } + /*RM46*/ + else if (cmd == RM_TIMEOUT_T_STUCK && + smc->r.rm_join && smc->r.bn_flag) { + GO_STATE(RM6_DIRECTED) ; + break ; + } + break ; + case ACTIONS(RM5_RING_OP_DUP) : + stop_rmt_timer0(smc) ; + stop_rmt_timer1(smc) ; + stop_rmt_timer2(smc) ; + DB_RMTN(1,"RMT : RM5_RING_OP_DUP\n",0,0) ; + ACTIONS_DONE() ; + break; + case RM5_RING_OP_DUP : + /*RM52*/ + if (smc->r.dup_addr_test == DA_PASSED) { + smc->r.da_flag = FALSE ; + GO_STATE(RM2_RING_OP) ; + break ; + } + /*RM54*/ + else if (cmd == RM_RING_NON_OP) { + smc->r.jm_flag = FALSE ; + smc->r.bn_flag = FALSE ; + GO_STATE(RM4_NON_OP_DUP) ; + break ; + } + break ; + case ACTIONS(RM6_DIRECTED) : + start_rmt_timer0(smc,smc->s.rmt_t_direct,RM_TIMEOUT_T_DIRECT) ; + stop_rmt_timer1(smc) ; + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ; + sm_ma_control(smc,MA_DIRECTED) ; + RS_SET(smc,RS_BEACON) ; + DB_RMTN(1,"RMT : RM6_DIRECTED\n",0,0) ; + ACTIONS_DONE() ; + break ; + case RM6_DIRECTED : + /*RM63*/ + if (cmd == RM_TIMEOUT_POLL) { + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL); + sm_mac_check_beacon_claim(smc) ; +#ifndef SUPERNET_3 + /* Because of problems with the Supernet II chip set + * sending of Directed Beacon will stop after 165ms + * therefore restart_trt_for_dbcn(smc) will be called + * to prevent this. + */ + restart_trt_for_dbcn(smc) ; +#endif /*SUPERNET_3*/ + break ; + } + if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) && + !smc->r.da_flag) { + smc->r.bn_flag = FALSE ; + GO_STATE(RM3_DETECT) ; + break ; + } + /*RM64*/ + else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) && + smc->r.da_flag) { + smc->r.bn_flag = FALSE ; + GO_STATE(RM4_NON_OP_DUP) ; + break ; + } + /*RM67*/ + else if (cmd == RM_TIMEOUT_T_DIRECT) { + GO_STATE(RM7_TRACE) ; + break ; + } + break ; + case ACTIONS(RM7_TRACE) : + stop_rmt_timer0(smc) ; + stop_rmt_timer1(smc) ; + stop_rmt_timer2(smc) ; + smc->e.trace_prop |= ENTITY_BIT(ENTITY_MAC) ; + queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ; + DB_RMTN(1,"RMT : RM7_TRACE\n",0,0) ; + ACTIONS_DONE() ; + break ; + case RM7_TRACE : + break ; + default: + SMT_PANIC(smc,SMT_E0122, SMT_E0122_MSG) ; + break; + } +} + +/* + * (jd) RMT duplicate address actions + * leave the ring or reinsert just as configured + */ +static void rmt_dup_actions(struct s_smc *smc) +{ + if (smc->r.jm_flag) { + } + else { + if (smc->s.rmt_dup_mac_behavior) { + SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ; + rmt_reinsert_actions(smc) ; + } + else { + SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ; + rmt_leave_actions(smc) ; + } + } +} + +/* + * Reconnect to the Ring + */ +static void rmt_reinsert_actions(struct s_smc *smc) +{ + queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; + queue_event(smc,EVENT_ECM,EC_CONNECT) ; +} + +/* + * duplicate address detected + */ +static void rmt_new_dup_actions(struct s_smc *smc) +{ + smc->r.da_flag = TRUE ; + smc->r.bn_flag = FALSE ; + smc->r.jm_flag = FALSE ; + /* + * we have three options : change address, jam or leave + * we leave the ring as default + * Optionally it's possible to reinsert after leaving the Ring + * but this will not conform with SMT Spec. + */ + if (smc->s.rmt_dup_mac_behavior) { + SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ; + rmt_reinsert_actions(smc) ; + } + else { + SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ; + rmt_leave_actions(smc) ; + } +} + + +/* + * leave the ring + */ +static void rmt_leave_actions(struct s_smc *smc) +{ + queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; + /* + * Note: Do NOT try again later. (with please reconnect) + * The station must be left from the ring! + */ +} + +/* + * SMT timer interface + * start RMT timer 0 + */ +static void start_rmt_timer0(struct s_smc *smc, u_long value, int event) +{ + smc->r.timer0_exp = FALSE ; /* clear timer event flag */ + smt_timer_start(smc,&smc->r.rmt_timer0,value,EV_TOKEN(EVENT_RMT,event)); +} + +/* + * SMT timer interface + * start RMT timer 1 + */ +static void start_rmt_timer1(struct s_smc *smc, u_long value, int event) +{ + smc->r.timer1_exp = FALSE ; /* clear timer event flag */ + smt_timer_start(smc,&smc->r.rmt_timer1,value,EV_TOKEN(EVENT_RMT,event)); +} + +/* + * SMT timer interface + * start RMT timer 2 + */ +static void start_rmt_timer2(struct s_smc *smc, u_long value, int event) +{ + smc->r.timer2_exp = FALSE ; /* clear timer event flag */ + smt_timer_start(smc,&smc->r.rmt_timer2,value,EV_TOKEN(EVENT_RMT,event)); +} + +/* + * SMT timer interface + * stop RMT timer 0 + */ +static void stop_rmt_timer0(struct s_smc *smc) +{ + if (smc->r.rmt_timer0.tm_active) + smt_timer_stop(smc,&smc->r.rmt_timer0) ; +} + +/* + * SMT timer interface + * stop RMT timer 1 + */ +static void stop_rmt_timer1(struct s_smc *smc) +{ + if (smc->r.rmt_timer1.tm_active) + smt_timer_stop(smc,&smc->r.rmt_timer1) ; +} + +/* + * SMT timer interface + * stop RMT timer 2 + */ +static void stop_rmt_timer2(struct s_smc *smc) +{ + if (smc->r.rmt_timer2.tm_active) + smt_timer_stop(smc,&smc->r.rmt_timer2) ; +} + diff --git a/drivers/net/fddi/skfp/skfddi.c b/drivers/net/fddi/skfp/skfddi.c new file mode 100644 index 0000000..3d9a459 --- /dev/null +++ b/drivers/net/fddi/skfp/skfddi.c @@ -0,0 +1,2260 @@ +/* + * File Name: + * skfddi.c + * + * Copyright Information: + * Copyright SysKonnect 1998,1999. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + * Abstract: + * A Linux device driver supporting the SysKonnect FDDI PCI controller + * familie. + * + * Maintainers: + * CG Christoph Goos (cgoos@syskonnect.de) + * + * Contributors: + * DM David S. Miller + * + * Address all question to: + * linux@syskonnect.de + * + * The technical manual for the adapters is available from SysKonnect's + * web pages: www.syskonnect.com + * Goto "Support" and search Knowledge Base for "manual". + * + * Driver Architecture: + * The driver architecture is based on the DEC FDDI driver by + * Lawrence V. Stefani and several ethernet drivers. + * I also used an existing Windows NT miniport driver. + * All hardware dependent functions are handled by the SysKonnect + * Hardware Module. + * The only headerfiles that are directly related to this source + * are skfddi.c, h/types.h, h/osdef1st.h, h/targetos.h. + * The others belong to the SysKonnect FDDI Hardware Module and + * should better not be changed. + * + * Modification History: + * Date Name Description + * 02-Mar-98 CG Created. + * + * 10-Mar-99 CG Support for 2.2.x added. + * 25-Mar-99 CG Corrected IRQ routing for SMP (APIC) + * 26-Oct-99 CG Fixed compilation error on 2.2.13 + * 12-Nov-99 CG Source code release + * 22-Nov-99 CG Included in kernel source. + * 07-May-00 DM 64 bit fixes, new dma interface + * 31-Jul-03 DB Audit copy_*_user in skfp_ioctl + * Daniele Bellucci + * 03-Dec-03 SH Convert to PCI device model + * + * Compilation options (-Dxxx): + * DRIVERDEBUG print lots of messages to log file + * DUMPPACKETS print received/transmitted packets to logfile + * + * Tested cpu architectures: + * - i386 + * - sparc64 + */ + +/* Version information string - should be updated prior to */ +/* each new release!!! */ +#define VERSION "2.07" + +static const char * const boot_msg = + "SysKonnect FDDI PCI Adapter driver v" VERSION " for\n" + " SK-55xx/SK-58xx adapters (SK-NET FDDI-FP/UP/LP)"; + +/* Include files */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "h/types.h" +#undef ADDR // undo Linux definition +#include "h/skfbi.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/smtstate.h" + + +// Define module-wide (static) routines +static int skfp_driver_init(struct net_device *dev); +static int skfp_open(struct net_device *dev); +static int skfp_close(struct net_device *dev); +static irqreturn_t skfp_interrupt(int irq, void *dev_id); +static struct net_device_stats *skfp_ctl_get_stats(struct net_device *dev); +static void skfp_ctl_set_multicast_list(struct net_device *dev); +static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev); +static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr); +static int skfp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static netdev_tx_t skfp_send_pkt(struct sk_buff *skb, + struct net_device *dev); +static void send_queued_packets(struct s_smc *smc); +static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr); +static void ResetAdapter(struct s_smc *smc); + + +// Functions needed by the hardware module +void *mac_drv_get_space(struct s_smc *smc, u_int size); +void *mac_drv_get_desc_mem(struct s_smc *smc, u_int size); +unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt); +unsigned long dma_master(struct s_smc *smc, void *virt, int len, int flag); +void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr, + int flag); +void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd); +void llc_restart_tx(struct s_smc *smc); +void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, + int frag_count, int len); +void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, + int frag_count); +void mac_drv_fill_rxd(struct s_smc *smc); +void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, + int frag_count); +int mac_drv_rx_init(struct s_smc *smc, int len, int fc, char *look_ahead, + int la_len); +void dump_data(unsigned char *Data, int length); + +// External functions from the hardware module +extern u_int mac_drv_check_space(void); +extern int mac_drv_init(struct s_smc *smc); +extern void hwm_tx_frag(struct s_smc *smc, char far * virt, u_long phys, + int len, int frame_status); +extern int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, + int frame_len, int frame_status); +extern void fddi_isr(struct s_smc *smc); +extern void hwm_rx_frag(struct s_smc *smc, char far * virt, u_long phys, + int len, int frame_status); +extern void mac_drv_rx_mode(struct s_smc *smc, int mode); +extern void mac_drv_clear_rx_queue(struct s_smc *smc); +extern void enable_tx_irq(struct s_smc *smc, u_short queue); + +static DEFINE_PCI_DEVICE_TABLE(skfddi_pci_tbl) = { + { PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, skfddi_pci_tbl); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mirko Lindner "); + +// Define module-wide (static) variables + +static int num_boards; /* total number of adapters configured */ + +static const struct net_device_ops skfp_netdev_ops = { + .ndo_open = skfp_open, + .ndo_stop = skfp_close, + .ndo_start_xmit = skfp_send_pkt, + .ndo_get_stats = skfp_ctl_get_stats, + .ndo_change_mtu = fddi_change_mtu, + .ndo_set_rx_mode = skfp_ctl_set_multicast_list, + .ndo_set_mac_address = skfp_ctl_set_mac_address, + .ndo_do_ioctl = skfp_ioctl, +}; + +/* + * ================= + * = skfp_init_one = + * ================= + * + * Overview: + * Probes for supported FDDI PCI controllers + * + * Returns: + * Condition code + * + * Arguments: + * pdev - pointer to PCI device information + * + * Functional Description: + * This is now called by PCI driver registration process + * for each board found. + * + * Return Codes: + * 0 - This device (fddi0, fddi1, etc) configured successfully + * -ENODEV - No devices present, or no SysKonnect FDDI PCI device + * present for this device name + * + * + * Side Effects: + * Device structures for FDDI adapters (fddi0, fddi1, etc) are + * initialized and the board resources are read and stored in + * the device structure. + */ +static int skfp_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev; + struct s_smc *smc; /* board pointer */ + void __iomem *mem; + int err; + + pr_debug("entering skfp_init_one\n"); + + if (num_boards == 0) + printk("%s\n", boot_msg); + + err = pci_enable_device(pdev); + if (err) + return err; + + err = pci_request_regions(pdev, "skfddi"); + if (err) + goto err_out1; + + pci_set_master(pdev); + +#ifdef MEM_MAPPED_IO + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + printk(KERN_ERR "skfp: region is not an MMIO resource\n"); + err = -EIO; + goto err_out2; + } + + mem = ioremap(pci_resource_start(pdev, 0), 0x4000); +#else + if (!(pci_resource_flags(pdev, 1) & IO_RESOURCE_IO)) { + printk(KERN_ERR "skfp: region is not PIO resource\n"); + err = -EIO; + goto err_out2; + } + + mem = ioport_map(pci_resource_start(pdev, 1), FP_IO_LEN); +#endif + if (!mem) { + printk(KERN_ERR "skfp: Unable to map register, " + "FDDI adapter will be disabled.\n"); + err = -EIO; + goto err_out2; + } + + dev = alloc_fddidev(sizeof(struct s_smc)); + if (!dev) { + printk(KERN_ERR "skfp: Unable to allocate fddi device, " + "FDDI adapter will be disabled.\n"); + err = -ENOMEM; + goto err_out3; + } + + dev->irq = pdev->irq; + dev->netdev_ops = &skfp_netdev_ops; + + SET_NETDEV_DEV(dev, &pdev->dev); + + /* Initialize board structure with bus-specific info */ + smc = netdev_priv(dev); + smc->os.dev = dev; + smc->os.bus_type = SK_BUS_TYPE_PCI; + smc->os.pdev = *pdev; + smc->os.QueueSkb = MAX_TX_QUEUE_LEN; + smc->os.MaxFrameSize = MAX_FRAME_SIZE; + smc->os.dev = dev; + smc->hw.slot = -1; + smc->hw.iop = mem; + smc->os.ResetRequested = FALSE; + skb_queue_head_init(&smc->os.SendSkbQueue); + + dev->base_addr = (unsigned long)mem; + + err = skfp_driver_init(dev); + if (err) + goto err_out4; + + err = register_netdev(dev); + if (err) + goto err_out5; + + ++num_boards; + pci_set_drvdata(pdev, dev); + + if ((pdev->subsystem_device & 0xff00) == 0x5500 || + (pdev->subsystem_device & 0xff00) == 0x5800) + printk("%s: SysKonnect FDDI PCI adapter" + " found (SK-%04X)\n", dev->name, + pdev->subsystem_device); + else + printk("%s: FDDI PCI adapter found\n", dev->name); + + return 0; +err_out5: + if (smc->os.SharedMemAddr) + pci_free_consistent(pdev, smc->os.SharedMemSize, + smc->os.SharedMemAddr, + smc->os.SharedMemDMA); + pci_free_consistent(pdev, MAX_FRAME_SIZE, + smc->os.LocalRxBuffer, smc->os.LocalRxBufferDMA); +err_out4: + free_netdev(dev); +err_out3: +#ifdef MEM_MAPPED_IO + iounmap(mem); +#else + ioport_unmap(mem); +#endif +err_out2: + pci_release_regions(pdev); +err_out1: + pci_disable_device(pdev); + return err; +} + +/* + * Called for each adapter board from pci_unregister_driver + */ +static void __devexit skfp_remove_one(struct pci_dev *pdev) +{ + struct net_device *p = pci_get_drvdata(pdev); + struct s_smc *lp = netdev_priv(p); + + unregister_netdev(p); + + if (lp->os.SharedMemAddr) { + pci_free_consistent(&lp->os.pdev, + lp->os.SharedMemSize, + lp->os.SharedMemAddr, + lp->os.SharedMemDMA); + lp->os.SharedMemAddr = NULL; + } + if (lp->os.LocalRxBuffer) { + pci_free_consistent(&lp->os.pdev, + MAX_FRAME_SIZE, + lp->os.LocalRxBuffer, + lp->os.LocalRxBufferDMA); + lp->os.LocalRxBuffer = NULL; + } +#ifdef MEM_MAPPED_IO + iounmap(lp->hw.iop); +#else + ioport_unmap(lp->hw.iop); +#endif + pci_release_regions(pdev); + free_netdev(p); + + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + +/* + * ==================== + * = skfp_driver_init = + * ==================== + * + * Overview: + * Initializes remaining adapter board structure information + * and makes sure adapter is in a safe state prior to skfp_open(). + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This function allocates additional resources such as the host memory + * blocks needed by the adapter. + * The adapter is also reset. The OS must call skfp_open() to open + * the adapter and bring it on-line. + * + * Return Codes: + * 0 - initialization succeeded + * -1 - initialization failed + */ +static int skfp_driver_init(struct net_device *dev) +{ + struct s_smc *smc = netdev_priv(dev); + skfddi_priv *bp = &smc->os; + int err = -EIO; + + pr_debug("entering skfp_driver_init\n"); + + // set the io address in private structures + bp->base_addr = dev->base_addr; + + // Get the interrupt level from the PCI Configuration Table + smc->hw.irq = dev->irq; + + spin_lock_init(&bp->DriverLock); + + // Allocate invalid frame + bp->LocalRxBuffer = pci_alloc_consistent(&bp->pdev, MAX_FRAME_SIZE, &bp->LocalRxBufferDMA); + if (!bp->LocalRxBuffer) { + printk("could not allocate mem for "); + printk("LocalRxBuffer: %d byte\n", MAX_FRAME_SIZE); + goto fail; + } + + // Determine the required size of the 'shared' memory area. + bp->SharedMemSize = mac_drv_check_space(); + pr_debug("Memory for HWM: %ld\n", bp->SharedMemSize); + if (bp->SharedMemSize > 0) { + bp->SharedMemSize += 16; // for descriptor alignment + + bp->SharedMemAddr = pci_alloc_consistent(&bp->pdev, + bp->SharedMemSize, + &bp->SharedMemDMA); + if (!bp->SharedMemAddr) { + printk("could not allocate mem for "); + printk("hardware module: %ld byte\n", + bp->SharedMemSize); + goto fail; + } + bp->SharedMemHeap = 0; // Nothing used yet. + + } else { + bp->SharedMemAddr = NULL; + bp->SharedMemHeap = 0; + } // SharedMemSize > 0 + + memset(bp->SharedMemAddr, 0, bp->SharedMemSize); + + card_stop(smc); // Reset adapter. + + pr_debug("mac_drv_init()..\n"); + if (mac_drv_init(smc) != 0) { + pr_debug("mac_drv_init() failed\n"); + goto fail; + } + read_address(smc, NULL); + pr_debug("HW-Addr: %pMF\n", smc->hw.fddi_canon_addr.a); + memcpy(dev->dev_addr, smc->hw.fddi_canon_addr.a, 6); + + smt_reset_defaults(smc, 0); + + return 0; + +fail: + if (bp->SharedMemAddr) { + pci_free_consistent(&bp->pdev, + bp->SharedMemSize, + bp->SharedMemAddr, + bp->SharedMemDMA); + bp->SharedMemAddr = NULL; + } + if (bp->LocalRxBuffer) { + pci_free_consistent(&bp->pdev, MAX_FRAME_SIZE, + bp->LocalRxBuffer, bp->LocalRxBufferDMA); + bp->LocalRxBuffer = NULL; + } + return err; +} // skfp_driver_init + + +/* + * ============= + * = skfp_open = + * ============= + * + * Overview: + * Opens the adapter + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This function brings the adapter to an operational state. + * + * Return Codes: + * 0 - Adapter was successfully opened + * -EAGAIN - Could not register IRQ + */ +static int skfp_open(struct net_device *dev) +{ + struct s_smc *smc = netdev_priv(dev); + int err; + + pr_debug("entering skfp_open\n"); + /* Register IRQ - support shared interrupts by passing device ptr */ + err = request_irq(dev->irq, skfp_interrupt, IRQF_SHARED, + dev->name, dev); + if (err) + return err; + + /* + * Set current address to factory MAC address + * + * Note: We've already done this step in skfp_driver_init. + * However, it's possible that a user has set a node + * address override, then closed and reopened the + * adapter. Unless we reset the device address field + * now, we'll continue to use the existing modified + * address. + */ + read_address(smc, NULL); + memcpy(dev->dev_addr, smc->hw.fddi_canon_addr.a, 6); + + init_smt(smc, NULL); + smt_online(smc, 1); + STI_FBI(); + + /* Clear local multicast address tables */ + mac_clear_multicast(smc); + + /* Disable promiscuous filter settings */ + mac_drv_rx_mode(smc, RX_DISABLE_PROMISC); + + netif_start_queue(dev); + return 0; +} // skfp_open + + +/* + * ============== + * = skfp_close = + * ============== + * + * Overview: + * Closes the device/module. + * + * Returns: + * Condition code + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This routine closes the adapter and brings it to a safe state. + * The interrupt service routine is deregistered with the OS. + * The adapter can be opened again with another call to skfp_open(). + * + * Return Codes: + * Always return 0. + * + * Assumptions: + * No further requests for this adapter are made after this routine is + * called. skfp_open() can be called to reset and reinitialize the + * adapter. + */ +static int skfp_close(struct net_device *dev) +{ + struct s_smc *smc = netdev_priv(dev); + skfddi_priv *bp = &smc->os; + + CLI_FBI(); + smt_reset_defaults(smc, 1); + card_stop(smc); + mac_drv_clear_tx_queue(smc); + mac_drv_clear_rx_queue(smc); + + netif_stop_queue(dev); + /* Deregister (free) IRQ */ + free_irq(dev->irq, dev); + + skb_queue_purge(&bp->SendSkbQueue); + bp->QueueSkb = MAX_TX_QUEUE_LEN; + + return 0; +} // skfp_close + + +/* + * ================== + * = skfp_interrupt = + * ================== + * + * Overview: + * Interrupt processing routine + * + * Returns: + * None + * + * Arguments: + * irq - interrupt vector + * dev_id - pointer to device information + * + * Functional Description: + * This routine calls the interrupt processing routine for this adapter. It + * disables and reenables adapter interrupts, as appropriate. We can support + * shared interrupts since the incoming dev_id pointer provides our device + * structure context. All the real work is done in the hardware module. + * + * Return Codes: + * None + * + * Assumptions: + * The interrupt acknowledgement at the hardware level (eg. ACKing the PIC + * on Intel-based systems) is done by the operating system outside this + * routine. + * + * System interrupts are enabled through this call. + * + * Side Effects: + * Interrupts are disabled, then reenabled at the adapter. + */ + +static irqreturn_t skfp_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct s_smc *smc; /* private board structure pointer */ + skfddi_priv *bp; + + smc = netdev_priv(dev); + bp = &smc->os; + + // IRQs enabled or disabled ? + if (inpd(ADDR(B0_IMSK)) == 0) { + // IRQs are disabled: must be shared interrupt + return IRQ_NONE; + } + // Note: At this point, IRQs are enabled. + if ((inpd(ISR_A) & smc->hw.is_imask) == 0) { // IRQ? + // Adapter did not issue an IRQ: must be shared interrupt + return IRQ_NONE; + } + CLI_FBI(); // Disable IRQs from our adapter. + spin_lock(&bp->DriverLock); + + // Call interrupt handler in hardware module (HWM). + fddi_isr(smc); + + if (smc->os.ResetRequested) { + ResetAdapter(smc); + smc->os.ResetRequested = FALSE; + } + spin_unlock(&bp->DriverLock); + STI_FBI(); // Enable IRQs from our adapter. + + return IRQ_HANDLED; +} // skfp_interrupt + + +/* + * ====================== + * = skfp_ctl_get_stats = + * ====================== + * + * Overview: + * Get statistics for FDDI adapter + * + * Returns: + * Pointer to FDDI statistics structure + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * Gets current MIB objects from adapter, then + * returns FDDI statistics structure as defined + * in if_fddi.h. + * + * Note: Since the FDDI statistics structure is + * still new and the device structure doesn't + * have an FDDI-specific get statistics handler, + * we'll return the FDDI statistics structure as + * a pointer to an Ethernet statistics structure. + * That way, at least the first part of the statistics + * structure can be decoded properly. + * We'll have to pay attention to this routine as the + * device structure becomes more mature and LAN media + * independent. + * + */ +static struct net_device_stats *skfp_ctl_get_stats(struct net_device *dev) +{ + struct s_smc *bp = netdev_priv(dev); + + /* Fill the bp->stats structure with driver-maintained counters */ + + bp->os.MacStat.port_bs_flag[0] = 0x1234; + bp->os.MacStat.port_bs_flag[1] = 0x5678; +// goos: need to fill out fddi statistic +#if 0 + /* Get FDDI SMT MIB objects */ + +/* Fill the bp->stats structure with the SMT MIB object values */ + + memcpy(bp->stats.smt_station_id, &bp->cmd_rsp_virt->smt_mib_get.smt_station_id, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_station_id)); + bp->stats.smt_op_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_op_version_id; + bp->stats.smt_hi_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_hi_version_id; + bp->stats.smt_lo_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_lo_version_id; + memcpy(bp->stats.smt_user_data, &bp->cmd_rsp_virt->smt_mib_get.smt_user_data, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_user_data)); + bp->stats.smt_mib_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_mib_version_id; + bp->stats.smt_mac_cts = bp->cmd_rsp_virt->smt_mib_get.smt_mac_ct; + bp->stats.smt_non_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_non_master_ct; + bp->stats.smt_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_master_ct; + bp->stats.smt_available_paths = bp->cmd_rsp_virt->smt_mib_get.smt_available_paths; + bp->stats.smt_config_capabilities = bp->cmd_rsp_virt->smt_mib_get.smt_config_capabilities; + bp->stats.smt_config_policy = bp->cmd_rsp_virt->smt_mib_get.smt_config_policy; + bp->stats.smt_connection_policy = bp->cmd_rsp_virt->smt_mib_get.smt_connection_policy; + bp->stats.smt_t_notify = bp->cmd_rsp_virt->smt_mib_get.smt_t_notify; + bp->stats.smt_stat_rpt_policy = bp->cmd_rsp_virt->smt_mib_get.smt_stat_rpt_policy; + bp->stats.smt_trace_max_expiration = bp->cmd_rsp_virt->smt_mib_get.smt_trace_max_expiration; + bp->stats.smt_bypass_present = bp->cmd_rsp_virt->smt_mib_get.smt_bypass_present; + bp->stats.smt_ecm_state = bp->cmd_rsp_virt->smt_mib_get.smt_ecm_state; + bp->stats.smt_cf_state = bp->cmd_rsp_virt->smt_mib_get.smt_cf_state; + bp->stats.smt_remote_disconnect_flag = bp->cmd_rsp_virt->smt_mib_get.smt_remote_disconnect_flag; + bp->stats.smt_station_status = bp->cmd_rsp_virt->smt_mib_get.smt_station_status; + bp->stats.smt_peer_wrap_flag = bp->cmd_rsp_virt->smt_mib_get.smt_peer_wrap_flag; + bp->stats.smt_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_msg_time_stamp.ls; + bp->stats.smt_transition_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_transition_time_stamp.ls; + bp->stats.mac_frame_status_functions = bp->cmd_rsp_virt->smt_mib_get.mac_frame_status_functions; + bp->stats.mac_t_max_capability = bp->cmd_rsp_virt->smt_mib_get.mac_t_max_capability; + bp->stats.mac_tvx_capability = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_capability; + bp->stats.mac_available_paths = bp->cmd_rsp_virt->smt_mib_get.mac_available_paths; + bp->stats.mac_current_path = bp->cmd_rsp_virt->smt_mib_get.mac_current_path; + memcpy(bp->stats.mac_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_upstream_nbr, FDDI_K_ALEN); + memcpy(bp->stats.mac_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_downstream_nbr, FDDI_K_ALEN); + memcpy(bp->stats.mac_old_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_upstream_nbr, FDDI_K_ALEN); + memcpy(bp->stats.mac_old_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_downstream_nbr, FDDI_K_ALEN); + bp->stats.mac_dup_address_test = bp->cmd_rsp_virt->smt_mib_get.mac_dup_address_test; + bp->stats.mac_requested_paths = bp->cmd_rsp_virt->smt_mib_get.mac_requested_paths; + bp->stats.mac_downstream_port_type = bp->cmd_rsp_virt->smt_mib_get.mac_downstream_port_type; + memcpy(bp->stats.mac_smt_address, &bp->cmd_rsp_virt->smt_mib_get.mac_smt_address, FDDI_K_ALEN); + bp->stats.mac_t_req = bp->cmd_rsp_virt->smt_mib_get.mac_t_req; + bp->stats.mac_t_neg = bp->cmd_rsp_virt->smt_mib_get.mac_t_neg; + bp->stats.mac_t_max = bp->cmd_rsp_virt->smt_mib_get.mac_t_max; + bp->stats.mac_tvx_value = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_value; + bp->stats.mac_frame_error_threshold = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_threshold; + bp->stats.mac_frame_error_ratio = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_ratio; + bp->stats.mac_rmt_state = bp->cmd_rsp_virt->smt_mib_get.mac_rmt_state; + bp->stats.mac_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_da_flag; + bp->stats.mac_una_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_unda_flag; + bp->stats.mac_frame_error_flag = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_flag; + bp->stats.mac_ma_unitdata_available = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_available; + bp->stats.mac_hardware_present = bp->cmd_rsp_virt->smt_mib_get.mac_hardware_present; + bp->stats.mac_ma_unitdata_enable = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_enable; + bp->stats.path_tvx_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_tvx_lower_bound; + bp->stats.path_t_max_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_t_max_lower_bound; + bp->stats.path_max_t_req = bp->cmd_rsp_virt->smt_mib_get.path_max_t_req; + memcpy(bp->stats.path_configuration, &bp->cmd_rsp_virt->smt_mib_get.path_configuration, sizeof(bp->cmd_rsp_virt->smt_mib_get.path_configuration)); + bp->stats.port_my_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[0]; + bp->stats.port_my_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[1]; + bp->stats.port_neighbor_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[0]; + bp->stats.port_neighbor_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[1]; + bp->stats.port_connection_policies[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[0]; + bp->stats.port_connection_policies[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[1]; + bp->stats.port_mac_indicated[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[0]; + bp->stats.port_mac_indicated[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[1]; + bp->stats.port_current_path[0] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[0]; + bp->stats.port_current_path[1] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[1]; + memcpy(&bp->stats.port_requested_paths[0 * 3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[0], 3); + memcpy(&bp->stats.port_requested_paths[1 * 3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[1], 3); + bp->stats.port_mac_placement[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[0]; + bp->stats.port_mac_placement[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[1]; + bp->stats.port_available_paths[0] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[0]; + bp->stats.port_available_paths[1] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[1]; + bp->stats.port_pmd_class[0] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[0]; + bp->stats.port_pmd_class[1] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[1]; + bp->stats.port_connection_capabilities[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[0]; + bp->stats.port_connection_capabilities[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[1]; + bp->stats.port_bs_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[0]; + bp->stats.port_bs_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[1]; + bp->stats.port_ler_estimate[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[0]; + bp->stats.port_ler_estimate[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[1]; + bp->stats.port_ler_cutoff[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[0]; + bp->stats.port_ler_cutoff[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[1]; + bp->stats.port_ler_alarm[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[0]; + bp->stats.port_ler_alarm[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[1]; + bp->stats.port_connect_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[0]; + bp->stats.port_connect_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[1]; + bp->stats.port_pcm_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[0]; + bp->stats.port_pcm_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[1]; + bp->stats.port_pc_withhold[0] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[0]; + bp->stats.port_pc_withhold[1] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[1]; + bp->stats.port_ler_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[0]; + bp->stats.port_ler_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[1]; + bp->stats.port_hardware_present[0] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[0]; + bp->stats.port_hardware_present[1] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[1]; + + + /* Fill the bp->stats structure with the FDDI counter values */ + + bp->stats.mac_frame_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.frame_cnt.ls; + bp->stats.mac_copied_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.copied_cnt.ls; + bp->stats.mac_transmit_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.transmit_cnt.ls; + bp->stats.mac_error_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.error_cnt.ls; + bp->stats.mac_lost_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.lost_cnt.ls; + bp->stats.port_lct_fail_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[0].ls; + bp->stats.port_lct_fail_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[1].ls; + bp->stats.port_lem_reject_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[0].ls; + bp->stats.port_lem_reject_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[1].ls; + bp->stats.port_lem_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[0].ls; + bp->stats.port_lem_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[1].ls; + +#endif + return (struct net_device_stats *)&bp->os.MacStat; +} // ctl_get_stat + + +/* + * ============================== + * = skfp_ctl_set_multicast_list = + * ============================== + * + * Overview: + * Enable/Disable LLC frame promiscuous mode reception + * on the adapter and/or update multicast address table. + * + * Returns: + * None + * + * Arguments: + * dev - pointer to device information + * + * Functional Description: + * This function acquires the driver lock and only calls + * skfp_ctl_set_multicast_list_wo_lock then. + * This routine follows a fairly simple algorithm for setting the + * adapter filters and CAM: + * + * if IFF_PROMISC flag is set + * enable promiscuous mode + * else + * disable promiscuous mode + * if number of multicast addresses <= max. multicast number + * add mc addresses to adapter table + * else + * enable promiscuous mode + * update adapter filters + * + * Assumptions: + * Multicast addresses are presented in canonical (LSB) format. + * + * Side Effects: + * On-board adapter filters are updated. + */ +static void skfp_ctl_set_multicast_list(struct net_device *dev) +{ + struct s_smc *smc = netdev_priv(dev); + skfddi_priv *bp = &smc->os; + unsigned long Flags; + + spin_lock_irqsave(&bp->DriverLock, Flags); + skfp_ctl_set_multicast_list_wo_lock(dev); + spin_unlock_irqrestore(&bp->DriverLock, Flags); +} // skfp_ctl_set_multicast_list + + + +static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev) +{ + struct s_smc *smc = netdev_priv(dev); + struct netdev_hw_addr *ha; + + /* Enable promiscuous mode, if necessary */ + if (dev->flags & IFF_PROMISC) { + mac_drv_rx_mode(smc, RX_ENABLE_PROMISC); + pr_debug("PROMISCUOUS MODE ENABLED\n"); + } + /* Else, update multicast address table */ + else { + mac_drv_rx_mode(smc, RX_DISABLE_PROMISC); + pr_debug("PROMISCUOUS MODE DISABLED\n"); + + // Reset all MC addresses + mac_clear_multicast(smc); + mac_drv_rx_mode(smc, RX_DISABLE_ALLMULTI); + + if (dev->flags & IFF_ALLMULTI) { + mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI); + pr_debug("ENABLE ALL MC ADDRESSES\n"); + } else if (!netdev_mc_empty(dev)) { + if (netdev_mc_count(dev) <= FPMAX_MULTICAST) { + /* use exact filtering */ + + // point to first multicast addr + netdev_for_each_mc_addr(ha, dev) { + mac_add_multicast(smc, + (struct fddi_addr *)ha->addr, + 1); + + pr_debug("ENABLE MC ADDRESS: %pMF\n", + ha->addr); + } + + } else { // more MC addresses than HW supports + + mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI); + pr_debug("ENABLE ALL MC ADDRESSES\n"); + } + } else { // no MC addresses + + pr_debug("DISABLE ALL MC ADDRESSES\n"); + } + + /* Update adapter filters */ + mac_update_multicast(smc); + } +} // skfp_ctl_set_multicast_list_wo_lock + + +/* + * =========================== + * = skfp_ctl_set_mac_address = + * =========================== + * + * Overview: + * set new mac address on adapter and update dev_addr field in device table. + * + * Returns: + * None + * + * Arguments: + * dev - pointer to device information + * addr - pointer to sockaddr structure containing unicast address to set + * + * Assumptions: + * The address pointed to by addr->sa_data is a valid unicast + * address and is presented in canonical (LSB) format. + */ +static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr) +{ + struct s_smc *smc = netdev_priv(dev); + struct sockaddr *p_sockaddr = (struct sockaddr *) addr; + skfddi_priv *bp = &smc->os; + unsigned long Flags; + + + memcpy(dev->dev_addr, p_sockaddr->sa_data, FDDI_K_ALEN); + spin_lock_irqsave(&bp->DriverLock, Flags); + ResetAdapter(smc); + spin_unlock_irqrestore(&bp->DriverLock, Flags); + + return 0; /* always return zero */ +} // skfp_ctl_set_mac_address + + +/* + * ============== + * = skfp_ioctl = + * ============== + * + * Overview: + * + * Perform IOCTL call functions here. Some are privileged operations and the + * effective uid is checked in those cases. + * + * Returns: + * status value + * 0 - success + * other - failure + * + * Arguments: + * dev - pointer to device information + * rq - pointer to ioctl request structure + * cmd - ? + * + */ + + +static int skfp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct s_smc *smc = netdev_priv(dev); + skfddi_priv *lp = &smc->os; + struct s_skfp_ioctl ioc; + int status = 0; + + if (copy_from_user(&ioc, rq->ifr_data, sizeof(struct s_skfp_ioctl))) + return -EFAULT; + + switch (ioc.cmd) { + case SKFP_GET_STATS: /* Get the driver statistics */ + ioc.len = sizeof(lp->MacStat); + status = copy_to_user(ioc.data, skfp_ctl_get_stats(dev), ioc.len) + ? -EFAULT : 0; + break; + case SKFP_CLR_STATS: /* Zero out the driver statistics */ + if (!capable(CAP_NET_ADMIN)) { + status = -EPERM; + } else { + memset(&lp->MacStat, 0, sizeof(lp->MacStat)); + } + break; + default: + printk("ioctl for %s: unknown cmd: %04x\n", dev->name, ioc.cmd); + status = -EOPNOTSUPP; + + } // switch + + return status; +} // skfp_ioctl + + +/* + * ===================== + * = skfp_send_pkt = + * ===================== + * + * Overview: + * Queues a packet for transmission and try to transmit it. + * + * Returns: + * Condition code + * + * Arguments: + * skb - pointer to sk_buff to queue for transmission + * dev - pointer to device information + * + * Functional Description: + * Here we assume that an incoming skb transmit request + * is contained in a single physically contiguous buffer + * in which the virtual address of the start of packet + * (skb->data) can be converted to a physical address + * by using pci_map_single(). + * + * We have an internal queue for packets we can not send + * immediately. Packets in this queue can be given to the + * adapter if transmit buffers are freed. + * + * We can't free the skb until after it's been DMA'd + * out by the adapter, so we'll keep it in the driver and + * return it in mac_drv_tx_complete. + * + * Return Codes: + * 0 - driver has queued and/or sent packet + * 1 - caller should requeue the sk_buff for later transmission + * + * Assumptions: + * The entire packet is stored in one physically + * contiguous buffer which is not cached and whose + * 32-bit physical address can be determined. + * + * It's vital that this routine is NOT reentered for the + * same board and that the OS is not in another section of + * code (eg. skfp_interrupt) for the same board on a + * different thread. + * + * Side Effects: + * None + */ +static netdev_tx_t skfp_send_pkt(struct sk_buff *skb, + struct net_device *dev) +{ + struct s_smc *smc = netdev_priv(dev); + skfddi_priv *bp = &smc->os; + + pr_debug("skfp_send_pkt\n"); + + /* + * Verify that incoming transmit request is OK + * + * Note: The packet size check is consistent with other + * Linux device drivers, although the correct packet + * size should be verified before calling the + * transmit routine. + */ + + if (!(skb->len >= FDDI_K_LLC_ZLEN && skb->len <= FDDI_K_LLC_LEN)) { + bp->MacStat.gen.tx_errors++; /* bump error counter */ + // dequeue packets from xmt queue and send them + netif_start_queue(dev); + dev_kfree_skb(skb); + return NETDEV_TX_OK; /* return "success" */ + } + if (bp->QueueSkb == 0) { // return with tbusy set: queue full + + netif_stop_queue(dev); + return NETDEV_TX_BUSY; + } + bp->QueueSkb--; + skb_queue_tail(&bp->SendSkbQueue, skb); + send_queued_packets(netdev_priv(dev)); + if (bp->QueueSkb == 0) { + netif_stop_queue(dev); + } + return NETDEV_TX_OK; + +} // skfp_send_pkt + + +/* + * ======================= + * = send_queued_packets = + * ======================= + * + * Overview: + * Send packets from the driver queue as long as there are some and + * transmit resources are available. + * + * Returns: + * None + * + * Arguments: + * smc - pointer to smc (adapter) structure + * + * Functional Description: + * Take a packet from queue if there is any. If not, then we are done. + * Check if there are resources to send the packet. If not, requeue it + * and exit. + * Set packet descriptor flags and give packet to adapter. + * Check if any send resources can be freed (we do not use the + * transmit complete interrupt). + */ +static void send_queued_packets(struct s_smc *smc) +{ + skfddi_priv *bp = &smc->os; + struct sk_buff *skb; + unsigned char fc; + int queue; + struct s_smt_fp_txd *txd; // Current TxD. + dma_addr_t dma_address; + unsigned long Flags; + + int frame_status; // HWM tx frame status. + + pr_debug("send queued packets\n"); + for (;;) { + // send first buffer from queue + skb = skb_dequeue(&bp->SendSkbQueue); + + if (!skb) { + pr_debug("queue empty\n"); + return; + } // queue empty ! + + spin_lock_irqsave(&bp->DriverLock, Flags); + fc = skb->data[0]; + queue = (fc & FC_SYNC_BIT) ? QUEUE_S : QUEUE_A0; +#ifdef ESS + // Check if the frame may/must be sent as a synchronous frame. + + if ((fc & ~(FC_SYNC_BIT | FC_LLC_PRIOR)) == FC_ASYNC_LLC) { + // It's an LLC frame. + if (!smc->ess.sync_bw_available) + fc &= ~FC_SYNC_BIT; // No bandwidth available. + + else { // Bandwidth is available. + + if (smc->mib.fddiESSSynchTxMode) { + // Send as sync. frame. + fc |= FC_SYNC_BIT; + } + } + } +#endif // ESS + frame_status = hwm_tx_init(smc, fc, 1, skb->len, queue); + + if ((frame_status & (LOC_TX | LAN_TX)) == 0) { + // Unable to send the frame. + + if ((frame_status & RING_DOWN) != 0) { + // Ring is down. + pr_debug("Tx attempt while ring down.\n"); + } else if ((frame_status & OUT_OF_TXD) != 0) { + pr_debug("%s: out of TXDs.\n", bp->dev->name); + } else { + pr_debug("%s: out of transmit resources", + bp->dev->name); + } + + // Note: We will retry the operation as soon as + // transmit resources become available. + skb_queue_head(&bp->SendSkbQueue, skb); + spin_unlock_irqrestore(&bp->DriverLock, Flags); + return; // Packet has been queued. + + } // if (unable to send frame) + + bp->QueueSkb++; // one packet less in local queue + + // source address in packet ? + CheckSourceAddress(skb->data, smc->hw.fddi_canon_addr.a); + + txd = (struct s_smt_fp_txd *) HWM_GET_CURR_TXD(smc, queue); + + dma_address = pci_map_single(&bp->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); + if (frame_status & LAN_TX) { + txd->txd_os.skb = skb; // save skb + txd->txd_os.dma_addr = dma_address; // save dma mapping + } + hwm_tx_frag(smc, skb->data, dma_address, skb->len, + frame_status | FIRST_FRAG | LAST_FRAG | EN_IRQ_EOF); + + if (!(frame_status & LAN_TX)) { // local only frame + pci_unmap_single(&bp->pdev, dma_address, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + } + spin_unlock_irqrestore(&bp->DriverLock, Flags); + } // for + + return; // never reached + +} // send_queued_packets + + +/************************ + * + * CheckSourceAddress + * + * Verify if the source address is set. Insert it if necessary. + * + ************************/ +static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr) +{ + unsigned char SRBit; + + if ((((unsigned long) frame[1 + 6]) & ~0x01) != 0) // source routing bit + + return; + if ((unsigned short) frame[1 + 10] != 0) + return; + SRBit = frame[1 + 6] & 0x01; + memcpy(&frame[1 + 6], hw_addr, 6); + frame[8] |= SRBit; +} // CheckSourceAddress + + +/************************ + * + * ResetAdapter + * + * Reset the adapter and bring it back to operational mode. + * Args + * smc - A pointer to the SMT context struct. + * Out + * Nothing. + * + ************************/ +static void ResetAdapter(struct s_smc *smc) +{ + + pr_debug("[fddi: ResetAdapter]\n"); + + // Stop the adapter. + + card_stop(smc); // Stop all activity. + + // Clear the transmit and receive descriptor queues. + mac_drv_clear_tx_queue(smc); + mac_drv_clear_rx_queue(smc); + + // Restart the adapter. + + smt_reset_defaults(smc, 1); // Initialize the SMT module. + + init_smt(smc, (smc->os.dev)->dev_addr); // Initialize the hardware. + + smt_online(smc, 1); // Insert into the ring again. + STI_FBI(); + + // Restore original receive mode (multicasts, promiscuous, etc.). + skfp_ctl_set_multicast_list_wo_lock(smc->os.dev); +} // ResetAdapter + + +//--------------- functions called by hardware module ---------------- + +/************************ + * + * llc_restart_tx + * + * The hardware driver calls this routine when the transmit complete + * interrupt bits (end of frame) for the synchronous or asynchronous + * queue is set. + * + * NOTE The hardware driver calls this function also if no packets are queued. + * The routine must be able to handle this case. + * Args + * smc - A pointer to the SMT context struct. + * Out + * Nothing. + * + ************************/ +void llc_restart_tx(struct s_smc *smc) +{ + skfddi_priv *bp = &smc->os; + + pr_debug("[llc_restart_tx]\n"); + + // Try to send queued packets + spin_unlock(&bp->DriverLock); + send_queued_packets(smc); + spin_lock(&bp->DriverLock); + netif_start_queue(bp->dev);// system may send again if it was blocked + +} // llc_restart_tx + + +/************************ + * + * mac_drv_get_space + * + * The hardware module calls this function to allocate the memory + * for the SMT MBufs if the define MB_OUTSIDE_SMC is specified. + * Args + * smc - A pointer to the SMT context struct. + * + * size - Size of memory in bytes to allocate. + * Out + * != 0 A pointer to the virtual address of the allocated memory. + * == 0 Allocation error. + * + ************************/ +void *mac_drv_get_space(struct s_smc *smc, unsigned int size) +{ + void *virt; + + pr_debug("mac_drv_get_space (%d bytes), ", size); + virt = (void *) (smc->os.SharedMemAddr + smc->os.SharedMemHeap); + + if ((smc->os.SharedMemHeap + size) > smc->os.SharedMemSize) { + printk("Unexpected SMT memory size requested: %d\n", size); + return NULL; + } + smc->os.SharedMemHeap += size; // Move heap pointer. + + pr_debug("mac_drv_get_space end\n"); + pr_debug("virt addr: %lx\n", (ulong) virt); + pr_debug("bus addr: %lx\n", (ulong) + (smc->os.SharedMemDMA + + ((char *) virt - (char *)smc->os.SharedMemAddr))); + return virt; +} // mac_drv_get_space + + +/************************ + * + * mac_drv_get_desc_mem + * + * This function is called by the hardware dependent module. + * It allocates the memory for the RxD and TxD descriptors. + * + * This memory must be non-cached, non-movable and non-swappable. + * This memory should start at a physical page boundary. + * Args + * smc - A pointer to the SMT context struct. + * + * size - Size of memory in bytes to allocate. + * Out + * != 0 A pointer to the virtual address of the allocated memory. + * == 0 Allocation error. + * + ************************/ +void *mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size) +{ + + char *virt; + + pr_debug("mac_drv_get_desc_mem\n"); + + // Descriptor memory must be aligned on 16-byte boundary. + + virt = mac_drv_get_space(smc, size); + + size = (u_int) (16 - (((unsigned long) virt) & 15UL)); + size = size % 16; + + pr_debug("Allocate %u bytes alignment gap ", size); + pr_debug("for descriptor memory.\n"); + + if (!mac_drv_get_space(smc, size)) { + printk("fddi: Unable to align descriptor memory.\n"); + return NULL; + } + return virt + size; +} // mac_drv_get_desc_mem + + +/************************ + * + * mac_drv_virt2phys + * + * Get the physical address of a given virtual address. + * Args + * smc - A pointer to the SMT context struct. + * + * virt - A (virtual) pointer into our 'shared' memory area. + * Out + * Physical address of the given virtual address. + * + ************************/ +unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt) +{ + return smc->os.SharedMemDMA + + ((char *) virt - (char *)smc->os.SharedMemAddr); +} // mac_drv_virt2phys + + +/************************ + * + * dma_master + * + * The HWM calls this function, when the driver leads through a DMA + * transfer. If the OS-specific module must prepare the system hardware + * for the DMA transfer, it should do it in this function. + * + * The hardware module calls this dma_master if it wants to send an SMT + * frame. This means that the virt address passed in here is part of + * the 'shared' memory area. + * Args + * smc - A pointer to the SMT context struct. + * + * virt - The virtual address of the data. + * + * len - The length in bytes of the data. + * + * flag - Indicates the transmit direction and the buffer type: + * DMA_RD (0x01) system RAM ==> adapter buffer memory + * DMA_WR (0x02) adapter buffer memory ==> system RAM + * SMT_BUF (0x80) SMT buffer + * + * >> NOTE: SMT_BUF and DMA_RD are always set for PCI. << + * Out + * Returns the pyhsical address for the DMA transfer. + * + ************************/ +u_long dma_master(struct s_smc * smc, void *virt, int len, int flag) +{ + return smc->os.SharedMemDMA + + ((char *) virt - (char *)smc->os.SharedMemAddr); +} // dma_master + + +/************************ + * + * dma_complete + * + * The hardware module calls this routine when it has completed a DMA + * transfer. If the operating system dependent module has set up the DMA + * channel via dma_master() (e.g. Windows NT or AIX) it should clean up + * the DMA channel. + * Args + * smc - A pointer to the SMT context struct. + * + * descr - A pointer to a TxD or RxD, respectively. + * + * flag - Indicates the DMA transfer direction / SMT buffer: + * DMA_RD (0x01) system RAM ==> adapter buffer memory + * DMA_WR (0x02) adapter buffer memory ==> system RAM + * SMT_BUF (0x80) SMT buffer (managed by HWM) + * Out + * Nothing. + * + ************************/ +void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr, int flag) +{ + /* For TX buffers, there are two cases. If it is an SMT transmit + * buffer, there is nothing to do since we use consistent memory + * for the 'shared' memory area. The other case is for normal + * transmit packets given to us by the networking stack, and in + * that case we cleanup the PCI DMA mapping in mac_drv_tx_complete + * below. + * + * For RX buffers, we have to unmap dynamic PCI DMA mappings here + * because the hardware module is about to potentially look at + * the contents of the buffer. If we did not call the PCI DMA + * unmap first, the hardware module could read inconsistent data. + */ + if (flag & DMA_WR) { + skfddi_priv *bp = &smc->os; + volatile struct s_smt_fp_rxd *r = &descr->r; + + /* If SKB is NULL, we used the local buffer. */ + if (r->rxd_os.skb && r->rxd_os.dma_addr) { + int MaxFrameSize = bp->MaxFrameSize; + + pci_unmap_single(&bp->pdev, r->rxd_os.dma_addr, + MaxFrameSize, PCI_DMA_FROMDEVICE); + r->rxd_os.dma_addr = 0; + } + } +} // dma_complete + + +/************************ + * + * mac_drv_tx_complete + * + * Transmit of a packet is complete. Release the tx staging buffer. + * + * Args + * smc - A pointer to the SMT context struct. + * + * txd - A pointer to the last TxD which is used by the frame. + * Out + * Returns nothing. + * + ************************/ +void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd) +{ + struct sk_buff *skb; + + pr_debug("entering mac_drv_tx_complete\n"); + // Check if this TxD points to a skb + + if (!(skb = txd->txd_os.skb)) { + pr_debug("TXD with no skb assigned.\n"); + return; + } + txd->txd_os.skb = NULL; + + // release the DMA mapping + pci_unmap_single(&smc->os.pdev, txd->txd_os.dma_addr, + skb->len, PCI_DMA_TODEVICE); + txd->txd_os.dma_addr = 0; + + smc->os.MacStat.gen.tx_packets++; // Count transmitted packets. + smc->os.MacStat.gen.tx_bytes+=skb->len; // Count bytes + + // free the skb + dev_kfree_skb_irq(skb); + + pr_debug("leaving mac_drv_tx_complete\n"); +} // mac_drv_tx_complete + + +/************************ + * + * dump packets to logfile + * + ************************/ +#ifdef DUMPPACKETS +void dump_data(unsigned char *Data, int length) +{ + int i, j; + unsigned char s[255], sh[10]; + if (length > 64) { + length = 64; + } + printk(KERN_INFO "---Packet start---\n"); + for (i = 0, j = 0; i < length / 8; i++, j += 8) + printk(KERN_INFO "%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]); + strcpy(s, ""); + for (i = 0; i < length % 8; i++) { + sprintf(sh, "%02x ", Data[j + i]); + strcat(s, sh); + } + printk(KERN_INFO "%s\n", s); + printk(KERN_INFO "------------------\n"); +} // dump_data +#else +#define dump_data(data,len) +#endif // DUMPPACKETS + +/************************ + * + * mac_drv_rx_complete + * + * The hardware module calls this function if an LLC frame is received + * in a receive buffer. Also the SMT, NSA, and directed beacon frames + * from the network will be passed to the LLC layer by this function + * if passing is enabled. + * + * mac_drv_rx_complete forwards the frame to the LLC layer if it should + * be received. It also fills the RxD ring with new receive buffers if + * some can be queued. + * Args + * smc - A pointer to the SMT context struct. + * + * rxd - A pointer to the first RxD which is used by the receive frame. + * + * frag_count - Count of RxDs used by the received frame. + * + * len - Frame length. + * Out + * Nothing. + * + ************************/ +void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, + int frag_count, int len) +{ + skfddi_priv *bp = &smc->os; + struct sk_buff *skb; + unsigned char *virt, *cp; + unsigned short ri; + u_int RifLength; + + pr_debug("entering mac_drv_rx_complete (len=%d)\n", len); + if (frag_count != 1) { // This is not allowed to happen. + + printk("fddi: Multi-fragment receive!\n"); + goto RequeueRxd; // Re-use the given RXD(s). + + } + skb = rxd->rxd_os.skb; + if (!skb) { + pr_debug("No skb in rxd\n"); + smc->os.MacStat.gen.rx_errors++; + goto RequeueRxd; + } + virt = skb->data; + + // The DMA mapping was released in dma_complete above. + + dump_data(skb->data, len); + + /* + * FDDI Frame format: + * +-------+-------+-------+------------+--------+------------+ + * | FC[1] | DA[6] | SA[6] | RIF[0..18] | LLC[3] | Data[0..n] | + * +-------+-------+-------+------------+--------+------------+ + * + * FC = Frame Control + * DA = Destination Address + * SA = Source Address + * RIF = Routing Information Field + * LLC = Logical Link Control + */ + + // Remove Routing Information Field (RIF), if present. + + if ((virt[1 + 6] & FDDI_RII) == 0) + RifLength = 0; + else { + int n; +// goos: RIF removal has still to be tested + pr_debug("RIF found\n"); + // Get RIF length from Routing Control (RC) field. + cp = virt + FDDI_MAC_HDR_LEN; // Point behind MAC header. + + ri = ntohs(*((__be16 *) cp)); + RifLength = ri & FDDI_RCF_LEN_MASK; + if (len < (int) (FDDI_MAC_HDR_LEN + RifLength)) { + printk("fddi: Invalid RIF.\n"); + goto RequeueRxd; // Discard the frame. + + } + virt[1 + 6] &= ~FDDI_RII; // Clear RII bit. + // regions overlap + + virt = cp + RifLength; + for (n = FDDI_MAC_HDR_LEN; n; n--) + *--virt = *--cp; + // adjust sbd->data pointer + skb_pull(skb, RifLength); + len -= RifLength; + RifLength = 0; + } + + // Count statistics. + smc->os.MacStat.gen.rx_packets++; // Count indicated receive + // packets. + smc->os.MacStat.gen.rx_bytes+=len; // Count bytes. + + // virt points to header again + if (virt[1] & 0x01) { // Check group (multicast) bit. + + smc->os.MacStat.gen.multicast++; + } + + // deliver frame to system + rxd->rxd_os.skb = NULL; + skb_trim(skb, len); + skb->protocol = fddi_type_trans(skb, bp->dev); + + netif_rx(skb); + + HWM_RX_CHECK(smc, RX_LOW_WATERMARK); + return; + + RequeueRxd: + pr_debug("Rx: re-queue RXD.\n"); + mac_drv_requeue_rxd(smc, rxd, frag_count); + smc->os.MacStat.gen.rx_errors++; // Count receive packets + // not indicated. + +} // mac_drv_rx_complete + + +/************************ + * + * mac_drv_requeue_rxd + * + * The hardware module calls this function to request the OS-specific + * module to queue the receive buffer(s) represented by the pointer + * to the RxD and the frag_count into the receive queue again. This + * buffer was filled with an invalid frame or an SMT frame. + * Args + * smc - A pointer to the SMT context struct. + * + * rxd - A pointer to the first RxD which is used by the receive frame. + * + * frag_count - Count of RxDs used by the received frame. + * Out + * Nothing. + * + ************************/ +void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, + int frag_count) +{ + volatile struct s_smt_fp_rxd *next_rxd; + volatile struct s_smt_fp_rxd *src_rxd; + struct sk_buff *skb; + int MaxFrameSize; + unsigned char *v_addr; + dma_addr_t b_addr; + + if (frag_count != 1) // This is not allowed to happen. + + printk("fddi: Multi-fragment requeue!\n"); + + MaxFrameSize = smc->os.MaxFrameSize; + src_rxd = rxd; + for (; frag_count > 0; frag_count--) { + next_rxd = src_rxd->rxd_next; + rxd = HWM_GET_CURR_RXD(smc); + + skb = src_rxd->rxd_os.skb; + if (skb == NULL) { // this should not happen + + pr_debug("Requeue with no skb in rxd!\n"); + skb = alloc_skb(MaxFrameSize + 3, GFP_ATOMIC); + if (skb) { + // we got a skb + rxd->rxd_os.skb = skb; + skb_reserve(skb, 3); + skb_put(skb, MaxFrameSize); + v_addr = skb->data; + b_addr = pci_map_single(&smc->os.pdev, + v_addr, + MaxFrameSize, + PCI_DMA_FROMDEVICE); + rxd->rxd_os.dma_addr = b_addr; + } else { + // no skb available, use local buffer + pr_debug("Queueing invalid buffer!\n"); + rxd->rxd_os.skb = NULL; + v_addr = smc->os.LocalRxBuffer; + b_addr = smc->os.LocalRxBufferDMA; + } + } else { + // we use skb from old rxd + rxd->rxd_os.skb = skb; + v_addr = skb->data; + b_addr = pci_map_single(&smc->os.pdev, + v_addr, + MaxFrameSize, + PCI_DMA_FROMDEVICE); + rxd->rxd_os.dma_addr = b_addr; + } + hwm_rx_frag(smc, v_addr, b_addr, MaxFrameSize, + FIRST_FRAG | LAST_FRAG); + + src_rxd = next_rxd; + } +} // mac_drv_requeue_rxd + + +/************************ + * + * mac_drv_fill_rxd + * + * The hardware module calls this function at initialization time + * to fill the RxD ring with receive buffers. It is also called by + * mac_drv_rx_complete if rx_free is large enough to queue some new + * receive buffers into the RxD ring. mac_drv_fill_rxd queues new + * receive buffers as long as enough RxDs and receive buffers are + * available. + * Args + * smc - A pointer to the SMT context struct. + * Out + * Nothing. + * + ************************/ +void mac_drv_fill_rxd(struct s_smc *smc) +{ + int MaxFrameSize; + unsigned char *v_addr; + unsigned long b_addr; + struct sk_buff *skb; + volatile struct s_smt_fp_rxd *rxd; + + pr_debug("entering mac_drv_fill_rxd\n"); + + // Walk through the list of free receive buffers, passing receive + // buffers to the HWM as long as RXDs are available. + + MaxFrameSize = smc->os.MaxFrameSize; + // Check if there is any RXD left. + while (HWM_GET_RX_FREE(smc) > 0) { + pr_debug(".\n"); + + rxd = HWM_GET_CURR_RXD(smc); + skb = alloc_skb(MaxFrameSize + 3, GFP_ATOMIC); + if (skb) { + // we got a skb + skb_reserve(skb, 3); + skb_put(skb, MaxFrameSize); + v_addr = skb->data; + b_addr = pci_map_single(&smc->os.pdev, + v_addr, + MaxFrameSize, + PCI_DMA_FROMDEVICE); + rxd->rxd_os.dma_addr = b_addr; + } else { + // no skb available, use local buffer + // System has run out of buffer memory, but we want to + // keep the receiver running in hope of better times. + // Multiple descriptors may point to this local buffer, + // so data in it must be considered invalid. + pr_debug("Queueing invalid buffer!\n"); + v_addr = smc->os.LocalRxBuffer; + b_addr = smc->os.LocalRxBufferDMA; + } + + rxd->rxd_os.skb = skb; + + // Pass receive buffer to HWM. + hwm_rx_frag(smc, v_addr, b_addr, MaxFrameSize, + FIRST_FRAG | LAST_FRAG); + } + pr_debug("leaving mac_drv_fill_rxd\n"); +} // mac_drv_fill_rxd + + +/************************ + * + * mac_drv_clear_rxd + * + * The hardware module calls this function to release unused + * receive buffers. + * Args + * smc - A pointer to the SMT context struct. + * + * rxd - A pointer to the first RxD which is used by the receive buffer. + * + * frag_count - Count of RxDs used by the receive buffer. + * Out + * Nothing. + * + ************************/ +void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, + int frag_count) +{ + + struct sk_buff *skb; + + pr_debug("entering mac_drv_clear_rxd\n"); + + if (frag_count != 1) // This is not allowed to happen. + + printk("fddi: Multi-fragment clear!\n"); + + for (; frag_count > 0; frag_count--) { + skb = rxd->rxd_os.skb; + if (skb != NULL) { + skfddi_priv *bp = &smc->os; + int MaxFrameSize = bp->MaxFrameSize; + + pci_unmap_single(&bp->pdev, rxd->rxd_os.dma_addr, + MaxFrameSize, PCI_DMA_FROMDEVICE); + + dev_kfree_skb(skb); + rxd->rxd_os.skb = NULL; + } + rxd = rxd->rxd_next; // Next RXD. + + } +} // mac_drv_clear_rxd + + +/************************ + * + * mac_drv_rx_init + * + * The hardware module calls this routine when an SMT or NSA frame of the + * local SMT should be delivered to the LLC layer. + * + * It is necessary to have this function, because there is no other way to + * copy the contents of SMT MBufs into receive buffers. + * + * mac_drv_rx_init allocates the required target memory for this frame, + * and receives the frame fragment by fragment by calling mac_drv_rx_frag. + * Args + * smc - A pointer to the SMT context struct. + * + * len - The length (in bytes) of the received frame (FC, DA, SA, Data). + * + * fc - The Frame Control field of the received frame. + * + * look_ahead - A pointer to the lookahead data buffer (may be NULL). + * + * la_len - The length of the lookahead data stored in the lookahead + * buffer (may be zero). + * Out + * Always returns zero (0). + * + ************************/ +int mac_drv_rx_init(struct s_smc *smc, int len, int fc, + char *look_ahead, int la_len) +{ + struct sk_buff *skb; + + pr_debug("entering mac_drv_rx_init(len=%d)\n", len); + + // "Received" a SMT or NSA frame of the local SMT. + + if (len != la_len || len < FDDI_MAC_HDR_LEN || !look_ahead) { + pr_debug("fddi: Discard invalid local SMT frame\n"); + pr_debug(" len=%d, la_len=%d, (ULONG) look_ahead=%08lXh.\n", + len, la_len, (unsigned long) look_ahead); + return 0; + } + skb = alloc_skb(len + 3, GFP_ATOMIC); + if (!skb) { + pr_debug("fddi: Local SMT: skb memory exhausted.\n"); + return 0; + } + skb_reserve(skb, 3); + skb_put(skb, len); + skb_copy_to_linear_data(skb, look_ahead, len); + + // deliver frame to system + skb->protocol = fddi_type_trans(skb, smc->os.dev); + netif_rx(skb); + + return 0; +} // mac_drv_rx_init + + +/************************ + * + * smt_timer_poll + * + * This routine is called periodically by the SMT module to clean up the + * driver. + * + * Return any queued frames back to the upper protocol layers if the ring + * is down. + * Args + * smc - A pointer to the SMT context struct. + * Out + * Nothing. + * + ************************/ +void smt_timer_poll(struct s_smc *smc) +{ +} // smt_timer_poll + + +/************************ + * + * ring_status_indication + * + * This function indicates a change of the ring state. + * Args + * smc - A pointer to the SMT context struct. + * + * status - The current ring status. + * Out + * Nothing. + * + ************************/ +void ring_status_indication(struct s_smc *smc, u_long status) +{ + pr_debug("ring_status_indication( "); + if (status & RS_RES15) + pr_debug("RS_RES15 "); + if (status & RS_HARDERROR) + pr_debug("RS_HARDERROR "); + if (status & RS_SOFTERROR) + pr_debug("RS_SOFTERROR "); + if (status & RS_BEACON) + pr_debug("RS_BEACON "); + if (status & RS_PATHTEST) + pr_debug("RS_PATHTEST "); + if (status & RS_SELFTEST) + pr_debug("RS_SELFTEST "); + if (status & RS_RES9) + pr_debug("RS_RES9 "); + if (status & RS_DISCONNECT) + pr_debug("RS_DISCONNECT "); + if (status & RS_RES7) + pr_debug("RS_RES7 "); + if (status & RS_DUPADDR) + pr_debug("RS_DUPADDR "); + if (status & RS_NORINGOP) + pr_debug("RS_NORINGOP "); + if (status & RS_VERSION) + pr_debug("RS_VERSION "); + if (status & RS_STUCKBYPASSS) + pr_debug("RS_STUCKBYPASSS "); + if (status & RS_EVENT) + pr_debug("RS_EVENT "); + if (status & RS_RINGOPCHANGE) + pr_debug("RS_RINGOPCHANGE "); + if (status & RS_RES0) + pr_debug("RS_RES0 "); + pr_debug("]\n"); +} // ring_status_indication + + +/************************ + * + * smt_get_time + * + * Gets the current time from the system. + * Args + * None. + * Out + * The current time in TICKS_PER_SECOND. + * + * TICKS_PER_SECOND has the unit 'count of timer ticks per second'. It is + * defined in "targetos.h". The definition of TICKS_PER_SECOND must comply + * to the time returned by smt_get_time(). + * + ************************/ +unsigned long smt_get_time(void) +{ + return jiffies; +} // smt_get_time + + +/************************ + * + * smt_stat_counter + * + * Status counter update (ring_op, fifo full). + * Args + * smc - A pointer to the SMT context struct. + * + * stat - = 0: A ring operational change occurred. + * = 1: The FORMAC FIFO buffer is full / FIFO overflow. + * Out + * Nothing. + * + ************************/ +void smt_stat_counter(struct s_smc *smc, int stat) +{ +// BOOLEAN RingIsUp ; + + pr_debug("smt_stat_counter\n"); + switch (stat) { + case 0: + pr_debug("Ring operational change.\n"); + break; + case 1: + pr_debug("Receive fifo overflow.\n"); + smc->os.MacStat.gen.rx_errors++; + break; + default: + pr_debug("Unknown status (%d).\n", stat); + break; + } +} // smt_stat_counter + + +/************************ + * + * cfm_state_change + * + * Sets CFM state in custom statistics. + * Args + * smc - A pointer to the SMT context struct. + * + * c_state - Possible values are: + * + * EC0_OUT, EC1_IN, EC2_TRACE, EC3_LEAVE, EC4_PATH_TEST, + * EC5_INSERT, EC6_CHECK, EC7_DEINSERT + * Out + * Nothing. + * + ************************/ +void cfm_state_change(struct s_smc *smc, int c_state) +{ +#ifdef DRIVERDEBUG + char *s; + + switch (c_state) { + case SC0_ISOLATED: + s = "SC0_ISOLATED"; + break; + case SC1_WRAP_A: + s = "SC1_WRAP_A"; + break; + case SC2_WRAP_B: + s = "SC2_WRAP_B"; + break; + case SC4_THRU_A: + s = "SC4_THRU_A"; + break; + case SC5_THRU_B: + s = "SC5_THRU_B"; + break; + case SC7_WRAP_S: + s = "SC7_WRAP_S"; + break; + case SC9_C_WRAP_A: + s = "SC9_C_WRAP_A"; + break; + case SC10_C_WRAP_B: + s = "SC10_C_WRAP_B"; + break; + case SC11_C_WRAP_S: + s = "SC11_C_WRAP_S"; + break; + default: + pr_debug("cfm_state_change: unknown %d\n", c_state); + return; + } + pr_debug("cfm_state_change: %s\n", s); +#endif // DRIVERDEBUG +} // cfm_state_change + + +/************************ + * + * ecm_state_change + * + * Sets ECM state in custom statistics. + * Args + * smc - A pointer to the SMT context struct. + * + * e_state - Possible values are: + * + * SC0_ISOLATED, SC1_WRAP_A (5), SC2_WRAP_B (6), SC4_THRU_A (12), + * SC5_THRU_B (7), SC7_WRAP_S (8) + * Out + * Nothing. + * + ************************/ +void ecm_state_change(struct s_smc *smc, int e_state) +{ +#ifdef DRIVERDEBUG + char *s; + + switch (e_state) { + case EC0_OUT: + s = "EC0_OUT"; + break; + case EC1_IN: + s = "EC1_IN"; + break; + case EC2_TRACE: + s = "EC2_TRACE"; + break; + case EC3_LEAVE: + s = "EC3_LEAVE"; + break; + case EC4_PATH_TEST: + s = "EC4_PATH_TEST"; + break; + case EC5_INSERT: + s = "EC5_INSERT"; + break; + case EC6_CHECK: + s = "EC6_CHECK"; + break; + case EC7_DEINSERT: + s = "EC7_DEINSERT"; + break; + default: + s = "unknown"; + break; + } + pr_debug("ecm_state_change: %s\n", s); +#endif //DRIVERDEBUG +} // ecm_state_change + + +/************************ + * + * rmt_state_change + * + * Sets RMT state in custom statistics. + * Args + * smc - A pointer to the SMT context struct. + * + * r_state - Possible values are: + * + * RM0_ISOLATED, RM1_NON_OP, RM2_RING_OP, RM3_DETECT, + * RM4_NON_OP_DUP, RM5_RING_OP_DUP, RM6_DIRECTED, RM7_TRACE + * Out + * Nothing. + * + ************************/ +void rmt_state_change(struct s_smc *smc, int r_state) +{ +#ifdef DRIVERDEBUG + char *s; + + switch (r_state) { + case RM0_ISOLATED: + s = "RM0_ISOLATED"; + break; + case RM1_NON_OP: + s = "RM1_NON_OP - not operational"; + break; + case RM2_RING_OP: + s = "RM2_RING_OP - ring operational"; + break; + case RM3_DETECT: + s = "RM3_DETECT - detect dupl addresses"; + break; + case RM4_NON_OP_DUP: + s = "RM4_NON_OP_DUP - dupl. addr detected"; + break; + case RM5_RING_OP_DUP: + s = "RM5_RING_OP_DUP - ring oper. with dupl. addr"; + break; + case RM6_DIRECTED: + s = "RM6_DIRECTED - sending directed beacons"; + break; + case RM7_TRACE: + s = "RM7_TRACE - trace initiated"; + break; + default: + s = "unknown"; + break; + } + pr_debug("[rmt_state_change: %s]\n", s); +#endif // DRIVERDEBUG +} // rmt_state_change + + +/************************ + * + * drv_reset_indication + * + * This function is called by the SMT when it has detected a severe + * hardware problem. The driver should perform a reset on the adapter + * as soon as possible, but not from within this function. + * Args + * smc - A pointer to the SMT context struct. + * Out + * Nothing. + * + ************************/ +void drv_reset_indication(struct s_smc *smc) +{ + pr_debug("entering drv_reset_indication\n"); + + smc->os.ResetRequested = TRUE; // Set flag. + +} // drv_reset_indication + +static struct pci_driver skfddi_pci_driver = { + .name = "skfddi", + .id_table = skfddi_pci_tbl, + .probe = skfp_init_one, + .remove = __devexit_p(skfp_remove_one), +}; + +static int __init skfd_init(void) +{ + return pci_register_driver(&skfddi_pci_driver); +} + +static void __exit skfd_exit(void) +{ + pci_unregister_driver(&skfddi_pci_driver); +} + +module_init(skfd_init); +module_exit(skfd_exit); diff --git a/drivers/net/fddi/skfp/smt.c b/drivers/net/fddi/skfp/smt.c new file mode 100644 index 0000000..08d9432 --- /dev/null +++ b/drivers/net/fddi/skfp/smt.c @@ -0,0 +1,2046 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/smt_p.h" +#include +#include + +#define KERNEL +#include "h/smtstate.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)smt.c 2.43 98/11/23 (C) SK " ; +#endif + +/* + * FC in SMbuf + */ +#define m_fc(mb) ((mb)->sm_data[0]) + +#define SMT_TID_MAGIC 0x1f0a7b3c + +#ifdef DEBUG +static const char *const smt_type_name[] = { + "SMT_00??", "SMT_INFO", "SMT_02??", "SMT_03??", + "SMT_04??", "SMT_05??", "SMT_06??", "SMT_07??", + "SMT_08??", "SMT_09??", "SMT_0A??", "SMT_0B??", + "SMT_0C??", "SMT_0D??", "SMT_0E??", "SMT_NSA" +} ; + +static const char *const smt_class_name[] = { + "UNKNOWN","NIF","SIF_CONFIG","SIF_OPER","ECF","RAF","RDF", + "SRF","PMF_GET","PMF_SET","ESF" +} ; +#endif +#define LAST_CLASS (SMT_PMF_SET) + +static const struct fddi_addr SMT_Unknown = { + { 0,0,0x1f,0,0,0 } +} ; + +/* + * function prototypes + */ +#ifdef LITTLE_ENDIAN +static int smt_swap_short(u_short s); +#endif +static int mac_index(struct s_smc *smc, int mac); +static int phy_index(struct s_smc *smc, int phy); +static int mac_con_resource_index(struct s_smc *smc, int mac); +static int phy_con_resource_index(struct s_smc *smc, int phy); +static void smt_send_rdf(struct s_smc *smc, SMbuf *rej, int fc, int reason, + int local); +static void smt_send_nif(struct s_smc *smc, const struct fddi_addr *dest, + int fc, u_long tid, int type, int local); +static void smt_send_ecf(struct s_smc *smc, struct fddi_addr *dest, int fc, + u_long tid, int type, int len); +static void smt_echo_test(struct s_smc *smc, int dna); +static void smt_send_sif_config(struct s_smc *smc, struct fddi_addr *dest, + u_long tid, int local); +static void smt_send_sif_operation(struct s_smc *smc, struct fddi_addr *dest, + u_long tid, int local); +#ifdef LITTLE_ENDIAN +static void smt_string_swap(char *data, const char *format, int len); +#endif +static void smt_add_frame_len(SMbuf *mb, int len); +static void smt_fill_una(struct s_smc *smc, struct smt_p_una *una); +static void smt_fill_sde(struct s_smc *smc, struct smt_p_sde *sde); +static void smt_fill_state(struct s_smc *smc, struct smt_p_state *state); +static void smt_fill_timestamp(struct s_smc *smc, struct smt_p_timestamp *ts); +static void smt_fill_policy(struct s_smc *smc, struct smt_p_policy *policy); +static void smt_fill_latency(struct s_smc *smc, struct smt_p_latency *latency); +static void smt_fill_neighbor(struct s_smc *smc, struct smt_p_neighbor *neighbor); +static int smt_fill_path(struct s_smc *smc, struct smt_p_path *path); +static void smt_fill_mac_status(struct s_smc *smc, struct smt_p_mac_status *st); +static void smt_fill_lem(struct s_smc *smc, struct smt_p_lem *lem, int phy); +static void smt_fill_version(struct s_smc *smc, struct smt_p_version *vers); +static void smt_fill_fsc(struct s_smc *smc, struct smt_p_fsc *fsc); +static void smt_fill_mac_counter(struct s_smc *smc, struct smt_p_mac_counter *mc); +static void smt_fill_mac_fnc(struct s_smc *smc, struct smt_p_mac_fnc *fnc); +static void smt_fill_manufacturer(struct s_smc *smc, + struct smp_p_manufacturer *man); +static void smt_fill_user(struct s_smc *smc, struct smp_p_user *user); +static void smt_fill_setcount(struct s_smc *smc, struct smt_p_setcount *setcount); +static void smt_fill_echo(struct s_smc *smc, struct smt_p_echo *echo, u_long seed, + int len); + +static void smt_clear_una_dna(struct s_smc *smc); +static void smt_clear_old_una_dna(struct s_smc *smc); +#ifdef CONCENTRATOR +static int entity_to_index(void); +#endif +static void update_dac(struct s_smc *smc, int report); +static int div_ratio(u_long upper, u_long lower); +#ifdef USE_CAN_ADDR +static void hwm_conv_can(struct s_smc *smc, char *data, int len); +#else +#define hwm_conv_can(smc,data,len) +#endif + + +static inline int is_my_addr(const struct s_smc *smc, + const struct fddi_addr *addr) +{ + return(*(short *)(&addr->a[0]) == + *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[0]) + && *(short *)(&addr->a[2]) == + *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[2]) + && *(short *)(&addr->a[4]) == + *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[4])) ; +} + +static inline int is_broadcast(const struct fddi_addr *addr) +{ + return *(u_short *)(&addr->a[0]) == 0xffff && + *(u_short *)(&addr->a[2]) == 0xffff && + *(u_short *)(&addr->a[4]) == 0xffff; +} + +static inline int is_individual(const struct fddi_addr *addr) +{ + return !(addr->a[0] & GROUP_ADDR); +} + +static inline int is_equal(const struct fddi_addr *addr1, + const struct fddi_addr *addr2) +{ + return *(u_short *)(&addr1->a[0]) == *(u_short *)(&addr2->a[0]) && + *(u_short *)(&addr1->a[2]) == *(u_short *)(&addr2->a[2]) && + *(u_short *)(&addr1->a[4]) == *(u_short *)(&addr2->a[4]); +} + +/* + * list of mandatory paras in frames + */ +static const u_short plist_nif[] = { SMT_P_UNA,SMT_P_SDE,SMT_P_STATE,0 } ; + +/* + * init SMT agent + */ +void smt_agent_init(struct s_smc *smc) +{ + int i ; + + /* + * get MAC address + */ + smc->mib.m[MAC0].fddiMACSMTAddress = smc->hw.fddi_home_addr ; + + /* + * get OUI address from driver (bia == built-in-address) + */ + smc->mib.fddiSMTStationId.sid_oem[0] = 0 ; + smc->mib.fddiSMTStationId.sid_oem[1] = 0 ; + driver_get_bia(smc,&smc->mib.fddiSMTStationId.sid_node) ; + for (i = 0 ; i < 6 ; i ++) { + smc->mib.fddiSMTStationId.sid_node.a[i] = + bitrev8(smc->mib.fddiSMTStationId.sid_node.a[i]); + } + smc->mib.fddiSMTManufacturerData[0] = + smc->mib.fddiSMTStationId.sid_node.a[0] ; + smc->mib.fddiSMTManufacturerData[1] = + smc->mib.fddiSMTStationId.sid_node.a[1] ; + smc->mib.fddiSMTManufacturerData[2] = + smc->mib.fddiSMTStationId.sid_node.a[2] ; + smc->sm.smt_tid = 0 ; + smc->mib.m[MAC0].fddiMACDupAddressTest = DA_NONE ; + smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ; +#ifndef SLIM_SMT + smt_clear_una_dna(smc) ; + smt_clear_old_una_dna(smc) ; +#endif + for (i = 0 ; i < SMT_MAX_TEST ; i++) + smc->sm.pend[i] = 0 ; + smc->sm.please_reconnect = 0 ; + smc->sm.uniq_ticks = 0 ; +} + +/* + * SMT task + * forever + * delay 30 seconds + * send NIF + * check tvu & tvd + * end + */ +void smt_agent_task(struct s_smc *smc) +{ + smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L, + EV_TOKEN(EVENT_SMT,SM_TIMER)) ; + DB_SMT("SMT agent task\n",0,0) ; +} + +#ifndef SMT_REAL_TOKEN_CT +void smt_emulate_token_ct(struct s_smc *smc, int mac_index) +{ + u_long count; + u_long time; + + + time = smt_get_time(); + count = ((time - smc->sm.last_tok_time[mac_index]) * + 100)/TICKS_PER_SECOND; + + /* + * Only when ring is up we will have a token count. The + * flag is unfortunately a single instance value. This + * doesn't matter now, because we currently have only + * one MAC instance. + */ + if (smc->hw.mac_ring_is_up){ + smc->mib.m[mac_index].fddiMACToken_Ct += count; + } + + /* Remember current time */ + smc->sm.last_tok_time[mac_index] = time; + +} +#endif + +/*ARGSUSED1*/ +void smt_event(struct s_smc *smc, int event) +{ + u_long time ; +#ifndef SMT_REAL_TOKEN_CT + int i ; +#endif + + + if (smc->sm.please_reconnect) { + smc->sm.please_reconnect -- ; + if (smc->sm.please_reconnect == 0) { + /* Counted down */ + queue_event(smc,EVENT_ECM,EC_CONNECT) ; + } + } + + if (event == SM_FAST) + return ; + + /* + * timer for periodic cleanup in driver + * reset and start the watchdog (FM2) + * ESS timer + * SBA timer + */ + smt_timer_poll(smc) ; + smt_start_watchdog(smc) ; +#ifndef SLIM_SMT +#ifndef BOOT +#ifdef ESS + ess_timer_poll(smc) ; +#endif +#endif +#ifdef SBA + sba_timer_poll(smc) ; +#endif + + smt_srf_event(smc,0,0,0) ; + +#endif /* no SLIM_SMT */ + + time = smt_get_time() ; + + if (time - smc->sm.smt_last_lem >= TICKS_PER_SECOND*8) { + /* + * Use 8 sec. for the time intervall, it simplifies the + * LER estimation. + */ + struct fddi_mib_m *mib ; + u_long upper ; + u_long lower ; + int cond ; + int port; + struct s_phy *phy ; + /* + * calculate LEM bit error rate + */ + sm_lem_evaluate(smc) ; + smc->sm.smt_last_lem = time ; + + /* + * check conditions + */ +#ifndef SLIM_SMT + mac_update_counter(smc) ; + mib = smc->mib.m ; + upper = + (mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) + + (mib->fddiMACError_Ct - mib->fddiMACOld_Error_Ct) ; + lower = + (mib->fddiMACFrame_Ct - mib->fddiMACOld_Frame_Ct) + + (mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) ; + mib->fddiMACFrameErrorRatio = div_ratio(upper,lower) ; + + cond = + ((!mib->fddiMACFrameErrorThreshold && + mib->fddiMACError_Ct != mib->fddiMACOld_Error_Ct) || + (mib->fddiMACFrameErrorRatio > + mib->fddiMACFrameErrorThreshold)) ; + + if (cond != mib->fddiMACFrameErrorFlag) + smt_srf_event(smc,SMT_COND_MAC_FRAME_ERROR, + INDEX_MAC,cond) ; + + upper = + (mib->fddiMACNotCopied_Ct - mib->fddiMACOld_NotCopied_Ct) ; + lower = + upper + + (mib->fddiMACCopied_Ct - mib->fddiMACOld_Copied_Ct) ; + mib->fddiMACNotCopiedRatio = div_ratio(upper,lower) ; + + cond = + ((!mib->fddiMACNotCopiedThreshold && + mib->fddiMACNotCopied_Ct != + mib->fddiMACOld_NotCopied_Ct)|| + (mib->fddiMACNotCopiedRatio > + mib->fddiMACNotCopiedThreshold)) ; + + if (cond != mib->fddiMACNotCopiedFlag) + smt_srf_event(smc,SMT_COND_MAC_NOT_COPIED, + INDEX_MAC,cond) ; + + /* + * set old values + */ + mib->fddiMACOld_Frame_Ct = mib->fddiMACFrame_Ct ; + mib->fddiMACOld_Copied_Ct = mib->fddiMACCopied_Ct ; + mib->fddiMACOld_Error_Ct = mib->fddiMACError_Ct ; + mib->fddiMACOld_Lost_Ct = mib->fddiMACLost_Ct ; + mib->fddiMACOld_NotCopied_Ct = mib->fddiMACNotCopied_Ct ; + + /* + * Check port EBError Condition + */ + for (port = 0; port < NUMPHYS; port ++) { + phy = &smc->y[port] ; + + if (!phy->mib->fddiPORTHardwarePresent) { + continue; + } + + cond = (phy->mib->fddiPORTEBError_Ct - + phy->mib->fddiPORTOldEBError_Ct > 5) ; + + /* If ratio is more than 5 in 8 seconds + * Set the condition. + */ + smt_srf_event(smc,SMT_COND_PORT_EB_ERROR, + (int) (INDEX_PORT+ phy->np) ,cond) ; + + /* + * set old values + */ + phy->mib->fddiPORTOldEBError_Ct = + phy->mib->fddiPORTEBError_Ct ; + } + +#endif /* no SLIM_SMT */ + } + +#ifndef SLIM_SMT + + if (time - smc->sm.smt_last_notify >= (u_long) + (smc->mib.fddiSMTTT_Notify * TICKS_PER_SECOND) ) { + /* + * we can either send an announcement or a request + * a request will trigger a reply so that we can update + * our dna + * note: same tid must be used until reply is received + */ + if (!smc->sm.pend[SMT_TID_NIF]) + smc->sm.pend[SMT_TID_NIF] = smt_get_tid(smc) ; + smt_send_nif(smc,&fddi_broadcast, FC_SMT_NSA, + smc->sm.pend[SMT_TID_NIF], SMT_REQUEST,0) ; + smc->sm.smt_last_notify = time ; + } + + /* + * check timer + */ + if (smc->sm.smt_tvu && + time - smc->sm.smt_tvu > 228*TICKS_PER_SECOND) { + DB_SMT("SMT : UNA expired\n",0,0) ; + smc->sm.smt_tvu = 0 ; + + if (!is_equal(&smc->mib.m[MAC0].fddiMACUpstreamNbr, + &SMT_Unknown)){ + /* Do not update unknown address */ + smc->mib.m[MAC0].fddiMACOldUpstreamNbr= + smc->mib.m[MAC0].fddiMACUpstreamNbr ; + } + smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ; + smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ; + /* + * Make sure the fddiMACUNDA_Flag = FALSE is + * included in the SRF so we don't generate + * a separate SRF for the deassertion of this + * condition + */ + update_dac(smc,0) ; + smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE, + INDEX_MAC,0) ; + } + if (smc->sm.smt_tvd && + time - smc->sm.smt_tvd > 228*TICKS_PER_SECOND) { + DB_SMT("SMT : DNA expired\n",0,0) ; + smc->sm.smt_tvd = 0 ; + if (!is_equal(&smc->mib.m[MAC0].fddiMACDownstreamNbr, + &SMT_Unknown)){ + /* Do not update unknown address */ + smc->mib.m[MAC0].fddiMACOldDownstreamNbr= + smc->mib.m[MAC0].fddiMACDownstreamNbr ; + } + smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ; + smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE, + INDEX_MAC,0) ; + } + +#endif /* no SLIM_SMT */ + +#ifndef SMT_REAL_TOKEN_CT + /* + * Token counter emulation section. If hardware supports the token + * count, the token counter will be updated in mac_update_counter. + */ + for (i = MAC0; i < NUMMACS; i++ ){ + if (time - smc->sm.last_tok_time[i] > 2*TICKS_PER_SECOND ){ + smt_emulate_token_ct( smc, i ); + } + } +#endif + + smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L, + EV_TOKEN(EVENT_SMT,SM_TIMER)) ; +} + +static int div_ratio(u_long upper, u_long lower) +{ + if ((upper<<16L) < upper) + upper = 0xffff0000L ; + else + upper <<= 16L ; + if (!lower) + return 0; + return (int)(upper/lower) ; +} + +#ifndef SLIM_SMT + +/* + * receive packet handler + */ +void smt_received_pack(struct s_smc *smc, SMbuf *mb, int fs) +/* int fs; frame status */ +{ + struct smt_header *sm ; + int local ; + + int illegal = 0 ; + + switch (m_fc(mb)) { + case FC_SMT_INFO : + case FC_SMT_LAN_LOC : + case FC_SMT_LOC : + case FC_SMT_NSA : + break ; + default : + smt_free_mbuf(smc,mb) ; + return ; + } + + smc->mib.m[MAC0].fddiMACSMTCopied_Ct++ ; + sm = smtod(mb,struct smt_header *) ; + local = ((fs & L_INDICATOR) != 0) ; + hwm_conv_can(smc,(char *)sm,12) ; + + /* check destination address */ + if (is_individual(&sm->smt_dest) && !is_my_addr(smc,&sm->smt_dest)) { + smt_free_mbuf(smc,mb) ; + return ; + } +#if 0 /* for DUP recognition, do NOT filter them */ + /* ignore loop back packets */ + if (is_my_addr(smc,&sm->smt_source) && !local) { + smt_free_mbuf(smc,mb) ; + return ; + } +#endif + + smt_swap_para(sm,(int) mb->sm_len,1) ; + DB_SMT("SMT : received packet [%s] at 0x%x\n", + smt_type_name[m_fc(mb) & 0xf],sm) ; + DB_SMT("SMT : version %d, class %s\n",sm->smt_version, + smt_class_name[(sm->smt_class>LAST_CLASS)?0 : sm->smt_class]) ; + +#ifdef SBA + /* + * check if NSA frame + */ + if (m_fc(mb) == FC_SMT_NSA && sm->smt_class == SMT_NIF && + (sm->smt_type == SMT_ANNOUNCE || sm->smt_type == SMT_REQUEST)) { + smc->sba.sm = sm ; + sba(smc,NIF) ; + } +#endif + + /* + * ignore any packet with NSA and A-indicator set + */ + if ( (fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) { + DB_SMT("SMT : ignoring NSA with A-indicator set from %s\n", + addr_to_string(&sm->smt_source),0) ; + smt_free_mbuf(smc,mb) ; + return ; + } + + /* + * ignore frames with illegal length + */ + if (((sm->smt_class == SMT_ECF) && (sm->smt_len > SMT_MAX_ECHO_LEN)) || + ((sm->smt_class != SMT_ECF) && (sm->smt_len > SMT_MAX_INFO_LEN))) { + smt_free_mbuf(smc,mb) ; + return ; + } + + /* + * check SMT version + */ + switch (sm->smt_class) { + case SMT_NIF : + case SMT_SIF_CONFIG : + case SMT_SIF_OPER : + case SMT_ECF : + if (sm->smt_version != SMT_VID) + illegal = 1; + break ; + default : + if (sm->smt_version != SMT_VID_2) + illegal = 1; + break ; + } + if (illegal) { + DB_SMT("SMT : version = %d, dest = %s\n", + sm->smt_version,addr_to_string(&sm->smt_source)) ; + smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_VERSION,local) ; + smt_free_mbuf(smc,mb) ; + return ; + } + if ((sm->smt_len > mb->sm_len - sizeof(struct smt_header)) || + ((sm->smt_len & 3) && (sm->smt_class != SMT_ECF))) { + DB_SMT("SMT: info length error, len = %d\n",sm->smt_len,0) ; + smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH,local) ; + smt_free_mbuf(smc,mb) ; + return ; + } + switch (sm->smt_class) { + case SMT_NIF : + if (smt_check_para(smc,sm,plist_nif)) { + DB_SMT("SMT: NIF with para problem, ignoring\n",0,0) ; + break ; + } + switch (sm->smt_type) { + case SMT_ANNOUNCE : + case SMT_REQUEST : + if (!(fs & C_INDICATOR) && m_fc(mb) == FC_SMT_NSA + && is_broadcast(&sm->smt_dest)) { + struct smt_p_state *st ; + + /* set my UNA */ + if (!is_equal( + &smc->mib.m[MAC0].fddiMACUpstreamNbr, + &sm->smt_source)) { + DB_SMT("SMT : updated my UNA = %s\n", + addr_to_string(&sm->smt_source),0) ; + if (!is_equal(&smc->mib.m[MAC0]. + fddiMACUpstreamNbr,&SMT_Unknown)){ + /* Do not update unknown address */ + smc->mib.m[MAC0].fddiMACOldUpstreamNbr= + smc->mib.m[MAC0].fddiMACUpstreamNbr ; + } + + smc->mib.m[MAC0].fddiMACUpstreamNbr = + sm->smt_source ; + smt_srf_event(smc, + SMT_EVENT_MAC_NEIGHBOR_CHANGE, + INDEX_MAC,0) ; + smt_echo_test(smc,0) ; + } + smc->sm.smt_tvu = smt_get_time() ; + st = (struct smt_p_state *) + sm_to_para(smc,sm,SMT_P_STATE) ; + if (st) { + smc->mib.m[MAC0].fddiMACUNDA_Flag = + (st->st_dupl_addr & SMT_ST_MY_DUPA) ? + TRUE : FALSE ; + update_dac(smc,1) ; + } + } + if ((sm->smt_type == SMT_REQUEST) && + is_individual(&sm->smt_source) && + ((!(fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) || + (m_fc(mb) != FC_SMT_NSA))) { + DB_SMT("SMT : replying to NIF request %s\n", + addr_to_string(&sm->smt_source),0) ; + smt_send_nif(smc,&sm->smt_source, + FC_SMT_INFO, + sm->smt_tid, + SMT_REPLY,local) ; + } + break ; + case SMT_REPLY : + DB_SMT("SMT : received NIF response from %s\n", + addr_to_string(&sm->smt_source),0) ; + if (fs & A_INDICATOR) { + smc->sm.pend[SMT_TID_NIF] = 0 ; + DB_SMT("SMT : duplicate address\n",0,0) ; + smc->mib.m[MAC0].fddiMACDupAddressTest = + DA_FAILED ; + smc->r.dup_addr_test = DA_FAILED ; + queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ; + smc->mib.m[MAC0].fddiMACDA_Flag = TRUE ; + update_dac(smc,1) ; + break ; + } + if (sm->smt_tid == smc->sm.pend[SMT_TID_NIF]) { + smc->sm.pend[SMT_TID_NIF] = 0 ; + /* set my DNA */ + if (!is_equal( + &smc->mib.m[MAC0].fddiMACDownstreamNbr, + &sm->smt_source)) { + DB_SMT("SMT : updated my DNA\n",0,0) ; + if (!is_equal(&smc->mib.m[MAC0]. + fddiMACDownstreamNbr, &SMT_Unknown)){ + /* Do not update unknown address */ + smc->mib.m[MAC0].fddiMACOldDownstreamNbr = + smc->mib.m[MAC0].fddiMACDownstreamNbr ; + } + + smc->mib.m[MAC0].fddiMACDownstreamNbr = + sm->smt_source ; + smt_srf_event(smc, + SMT_EVENT_MAC_NEIGHBOR_CHANGE, + INDEX_MAC,0) ; + smt_echo_test(smc,1) ; + } + smc->mib.m[MAC0].fddiMACDA_Flag = FALSE ; + update_dac(smc,1) ; + smc->sm.smt_tvd = smt_get_time() ; + smc->mib.m[MAC0].fddiMACDupAddressTest = + DA_PASSED ; + if (smc->r.dup_addr_test != DA_PASSED) { + smc->r.dup_addr_test = DA_PASSED ; + queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ; + } + } + else if (sm->smt_tid == + smc->sm.pend[SMT_TID_NIF_TEST]) { + DB_SMT("SMT : NIF test TID ok\n",0,0) ; + } + else { + DB_SMT("SMT : expected TID %lx, got %lx\n", + smc->sm.pend[SMT_TID_NIF],sm->smt_tid) ; + } + break ; + default : + illegal = 2 ; + break ; + } + break ; + case SMT_SIF_CONFIG : /* station information */ + if (sm->smt_type != SMT_REQUEST) + break ; + DB_SMT("SMT : replying to SIF Config request from %s\n", + addr_to_string(&sm->smt_source),0) ; + smt_send_sif_config(smc,&sm->smt_source,sm->smt_tid,local) ; + break ; + case SMT_SIF_OPER : /* station information */ + if (sm->smt_type != SMT_REQUEST) + break ; + DB_SMT("SMT : replying to SIF Operation request from %s\n", + addr_to_string(&sm->smt_source),0) ; + smt_send_sif_operation(smc,&sm->smt_source,sm->smt_tid,local) ; + break ; + case SMT_ECF : /* echo frame */ + switch (sm->smt_type) { + case SMT_REPLY : + smc->mib.priv.fddiPRIVECF_Reply_Rx++ ; + DB_SMT("SMT: received ECF reply from %s\n", + addr_to_string(&sm->smt_source),0) ; + if (sm_to_para(smc,sm,SMT_P_ECHODATA) == NULL) { + DB_SMT("SMT: ECHODATA missing\n",0,0) ; + break ; + } + if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF]) { + DB_SMT("SMT : ECF test TID ok\n",0,0) ; + } + else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_UNA]) { + DB_SMT("SMT : ECF test UNA ok\n",0,0) ; + } + else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_DNA]) { + DB_SMT("SMT : ECF test DNA ok\n",0,0) ; + } + else { + DB_SMT("SMT : expected TID %lx, got %lx\n", + smc->sm.pend[SMT_TID_ECF], + sm->smt_tid) ; + } + break ; + case SMT_REQUEST : + smc->mib.priv.fddiPRIVECF_Req_Rx++ ; + { + if (sm->smt_len && !sm_to_para(smc,sm,SMT_P_ECHODATA)) { + DB_SMT("SMT: ECF with para problem,sending RDF\n",0,0) ; + smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH, + local) ; + break ; + } + DB_SMT("SMT - sending ECF reply to %s\n", + addr_to_string(&sm->smt_source),0) ; + + /* set destination addr. & reply */ + sm->smt_dest = sm->smt_source ; + sm->smt_type = SMT_REPLY ; + dump_smt(smc,sm,"ECF REPLY") ; + smc->mib.priv.fddiPRIVECF_Reply_Tx++ ; + smt_send_frame(smc,mb,FC_SMT_INFO,local) ; + return ; /* DON'T free mbuf */ + } + default : + illegal = 1 ; + break ; + } + break ; +#ifndef BOOT + case SMT_RAF : /* resource allocation */ +#ifdef ESS + DB_ESSN(2,"ESS: RAF frame received\n",0,0) ; + fs = ess_raf_received_pack(smc,mb,sm,fs) ; +#endif + +#ifdef SBA + DB_SBAN(2,"SBA: RAF frame received\n",0,0) ; + sba_raf_received_pack(smc,sm,fs) ; +#endif + break ; + case SMT_RDF : /* request denied */ + smc->mib.priv.fddiPRIVRDF_Rx++ ; + break ; + case SMT_ESF : /* extended service - not supported */ + if (sm->smt_type == SMT_REQUEST) { + DB_SMT("SMT - received ESF, sending RDF\n",0,0) ; + smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ; + } + break ; + case SMT_PMF_GET : + case SMT_PMF_SET : + if (sm->smt_type != SMT_REQUEST) + break ; + /* update statistics */ + if (sm->smt_class == SMT_PMF_GET) + smc->mib.priv.fddiPRIVPMF_Get_Rx++ ; + else + smc->mib.priv.fddiPRIVPMF_Set_Rx++ ; + /* + * ignore PMF SET with I/G set + */ + if ((sm->smt_class == SMT_PMF_SET) && + !is_individual(&sm->smt_dest)) { + DB_SMT("SMT: ignoring PMF-SET with I/G set\n",0,0) ; + break ; + } + smt_pmf_received_pack(smc,mb, local) ; + break ; + case SMT_SRF : + dump_smt(smc,sm,"SRF received") ; + break ; + default : + if (sm->smt_type != SMT_REQUEST) + break ; + /* + * For frames with unknown class: + * we need to send a RDF frame according to 8.1.3.1.1, + * only if it is a REQUEST. + */ + DB_SMT("SMT : class = %d, send RDF to %s\n", + sm->smt_class, addr_to_string(&sm->smt_source)) ; + + smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ; + break ; +#endif + } + if (illegal) { + DB_SMT("SMT: discarding invalid frame, reason = %d\n", + illegal,0) ; + } + smt_free_mbuf(smc,mb) ; +} + +static void update_dac(struct s_smc *smc, int report) +{ + int cond ; + + cond = ( smc->mib.m[MAC0].fddiMACUNDA_Flag | + smc->mib.m[MAC0].fddiMACDA_Flag) != 0 ; + if (report && (cond != smc->mib.m[MAC0].fddiMACDuplicateAddressCond)) + smt_srf_event(smc, SMT_COND_MAC_DUP_ADDR,INDEX_MAC,cond) ; + else + smc->mib.m[MAC0].fddiMACDuplicateAddressCond = cond ; +} + +/* + * send SMT frame + * set source address + * set station ID + * send frame + */ +void smt_send_frame(struct s_smc *smc, SMbuf *mb, int fc, int local) +/* SMbuf *mb; buffer to send */ +/* int fc; FC value */ +{ + struct smt_header *sm ; + + if (!smc->r.sm_ma_avail && !local) { + smt_free_mbuf(smc,mb) ; + return ; + } + sm = smtod(mb,struct smt_header *) ; + sm->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ; + sm->smt_sid = smc->mib.fddiSMTStationId ; + + smt_swap_para(sm,(int) mb->sm_len,0) ; /* swap para & header */ + hwm_conv_can(smc,(char *)sm,12) ; /* convert SA and DA */ + smc->mib.m[MAC0].fddiMACSMTTransmit_Ct++ ; + smt_send_mbuf(smc,mb,local ? FC_SMT_LOC : fc) ; +} + +/* + * generate and send RDF + */ +static void smt_send_rdf(struct s_smc *smc, SMbuf *rej, int fc, int reason, + int local) +/* SMbuf *rej; mbuf of offending frame */ +/* int fc; FC of denied frame */ +/* int reason; reason code */ +{ + SMbuf *mb ; + struct smt_header *sm ; /* header of offending frame */ + struct smt_rdf *rdf ; + int len ; + int frame_len ; + + sm = smtod(rej,struct smt_header *) ; + if (sm->smt_type != SMT_REQUEST) + return ; + + DB_SMT("SMT: sending RDF to %s,reason = 0x%x\n", + addr_to_string(&sm->smt_source),reason) ; + + + /* + * note: get framelength from MAC length, NOT from SMT header + * smt header length is included in sm_len + */ + frame_len = rej->sm_len ; + + if (!(mb=smt_build_frame(smc,SMT_RDF,SMT_REPLY,sizeof(struct smt_rdf)))) + return ; + rdf = smtod(mb,struct smt_rdf *) ; + rdf->smt.smt_tid = sm->smt_tid ; /* use TID from sm */ + rdf->smt.smt_dest = sm->smt_source ; /* set dest = source */ + + /* set P12 */ + rdf->reason.para.p_type = SMT_P_REASON ; + rdf->reason.para.p_len = sizeof(struct smt_p_reason) - PARA_LEN ; + rdf->reason.rdf_reason = reason ; + + /* set P14 */ + rdf->version.para.p_type = SMT_P_VERSION ; + rdf->version.para.p_len = sizeof(struct smt_p_version) - PARA_LEN ; + rdf->version.v_pad = 0 ; + rdf->version.v_n = 1 ; + rdf->version.v_index = 1 ; + rdf->version.v_version[0] = SMT_VID_2 ; + rdf->version.v_pad2 = 0 ; + + /* set P13 */ + if ((unsigned) frame_len <= SMT_MAX_INFO_LEN - sizeof(*rdf) + + 2*sizeof(struct smt_header)) + len = frame_len ; + else + len = SMT_MAX_INFO_LEN - sizeof(*rdf) + + 2*sizeof(struct smt_header) ; + /* make length multiple of 4 */ + len &= ~3 ; + rdf->refused.para.p_type = SMT_P_REFUSED ; + /* length of para is smt_frame + ref_fc */ + rdf->refused.para.p_len = len + 4 ; + rdf->refused.ref_fc = fc ; + + /* swap it back */ + smt_swap_para(sm,frame_len,0) ; + + memcpy((char *) &rdf->refused.ref_header,(char *) sm,len) ; + + len -= sizeof(struct smt_header) ; + mb->sm_len += len ; + rdf->smt.smt_len += len ; + + dump_smt(smc,(struct smt_header *)rdf,"RDF") ; + smc->mib.priv.fddiPRIVRDF_Tx++ ; + smt_send_frame(smc,mb,FC_SMT_INFO,local) ; +} + +/* + * generate and send NIF + */ +static void smt_send_nif(struct s_smc *smc, const struct fddi_addr *dest, + int fc, u_long tid, int type, int local) +/* struct fddi_addr *dest; dest address */ +/* int fc; frame control */ +/* u_long tid; transaction id */ +/* int type; frame type */ +{ + struct smt_nif *nif ; + SMbuf *mb ; + + if (!(mb = smt_build_frame(smc,SMT_NIF,type,sizeof(struct smt_nif)))) + return ; + nif = smtod(mb, struct smt_nif *) ; + smt_fill_una(smc,&nif->una) ; /* set UNA */ + smt_fill_sde(smc,&nif->sde) ; /* set station descriptor */ + smt_fill_state(smc,&nif->state) ; /* set state information */ +#ifdef SMT6_10 + smt_fill_fsc(smc,&nif->fsc) ; /* set frame status cap. */ +#endif + nif->smt.smt_dest = *dest ; /* destination address */ + nif->smt.smt_tid = tid ; /* transaction ID */ + dump_smt(smc,(struct smt_header *)nif,"NIF") ; + smt_send_frame(smc,mb,fc,local) ; +} + +#ifdef DEBUG +/* + * send NIF request (test purpose) + */ +static void smt_send_nif_request(struct s_smc *smc, struct fddi_addr *dest) +{ + smc->sm.pend[SMT_TID_NIF_TEST] = smt_get_tid(smc) ; + smt_send_nif(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_NIF_TEST], + SMT_REQUEST,0) ; +} + +/* + * send ECF request (test purpose) + */ +static void smt_send_ecf_request(struct s_smc *smc, struct fddi_addr *dest, + int len) +{ + smc->sm.pend[SMT_TID_ECF] = smt_get_tid(smc) ; + smt_send_ecf(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_ECF], + SMT_REQUEST,len) ; +} +#endif + +/* + * echo test + */ +static void smt_echo_test(struct s_smc *smc, int dna) +{ + u_long tid ; + + smc->sm.pend[dna ? SMT_TID_ECF_DNA : SMT_TID_ECF_UNA] = + tid = smt_get_tid(smc) ; + smt_send_ecf(smc, dna ? + &smc->mib.m[MAC0].fddiMACDownstreamNbr : + &smc->mib.m[MAC0].fddiMACUpstreamNbr, + FC_SMT_INFO,tid, SMT_REQUEST, (SMT_TEST_ECHO_LEN & ~3)-8) ; +} + +/* + * generate and send ECF + */ +static void smt_send_ecf(struct s_smc *smc, struct fddi_addr *dest, int fc, + u_long tid, int type, int len) +/* struct fddi_addr *dest; dest address */ +/* int fc; frame control */ +/* u_long tid; transaction id */ +/* int type; frame type */ +/* int len; frame length */ +{ + struct smt_ecf *ecf ; + SMbuf *mb ; + + if (!(mb = smt_build_frame(smc,SMT_ECF,type,SMT_ECF_LEN + len))) + return ; + ecf = smtod(mb, struct smt_ecf *) ; + + smt_fill_echo(smc,&ecf->ec_echo,tid,len) ; /* set ECHO */ + ecf->smt.smt_dest = *dest ; /* destination address */ + ecf->smt.smt_tid = tid ; /* transaction ID */ + smc->mib.priv.fddiPRIVECF_Req_Tx++ ; + smt_send_frame(smc,mb,fc,0) ; +} + +/* + * generate and send SIF config response + */ + +static void smt_send_sif_config(struct s_smc *smc, struct fddi_addr *dest, + u_long tid, int local) +/* struct fddi_addr *dest; dest address */ +/* u_long tid; transaction id */ +{ + struct smt_sif_config *sif ; + SMbuf *mb ; + int len ; + if (!(mb = smt_build_frame(smc,SMT_SIF_CONFIG,SMT_REPLY, + SIZEOF_SMT_SIF_CONFIG))) + return ; + + sif = smtod(mb, struct smt_sif_config *) ; + smt_fill_timestamp(smc,&sif->ts) ; /* set time stamp */ + smt_fill_sde(smc,&sif->sde) ; /* set station descriptor */ + smt_fill_version(smc,&sif->version) ; /* set version information */ + smt_fill_state(smc,&sif->state) ; /* set state information */ + smt_fill_policy(smc,&sif->policy) ; /* set station policy */ + smt_fill_latency(smc,&sif->latency); /* set station latency */ + smt_fill_neighbor(smc,&sif->neighbor); /* set station neighbor */ + smt_fill_setcount(smc,&sif->setcount) ; /* set count */ + len = smt_fill_path(smc,&sif->path); /* set station path descriptor*/ + sif->smt.smt_dest = *dest ; /* destination address */ + sif->smt.smt_tid = tid ; /* transaction ID */ + smt_add_frame_len(mb,len) ; /* adjust length fields */ + dump_smt(smc,(struct smt_header *)sif,"SIF Configuration Reply") ; + smt_send_frame(smc,mb,FC_SMT_INFO,local) ; +} + +/* + * generate and send SIF operation response + */ + +static void smt_send_sif_operation(struct s_smc *smc, struct fddi_addr *dest, + u_long tid, int local) +/* struct fddi_addr *dest; dest address */ +/* u_long tid; transaction id */ +{ + struct smt_sif_operation *sif ; + SMbuf *mb ; + int ports ; + int i ; + + ports = NUMPHYS ; +#ifndef CONCENTRATOR + if (smc->s.sas == SMT_SAS) + ports = 1 ; +#endif + + if (!(mb = smt_build_frame(smc,SMT_SIF_OPER,SMT_REPLY, + SIZEOF_SMT_SIF_OPERATION+ports*sizeof(struct smt_p_lem)))) + return ; + sif = smtod(mb, struct smt_sif_operation *) ; + smt_fill_timestamp(smc,&sif->ts) ; /* set time stamp */ + smt_fill_mac_status(smc,&sif->status) ; /* set mac status */ + smt_fill_mac_counter(smc,&sif->mc) ; /* set mac counter field */ + smt_fill_mac_fnc(smc,&sif->fnc) ; /* set frame not copied counter */ + smt_fill_manufacturer(smc,&sif->man) ; /* set manufacturer field */ + smt_fill_user(smc,&sif->user) ; /* set user field */ + smt_fill_setcount(smc,&sif->setcount) ; /* set count */ + /* + * set link error mon information + */ + if (ports == 1) { + smt_fill_lem(smc,sif->lem,PS) ; + } + else { + for (i = 0 ; i < ports ; i++) { + smt_fill_lem(smc,&sif->lem[i],i) ; + } + } + + sif->smt.smt_dest = *dest ; /* destination address */ + sif->smt.smt_tid = tid ; /* transaction ID */ + dump_smt(smc,(struct smt_header *)sif,"SIF Operation Reply") ; + smt_send_frame(smc,mb,FC_SMT_INFO,local) ; +} + +/* + * get and initialize SMT frame + */ +SMbuf *smt_build_frame(struct s_smc *smc, int class, int type, + int length) +{ + SMbuf *mb ; + struct smt_header *smt ; + +#if 0 + if (!smc->r.sm_ma_avail) { + return 0; + } +#endif + if (!(mb = smt_get_mbuf(smc))) + return mb; + + mb->sm_len = length ; + smt = smtod(mb, struct smt_header *) ; + smt->smt_dest = fddi_broadcast ; /* set dest = broadcast */ + smt->smt_class = class ; + smt->smt_type = type ; + switch (class) { + case SMT_NIF : + case SMT_SIF_CONFIG : + case SMT_SIF_OPER : + case SMT_ECF : + smt->smt_version = SMT_VID ; + break ; + default : + smt->smt_version = SMT_VID_2 ; + break ; + } + smt->smt_tid = smt_get_tid(smc) ; /* set transaction ID */ + smt->smt_pad = 0 ; + smt->smt_len = length - sizeof(struct smt_header) ; + return mb; +} + +static void smt_add_frame_len(SMbuf *mb, int len) +{ + struct smt_header *smt ; + + smt = smtod(mb, struct smt_header *) ; + smt->smt_len += len ; + mb->sm_len += len ; +} + + + +/* + * fill values in UNA parameter + */ +static void smt_fill_una(struct s_smc *smc, struct smt_p_una *una) +{ + SMTSETPARA(una,SMT_P_UNA) ; + una->una_pad = 0 ; + una->una_node = smc->mib.m[MAC0].fddiMACUpstreamNbr ; +} + +/* + * fill values in SDE parameter + */ +static void smt_fill_sde(struct s_smc *smc, struct smt_p_sde *sde) +{ + SMTSETPARA(sde,SMT_P_SDE) ; + sde->sde_non_master = smc->mib.fddiSMTNonMaster_Ct ; + sde->sde_master = smc->mib.fddiSMTMaster_Ct ; + sde->sde_mac_count = NUMMACS ; /* only 1 MAC */ +#ifdef CONCENTRATOR + sde->sde_type = SMT_SDE_CONCENTRATOR ; +#else + sde->sde_type = SMT_SDE_STATION ; +#endif +} + +/* + * fill in values in station state parameter + */ +static void smt_fill_state(struct s_smc *smc, struct smt_p_state *state) +{ + int top ; + int twist ; + + SMTSETPARA(state,SMT_P_STATE) ; + state->st_pad = 0 ; + + /* determine topology */ + top = 0 ; + if (smc->mib.fddiSMTPeerWrapFlag) { + top |= SMT_ST_WRAPPED ; /* state wrapped */ + } +#ifdef CONCENTRATOR + if (cfm_status_unattached(smc)) { + top |= SMT_ST_UNATTACHED ; /* unattached concentrator */ + } +#endif + if ((twist = pcm_status_twisted(smc)) & 1) { + top |= SMT_ST_TWISTED_A ; /* twisted cable */ + } + if (twist & 2) { + top |= SMT_ST_TWISTED_B ; /* twisted cable */ + } +#ifdef OPT_SRF + top |= SMT_ST_SRF ; +#endif + if (pcm_rooted_station(smc)) + top |= SMT_ST_ROOTED_S ; + if (smc->mib.a[0].fddiPATHSbaPayload != 0) + top |= SMT_ST_SYNC_SERVICE ; + state->st_topology = top ; + state->st_dupl_addr = + ((smc->mib.m[MAC0].fddiMACDA_Flag ? SMT_ST_MY_DUPA : 0 ) | + (smc->mib.m[MAC0].fddiMACUNDA_Flag ? SMT_ST_UNA_DUPA : 0)) ; +} + +/* + * fill values in timestamp parameter + */ +static void smt_fill_timestamp(struct s_smc *smc, struct smt_p_timestamp *ts) +{ + + SMTSETPARA(ts,SMT_P_TIMESTAMP) ; + smt_set_timestamp(smc,ts->ts_time) ; +} + +void smt_set_timestamp(struct s_smc *smc, u_char *p) +{ + u_long time ; + u_long utime ; + + /* + * timestamp is 64 bits long ; resolution is 80 nS + * our clock resolution is 10mS + * 10mS/80ns = 125000 ~ 2^17 = 131072 + */ + utime = smt_get_time() ; + time = utime * 100 ; + time /= TICKS_PER_SECOND ; + p[0] = 0 ; + p[1] = (u_char)((time>>(8+8+8+8-1)) & 1) ; + p[2] = (u_char)(time>>(8+8+8-1)) ; + p[3] = (u_char)(time>>(8+8-1)) ; + p[4] = (u_char)(time>>(8-1)) ; + p[5] = (u_char)(time<<1) ; + p[6] = (u_char)(smc->sm.uniq_ticks>>8) ; + p[7] = (u_char)smc->sm.uniq_ticks ; + /* + * make sure we don't wrap: restart whenever the upper digits change + */ + if (utime != smc->sm.uniq_time) { + smc->sm.uniq_ticks = 0 ; + } + smc->sm.uniq_ticks++ ; + smc->sm.uniq_time = utime ; +} + +/* + * fill values in station policy parameter + */ +static void smt_fill_policy(struct s_smc *smc, struct smt_p_policy *policy) +{ + int i ; + const u_char *map ; + u_short in ; + u_short out ; + + /* + * MIB para 101b (fddiSMTConnectionPolicy) coding + * is different from 0005 coding + */ + static const u_char ansi_weirdness[16] = { + 0,7,5,3,8,1,6,4,9,10,2,11,12,13,14,15 + } ; + SMTSETPARA(policy,SMT_P_POLICY) ; + + out = 0 ; + in = smc->mib.fddiSMTConnectionPolicy ; + for (i = 0, map = ansi_weirdness ; i < 16 ; i++) { + if (in & 1) + out |= (1<<*map) ; + in >>= 1 ; + map++ ; + } + policy->pl_config = smc->mib.fddiSMTConfigPolicy ; + policy->pl_connect = out ; +} + +/* + * fill values in latency equivalent parameter + */ +static void smt_fill_latency(struct s_smc *smc, struct smt_p_latency *latency) +{ + SMTSETPARA(latency,SMT_P_LATENCY) ; + + latency->lt_phyout_idx1 = phy_index(smc,0) ; + latency->lt_latency1 = 10 ; /* in octets (byte clock) */ + /* + * note: latency has two phy entries by definition + * for a SAS, the 2nd one is null + */ + if (smc->s.sas == SMT_DAS) { + latency->lt_phyout_idx2 = phy_index(smc,1) ; + latency->lt_latency2 = 10 ; /* in octets (byte clock) */ + } + else { + latency->lt_phyout_idx2 = 0 ; + latency->lt_latency2 = 0 ; + } +} + +/* + * fill values in MAC neighbors parameter + */ +static void smt_fill_neighbor(struct s_smc *smc, struct smt_p_neighbor *neighbor) +{ + SMTSETPARA(neighbor,SMT_P_NEIGHBORS) ; + + neighbor->nb_mib_index = INDEX_MAC ; + neighbor->nb_mac_index = mac_index(smc,1) ; + neighbor->nb_una = smc->mib.m[MAC0].fddiMACUpstreamNbr ; + neighbor->nb_dna = smc->mib.m[MAC0].fddiMACDownstreamNbr ; +} + +/* + * fill values in path descriptor + */ +#ifdef CONCENTRATOR +#define ALLPHYS NUMPHYS +#else +#define ALLPHYS ((smc->s.sas == SMT_SAS) ? 1 : 2) +#endif + +static int smt_fill_path(struct s_smc *smc, struct smt_p_path *path) +{ + SK_LOC_DECL(int,type) ; + SK_LOC_DECL(int,state) ; + SK_LOC_DECL(int,remote) ; + SK_LOC_DECL(int,mac) ; + int len ; + int p ; + int physp ; + struct smt_phy_rec *phy ; + struct smt_mac_rec *pd_mac ; + + len = PARA_LEN + + sizeof(struct smt_mac_rec) * NUMMACS + + sizeof(struct smt_phy_rec) * ALLPHYS ; + path->para.p_type = SMT_P_PATH ; + path->para.p_len = len - PARA_LEN ; + + /* PHYs */ + for (p = 0,phy = path->pd_phy ; p < ALLPHYS ; p++, phy++) { + physp = p ; +#ifndef CONCENTRATOR + if (smc->s.sas == SMT_SAS) + physp = PS ; +#endif + pcm_status_state(smc,physp,&type,&state,&remote,&mac) ; +#ifdef LITTLE_ENDIAN + phy->phy_mib_index = smt_swap_short((u_short)p+INDEX_PORT) ; +#else + phy->phy_mib_index = p+INDEX_PORT ; +#endif + phy->phy_type = type ; + phy->phy_connect_state = state ; + phy->phy_remote_type = remote ; + phy->phy_remote_mac = mac ; + phy->phy_resource_idx = phy_con_resource_index(smc,p) ; + } + + /* MAC */ + pd_mac = (struct smt_mac_rec *) phy ; + pd_mac->mac_addr = smc->mib.m[MAC0].fddiMACSMTAddress ; + pd_mac->mac_resource_idx = mac_con_resource_index(smc,1) ; + return len; +} + +/* + * fill values in mac status + */ +static void smt_fill_mac_status(struct s_smc *smc, struct smt_p_mac_status *st) +{ + SMTSETPARA(st,SMT_P_MAC_STATUS) ; + + st->st_mib_index = INDEX_MAC ; + st->st_mac_index = mac_index(smc,1) ; + + mac_update_counter(smc) ; + /* + * timer values are represented in SMT as 2's complement numbers + * units : internal : 2's complement BCLK + */ + st->st_t_req = smc->mib.m[MAC0].fddiMACT_Req ; + st->st_t_neg = smc->mib.m[MAC0].fddiMACT_Neg ; + st->st_t_max = smc->mib.m[MAC0].fddiMACT_Max ; + st->st_tvx_value = smc->mib.m[MAC0].fddiMACTvxValue ; + st->st_t_min = smc->mib.m[MAC0].fddiMACT_Min ; + + st->st_sba = smc->mib.a[PATH0].fddiPATHSbaPayload ; + st->st_frame_ct = smc->mib.m[MAC0].fddiMACFrame_Ct ; + st->st_error_ct = smc->mib.m[MAC0].fddiMACError_Ct ; + st->st_lost_ct = smc->mib.m[MAC0].fddiMACLost_Ct ; +} + +/* + * fill values in LEM status + */ +static void smt_fill_lem(struct s_smc *smc, struct smt_p_lem *lem, int phy) +{ + struct fddi_mib_p *mib ; + + mib = smc->y[phy].mib ; + + SMTSETPARA(lem,SMT_P_LEM) ; + lem->lem_mib_index = phy+INDEX_PORT ; + lem->lem_phy_index = phy_index(smc,phy) ; + lem->lem_pad2 = 0 ; + lem->lem_cutoff = mib->fddiPORTLer_Cutoff ; + lem->lem_alarm = mib->fddiPORTLer_Alarm ; + /* long term bit error rate */ + lem->lem_estimate = mib->fddiPORTLer_Estimate ; + /* # of rejected connections */ + lem->lem_reject_ct = mib->fddiPORTLem_Reject_Ct ; + lem->lem_ct = mib->fddiPORTLem_Ct ; /* total number of errors */ +} + +/* + * fill version parameter + */ +static void smt_fill_version(struct s_smc *smc, struct smt_p_version *vers) +{ + SK_UNUSED(smc) ; + SMTSETPARA(vers,SMT_P_VERSION) ; + vers->v_pad = 0 ; + vers->v_n = 1 ; /* one version is enough .. */ + vers->v_index = 1 ; + vers->v_version[0] = SMT_VID_2 ; + vers->v_pad2 = 0 ; +} + +#ifdef SMT6_10 +/* + * fill frame status capabilities + */ +/* + * note: this para 200B is NOT in swap table, because it's also set in + * PMF add_para + */ +static void smt_fill_fsc(struct s_smc *smc, struct smt_p_fsc *fsc) +{ + SK_UNUSED(smc) ; + SMTSETPARA(fsc,SMT_P_FSC) ; + fsc->fsc_pad0 = 0 ; + fsc->fsc_mac_index = INDEX_MAC ; /* this is MIB ; MIB is NOT + * mac_index ()i ! + */ + fsc->fsc_pad1 = 0 ; + fsc->fsc_value = FSC_TYPE0 ; /* "normal" node */ +#ifdef LITTLE_ENDIAN + fsc->fsc_mac_index = smt_swap_short(INDEX_MAC) ; + fsc->fsc_value = smt_swap_short(FSC_TYPE0) ; +#endif +} +#endif + +/* + * fill mac counter field + */ +static void smt_fill_mac_counter(struct s_smc *smc, struct smt_p_mac_counter *mc) +{ + SMTSETPARA(mc,SMT_P_MAC_COUNTER) ; + mc->mc_mib_index = INDEX_MAC ; + mc->mc_index = mac_index(smc,1) ; + mc->mc_receive_ct = smc->mib.m[MAC0].fddiMACCopied_Ct ; + mc->mc_transmit_ct = smc->mib.m[MAC0].fddiMACTransmit_Ct ; +} + +/* + * fill mac frame not copied counter + */ +static void smt_fill_mac_fnc(struct s_smc *smc, struct smt_p_mac_fnc *fnc) +{ + SMTSETPARA(fnc,SMT_P_MAC_FNC) ; + fnc->nc_mib_index = INDEX_MAC ; + fnc->nc_index = mac_index(smc,1) ; + fnc->nc_counter = smc->mib.m[MAC0].fddiMACNotCopied_Ct ; +} + + +/* + * fill manufacturer field + */ +static void smt_fill_manufacturer(struct s_smc *smc, + struct smp_p_manufacturer *man) +{ + SMTSETPARA(man,SMT_P_MANUFACTURER) ; + memcpy((char *) man->mf_data, + (char *) smc->mib.fddiSMTManufacturerData, + sizeof(man->mf_data)) ; +} + +/* + * fill user field + */ +static void smt_fill_user(struct s_smc *smc, struct smp_p_user *user) +{ + SMTSETPARA(user,SMT_P_USER) ; + memcpy((char *) user->us_data, + (char *) smc->mib.fddiSMTUserData, + sizeof(user->us_data)) ; +} + +/* + * fill set count + */ +static void smt_fill_setcount(struct s_smc *smc, struct smt_p_setcount *setcount) +{ + SK_UNUSED(smc) ; + SMTSETPARA(setcount,SMT_P_SETCOUNT) ; + setcount->count = smc->mib.fddiSMTSetCount.count ; + memcpy((char *)setcount->timestamp, + (char *)smc->mib.fddiSMTSetCount.timestamp,8) ; +} + +/* + * fill echo data + */ +static void smt_fill_echo(struct s_smc *smc, struct smt_p_echo *echo, u_long seed, + int len) +{ + u_char *p ; + + SK_UNUSED(smc) ; + SMTSETPARA(echo,SMT_P_ECHODATA) ; + echo->para.p_len = len ; + for (p = echo->ec_data ; len ; len--) { + *p++ = (u_char) seed ; + seed += 13 ; + } +} + +/* + * clear DNA and UNA + * called from CFM if configuration changes + */ +static void smt_clear_una_dna(struct s_smc *smc) +{ + smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ; + smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ; +} + +static void smt_clear_old_una_dna(struct s_smc *smc) +{ + smc->mib.m[MAC0].fddiMACOldUpstreamNbr = SMT_Unknown ; + smc->mib.m[MAC0].fddiMACOldDownstreamNbr = SMT_Unknown ; +} + +u_long smt_get_tid(struct s_smc *smc) +{ + u_long tid ; + while ((tid = ++(smc->sm.smt_tid) ^ SMT_TID_MAGIC) == 0) + ; + return tid & 0x3fffffffL; +} + + +/* + * table of parameter lengths + */ +static const struct smt_pdef { + int ptype ; + int plen ; + const char *pswap ; +} smt_pdef[] = { + { SMT_P_UNA, sizeof(struct smt_p_una) , + SWAP_SMT_P_UNA } , + { SMT_P_SDE, sizeof(struct smt_p_sde) , + SWAP_SMT_P_SDE } , + { SMT_P_STATE, sizeof(struct smt_p_state) , + SWAP_SMT_P_STATE } , + { SMT_P_TIMESTAMP,sizeof(struct smt_p_timestamp) , + SWAP_SMT_P_TIMESTAMP } , + { SMT_P_POLICY, sizeof(struct smt_p_policy) , + SWAP_SMT_P_POLICY } , + { SMT_P_LATENCY, sizeof(struct smt_p_latency) , + SWAP_SMT_P_LATENCY } , + { SMT_P_NEIGHBORS,sizeof(struct smt_p_neighbor) , + SWAP_SMT_P_NEIGHBORS } , + { SMT_P_PATH, sizeof(struct smt_p_path) , + SWAP_SMT_P_PATH } , + { SMT_P_MAC_STATUS,sizeof(struct smt_p_mac_status) , + SWAP_SMT_P_MAC_STATUS } , + { SMT_P_LEM, sizeof(struct smt_p_lem) , + SWAP_SMT_P_LEM } , + { SMT_P_MAC_COUNTER,sizeof(struct smt_p_mac_counter) , + SWAP_SMT_P_MAC_COUNTER } , + { SMT_P_MAC_FNC,sizeof(struct smt_p_mac_fnc) , + SWAP_SMT_P_MAC_FNC } , + { SMT_P_PRIORITY,sizeof(struct smt_p_priority) , + SWAP_SMT_P_PRIORITY } , + { SMT_P_EB,sizeof(struct smt_p_eb) , + SWAP_SMT_P_EB } , + { SMT_P_MANUFACTURER,sizeof(struct smp_p_manufacturer) , + SWAP_SMT_P_MANUFACTURER } , + { SMT_P_REASON, sizeof(struct smt_p_reason) , + SWAP_SMT_P_REASON } , + { SMT_P_REFUSED, sizeof(struct smt_p_refused) , + SWAP_SMT_P_REFUSED } , + { SMT_P_VERSION, sizeof(struct smt_p_version) , + SWAP_SMT_P_VERSION } , +#ifdef ESS + { SMT_P0015, sizeof(struct smt_p_0015) , SWAP_SMT_P0015 } , + { SMT_P0016, sizeof(struct smt_p_0016) , SWAP_SMT_P0016 } , + { SMT_P0017, sizeof(struct smt_p_0017) , SWAP_SMT_P0017 } , + { SMT_P0018, sizeof(struct smt_p_0018) , SWAP_SMT_P0018 } , + { SMT_P0019, sizeof(struct smt_p_0019) , SWAP_SMT_P0019 } , + { SMT_P001A, sizeof(struct smt_p_001a) , SWAP_SMT_P001A } , + { SMT_P001B, sizeof(struct smt_p_001b) , SWAP_SMT_P001B } , + { SMT_P001C, sizeof(struct smt_p_001c) , SWAP_SMT_P001C } , + { SMT_P001D, sizeof(struct smt_p_001d) , SWAP_SMT_P001D } , +#endif +#if 0 + { SMT_P_FSC, sizeof(struct smt_p_fsc) , + SWAP_SMT_P_FSC } , +#endif + + { SMT_P_SETCOUNT,0, SWAP_SMT_P_SETCOUNT } , + { SMT_P1048, 0, SWAP_SMT_P1048 } , + { SMT_P208C, 0, SWAP_SMT_P208C } , + { SMT_P208D, 0, SWAP_SMT_P208D } , + { SMT_P208E, 0, SWAP_SMT_P208E } , + { SMT_P208F, 0, SWAP_SMT_P208F } , + { SMT_P2090, 0, SWAP_SMT_P2090 } , +#ifdef ESS + { SMT_P320B, sizeof(struct smt_p_320b) , SWAP_SMT_P320B } , + { SMT_P320F, sizeof(struct smt_p_320f) , SWAP_SMT_P320F } , + { SMT_P3210, sizeof(struct smt_p_3210) , SWAP_SMT_P3210 } , +#endif + { SMT_P4050, 0, SWAP_SMT_P4050 } , + { SMT_P4051, 0, SWAP_SMT_P4051 } , + { SMT_P4052, 0, SWAP_SMT_P4052 } , + { SMT_P4053, 0, SWAP_SMT_P4053 } , +} ; + +#define N_SMT_PLEN ARRAY_SIZE(smt_pdef) + +int smt_check_para(struct s_smc *smc, struct smt_header *sm, + const u_short list[]) +{ + const u_short *p = list ; + while (*p) { + if (!sm_to_para(smc,sm,(int) *p)) { + DB_SMT("SMT: smt_check_para - missing para %x\n",*p,0); + return -1; + } + p++ ; + } + return 0; +} + +void *sm_to_para(struct s_smc *smc, struct smt_header *sm, int para) +{ + char *p ; + int len ; + int plen ; + void *found = NULL; + + SK_UNUSED(smc) ; + + len = sm->smt_len ; + p = (char *)(sm+1) ; /* pointer to info */ + while (len > 0 ) { + if (((struct smt_para *)p)->p_type == para) + found = (void *) p ; + plen = ((struct smt_para *)p)->p_len + PARA_LEN ; + p += plen ; + len -= plen ; + if (len < 0) { + DB_SMT("SMT : sm_to_para - length error %d\n",plen,0) ; + return NULL; + } + if ((plen & 3) && (para != SMT_P_ECHODATA)) { + DB_SMT("SMT : sm_to_para - odd length %d\n",plen,0) ; + return NULL; + } + if (found) + return found; + } + return NULL; +} + +#if 0 +/* + * send ANTC data test frame + */ +void fddi_send_antc(struct s_smc *smc, struct fddi_addr *dest) +{ + SK_UNUSED(smc) ; + SK_UNUSED(dest) ; +#if 0 + SMbuf *mb ; + struct smt_header *smt ; + int i ; + char *p ; + + mb = smt_get_mbuf() ; + mb->sm_len = 3000+12 ; + p = smtod(mb, char *) + 12 ; + for (i = 0 ; i < 3000 ; i++) + *p++ = 1 << (i&7) ; + + smt = smtod(mb, struct smt_header *) ; + smt->smt_dest = *dest ; + smt->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ; + smt_send_mbuf(smc,mb,FC_ASYNC_LLC) ; +#endif +} +#endif + +#ifdef DEBUG +char *addr_to_string(struct fddi_addr *addr) +{ + int i ; + static char string[6*3] = "****" ; + + for (i = 0 ; i < 6 ; i++) { + string[i * 3] = hex_asc_hi(addr->a[i]); + string[i * 3 + 1] = hex_asc_lo(addr->a[i]); + string[i * 3 + 2] = ':'; + } + string[5 * 3 + 2] = 0; + return string; +} +#endif + +#ifdef AM29K +int smt_ifconfig(int argc, char *argv[]) +{ + if (argc >= 2 && !strcmp(argv[0],"opt_bypass") && + !strcmp(argv[1],"yes")) { + smc->mib.fddiSMTBypassPresent = 1 ; + return 0; + } + return amdfddi_config(0, argc, argv); +} +#endif + +/* + * return static mac index + */ +static int mac_index(struct s_smc *smc, int mac) +{ + SK_UNUSED(mac) ; +#ifdef CONCENTRATOR + SK_UNUSED(smc) ; + return NUMPHYS + 1; +#else + return (smc->s.sas == SMT_SAS) ? 2 : 3; +#endif +} + +/* + * return static phy index + */ +static int phy_index(struct s_smc *smc, int phy) +{ + SK_UNUSED(smc) ; + return phy + 1; +} + +/* + * return dynamic mac connection resource index + */ +static int mac_con_resource_index(struct s_smc *smc, int mac) +{ +#ifdef CONCENTRATOR + SK_UNUSED(smc) ; + SK_UNUSED(mac) ; + return entity_to_index(smc, cem_get_downstream(smc, ENTITY_MAC)); +#else + SK_UNUSED(mac) ; + switch (smc->mib.fddiSMTCF_State) { + case SC9_C_WRAP_A : + case SC5_THRU_B : + case SC11_C_WRAP_S : + return 1; + case SC10_C_WRAP_B : + case SC4_THRU_A : + return 2; + } + return smc->s.sas == SMT_SAS ? 2 : 3; +#endif +} + +/* + * return dynamic phy connection resource index + */ +static int phy_con_resource_index(struct s_smc *smc, int phy) +{ +#ifdef CONCENTRATOR + return entity_to_index(smc, cem_get_downstream(smc, ENTITY_PHY(phy))) ; +#else + switch (smc->mib.fddiSMTCF_State) { + case SC9_C_WRAP_A : + return phy == PA ? 3 : 2; + case SC10_C_WRAP_B : + return phy == PA ? 1 : 3; + case SC4_THRU_A : + return phy == PA ? 3 : 1; + case SC5_THRU_B : + return phy == PA ? 2 : 3; + case SC11_C_WRAP_S : + return 2; + } + return phy; +#endif +} + +#ifdef CONCENTRATOR +static int entity_to_index(struct s_smc *smc, int e) +{ + if (e == ENTITY_MAC) + return mac_index(smc, 1); + else + return phy_index(smc, e - ENTITY_PHY(0)); +} +#endif + +#ifdef LITTLE_ENDIAN +static int smt_swap_short(u_short s) +{ + return ((s>>8)&0xff) | ((s&0xff)<<8); +} + +void smt_swap_para(struct smt_header *sm, int len, int direction) +/* int direction; 0 encode 1 decode */ +{ + struct smt_para *pa ; + const struct smt_pdef *pd ; + char *p ; + int plen ; + int type ; + int i ; + +/* printf("smt_swap_para sm %x len %d dir %d\n", + sm,len,direction) ; + */ + smt_string_swap((char *)sm,SWAP_SMTHEADER,len) ; + + /* swap args */ + len -= sizeof(struct smt_header) ; + + p = (char *) (sm + 1) ; + while (len > 0) { + pa = (struct smt_para *) p ; + plen = pa->p_len ; + type = pa->p_type ; + pa->p_type = smt_swap_short(pa->p_type) ; + pa->p_len = smt_swap_short(pa->p_len) ; + if (direction) { + plen = pa->p_len ; + type = pa->p_type ; + } + /* + * note: paras can have 0 length ! + */ + if (plen < 0) + break ; + plen += PARA_LEN ; + for (i = N_SMT_PLEN, pd = smt_pdef; i ; i--,pd++) { + if (pd->ptype == type) + break ; + } + if (i && pd->pswap) { + smt_string_swap(p+PARA_LEN,pd->pswap,len) ; + } + len -= plen ; + p += plen ; + } +} + +static void smt_string_swap(char *data, const char *format, int len) +{ + const char *open_paren = NULL ; + int x ; + + while (len > 0 && *format) { + switch (*format) { + case '[' : + open_paren = format ; + break ; + case ']' : + format = open_paren ; + break ; + case '1' : + case '2' : + case '3' : + case '4' : + case '5' : + case '6' : + case '7' : + case '8' : + case '9' : + data += *format - '0' ; + len -= *format - '0' ; + break ; + case 'c': + data++ ; + len-- ; + break ; + case 's' : + x = data[0] ; + data[0] = data[1] ; + data[1] = x ; + data += 2 ; + len -= 2 ; + break ; + case 'l' : + x = data[0] ; + data[0] = data[3] ; + data[3] = x ; + x = data[1] ; + data[1] = data[2] ; + data[2] = x ; + data += 4 ; + len -= 4 ; + break ; + } + format++ ; + } +} +#else +void smt_swap_para(struct smt_header *sm, int len, int direction) +/* int direction; 0 encode 1 decode */ +{ + SK_UNUSED(sm) ; + SK_UNUSED(len) ; + SK_UNUSED(direction) ; +} +#endif + +/* + * PMF actions + */ +int smt_action(struct s_smc *smc, int class, int code, int index) +{ + int event ; + int port ; + DB_SMT("SMT: action %d code %d\n",class,code) ; + switch(class) { + case SMT_STATION_ACTION : + switch(code) { + case SMT_STATION_ACTION_CONNECT : + smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ; + queue_event(smc,EVENT_ECM,EC_CONNECT) ; + break ; + case SMT_STATION_ACTION_DISCONNECT : + queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; + smc->mib.fddiSMTRemoteDisconnectFlag = TRUE ; + RS_SET(smc,RS_DISCONNECT) ; + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_DISCONNECT, + smt_get_event_word(smc)); + break ; + case SMT_STATION_ACTION_PATHTEST : + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_SMT_EVENT, (u_long) FDDI_PATH_TEST, + smt_get_event_word(smc)); + break ; + case SMT_STATION_ACTION_SELFTEST : + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_SELF_TEST, + smt_get_event_word(smc)); + break ; + case SMT_STATION_ACTION_DISABLE_A : + if (smc->y[PA].pc_mode == PM_PEER) { + RS_SET(smc,RS_EVENT) ; + queue_event(smc,EVENT_PCM+PA,PC_DISABLE) ; + } + break ; + case SMT_STATION_ACTION_DISABLE_B : + if (smc->y[PB].pc_mode == PM_PEER) { + RS_SET(smc,RS_EVENT) ; + queue_event(smc,EVENT_PCM+PB,PC_DISABLE) ; + } + break ; + case SMT_STATION_ACTION_DISABLE_M : + for (port = 0 ; port < NUMPHYS ; port++) { + if (smc->mib.p[port].fddiPORTMy_Type != TM) + continue ; + RS_SET(smc,RS_EVENT) ; + queue_event(smc,EVENT_PCM+port,PC_DISABLE) ; + } + break ; + default : + return 1; + } + break ; + case SMT_PORT_ACTION : + switch(code) { + case SMT_PORT_ACTION_ENABLE : + event = PC_ENABLE ; + break ; + case SMT_PORT_ACTION_DISABLE : + event = PC_DISABLE ; + break ; + case SMT_PORT_ACTION_MAINT : + event = PC_MAINT ; + break ; + case SMT_PORT_ACTION_START : + event = PC_START ; + break ; + case SMT_PORT_ACTION_STOP : + event = PC_STOP ; + break ; + default : + return 1; + } + queue_event(smc,EVENT_PCM+index,event) ; + break ; + default : + return 1; + } + return 0; +} + +/* + * canonical conversion of bytes beginning form *data + */ +#ifdef USE_CAN_ADDR +static void hwm_conv_can(struct s_smc *smc, char *data, int len) +{ + int i ; + + SK_UNUSED(smc) ; + + for (i = len; i ; i--, data++) + *data = bitrev8(*data); +} +#endif + +#endif /* no SLIM_SMT */ + diff --git a/drivers/net/fddi/skfp/smtdef.c b/drivers/net/fddi/skfp/smtdef.c new file mode 100644 index 0000000..1acab0b --- /dev/null +++ b/drivers/net/fddi/skfp/smtdef.c @@ -0,0 +1,355 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + SMT/CMT defaults +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#ifndef OEM_USER_DATA +#define OEM_USER_DATA "SK-NET FDDI V2.0 Userdata" +#endif + +#ifndef lint +static const char ID_sccs[] = "@(#)smtdef.c 2.53 99/08/11 (C) SK " ; +#endif + +/* + * defaults + */ +#define TTMS(x) ((u_long)(x)*1000L) +#define TTS(x) ((u_long)(x)*1000000L) +#define TTUS(x) ((u_long)(x)) + +#define DEFAULT_TB_MIN TTMS(5) +#define DEFAULT_TB_MAX TTMS(50) +#define DEFAULT_C_MIN TTUS(1600) +#define DEFAULT_T_OUT TTMS(100+5) +#define DEFAULT_TL_MIN TTUS(30) +#define DEFAULT_LC_SHORT TTMS(50+5) +#define DEFAULT_LC_MEDIUM TTMS(500+20) +#define DEFAULT_LC_LONG TTS(5)+TTMS(50) +#define DEFAULT_LC_EXTENDED TTS(50)+TTMS(50) +#define DEFAULT_T_NEXT_9 TTMS(200+10) +#define DEFAULT_NS_MAX TTUS(1310) +#define DEFAULT_I_MAX TTMS(25) +#define DEFAULT_IN_MAX TTMS(40) +#define DEFAULT_TD_MIN TTMS(5) +#define DEFAULT_T_NON_OP TTS(1) +#define DEFAULT_T_STUCK TTS(8) +#define DEFAULT_T_DIRECT TTMS(370) +#define DEFAULT_T_JAM TTMS(370) +#define DEFAULT_T_ANNOUNCE TTMS(2500) +#define DEFAULT_D_MAX TTUS(1617) +#define DEFAULT_LEM_ALARM (8) +#define DEFAULT_LEM_CUTOFF (7) +#define DEFAULT_TEST_DONE TTS(1) +#define DEFAULT_CHECK_POLL TTS(1) +#define DEFAULT_POLL TTMS(50) + +/* + * LCT errors threshold + */ +#define DEFAULT_LCT_SHORT 1 +#define DEFAULT_LCT_MEDIUM 3 +#define DEFAULT_LCT_LONG 5 +#define DEFAULT_LCT_EXTEND 50 + +/* Forward declarations */ +void smt_reset_defaults(struct s_smc *smc, int level); +static void smt_init_mib(struct s_smc *smc, int level); +static int set_min_max(int maxflag, u_long mib, u_long limit, u_long *oper); + +#define MS2BCLK(x) ((x)*12500L) +#define US2BCLK(x) ((x)*1250L) + +void smt_reset_defaults(struct s_smc *smc, int level) +{ + struct smt_config *smt ; + int i ; + u_long smt_boot_time; + + + smt_init_mib(smc,level) ; + + smc->os.smc_version = SMC_VERSION ; + smt_boot_time = smt_get_time(); + for( i = 0; i < NUMMACS; i++ ) + smc->sm.last_tok_time[i] = smt_boot_time ; + smt = &smc->s ; + smt->attach_s = 0 ; + smt->build_ring_map = 1 ; + smt->sas = SMT_DAS ; + smt->numphys = NUMPHYS ; + smt->pcm_tb_min = DEFAULT_TB_MIN ; + smt->pcm_tb_max = DEFAULT_TB_MAX ; + smt->pcm_c_min = DEFAULT_C_MIN ; + smt->pcm_t_out = DEFAULT_T_OUT ; + smt->pcm_tl_min = DEFAULT_TL_MIN ; + smt->pcm_lc_short = DEFAULT_LC_SHORT ; + smt->pcm_lc_medium = DEFAULT_LC_MEDIUM ; + smt->pcm_lc_long = DEFAULT_LC_LONG ; + smt->pcm_lc_extended = DEFAULT_LC_EXTENDED ; + smt->pcm_t_next_9 = DEFAULT_T_NEXT_9 ; + smt->pcm_ns_max = DEFAULT_NS_MAX ; + smt->ecm_i_max = DEFAULT_I_MAX ; + smt->ecm_in_max = DEFAULT_IN_MAX ; + smt->ecm_td_min = DEFAULT_TD_MIN ; + smt->ecm_test_done = DEFAULT_TEST_DONE ; + smt->ecm_check_poll = DEFAULT_CHECK_POLL ; + smt->rmt_t_non_op = DEFAULT_T_NON_OP ; + smt->rmt_t_stuck = DEFAULT_T_STUCK ; + smt->rmt_t_direct = DEFAULT_T_DIRECT ; + smt->rmt_t_jam = DEFAULT_T_JAM ; + smt->rmt_t_announce = DEFAULT_T_ANNOUNCE ; + smt->rmt_t_poll = DEFAULT_POLL ; + smt->rmt_dup_mac_behavior = FALSE ; /* See Struct smt_config */ + smt->mac_d_max = DEFAULT_D_MAX ; + + smt->lct_short = DEFAULT_LCT_SHORT ; + smt->lct_medium = DEFAULT_LCT_MEDIUM ; + smt->lct_long = DEFAULT_LCT_LONG ; + smt->lct_extended = DEFAULT_LCT_EXTEND ; + +#ifndef SLIM_SMT +#ifdef ESS + if (level == 0) { + smc->ess.sync_bw_available = FALSE ; + smc->mib.fddiESSPayload = 0 ; + smc->mib.fddiESSOverhead = 0 ; + smc->mib.fddiESSMaxTNeg = (u_long)(- MS2BCLK(25)) ; + smc->mib.fddiESSMinSegmentSize = 1 ; + smc->mib.fddiESSCategory = SB_STATIC ; + smc->mib.fddiESSSynchTxMode = FALSE ; + smc->ess.raf_act_timer_poll = FALSE ; + smc->ess.timer_count = 7 ; /* first RAF alc req after 3s */ + } + smc->ess.local_sba_active = FALSE ; + smc->ess.sba_reply_pend = NULL ; +#endif +#ifdef SBA + smt_init_sba(smc,level) ; +#endif +#endif /* no SLIM_SMT */ +#ifdef TAG_MODE + if (level == 0) { + smc->hw.pci_fix_value = 0 ; + } +#endif +} + +/* + * manufacturer data + */ +static const char man_data[32] = +/* 01234567890123456789012345678901 */ + "xxxSK-NET FDDI SMT 7.3 - V2.8.8" ; + +static void smt_init_mib(struct s_smc *smc, int level) +{ + struct fddi_mib *mib ; + struct fddi_mib_p *pm ; + int port ; + int path ; + + mib = &smc->mib ; + if (level == 0) { + /* + * set EVERYTHING to ZERO + * EXCEPT hw and os + */ + memset(((char *)smc)+ + sizeof(struct s_smt_os)+sizeof(struct s_smt_hw), 0, + sizeof(struct s_smc) - + sizeof(struct s_smt_os) - sizeof(struct s_smt_hw)) ; + } + else { + mib->fddiSMTRemoteDisconnectFlag = 0 ; + mib->fddiSMTPeerWrapFlag = 0 ; + } + + mib->fddiSMTOpVersionId = 2 ; + mib->fddiSMTHiVersionId = 2 ; + mib->fddiSMTLoVersionId = 2 ; + memcpy((char *) mib->fddiSMTManufacturerData,man_data,32) ; + if (level == 0) { + strcpy(mib->fddiSMTUserData,OEM_USER_DATA) ; + } + mib->fddiSMTMIBVersionId = 1 ; + mib->fddiSMTMac_Ct = NUMMACS ; + mib->fddiSMTConnectionPolicy = POLICY_MM | POLICY_AA | POLICY_BB ; + + /* + * fddiSMTNonMaster_Ct and fddiSMTMaster_Ct are set in smt_fixup_mib + * s.sas is not set yet (is set in init driver) + */ + mib->fddiSMTAvailablePaths = MIB_PATH_P | MIB_PATH_S ; + + mib->fddiSMTConfigCapabilities = 0 ; /* no hold,no wrap_ab*/ + mib->fddiSMTTT_Notify = 10 ; + mib->fddiSMTStatRptPolicy = TRUE ; + mib->fddiSMTTrace_MaxExpiration = SEC2MIB(7) ; + mib->fddiSMTMACIndexes = INDEX_MAC ; + mib->fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ; /* separated */ + + mib->m[MAC0].fddiMACIndex = INDEX_MAC ; + mib->m[MAC0].fddiMACFrameStatusFunctions = FSC_TYPE0 ; + mib->m[MAC0].fddiMACRequestedPaths = + MIB_P_PATH_LOCAL | + MIB_P_PATH_SEC_ALTER | + MIB_P_PATH_PRIM_ALTER ; + mib->m[MAC0].fddiMACAvailablePaths = MIB_PATH_P ; + mib->m[MAC0].fddiMACCurrentPath = MIB_PATH_PRIMARY ; + mib->m[MAC0].fddiMACT_MaxCapabilitiy = (u_long)(- MS2BCLK(165)) ; + mib->m[MAC0].fddiMACTVXCapabilitiy = (u_long)(- US2BCLK(52)) ; + if (level == 0) { + mib->m[MAC0].fddiMACTvxValue = (u_long)(- US2BCLK(27)) ; + mib->m[MAC0].fddiMACTvxValueMIB = (u_long)(- US2BCLK(27)) ; + mib->m[MAC0].fddiMACT_Req = (u_long)(- MS2BCLK(165)) ; + mib->m[MAC0].fddiMACT_ReqMIB = (u_long)(- MS2BCLK(165)) ; + mib->m[MAC0].fddiMACT_Max = (u_long)(- MS2BCLK(165)) ; + mib->m[MAC0].fddiMACT_MaxMIB = (u_long)(- MS2BCLK(165)) ; + mib->m[MAC0].fddiMACT_Min = (u_long)(- MS2BCLK(4)) ; + } + mib->m[MAC0].fddiMACHardwarePresent = TRUE ; + mib->m[MAC0].fddiMACMA_UnitdataEnable = TRUE ; + mib->m[MAC0].fddiMACFrameErrorThreshold = 1 ; + mib->m[MAC0].fddiMACNotCopiedThreshold = 1 ; + /* + * Path attributes + */ + for (path = 0 ; path < NUMPATHS ; path++) { + mib->a[path].fddiPATHIndex = INDEX_PATH + path ; + if (level == 0) { + mib->a[path].fddiPATHTVXLowerBound = + (u_long)(- US2BCLK(27)) ; + mib->a[path].fddiPATHT_MaxLowerBound = + (u_long)(- MS2BCLK(165)) ; + mib->a[path].fddiPATHMaxT_Req = + (u_long)(- MS2BCLK(165)) ; + } + } + + + /* + * Port attributes + */ + pm = mib->p ; + for (port = 0 ; port < NUMPHYS ; port++) { + /* + * set MIB pointer in phy + */ + /* Attention: don't initialize mib pointer here! */ + /* It must be initialized during phase 2 */ + smc->y[port].mib = NULL; + mib->fddiSMTPORTIndexes[port] = port+INDEX_PORT ; + + pm->fddiPORTIndex = port+INDEX_PORT ; + pm->fddiPORTHardwarePresent = TRUE ; + if (level == 0) { + pm->fddiPORTLer_Alarm = DEFAULT_LEM_ALARM ; + pm->fddiPORTLer_Cutoff = DEFAULT_LEM_CUTOFF ; + } + /* + * fddiPORTRequestedPaths are set in pcmplc.c + * we don't know the port type yet ! + */ + pm->fddiPORTRequestedPaths[1] = 0 ; + pm->fddiPORTRequestedPaths[2] = 0 ; + pm->fddiPORTRequestedPaths[3] = 0 ; + pm->fddiPORTAvailablePaths = MIB_PATH_P ; + pm->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ; + pm++ ; + } + + (void) smt_set_mac_opvalues(smc) ; +} + +int smt_set_mac_opvalues(struct s_smc *smc) +{ + int st ; + int st2 ; + + st = set_min_max(1,smc->mib.m[MAC0].fddiMACTvxValueMIB, + smc->mib.a[PATH0].fddiPATHTVXLowerBound, + &smc->mib.m[MAC0].fddiMACTvxValue) ; + st |= set_min_max(0,smc->mib.m[MAC0].fddiMACT_MaxMIB, + smc->mib.a[PATH0].fddiPATHT_MaxLowerBound, + &smc->mib.m[MAC0].fddiMACT_Max) ; + st |= (st2 = set_min_max(0,smc->mib.m[MAC0].fddiMACT_ReqMIB, + smc->mib.a[PATH0].fddiPATHMaxT_Req, + &smc->mib.m[MAC0].fddiMACT_Req)) ; + if (st2) { + /* Treq attribute changed remotely. So send an AIX_EVENT to the + * user + */ + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_T_REQ, + smt_get_event_word(smc)); + } + return st; +} + +void smt_fixup_mib(struct s_smc *smc) +{ +#ifdef CONCENTRATOR + switch (smc->s.sas) { + case SMT_SAS : + smc->mib.fddiSMTNonMaster_Ct = 1 ; + break ; + case SMT_DAS : + smc->mib.fddiSMTNonMaster_Ct = 2 ; + break ; + case SMT_NAC : + smc->mib.fddiSMTNonMaster_Ct = 0 ; + break ; + } + smc->mib.fddiSMTMaster_Ct = NUMPHYS - smc->mib.fddiSMTNonMaster_Ct ; +#else + switch (smc->s.sas) { + case SMT_SAS : + smc->mib.fddiSMTNonMaster_Ct = 1 ; + break ; + case SMT_DAS : + smc->mib.fddiSMTNonMaster_Ct = 2 ; + break ; + } + smc->mib.fddiSMTMaster_Ct = 0 ; +#endif +} + +/* + * determine new setting for operational value + * if limit is lower than mib + * use limit + * else + * use mib + * NOTE : numbers are negative, negate comparison ! + */ +static int set_min_max(int maxflag, u_long mib, u_long limit, u_long *oper) +{ + u_long old ; + old = *oper ; + if ((limit > mib) ^ maxflag) + *oper = limit ; + else + *oper = mib ; + return old != *oper; +} + diff --git a/drivers/net/fddi/skfp/smtinit.c b/drivers/net/fddi/skfp/smtinit.c new file mode 100644 index 0000000..e3a0c0b --- /dev/null +++ b/drivers/net/fddi/skfp/smtinit.c @@ -0,0 +1,125 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + Init SMT + call all module level initialization routines +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)smtinit.c 1.15 97/05/06 (C) SK " ; +#endif + +void init_fddi_driver(struct s_smc *smc, u_char *mac_addr); + +/* define global debug variable */ +#if defined(DEBUG) && !defined(DEBUG_BRD) +struct smt_debug debug; +#endif + +#ifndef MULT_OEM +#define OEMID(smc,i) oem_id[i] + extern u_char oem_id[] ; +#else /* MULT_OEM */ +#define OEMID(smc,i) smc->hw.oem_id->oi_mark[i] + extern struct s_oem_ids oem_ids[] ; +#endif /* MULT_OEM */ + +/* + * Set OEM specific values + * + * Can not be called in smt_reset_defaults, because it is not sure that + * the OEM ID is already defined. + */ +static void set_oem_spec_val(struct s_smc *smc) +{ + struct fddi_mib *mib ; + + mib = &smc->mib ; + + /* + * set IBM specific values + */ + if (OEMID(smc,0) == 'I') { + mib->fddiSMTConnectionPolicy = POLICY_MM ; + } +} + +/* + * Init SMT + */ +int init_smt(struct s_smc *smc, u_char *mac_addr) +/* u_char *mac_addr; canonical address or NULL */ +{ + int p ; + +#if defined(DEBUG) && !defined(DEBUG_BRD) + debug.d_smt = 0 ; + debug.d_smtf = 0 ; + debug.d_rmt = 0 ; + debug.d_ecm = 0 ; + debug.d_pcm = 0 ; + debug.d_cfm = 0 ; + + debug.d_plc = 0 ; +#ifdef ESS + debug.d_ess = 0 ; +#endif +#ifdef SBA + debug.d_sba = 0 ; +#endif +#endif /* DEBUG && !DEBUG_BRD */ + + /* First initialize the ports mib->pointers */ + for ( p = 0; p < NUMPHYS; p ++ ) { + smc->y[p].mib = & smc->mib.p[p] ; + } + + set_oem_spec_val(smc) ; + (void) smt_set_mac_opvalues(smc) ; + init_fddi_driver(smc,mac_addr) ; /* HW driver */ + smt_fixup_mib(smc) ; /* update values that depend on s.sas */ + + ev_init(smc) ; /* event queue */ +#ifndef SLIM_SMT + smt_init_evc(smc) ; /* evcs in MIB */ +#endif /* no SLIM_SMT */ + smt_timer_init(smc) ; /* timer package */ + smt_agent_init(smc) ; /* SMT frame manager */ + + pcm_init(smc) ; /* PCM state machine */ + ecm_init(smc) ; /* ECM state machine */ + cfm_init(smc) ; /* CFM state machine */ + rmt_init(smc) ; /* RMT state machine */ + + for (p = 0 ; p < NUMPHYS ; p++) { + pcm(smc,p,0) ; /* PCM A state machine */ + } + ecm(smc,0) ; /* ECM state machine */ + cfm(smc,0) ; /* CFM state machine */ + rmt(smc,0) ; /* RMT state machine */ + + smt_agent_task(smc) ; /* NIF FSM etc */ + + PNMI_INIT(smc) ; /* PNMI initialization */ + + return 0; +} + diff --git a/drivers/net/fddi/skfp/smttimer.c b/drivers/net/fddi/skfp/smttimer.c new file mode 100644 index 0000000..531795e --- /dev/null +++ b/drivers/net/fddi/skfp/smttimer.c @@ -0,0 +1,156 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + SMT timer +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)smttimer.c 2.4 97/08/04 (C) SK " ; +#endif + +static void timer_done(struct s_smc *smc, int restart); + +void smt_timer_init(struct s_smc *smc) +{ + smc->t.st_queue = NULL; + smc->t.st_fast.tm_active = FALSE ; + smc->t.st_fast.tm_next = NULL; + hwt_init(smc) ; +} + +void smt_timer_stop(struct s_smc *smc, struct smt_timer *timer) +{ + struct smt_timer **prev ; + struct smt_timer *tm ; + + /* + * remove timer from queue + */ + timer->tm_active = FALSE ; + if (smc->t.st_queue == timer && !timer->tm_next) { + hwt_stop(smc) ; + } + for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) { + if (tm == timer) { + *prev = tm->tm_next ; + if (tm->tm_next) { + tm->tm_next->tm_delta += tm->tm_delta ; + } + return ; + } + } +} + +void smt_timer_start(struct s_smc *smc, struct smt_timer *timer, u_long time, + u_long token) +{ + struct smt_timer **prev ; + struct smt_timer *tm ; + u_long delta = 0 ; + + time /= 16 ; /* input is uS, clock ticks are 16uS */ + if (!time) + time = 1 ; + smt_timer_stop(smc,timer) ; + timer->tm_smc = smc ; + timer->tm_token = token ; + timer->tm_active = TRUE ; + if (!smc->t.st_queue) { + smc->t.st_queue = timer ; + timer->tm_next = NULL; + timer->tm_delta = time ; + hwt_start(smc,time) ; + return ; + } + /* + * timer correction + */ + timer_done(smc,0) ; + + /* + * find position in queue + */ + delta = 0 ; + for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) { + if (delta + tm->tm_delta > time) { + break ; + } + delta += tm->tm_delta ; + } + /* insert in queue */ + *prev = timer ; + timer->tm_next = tm ; + timer->tm_delta = time - delta ; + if (tm) + tm->tm_delta -= timer->tm_delta ; + /* + * start new with first + */ + hwt_start(smc,smc->t.st_queue->tm_delta) ; +} + +void smt_force_irq(struct s_smc *smc) +{ + smt_timer_start(smc,&smc->t.st_fast,32L, EV_TOKEN(EVENT_SMT,SM_FAST)); +} + +void smt_timer_done(struct s_smc *smc) +{ + timer_done(smc,1) ; +} + +static void timer_done(struct s_smc *smc, int restart) +{ + u_long delta ; + struct smt_timer *tm ; + struct smt_timer *next ; + struct smt_timer **last ; + int done = 0 ; + + delta = hwt_read(smc) ; + last = &smc->t.st_queue ; + tm = smc->t.st_queue ; + while (tm && !done) { + if (delta >= tm->tm_delta) { + tm->tm_active = FALSE ; + delta -= tm->tm_delta ; + last = &tm->tm_next ; + tm = tm->tm_next ; + } + else { + tm->tm_delta -= delta ; + delta = 0 ; + done = 1 ; + } + } + *last = NULL; + next = smc->t.st_queue ; + smc->t.st_queue = tm ; + + for ( tm = next ; tm ; tm = next) { + next = tm->tm_next ; + timer_event(smc,tm->tm_token) ; + } + + if (restart && smc->t.st_queue) + hwt_start(smc,smc->t.st_queue->tm_delta) ; +} + diff --git a/drivers/net/fddi/skfp/srf.c b/drivers/net/fddi/skfp/srf.c new file mode 100644 index 0000000..f6f7baf --- /dev/null +++ b/drivers/net/fddi/skfp/srf.c @@ -0,0 +1,429 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + SMT 7.2 Status Response Frame Implementation + SRF state machine and frame generation +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/smt_p.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef SLIM_SMT +#ifndef BOOT + +#ifndef lint +static const char ID_sccs[] = "@(#)srf.c 1.18 97/08/04 (C) SK " ; +#endif + + +/* + * function declarations + */ +static void clear_all_rep(struct s_smc *smc); +static void clear_reported(struct s_smc *smc); +static void smt_send_srf(struct s_smc *smc); +static struct s_srf_evc *smt_get_evc(struct s_smc *smc, int code, int index); + +#define MAX_EVCS ARRAY_SIZE(smc->evcs) + +struct evc_init { + u_char code ; + u_char index ; + u_char n ; + u_short para ; +} ; + +static const struct evc_init evc_inits[] = { + { SMT_COND_SMT_PEER_WRAP, 0,1,SMT_P1048 } , + + { SMT_COND_MAC_DUP_ADDR, INDEX_MAC, NUMMACS,SMT_P208C } , + { SMT_COND_MAC_FRAME_ERROR, INDEX_MAC, NUMMACS,SMT_P208D } , + { SMT_COND_MAC_NOT_COPIED, INDEX_MAC, NUMMACS,SMT_P208E } , + { SMT_EVENT_MAC_NEIGHBOR_CHANGE, INDEX_MAC, NUMMACS,SMT_P208F } , + { SMT_EVENT_MAC_PATH_CHANGE, INDEX_MAC, NUMMACS,SMT_P2090 } , + + { SMT_COND_PORT_LER, INDEX_PORT,NUMPHYS,SMT_P4050 } , + { SMT_COND_PORT_EB_ERROR, INDEX_PORT,NUMPHYS,SMT_P4052 } , + { SMT_EVENT_PORT_CONNECTION, INDEX_PORT,NUMPHYS,SMT_P4051 } , + { SMT_EVENT_PORT_PATH_CHANGE, INDEX_PORT,NUMPHYS,SMT_P4053 } , +} ; + +#define MAX_INIT_EVC ARRAY_SIZE(evc_inits) + +void smt_init_evc(struct s_smc *smc) +{ + struct s_srf_evc *evc ; + const struct evc_init *init ; + int i ; + int index ; + int offset ; + + static u_char fail_safe = FALSE ; + + memset((char *)smc->evcs,0,sizeof(smc->evcs)) ; + + evc = smc->evcs ; + init = evc_inits ; + + for (i = 0 ; (unsigned) i < MAX_INIT_EVC ; i++) { + for (index = 0 ; index < init->n ; index++) { + evc->evc_code = init->code ; + evc->evc_para = init->para ; + evc->evc_index = init->index + index ; +#ifndef DEBUG + evc->evc_multiple = &fail_safe ; + evc->evc_cond_state = &fail_safe ; +#endif + evc++ ; + } + init++ ; + } + + if ((unsigned) (evc - smc->evcs) > MAX_EVCS) { + SMT_PANIC(smc,SMT_E0127, SMT_E0127_MSG) ; + } + + /* + * conditions + */ + smc->evcs[0].evc_cond_state = &smc->mib.fddiSMTPeerWrapFlag ; + smc->evcs[1].evc_cond_state = + &smc->mib.m[MAC0].fddiMACDuplicateAddressCond ; + smc->evcs[2].evc_cond_state = + &smc->mib.m[MAC0].fddiMACFrameErrorFlag ; + smc->evcs[3].evc_cond_state = + &smc->mib.m[MAC0].fddiMACNotCopiedFlag ; + + /* + * events + */ + smc->evcs[4].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_N ; + smc->evcs[5].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_P ; + + offset = 6 ; + for (i = 0 ; i < NUMPHYS ; i++) { + /* + * conditions + */ + smc->evcs[offset + 0*NUMPHYS].evc_cond_state = + &smc->mib.p[i].fddiPORTLerFlag ; + smc->evcs[offset + 1*NUMPHYS].evc_cond_state = + &smc->mib.p[i].fddiPORTEB_Condition ; + + /* + * events + */ + smc->evcs[offset + 2*NUMPHYS].evc_multiple = + &smc->mib.p[i].fddiPORTMultiple_U ; + smc->evcs[offset + 3*NUMPHYS].evc_multiple = + &smc->mib.p[i].fddiPORTMultiple_P ; + offset++ ; + } +#ifdef DEBUG + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + if (SMT_IS_CONDITION(evc->evc_code)) { + if (!evc->evc_cond_state) { + SMT_PANIC(smc,SMT_E0128, SMT_E0128_MSG) ; + } + evc->evc_multiple = &fail_safe ; + } + else { + if (!evc->evc_multiple) { + SMT_PANIC(smc,SMT_E0129, SMT_E0129_MSG) ; + } + evc->evc_cond_state = &fail_safe ; + } + } +#endif + smc->srf.TSR = smt_get_time() ; + smc->srf.sr_state = SR0_WAIT ; +} + +static struct s_srf_evc *smt_get_evc(struct s_smc *smc, int code, int index) +{ + int i ; + struct s_srf_evc *evc ; + + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + if (evc->evc_code == code && evc->evc_index == index) + return evc; + } + return NULL; +} + +#define THRESHOLD_2 (2*TICKS_PER_SECOND) +#define THRESHOLD_32 (32*TICKS_PER_SECOND) + +#ifdef DEBUG +static const char * const srf_names[] = { + "None","MACPathChangeEvent", "MACNeighborChangeEvent", + "PORTPathChangeEvent", "PORTUndesiredConnectionAttemptEvent", + "SMTPeerWrapCondition", "SMTHoldCondition", + "MACFrameErrorCondition", "MACDuplicateAddressCondition", + "MACNotCopiedCondition", "PORTEBErrorCondition", + "PORTLerCondition" +} ; +#endif + +void smt_srf_event(struct s_smc *smc, int code, int index, int cond) +{ + struct s_srf_evc *evc ; + int cond_asserted = 0 ; + int cond_deasserted = 0 ; + int event_occurred = 0 ; + int tsr ; + int T_Limit = 2*TICKS_PER_SECOND ; + + if (code == SMT_COND_MAC_DUP_ADDR && cond) { + RS_SET(smc,RS_DUPADDR) ; + } + + if (code) { + DB_SMT("SRF: %s index %d\n",srf_names[code],index) ; + + if (!(evc = smt_get_evc(smc,code,index))) { + DB_SMT("SRF : smt_get_evc() failed\n",0,0) ; + return ; + } + /* + * ignore condition if no change + */ + if (SMT_IS_CONDITION(code)) { + if (*evc->evc_cond_state == cond) + return ; + } + + /* + * set transition time stamp + */ + smt_set_timestamp(smc,smc->mib.fddiSMTTransitionTimeStamp) ; + if (SMT_IS_CONDITION(code)) { + DB_SMT("SRF: condition is %s\n",cond ? "ON":"OFF",0) ; + if (cond) { + *evc->evc_cond_state = TRUE ; + evc->evc_rep_required = TRUE ; + smc->srf.any_report = TRUE ; + cond_asserted = TRUE ; + } + else { + *evc->evc_cond_state = FALSE ; + cond_deasserted = TRUE ; + } + } + else { + if (evc->evc_rep_required) { + *evc->evc_multiple = TRUE ; + } + else { + evc->evc_rep_required = TRUE ; + *evc->evc_multiple = FALSE ; + } + smc->srf.any_report = TRUE ; + event_occurred = TRUE ; + } +#ifdef FDDI_MIB + snmp_srf_event(smc,evc) ; +#endif /* FDDI_MIB */ + } + tsr = smt_get_time() - smc->srf.TSR ; + + switch (smc->srf.sr_state) { + case SR0_WAIT : + /* SR01a */ + if (cond_asserted && tsr < T_Limit) { + smc->srf.SRThreshold = THRESHOLD_2 ; + smc->srf.sr_state = SR1_HOLDOFF ; + break ; + } + /* SR01b */ + if (cond_deasserted && tsr < T_Limit) { + smc->srf.sr_state = SR1_HOLDOFF ; + break ; + } + /* SR01c */ + if (event_occurred && tsr < T_Limit) { + smc->srf.sr_state = SR1_HOLDOFF ; + break ; + } + /* SR00b */ + if (cond_asserted && tsr >= T_Limit) { + smc->srf.SRThreshold = THRESHOLD_2 ; + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR00c */ + if (cond_deasserted && tsr >= T_Limit) { + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR00d */ + if (event_occurred && tsr >= T_Limit) { + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR00e */ + if (smc->srf.any_report && (u_long) tsr >= + smc->srf.SRThreshold) { + smc->srf.SRThreshold *= 2 ; + if (smc->srf.SRThreshold > THRESHOLD_32) + smc->srf.SRThreshold = THRESHOLD_32 ; + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR02 */ + if (!smc->mib.fddiSMTStatRptPolicy) { + smc->srf.sr_state = SR2_DISABLED ; + break ; + } + break ; + case SR1_HOLDOFF : + /* SR10b */ + if (tsr >= T_Limit) { + smc->srf.sr_state = SR0_WAIT ; + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR11a */ + if (cond_asserted) { + smc->srf.SRThreshold = THRESHOLD_2 ; + } + /* SR11b */ + /* SR11c */ + /* handled above */ + /* SR12 */ + if (!smc->mib.fddiSMTStatRptPolicy) { + smc->srf.sr_state = SR2_DISABLED ; + break ; + } + break ; + case SR2_DISABLED : + if (smc->mib.fddiSMTStatRptPolicy) { + smc->srf.sr_state = SR0_WAIT ; + smc->srf.TSR = smt_get_time() ; + smc->srf.SRThreshold = THRESHOLD_2 ; + clear_all_rep(smc) ; + break ; + } + break ; + } +} + +static void clear_all_rep(struct s_smc *smc) +{ + struct s_srf_evc *evc ; + int i ; + + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + evc->evc_rep_required = FALSE ; + if (SMT_IS_CONDITION(evc->evc_code)) + *evc->evc_cond_state = FALSE ; + } + smc->srf.any_report = FALSE ; +} + +static void clear_reported(struct s_smc *smc) +{ + struct s_srf_evc *evc ; + int i ; + + smc->srf.any_report = FALSE ; + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + if (SMT_IS_CONDITION(evc->evc_code)) { + if (*evc->evc_cond_state == FALSE) + evc->evc_rep_required = FALSE ; + else + smc->srf.any_report = TRUE ; + } + else { + evc->evc_rep_required = FALSE ; + *evc->evc_multiple = FALSE ; + } + } +} + +/* + * build and send SMT SRF frame + */ +static void smt_send_srf(struct s_smc *smc) +{ + + struct smt_header *smt ; + struct s_srf_evc *evc ; + SK_LOC_DECL(struct s_pcon,pcon) ; + SMbuf *mb ; + int i ; + + static const struct fddi_addr SMT_SRF_DA = { + { 0x80, 0x01, 0x43, 0x00, 0x80, 0x08 } + } ; + + /* + * build SMT header + */ + if (!smc->r.sm_ma_avail) + return ; + if (!(mb = smt_build_frame(smc,SMT_SRF,SMT_ANNOUNCE,0))) + return ; + + RS_SET(smc,RS_SOFTERROR) ; + + smt = smtod(mb, struct smt_header *) ; + smt->smt_dest = SMT_SRF_DA ; /* DA == SRF multicast */ + + /* + * setup parameter status + */ + pcon.pc_len = SMT_MAX_INFO_LEN ; /* max para length */ + pcon.pc_err = 0 ; /* no error */ + pcon.pc_badset = 0 ; /* no bad set count */ + pcon.pc_p = (void *) (smt + 1) ; /* paras start here */ + + smt_add_para(smc,&pcon,(u_short) SMT_P1033,0,0) ; + smt_add_para(smc,&pcon,(u_short) SMT_P1034,0,0) ; + + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + if (evc->evc_rep_required) { + smt_add_para(smc,&pcon,evc->evc_para, + (int)evc->evc_index,0) ; + } + } + smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ; + mb->sm_len = smt->smt_len + sizeof(struct smt_header) ; + + DB_SMT("SRF: sending SRF at %x, len %d\n",smt,mb->sm_len) ; + DB_SMT("SRF: state SR%d Threshold %d\n", + smc->srf.sr_state,smc->srf.SRThreshold/TICKS_PER_SECOND) ; +#ifdef DEBUG + dump_smt(smc,smt,"SRF Send") ; +#endif + smt_send_frame(smc,mb,FC_SMT_INFO,0) ; + clear_reported(smc) ; +} + +#endif /* no BOOT */ +#endif /* no SLIM_SMT */ + diff --git a/drivers/net/skfp/Makefile b/drivers/net/skfp/Makefile deleted file mode 100644 index b0be023..0000000 --- a/drivers/net/skfp/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# -# Makefile for the SysKonnect FDDI PCI adapter driver -# - -obj-$(CONFIG_SKFP) += skfp.o - -skfp-objs := skfddi.o hwmtm.o fplustm.o smt.o cfm.o \ - ecm.o pcmplc.o pmf.o queue.o rmt.o \ - smtdef.o smtinit.o smttimer.o srf.o hwt.o \ - drvfbi.o ess.o - -# NOTE: -# Compiling this driver produces some warnings (and some more are -# switched off below), but I did not fix this, because the Hardware -# Module source (see skfddi.c for details) is used for different -# drivers, and fixing it for Linux might bring problems on other -# projects. To keep the source common for all those drivers (and -# thus simplify fixes to it), please do not clean it up! - -ccflags-y := -Idrivers/net/skfp -DPCI -DMEM_MAPPED_IO -Wno-strict-prototypes diff --git a/drivers/net/skfp/cfm.c b/drivers/net/skfp/cfm.c deleted file mode 100644 index e395ace..0000000 --- a/drivers/net/skfp/cfm.c +++ /dev/null @@ -1,627 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - SMT CFM - Configuration Management - DAS with single MAC -*/ - -/* - * Hardware independent state machine implemantation - * The following external SMT functions are referenced : - * - * queue_event() - * - * The following external HW dependent functions are referenced : - * config_mux() - * - * The following HW dependent events are required : - * NONE - */ - -#include "h/types.h" -#include "h/fddi.h" -#include "h/smc.h" - -#define KERNEL -#include "h/smtstate.h" - -#ifndef lint -static const char ID_sccs[] = "@(#)cfm.c 2.18 98/10/06 (C) SK " ; -#endif - -/* - * FSM Macros - */ -#define AFLAG 0x10 -#define GO_STATE(x) (smc->mib.fddiSMTCF_State = (x)|AFLAG) -#define ACTIONS_DONE() (smc->mib.fddiSMTCF_State &= ~AFLAG) -#define ACTIONS(x) (x|AFLAG) - -#ifdef DEBUG -/* - * symbolic state names - */ -static const char * const cfm_states[] = { - "SC0_ISOLATED","CF1","CF2","CF3","CF4", - "SC1_WRAP_A","SC2_WRAP_B","SC5_TRHU_B","SC7_WRAP_S", - "SC9_C_WRAP_A","SC10_C_WRAP_B","SC11_C_WRAP_S","SC4_THRU_A" -} ; - -/* - * symbolic event names - */ -static const char * const cfm_events[] = { - "NONE","CF_LOOP_A","CF_LOOP_B","CF_JOIN_A","CF_JOIN_B" -} ; -#endif - -/* - * map from state to downstream port type - */ -static const unsigned char cf_to_ptype[] = { - TNONE,TNONE,TNONE,TNONE,TNONE, - TNONE,TB,TB,TS, - TA,TB,TS,TB -} ; - -/* - * CEM port states - */ -#define CEM_PST_DOWN 0 -#define CEM_PST_UP 1 -#define CEM_PST_HOLD 2 -/* define portstate array only for A and B port */ -/* Do this within the smc structure (use in multiple cards) */ - -/* - * all Globals are defined in smc.h - * struct s_cfm - */ - -/* - * function declarations - */ -static void cfm_fsm(struct s_smc *smc, int cmd); - -/* - init CFM state machine - clear all CFM vars and flags -*/ -void cfm_init(struct s_smc *smc) -{ - smc->mib.fddiSMTCF_State = ACTIONS(SC0_ISOLATED) ; - smc->r.rm_join = 0 ; - smc->r.rm_loop = 0 ; - smc->y[PA].scrub = 0 ; - smc->y[PB].scrub = 0 ; - smc->y[PA].cem_pst = CEM_PST_DOWN ; - smc->y[PB].cem_pst = CEM_PST_DOWN ; -} - -/* Some terms conditions used by the selection criteria */ -#define THRU_ENABLED(smc) (smc->y[PA].pc_mode != PM_TREE && \ - smc->y[PB].pc_mode != PM_TREE) -/* Selection criteria for the ports */ -static void selection_criteria (struct s_smc *smc, struct s_phy *phy) -{ - - switch (phy->mib->fddiPORTMy_Type) { - case TA: - if ( !THRU_ENABLED(smc) && smc->y[PB].cf_join ) { - phy->wc_flag = TRUE ; - } else { - phy->wc_flag = FALSE ; - } - - break; - case TB: - /* take precedence over PA */ - phy->wc_flag = FALSE ; - break; - case TS: - phy->wc_flag = FALSE ; - break; - case TM: - phy->wc_flag = FALSE ; - break; - } - -} - -void all_selection_criteria(struct s_smc *smc) -{ - struct s_phy *phy ; - int p ; - - for ( p = 0,phy = smc->y ; p < NUMPHYS; p++, phy++ ) { - /* Do the selection criteria */ - selection_criteria (smc,phy); - } -} - -static void cem_priv_state(struct s_smc *smc, int event) -/* State machine for private PORT states: used to optimize dual homing */ -{ - int np; /* Number of the port */ - int i; - - /* Do this only in a DAS */ - if (smc->s.sas != SMT_DAS ) - return ; - - np = event - CF_JOIN; - - if (np != PA && np != PB) { - return ; - } - /* Change the port state according to the event (portnumber) */ - if (smc->y[np].cf_join) { - smc->y[np].cem_pst = CEM_PST_UP ; - } else if (!smc->y[np].wc_flag) { - /* set the port to done only if it is not withheld */ - smc->y[np].cem_pst = CEM_PST_DOWN ; - } - - /* Don't set an hold port to down */ - - /* Check all ports of restart conditions */ - for (i = 0 ; i < 2 ; i ++ ) { - /* Check all port for PORT is on hold and no withhold is done */ - if ( smc->y[i].cem_pst == CEM_PST_HOLD && !smc->y[i].wc_flag ) { - smc->y[i].cem_pst = CEM_PST_DOWN; - queue_event(smc,(int)(EVENT_PCM+i),PC_START) ; - } - if ( smc->y[i].cem_pst == CEM_PST_UP && smc->y[i].wc_flag ) { - smc->y[i].cem_pst = CEM_PST_HOLD; - queue_event(smc,(int)(EVENT_PCM+i),PC_START) ; - } - if ( smc->y[i].cem_pst == CEM_PST_DOWN && smc->y[i].wc_flag ) { - /* - * The port must be restarted when the wc_flag - * will be reset. So set the port on hold. - */ - smc->y[i].cem_pst = CEM_PST_HOLD; - } - } - return ; -} - -/* - CFM state machine - called by dispatcher - - do - display state change - process event - until SM is stable -*/ -void cfm(struct s_smc *smc, int event) -{ - int state ; /* remember last state */ - int cond ; - int oldstate ; - - /* We will do the following: */ - /* - compute the variable WC_Flag for every port (This is where */ - /* we can extend the requested path checking !!) */ - /* - do the old (SMT 6.2 like) state machine */ - /* - do the resulting station states */ - - all_selection_criteria (smc); - - /* We will check now whether a state transition is allowed or not */ - /* - change the portstates */ - cem_priv_state (smc, event); - - oldstate = smc->mib.fddiSMTCF_State ; - do { - DB_CFM("CFM : state %s%s", - (smc->mib.fddiSMTCF_State & AFLAG) ? "ACTIONS " : "", - cfm_states[smc->mib.fddiSMTCF_State & ~AFLAG]) ; - DB_CFM(" event %s\n",cfm_events[event],0) ; - state = smc->mib.fddiSMTCF_State ; - cfm_fsm(smc,event) ; - event = 0 ; - } while (state != smc->mib.fddiSMTCF_State) ; - -#ifndef SLIM_SMT - /* - * check peer wrap condition - */ - cond = FALSE ; - if ( (smc->mib.fddiSMTCF_State == SC9_C_WRAP_A && - smc->y[PA].pc_mode == PM_PEER) || - (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B && - smc->y[PB].pc_mode == PM_PEER) || - (smc->mib.fddiSMTCF_State == SC11_C_WRAP_S && - smc->y[PS].pc_mode == PM_PEER && - smc->y[PS].mib->fddiPORTNeighborType != TS ) ) { - cond = TRUE ; - } - if (cond != smc->mib.fddiSMTPeerWrapFlag) - smt_srf_event(smc,SMT_COND_SMT_PEER_WRAP,0,cond) ; - -#if 0 - /* - * Don't send ever MAC_PATH_CHANGE events. Our MAC is hard-wired - * to the primary path. - */ - /* - * path change - */ - if (smc->mib.fddiSMTCF_State != oldstate) { - smt_srf_event(smc,SMT_EVENT_MAC_PATH_CHANGE,INDEX_MAC,0) ; - } -#endif -#endif /* no SLIM_SMT */ - - /* - * set MAC port type - */ - smc->mib.m[MAC0].fddiMACDownstreamPORTType = - cf_to_ptype[smc->mib.fddiSMTCF_State] ; - cfm_state_change(smc,(int)smc->mib.fddiSMTCF_State) ; -} - -/* - process CFM event -*/ -/*ARGSUSED1*/ -static void cfm_fsm(struct s_smc *smc, int cmd) -{ - switch(smc->mib.fddiSMTCF_State) { - case ACTIONS(SC0_ISOLATED) : - smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; - smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; - smc->mib.p[PA].fddiPORTMACPlacement = 0 ; - smc->mib.p[PB].fddiPORTMACPlacement = 0 ; - smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ; - config_mux(smc,MUX_ISOLATE) ; /* configure PHY Mux */ - smc->r.rm_loop = FALSE ; - smc->r.rm_join = FALSE ; - queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ - /* Don't do the WC-Flag changing here */ - ACTIONS_DONE() ; - DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; - break; - case SC0_ISOLATED : - /*SC07*/ - /*SAS port can be PA or PB ! */ - if (smc->s.sas && (smc->y[PA].cf_join || smc->y[PA].cf_loop || - smc->y[PB].cf_join || smc->y[PB].cf_loop)) { - GO_STATE(SC11_C_WRAP_S) ; - break ; - } - /*SC01*/ - if ((smc->y[PA].cem_pst == CEM_PST_UP && smc->y[PA].cf_join && - !smc->y[PA].wc_flag) || smc->y[PA].cf_loop) { - GO_STATE(SC9_C_WRAP_A) ; - break ; - } - /*SC02*/ - if ((smc->y[PB].cem_pst == CEM_PST_UP && smc->y[PB].cf_join && - !smc->y[PB].wc_flag) || smc->y[PB].cf_loop) { - GO_STATE(SC10_C_WRAP_B) ; - break ; - } - break ; - case ACTIONS(SC9_C_WRAP_A) : - smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ; - smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; - smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ; - smc->mib.p[PB].fddiPORTMACPlacement = 0 ; - smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ; - config_mux(smc,MUX_WRAPA) ; /* configure PHY mux */ - if (smc->y[PA].cf_loop) { - smc->r.rm_join = FALSE ; - smc->r.rm_loop = TRUE ; - queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */ - } - if (smc->y[PA].cf_join) { - smc->r.rm_loop = FALSE ; - smc->r.rm_join = TRUE ; - queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ - } - ACTIONS_DONE() ; - DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; - break ; - case SC9_C_WRAP_A : - /*SC10*/ - if ( (smc->y[PA].wc_flag || !smc->y[PA].cf_join) && - !smc->y[PA].cf_loop ) { - GO_STATE(SC0_ISOLATED) ; - break ; - } - /*SC12*/ - else if ( (smc->y[PB].cf_loop && smc->y[PA].cf_join && - smc->y[PA].cem_pst == CEM_PST_UP) || - ((smc->y[PB].cf_loop || - (smc->y[PB].cf_join && - smc->y[PB].cem_pst == CEM_PST_UP)) && - (smc->y[PA].pc_mode == PM_TREE || - smc->y[PB].pc_mode == PM_TREE))) { - smc->y[PA].scrub = TRUE ; - GO_STATE(SC10_C_WRAP_B) ; - break ; - } - /*SC14*/ - else if (!smc->s.attach_s && - smc->y[PA].cf_join && - smc->y[PA].cem_pst == CEM_PST_UP && - smc->y[PA].pc_mode == PM_PEER && smc->y[PB].cf_join && - smc->y[PB].cem_pst == CEM_PST_UP && - smc->y[PB].pc_mode == PM_PEER) { - smc->y[PA].scrub = TRUE ; - smc->y[PB].scrub = TRUE ; - GO_STATE(SC4_THRU_A) ; - break ; - } - /*SC15*/ - else if ( smc->s.attach_s && - smc->y[PA].cf_join && - smc->y[PA].cem_pst == CEM_PST_UP && - smc->y[PA].pc_mode == PM_PEER && - smc->y[PB].cf_join && - smc->y[PB].cem_pst == CEM_PST_UP && - smc->y[PB].pc_mode == PM_PEER) { - smc->y[PA].scrub = TRUE ; - smc->y[PB].scrub = TRUE ; - GO_STATE(SC5_THRU_B) ; - break ; - } - break ; - case ACTIONS(SC10_C_WRAP_B) : - smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; - smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ; - smc->mib.p[PA].fddiPORTMACPlacement = 0 ; - smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ; - smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ; - config_mux(smc,MUX_WRAPB) ; /* configure PHY mux */ - if (smc->y[PB].cf_loop) { - smc->r.rm_join = FALSE ; - smc->r.rm_loop = TRUE ; - queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */ - } - if (smc->y[PB].cf_join) { - smc->r.rm_loop = FALSE ; - smc->r.rm_join = TRUE ; - queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ - } - ACTIONS_DONE() ; - DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; - break ; - case SC10_C_WRAP_B : - /*SC20*/ - if ( !smc->y[PB].cf_join && !smc->y[PB].cf_loop ) { - GO_STATE(SC0_ISOLATED) ; - break ; - } - /*SC21*/ - else if ( smc->y[PA].cf_loop && smc->y[PA].pc_mode == PM_PEER && - smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) { - smc->y[PB].scrub = TRUE ; - GO_STATE(SC9_C_WRAP_A) ; - break ; - } - /*SC24*/ - else if (!smc->s.attach_s && - smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER && - smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) { - smc->y[PA].scrub = TRUE ; - smc->y[PB].scrub = TRUE ; - GO_STATE(SC4_THRU_A) ; - break ; - } - /*SC25*/ - else if ( smc->s.attach_s && - smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER && - smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) { - smc->y[PA].scrub = TRUE ; - smc->y[PB].scrub = TRUE ; - GO_STATE(SC5_THRU_B) ; - break ; - } - break ; - case ACTIONS(SC4_THRU_A) : - smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ; - smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ; - smc->mib.p[PA].fddiPORTMACPlacement = 0 ; - smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ; - smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ; - config_mux(smc,MUX_THRUA) ; /* configure PHY mux */ - smc->r.rm_loop = FALSE ; - smc->r.rm_join = TRUE ; - queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ - ACTIONS_DONE() ; - DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; - break ; - case SC4_THRU_A : - /*SC41*/ - if (smc->y[PB].wc_flag || !smc->y[PB].cf_join) { - smc->y[PA].scrub = TRUE ; - GO_STATE(SC9_C_WRAP_A) ; - break ; - } - /*SC42*/ - else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) { - smc->y[PB].scrub = TRUE ; - GO_STATE(SC10_C_WRAP_B) ; - break ; - } - /*SC45*/ - else if (smc->s.attach_s) { - smc->y[PB].scrub = TRUE ; - GO_STATE(SC5_THRU_B) ; - break ; - } - break ; - case ACTIONS(SC5_THRU_B) : - smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ; - smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ; - smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ; - smc->mib.p[PB].fddiPORTMACPlacement = 0 ; - smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ; - config_mux(smc,MUX_THRUB) ; /* configure PHY mux */ - smc->r.rm_loop = FALSE ; - smc->r.rm_join = TRUE ; - queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ - ACTIONS_DONE() ; - DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; - break ; - case SC5_THRU_B : - /*SC51*/ - if (!smc->y[PB].cf_join || smc->y[PB].wc_flag) { - smc->y[PA].scrub = TRUE ; - GO_STATE(SC9_C_WRAP_A) ; - break ; - } - /*SC52*/ - else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) { - smc->y[PB].scrub = TRUE ; - GO_STATE(SC10_C_WRAP_B) ; - break ; - } - /*SC54*/ - else if (!smc->s.attach_s) { - smc->y[PA].scrub = TRUE ; - GO_STATE(SC4_THRU_A) ; - break ; - } - break ; - case ACTIONS(SC11_C_WRAP_S) : - smc->mib.p[PS].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ; - smc->mib.p[PS].fddiPORTMACPlacement = INDEX_MAC ; - smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ; - config_mux(smc,MUX_WRAPS) ; /* configure PHY mux */ - if (smc->y[PA].cf_loop || smc->y[PB].cf_loop) { - smc->r.rm_join = FALSE ; - smc->r.rm_loop = TRUE ; - queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */ - } - if (smc->y[PA].cf_join || smc->y[PB].cf_join) { - smc->r.rm_loop = FALSE ; - smc->r.rm_join = TRUE ; - queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ - } - ACTIONS_DONE() ; - DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; - break ; - case SC11_C_WRAP_S : - /*SC70*/ - if ( !smc->y[PA].cf_join && !smc->y[PA].cf_loop && - !smc->y[PB].cf_join && !smc->y[PB].cf_loop) { - GO_STATE(SC0_ISOLATED) ; - break ; - } - break ; - default: - SMT_PANIC(smc,SMT_E0106, SMT_E0106_MSG) ; - break; - } -} - -/* - * get MAC's input Port - * return : - * PA or PB - */ -int cfm_get_mac_input(struct s_smc *smc) -{ - return (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B || - smc->mib.fddiSMTCF_State == SC5_THRU_B) ? PB : PA; -} - -/* - * get MAC's output Port - * return : - * PA or PB - */ -int cfm_get_mac_output(struct s_smc *smc) -{ - return (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B || - smc->mib.fddiSMTCF_State == SC4_THRU_A) ? PB : PA; -} - -static char path_iso[] = { - 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_ISO, - 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_ISO, - 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_ISO -} ; - -static char path_wrap_a[] = { - 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_PRIM, - 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM, - 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_ISO -} ; - -static char path_wrap_b[] = { - 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_PRIM, - 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM, - 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_ISO -} ; - -static char path_thru[] = { - 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_PRIM, - 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM, - 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_PRIM -} ; - -static char path_wrap_s[] = { - 0,0, 0,RES_PORT, 0,PS + INDEX_PORT, 0,PATH_PRIM, - 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM, -} ; - -static char path_iso_s[] = { - 0,0, 0,RES_PORT, 0,PS + INDEX_PORT, 0,PATH_ISO, - 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_ISO, -} ; - -int cem_build_path(struct s_smc *smc, char *to, int path_index) -{ - char *path ; - int len ; - - switch (smc->mib.fddiSMTCF_State) { - default : - case SC0_ISOLATED : - path = smc->s.sas ? path_iso_s : path_iso ; - len = smc->s.sas ? sizeof(path_iso_s) : sizeof(path_iso) ; - break ; - case SC9_C_WRAP_A : - path = path_wrap_a ; - len = sizeof(path_wrap_a) ; - break ; - case SC10_C_WRAP_B : - path = path_wrap_b ; - len = sizeof(path_wrap_b) ; - break ; - case SC4_THRU_A : - path = path_thru ; - len = sizeof(path_thru) ; - break ; - case SC11_C_WRAP_S : - path = path_wrap_s ; - len = sizeof(path_wrap_s) ; - break ; - } - memcpy(to,path,len) ; - - LINT_USE(path_index); - - return len; -} diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c deleted file mode 100644 index 07da97c..0000000 --- a/drivers/net/skfp/drvfbi.c +++ /dev/null @@ -1,584 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - * FBI board dependent Driver for SMT and LLC - */ - -#include "h/types.h" -#include "h/fddi.h" -#include "h/smc.h" -#include "h/supern_2.h" -#include "h/skfbiinc.h" -#include - -#ifndef lint -static const char ID_sccs[] = "@(#)drvfbi.c 1.63 99/02/11 (C) SK " ; -#endif - -/* - * PCM active state - */ -#define PC8_ACTIVE 8 - -#define LED_Y_ON 0x11 /* Used for ring up/down indication */ -#define LED_Y_OFF 0x10 - - -#define MS2BCLK(x) ((x)*12500L) - -/* - * valid configuration values are: - */ - -/* - * xPOS_ID:xxxx - * | \ / - * | \/ - * | --------------------- the patched POS_ID of the Adapter - * | xxxx = (Vendor ID low byte, - * | Vendor ID high byte, - * | Device ID low byte, - * | Device ID high byte) - * +------------------------------ the patched oem_id must be - * 'S' for SK or 'I' for IBM - * this is a short id for the driver. - */ -#ifndef MULT_OEM -#ifndef OEM_CONCEPT -const u_char oem_id[] = "xPOS_ID:xxxx" ; -#else /* OEM_CONCEPT */ -const u_char oem_id[] = OEM_ID ; -#endif /* OEM_CONCEPT */ -#define ID_BYTE0 8 -#define OEMID(smc,i) oem_id[ID_BYTE0 + i] -#else /* MULT_OEM */ -const struct s_oem_ids oem_ids[] = { -#include "oemids.h" -{0} -}; -#define OEMID(smc,i) smc->hw.oem_id->oi_id[i] -#endif /* MULT_OEM */ - -/* Prototypes of external functions */ -#ifdef AIX -extern int AIX_vpdReadByte() ; -#endif - - -/* Prototype of a local function. */ -static void smt_stop_watchdog(struct s_smc *smc); - -/* - * FDDI card reset - */ -static void card_start(struct s_smc *smc) -{ - int i ; -#ifdef PCI - u_char rev_id ; - u_short word; -#endif - - smt_stop_watchdog(smc) ; - -#ifdef PCI - /* - * make sure no transfer activity is pending - */ - outpw(FM_A(FM_MDREG1),FM_MINIT) ; - outp(ADDR(B0_CTRL), CTRL_HPI_SET) ; - hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ; - /* - * now reset everything - */ - outp(ADDR(B0_CTRL),CTRL_RST_SET) ; /* reset for all chips */ - i = (int) inp(ADDR(B0_CTRL)) ; /* do dummy read */ - SK_UNUSED(i) ; /* Make LINT happy. */ - outp(ADDR(B0_CTRL), CTRL_RST_CLR) ; - - /* - * Reset all bits in the PCI STATUS register - */ - outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_ON) ; /* enable for writes */ - word = inpw(PCI_C(PCI_STATUS)) ; - outpw(PCI_C(PCI_STATUS), word | PCI_ERRBITS) ; - outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_OFF) ; /* disable writes */ - - /* - * Release the reset of all the State machines - * Release Master_Reset - * Release HPI_SM_Reset - */ - outp(ADDR(B0_CTRL), CTRL_MRST_CLR|CTRL_HPI_CLR) ; - - /* - * determine the adapter type - * Note: Do it here, because some drivers may call card_start() once - * at very first before any other initialization functions is - * executed. - */ - rev_id = inp(PCI_C(PCI_REV_ID)) ; - if ((rev_id & 0xf0) == SK_ML_ID_1 || (rev_id & 0xf0) == SK_ML_ID_2) { - smc->hw.hw_is_64bit = TRUE ; - } else { - smc->hw.hw_is_64bit = FALSE ; - } - - /* - * Watermark initialization - */ - if (!smc->hw.hw_is_64bit) { - outpd(ADDR(B4_R1_F), RX_WATERMARK) ; - outpd(ADDR(B5_XA_F), TX_WATERMARK) ; - outpd(ADDR(B5_XS_F), TX_WATERMARK) ; - } - - outp(ADDR(B0_CTRL),CTRL_RST_CLR) ; /* clear the reset chips */ - outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_ON|LED_GB_OFF) ; /* ye LED on */ - - /* init the timer value for the watch dog 2,5 minutes */ - outpd(ADDR(B2_WDOG_INI),0x6FC23AC0) ; - - /* initialize the ISR mask */ - smc->hw.is_imask = ISR_MASK ; - smc->hw.hw_state = STOPPED ; -#endif - GET_PAGE(0) ; /* necessary for BOOT */ -} - -void card_stop(struct s_smc *smc) -{ - smt_stop_watchdog(smc) ; - smc->hw.mac_ring_is_up = 0 ; /* ring down */ - -#ifdef PCI - /* - * make sure no transfer activity is pending - */ - outpw(FM_A(FM_MDREG1),FM_MINIT) ; - outp(ADDR(B0_CTRL), CTRL_HPI_SET) ; - hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ; - /* - * now reset everything - */ - outp(ADDR(B0_CTRL),CTRL_RST_SET) ; /* reset for all chips */ - outp(ADDR(B0_CTRL),CTRL_RST_CLR) ; /* reset for all chips */ - outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_OFF|LED_GB_OFF) ; /* all LEDs off */ - smc->hw.hw_state = STOPPED ; -#endif -} -/*--------------------------- ISR handling ----------------------------------*/ - -void mac1_irq(struct s_smc *smc, u_short stu, u_short stl) -{ - int restart_tx = 0 ; -again: - - /* - * parity error: note encoding error is not possible in tag mode - */ - if (stl & (FM_SPCEPDS | /* parity err. syn.q.*/ - FM_SPCEPDA0 | /* parity err. a.q.0 */ - FM_SPCEPDA1)) { /* parity err. a.q.1 */ - SMT_PANIC(smc,SMT_E0134, SMT_E0134_MSG) ; - } - /* - * buffer underrun: can only occur if a tx threshold is specified - */ - if (stl & (FM_STBURS | /* tx buffer underrun syn.q.*/ - FM_STBURA0 | /* tx buffer underrun a.q.0 */ - FM_STBURA1)) { /* tx buffer underrun a.q.2 */ - SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ; - } - - if ( (stu & (FM_SXMTABT | /* transmit abort */ - FM_STXABRS | /* syn. tx abort */ - FM_STXABRA0)) || /* asyn. tx abort */ - (stl & (FM_SQLCKS | /* lock for syn. q. */ - FM_SQLCKA0)) ) { /* lock for asyn. q. */ - formac_tx_restart(smc) ; /* init tx */ - restart_tx = 1 ; - stu = inpw(FM_A(FM_ST1U)) ; - stl = inpw(FM_A(FM_ST1L)) ; - stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ; - if (stu || stl) - goto again ; - } - - if (stu & (FM_STEFRMA0 | /* end of asyn tx */ - FM_STEFRMS)) { /* end of sync tx */ - restart_tx = 1 ; - } - - if (restart_tx) - llc_restart_tx(smc) ; -} - -/* - * interrupt source= plc1 - * this function is called in nwfbisr.asm - */ -void plc1_irq(struct s_smc *smc) -{ - u_short st = inpw(PLC(PB,PL_INTR_EVENT)) ; - - plc_irq(smc,PB,st) ; -} - -/* - * interrupt source= plc2 - * this function is called in nwfbisr.asm - */ -void plc2_irq(struct s_smc *smc) -{ - u_short st = inpw(PLC(PA,PL_INTR_EVENT)) ; - - plc_irq(smc,PA,st) ; -} - - -/* - * interrupt source= timer - */ -void timer_irq(struct s_smc *smc) -{ - hwt_restart(smc); - smc->hw.t_stop = smc->hw.t_start; - smt_timer_done(smc) ; -} - -/* - * return S-port (PA or PB) - */ -int pcm_get_s_port(struct s_smc *smc) -{ - SK_UNUSED(smc) ; - return PS; -} - -/* - * Station Label = "FDDI-XYZ" where - * - * X = connector type - * Y = PMD type - * Z = port type - */ -#define STATION_LABEL_CONNECTOR_OFFSET 5 -#define STATION_LABEL_PMD_OFFSET 6 -#define STATION_LABEL_PORT_OFFSET 7 - -void read_address(struct s_smc *smc, u_char *mac_addr) -{ - char ConnectorType ; - char PmdType ; - int i ; - -#ifdef PCI - for (i = 0; i < 6; i++) { /* read mac address from board */ - smc->hw.fddi_phys_addr.a[i] = - bitrev8(inp(ADDR(B2_MAC_0+i))); - } -#endif - - ConnectorType = inp(ADDR(B2_CONN_TYP)) ; - PmdType = inp(ADDR(B2_PMD_TYP)) ; - - smc->y[PA].pmd_type[PMD_SK_CONN] = - smc->y[PB].pmd_type[PMD_SK_CONN] = ConnectorType ; - smc->y[PA].pmd_type[PMD_SK_PMD ] = - smc->y[PB].pmd_type[PMD_SK_PMD ] = PmdType ; - - if (mac_addr) { - for (i = 0; i < 6 ;i++) { - smc->hw.fddi_canon_addr.a[i] = mac_addr[i] ; - smc->hw.fddi_home_addr.a[i] = bitrev8(mac_addr[i]); - } - return ; - } - smc->hw.fddi_home_addr = smc->hw.fddi_phys_addr ; - - for (i = 0; i < 6 ;i++) { - smc->hw.fddi_canon_addr.a[i] = - bitrev8(smc->hw.fddi_phys_addr.a[i]); - } -} - -/* - * FDDI card soft reset - */ -void init_board(struct s_smc *smc, u_char *mac_addr) -{ - card_start(smc) ; - read_address(smc,mac_addr) ; - - if (!(inp(ADDR(B0_DAS)) & DAS_AVAIL)) - smc->s.sas = SMT_SAS ; /* Single att. station */ - else - smc->s.sas = SMT_DAS ; /* Dual att. station */ - - if (!(inp(ADDR(B0_DAS)) & DAS_BYP_ST)) - smc->mib.fddiSMTBypassPresent = 0 ; - /* without opt. bypass */ - else - smc->mib.fddiSMTBypassPresent = 1 ; - /* with opt. bypass */ -} - -/* - * insert or deinsert optical bypass (called by ECM) - */ -void sm_pm_bypass_req(struct s_smc *smc, int mode) -{ - DB_ECMN(1,"ECM : sm_pm_bypass_req(%s)\n",(mode == BP_INSERT) ? - "BP_INSERT" : "BP_DEINSERT",0) ; - - if (smc->s.sas != SMT_DAS) - return ; - -#ifdef PCI - switch(mode) { - case BP_INSERT : - outp(ADDR(B0_DAS),DAS_BYP_INS) ; /* insert station */ - break ; - case BP_DEINSERT : - outp(ADDR(B0_DAS),DAS_BYP_RMV) ; /* bypass station */ - break ; - } -#endif -} - -/* - * check if bypass connected - */ -int sm_pm_bypass_present(struct s_smc *smc) -{ - return (inp(ADDR(B0_DAS)) & DAS_BYP_ST) ? TRUE : FALSE; -} - -void plc_clear_irq(struct s_smc *smc, int p) -{ - SK_UNUSED(p) ; - - SK_UNUSED(smc) ; -} - - -/* - * led_indication called by rmt_indication() and - * pcm_state_change() - * - * Input: - * smc: SMT context - * led_event: - * 0 Only switch green LEDs according to their respective PCM state - * LED_Y_OFF just switch yellow LED off - * LED_Y_ON just switch yello LED on - */ -static void led_indication(struct s_smc *smc, int led_event) -{ - /* use smc->hw.mac_ring_is_up == TRUE - * as indication for Ring Operational - */ - u_short led_state ; - struct s_phy *phy ; - struct fddi_mib_p *mib_a ; - struct fddi_mib_p *mib_b ; - - phy = &smc->y[PA] ; - mib_a = phy->mib ; - phy = &smc->y[PB] ; - mib_b = phy->mib ; - -#ifdef PCI - led_state = 0 ; - - /* Ring up = yellow led OFF*/ - if (led_event == LED_Y_ON) { - led_state |= LED_MY_ON ; - } - else if (led_event == LED_Y_OFF) { - led_state |= LED_MY_OFF ; - } - else { /* PCM state changed */ - /* Link at Port A/S = green led A ON */ - if (mib_a->fddiPORTPCMState == PC8_ACTIVE) { - led_state |= LED_GA_ON ; - } - else { - led_state |= LED_GA_OFF ; - } - - /* Link at Port B = green led B ON */ - if (mib_b->fddiPORTPCMState == PC8_ACTIVE) { - led_state |= LED_GB_ON ; - } - else { - led_state |= LED_GB_OFF ; - } - } - - outp(ADDR(B0_LED), led_state) ; -#endif /* PCI */ - -} - - -void pcm_state_change(struct s_smc *smc, int plc, int p_state) -{ - /* - * the current implementation of pcm_state_change() in the driver - * parts must be renamed to drv_pcm_state_change() which will be called - * now after led_indication. - */ - DRV_PCM_STATE_CHANGE(smc,plc,p_state) ; - - led_indication(smc,0) ; -} - - -void rmt_indication(struct s_smc *smc, int i) -{ - /* Call a driver special function if defined */ - DRV_RMT_INDICATION(smc,i) ; - - led_indication(smc, i ? LED_Y_OFF : LED_Y_ON) ; -} - - -/* - * llc_recover_tx called by init_tx (fplus.c) - */ -void llc_recover_tx(struct s_smc *smc) -{ -#ifdef LOAD_GEN - extern int load_gen_flag ; - - load_gen_flag = 0 ; -#endif -#ifndef SYNC - smc->hw.n_a_send= 0 ; -#else - SK_UNUSED(smc) ; -#endif -} - -#ifdef MULT_OEM -static int is_equal_num(char comp1[], char comp2[], int num) -{ - int i ; - - for (i = 0 ; i < num ; i++) { - if (comp1[i] != comp2[i]) - return 0; - } - return 1; -} /* is_equal_num */ - - -/* - * set the OEM ID defaults, and test the contents of the OEM data base - * The default OEM is the first ACTIVE entry in the OEM data base - * - * returns: 0 success - * 1 error in data base - * 2 data base empty - * 3 no active entry - */ -int set_oi_id_def(struct s_smc *smc) -{ - int sel_id ; - int i ; - int act_entries ; - - i = 0 ; - sel_id = -1 ; - act_entries = FALSE ; - smc->hw.oem_id = 0 ; - smc->hw.oem_min_status = OI_STAT_ACTIVE ; - - /* check OEM data base */ - while (oem_ids[i].oi_status) { - switch (oem_ids[i].oi_status) { - case OI_STAT_ACTIVE: - act_entries = TRUE ; /* we have active IDs */ - if (sel_id == -1) - sel_id = i ; /* save the first active ID */ - case OI_STAT_VALID: - case OI_STAT_PRESENT: - i++ ; - break ; /* entry ok */ - default: - return 1; /* invalid oi_status */ - } - } - - if (i == 0) - return 2; - if (!act_entries) - return 3; - - /* ok, we have a valid OEM data base with an active entry */ - smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[sel_id] ; - return 0; -} -#endif /* MULT_OEM */ - -void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr) -{ - int i ; - - for (i = 0 ; i < 6 ; i++) - bia_addr->a[i] = bitrev8(smc->hw.fddi_phys_addr.a[i]); -} - -void smt_start_watchdog(struct s_smc *smc) -{ - SK_UNUSED(smc) ; /* Make LINT happy. */ - -#ifndef DEBUG - -#ifdef PCI - if (smc->hw.wdog_used) { - outpw(ADDR(B2_WDOG_CRTL),TIM_START) ; /* Start timer. */ - } -#endif - -#endif /* DEBUG */ -} - -static void smt_stop_watchdog(struct s_smc *smc) -{ - SK_UNUSED(smc) ; /* Make LINT happy. */ -#ifndef DEBUG - -#ifdef PCI - if (smc->hw.wdog_used) { - outpw(ADDR(B2_WDOG_CRTL),TIM_STOP) ; /* Stop timer. */ - } -#endif - -#endif /* DEBUG */ -} - -#ifdef PCI - -void mac_do_pci_fix(struct s_smc *smc) -{ - SK_UNUSED(smc) ; -} -#endif /* PCI */ - diff --git a/drivers/net/skfp/ecm.c b/drivers/net/skfp/ecm.c deleted file mode 100644 index 47d922c..0000000 --- a/drivers/net/skfp/ecm.c +++ /dev/null @@ -1,536 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - SMT ECM - Entity Coordination Management - Hardware independent state machine -*/ - -/* - * Hardware independent state machine implemantation - * The following external SMT functions are referenced : - * - * queue_event() - * smt_timer_start() - * smt_timer_stop() - * - * The following external HW dependent functions are referenced : - * sm_pm_bypass_req() - * sm_pm_ls_latch() - * sm_pm_get_ls() - * - * The following HW dependent events are required : - * NONE - * - */ - -#include "h/types.h" -#include "h/fddi.h" -#include "h/smc.h" - -#define KERNEL -#include "h/smtstate.h" - -#ifndef lint -static const char ID_sccs[] = "@(#)ecm.c 2.7 99/08/05 (C) SK " ; -#endif - -/* - * FSM Macros - */ -#define AFLAG 0x10 -#define GO_STATE(x) (smc->mib.fddiSMTECMState = (x)|AFLAG) -#define ACTIONS_DONE() (smc->mib.fddiSMTECMState &= ~AFLAG) -#define ACTIONS(x) (x|AFLAG) - -#define EC0_OUT 0 /* not inserted */ -#define EC1_IN 1 /* inserted */ -#define EC2_TRACE 2 /* tracing */ -#define EC3_LEAVE 3 /* leaving the ring */ -#define EC4_PATH_TEST 4 /* performing path test */ -#define EC5_INSERT 5 /* bypass being turned on */ -#define EC6_CHECK 6 /* checking bypass */ -#define EC7_DEINSERT 7 /* bypass being turnde off */ - -#ifdef DEBUG -/* - * symbolic state names - */ -static const char * const ecm_states[] = { - "EC0_OUT","EC1_IN","EC2_TRACE","EC3_LEAVE","EC4_PATH_TEST", - "EC5_INSERT","EC6_CHECK","EC7_DEINSERT" -} ; - -/* - * symbolic event names - */ -static const char * const ecm_events[] = { - "NONE","EC_CONNECT","EC_DISCONNECT","EC_TRACE_PROP","EC_PATH_TEST", - "EC_TIMEOUT_TD","EC_TIMEOUT_TMAX", - "EC_TIMEOUT_IMAX","EC_TIMEOUT_INMAX","EC_TEST_DONE" -} ; -#endif - -/* - * all Globals are defined in smc.h - * struct s_ecm - */ - -/* - * function declarations - */ - -static void ecm_fsm(struct s_smc *smc, int cmd); -static void start_ecm_timer(struct s_smc *smc, u_long value, int event); -static void stop_ecm_timer(struct s_smc *smc); -static void prop_actions(struct s_smc *smc); - -/* - init ECM state machine - clear all ECM vars and flags -*/ -void ecm_init(struct s_smc *smc) -{ - smc->e.path_test = PT_PASSED ; - smc->e.trace_prop = 0 ; - smc->e.sb_flag = 0 ; - smc->mib.fddiSMTECMState = ACTIONS(EC0_OUT) ; - smc->e.ecm_line_state = FALSE ; -} - -/* - ECM state machine - called by dispatcher - - do - display state change - process event - until SM is stable -*/ -void ecm(struct s_smc *smc, int event) -{ - int state ; - - do { - DB_ECM("ECM : state %s%s", - (smc->mib.fddiSMTECMState & AFLAG) ? "ACTIONS " : "", - ecm_states[smc->mib.fddiSMTECMState & ~AFLAG]) ; - DB_ECM(" event %s\n",ecm_events[event],0) ; - state = smc->mib.fddiSMTECMState ; - ecm_fsm(smc,event) ; - event = 0 ; - } while (state != smc->mib.fddiSMTECMState) ; - ecm_state_change(smc,(int)smc->mib.fddiSMTECMState) ; -} - -/* - process ECM event -*/ -static void ecm_fsm(struct s_smc *smc, int cmd) -{ - int ls_a ; /* current line state PHY A */ - int ls_b ; /* current line state PHY B */ - int p ; /* ports */ - - - smc->mib.fddiSMTBypassPresent = sm_pm_bypass_present(smc) ; - if (cmd == EC_CONNECT) - smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ; - - /* For AIX event notification: */ - /* Is a disconnect command remotely issued ? */ - if (cmd == EC_DISCONNECT && - smc->mib.fddiSMTRemoteDisconnectFlag == TRUE) - AIX_EVENT (smc, (u_long) CIO_HARD_FAIL, (u_long) - FDDI_REMOTE_DISCONNECT, smt_get_event_word(smc), - smt_get_error_word(smc) ); - - /*jd 05-Aug-1999 Bug #10419 "Port Disconnect fails at Dup MAc Cond."*/ - if (cmd == EC_CONNECT) { - smc->e.DisconnectFlag = FALSE ; - } - else if (cmd == EC_DISCONNECT) { - smc->e.DisconnectFlag = TRUE ; - } - - switch(smc->mib.fddiSMTECMState) { - case ACTIONS(EC0_OUT) : - /* - * We do not perform a path test - */ - smc->e.path_test = PT_PASSED ; - smc->e.ecm_line_state = FALSE ; - stop_ecm_timer(smc) ; - ACTIONS_DONE() ; - break ; - case EC0_OUT: - /*EC01*/ - if (cmd == EC_CONNECT && !smc->mib.fddiSMTBypassPresent - && smc->e.path_test==PT_PASSED) { - GO_STATE(EC1_IN) ; - break ; - } - /*EC05*/ - else if (cmd == EC_CONNECT && (smc->e.path_test==PT_PASSED) && - smc->mib.fddiSMTBypassPresent && - (smc->s.sas == SMT_DAS)) { - GO_STATE(EC5_INSERT) ; - break ; - } - break; - case ACTIONS(EC1_IN) : - stop_ecm_timer(smc) ; - smc->e.trace_prop = 0 ; - sm_ma_control(smc,MA_TREQ) ; - for (p = 0 ; p < NUMPHYS ; p++) - if (smc->mib.p[p].fddiPORTHardwarePresent) - queue_event(smc,EVENT_PCMA+p,PC_START) ; - ACTIONS_DONE() ; - break ; - case EC1_IN: - /*EC12*/ - if (cmd == EC_TRACE_PROP) { - prop_actions(smc) ; - GO_STATE(EC2_TRACE) ; - break ; - } - /*EC13*/ - else if (cmd == EC_DISCONNECT) { - GO_STATE(EC3_LEAVE) ; - break ; - } - break; - case ACTIONS(EC2_TRACE) : - start_ecm_timer(smc,MIB2US(smc->mib.fddiSMTTrace_MaxExpiration), - EC_TIMEOUT_TMAX) ; - ACTIONS_DONE() ; - break ; - case EC2_TRACE : - /*EC22*/ - if (cmd == EC_TRACE_PROP) { - prop_actions(smc) ; - GO_STATE(EC2_TRACE) ; - break ; - } - /*EC23a*/ - else if (cmd == EC_DISCONNECT) { - smc->e.path_test = PT_EXITING ; - GO_STATE(EC3_LEAVE) ; - break ; - } - /*EC23b*/ - else if (smc->e.path_test == PT_PENDING) { - GO_STATE(EC3_LEAVE) ; - break ; - } - /*EC23c*/ - else if (cmd == EC_TIMEOUT_TMAX) { - /* Trace_Max is expired */ - /* -> send AIX_EVENT */ - AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, - (u_long) FDDI_SMT_ERROR, (u_long) - FDDI_TRACE_MAX, smt_get_error_word(smc)); - smc->e.path_test = PT_PENDING ; - GO_STATE(EC3_LEAVE) ; - break ; - } - break ; - case ACTIONS(EC3_LEAVE) : - start_ecm_timer(smc,smc->s.ecm_td_min,EC_TIMEOUT_TD) ; - for (p = 0 ; p < NUMPHYS ; p++) - queue_event(smc,EVENT_PCMA+p,PC_STOP) ; - ACTIONS_DONE() ; - break ; - case EC3_LEAVE: - /*EC30*/ - if (cmd == EC_TIMEOUT_TD && !smc->mib.fddiSMTBypassPresent && - (smc->e.path_test != PT_PENDING)) { - GO_STATE(EC0_OUT) ; - break ; - } - /*EC34*/ - else if (cmd == EC_TIMEOUT_TD && - (smc->e.path_test == PT_PENDING)) { - GO_STATE(EC4_PATH_TEST) ; - break ; - } - /*EC31*/ - else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) { - GO_STATE(EC1_IN) ; - break ; - } - /*EC33*/ - else if (cmd == EC_DISCONNECT && - smc->e.path_test == PT_PENDING) { - smc->e.path_test = PT_EXITING ; - /* - * stay in state - state will be left via timeout - */ - } - /*EC37*/ - else if (cmd == EC_TIMEOUT_TD && - smc->mib.fddiSMTBypassPresent && - smc->e.path_test != PT_PENDING) { - GO_STATE(EC7_DEINSERT) ; - break ; - } - break ; - case ACTIONS(EC4_PATH_TEST) : - stop_ecm_timer(smc) ; - smc->e.path_test = PT_TESTING ; - start_ecm_timer(smc,smc->s.ecm_test_done,EC_TEST_DONE) ; - /* now perform path test ... just a simulation */ - ACTIONS_DONE() ; - break ; - case EC4_PATH_TEST : - /* path test done delay */ - if (cmd == EC_TEST_DONE) - smc->e.path_test = PT_PASSED ; - - if (smc->e.path_test == PT_FAILED) - RS_SET(smc,RS_PATHTEST) ; - - /*EC40a*/ - if (smc->e.path_test == PT_FAILED && - !smc->mib.fddiSMTBypassPresent) { - GO_STATE(EC0_OUT) ; - break ; - } - /*EC40b*/ - else if (cmd == EC_DISCONNECT && - !smc->mib.fddiSMTBypassPresent) { - GO_STATE(EC0_OUT) ; - break ; - } - /*EC41*/ - else if (smc->e.path_test == PT_PASSED) { - GO_STATE(EC1_IN) ; - break ; - } - /*EC47a*/ - else if (smc->e.path_test == PT_FAILED && - smc->mib.fddiSMTBypassPresent) { - GO_STATE(EC7_DEINSERT) ; - break ; - } - /*EC47b*/ - else if (cmd == EC_DISCONNECT && - smc->mib.fddiSMTBypassPresent) { - GO_STATE(EC7_DEINSERT) ; - break ; - } - break ; - case ACTIONS(EC5_INSERT) : - sm_pm_bypass_req(smc,BP_INSERT); - start_ecm_timer(smc,smc->s.ecm_in_max,EC_TIMEOUT_INMAX) ; - ACTIONS_DONE() ; - break ; - case EC5_INSERT : - /*EC56*/ - if (cmd == EC_TIMEOUT_INMAX) { - GO_STATE(EC6_CHECK) ; - break ; - } - /*EC57*/ - else if (cmd == EC_DISCONNECT) { - GO_STATE(EC7_DEINSERT) ; - break ; - } - break ; - case ACTIONS(EC6_CHECK) : - /* - * in EC6_CHECK, we *POLL* the line state ! - * check whether both bypass switches have switched. - */ - start_ecm_timer(smc,smc->s.ecm_check_poll,0) ; - smc->e.ecm_line_state = TRUE ; /* flag to pcm: report Q/HLS */ - (void) sm_pm_ls_latch(smc,PA,1) ; /* enable line state latch */ - (void) sm_pm_ls_latch(smc,PB,1) ; /* enable line state latch */ - ACTIONS_DONE() ; - break ; - case EC6_CHECK : - ls_a = sm_pm_get_ls(smc,PA) ; - ls_b = sm_pm_get_ls(smc,PB) ; - - /*EC61*/ - if (((ls_a == PC_QLS) || (ls_a == PC_HLS)) && - ((ls_b == PC_QLS) || (ls_b == PC_HLS)) ) { - smc->e.sb_flag = FALSE ; - smc->e.ecm_line_state = FALSE ; - GO_STATE(EC1_IN) ; - break ; - } - /*EC66*/ - else if (!smc->e.sb_flag && - (((ls_a == PC_ILS) && (ls_b == PC_QLS)) || - ((ls_a == PC_QLS) && (ls_b == PC_ILS)))){ - smc->e.sb_flag = TRUE ; - DB_ECMN(1,"ECM : EC6_CHECK - stuck bypass\n",0,0) ; - AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) - FDDI_SMT_ERROR, (u_long) FDDI_BYPASS_STUCK, - smt_get_error_word(smc)); - } - /*EC67*/ - else if (cmd == EC_DISCONNECT) { - smc->e.ecm_line_state = FALSE ; - GO_STATE(EC7_DEINSERT) ; - break ; - } - else { - /* - * restart poll - */ - start_ecm_timer(smc,smc->s.ecm_check_poll,0) ; - } - break ; - case ACTIONS(EC7_DEINSERT) : - sm_pm_bypass_req(smc,BP_DEINSERT); - start_ecm_timer(smc,smc->s.ecm_i_max,EC_TIMEOUT_IMAX) ; - ACTIONS_DONE() ; - break ; - case EC7_DEINSERT: - /*EC70*/ - if (cmd == EC_TIMEOUT_IMAX) { - GO_STATE(EC0_OUT) ; - break ; - } - /*EC75*/ - else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) { - GO_STATE(EC5_INSERT) ; - break ; - } - break; - default: - SMT_PANIC(smc,SMT_E0107, SMT_E0107_MSG) ; - break; - } -} - -#ifndef CONCENTRATOR -/* - * trace propagation actions for SAS & DAS - */ -static void prop_actions(struct s_smc *smc) -{ - int port_in = 0 ; - int port_out = 0 ; - - RS_SET(smc,RS_EVENT) ; - switch (smc->s.sas) { - case SMT_SAS : - port_in = port_out = pcm_get_s_port(smc) ; - break ; - case SMT_DAS : - port_in = cfm_get_mac_input(smc) ; /* PA or PB */ - port_out = cfm_get_mac_output(smc) ; /* PA or PB */ - break ; - case SMT_NAC : - SMT_PANIC(smc,SMT_E0108, SMT_E0108_MSG) ; - return ; - } - - DB_ECM("ECM : prop_actions - trace_prop %d\n", smc->e.trace_prop,0) ; - DB_ECM("ECM : prop_actions - in %d out %d\n", port_in,port_out) ; - - if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) { - /* trace initiatior */ - DB_ECM("ECM : initiate TRACE on PHY %c\n",'A'+port_in-PA,0) ; - queue_event(smc,EVENT_PCM+port_in,PC_TRACE) ; - } - else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PA))) && - port_out != PA) { - /* trace propagate upstream */ - DB_ECM("ECM : propagate TRACE on PHY B\n",0,0) ; - queue_event(smc,EVENT_PCMB,PC_TRACE) ; - } - else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PB))) && - port_out != PB) { - /* trace propagate upstream */ - DB_ECM("ECM : propagate TRACE on PHY A\n",0,0) ; - queue_event(smc,EVENT_PCMA,PC_TRACE) ; - } - else { - /* signal trace termination */ - DB_ECM("ECM : TRACE terminated\n",0,0) ; - smc->e.path_test = PT_PENDING ; - } - smc->e.trace_prop = 0 ; -} -#else -/* - * trace propagation actions for Concentrator - */ -static void prop_actions(struct s_smc *smc) -{ - int initiator ; - int upstream ; - int p ; - - RS_SET(smc,RS_EVENT) ; - while (smc->e.trace_prop) { - DB_ECM("ECM : prop_actions - trace_prop %d\n", - smc->e.trace_prop,0) ; - - if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) { - initiator = ENTITY_MAC ; - smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_MAC) ; - DB_ECM("ECM: MAC initiates trace\n",0,0) ; - } - else { - for (p = NUMPHYS-1 ; p >= 0 ; p--) { - if (smc->e.trace_prop & - ENTITY_BIT(ENTITY_PHY(p))) - break ; - } - initiator = ENTITY_PHY(p) ; - smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_PHY(p)) ; - } - upstream = cem_get_upstream(smc,initiator) ; - - if (upstream == ENTITY_MAC) { - /* signal trace termination */ - DB_ECM("ECM : TRACE terminated\n",0,0) ; - smc->e.path_test = PT_PENDING ; - } - else { - /* trace propagate upstream */ - DB_ECM("ECM : propagate TRACE on PHY %d\n",upstream,0) ; - queue_event(smc,EVENT_PCM+upstream,PC_TRACE) ; - } - } -} -#endif - - -/* - * SMT timer interface - * start ECM timer - */ -static void start_ecm_timer(struct s_smc *smc, u_long value, int event) -{ - smt_timer_start(smc,&smc->e.ecm_timer,value,EV_TOKEN(EVENT_ECM,event)); -} - -/* - * SMT timer interface - * stop ECM timer - */ -static void stop_ecm_timer(struct s_smc *smc) -{ - if (smc->e.ecm_timer.tm_active) - smt_timer_stop(smc,&smc->e.ecm_timer) ; -} diff --git a/drivers/net/skfp/ess.c b/drivers/net/skfp/ess.c deleted file mode 100644 index 2fc5987..0000000 --- a/drivers/net/skfp/ess.c +++ /dev/null @@ -1,720 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - * ******************************************************************* - * This SBA code implements the Synchronous Bandwidth Allocation - * functions described in the "FDDI Synchronous Forum Implementer's - * Agreement" dated December 1th, 1993. - * ******************************************************************* - * - * PURPOSE: The purpose of this function is to control - * synchronous allocations on a single FDDI segment. - * Allocations are limited to the primary FDDI ring. - * The SBM provides recovery mechanisms to recover - * unused bandwidth also resolves T_Neg and - * reconfiguration changes. Many of the SBM state - * machine inputs are sourced by the underlying - * FDDI sub-system supporting the SBA application. - * - * ******************************************************************* - */ - -#include "h/types.h" -#include "h/fddi.h" -#include "h/smc.h" -#include "h/smt_p.h" - - -#ifndef SLIM_SMT - -#ifdef ESS - -#ifndef lint -static const char ID_sccs[] = "@(#)ess.c 1.10 96/02/23 (C) SK" ; -#define LINT_USE(x) -#else -#define LINT_USE(x) (x)=(x) -#endif -#define MS2BCLK(x) ((x)*12500L) - -/* - ------------------------------------------------------------- - LOCAL VARIABLES: - ------------------------------------------------------------- -*/ - -static const u_short plist_raf_alc_res[] = { SMT_P0012, SMT_P320B, SMT_P320F, - SMT_P3210, SMT_P0019, SMT_P001A, - SMT_P001D, 0 } ; - -static const u_short plist_raf_chg_req[] = { SMT_P320B, SMT_P320F, SMT_P3210, - SMT_P001A, 0 } ; - -static const struct fddi_addr smt_sba_da = {{0x80,0x01,0x43,0x00,0x80,0x0C}} ; -static const struct fddi_addr null_addr = {{0,0,0,0,0,0}} ; - -/* - ------------------------------------------------------------- - GLOBAL VARIABLES: - ------------------------------------------------------------- -*/ - - -/* - ------------------------------------------------------------- - LOCAL FUNCTIONS: - ------------------------------------------------------------- -*/ - -static void ess_send_response(struct s_smc *smc, struct smt_header *sm, - int sba_cmd); -static void ess_config_fifo(struct s_smc *smc); -static void ess_send_alc_req(struct s_smc *smc); -static void ess_send_frame(struct s_smc *smc, SMbuf *mb); - -/* - ------------------------------------------------------------- - EXTERNAL FUNCTIONS: - ------------------------------------------------------------- -*/ - -/* - ------------------------------------------------------------- - PUBLIC FUNCTIONS: - ------------------------------------------------------------- -*/ - -void ess_timer_poll(struct s_smc *smc); -void ess_para_change(struct s_smc *smc); -int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm, - int fs); -static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead); - - -/* - * -------------------------------------------------------------------------- - * End Station Support (ESS) - * -------------------------------------------------------------------------- - */ - -/* - * evaluate the RAF frame - */ -int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm, - int fs) -{ - void *p ; /* universal pointer */ - struct smt_p_0016 *cmd ; /* para: command for the ESS */ - SMbuf *db ; - u_long msg_res_type ; /* recource type */ - u_long payload, overhead ; - int local ; - int i ; - - /* - * Message Processing Code - */ - local = ((fs & L_INDICATOR) != 0) ; - - /* - * get the resource type - */ - if (!(p = (void *) sm_to_para(smc,sm,SMT_P0015))) { - DB_ESS("ESS: RAF frame error, parameter type not found\n",0,0) ; - return fs; - } - msg_res_type = ((struct smt_p_0015 *)p)->res_type ; - - /* - * get the pointer to the ESS command - */ - if (!(cmd = (struct smt_p_0016 *) sm_to_para(smc,sm,SMT_P0016))) { - /* - * error in frame: para ESS command was not found - */ - DB_ESS("ESS: RAF frame error, parameter command not found\n",0,0); - return fs; - } - - DB_ESSN(2,"fc %x ft %x\n",sm->smt_class,sm->smt_type) ; - DB_ESSN(2,"ver %x tran %lx\n",sm->smt_version,sm->smt_tid) ; - DB_ESSN(2,"stn_id %s\n",addr_to_string(&sm->smt_source),0) ; - - DB_ESSN(2,"infolen %x res %x\n",sm->smt_len, msg_res_type) ; - DB_ESSN(2,"sbacmd %x\n",cmd->sba_cmd,0) ; - - /* - * evaluate the ESS command - */ - switch (cmd->sba_cmd) { - - /* - * Process an ESS Allocation Request - */ - case REQUEST_ALLOCATION : - /* - * check for an RAF Request (Allocation Request) - */ - if (sm->smt_type == SMT_REQUEST) { - /* - * process the Allocation request only if the frame is - * local and no static allocation is used - */ - if (!local || smc->mib.fddiESSPayload) - return fs; - - p = (void *) sm_to_para(smc,sm,SMT_P0019) ; - for (i = 0; i < 5; i++) { - if (((struct smt_p_0019 *)p)->alloc_addr.a[i]) { - return fs; - } - } - - /* - * Note: The Application should send a LAN_LOC_FRAME. - * The ESS do not send the Frame to the network! - */ - smc->ess.alloc_trans_id = sm->smt_tid ; - DB_ESS("ESS: save Alloc Req Trans ID %lx\n",sm->smt_tid,0); - p = (void *) sm_to_para(smc,sm,SMT_P320F) ; - ((struct smt_p_320f *)p)->mib_payload = - smc->mib.a[PATH0].fddiPATHSbaPayload ; - p = (void *) sm_to_para(smc,sm,SMT_P3210) ; - ((struct smt_p_3210 *)p)->mib_overhead = - smc->mib.a[PATH0].fddiPATHSbaOverhead ; - sm->smt_dest = smt_sba_da ; - - if (smc->ess.local_sba_active) - return fs | I_INDICATOR; - - if (!(db = smt_get_mbuf(smc))) - return fs; - - db->sm_len = mb->sm_len ; - db->sm_off = mb->sm_off ; - memcpy(((char *)(db->sm_data+db->sm_off)),(char *)sm, - (int)db->sm_len) ; - dump_smt(smc, - (struct smt_header *)(db->sm_data+db->sm_off), - "RAF") ; - smt_send_frame(smc,db,FC_SMT_INFO,0) ; - return fs; - } - - /* - * The RAF frame is an Allocation Response ! - * check the parameters - */ - if (smt_check_para(smc,sm,plist_raf_alc_res)) { - DB_ESS("ESS: RAF with para problem, ignoring\n",0,0) ; - return fs; - } - - /* - * VERIFY THE FRAME IS WELL BUILT: - * - * 1. path index = primary ring only - * 2. resource type = sync bw only - * 3. trans action id = alloc_trans_id - * 4. reason code = success - * - * If any are violated, discard the RAF frame - */ - if ((((struct smt_p_320b *)sm_to_para(smc,sm,SMT_P320B))->path_index - != PRIMARY_RING) || - (msg_res_type != SYNC_BW) || - (((struct smt_p_reason *)sm_to_para(smc,sm,SMT_P0012))->rdf_reason - != SMT_RDF_SUCCESS) || - (sm->smt_tid != smc->ess.alloc_trans_id)) { - - DB_ESS("ESS: Allocation Response not accepted\n",0,0) ; - return fs; - } - - /* - * Extract message parameters - */ - p = (void *) sm_to_para(smc,sm,SMT_P320F) ; - if (!p) { - printk(KERN_ERR "ESS: sm_to_para failed"); - return fs; - } - payload = ((struct smt_p_320f *)p)->mib_payload ; - p = (void *) sm_to_para(smc,sm,SMT_P3210) ; - if (!p) { - printk(KERN_ERR "ESS: sm_to_para failed"); - return fs; - } - overhead = ((struct smt_p_3210 *)p)->mib_overhead ; - - DB_ESSN(2,"payload= %lx overhead= %lx\n",payload,overhead) ; - - /* - * process the bandwidth allocation - */ - (void)process_bw_alloc(smc,(long)payload,(long)overhead) ; - - return fs; - /* end of Process Allocation Request */ - - /* - * Process an ESS Change Request - */ - case CHANGE_ALLOCATION : - /* - * except only replies - */ - if (sm->smt_type != SMT_REQUEST) { - DB_ESS("ESS: Do not process Change Responses\n",0,0) ; - return fs; - } - - /* - * check the para for the Change Request - */ - if (smt_check_para(smc,sm,plist_raf_chg_req)) { - DB_ESS("ESS: RAF with para problem, ignoring\n",0,0) ; - return fs; - } - - /* - * Verify the path index and resource - * type are correct. If any of - * these are false, don't process this - * change request frame. - */ - if ((((struct smt_p_320b *)sm_to_para(smc,sm,SMT_P320B))->path_index - != PRIMARY_RING) || (msg_res_type != SYNC_BW)) { - DB_ESS("ESS: RAF frame with para problem, ignoring\n",0,0) ; - return fs; - } - - /* - * Extract message queue parameters - */ - p = (void *) sm_to_para(smc,sm,SMT_P320F) ; - payload = ((struct smt_p_320f *)p)->mib_payload ; - p = (void *) sm_to_para(smc,sm,SMT_P3210) ; - overhead = ((struct smt_p_3210 *)p)->mib_overhead ; - - DB_ESSN(2,"ESS: Change Request from %s\n", - addr_to_string(&sm->smt_source),0) ; - DB_ESSN(2,"payload= %lx overhead= %lx\n",payload,overhead) ; - - /* - * process the bandwidth allocation - */ - if(!process_bw_alloc(smc,(long)payload,(long)overhead)) - return fs; - - /* - * send an RAF Change Reply - */ - ess_send_response(smc,sm,CHANGE_ALLOCATION) ; - - return fs; - /* end of Process Change Request */ - - /* - * Process Report Response - */ - case REPORT_ALLOCATION : - /* - * except only requests - */ - if (sm->smt_type != SMT_REQUEST) { - DB_ESS("ESS: Do not process a Report Reply\n",0,0) ; - return fs; - } - - DB_ESSN(2,"ESS: Report Request from %s\n", - addr_to_string(&(sm->smt_source)),0) ; - - /* - * verify that the resource type is sync bw only - */ - if (msg_res_type != SYNC_BW) { - DB_ESS("ESS: ignoring RAF with para problem\n",0,0) ; - return fs; - } - - /* - * send an RAF Change Reply - */ - ess_send_response(smc,sm,REPORT_ALLOCATION) ; - - return fs; - /* end of Process Report Request */ - - default: - /* - * error in frame - */ - DB_ESS("ESS: ignoring RAF with bad sba_cmd\n",0,0) ; - break ; - } - - return fs; -} - -/* - * determines the synchronous bandwidth, set the TSYNC register and the - * mib variables SBAPayload, SBAOverhead and fddiMACT-NEG. - */ -static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead) -{ - /* - * determine the synchronous bandwidth (sync_bw) in bytes per T-NEG, - * if the payload is greater than zero. - * For the SBAPayload and the SBAOverhead we have the following - * unite quations - * _ _ - * | bytes | - * SBAPayload = | 8000 ------ | - * | s | - * - - - * _ _ - * | bytes | - * SBAOverhead = | ------ | - * | T-NEG | - * - - - * - * T-NEG is described by the equation: - * - * (-) fddiMACT-NEG - * T-NEG = ------------------- - * 12500000 1/s - * - * The number of bytes we are able to send is the payload - * plus the overhead. - * - * bytes T-NEG SBAPayload 8000 bytes/s - * sync_bw = SBAOverhead ------ + ----------------------------- - * T-NEG T-NEG - * - * - * 1 - * sync_bw = SBAOverhead + ---- (-)fddiMACT-NEG * SBAPayload - * 1562 - * - */ - - /* - * set the mib attributes fddiPATHSbaOverhead, fddiPATHSbaPayload - */ -/* if (smt_set_obj(smc,SMT_P320F,payload,S_SET)) { - DB_ESS("ESS: SMT does not accept the payload value\n",0,0) ; - return FALSE; - } - if (smt_set_obj(smc,SMT_P3210,overhead,S_SET)) { - DB_ESS("ESS: SMT does not accept the overhead value\n",0,0) ; - return FALSE; - } */ - - /* premliminary */ - if (payload > MAX_PAYLOAD || overhead > 5000) { - DB_ESS("ESS: payload / overhead not accepted\n",0,0) ; - return FALSE; - } - - /* - * start the iterative allocation process if the payload or the overhead - * are smaller than the parsed values - */ - if (smc->mib.fddiESSPayload && - ((u_long)payload != smc->mib.fddiESSPayload || - (u_long)overhead != smc->mib.fddiESSOverhead)) { - smc->ess.raf_act_timer_poll = TRUE ; - smc->ess.timer_count = 0 ; - } - - /* - * evulate the Payload - */ - if (payload) { - DB_ESSN(2,"ESS: turn SMT_ST_SYNC_SERVICE bit on\n",0,0) ; - smc->ess.sync_bw_available = TRUE ; - - smc->ess.sync_bw = overhead - - (long)smc->mib.m[MAC0].fddiMACT_Neg * - payload / 1562 ; - } - else { - DB_ESSN(2,"ESS: turn SMT_ST_SYNC_SERVICE bit off\n",0,0) ; - smc->ess.sync_bw_available = FALSE ; - smc->ess.sync_bw = 0 ; - overhead = 0 ; - } - - smc->mib.a[PATH0].fddiPATHSbaPayload = payload ; - smc->mib.a[PATH0].fddiPATHSbaOverhead = overhead ; - - - DB_ESSN(2,"tsync = %lx\n",smc->ess.sync_bw,0) ; - - ess_config_fifo(smc) ; - set_formac_tsync(smc,smc->ess.sync_bw) ; - return TRUE; -} - -static void ess_send_response(struct s_smc *smc, struct smt_header *sm, - int sba_cmd) -{ - struct smt_sba_chg *chg ; - SMbuf *mb ; - void *p ; - - /* - * get and initialize the response frame - */ - if (sba_cmd == CHANGE_ALLOCATION) { - if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REPLY, - sizeof(struct smt_sba_chg)))) - return ; - } - else { - if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REPLY, - sizeof(struct smt_sba_rep_res)))) - return ; - } - - chg = smtod(mb,struct smt_sba_chg *) ; - chg->smt.smt_tid = sm->smt_tid ; - chg->smt.smt_dest = sm->smt_source ; - - /* set P15 */ - chg->s_type.para.p_type = SMT_P0015 ; - chg->s_type.para.p_len = sizeof(struct smt_p_0015) - PARA_LEN ; - chg->s_type.res_type = SYNC_BW ; - - /* set P16 */ - chg->cmd.para.p_type = SMT_P0016 ; - chg->cmd.para.p_len = sizeof(struct smt_p_0016) - PARA_LEN ; - chg->cmd.sba_cmd = sba_cmd ; - - /* set P320B */ - chg->path.para.p_type = SMT_P320B ; - chg->path.para.p_len = sizeof(struct smt_p_320b) - PARA_LEN ; - chg->path.mib_index = SBAPATHINDEX ; - chg->path.path_pad = 0; - chg->path.path_index = PRIMARY_RING ; - - /* set P320F */ - chg->payload.para.p_type = SMT_P320F ; - chg->payload.para.p_len = sizeof(struct smt_p_320f) - PARA_LEN ; - chg->payload.mib_index = SBAPATHINDEX ; - chg->payload.mib_payload = smc->mib.a[PATH0].fddiPATHSbaPayload ; - - /* set P3210 */ - chg->overhead.para.p_type = SMT_P3210 ; - chg->overhead.para.p_len = sizeof(struct smt_p_3210) - PARA_LEN ; - chg->overhead.mib_index = SBAPATHINDEX ; - chg->overhead.mib_overhead = smc->mib.a[PATH0].fddiPATHSbaOverhead ; - - if (sba_cmd == CHANGE_ALLOCATION) { - /* set P1A */ - chg->cat.para.p_type = SMT_P001A ; - chg->cat.para.p_len = sizeof(struct smt_p_001a) - PARA_LEN ; - p = (void *) sm_to_para(smc,sm,SMT_P001A) ; - chg->cat.category = ((struct smt_p_001a *)p)->category ; - } - dump_smt(smc,(struct smt_header *)chg,"RAF") ; - ess_send_frame(smc,mb) ; -} - -void ess_timer_poll(struct s_smc *smc) -{ - if (!smc->ess.raf_act_timer_poll) - return ; - - DB_ESSN(2,"ESS: timer_poll\n",0,0) ; - - smc->ess.timer_count++ ; - if (smc->ess.timer_count == 10) { - smc->ess.timer_count = 0 ; - ess_send_alc_req(smc) ; - } -} - -static void ess_send_alc_req(struct s_smc *smc) -{ - struct smt_sba_alc_req *req ; - SMbuf *mb ; - - /* - * send never allocation request where the requested payload and - * overhead is zero or deallocate bandwidth when no bandwidth is - * parsed - */ - if (!smc->mib.fddiESSPayload) { - smc->mib.fddiESSOverhead = 0 ; - } - else { - if (!smc->mib.fddiESSOverhead) - smc->mib.fddiESSOverhead = DEFAULT_OV ; - } - - if (smc->mib.fddiESSOverhead == - smc->mib.a[PATH0].fddiPATHSbaOverhead && - smc->mib.fddiESSPayload == - smc->mib.a[PATH0].fddiPATHSbaPayload){ - smc->ess.raf_act_timer_poll = FALSE ; - smc->ess.timer_count = 7 ; /* next RAF alc req after 3 s */ - return ; - } - - /* - * get and initialize the response frame - */ - if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REQUEST, - sizeof(struct smt_sba_alc_req)))) - return ; - req = smtod(mb,struct smt_sba_alc_req *) ; - req->smt.smt_tid = smc->ess.alloc_trans_id = smt_get_tid(smc) ; - req->smt.smt_dest = smt_sba_da ; - - /* set P15 */ - req->s_type.para.p_type = SMT_P0015 ; - req->s_type.para.p_len = sizeof(struct smt_p_0015) - PARA_LEN ; - req->s_type.res_type = SYNC_BW ; - - /* set P16 */ - req->cmd.para.p_type = SMT_P0016 ; - req->cmd.para.p_len = sizeof(struct smt_p_0016) - PARA_LEN ; - req->cmd.sba_cmd = REQUEST_ALLOCATION ; - - /* - * set the parameter type and parameter length of all used - * parameters - */ - - /* set P320B */ - req->path.para.p_type = SMT_P320B ; - req->path.para.p_len = sizeof(struct smt_p_320b) - PARA_LEN ; - req->path.mib_index = SBAPATHINDEX ; - req->path.path_pad = 0; - req->path.path_index = PRIMARY_RING ; - - /* set P0017 */ - req->pl_req.para.p_type = SMT_P0017 ; - req->pl_req.para.p_len = sizeof(struct smt_p_0017) - PARA_LEN ; - req->pl_req.sba_pl_req = smc->mib.fddiESSPayload - - smc->mib.a[PATH0].fddiPATHSbaPayload ; - - /* set P0018 */ - req->ov_req.para.p_type = SMT_P0018 ; - req->ov_req.para.p_len = sizeof(struct smt_p_0018) - PARA_LEN ; - req->ov_req.sba_ov_req = smc->mib.fddiESSOverhead - - smc->mib.a[PATH0].fddiPATHSbaOverhead ; - - /* set P320F */ - req->payload.para.p_type = SMT_P320F ; - req->payload.para.p_len = sizeof(struct smt_p_320f) - PARA_LEN ; - req->payload.mib_index = SBAPATHINDEX ; - req->payload.mib_payload = smc->mib.a[PATH0].fddiPATHSbaPayload ; - - /* set P3210 */ - req->overhead.para.p_type = SMT_P3210 ; - req->overhead.para.p_len = sizeof(struct smt_p_3210) - PARA_LEN ; - req->overhead.mib_index = SBAPATHINDEX ; - req->overhead.mib_overhead = smc->mib.a[PATH0].fddiPATHSbaOverhead ; - - /* set P19 */ - req->a_addr.para.p_type = SMT_P0019 ; - req->a_addr.para.p_len = sizeof(struct smt_p_0019) - PARA_LEN ; - req->a_addr.sba_pad = 0; - req->a_addr.alloc_addr = null_addr ; - - /* set P1A */ - req->cat.para.p_type = SMT_P001A ; - req->cat.para.p_len = sizeof(struct smt_p_001a) - PARA_LEN ; - req->cat.category = smc->mib.fddiESSCategory ; - - /* set P1B */ - req->tneg.para.p_type = SMT_P001B ; - req->tneg.para.p_len = sizeof(struct smt_p_001b) - PARA_LEN ; - req->tneg.max_t_neg = smc->mib.fddiESSMaxTNeg ; - - /* set P1C */ - req->segm.para.p_type = SMT_P001C ; - req->segm.para.p_len = sizeof(struct smt_p_001c) - PARA_LEN ; - req->segm.min_seg_siz = smc->mib.fddiESSMinSegmentSize ; - - dump_smt(smc,(struct smt_header *)req,"RAF") ; - ess_send_frame(smc,mb) ; -} - -static void ess_send_frame(struct s_smc *smc, SMbuf *mb) -{ - /* - * check if the frame must be send to the own ESS - */ - if (smc->ess.local_sba_active) { - /* - * Send the Change Reply to the local SBA - */ - DB_ESS("ESS:Send to the local SBA\n",0,0) ; - if (!smc->ess.sba_reply_pend) - smc->ess.sba_reply_pend = mb ; - else { - DB_ESS("Frame is lost - another frame was pending\n",0,0); - smt_free_mbuf(smc,mb) ; - } - } - else { - /* - * Send the SBA RAF Change Reply to the network - */ - DB_ESS("ESS:Send to the network\n",0,0) ; - smt_send_frame(smc,mb,FC_SMT_INFO,0) ; - } -} - -void ess_para_change(struct s_smc *smc) -{ - (void)process_bw_alloc(smc,(long)smc->mib.a[PATH0].fddiPATHSbaPayload, - (long)smc->mib.a[PATH0].fddiPATHSbaOverhead) ; -} - -static void ess_config_fifo(struct s_smc *smc) -{ - /* - * if nothing to do exit - */ - if (smc->mib.a[PATH0].fddiPATHSbaPayload) { - if (smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON && - (smc->hw.fp.fifo.fifo_config_mode&SEND_ASYNC_AS_SYNC) == - smc->mib.fddiESSSynchTxMode) { - return ; - } - } - else { - if (!(smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON)) { - return ; - } - } - - /* - * split up the FIFO and reinitialize the queues - */ - formac_reinit_tx(smc) ; -} - -#endif /* ESS */ - -#endif /* no SLIM_SMT */ - diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c deleted file mode 100644 index a20ed1a..0000000 --- a/drivers/net/skfp/fplustm.c +++ /dev/null @@ -1,1491 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - * FORMAC+ Driver for tag mode - */ - -#include "h/types.h" -#include "h/fddi.h" -#include "h/smc.h" -#include "h/supern_2.h" -#include - -#ifndef lint -static const char ID_sccs[] = "@(#)fplustm.c 1.32 99/02/23 (C) SK " ; -#endif - -#ifndef UNUSED -#ifdef lint -#define UNUSED(x) (x) = (x) -#else -#define UNUSED(x) -#endif -#endif - -#define FM_ADDRX (FM_ADDET|FM_EXGPA0|FM_EXGPA1) -#define MS2BCLK(x) ((x)*12500L) -#define US2BCLK(x) ((x)*1250L) - -/* - * prototypes for static function - */ -static void build_claim_beacon(struct s_smc *smc, u_long t_request); -static int init_mac(struct s_smc *smc, int all); -static void rtm_init(struct s_smc *smc); -static void smt_split_up_fifo(struct s_smc *smc); - -#if (!defined(NO_SMT_PANIC) || defined(DEBUG)) -static char write_mdr_warning [] = "E350 write_mdr() FM_SNPPND is set\n"; -static char cam_warning [] = "E_SMT_004: CAM still busy\n"; -#endif - -#define DUMMY_READ() smc->hw.mc_dummy = (u_short) inp(ADDR(B0_RAP)) - -#define CHECK_NPP() { unsigned k = 10000 ;\ - while ((inpw(FM_A(FM_STMCHN)) & FM_SNPPND) && k) k--;\ - if (!k) { \ - SMT_PANIC(smc,SMT_E0130, SMT_E0130_MSG) ; \ - } \ - } - -#define CHECK_CAM() { unsigned k = 10 ;\ - while (!(inpw(FM_A(FM_AFSTAT)) & FM_DONE) && k) k--;\ - if (!k) { \ - SMT_PANIC(smc,SMT_E0131, SMT_E0131_MSG) ; \ - } \ - } - -const struct fddi_addr fddi_broadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; -static const struct fddi_addr null_addr = {{0,0,0,0,0,0}}; -static const struct fddi_addr dbeacon_multi = {{0x01,0x80,0xc2,0x00,0x01,0x00}}; - -static const u_short my_said = 0xffff ; /* short address (n.u.) */ -static const u_short my_sagp = 0xffff ; /* short group address (n.u.) */ - -/* - * define my address - */ -#ifdef USE_CAN_ADDR -#define MA smc->hw.fddi_canon_addr -#else -#define MA smc->hw.fddi_home_addr -#endif - - -/* - * useful interrupt bits - */ -static const int mac_imsk1u = FM_STXABRS | FM_STXABRA0 | FM_SXMTABT ; -static const int mac_imsk1l = FM_SQLCKS | FM_SQLCKA0 | FM_SPCEPDS | FM_SPCEPDA0| - FM_STBURS | FM_STBURA0 ; - - /* delete FM_SRBFL after tests */ -static const int mac_imsk2u = FM_SERRSF | FM_SNFSLD | FM_SRCVOVR | FM_SRBFL | - FM_SMYCLM ; -static const int mac_imsk2l = FM_STRTEXR | FM_SDUPCLM | FM_SFRMCTR | - FM_SERRCTR | FM_SLSTCTR | - FM_STRTEXP | FM_SMULTDA | FM_SRNGOP ; - -static const int mac_imsk3u = FM_SRCVOVR2 | FM_SRBFL2 ; -static const int mac_imsk3l = FM_SRPERRQ2 | FM_SRPERRQ1 ; - -static const int mac_beacon_imsk2u = FM_SOTRBEC | FM_SMYBEC | FM_SBEC | - FM_SLOCLM | FM_SHICLM | FM_SMYCLM | FM_SCLM ; - - -static u_long mac_get_tneg(struct s_smc *smc) -{ - u_long tneg ; - - tneg = (u_long)((long)inpw(FM_A(FM_TNEG))<<5) ; - return (u_long)((tneg + ((inpw(FM_A(FM_TMRS))>>10)&0x1f)) | - 0xffe00000L) ; -} - -void mac_update_counter(struct s_smc *smc) -{ - smc->mib.m[MAC0].fddiMACFrame_Ct = - (smc->mib.m[MAC0].fddiMACFrame_Ct & 0xffff0000L) - + (u_short) inpw(FM_A(FM_FCNTR)) ; - smc->mib.m[MAC0].fddiMACLost_Ct = - (smc->mib.m[MAC0].fddiMACLost_Ct & 0xffff0000L) - + (u_short) inpw(FM_A(FM_LCNTR)) ; - smc->mib.m[MAC0].fddiMACError_Ct = - (smc->mib.m[MAC0].fddiMACError_Ct & 0xffff0000L) - + (u_short) inpw(FM_A(FM_ECNTR)) ; - smc->mib.m[MAC0].fddiMACT_Neg = mac_get_tneg(smc) ; -#ifdef SMT_REAL_TOKEN_CT - /* - * If the token counter is emulated it is updated in smt_event. - */ - TBD -#else - smt_emulate_token_ct( smc, MAC0 ); -#endif -} - -/* - * write long value into buffer memory over memory data register (MDR), - */ -static void write_mdr(struct s_smc *smc, u_long val) -{ - CHECK_NPP() ; - MDRW(val) ; -} - -#if 0 -/* - * read long value from buffer memory over memory data register (MDR), - */ -static u_long read_mdr(struct s_smc *smc, unsigned int addr) -{ - long p ; - CHECK_NPP() ; - MARR(addr) ; - outpw(FM_A(FM_CMDREG1),FM_IRMEMWO) ; - CHECK_NPP() ; /* needed for PCI to prevent from timeing violations */ -/* p = MDRR() ; */ /* bad read values if the workaround */ - /* smc->hw.mc_dummy = *((short volatile far *)(addr)))*/ - /* is used */ - p = (u_long)inpw(FM_A(FM_MDRU))<<16 ; - p += (u_long)inpw(FM_A(FM_MDRL)) ; - return p; -} -#endif - -/* - * clear buffer memory - */ -static void init_ram(struct s_smc *smc) -{ - u_short i ; - - smc->hw.fp.fifo.rbc_ram_start = 0 ; - smc->hw.fp.fifo.rbc_ram_end = - smc->hw.fp.fifo.rbc_ram_start + RBC_MEM_SIZE ; - CHECK_NPP() ; - MARW(smc->hw.fp.fifo.rbc_ram_start) ; - for (i = smc->hw.fp.fifo.rbc_ram_start; - i < (u_short) (smc->hw.fp.fifo.rbc_ram_end-1); i++) - write_mdr(smc,0L) ; - /* Erase the last byte too */ - write_mdr(smc,0L) ; -} - -/* - * set receive FIFO pointer - */ -static void set_recvptr(struct s_smc *smc) -{ - /* - * initialize the pointer for receive queue 1 - */ - outpw(FM_A(FM_RPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* RPR1 */ - outpw(FM_A(FM_SWPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* SWPR1 */ - outpw(FM_A(FM_WPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* WPR1 */ - outpw(FM_A(FM_EARV1),smc->hw.fp.fifo.tx_s_start-1) ; /* EARV1 */ - - /* - * initialize the pointer for receive queue 2 - */ - if (smc->hw.fp.fifo.rx2_fifo_size) { - outpw(FM_A(FM_RPR2),smc->hw.fp.fifo.rx2_fifo_start) ; - outpw(FM_A(FM_SWPR2),smc->hw.fp.fifo.rx2_fifo_start) ; - outpw(FM_A(FM_WPR2),smc->hw.fp.fifo.rx2_fifo_start) ; - outpw(FM_A(FM_EARV2),smc->hw.fp.fifo.rbc_ram_end-1) ; - } - else { - outpw(FM_A(FM_RPR2),smc->hw.fp.fifo.rbc_ram_end-1) ; - outpw(FM_A(FM_SWPR2),smc->hw.fp.fifo.rbc_ram_end-1) ; - outpw(FM_A(FM_WPR2),smc->hw.fp.fifo.rbc_ram_end-1) ; - outpw(FM_A(FM_EARV2),smc->hw.fp.fifo.rbc_ram_end-1) ; - } -} - -/* - * set transmit FIFO pointer - */ -static void set_txptr(struct s_smc *smc) -{ - outpw(FM_A(FM_CMDREG2),FM_IRSTQ) ; /* reset transmit queues */ - - /* - * initialize the pointer for asynchronous transmit queue - */ - outpw(FM_A(FM_RPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* RPXA0 */ - outpw(FM_A(FM_SWPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* SWPXA0 */ - outpw(FM_A(FM_WPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* WPXA0 */ - outpw(FM_A(FM_EAA0),smc->hw.fp.fifo.rx2_fifo_start-1) ; /* EAA0 */ - - /* - * initialize the pointer for synchronous transmit queue - */ - if (smc->hw.fp.fifo.tx_s_size) { - outpw(FM_A(FM_RPXS),smc->hw.fp.fifo.tx_s_start) ; - outpw(FM_A(FM_SWPXS),smc->hw.fp.fifo.tx_s_start) ; - outpw(FM_A(FM_WPXS),smc->hw.fp.fifo.tx_s_start) ; - outpw(FM_A(FM_EAS),smc->hw.fp.fifo.tx_a0_start-1) ; - } - else { - outpw(FM_A(FM_RPXS),smc->hw.fp.fifo.tx_a0_start-1) ; - outpw(FM_A(FM_SWPXS),smc->hw.fp.fifo.tx_a0_start-1) ; - outpw(FM_A(FM_WPXS),smc->hw.fp.fifo.tx_a0_start-1) ; - outpw(FM_A(FM_EAS),smc->hw.fp.fifo.tx_a0_start-1) ; - } -} - -/* - * init memory buffer management registers - */ -static void init_rbc(struct s_smc *smc) -{ - u_short rbc_ram_addr ; - - /* - * set unused pointers or permanent pointers - */ - rbc_ram_addr = smc->hw.fp.fifo.rx2_fifo_start - 1 ; - - outpw(FM_A(FM_RPXA1),rbc_ram_addr) ; /* a1-send pointer */ - outpw(FM_A(FM_WPXA1),rbc_ram_addr) ; - outpw(FM_A(FM_SWPXA1),rbc_ram_addr) ; - outpw(FM_A(FM_EAA1),rbc_ram_addr) ; - - set_recvptr(smc) ; - set_txptr(smc) ; -} - -/* - * init rx pointer - */ -static void init_rx(struct s_smc *smc) -{ - struct s_smt_rx_queue *queue ; - - /* - * init all tx data structures for receive queue 1 - */ - smc->hw.fp.rx[QUEUE_R1] = queue = &smc->hw.fp.rx_q[QUEUE_R1] ; - queue->rx_bmu_ctl = (HW_PTR) ADDR(B0_R1_CSR) ; - queue->rx_bmu_dsc = (HW_PTR) ADDR(B4_R1_DA) ; - - /* - * init all tx data structures for receive queue 2 - */ - smc->hw.fp.rx[QUEUE_R2] = queue = &smc->hw.fp.rx_q[QUEUE_R2] ; - queue->rx_bmu_ctl = (HW_PTR) ADDR(B0_R2_CSR) ; - queue->rx_bmu_dsc = (HW_PTR) ADDR(B4_R2_DA) ; -} - -/* - * set the TSYNC register of the FORMAC to regulate synchronous transmission - */ -void set_formac_tsync(struct s_smc *smc, long sync_bw) -{ - outpw(FM_A(FM_TSYNC),(unsigned int) (((-sync_bw) >> 5) & 0xffff) ) ; -} - -/* - * init all tx data structures - */ -static void init_tx(struct s_smc *smc) -{ - struct s_smt_tx_queue *queue ; - - /* - * init all tx data structures for the synchronous queue - */ - smc->hw.fp.tx[QUEUE_S] = queue = &smc->hw.fp.tx_q[QUEUE_S] ; - queue->tx_bmu_ctl = (HW_PTR) ADDR(B0_XS_CSR) ; - queue->tx_bmu_dsc = (HW_PTR) ADDR(B5_XS_DA) ; - -#ifdef ESS - set_formac_tsync(smc,smc->ess.sync_bw) ; -#endif - - /* - * init all tx data structures for the asynchronous queue 0 - */ - smc->hw.fp.tx[QUEUE_A0] = queue = &smc->hw.fp.tx_q[QUEUE_A0] ; - queue->tx_bmu_ctl = (HW_PTR) ADDR(B0_XA_CSR) ; - queue->tx_bmu_dsc = (HW_PTR) ADDR(B5_XA_DA) ; - - - llc_recover_tx(smc) ; -} - -static void mac_counter_init(struct s_smc *smc) -{ - int i ; - u_long *ec ; - - /* - * clear FORMAC+ frame-, lost- and error counter - */ - outpw(FM_A(FM_FCNTR),0) ; - outpw(FM_A(FM_LCNTR),0) ; - outpw(FM_A(FM_ECNTR),0) ; - /* - * clear internal error counter structure - */ - ec = (u_long *)&smc->hw.fp.err_stats ; - for (i = (sizeof(struct err_st)/sizeof(long)) ; i ; i--) - *ec++ = 0L ; - smc->mib.m[MAC0].fddiMACRingOp_Ct = 0 ; -} - -/* - * set FORMAC address, and t_request - */ -static void set_formac_addr(struct s_smc *smc) -{ - long t_requ = smc->mib.m[MAC0].fddiMACT_Req ; - - outpw(FM_A(FM_SAID),my_said) ; /* set short address */ - outpw(FM_A(FM_LAIL),(unsigned)((smc->hw.fddi_home_addr.a[4]<<8) + - smc->hw.fddi_home_addr.a[5])) ; - outpw(FM_A(FM_LAIC),(unsigned)((smc->hw.fddi_home_addr.a[2]<<8) + - smc->hw.fddi_home_addr.a[3])) ; - outpw(FM_A(FM_LAIM),(unsigned)((smc->hw.fddi_home_addr.a[0]<<8) + - smc->hw.fddi_home_addr.a[1])) ; - - outpw(FM_A(FM_SAGP),my_sagp) ; /* set short group address */ - - outpw(FM_A(FM_LAGL),(unsigned)((smc->hw.fp.group_addr.a[4]<<8) + - smc->hw.fp.group_addr.a[5])) ; - outpw(FM_A(FM_LAGC),(unsigned)((smc->hw.fp.group_addr.a[2]<<8) + - smc->hw.fp.group_addr.a[3])) ; - outpw(FM_A(FM_LAGM),(unsigned)((smc->hw.fp.group_addr.a[0]<<8) + - smc->hw.fp.group_addr.a[1])) ; - - /* set r_request regs. (MSW & LSW of TRT ) */ - outpw(FM_A(FM_TREQ1),(unsigned)(t_requ>>16)) ; - outpw(FM_A(FM_TREQ0),(unsigned)t_requ) ; -} - -static void set_int(char *p, int l) -{ - p[0] = (char)(l >> 24) ; - p[1] = (char)(l >> 16) ; - p[2] = (char)(l >> 8) ; - p[3] = (char)(l >> 0) ; -} - -/* - * copy TX descriptor to buffer mem - * append FC field and MAC frame - * if more bit is set in descr - * append pointer to descriptor (endless loop) - * else - * append 'end of chain' pointer - */ -static void copy_tx_mac(struct s_smc *smc, u_long td, struct fddi_mac *mac, - unsigned off, int len) -/* u_long td; transmit descriptor */ -/* struct fddi_mac *mac; mac frame pointer */ -/* unsigned off; start address within buffer memory */ -/* int len ; length of the frame including the FC */ -{ - int i ; - __le32 *p ; - - CHECK_NPP() ; - MARW(off) ; /* set memory address reg for writes */ - - p = (__le32 *) mac ; - for (i = (len + 3)/4 ; i ; i--) { - if (i == 1) { - /* last word, set the tag bit */ - outpw(FM_A(FM_CMDREG2),FM_ISTTB) ; - } - write_mdr(smc,le32_to_cpu(*p)) ; - p++ ; - } - - outpw(FM_A(FM_CMDREG2),FM_ISTTB) ; /* set the tag bit */ - write_mdr(smc,td) ; /* write over memory data reg to buffer */ -} - -/* - BEGIN_MANUAL_ENTRY(module;tests;3) - How to test directed beacon frames - ---------------------------------------------------------------- - - o Insert a break point in the function build_claim_beacon() - before calling copy_tx_mac() for building the claim frame. - o Modify the RM3_DETECT case so that the RM6_DETECT state - will always entered from the RM3_DETECT state (function rmt_fsm(), - rmt.c) - o Compile the driver. - o Set the parameter TREQ in the protocol.ini or net.cfg to a - small value to make sure your station will win the claim - process. - o Start the driver. - o When you reach the break point, modify the SA and DA address - of the claim frame (e.g. SA = DA = 10005affffff). - o When you see RM3_DETECT and RM6_DETECT, observe the direct - beacon frames on the UPPSLANA. - - END_MANUAL_ENTRY - */ -static void directed_beacon(struct s_smc *smc) -{ - SK_LOC_DECL(__le32,a[2]) ; - - /* - * set UNA in frame - * enable FORMAC to send endless queue of directed beacon - * important: the UNA starts at byte 1 (not at byte 0) - */ - * (char *) a = (char) ((long)DBEACON_INFO<<24L) ; - a[1] = 0 ; - memcpy((char *)a+1,(char *) &smc->mib.m[MAC0].fddiMACUpstreamNbr,6) ; - - CHECK_NPP() ; - /* set memory address reg for writes */ - MARW(smc->hw.fp.fifo.rbc_ram_start+DBEACON_FRAME_OFF+4) ; - write_mdr(smc,le32_to_cpu(a[0])) ; - outpw(FM_A(FM_CMDREG2),FM_ISTTB) ; /* set the tag bit */ - write_mdr(smc,le32_to_cpu(a[1])) ; - - outpw(FM_A(FM_SABC),smc->hw.fp.fifo.rbc_ram_start + DBEACON_FRAME_OFF) ; -} - -/* - setup claim & beacon pointer - NOTE : - special frame packets end with a pointer to their own - descriptor, and the MORE bit is set in the descriptor -*/ -static void build_claim_beacon(struct s_smc *smc, u_long t_request) -{ - u_int td ; - int len ; - struct fddi_mac_sf *mac ; - - /* - * build claim packet - */ - len = 17 ; - td = TX_DESCRIPTOR | ((((u_int)len-1)&3)<<27) ; - mac = &smc->hw.fp.mac_sfb ; - mac->mac_fc = FC_CLAIM ; - /* DA == SA in claim frame */ - mac->mac_source = mac->mac_dest = MA ; - /* 2's complement */ - set_int((char *)mac->mac_info,(int)t_request) ; - - copy_tx_mac(smc,td,(struct fddi_mac *)mac, - smc->hw.fp.fifo.rbc_ram_start + CLAIM_FRAME_OFF,len) ; - /* set CLAIM start pointer */ - outpw(FM_A(FM_SACL),smc->hw.fp.fifo.rbc_ram_start + CLAIM_FRAME_OFF) ; - - /* - * build beacon packet - */ - len = 17 ; - td = TX_DESCRIPTOR | ((((u_int)len-1)&3)<<27) ; - mac->mac_fc = FC_BEACON ; - mac->mac_source = MA ; - mac->mac_dest = null_addr ; /* DA == 0 in beacon frame */ - set_int((char *) mac->mac_info,((int)BEACON_INFO<<24) + 0 ) ; - - copy_tx_mac(smc,td,(struct fddi_mac *)mac, - smc->hw.fp.fifo.rbc_ram_start + BEACON_FRAME_OFF,len) ; - /* set beacon start pointer */ - outpw(FM_A(FM_SABC),smc->hw.fp.fifo.rbc_ram_start + BEACON_FRAME_OFF) ; - - /* - * build directed beacon packet - * contains optional UNA - */ - len = 23 ; - td = TX_DESCRIPTOR | ((((u_int)len-1)&3)<<27) ; - mac->mac_fc = FC_BEACON ; - mac->mac_source = MA ; - mac->mac_dest = dbeacon_multi ; /* multicast */ - set_int((char *) mac->mac_info,((int)DBEACON_INFO<<24) + 0 ) ; - set_int((char *) mac->mac_info+4,0) ; - set_int((char *) mac->mac_info+8,0) ; - - copy_tx_mac(smc,td,(struct fddi_mac *)mac, - smc->hw.fp.fifo.rbc_ram_start + DBEACON_FRAME_OFF,len) ; - - /* end of claim/beacon queue */ - outpw(FM_A(FM_EACB),smc->hw.fp.fifo.rx1_fifo_start-1) ; - - outpw(FM_A(FM_WPXSF),0) ; - outpw(FM_A(FM_RPXSF),0) ; -} - -static void formac_rcv_restart(struct s_smc *smc) -{ - /* enable receive function */ - SETMASK(FM_A(FM_MDREG1),smc->hw.fp.rx_mode,FM_ADDRX) ; - - outpw(FM_A(FM_CMDREG1),FM_ICLLR) ; /* clear receive lock */ -} - -void formac_tx_restart(struct s_smc *smc) -{ - outpw(FM_A(FM_CMDREG1),FM_ICLLS) ; /* clear s-frame lock */ - outpw(FM_A(FM_CMDREG1),FM_ICLLA0) ; /* clear a-frame lock */ -} - -static void enable_formac(struct s_smc *smc) -{ - /* set formac IMSK : 0 enables irq */ - outpw(FM_A(FM_IMSK1U),(unsigned short)~mac_imsk1u); - outpw(FM_A(FM_IMSK1L),(unsigned short)~mac_imsk1l); - outpw(FM_A(FM_IMSK2U),(unsigned short)~mac_imsk2u); - outpw(FM_A(FM_IMSK2L),(unsigned short)~mac_imsk2l); - outpw(FM_A(FM_IMSK3U),(unsigned short)~mac_imsk3u); - outpw(FM_A(FM_IMSK3L),(unsigned short)~mac_imsk3l); -} - -#if 0 /* Removed because the driver should use the ASICs TX complete IRQ. */ - /* The FORMACs tx complete IRQ should be used any longer */ - -/* - BEGIN_MANUAL_ENTRY(if,func;others;4) - - void enable_tx_irq(smc, queue) - struct s_smc *smc ; - u_short queue ; - -Function DOWNCALL (SMT, fplustm.c) - enable_tx_irq() enables the FORMACs transmit complete - interrupt of the queue. - -Para queue = QUEUE_S: synchronous queue - = QUEUE_A0: asynchronous queue - -Note After any ring operational change the transmit complete - interrupts are disabled. - The operating system dependent module must enable - the transmit complete interrupt of a queue, - - when it queues the first frame, - because of no transmit resources are beeing - available and - - when it escapes from the function llc_restart_tx - while some frames are still queued. - - END_MANUAL_ENTRY - */ -void enable_tx_irq(struct s_smc *smc, u_short queue) -/* u_short queue; 0 = synchronous queue, 1 = asynchronous queue 0 */ -{ - u_short imask ; - - imask = ~(inpw(FM_A(FM_IMSK1U))) ; - - if (queue == 0) { - outpw(FM_A(FM_IMSK1U),~(imask|FM_STEFRMS)) ; - } - if (queue == 1) { - outpw(FM_A(FM_IMSK1U),~(imask|FM_STEFRMA0)) ; - } -} - -/* - BEGIN_MANUAL_ENTRY(if,func;others;4) - - void disable_tx_irq(smc, queue) - struct s_smc *smc ; - u_short queue ; - -Function DOWNCALL (SMT, fplustm.c) - disable_tx_irq disables the FORMACs transmit complete - interrupt of the queue - -Para queue = QUEUE_S: synchronous queue - = QUEUE_A0: asynchronous queue - -Note The operating system dependent module should disable - the transmit complete interrupts if it escapes from the - function llc_restart_tx and no frames are queued. - - END_MANUAL_ENTRY - */ -void disable_tx_irq(struct s_smc *smc, u_short queue) -/* u_short queue; 0 = synchronous queue, 1 = asynchronous queue 0 */ -{ - u_short imask ; - - imask = ~(inpw(FM_A(FM_IMSK1U))) ; - - if (queue == 0) { - outpw(FM_A(FM_IMSK1U),~(imask&~FM_STEFRMS)) ; - } - if (queue == 1) { - outpw(FM_A(FM_IMSK1U),~(imask&~FM_STEFRMA0)) ; - } -} -#endif - -static void disable_formac(struct s_smc *smc) -{ - /* clear formac IMSK : 1 disables irq */ - outpw(FM_A(FM_IMSK1U),MW) ; - outpw(FM_A(FM_IMSK1L),MW) ; - outpw(FM_A(FM_IMSK2U),MW) ; - outpw(FM_A(FM_IMSK2L),MW) ; - outpw(FM_A(FM_IMSK3U),MW) ; - outpw(FM_A(FM_IMSK3L),MW) ; -} - - -static void mac_ring_up(struct s_smc *smc, int up) -{ - if (up) { - formac_rcv_restart(smc) ; /* enable receive function */ - smc->hw.mac_ring_is_up = TRUE ; - llc_restart_tx(smc) ; /* TX queue */ - } - else { - /* disable receive function */ - SETMASK(FM_A(FM_MDREG1),FM_MDISRCV,FM_ADDET) ; - - /* abort current transmit activity */ - outpw(FM_A(FM_CMDREG2),FM_IACTR) ; - - smc->hw.mac_ring_is_up = FALSE ; - } -} - -/*--------------------------- ISR handling ----------------------------------*/ -/* - * mac1_irq is in drvfbi.c - */ - -/* - * mac2_irq: status bits for the receive queue 1, and ring status - * ring status indication bits - */ -void mac2_irq(struct s_smc *smc, u_short code_s2u, u_short code_s2l) -{ - u_short change_s2l ; - u_short change_s2u ; - - /* (jd) 22-Feb-1999 - * Restart 2_DMax Timer after end of claiming or beaconing - */ - if (code_s2u & (FM_SCLM|FM_SHICLM|FM_SBEC|FM_SOTRBEC)) { - queue_event(smc,EVENT_RMT,RM_TX_STATE_CHANGE) ; - } - else if (code_s2l & (FM_STKISS)) { - queue_event(smc,EVENT_RMT,RM_TX_STATE_CHANGE) ; - } - - /* - * XOR current st bits with the last to avoid useless RMT event queuing - */ - change_s2l = smc->hw.fp.s2l ^ code_s2l ; - change_s2u = smc->hw.fp.s2u ^ code_s2u ; - - if ((change_s2l & FM_SRNGOP) || - (!smc->hw.mac_ring_is_up && ((code_s2l & FM_SRNGOP)))) { - if (code_s2l & FM_SRNGOP) { - mac_ring_up(smc,1) ; - queue_event(smc,EVENT_RMT,RM_RING_OP) ; - smc->mib.m[MAC0].fddiMACRingOp_Ct++ ; - } - else { - mac_ring_up(smc,0) ; - queue_event(smc,EVENT_RMT,RM_RING_NON_OP) ; - } - goto mac2_end ; - } - if (code_s2l & FM_SMISFRM) { /* missed frame */ - smc->mib.m[MAC0].fddiMACNotCopied_Ct++ ; - } - if (code_s2u & (FM_SRCVOVR | /* recv. FIFO overflow */ - FM_SRBFL)) { /* recv. buffer full */ - smc->hw.mac_ct.mac_r_restart_counter++ ; -/* formac_rcv_restart(smc) ; */ - smt_stat_counter(smc,1) ; -/* goto mac2_end ; */ - } - if (code_s2u & FM_SOTRBEC) - queue_event(smc,EVENT_RMT,RM_OTHER_BEACON) ; - if (code_s2u & FM_SMYBEC) - queue_event(smc,EVENT_RMT,RM_MY_BEACON) ; - if (change_s2u & code_s2u & FM_SLOCLM) { - DB_RMTN(2,"RMT : lower claim received\n",0,0) ; - } - if ((code_s2u & FM_SMYCLM) && !(code_s2l & FM_SDUPCLM)) { - /* - * This is my claim and that claim is not detected as a - * duplicate one. - */ - queue_event(smc,EVENT_RMT,RM_MY_CLAIM) ; - } - if (code_s2l & FM_SDUPCLM) { - /* - * If a duplicate claim frame (same SA but T_Bid != T_Req) - * this flag will be set. - * In the RMT state machine we need a RM_VALID_CLAIM event - * to do the appropriate state change. - * RM(34c) - */ - queue_event(smc,EVENT_RMT,RM_VALID_CLAIM) ; - } - if (change_s2u & code_s2u & FM_SHICLM) { - DB_RMTN(2,"RMT : higher claim received\n",0,0) ; - } - if ( (code_s2l & FM_STRTEXP) || - (code_s2l & FM_STRTEXR) ) - queue_event(smc,EVENT_RMT,RM_TRT_EXP) ; - if (code_s2l & FM_SMULTDA) { - /* - * The MAC has found a 2. MAC with the same address. - * Signal dup_addr_test = failed to RMT state machine. - * RM(25) - */ - smc->r.dup_addr_test = DA_FAILED ; - queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ; - } - if (code_s2u & FM_SBEC) - smc->hw.fp.err_stats.err_bec_stat++ ; - if (code_s2u & FM_SCLM) - smc->hw.fp.err_stats.err_clm_stat++ ; - if (code_s2l & FM_STVXEXP) - smc->mib.m[MAC0].fddiMACTvxExpired_Ct++ ; - if ((code_s2u & (FM_SBEC|FM_SCLM))) { - if (!(change_s2l & FM_SRNGOP) && (smc->hw.fp.s2l & FM_SRNGOP)) { - mac_ring_up(smc,0) ; - queue_event(smc,EVENT_RMT,RM_RING_NON_OP) ; - - mac_ring_up(smc,1) ; - queue_event(smc,EVENT_RMT,RM_RING_OP) ; - smc->mib.m[MAC0].fddiMACRingOp_Ct++ ; - } - } - if (code_s2l & FM_SPHINV) - smc->hw.fp.err_stats.err_phinv++ ; - if (code_s2l & FM_SSIFG) - smc->hw.fp.err_stats.err_sifg_det++ ; - if (code_s2l & FM_STKISS) - smc->hw.fp.err_stats.err_tkiss++ ; - if (code_s2l & FM_STKERR) - smc->hw.fp.err_stats.err_tkerr++ ; - if (code_s2l & FM_SFRMCTR) - smc->mib.m[MAC0].fddiMACFrame_Ct += 0x10000L ; - if (code_s2l & FM_SERRCTR) - smc->mib.m[MAC0].fddiMACError_Ct += 0x10000L ; - if (code_s2l & FM_SLSTCTR) - smc->mib.m[MAC0].fddiMACLost_Ct += 0x10000L ; - if (code_s2u & FM_SERRSF) { - SMT_PANIC(smc,SMT_E0114, SMT_E0114_MSG) ; - } -mac2_end: - /* notice old status */ - smc->hw.fp.s2l = code_s2l ; - smc->hw.fp.s2u = code_s2u ; - outpw(FM_A(FM_IMSK2U),~mac_imsk2u) ; -} - -/* - * mac3_irq: receive queue 2 bits and address detection bits - */ -void mac3_irq(struct s_smc *smc, u_short code_s3u, u_short code_s3l) -{ - UNUSED(code_s3l) ; - - if (code_s3u & (FM_SRCVOVR2 | /* recv. FIFO overflow */ - FM_SRBFL2)) { /* recv. buffer full */ - smc->hw.mac_ct.mac_r_restart_counter++ ; - smt_stat_counter(smc,1); - } - - - if (code_s3u & FM_SRPERRQ2) { /* parity error receive queue 2 */ - SMT_PANIC(smc,SMT_E0115, SMT_E0115_MSG) ; - } - if (code_s3u & FM_SRPERRQ1) { /* parity error receive queue 2 */ - SMT_PANIC(smc,SMT_E0116, SMT_E0116_MSG) ; - } -} - - -/* - * take formac offline - */ -static void formac_offline(struct s_smc *smc) -{ - outpw(FM_A(FM_CMDREG2),FM_IACTR) ;/* abort current transmit activity */ - - /* disable receive function */ - SETMASK(FM_A(FM_MDREG1),FM_MDISRCV,FM_ADDET) ; - - /* FORMAC+ 'Initialize Mode' */ - SETMASK(FM_A(FM_MDREG1),FM_MINIT,FM_MMODE) ; - - disable_formac(smc) ; - smc->hw.mac_ring_is_up = FALSE ; - smc->hw.hw_state = STOPPED ; -} - -/* - * bring formac online - */ -static void formac_online(struct s_smc *smc) -{ - enable_formac(smc) ; - SETMASK(FM_A(FM_MDREG1),FM_MONLINE | FM_SELRA | MDR1INIT | - smc->hw.fp.rx_mode, FM_MMODE | FM_SELRA | FM_ADDRX) ; -} - -/* - * FORMAC+ full init. (tx, rx, timer, counter, claim & beacon) - */ -int init_fplus(struct s_smc *smc) -{ - smc->hw.fp.nsa_mode = FM_MRNNSAFNMA ; - smc->hw.fp.rx_mode = FM_MDAMA ; - smc->hw.fp.group_addr = fddi_broadcast ; - smc->hw.fp.func_addr = 0 ; - smc->hw.fp.frselreg_init = 0 ; - - init_driver_fplus(smc) ; - if (smc->s.sas == SMT_DAS) - smc->hw.fp.mdr3init |= FM_MENDAS ; - - smc->hw.mac_ct.mac_nobuf_counter = 0 ; - smc->hw.mac_ct.mac_r_restart_counter = 0 ; - - smc->hw.fp.fm_st1u = (HW_PTR) ADDR(B0_ST1U) ; - smc->hw.fp.fm_st1l = (HW_PTR) ADDR(B0_ST1L) ; - smc->hw.fp.fm_st2u = (HW_PTR) ADDR(B0_ST2U) ; - smc->hw.fp.fm_st2l = (HW_PTR) ADDR(B0_ST2L) ; - smc->hw.fp.fm_st3u = (HW_PTR) ADDR(B0_ST3U) ; - smc->hw.fp.fm_st3l = (HW_PTR) ADDR(B0_ST3L) ; - - smc->hw.fp.s2l = smc->hw.fp.s2u = 0 ; - smc->hw.mac_ring_is_up = 0 ; - - mac_counter_init(smc) ; - - /* convert BCKL units to symbol time */ - smc->hw.mac_pa.t_neg = (u_long)0 ; - smc->hw.mac_pa.t_pri = (u_long)0 ; - - /* make sure all PCI settings are correct */ - mac_do_pci_fix(smc) ; - - return init_mac(smc, 1); - /* enable_formac(smc) ; */ -} - -static int init_mac(struct s_smc *smc, int all) -{ - u_short t_max,x ; - u_long time=0 ; - - /* - * clear memory - */ - outpw(FM_A(FM_MDREG1),FM_MINIT) ; /* FORMAC+ init mode */ - set_formac_addr(smc) ; - outpw(FM_A(FM_MDREG1),FM_MMEMACT) ; /* FORMAC+ memory activ mode */ - /* Note: Mode register 2 is set here, incase parity is enabled. */ - outpw(FM_A(FM_MDREG2),smc->hw.fp.mdr2init) ; - - if (all) { - init_ram(smc) ; - } - else { - /* - * reset the HPI, the Master and the BMUs - */ - outp(ADDR(B0_CTRL), CTRL_HPI_SET) ; - time = hwt_quick_read(smc) ; - } - - /* - * set all pointers, frames etc - */ - smt_split_up_fifo(smc) ; - - init_tx(smc) ; - init_rx(smc) ; - init_rbc(smc) ; - - build_claim_beacon(smc,smc->mib.m[MAC0].fddiMACT_Req) ; - - /* set RX threshold */ - /* see Errata #SN2 Phantom receive overflow */ - outpw(FM_A(FM_FRMTHR),14<<12) ; /* switch on */ - - /* set formac work mode */ - outpw(FM_A(FM_MDREG1),MDR1INIT | FM_SELRA | smc->hw.fp.rx_mode) ; - outpw(FM_A(FM_MDREG2),smc->hw.fp.mdr2init) ; - outpw(FM_A(FM_MDREG3),smc->hw.fp.mdr3init) ; - outpw(FM_A(FM_FRSELREG),smc->hw.fp.frselreg_init) ; - - /* set timer */ - /* - * errata #22 fplus: - * T_MAX must not be FFFE - * or one of FFDF, FFB8, FF91 (-0x27 etc..) - */ - t_max = (u_short)(smc->mib.m[MAC0].fddiMACT_Max/32) ; - x = t_max/0x27 ; - x *= 0x27 ; - if ((t_max == 0xfffe) || (t_max - x == 0x16)) - t_max-- ; - outpw(FM_A(FM_TMAX),(u_short)t_max) ; - - /* BugFix for report #10204 */ - if (smc->mib.m[MAC0].fddiMACTvxValue < (u_long) (- US2BCLK(52))) { - outpw(FM_A(FM_TVX), (u_short) (- US2BCLK(52))/255 & MB) ; - } else { - outpw(FM_A(FM_TVX), - (u_short)((smc->mib.m[MAC0].fddiMACTvxValue/255) & MB)) ; - } - - outpw(FM_A(FM_CMDREG1),FM_ICLLS) ; /* clear s-frame lock */ - outpw(FM_A(FM_CMDREG1),FM_ICLLA0) ; /* clear a-frame lock */ - outpw(FM_A(FM_CMDREG1),FM_ICLLR); /* clear receive lock */ - - /* Auto unlock receice threshold for receive queue 1 and 2 */ - outpw(FM_A(FM_UNLCKDLY),(0xff|(0xff<<8))) ; - - rtm_init(smc) ; /* RT-Monitor */ - - if (!all) { - /* - * after 10ms, reset the BMUs and repair the rings - */ - hwt_wait_time(smc,time,MS2BCLK(10)) ; - outpd(ADDR(B0_R1_CSR),CSR_SET_RESET) ; - outpd(ADDR(B0_XA_CSR),CSR_SET_RESET) ; - outpd(ADDR(B0_XS_CSR),CSR_SET_RESET) ; - outp(ADDR(B0_CTRL), CTRL_HPI_CLR) ; - outpd(ADDR(B0_R1_CSR),CSR_CLR_RESET) ; - outpd(ADDR(B0_XA_CSR),CSR_CLR_RESET) ; - outpd(ADDR(B0_XS_CSR),CSR_CLR_RESET) ; - if (!smc->hw.hw_is_64bit) { - outpd(ADDR(B4_R1_F), RX_WATERMARK) ; - outpd(ADDR(B5_XA_F), TX_WATERMARK) ; - outpd(ADDR(B5_XS_F), TX_WATERMARK) ; - } - smc->hw.hw_state = STOPPED ; - mac_drv_repair_descr(smc) ; - } - smc->hw.hw_state = STARTED ; - - return 0; -} - - -/* - * called by CFM - */ -void config_mux(struct s_smc *smc, int mux) -{ - plc_config_mux(smc,mux) ; - - SETMASK(FM_A(FM_MDREG1),FM_SELRA,FM_SELRA) ; -} - -/* - * called by RMT - * enable CLAIM/BEACON interrupts - * (only called if these events are of interest, e.g. in DETECT state - * the interrupt must not be permanently enabled - * RMT calls this function periodically (timer driven polling) - */ -void sm_mac_check_beacon_claim(struct s_smc *smc) -{ - /* set formac IMSK : 0 enables irq */ - outpw(FM_A(FM_IMSK2U),~(mac_imsk2u | mac_beacon_imsk2u)) ; - /* the driver must receive the directed beacons */ - formac_rcv_restart(smc) ; - process_receive(smc) ; -} - -/*-------------------------- interface functions ----------------------------*/ -/* - * control MAC layer (called by RMT) - */ -void sm_ma_control(struct s_smc *smc, int mode) -{ - switch(mode) { - case MA_OFFLINE : - /* Add to make the MAC offline in RM0_ISOLATED state */ - formac_offline(smc) ; - break ; - case MA_RESET : - (void)init_mac(smc,0) ; - break ; - case MA_BEACON : - formac_online(smc) ; - break ; - case MA_DIRECTED : - directed_beacon(smc) ; - break ; - case MA_TREQ : - /* - * no actions necessary, TREQ is already set - */ - break ; - } -} - -int sm_mac_get_tx_state(struct s_smc *smc) -{ - return (inpw(FM_A(FM_STMCHN))>>4) & 7; -} - -/* - * multicast functions - */ - -static struct s_fpmc* mac_get_mc_table(struct s_smc *smc, - struct fddi_addr *user, - struct fddi_addr *own, - int del, int can) -{ - struct s_fpmc *tb ; - struct s_fpmc *slot ; - u_char *p ; - int i ; - - /* - * set own = can(user) - */ - *own = *user ; - if (can) { - p = own->a ; - for (i = 0 ; i < 6 ; i++, p++) - *p = bitrev8(*p); - } - slot = NULL; - for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){ - if (!tb->n) { /* not used */ - if (!del && !slot) /* if !del save first free */ - slot = tb ; - continue ; - } - if (memcmp((char *)&tb->a,(char *)own,6)) - continue ; - return tb; - } - return slot; /* return first free or NULL */ -} - -/* - BEGIN_MANUAL_ENTRY(if,func;others;2) - - void mac_clear_multicast(smc) - struct s_smc *smc ; - -Function DOWNCALL (SMT, fplustm.c) - Clear all multicast entries - - END_MANUAL_ENTRY() - */ -void mac_clear_multicast(struct s_smc *smc) -{ - struct s_fpmc *tb ; - int i ; - - smc->hw.fp.os_slots_used = 0 ; /* note the SMT addresses */ - /* will not be deleted */ - for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){ - if (!tb->perm) { - tb->n = 0 ; - } - } -} - -/* - BEGIN_MANUAL_ENTRY(if,func;others;2) - - int mac_add_multicast(smc,addr,can) - struct s_smc *smc ; - struct fddi_addr *addr ; - int can ; - -Function DOWNCALL (SMC, fplustm.c) - Add an entry to the multicast table - -Para addr pointer to a multicast address - can = 0: the multicast address has the physical format - = 1: the multicast address has the canonical format - | 0x80 permanent - -Returns 0: success - 1: address table full - -Note After a 'driver reset' or a 'station set address' all - entries of the multicast table are cleared. - In this case the driver has to fill the multicast table again. - After the operating system dependent module filled - the multicast table it must call mac_update_multicast - to activate the new multicast addresses! - - END_MANUAL_ENTRY() - */ -int mac_add_multicast(struct s_smc *smc, struct fddi_addr *addr, int can) -{ - SK_LOC_DECL(struct fddi_addr,own) ; - struct s_fpmc *tb ; - - /* - * check if there are free table entries - */ - if (can & 0x80) { - if (smc->hw.fp.smt_slots_used >= SMT_MAX_MULTI) { - return 1; - } - } - else { - if (smc->hw.fp.os_slots_used >= FPMAX_MULTICAST-SMT_MAX_MULTI) { - return 1; - } - } - - /* - * find empty slot - */ - if (!(tb = mac_get_mc_table(smc,addr,&own,0,can & ~0x80))) - return 1; - tb->n++ ; - tb->a = own ; - tb->perm = (can & 0x80) ? 1 : 0 ; - - if (can & 0x80) - smc->hw.fp.smt_slots_used++ ; - else - smc->hw.fp.os_slots_used++ ; - - return 0; -} - -/* - * mode - */ - -#define RX_MODE_PROM 0x1 -#define RX_MODE_ALL_MULTI 0x2 - -/* - BEGIN_MANUAL_ENTRY(if,func;others;2) - - void mac_update_multicast(smc) - struct s_smc *smc ; - -Function DOWNCALL (SMT, fplustm.c) - Update FORMAC multicast registers - - END_MANUAL_ENTRY() - */ -void mac_update_multicast(struct s_smc *smc) -{ - struct s_fpmc *tb ; - u_char *fu ; - int i ; - - /* - * invalidate the CAM - */ - outpw(FM_A(FM_AFCMD),FM_IINV_CAM) ; - - /* - * set the functional address - */ - if (smc->hw.fp.func_addr) { - fu = (u_char *) &smc->hw.fp.func_addr ; - outpw(FM_A(FM_AFMASK2),0xffff) ; - outpw(FM_A(FM_AFMASK1),(u_short) ~((fu[0] << 8) + fu[1])) ; - outpw(FM_A(FM_AFMASK0),(u_short) ~((fu[2] << 8) + fu[3])) ; - outpw(FM_A(FM_AFPERS),FM_VALID|FM_DA) ; - outpw(FM_A(FM_AFCOMP2), 0xc000) ; - outpw(FM_A(FM_AFCOMP1), 0x0000) ; - outpw(FM_A(FM_AFCOMP0), 0x0000) ; - outpw(FM_A(FM_AFCMD),FM_IWRITE_CAM) ; - } - - /* - * set the mask and the personality register(s) - */ - outpw(FM_A(FM_AFMASK0),0xffff) ; - outpw(FM_A(FM_AFMASK1),0xffff) ; - outpw(FM_A(FM_AFMASK2),0xffff) ; - outpw(FM_A(FM_AFPERS),FM_VALID|FM_DA) ; - - for (i = 0, tb = smc->hw.fp.mc.table; i < FPMAX_MULTICAST; i++, tb++) { - if (tb->n) { - CHECK_CAM() ; - - /* - * write the multicast address into the CAM - */ - outpw(FM_A(FM_AFCOMP2), - (u_short)((tb->a.a[0]<<8)+tb->a.a[1])) ; - outpw(FM_A(FM_AFCOMP1), - (u_short)((tb->a.a[2]<<8)+tb->a.a[3])) ; - outpw(FM_A(FM_AFCOMP0), - (u_short)((tb->a.a[4]<<8)+tb->a.a[5])) ; - outpw(FM_A(FM_AFCMD),FM_IWRITE_CAM) ; - } - } -} - -/* - BEGIN_MANUAL_ENTRY(if,func;others;3) - - void mac_set_rx_mode(smc,mode) - struct s_smc *smc ; - int mode ; - -Function DOWNCALL/INTERN (SMT, fplustm.c) - This function enables / disables the selected receive. - Don't call this function if the hardware module is - used -- use mac_drv_rx_mode() instead of. - -Para mode = 1 RX_ENABLE_ALLMULTI enable all multicasts - 2 RX_DISABLE_ALLMULTI disable "enable all multicasts" - 3 RX_ENABLE_PROMISC enable promiscuous - 4 RX_DISABLE_PROMISC disable promiscuous - 5 RX_ENABLE_NSA enable reception of NSA frames - 6 RX_DISABLE_NSA disable reception of NSA frames - -Note The selected receive modes will be lost after 'driver reset' - or 'set station address' - - END_MANUAL_ENTRY - */ -void mac_set_rx_mode(struct s_smc *smc, int mode) -{ - switch (mode) { - case RX_ENABLE_ALLMULTI : - smc->hw.fp.rx_prom |= RX_MODE_ALL_MULTI ; - break ; - case RX_DISABLE_ALLMULTI : - smc->hw.fp.rx_prom &= ~RX_MODE_ALL_MULTI ; - break ; - case RX_ENABLE_PROMISC : - smc->hw.fp.rx_prom |= RX_MODE_PROM ; - break ; - case RX_DISABLE_PROMISC : - smc->hw.fp.rx_prom &= ~RX_MODE_PROM ; - break ; - case RX_ENABLE_NSA : - smc->hw.fp.nsa_mode = FM_MDAMA ; - smc->hw.fp.rx_mode = (smc->hw.fp.rx_mode & ~FM_ADDET) | - smc->hw.fp.nsa_mode ; - break ; - case RX_DISABLE_NSA : - smc->hw.fp.nsa_mode = FM_MRNNSAFNMA ; - smc->hw.fp.rx_mode = (smc->hw.fp.rx_mode & ~FM_ADDET) | - smc->hw.fp.nsa_mode ; - break ; - } - if (smc->hw.fp.rx_prom & RX_MODE_PROM) { - smc->hw.fp.rx_mode = FM_MLIMPROM ; - } - else if (smc->hw.fp.rx_prom & RX_MODE_ALL_MULTI) { - smc->hw.fp.rx_mode = smc->hw.fp.nsa_mode | FM_EXGPA0 ; - } - else - smc->hw.fp.rx_mode = smc->hw.fp.nsa_mode ; - SETMASK(FM_A(FM_MDREG1),smc->hw.fp.rx_mode,FM_ADDRX) ; - mac_update_multicast(smc) ; -} - -/* - BEGIN_MANUAL_ENTRY(module;tests;3) - How to test the Restricted Token Monitor - ---------------------------------------------------------------- - - o Insert a break point in the function rtm_irq() - o Remove all stations with a restricted token monitor from the - network. - o Connect a UPPS ISA or EISA station to the network. - o Give the FORMAC of UPPS station the command to send - restricted tokens until the ring becomes instable. - o Now connect your test test client. - o The restricted token monitor should detect the restricted token, - and your break point will be reached. - o You can ovserve how the station will clean the ring. - - END_MANUAL_ENTRY - */ -void rtm_irq(struct s_smc *smc) -{ - outpw(ADDR(B2_RTM_CRTL),TIM_CL_IRQ) ; /* clear IRQ */ - if (inpw(ADDR(B2_RTM_CRTL)) & TIM_RES_TOK) { - outpw(FM_A(FM_CMDREG1),FM_ICL) ; /* force claim */ - DB_RMT("RMT: fddiPATHT_Rmode expired\n",0,0) ; - AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, - (u_long) FDDI_SMT_EVENT, - (u_long) FDDI_RTT, smt_get_event_word(smc)); - } - outpw(ADDR(B2_RTM_CRTL),TIM_START) ; /* enable RTM monitoring */ -} - -static void rtm_init(struct s_smc *smc) -{ - outpd(ADDR(B2_RTM_INI),0) ; /* timer = 0 */ - outpw(ADDR(B2_RTM_CRTL),TIM_START) ; /* enable IRQ */ -} - -void rtm_set_timer(struct s_smc *smc) -{ - /* - * MIB timer and hardware timer have the same resolution of 80nS - */ - DB_RMT("RMT: setting new fddiPATHT_Rmode, t = %d ns\n", - (int) smc->mib.a[PATH0].fddiPATHT_Rmode,0) ; - outpd(ADDR(B2_RTM_INI),smc->mib.a[PATH0].fddiPATHT_Rmode) ; -} - -static void smt_split_up_fifo(struct s_smc *smc) -{ - -/* - BEGIN_MANUAL_ENTRY(module;mem;1) - ------------------------------------------------------------- - RECEIVE BUFFER MEMORY DIVERSION - ------------------------------------------------------------- - - R1_RxD == SMT_R1_RXD_COUNT - R2_RxD == SMT_R2_RXD_COUNT - - SMT_R1_RXD_COUNT must be unequal zero - - | R1_RxD R2_RxD |R1_RxD R2_RxD | R1_RxD R2_RxD - | x 0 | x 1-3 | x < 3 - ---------------------------------------------------------------------- - | 63,75 kB | 54,75 | R1_RxD - rx queue 1 | RX_FIFO_SPACE | RX_LARGE_FIFO| ------------- * 63,75 kB - | | | R1_RxD+R2_RxD - ---------------------------------------------------------------------- - | | 9 kB | R2_RxD - rx queue 2 | 0 kB | RX_SMALL_FIFO| ------------- * 63,75 kB - | (not used) | | R1_RxD+R2_RxD - - END_MANUAL_ENTRY -*/ - - if (SMT_R1_RXD_COUNT == 0) { - SMT_PANIC(smc,SMT_E0117, SMT_E0117_MSG) ; - } - - switch(SMT_R2_RXD_COUNT) { - case 0: - smc->hw.fp.fifo.rx1_fifo_size = RX_FIFO_SPACE ; - smc->hw.fp.fifo.rx2_fifo_size = 0 ; - break ; - case 1: - case 2: - case 3: - smc->hw.fp.fifo.rx1_fifo_size = RX_LARGE_FIFO ; - smc->hw.fp.fifo.rx2_fifo_size = RX_SMALL_FIFO ; - break ; - default: /* this is not the real defaule */ - smc->hw.fp.fifo.rx1_fifo_size = RX_FIFO_SPACE * - SMT_R1_RXD_COUNT/(SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) ; - smc->hw.fp.fifo.rx2_fifo_size = RX_FIFO_SPACE * - SMT_R2_RXD_COUNT/(SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) ; - break ; - } - -/* - BEGIN_MANUAL_ENTRY(module;mem;1) - ------------------------------------------------------------- - TRANSMIT BUFFER MEMORY DIVERSION - ------------------------------------------------------------- - - - | no sync bw | sync bw available and | sync bw available and - | available | SynchTxMode = SPLIT | SynchTxMode = ALL - ----------------------------------------------------------------------- - sync tx | 0 kB | 32 kB | 55 kB - queue | | TX_MEDIUM_FIFO | TX_LARGE_FIFO - ----------------------------------------------------------------------- - async tx | 64 kB | 32 kB | 9 k - queue | TX_FIFO_SPACE| TX_MEDIUM_FIFO | TX_SMALL_FIFO - - END_MANUAL_ENTRY -*/ - - /* - * set the tx mode bits - */ - if (smc->mib.a[PATH0].fddiPATHSbaPayload) { -#ifdef ESS - smc->hw.fp.fifo.fifo_config_mode |= - smc->mib.fddiESSSynchTxMode | SYNC_TRAFFIC_ON ; -#endif - } - else { - smc->hw.fp.fifo.fifo_config_mode &= - ~(SEND_ASYNC_AS_SYNC|SYNC_TRAFFIC_ON) ; - } - - /* - * split up the FIFO - */ - if (smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON) { - if (smc->hw.fp.fifo.fifo_config_mode & SEND_ASYNC_AS_SYNC) { - smc->hw.fp.fifo.tx_s_size = TX_LARGE_FIFO ; - smc->hw.fp.fifo.tx_a0_size = TX_SMALL_FIFO ; - } - else { - smc->hw.fp.fifo.tx_s_size = TX_MEDIUM_FIFO ; - smc->hw.fp.fifo.tx_a0_size = TX_MEDIUM_FIFO ; - } - } - else { - smc->hw.fp.fifo.tx_s_size = 0 ; - smc->hw.fp.fifo.tx_a0_size = TX_FIFO_SPACE ; - } - - smc->hw.fp.fifo.rx1_fifo_start = smc->hw.fp.fifo.rbc_ram_start + - RX_FIFO_OFF ; - smc->hw.fp.fifo.tx_s_start = smc->hw.fp.fifo.rx1_fifo_start + - smc->hw.fp.fifo.rx1_fifo_size ; - smc->hw.fp.fifo.tx_a0_start = smc->hw.fp.fifo.tx_s_start + - smc->hw.fp.fifo.tx_s_size ; - smc->hw.fp.fifo.rx2_fifo_start = smc->hw.fp.fifo.tx_a0_start + - smc->hw.fp.fifo.tx_a0_size ; - - DB_SMT("FIFO split: mode = %x\n",smc->hw.fp.fifo.fifo_config_mode,0) ; - DB_SMT("rbc_ram_start = %x rbc_ram_end = %x\n", - smc->hw.fp.fifo.rbc_ram_start, smc->hw.fp.fifo.rbc_ram_end) ; - DB_SMT("rx1_fifo_start = %x tx_s_start = %x\n", - smc->hw.fp.fifo.rx1_fifo_start, smc->hw.fp.fifo.tx_s_start) ; - DB_SMT("tx_a0_start = %x rx2_fifo_start = %x\n", - smc->hw.fp.fifo.tx_a0_start, smc->hw.fp.fifo.rx2_fifo_start) ; -} - -void formac_reinit_tx(struct s_smc *smc) -{ - /* - * Split up the FIFO and reinitialize the MAC if synchronous - * bandwidth becomes available but no synchronous queue is - * configured. - */ - if (!smc->hw.fp.fifo.tx_s_size && smc->mib.a[PATH0].fddiPATHSbaPayload){ - (void)init_mac(smc,0) ; - } -} - diff --git a/drivers/net/skfp/h/cmtdef.h b/drivers/net/skfp/h/cmtdef.h deleted file mode 100644 index 5a6c612..0000000 --- a/drivers/net/skfp/h/cmtdef.h +++ /dev/null @@ -1,756 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -#ifndef _CMTDEF_ -#define _CMTDEF_ - -/* **************************************************************** */ - -/* - * implementation specific constants - * MODIIFY THE FOLLOWING THREE DEFINES - */ -#define AMDPLC /* if Amd PLC chip used */ -#ifdef CONC -#define NUMPHYS 12 /* 2 for SAS or DAS, more for Concentrator */ -#else -#ifdef CONC_II -#define NUMPHYS 24 /* 2 for SAS or DAS, more for Concentrator */ -#else -#define NUMPHYS 2 /* 2 for SAS or DAS, more for Concentrator */ -#endif -#endif -#define NUMMACS 1 /* only 1 supported at the moment */ -#define NUMPATHS 2 /* primary and secondary path supported */ - -/* - * DO NOT MODIFY BEYOND THIS POINT - */ - -/* **************************************************************** */ - -#if NUMPHYS > 2 -#define CONCENTRATOR -#endif - -/* - * Definitions for comfortable LINT usage - */ -#ifdef lint -#define LINT_USE(x) (x)=(x) -#else -#define LINT_USE(x) -#endif - -#ifdef DEBUG -#define DB_PR(flag,a,b,c) { if (flag) printf(a,b,c) ; } -#else -#define DB_PR(flag,a,b,c) -#endif - -#ifdef DEBUG_BRD -#define DB_ECM(a,b,c) DB_PR((smc->debug.d_smt&1),a,b,c) -#define DB_ECMN(n,a,b,c) DB_PR((smc->debug.d_ecm >=(n)),a,b,c) -#define DB_RMT(a,b,c) DB_PR((smc->debug.d_smt&2),a,b,c) -#define DB_RMTN(n,a,b,c) DB_PR((smc->debug.d_rmt >=(n)),a,b,c) -#define DB_CFM(a,b,c) DB_PR((smc->debug.d_smt&4),a,b,c) -#define DB_CFMN(n,a,b,c) DB_PR((smc->debug.d_cfm >=(n)),a,b,c) -#define DB_PCM(a,b,c) DB_PR((smc->debug.d_smt&8),a,b,c) -#define DB_PCMN(n,a,b,c) DB_PR((smc->debug.d_pcm >=(n)),a,b,c) -#define DB_SMT(a,b,c) DB_PR((smc->debug.d_smtf),a,b,c) -#define DB_SMTN(n,a,b,c) DB_PR((smc->debug.d_smtf >=(n)),a,b,c) -#define DB_SBA(a,b,c) DB_PR((smc->debug.d_sba),a,b,c) -#define DB_SBAN(n,a,b,c) DB_PR((smc->debug.d_sba >=(n)),a,b,c) -#define DB_ESS(a,b,c) DB_PR((smc->debug.d_ess),a,b,c) -#define DB_ESSN(n,a,b,c) DB_PR((smc->debug.d_ess >=(n)),a,b,c) -#else -#define DB_ECM(a,b,c) DB_PR((debug.d_smt&1),a,b,c) -#define DB_ECMN(n,a,b,c) DB_PR((debug.d_ecm >=(n)),a,b,c) -#define DB_RMT(a,b,c) DB_PR((debug.d_smt&2),a,b,c) -#define DB_RMTN(n,a,b,c) DB_PR((debug.d_rmt >=(n)),a,b,c) -#define DB_CFM(a,b,c) DB_PR((debug.d_smt&4),a,b,c) -#define DB_CFMN(n,a,b,c) DB_PR((debug.d_cfm >=(n)),a,b,c) -#define DB_PCM(a,b,c) DB_PR((debug.d_smt&8),a,b,c) -#define DB_PCMN(n,a,b,c) DB_PR((debug.d_pcm >=(n)),a,b,c) -#define DB_SMT(a,b,c) DB_PR((debug.d_smtf),a,b,c) -#define DB_SMTN(n,a,b,c) DB_PR((debug.d_smtf >=(n)),a,b,c) -#define DB_SBA(a,b,c) DB_PR((debug.d_sba),a,b,c) -#define DB_SBAN(n,a,b,c) DB_PR((debug.d_sba >=(n)),a,b,c) -#define DB_ESS(a,b,c) DB_PR((debug.d_ess),a,b,c) -#define DB_ESSN(n,a,b,c) DB_PR((debug.d_ess >=(n)),a,b,c) -#endif - -#ifndef SS_NOT_DS -#define SK_LOC_DECL(type,var) type var -#else -#define SK_LOC_DECL(type,var) static type var -#endif -/* - * PHYs and PORTS - * Note: Don't touch the definition of PA and PB. Those might be used - * by some "for" loops. - */ -#define PA 0 -#define PB 1 -#if defined(SUPERNET_3) || defined(CONC_II) -/* - * The port indices have to be different, - * because the MAC output goes through the 2. PLC - * Conc II: It has to be the first port in the row. - */ -#define PS 0 /* Internal PLC which is the same as PA */ -#else -#define PS 1 -#endif -#define PM 2 /* PM .. PA+NUM_PHYS-1 */ - -/* - * PHY types - as in path descriptor 'fddiPHYType' - */ -#define TA 0 /* A port */ -#define TB 1 /* B port */ -#define TS 2 /* S port */ -#define TM 3 /* M port */ -#define TNONE 4 - - -/* - * indexes in MIB - */ -#define INDEX_MAC 1 -#define INDEX_PATH 1 -#define INDEX_PORT 1 - - -/* - * policies - */ -#define POLICY_AA (1<<0) /* reject AA */ -#define POLICY_AB (1<<1) /* reject AB */ -#define POLICY_AS (1<<2) /* reject AS */ -#define POLICY_AM (1<<3) /* reject AM */ -#define POLICY_BA (1<<4) /* reject BA */ -#define POLICY_BB (1<<5) /* reject BB */ -#define POLICY_BS (1<<6) /* reject BS */ -#define POLICY_BM (1<<7) /* reject BM */ -#define POLICY_SA (1<<8) /* reject SA */ -#define POLICY_SB (1<<9) /* reject SB */ -#define POLICY_SS (1<<10) /* reject SS */ -#define POLICY_SM (1<<11) /* reject SM */ -#define POLICY_MA (1<<12) /* reject MA */ -#define POLICY_MB (1<<13) /* reject MB */ -#define POLICY_MS (1<<14) /* reject MS */ -#define POLICY_MM (1<<15) /* reject MM */ - -/* - * commands - */ - -/* - * EVENTS - * event classes - */ -#define EVENT_ECM 1 /* event class ECM */ -#define EVENT_CFM 2 /* event class CFM */ -#define EVENT_RMT 3 /* event class RMT */ -#define EVENT_SMT 4 /* event class SMT */ -#define EVENT_PCM 5 /* event class PCM */ -#define EVENT_PCMA 5 /* event class PCMA */ -#define EVENT_PCMB 6 /* event class PCMB */ - -/* WARNING : - * EVENT_PCM* must be last in the above list - * if more than two ports are used, EVENT_PCM .. EVENT_PCMA+NUM_PHYS-1 - * are used ! - */ - -#define EV_TOKEN(class,event) (((u_long)(class)<<16L)|((u_long)(event))) -#define EV_T_CLASS(token) ((int)((token)>>16)&0xffff) -#define EV_T_EVENT(token) ((int)(token)&0xffff) - -/* - * ECM events - */ -#define EC_CONNECT 1 /* connect request */ -#define EC_DISCONNECT 2 /* disconnect request */ -#define EC_TRACE_PROP 3 /* trace propagation */ -#define EC_PATH_TEST 4 /* path test */ -#define EC_TIMEOUT_TD 5 /* timer TD_min */ -#define EC_TIMEOUT_TMAX 6 /* timer trace_max */ -#define EC_TIMEOUT_IMAX 7 /* timer I_max */ -#define EC_TIMEOUT_INMAX 8 /* timer IN_max */ -#define EC_TEST_DONE 9 /* path test done */ - -/* - * CFM events - */ -#define CF_LOOP 1 /* cf_loop flag from PCM */ -#define CF_LOOP_A 1 /* cf_loop flag from PCM */ -#define CF_LOOP_B 2 /* cf_loop flag from PCM */ -#define CF_JOIN 3 /* cf_join flag from PCM */ -#define CF_JOIN_A 3 /* cf_join flag from PCM */ -#define CF_JOIN_B 4 /* cf_join flag from PCM */ - -/* - * PCM events - */ -#define PC_START 1 -#define PC_STOP 2 -#define PC_LOOP 3 -#define PC_JOIN 4 -#define PC_SIGNAL 5 -#define PC_REJECT 6 -#define PC_MAINT 7 -#define PC_TRACE 8 -#define PC_PDR 9 -#define PC_ENABLE 10 -#define PC_DISABLE 11 - -/* - * must be ordered as in LineStateType - */ -#define PC_QLS 12 -#define PC_ILS 13 -#define PC_MLS 14 -#define PC_HLS 15 -#define PC_LS_PDR 16 -#define PC_LS_NONE 17 -#define LS2MIB(x) ((x)-PC_QLS) -#define MIB2LS(x) ((x)+PC_QLS) - -#define PC_TIMEOUT_TB_MAX 18 /* timer TB_max */ -#define PC_TIMEOUT_TB_MIN 19 /* timer TB_min */ -#define PC_TIMEOUT_C_MIN 20 /* timer C_Min */ -#define PC_TIMEOUT_T_OUT 21 /* timer T_Out */ -#define PC_TIMEOUT_TL_MIN 22 /* timer TL_Min */ -#define PC_TIMEOUT_T_NEXT 23 /* timer t_next[] */ -#define PC_TIMEOUT_LCT 24 -#define PC_NSE 25 /* NOISE hardware timer */ -#define PC_LEM 26 /* LEM done */ - -/* - * RMT events meaning from - */ -#define RM_RING_OP 1 /* ring operational MAC */ -#define RM_RING_NON_OP 2 /* ring not operational MAC */ -#define RM_MY_BEACON 3 /* recvd my beacon MAC */ -#define RM_OTHER_BEACON 4 /* recvd other beacon MAC */ -#define RM_MY_CLAIM 5 /* recvd my claim MAC */ -#define RM_TRT_EXP 6 /* TRT exp MAC */ -#define RM_VALID_CLAIM 7 /* claim from dup addr MAC */ -#define RM_JOIN 8 /* signal rm_join CFM */ -#define RM_LOOP 9 /* signal rm_loop CFM */ -#define RM_DUP_ADDR 10 /* dup_addr_test hange SMT-NIF */ -#define RM_ENABLE_FLAG 11 /* enable flag */ - -#define RM_TIMEOUT_NON_OP 12 /* timeout T_Non_OP */ -#define RM_TIMEOUT_T_STUCK 13 /* timeout T_Stuck */ -#define RM_TIMEOUT_ANNOUNCE 14 /* timeout T_Announce */ -#define RM_TIMEOUT_T_DIRECT 15 /* timeout T_Direct */ -#define RM_TIMEOUT_D_MAX 16 /* timeout D_Max */ -#define RM_TIMEOUT_POLL 17 /* claim/beacon poller */ -#define RM_TX_STATE_CHANGE 18 /* To restart timer for D_Max */ - -/* - * SMT events - */ -#define SM_TIMER 1 /* timer */ -#define SM_FAST 2 /* smt_force_irq */ - -/* PC modes */ -#define PM_NONE 0 -#define PM_PEER 1 -#define PM_TREE 2 - -/* - * PCM withhold codes - * MIB PC-WithholdType ENUM - */ -#define PC_WH_NONE 0 /* ok */ -#define PC_WH_M_M 1 /* M to M */ -#define PC_WH_OTHER 2 /* other incompatible phys */ -#define PC_WH_PATH 3 /* path not available */ -/* - * LCT duration - */ -#define LC_SHORT 1 /* short LCT */ -#define LC_MEDIUM 2 /* medium LCT */ -#define LC_LONG 3 /* long LCT */ -#define LC_EXTENDED 4 /* extended LCT */ - -/* - * path_test values - */ -#define PT_NONE 0 -#define PT_TESTING 1 /* test is running */ -#define PT_PASSED 2 /* test passed */ -#define PT_FAILED 3 /* test failed */ -#define PT_PENDING 4 /* path test follows */ -#define PT_EXITING 5 /* disconnected while in trace/leave */ - -/* - * duplicate address test - * MIB DupAddressTest ENUM - */ -#define DA_NONE 0 /* */ -#define DA_PASSED 1 /* test passed */ -#define DA_FAILED 2 /* test failed */ - - -/* - * optical bypass - */ -#define BP_DEINSERT 0 /* disable bypass */ -#define BP_INSERT 1 /* enable bypass */ - -/* - * ODL enable/disable - */ -#define PM_TRANSMIT_DISABLE 0 /* disable xmit */ -#define PM_TRANSMIT_ENABLE 1 /* enable xmit */ - -/* - * parameter for config_mux - * note : number is index in config_endec table ! - */ -#define MUX_THRUA 0 /* through A */ -#define MUX_THRUB 1 /* through B */ -#define MUX_WRAPA 2 /* wrap A */ -#define MUX_WRAPB 3 /* wrap B */ -#define MUX_ISOLATE 4 /* isolated */ -#define MUX_WRAPS 5 /* SAS */ - -/* - * MAC control - */ -#define MA_RESET 0 -#define MA_BEACON 1 -#define MA_CLAIM 2 -#define MA_DIRECTED 3 /* directed beacon */ -#define MA_TREQ 4 /* change T_Req */ -#define MA_OFFLINE 5 /* switch MAC to offline */ - - -/* - * trace prop - * bit map for trace propagation - */ -#define ENTITY_MAC (NUMPHYS) -#define ENTITY_PHY(p) (p) -#define ENTITY_BIT(m) (1<<(m)) - -/* - * Resource Tag Types - */ -#define PATH_ISO 0 /* isolated */ -#define PATH_PRIM 3 /* primary path */ -#define PATH_THRU 5 /* through path */ - -#define RES_MAC 2 /* resource type MAC */ -#define RES_PORT 4 /* resource type PORT */ - - -/* - * CFM state - * oops: MUST MATCH CF-StateType in SMT7.2 ! - */ -#define SC0_ISOLATED 0 /* isolated */ -#define SC1_WRAP_A 5 /* wrap A (not used) */ -#define SC2_WRAP_B 6 /* wrap B (not used) */ -#define SC4_THRU_A 12 /* through A */ -#define SC5_THRU_B 7 /* through B (used in SMT 6.2) */ -#define SC7_WRAP_S 8 /* SAS (not used) */ -#define SC9_C_WRAP_A 9 /* c wrap A */ -#define SC10_C_WRAP_B 10 /* c wrap B */ -#define SC11_C_WRAP_S 11 /* c wrap S */ - -/* - * convert MIB time in units of 80nS to uS - */ -#define MIB2US(t) ((t)/12) -#define SEC2MIB(s) ((s)*12500000L) -/* - * SMT timer - */ -struct smt_timer { - struct smt_timer *tm_next ; /* linked list */ - struct s_smc *tm_smc ; /* pointer to context */ - u_long tm_delta ; /* delta time */ - u_long tm_token ; /* token value */ - u_short tm_active ; /* flag : active/inactive */ - u_short tm_pad ; /* pad field */ -} ; - -/* - * communication structures - */ -struct mac_parameter { - u_long t_neg ; /* T_Neg parameter */ - u_long t_pri ; /* T_Pri register in MAC */ -} ; - -/* - * MAC counters - */ -struct mac_counter { - u_long mac_nobuf_counter ; /* MAC SW counter: no buffer */ - u_long mac_r_restart_counter ; /* MAC SW counter: rx restarted */ -} ; - -/* - * para struct context for SMT parameters - */ -struct s_pcon { - int pc_len ; - int pc_err ; - int pc_badset ; - void *pc_p ; -} ; - -/* - * link error monitor - */ -#define LEM_AVG 5 -struct lem_counter { -#ifdef AM29K - int lem_on ; - u_long lem_errors ; - u_long lem_symbols ; - u_long lem_tsymbols ; - int lem_s_count ; - int lem_n_s ; - int lem_values ; - int lem_index ; - int lem_avg_ber[LEM_AVG] ; - int lem_sum ; -#else - u_short lem_float_ber ; /* 10E-nn bit error rate */ - u_long lem_errors ; /* accumulated error count */ - u_short lem_on ; -#endif -} ; - -#define NUMBITS 10 - -#ifdef AMDPLC - -/* - * PLC state table - */ -struct s_plc { - u_short p_state ; /* current state */ - u_short p_bits ; /* number of bits to send */ - u_short p_start ; /* first bit pos */ - u_short p_pad ; /* padding for alignment */ - u_long soft_err ; /* error counter */ - u_long parity_err ; /* error counter */ - u_long ebuf_err ; /* error counter */ - u_long ebuf_cont ; /* continuous error counter */ - u_long phyinv ; /* error counter */ - u_long vsym_ctr ; /* error counter */ - u_long mini_ctr ; /* error counter */ - u_long tpc_exp ; /* error counter */ - u_long np_err ; /* error counter */ - u_long b_pcs ; /* error counter */ - u_long b_tpc ; /* error counter */ - u_long b_tne ; /* error counter */ - u_long b_qls ; /* error counter */ - u_long b_ils ; /* error counter */ - u_long b_hls ; /* error counter */ -} ; -#endif - -#ifdef PROTOTYP_INC -#include "fddi/driver.pro" -#else /* PROTOTYP_INC */ -/* - * function prototypes - */ -#include "h/mbuf.h" /* Type definitions for MBUFs */ -#include "h/smtstate.h" /* struct smt_state */ - -void hwt_restart(struct s_smc *smc); /* hwt.c */ -SMbuf *smt_build_frame(struct s_smc *smc, int class, int type, - int length); /* smt.c */ -SMbuf *smt_get_mbuf(struct s_smc *smc); /* drvsr.c */ -void *sm_to_para(struct s_smc *smc, struct smt_header *sm, - int para); /* smt.c */ - -#ifndef SK_UNUSED -#define SK_UNUSED(var) (void)(var) -#endif - -void queue_event(struct s_smc *smc, int class, int event); -void ecm(struct s_smc *smc, int event); -void ecm_init(struct s_smc *smc); -void rmt(struct s_smc *smc, int event); -void rmt_init(struct s_smc *smc); -void pcm(struct s_smc *smc, const int np, int event); -void pcm_init(struct s_smc *smc); -void cfm(struct s_smc *smc, int event); -void cfm_init(struct s_smc *smc); -void smt_timer_start(struct s_smc *smc, struct smt_timer *timer, u_long time, - u_long token); -void smt_timer_stop(struct s_smc *smc, struct smt_timer *timer); -void pcm_status_state(struct s_smc *smc, int np, int *type, int *state, - int *remote, int *mac); -void plc_config_mux(struct s_smc *smc, int mux); -void sm_lem_evaluate(struct s_smc *smc); -void mac_update_counter(struct s_smc *smc); -void sm_pm_ls_latch(struct s_smc *smc, int phy, int on_off); -void sm_ma_control(struct s_smc *smc, int mode); -void sm_mac_check_beacon_claim(struct s_smc *smc); -void config_mux(struct s_smc *smc, int mux); -void smt_agent_init(struct s_smc *smc); -void smt_timer_init(struct s_smc *smc); -void smt_received_pack(struct s_smc *smc, SMbuf *mb, int fs); -void smt_add_para(struct s_smc *smc, struct s_pcon *pcon, u_short para, - int index, int local); -void smt_swap_para(struct smt_header *sm, int len, int direction); -void ev_init(struct s_smc *smc); -void hwt_init(struct s_smc *smc); -u_long hwt_read(struct s_smc *smc); -void hwt_stop(struct s_smc *smc); -void hwt_start(struct s_smc *smc, u_long time); -void smt_send_mbuf(struct s_smc *smc, SMbuf *mb, int fc); -void smt_free_mbuf(struct s_smc *smc, SMbuf *mb); -void sm_pm_bypass_req(struct s_smc *smc, int mode); -void rmt_indication(struct s_smc *smc, int i); -void cfm_state_change(struct s_smc *smc, int c_state); - -#if defined(DEBUG) || !defined(NO_SMT_PANIC) -void smt_panic(struct s_smc *smc, char *text); -#else -#define smt_panic(smc,text) -#endif /* DEBUG || !NO_SMT_PANIC */ - -void smt_stat_counter(struct s_smc *smc, int stat); -void smt_timer_poll(struct s_smc *smc); -u_long smt_get_time(void); -u_long smt_get_tid(struct s_smc *smc); -void smt_timer_done(struct s_smc *smc); -void smt_fixup_mib(struct s_smc *smc); -void smt_reset_defaults(struct s_smc *smc, int level); -void smt_agent_task(struct s_smc *smc); -int smt_check_para(struct s_smc *smc, struct smt_header *sm, - const u_short list[]); -void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr); - -#ifdef SUPERNET_3 -void drv_reset_indication(struct s_smc *smc); -#endif /* SUPERNET_3 */ - -void smt_start_watchdog(struct s_smc *smc); -void smt_event(struct s_smc *smc, int event); -void timer_event(struct s_smc *smc, u_long token); -void ev_dispatcher(struct s_smc *smc); -void pcm_get_state(struct s_smc *smc, struct smt_state *state); -void ecm_state_change(struct s_smc *smc, int e_state); -int sm_pm_bypass_present(struct s_smc *smc); -void pcm_state_change(struct s_smc *smc, int plc, int p_state); -void rmt_state_change(struct s_smc *smc, int r_state); -int sm_pm_get_ls(struct s_smc *smc, int phy); -int pcm_get_s_port(struct s_smc *smc); -int pcm_rooted_station(struct s_smc *smc); -int cfm_get_mac_input(struct s_smc *smc); -int cfm_get_mac_output(struct s_smc *smc); -int cem_build_path(struct s_smc *smc, char *to, int path_index); -int sm_mac_get_tx_state(struct s_smc *smc); -char *get_pcmstate(struct s_smc *smc, int np); -int smt_action(struct s_smc *smc, int class, int code, int index); -u_short smt_online(struct s_smc *smc, int on); -void smt_force_irq(struct s_smc *smc); -void smt_pmf_received_pack(struct s_smc *smc, SMbuf *mb, int local); -void smt_send_frame(struct s_smc *smc, SMbuf *mb, int fc, int local); -void smt_set_timestamp(struct s_smc *smc, u_char *p); -void mac_set_rx_mode(struct s_smc *smc, int mode); -int mac_add_multicast(struct s_smc *smc, struct fddi_addr *addr, int can); -void mac_update_multicast(struct s_smc *smc); -void mac_clear_multicast(struct s_smc *smc); -void set_formac_tsync(struct s_smc *smc, long sync_bw); -void formac_reinit_tx(struct s_smc *smc); -void formac_tx_restart(struct s_smc *smc); -void process_receive(struct s_smc *smc); -void init_driver_fplus(struct s_smc *smc); -void rtm_irq(struct s_smc *smc); -void rtm_set_timer(struct s_smc *smc); -void ring_status_indication(struct s_smc *smc, u_long status); -void llc_recover_tx(struct s_smc *smc); -void llc_restart_tx(struct s_smc *smc); -void plc_clear_irq(struct s_smc *smc, int p); -void plc_irq(struct s_smc *smc, int np, unsigned int cmd); -int smt_set_mac_opvalues(struct s_smc *smc); - -#ifdef TAG_MODE -void mac_do_pci_fix(struct s_smc *smc); -void mac_drv_clear_tx_queue(struct s_smc *smc); -void mac_drv_repair_descr(struct s_smc *smc); -u_long hwt_quick_read(struct s_smc *smc); -void hwt_wait_time(struct s_smc *smc, u_long start, long duration); -#endif - -#ifdef SMT_PNMI -int pnmi_init(struct s_smc* smc); -int pnmi_process_ndis_id(struct s_smc *smc, u_long ndis_oid, void *buf, int len, - int *BytesAccessed, int *BytesNeeded, u_char action); -#endif - -#ifdef SBA -#ifndef _H2INC -void sba(); -#endif -void sba_raf_received_pack(); -void sba_timer_poll(); -void smt_init_sba(); -#endif - -#ifdef ESS -int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm, - int fs); -void ess_timer_poll(struct s_smc *smc); -void ess_para_change(struct s_smc *smc); -#endif - -#ifndef BOOT -void smt_init_evc(struct s_smc *smc); -void smt_srf_event(struct s_smc *smc, int code, int index, int cond); -#else -#define smt_init_evc(smc) -#define smt_srf_event(smc,code,index,cond) -#endif - -#ifndef SMT_REAL_TOKEN_CT -void smt_emulate_token_ct(struct s_smc *smc, int mac_index); -#endif - -#if defined(DEBUG) && !defined(BOOT) -void dump_smt(struct s_smc *smc, struct smt_header *sm, char *text); -#else -#define dump_smt(smc,sm,text) -#endif - -#ifdef DEBUG -char* addr_to_string(struct fddi_addr *addr); -void dump_hex(char *p, int len); -#endif - -#endif /* PROTOTYP_INC */ - -/* PNMI default defines */ -#ifndef PNMI_INIT -#define PNMI_INIT(smc) /* Nothing */ -#endif -#ifndef PNMI_GET_ID -#define PNMI_GET_ID( smc, ndis_oid, buf, len, BytesWritten, BytesNeeded ) \ - ( 1 ? (-1) : (-1) ) -#endif -#ifndef PNMI_SET_ID -#define PNMI_SET_ID( smc, ndis_oid, buf, len, BytesRead, BytesNeeded, \ - set_type) ( 1 ? (-1) : (-1) ) -#endif - -/* - * SMT_PANIC defines - */ -#ifndef SMT_PANIC -#define SMT_PANIC(smc,nr,msg) smt_panic (smc, msg) -#endif - -#ifndef SMT_ERR_LOG -#define SMT_ERR_LOG(smc,nr,msg) SMT_PANIC (smc, nr, msg) -#endif - -#ifndef SMT_EBASE -#define SMT_EBASE 100 -#endif - -#define SMT_E0100 SMT_EBASE + 0 -#define SMT_E0100_MSG "cfm FSM: invalid ce_type" -#define SMT_E0101 SMT_EBASE + 1 -#define SMT_E0101_MSG "CEM: case ???" -#define SMT_E0102 SMT_EBASE + 2 -#define SMT_E0102_MSG "CEM A: invalid state" -#define SMT_E0103 SMT_EBASE + 3 -#define SMT_E0103_MSG "CEM B: invalid state" -#define SMT_E0104 SMT_EBASE + 4 -#define SMT_E0104_MSG "CEM M: invalid state" -#define SMT_E0105 SMT_EBASE + 5 -#define SMT_E0105_MSG "CEM S: invalid state" -#define SMT_E0106 SMT_EBASE + 6 -#define SMT_E0106_MSG "CFM : invalid state" -#define SMT_E0107 SMT_EBASE + 7 -#define SMT_E0107_MSG "ECM : invalid state" -#define SMT_E0108 SMT_EBASE + 8 -#define SMT_E0108_MSG "prop_actions : NAC in DAS CFM" -#define SMT_E0109 SMT_EBASE + 9 -#define SMT_E0109_MSG "ST2U.FM_SERRSF error in special frame" -#define SMT_E0110 SMT_EBASE + 10 -#define SMT_E0110_MSG "ST2U.FM_SRFRCTOV recv. count. overflow" -#define SMT_E0111 SMT_EBASE + 11 -#define SMT_E0111_MSG "ST2U.FM_SNFSLD NP & FORMAC simult. load" -#define SMT_E0112 SMT_EBASE + 12 -#define SMT_E0112_MSG "ST2U.FM_SRCVFRM single-frame recv.-mode" -#define SMT_E0113 SMT_EBASE + 13 -#define SMT_E0113_MSG "FPLUS: Buffer Memory Error" -#define SMT_E0114 SMT_EBASE + 14 -#define SMT_E0114_MSG "ST2U.FM_SERRSF error in special frame" -#define SMT_E0115 SMT_EBASE + 15 -#define SMT_E0115_MSG "ST3L: parity error in receive queue 2" -#define SMT_E0116 SMT_EBASE + 16 -#define SMT_E0116_MSG "ST3L: parity error in receive queue 1" -#define SMT_E0117 SMT_EBASE + 17 -#define SMT_E0117_MSG "E_SMT_001: RxD count for receive queue 1 = 0" -#define SMT_E0118 SMT_EBASE + 18 -#define SMT_E0118_MSG "PCM : invalid state" -#define SMT_E0119 SMT_EBASE + 19 -#define SMT_E0119_MSG "smt_add_para" -#define SMT_E0120 SMT_EBASE + 20 -#define SMT_E0120_MSG "smt_set_para" -#define SMT_E0121 SMT_EBASE + 21 -#define SMT_E0121_MSG "invalid event in dispatcher" -#define SMT_E0122 SMT_EBASE + 22 -#define SMT_E0122_MSG "RMT : invalid state" -#define SMT_E0123 SMT_EBASE + 23 -#define SMT_E0123_MSG "SBA: state machine has invalid state" -#define SMT_E0124 SMT_EBASE + 24 -#define SMT_E0124_MSG "sba_free_session() called with NULL pointer" -#define SMT_E0125 SMT_EBASE + 25 -#define SMT_E0125_MSG "SBA : invalid session pointer" -#define SMT_E0126 SMT_EBASE + 26 -#define SMT_E0126_MSG "smt_free_mbuf() called with NULL pointer\n" -#define SMT_E0127 SMT_EBASE + 27 -#define SMT_E0127_MSG "sizeof evcs" -#define SMT_E0128 SMT_EBASE + 28 -#define SMT_E0128_MSG "evc->evc_cond_state = 0" -#define SMT_E0129 SMT_EBASE + 29 -#define SMT_E0129_MSG "evc->evc_multiple = 0" -#define SMT_E0130 SMT_EBASE + 30 -#define SMT_E0130_MSG write_mdr_warning -#define SMT_E0131 SMT_EBASE + 31 -#define SMT_E0131_MSG cam_warning -#define SMT_E0132 SMT_EBASE + 32 -#define SMT_E0132_MSG "ST1L.FM_SPCEPDx parity/coding error" -#define SMT_E0133 SMT_EBASE + 33 -#define SMT_E0133_MSG "ST1L.FM_STBURx tx buffer underrun" -#define SMT_E0134 SMT_EBASE + 34 -#define SMT_E0134_MSG "ST1L.FM_SPCEPDx parity error" -#define SMT_E0135 SMT_EBASE + 35 -#define SMT_E0135_MSG "RMT: duplicate MAC address detected. Ring left!" -#define SMT_E0136 SMT_EBASE + 36 -#define SMT_E0136_MSG "Elasticity Buffer hang-up" -#define SMT_E0137 SMT_EBASE + 37 -#define SMT_E0137_MSG "SMT: queue overrun" -#define SMT_E0138 SMT_EBASE + 38 -#define SMT_E0138_MSG "RMT: duplicate MAC address detected. Ring NOT left!" -#endif /* _CMTDEF_ */ diff --git a/drivers/net/skfp/h/fddi.h b/drivers/net/skfp/h/fddi.h deleted file mode 100644 index c9a28a8..0000000 --- a/drivers/net/skfp/h/fddi.h +++ /dev/null @@ -1,69 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -#ifndef _FDDI_ -#define _FDDI_ - -struct fddi_addr { - u_char a[6] ; -} ; - -#define GROUP_ADDR 0x80 /* MSB in a[0] */ - -struct fddi_mac { - struct fddi_addr mac_dest ; - struct fddi_addr mac_source ; - u_char mac_info[4478] ; -} ; - -#define FDDI_MAC_SIZE (12) -#define FDDI_RAW_MTU (4500-5) /* exl. Pr,SD, ED/FS */ -#define FDDI_RAW (4500) - -/* - * FC values - */ -#define FC_VOID 0x40 /* void frame */ -#define FC_TOKEN 0x80 /* token */ -#define FC_RES_TOKEN 0xc0 /* restricted token */ -#define FC_SMT_INFO 0x41 /* SMT Info frame */ -/* - * FC_SMT_LAN_LOC && FC_SMT_LOC are SK specific ! - */ -#define FC_SMT_LAN_LOC 0x42 /* local SMT Info frame */ -#define FC_SMT_LOC 0x43 /* local SMT Info frame */ -#define FC_SMT_NSA 0x4f /* SMT NSA frame */ -#define FC_MAC 0xc0 /* MAC frame */ -#define FC_BEACON 0xc2 /* MAC beacon frame */ -#define FC_CLAIM 0xc3 /* MAC claim frame */ -#define FC_SYNC_LLC 0xd0 /* sync. LLC frame */ -#define FC_ASYNC_LLC 0x50 /* async. LLC frame */ -#define FC_SYNC_BIT 0x80 /* sync. bit in FC */ - -#define FC_LLC_PRIOR 0x07 /* priority bits */ - -#define BEACON_INFO 0 /* beacon type */ -#define DBEACON_INFO 1 /* beacon type DIRECTED */ - - -/* - * indicator bits - */ -#define C_INDICATOR (1<<0) -#define A_INDICATOR (1<<1) -#define E_INDICATOR (1<<2) -#define I_INDICATOR (1<<6) /* SK specific */ -#define L_INDICATOR (1<<7) /* SK specific */ - -#endif /* _FDDI_ */ diff --git a/drivers/net/skfp/h/fddimib.h b/drivers/net/skfp/h/fddimib.h deleted file mode 100644 index d1acdc7..0000000 --- a/drivers/net/skfp/h/fddimib.h +++ /dev/null @@ -1,349 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - * FDDI MIB - */ - -/* - * typedefs - */ - -typedef u_long Counter ; -typedef u_char TimeStamp[8] ; -typedef struct fddi_addr LongAddr ; -typedef u_long Timer_2 ; -typedef u_long Timer ; -typedef u_short ResId ; -typedef u_short SMTEnum ; -typedef u_char SMTFlag ; - -typedef struct { - Counter count ; - TimeStamp timestamp ; -} SetCountType ; - -/* - * bits for bit string "available_path" - */ -#define MIB_PATH_P (1<<0) -#define MIB_PATH_S (1<<1) -#define MIB_PATH_L (1<<2) - -/* - * bits for bit string PermittedPaths & RequestedPaths (SIZE(8)) - */ -#define MIB_P_PATH_LOCAL (1<<0) -#define MIB_P_PATH_SEC_ALTER (1<<1) -#define MIB_P_PATH_PRIM_ALTER (1<<2) -#define MIB_P_PATH_CON_ALTER (1<<3) -#define MIB_P_PATH_SEC_PREFER (1<<4) -#define MIB_P_PATH_PRIM_PREFER (1<<5) -#define MIB_P_PATH_CON_PREFER (1<<6) -#define MIB_P_PATH_THRU (1<<7) - -/* - * enum current path - */ -#define MIB_PATH_ISOLATED 0 -#define MIB_PATH_LOCAL 1 -#define MIB_PATH_SECONDARY 2 -#define MIB_PATH_PRIMARY 3 -#define MIB_PATH_CONCATENATED 4 -#define MIB_PATH_THRU 5 - -/* - * enum PMDClass - */ -#define MIB_PMDCLASS_MULTI 0 -#define MIB_PMDCLASS_SINGLE1 1 -#define MIB_PMDCLASS_SINGLE2 2 -#define MIB_PMDCLASS_SONET 3 -#define MIB_PMDCLASS_LCF 4 -#define MIB_PMDCLASS_TP 5 -#define MIB_PMDCLASS_UNKNOWN 6 -#define MIB_PMDCLASS_UNSPEC 7 - -/* - * enum SMTStationStatus - */ -#define MIB_SMT_STASTA_CON 0 -#define MIB_SMT_STASTA_SEPA 1 -#define MIB_SMT_STASTA_THRU 2 - - -struct fddi_mib { - /* - * private - */ - u_char fddiPRPMFPasswd[8] ; - struct smt_sid fddiPRPMFStation ; - -#ifdef ESS - /* - * private variables for static allocation of the - * End Station Support - */ - u_long fddiESSPayload ; /* payload for static alloc */ - u_long fddiESSOverhead ; /* frame ov for static alloc */ - u_long fddiESSMaxTNeg ; /* maximum of T-NEG */ - u_long fddiESSMinSegmentSize ; /* min size of the sync frames */ - u_long fddiESSCategory ; /* category for the Alloc req */ - short fddiESSSynchTxMode ; /* send all LLC frames as sync */ -#endif /* ESS */ -#ifdef SBA - /* - * private variables for the Synchronous Bandwidth Allocator - */ - char fddiSBACommand ; /* holds the parsed SBA cmd */ - u_char fddiSBAAvailable ; /* SBA allocatable value */ -#endif /* SBA */ - - /* - * SMT standard mib - */ - struct smt_sid fddiSMTStationId ; - u_short fddiSMTOpVersionId ; - u_short fddiSMTHiVersionId ; - u_short fddiSMTLoVersionId ; - u_char fddiSMTManufacturerData[32] ; - u_char fddiSMTUserData[32] ; - u_short fddiSMTMIBVersionId ; - - /* - * ConfigGrp - */ - u_char fddiSMTMac_Ct ; - u_char fddiSMTNonMaster_Ct ; - u_char fddiSMTMaster_Ct ; - u_char fddiSMTAvailablePaths ; - u_short fddiSMTConfigCapabilities ; - u_short fddiSMTConfigPolicy ; - u_short fddiSMTConnectionPolicy ; - u_short fddiSMTTT_Notify ; - u_char fddiSMTStatRptPolicy ; - u_long fddiSMTTrace_MaxExpiration ; - u_short fddiSMTPORTIndexes[NUMPHYS] ; - u_short fddiSMTMACIndexes ; - u_char fddiSMTBypassPresent ; - - /* - * StatusGrp - */ - SMTEnum fddiSMTECMState ; - SMTEnum fddiSMTCF_State ; - SMTEnum fddiSMTStationStatus ; - u_char fddiSMTRemoteDisconnectFlag ; - u_char fddiSMTPeerWrapFlag ; - - /* - * MIBOperationGrp - */ - TimeStamp fddiSMTTimeStamp ; - TimeStamp fddiSMTTransitionTimeStamp ; - SetCountType fddiSMTSetCount ; - struct smt_sid fddiSMTLastSetStationId ; - - struct fddi_mib_m { - u_short fddiMACFrameStatusFunctions ; - Timer_2 fddiMACT_MaxCapabilitiy ; - Timer_2 fddiMACTVXCapabilitiy ; - - /* ConfigGrp */ - u_char fddiMACMultiple_N ; /* private */ - u_char fddiMACMultiple_P ; /* private */ - u_char fddiMACDuplicateAddressCond ;/* private */ - u_char fddiMACAvailablePaths ; - u_short fddiMACCurrentPath ; - LongAddr fddiMACUpstreamNbr ; - LongAddr fddiMACDownstreamNbr ; - LongAddr fddiMACOldUpstreamNbr ; - LongAddr fddiMACOldDownstreamNbr ; - SMTEnum fddiMACDupAddressTest ; - u_short fddiMACRequestedPaths ; - SMTEnum fddiMACDownstreamPORTType ; - ResId fddiMACIndex ; - - /* AddressGrp */ - LongAddr fddiMACSMTAddress ; - - /* OperationGrp */ - Timer_2 fddiMACT_Min ; /* private */ - Timer_2 fddiMACT_ReqMIB ; - Timer_2 fddiMACT_Req ; /* private */ - Timer_2 fddiMACT_Neg ; - Timer_2 fddiMACT_MaxMIB ; - Timer_2 fddiMACT_Max ; /* private */ - Timer_2 fddiMACTvxValueMIB ; - Timer_2 fddiMACTvxValue ; /* private */ - Timer_2 fddiMACT_Pri0 ; - Timer_2 fddiMACT_Pri1 ; - Timer_2 fddiMACT_Pri2 ; - Timer_2 fddiMACT_Pri3 ; - Timer_2 fddiMACT_Pri4 ; - Timer_2 fddiMACT_Pri5 ; - Timer_2 fddiMACT_Pri6 ; - - /* CountersGrp */ - Counter fddiMACFrame_Ct ; - Counter fddiMACCopied_Ct ; - Counter fddiMACTransmit_Ct ; - Counter fddiMACToken_Ct ; - Counter fddiMACError_Ct ; - Counter fddiMACLost_Ct ; - Counter fddiMACTvxExpired_Ct ; - Counter fddiMACNotCopied_Ct ; - Counter fddiMACRingOp_Ct ; - - Counter fddiMACSMTCopied_Ct ; /* private */ - Counter fddiMACSMTTransmit_Ct ; /* private */ - - /* private for delta ratio */ - Counter fddiMACOld_Frame_Ct ; - Counter fddiMACOld_Copied_Ct ; - Counter fddiMACOld_Error_Ct ; - Counter fddiMACOld_Lost_Ct ; - Counter fddiMACOld_NotCopied_Ct ; - - /* FrameErrorConditionGrp */ - u_short fddiMACFrameErrorThreshold ; - u_short fddiMACFrameErrorRatio ; - - /* NotCopiedConditionGrp */ - u_short fddiMACNotCopiedThreshold ; - u_short fddiMACNotCopiedRatio ; - - /* StatusGrp */ - SMTEnum fddiMACRMTState ; - SMTFlag fddiMACDA_Flag ; - SMTFlag fddiMACUNDA_Flag ; - SMTFlag fddiMACFrameErrorFlag ; - SMTFlag fddiMACNotCopiedFlag ; - SMTFlag fddiMACMA_UnitdataAvailable ; - SMTFlag fddiMACHardwarePresent ; - SMTFlag fddiMACMA_UnitdataEnable ; - - } m[NUMMACS] ; -#define MAC0 0 - - struct fddi_mib_a { - ResId fddiPATHIndex ; - u_long fddiPATHSbaPayload ; - u_long fddiPATHSbaOverhead ; - /* fddiPATHConfiguration is built on demand */ - /* u_long fddiPATHConfiguration ; */ - Timer fddiPATHT_Rmode ; - u_long fddiPATHSbaAvailable ; - Timer_2 fddiPATHTVXLowerBound ; - Timer_2 fddiPATHT_MaxLowerBound ; - Timer_2 fddiPATHMaxT_Req ; - } a[NUMPATHS] ; -#define PATH0 0 - - struct fddi_mib_p { - /* ConfigGrp */ - SMTEnum fddiPORTMy_Type ; - SMTEnum fddiPORTNeighborType ; - u_char fddiPORTConnectionPolicies ; - struct { - u_char T_val ; - u_char R_val ; - } fddiPORTMacIndicated ; - SMTEnum fddiPORTCurrentPath ; - /* must be 4: is 32 bit in SMT format - * indices : - * 1 none - * 2 tree - * 3 peer - */ - u_char fddiPORTRequestedPaths[4] ; - u_short fddiPORTMACPlacement ; - u_char fddiPORTAvailablePaths ; - u_char fddiPORTConnectionCapabilities ; - SMTEnum fddiPORTPMDClass ; - ResId fddiPORTIndex ; - - /* OperationGrp */ - SMTEnum fddiPORTMaint_LS ; - SMTEnum fddiPORTPC_LS ; - u_char fddiPORTBS_Flag ; - - /* ErrorCtrsGrp */ - Counter fddiPORTLCTFail_Ct ; - Counter fddiPORTEBError_Ct ; - Counter fddiPORTOldEBError_Ct ; - - /* LerGrp */ - Counter fddiPORTLem_Reject_Ct ; - Counter fddiPORTLem_Ct ; - u_char fddiPORTLer_Estimate ; - u_char fddiPORTLer_Cutoff ; - u_char fddiPORTLer_Alarm ; - - /* StatusGrp */ - SMTEnum fddiPORTConnectState ; - SMTEnum fddiPORTPCMState ; /* real value */ - SMTEnum fddiPORTPCMStateX ; /* value for MIB */ - SMTEnum fddiPORTPC_Withhold ; - SMTFlag fddiPORTHardwarePresent ; - u_char fddiPORTLerFlag ; - - u_char fddiPORTMultiple_U ; /* private */ - u_char fddiPORTMultiple_P ; /* private */ - u_char fddiPORTEB_Condition ; /* private */ - } p[NUMPHYS] ; - struct { - Counter fddiPRIVECF_Req_Rx ; /* ECF req received */ - Counter fddiPRIVECF_Reply_Rx ; /* ECF repl received */ - Counter fddiPRIVECF_Req_Tx ; /* ECF req transm */ - Counter fddiPRIVECF_Reply_Tx ; /* ECF repl transm */ - Counter fddiPRIVPMF_Get_Rx ; /* PMF Get rec */ - Counter fddiPRIVPMF_Set_Rx ; /* PMF Set rec */ - Counter fddiPRIVRDF_Rx ; /* RDF received */ - Counter fddiPRIVRDF_Tx ; /* RDF transmitted */ - } priv ; -} ; - -/* - * OIDs for statistics - */ -#define SMT_OID_CF_STATE 1 /* fddiSMTCF_State */ -#define SMT_OID_PCM_STATE_A 2 /* fddiPORTPCMState port A */ -#define SMT_OID_PCM_STATE_B 17 /* fddiPORTPCMState port B */ -#define SMT_OID_RMT_STATE 3 /* fddiMACRMTState */ -#define SMT_OID_UNA 4 /* fddiMACUpstreamNbr */ -#define SMT_OID_DNA 5 /* fddiMACOldDownstreamNbr */ -#define SMT_OID_ERROR_CT 6 /* fddiMACError_Ct */ -#define SMT_OID_LOST_CT 7 /* fddiMACLost_Ct */ -#define SMT_OID_LEM_CT 8 /* fddiPORTLem_Ct */ -#define SMT_OID_LEM_CT_A 11 /* fddiPORTLem_Ct port A */ -#define SMT_OID_LEM_CT_B 12 /* fddiPORTLem_Ct port B */ -#define SMT_OID_LCT_FAIL_CT 9 /* fddiPORTLCTFail_Ct */ -#define SMT_OID_LCT_FAIL_CT_A 13 /* fddiPORTLCTFail_Ct port A */ -#define SMT_OID_LCT_FAIL_CT_B 14 /* fddiPORTLCTFail_Ct port B */ -#define SMT_OID_LEM_REJECT_CT 10 /* fddiPORTLem_Reject_Ct */ -#define SMT_OID_LEM_REJECT_CT_A 15 /* fddiPORTLem_Reject_Ct port A */ -#define SMT_OID_LEM_REJECT_CT_B 16 /* fddiPORTLem_Reject_Ct port B */ - -/* - * SK MIB - */ -#define SMT_OID_ECF_REQ_RX 20 /* ECF requests received */ -#define SMT_OID_ECF_REPLY_RX 21 /* ECF replies received */ -#define SMT_OID_ECF_REQ_TX 22 /* ECF requests transmitted */ -#define SMT_OID_ECF_REPLY_TX 23 /* ECF replies transmitted */ -#define SMT_OID_PMF_GET_RX 24 /* PMF get requests received */ -#define SMT_OID_PMF_SET_RX 25 /* PMF set requests received */ -#define SMT_OID_RDF_RX 26 /* RDF received */ -#define SMT_OID_RDF_TX 27 /* RDF transmitted */ diff --git a/drivers/net/skfp/h/fplustm.h b/drivers/net/skfp/h/fplustm.h deleted file mode 100644 index d43191e..0000000 --- a/drivers/net/skfp/h/fplustm.h +++ /dev/null @@ -1,274 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - * AMD Fplus in tag mode data structs - * defs for fplustm.c - */ - -#ifndef _FPLUS_ -#define _FPLUS_ - -#ifndef HW_PTR -#define HW_PTR void __iomem * -#endif - -/* - * fplus error statistic structure - */ -struct err_st { - u_long err_valid ; /* memory status valid */ - u_long err_abort ; /* memory status receive abort */ - u_long err_e_indicator ; /* error indicator */ - u_long err_crc ; /* error detected (CRC or length) */ - u_long err_llc_frame ; /* LLC frame */ - u_long err_mac_frame ; /* MAC frame */ - u_long err_smt_frame ; /* SMT frame */ - u_long err_imp_frame ; /* implementer frame */ - u_long err_no_buf ; /* no buffer available */ - u_long err_too_long ; /* longer than max. buffer */ - u_long err_bec_stat ; /* beacon state entered */ - u_long err_clm_stat ; /* claim state entered */ - u_long err_sifg_det ; /* short interframe gap detect */ - u_long err_phinv ; /* PHY invalid */ - u_long err_tkiss ; /* token issued */ - u_long err_tkerr ; /* token error */ -} ; - -/* - * Transmit Descriptor struct - */ -struct s_smt_fp_txd { - __le32 txd_tbctrl ; /* transmit buffer control */ - __le32 txd_txdscr ; /* transmit frame status word */ - __le32 txd_tbadr ; /* physical tx buffer address */ - __le32 txd_ntdadr ; /* physical pointer to the next TxD */ -#ifdef ENA_64BIT_SUP - __le32 txd_tbadr_hi ; /* physical tx buffer addr (high dword)*/ -#endif - char far *txd_virt ; /* virtual pointer to the data frag */ - /* virt pointer to the next TxD */ - struct s_smt_fp_txd volatile far *txd_next ; - struct s_txd_os txd_os ; /* OS - specific struct */ -} ; - -/* - * Receive Descriptor struct - */ -struct s_smt_fp_rxd { - __le32 rxd_rbctrl ; /* receive buffer control */ - __le32 rxd_rfsw ; /* receive frame status word */ - __le32 rxd_rbadr ; /* physical rx buffer address */ - __le32 rxd_nrdadr ; /* physical pointer to the next RxD */ -#ifdef ENA_64BIT_SUP - __le32 rxd_rbadr_hi ; /* physical tx buffer addr (high dword)*/ -#endif - char far *rxd_virt ; /* virtual pointer to the data frag */ - /* virt pointer to the next RxD */ - struct s_smt_fp_rxd volatile far *rxd_next ; - struct s_rxd_os rxd_os ; /* OS - specific struct */ -} ; - -/* - * Descriptor Union Definition - */ -union s_fp_descr { - struct s_smt_fp_txd t ; /* pointer to the TxD */ - struct s_smt_fp_rxd r ; /* pointer to the RxD */ -} ; - -/* - * TxD Ring Control struct - */ -struct s_smt_tx_queue { - struct s_smt_fp_txd volatile *tx_curr_put ; /* next free TxD */ - struct s_smt_fp_txd volatile *tx_prev_put ; /* shadow put pointer */ - struct s_smt_fp_txd volatile *tx_curr_get ; /* next TxD to release*/ - u_short tx_free ; /* count of free TxD's */ - u_short tx_used ; /* count of used TxD's */ - HW_PTR tx_bmu_ctl ; /* BMU addr for tx start */ - HW_PTR tx_bmu_dsc ; /* BMU addr for curr dsc. */ -} ; - -/* - * RxD Ring Control struct - */ -struct s_smt_rx_queue { - struct s_smt_fp_rxd volatile *rx_curr_put ; /* next RxD to queue into */ - struct s_smt_fp_rxd volatile *rx_prev_put ; /* shadow put pointer */ - struct s_smt_fp_rxd volatile *rx_curr_get ; /* next RxD to fill */ - u_short rx_free ; /* count of free RxD's */ - u_short rx_used ; /* count of used RxD's */ - HW_PTR rx_bmu_ctl ; /* BMU addr for rx start */ - HW_PTR rx_bmu_dsc ; /* BMU addr for curr dsc. */ -} ; - -#define VOID_FRAME_OFF 0x00 -#define CLAIM_FRAME_OFF 0x08 -#define BEACON_FRAME_OFF 0x10 -#define DBEACON_FRAME_OFF 0x18 -#define RX_FIFO_OFF 0x21 /* to get a prime number for */ - /* the RX_FIFO_SPACE */ - -#define RBC_MEM_SIZE 0x8000 -#define SEND_ASYNC_AS_SYNC 0x1 -#define SYNC_TRAFFIC_ON 0x2 - -/* big FIFO memory */ -#define RX_FIFO_SPACE 0x4000 - RX_FIFO_OFF -#define TX_FIFO_SPACE 0x4000 - -#define TX_SMALL_FIFO 0x0900 -#define TX_MEDIUM_FIFO TX_FIFO_SPACE / 2 -#define TX_LARGE_FIFO TX_FIFO_SPACE - TX_SMALL_FIFO - -#define RX_SMALL_FIFO 0x0900 -#define RX_LARGE_FIFO RX_FIFO_SPACE - RX_SMALL_FIFO - -struct s_smt_fifo_conf { - u_short rbc_ram_start ; /* FIFO start address */ - u_short rbc_ram_end ; /* FIFO size */ - u_short rx1_fifo_start ; /* rx queue start address */ - u_short rx1_fifo_size ; /* rx queue size */ - u_short rx2_fifo_start ; /* rx queue start address */ - u_short rx2_fifo_size ; /* rx queue size */ - u_short tx_s_start ; /* sync queue start address */ - u_short tx_s_size ; /* sync queue size */ - u_short tx_a0_start ; /* async queue A0 start address */ - u_short tx_a0_size ; /* async queue A0 size */ - u_short fifo_config_mode ; /* FIFO configuration mode */ -} ; - -#define FM_ADDRX (FM_ADDET|FM_EXGPA0|FM_EXGPA1) - -struct s_smt_fp { - u_short mdr2init ; /* mode register 2 init value */ - u_short mdr3init ; /* mode register 3 init value */ - u_short frselreg_init ; /* frame selection register init val */ - u_short rx_mode ; /* address mode broad/multi/promisc */ - u_short nsa_mode ; - u_short rx_prom ; - u_short exgpa ; - - struct err_st err_stats ; /* error statistics */ - - /* - * MAC buffers - */ - struct fddi_mac_sf { /* special frame build buffer */ - u_char mac_fc ; - struct fddi_addr mac_dest ; - struct fddi_addr mac_source ; - u_char mac_info[0x20] ; - } mac_sfb ; - - - /* - * queues - */ -#define QUEUE_S 0 -#define QUEUE_A0 1 -#define QUEUE_R1 0 -#define QUEUE_R2 1 -#define USED_QUEUES 2 - - /* - * queue pointers; points to the queue dependent variables - */ - struct s_smt_tx_queue *tx[USED_QUEUES] ; - struct s_smt_rx_queue *rx[USED_QUEUES] ; - - /* - * queue dependent variables - */ - struct s_smt_tx_queue tx_q[USED_QUEUES] ; - struct s_smt_rx_queue rx_q[USED_QUEUES] ; - - /* - * FIFO configuration struct - */ - struct s_smt_fifo_conf fifo ; - - /* last formac status */ - u_short s2u ; - u_short s2l ; - - /* calculated FORMAC+ reg.addr. */ - HW_PTR fm_st1u ; - HW_PTR fm_st1l ; - HW_PTR fm_st2u ; - HW_PTR fm_st2l ; - HW_PTR fm_st3u ; - HW_PTR fm_st3l ; - - - /* - * multicast table - */ -#define FPMAX_MULTICAST 32 -#define SMT_MAX_MULTI 4 - struct { - struct s_fpmc { - struct fddi_addr a ; /* mc address */ - u_char n ; /* usage counter */ - u_char perm ; /* flag: permanent */ - } table[FPMAX_MULTICAST] ; - } mc ; - struct fddi_addr group_addr ; - u_long func_addr ; /* functional address */ - int smt_slots_used ; /* count of table entries for the SMT */ - int os_slots_used ; /* count of table entries */ - /* used by the os-specific module */ -} ; - -/* - * modes for mac_set_rx_mode() - */ -#define RX_ENABLE_ALLMULTI 1 /* enable all multicasts */ -#define RX_DISABLE_ALLMULTI 2 /* disable "enable all multicasts" */ -#define RX_ENABLE_PROMISC 3 /* enable promiscuous */ -#define RX_DISABLE_PROMISC 4 /* disable promiscuous */ -#define RX_ENABLE_NSA 5 /* enable reception of NSA frames */ -#define RX_DISABLE_NSA 6 /* disable reception of NSA frames */ - - -/* - * support for byte reversal in AIX - * (descriptors and pointers must be byte reversed in memory - * CPU is big endian; M-Channel is little endian) - */ -#ifdef AIX -#define MDR_REV -#define AIX_REVERSE(x) ((((x)<<24L)&0xff000000L) + \ - (((x)<< 8L)&0x00ff0000L) + \ - (((x)>> 8L)&0x0000ff00L) + \ - (((x)>>24L)&0x000000ffL)) -#else -#ifndef AIX_REVERSE -#define AIX_REVERSE(x) (x) -#endif -#endif - -#ifdef MDR_REV -#define MDR_REVERSE(x) ((((x)<<24L)&0xff000000L) + \ - (((x)<< 8L)&0x00ff0000L) + \ - (((x)>> 8L)&0x0000ff00L) + \ - (((x)>>24L)&0x000000ffL)) -#else -#ifndef MDR_REVERSE -#define MDR_REVERSE(x) (x) -#endif -#endif - -#endif diff --git a/drivers/net/skfp/h/hwmtm.h b/drivers/net/skfp/h/hwmtm.h deleted file mode 100644 index e1a7e5f..0000000 --- a/drivers/net/skfp/h/hwmtm.h +++ /dev/null @@ -1,399 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -#ifndef _HWM_ -#define _HWM_ - -#include "h/mbuf.h" - -/* - * MACRO for DMA synchronization: - * The descriptor 'desc' is flushed for the device 'flag'. - * Devices are the CPU (DDI_DMA_SYNC_FORCPU) and the - * adapter (DDI_DMA_SYNC_FORDEV). - * - * 'desc' Pointer to a Rx or Tx descriptor. - * 'flag' Flag for direction (view for CPU or DEVICE) that - * should be synchronized. - * - * Empty macros and defines are specified here. The real macro - * is os-specific and should be defined in osdef1st.h. - */ -#ifndef DRV_BUF_FLUSH -#define DRV_BUF_FLUSH(desc,flag) -#define DDI_DMA_SYNC_FORCPU -#define DDI_DMA_SYNC_FORDEV -#endif - - /* - * hardware modul dependent receive modes - */ -#define RX_ENABLE_PASS_SMT 21 -#define RX_DISABLE_PASS_SMT 22 -#define RX_ENABLE_PASS_NSA 23 -#define RX_DISABLE_PASS_NSA 24 -#define RX_ENABLE_PASS_DB 25 -#define RX_DISABLE_PASS_DB 26 -#define RX_DISABLE_PASS_ALL 27 -#define RX_DISABLE_LLC_PROMISC 28 -#define RX_ENABLE_LLC_PROMISC 29 - - -#ifndef DMA_RD -#define DMA_RD 1 /* memory -> hw */ -#endif -#ifndef DMA_WR -#define DMA_WR 2 /* hw -> memory */ -#endif -#define SMT_BUF 0x80 - - /* - * bits of the frame status byte - */ -#define EN_IRQ_EOF 0x02 /* get IRQ after end of frame transmission */ -#define LOC_TX 0x04 /* send frame to the local SMT */ -#define LAST_FRAG 0x08 /* last TxD of the frame */ -#define FIRST_FRAG 0x10 /* first TxD of the frame */ -#define LAN_TX 0x20 /* send frame to network if set */ -#define RING_DOWN 0x40 /* error: unable to send, ring down */ -#define OUT_OF_TXD 0x80 /* error: not enough TxDs available */ - - -#ifndef NULL -#define NULL 0 -#endif - -#ifdef LITTLE_ENDIAN -#define HWM_REVERSE(x) (x) -#else -#define HWM_REVERSE(x) ((((x)<<24L)&0xff000000L) + \ - (((x)<< 8L)&0x00ff0000L) + \ - (((x)>> 8L)&0x0000ff00L) + \ - (((x)>>24L)&0x000000ffL)) -#endif - -#define C_INDIC (1L<<25) -#define A_INDIC (1L<<26) -#define RD_FS_LOCAL 0x80 - - /* - * DEBUG FLAGS - */ -#define DEBUG_SMTF 1 -#define DEBUG_SMT 2 -#define DEBUG_ECM 3 -#define DEBUG_RMT 4 -#define DEBUG_CFM 5 -#define DEBUG_PCM 6 -#define DEBUG_SBA 7 -#define DEBUG_ESS 8 - -#define DB_HWM_RX 10 -#define DB_HWM_TX 11 -#define DB_HWM_GEN 12 - -struct s_mbuf_pool { -#ifndef MB_OUTSIDE_SMC - SMbuf mb[MAX_MBUF] ; /* mbuf pool */ -#endif - SMbuf *mb_start ; /* points to the first mb */ - SMbuf *mb_free ; /* free queue */ -} ; - -struct hwm_r { - /* - * hardware modul specific receive variables - */ - u_int len ; /* length of the whole frame */ - char *mb_pos ; /* SMbuf receive position */ -} ; - -struct hw_modul { - /* - * All hardware modul specific variables - */ - struct s_mbuf_pool mbuf_pool ; - struct hwm_r r ; - - union s_fp_descr volatile *descr_p ; /* points to the desriptor area */ - - u_short pass_SMT ; /* pass SMT frames */ - u_short pass_NSA ; /* pass all NSA frames */ - u_short pass_DB ; /* pass Direct Beacon Frames */ - u_short pass_llc_promisc ; /* pass all llc frames (default ON) */ - - SMbuf *llc_rx_pipe ; /* points to the first queued llc fr */ - SMbuf *llc_rx_tail ; /* points to the last queued llc fr */ - int queued_rx_frames ; /* number of queued frames */ - - SMbuf *txd_tx_pipe ; /* points to first mb in the txd ring */ - SMbuf *txd_tx_tail ; /* points to last mb in the txd ring */ - int queued_txd_mb ; /* number of SMT MBufs in txd ring */ - - int rx_break ; /* rev. was breaked because ind. off */ - int leave_isr ; /* leave fddi_isr immedeately if set */ - int isr_flag ; /* set, when HWM is entered from isr */ - /* - * variables for the current transmit frame - */ - struct s_smt_tx_queue *tx_p ; /* pointer to the transmit queue */ - u_long tx_descr ; /* tx descriptor for FORMAC+ */ - int tx_len ; /* tx frame length */ - SMbuf *tx_mb ; /* SMT tx MBuf pointer */ - char *tx_data ; /* data pointer to the SMT tx Mbuf */ - - int detec_count ; /* counter for out of RxD condition */ - u_long rx_len_error ; /* rx len FORMAC != sum of fragments */ -} ; - - -/* - * DEBUG structs and macros - */ - -#ifdef DEBUG -struct os_debug { - int hwm_rx ; - int hwm_tx ; - int hwm_gen ; -} ; -#endif - -#ifdef DEBUG -#ifdef DEBUG_BRD -#define DB_P smc->debug -#else -#define DB_P debug -#endif - -#define DB_RX(a,b,c,lev) if (DB_P.d_os.hwm_rx >= (lev)) printf(a,b,c) -#define DB_TX(a,b,c,lev) if (DB_P.d_os.hwm_tx >= (lev)) printf(a,b,c) -#define DB_GEN(a,b,c,lev) if (DB_P.d_os.hwm_gen >= (lev)) printf(a,b,c) -#else /* DEBUG */ -#define DB_RX(a,b,c,lev) -#define DB_TX(a,b,c,lev) -#define DB_GEN(a,b,c,lev) -#endif /* DEBUG */ - -#ifndef SK_BREAK -#define SK_BREAK() -#endif - - -/* - * HWM Macros - */ - -/* - * BEGIN_MANUAL_ENTRY(HWM_GET_TX_PHYS) - * u_long HWM_GET_TX_PHYS(txd) - * - * function MACRO (hardware module, hwmtm.h) - * This macro may be invoked by the OS-specific module to read - * the physical address of the specified TxD. - * - * para txd pointer to the TxD - * - * END_MANUAL_ENTRY - */ -#define HWM_GET_TX_PHYS(txd) (u_long)AIX_REVERSE((txd)->txd_tbadr) - -/* - * BEGIN_MANUAL_ENTRY(HWM_GET_TX_LEN) - * int HWM_GET_TX_LEN(txd) - * - * function MACRO (hardware module, hwmtm.h) - * This macro may be invoked by the OS-specific module to read - * the fragment length of the specified TxD - * - * para rxd pointer to the TxD - * - * return the length of the fragment in bytes - * - * END_MANUAL_ENTRY - */ -#define HWM_GET_TX_LEN(txd) ((int)AIX_REVERSE((txd)->txd_tbctrl)& RD_LENGTH) - -/* - * BEGIN_MANUAL_ENTRY(HWM_GET_TX_USED) - * txd *HWM_GET_TX_USED(smc,queue) - * - * function MACRO (hardware module, hwmtm.h) - * This macro may be invoked by the OS-specific module to get the - * number of used TxDs for the queue, specified by the index. - * - * para queue the number of the send queue: Can be specified by - * QUEUE_A0, QUEUE_S or (frame_status & QUEUE_A0) - * - * return number of used TxDs for this send queue - * - * END_MANUAL_ENTRY - */ -#define HWM_GET_TX_USED(smc,queue) (int) (smc)->hw.fp.tx_q[queue].tx_used - -/* - * BEGIN_MANUAL_ENTRY(HWM_GET_CURR_TXD) - * txd *HWM_GET_CURR_TXD(smc,queue) - * - * function MACRO (hardware module, hwmtm.h) - * This macro may be invoked by the OS-specific module to get the - * pointer to the TxD which points to the current queue put - * position. - * - * para queue the number of the send queue: Can be specified by - * QUEUE_A0, QUEUE_S or (frame_status & QUEUE_A0) - * - * return pointer to the current TxD - * - * END_MANUAL_ENTRY - */ -#define HWM_GET_CURR_TXD(smc,queue) (struct s_smt_fp_txd volatile *)\ - (smc)->hw.fp.tx_q[queue].tx_curr_put - -/* - * BEGIN_MANUAL_ENTRY(HWM_GET_RX_FRAG_LEN) - * int HWM_GET_RX_FRAG_LEN(rxd) - * - * function MACRO (hardware module, hwmtm.h) - * This macro may be invoked by the OS-specific module to read - * the fragment length of the specified RxD - * - * para rxd pointer to the RxD - * - * return the length of the fragment in bytes - * - * END_MANUAL_ENTRY - */ -#define HWM_GET_RX_FRAG_LEN(rxd) ((int)AIX_REVERSE((rxd)->rxd_rbctrl)& \ - RD_LENGTH) - -/* - * BEGIN_MANUAL_ENTRY(HWM_GET_RX_PHYS) - * u_long HWM_GET_RX_PHYS(rxd) - * - * function MACRO (hardware module, hwmtm.h) - * This macro may be invoked by the OS-specific module to read - * the physical address of the specified RxD. - * - * para rxd pointer to the RxD - * - * return the RxD's physical pointer to the data fragment - * - * END_MANUAL_ENTRY - */ -#define HWM_GET_RX_PHYS(rxd) (u_long)AIX_REVERSE((rxd)->rxd_rbadr) - -/* - * BEGIN_MANUAL_ENTRY(HWM_GET_RX_USED) - * int HWM_GET_RX_USED(smc) - * - * function MACRO (hardware module, hwmtm.h) - * This macro may be invoked by the OS-specific module to get - * the count of used RXDs in receive queue 1. - * - * return the used RXD count of receive queue 1 - * - * NOTE: Remember, because of an ASIC bug at least one RXD should be unused - * in the descriptor ring ! - * - * END_MANUAL_ENTRY - */ -#define HWM_GET_RX_USED(smc) ((int)(smc)->hw.fp.rx_q[QUEUE_R1].rx_used) - -/* - * BEGIN_MANUAL_ENTRY(HWM_GET_RX_FREE) - * int HWM_GET_RX_FREE(smc) - * - * function MACRO (hardware module, hwmtm.h) - * This macro may be invoked by the OS-specific module to get - * the rxd_free count of receive queue 1. - * - * return the rxd_free count of receive queue 1 - * - * END_MANUAL_ENTRY - */ -#define HWM_GET_RX_FREE(smc) ((int)(smc)->hw.fp.rx_q[QUEUE_R1].rx_free-1) - -/* - * BEGIN_MANUAL_ENTRY(HWM_GET_CURR_RXD) - * rxd *HWM_GET_CURR_RXD(smc) - * - * function MACRO (hardware module, hwmtm.h) - * This macro may be invoked by the OS-specific module to get the - * pointer to the RxD which points to the current queue put - * position. - * - * return pointer to the current RxD - * - * END_MANUAL_ENTRY - */ -#define HWM_GET_CURR_RXD(smc) (struct s_smt_fp_rxd volatile *)\ - (smc)->hw.fp.rx_q[QUEUE_R1].rx_curr_put - -/* - * BEGIN_MANUAL_ENTRY(HWM_RX_CHECK) - * void HWM_RX_CHECK(smc,low_water) - * - * function MACRO (hardware module, hwmtm.h) - * This macro is invoked by the OS-specific before it left the - * function mac_drv_rx_complete. This macro calls mac_drv_fill_rxd - * if the number of used RxDs is equal or lower than the - * the given low water mark. - * - * para low_water low water mark of used RxD's - * - * END_MANUAL_ENTRY - */ -#ifndef HWM_NO_FLOW_CTL -#define HWM_RX_CHECK(smc,low_water) {\ - if ((low_water) >= (smc)->hw.fp.rx_q[QUEUE_R1].rx_used) {\ - mac_drv_fill_rxd(smc) ;\ - }\ -} -#else -#define HWM_RX_CHECK(smc,low_water) mac_drv_fill_rxd(smc) -#endif - -#ifndef HWM_EBASE -#define HWM_EBASE 500 -#endif - -#define HWM_E0001 HWM_EBASE + 1 -#define HWM_E0001_MSG "HWM: Wrong size of s_rxd_os struct" -#define HWM_E0002 HWM_EBASE + 2 -#define HWM_E0002_MSG "HWM: Wrong size of s_txd_os struct" -#define HWM_E0003 HWM_EBASE + 3 -#define HWM_E0003_MSG "HWM: smt_free_mbuf() called with NULL pointer" -#define HWM_E0004 HWM_EBASE + 4 -#define HWM_E0004_MSG "HWM: Parity error rx queue 1" -#define HWM_E0005 HWM_EBASE + 5 -#define HWM_E0005_MSG "HWM: Encoding error rx queue 1" -#define HWM_E0006 HWM_EBASE + 6 -#define HWM_E0006_MSG "HWM: Encoding error async tx queue" -#define HWM_E0007 HWM_EBASE + 7 -#define HWM_E0007_MSG "HWM: Encoding error sync tx queue" -#define HWM_E0008 HWM_EBASE + 8 -#define HWM_E0008_MSG "" -#define HWM_E0009 HWM_EBASE + 9 -#define HWM_E0009_MSG "HWM: Out of RxD condition detected" -#define HWM_E0010 HWM_EBASE + 10 -#define HWM_E0010_MSG "HWM: A protocol layer has tried to send a frame with an invalid frame control" -#define HWM_E0011 HWM_EBASE + 11 -#define HWM_E0011_MSG "HWM: mac_drv_clear_tx_queue was called although the hardware wasn't stopped" -#define HWM_E0012 HWM_EBASE + 12 -#define HWM_E0012_MSG "HWM: mac_drv_clear_rx_queue was called although the hardware wasn't stopped" -#define HWM_E0013 HWM_EBASE + 13 -#define HWM_E0013_MSG "HWM: mac_drv_repair_descr was called although the hardware wasn't stopped" - -#endif diff --git a/drivers/net/skfp/h/mbuf.h b/drivers/net/skfp/h/mbuf.h deleted file mode 100644 index f2aadcd..0000000 --- a/drivers/net/skfp/h/mbuf.h +++ /dev/null @@ -1,50 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -#ifndef _MBUF_ -#define _MBUF_ - -#define M_SIZE 4504 - -#ifndef MAX_MBUF -#define MAX_MBUF 4 -#endif - -#ifndef NO_STD_MBUF -#define sm_next m_next -#define sm_off m_off -#define sm_len m_len -#define sm_data m_data -#define SMbuf Mbuf -#define mtod smtod -#define mtodoff smtodoff -#endif - -struct s_mbuf { - struct s_mbuf *sm_next ; /* low level linked list */ - short sm_off ; /* offset in m_data */ - u_int sm_len ; /* len of data */ -#ifdef PCI - int sm_use_count ; -#endif - char sm_data[M_SIZE] ; -} ; - -typedef struct s_mbuf SMbuf ; - -/* mbuf head, to typed data */ -#define smtod(x,t) ((t)((x)->sm_data + (x)->sm_off)) -#define smtodoff(x,t,o) ((t)((x)->sm_data + (o))) - -#endif /* _MBUF_ */ diff --git a/drivers/net/skfp/h/osdef1st.h b/drivers/net/skfp/h/osdef1st.h deleted file mode 100644 index 763ca18..0000000 --- a/drivers/net/skfp/h/osdef1st.h +++ /dev/null @@ -1,125 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - * Operating system-dependent definitions that have to be defined - * before any other header files are included. - */ - -// HWM (HardWare Module) Definitions -// ----------------------- - -#include - -#ifdef __LITTLE_ENDIAN -#define LITTLE_ENDIAN -#else -#define BIG_ENDIAN -#endif - -// this is set in the makefile -// #define PCI /* only PCI adapters supported by this driver */ -// #define MEM_MAPPED_IO /* use memory mapped I/O */ - - -#define USE_CAN_ADDR /* DA and SA in MAC header are canonical. */ - -#define MB_OUTSIDE_SMC /* SMT Mbufs outside of smc struct. */ - -// ----------------------- - - -// SMT Definitions -// ----------------------- -#define SYNC /* allow synchronous frames */ - -// #define SBA /* Synchronous Bandwidth Allocator support */ - /* not available as free source */ - -#define ESS /* SBA End Station Support */ - -#define SMT_PANIC(smc, nr, msg) printk(KERN_INFO "SMT PANIC: code: %d, msg: %s\n",nr,msg) - - -#ifdef DEBUG -#define printf(s,args...) printk(KERN_INFO s, ## args) -#endif - -// #define HW_PTR u_long -// ----------------------- - - - -// HWM and OS-specific buffer definitions -// ----------------------- - -// default number of receive buffers. -#define NUM_RECEIVE_BUFFERS 10 - -// default number of transmit buffers. -#define NUM_TRANSMIT_BUFFERS 10 - -// Number of SMT buffers (Mbufs). -#define NUM_SMT_BUF 4 - -// Number of TXDs for asynchronous transmit queue. -#define HWM_ASYNC_TXD_COUNT (NUM_TRANSMIT_BUFFERS + NUM_SMT_BUF) - -// Number of TXDs for synchronous transmit queue. -#define HWM_SYNC_TXD_COUNT HWM_ASYNC_TXD_COUNT - - -// Number of RXDs for receive queue #1. -// Note: Workaround for ASIC Errata #7: One extra RXD is required. -#if (NUM_RECEIVE_BUFFERS > 100) -#define SMT_R1_RXD_COUNT (1 + 100) -#else -#define SMT_R1_RXD_COUNT (1 + NUM_RECEIVE_BUFFERS) -#endif - -// Number of RXDs for receive queue #2. -#define SMT_R2_RXD_COUNT 0 // Not used. -// ----------------------- - - - -/* - * OS-specific part of the transmit/receive descriptor structure (TXD/RXD). - * - * Note: The size of these structures must follow this rule: - * - * sizeof(struct) + 2*sizeof(void*) == n * 16, n >= 1 - * - * We use the dma_addr fields under Linux to keep track of the - * DMA address of the packet data, for later pci_unmap_single. -DaveM - */ - -struct s_txd_os { // os-specific part of transmit descriptor - struct sk_buff *skb; - dma_addr_t dma_addr; -} ; - -struct s_rxd_os { // os-specific part of receive descriptor - struct sk_buff *skb; - dma_addr_t dma_addr; -} ; - - -/* - * So we do not need to make too many modifications to the generic driver - * parts, we take advantage of the AIX byte swapping macro interface. - */ - -#define AIX_REVERSE(x) ((u32)le32_to_cpu((u32)(x))) -#define MDR_REVERSE(x) ((u32)le32_to_cpu((u32)(x))) diff --git a/drivers/net/skfp/h/sba.h b/drivers/net/skfp/h/sba.h deleted file mode 100644 index 638cf02..0000000 --- a/drivers/net/skfp/h/sba.h +++ /dev/null @@ -1,142 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - * Synchronous Bandwidth Allocation (SBA) structs - */ - -#ifndef _SBA_ -#define _SBA_ - -#include "h/mbuf.h" -#include "h/sba_def.h" - -#ifdef SBA - -/* Timer Cell Template */ -struct timer_cell { - struct timer_cell *next_ptr ; - struct timer_cell *prev_ptr ; - u_long start_time ; - struct s_sba_node_vars *node_var ; -} ; - -/* - * Node variables - */ -struct s_sba_node_vars { - u_char change_resp_flag ; - u_char report_resp_flag ; - u_char change_req_flag ; - u_char report_req_flag ; - long change_amount ; - long node_overhead ; - long node_payload ; - u_long node_status ; - u_char deallocate_status ; - u_char timer_state ; - u_short report_cnt ; - long lastrep_req_tranid ; - struct fddi_addr mac_address ; - struct s_sba_sessions *node_sessions ; - struct timer_cell timer ; -} ; - -/* - * Session variables - */ -struct s_sba_sessions { - u_long deallocate_status ; - long session_overhead ; - u_long min_segment_size ; - long session_payload ; - u_long session_status ; - u_long sba_category ; - long lastchg_req_tranid ; - u_short session_id ; - u_char class ; - u_char fddi2 ; - u_long max_t_neg ; - struct s_sba_sessions *next_session ; -} ; - -struct s_sba { - - struct s_sba_node_vars node[MAX_NODES] ; - struct s_sba_sessions session[MAX_SESSIONS] ; - - struct s_sba_sessions *free_session ; /* points to the first */ - /* free session */ - - struct timer_cell *tail_timer ; /* points to the last timer cell */ - - /* - * variables for allocation actions - */ - long total_payload ; /* Total Payload */ - long total_overhead ; /* Total Overhead */ - long sba_allocatable ; /* allocatable sync bandwidth */ - - /* - * RAF message receive parameters - */ - long msg_path_index ; /* Path Type */ - long msg_sba_pl_req ; /* Payload Request */ - long msg_sba_ov_req ; /* Overhead Request */ - long msg_mib_pl ; /* Current Payload for this Path */ - long msg_mib_ov ; /* Current Overhead for this Path*/ - long msg_category ; /* Category of the Allocation */ - u_long msg_max_t_neg ; /* longest T_Neg acceptable */ - u_long msg_min_seg_siz ; /* minimum segement size */ - struct smt_header *sm ; /* points to the rec message */ - struct fddi_addr *msg_alloc_addr ; /* Allocation Address */ - - /* - * SBA variables - */ - u_long sba_t_neg ; /* holds the last T_NEG */ - long sba_max_alloc ; /* the parsed value of SBAAvailable */ - - /* - * SBA state machine variables - */ - short sba_next_state ; /* the next state of the SBA */ - char sba_command ; /* holds the execuded SBA cmd */ - u_char sba_available ; /* parsed value after possible check */ -} ; - -#endif /* SBA */ - - /* - * variables for the End Station Support - */ -struct s_ess { - - /* - * flags and counters - */ - u_char sync_bw_available ; /* is set if sync bw is allocated */ - u_char local_sba_active ; /* set when a local sba is available */ - char raf_act_timer_poll ; /* activate the timer to send allc req */ - char timer_count ; /* counts every timer function call */ - - SMbuf *sba_reply_pend ; /* local reply for the sba is pending */ - - /* - * variables for the ess bandwidth control - */ - long sync_bw ; /* holds the allocaed sync bw */ - u_long alloc_trans_id ; /* trans id of the last alloc req */ -} ; -#endif diff --git a/drivers/net/skfp/h/sba_def.h b/drivers/net/skfp/h/sba_def.h deleted file mode 100644 index 0459a09..0000000 --- a/drivers/net/skfp/h/sba_def.h +++ /dev/null @@ -1,76 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -#define PHYS 0 /* physical addr */ -#define PERM_ADDR 0x80 /* permanet address */ -#define SB_STATIC 0x00000001 -#define MAX_PAYLOAD 1562 -#define PRIMARY_RING 0x00000001 -#ifndef NULL -#define NULL 0x00 -#endif - -/*********************** SB_Input Variable Values ***********************/ -/* may be needed when ever the SBA state machine is called */ - -#define UNKNOWN_SYNC_SOURCE 0x0001 -#define REQ_ALLOCATION 0x0002 -#define REPORT_RESP 0x0003 -#define CHANGE_RESP 0x0004 -#define TNEG 0x0005 -#define NIF 0x0006 -#define SB_STOP 0x0007 -#define SB_START 0x0008 -#define REPORT_TIMER 0x0009 -#define CHANGE_REQUIRED 0x000A - -#define DEFAULT_OV 50 - -#ifdef SBA -/**************************** SBA STATES *****************************/ - -#define SBA_STANDBY 0x00000000 -#define SBA_ACTIVE 0x00000001 -#define SBA_RECOVERY 0x00000002 -#define SBA_REPORT 0x00000003 -#define SBA_CHANGE 0x00000004 - -/**************************** OTHERS *********************************/ - -#define FIFTY_PERCENT 50 /* bytes per second */ -#define MAX_SESSIONS 150 -#define TWO_MINUTES 13079 /* 9.175 ms/tick */ -#define FIFTY_BYTES 50 -#define SBA_DENIED 0x0000000D -#define I_NEED_ONE 0x00000000 -#define MAX_NODES 50 -/*#define T_REPORT 0x59682F00L*/ /* 120s/80ns in Hex */ -#define TWO_MIN 120 /* seconds */ -#define SBA_ST_UNKNOWN 0x00000002 -#define SBA_ST_ACTIVE 0x00000001 -#define S_CLEAR 0x00000000L -#define ZERO 0x00000000 -#define FULL 0x00000000 /* old: 0xFFFFFFFFF */ -#define S_SET 0x00000001L -#define LOW_PRIO 0x02 /* ??????? */ -#define OK 0x01 /* ??????? */ -#define NOT_OK 0x00 /* ??????? */ - -/****************************************/ -/* deallocate_status[ni][si] values */ -/****************************************/ -#define TX_CHANGE 0X00000001L -#define PENDING 0x00000002L -#define NONE 0X00000000L -#endif diff --git a/drivers/net/skfp/h/skfbi.h b/drivers/net/skfp/h/skfbi.h deleted file mode 100644 index c1ba26c..0000000 --- a/drivers/net/skfp/h/skfbi.h +++ /dev/null @@ -1,1133 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -#ifndef _SKFBI_H_ -#define _SKFBI_H_ - -/* - * FDDI-Fx (x := {I(SA), P(CI)}) - * address calculation & function defines - */ - -/*--------------------------------------------------------------------------*/ -#ifdef PCI - -/* - * (DV) = only defined for Da Vinci - * (ML) = only defined for Monalisa - */ - -/* - * Configuration Space header - */ -#define PCI_VENDOR_ID 0x00 /* 16 bit Vendor ID */ -#define PCI_DEVICE_ID 0x02 /* 16 bit Device ID */ -#define PCI_COMMAND 0x04 /* 16 bit Command */ -#define PCI_STATUS 0x06 /* 16 bit Status */ -#define PCI_REV_ID 0x08 /* 8 bit Revision ID */ -#define PCI_CLASS_CODE 0x09 /* 24 bit Class Code */ -#define PCI_CACHE_LSZ 0x0c /* 8 bit Cache Line Size */ -#define PCI_LAT_TIM 0x0d /* 8 bit Latency Timer */ -#define PCI_HEADER_T 0x0e /* 8 bit Header Type */ -#define PCI_BIST 0x0f /* 8 bit Built-in selftest */ -#define PCI_BASE_1ST 0x10 /* 32 bit 1st Base address */ -#define PCI_BASE_2ND 0x14 /* 32 bit 2nd Base address */ -/* Byte 18..2b: Reserved */ -#define PCI_SUB_VID 0x2c /* 16 bit Subsystem Vendor ID */ -#define PCI_SUB_ID 0x2e /* 16 bit Subsystem ID */ -#define PCI_BASE_ROM 0x30 /* 32 bit Expansion ROM Base Address */ -/* Byte 34..33: Reserved */ -#define PCI_CAP_PTR 0x34 /* 8 bit (ML) Capabilities Ptr */ -/* Byte 35..3b: Reserved */ -#define PCI_IRQ_LINE 0x3c /* 8 bit Interrupt Line */ -#define PCI_IRQ_PIN 0x3d /* 8 bit Interrupt Pin */ -#define PCI_MIN_GNT 0x3e /* 8 bit Min_Gnt */ -#define PCI_MAX_LAT 0x3f /* 8 bit Max_Lat */ -/* Device Dependent Region */ -#define PCI_OUR_REG 0x40 /* 32 bit (DV) Our Register */ -#define PCI_OUR_REG_1 0x40 /* 32 bit (ML) Our Register 1 */ -#define PCI_OUR_REG_2 0x44 /* 32 bit (ML) Our Register 2 */ -/* Power Management Region */ -#define PCI_PM_CAP_ID 0x48 /* 8 bit (ML) Power Management Cap. ID */ -#define PCI_PM_NITEM 0x49 /* 8 bit (ML) Next Item Ptr */ -#define PCI_PM_CAP_REG 0x4a /* 16 bit (ML) Power Management Capabilities */ -#define PCI_PM_CTL_STS 0x4c /* 16 bit (ML) Power Manag. Control/Status */ -/* Byte 0x4e: Reserved */ -#define PCI_PM_DAT_REG 0x4f /* 8 bit (ML) Power Manag. Data Register */ -/* VPD Region */ -#define PCI_VPD_CAP_ID 0x50 /* 8 bit (ML) VPD Cap. ID */ -#define PCI_VPD_NITEM 0x51 /* 8 bit (ML) Next Item Ptr */ -#define PCI_VPD_ADR_REG 0x52 /* 16 bit (ML) VPD Address Register */ -#define PCI_VPD_DAT_REG 0x54 /* 32 bit (ML) VPD Data Register */ -/* Byte 58..ff: Reserved */ - -/* - * I2C Address (PCI Config) - * - * Note: The temperature and voltage sensors are relocated on a different - * I2C bus. - */ -#define I2C_ADDR_VPD 0xA0 /* I2C address for the VPD EEPROM */ - -/* - * Define Bits and Values of the registers - */ -/* PCI_VENDOR_ID 16 bit Vendor ID */ -/* PCI_DEVICE_ID 16 bit Device ID */ -/* Values for Vendor ID and Device ID shall be patched into the code */ -/* PCI_COMMAND 16 bit Command */ -#define PCI_FBTEN 0x0200 /* Bit 9: Fast Back-To-Back enable */ -#define PCI_SERREN 0x0100 /* Bit 8: SERR enable */ -#define PCI_ADSTEP 0x0080 /* Bit 7: Address Stepping */ -#define PCI_PERREN 0x0040 /* Bit 6: Parity Report Response enable */ -#define PCI_VGA_SNOOP 0x0020 /* Bit 5: VGA palette snoop */ -#define PCI_MWIEN 0x0010 /* Bit 4: Memory write an inv cycl ena */ -#define PCI_SCYCEN 0x0008 /* Bit 3: Special Cycle enable */ -#define PCI_BMEN 0x0004 /* Bit 2: Bus Master enable */ -#define PCI_MEMEN 0x0002 /* Bit 1: Memory Space Access enable */ -#define PCI_IOEN 0x0001 /* Bit 0: IO Space Access enable */ - -/* PCI_STATUS 16 bit Status */ -#define PCI_PERR 0x8000 /* Bit 15: Parity Error */ -#define PCI_SERR 0x4000 /* Bit 14: Signaled SERR */ -#define PCI_RMABORT 0x2000 /* Bit 13: Received Master Abort */ -#define PCI_RTABORT 0x1000 /* Bit 12: Received Target Abort */ -#define PCI_STABORT 0x0800 /* Bit 11: Sent Target Abort */ -#define PCI_DEVSEL 0x0600 /* Bit 10..9: DEVSEL Timing */ -#define PCI_DEV_FAST (0<<9) /* fast */ -#define PCI_DEV_MEDIUM (1<<9) /* medium */ -#define PCI_DEV_SLOW (2<<9) /* slow */ -#define PCI_DATAPERR 0x0100 /* Bit 8: DATA Parity error detected */ -#define PCI_FB2BCAP 0x0080 /* Bit 7: Fast Back-to-Back Capability */ -#define PCI_UDF 0x0040 /* Bit 6: User Defined Features */ -#define PCI_66MHZCAP 0x0020 /* Bit 5: 66 MHz PCI bus clock capable */ -#define PCI_NEWCAP 0x0010 /* Bit 4: New cap. list implemented */ - -#define PCI_ERRBITS (PCI_PERR|PCI_SERR|PCI_RMABORT|PCI_STABORT|PCI_DATAPERR) - -/* PCI_REV_ID 8 bit Revision ID */ -/* PCI_CLASS_CODE 24 bit Class Code */ -/* Byte 2: Base Class (02) */ -/* Byte 1: SubClass (02) */ -/* Byte 0: Programming Interface (00) */ - -/* PCI_CACHE_LSZ 8 bit Cache Line Size */ -/* Possible values: 0,2,4,8,16 */ - -/* PCI_LAT_TIM 8 bit Latency Timer */ - -/* PCI_HEADER_T 8 bit Header Type */ -#define PCI_HD_MF_DEV 0x80 /* Bit 7: 0= single, 1= multi-func dev */ -#define PCI_HD_TYPE 0x7f /* Bit 6..0: Header Layout 0= normal */ - -/* PCI_BIST 8 bit Built-in selftest */ -#define PCI_BIST_CAP 0x80 /* Bit 7: BIST Capable */ -#define PCI_BIST_ST 0x40 /* Bit 6: Start BIST */ -#define PCI_BIST_RET 0x0f /* Bit 3..0: Completion Code */ - -/* PCI_BASE_1ST 32 bit 1st Base address */ -#define PCI_MEMSIZE 0x800L /* use 2 kB Memory Base */ -#define PCI_MEMBASE_BITS 0xfffff800L /* Bit 31..11: Memory Base Address */ -#define PCI_MEMSIZE_BIIS 0x000007f0L /* Bit 10..4: Memory Size Req. */ -#define PCI_PREFEN 0x00000008L /* Bit 3: Prefetchable */ -#define PCI_MEM_TYP 0x00000006L /* Bit 2..1: Memory Type */ -#define PCI_MEM32BIT (0<<1) /* Base addr anywhere in 32 Bit range */ -#define PCI_MEM1M (1<<1) /* Base addr below 1 MegaByte */ -#define PCI_MEM64BIT (2<<1) /* Base addr anywhere in 64 Bit range */ -#define PCI_MEMSPACE 0x00000001L /* Bit 0: Memory Space Indic. */ - -/* PCI_BASE_2ND 32 bit 2nd Base address */ -#define PCI_IOBASE 0xffffff00L /* Bit 31..8: I/O Base address */ -#define PCI_IOSIZE 0x000000fcL /* Bit 7..2: I/O Size Requirements */ -#define PCI_IOSPACE 0x00000001L /* Bit 0: I/O Space Indicator */ - -/* PCI_SUB_VID 16 bit Subsystem Vendor ID */ -/* PCI_SUB_ID 16 bit Subsystem ID */ - -/* PCI_BASE_ROM 32 bit Expansion ROM Base Address */ -#define PCI_ROMBASE 0xfffe0000L /* Bit 31..17: ROM BASE address (1st) */ -#define PCI_ROMBASZ 0x0001c000L /* Bit 16..14: Treat as BASE or SIZE */ -#define PCI_ROMSIZE 0x00003800L /* Bit 13..11: ROM Size Requirements */ -#define PCI_ROMEN 0x00000001L /* Bit 0: Address Decode enable */ - -/* PCI_CAP_PTR 8 bit New Capabilities Pointers */ -/* PCI_IRQ_LINE 8 bit Interrupt Line */ -/* PCI_IRQ_PIN 8 bit Interrupt Pin */ -/* PCI_MIN_GNT 8 bit Min_Gnt */ -/* PCI_MAX_LAT 8 bit Max_Lat */ -/* Device Dependent Region */ -/* PCI_OUR_REG (DV) 32 bit Our Register */ -/* PCI_OUR_REG_1 (ML) 32 bit Our Register 1 */ - /* Bit 31..29: reserved */ -#define PCI_PATCH_DIR (3L<<27) /*(DV) Bit 28..27: Ext Patchs direction */ -#define PCI_PATCH_DIR_0 (1L<<27) /*(DV) Type of the pins EXT_PATCHS<1..0> */ -#define PCI_PATCH_DIR_1 (1L<<28) /* 0 = input */ - /* 1 = output */ -#define PCI_EXT_PATCHS (3L<<25) /*(DV) Bit 26..25: Extended Patches */ -#define PCI_EXT_PATCH_0 (1L<<25) /*(DV) */ -#define PCI_EXT_PATCH_1 (1L<<26) /* CLK for MicroWire (ML) */ -#define PCI_VIO (1L<<25) /*(ML) */ -#define PCI_EN_BOOT (1L<<24) /* Bit 24: Enable BOOT via ROM */ - /* 1 = Don't boot with ROM */ - /* 0 = Boot with ROM */ -#define PCI_EN_IO (1L<<23) /* Bit 23: Mapping to IO space */ -#define PCI_EN_FPROM (1L<<22) /* Bit 22: FLASH mapped to mem? */ - /* 1 = Map Flash to Memory */ - /* 0 = Disable all addr. decoding */ -#define PCI_PAGESIZE (3L<<20) /* Bit 21..20: FLASH Page Size */ -#define PCI_PAGE_16 (0L<<20) /* 16 k pages */ -#define PCI_PAGE_32K (1L<<20) /* 32 k pages */ -#define PCI_PAGE_64K (2L<<20) /* 64 k pages */ -#define PCI_PAGE_128K (3L<<20) /* 128 k pages */ - /* Bit 19: reserved (ML) and (DV) */ -#define PCI_PAGEREG (7L<<16) /* Bit 18..16: Page Register */ - /* Bit 15: reserved */ -#define PCI_FORCE_BE (1L<<14) /* Bit 14: Assert all BEs on MR */ -#define PCI_DIS_MRL (1L<<13) /* Bit 13: Disable Mem R Line */ -#define PCI_DIS_MRM (1L<<12) /* Bit 12: Disable Mem R multip */ -#define PCI_DIS_MWI (1L<<11) /* Bit 11: Disable Mem W & inv */ -#define PCI_DISC_CLS (1L<<10) /* Bit 10: Disc: cacheLsz bound */ -#define PCI_BURST_DIS (1L<<9) /* Bit 9: Burst Disable */ -#define PCI_BYTE_SWAP (1L<<8) /*(DV) Bit 8: Byte Swap in DATA */ -#define PCI_SKEW_DAS (0xfL<<4) /* Bit 7..4: Skew Ctrl, DAS Ext */ -#define PCI_SKEW_BASE (0xfL<<0) /* Bit 3..0: Skew Ctrl, Base */ - -/* PCI_OUR_REG_2 (ML) 32 bit Our Register 2 (Monalisa only) */ -#define PCI_VPD_WR_TH (0xffL<<24) /* Bit 24..31 VPD Write Threshold */ -#define PCI_DEV_SEL (0x7fL<<17) /* Bit 17..23 EEPROM Device Select */ -#define PCI_VPD_ROM_SZ (7L<<14) /* Bit 14..16 VPD ROM Size */ - /* Bit 12..13 reserved */ -#define PCI_PATCH_DIR2 (0xfL<<8) /* Bit 8..11 Ext Patchs dir 2..5 */ -#define PCI_PATCH_DIR_2 (1L<<8) /* Bit 8 CS for MicroWire */ -#define PCI_PATCH_DIR_3 (1L<<9) -#define PCI_PATCH_DIR_4 (1L<<10) -#define PCI_PATCH_DIR_5 (1L<<11) -#define PCI_EXT_PATCHS2 (0xfL<<4) /* Bit 4..7 Extended Patches */ -#define PCI_EXT_PATCH_2 (1L<<4) /* Bit 4 CS for MicroWire */ -#define PCI_EXT_PATCH_3 (1L<<5) -#define PCI_EXT_PATCH_4 (1L<<6) -#define PCI_EXT_PATCH_5 (1L<<7) -#define PCI_EN_DUMMY_RD (1L<<3) /* Bit 3 Enable Dummy Read */ -#define PCI_REV_DESC (1L<<2) /* Bit 2 Reverse Desc. Bytes */ -#define PCI_USEADDR64 (1L<<1) /* Bit 1 Use 64 Bit Addresse */ -#define PCI_USEDATA64 (1L<<0) /* Bit 0 Use 64 Bit Data bus ext*/ - -/* Power Management Region */ -/* PCI_PM_CAP_ID 8 bit (ML) Power Management Cap. ID */ -/* PCI_PM_NITEM 8 bit (ML) Next Item Ptr */ -/* PCI_PM_CAP_REG 16 bit (ML) Power Management Capabilities*/ -#define PCI_PME_SUP (0x1f<<11) /* Bit 11..15 PM Manag. Event Support*/ -#define PCI_PM_D2_SUB (1<<10) /* Bit 10 D2 Support Bit */ -#define PCI_PM_D1_SUB (1<<9) /* Bit 9 D1 Support Bit */ - /* Bit 6..8 reserved */ -#define PCI_PM_DSI (1<<5) /* Bit 5 Device Specific Init.*/ -#define PCI_PM_APS (1<<4) /* Bit 4 Auxialiary Power Src */ -#define PCI_PME_CLOCK (1<<3) /* Bit 3 PM Event Clock */ -#define PCI_PM_VER (7<<0) /* Bit 0..2 PM PCI Spec. version */ - -/* PCI_PM_CTL_STS 16 bit (ML) Power Manag. Control/Status */ -#define PCI_PME_STATUS (1<<15) /* Bit 15 PFA doesn't sup. PME#*/ -#define PCI_PM_DAT_SCL (3<<13) /* Bit 13..14 dat reg Scaling factor */ -#define PCI_PM_DAT_SEL (0xf<<9) /* Bit 9..12 PM data selector field */ - /* Bit 7.. 2 reserved */ -#define PCI_PM_STATE (3<<0) /* Bit 0.. 1 Power Management State */ -#define PCI_PM_STATE_D0 (0<<0) /* D0: Operational (default) */ -#define PCI_PM_STATE_D1 (1<<0) /* D1: not supported */ -#define PCI_PM_STATE_D2 (2<<0) /* D2: not supported */ -#define PCI_PM_STATE_D3 (3<<0) /* D3: HOT, Power Down and Reset */ - -/* PCI_PM_DAT_REG 8 bit (ML) Power Manag. Data Register */ -/* VPD Region */ -/* PCI_VPD_CAP_ID 8 bit (ML) VPD Cap. ID */ -/* PCI_VPD_NITEM 8 bit (ML) Next Item Ptr */ -/* PCI_VPD_ADR_REG 16 bit (ML) VPD Address Register */ -#define PCI_VPD_FLAG (1<<15) /* Bit 15 starts VPD rd/wd cycle*/ - -/* PCI_VPD_DAT_REG 32 bit (ML) VPD Data Register */ - -/* - * Control Register File: - * Bank 0 - */ -#define B0_RAP 0x0000 /* 8 bit register address port */ - /* 0x0001 - 0x0003: reserved */ -#define B0_CTRL 0x0004 /* 8 bit control register */ -#define B0_DAS 0x0005 /* 8 Bit control register (DAS) */ -#define B0_LED 0x0006 /* 8 Bit LED register */ -#define B0_TST_CTRL 0x0007 /* 8 bit test control register */ -#define B0_ISRC 0x0008 /* 32 bit Interrupt source register */ -#define B0_IMSK 0x000c /* 32 bit Interrupt mask register */ - -/* 0x0010 - 0x006b: formac+ (supernet_3) fequently used registers */ -#define B0_CMDREG1 0x0010 /* write command reg 1 instruction */ -#define B0_CMDREG2 0x0014 /* write command reg 2 instruction */ -#define B0_ST1U 0x0010 /* read upper 16-bit of status reg 1 */ -#define B0_ST1L 0x0014 /* read lower 16-bit of status reg 1 */ -#define B0_ST2U 0x0018 /* read upper 16-bit of status reg 2 */ -#define B0_ST2L 0x001c /* read lower 16-bit of status reg 2 */ - -#define B0_MARR 0x0020 /* r/w the memory read addr register */ -#define B0_MARW 0x0024 /* r/w the memory write addr register*/ -#define B0_MDRU 0x0028 /* r/w upper 16-bit of mem. data reg */ -#define B0_MDRL 0x002c /* r/w lower 16-bit of mem. data reg */ - -#define B0_MDREG3 0x0030 /* r/w Mode Register 3 */ -#define B0_ST3U 0x0034 /* read upper 16-bit of status reg 3 */ -#define B0_ST3L 0x0038 /* read lower 16-bit of status reg 3 */ -#define B0_IMSK3U 0x003c /* r/w upper 16-bit of IMSK reg 3 */ -#define B0_IMSK3L 0x0040 /* r/w lower 16-bit of IMSK reg 3 */ -#define B0_IVR 0x0044 /* read Interrupt Vector register */ -#define B0_IMR 0x0048 /* r/w Interrupt mask register */ -/* 0x4c Hidden */ - -#define B0_CNTRL_A 0x0050 /* control register A (r/w) */ -#define B0_CNTRL_B 0x0054 /* control register B (r/w) */ -#define B0_INTR_MASK 0x0058 /* interrupt mask (r/w) */ -#define B0_XMIT_VECTOR 0x005c /* transmit vector register (r/w) */ - -#define B0_STATUS_A 0x0060 /* status register A (read only) */ -#define B0_STATUS_B 0x0064 /* status register B (read only) */ -#define B0_CNTRL_C 0x0068 /* control register C (r/w) */ -#define B0_MDREG1 0x006c /* r/w Mode Register 1 */ - -#define B0_R1_CSR 0x0070 /* 32 bit BMU control/status reg (rec q 1) */ -#define B0_R2_CSR 0x0074 /* 32 bit BMU control/status reg (rec q 2)(DV)*/ -#define B0_XA_CSR 0x0078 /* 32 bit BMU control/status reg (a xmit q) */ -#define B0_XS_CSR 0x007c /* 32 bit BMU control/status reg (s xmit q) */ - -/* - * Bank 1 - * - completely empty (this is the RAP Block window) - * Note: if RAP = 1 this page is reserved - */ - -/* - * Bank 2 - */ -#define B2_MAC_0 0x0100 /* 8 bit MAC address Byte 0 */ -#define B2_MAC_1 0x0101 /* 8 bit MAC address Byte 1 */ -#define B2_MAC_2 0x0102 /* 8 bit MAC address Byte 2 */ -#define B2_MAC_3 0x0103 /* 8 bit MAC address Byte 3 */ -#define B2_MAC_4 0x0104 /* 8 bit MAC address Byte 4 */ -#define B2_MAC_5 0x0105 /* 8 bit MAC address Byte 5 */ -#define B2_MAC_6 0x0106 /* 8 bit MAC address Byte 6 (== 0) (DV) */ -#define B2_MAC_7 0x0107 /* 8 bit MAC address Byte 7 (== 0) (DV) */ - -#define B2_CONN_TYP 0x0108 /* 8 bit Connector type */ -#define B2_PMD_TYP 0x0109 /* 8 bit PMD type */ - /* 0x010a - 0x010b: reserved */ - /* Eprom registers are currently of no use */ -#define B2_E_0 0x010c /* 8 bit EPROM Byte 0 */ -#define B2_E_1 0x010d /* 8 bit EPROM Byte 1 */ -#define B2_E_2 0x010e /* 8 bit EPROM Byte 2 */ -#define B2_E_3 0x010f /* 8 bit EPROM Byte 3 */ -#define B2_FAR 0x0110 /* 32 bit Flash-Prom Address Register/Counter */ -#define B2_FDP 0x0114 /* 8 bit Flash-Prom Data Port */ - /* 0x0115 - 0x0117: reserved */ -#define B2_LD_CRTL 0x0118 /* 8 bit loader control */ -#define B2_LD_TEST 0x0119 /* 8 bit loader test */ - /* 0x011a - 0x011f: reserved */ -#define B2_TI_INI 0x0120 /* 32 bit Timer init value */ -#define B2_TI_VAL 0x0124 /* 32 bit Timer value */ -#define B2_TI_CRTL 0x0128 /* 8 bit Timer control */ -#define B2_TI_TEST 0x0129 /* 8 Bit Timer Test */ - /* 0x012a - 0x012f: reserved */ -#define B2_WDOG_INI 0x0130 /* 32 bit Watchdog init value */ -#define B2_WDOG_VAL 0x0134 /* 32 bit Watchdog value */ -#define B2_WDOG_CRTL 0x0138 /* 8 bit Watchdog control */ -#define B2_WDOG_TEST 0x0139 /* 8 Bit Watchdog Test */ - /* 0x013a - 0x013f: reserved */ -#define B2_RTM_INI 0x0140 /* 32 bit RTM init value */ -#define B2_RTM_VAL 0x0144 /* 32 bit RTM value */ -#define B2_RTM_CRTL 0x0148 /* 8 bit RTM control */ -#define B2_RTM_TEST 0x0149 /* 8 Bit RTM Test */ - -#define B2_TOK_COUNT 0x014c /* (ML) 32 bit Token Counter */ -#define B2_DESC_ADDR_H 0x0150 /* (ML) 32 bit Desciptor Base Addr Reg High */ -#define B2_CTRL_2 0x0154 /* (ML) 8 bit Control Register 2 */ -#define B2_IFACE_REG 0x0155 /* (ML) 8 bit Interface Register */ - /* 0x0156: reserved */ -#define B2_TST_CTRL_2 0x0157 /* (ML) 8 bit Test Control Register 2 */ -#define B2_I2C_CTRL 0x0158 /* (ML) 32 bit I2C Control Register */ -#define B2_I2C_DATA 0x015c /* (ML) 32 bit I2C Data Register */ - -#define B2_IRQ_MOD_INI 0x0160 /* (ML) 32 bit IRQ Moderation Timer Init Reg. */ -#define B2_IRQ_MOD_VAL 0x0164 /* (ML) 32 bit IRQ Moderation Timer Value */ -#define B2_IRQ_MOD_CTRL 0x0168 /* (ML) 8 bit IRQ Moderation Timer Control */ -#define B2_IRQ_MOD_TEST 0x0169 /* (ML) 8 bit IRQ Moderation Timer Test */ - /* 0x016a - 0x017f: reserved */ - -/* - * Bank 3 - */ -/* - * This is a copy of the Configuration register file (lower half) - */ -#define B3_CFG_SPC 0x180 - -/* - * Bank 4 - */ -#define B4_R1_D 0x0200 /* 4*32 bit current receive Descriptor */ -#define B4_R1_DA 0x0210 /* 32 bit current rec desc address */ -#define B4_R1_AC 0x0214 /* 32 bit current receive Address Count */ -#define B4_R1_BC 0x0218 /* 32 bit current receive Byte Counter */ -#define B4_R1_CSR 0x021c /* 32 bit BMU Control/Status Register */ -#define B4_R1_F 0x0220 /* 32 bit flag register */ -#define B4_R1_T1 0x0224 /* 32 bit Test Register 1 */ -#define B4_R1_T1_TR 0x0224 /* 8 bit Test Register 1 TR */ -#define B4_R1_T1_WR 0x0225 /* 8 bit Test Register 1 WR */ -#define B4_R1_T1_RD 0x0226 /* 8 bit Test Register 1 RD */ -#define B4_R1_T1_SV 0x0227 /* 8 bit Test Register 1 SV */ -#define B4_R1_T2 0x0228 /* 32 bit Test Register 2 */ -#define B4_R1_T3 0x022c /* 32 bit Test Register 3 */ -#define B4_R1_DA_H 0x0230 /* (ML) 32 bit Curr Rx Desc Address High */ -#define B4_R1_AC_H 0x0234 /* (ML) 32 bit Curr Addr Counter High dword */ - /* 0x0238 - 0x023f: reserved */ - /* Receive queue 2 is removed on Monalisa */ -#define B4_R2_D 0x0240 /* 4*32 bit current receive Descriptor (q2) */ -#define B4_R2_DA 0x0250 /* 32 bit current rec desc address (q2) */ -#define B4_R2_AC 0x0254 /* 32 bit current receive Address Count (q2) */ -#define B4_R2_BC 0x0258 /* 32 bit current receive Byte Counter (q2) */ -#define B4_R2_CSR 0x025c /* 32 bit BMU Control/Status Register (q2) */ -#define B4_R2_F 0x0260 /* 32 bit flag register (q2) */ -#define B4_R2_T1 0x0264 /* 32 bit Test Register 1 (q2) */ -#define B4_R2_T1_TR 0x0264 /* 8 bit Test Register 1 TR (q2) */ -#define B4_R2_T1_WR 0x0265 /* 8 bit Test Register 1 WR (q2) */ -#define B4_R2_T1_RD 0x0266 /* 8 bit Test Register 1 RD (q2) */ -#define B4_R2_T1_SV 0x0267 /* 8 bit Test Register 1 SV (q2) */ -#define B4_R2_T2 0x0268 /* 32 bit Test Register 2 (q2) */ -#define B4_R2_T3 0x026c /* 32 bit Test Register 3 (q2) */ - /* 0x0270 - 0x027c: reserved */ - -/* - * Bank 5 - */ -#define B5_XA_D 0x0280 /* 4*32 bit current transmit Descriptor (xa) */ -#define B5_XA_DA 0x0290 /* 32 bit current tx desc address (xa) */ -#define B5_XA_AC 0x0294 /* 32 bit current tx Address Count (xa) */ -#define B5_XA_BC 0x0298 /* 32 bit current tx Byte Counter (xa) */ -#define B5_XA_CSR 0x029c /* 32 bit BMU Control/Status Register (xa) */ -#define B5_XA_F 0x02a0 /* 32 bit flag register (xa) */ -#define B5_XA_T1 0x02a4 /* 32 bit Test Register 1 (xa) */ -#define B5_XA_T1_TR 0x02a4 /* 8 bit Test Register 1 TR (xa) */ -#define B5_XA_T1_WR 0x02a5 /* 8 bit Test Register 1 WR (xa) */ -#define B5_XA_T1_RD 0x02a6 /* 8 bit Test Register 1 RD (xa) */ -#define B5_XA_T1_SV 0x02a7 /* 8 bit Test Register 1 SV (xa) */ -#define B5_XA_T2 0x02a8 /* 32 bit Test Register 2 (xa) */ -#define B5_XA_T3 0x02ac /* 32 bit Test Register 3 (xa) */ -#define B5_XA_DA_H 0x02b0 /* (ML) 32 bit Curr Tx Desc Address High */ -#define B5_XA_AC_H 0x02b4 /* (ML) 32 bit Curr Addr Counter High dword */ - /* 0x02b8 - 0x02bc: reserved */ -#define B5_XS_D 0x02c0 /* 4*32 bit current transmit Descriptor (xs) */ -#define B5_XS_DA 0x02d0 /* 32 bit current tx desc address (xs) */ -#define B5_XS_AC 0x02d4 /* 32 bit current transmit Address Count(xs) */ -#define B5_XS_BC 0x02d8 /* 32 bit current transmit Byte Counter (xs) */ -#define B5_XS_CSR 0x02dc /* 32 bit BMU Control/Status Register (xs) */ -#define B5_XS_F 0x02e0 /* 32 bit flag register (xs) */ -#define B5_XS_T1 0x02e4 /* 32 bit Test Register 1 (xs) */ -#define B5_XS_T1_TR 0x02e4 /* 8 bit Test Register 1 TR (xs) */ -#define B5_XS_T1_WR 0x02e5 /* 8 bit Test Register 1 WR (xs) */ -#define B5_XS_T1_RD 0x02e6 /* 8 bit Test Register 1 RD (xs) */ -#define B5_XS_T1_SV 0x02e7 /* 8 bit Test Register 1 SV (xs) */ -#define B5_XS_T2 0x02e8 /* 32 bit Test Register 2 (xs) */ -#define B5_XS_T3 0x02ec /* 32 bit Test Register 3 (xs) */ -#define B5_XS_DA_H 0x02f0 /* (ML) 32 bit Curr Tx Desc Address High */ -#define B5_XS_AC_H 0x02f4 /* (ML) 32 bit Curr Addr Counter High dword */ - /* 0x02f8 - 0x02fc: reserved */ - -/* - * Bank 6 - */ -/* External PLC-S registers (SN2 compatibility for DV) */ -/* External registers (ML) */ -#define B6_EXT_REG 0x300 - -/* - * Bank 7 - */ -/* DAS PLC-S Registers */ - -/* - * Bank 8 - 15 - */ -/* IFCP registers */ - -/*---------------------------------------------------------------------------*/ -/* Definitions of the Bits in the registers */ - -/* B0_RAP 16 bit register address port */ -#define RAP_RAP 0x0f /* Bit 3..0: 0 = block0, .., f = block15 */ - -/* B0_CTRL 8 bit control register */ -#define CTRL_FDDI_CLR (1<<7) /* Bit 7: (ML) Clear FDDI Reset */ -#define CTRL_FDDI_SET (1<<6) /* Bit 6: (ML) Set FDDI Reset */ -#define CTRL_HPI_CLR (1<<5) /* Bit 5: Clear HPI SM reset */ -#define CTRL_HPI_SET (1<<4) /* Bit 4: Set HPI SM reset */ -#define CTRL_MRST_CLR (1<<3) /* Bit 3: Clear Master reset */ -#define CTRL_MRST_SET (1<<2) /* Bit 2: Set Master reset */ -#define CTRL_RST_CLR (1<<1) /* Bit 1: Clear Software reset */ -#define CTRL_RST_SET (1<<0) /* Bit 0: Set Software reset */ - -/* B0_DAS 8 Bit control register (DAS) */ -#define BUS_CLOCK (1<<7) /* Bit 7: (ML) Bus Clock 0/1 = 33/66MHz */ -#define BUS_SLOT_SZ (1<<6) /* Bit 6: (ML) Slot Size 0/1 = 32/64 bit slot*/ - /* Bit 5..4: reserved */ -#define DAS_AVAIL (1<<3) /* Bit 3: 1 = DAS, 0 = SAS */ -#define DAS_BYP_ST (1<<2) /* Bit 2: 1 = avail,SAS, 0 = not avail */ -#define DAS_BYP_INS (1<<1) /* Bit 1: 1 = insert Bypass */ -#define DAS_BYP_RMV (1<<0) /* Bit 0: 1 = remove Bypass */ - -/* B0_LED 8 Bit LED register */ - /* Bit 7..6: reserved */ -#define LED_2_ON (1<<5) /* Bit 5: 1 = switch LED_2 on (left,gn)*/ -#define LED_2_OFF (1<<4) /* Bit 4: 1 = switch LED_2 off */ -#define LED_1_ON (1<<3) /* Bit 3: 1 = switch LED_1 on (mid,yel)*/ -#define LED_1_OFF (1<<2) /* Bit 2: 1 = switch LED_1 off */ -#define LED_0_ON (1<<1) /* Bit 1: 1 = switch LED_0 on (rght,gn)*/ -#define LED_0_OFF (1<<0) /* Bit 0: 1 = switch LED_0 off */ -/* This hardware defines are very ugly therefore we define some others */ - -#define LED_GA_ON LED_2_ON /* S port = A port */ -#define LED_GA_OFF LED_2_OFF /* S port = A port */ -#define LED_MY_ON LED_1_ON -#define LED_MY_OFF LED_1_OFF -#define LED_GB_ON LED_0_ON -#define LED_GB_OFF LED_0_OFF - -/* B0_TST_CTRL 8 bit test control register */ -#define TST_FRC_DPERR_MR (1<<7) /* Bit 7: force DATAPERR on MST RE. */ -#define TST_FRC_DPERR_MW (1<<6) /* Bit 6: force DATAPERR on MST WR. */ -#define TST_FRC_DPERR_TR (1<<5) /* Bit 5: force DATAPERR on TRG RE. */ -#define TST_FRC_DPERR_TW (1<<4) /* Bit 4: force DATAPERR on TRG WR. */ -#define TST_FRC_APERR_M (1<<3) /* Bit 3: force ADDRPERR on MST */ -#define TST_FRC_APERR_T (1<<2) /* Bit 2: force ADDRPERR on TRG */ -#define TST_CFG_WRITE_ON (1<<1) /* Bit 1: ena configuration reg. WR */ -#define TST_CFG_WRITE_OFF (1<<0) /* Bit 0: dis configuration reg. WR */ - -/* B0_ISRC 32 bit Interrupt source register */ - /* Bit 31..28: reserved */ -#define IS_I2C_READY (1L<<27) /* Bit 27: (ML) IRQ on end of I2C tx */ -#define IS_IRQ_SW (1L<<26) /* Bit 26: (ML) SW forced IRQ */ -#define IS_EXT_REG (1L<<25) /* Bit 25: (ML) IRQ from external reg*/ -#define IS_IRQ_STAT (1L<<24) /* Bit 24: IRQ status exception */ - /* PERR, RMABORT, RTABORT DATAPERR */ -#define IS_IRQ_MST_ERR (1L<<23) /* Bit 23: IRQ master error */ - /* RMABORT, RTABORT, DATAPERR */ -#define IS_TIMINT (1L<<22) /* Bit 22: IRQ_TIMER */ -#define IS_TOKEN (1L<<21) /* Bit 21: IRQ_RTM */ -/* - * Note: The DAS is our First Port (!=PA) - */ -#define IS_PLINT1 (1L<<20) /* Bit 20: IRQ_PHY_DAS */ -#define IS_PLINT2 (1L<<19) /* Bit 19: IRQ_IFCP_4 */ -#define IS_MINTR3 (1L<<18) /* Bit 18: IRQ_IFCP_3/IRQ_PHY */ -#define IS_MINTR2 (1L<<17) /* Bit 17: IRQ_IFCP_2/IRQ_MAC_2 */ -#define IS_MINTR1 (1L<<16) /* Bit 16: IRQ_IFCP_1/IRQ_MAC_1 */ -/* Receive Queue 1 */ -#define IS_R1_P (1L<<15) /* Bit 15: Parity Error (q1) */ -#define IS_R1_B (1L<<14) /* Bit 14: End of Buffer (q1) */ -#define IS_R1_F (1L<<13) /* Bit 13: End of Frame (q1) */ -#define IS_R1_C (1L<<12) /* Bit 12: Encoding Error (q1) */ -/* Receive Queue 2 */ -#define IS_R2_P (1L<<11) /* Bit 11: (DV) Parity Error (q2) */ -#define IS_R2_B (1L<<10) /* Bit 10: (DV) End of Buffer (q2) */ -#define IS_R2_F (1L<<9) /* Bit 9: (DV) End of Frame (q2) */ -#define IS_R2_C (1L<<8) /* Bit 8: (DV) Encoding Error (q2) */ -/* Asynchronous Transmit queue */ - /* Bit 7: reserved */ -#define IS_XA_B (1L<<6) /* Bit 6: End of Buffer (xa) */ -#define IS_XA_F (1L<<5) /* Bit 5: End of Frame (xa) */ -#define IS_XA_C (1L<<4) /* Bit 4: Encoding Error (xa) */ -/* Synchronous Transmit queue */ - /* Bit 3: reserved */ -#define IS_XS_B (1L<<2) /* Bit 2: End of Buffer (xs) */ -#define IS_XS_F (1L<<1) /* Bit 1: End of Frame (xs) */ -#define IS_XS_C (1L<<0) /* Bit 0: Encoding Error (xs) */ - -/* - * Define all valid interrupt source Bits from GET_ISR () - */ -#define ALL_IRSR 0x01ffff77L /* (DV) */ -#define ALL_IRSR_ML 0x0ffff077L /* (ML) */ - - -/* B0_IMSK 32 bit Interrupt mask register */ -/* - * The Bit definnition of this register are the same as of the interrupt - * source register. These definition are directly derived from the Hardware - * spec. - */ - /* Bit 31..28: reserved */ -#define IRQ_I2C_READY (1L<<27) /* Bit 27: (ML) IRQ on end of I2C tx */ -#define IRQ_SW (1L<<26) /* Bit 26: (ML) SW forced IRQ */ -#define IRQ_EXT_REG (1L<<25) /* Bit 25: (ML) IRQ from external reg*/ -#define IRQ_STAT (1L<<24) /* Bit 24: IRQ status exception */ - /* PERR, RMABORT, RTABORT DATAPERR */ -#define IRQ_MST_ERR (1L<<23) /* Bit 23: IRQ master error */ - /* RMABORT, RTABORT, DATAPERR */ -#define IRQ_TIMER (1L<<22) /* Bit 22: IRQ_TIMER */ -#define IRQ_RTM (1L<<21) /* Bit 21: IRQ_RTM */ -#define IRQ_DAS (1L<<20) /* Bit 20: IRQ_PHY_DAS */ -#define IRQ_IFCP_4 (1L<<19) /* Bit 19: IRQ_IFCP_4 */ -#define IRQ_IFCP_3 (1L<<18) /* Bit 18: IRQ_IFCP_3/IRQ_PHY */ -#define IRQ_IFCP_2 (1L<<17) /* Bit 17: IRQ_IFCP_2/IRQ_MAC_2 */ -#define IRQ_IFCP_1 (1L<<16) /* Bit 16: IRQ_IFCP_1/IRQ_MAC_1 */ -/* Receive Queue 1 */ -#define IRQ_R1_P (1L<<15) /* Bit 15: Parity Error (q1) */ -#define IRQ_R1_B (1L<<14) /* Bit 14: End of Buffer (q1) */ -#define IRQ_R1_F (1L<<13) /* Bit 13: End of Frame (q1) */ -#define IRQ_R1_C (1L<<12) /* Bit 12: Encoding Error (q1) */ -/* Receive Queue 2 */ -#define IRQ_R2_P (1L<<11) /* Bit 11: (DV) Parity Error (q2) */ -#define IRQ_R2_B (1L<<10) /* Bit 10: (DV) End of Buffer (q2) */ -#define IRQ_R2_F (1L<<9) /* Bit 9: (DV) End of Frame (q2) */ -#define IRQ_R2_C (1L<<8) /* Bit 8: (DV) Encoding Error (q2) */ -/* Asynchronous Transmit queue */ - /* Bit 7: reserved */ -#define IRQ_XA_B (1L<<6) /* Bit 6: End of Buffer (xa) */ -#define IRQ_XA_F (1L<<5) /* Bit 5: End of Frame (xa) */ -#define IRQ_XA_C (1L<<4) /* Bit 4: Encoding Error (xa) */ -/* Synchronous Transmit queue */ - /* Bit 3: reserved */ -#define IRQ_XS_B (1L<<2) /* Bit 2: End of Buffer (xs) */ -#define IRQ_XS_F (1L<<1) /* Bit 1: End of Frame (xs) */ -#define IRQ_XS_C (1L<<0) /* Bit 0: Encoding Error (xs) */ - -/* 0x0010 - 0x006b: formac+ (supernet_3) fequently used registers */ -/* B0_R1_CSR 32 bit BMU control/status reg (rec q 1 ) */ -/* B0_R2_CSR 32 bit BMU control/status reg (rec q 2 ) */ -/* B0_XA_CSR 32 bit BMU control/status reg (a xmit q ) */ -/* B0_XS_CSR 32 bit BMU control/status reg (s xmit q ) */ -/* The registers are the same as B4_R1_CSR, B4_R2_CSR, B5_Xa_CSR, B5_XS_CSR */ - -/* B2_MAC_0 8 bit MAC address Byte 0 */ -/* B2_MAC_1 8 bit MAC address Byte 1 */ -/* B2_MAC_2 8 bit MAC address Byte 2 */ -/* B2_MAC_3 8 bit MAC address Byte 3 */ -/* B2_MAC_4 8 bit MAC address Byte 4 */ -/* B2_MAC_5 8 bit MAC address Byte 5 */ -/* B2_MAC_6 8 bit MAC address Byte 6 (== 0) (DV) */ -/* B2_MAC_7 8 bit MAC address Byte 7 (== 0) (DV) */ - -/* B2_CONN_TYP 8 bit Connector type */ -/* B2_PMD_TYP 8 bit PMD type */ -/* Values of connector and PMD type comply to SysKonnect internal std */ - -/* The EPROM register are currently of no use */ -/* B2_E_0 8 bit EPROM Byte 0 */ -/* B2_E_1 8 bit EPROM Byte 1 */ -/* B2_E_2 8 bit EPROM Byte 2 */ -/* B2_E_3 8 bit EPROM Byte 3 */ - -/* B2_FAR 32 bit Flash-Prom Address Register/Counter */ -#define FAR_ADDR 0x1ffffL /* Bit 16..0: FPROM Address mask */ - -/* B2_FDP 8 bit Flash-Prom Data Port */ - -/* B2_LD_CRTL 8 bit loader control */ -/* Bits are currently reserved */ - -/* B2_LD_TEST 8 bit loader test */ -#define LD_T_ON (1<<3) /* Bit 3: Loader Testmode on */ -#define LD_T_OFF (1<<2) /* Bit 2: Loader Testmode off */ -#define LD_T_STEP (1<<1) /* Bit 1: Decrement FPROM addr. Counter */ -#define LD_START (1<<0) /* Bit 0: Start loading FPROM */ - -/* B2_TI_INI 32 bit Timer init value */ -/* B2_TI_VAL 32 bit Timer value */ -/* B2_TI_CRTL 8 bit Timer control */ -/* B2_TI_TEST 8 Bit Timer Test */ -/* B2_WDOG_INI 32 bit Watchdog init value */ -/* B2_WDOG_VAL 32 bit Watchdog value */ -/* B2_WDOG_CRTL 8 bit Watchdog control */ -/* B2_WDOG_TEST 8 Bit Watchdog Test */ -/* B2_RTM_INI 32 bit RTM init value */ -/* B2_RTM_VAL 32 bit RTM value */ -/* B2_RTM_CRTL 8 bit RTM control */ -/* B2_RTM_TEST 8 Bit RTM Test */ -/* B2__CRTL 8 bit control */ -/* B2_IRQ_MOD_INI 32 bit IRQ Moderation Timer Init Reg. (ML) */ -/* B2_IRQ_MOD_VAL 32 bit IRQ Moderation Timer Value (ML) */ -/* B2_IRQ_MOD_CTRL 8 bit IRQ Moderation Timer Control (ML) */ -/* B2_IRQ_MOD_TEST 8 bit IRQ Moderation Timer Test (ML) */ -#define GET_TOK_CT (1<<4) /* Bit 4: Get the Token Counter (RTM) */ -#define TIM_RES_TOK (1<<3) /* Bit 3: RTM Status: 1 == restricted */ -#define TIM_ALARM (1<<3) /* Bit 3: Timer Alarm (WDOG) */ -#define TIM_START (1<<2) /* Bit 2: Start Timer (TI,WDOG,RTM,IRQ_MOD)*/ -#define TIM_STOP (1<<1) /* Bit 1: Stop Timer (TI,WDOG,RTM,IRQ_MOD) */ -#define TIM_CL_IRQ (1<<0) /* Bit 0: Clear Timer IRQ (TI,WDOG,RTM) */ -/* B2__TEST 8 Bit Test */ -#define TIM_T_ON (1<<2) /* Bit 2: Test mode on (TI,WDOG,RTM,IRQ_MOD) */ -#define TIM_T_OFF (1<<1) /* Bit 1: Test mode off (TI,WDOG,RTM,IRQ_MOD) */ -#define TIM_T_STEP (1<<0) /* Bit 0: Test step (TI,WDOG,RTM,IRQ_MOD) */ - -/* B2_TOK_COUNT 0x014c (ML) 32 bit Token Counter */ -/* B2_DESC_ADDR_H 0x0150 (ML) 32 bit Desciptor Base Addr Reg High */ -/* B2_CTRL_2 0x0154 (ML) 8 bit Control Register 2 */ - /* Bit 7..5: reserved */ -#define CTRL_CL_I2C_IRQ (1<<4) /* Bit 4: Clear I2C IRQ */ -#define CTRL_ST_SW_IRQ (1<<3) /* Bit 3: Set IRQ SW Request */ -#define CTRL_CL_SW_IRQ (1<<2) /* Bit 2: Clear IRQ SW Request */ -#define CTRL_STOP_DONE (1<<1) /* Bit 1: Stop Master is finished */ -#define CTRL_STOP_MAST (1<<0) /* Bit 0: Command Bit to stop the master*/ - -/* B2_IFACE_REG 0x0155 (ML) 8 bit Interface Register */ - /* Bit 7..3: reserved */ -#define IF_I2C_DATA_DIR (1<<2) /* Bit 2: direction of IF_I2C_DATA*/ -#define IF_I2C_DATA (1<<1) /* Bit 1: I2C Data Port */ -#define IF_I2C_CLK (1<<0) /* Bit 0: I2C Clock Port */ - - /* 0x0156: reserved */ -/* B2_TST_CTRL_2 0x0157 (ML) 8 bit Test Control Register 2 */ - /* Bit 7..4: reserved */ - /* force the following error on */ - /* the next master read/write */ -#define TST_FRC_DPERR_MR64 (1<<3) /* Bit 3: DataPERR RD 64 */ -#define TST_FRC_DPERR_MW64 (1<<2) /* Bit 2: DataPERR WR 64 */ -#define TST_FRC_APERR_1M64 (1<<1) /* Bit 1: AddrPERR on 1. phase */ -#define TST_FRC_APERR_2M64 (1<<0) /* Bit 0: AddrPERR on 2. phase */ - -/* B2_I2C_CTRL 0x0158 (ML) 32 bit I2C Control Register */ -#define I2C_FLAG (1L<<31) /* Bit 31: Start read/write if WR */ -#define I2C_ADDR (0x7fffL<<16) /* Bit 30..16: Addr to be read/written*/ -#define I2C_DEV_SEL (0x7fL<<9) /* Bit 9..15: I2C Device Select */ - /* Bit 5.. 8: reserved */ -#define I2C_BURST_LEN (1L<<4) /* Bit 4 Burst Len, 1/4 bytes */ -#define I2C_DEV_SIZE (7L<<1) /* Bit 1.. 3: I2C Device Size */ -#define I2C_025K_DEV (0L<<1) /* 0: 256 Bytes or smaller*/ -#define I2C_05K_DEV (1L<<1) /* 1: 512 Bytes */ -#define I2C_1K_DEV (2L<<1) /* 2: 1024 Bytes */ -#define I2C_2K_DEV (3L<<1) /* 3: 2048 Bytes */ -#define I2C_4K_DEV (4L<<1) /* 4: 4096 Bytes */ -#define I2C_8K_DEV (5L<<1) /* 5: 8192 Bytes */ -#define I2C_16K_DEV (6L<<1) /* 6: 16384 Bytes */ -#define I2C_32K_DEV (7L<<1) /* 7: 32768 Bytes */ -#define I2C_STOP_BIT (1<<0) /* Bit 0: Interrupt I2C transfer */ - -/* - * I2C Addresses - * - * The temperature sensor and the voltage sensor are on the same I2C bus. - * Note: The voltage sensor (Micorwire) will be selected by PCI_EXT_PATCH_1 - * in PCI_OUR_REG 1. - */ -#define I2C_ADDR_TEMP 0x90 /* I2C Address Temperature Sensor */ - -/* B2_I2C_DATA 0x015c (ML) 32 bit I2C Data Register */ - -/* B4_R1_D 4*32 bit current receive Descriptor (q1) */ -/* B4_R1_DA 32 bit current rec desc address (q1) */ -/* B4_R1_AC 32 bit current receive Address Count (q1) */ -/* B4_R1_BC 32 bit current receive Byte Counter (q1) */ -/* B4_R1_CSR 32 bit BMU Control/Status Register (q1) */ -/* B4_R1_F 32 bit flag register (q1) */ -/* B4_R1_T1 32 bit Test Register 1 (q1) */ -/* B4_R1_T2 32 bit Test Register 2 (q1) */ -/* B4_R1_T3 32 bit Test Register 3 (q1) */ -/* B4_R2_D 4*32 bit current receive Descriptor (q2) */ -/* B4_R2_DA 32 bit current rec desc address (q2) */ -/* B4_R2_AC 32 bit current receive Address Count (q2) */ -/* B4_R2_BC 32 bit current receive Byte Counter (q2) */ -/* B4_R2_CSR 32 bit BMU Control/Status Register (q2) */ -/* B4_R2_F 32 bit flag register (q2) */ -/* B4_R2_T1 32 bit Test Register 1 (q2) */ -/* B4_R2_T2 32 bit Test Register 2 (q2) */ -/* B4_R2_T3 32 bit Test Register 3 (q2) */ -/* B5_XA_D 4*32 bit current receive Descriptor (xa) */ -/* B5_XA_DA 32 bit current rec desc address (xa) */ -/* B5_XA_AC 32 bit current receive Address Count (xa) */ -/* B5_XA_BC 32 bit current receive Byte Counter (xa) */ -/* B5_XA_CSR 32 bit BMU Control/Status Register (xa) */ -/* B5_XA_F 32 bit flag register (xa) */ -/* B5_XA_T1 32 bit Test Register 1 (xa) */ -/* B5_XA_T2 32 bit Test Register 2 (xa) */ -/* B5_XA_T3 32 bit Test Register 3 (xa) */ -/* B5_XS_D 4*32 bit current receive Descriptor (xs) */ -/* B5_XS_DA 32 bit current rec desc address (xs) */ -/* B5_XS_AC 32 bit current receive Address Count (xs) */ -/* B5_XS_BC 32 bit current receive Byte Counter (xs) */ -/* B5_XS_CSR 32 bit BMU Control/Status Register (xs) */ -/* B5_XS_F 32 bit flag register (xs) */ -/* B5_XS_T1 32 bit Test Register 1 (xs) */ -/* B5_XS_T2 32 bit Test Register 2 (xs) */ -/* B5_XS_T3 32 bit Test Register 3 (xs) */ -/* B5__CSR 32 bit BMU Control/Status Register (xx) */ -#define CSR_DESC_CLEAR (1L<<21) /* Bit 21: Clear Reset for Descr */ -#define CSR_DESC_SET (1L<<20) /* Bit 20: Set Reset for Descr */ -#define CSR_FIFO_CLEAR (1L<<19) /* Bit 19: Clear Reset for FIFO */ -#define CSR_FIFO_SET (1L<<18) /* Bit 18: Set Reset for FIFO */ -#define CSR_HPI_RUN (1L<<17) /* Bit 17: Release HPI SM */ -#define CSR_HPI_RST (1L<<16) /* Bit 16: Reset HPI SM to Idle */ -#define CSR_SV_RUN (1L<<15) /* Bit 15: Release Supervisor SM */ -#define CSR_SV_RST (1L<<14) /* Bit 14: Reset Supervisor SM */ -#define CSR_DREAD_RUN (1L<<13) /* Bit 13: Release Descr Read SM */ -#define CSR_DREAD_RST (1L<<12) /* Bit 12: Reset Descr Read SM */ -#define CSR_DWRITE_RUN (1L<<11) /* Bit 11: Rel. Descr Write SM */ -#define CSR_DWRITE_RST (1L<<10) /* Bit 10: Reset Descr Write SM */ -#define CSR_TRANS_RUN (1L<<9) /* Bit 9: Release Transfer SM */ -#define CSR_TRANS_RST (1L<<8) /* Bit 8: Reset Transfer SM */ - /* Bit 7..5: reserved */ -#define CSR_START (1L<<4) /* Bit 4: Start Rec/Xmit Queue */ -#define CSR_IRQ_CL_P (1L<<3) /* Bit 3: Clear Parity IRQ, Rcv */ -#define CSR_IRQ_CL_B (1L<<2) /* Bit 2: Clear EOB IRQ */ -#define CSR_IRQ_CL_F (1L<<1) /* Bit 1: Clear EOF IRQ */ -#define CSR_IRQ_CL_C (1L<<0) /* Bit 0: Clear ERR IRQ */ - -#define CSR_SET_RESET (CSR_DESC_SET|CSR_FIFO_SET|CSR_HPI_RST|CSR_SV_RST|\ - CSR_DREAD_RST|CSR_DWRITE_RST|CSR_TRANS_RST) -#define CSR_CLR_RESET (CSR_DESC_CLEAR|CSR_FIFO_CLEAR|CSR_HPI_RUN|CSR_SV_RUN|\ - CSR_DREAD_RUN|CSR_DWRITE_RUN|CSR_TRANS_RUN) - - -/* B5__F 32 bit flag register (xx) */ - /* Bit 28..31: reserved */ -#define F_ALM_FULL (1L<<27) /* Bit 27: (ML) FIFO almost full */ -#define F_FIFO_EOF (1L<<26) /* Bit 26: (ML) Fag bit in FIFO */ -#define F_WM_REACHED (1L<<25) /* Bit 25: (ML) Watermark reached */ -#define F_UP_DW_USED (1L<<24) /* Bit 24: (ML) Upper Dword used (bug)*/ - /* Bit 23: reserved */ -#define F_FIFO_LEVEL (0x1fL<<16) /* Bit 16..22:(ML) # of Qwords in FIFO*/ - /* Bit 8..15: reserved */ -#define F_ML_WATER_M 0x0000ffL /* Bit 0.. 7:(ML) Watermark */ -#define FLAG_WATER 0x00001fL /* Bit 4..0:(DV) Level of req data tr.*/ - -/* B5__T1 32 bit Test Register 1 (xx) */ -/* Holds four State Machine control Bytes */ -#define SM_CRTL_SV (0xffL<<24) /* Bit 31..24: Control Supervisor SM */ -#define SM_CRTL_RD (0xffL<<16) /* Bit 23..16: Control Read Desc SM */ -#define SM_CRTL_WR (0xffL<<8) /* Bit 15..8: Control Write Desc SM */ -#define SM_CRTL_TR (0xffL<<0) /* Bit 7..0: Control Transfer SM */ - -/* B4__T1_TR 8 bit Test Register 1 TR (xx) */ -/* B4__T1_WR 8 bit Test Register 1 WR (xx) */ -/* B4__T1_RD 8 bit Test Register 1 RD (xx) */ -/* B4__T1_SV 8 bit Test Register 1 SV (xx) */ -/* The control status byte of each machine looks like ... */ -#define SM_STATE 0xf0 /* Bit 7..4: State which shall be loaded */ -#define SM_LOAD 0x08 /* Bit 3: Load the SM with SM_STATE */ -#define SM_TEST_ON 0x04 /* Bit 2: Switch on SM Test Mode */ -#define SM_TEST_OFF 0x02 /* Bit 1: Go off the Test Mode */ -#define SM_STEP 0x01 /* Bit 0: Step the State Machine */ - -/* The coding of the states */ -#define SM_SV_IDLE 0x0 /* Supervisor Idle Tr/Re */ -#define SM_SV_RES_START 0x1 /* Supervisor Res_Start Tr/Re */ -#define SM_SV_GET_DESC 0x3 /* Supervisor Get_Desc Tr/Re */ -#define SM_SV_CHECK 0x2 /* Supervisor Check Tr/Re */ -#define SM_SV_MOV_DATA 0x6 /* Supervisor Move_Data Tr/Re */ -#define SM_SV_PUT_DESC 0x7 /* Supervisor Put_Desc Tr/Re */ -#define SM_SV_SET_IRQ 0x5 /* Supervisor Set_Irq Tr/Re */ - -#define SM_RD_IDLE 0x0 /* Read Desc. Idle Tr/Re */ -#define SM_RD_LOAD 0x1 /* Read Desc. Load Tr/Re */ -#define SM_RD_WAIT_TC 0x3 /* Read Desc. Wait_TC Tr/Re */ -#define SM_RD_RST_EOF 0x6 /* Read Desc. Reset_EOF Re */ -#define SM_RD_WDONE_R 0x2 /* Read Desc. Wait_Done Re */ -#define SM_RD_WDONE_T 0x4 /* Read Desc. Wait_Done Tr */ - -#define SM_TR_IDLE 0x0 /* Trans. Data Idle Tr/Re */ -#define SM_TR_LOAD 0x3 /* Trans. Data Load Tr/Re */ -#define SM_TR_LOAD_R_ML 0x1 /* Trans. Data Load /Re (ML) */ -#define SM_TR_WAIT_TC 0x2 /* Trans. Data Wait_TC Tr/Re */ -#define SM_TR_WDONE 0x4 /* Trans. Data Wait_Done Tr/Re */ - -#define SM_WR_IDLE 0x0 /* Write Desc. Idle Tr/Re */ -#define SM_WR_ABLEN 0x1 /* Write Desc. Act_Buf_Length Tr/Re */ -#define SM_WR_LD_A4 0x2 /* Write Desc. Load_A4 Re */ -#define SM_WR_RES_OWN 0x2 /* Write Desc. Res_OWN Tr */ -#define SM_WR_WAIT_EOF 0x3 /* Write Desc. Wait_EOF Re */ -#define SM_WR_LD_N2C_R 0x4 /* Write Desc. Load_N2C Re */ -#define SM_WR_WAIT_TC_R 0x5 /* Write Desc. Wait_TC Re */ -#define SM_WR_WAIT_TC4 0x6 /* Write Desc. Wait_TC4 Re */ -#define SM_WR_LD_A_T 0x6 /* Write Desc. Load_A Tr */ -#define SM_WR_LD_A_R 0x7 /* Write Desc. Load_A Re */ -#define SM_WR_WAIT_TC_T 0x7 /* Write Desc. Wait_TC Tr */ -#define SM_WR_LD_N2C_T 0xc /* Write Desc. Load_N2C Tr */ -#define SM_WR_WDONE_T 0x9 /* Write Desc. Wait_Done Tr */ -#define SM_WR_WDONE_R 0xc /* Write Desc. Wait_Done Re */ -#define SM_WR_LD_D_AD 0xe /* Write Desc. Load_Dumr_A Re (ML) */ -#define SM_WR_WAIT_D_TC 0xf /* Write Desc. Wait_Dumr_TC Re (ML) */ - -/* B5__T2 32 bit Test Register 2 (xx) */ -/* Note: This register is only defined for the transmit queues */ - /* Bit 31..8: reserved */ -#define AC_TEST_ON (1<<7) /* Bit 7: Address Counter Test Mode on */ -#define AC_TEST_OFF (1<<6) /* Bit 6: Address Counter Test Mode off*/ -#define BC_TEST_ON (1<<5) /* Bit 5: Byte Counter Test Mode on */ -#define BC_TEST_OFF (1<<4) /* Bit 4: Byte Counter Test Mode off */ -#define TEST_STEP04 (1<<3) /* Bit 3: Inc AC/Dec BC by 4 */ -#define TEST_STEP03 (1<<2) /* Bit 2: Inc AC/Dec BC by 3 */ -#define TEST_STEP02 (1<<1) /* Bit 1: Inc AC/Dec BC by 2 */ -#define TEST_STEP01 (1<<0) /* Bit 0: Inc AC/Dec BC by 1 */ - -/* B5__T3 32 bit Test Register 3 (xx) */ -/* Note: This register is only defined for the transmit queues */ - /* Bit 31..8: reserved */ -#define T3_MUX_2 (1<<7) /* Bit 7: (ML) Mux position MSB */ -#define T3_VRAM_2 (1<<6) /* Bit 6: (ML) Virtual RAM buffer addr MSB */ -#define T3_LOOP (1<<5) /* Bit 5: Set Loopback (Xmit) */ -#define T3_UNLOOP (1<<4) /* Bit 4: Unset Loopback (Xmit) */ -#define T3_MUX (3<<2) /* Bit 3..2: Mux position */ -#define T3_VRAM (3<<0) /* Bit 1..0: Virtual RAM buffer Address */ - -/* PCI card IDs */ -/* - * Note: The following 4 byte definitions shall not be used! Use OEM Concept! - */ -#define PCI_VEND_ID0 0x48 /* PCI vendor ID (SysKonnect) */ -#define PCI_VEND_ID1 0x11 /* PCI vendor ID (SysKonnect) */ - /* (High byte) */ -#define PCI_DEV_ID0 0x00 /* PCI device ID */ -#define PCI_DEV_ID1 0x40 /* PCI device ID (High byte) */ - -/*#define PCI_CLASS 0x02*/ /* PCI class code: network device */ -#define PCI_NW_CLASS 0x02 /* PCI class code: network device */ -#define PCI_SUB_CLASS 0x02 /* PCI subclass ID: FDDI device */ -#define PCI_PROG_INTFC 0x00 /* PCI programming Interface (=0) */ - -/* - * address transmission from logical to physical offset address on board - */ -#define FMA(a) (0x0400|((a)<<2)) /* FORMAC+ (r/w) (SN3) */ -#define P1(a) (0x0380|((a)<<2)) /* PLC1 (r/w) (DAS) */ -#define P2(a) (0x0600|((a)<<2)) /* PLC2 (r/w) (covered by the SN3) */ -#define PRA(a) (B2_MAC_0 + (a)) /* configuration PROM (MAC address) */ - -/* - * FlashProm specification - */ -#define MAX_PAGES 0x20000L /* Every byte has a single page */ -#define MAX_FADDR 1 /* 1 byte per page */ - -/* - * Receive / Transmit Buffer Control word - */ -#define BMU_OWN (1UL<<31) /* OWN bit: 0 == host, 1 == adapter */ -#define BMU_STF (1L<<30) /* Start of Frame ? */ -#define BMU_EOF (1L<<29) /* End of Frame ? */ -#define BMU_EN_IRQ_EOB (1L<<28) /* Enable "End of Buffer" IRQ */ -#define BMU_EN_IRQ_EOF (1L<<27) /* Enable "End of Frame" IRQ */ -#define BMU_DEV_0 (1L<<26) /* RX: don't transfer to system mem */ -#define BMU_SMT_TX (1L<<25) /* TX: if set, buffer type SMT_MBuf */ -#define BMU_ST_BUF (1L<<25) /* RX: copy of start of frame */ -#define BMU_UNUSED (1L<<24) /* Set if the Descr is curr unused */ -#define BMU_SW (3L<<24) /* 2 Bits reserved for SW usage */ -#define BMU_CHECK 0x00550000L /* To identify the control word */ -#define BMU_BBC 0x0000FFFFL /* R/T Buffer Byte Count */ - -/* - * physical address offset + IO-Port base address - */ -#ifdef MEM_MAPPED_IO -#define ADDR(a) (char far *) smc->hw.iop+(a) -#define ADDRS(smc,a) (char far *) (smc)->hw.iop+(a) -#else -#define ADDR(a) (((a)>>7) ? (outp(smc->hw.iop+B0_RAP,(a)>>7), \ - (smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) : \ - (smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) -#define ADDRS(smc,a) (((a)>>7) ? (outp((smc)->hw.iop+B0_RAP,(a)>>7), \ - ((smc)->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) : \ - ((smc)->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) -#endif - -/* - * Define a macro to access the configuration space - */ -#define PCI_C(a) ADDR(B3_CFG_SPC + (a)) /* PCI Config Space */ - -#define EXT_R(a) ADDR(B6_EXT_REG + (a)) /* External Registers */ - -/* - * Define some values needed for the MAC address (PROM) - */ -#define SA_MAC (0) /* start addr. MAC_AD within the PROM */ -#define PRA_OFF (0) /* offset correction when 4th byte reading */ - -#define SKFDDI_PSZ 8 /* address PROM size */ - -#define FM_A(a) ADDR(FMA(a)) /* FORMAC Plus physical addr */ -#define P1_A(a) ADDR(P1(a)) /* PLC1 (r/w) */ -#define P2_A(a) ADDR(P2(a)) /* PLC2 (r/w) (DAS) */ -#define PR_A(a) ADDR(PRA(a)) /* config. PROM (MAC address) */ - -/* - * Macro to read the PROM - */ -#define READ_PROM(a) ((u_char)inp(a)) - -#define GET_PAGE(bank) outpd(ADDR(B2_FAR),bank) -#define VPP_ON() -#define VPP_OFF() - -/* - * Note: Values of the Interrupt Source Register are defined above - */ -#define ISR_A ADDR(B0_ISRC) -#define GET_ISR() inpd(ISR_A) -#define GET_ISR_SMP(iop) inpd((iop)+B0_ISRC) -#define CHECK_ISR() (inpd(ISR_A) & inpd(ADDR(B0_IMSK))) -#define CHECK_ISR_SMP(iop) (inpd((iop)+B0_ISRC) & inpd((iop)+B0_IMSK)) - -#define BUS_CHECK() - -/* - * CLI_FBI: Disable Board Interrupts - * STI_FBI: Enable Board Interrupts - */ -#ifndef UNIX -#define CLI_FBI() outpd(ADDR(B0_IMSK),0) -#else -#define CLI_FBI(smc) outpd(ADDRS((smc),B0_IMSK),0) -#endif - -#ifndef UNIX -#define STI_FBI() outpd(ADDR(B0_IMSK),smc->hw.is_imask) -#else -#define STI_FBI(smc) outpd(ADDRS((smc),B0_IMSK),(smc)->hw.is_imask) -#endif - -#define CLI_FBI_SMP(iop) outpd((iop)+B0_IMSK,0) -#define STI_FBI_SMP(smc,iop) outpd((iop)+B0_IMSK,(smc)->hw.is_imask) - -#endif /* PCI */ -/*--------------------------------------------------------------------------*/ - -/* - * 12 bit transfer (dword) counter: - * (ISA: 2*trc = number of byte) - * (EISA: 4*trc = number of byte) - * (MCA: 4*trc = number of byte) - */ -#define MAX_TRANS (0x0fff) - -/* - * PC PIC - */ -#define MST_8259 (0x20) -#define SLV_8259 (0xA0) - -#define TPS (18) /* ticks per second */ - -/* - * error timer defs - */ -#define TN (4) /* number of supported timer = TN+1 */ -#define SNPPND_TIME (5) /* buffer memory access over mem. data reg. */ - -#define MAC_AD 0x405a0000 - -#define MODR1 FM_A(FM_MDREG1) /* mode register 1 */ -#define MODR2 FM_A(FM_MDREG2) /* mode register 2 */ - -#define CMDR1 FM_A(FM_CMDREG1) /* command register 1 */ -#define CMDR2 FM_A(FM_CMDREG2) /* command register 2 */ - - -/* - * function defines - */ -#define CLEAR(io,mask) outpw((io),inpw(io)&(~(mask))) -#define SET(io,mask) outpw((io),inpw(io)|(mask)) -#define GET(io,mask) (inpw(io)&(mask)) -#define SETMASK(io,val,mask) outpw((io),(inpw(io) & ~(mask)) | (val)) - -/* - * PHY Port A (PA) = PLC 1 - * With SuperNet 3 PHY-A and PHY S are identical. - */ -#define PLC(np,reg) (((np) == PA) ? P2_A(reg) : P1_A(reg)) - -/* - * set memory address register for write and read - */ -#define MARW(ma) outpw(FM_A(FM_MARW),(unsigned int)(ma)) -#define MARR(ma) outpw(FM_A(FM_MARR),(unsigned int)(ma)) - -/* - * read/write from/to memory data register - */ -/* write double word */ -#define MDRW(dd) outpw(FM_A(FM_MDRU),(unsigned int)((dd)>>16)) ;\ - outpw(FM_A(FM_MDRL),(unsigned int)(dd)) - -#ifndef WINNT -/* read double word */ -#define MDRR() (((long)inpw(FM_A(FM_MDRU))<<16) + inpw(FM_A(FM_MDRL))) - -/* read FORMAC+ 32-bit status register */ -#define GET_ST1() (((long)inpw(FM_A(FM_ST1U))<<16) + inpw(FM_A(FM_ST1L))) -#define GET_ST2() (((long)inpw(FM_A(FM_ST2U))<<16) + inpw(FM_A(FM_ST2L))) -#ifdef SUPERNET_3 -#define GET_ST3() (((long)inpw(FM_A(FM_ST3U))<<16) + inpw(FM_A(FM_ST3L))) -#endif -#else -/* read double word */ -#define MDRR() inp2w((FM_A(FM_MDRU)),(FM_A(FM_MDRL))) - -/* read FORMAC+ 32-bit status register */ -#define GET_ST1() inp2w((FM_A(FM_ST1U)),(FM_A(FM_ST1L))) -#define GET_ST2() inp2w((FM_A(FM_ST2U)),(FM_A(FM_ST2L))) -#ifdef SUPERNET_3 -#define GET_ST3() inp2w((FM_A(FM_ST3U)),(FM_A(FM_ST3L))) -#endif -#endif - -/* Special timer macro for 82c54 */ - /* timer access over data bus bit 8..15 */ -#define OUT_82c54_TIMER(port,val) outpw(TI_A(port),(val)<<8) -#define IN_82c54_TIMER(port) ((inpw(TI_A(port))>>8) & 0xff) - - -#ifdef DEBUG -#define DB_MAC(mac,st) {if (debug_mac & 0x1)\ - printf("M") ;\ - if (debug_mac & 0x2)\ - printf("\tMAC %d status 0x%08lx\n",mac,st) ;\ - if (debug_mac & 0x4)\ - dp_mac(mac,st) ;\ -} - -#define DB_PLC(p,iev) { if (debug_plc & 0x1)\ - printf("P") ;\ - if (debug_plc & 0x2)\ - printf("\tPLC %s Int 0x%04x\n", \ - (p == PA) ? "A" : "B", iev) ;\ - if (debug_plc & 0x4)\ - dp_plc(p,iev) ;\ -} - -#define DB_TIMER() { if (debug_timer & 0x1)\ - printf("T") ;\ - if (debug_timer & 0x2)\ - printf("\tTimer ISR\n") ;\ -} - -#else /* no DEBUG */ - -#define DB_MAC(mac,st) -#define DB_PLC(p,iev) -#define DB_TIMER() - -#endif /* no DEBUG */ - -#define INC_PTR(sp,cp,ep) if (++cp == ep) cp = sp -/* - * timer defs - */ -#define COUNT(t) ((t)<<6) /* counter */ -#define RW_OP(o) ((o)<<4) /* read/write operation */ -#define TMODE(m) ((m)<<1) /* timer mode */ - -#endif diff --git a/drivers/net/skfp/h/skfbiinc.h b/drivers/net/skfp/h/skfbiinc.h deleted file mode 100644 index ac2d719..0000000 --- a/drivers/net/skfp/h/skfbiinc.h +++ /dev/null @@ -1,97 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -#ifndef _SKFBIINC_ -#define _SKFBIINC_ - -#include "h/supern_2.h" - -/* - * special defines for use into .asm files - */ -#define ERR_FLAGS (FS_MSRABT | FS_SEAC2 | FS_SFRMERR | FS_SFRMTY1) - -#ifdef PCI -#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \ - IS_MINTR2 | IS_MINTR3 | IS_R1_P | \ - IS_R1_C | IS_XA_C | IS_XS_C) -#endif - -#ifdef PCI -#define ISR_MASK (IS_MINTR1 | IS_R1_F | IS_XS_F| IS_XA_F | IMASK_FAST) -#else -#define ISR_MASK (IS_MINTR1 | IS_MINTR2 | IMASK_FAST) -#endif - -#define FMA_FM_CMDREG1 FMA(FM_CMDREG1) -#define FMA_FM_CMDREG2 FMA(FM_CMDREG2) -#define FMA_FM_STMCHN FMA(FM_STMCHN) -#define FMA_FM_RPR FMA(FM_RPR) -#define FMA_FM_WPXA0 FMA(FM_WPXA0) -#define FMA_FM_WPXA2 FMA(FM_WPXA2) -#define FMA_FM_MARR FMA(FM_MARR) -#define FMA_FM_MARW FMA(FM_MARW) -#define FMA_FM_MDRU FMA(FM_MDRU) -#define FMA_FM_MDRL FMA(FM_MDRL) -#define FMA_ST1L FMA(FM_ST1L) -#define FMA_ST1U FMA(FM_ST1U) -#define FMA_ST2L FMA(FM_ST2L) -#define FMA_ST2U FMA(FM_ST2U) -#ifdef SUPERNET_3 -#define FMA_ST3L FMA(FM_ST3L) -#define FMA_ST3U FMA(FM_ST3U) -#endif - -#define TMODE_RRQ RQ_RRQ -#define TMODE_WAQ2 RQ_WA2 -#define HSRA HSR(0) - - -#define FMA_FM_ST1L FMA_ST1L -#define FMA_FM_ST1U FMA_ST1U -#define FMA_FM_ST2L FMA_ST2L -#define FMA_FM_ST2U FMA_ST2U -#ifdef SUPERNET_3 -#define FMA_FM_ST3L FMA_ST3L -#define FMA_FM_ST3U FMA_ST3U -#endif - -#define FMA_FM_SWPR FMA(FM_SWPR) - -#define FMA_FM_RPXA0 FMA(FM_RPXA0) - -#define FMA_FM_RPXS FMA(FM_RPXS) -#define FMA_FM_WPXS FMA(FM_WPXS) - -#define FMA_FM_IMSK1U FMA(FM_IMSK1U) -#define FMA_FM_IMSK1L FMA(FM_IMSK1L) - -#define FMA_FM_EAS FMA(FM_EAS) -#define FMA_FM_EAA0 FMA(FM_EAA0) - -#define TMODE_WAQ0 RQ_WA0 -#define TMODE_WSQ RQ_WSQ - -/* Define default for DRV_PCM_STATE_CHANGE */ -#ifndef DRV_PCM_STATE_CHANGE -#define DRV_PCM_STATE_CHANGE(smc,plc,p_state) /* nothing */ -#endif - -/* Define default for DRV_RMT_INDICATION */ -#ifndef DRV_RMT_INDICATION -#define DRV_RMT_INDICATION(smc,i) /* nothing */ -#endif - -#endif /* n_SKFBIINC_ */ - diff --git a/drivers/net/skfp/h/smc.h b/drivers/net/skfp/h/smc.h deleted file mode 100644 index c774a95..0000000 --- a/drivers/net/skfp/h/smc.h +++ /dev/null @@ -1,488 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -#ifndef _SCMECM_ -#define _SCMECM_ - -#if defined(PCI) && !defined(OSDEF) -/* - * In the case of the PCI bus the file osdef1st.h must be present - */ -#define OSDEF -#endif - -#ifdef PCI -#ifndef SUPERNET_3 -#define SUPERNET_3 -#endif -#ifndef TAG_MODE -#define TAG_MODE -#endif -#endif - -/* - * include all other files in required order - * the following files must have been included before: - * types.h - * fddi.h - */ -#ifdef OSDEF -#include "h/osdef1st.h" -#endif /* OSDEF */ -#ifdef OEM_CONCEPT -#include "oemdef.h" -#endif /* OEM_CONCEPT */ -#include "h/smt.h" -#include "h/cmtdef.h" -#include "h/fddimib.h" -#include "h/targethw.h" /* all target hw dependencies */ -#include "h/targetos.h" /* all target os dependencies */ -#ifdef ESS -#include "h/sba.h" -#endif - -/* - * Event Queue - * queue.c - * events are class/value pairs - * class is addressee, e.g. RMT, PCM etc. - * value is command, e.g. line state change, ring op change etc. - */ -struct event_queue { - u_short class ; /* event class */ - u_short event ; /* event value */ -} ; - -/* - * define event queue as circular buffer - */ -#ifdef CONCENTRATOR -#define MAX_EVENT 128 -#else /* nCONCENTRATOR */ -#define MAX_EVENT 64 -#endif /* nCONCENTRATOR */ - -struct s_queue { - - struct event_queue ev_queue[MAX_EVENT]; - struct event_queue *ev_put ; - struct event_queue *ev_get ; -} ; - -/* - * ECM - Entity Coordination Management - * ecm.c - */ -struct s_ecm { - u_char path_test ; /* ECM path test variable */ - u_char sb_flag ; /* ECM stuck bypass */ - u_char DisconnectFlag ; /* jd 05-Aug-1999 Bug #10419 - * ECM disconnected */ - u_char ecm_line_state ; /* flag to dispatcher : line states */ - u_long trace_prop ; /* ECM Trace_Prop flag >= 16 bits !! */ - /* NUMPHYS note: - * this variable must have enough bits to hold all entiies in - * the station. So NUMPHYS may not be greater than 31. - */ - char ec_pad[2] ; - struct smt_timer ecm_timer ; /* timer */ -} ; - - -/* - * RMT - Ring Management - * rmt.c - */ -struct s_rmt { - u_char dup_addr_test ; /* state of dupl. addr. test */ - u_char da_flag ; /* flag : duplicate address det. */ - u_char loop_avail ; /* flag : MAC available for loopback */ - u_char sm_ma_avail ; /* flag : MAC available for SMT */ - u_char no_flag ; /* flag : ring not operational */ - u_char bn_flag ; /* flag : MAC reached beacon state */ - u_char jm_flag ; /* flag : jamming in NON_OP_DUP */ - u_char rm_join ; /* CFM flag RM_Join */ - u_char rm_loop ; /* CFM flag RM_Loop */ - - long fast_rm_join ; /* bit mask of active ports */ - /* - * timer and flags - */ - struct smt_timer rmt_timer0 ; /* timer 0 */ - struct smt_timer rmt_timer1 ; /* timer 1 */ - struct smt_timer rmt_timer2 ; /* timer 2 */ - u_char timer0_exp ; /* flag : timer 0 expired */ - u_char timer1_exp ; /* flag : timer 1 expired */ - u_char timer2_exp ; /* flag : timer 2 expired */ - - u_char rm_pad1[1] ; -} ; - -/* - * CFM - Configuration Management - * cfm.c - * used for SAS and DAS - */ -struct s_cfm { - u_char cf_state; /* CFM state machine current state */ - u_char cf_pad[3] ; -} ; - -/* - * CEM - Configuration Element Management - * cem.c - * used for Concentrator - */ -#ifdef CONCENTRATOR -struct s_cem { - int ce_state ; /* CEM state */ - int ce_port ; /* PA PB PM PM+1 .. */ - int ce_type ; /* TA TB TS TM */ -} ; - -/* - * linked list of CCEs in current token path - */ -struct s_c_ring { - struct s_c_ring *c_next ; - char c_entity ; -} ; - -struct mib_path_config { - u_long fddimibPATHConfigSMTIndex; - u_long fddimibPATHConfigPATHIndex; - u_long fddimibPATHConfigTokenOrder; - u_long fddimibPATHConfigResourceType; -#define SNMP_RES_TYPE_MAC 2 /* Resource is a MAC */ -#define SNMP_RES_TYPE_PORT 4 /* Resource is a PORT */ - u_long fddimibPATHConfigResourceIndex; - u_long fddimibPATHConfigCurrentPath; -#define SNMP_PATH_ISOLATED 1 /* Current path is isolated */ -#define SNMP_PATH_LOCAL 2 /* Current path is local */ -#define SNMP_PATH_SECONDARY 3 /* Current path is secondary */ -#define SNMP_PATH_PRIMARY 4 /* Current path is primary */ -#define SNMP_PATH_CONCATENATED 5 /* Current path is concatenated */ -#define SNMP_PATH_THRU 6 /* Current path is thru */ -}; - - -#endif - -/* - * PCM connect states - */ -#define PCM_DISABLED 0 -#define PCM_CONNECTING 1 -#define PCM_STANDBY 2 -#define PCM_ACTIVE 3 - -struct s_pcm { - u_char pcm_pad[3] ; -} ; - -/* - * PHY struct - * one per physical port - */ -struct s_phy { - /* Inter Module Globals */ - struct fddi_mib_p *mib ; - - u_char np ; /* index 0 .. NUMPHYS */ - u_char cf_join ; - u_char cf_loop ; - u_char wc_flag ; /* withhold connection flag */ - u_char pc_mode ; /* Holds the negotiated mode of the PCM */ - u_char pc_lem_fail ; /* flag : LCT failed */ - u_char lc_test ; - u_char scrub ; /* CFM flag Scrub -> PCM */ - char phy_name ; - u_char pmd_type[2] ; /* SK connector/transceiver type codes */ -#define PMD_SK_CONN 0 /* pmd_type[PMD_SK_CONN] = Connector */ -#define PMD_SK_PMD 1 /* pmd_type[PMD_SK_PMD] = Xver */ - u_char pmd_scramble ; /* scrambler on/off */ - - /* inner Module Globals */ - u_char curr_ls ; /* current line state */ - u_char ls_flag ; - u_char rc_flag ; - u_char tc_flag ; - u_char td_flag ; - u_char bitn ; - u_char tr_flag ; /* trace recvd while in active */ - u_char twisted ; /* flag to indicate an A-A or B-B connection */ - u_char t_val[NUMBITS] ; /* transmit bits for signaling */ - u_char r_val[NUMBITS] ; /* receive bits for signaling */ - u_long t_next[NUMBITS] ; - struct smt_timer pcm_timer0 ; - struct smt_timer pcm_timer1 ; - struct smt_timer pcm_timer2 ; - u_char timer0_exp ; - u_char timer1_exp ; - u_char timer2_exp ; - u_char pcm_pad1[1] ; - int cem_pst ; /* CEM privae state; used for dual homing */ - struct lem_counter lem ; -#ifdef AMDPLC - struct s_plc plc ; -#endif -} ; - -/* - * timer package - * smttimer.c - */ -struct s_timer { - struct smt_timer *st_queue ; - struct smt_timer st_fast ; -} ; - -/* - * SRF types and data - */ -#define SMT_EVENT_BASE 1 -#define SMT_EVENT_MAC_PATH_CHANGE (SMT_EVENT_BASE+0) -#define SMT_EVENT_MAC_NEIGHBOR_CHANGE (SMT_EVENT_BASE+1) -#define SMT_EVENT_PORT_PATH_CHANGE (SMT_EVENT_BASE+2) -#define SMT_EVENT_PORT_CONNECTION (SMT_EVENT_BASE+3) - -#define SMT_IS_CONDITION(x) ((x)>=SMT_COND_BASE) - -#define SMT_COND_BASE (SMT_EVENT_PORT_CONNECTION+1) -#define SMT_COND_SMT_PEER_WRAP (SMT_COND_BASE+0) -#define SMT_COND_SMT_HOLD (SMT_COND_BASE+1) -#define SMT_COND_MAC_FRAME_ERROR (SMT_COND_BASE+2) -#define SMT_COND_MAC_DUP_ADDR (SMT_COND_BASE+3) -#define SMT_COND_MAC_NOT_COPIED (SMT_COND_BASE+4) -#define SMT_COND_PORT_EB_ERROR (SMT_COND_BASE+5) -#define SMT_COND_PORT_LER (SMT_COND_BASE+6) - -#define SR0_WAIT 0 -#define SR1_HOLDOFF 1 -#define SR2_DISABLED 2 - -struct s_srf { - u_long SRThreshold ; /* threshold value */ - u_char RT_Flag ; /* report transmitted flag */ - u_char sr_state ; /* state-machine */ - u_char any_report ; /* any report required */ - u_long TSR ; /* timer */ - u_short ring_status ; /* IBM ring status */ -} ; - -/* - * IBM token ring status - */ -#define RS_RES15 (1<<15) /* reserved */ -#define RS_HARDERROR (1<<14) /* ring down */ -#define RS_SOFTERROR (1<<13) /* sent SRF */ -#define RS_BEACON (1<<12) /* transmitted beacon */ -#define RS_PATHTEST (1<<11) /* path test failed */ -#define RS_SELFTEST (1<<10) /* selftest required */ -#define RS_RES9 (1<< 9) /* reserved */ -#define RS_DISCONNECT (1<< 8) /* remote disconnect */ -#define RS_RES7 (1<< 7) /* reserved */ -#define RS_DUPADDR (1<< 6) /* duplicate address */ -#define RS_NORINGOP (1<< 5) /* no ring op */ -#define RS_VERSION (1<< 4) /* SMT version mismatch */ -#define RS_STUCKBYPASSS (1<< 3) /* stuck bypass */ -#define RS_EVENT (1<< 2) /* FDDI event occurred */ -#define RS_RINGOPCHANGE (1<< 1) /* ring op changed */ -#define RS_RES0 (1<< 0) /* reserved */ - -#define RS_SET(smc,bit) \ - ring_status_indication(smc,smc->srf.ring_status |= bit) -#define RS_CLEAR(smc,bit) \ - ring_status_indication(smc,smc->srf.ring_status &= ~bit) - -#define RS_CLEAR_EVENT (0xffff & ~(RS_NORINGOP)) - -/* Define the AIX-event-Notification as null function if it isn't defined */ -/* in the targetos.h file */ -#ifndef AIX_EVENT -#define AIX_EVENT(smc,opt0,opt1,opt2,opt3) /* nothing */ -#endif - -struct s_srf_evc { - u_char evc_code ; /* event code type */ - u_char evc_index ; /* index for mult. instances */ - u_char evc_rep_required ; /* report required */ - u_short evc_para ; /* SMT Para Number */ - u_char *evc_cond_state ; /* condition state */ - u_char *evc_multiple ; /* multiple occurrence */ -} ; - -/* - * Values used by frame based services - * smt.c - */ -#define SMT_MAX_TEST 5 -#define SMT_TID_NIF 0 /* pending NIF request */ -#define SMT_TID_NIF_TEST 1 /* pending NIF test */ -#define SMT_TID_ECF_UNA 2 /* pending ECF UNA test */ -#define SMT_TID_ECF_DNA 3 /* pending ECF DNA test */ -#define SMT_TID_ECF 4 /* pending ECF test */ - -struct smt_values { - u_long smt_tvu ; /* timer valid una */ - u_long smt_tvd ; /* timer valid dna */ - u_long smt_tid ; /* transaction id */ - u_long pend[SMT_MAX_TEST] ; /* TID of requests */ - u_long uniq_time ; /* unique time stamp */ - u_short uniq_ticks ; /* unique time stamp */ - u_short please_reconnect ; /* flag : reconnect */ - u_long smt_last_lem ; - u_long smt_last_notify ; - struct smt_timer smt_timer ; /* SMT NIF timer */ - u_long last_tok_time[NUMMACS]; /* token cnt emulation */ -} ; - -/* - * SMT/CMT configurable parameters - */ -#define SMT_DAS 0 /* dual attach */ -#define SMT_SAS 1 /* single attach */ -#define SMT_NAC 2 /* null attach concentrator */ - -struct smt_config { - u_char attach_s ; /* CFM attach to secondary path */ - u_char sas ; /* SMT_DAS/SAS/NAC */ - u_char build_ring_map ; /* build ringmap if TRUE */ - u_char numphys ; /* number of active phys */ - u_char sc_pad[1] ; - - u_long pcm_tb_min ; /* PCM : TB_Min timer value */ - u_long pcm_tb_max ; /* PCM : TB_Max timer value */ - u_long pcm_c_min ; /* PCM : C_Min timer value */ - u_long pcm_t_out ; /* PCM : T_Out timer value */ - u_long pcm_tl_min ; /* PCM : TL_min timer value */ - u_long pcm_lc_short ; /* PCM : LC_Short timer value */ - u_long pcm_lc_medium ; /* PCM : LC_Medium timer value */ - u_long pcm_lc_long ; /* PCM : LC_Long timer value */ - u_long pcm_lc_extended ; /* PCM : LC_Extended timer value */ - u_long pcm_t_next_9 ; /* PCM : T_Next[9] timer value */ - u_long pcm_ns_max ; /* PCM : NS_Max timer value */ - - u_long ecm_i_max ; /* ECM : I_Max timer value */ - u_long ecm_in_max ; /* ECM : IN_Max timer value */ - u_long ecm_td_min ; /* ECM : TD_Min timer */ - u_long ecm_test_done ; /* ECM : path test done timer */ - u_long ecm_check_poll ; /* ECM : check bypass poller */ - - u_long rmt_t_non_op ; /* RMT : T_Non_OP timer value */ - u_long rmt_t_stuck ; /* RMT : T_Stuck timer value */ - u_long rmt_t_direct ; /* RMT : T_Direct timer value */ - u_long rmt_t_jam ; /* RMT : T_Jam timer value */ - u_long rmt_t_announce ; /* RMT : T_Announce timer value */ - u_long rmt_t_poll ; /* RMT : claim/beacon poller */ - u_long rmt_dup_mac_behavior ; /* Flag for the beavior of SMT if - * a Duplicate MAC Address was detected. - * FALSE: SMT will leave finally the ring - * TRUE: SMT will reinstert into the ring - */ - u_long mac_d_max ; /* MAC : D_Max timer value */ - - u_long lct_short ; /* LCT : error threshold */ - u_long lct_medium ; /* LCT : error threshold */ - u_long lct_long ; /* LCT : error threshold */ - u_long lct_extended ; /* LCT : error threshold */ -} ; - -#ifdef DEBUG -/* - * Debugging struct sometimes used in smc - */ -struct smt_debug { - int d_smtf ; - int d_smt ; - int d_ecm ; - int d_rmt ; - int d_cfm ; - int d_pcm ; - int d_plc ; -#ifdef ESS - int d_ess ; -#endif -#ifdef SBA - int d_sba ; -#endif - struct os_debug d_os; /* Include specific OS DEBUG struct */ -} ; - -#ifndef DEBUG_BRD -/* all boards shall be debugged with one debug struct */ -extern struct smt_debug debug; /* Declaration of debug struct */ -#endif /* DEBUG_BRD */ - -#endif /* DEBUG */ - -/* - * the SMT Context Struct SMC - * this struct contains ALL global variables of SMT - */ -struct s_smc { - struct s_smt_os os ; /* os specific */ - struct s_smt_hw hw ; /* hardware */ - -/* - * NOTE: os and hw MUST BE the first two structs - * anything beyond hw WILL BE SET TO ZERO in smt_set_defaults() - */ - struct smt_config s ; /* smt constants */ - struct smt_values sm ; /* smt variables */ - struct s_ecm e ; /* ecm */ - struct s_rmt r ; /* rmt */ - struct s_cfm cf ; /* cfm/cem */ -#ifdef CONCENTRATOR - struct s_cem ce[NUMPHYS] ; /* cem */ - struct s_c_ring cr[NUMPHYS+NUMMACS] ; -#endif - struct s_pcm p ; /* pcm */ - struct s_phy y[NUMPHYS] ; /* phy */ - struct s_queue q ; /* queue */ - struct s_timer t ; /* timer */ - struct s_srf srf ; /* SRF */ - struct s_srf_evc evcs[6+NUMPHYS*4] ; - struct fddi_mib mib ; /* __THE_MIB__ */ -#ifdef SBA - struct s_sba sba ; /* SBA variables */ -#endif -#ifdef ESS - struct s_ess ess ; /* Ess variables */ -#endif -#if defined(DEBUG) && defined(DEBUG_BRD) - /* If you want all single board to be debugged separately */ - struct smt_debug debug; /* Declaration of debug struct */ -#endif /* DEBUG_BRD && DEBUG */ -} ; - -extern const struct fddi_addr fddi_broadcast; - -extern void all_selection_criteria(struct s_smc *smc); -extern void card_stop(struct s_smc *smc); -extern void init_board(struct s_smc *smc, u_char *mac_addr); -extern int init_fplus(struct s_smc *smc); -extern void init_plc(struct s_smc *smc); -extern int init_smt(struct s_smc *smc, u_char * mac_addr); -extern void mac1_irq(struct s_smc *smc, u_short stu, u_short stl); -extern void mac2_irq(struct s_smc *smc, u_short code_s2u, u_short code_s2l); -extern void mac3_irq(struct s_smc *smc, u_short code_s3u, u_short code_s3l); -extern int pcm_status_twisted(struct s_smc *smc); -extern void plc1_irq(struct s_smc *smc); -extern void plc2_irq(struct s_smc *smc); -extern void read_address(struct s_smc *smc, u_char * mac_addr); -extern void timer_irq(struct s_smc *smc); - -#endif /* _SCMECM_ */ - diff --git a/drivers/net/skfp/h/smt.h b/drivers/net/skfp/h/smt.h deleted file mode 100644 index 2030f9c..0000000 --- a/drivers/net/skfp/h/smt.h +++ /dev/null @@ -1,882 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - * SMT 7.2 frame definitions - */ - -#ifndef _SMT_ -#define _SMT_ - -/* #define SMT5_10 */ -#define SMT6_10 -#define SMT7_20 - -#define OPT_PMF /* if parameter management is supported */ -#define OPT_SRF /* if status report is supported */ - -/* - * SMT frame version 5.1 - */ - -#define SMT_VID 0x0001 /* V 5.1 .. 6.1 */ -#define SMT_VID_2 0x0002 /* V 7.2 */ - -struct smt_sid { - u_char sid_oem[2] ; /* implementation spec. */ - struct fddi_addr sid_node ; /* node address */ -} ; - -typedef u_char t_station_id[8] ; - -/* - * note on alignment : - * sizeof(struct smt_header) = 32 - * all parameters are long aligned - * if struct smt_header starts at offset 0, all longs are aligned correctly - * (FC starts at offset 3) - */ -_packed struct smt_header { - struct fddi_addr smt_dest ; /* destination address */ - struct fddi_addr smt_source ; /* source address */ - u_char smt_class ; /* NIF, SIF ... */ - u_char smt_type ; /* req., response .. */ - u_short smt_version ; /* version id */ - u_int smt_tid ; /* transaction ID */ - struct smt_sid smt_sid ; /* station ID */ - u_short smt_pad ; /* pad with 0 */ - u_short smt_len ; /* length of info field */ -} ; -#define SWAP_SMTHEADER "662sl8ss" - -#if 0 -/* - * MAC FC values - */ -#define FC_SMT_INFO 0x41 /* SMT info */ -#define FC_SMT_NSA 0x4f /* SMT Next Station Addressing */ -#endif - - -/* - * type codes - */ -#define SMT_ANNOUNCE 0x01 /* announcement */ -#define SMT_REQUEST 0x02 /* request */ -#define SMT_REPLY 0x03 /* reply */ - -/* - * class codes - */ -#define SMT_NIF 0x01 /* neighbor information frames */ -#define SMT_SIF_CONFIG 0x02 /* station information configuration */ -#define SMT_SIF_OPER 0x03 /* station information operation */ -#define SMT_ECF 0x04 /* echo frames */ -#define SMT_RAF 0x05 /* resource allocation */ -#define SMT_RDF 0x06 /* request denied */ -#define SMT_SRF 0x07 /* status report */ -#define SMT_PMF_GET 0x08 /* parameter management get */ -#define SMT_PMF_SET 0x09 /* parameter management set */ -#define SMT_ESF 0xff /* extended service */ - -#define SMT_MAX_ECHO_LEN 4458 /* max length of SMT Echo */ -#if defined(CONC) || defined(CONC_II) -#define SMT_TEST_ECHO_LEN 50 /* test length of SMT Echo */ -#else -#define SMT_TEST_ECHO_LEN SMT_MAX_ECHO_LEN /* test length */ -#endif - -#define SMT_MAX_INFO_LEN (4352-20) /* max length for SMT info */ - - -/* - * parameter types - */ - -struct smt_para { - u_short p_type ; /* type */ - u_short p_len ; /* length of parameter */ -} ; - -#define PARA_LEN (sizeof(struct smt_para)) - -#define SMTSETPARA(p,t) (p)->para.p_type = (t),\ - (p)->para.p_len = sizeof(*(p)) - PARA_LEN - -/* - * P01 : Upstream Neighbor Address, UNA - */ -#define SMT_P_UNA 0x0001 /* upstream neighbor address */ -#define SWAP_SMT_P_UNA "s6" - -struct smt_p_una { - struct smt_para para ; /* generic parameter header */ - u_short una_pad ; - struct fddi_addr una_node ; /* node address, zero if unknown */ -} ; - -/* - * P02 : Station Descriptor - */ -#define SMT_P_SDE 0x0002 /* station descriptor */ -#define SWAP_SMT_P_SDE "1111" - -#define SMT_SDE_STATION 0 /* end node */ -#define SMT_SDE_CONCENTRATOR 1 /* concentrator */ - -struct smt_p_sde { - struct smt_para para ; /* generic parameter header */ - u_char sde_type ; /* station type */ - u_char sde_mac_count ; /* number of MACs */ - u_char sde_non_master ; /* number of A,B or S ports */ - u_char sde_master ; /* number of S ports on conc. */ -} ; - -/* - * P03 : Station State - */ -#define SMT_P_STATE 0x0003 /* station state */ -#define SWAP_SMT_P_STATE "scc" - -struct smt_p_state { - struct smt_para para ; /* generic parameter header */ - u_short st_pad ; - u_char st_topology ; /* topology */ - u_char st_dupl_addr ; /* duplicate address detected */ -} ; -#define SMT_ST_WRAPPED (1<<0) /* station wrapped */ -#define SMT_ST_UNATTACHED (1<<1) /* unattached concentrator */ -#define SMT_ST_TWISTED_A (1<<2) /* A-A connection, twisted ring */ -#define SMT_ST_TWISTED_B (1<<3) /* B-B connection, twisted ring */ -#define SMT_ST_ROOTED_S (1<<4) /* rooted station */ -#define SMT_ST_SRF (1<<5) /* SRF protocol supported */ -#define SMT_ST_SYNC_SERVICE (1<<6) /* use synchronous bandwidth */ - -#define SMT_ST_MY_DUPA (1<<0) /* my station detected dupl. */ -#define SMT_ST_UNA_DUPA (1<<1) /* my UNA detected duplicate */ - -/* - * P04 : timestamp - */ -#define SMT_P_TIMESTAMP 0x0004 /* time stamp */ -#define SWAP_SMT_P_TIMESTAMP "8" -struct smt_p_timestamp { - struct smt_para para ; /* generic parameter header */ - u_char ts_time[8] ; /* time, resolution 80nS, unique */ -} ; - -/* - * P05 : station policies - */ -#define SMT_P_POLICY 0x0005 /* station policies */ -#define SWAP_SMT_P_POLICY "ss" - -struct smt_p_policy { - struct smt_para para ; /* generic parameter header */ - u_short pl_config ; - u_short pl_connect ; /* bit string POLICY_AA ... */ -} ; -#define SMT_PL_HOLD 1 /* hold policy supported (Dual MAC) */ - -/* - * P06 : latency equivalent - */ -#define SMT_P_LATENCY 0x0006 /* latency */ -#define SWAP_SMT_P_LATENCY "ssss" - -/* - * note: latency has two phy entries by definition - * for a SAS, the 2nd one is null - */ -struct smt_p_latency { - struct smt_para para ; /* generic parameter header */ - u_short lt_phyout_idx1 ; /* index */ - u_short lt_latency1 ; /* latency , unit : byte clock */ - u_short lt_phyout_idx2 ; /* 0 if SAS */ - u_short lt_latency2 ; /* 0 if SAS */ -} ; - -/* - * P07 : MAC neighbors - */ -#define SMT_P_NEIGHBORS 0x0007 /* MAC neighbor description */ -#define SWAP_SMT_P_NEIGHBORS "ss66" - -struct smt_p_neighbor { - struct smt_para para ; /* generic parameter header */ - u_short nb_mib_index ; /* MIB index */ - u_short nb_mac_index ; /* n+1 .. n+m, m = #MACs, n = #PHYs */ - struct fddi_addr nb_una ; /* UNA , 0 for unknown */ - struct fddi_addr nb_dna ; /* DNA , 0 for unknown */ -} ; - -/* - * PHY record - */ -#define SMT_PHY_A 0 /* A port */ -#define SMT_PHY_B 1 /* B port */ -#define SMT_PHY_S 2 /* slave port */ -#define SMT_PHY_M 3 /* master port */ - -#define SMT_CS_DISABLED 0 /* connect state : disabled */ -#define SMT_CS_CONNECTING 1 /* connect state : connecting */ -#define SMT_CS_STANDBY 2 /* connect state : stand by */ -#define SMT_CS_ACTIVE 3 /* connect state : active */ - -#define SMT_RM_NONE 0 -#define SMT_RM_MAC 1 - -struct smt_phy_rec { - u_short phy_mib_index ; /* MIB index */ - u_char phy_type ; /* A/B/S/M */ - u_char phy_connect_state ; /* disabled/connecting/active */ - u_char phy_remote_type ; /* A/B/S/M */ - u_char phy_remote_mac ; /* none/remote */ - u_short phy_resource_idx ; /* 1 .. n */ -} ; - -/* - * MAC record - */ -struct smt_mac_rec { - struct fddi_addr mac_addr ; /* MAC address */ - u_short mac_resource_idx ; /* n+1 .. n+m */ -} ; - -/* - * P08 : path descriptors - * should be really an array ; however our environment has a fixed number of - * PHYs and MACs - */ -#define SMT_P_PATH 0x0008 /* path descriptor */ -#define SWAP_SMT_P_PATH "[6s]" - -struct smt_p_path { - struct smt_para para ; /* generic parameter header */ - struct smt_phy_rec pd_phy[2] ; /* PHY A */ - struct smt_mac_rec pd_mac ; /* MAC record */ -} ; - -/* - * P09 : MAC status - */ -#define SMT_P_MAC_STATUS 0x0009 /* MAC status */ -#define SWAP_SMT_P_MAC_STATUS "sslllllllll" - -struct smt_p_mac_status { - struct smt_para para ; /* generic parameter header */ - u_short st_mib_index ; /* MIB index */ - u_short st_mac_index ; /* n+1 .. n+m */ - u_int st_t_req ; /* T_Req */ - u_int st_t_neg ; /* T_Neg */ - u_int st_t_max ; /* T_Max */ - u_int st_tvx_value ; /* TVX_Value */ - u_int st_t_min ; /* T_Min */ - u_int st_sba ; /* synchr. bandwidth alloc */ - u_int st_frame_ct ; /* frame counter */ - u_int st_error_ct ; /* error counter */ - u_int st_lost_ct ; /* lost frames counter */ -} ; - -/* - * P0A : PHY link error rate monitoring - */ -#define SMT_P_LEM 0x000a /* link error monitor */ -#define SWAP_SMT_P_LEM "ssccccll" -/* - * units of lem_cutoff,lem_alarm,lem_estimate : 10**-x - */ -struct smt_p_lem { - struct smt_para para ; /* generic parameter header */ - u_short lem_mib_index ; /* MIB index */ - u_short lem_phy_index ; /* 1 .. n */ - u_char lem_pad2 ; /* be nice and make it even . */ - u_char lem_cutoff ; /* 0x4 .. 0xf, default 0x7 */ - u_char lem_alarm ; /* 0x4 .. 0xf, default 0x8 */ - u_char lem_estimate ; /* 0x0 .. 0xff */ - u_int lem_reject_ct ; /* 0x00000000 .. 0xffffffff */ - u_int lem_ct ; /* 0x00000000 .. 0xffffffff */ -} ; - -/* - * P0B : MAC frame counters - */ -#define SMT_P_MAC_COUNTER 0x000b /* MAC frame counters */ -#define SWAP_SMT_P_MAC_COUNTER "ssll" - -struct smt_p_mac_counter { - struct smt_para para ; /* generic parameter header */ - u_short mc_mib_index ; /* MIB index */ - u_short mc_index ; /* mac index */ - u_int mc_receive_ct ; /* receive counter */ - u_int mc_transmit_ct ; /* transmit counter */ -} ; - -/* - * P0C : MAC frame not copied counter - */ -#define SMT_P_MAC_FNC 0x000c /* MAC frame not copied counter */ -#define SWAP_SMT_P_MAC_FNC "ssl" - -struct smt_p_mac_fnc { - struct smt_para para ; /* generic parameter header */ - u_short nc_mib_index ; /* MIB index */ - u_short nc_index ; /* mac index */ - u_int nc_counter ; /* not copied counter */ -} ; - - -/* - * P0D : MAC priority values - */ -#define SMT_P_PRIORITY 0x000d /* MAC priority values */ -#define SWAP_SMT_P_PRIORITY "ssl" - -struct smt_p_priority { - struct smt_para para ; /* generic parameter header */ - u_short pr_mib_index ; /* MIB index */ - u_short pr_index ; /* mac index */ - u_int pr_priority[7] ; /* priority values */ -} ; - -/* - * P0E : PHY elasticity buffer status - */ -#define SMT_P_EB 0x000e /* PHY EB status */ -#define SWAP_SMT_P_EB "ssl" - -struct smt_p_eb { - struct smt_para para ; /* generic parameter header */ - u_short eb_mib_index ; /* MIB index */ - u_short eb_index ; /* phy index */ - u_int eb_error_ct ; /* # of eb overflows */ -} ; - -/* - * P0F : manufacturer field - */ -#define SMT_P_MANUFACTURER 0x000f /* manufacturer field */ -#define SWAP_SMT_P_MANUFACTURER "" - -struct smp_p_manufacturer { - struct smt_para para ; /* generic parameter header */ - u_char mf_data[32] ; /* OUI + arbitrary data */ -} ; - -/* - * P10 : user field - */ -#define SMT_P_USER 0x0010 /* manufacturer field */ -#define SWAP_SMT_P_USER "" - -struct smp_p_user { - struct smt_para para ; /* generic parameter header */ - u_char us_data[32] ; /* arbitrary data */ -} ; - - - -/* - * P11 : echo data - */ -#define SMT_P_ECHODATA 0x0011 /* echo data */ -#define SWAP_SMT_P_ECHODATA "" - -struct smt_p_echo { - struct smt_para para ; /* generic parameter header */ - u_char ec_data[SMT_MAX_ECHO_LEN-4] ; /* echo data */ -} ; - -/* - * P12 : reason code - */ -#define SMT_P_REASON 0x0012 /* reason code */ -#define SWAP_SMT_P_REASON "l" - -struct smt_p_reason { - struct smt_para para ; /* generic parameter header */ - u_int rdf_reason ; /* CLASS/VERSION */ -} ; -#define SMT_RDF_CLASS 0x00000001 /* class not supported */ -#define SMT_RDF_VERSION 0x00000002 /* version not supported */ -#define SMT_RDF_SUCCESS 0x00000003 /* success (PMF) */ -#define SMT_RDF_BADSET 0x00000004 /* bad set count (PMF) */ -#define SMT_RDF_ILLEGAL 0x00000005 /* read only (PMF) */ -#define SMT_RDF_NOPARAM 0x6 /* parameter not supported (PMF) */ -#define SMT_RDF_RANGE 0x8 /* out of range */ -#define SMT_RDF_AUTHOR 0x9 /* not autohorized */ -#define SMT_RDF_LENGTH 0x0a /* length error */ -#define SMT_RDF_TOOLONG 0x0b /* length error */ -#define SMT_RDF_SBA 0x0d /* SBA denied */ - -/* - * P13 : refused frame beginning - */ -#define SMT_P_REFUSED 0x0013 /* refused frame beginning */ -#define SWAP_SMT_P_REFUSED "l" - -struct smt_p_refused { - struct smt_para para ; /* generic parameter header */ - u_int ref_fc ; /* 3 bytes 0 + FC */ - struct smt_header ref_header ; /* refused header */ -} ; - -/* - * P14 : supported SMT versions - */ -#define SMT_P_VERSION 0x0014 /* SMT supported versions */ -#define SWAP_SMT_P_VERSION "sccss" - -struct smt_p_version { - struct smt_para para ; /* generic parameter header */ - u_short v_pad ; - u_char v_n ; /* 1 .. 0xff, #versions */ - u_char v_index ; /* 1 .. 0xff, index of op. v. */ - u_short v_version[1] ; /* list of min. 1 version */ - u_short v_pad2 ; /* pad if necessary */ -} ; - -/* - * P15 : Resource Type - */ -#define SWAP_SMT_P0015 "l" - -struct smt_p_0015 { - struct smt_para para ; /* generic parameter header */ - u_int res_type ; /* recsource type */ -} ; - -#define SYNC_BW 0x00000001L /* Synchronous Bandwidth */ - -/* - * P16 : SBA Command - */ -#define SWAP_SMT_P0016 "l" - -struct smt_p_0016 { - struct smt_para para ; /* generic parameter header */ - u_int sba_cmd ; /* command for the SBA */ -} ; - -#define REQUEST_ALLOCATION 0x1 /* req allocation of sync bandwidth */ -#define REPORT_ALLOCATION 0x2 /* rep of sync bandwidth allocation */ -#define CHANGE_ALLOCATION 0x3 /* forces a station using sync band-*/ - /* width to change its current allo-*/ - /* cation */ - -/* - * P17 : SBA Payload Request - */ -#define SWAP_SMT_P0017 "l" - -struct smt_p_0017 { - struct smt_para para ; /* generic parameter header */ - int sba_pl_req ; /* total sync bandwidth measured in */ -} ; /* bytes per 125 us */ - -/* - * P18 : SBA Overhead Request - */ -#define SWAP_SMT_P0018 "l" - -struct smt_p_0018 { - struct smt_para para ; /* generic parameter header */ - int sba_ov_req ; /* total sync bandwidth req for overhead*/ -} ; /* measuered in bytes per T_Neg */ - -/* - * P19 : SBA Allocation Address - */ -#define SWAP_SMT_P0019 "s6" - -struct smt_p_0019 { - struct smt_para para ; /* generic parameter header */ - u_short sba_pad ; - struct fddi_addr alloc_addr ; /* Allocation Address */ -} ; - -/* - * P1A : SBA Category - */ -#define SWAP_SMT_P001A "l" - -struct smt_p_001a { - struct smt_para para ; /* generic parameter header */ - u_int category ; /* Allocator defined classification */ -} ; - -/* - * P1B : Maximum T_Neg - */ -#define SWAP_SMT_P001B "l" - -struct smt_p_001b { - struct smt_para para ; /* generic parameter header */ - u_int max_t_neg ; /* longest T_NEG for the sync service*/ -} ; - -/* - * P1C : Minimum SBA Segment Size - */ -#define SWAP_SMT_P001C "l" - -struct smt_p_001c { - struct smt_para para ; /* generic parameter header */ - u_int min_seg_siz ; /* smallest number of bytes per frame*/ -} ; - -/* - * P1D : SBA Allocatable - */ -#define SWAP_SMT_P001D "l" - -struct smt_p_001d { - struct smt_para para ; /* generic parameter header */ - u_int allocatable ; /* total sync bw available for alloc */ -} ; - -/* - * P20 0B : frame status capabilities - * NOTE: not in swap table, is used by smt.c AND PMF table - */ -#define SMT_P_FSC 0x200b -/* #define SWAP_SMT_P_FSC "ssss" */ - -struct smt_p_fsc { - struct smt_para para ; /* generic parameter header */ - u_short fsc_pad0 ; - u_short fsc_mac_index ; /* mac index 1 .. ff */ - u_short fsc_pad1 ; - u_short fsc_value ; /* FSC_TYPE[0-2] */ -} ; - -#define FSC_TYPE0 0 /* "normal" node (A/C handling) */ -#define FSC_TYPE1 1 /* Special A/C indicator forwarding */ -#define FSC_TYPE2 2 /* Special A/C indicator forwarding */ - -/* - * P00 21 : user defined authoriziation (see pmf.c) - */ -#define SMT_P_AUTHOR 0x0021 - -/* - * notification parameters - */ -#define SWAP_SMT_P1048 "ll" -struct smt_p_1048 { - u_int p1048_flag ; - u_int p1048_cf_state ; -} ; - -/* - * NOTE: all 2xxx 3xxx and 4xxx must include the INDEX in the swap string, - * even so the INDEX is NOT part of the struct. - * INDEX is already swapped in pmf.c, format in string is '4' - */ -#define SWAP_SMT_P208C "4lss66" -struct smt_p_208c { - u_int p208c_flag ; - u_short p208c_pad ; - u_short p208c_dupcondition ; - struct fddi_addr p208c_fddilong ; - struct fddi_addr p208c_fddiunalong ; -} ; - -#define SWAP_SMT_P208D "4lllll" -struct smt_p_208d { - u_int p208d_flag ; - u_int p208d_frame_ct ; - u_int p208d_error_ct ; - u_int p208d_lost_ct ; - u_int p208d_ratio ; -} ; - -#define SWAP_SMT_P208E "4llll" -struct smt_p_208e { - u_int p208e_flag ; - u_int p208e_not_copied ; - u_int p208e_copied ; - u_int p208e_not_copied_ratio ; -} ; - -#define SWAP_SMT_P208F "4ll6666s6" - -struct smt_p_208f { - u_int p208f_multiple ; - u_int p208f_nacondition ; - struct fddi_addr p208f_old_una ; - struct fddi_addr p208f_new_una ; - struct fddi_addr p208f_old_dna ; - struct fddi_addr p208f_new_dna ; - u_short p208f_curren_path ; - struct fddi_addr p208f_smt_address ; -} ; - -#define SWAP_SMT_P2090 "4lssl" - -struct smt_p_2090 { - u_int p2090_multiple ; - u_short p2090_availablepaths ; - u_short p2090_currentpath ; - u_int p2090_requestedpaths ; -} ; - -/* - * NOTE: - * special kludge for parameters 320b,320f,3210 - * these parameters are part of RAF frames - * RAF frames are parsed in SBA.C and must be swapped - * PMF.C has special code to avoid double swapping - */ -#ifdef LITTLE_ENDIAN -#define SBAPATHINDEX (0x01000000L) -#else -#define SBAPATHINDEX (0x01L) -#endif - -#define SWAP_SMT_P320B "42s" - -struct smt_p_320b { - struct smt_para para ; /* generic parameter header */ - u_int mib_index ; - u_short path_pad ; - u_short path_index ; -} ; - -#define SWAP_SMT_P320F "4l" - -struct smt_p_320f { - struct smt_para para ; /* generic parameter header */ - u_int mib_index ; - u_int mib_payload ; -} ; - -#define SWAP_SMT_P3210 "4l" - -struct smt_p_3210 { - struct smt_para para ; /* generic parameter header */ - u_int mib_index ; - u_int mib_overhead ; -} ; - -#define SWAP_SMT_P4050 "4l1111ll" - -struct smt_p_4050 { - u_int p4050_flag ; - u_char p4050_pad ; - u_char p4050_cutoff ; - u_char p4050_alarm ; - u_char p4050_estimate ; - u_int p4050_reject_ct ; - u_int p4050_ct ; -} ; - -#define SWAP_SMT_P4051 "4lssss" -struct smt_p_4051 { - u_int p4051_multiple ; - u_short p4051_porttype ; - u_short p4051_connectstate ; - u_short p4051_pc_neighbor ; - u_short p4051_pc_withhold ; -} ; - -#define SWAP_SMT_P4052 "4ll" -struct smt_p_4052 { - u_int p4052_flag ; - u_int p4052_eberrorcount ; -} ; - -#define SWAP_SMT_P4053 "4lsslss" - -struct smt_p_4053 { - u_int p4053_multiple ; - u_short p4053_availablepaths ; - u_short p4053_currentpath ; - u_int p4053_requestedpaths ; - u_short p4053_mytype ; - u_short p4053_neighbortype ; -} ; - - -#define SMT_P_SETCOUNT 0x1035 -#define SWAP_SMT_P_SETCOUNT "l8" - -struct smt_p_setcount { - struct smt_para para ; /* generic parameter header */ - u_int count ; - u_char timestamp[8] ; -} ; - -/* - * SMT FRAMES - */ - -/* - * NIF : neighbor information frames - */ -struct smt_nif { - struct smt_header smt ; /* generic header */ - struct smt_p_una una ; /* UNA */ - struct smt_p_sde sde ; /* station descriptor */ - struct smt_p_state state ; /* station state */ -#ifdef SMT6_10 - struct smt_p_fsc fsc ; /* frame status cap. */ -#endif -} ; - -/* - * SIF : station information frames - */ -struct smt_sif_config { - struct smt_header smt ; /* generic header */ - struct smt_p_timestamp ts ; /* time stamp */ - struct smt_p_sde sde ; /* station descriptor */ - struct smt_p_version version ; /* supported versions */ - struct smt_p_state state ; /* station state */ - struct smt_p_policy policy ; /* station policy */ - struct smt_p_latency latency ; /* path latency */ - struct smt_p_neighbor neighbor ; /* neighbors, we have only one*/ -#ifdef OPT_PMF - struct smt_p_setcount setcount ; /* Set Count mandatory */ -#endif - /* WARNING : path MUST BE LAST FIELD !!! (see smt.c:smt_fill_path) */ - struct smt_p_path path ; /* path descriptor */ -} ; -#define SIZEOF_SMT_SIF_CONFIG (sizeof(struct smt_sif_config)- \ - sizeof(struct smt_p_path)) - -struct smt_sif_operation { - struct smt_header smt ; /* generic header */ - struct smt_p_timestamp ts ; /* time stamp */ - struct smt_p_mac_status status ; /* mac status */ - struct smt_p_mac_counter mc ; /* MAC counter */ - struct smt_p_mac_fnc fnc ; /* MAC frame not copied */ - struct smp_p_manufacturer man ; /* manufacturer field */ - struct smp_p_user user ; /* user field */ -#ifdef OPT_PMF - struct smt_p_setcount setcount ; /* Set Count mandatory */ -#endif - /* must be last */ - struct smt_p_lem lem[1] ; /* phy lem status */ -} ; -#define SIZEOF_SMT_SIF_OPERATION (sizeof(struct smt_sif_operation)- \ - sizeof(struct smt_p_lem)) - -/* - * ECF : echo frame - */ -struct smt_ecf { - struct smt_header smt ; /* generic header */ - struct smt_p_echo ec_echo ; /* echo parameter */ -} ; -#define SMT_ECF_LEN (sizeof(struct smt_header)+sizeof(struct smt_para)) - -/* - * RDF : request denied frame - */ -struct smt_rdf { - struct smt_header smt ; /* generic header */ - struct smt_p_reason reason ; /* reason code */ - struct smt_p_version version ; /* supported versions */ - struct smt_p_refused refused ; /* refused frame fragment */ -} ; - -/* - * SBA Request Allocation Response Frame - */ -struct smt_sba_alc_res { - struct smt_header smt ; /* generic header */ - struct smt_p_0015 s_type ; /* resource type */ - struct smt_p_0016 cmd ; /* SBA command */ - struct smt_p_reason reason ; /* reason code */ - struct smt_p_320b path ; /* path type */ - struct smt_p_320f payload ; /* current SBA payload */ - struct smt_p_3210 overhead ; /* current SBA overhead */ - struct smt_p_0019 a_addr ; /* Allocation Address */ - struct smt_p_001a cat ; /* Category - from the request */ - struct smt_p_001d alloc ; /* SBA Allocatable */ -} ; - -/* - * SBA Request Allocation Request Frame - */ -struct smt_sba_alc_req { - struct smt_header smt ; /* generic header */ - struct smt_p_0015 s_type ; /* resource type */ - struct smt_p_0016 cmd ; /* SBA command */ - struct smt_p_320b path ; /* path type */ - struct smt_p_0017 pl_req ; /* requested payload */ - struct smt_p_0018 ov_req ; /* requested SBA overhead */ - struct smt_p_320f payload ; /* current SBA payload */ - struct smt_p_3210 overhead ; /* current SBA overhead */ - struct smt_p_0019 a_addr ; /* Allocation Address */ - struct smt_p_001a cat ; /* Category - from the request */ - struct smt_p_001b tneg ; /* max T-NEG */ - struct smt_p_001c segm ; /* minimum segment size */ -} ; - -/* - * SBA Change Allocation Request Frame - */ -struct smt_sba_chg { - struct smt_header smt ; /* generic header */ - struct smt_p_0015 s_type ; /* resource type */ - struct smt_p_0016 cmd ; /* SBA command */ - struct smt_p_320b path ; /* path type */ - struct smt_p_320f payload ; /* current SBA payload */ - struct smt_p_3210 overhead ; /* current SBA overhead */ - struct smt_p_001a cat ; /* Category - from the request */ -} ; - -/* - * SBA Report Allocation Request Frame - */ -struct smt_sba_rep_req { - struct smt_header smt ; /* generic header */ - struct smt_p_0015 s_type ; /* resource type */ - struct smt_p_0016 cmd ; /* SBA command */ -} ; - -/* - * SBA Report Allocation Response Frame - */ -struct smt_sba_rep_res { - struct smt_header smt ; /* generic header */ - struct smt_p_0015 s_type ; /* resource type */ - struct smt_p_0016 cmd ; /* SBA command */ - struct smt_p_320b path ; /* path type */ - struct smt_p_320f payload ; /* current SBA payload */ - struct smt_p_3210 overhead ; /* current SBA overhead */ -} ; - -/* - * actions - */ -#define SMT_STATION_ACTION 1 -#define SMT_STATION_ACTION_CONNECT 0 -#define SMT_STATION_ACTION_DISCONNECT 1 -#define SMT_STATION_ACTION_PATHTEST 2 -#define SMT_STATION_ACTION_SELFTEST 3 -#define SMT_STATION_ACTION_DISABLE_A 4 -#define SMT_STATION_ACTION_DISABLE_B 5 -#define SMT_STATION_ACTION_DISABLE_M 6 - -#define SMT_PORT_ACTION 2 -#define SMT_PORT_ACTION_MAINT 0 -#define SMT_PORT_ACTION_ENABLE 1 -#define SMT_PORT_ACTION_DISABLE 2 -#define SMT_PORT_ACTION_START 3 -#define SMT_PORT_ACTION_STOP 4 - -#endif /* _SMT_ */ diff --git a/drivers/net/skfp/h/smt_p.h b/drivers/net/skfp/h/smt_p.h deleted file mode 100644 index 99f9be9..0000000 --- a/drivers/net/skfp/h/smt_p.h +++ /dev/null @@ -1,326 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - * defines for all SMT attributes - */ - -/* - * this boring file was produced by perl - * thanks Larry ! - */ -#define SMT_P0012 0x0012 - -#define SMT_P0015 0x0015 -#define SMT_P0016 0x0016 -#define SMT_P0017 0x0017 -#define SMT_P0018 0x0018 -#define SMT_P0019 0x0019 - -#define SMT_P001A 0x001a -#define SMT_P001B 0x001b -#define SMT_P001C 0x001c -#define SMT_P001D 0x001d - -#define SMT_P100A 0x100a -#define SMT_P100B 0x100b -#define SMT_P100C 0x100c -#define SMT_P100D 0x100d -#define SMT_P100E 0x100e -#define SMT_P100F 0x100f -#define SMT_P1010 0x1010 -#define SMT_P1011 0x1011 -#define SMT_P1012 0x1012 -#define SMT_P1013 0x1013 -#define SMT_P1014 0x1014 -#define SMT_P1015 0x1015 -#define SMT_P1016 0x1016 -#define SMT_P1017 0x1017 -#define SMT_P1018 0x1018 -#define SMT_P1019 0x1019 -#define SMT_P101A 0x101a -#define SMT_P101B 0x101b -#define SMT_P101C 0x101c -#define SMT_P101D 0x101d -#define SMT_P101E 0x101e -#define SMT_P101F 0x101f -#define SMT_P1020 0x1020 -#define SMT_P1021 0x1021 -#define SMT_P1022 0x1022 -#define SMT_P1023 0x1023 -#define SMT_P1024 0x1024 -#define SMT_P1025 0x1025 -#define SMT_P1026 0x1026 -#define SMT_P1027 0x1027 -#define SMT_P1028 0x1028 -#define SMT_P1029 0x1029 -#define SMT_P102A 0x102a -#define SMT_P102B 0x102b -#define SMT_P102C 0x102c -#define SMT_P102D 0x102d -#define SMT_P102E 0x102e -#define SMT_P102F 0x102f -#define SMT_P1030 0x1030 -#define SMT_P1031 0x1031 -#define SMT_P1032 0x1032 -#define SMT_P1033 0x1033 -#define SMT_P1034 0x1034 -#define SMT_P1035 0x1035 -#define SMT_P1036 0x1036 -#define SMT_P1037 0x1037 -#define SMT_P1038 0x1038 -#define SMT_P1039 0x1039 -#define SMT_P103A 0x103a -#define SMT_P103B 0x103b -#define SMT_P103C 0x103c -#define SMT_P103D 0x103d -#define SMT_P103E 0x103e -#define SMT_P103F 0x103f -#define SMT_P1040 0x1040 -#define SMT_P1041 0x1041 -#define SMT_P1042 0x1042 -#define SMT_P1043 0x1043 -#define SMT_P1044 0x1044 -#define SMT_P1045 0x1045 -#define SMT_P1046 0x1046 -#define SMT_P1047 0x1047 -#define SMT_P1048 0x1048 -#define SMT_P1049 0x1049 -#define SMT_P104A 0x104a -#define SMT_P104B 0x104b -#define SMT_P104C 0x104c -#define SMT_P104D 0x104d -#define SMT_P104E 0x104e -#define SMT_P104F 0x104f -#define SMT_P1050 0x1050 -#define SMT_P1051 0x1051 -#define SMT_P1052 0x1052 -#define SMT_P1053 0x1053 -#define SMT_P1054 0x1054 - -#define SMT_P10F0 0x10f0 -#define SMT_P10F1 0x10f1 -#ifdef ESS -#define SMT_P10F2 0x10f2 -#define SMT_P10F3 0x10f3 -#define SMT_P10F4 0x10f4 -#define SMT_P10F5 0x10f5 -#define SMT_P10F6 0x10f6 -#define SMT_P10F7 0x10f7 -#endif -#ifdef SBA -#define SMT_P10F8 0x10f8 -#define SMT_P10F9 0x10f9 -#endif - -#define SMT_P200A 0x200a -#define SMT_P200B 0x200b -#define SMT_P200C 0x200c -#define SMT_P200D 0x200d -#define SMT_P200E 0x200e -#define SMT_P200F 0x200f -#define SMT_P2010 0x2010 -#define SMT_P2011 0x2011 -#define SMT_P2012 0x2012 -#define SMT_P2013 0x2013 -#define SMT_P2014 0x2014 -#define SMT_P2015 0x2015 -#define SMT_P2016 0x2016 -#define SMT_P2017 0x2017 -#define SMT_P2018 0x2018 -#define SMT_P2019 0x2019 -#define SMT_P201A 0x201a -#define SMT_P201B 0x201b -#define SMT_P201C 0x201c -#define SMT_P201D 0x201d -#define SMT_P201E 0x201e -#define SMT_P201F 0x201f -#define SMT_P2020 0x2020 -#define SMT_P2021 0x2021 -#define SMT_P2022 0x2022 -#define SMT_P2023 0x2023 -#define SMT_P2024 0x2024 -#define SMT_P2025 0x2025 -#define SMT_P2026 0x2026 -#define SMT_P2027 0x2027 -#define SMT_P2028 0x2028 -#define SMT_P2029 0x2029 -#define SMT_P202A 0x202a -#define SMT_P202B 0x202b -#define SMT_P202C 0x202c -#define SMT_P202D 0x202d -#define SMT_P202E 0x202e -#define SMT_P202F 0x202f -#define SMT_P2030 0x2030 -#define SMT_P2031 0x2031 -#define SMT_P2032 0x2032 -#define SMT_P2033 0x2033 -#define SMT_P2034 0x2034 -#define SMT_P2035 0x2035 -#define SMT_P2036 0x2036 -#define SMT_P2037 0x2037 -#define SMT_P2038 0x2038 -#define SMT_P2039 0x2039 -#define SMT_P203A 0x203a -#define SMT_P203B 0x203b -#define SMT_P203C 0x203c -#define SMT_P203D 0x203d -#define SMT_P203E 0x203e -#define SMT_P203F 0x203f -#define SMT_P2040 0x2040 -#define SMT_P2041 0x2041 -#define SMT_P2042 0x2042 -#define SMT_P2043 0x2043 -#define SMT_P2044 0x2044 -#define SMT_P2045 0x2045 -#define SMT_P2046 0x2046 -#define SMT_P2047 0x2047 -#define SMT_P2048 0x2048 -#define SMT_P2049 0x2049 -#define SMT_P204A 0x204a -#define SMT_P204B 0x204b -#define SMT_P204C 0x204c -#define SMT_P204D 0x204d -#define SMT_P204E 0x204e -#define SMT_P204F 0x204f -#define SMT_P2050 0x2050 -#define SMT_P2051 0x2051 -#define SMT_P2052 0x2052 -#define SMT_P2053 0x2053 -#define SMT_P2054 0x2054 -#define SMT_P2055 0x2055 -#define SMT_P2056 0x2056 -#define SMT_P2057 0x2057 -#define SMT_P2058 0x2058 -#define SMT_P2059 0x2059 -#define SMT_P205A 0x205a -#define SMT_P205B 0x205b -#define SMT_P205C 0x205c -#define SMT_P205D 0x205d -#define SMT_P205E 0x205e -#define SMT_P205F 0x205f -#define SMT_P2060 0x2060 -#define SMT_P2061 0x2061 -#define SMT_P2062 0x2062 -#define SMT_P2063 0x2063 -#define SMT_P2064 0x2064 -#define SMT_P2065 0x2065 -#define SMT_P2066 0x2066 -#define SMT_P2067 0x2067 -#define SMT_P2068 0x2068 -#define SMT_P2069 0x2069 -#define SMT_P206A 0x206a -#define SMT_P206B 0x206b -#define SMT_P206C 0x206c -#define SMT_P206D 0x206d -#define SMT_P206E 0x206e -#define SMT_P206F 0x206f -#define SMT_P2070 0x2070 -#define SMT_P2071 0x2071 -#define SMT_P2072 0x2072 -#define SMT_P2073 0x2073 -#define SMT_P2074 0x2074 -#define SMT_P2075 0x2075 -#define SMT_P2076 0x2076 - -#define SMT_P208C 0x208c -#define SMT_P208D 0x208d -#define SMT_P208E 0x208e -#define SMT_P208F 0x208f -#define SMT_P2090 0x2090 - -#define SMT_P20F0 0x20F0 -#define SMT_P20F1 0x20F1 - -#define SMT_P320A 0x320a -#define SMT_P320B 0x320b -#define SMT_P320C 0x320c -#define SMT_P320D 0x320d -#define SMT_P320E 0x320e -#define SMT_P320F 0x320f -#define SMT_P3210 0x3210 -#define SMT_P3211 0x3211 -#define SMT_P3212 0x3212 -#define SMT_P3213 0x3213 -#define SMT_P3214 0x3214 -#define SMT_P3215 0x3215 -#define SMT_P3216 0x3216 -#define SMT_P3217 0x3217 - -#define SMT_P400A 0x400a -#define SMT_P400B 0x400b -#define SMT_P400C 0x400c -#define SMT_P400D 0x400d -#define SMT_P400E 0x400e -#define SMT_P400F 0x400f -#define SMT_P4010 0x4010 -#define SMT_P4011 0x4011 -#define SMT_P4012 0x4012 -#define SMT_P4013 0x4013 -#define SMT_P4014 0x4014 -#define SMT_P4015 0x4015 -#define SMT_P4016 0x4016 -#define SMT_P4017 0x4017 -#define SMT_P4018 0x4018 -#define SMT_P4019 0x4019 -#define SMT_P401A 0x401a -#define SMT_P401B 0x401b -#define SMT_P401C 0x401c -#define SMT_P401D 0x401d -#define SMT_P401E 0x401e -#define SMT_P401F 0x401f -#define SMT_P4020 0x4020 -#define SMT_P4021 0x4021 -#define SMT_P4022 0x4022 -#define SMT_P4023 0x4023 -#define SMT_P4024 0x4024 -#define SMT_P4025 0x4025 -#define SMT_P4026 0x4026 -#define SMT_P4027 0x4027 -#define SMT_P4028 0x4028 -#define SMT_P4029 0x4029 -#define SMT_P402A 0x402a -#define SMT_P402B 0x402b -#define SMT_P402C 0x402c -#define SMT_P402D 0x402d -#define SMT_P402E 0x402e -#define SMT_P402F 0x402f -#define SMT_P4030 0x4030 -#define SMT_P4031 0x4031 -#define SMT_P4032 0x4032 -#define SMT_P4033 0x4033 -#define SMT_P4034 0x4034 -#define SMT_P4035 0x4035 -#define SMT_P4036 0x4036 -#define SMT_P4037 0x4037 -#define SMT_P4038 0x4038 -#define SMT_P4039 0x4039 -#define SMT_P403A 0x403a -#define SMT_P403B 0x403b -#define SMT_P403C 0x403c -#define SMT_P403D 0x403d -#define SMT_P403E 0x403e -#define SMT_P403F 0x403f -#define SMT_P4040 0x4040 -#define SMT_P4041 0x4041 -#define SMT_P4042 0x4042 -#define SMT_P4043 0x4043 -#define SMT_P4044 0x4044 -#define SMT_P4045 0x4045 -#define SMT_P4046 0x4046 - -#define SMT_P4050 0x4050 -#define SMT_P4051 0x4051 -#define SMT_P4052 0x4052 -#define SMT_P4053 0x4053 diff --git a/drivers/net/skfp/h/smtstate.h b/drivers/net/skfp/h/smtstate.h deleted file mode 100644 index 62fe695..0000000 --- a/drivers/net/skfp/h/smtstate.h +++ /dev/null @@ -1,106 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -#ifndef _SKFP_H_SMTSTATE_H_ -#define _SKFP_H_SMTSTATE_H_ - -/* - * SMT state definitions - */ - -#ifndef KERNEL -/* - * PCM states - */ -#define PC0_OFF 0 -#define PC1_BREAK 1 -#define PC2_TRACE 2 -#define PC3_CONNECT 3 -#define PC4_NEXT 4 -#define PC5_SIGNAL 5 -#define PC6_JOIN 6 -#define PC7_VERIFY 7 -#define PC8_ACTIVE 8 -#define PC9_MAINT 9 - -/* - * PCM modes - */ -#define PM_NONE 0 -#define PM_PEER 1 -#define PM_TREE 2 - -/* - * PCM type - */ -#define TA 0 -#define TB 1 -#define TS 2 -#define TM 3 -#define TNONE 4 - -/* - * CFM states - */ -#define SC0_ISOLATED 0 /* isolated */ -#define SC1_WRAP_A 5 /* wrap A */ -#define SC2_WRAP_B 6 /* wrap B */ -#define SC4_THRU_A 12 /* through A */ -#define SC5_THRU_B 7 /* through B (SMt 6.2) */ -#define SC7_WRAP_S 8 /* SAS */ - -/* - * ECM states - */ -#define EC0_OUT 0 -#define EC1_IN 1 -#define EC2_TRACE 2 -#define EC3_LEAVE 3 -#define EC4_PATH_TEST 4 -#define EC5_INSERT 5 -#define EC6_CHECK 6 -#define EC7_DEINSERT 7 - -/* - * RMT states - */ -#define RM0_ISOLATED 0 -#define RM1_NON_OP 1 /* not operational */ -#define RM2_RING_OP 2 /* ring operational */ -#define RM3_DETECT 3 /* detect dupl addresses */ -#define RM4_NON_OP_DUP 4 /* dupl. addr detected */ -#define RM5_RING_OP_DUP 5 /* ring oper. with dupl. addr */ -#define RM6_DIRECTED 6 /* sending directed beacons */ -#define RM7_TRACE 7 /* trace initiated */ -#endif - -struct pcm_state { - unsigned char pcm_type ; /* TA TB TS TM */ - unsigned char pcm_state ; /* state PC[0-9]_* */ - unsigned char pcm_mode ; /* PM_{NONE,PEER,TREE} */ - unsigned char pcm_neighbor ; /* TA TB TS TM */ - unsigned char pcm_bsf ; /* flag bs : TRUE/FALSE */ - unsigned char pcm_lsf ; /* flag ls : TRUE/FALSE */ - unsigned char pcm_lct_fail ; /* counter lct_fail */ - unsigned char pcm_ls_rx ; /* rx line state */ - short pcm_r_val ; /* signaling bits */ - short pcm_t_val ; /* signaling bits */ -} ; - -struct smt_state { - struct pcm_state pcm_state[NUMPHYS] ; /* port A & port B */ -} ; - -#endif - diff --git a/drivers/net/skfp/h/supern_2.h b/drivers/net/skfp/h/supern_2.h deleted file mode 100644 index 0b73690..0000000 --- a/drivers/net/skfp/h/supern_2.h +++ /dev/null @@ -1,1059 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - defines for AMD Supernet II chip set - the chips are referred to as - FPLUS Formac Plus - PLC Physical Layer - - added defines for AMD Supernet III chip set - added comments on differences between Supernet II and Supernet III - added defines for the Motorola ELM (MOT_ELM) -*/ - -#ifndef _SUPERNET_ -#define _SUPERNET_ - -/* - * Define Supernet 3 when used - */ -#ifdef PCI -#ifndef SUPERNET_3 -#define SUPERNET_3 -#endif -#define TAG -#endif - -#define MB 0xff -#define MW 0xffff -#define MD 0xffffffff - -/* - * FORMAC frame status (rx_msext) - */ -#define FS_EI (1<<2) -#define FS_AI (1<<1) -#define FS_CI (1<<0) - -#define FS_MSVALID (1<<15) /* end of queue */ -#define FS_MSRABT (1<<14) /* frame was aborted during reception*/ -#define FS_SSRCRTG (1<<12) /* if SA has set MSB (source-routing)*/ -#define FS_SEAC2 (FS_EI<<9) /* error indicator */ -#define FS_SEAC1 (FS_AI<<9) /* address indicator */ -#define FS_SEAC0 (FS_CI<<9) /* copy indicator */ -#define FS_SFRMERR (1<<8) /* error detected (CRC or length) */ -#define FS_SADRRG (1<<7) /* address recognized */ -#define FS_SFRMTY2 (1<<6) /* frame-class bit */ -#define FS_SFRMTY1 (1<<5) /* frame-type bit (impementor) */ -#define FS_SFRMTY0 (1<<4) /* frame-type bit (LLC) */ -#define FS_ERFBB1 (1<<1) /* byte offset (depends on LSB bit) */ -#define FS_ERFBB0 (1<<0) /* - " - */ - -/* - * status frame type - */ -#define FRM_SMT (0) /* asynchr. frames */ -#define FRM_LLCA (1) -#define FRM_IMPA (2) -#define FRM_MAC (4) /* synchr. frames */ -#define FRM_LLCS (5) -#define FRM_IMPS (6) - -/* - * bits in rx_descr.i (receive frame status word) - */ -#define RX_MSVALID ((long)1<<31) /* memory status valid */ -#define RX_MSRABT ((long)1<<30) /* memory status receive abort */ -#define RX_FS_E ((long)FS_SEAC2<<16) /* error indicator */ -#define RX_FS_A ((long)FS_SEAC1<<16) /* address indicator */ -#define RX_FS_C ((long)FS_SEAC0<<16) /* copy indicator */ -#define RX_FS_CRC ((long)FS_SFRMERR<<16)/* error detected */ -#define RX_FS_ADDRESS ((long)FS_SADRRG<<16) /* address recognized */ -#define RX_FS_MAC ((long)FS_SFRMTY2<<16)/* MAC frame */ -#define RX_FS_SMT ((long)0<<16) /* SMT frame */ -#define RX_FS_IMPL ((long)FS_SFRMTY1<<16)/* implementer frame */ -#define RX_FS_LLC ((long)FS_SFRMTY0<<16)/* LLC frame */ - -/* - * receive frame descriptor - */ -union rx_descr { - struct { -#ifdef LITTLE_ENDIAN - unsigned rx_length :16 ; /* frame length lower/upper byte */ - unsigned rx_erfbb :2 ; /* received frame byte boundary */ - unsigned rx_reserv2:2 ; /* reserved */ - unsigned rx_sfrmty :3 ; /* frame type bits */ - unsigned rx_sadrrg :1 ; /* DA == MA or broad-/multicast */ - unsigned rx_sfrmerr:1 ; /* received frame not valid */ - unsigned rx_seac0 :1 ; /* frame-copied C-indicator */ - unsigned rx_seac1 :1 ; /* address-match A-indicator */ - unsigned rx_seac2 :1 ; /* frame-error E-indicator */ - unsigned rx_ssrcrtg:1 ; /* == 1 SA has MSB set */ - unsigned rx_reserv1:1 ; /* reserved */ - unsigned rx_msrabt :1 ; /* memory status receive abort */ - unsigned rx_msvalid:1 ; /* memory status valid */ -#else - unsigned rx_msvalid:1 ; /* memory status valid */ - unsigned rx_msrabt :1 ; /* memory status receive abort */ - unsigned rx_reserv1:1 ; /* reserved */ - unsigned rx_ssrcrtg:1 ; /* == 1 SA has MSB set */ - unsigned rx_seac2 :1 ; /* frame-error E-indicator */ - unsigned rx_seac1 :1 ; /* address-match A-indicator */ - unsigned rx_seac0 :1 ; /* frame-copied C-indicator */ - unsigned rx_sfrmerr:1 ; /* received frame not valid */ - unsigned rx_sadrrg :1 ; /* DA == MA or broad-/multicast */ - unsigned rx_sfrmty :3 ; /* frame type bits */ - unsigned rx_erfbb :2 ; /* received frame byte boundary */ - unsigned rx_reserv2:2 ; /* reserved */ - unsigned rx_length :16 ; /* frame length lower/upper byte */ -#endif - } r ; - long i ; -} ; - -/* defines for Receive Frame Descriptor access */ -#define RD_S_ERFBB 0x00030000L /* received frame byte boundary */ -#define RD_S_RES2 0x000c0000L /* reserved */ -#define RD_S_SFRMTY 0x00700000L /* frame type bits */ -#define RD_S_SADRRG 0x00800000L /* DA == MA or broad-/multicast */ -#define RD_S_SFRMERR 0x01000000L /* received frame not valid */ -#define RD_S_SEAC 0x0e000000L /* frame status indicators */ -#define RD_S_SEAC0 0x02000000L /* frame-copied case-indicator */ -#define RD_S_SEAC1 0x04000000L /* address-match A-indicator */ -#define RD_S_SEAC2 0x08000000L /* frame-error E-indicator */ -#define RD_S_SSRCRTG 0x10000000L /* == 1 SA has MSB set */ -#define RD_S_RES1 0x20000000L /* reserved */ -#define RD_S_MSRABT 0x40000000L /* memory status receive abort */ -#define RD_S_MSVALID 0x80000000L /* memory status valid */ - -#define RD_STATUS 0xffff0000L -#define RD_LENGTH 0x0000ffffL - -/* defines for Receive Frames Status Word values */ -/*RD_S_SFRMTY*/ -#define RD_FRM_SMT (unsigned long)(0<<20) /* asynchr. frames */ -#define RD_FRM_LLCA (unsigned long)(1<<20) -#define RD_FRM_IMPA (unsigned long)(2<<20) -#define RD_FRM_MAC (unsigned long)(4<<20) /* synchr. frames */ -#define RD_FRM_LLCS (unsigned long)(5<<20) -#define RD_FRM_IMPS (unsigned long)(6<<20) - -#define TX_DESCRIPTOR 0x40000000L -#define TX_OFFSET_3 0x18000000L - -#define TXP1 2 - -/* - * transmit frame descriptor - */ -union tx_descr { - struct { -#ifdef LITTLE_ENDIAN - unsigned tx_length:16 ; /* frame length lower/upper byte */ - unsigned tx_res :8 ; /* reserved (bit 16..23) */ - unsigned tx_xmtabt:1 ; /* transmit abort */ - unsigned tx_nfcs :1 ; /* no frame check sequence */ - unsigned tx_xdone :1 ; /* give up token */ - unsigned tx_rpxm :2 ; /* byte offset */ - unsigned tx_pat1 :2 ; /* must be TXP1 */ - unsigned tx_more :1 ; /* more frame in chain */ -#else - unsigned tx_more :1 ; /* more frame in chain */ - unsigned tx_pat1 :2 ; /* must be TXP1 */ - unsigned tx_rpxm :2 ; /* byte offset */ - unsigned tx_xdone :1 ; /* give up token */ - unsigned tx_nfcs :1 ; /* no frame check sequence */ - unsigned tx_xmtabt:1 ; /* transmit abort */ - unsigned tx_res :8 ; /* reserved (bit 16..23) */ - unsigned tx_length:16 ; /* frame length lower/upper byte */ -#endif - } t ; - long i ; -} ; - -/* defines for Transmit Descriptor access */ -#define TD_C_MORE 0x80000000L /* more frame in chain */ -#define TD_C_DESCR 0x60000000L /* must be TXP1 */ -#define TD_C_TXFBB 0x18000000L /* byte offset */ -#define TD_C_XDONE 0x04000000L /* give up token */ -#define TD_C_NFCS 0x02000000L /* no frame check sequence */ -#define TD_C_XMTABT 0x01000000L /* transmit abort */ - -#define TD_C_LNCNU 0x0000ff00L -#define TD_C_LNCNL 0x000000ffL -#define TD_C_LNCN 0x0000ffffL /* frame length lower/upper byte */ - -/* - * transmit pointer - */ -union tx_pointer { - struct t { -#ifdef LITTLE_ENDIAN - unsigned tp_pointer:16 ; /* pointer to tx_descr (low/high) */ - unsigned tp_res :8 ; /* reserved (bit 16..23) */ - unsigned tp_pattern:8 ; /* fixed pattern (bit 24..31) */ -#else - unsigned tp_pattern:8 ; /* fixed pattern (bit 24..31) */ - unsigned tp_res :8 ; /* reserved (bit 16..23) */ - unsigned tp_pointer:16 ; /* pointer to tx_descr (low/high) */ -#endif - } t ; - long i ; -} ; - -/* defines for Nontag Mode Pointer access */ -#define TD_P_CNTRL 0xff000000L -#define TD_P_RPXU 0x0000ff00L -#define TD_P_RPXL 0x000000ffL -#define TD_P_RPX 0x0000ffffL - - -#define TX_PATTERN 0xa0 -#define TX_POINTER_END 0xa0000000L -#define TX_INT_PATTERN 0xa0000000L - -struct tx_queue { - struct tx_queue *tq_next ; - u_short tq_pack_offset ; /* offset buffer memory */ - u_char tq_pad[2] ; -} ; - -/* - defines for FORMAC Plus (Am79C830) -*/ - -/* - * FORMAC+ read/write (r/w) registers - */ -#define FM_CMDREG1 0x00 /* write command reg 1 instruction */ -#define FM_CMDREG2 0x01 /* write command reg 2 instruction */ -#define FM_ST1U 0x00 /* read upper 16-bit of status reg 1 */ -#define FM_ST1L 0x01 /* read lower 16-bit of status reg 1 */ -#define FM_ST2U 0x02 /* read upper 16-bit of status reg 2 */ -#define FM_ST2L 0x03 /* read lower 16-bit of status reg 2 */ -#define FM_IMSK1U 0x04 /* r/w upper 16-bit of IMSK 1 */ -#define FM_IMSK1L 0x05 /* r/w lower 16-bit of IMSK 1 */ -#define FM_IMSK2U 0x06 /* r/w upper 16-bit of IMSK 2 */ -#define FM_IMSK2L 0x07 /* r/w lower 16-bit of IMSK 2 */ -#define FM_SAID 0x08 /* r/w short addr.-individual */ -#define FM_LAIM 0x09 /* r/w long addr.-ind. (MSW of LAID) */ -#define FM_LAIC 0x0a /* r/w long addr.-ind. (middle)*/ -#define FM_LAIL 0x0b /* r/w long addr.-ind. (LSW) */ -#define FM_SAGP 0x0c /* r/w short address-group */ -#define FM_LAGM 0x0d /* r/w long addr.-gr. (MSW of LAGP) */ -#define FM_LAGC 0x0e /* r/w long addr.-gr. (middle) */ -#define FM_LAGL 0x0f /* r/w long addr.-gr. (LSW) */ -#define FM_MDREG1 0x10 /* r/w 16-bit mode reg 1 */ -#define FM_STMCHN 0x11 /* read state-machine reg */ -#define FM_MIR1 0x12 /* read upper 16-bit of MAC Info Reg */ -#define FM_MIR0 0x13 /* read lower 16-bit of MAC Info Reg */ -#define FM_TMAX 0x14 /* r/w 16-bit TMAX reg */ -#define FM_TVX 0x15 /* write 8-bit TVX reg with NP7-0 - read TVX on NP7-0, timer on NP15-8*/ -#define FM_TRT 0x16 /* r/w upper 16-bit of TRT timer */ -#define FM_THT 0x17 /* r/w upper 16-bit of THT timer */ -#define FM_TNEG 0x18 /* read upper 16-bit of TNEG (TTRT) */ -#define FM_TMRS 0x19 /* read lower 5-bit of TNEG,TRT,THT */ - /* F E D C B A 9 8 7 6 5 4 3 2 1 0 - x |-TNEG4-0| |-TRT4-0-| |-THT4-0-| (x-late count) */ -#define FM_TREQ0 0x1a /* r/w 16-bit TREQ0 reg (LSW of TRT) */ -#define FM_TREQ1 0x1b /* r/w 16-bit TREQ1 reg (MSW of TRT) */ -#define FM_PRI0 0x1c /* r/w priority r. for asyn.-queue 0 */ -#define FM_PRI1 0x1d /* r/w priority r. for asyn.-queue 1 */ -#define FM_PRI2 0x1e /* r/w priority r. for asyn.-queue 2 */ -#define FM_TSYNC 0x1f /* r/w 16-bit of the TSYNC register */ -#define FM_MDREG2 0x20 /* r/w 16-bit mode reg 2 */ -#define FM_FRMTHR 0x21 /* r/w the frame threshold register */ -#define FM_EACB 0x22 /* r/w end addr of claim/beacon area */ -#define FM_EARV 0x23 /* r/w end addr of receive queue */ -/* Supernet 3 */ -#define FM_EARV1 FM_EARV - -#define FM_EAS 0x24 /* r/w end addr of synchr. queue */ -#define FM_EAA0 0x25 /* r/w end addr of asyn. queue 0 */ -#define FM_EAA1 0x26 /* r/w end addr of asyn. queue 1 */ -#define FM_EAA2 0x27 /* r/w end addr of asyn. queue 2 */ -#define FM_SACL 0x28 /* r/w start addr of claim frame */ -#define FM_SABC 0x29 /* r/w start addr of beacon frame */ -#define FM_WPXSF 0x2a /* r/w the write ptr. for special fr.*/ -#define FM_RPXSF 0x2b /* r/w the read ptr. for special fr. */ -#define FM_RPR 0x2d /* r/w the read ptr. for receive qu. */ -#define FM_WPR 0x2e /* r/w the write ptr. for receive qu.*/ -#define FM_SWPR 0x2f /* r/w the shadow wr.-ptr. for rec.q.*/ -/* Supernet 3 */ -#define FM_RPR1 FM_RPR -#define FM_WPR1 FM_WPR -#define FM_SWPR1 FM_SWPR - -#define FM_WPXS 0x30 /* r/w the write ptr. for synchr. qu.*/ -#define FM_WPXA0 0x31 /* r/w the write ptr. for asyn. qu.0 */ -#define FM_WPXA1 0x32 /* r/w the write ptr. for asyn. qu.1 */ -#define FM_WPXA2 0x33 /* r/w the write ptr. for asyn. qu.2 */ -#define FM_SWPXS 0x34 /* r/w the shadow wr.-ptr. for syn.q.*/ -#define FM_SWPXA0 0x35 /* r/w the shad. wr.-ptr. for asyn.q0*/ -#define FM_SWPXA1 0x36 /* r/w the shad. wr.-ptr. for asyn.q1*/ -#define FM_SWPXA2 0x37 /* r/w the shad. wr.-ptr. for asyn.q2*/ -#define FM_RPXS 0x38 /* r/w the read ptr. for synchr. qu. */ -#define FM_RPXA0 0x39 /* r/w the read ptr. for asyn. qu. 0 */ -#define FM_RPXA1 0x3a /* r/w the read ptr. for asyn. qu. 1 */ -#define FM_RPXA2 0x3b /* r/w the read ptr. for asyn. qu. 2 */ -#define FM_MARR 0x3c /* r/w the memory read addr register */ -#define FM_MARW 0x3d /* r/w the memory write addr register*/ -#define FM_MDRU 0x3e /* r/w upper 16-bit of mem. data reg */ -#define FM_MDRL 0x3f /* r/w lower 16-bit of mem. data reg */ - -/* following instructions relate to MAC counters and timer */ -#define FM_TMSYNC 0x40 /* r/w upper 16 bits of TMSYNC timer */ -#define FM_FCNTR 0x41 /* r/w the 16-bit frame counter */ -#define FM_LCNTR 0x42 /* r/w the 16-bit lost counter */ -#define FM_ECNTR 0x43 /* r/w the 16-bit error counter */ - -/* Supernet 3: extensions to old register block */ -#define FM_FSCNTR 0x44 /* r/? Frame Strip Counter */ -#define FM_FRSELREG 0x45 /* r/w Frame Selection Register */ - -/* Supernet 3: extensions for 2. receive queue etc. */ -#define FM_MDREG3 0x60 /* r/w Mode Register 3 */ -#define FM_ST3U 0x61 /* read upper 16-bit of status reg 3 */ -#define FM_ST3L 0x62 /* read lower 16-bit of status reg 3 */ -#define FM_IMSK3U 0x63 /* r/w upper 16-bit of IMSK reg 3 */ -#define FM_IMSK3L 0x64 /* r/w lower 16-bit of IMSK reg 3 */ -#define FM_IVR 0x65 /* read Interrupt Vector register */ -#define FM_IMR 0x66 /* r/w Interrupt mask register */ -/* 0x67 Hidden */ -#define FM_RPR2 0x68 /* r/w the read ptr. for rec. qu. 2 */ -#define FM_WPR2 0x69 /* r/w the write ptr. for rec. qu. 2 */ -#define FM_SWPR2 0x6a /* r/w the shadow wptr. for rec. q. 2 */ -#define FM_EARV2 0x6b /* r/w end addr of rec. qu. 2 */ -#define FM_UNLCKDLY 0x6c /* r/w Auto Unlock Delay register */ - /* Bit 15-8: RECV2 unlock threshold */ - /* Bit 7-0: RECV1 unlock threshold */ -/* 0x6f-0x73 Hidden */ -#define FM_LTDPA1 0x79 /* r/w Last Trans desc ptr for A1 qu. */ -/* 0x80-0x9a PLCS registers of built-in PLCS (Supernet 3 only) */ - -/* Supernet 3: Adderss Filter Registers */ -#define FM_AFCMD 0xb0 /* r/w Address Filter Command Reg */ -#define FM_AFSTAT 0xb2 /* r/w Address Filter Status Reg */ -#define FM_AFBIST 0xb4 /* r/w Address Filter BIST signature */ -#define FM_AFCOMP2 0xb6 /* r/w Address Filter Comparand 2 */ -#define FM_AFCOMP1 0xb8 /* r/w Address Filter Comparand 1 */ -#define FM_AFCOMP0 0xba /* r/w Address Filter Comparand 0 */ -#define FM_AFMASK2 0xbc /* r/w Address Filter Mask 2 */ -#define FM_AFMASK1 0xbe /* r/w Address Filter Mask 1 */ -#define FM_AFMASK0 0xc0 /* r/w Address Filter Mask 0 */ -#define FM_AFPERS 0xc2 /* r/w Address Filter Personality Reg */ - -/* Supernet 3: Orion (PDX?) Registers */ -#define FM_ORBIST 0xd0 /* r/w Orion BIST signature */ -#define FM_ORSTAT 0xd2 /* r/w Orion Status Register */ - - -/* - * Mode Register 1 (MDREG1) - */ -#define FM_RES0 0x0001 /* reserved */ - /* SN3: other definition */ -#define FM_XMTINH_HOLD 0x0002 /* transmit-inhibit/hold bit */ - /* SN3: other definition */ -#define FM_HOFLXI 0x0003 /* SN3: Hold / Flush / Inhibit */ -#define FM_FULL_HALF 0x0004 /* full-duplex/half-duplex bit */ -#define FM_LOCKTX 0x0008 /* lock-transmit-asynchr.-queues bit */ -#define FM_EXGPA0 0x0010 /* extended-group-addressing bit 0 */ -#define FM_EXGPA1 0x0020 /* extended-group-addressing bit 1 */ -#define FM_DISCRY 0x0040 /* disable-carry bit */ - /* SN3: reserved */ -#define FM_SELRA 0x0080 /* select input from PHY (1=RA,0=RB) */ - -#define FM_ADDET 0x0700 /* address detection */ -#define FM_MDAMA (0<<8) /* address detection : DA = MA */ -#define FM_MDASAMA (1<<8) /* address detection : DA=MA||SA=MA */ -#define FM_MRNNSAFNMA (2<<8) /* rec. non-NSA frames DA=MA&&SA!=MA */ -#define FM_MRNNSAF (3<<8) /* rec. non-NSA frames DA = MA */ -#define FM_MDISRCV (4<<8) /* disable receive function */ -#define FM_MRES0 (5<<8) /* reserve */ -#define FM_MLIMPROM (6<<8) /* limited-promiscuous mode */ -#define FM_MPROMISCOUS (7<<8) /* address detection : promiscuous */ - -#define FM_SELSA 0x0800 /* select-short-address bit */ - -#define FM_MMODE 0x7000 /* mode select */ -#define FM_MINIT (0<<12) /* initialize */ -#define FM_MMEMACT (1<<12) /* memory activate */ -#define FM_MONLINESP (2<<12) /* on-line special */ -#define FM_MONLINE (3<<12) /* on-line (FDDI operational mode) */ -#define FM_MILOOP (4<<12) /* internal loopback */ -#define FM_MRES1 (5<<12) /* reserved */ -#define FM_MRES2 (6<<12) /* reserved */ -#define FM_MELOOP (7<<12) /* external loopback */ - -#define FM_SNGLFRM 0x8000 /* single-frame-receive mode */ - /* SN3: reserved */ - -#define MDR1INIT (FM_MINIT | FM_MDAMA) - -/* - * Mode Register 2 (MDREG2) - */ -#define FM_AFULL 0x000f /* 4-bit value (empty loc.in txqueue)*/ -#define FM_RCVERR 0x0010 /* rec.-errored-frames bit */ -#define FM_SYMCTL 0x0020 /* sysmbol-control bit */ - /* SN3: reserved */ -#define FM_SYNPRQ 0x0040 /* synchron.-NP-DMA-request bit */ -#define FM_ENNPRQ 0x0080 /* enable-NP-DMA-request bit */ -#define FM_ENHSRQ 0x0100 /* enable-host-request bit */ -#define FM_RXFBB01 0x0600 /* rec. frame byte boundary bit0 & 1 */ -#define FM_LSB 0x0800 /* determ. ordering of bytes in buffer*/ -#define FM_PARITY 0x1000 /* 1 = even, 0 = odd */ -#define FM_CHKPAR 0x2000 /* 1 = parity of 32-bit buffer BD-bus*/ -#define FM_STRPFCS 0x4000 /* 1 = strips FCS field of rec.frame */ -#define FM_BMMODE 0x8000 /* Buffer-Memory-Mode (1 = tag mode) */ - /* SN3: 1 = tag, 0 = modified tag */ - -/* - * Status Register 1, Upper 16 Bits (ST1U) - */ -#define FM_STEFRMS 0x0001 /* transmit end of frame: synchr. qu.*/ -#define FM_STEFRMA0 0x0002 /* transmit end of frame: asyn. qu.0 */ -#define FM_STEFRMA1 0x0004 /* transmit end of frame: asyn. qu.1 */ -#define FM_STEFRMA2 0x0008 /* transmit end of frame: asyn. qu.2 */ - /* SN3: reserved */ -#define FM_STECFRMS 0x0010 /* transmit end of chain of syn. qu. */ - /* SN3: reserved */ -#define FM_STECFRMA0 0x0020 /* transmit end of chain of asyn. q0 */ - /* SN3: reserved */ -#define FM_STECFRMA1 0x0040 /* transmit end of chain of asyn. q1 */ - /* SN3: STECMDA1 */ -#define FM_STECMDA1 0x0040 /* SN3: 'no description' */ -#define FM_STECFRMA2 0x0080 /* transmit end of chain of asyn. q2 */ - /* SN3: reserved */ -#define FM_STEXDONS 0x0100 /* transmit until XDONE in syn. qu. */ -#define FM_STBFLA 0x0200 /* asynchr.-queue trans. buffer full */ -#define FM_STBFLS 0x0400 /* synchr.-queue transm. buffer full */ -#define FM_STXABRS 0x0800 /* synchr. queue transmit-abort */ -#define FM_STXABRA0 0x1000 /* asynchr. queue 0 transmit-abort */ -#define FM_STXABRA1 0x2000 /* asynchr. queue 1 transmit-abort */ -#define FM_STXABRA2 0x4000 /* asynchr. queue 2 transmit-abort */ - /* SN3: reserved */ -#define FM_SXMTABT 0x8000 /* transmit abort */ - -/* - * Status Register 1, Lower 16 Bits (ST1L) - */ -#define FM_SQLCKS 0x0001 /* queue lock for synchr. queue */ -#define FM_SQLCKA0 0x0002 /* queue lock for asynchr. queue 0 */ -#define FM_SQLCKA1 0x0004 /* queue lock for asynchr. queue 1 */ -#define FM_SQLCKA2 0x0008 /* queue lock for asynchr. queue 2 */ - /* SN3: reserved */ -#define FM_STXINFLS 0x0010 /* transmit instruction full: syn. */ - /* SN3: reserved */ -#define FM_STXINFLA0 0x0020 /* transmit instruction full: asyn.0 */ - /* SN3: reserved */ -#define FM_STXINFLA1 0x0040 /* transmit instruction full: asyn.1 */ - /* SN3: reserved */ -#define FM_STXINFLA2 0x0080 /* transmit instruction full: asyn.2 */ - /* SN3: reserved */ -#define FM_SPCEPDS 0x0100 /* parity/coding error: syn. queue */ -#define FM_SPCEPDA0 0x0200 /* parity/coding error: asyn. queue0 */ -#define FM_SPCEPDA1 0x0400 /* parity/coding error: asyn. queue1 */ -#define FM_SPCEPDA2 0x0800 /* parity/coding error: asyn. queue2 */ - /* SN3: reserved */ -#define FM_STBURS 0x1000 /* transmit buffer underrun: syn. q. */ -#define FM_STBURA0 0x2000 /* transmit buffer underrun: asyn.0 */ -#define FM_STBURA1 0x4000 /* transmit buffer underrun: asyn.1 */ -#define FM_STBURA2 0x8000 /* transmit buffer underrun: asyn.2 */ - /* SN3: reserved */ - -/* - * Status Register 2, Upper 16 Bits (ST2U) - */ -#define FM_SOTRBEC 0x0001 /* other beacon received */ -#define FM_SMYBEC 0x0002 /* my beacon received */ -#define FM_SBEC 0x0004 /* beacon state entered */ -#define FM_SLOCLM 0x0008 /* low claim received */ -#define FM_SHICLM 0x0010 /* high claim received */ -#define FM_SMYCLM 0x0020 /* my claim received */ -#define FM_SCLM 0x0040 /* claim state entered */ -#define FM_SERRSF 0x0080 /* error in special frame */ -#define FM_SNFSLD 0x0100 /* NP and FORMAC+ simultaneous load */ -#define FM_SRFRCTOV 0x0200 /* receive frame counter overflow */ - /* SN3: reserved */ -#define FM_SRCVFRM 0x0400 /* receive frame */ - /* SN3: reserved */ -#define FM_SRCVOVR 0x0800 /* receive FIFO overflow */ -#define FM_SRBFL 0x1000 /* receive buffer full */ -#define FM_SRABT 0x2000 /* receive abort */ -#define FM_SRBMT 0x4000 /* receive buffer empty */ -#define FM_SRCOMP 0x8000 /* receive complete. Nontag mode */ - -/* - * Status Register 2, Lower 16 Bits (ST2L) - * Attention: SN3 docu shows these bits the other way around - */ -#define FM_SRES0 0x0001 /* reserved */ -#define FM_SESTRIPTK 0x0001 /* SN3: 'no description' */ -#define FM_STRTEXR 0x0002 /* TRT expired in claim | beacon st. */ -#define FM_SDUPCLM 0x0004 /* duplicate claim received */ -#define FM_SSIFG 0x0008 /* short interframe gap */ -#define FM_SFRMCTR 0x0010 /* frame counter overflow */ -#define FM_SERRCTR 0x0020 /* error counter overflow */ -#define FM_SLSTCTR 0x0040 /* lost counter overflow */ -#define FM_SPHINV 0x0080 /* PHY invalid */ -#define FM_SADET 0x0100 /* address detect */ -#define FM_SMISFRM 0x0200 /* missed frame */ -#define FM_STRTEXP 0x0400 /* TRT expired and late count > 0 */ -#define FM_STVXEXP 0x0800 /* TVX expired */ -#define FM_STKISS 0x1000 /* token issued */ -#define FM_STKERR 0x2000 /* token error */ -#define FM_SMULTDA 0x4000 /* multiple destination address */ -#define FM_SRNGOP 0x8000 /* ring operational */ - -/* - * Supernet 3: - * Status Register 3, Upper 16 Bits (ST3U) - */ -#define FM_SRQUNLCK1 0x0001 /* receive queue unlocked queue 1 */ -#define FM_SRQUNLCK2 0x0002 /* receive queue unlocked queue 2 */ -#define FM_SRPERRQ1 0x0004 /* receive parity error rx queue 1 */ -#define FM_SRPERRQ2 0x0008 /* receive parity error rx queue 2 */ - /* Bit 4-10: reserved */ -#define FM_SRCVOVR2 0x0800 /* receive FIFO overfull rx queue 2 */ -#define FM_SRBFL2 0x1000 /* receive buffer full rx queue 2 */ -#define FM_SRABT2 0x2000 /* receive abort rx queue 2 */ -#define FM_SRBMT2 0x4000 /* receive buf empty rx queue 2 */ -#define FM_SRCOMP2 0x8000 /* receive comp rx queue 2 */ - -/* - * Supernet 3: - * Status Register 3, Lower 16 Bits (ST3L) - */ -#define FM_AF_BIST_DONE 0x0001 /* Address Filter BIST is done */ -#define FM_PLC_BIST_DONE 0x0002 /* internal PLC Bist is done */ -#define FM_PDX_BIST_DONE 0x0004 /* PDX BIST is done */ - /* Bit 3: reserved */ -#define FM_SICAMDAMAT 0x0010 /* Status internal CAM DA match */ -#define FM_SICAMDAXACT 0x0020 /* Status internal CAM DA exact match */ -#define FM_SICAMSAMAT 0x0040 /* Status internal CAM SA match */ -#define FM_SICAMSAXACT 0x0080 /* Status internal CAM SA exact match */ - -/* - * MAC State-Machine Register FM_STMCHN - */ -#define FM_MDRTAG 0x0004 /* tag bit of long word read */ -#define FM_SNPPND 0x0008 /* r/w from buffer mem. is pending */ -#define FM_TXSTAT 0x0070 /* transmitter state machine state */ -#define FM_RCSTAT 0x0380 /* receiver state machine state */ -#define FM_TM01 0x0c00 /* indicate token mode */ -#define FM_SIM 0x1000 /* indicate send immediate-mode */ -#define FM_REV 0xe000 /* FORMAC Plus revision number */ - -/* - * Supernet 3 - * Mode Register 3 - */ -#define FM_MENRS 0x0001 /* Ena enhanced rec status encoding */ -#define FM_MENXS 0x0002 /* Ena enhanced xmit status encoding */ -#define FM_MENXCT 0x0004 /* Ena EXACT/INEXACT matching */ -#define FM_MENAFULL 0x0008 /* Ena enh QCTRL encoding for AFULL */ -#define FM_MEIND 0x0030 /* Ena enh A,C indicator settings */ -#define FM_MENQCTRL 0x0040 /* Ena enh QCTRL encoding */ -#define FM_MENRQAUNLCK 0x0080 /* Ena rec q auto unlock */ -#define FM_MENDAS 0x0100 /* Ena DAS connections by cntr MUX */ -#define FM_MENPLCCST 0x0200 /* Ena Counter Segm test in PLC blck */ -#define FM_MENSGLINT 0x0400 /* Ena Vectored Interrupt reading */ -#define FM_MENDRCV 0x0800 /* Ena dual receive queue operation */ -#define FM_MENFCLOC 0x3000 /* Ena FC location within frm data */ -#define FM_MENTRCMD 0x4000 /* Ena ASYNC1 xmit only after command */ -#define FM_MENTDLPBK 0x8000 /* Ena TDAT to RDAT lkoopback */ - -/* - * Supernet 3 - * Frame Selection Register - */ -#define FM_RECV1 0x000f /* options for receive queue 1 */ -#define FM_RCV1_ALL (0<<0) /* receive all frames */ -#define FM_RCV1_LLC (1<<0) /* rec all LLC frames */ -#define FM_RCV1_SMT (2<<0) /* rec all SMT frames */ -#define FM_RCV1_NSMT (3<<0) /* rec non-SMT frames */ -#define FM_RCV1_IMP (4<<0) /* rec Implementor frames */ -#define FM_RCV1_MAC (5<<0) /* rec all MAC frames */ -#define FM_RCV1_SLLC (6<<0) /* rec all sync LLC frames */ -#define FM_RCV1_ALLC (7<<0) /* rec all async LLC frames */ -#define FM_RCV1_VOID (8<<0) /* rec all void frames */ -#define FM_RCV1_ALSMT (9<<0) /* rec all async LLC & SMT frames */ -#define FM_RECV2 0x00f0 /* options for receive queue 2 */ -#define FM_RCV2_ALL (0<<4) /* receive all other frames */ -#define FM_RCV2_LLC (1<<4) /* rec all LLC frames */ -#define FM_RCV2_SMT (2<<4) /* rec all SMT frames */ -#define FM_RCV2_NSMT (3<<4) /* rec non-SMT frames */ -#define FM_RCV2_IMP (4<<4) /* rec Implementor frames */ -#define FM_RCV2_MAC (5<<4) /* rec all MAC frames */ -#define FM_RCV2_SLLC (6<<4) /* rec all sync LLC frames */ -#define FM_RCV2_ALLC (7<<4) /* rec all async LLC frames */ -#define FM_RCV2_VOID (8<<4) /* rec all void frames */ -#define FM_RCV2_ALSMT (9<<4) /* rec all async LLC & SMT frames */ -#define FM_ENXMTADSWAP 0x4000 /* enh rec addr swap (phys -> can) */ -#define FM_ENRCVADSWAP 0x8000 /* enh tx addr swap (can -> phys) */ - -/* - * Supernet 3: - * Address Filter Command Register (AFCMD) - */ -#define FM_INST 0x0007 /* Address Filter Operation */ -#define FM_IINV_CAM (0<<0) /* Invalidate CAM */ -#define FM_IWRITE_CAM (1<<0) /* Write CAM */ -#define FM_IREAD_CAM (2<<0) /* Read CAM */ -#define FM_IRUN_BIST (3<<0) /* Run BIST */ -#define FM_IFIND (4<<0) /* Find */ -#define FM_IINV (5<<0) /* Invalidate */ -#define FM_ISKIP (6<<0) /* Skip */ -#define FM_ICL_SKIP (7<<0) /* Clear all SKIP bits */ - -/* - * Supernet 3: - * Address Filter Status Register (AFSTAT) - */ - /* Bit 0-4: reserved */ -#define FM_REV_NO 0x00e0 /* Revision Number of Address Filter */ -#define FM_BIST_DONE 0x0100 /* BIST complete */ -#define FM_EMPTY 0x0200 /* CAM empty */ -#define FM_ERROR 0x0400 /* Error (improper operation) */ -#define FM_MULT 0x0800 /* Multiple Match */ -#define FM_EXACT 0x1000 /* Exact Match */ -#define FM_FOUND 0x2000 /* Comparand found in CAM */ -#define FM_FULL 0x4000 /* CAM full */ -#define FM_DONE 0x8000 /* DONE indicator */ - -/* - * Supernet 3: - * BIST Signature Register (AFBIST) - */ -#define AF_BIST_SIGNAT 0x0553 /* Address Filter BIST Signature */ - -/* - * Supernet 3: - * Personality Register (AFPERS) - */ -#define FM_VALID 0x0001 /* CAM Entry Valid */ -#define FM_DA 0x0002 /* Destination Address */ -#define FM_DAX 0x0004 /* Destination Address Exact */ -#define FM_SA 0x0008 /* Source Address */ -#define FM_SAX 0x0010 /* Source Address Exact */ -#define FM_SKIP 0x0020 /* Skip this entry */ - -/* - * instruction set for command register 1 (NPADDR6-0 = 0x00) - */ -#define FM_IRESET 0x01 /* software reset */ -#define FM_IRMEMWI 0x02 /* load Memory Data Reg., inc MARR */ -#define FM_IRMEMWO 0x03 /* load MDR from buffer memory, n.i. */ -#define FM_IIL 0x04 /* idle/listen */ -#define FM_ICL 0x05 /* claim/listen */ -#define FM_IBL 0x06 /* beacon/listen */ -#define FM_ILTVX 0x07 /* load TVX timer from TVX reg */ -#define FM_INRTM 0x08 /* nonrestricted token mode */ -#define FM_IENTM 0x09 /* enter nonrestricted token mode */ -#define FM_IERTM 0x0a /* enter restricted token mode */ -#define FM_IRTM 0x0b /* restricted token mode */ -#define FM_ISURT 0x0c /* send unrestricted token */ -#define FM_ISRT 0x0d /* send restricted token */ -#define FM_ISIM 0x0e /* enter send-immediate mode */ -#define FM_IESIM 0x0f /* exit send-immediate mode */ -#define FM_ICLLS 0x11 /* clear synchronous queue lock */ -#define FM_ICLLA0 0x12 /* clear asynchronous queue 0 lock */ -#define FM_ICLLA1 0x14 /* clear asynchronous queue 1 lock */ -#define FM_ICLLA2 0x18 /* clear asynchronous queue 2 lock */ - /* SN3: reserved */ -#define FM_ICLLR 0x20 /* clear receive queue (SN3:1) lock */ -#define FM_ICLLR2 0x21 /* SN3: clear receive queue 2 lock */ -#define FM_ITRXBUS 0x22 /* SN3: Tristate X-Bus (SAS only) */ -#define FM_IDRXBUS 0x23 /* SN3: drive X-Bus */ -#define FM_ICLLAL 0x3f /* clear all queue locks */ - -/* - * instruction set for command register 2 (NPADDR6-0 = 0x01) - */ -#define FM_ITRS 0x01 /* transmit synchronous queue */ - /* SN3: reserved */ -#define FM_ITRA0 0x02 /* transmit asynchronous queue 0 */ - /* SN3: reserved */ -#define FM_ITRA1 0x04 /* transmit asynchronous queue 1 */ - /* SN3: reserved */ -#define FM_ITRA2 0x08 /* transmit asynchronous queue 2 */ - /* SN3: reserved */ -#define FM_IACTR 0x10 /* abort current transmit activity */ -#define FM_IRSTQ 0x20 /* reset transmit queues */ -#define FM_ISTTB 0x30 /* set tag bit */ -#define FM_IERSF 0x40 /* enable receive single frame */ - /* SN3: reserved */ -#define FM_ITR 0x50 /* SN3: Transmit Command */ - - -/* - * defines for PLC (Am79C864) - */ - -/* - * PLC read/write (r/w) registers - */ -#define PL_CNTRL_A 0x00 /* control register A (r/w) */ -#define PL_CNTRL_B 0x01 /* control register B (r/w) */ -#define PL_INTR_MASK 0x02 /* interrupt mask (r/w) */ -#define PL_XMIT_VECTOR 0x03 /* transmit vector register (r/w) */ -#define PL_VECTOR_LEN 0x04 /* transmit vector length (r/w) */ -#define PL_LE_THRESHOLD 0x05 /* link error event threshold (r/w) */ -#define PL_C_MIN 0x06 /* minimum connect state time (r/w) */ -#define PL_TL_MIN 0x07 /* min. line state transmit t. (r/w) */ -#define PL_TB_MIN 0x08 /* minimum break time (r/w) */ -#define PL_T_OUT 0x09 /* signal timeout (r/w) */ -#define PL_CNTRL_C 0x0a /* control register C (r/w) */ -#define PL_LC_LENGTH 0x0b /* link confidence test time (r/w) */ -#define PL_T_SCRUB 0x0c /* scrub time = MAC TVX (r/w) */ -#define PL_NS_MAX 0x0d /* max. noise time before break (r/w)*/ -#define PL_TPC_LOAD_V 0x0e /* TPC timer load value (write only) */ -#define PL_TNE_LOAD_V 0x0f /* TNE timer load value (write only) */ -#define PL_STATUS_A 0x10 /* status register A (read only) */ -#define PL_STATUS_B 0x11 /* status register B (read only) */ -#define PL_TPC 0x12 /* timer for PCM (ro) [20.48 us] */ -#define PL_TNE 0x13 /* time of noise event [0.32 us] */ -#define PL_CLK_DIV 0x14 /* TNE clock divider (read only) */ -#define PL_BIST_SIGNAT 0x15 /* built in self test signature (ro)*/ -#define PL_RCV_VECTOR 0x16 /* receive vector reg. (read only) */ -#define PL_INTR_EVENT 0x17 /* interrupt event reg. (read only) */ -#define PL_VIOL_SYM_CTR 0x18 /* violation symbol count. (read o) */ -#define PL_MIN_IDLE_CTR 0x19 /* minimum idle counter (read only) */ -#define PL_LINK_ERR_CTR 0x1a /* link error event ctr.(read only) */ -#ifdef MOT_ELM -#define PL_T_FOT_ASS 0x1e /* FOTOFF Assert Timer */ -#define PL_T_FOT_DEASS 0x1f /* FOTOFF Deassert Timer */ -#endif /* MOT_ELM */ - -#ifdef MOT_ELM -/* - * Special Quad-Elm Registers. - * A Quad-ELM consists of for ELMs and these additional registers. - */ -#define QELM_XBAR_W 0x80 /* Crossbar Control ELM W */ -#define QELM_XBAR_X 0x81 /* Crossbar Control ELM X */ -#define QELM_XBAR_Y 0x82 /* Crossbar Control ELM Y */ -#define QELM_XBAR_Z 0x83 /* Crossbar Control ELM Z */ -#define QELM_XBAR_P 0x84 /* Crossbar Control Bus P */ -#define QELM_XBAR_S 0x85 /* Crossbar Control Bus S */ -#define QELM_XBAR_R 0x86 /* Crossbar Control Bus R */ -#define QELM_WR_XBAR 0x87 /* Write the Crossbar now (write) */ -#define QELM_CTR_W 0x88 /* Counter W */ -#define QELM_CTR_X 0x89 /* Counter X */ -#define QELM_CTR_Y 0x8a /* Counter Y */ -#define QELM_CTR_Z 0x8b /* Counter Z */ -#define QELM_INT_MASK 0x8c /* Interrupt mask register */ -#define QELM_INT_DATA 0x8d /* Interrupt data (event) register */ -#define QELM_ELMB 0x00 /* Elm base */ -#define QELM_ELM_SIZE 0x20 /* ELM size */ -#endif /* MOT_ELM */ -/* - * PLC control register A (PL_CNTRL_A: log. addr. 0x00) - * It is used for timer configuration, specification of PCM MAINT state option, - * counter interrupt frequency, PLC data path config. and Built In Self Test. - */ -#define PL_RUN_BIST 0x0001 /* begin running its Built In Self T.*/ -#define PL_RF_DISABLE 0x0002 /* disable the Repeat Filter state m.*/ -#define PL_SC_REM_LOOP 0x0004 /* remote loopback path */ -#define PL_SC_BYPASS 0x0008 /* by providing a physical bypass */ -#define PL_LM_LOC_LOOP 0x0010 /* loop path just after elastic buff.*/ -#define PL_EB_LOC_LOOP 0x0020 /* loop path just prior to PDT/PDR IF*/ -#define PL_FOT_OFF 0x0040 /* assertion of /FOTOFF pin of PLC */ -#define PL_LOOPBACK 0x0080 /* it cause the /LPBCK pin ass. low */ -#define PL_MINI_CTR_INT 0x0100 /* partially contr. when bit is ass. */ -#define PL_VSYM_CTR_INT 0x0200 /* controls when int bit is asserted */ -#define PL_ENA_PAR_CHK 0x0400 /* enable parity check */ -#define PL_REQ_SCRUB 0x0800 /* limited access to scrub capability*/ -#define PL_TPC_16BIT 0x1000 /* causes the TPC as a 16 bit timer */ -#define PL_TNE_16BIT 0x2000 /* causes the TNE as a 16 bit timer */ -#define PL_NOISE_TIMER 0x4000 /* allows the noise timing function */ - -/* - * PLC control register B (PL_CNTRL_B: log. addr. 0x01) - * It contains signals and requeste to direct the process of PCM and it is also - * used to control the Line State Match interrupt. - */ -#define PL_PCM_CNTRL 0x0003 /* control PCM state machine */ -#define PL_PCM_NAF (0) /* state is not affected */ -#define PL_PCM_START (1) /* goes to the BREAK state */ -#define PL_PCM_TRACE (2) /* goes to the TRACE state */ -#define PL_PCM_STOP (3) /* goes to the OFF state */ - -#define PL_MAINT 0x0004 /* if OFF state --> MAINT state */ -#define PL_LONG 0x0008 /* perf. a long Link Confid.Test(LCT)*/ -#define PL_PC_JOIN 0x0010 /* if NEXT state --> JOIN state */ - -#define PL_PC_LOOP 0x0060 /* loopback used in the LCT */ -#define PL_NOLCT (0<<5) /* no LCT is performed */ -#define PL_TPDR (1<<5) /* PCM asserts transmit PDR */ -#define PL_TIDLE (2<<5) /* PCM asserts transmit idle */ -#define PL_RLBP (3<<5) /* trans. PDR & remote loopb. path */ - -#define PL_CLASS_S 0x0080 /* signif. that single att. station */ - -#define PL_MAINT_LS 0x0700 /* line state while in the MAINT st. */ -#define PL_M_QUI0 (0<<8) /* transmit QUIET line state */ -#define PL_M_IDLE (1<<8) /* transmit IDLE line state */ -#define PL_M_HALT (2<<8) /* transmit HALT line state */ -#define PL_M_MASTR (3<<8) /* transmit MASTER line state */ -#define PL_M_QUI1 (4<<8) /* transmit QUIET line state */ -#define PL_M_QUI2 (5<<8) /* transmit QUIET line state */ -#define PL_M_TPDR (6<<8) /* tr. PHY_DATA requ.-symbol is tr.ed*/ -#define PL_M_QUI3 (7<<8) /* transmit QUIET line state */ - -#define PL_MATCH_LS 0x7800 /* line state to be comp. with curr.*/ -#define PL_I_ANY (0<<11) /* Int. on any change in *_LINE_ST */ -#define PL_I_IDLE (1<<11) /* Interrupt on IDLE line state */ -#define PL_I_HALT (2<<11) /* Interrupt on HALT line state */ -#define PL_I_MASTR (4<<11) /* Interrupt on MASTER line state */ -#define PL_I_QUIET (8<<11) /* Interrupt on QUIET line state */ - -#define PL_CONFIG_CNTRL 0x8000 /* control over scrub, byp. & loopb.*/ - -/* - * PLC control register C (PL_CNTRL_C: log. addr. 0x0a) - * It contains the scrambling control registers (PLC-S only) - */ -#define PL_C_CIPHER_ENABLE (1<<0) /* enable scrambler */ -#define PL_C_CIPHER_LPBCK (1<<1) /* loopback scrambler */ -#define PL_C_SDOFF_ENABLE (1<<6) /* enable SDOFF timer */ -#define PL_C_SDON_ENABLE (1<<7) /* enable SDON timer */ -#ifdef MOT_ELM -#define PL_C_FOTOFF_CTRL (3<<2) /* FOTOFF timer control */ -#define PL_C_FOTOFF_TIM (0<<2) /* FOTOFF use timer for (de)-assert */ -#define PL_C_FOTOFF_INA (2<<2) /* FOTOFF forced inactive */ -#define PL_C_FOTOFF_ACT (3<<2) /* FOTOFF forced active */ -#define PL_C_FOTOFF_SRCE (1<<4) /* FOTOFF source is PCM state != OFF */ -#define PL_C_RXDATA_EN (1<<5) /* Rec scr data forced to 0 */ -#define PL_C_SDNRZEN (1<<8) /* Monitor rec descr. data for act */ -#else /* nMOT_ELM */ -#define PL_C_FOTOFF_CTRL (3<<8) /* FOTOFF timer control */ -#define PL_C_FOTOFF_0 (0<<8) /* timer off */ -#define PL_C_FOTOFF_30 (1<<8) /* 30uS */ -#define PL_C_FOTOFF_50 (2<<8) /* 50uS */ -#define PL_C_FOTOFF_NEVER (3<<8) /* never */ -#define PL_C_SDON_TIMER (3<<10) /* SDON timer control */ -#define PL_C_SDON_084 (0<<10) /* 0.84 uS */ -#define PL_C_SDON_132 (1<<10) /* 1.32 uS */ -#define PL_C_SDON_252 (2<<10) /* 2.52 uS */ -#define PL_C_SDON_512 (3<<10) /* 5.12 uS */ -#define PL_C_SOFF_TIMER (3<<12) /* SDOFF timer control */ -#define PL_C_SOFF_076 (0<<12) /* 0.76 uS */ -#define PL_C_SOFF_132 (1<<12) /* 1.32 uS */ -#define PL_C_SOFF_252 (2<<12) /* 2.52 uS */ -#define PL_C_SOFF_512 (3<<12) /* 5.12 uS */ -#define PL_C_TSEL (3<<14) /* scrambler path select */ -#endif /* nMOT_ELM */ - -/* - * PLC status register A (PL_STATUS_A: log. addr. 0x10) - * It is used to report status information to the Node Processor about the - * Line State Machine (LSM). - */ -#ifdef MOT_ELM -#define PLC_INT_MASK 0xc000 /* ELM integration bits in status A */ -#define PLC_INT_C 0x0000 /* ELM Revision Band C */ -#define PLC_INT_CAMEL 0x4000 /* ELM integrated into CAMEL */ -#define PLC_INT_QE 0x8000 /* ELM integrated into Quad ELM */ -#define PLC_REV_MASK 0x3800 /* revision bits in status A */ -#define PLC_REVISION_B 0x0000 /* rev bits for ELM Rev B */ -#define PLC_REVISION_QA 0x0800 /* rev bits for ELM core in QELM-A */ -#else /* nMOT_ELM */ -#define PLC_REV_MASK 0xf800 /* revision bits in status A */ -#define PLC_REVISION_A 0x0000 /* revision bits for PLC */ -#define PLC_REVISION_S 0xf800 /* revision bits for PLC-S */ -#define PLC_REV_SN3 0x7800 /* revision bits for PLC-S in IFCP */ -#endif /* nMOT_ELM */ -#define PL_SYM_PR_CTR 0x0007 /* contains the LSM symbol pair Ctr. */ -#define PL_UNKN_LINE_ST 0x0008 /* unknown line state bit from LSM */ -#define PL_LSM_STATE 0x0010 /* state bit of LSM */ - -#define PL_LINE_ST 0x00e0 /* contains recogn. line state of LSM*/ -#define PL_L_NLS (0<<5) /* noise line state */ -#define PL_L_ALS (1<<5) /* activ line state */ -#define PL_L_UND (2<<5) /* undefined */ -#define PL_L_ILS4 (3<<5) /* idle l. s. (after 4 idle symbols) */ -#define PL_L_QLS (4<<5) /* quiet line state */ -#define PL_L_MLS (5<<5) /* master line state */ -#define PL_L_HLS (6<<5) /* halt line state */ -#define PL_L_ILS16 (7<<5) /* idle line state (after 16 idle s.)*/ - -#define PL_PREV_LINE_ST 0x0300 /* value of previous line state */ -#define PL_P_QLS (0<<8) /* quiet line state */ -#define PL_P_MLS (1<<8) /* master line state */ -#define PL_P_HLS (2<<8) /* halt line state */ -#define PL_P_ILS16 (3<<8) /* idle line state (after 16 idle s.)*/ - -#define PL_SIGNAL_DET 0x0400 /* 1=that signal detect is deasserted*/ - - -/* - * PLC status register B (PL_STATUS_B: log. addr. 0x11) - * It contains signals and status from the repeat filter and PCM state machine. - */ -#define PL_BREAK_REASON 0x0007 /* reason for PCM state mach.s to br.*/ -#define PL_B_NOT (0) /* PCM SM has not gone to BREAK state*/ -#define PL_B_PCS (1) /* PC_Start issued */ -#define PL_B_TPC (2) /* TPC timer expired after T_OUT */ -#define PL_B_TNE (3) /* TNE timer expired after NS_MAX */ -#define PL_B_QLS (4) /* quit line state detected */ -#define PL_B_ILS (5) /* idle line state detected */ -#define PL_B_HLS (6) /* halt line state detected */ - -#define PL_TCF 0x0008 /* transmit code flag (start exec.) */ -#define PL_RCF 0x0010 /* receive code flag (start exec.) */ -#define PL_LSF 0x0020 /* line state flag (l.s. has been r.)*/ -#define PL_PCM_SIGNAL 0x0040 /* indic. that XMIT_VECTOR hb.written*/ - -#define PL_PCM_STATE 0x0780 /* state bits of PCM state machine */ -#define PL_PC0 (0<<7) /* OFF - when /RST or PCM_CNTRL */ -#define PL_PC1 (1<<7) /* BREAK - entry point in start PCM*/ -#define PL_PC2 (2<<7) /* TRACE - to localize stuck Beacon*/ -#define PL_PC3 (3<<7) /* CONNECT - synchronize ends of conn*/ -#define PL_PC4 (4<<7) /* NEXT - to separate the signalng*/ -#define PL_PC5 (5<<7) /* SIGNAL - PCM trans/rec. bit infos*/ -#define PL_PC6 (6<<7) /* JOIN - 1. state to activ conn. */ -#define PL_PC7 (7<<7) /* VERIFY - 2. - " - (3. ACTIVE) */ -#define PL_PC8 (8<<7) /* ACTIVE - PHY has been incorporated*/ -#define PL_PC9 (9<<7) /* MAINT - for test purposes or so - that PCM op. completely in softw. */ - -#define PL_PCI_SCRUB 0x0800 /* scrubbing function is being exec. */ - -#define PL_PCI_STATE 0x3000 /* Physical Connect. Insertion SM */ -#define PL_CI_REMV (0<<12) /* REMOVED */ -#define PL_CI_ISCR (1<<12) /* INSERT_SCRUB */ -#define PL_CI_RSCR (2<<12) /* REMOVE_SCRUB */ -#define PL_CI_INS (3<<12) /* INSERTED */ - -#define PL_RF_STATE 0xc000 /* state bit of repeate filter SM */ -#define PL_RF_REPT (0<<14) /* REPEAT */ -#define PL_RF_IDLE (1<<14) /* IDLE */ -#define PL_RF_HALT1 (2<<14) /* HALT1 */ -#define PL_RF_HALT2 (3<<14) /* HALT2 */ - - -/* - * PLC interrupt event register (PL_INTR_EVENT: log. addr. 0x17) - * It is read only and is clearde whenever it is read! - * It is used by the PLC to report events to the node processor. - */ -#define PL_PARITY_ERR 0x0001 /* p. error h.b.detected on TX9-0 inp*/ -#define PL_LS_MATCH 0x0002 /* l.s.== l.s. PLC_CNTRL_B's MATCH_LS*/ -#define PL_PCM_CODE 0x0004 /* transmit&receive | LCT complete */ -#define PL_TRACE_PROP 0x0008 /* master l.s. while PCM ACTIV|TRACE */ -#define PL_SELF_TEST 0x0010 /* QUIET|HALT while PCM in TRACE st. */ -#define PL_PCM_BREAK 0x0020 /* PCM has entered the BREAK state */ -#define PL_PCM_ENABLED 0x0040 /* asserted SC_JOIN, scrub. & ACTIV */ -#define PL_TPC_EXPIRED 0x0080 /* TPC timer reached zero */ -#define PL_TNE_EXPIRED 0x0100 /* TNE timer reached zero */ -#define PL_EBUF_ERR 0x0200 /* elastic buff. det. over-|underflow*/ -#define PL_PHYINV 0x0400 /* physical layer invalid signal */ -#define PL_VSYM_CTR 0x0800 /* violation symbol counter has incr.*/ -#define PL_MINI_CTR 0x1000 /* dep. on PLC_CNTRL_A's MINI_CTR_INT*/ -#define PL_LE_CTR 0x2000 /* link error event counter */ -#define PL_LSDO 0x4000 /* SDO input pin changed to a 1 */ -#define PL_NP_ERR 0x8000 /* NP has requested to r/w an inv. r.*/ - -/* - * The PLC interrupt mask register (PL_INTR_MASK: log. addr. 0x02) constr. is - * equal PL_INTR_EVENT register. - * For each set bit, the setting of corresponding bit generate an int to NP. - */ - -#ifdef MOT_ELM -/* - * Quad ELM Crosbar Control register values (QELM_XBAR_?) - */ -#define QELM_XOUT_IDLE 0x0000 /* Idles/Passthrough */ -#define QELM_XOUT_P 0x0001 /* Output to: Bus P */ -#define QELM_XOUT_S 0x0002 /* Output to: Bus S */ -#define QELM_XOUT_R 0x0003 /* Output to: Bus R */ -#define QELM_XOUT_W 0x0004 /* Output to: ELM W */ -#define QELM_XOUT_X 0x0005 /* Output to: ELM X */ -#define QELM_XOUT_Y 0x0006 /* Output to: ELM Y */ -#define QELM_XOUT_Z 0x0007 /* Output to: ELM Z */ - -/* - * Quad ELM Interrupt data and event registers. - */ -#define QELM_NP_ERR (1<<15) /* Node Processor Error */ -#define QELM_COUNT_Z (1<<7) /* Counter Z Interrupt */ -#define QELM_COUNT_Y (1<<6) /* Counter Y Interrupt */ -#define QELM_COUNT_X (1<<5) /* Counter X Interrupt */ -#define QELM_COUNT_W (1<<4) /* Counter W Interrupt */ -#define QELM_ELM_Z (1<<3) /* ELM Z Interrupt */ -#define QELM_ELM_Y (1<<2) /* ELM Y Interrupt */ -#define QELM_ELM_X (1<<1) /* ELM X Interrupt */ -#define QELM_ELM_W (1<<0) /* ELM W Interrupt */ -#endif /* MOT_ELM */ -/* - * PLC Timing Parameters - */ -#define TP_C_MIN 0xff9c /* 2 ms */ -#define TP_TL_MIN 0xfff0 /* 0.3 ms */ -#define TP_TB_MIN 0xff10 /* 5 ms */ -#define TP_T_OUT 0xd9db /* 200 ms */ -#define TP_LC_LENGTH 0xf676 /* 50 ms */ -#define TP_LC_LONGLN 0xa0a2 /* 500 ms */ -#define TP_T_SCRUB 0xff6d /* 3.5 ms */ -#define TP_NS_MAX 0xf021 /* 1.3 ms */ - -/* - * BIST values - */ -#define PLC_BIST 0x6ecd /* BIST signature for PLC */ -#define PLCS_BIST 0x5b6b /* BIST signature for PLC-S */ -#define PLC_ELM_B_BIST 0x6ecd /* BIST signature of ELM Rev. B */ -#define PLC_ELM_D_BIST 0x5b6b /* BIST signature of ELM Rev. D */ -#define PLC_CAM_A_BIST 0x9e75 /* BIST signature of CAMEL Rev. A */ -#define PLC_CAM_B_BIST 0x5b6b /* BIST signature of CAMEL Rev. B */ -#define PLC_IFD_A_BIST 0x9e75 /* BIST signature of IFDDI Rev. A */ -#define PLC_IFD_B_BIST 0x5b6b /* BIST signature of IFDDI Rev. B */ -#define PLC_QELM_A_BIST 0x5b6b /* BIST signature of QELM Rev. A */ - -/* - FDDI board recources - */ - -/* - * request register array (log. addr: RQA_A + a<<1 {a=0..7}) write only. - * It specifies to FORMAC+ the type of buffer memory access the host requires. - */ -#define RQ_NOT 0 /* not request */ -#define RQ_RES 1 /* reserved */ -#define RQ_SFW 2 /* special frame write */ -#define RQ_RRQ 3 /* read request: receive queue */ -#define RQ_WSQ 4 /* write request: synchronous queue */ -#define RQ_WA0 5 /* write requ.: asynchronous queue 0 */ -#define RQ_WA1 6 /* write requ.: asynchronous queue 1 */ -#define RQ_WA2 7 /* write requ.: asynchronous queue 2 */ - -#define SZ_LONG (sizeof(long)) - -/* - * FDDI defaults - * NOTE : In the ANSI docs, times are specified in units of "symbol time". - * AMD chips use BCLK as unit. 1 BCKL == 2 symbols - */ -#define COMPLREF ((u_long)32*256*256) /* two's complement 21 bit */ -#define MSTOBCLK(x) ((u_long)(x)*12500L) -#define MSTOTVX(x) (((u_long)(x)*1000L)/80/255) - -#endif /* _SUPERNET_ */ diff --git a/drivers/net/skfp/h/targethw.h b/drivers/net/skfp/h/targethw.h deleted file mode 100644 index 626dc72..0000000 --- a/drivers/net/skfp/h/targethw.h +++ /dev/null @@ -1,138 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -#ifndef _TARGETHW_ -#define _TARGETHW_ - - /* - * PCI Watermark definition - */ -#ifdef PCI -#define RX_WATERMARK 24 -#define TX_WATERMARK 24 -#define SK_ML_ID_1 0x20 -#define SK_ML_ID_2 0x30 -#endif - -#include "h/skfbi.h" -#ifndef TAG_MODE -#include "h/fplus.h" -#else -#include "h/fplustm.h" -#endif - -#ifndef HW_PTR -#define HW_PTR void __iomem * -#endif - -#ifdef MULT_OEM -#define OI_STAT_LAST 0 /* end of OEM data base */ -#define OI_STAT_PRESENT 1 /* entry present but not empty */ -#define OI_STAT_VALID 2 /* holds valid ID, but is not active */ -#define OI_STAT_ACTIVE 3 /* holds valid ID, entry is active */ - /* active = adapter is supported */ - -/* Memory representation of IDs must match representation in adapter. */ -struct s_oem_ids { - u_char oi_status ; /* Stat: last, present, valid, active */ - u_char oi_mark[5] ; /* "PID00" .. "PID07" .. */ - u_char oi_id[4] ; /* id bytes, representation as */ - /* defined by hardware, */ -#ifdef PCI - u_char oi_sub_id[4] ; /* sub id bytes, representation as */ - /* defined by hardware, */ -#endif -} ; -#endif /* MULT_OEM */ - - -struct s_smt_hw { - /* - * global - */ - HW_PTR iop ; /* IO base address */ - short dma ; /* DMA channel */ - short irq ; /* IRQ level */ - short eprom ; /* FLASH prom */ - -#ifndef SYNC - u_short n_a_send ; /* pending send requests */ -#endif - -#if defined(PCI) - short slot ; /* slot number */ - short max_slots ; /* maximum number of slots */ - short wdog_used ; /* TRUE if the watch dog is used */ -#endif - -#ifdef PCI - u_short pci_handle ; /* handle to access the BIOS func */ - u_long is_imask ; /* int maske for the int source reg */ - u_long phys_mem_addr ; /* physical memory address */ - u_short mc_dummy ; /* work around for MC compiler bug */ - /* - * state of the hardware - */ - u_short hw_state ; /* started or stopped */ - -#define STARTED 1 -#define STOPPED 0 - - int hw_is_64bit ; /* does we have a 64 bit adapter */ -#endif - -#ifdef TAG_MODE - u_long pci_fix_value ; /* value parsed by PCIFIX */ -#endif - - /* - * hwt.c - */ - u_long t_start ; /* HWT start */ - u_long t_stop ; /* HWT stop */ - u_short timer_activ ; /* HWT timer active */ - - /* - * PIC - */ - u_char pic_a1 ; - u_char pic_21 ; - - /* - * GENERIC ; do not modify beyond this line - */ - - /* - * physical and canonical address - */ - struct fddi_addr fddi_home_addr ; - struct fddi_addr fddi_canon_addr ; - struct fddi_addr fddi_phys_addr ; - - /* - * mac variables - */ - struct mac_parameter mac_pa ; /* tmin, tmax, tvx, treq .. */ - struct mac_counter mac_ct ; /* recv., lost, error */ - u_short mac_ring_is_up ; /* ring is up flag */ - - struct s_smt_fp fp ; /* formac+ */ - -#ifdef MULT_OEM - struct s_oem_ids *oem_id ; /* pointer to selected id */ - int oem_min_status ; /* IDs to take care of */ -#endif /* MULT_OEM */ - -} ; -#endif diff --git a/drivers/net/skfp/h/targetos.h b/drivers/net/skfp/h/targetos.h deleted file mode 100644 index 5d940e7..0000000 --- a/drivers/net/skfp/h/targetos.h +++ /dev/null @@ -1,165 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - * Operating system specific definitions for driver and - * hardware module. - */ - -#ifndef TARGETOS_H -#define TARGETOS_H - - -//-------- those should go into include/linux/pci.h -#define PCI_VENDOR_ID_SK 0x1148 -#define PCI_DEVICE_ID_SK_FP 0x4000 -//-------- - - - -//-------- those should go into include/linux/if_fddi.h -#define FDDI_MAC_HDR_LEN 13 - -#define FDDI_RII 0x01 /* routing information bit */ -#define FDDI_RCF_DIR_BIT 0x80 -#define FDDI_RCF_LEN_MASK 0x1f -#define FDDI_RCF_BROADCAST 0x8000 -#define FDDI_RCF_LIMITED_BROADCAST 0xA000 -#define FDDI_RCF_FRAME2K 0x20 -#define FDDI_RCF_FRAME4K 0x30 -//-------- - - -#undef ADDR - -#include -#include -#include -#include -#include -#include - -// is redefined by linux, but we need our definition -#undef ADDR -#ifdef MEM_MAPPED_IO -#define ADDR(a) (smc->hw.iop+(a)) -#else -#define ADDR(a) (((a)>>7) ? (outp(smc->hw.iop+B0_RAP,(a)>>7), (smc->hw.iop+( ((a)&0x7F) | ((a)>>7 ? 0x80:0)) )) : (smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) -#endif - -#include "h/hwmtm.h" - -#define TRUE 1 -#define FALSE 0 - -// HWM Definitions -// ----------------------- -#define FDDI_TRACE(string, arg1, arg2, arg3) // Performance analysis. -#ifdef PCI -#define NDD_TRACE(string, arg1, arg2, arg3) // Performance analysis. -#endif // PCI -#define SMT_PAGESIZE PAGE_SIZE // Size of a memory page (power of 2). -// ----------------------- - - -// SMT Definitions -// ----------------------- -#define TICKS_PER_SECOND HZ -#define SMC_VERSION 1 -// ----------------------- - - -// OS-Driver Definitions -// ----------------------- -#define NO_ADDRESS 0xffe0 /* No Device (I/O) Address */ -#define SKFP_MAX_NUM_BOARDS 8 /* maximum number of PCI boards */ - -#define SK_BUS_TYPE_PCI 0 -#define SK_BUS_TYPE_EISA 1 - -#define FP_IO_LEN 256 /* length of IO area used */ - -#define u8 unsigned char -#define u16 unsigned short -#define u32 unsigned int - -#define MAX_TX_QUEUE_LEN 20 // number of packets queued by driver -#define MAX_FRAME_SIZE 4550 - -#define RX_LOW_WATERMARK NUM_RECEIVE_BUFFERS / 2 -#define TX_LOW_WATERMARK NUM_TRANSMIT_BUFFERS - 2 - -/* -** Include the IOCTL stuff -*/ -#include - -#define SKFPIOCTL SIOCDEVPRIVATE - -struct s_skfp_ioctl { - unsigned short cmd; /* Command to run */ - unsigned short len; /* Length of the data buffer */ - unsigned char __user *data; /* Pointer to the data buffer */ -}; - -/* -** Recognised ioctl commands for the driver -*/ -#define SKFP_GET_STATS 0x05 /* Get the driver statistics */ -#define SKFP_CLR_STATS 0x06 /* Zero out the driver statistics */ - -// The per-adapter driver structure -struct s_smt_os { - struct net_device *dev; - struct net_device *next_module; - u32 bus_type; /* bus type (0 == PCI, 1 == EISA) */ - struct pci_dev pdev; /* PCI device structure */ - - unsigned long base_addr; - unsigned char factory_mac_addr[8]; - ulong SharedMemSize; - ulong SharedMemHeap; - void* SharedMemAddr; - dma_addr_t SharedMemDMA; - - ulong QueueSkb; - struct sk_buff_head SendSkbQueue; - - ulong MaxFrameSize; - u8 ResetRequested; - - // MAC statistics structure - struct fddi_statistics MacStat; - - // receive into this local buffer if no skb available - // data will be not valid, because multiple RxDs can - // point here at the same time, it must be at least - // MAX_FRAME_SIZE bytes in size - unsigned char *LocalRxBuffer; - dma_addr_t LocalRxBufferDMA; - - // Version (required by SMT module). - u_long smc_version ; - - // Required by Hardware Module (HWM). - struct hw_modul hwm ; - - // For SMP-savety - spinlock_t DriverLock; - -}; - -typedef struct s_smt_os skfddi_priv; - -#endif // _TARGETOS_ diff --git a/drivers/net/skfp/h/types.h b/drivers/net/skfp/h/types.h deleted file mode 100644 index 5a3bf83..0000000 --- a/drivers/net/skfp/h/types.h +++ /dev/null @@ -1,39 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -#include -/* - ---------------------- - Basic SMT system types - ---------------------- -*/ -#ifndef _TYPES_ -#define _TYPES_ - -#define _packed -#ifndef far -#define far -#endif -#ifndef _far -#define _far -#endif - -#define inp(p) ioread8(p) -#define inpw(p) ioread16(p) -#define inpd(p) ioread32(p) -#define outp(p,c) iowrite8(c,p) -#define outpw(p,s) iowrite16(s,p) -#define outpd(p,l) iowrite32(l,p) - -#endif /* _TYPES_ */ diff --git a/drivers/net/skfp/hwmtm.c b/drivers/net/skfp/hwmtm.c deleted file mode 100644 index e26398b..0000000 --- a/drivers/net/skfp/hwmtm.c +++ /dev/null @@ -1,2178 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -#ifndef lint -static char const ID_sccs[] = "@(#)hwmtm.c 1.40 99/05/31 (C) SK" ; -#endif - -#define HWMTM - -#ifndef FDDI -#define FDDI -#endif - -#include "h/types.h" -#include "h/fddi.h" -#include "h/smc.h" -#include "h/supern_2.h" -#include "h/skfbiinc.h" - -/* - ------------------------------------------------------------- - DOCUMENTATION - ------------------------------------------------------------- - BEGIN_MANUAL_ENTRY(DOCUMENTATION) - - T B D - - END_MANUAL_ENTRY -*/ -/* - ------------------------------------------------------------- - LOCAL VARIABLES: - ------------------------------------------------------------- -*/ -#ifdef COMMON_MB_POOL -static SMbuf *mb_start = 0 ; -static SMbuf *mb_free = 0 ; -static int mb_init = FALSE ; -static int call_count = 0 ; -#endif - -/* - ------------------------------------------------------------- - EXTERNE VARIABLES: - ------------------------------------------------------------- -*/ - -#ifdef DEBUG -#ifndef DEBUG_BRD -extern struct smt_debug debug ; -#endif -#endif - -#ifdef NDIS_OS2 -extern u_char offDepth ; -extern u_char force_irq_pending ; -#endif - -/* - ------------------------------------------------------------- - LOCAL FUNCTIONS: - ------------------------------------------------------------- -*/ - -static void queue_llc_rx(struct s_smc *smc, SMbuf *mb); -static void smt_to_llc(struct s_smc *smc, SMbuf *mb); -static void init_txd_ring(struct s_smc *smc); -static void init_rxd_ring(struct s_smc *smc); -static void queue_txd_mb(struct s_smc *smc, SMbuf *mb); -static u_long init_descr_ring(struct s_smc *smc, union s_fp_descr volatile *start, - int count); -static u_long repair_txd_ring(struct s_smc *smc, struct s_smt_tx_queue *queue); -static u_long repair_rxd_ring(struct s_smc *smc, struct s_smt_rx_queue *queue); -static SMbuf* get_llc_rx(struct s_smc *smc); -static SMbuf* get_txd_mb(struct s_smc *smc); -static void mac_drv_clear_txd(struct s_smc *smc); - -/* - ------------------------------------------------------------- - EXTERNAL FUNCTIONS: - ------------------------------------------------------------- -*/ -/* The external SMT functions are listed in cmtdef.h */ - -extern void* mac_drv_get_space(struct s_smc *smc, unsigned int size); -extern void* mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size); -extern void mac_drv_fill_rxd(struct s_smc *smc); -extern void mac_drv_tx_complete(struct s_smc *smc, - volatile struct s_smt_fp_txd *txd); -extern void mac_drv_rx_complete(struct s_smc *smc, - volatile struct s_smt_fp_rxd *rxd, - int frag_count, int len); -extern void mac_drv_requeue_rxd(struct s_smc *smc, - volatile struct s_smt_fp_rxd *rxd, - int frag_count); -extern void mac_drv_clear_rxd(struct s_smc *smc, - volatile struct s_smt_fp_rxd *rxd, int frag_count); - -#ifdef USE_OS_CPY -extern void hwm_cpy_rxd2mb(void); -extern void hwm_cpy_txd2mb(void); -#endif - -#ifdef ALL_RX_COMPLETE -extern void mac_drv_all_receives_complete(void); -#endif - -extern u_long mac_drv_virt2phys(struct s_smc *smc, void *virt); -extern u_long dma_master(struct s_smc *smc, void *virt, int len, int flag); - -#ifdef NDIS_OS2 -extern void post_proc(void); -#else -extern void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr, - int flag); -#endif - -extern int mac_drv_rx_init(struct s_smc *smc, int len, int fc, char *look_ahead, - int la_len); - -/* - ------------------------------------------------------------- - PUBLIC FUNCTIONS: - ------------------------------------------------------------- -*/ -void process_receive(struct s_smc *smc); -void fddi_isr(struct s_smc *smc); -void smt_free_mbuf(struct s_smc *smc, SMbuf *mb); -void init_driver_fplus(struct s_smc *smc); -void mac_drv_rx_mode(struct s_smc *smc, int mode); -void init_fddi_driver(struct s_smc *smc, u_char *mac_addr); -void mac_drv_clear_tx_queue(struct s_smc *smc); -void mac_drv_clear_rx_queue(struct s_smc *smc); -void hwm_tx_frag(struct s_smc *smc, char far *virt, u_long phys, int len, - int frame_status); -void hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len, - int frame_status); - -int mac_drv_init(struct s_smc *smc); -int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, int frame_len, - int frame_status); - -u_int mac_drv_check_space(void); - -SMbuf* smt_get_mbuf(struct s_smc *smc); - -#ifdef DEBUG - void mac_drv_debug_lev(void); -#endif - -/* - ------------------------------------------------------------- - MACROS: - ------------------------------------------------------------- -*/ -#ifndef UNUSED -#ifdef lint -#define UNUSED(x) (x) = (x) -#else -#define UNUSED(x) -#endif -#endif - -#ifdef USE_CAN_ADDR -#define MA smc->hw.fddi_canon_addr.a -#define GROUP_ADDR_BIT 0x01 -#else -#define MA smc->hw.fddi_home_addr.a -#define GROUP_ADDR_BIT 0x80 -#endif - -#define RXD_TXD_COUNT (HWM_ASYNC_TXD_COUNT+HWM_SYNC_TXD_COUNT+\ - SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) - -#ifdef MB_OUTSIDE_SMC -#define EXT_VIRT_MEM ((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd) +\ - MAX_MBUF*sizeof(SMbuf)) -#define EXT_VIRT_MEM_2 ((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)) -#else -#define EXT_VIRT_MEM ((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)) -#endif - - /* - * define critical read for 16 Bit drivers - */ -#if defined(NDIS_OS2) || defined(ODI2) -#define CR_READ(var) ((var) & 0xffff0000 | ((var) & 0xffff)) -#else -#define CR_READ(var) (__le32)(var) -#endif - -#define IMASK_SLOW (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \ - IS_MINTR1 | IS_MINTR2 | IS_MINTR3 | IS_R1_P | \ - IS_R1_C | IS_XA_C | IS_XS_C) - -/* - ------------------------------------------------------------- - INIT- AND SMT FUNCTIONS: - ------------------------------------------------------------- -*/ - - -/* - * BEGIN_MANUAL_ENTRY(mac_drv_check_space) - * u_int mac_drv_check_space() - * - * function DOWNCALL (drvsr.c) - * This function calculates the needed non virtual - * memory for MBufs, RxD and TxD descriptors etc. - * needed by the driver. - * - * return u_int memory in bytes - * - * END_MANUAL_ENTRY - */ -u_int mac_drv_check_space(void) -{ -#ifdef MB_OUTSIDE_SMC -#ifdef COMMON_MB_POOL - call_count++ ; - if (call_count == 1) { - return EXT_VIRT_MEM; - } - else { - return EXT_VIRT_MEM_2; - } -#else - return EXT_VIRT_MEM; -#endif -#else - return 0; -#endif -} - -/* - * BEGIN_MANUAL_ENTRY(mac_drv_init) - * void mac_drv_init(smc) - * - * function DOWNCALL (drvsr.c) - * In this function the hardware module allocates it's - * memory. - * The operating system dependent module should call - * mac_drv_init once, after the adatper is detected. - * END_MANUAL_ENTRY - */ -int mac_drv_init(struct s_smc *smc) -{ - if (sizeof(struct s_smt_fp_rxd) % 16) { - SMT_PANIC(smc,HWM_E0001,HWM_E0001_MSG) ; - } - if (sizeof(struct s_smt_fp_txd) % 16) { - SMT_PANIC(smc,HWM_E0002,HWM_E0002_MSG) ; - } - - /* - * get the required memory for the RxDs and TxDs - */ - if (!(smc->os.hwm.descr_p = (union s_fp_descr volatile *) - mac_drv_get_desc_mem(smc,(u_int) - (RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)))) { - return 1; /* no space the hwm modul can't work */ - } - - /* - * get the memory for the SMT MBufs - */ -#ifndef MB_OUTSIDE_SMC - smc->os.hwm.mbuf_pool.mb_start=(SMbuf *)(&smc->os.hwm.mbuf_pool.mb[0]) ; -#else -#ifndef COMMON_MB_POOL - if (!(smc->os.hwm.mbuf_pool.mb_start = (SMbuf *) mac_drv_get_space(smc, - MAX_MBUF*sizeof(SMbuf)))) { - return 1; /* no space the hwm modul can't work */ - } -#else - if (!mb_start) { - if (!(mb_start = (SMbuf *) mac_drv_get_space(smc, - MAX_MBUF*sizeof(SMbuf)))) { - return 1; /* no space the hwm modul can't work */ - } - } -#endif -#endif - return 0; -} - -/* - * BEGIN_MANUAL_ENTRY(init_driver_fplus) - * init_driver_fplus(smc) - * - * Sets hardware modul specific values for the mode register 2 - * (e.g. the byte alignment for the received frames, the position of the - * least significant byte etc.) - * END_MANUAL_ENTRY - */ -void init_driver_fplus(struct s_smc *smc) -{ - smc->hw.fp.mdr2init = FM_LSB | FM_BMMODE | FM_ENNPRQ | FM_ENHSRQ | 3 ; - -#ifdef PCI - smc->hw.fp.mdr2init |= FM_CHKPAR | FM_PARITY ; -#endif - smc->hw.fp.mdr3init = FM_MENRQAUNLCK | FM_MENRS ; - -#ifdef USE_CAN_ADDR - /* enable address bit swapping */ - smc->hw.fp.frselreg_init = FM_ENXMTADSWAP | FM_ENRCVADSWAP ; -#endif -} - -static u_long init_descr_ring(struct s_smc *smc, - union s_fp_descr volatile *start, - int count) -{ - int i ; - union s_fp_descr volatile *d1 ; - union s_fp_descr volatile *d2 ; - u_long phys ; - - DB_GEN("descr ring starts at = %x ",(void *)start,0,3) ; - for (i=count-1, d1=start; i ; i--) { - d2 = d1 ; - d1++ ; /* descr is owned by the host */ - d2->r.rxd_rbctrl = cpu_to_le32(BMU_CHECK) ; - d2->r.rxd_next = &d1->r ; - phys = mac_drv_virt2phys(smc,(void *)d1) ; - d2->r.rxd_nrdadr = cpu_to_le32(phys) ; - } - DB_GEN("descr ring ends at = %x ",(void *)d1,0,3) ; - d1->r.rxd_rbctrl = cpu_to_le32(BMU_CHECK) ; - d1->r.rxd_next = &start->r ; - phys = mac_drv_virt2phys(smc,(void *)start) ; - d1->r.rxd_nrdadr = cpu_to_le32(phys) ; - - for (i=count, d1=start; i ; i--) { - DRV_BUF_FLUSH(&d1->r,DDI_DMA_SYNC_FORDEV) ; - d1++; - } - return phys; -} - -static void init_txd_ring(struct s_smc *smc) -{ - struct s_smt_fp_txd volatile *ds ; - struct s_smt_tx_queue *queue ; - u_long phys ; - - /* - * initialize the transmit descriptors - */ - ds = (struct s_smt_fp_txd volatile *) ((char *)smc->os.hwm.descr_p + - SMT_R1_RXD_COUNT*sizeof(struct s_smt_fp_rxd)) ; - queue = smc->hw.fp.tx[QUEUE_A0] ; - DB_GEN("Init async TxD ring, %d TxDs ",HWM_ASYNC_TXD_COUNT,0,3) ; - (void)init_descr_ring(smc,(union s_fp_descr volatile *)ds, - HWM_ASYNC_TXD_COUNT) ; - phys = le32_to_cpu(ds->txd_ntdadr) ; - ds++ ; - queue->tx_curr_put = queue->tx_curr_get = ds ; - ds-- ; - queue->tx_free = HWM_ASYNC_TXD_COUNT ; - queue->tx_used = 0 ; - outpd(ADDR(B5_XA_DA),phys) ; - - ds = (struct s_smt_fp_txd volatile *) ((char *)ds + - HWM_ASYNC_TXD_COUNT*sizeof(struct s_smt_fp_txd)) ; - queue = smc->hw.fp.tx[QUEUE_S] ; - DB_GEN("Init sync TxD ring, %d TxDs ",HWM_SYNC_TXD_COUNT,0,3) ; - (void)init_descr_ring(smc,(union s_fp_descr volatile *)ds, - HWM_SYNC_TXD_COUNT) ; - phys = le32_to_cpu(ds->txd_ntdadr) ; - ds++ ; - queue->tx_curr_put = queue->tx_curr_get = ds ; - queue->tx_free = HWM_SYNC_TXD_COUNT ; - queue->tx_used = 0 ; - outpd(ADDR(B5_XS_DA),phys) ; -} - -static void init_rxd_ring(struct s_smc *smc) -{ - struct s_smt_fp_rxd volatile *ds ; - struct s_smt_rx_queue *queue ; - u_long phys ; - - /* - * initialize the receive descriptors - */ - ds = (struct s_smt_fp_rxd volatile *) smc->os.hwm.descr_p ; - queue = smc->hw.fp.rx[QUEUE_R1] ; - DB_GEN("Init RxD ring, %d RxDs ",SMT_R1_RXD_COUNT,0,3) ; - (void)init_descr_ring(smc,(union s_fp_descr volatile *)ds, - SMT_R1_RXD_COUNT) ; - phys = le32_to_cpu(ds->rxd_nrdadr) ; - ds++ ; - queue->rx_curr_put = queue->rx_curr_get = ds ; - queue->rx_free = SMT_R1_RXD_COUNT ; - queue->rx_used = 0 ; - outpd(ADDR(B4_R1_DA),phys) ; -} - -/* - * BEGIN_MANUAL_ENTRY(init_fddi_driver) - * void init_fddi_driver(smc,mac_addr) - * - * initializes the driver and it's variables - * - * END_MANUAL_ENTRY - */ -void init_fddi_driver(struct s_smc *smc, u_char *mac_addr) -{ - SMbuf *mb ; - int i ; - - init_board(smc,mac_addr) ; - (void)init_fplus(smc) ; - - /* - * initialize the SMbufs for the SMT - */ -#ifndef COMMON_MB_POOL - mb = smc->os.hwm.mbuf_pool.mb_start ; - smc->os.hwm.mbuf_pool.mb_free = (SMbuf *)NULL ; - for (i = 0; i < MAX_MBUF; i++) { - mb->sm_use_count = 1 ; - smt_free_mbuf(smc,mb) ; - mb++ ; - } -#else - mb = mb_start ; - if (!mb_init) { - mb_free = 0 ; - for (i = 0; i < MAX_MBUF; i++) { - mb->sm_use_count = 1 ; - smt_free_mbuf(smc,mb) ; - mb++ ; - } - mb_init = TRUE ; - } -#endif - - /* - * initialize the other variables - */ - smc->os.hwm.llc_rx_pipe = smc->os.hwm.llc_rx_tail = (SMbuf *)NULL ; - smc->os.hwm.txd_tx_pipe = smc->os.hwm.txd_tx_tail = NULL ; - smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = smc->os.hwm.pass_DB = 0 ; - smc->os.hwm.pass_llc_promisc = TRUE ; - smc->os.hwm.queued_rx_frames = smc->os.hwm.queued_txd_mb = 0 ; - smc->os.hwm.detec_count = 0 ; - smc->os.hwm.rx_break = 0 ; - smc->os.hwm.rx_len_error = 0 ; - smc->os.hwm.isr_flag = FALSE ; - - /* - * make sure that the start pointer is 16 byte aligned - */ - i = 16 - ((long)smc->os.hwm.descr_p & 0xf) ; - if (i != 16) { - DB_GEN("i = %d",i,0,3) ; - smc->os.hwm.descr_p = (union s_fp_descr volatile *) - ((char *)smc->os.hwm.descr_p+i) ; - } - DB_GEN("pt to descr area = %x",(void *)smc->os.hwm.descr_p,0,3) ; - - init_txd_ring(smc) ; - init_rxd_ring(smc) ; - mac_drv_fill_rxd(smc) ; - - init_plc(smc) ; -} - - -SMbuf *smt_get_mbuf(struct s_smc *smc) -{ - register SMbuf *mb ; - -#ifndef COMMON_MB_POOL - mb = smc->os.hwm.mbuf_pool.mb_free ; -#else - mb = mb_free ; -#endif - if (mb) { -#ifndef COMMON_MB_POOL - smc->os.hwm.mbuf_pool.mb_free = mb->sm_next ; -#else - mb_free = mb->sm_next ; -#endif - mb->sm_off = 8 ; - mb->sm_use_count = 1 ; - } - DB_GEN("get SMbuf: mb = %x",(void *)mb,0,3) ; - return mb; /* May be NULL */ -} - -void smt_free_mbuf(struct s_smc *smc, SMbuf *mb) -{ - - if (mb) { - mb->sm_use_count-- ; - DB_GEN("free_mbuf: sm_use_count = %d",mb->sm_use_count,0,3) ; - /* - * If the use_count is != zero the MBuf is queued - * more than once and must not queued into the - * free MBuf queue - */ - if (!mb->sm_use_count) { - DB_GEN("free SMbuf: mb = %x",(void *)mb,0,3) ; -#ifndef COMMON_MB_POOL - mb->sm_next = smc->os.hwm.mbuf_pool.mb_free ; - smc->os.hwm.mbuf_pool.mb_free = mb ; -#else - mb->sm_next = mb_free ; - mb_free = mb ; -#endif - } - } - else - SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; -} - - -/* - * BEGIN_MANUAL_ENTRY(mac_drv_repair_descr) - * void mac_drv_repair_descr(smc) - * - * function called from SMT (HWM / hwmtm.c) - * The BMU is idle when this function is called. - * Mac_drv_repair_descr sets up the physical address - * for all receive and transmit queues where the BMU - * should continue. - * It may be that the BMU was reseted during a fragmented - * transfer. In this case there are some fragments which will - * never completed by the BMU. The OWN bit of this fragments - * must be switched to be owned by the host. - * - * Give a start command to the receive BMU. - * Start the transmit BMUs if transmit frames pending. - * - * END_MANUAL_ENTRY - */ -void mac_drv_repair_descr(struct s_smc *smc) -{ - u_long phys ; - - if (smc->hw.hw_state != STOPPED) { - SK_BREAK() ; - SMT_PANIC(smc,HWM_E0013,HWM_E0013_MSG) ; - return ; - } - - /* - * repair tx queues: don't start - */ - phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_A0]) ; - outpd(ADDR(B5_XA_DA),phys) ; - if (smc->hw.fp.tx_q[QUEUE_A0].tx_used) { - outpd(ADDR(B0_XA_CSR),CSR_START) ; - } - phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_S]) ; - outpd(ADDR(B5_XS_DA),phys) ; - if (smc->hw.fp.tx_q[QUEUE_S].tx_used) { - outpd(ADDR(B0_XS_CSR),CSR_START) ; - } - - /* - * repair rx queues - */ - phys = repair_rxd_ring(smc,smc->hw.fp.rx[QUEUE_R1]) ; - outpd(ADDR(B4_R1_DA),phys) ; - outpd(ADDR(B0_R1_CSR),CSR_START) ; -} - -static u_long repair_txd_ring(struct s_smc *smc, struct s_smt_tx_queue *queue) -{ - int i ; - int tx_used ; - u_long phys ; - u_long tbctrl ; - struct s_smt_fp_txd volatile *t ; - - SK_UNUSED(smc) ; - - t = queue->tx_curr_get ; - tx_used = queue->tx_used ; - for (i = tx_used+queue->tx_free-1 ; i ; i-- ) { - t = t->txd_next ; - } - phys = le32_to_cpu(t->txd_ntdadr) ; - - t = queue->tx_curr_get ; - while (tx_used) { - DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ; - tbctrl = le32_to_cpu(t->txd_tbctrl) ; - - if (tbctrl & BMU_OWN) { - if (tbctrl & BMU_STF) { - break ; /* exit the loop */ - } - else { - /* - * repair the descriptor - */ - t->txd_tbctrl &= ~cpu_to_le32(BMU_OWN) ; - } - } - phys = le32_to_cpu(t->txd_ntdadr) ; - DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; - t = t->txd_next ; - tx_used-- ; - } - return phys; -} - -/* - * Repairs the receive descriptor ring and returns the physical address - * where the BMU should continue working. - * - * o The physical address where the BMU was stopped has to be - * determined. This is the next RxD after rx_curr_get with an OWN - * bit set. - * o The BMU should start working at beginning of the next frame. - * RxDs with an OWN bit set but with a reset STF bit should be - * skipped and owned by the driver (OWN = 0). - */ -static u_long repair_rxd_ring(struct s_smc *smc, struct s_smt_rx_queue *queue) -{ - int i ; - int rx_used ; - u_long phys ; - u_long rbctrl ; - struct s_smt_fp_rxd volatile *r ; - - SK_UNUSED(smc) ; - - r = queue->rx_curr_get ; - rx_used = queue->rx_used ; - for (i = SMT_R1_RXD_COUNT-1 ; i ; i-- ) { - r = r->rxd_next ; - } - phys = le32_to_cpu(r->rxd_nrdadr) ; - - r = queue->rx_curr_get ; - while (rx_used) { - DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; - rbctrl = le32_to_cpu(r->rxd_rbctrl) ; - - if (rbctrl & BMU_OWN) { - if (rbctrl & BMU_STF) { - break ; /* exit the loop */ - } - else { - /* - * repair the descriptor - */ - r->rxd_rbctrl &= ~cpu_to_le32(BMU_OWN) ; - } - } - phys = le32_to_cpu(r->rxd_nrdadr) ; - DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; - r = r->rxd_next ; - rx_used-- ; - } - return phys; -} - - -/* - ------------------------------------------------------------- - INTERRUPT SERVICE ROUTINE: - ------------------------------------------------------------- -*/ - -/* - * BEGIN_MANUAL_ENTRY(fddi_isr) - * void fddi_isr(smc) - * - * function DOWNCALL (drvsr.c) - * interrupt service routine, handles the interrupt requests - * generated by the FDDI adapter. - * - * NOTE: The operating system dependent module must guarantee that the - * interrupts of the adapter are disabled when it calls fddi_isr. - * - * About the USE_BREAK_ISR mechanismn: - * - * The main requirement of this mechanismn is to force an timer IRQ when - * leaving process_receive() with leave_isr set. process_receive() may - * be called at any time from anywhere! - * To be sure we don't miss such event we set 'force_irq' per default. - * We have to force and Timer IRQ if 'smc->os.hwm.leave_isr' AND - * 'force_irq' are set. 'force_irq' may be reset if a receive complete - * IRQ is pending. - * - * END_MANUAL_ENTRY - */ -void fddi_isr(struct s_smc *smc) -{ - u_long is ; /* ISR source */ - u_short stu, stl ; - SMbuf *mb ; - -#ifdef USE_BREAK_ISR - int force_irq ; -#endif - -#ifdef ODI2 - if (smc->os.hwm.rx_break) { - mac_drv_fill_rxd(smc) ; - if (smc->hw.fp.rx_q[QUEUE_R1].rx_used > 0) { - smc->os.hwm.rx_break = 0 ; - process_receive(smc) ; - } - else { - smc->os.hwm.detec_count = 0 ; - smt_force_irq(smc) ; - } - } -#endif - smc->os.hwm.isr_flag = TRUE ; - -#ifdef USE_BREAK_ISR - force_irq = TRUE ; - if (smc->os.hwm.leave_isr) { - smc->os.hwm.leave_isr = FALSE ; - process_receive(smc) ; - } -#endif - - while ((is = GET_ISR() & ISR_MASK)) { - NDD_TRACE("CH0B",is,0,0) ; - DB_GEN("ISA = 0x%x",is,0,7) ; - - if (is & IMASK_SLOW) { - NDD_TRACE("CH1b",is,0,0) ; - if (is & IS_PLINT1) { /* PLC1 */ - plc1_irq(smc) ; - } - if (is & IS_PLINT2) { /* PLC2 */ - plc2_irq(smc) ; - } - if (is & IS_MINTR1) { /* FORMAC+ STU1(U/L) */ - stu = inpw(FM_A(FM_ST1U)) ; - stl = inpw(FM_A(FM_ST1L)) ; - DB_GEN("Slow transmit complete",0,0,6) ; - mac1_irq(smc,stu,stl) ; - } - if (is & IS_MINTR2) { /* FORMAC+ STU2(U/L) */ - stu= inpw(FM_A(FM_ST2U)) ; - stl= inpw(FM_A(FM_ST2L)) ; - DB_GEN("Slow receive complete",0,0,6) ; - DB_GEN("stl = %x : stu = %x",stl,stu,7) ; - mac2_irq(smc,stu,stl) ; - } - if (is & IS_MINTR3) { /* FORMAC+ STU3(U/L) */ - stu= inpw(FM_A(FM_ST3U)) ; - stl= inpw(FM_A(FM_ST3L)) ; - DB_GEN("FORMAC Mode Register 3",0,0,6) ; - mac3_irq(smc,stu,stl) ; - } - if (is & IS_TIMINT) { /* Timer 82C54-2 */ - timer_irq(smc) ; -#ifdef NDIS_OS2 - force_irq_pending = 0 ; -#endif - /* - * out of RxD detection - */ - if (++smc->os.hwm.detec_count > 4) { - /* - * check out of RxD condition - */ - process_receive(smc) ; - } - } - if (is & IS_TOKEN) { /* Restricted Token Monitor */ - rtm_irq(smc) ; - } - if (is & IS_R1_P) { /* Parity error rx queue 1 */ - /* clear IRQ */ - outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_P) ; - SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; - } - if (is & IS_R1_C) { /* Encoding error rx queue 1 */ - /* clear IRQ */ - outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_C) ; - SMT_PANIC(smc,HWM_E0005,HWM_E0005_MSG) ; - } - if (is & IS_XA_C) { /* Encoding error async tx q */ - /* clear IRQ */ - outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_C) ; - SMT_PANIC(smc,HWM_E0006,HWM_E0006_MSG) ; - } - if (is & IS_XS_C) { /* Encoding error sync tx q */ - /* clear IRQ */ - outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_C) ; - SMT_PANIC(smc,HWM_E0007,HWM_E0007_MSG) ; - } - } - - /* - * Fast Tx complete Async/Sync Queue (BMU service) - */ - if (is & (IS_XS_F|IS_XA_F)) { - DB_GEN("Fast tx complete queue",0,0,6) ; - /* - * clear IRQ, Note: no IRQ is lost, because - * we always service both queues - */ - outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_F) ; - outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_F) ; - mac_drv_clear_txd(smc) ; - llc_restart_tx(smc) ; - } - - /* - * Fast Rx Complete (BMU service) - */ - if (is & IS_R1_F) { - DB_GEN("Fast receive complete",0,0,6) ; - /* clear IRQ */ -#ifndef USE_BREAK_ISR - outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ; - process_receive(smc) ; -#else - process_receive(smc) ; - if (smc->os.hwm.leave_isr) { - force_irq = FALSE ; - } else { - outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ; - process_receive(smc) ; - } -#endif - } - -#ifndef NDIS_OS2 - while ((mb = get_llc_rx(smc))) { - smt_to_llc(smc,mb) ; - } -#else - if (offDepth) - post_proc() ; - - while (!offDepth && (mb = get_llc_rx(smc))) { - smt_to_llc(smc,mb) ; - } - - if (!offDepth && smc->os.hwm.rx_break) { - process_receive(smc) ; - } -#endif - if (smc->q.ev_get != smc->q.ev_put) { - NDD_TRACE("CH2a",0,0,0) ; - ev_dispatcher(smc) ; - } -#ifdef NDIS_OS2 - post_proc() ; - if (offDepth) { /* leave fddi_isr because */ - break ; /* indications not allowed */ - } -#endif -#ifdef USE_BREAK_ISR - if (smc->os.hwm.leave_isr) { - break ; /* leave fddi_isr */ - } -#endif - - /* NOTE: when the isr is left, no rx is pending */ - } /* end of interrupt source polling loop */ - -#ifdef USE_BREAK_ISR - if (smc->os.hwm.leave_isr && force_irq) { - smt_force_irq(smc) ; - } -#endif - smc->os.hwm.isr_flag = FALSE ; - NDD_TRACE("CH0E",0,0,0) ; -} - - -/* - ------------------------------------------------------------- - RECEIVE FUNCTIONS: - ------------------------------------------------------------- -*/ - -#ifndef NDIS_OS2 -/* - * BEGIN_MANUAL_ENTRY(mac_drv_rx_mode) - * void mac_drv_rx_mode(smc,mode) - * - * function DOWNCALL (fplus.c) - * Corresponding to the parameter mode, the operating system - * dependent module can activate several receive modes. - * - * para mode = 1: RX_ENABLE_ALLMULTI enable all multicasts - * = 2: RX_DISABLE_ALLMULTI disable "enable all multicasts" - * = 3: RX_ENABLE_PROMISC enable promiscuous - * = 4: RX_DISABLE_PROMISC disable promiscuous - * = 5: RX_ENABLE_NSA enable rec. of all NSA frames - * (disabled after 'driver reset' & 'set station address') - * = 6: RX_DISABLE_NSA disable rec. of all NSA frames - * - * = 21: RX_ENABLE_PASS_SMT ( see description ) - * = 22: RX_DISABLE_PASS_SMT ( " " ) - * = 23: RX_ENABLE_PASS_NSA ( " " ) - * = 24: RX_DISABLE_PASS_NSA ( " " ) - * = 25: RX_ENABLE_PASS_DB ( " " ) - * = 26: RX_DISABLE_PASS_DB ( " " ) - * = 27: RX_DISABLE_PASS_ALL ( " " ) - * = 28: RX_DISABLE_LLC_PROMISC ( " " ) - * = 29: RX_ENABLE_LLC_PROMISC ( " " ) - * - * - * RX_ENABLE_PASS_SMT / RX_DISABLE_PASS_SMT - * - * If the operating system dependent module activates the - * mode RX_ENABLE_PASS_SMT, the hardware module - * duplicates all SMT frames with the frame control - * FC_SMT_INFO and passes them to the LLC receive channel - * by calling mac_drv_rx_init. - * The SMT Frames which are sent by the local SMT and the NSA - * frames whose A- and C-Indicator is not set are also duplicated - * and passed. - * The receive mode RX_DISABLE_PASS_SMT disables the passing - * of SMT frames. - * - * RX_ENABLE_PASS_NSA / RX_DISABLE_PASS_NSA - * - * If the operating system dependent module activates the - * mode RX_ENABLE_PASS_NSA, the hardware module - * duplicates all NSA frames with frame control FC_SMT_NSA - * and a set A-Indicator and passed them to the LLC - * receive channel by calling mac_drv_rx_init. - * All NSA Frames which are sent by the local SMT - * are also duplicated and passed. - * The receive mode RX_DISABLE_PASS_NSA disables the passing - * of NSA frames with the A- or C-Indicator set. - * - * NOTE: For fear that the hardware module receives NSA frames with - * a reset A-Indicator, the operating system dependent module - * has to call mac_drv_rx_mode with the mode RX_ENABLE_NSA - * before activate the RX_ENABLE_PASS_NSA mode and after every - * 'driver reset' and 'set station address'. - * - * RX_ENABLE_PASS_DB / RX_DISABLE_PASS_DB - * - * If the operating system dependent module activates the - * mode RX_ENABLE_PASS_DB, direct BEACON frames - * (FC_BEACON frame control) are passed to the LLC receive - * channel by mac_drv_rx_init. - * The receive mode RX_DISABLE_PASS_DB disables the passing - * of direct BEACON frames. - * - * RX_DISABLE_PASS_ALL - * - * Disables all special receives modes. It is equal to - * call mac_drv_set_rx_mode successively with the - * parameters RX_DISABLE_NSA, RX_DISABLE_PASS_SMT, - * RX_DISABLE_PASS_NSA and RX_DISABLE_PASS_DB. - * - * RX_ENABLE_LLC_PROMISC - * - * (default) all received LLC frames and all SMT/NSA/DBEACON - * frames depending on the attitude of the flags - * PASS_SMT/PASS_NSA/PASS_DBEACON will be delivered to the - * LLC layer - * - * RX_DISABLE_LLC_PROMISC - * - * all received SMT/NSA/DBEACON frames depending on the - * attitude of the flags PASS_SMT/PASS_NSA/PASS_DBEACON - * will be delivered to the LLC layer. - * all received LLC frames with a directed address, Multicast - * or Broadcast address will be delivered to the LLC - * layer too. - * - * END_MANUAL_ENTRY - */ -void mac_drv_rx_mode(struct s_smc *smc, int mode) -{ - switch(mode) { - case RX_ENABLE_PASS_SMT: - smc->os.hwm.pass_SMT = TRUE ; - break ; - case RX_DISABLE_PASS_SMT: - smc->os.hwm.pass_SMT = FALSE ; - break ; - case RX_ENABLE_PASS_NSA: - smc->os.hwm.pass_NSA = TRUE ; - break ; - case RX_DISABLE_PASS_NSA: - smc->os.hwm.pass_NSA = FALSE ; - break ; - case RX_ENABLE_PASS_DB: - smc->os.hwm.pass_DB = TRUE ; - break ; - case RX_DISABLE_PASS_DB: - smc->os.hwm.pass_DB = FALSE ; - break ; - case RX_DISABLE_PASS_ALL: - smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = FALSE ; - smc->os.hwm.pass_DB = FALSE ; - smc->os.hwm.pass_llc_promisc = TRUE ; - mac_set_rx_mode(smc,RX_DISABLE_NSA) ; - break ; - case RX_DISABLE_LLC_PROMISC: - smc->os.hwm.pass_llc_promisc = FALSE ; - break ; - case RX_ENABLE_LLC_PROMISC: - smc->os.hwm.pass_llc_promisc = TRUE ; - break ; - case RX_ENABLE_ALLMULTI: - case RX_DISABLE_ALLMULTI: - case RX_ENABLE_PROMISC: - case RX_DISABLE_PROMISC: - case RX_ENABLE_NSA: - case RX_DISABLE_NSA: - default: - mac_set_rx_mode(smc,mode) ; - break ; - } -} -#endif /* ifndef NDIS_OS2 */ - -/* - * process receive queue - */ -void process_receive(struct s_smc *smc) -{ - int i ; - int n ; - int frag_count ; /* number of RxDs of the curr rx buf */ - int used_frags ; /* number of RxDs of the curr frame */ - struct s_smt_rx_queue *queue ; /* points to the queue ctl struct */ - struct s_smt_fp_rxd volatile *r ; /* rxd pointer */ - struct s_smt_fp_rxd volatile *rxd ; /* first rxd of rx frame */ - u_long rbctrl ; /* receive buffer control word */ - u_long rfsw ; /* receive frame status word */ - u_short rx_used ; - u_char far *virt ; - char far *data ; - SMbuf *mb ; - u_char fc ; /* Frame control */ - int len ; /* Frame length */ - - smc->os.hwm.detec_count = 0 ; - queue = smc->hw.fp.rx[QUEUE_R1] ; - NDD_TRACE("RHxB",0,0,0) ; - for ( ; ; ) { - r = queue->rx_curr_get ; - rx_used = queue->rx_used ; - frag_count = 0 ; - -#ifdef USE_BREAK_ISR - if (smc->os.hwm.leave_isr) { - goto rx_end ; - } -#endif -#ifdef NDIS_OS2 - if (offDepth) { - smc->os.hwm.rx_break = 1 ; - goto rx_end ; - } - smc->os.hwm.rx_break = 0 ; -#endif -#ifdef ODI2 - if (smc->os.hwm.rx_break) { - goto rx_end ; - } -#endif - n = 0 ; - do { - DB_RX("Check RxD %x for OWN and EOF",(void *)r,0,5) ; - DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; - rbctrl = le32_to_cpu(CR_READ(r->rxd_rbctrl)); - - if (rbctrl & BMU_OWN) { - NDD_TRACE("RHxE",r,rfsw,rbctrl) ; - DB_RX("End of RxDs",0,0,4) ; - goto rx_end ; - } - /* - * out of RxD detection - */ - if (!rx_used) { - SK_BREAK() ; - SMT_PANIC(smc,HWM_E0009,HWM_E0009_MSG) ; - /* Either we don't have an RxD or all - * RxDs are filled. Therefore it's allowed - * for to set the STOPPED flag */ - smc->hw.hw_state = STOPPED ; - mac_drv_clear_rx_queue(smc) ; - smc->hw.hw_state = STARTED ; - mac_drv_fill_rxd(smc) ; - smc->os.hwm.detec_count = 0 ; - goto rx_end ; - } - rfsw = le32_to_cpu(r->rxd_rfsw) ; - if ((rbctrl & BMU_STF) != ((rbctrl & BMU_ST_BUF) <<5)) { - /* - * The BMU_STF bit is deleted, 1 frame is - * placed into more than 1 rx buffer - * - * skip frame by setting the rx len to 0 - * - * if fragment count == 0 - * The missing STF bit belongs to the - * current frame, search for the - * EOF bit to complete the frame - * else - * the fragment belongs to the next frame, - * exit the loop and process the frame - */ - SK_BREAK() ; - rfsw = 0 ; - if (frag_count) { - break ; - } - } - n += rbctrl & 0xffff ; - r = r->rxd_next ; - frag_count++ ; - rx_used-- ; - } while (!(rbctrl & BMU_EOF)) ; - used_frags = frag_count ; - DB_RX("EOF set in RxD, used_frags = %d ",used_frags,0,5) ; - - /* may be next 2 DRV_BUF_FLUSH() can be skipped, because */ - /* BMU_ST_BUF will not be changed by the ASIC */ - DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; - while (rx_used && !(r->rxd_rbctrl & cpu_to_le32(BMU_ST_BUF))) { - DB_RX("Check STF bit in %x",(void *)r,0,5) ; - r = r->rxd_next ; - DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; - frag_count++ ; - rx_used-- ; - } - DB_RX("STF bit found",0,0,5) ; - - /* - * The received frame is finished for the process receive - */ - rxd = queue->rx_curr_get ; - queue->rx_curr_get = r ; - queue->rx_free += frag_count ; - queue->rx_used = rx_used ; - - /* - * ASIC Errata no. 7 (STF - Bit Bug) - */ - rxd->rxd_rbctrl &= cpu_to_le32(~BMU_STF) ; - - for (r=rxd, i=frag_count ; i ; r=r->rxd_next, i--){ - DB_RX("dma_complete for RxD %x",(void *)r,0,5) ; - dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR); - } - smc->hw.fp.err_stats.err_valid++ ; - smc->mib.m[MAC0].fddiMACCopied_Ct++ ; - - /* the length of the data including the FC */ - len = (rfsw & RD_LENGTH) - 4 ; - - DB_RX("frame length = %d",len,0,4) ; - /* - * check the frame_length and all error flags - */ - if (rfsw & (RX_MSRABT|RX_FS_E|RX_FS_CRC|RX_FS_IMPL)){ - if (rfsw & RD_S_MSRABT) { - DB_RX("Frame aborted by the FORMAC",0,0,2) ; - smc->hw.fp.err_stats.err_abort++ ; - } - /* - * check frame status - */ - if (rfsw & RD_S_SEAC2) { - DB_RX("E-Indicator set",0,0,2) ; - smc->hw.fp.err_stats.err_e_indicator++ ; - } - if (rfsw & RD_S_SFRMERR) { - DB_RX("CRC error",0,0,2) ; - smc->hw.fp.err_stats.err_crc++ ; - } - if (rfsw & RX_FS_IMPL) { - DB_RX("Implementer frame",0,0,2) ; - smc->hw.fp.err_stats.err_imp_frame++ ; - } - goto abort_frame ; - } - if (len > FDDI_RAW_MTU-4) { - DB_RX("Frame too long error",0,0,2) ; - smc->hw.fp.err_stats.err_too_long++ ; - goto abort_frame ; - } - /* - * SUPERNET 3 Bug: FORMAC delivers status words - * of aborded frames to the BMU - */ - if (len <= 4) { - DB_RX("Frame length = 0",0,0,2) ; - goto abort_frame ; - } - - if (len != (n-4)) { - DB_RX("BMU: rx len differs: [%d:%d]",len,n,4); - smc->os.hwm.rx_len_error++ ; - goto abort_frame ; - } - - /* - * Check SA == MA - */ - virt = (u_char far *) rxd->rxd_virt ; - DB_RX("FC = %x",*virt,0,2) ; - if (virt[12] == MA[5] && - virt[11] == MA[4] && - virt[10] == MA[3] && - virt[9] == MA[2] && - virt[8] == MA[1] && - (virt[7] & ~GROUP_ADDR_BIT) == MA[0]) { - goto abort_frame ; - } - - /* - * test if LLC frame - */ - if (rfsw & RX_FS_LLC) { - /* - * if pass_llc_promisc is disable - * if DA != Multicast or Broadcast or DA!=MA - * abort the frame - */ - if (!smc->os.hwm.pass_llc_promisc) { - if(!(virt[1] & GROUP_ADDR_BIT)) { - if (virt[6] != MA[5] || - virt[5] != MA[4] || - virt[4] != MA[3] || - virt[3] != MA[2] || - virt[2] != MA[1] || - virt[1] != MA[0]) { - DB_RX("DA != MA and not multi- or broadcast",0,0,2) ; - goto abort_frame ; - } - } - } - - /* - * LLC frame received - */ - DB_RX("LLC - receive",0,0,4) ; - mac_drv_rx_complete(smc,rxd,frag_count,len) ; - } - else { - if (!(mb = smt_get_mbuf(smc))) { - smc->hw.fp.err_stats.err_no_buf++ ; - DB_RX("No SMbuf; receive terminated",0,0,4) ; - goto abort_frame ; - } - data = smtod(mb,char *) - 1 ; - - /* - * copy the frame into a SMT_MBuf - */ -#ifdef USE_OS_CPY - hwm_cpy_rxd2mb(rxd,data,len) ; -#else - for (r=rxd, i=used_frags ; i ; r=r->rxd_next, i--){ - n = le32_to_cpu(r->rxd_rbctrl) & RD_LENGTH ; - DB_RX("cp SMT frame to mb: len = %d",n,0,6) ; - memcpy(data,r->rxd_virt,n) ; - data += n ; - } - data = smtod(mb,char *) - 1 ; -#endif - fc = *(char *)mb->sm_data = *data ; - mb->sm_len = len - 1 ; /* len - fc */ - data++ ; - - /* - * SMT frame received - */ - switch(fc) { - case FC_SMT_INFO : - smc->hw.fp.err_stats.err_smt_frame++ ; - DB_RX("SMT frame received ",0,0,5) ; - - if (smc->os.hwm.pass_SMT) { - DB_RX("pass SMT frame ",0,0,5) ; - mac_drv_rx_complete(smc, rxd, - frag_count,len) ; - } - else { - DB_RX("requeue RxD",0,0,5) ; - mac_drv_requeue_rxd(smc,rxd,frag_count); - } - - smt_received_pack(smc,mb,(int)(rfsw>>25)) ; - break ; - case FC_SMT_NSA : - smc->hw.fp.err_stats.err_smt_frame++ ; - DB_RX("SMT frame received ",0,0,5) ; - - /* if pass_NSA set pass the NSA frame or */ - /* pass_SMT set and the A-Indicator */ - /* is not set, pass the NSA frame */ - if (smc->os.hwm.pass_NSA || - (smc->os.hwm.pass_SMT && - !(rfsw & A_INDIC))) { - DB_RX("pass SMT frame ",0,0,5) ; - mac_drv_rx_complete(smc, rxd, - frag_count,len) ; - } - else { - DB_RX("requeue RxD",0,0,5) ; - mac_drv_requeue_rxd(smc,rxd,frag_count); - } - - smt_received_pack(smc,mb,(int)(rfsw>>25)) ; - break ; - case FC_BEACON : - if (smc->os.hwm.pass_DB) { - DB_RX("pass DB frame ",0,0,5) ; - mac_drv_rx_complete(smc, rxd, - frag_count,len) ; - } - else { - DB_RX("requeue RxD",0,0,5) ; - mac_drv_requeue_rxd(smc,rxd,frag_count); - } - smt_free_mbuf(smc,mb) ; - break ; - default : - /* - * unknown FC abord the frame - */ - DB_RX("unknown FC error",0,0,2) ; - smt_free_mbuf(smc,mb) ; - DB_RX("requeue RxD",0,0,5) ; - mac_drv_requeue_rxd(smc,rxd,frag_count) ; - if ((fc & 0xf0) == FC_MAC) - smc->hw.fp.err_stats.err_mac_frame++ ; - else - smc->hw.fp.err_stats.err_imp_frame++ ; - - break ; - } - } - - DB_RX("next RxD is %x ",queue->rx_curr_get,0,3) ; - NDD_TRACE("RHx1",queue->rx_curr_get,0,0) ; - - continue ; - /*--------------------------------------------------------------------*/ -abort_frame: - DB_RX("requeue RxD",0,0,5) ; - mac_drv_requeue_rxd(smc,rxd,frag_count) ; - - DB_RX("next RxD is %x ",queue->rx_curr_get,0,3) ; - NDD_TRACE("RHx2",queue->rx_curr_get,0,0) ; - } -rx_end: -#ifdef ALL_RX_COMPLETE - mac_drv_all_receives_complete(smc) ; -#endif - return ; /* lint bug: needs return detect end of function */ -} - -static void smt_to_llc(struct s_smc *smc, SMbuf *mb) -{ - u_char fc ; - - DB_RX("send a queued frame to the llc layer",0,0,4) ; - smc->os.hwm.r.len = mb->sm_len ; - smc->os.hwm.r.mb_pos = smtod(mb,char *) ; - fc = *smc->os.hwm.r.mb_pos ; - (void)mac_drv_rx_init(smc,(int)mb->sm_len,(int)fc, - smc->os.hwm.r.mb_pos,(int)mb->sm_len) ; - smt_free_mbuf(smc,mb) ; -} - -/* - * BEGIN_MANUAL_ENTRY(hwm_rx_frag) - * void hwm_rx_frag(smc,virt,phys,len,frame_status) - * - * function MACRO (hardware module, hwmtm.h) - * This function calls dma_master for preparing the - * system hardware for the DMA transfer and initializes - * the current RxD with the length and the physical and - * virtual address of the fragment. Furthermore, it sets the - * STF and EOF bits depending on the frame status byte, - * switches the OWN flag of the RxD, so that it is owned by the - * adapter and issues an rx_start. - * - * para virt virtual pointer to the fragment - * len the length of the fragment - * frame_status status of the frame, see design description - * - * NOTE: It is possible to call this function with a fragment length - * of zero. - * - * END_MANUAL_ENTRY - */ -void hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len, - int frame_status) -{ - struct s_smt_fp_rxd volatile *r ; - __le32 rbctrl; - - NDD_TRACE("RHfB",virt,len,frame_status) ; - DB_RX("hwm_rx_frag: len = %d, frame_status = %x\n",len,frame_status,2) ; - r = smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put ; - r->rxd_virt = virt ; - r->rxd_rbadr = cpu_to_le32(phys) ; - rbctrl = cpu_to_le32( (((__u32)frame_status & - (FIRST_FRAG|LAST_FRAG))<<26) | - (((u_long) frame_status & FIRST_FRAG) << 21) | - BMU_OWN | BMU_CHECK | BMU_EN_IRQ_EOF | len) ; - r->rxd_rbctrl = rbctrl ; - - DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; - outpd(ADDR(B0_R1_CSR),CSR_START) ; - smc->hw.fp.rx_q[QUEUE_R1].rx_free-- ; - smc->hw.fp.rx_q[QUEUE_R1].rx_used++ ; - smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put = r->rxd_next ; - NDD_TRACE("RHfE",r,le32_to_cpu(r->rxd_rbadr),0) ; -} - -/* - * BEGINN_MANUAL_ENTRY(mac_drv_clear_rx_queue) - * - * void mac_drv_clear_rx_queue(smc) - * struct s_smc *smc ; - * - * function DOWNCALL (hardware module, hwmtm.c) - * mac_drv_clear_rx_queue is called by the OS-specific module - * after it has issued a card_stop. - * In this case, the frames in the receive queue are obsolete and - * should be removed. For removing mac_drv_clear_rx_queue - * calls dma_master for each RxD and mac_drv_clear_rxd for each - * receive buffer. - * - * NOTE: calling sequence card_stop: - * CLI_FBI(), card_stop(), - * mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(), - * - * NOTE: The caller is responsible that the BMUs are idle - * when this function is called. - * - * END_MANUAL_ENTRY - */ -void mac_drv_clear_rx_queue(struct s_smc *smc) -{ - struct s_smt_fp_rxd volatile *r ; - struct s_smt_fp_rxd volatile *next_rxd ; - struct s_smt_rx_queue *queue ; - int frag_count ; - int i ; - - if (smc->hw.hw_state != STOPPED) { - SK_BREAK() ; - SMT_PANIC(smc,HWM_E0012,HWM_E0012_MSG) ; - return ; - } - - queue = smc->hw.fp.rx[QUEUE_R1] ; - DB_RX("clear_rx_queue",0,0,5) ; - - /* - * dma_complete and mac_drv_clear_rxd for all RxDs / receive buffers - */ - r = queue->rx_curr_get ; - while (queue->rx_used) { - DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; - DB_RX("switch OWN bit of RxD 0x%x ",r,0,5) ; - r->rxd_rbctrl &= ~cpu_to_le32(BMU_OWN) ; - frag_count = 1 ; - DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; - r = r->rxd_next ; - DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; - while (r != queue->rx_curr_put && - !(r->rxd_rbctrl & cpu_to_le32(BMU_ST_BUF))) { - DB_RX("Check STF bit in %x",(void *)r,0,5) ; - r->rxd_rbctrl &= ~cpu_to_le32(BMU_OWN) ; - DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; - r = r->rxd_next ; - DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; - frag_count++ ; - } - DB_RX("STF bit found",0,0,5) ; - next_rxd = r ; - - for (r=queue->rx_curr_get,i=frag_count; i ; r=r->rxd_next,i--){ - DB_RX("dma_complete for RxD %x",(void *)r,0,5) ; - dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR); - } - - DB_RX("mac_drv_clear_rxd: RxD %x frag_count %d ", - (void *)queue->rx_curr_get,frag_count,5) ; - mac_drv_clear_rxd(smc,queue->rx_curr_get,frag_count) ; - - queue->rx_curr_get = next_rxd ; - queue->rx_used -= frag_count ; - queue->rx_free += frag_count ; - } -} - - -/* - ------------------------------------------------------------- - SEND FUNCTIONS: - ------------------------------------------------------------- -*/ - -/* - * BEGIN_MANUAL_ENTRY(hwm_tx_init) - * int hwm_tx_init(smc,fc,frag_count,frame_len,frame_status) - * - * function DOWN_CALL (hardware module, hwmtm.c) - * hwm_tx_init checks if the frame can be sent through the - * corresponding send queue. - * - * para fc the frame control. To determine through which - * send queue the frame should be transmitted. - * 0x50 - 0x57: asynchronous LLC frame - * 0xD0 - 0xD7: synchronous LLC frame - * 0x41, 0x4F: SMT frame to the network - * 0x42: SMT frame to the network and to the local SMT - * 0x43: SMT frame to the local SMT - * frag_count count of the fragments for this frame - * frame_len length of the frame - * frame_status status of the frame, the send queue bit is already - * specified - * - * return frame_status - * - * END_MANUAL_ENTRY - */ -int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, int frame_len, - int frame_status) -{ - NDD_TRACE("THiB",fc,frag_count,frame_len) ; - smc->os.hwm.tx_p = smc->hw.fp.tx[frame_status & QUEUE_A0] ; - smc->os.hwm.tx_descr = TX_DESCRIPTOR | (((u_long)(frame_len-1)&3)<<27) ; - smc->os.hwm.tx_len = frame_len ; - DB_TX("hwm_tx_init: fc = %x, len = %d",fc,frame_len,3) ; - if ((fc & ~(FC_SYNC_BIT|FC_LLC_PRIOR)) == FC_ASYNC_LLC) { - frame_status |= LAN_TX ; - } - else { - switch (fc) { - case FC_SMT_INFO : - case FC_SMT_NSA : - frame_status |= LAN_TX ; - break ; - case FC_SMT_LOC : - frame_status |= LOC_TX ; - break ; - case FC_SMT_LAN_LOC : - frame_status |= LAN_TX | LOC_TX ; - break ; - default : - SMT_PANIC(smc,HWM_E0010,HWM_E0010_MSG) ; - } - } - if (!smc->hw.mac_ring_is_up) { - frame_status &= ~LAN_TX ; - frame_status |= RING_DOWN ; - DB_TX("Ring is down: terminate LAN_TX",0,0,2) ; - } - if (frag_count > smc->os.hwm.tx_p->tx_free) { -#ifndef NDIS_OS2 - mac_drv_clear_txd(smc) ; - if (frag_count > smc->os.hwm.tx_p->tx_free) { - DB_TX("Out of TxDs, terminate LAN_TX",0,0,2) ; - frame_status &= ~LAN_TX ; - frame_status |= OUT_OF_TXD ; - } -#else - DB_TX("Out of TxDs, terminate LAN_TX",0,0,2) ; - frame_status &= ~LAN_TX ; - frame_status |= OUT_OF_TXD ; -#endif - } - DB_TX("frame_status = %x",frame_status,0,3) ; - NDD_TRACE("THiE",frame_status,smc->os.hwm.tx_p->tx_free,0) ; - return frame_status; -} - -/* - * BEGIN_MANUAL_ENTRY(hwm_tx_frag) - * void hwm_tx_frag(smc,virt,phys,len,frame_status) - * - * function DOWNCALL (hardware module, hwmtm.c) - * If the frame should be sent to the LAN, this function calls - * dma_master, fills the current TxD with the virtual and the - * physical address, sets the STF and EOF bits dependent on - * the frame status, and requests the BMU to start the - * transmit. - * If the frame should be sent to the local SMT, an SMT_MBuf - * is allocated if the FIRST_FRAG bit is set in the frame_status. - * The fragment of the frame is copied into the SMT MBuf. - * The function smt_received_pack is called if the LAST_FRAG - * bit is set in the frame_status word. - * - * para virt virtual pointer to the fragment - * len the length of the fragment - * frame_status status of the frame, see design description - * - * return nothing returned, no parameter is modified - * - * NOTE: It is possible to invoke this macro with a fragment length - * of zero. - * - * END_MANUAL_ENTRY - */ -void hwm_tx_frag(struct s_smc *smc, char far *virt, u_long phys, int len, - int frame_status) -{ - struct s_smt_fp_txd volatile *t ; - struct s_smt_tx_queue *queue ; - __le32 tbctrl ; - - queue = smc->os.hwm.tx_p ; - - NDD_TRACE("THfB",virt,len,frame_status) ; - /* Bug fix: AF / May 31 1999 (#missing) - * snmpinfo problem reported by IBM is caused by invalid - * t-pointer (txd) if LAN_TX is not set but LOC_TX only. - * Set: t = queue->tx_curr_put here ! - */ - t = queue->tx_curr_put ; - - DB_TX("hwm_tx_frag: len = %d, frame_status = %x ",len,frame_status,2) ; - if (frame_status & LAN_TX) { - /* '*t' is already defined */ - DB_TX("LAN_TX: TxD = %x, virt = %x ",t,virt,3) ; - t->txd_virt = virt ; - t->txd_txdscr = cpu_to_le32(smc->os.hwm.tx_descr) ; - t->txd_tbadr = cpu_to_le32(phys) ; - tbctrl = cpu_to_le32((((__u32)frame_status & - (FIRST_FRAG|LAST_FRAG|EN_IRQ_EOF))<< 26) | - BMU_OWN|BMU_CHECK |len) ; - t->txd_tbctrl = tbctrl ; - -#ifndef AIX - DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; - outpd(queue->tx_bmu_ctl,CSR_START) ; -#else /* ifndef AIX */ - DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; - if (frame_status & QUEUE_A0) { - outpd(ADDR(B0_XA_CSR),CSR_START) ; - } - else { - outpd(ADDR(B0_XS_CSR),CSR_START) ; - } -#endif - queue->tx_free-- ; - queue->tx_used++ ; - queue->tx_curr_put = t->txd_next ; - if (frame_status & LAST_FRAG) { - smc->mib.m[MAC0].fddiMACTransmit_Ct++ ; - } - } - if (frame_status & LOC_TX) { - DB_TX("LOC_TX: ",0,0,3) ; - if (frame_status & FIRST_FRAG) { - if(!(smc->os.hwm.tx_mb = smt_get_mbuf(smc))) { - smc->hw.fp.err_stats.err_no_buf++ ; - DB_TX("No SMbuf; transmit terminated",0,0,4) ; - } - else { - smc->os.hwm.tx_data = - smtod(smc->os.hwm.tx_mb,char *) - 1 ; -#ifdef USE_OS_CPY -#ifdef PASS_1ST_TXD_2_TX_COMP - hwm_cpy_txd2mb(t,smc->os.hwm.tx_data, - smc->os.hwm.tx_len) ; -#endif -#endif - } - } - if (smc->os.hwm.tx_mb) { -#ifndef USE_OS_CPY - DB_TX("copy fragment into MBuf ",0,0,3) ; - memcpy(smc->os.hwm.tx_data,virt,len) ; - smc->os.hwm.tx_data += len ; -#endif - if (frame_status & LAST_FRAG) { -#ifdef USE_OS_CPY -#ifndef PASS_1ST_TXD_2_TX_COMP - /* - * hwm_cpy_txd2mb(txd,data,len) copies 'len' - * bytes from the virtual pointer in 'rxd' - * to 'data'. The virtual pointer of the - * os-specific tx-buffer should be written - * in the LAST txd. - */ - hwm_cpy_txd2mb(t,smc->os.hwm.tx_data, - smc->os.hwm.tx_len) ; -#endif /* nPASS_1ST_TXD_2_TX_COMP */ -#endif /* USE_OS_CPY */ - smc->os.hwm.tx_data = - smtod(smc->os.hwm.tx_mb,char *) - 1 ; - *(char *)smc->os.hwm.tx_mb->sm_data = - *smc->os.hwm.tx_data ; - smc->os.hwm.tx_data++ ; - smc->os.hwm.tx_mb->sm_len = - smc->os.hwm.tx_len - 1 ; - DB_TX("pass LLC frame to SMT ",0,0,3) ; - smt_received_pack(smc,smc->os.hwm.tx_mb, - RD_FS_LOCAL) ; - } - } - } - NDD_TRACE("THfE",t,queue->tx_free,0) ; -} - - -/* - * queues a receive for later send - */ -static void queue_llc_rx(struct s_smc *smc, SMbuf *mb) -{ - DB_GEN("queue_llc_rx: mb = %x",(void *)mb,0,4) ; - smc->os.hwm.queued_rx_frames++ ; - mb->sm_next = (SMbuf *)NULL ; - if (smc->os.hwm.llc_rx_pipe == NULL) { - smc->os.hwm.llc_rx_pipe = mb ; - } - else { - smc->os.hwm.llc_rx_tail->sm_next = mb ; - } - smc->os.hwm.llc_rx_tail = mb ; - - /* - * force an timer IRQ to receive the data - */ - if (!smc->os.hwm.isr_flag) { - smt_force_irq(smc) ; - } -} - -/* - * get a SMbuf from the llc_rx_queue - */ -static SMbuf *get_llc_rx(struct s_smc *smc) -{ - SMbuf *mb ; - - if ((mb = smc->os.hwm.llc_rx_pipe)) { - smc->os.hwm.queued_rx_frames-- ; - smc->os.hwm.llc_rx_pipe = mb->sm_next ; - } - DB_GEN("get_llc_rx: mb = 0x%x",(void *)mb,0,4) ; - return mb; -} - -/* - * queues a transmit SMT MBuf during the time were the MBuf is - * queued the TxD ring - */ -static void queue_txd_mb(struct s_smc *smc, SMbuf *mb) -{ - DB_GEN("_rx: queue_txd_mb = %x",(void *)mb,0,4) ; - smc->os.hwm.queued_txd_mb++ ; - mb->sm_next = (SMbuf *)NULL ; - if (smc->os.hwm.txd_tx_pipe == NULL) { - smc->os.hwm.txd_tx_pipe = mb ; - } - else { - smc->os.hwm.txd_tx_tail->sm_next = mb ; - } - smc->os.hwm.txd_tx_tail = mb ; -} - -/* - * get a SMbuf from the txd_tx_queue - */ -static SMbuf *get_txd_mb(struct s_smc *smc) -{ - SMbuf *mb ; - - if ((mb = smc->os.hwm.txd_tx_pipe)) { - smc->os.hwm.queued_txd_mb-- ; - smc->os.hwm.txd_tx_pipe = mb->sm_next ; - } - DB_GEN("get_txd_mb: mb = 0x%x",(void *)mb,0,4) ; - return mb; -} - -/* - * SMT Send function - */ -void smt_send_mbuf(struct s_smc *smc, SMbuf *mb, int fc) -{ - char far *data ; - int len ; - int n ; - int i ; - int frag_count ; - int frame_status ; - SK_LOC_DECL(char far,*virt[3]) ; - int frag_len[3] ; - struct s_smt_tx_queue *queue ; - struct s_smt_fp_txd volatile *t ; - u_long phys ; - __le32 tbctrl; - - NDD_TRACE("THSB",mb,fc,0) ; - DB_TX("smt_send_mbuf: mb = 0x%x, fc = 0x%x",mb,fc,4) ; - - mb->sm_off-- ; /* set to fc */ - mb->sm_len++ ; /* + fc */ - data = smtod(mb,char *) ; - *data = fc ; - if (fc == FC_SMT_LOC) - *data = FC_SMT_INFO ; - - /* - * determine the frag count and the virt addresses of the frags - */ - frag_count = 0 ; - len = mb->sm_len ; - while (len) { - n = SMT_PAGESIZE - ((long)data & (SMT_PAGESIZE-1)) ; - if (n >= len) { - n = len ; - } - DB_TX("frag: virt/len = 0x%x/%d ",(void *)data,n,5) ; - virt[frag_count] = data ; - frag_len[frag_count] = n ; - frag_count++ ; - len -= n ; - data += n ; - } - - /* - * determine the frame status - */ - queue = smc->hw.fp.tx[QUEUE_A0] ; - if (fc == FC_BEACON || fc == FC_SMT_LOC) { - frame_status = LOC_TX ; - } - else { - frame_status = LAN_TX ; - if ((smc->os.hwm.pass_NSA &&(fc == FC_SMT_NSA)) || - (smc->os.hwm.pass_SMT &&(fc == FC_SMT_INFO))) - frame_status |= LOC_TX ; - } - - if (!smc->hw.mac_ring_is_up || frag_count > queue->tx_free) { - frame_status &= ~LAN_TX; - if (frame_status) { - DB_TX("Ring is down: terminate LAN_TX",0,0,2) ; - } - else { - DB_TX("Ring is down: terminate transmission",0,0,2) ; - smt_free_mbuf(smc,mb) ; - return ; - } - } - DB_TX("frame_status = 0x%x ",frame_status,0,5) ; - - if ((frame_status & LAN_TX) && (frame_status & LOC_TX)) { - mb->sm_use_count = 2 ; - } - - if (frame_status & LAN_TX) { - t = queue->tx_curr_put ; - frame_status |= FIRST_FRAG ; - for (i = 0; i < frag_count; i++) { - DB_TX("init TxD = 0x%x",(void *)t,0,5) ; - if (i == frag_count-1) { - frame_status |= LAST_FRAG ; - t->txd_txdscr = cpu_to_le32(TX_DESCRIPTOR | - (((__u32)(mb->sm_len-1)&3) << 27)) ; - } - t->txd_virt = virt[i] ; - phys = dma_master(smc, (void far *)virt[i], - frag_len[i], DMA_RD|SMT_BUF) ; - t->txd_tbadr = cpu_to_le32(phys) ; - tbctrl = cpu_to_le32((((__u32)frame_status & - (FIRST_FRAG|LAST_FRAG)) << 26) | - BMU_OWN | BMU_CHECK | BMU_SMT_TX |frag_len[i]) ; - t->txd_tbctrl = tbctrl ; -#ifndef AIX - DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; - outpd(queue->tx_bmu_ctl,CSR_START) ; -#else - DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; - outpd(ADDR(B0_XA_CSR),CSR_START) ; -#endif - frame_status &= ~FIRST_FRAG ; - queue->tx_curr_put = t = t->txd_next ; - queue->tx_free-- ; - queue->tx_used++ ; - } - smc->mib.m[MAC0].fddiMACTransmit_Ct++ ; - queue_txd_mb(smc,mb) ; - } - - if (frame_status & LOC_TX) { - DB_TX("pass Mbuf to LLC queue",0,0,5) ; - queue_llc_rx(smc,mb) ; - } - - /* - * We need to unqueue the free SMT_MBUFs here, because it may - * be that the SMT want's to send more than 1 frame for one down call - */ - mac_drv_clear_txd(smc) ; - NDD_TRACE("THSE",t,queue->tx_free,frag_count) ; -} - -/* BEGIN_MANUAL_ENTRY(mac_drv_clear_txd) - * void mac_drv_clear_txd(smc) - * - * function DOWNCALL (hardware module, hwmtm.c) - * mac_drv_clear_txd searches in both send queues for TxD's - * which were finished by the adapter. It calls dma_complete - * for each TxD. If the last fragment of an LLC frame is - * reached, it calls mac_drv_tx_complete to release the - * send buffer. - * - * return nothing - * - * END_MANUAL_ENTRY - */ -static void mac_drv_clear_txd(struct s_smc *smc) -{ - struct s_smt_tx_queue *queue ; - struct s_smt_fp_txd volatile *t1 ; - struct s_smt_fp_txd volatile *t2 = NULL ; - SMbuf *mb ; - u_long tbctrl ; - int i ; - int frag_count ; - int n ; - - NDD_TRACE("THcB",0,0,0) ; - for (i = QUEUE_S; i <= QUEUE_A0; i++) { - queue = smc->hw.fp.tx[i] ; - t1 = queue->tx_curr_get ; - DB_TX("clear_txd: QUEUE = %d (0=sync/1=async)",i,0,5) ; - - for ( ; ; ) { - frag_count = 0 ; - - do { - DRV_BUF_FLUSH(t1,DDI_DMA_SYNC_FORCPU) ; - DB_TX("check OWN/EOF bit of TxD 0x%x",t1,0,5) ; - tbctrl = le32_to_cpu(CR_READ(t1->txd_tbctrl)); - - if (tbctrl & BMU_OWN || !queue->tx_used){ - DB_TX("End of TxDs queue %d",i,0,4) ; - goto free_next_queue ; /* next queue */ - } - t1 = t1->txd_next ; - frag_count++ ; - } while (!(tbctrl & BMU_EOF)) ; - - t1 = queue->tx_curr_get ; - for (n = frag_count; n; n--) { - tbctrl = le32_to_cpu(t1->txd_tbctrl) ; - dma_complete(smc, - (union s_fp_descr volatile *) t1, - (int) (DMA_RD | - ((tbctrl & BMU_SMT_TX) >> 18))) ; - t2 = t1 ; - t1 = t1->txd_next ; - } - - if (tbctrl & BMU_SMT_TX) { - mb = get_txd_mb(smc) ; - smt_free_mbuf(smc,mb) ; - } - else { -#ifndef PASS_1ST_TXD_2_TX_COMP - DB_TX("mac_drv_tx_comp for TxD 0x%x",t2,0,4) ; - mac_drv_tx_complete(smc,t2) ; -#else - DB_TX("mac_drv_tx_comp for TxD 0x%x", - queue->tx_curr_get,0,4) ; - mac_drv_tx_complete(smc,queue->tx_curr_get) ; -#endif - } - queue->tx_curr_get = t1 ; - queue->tx_free += frag_count ; - queue->tx_used -= frag_count ; - } -free_next_queue: ; - } - NDD_TRACE("THcE",0,0,0) ; -} - -/* - * BEGINN_MANUAL_ENTRY(mac_drv_clear_tx_queue) - * - * void mac_drv_clear_tx_queue(smc) - * struct s_smc *smc ; - * - * function DOWNCALL (hardware module, hwmtm.c) - * mac_drv_clear_tx_queue is called from the SMT when - * the RMT state machine has entered the ISOLATE state. - * This function is also called by the os-specific module - * after it has called the function card_stop(). - * In this case, the frames in the send queues are obsolete and - * should be removed. - * - * note calling sequence: - * CLI_FBI(), card_stop(), - * mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(), - * - * NOTE: The caller is responsible that the BMUs are idle - * when this function is called. - * - * END_MANUAL_ENTRY - */ -void mac_drv_clear_tx_queue(struct s_smc *smc) -{ - struct s_smt_fp_txd volatile *t ; - struct s_smt_tx_queue *queue ; - int tx_used ; - int i ; - - if (smc->hw.hw_state != STOPPED) { - SK_BREAK() ; - SMT_PANIC(smc,HWM_E0011,HWM_E0011_MSG) ; - return ; - } - - for (i = QUEUE_S; i <= QUEUE_A0; i++) { - queue = smc->hw.fp.tx[i] ; - DB_TX("clear_tx_queue: QUEUE = %d (0=sync/1=async)",i,0,5) ; - - /* - * switch the OWN bit of all pending frames to the host - */ - t = queue->tx_curr_get ; - tx_used = queue->tx_used ; - while (tx_used) { - DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ; - DB_TX("switch OWN bit of TxD 0x%x ",t,0,5) ; - t->txd_tbctrl &= ~cpu_to_le32(BMU_OWN) ; - DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; - t = t->txd_next ; - tx_used-- ; - } - } - - /* - * release all TxD's for both send queues - */ - mac_drv_clear_txd(smc) ; - - for (i = QUEUE_S; i <= QUEUE_A0; i++) { - queue = smc->hw.fp.tx[i] ; - t = queue->tx_curr_get ; - - /* - * write the phys pointer of the NEXT descriptor into the - * BMU's current address descriptor pointer and set - * tx_curr_get and tx_curr_put to this position - */ - if (i == QUEUE_S) { - outpd(ADDR(B5_XS_DA),le32_to_cpu(t->txd_ntdadr)) ; - } - else { - outpd(ADDR(B5_XA_DA),le32_to_cpu(t->txd_ntdadr)) ; - } - - queue->tx_curr_put = queue->tx_curr_get->txd_next ; - queue->tx_curr_get = queue->tx_curr_put ; - } -} - - -/* - ------------------------------------------------------------- - TEST FUNCTIONS: - ------------------------------------------------------------- -*/ - -#ifdef DEBUG -/* - * BEGIN_MANUAL_ENTRY(mac_drv_debug_lev) - * void mac_drv_debug_lev(smc,flag,lev) - * - * function DOWNCALL (drvsr.c) - * To get a special debug info the user can assign a debug level - * to any debug flag. - * - * para flag debug flag, possible values are: - * = 0: reset all debug flags (the defined level is - * ignored) - * = 1: debug.d_smtf - * = 2: debug.d_smt - * = 3: debug.d_ecm - * = 4: debug.d_rmt - * = 5: debug.d_cfm - * = 6: debug.d_pcm - * - * = 10: debug.d_os.hwm_rx (hardware module receive path) - * = 11: debug.d_os.hwm_tx(hardware module transmit path) - * = 12: debug.d_os.hwm_gen(hardware module general flag) - * - * lev debug level - * - * END_MANUAL_ENTRY - */ -void mac_drv_debug_lev(struct s_smc *smc, int flag, int lev) -{ - switch(flag) { - case (int)NULL: - DB_P.d_smtf = DB_P.d_smt = DB_P.d_ecm = DB_P.d_rmt = 0 ; - DB_P.d_cfm = 0 ; - DB_P.d_os.hwm_rx = DB_P.d_os.hwm_tx = DB_P.d_os.hwm_gen = 0 ; -#ifdef SBA - DB_P.d_sba = 0 ; -#endif -#ifdef ESS - DB_P.d_ess = 0 ; -#endif - break ; - case DEBUG_SMTF: - DB_P.d_smtf = lev ; - break ; - case DEBUG_SMT: - DB_P.d_smt = lev ; - break ; - case DEBUG_ECM: - DB_P.d_ecm = lev ; - break ; - case DEBUG_RMT: - DB_P.d_rmt = lev ; - break ; - case DEBUG_CFM: - DB_P.d_cfm = lev ; - break ; - case DEBUG_PCM: - DB_P.d_pcm = lev ; - break ; - case DEBUG_SBA: -#ifdef SBA - DB_P.d_sba = lev ; -#endif - break ; - case DEBUG_ESS: -#ifdef ESS - DB_P.d_ess = lev ; -#endif - break ; - case DB_HWM_RX: - DB_P.d_os.hwm_rx = lev ; - break ; - case DB_HWM_TX: - DB_P.d_os.hwm_tx = lev ; - break ; - case DB_HWM_GEN: - DB_P.d_os.hwm_gen = lev ; - break ; - default: - break ; - } -} -#endif diff --git a/drivers/net/skfp/hwt.c b/drivers/net/skfp/hwt.c deleted file mode 100644 index c0798fd..0000000 --- a/drivers/net/skfp/hwt.c +++ /dev/null @@ -1,269 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - * Timer Driver for FBI board (timer chip 82C54) - */ - -/* - * Modifications: - * - * 28-Jun-1994 sw Edit v1.6. - * MCA: Added support for the SK-NET FDDI-FM2 adapter. The - * following functions have been added(+) or modified(*): - * hwt_start(*), hwt_stop(*), hwt_restart(*), hwt_read(*) - */ - -#include "h/types.h" -#include "h/fddi.h" -#include "h/smc.h" - -#ifndef lint -static const char ID_sccs[] = "@(#)hwt.c 1.13 97/04/23 (C) SK " ; -#endif - -/* - * Prototypes of local functions. - */ -/* 28-Jun-1994 sw - Note: hwt_restart() is also used in module 'drvfbi.c'. */ -/*static void hwt_restart() ; */ - -/************************ - * - * hwt_start - * - * Start hardware timer (clock ticks are 16us). - * - * void hwt_start( - * struct s_smc *smc, - * u_long time) ; - * In - * smc - A pointer to the SMT Context structure. - * - * time - The time in units of 16us to load the timer with. - * Out - * Nothing. - * - ************************/ -#define HWT_MAX (65000) - -void hwt_start(struct s_smc *smc, u_long time) -{ - u_short cnt ; - - if (time > HWT_MAX) - time = HWT_MAX ; - - smc->hw.t_start = time ; - smc->hw.t_stop = 0L ; - - cnt = (u_short)time ; - /* - * if time < 16 us - * time = 16 us - */ - if (!cnt) - cnt++ ; - - outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ; /* Load timer value. */ - outpw(ADDR(B2_TI_CRTL), TIM_START) ; /* Start timer. */ - - smc->hw.timer_activ = TRUE ; -} - -/************************ - * - * hwt_stop - * - * Stop hardware timer. - * - * void hwt_stop( - * struct s_smc *smc) ; - * In - * smc - A pointer to the SMT Context structure. - * Out - * Nothing. - * - ************************/ -void hwt_stop(struct s_smc *smc) -{ - outpw(ADDR(B2_TI_CRTL), TIM_STOP) ; - outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ; - - smc->hw.timer_activ = FALSE ; -} - -/************************ - * - * hwt_init - * - * Initialize hardware timer. - * - * void hwt_init( - * struct s_smc *smc) ; - * In - * smc - A pointer to the SMT Context structure. - * Out - * Nothing. - * - ************************/ -void hwt_init(struct s_smc *smc) -{ - smc->hw.t_start = 0 ; - smc->hw.t_stop = 0 ; - smc->hw.timer_activ = FALSE ; - - hwt_restart(smc) ; -} - -/************************ - * - * hwt_restart - * - * Clear timer interrupt. - * - * void hwt_restart( - * struct s_smc *smc) ; - * In - * smc - A pointer to the SMT Context structure. - * Out - * Nothing. - * - ************************/ -void hwt_restart(struct s_smc *smc) -{ - hwt_stop(smc) ; -} - -/************************ - * - * hwt_read - * - * Stop hardware timer and read time elapsed since last start. - * - * u_long hwt_read(smc) ; - * In - * smc - A pointer to the SMT Context structure. - * Out - * The elapsed time since last start in units of 16us. - * - ************************/ -u_long hwt_read(struct s_smc *smc) -{ - u_short tr ; - u_long is ; - - if (smc->hw.timer_activ) { - hwt_stop(smc) ; - tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ; - - is = GET_ISR() ; - /* Check if timer expired (or wraparound). */ - if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) { - hwt_restart(smc) ; - smc->hw.t_stop = smc->hw.t_start ; - } - else - smc->hw.t_stop = smc->hw.t_start - tr ; - } - return smc->hw.t_stop; -} - -#ifdef PCI -/************************ - * - * hwt_quick_read - * - * Stop hardware timer and read timer value and start the timer again. - * - * u_long hwt_read(smc) ; - * In - * smc - A pointer to the SMT Context structure. - * Out - * current timer value in units of 80ns. - * - ************************/ -u_long hwt_quick_read(struct s_smc *smc) -{ - u_long interval ; - u_long time ; - - interval = inpd(ADDR(B2_TI_INI)) ; - outpw(ADDR(B2_TI_CRTL), TIM_STOP) ; - time = inpd(ADDR(B2_TI_VAL)) ; - outpd(ADDR(B2_TI_INI),time) ; - outpw(ADDR(B2_TI_CRTL), TIM_START) ; - outpd(ADDR(B2_TI_INI),interval) ; - - return time; -} - -/************************ - * - * hwt_wait_time(smc,start,duration) - * - * This function returnes after the amount of time is elapsed - * since the start time. - * - * para start start time - * duration time to wait - * - * NOTE: The function will return immediately, if the timer is not - * started - ************************/ -void hwt_wait_time(struct s_smc *smc, u_long start, long int duration) -{ - long diff ; - long interval ; - int wrapped ; - - /* - * check if timer is running - */ - if (smc->hw.timer_activ == FALSE || - hwt_quick_read(smc) == hwt_quick_read(smc)) { - return ; - } - - interval = inpd(ADDR(B2_TI_INI)) ; - if (interval > duration) { - do { - diff = (long)(start - hwt_quick_read(smc)) ; - if (diff < 0) { - diff += interval ; - } - } while (diff <= duration) ; - } - else { - diff = interval ; - wrapped = 0 ; - do { - if (!wrapped) { - if (hwt_quick_read(smc) >= start) { - diff += interval ; - wrapped = 1 ; - } - } - else { - if (hwt_quick_read(smc) < start) { - wrapped = 0 ; - } - } - } while (diff <= duration) ; - } -} -#endif - diff --git a/drivers/net/skfp/pcmplc.c b/drivers/net/skfp/pcmplc.c deleted file mode 100644 index 88d02d0..0000000 --- a/drivers/net/skfp/pcmplc.c +++ /dev/null @@ -1,2014 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - PCM - Physical Connection Management -*/ - -/* - * Hardware independent state machine implemantation - * The following external SMT functions are referenced : - * - * queue_event() - * smt_timer_start() - * smt_timer_stop() - * - * The following external HW dependent functions are referenced : - * sm_pm_control() - * sm_ph_linestate() - * sm_pm_ls_latch() - * - * The following HW dependent events are required : - * PC_QLS - * PC_ILS - * PC_HLS - * PC_MLS - * PC_NSE - * PC_LEM - * - */ - - -#include "h/types.h" -#include "h/fddi.h" -#include "h/smc.h" -#include "h/supern_2.h" -#define KERNEL -#include "h/smtstate.h" - -#ifndef lint -static const char ID_sccs[] = "@(#)pcmplc.c 2.55 99/08/05 (C) SK " ; -#endif - -#ifdef FDDI_MIB -extern int snmp_fddi_trap( -#ifdef ANSIC -struct s_smc * smc, int type, int index -#endif -); -#endif -#ifdef CONCENTRATOR -extern int plc_is_installed( -#ifdef ANSIC -struct s_smc *smc , -int p -#endif -) ; -#endif -/* - * FSM Macros - */ -#define AFLAG (0x20) -#define GO_STATE(x) (mib->fddiPORTPCMState = (x)|AFLAG) -#define ACTIONS_DONE() (mib->fddiPORTPCMState &= ~AFLAG) -#define ACTIONS(x) (x|AFLAG) - -/* - * PCM states - */ -#define PC0_OFF 0 -#define PC1_BREAK 1 -#define PC2_TRACE 2 -#define PC3_CONNECT 3 -#define PC4_NEXT 4 -#define PC5_SIGNAL 5 -#define PC6_JOIN 6 -#define PC7_VERIFY 7 -#define PC8_ACTIVE 8 -#define PC9_MAINT 9 - -#ifdef DEBUG -/* - * symbolic state names - */ -static const char * const pcm_states[] = { - "PC0_OFF","PC1_BREAK","PC2_TRACE","PC3_CONNECT","PC4_NEXT", - "PC5_SIGNAL","PC6_JOIN","PC7_VERIFY","PC8_ACTIVE","PC9_MAINT" -} ; - -/* - * symbolic event names - */ -static const char * const pcm_events[] = { - "NONE","PC_START","PC_STOP","PC_LOOP","PC_JOIN","PC_SIGNAL", - "PC_REJECT","PC_MAINT","PC_TRACE","PC_PDR", - "PC_ENABLE","PC_DISABLE", - "PC_QLS","PC_ILS","PC_MLS","PC_HLS","PC_LS_PDR","PC_LS_NONE", - "PC_TIMEOUT_TB_MAX","PC_TIMEOUT_TB_MIN", - "PC_TIMEOUT_C_MIN","PC_TIMEOUT_T_OUT", - "PC_TIMEOUT_TL_MIN","PC_TIMEOUT_T_NEXT","PC_TIMEOUT_LCT", - "PC_NSE","PC_LEM" -} ; -#endif - -#ifdef MOT_ELM -/* - * PCL-S control register - * this register in the PLC-S controls the scrambling parameters - */ -#define PLCS_CONTROL_C_U 0 -#define PLCS_CONTROL_C_S (PL_C_SDOFF_ENABLE | PL_C_SDON_ENABLE | \ - PL_C_CIPHER_ENABLE) -#define PLCS_FASSERT_U 0 -#define PLCS_FASSERT_S 0xFd76 /* 52.0 us */ -#define PLCS_FDEASSERT_U 0 -#define PLCS_FDEASSERT_S 0 -#else /* nMOT_ELM */ -/* - * PCL-S control register - * this register in the PLC-S controls the scrambling parameters - * can be patched for ANSI compliance if standard changes - */ -static const u_char plcs_control_c_u[17] = "PLC_CNTRL_C_U=\0\0" ; -static const u_char plcs_control_c_s[17] = "PLC_CNTRL_C_S=\01\02" ; - -#define PLCS_CONTROL_C_U (plcs_control_c_u[14] | (plcs_control_c_u[15]<<8)) -#define PLCS_CONTROL_C_S (plcs_control_c_s[14] | (plcs_control_c_s[15]<<8)) -#endif /* nMOT_ELM */ - -/* - * external vars - */ -/* struct definition see 'cmtdef.h' (also used by CFM) */ - -#define PS_OFF 0 -#define PS_BIT3 1 -#define PS_BIT4 2 -#define PS_BIT7 3 -#define PS_LCT 4 -#define PS_BIT8 5 -#define PS_JOIN 6 -#define PS_ACTIVE 7 - -#define LCT_LEM_MAX 255 - -/* - * PLC timing parameter - */ - -#define PLC_MS(m) ((int)((0x10000L-(m*100000L/2048)))) -#define SLOW_TL_MIN PLC_MS(6) -#define SLOW_C_MIN PLC_MS(10) - -static const struct plt { - int timer ; /* relative plc timer address */ - int para ; /* default timing parameters */ -} pltm[] = { - { PL_C_MIN, SLOW_C_MIN }, /* min t. to remain Connect State */ - { PL_TL_MIN, SLOW_TL_MIN }, /* min t. to transmit a Line State */ - { PL_TB_MIN, TP_TB_MIN }, /* min break time */ - { PL_T_OUT, TP_T_OUT }, /* Signaling timeout */ - { PL_LC_LENGTH, TP_LC_LENGTH }, /* Link Confidence Test Time */ - { PL_T_SCRUB, TP_T_SCRUB }, /* Scrub Time == MAC TVX time ! */ - { PL_NS_MAX, TP_NS_MAX }, /* max t. that noise is tolerated */ - { 0,0 } -} ; - -/* - * interrupt mask - */ -#ifdef SUPERNET_3 -/* - * Do we need the EBUF error during signaling, too, to detect SUPERNET_3 - * PLL bug? - */ -static const int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | - PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR; -#else /* SUPERNET_3 */ -/* - * We do NOT need the elasticity buffer error during signaling. - */ -static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | - PL_PCM_ENABLED | PL_SELF_TEST ; -#endif /* SUPERNET_3 */ -static const int plc_imsk_act = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | - PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR; - -/* internal functions */ -static void pcm_fsm(struct s_smc *smc, struct s_phy *phy, int cmd); -static void pc_rcode_actions(struct s_smc *smc, int bit, struct s_phy *phy); -static void pc_tcode_actions(struct s_smc *smc, const int bit, struct s_phy *phy); -static void reset_lem_struct(struct s_phy *phy); -static void plc_init(struct s_smc *smc, int p); -static void sm_ph_lem_start(struct s_smc *smc, int np, int threshold); -static void sm_ph_lem_stop(struct s_smc *smc, int np); -static void sm_ph_linestate(struct s_smc *smc, int phy, int ls); -static void real_init_plc(struct s_smc *smc); - -/* - * SMT timer interface - * start PCM timer 0 - */ -static void start_pcm_timer0(struct s_smc *smc, u_long value, int event, - struct s_phy *phy) -{ - phy->timer0_exp = FALSE ; /* clear timer event flag */ - smt_timer_start(smc,&phy->pcm_timer0,value, - EV_TOKEN(EVENT_PCM+phy->np,event)) ; -} -/* - * SMT timer interface - * stop PCM timer 0 - */ -static void stop_pcm_timer0(struct s_smc *smc, struct s_phy *phy) -{ - if (phy->pcm_timer0.tm_active) - smt_timer_stop(smc,&phy->pcm_timer0) ; -} - -/* - init PCM state machine (called by driver) - clear all PCM vars and flags -*/ -void pcm_init(struct s_smc *smc) -{ - int i ; - int np ; - struct s_phy *phy ; - struct fddi_mib_p *mib ; - - for (np = 0,phy = smc->y ; np < NUMPHYS ; np++,phy++) { - /* Indicates the type of PHY being used */ - mib = phy->mib ; - mib->fddiPORTPCMState = ACTIONS(PC0_OFF) ; - phy->np = np ; - switch (smc->s.sas) { -#ifdef CONCENTRATOR - case SMT_SAS : - mib->fddiPORTMy_Type = (np == PS) ? TS : TM ; - break ; - case SMT_DAS : - mib->fddiPORTMy_Type = (np == PA) ? TA : - (np == PB) ? TB : TM ; - break ; - case SMT_NAC : - mib->fddiPORTMy_Type = TM ; - break; -#else - case SMT_SAS : - mib->fddiPORTMy_Type = (np == PS) ? TS : TNONE ; - mib->fddiPORTHardwarePresent = (np == PS) ? TRUE : - FALSE ; -#ifndef SUPERNET_3 - smc->y[PA].mib->fddiPORTPCMState = PC0_OFF ; -#else - smc->y[PB].mib->fddiPORTPCMState = PC0_OFF ; -#endif - break ; - case SMT_DAS : - mib->fddiPORTMy_Type = (np == PB) ? TB : TA ; - break ; -#endif - } - /* - * set PMD-type - */ - phy->pmd_scramble = 0 ; - switch (phy->pmd_type[PMD_SK_PMD]) { - case 'P' : - mib->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ; - break ; - case 'L' : - mib->fddiPORTPMDClass = MIB_PMDCLASS_LCF ; - break ; - case 'D' : - mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; - break ; - case 'S' : - mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; - phy->pmd_scramble = TRUE ; - break ; - case 'U' : - mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; - phy->pmd_scramble = TRUE ; - break ; - case '1' : - mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ; - break ; - case '2' : - mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ; - break ; - case '3' : - mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ; - break ; - case '4' : - mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ; - break ; - case 'H' : - mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ; - break ; - case 'I' : - mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; - break ; - case 'G' : - mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; - break ; - default: - mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ; - break ; - } - /* - * A and B port can be on primary and secondary path - */ - switch (mib->fddiPORTMy_Type) { - case TA : - mib->fddiPORTAvailablePaths |= MIB_PATH_S ; - mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; - mib->fddiPORTRequestedPaths[2] = - MIB_P_PATH_LOCAL | - MIB_P_PATH_CON_ALTER | - MIB_P_PATH_SEC_PREFER ; - mib->fddiPORTRequestedPaths[3] = - MIB_P_PATH_LOCAL | - MIB_P_PATH_CON_ALTER | - MIB_P_PATH_SEC_PREFER | - MIB_P_PATH_THRU ; - break ; - case TB : - mib->fddiPORTAvailablePaths |= MIB_PATH_S ; - mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; - mib->fddiPORTRequestedPaths[2] = - MIB_P_PATH_LOCAL | - MIB_P_PATH_PRIM_PREFER ; - mib->fddiPORTRequestedPaths[3] = - MIB_P_PATH_LOCAL | - MIB_P_PATH_PRIM_PREFER | - MIB_P_PATH_CON_PREFER | - MIB_P_PATH_THRU ; - break ; - case TS : - mib->fddiPORTAvailablePaths |= MIB_PATH_S ; - mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; - mib->fddiPORTRequestedPaths[2] = - MIB_P_PATH_LOCAL | - MIB_P_PATH_CON_ALTER | - MIB_P_PATH_PRIM_PREFER ; - mib->fddiPORTRequestedPaths[3] = - MIB_P_PATH_LOCAL | - MIB_P_PATH_CON_ALTER | - MIB_P_PATH_PRIM_PREFER ; - break ; - case TM : - mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; - mib->fddiPORTRequestedPaths[2] = - MIB_P_PATH_LOCAL | - MIB_P_PATH_SEC_ALTER | - MIB_P_PATH_PRIM_ALTER ; - mib->fddiPORTRequestedPaths[3] = 0 ; - break ; - } - - phy->pc_lem_fail = FALSE ; - mib->fddiPORTPCMStateX = mib->fddiPORTPCMState ; - mib->fddiPORTLCTFail_Ct = 0 ; - mib->fddiPORTBS_Flag = 0 ; - mib->fddiPORTCurrentPath = MIB_PATH_ISOLATED ; - mib->fddiPORTNeighborType = TNONE ; - phy->ls_flag = 0 ; - phy->rc_flag = 0 ; - phy->tc_flag = 0 ; - phy->td_flag = 0 ; - if (np >= PM) - phy->phy_name = '0' + np - PM ; - else - phy->phy_name = 'A' + np ; - phy->wc_flag = FALSE ; /* set by SMT */ - memset((char *)&phy->lem,0,sizeof(struct lem_counter)) ; - reset_lem_struct(phy) ; - memset((char *)&phy->plc,0,sizeof(struct s_plc)) ; - phy->plc.p_state = PS_OFF ; - for (i = 0 ; i < NUMBITS ; i++) { - phy->t_next[i] = 0 ; - } - } - real_init_plc(smc) ; -} - -void init_plc(struct s_smc *smc) -{ - SK_UNUSED(smc) ; - - /* - * dummy - * this is an obsolete public entry point that has to remain - * for compat. It is used by various drivers. - * the work is now done in real_init_plc() - * which is called from pcm_init() ; - */ -} - -static void real_init_plc(struct s_smc *smc) -{ - int p ; - - for (p = 0 ; p < NUMPHYS ; p++) - plc_init(smc,p) ; -} - -static void plc_init(struct s_smc *smc, int p) -{ - int i ; -#ifndef MOT_ELM - int rev ; /* Revision of PLC-x */ -#endif /* MOT_ELM */ - - /* transit PCM state machine to MAINT state */ - outpw(PLC(p,PL_CNTRL_B),0) ; - outpw(PLC(p,PL_CNTRL_B),PL_PCM_STOP) ; - outpw(PLC(p,PL_CNTRL_A),0) ; - - /* - * if PLC-S then set control register C - */ -#ifndef MOT_ELM - rev = inpw(PLC(p,PL_STATUS_A)) & PLC_REV_MASK ; - if (rev != PLC_REVISION_A) -#endif /* MOT_ELM */ - { - if (smc->y[p].pmd_scramble) { - outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_S) ; -#ifdef MOT_ELM - outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_S) ; - outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_S) ; -#endif /* MOT_ELM */ - } - else { - outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_U) ; -#ifdef MOT_ELM - outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_U) ; - outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_U) ; -#endif /* MOT_ELM */ - } - } - - /* - * set timer register - */ - for ( i = 0 ; pltm[i].timer; i++) /* set timer parameter reg */ - outpw(PLC(p,pltm[i].timer),pltm[i].para) ; - - (void)inpw(PLC(p,PL_INTR_EVENT)) ; /* clear interrupt event reg */ - plc_clear_irq(smc,p) ; - outpw(PLC(p,PL_INTR_MASK),plc_imsk_na); /* enable non active irq's */ - - /* - * if PCM is configured for class s, it will NOT go to the - * REMOVE state if offline (page 3-36;) - * in the concentrator, all inactive PHYS always must be in - * the remove state - * there's no real need to use this feature at all .. - */ -#ifndef CONCENTRATOR - if ((smc->s.sas == SMT_SAS) && (p == PS)) { - outpw(PLC(p,PL_CNTRL_B),PL_CLASS_S) ; - } -#endif -} - -/* - * control PCM state machine - */ -static void plc_go_state(struct s_smc *smc, int p, int state) -{ - HW_PTR port ; - int val ; - - SK_UNUSED(smc) ; - - port = (HW_PTR) (PLC(p,PL_CNTRL_B)) ; - val = inpw(port) & ~(PL_PCM_CNTRL | PL_MAINT) ; - outpw(port,val) ; - outpw(port,val | state) ; -} - -/* - * read current line state (called by ECM & PCM) - */ -int sm_pm_get_ls(struct s_smc *smc, int phy) -{ - int state ; - -#ifdef CONCENTRATOR - if (!plc_is_installed(smc,phy)) - return PC_QLS; -#endif - - state = inpw(PLC(phy,PL_STATUS_A)) & PL_LINE_ST ; - switch(state) { - case PL_L_QLS: - state = PC_QLS ; - break ; - case PL_L_MLS: - state = PC_MLS ; - break ; - case PL_L_HLS: - state = PC_HLS ; - break ; - case PL_L_ILS4: - case PL_L_ILS16: - state = PC_ILS ; - break ; - case PL_L_ALS: - state = PC_LS_PDR ; - break ; - default : - state = PC_LS_NONE ; - } - return state; -} - -static int plc_send_bits(struct s_smc *smc, struct s_phy *phy, int len) -{ - int np = phy->np ; /* PHY index */ - int n ; - int i ; - - SK_UNUSED(smc) ; - - /* create bit vector */ - for (i = len-1,n = 0 ; i >= 0 ; i--) { - n = (n<<1) | phy->t_val[phy->bitn+i] ; - } - if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) { -#if 0 - printf("PL_PCM_SIGNAL is set\n") ; -#endif - return 1; - } - /* write bit[n] & length = 1 to regs */ - outpw(PLC(np,PL_VECTOR_LEN),len-1) ; /* len=nr-1 */ - outpw(PLC(np,PL_XMIT_VECTOR),n) ; -#ifdef DEBUG -#if 1 -#ifdef DEBUG_BRD - if (smc->debug.d_plc & 0x80) -#else - if (debug.d_plc & 0x80) -#endif - printf("SIGNALING bit %d .. %d\n",phy->bitn,phy->bitn+len-1) ; -#endif -#endif - return 0; -} - -/* - * config plc muxes - */ -void plc_config_mux(struct s_smc *smc, int mux) -{ - if (smc->s.sas != SMT_DAS) - return ; - if (mux == MUX_WRAPB) { - SETMASK(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ; - SETMASK(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP,PL_SC_REM_LOOP) ; - } - else { - CLEAR(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL) ; - CLEAR(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP) ; - } - CLEAR(PLC(PB,PL_CNTRL_B),PL_CONFIG_CNTRL) ; - CLEAR(PLC(PB,PL_CNTRL_A),PL_SC_REM_LOOP) ; -} - -/* - PCM state machine - called by dispatcher & fddi_init() (driver) - do - display state change - process event - until SM is stable -*/ -void pcm(struct s_smc *smc, const int np, int event) -{ - int state ; - int oldstate ; - struct s_phy *phy ; - struct fddi_mib_p *mib ; - -#ifndef CONCENTRATOR - /* - * ignore 2nd PHY if SAS - */ - if ((np != PS) && (smc->s.sas == SMT_SAS)) - return ; -#endif - phy = &smc->y[np] ; - mib = phy->mib ; - oldstate = mib->fddiPORTPCMState ; - do { - DB_PCM("PCM %c: state %s", - phy->phy_name, - (mib->fddiPORTPCMState & AFLAG) ? "ACTIONS " : "") ; - DB_PCM("%s, event %s\n", - pcm_states[mib->fddiPORTPCMState & ~AFLAG], - pcm_events[event]) ; - state = mib->fddiPORTPCMState ; - pcm_fsm(smc,phy,event) ; - event = 0 ; - } while (state != mib->fddiPORTPCMState) ; - /* - * because the PLC does the bit signaling for us, - * we're always in SIGNAL state - * the MIB want's to see CONNECT - * we therefore fake an entry in the MIB - */ - if (state == PC5_SIGNAL) - mib->fddiPORTPCMStateX = PC3_CONNECT ; - else - mib->fddiPORTPCMStateX = state ; - -#ifndef SLIM_SMT - /* - * path change - */ - if ( mib->fddiPORTPCMState != oldstate && - ((oldstate == PC8_ACTIVE) || (mib->fddiPORTPCMState == PC8_ACTIVE))) { - smt_srf_event(smc,SMT_EVENT_PORT_PATH_CHANGE, - (int) (INDEX_PORT+ phy->np),0) ; - } -#endif - -#ifdef FDDI_MIB - /* check whether a snmp-trap has to be sent */ - - if ( mib->fddiPORTPCMState != oldstate ) { - /* a real state change took place */ - DB_SNMP ("PCM from %d to %d\n", oldstate, mib->fddiPORTPCMState); - if ( mib->fddiPORTPCMState == PC0_OFF ) { - /* send first trap */ - snmp_fddi_trap (smc, 1, (int) mib->fddiPORTIndex ); - } else if ( oldstate == PC0_OFF ) { - /* send second trap */ - snmp_fddi_trap (smc, 2, (int) mib->fddiPORTIndex ); - } else if ( mib->fddiPORTPCMState != PC2_TRACE && - oldstate == PC8_ACTIVE ) { - /* send third trap */ - snmp_fddi_trap (smc, 3, (int) mib->fddiPORTIndex ); - } else if ( mib->fddiPORTPCMState == PC8_ACTIVE ) { - /* send fourth trap */ - snmp_fddi_trap (smc, 4, (int) mib->fddiPORTIndex ); - } - } -#endif - - pcm_state_change(smc,np,state) ; -} - -/* - * PCM state machine - */ -static void pcm_fsm(struct s_smc *smc, struct s_phy *phy, int cmd) -{ - int i ; - int np = phy->np ; /* PHY index */ - struct s_plc *plc ; - struct fddi_mib_p *mib ; -#ifndef MOT_ELM - u_short plc_rev ; /* Revision of the plc */ -#endif /* nMOT_ELM */ - - plc = &phy->plc ; - mib = phy->mib ; - - /* - * general transitions independent of state - */ - switch (cmd) { - case PC_STOP : - /*PC00-PC80*/ - if (mib->fddiPORTPCMState != PC9_MAINT) { - GO_STATE(PC0_OFF) ; - AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) - FDDI_PORT_EVENT, (u_long) FDDI_PORT_STOP, - smt_get_port_event_word(smc)); - } - return ; - case PC_START : - /*PC01-PC81*/ - if (mib->fddiPORTPCMState != PC9_MAINT) - GO_STATE(PC1_BREAK) ; - return ; - case PC_DISABLE : - /* PC09-PC99 */ - GO_STATE(PC9_MAINT) ; - AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) - FDDI_PORT_EVENT, (u_long) FDDI_PORT_DISABLED, - smt_get_port_event_word(smc)); - return ; - case PC_TIMEOUT_LCT : - /* if long or extended LCT */ - stop_pcm_timer0(smc,phy) ; - CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; - /* end of LCT is indicate by PCM_CODE (initiate PCM event) */ - return ; - } - - switch(mib->fddiPORTPCMState) { - case ACTIONS(PC0_OFF) : - stop_pcm_timer0(smc,phy) ; - outpw(PLC(np,PL_CNTRL_A),0) ; - CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; - CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; - sm_ph_lem_stop(smc,np) ; /* disable LEM */ - phy->cf_loop = FALSE ; - phy->cf_join = FALSE ; - queue_event(smc,EVENT_CFM,CF_JOIN+np) ; - plc_go_state(smc,np,PL_PCM_STOP) ; - mib->fddiPORTConnectState = PCM_DISABLED ; - ACTIONS_DONE() ; - break ; - case PC0_OFF: - /*PC09*/ - if (cmd == PC_MAINT) { - GO_STATE(PC9_MAINT) ; - break ; - } - break ; - case ACTIONS(PC1_BREAK) : - /* Stop the LCT timer if we came from Signal state */ - stop_pcm_timer0(smc,phy) ; - ACTIONS_DONE() ; - plc_go_state(smc,np,0) ; - CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; - CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; - sm_ph_lem_stop(smc,np) ; /* disable LEM */ - /* - * if vector is already loaded, go to OFF to clear PCM_SIGNAL - */ -#if 0 - if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) { - plc_go_state(smc,np,PL_PCM_STOP) ; - /* TB_MIN ? */ - } -#endif - /* - * Go to OFF state in any case. - */ - plc_go_state(smc,np,PL_PCM_STOP) ; - - if (mib->fddiPORTPC_Withhold == PC_WH_NONE) - mib->fddiPORTConnectState = PCM_CONNECTING ; - phy->cf_loop = FALSE ; - phy->cf_join = FALSE ; - queue_event(smc,EVENT_CFM,CF_JOIN+np) ; - phy->ls_flag = FALSE ; - phy->pc_mode = PM_NONE ; /* needed by CFM */ - phy->bitn = 0 ; /* bit signaling start bit */ - for (i = 0 ; i < 3 ; i++) - pc_tcode_actions(smc,i,phy) ; - - /* Set the non-active interrupt mask register */ - outpw(PLC(np,PL_INTR_MASK),plc_imsk_na) ; - - /* - * If the LCT was stopped. There might be a - * PCM_CODE interrupt event present. - * This must be cleared. - */ - (void)inpw(PLC(np,PL_INTR_EVENT)) ; -#ifndef MOT_ELM - /* Get the plc revision for revision dependent code */ - plc_rev = inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK ; - - if (plc_rev != PLC_REV_SN3) -#endif /* MOT_ELM */ - { - /* - * No supernet III PLC, so set Xmit verctor and - * length BEFORE starting the state machine. - */ - if (plc_send_bits(smc,phy,3)) { - return ; - } - } - - /* - * Now give the Start command. - * - The start command shall be done before setting the bits - * to be signaled. (In PLC-S description and PLCS in SN3. - * - The start command shall be issued AFTER setting the - * XMIT vector and the XMIT length register. - * - * We do it exactly according this specs for the old PLC and - * the new PLCS inside the SN3. - * For the usual PLCS we try it the way it is done for the - * old PLC and set the XMIT registers again, if the PLC is - * not in SIGNAL state. This is done according to an PLCS - * errata workaround. - */ - - plc_go_state(smc,np,PL_PCM_START) ; - - /* - * workaround for PLC-S eng. sample errata - */ -#ifdef MOT_ELM - if (!(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL)) -#else /* nMOT_ELM */ - if (((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) != - PLC_REVISION_A) && - !(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL)) -#endif /* nMOT_ELM */ - { - /* - * Set register again (PLCS errata) or the first time - * (new SN3 PLCS). - */ - (void) plc_send_bits(smc,phy,3) ; - } - /* - * end of workaround - */ - - GO_STATE(PC5_SIGNAL) ; - plc->p_state = PS_BIT3 ; - plc->p_bits = 3 ; - plc->p_start = 0 ; - - break ; - case PC1_BREAK : - break ; - case ACTIONS(PC2_TRACE) : - plc_go_state(smc,np,PL_PCM_TRACE) ; - ACTIONS_DONE() ; - break ; - case PC2_TRACE : - break ; - - case PC3_CONNECT : /* these states are done by hardware */ - case PC4_NEXT : - break ; - - case ACTIONS(PC5_SIGNAL) : - ACTIONS_DONE() ; - case PC5_SIGNAL : - if ((cmd != PC_SIGNAL) && (cmd != PC_TIMEOUT_LCT)) - break ; - switch (plc->p_state) { - case PS_BIT3 : - for (i = 0 ; i <= 2 ; i++) - pc_rcode_actions(smc,i,phy) ; - pc_tcode_actions(smc,3,phy) ; - plc->p_state = PS_BIT4 ; - plc->p_bits = 1 ; - plc->p_start = 3 ; - phy->bitn = 3 ; - if (plc_send_bits(smc,phy,1)) { - return ; - } - break ; - case PS_BIT4 : - pc_rcode_actions(smc,3,phy) ; - for (i = 4 ; i <= 6 ; i++) - pc_tcode_actions(smc,i,phy) ; - plc->p_state = PS_BIT7 ; - plc->p_bits = 3 ; - plc->p_start = 4 ; - phy->bitn = 4 ; - if (plc_send_bits(smc,phy,3)) { - return ; - } - break ; - case PS_BIT7 : - for (i = 3 ; i <= 6 ; i++) - pc_rcode_actions(smc,i,phy) ; - plc->p_state = PS_LCT ; - plc->p_bits = 0 ; - plc->p_start = 7 ; - phy->bitn = 7 ; - sm_ph_lem_start(smc,np,(int)smc->s.lct_short) ; /* enable LEM */ - /* start LCT */ - i = inpw(PLC(np,PL_CNTRL_B)) & ~PL_PC_LOOP ; - outpw(PLC(np,PL_CNTRL_B),i) ; /* must be cleared */ - outpw(PLC(np,PL_CNTRL_B),i | PL_RLBP) ; - break ; - case PS_LCT : - /* check for local LCT failure */ - pc_tcode_actions(smc,7,phy) ; - /* - * set tval[7] - */ - plc->p_state = PS_BIT8 ; - plc->p_bits = 1 ; - plc->p_start = 7 ; - phy->bitn = 7 ; - if (plc_send_bits(smc,phy,1)) { - return ; - } - break ; - case PS_BIT8 : - /* check for remote LCT failure */ - pc_rcode_actions(smc,7,phy) ; - if (phy->t_val[7] || phy->r_val[7]) { - plc_go_state(smc,np,PL_PCM_STOP) ; - GO_STATE(PC1_BREAK) ; - break ; - } - for (i = 8 ; i <= 9 ; i++) - pc_tcode_actions(smc,i,phy) ; - plc->p_state = PS_JOIN ; - plc->p_bits = 2 ; - plc->p_start = 8 ; - phy->bitn = 8 ; - if (plc_send_bits(smc,phy,2)) { - return ; - } - break ; - case PS_JOIN : - for (i = 8 ; i <= 9 ; i++) - pc_rcode_actions(smc,i,phy) ; - plc->p_state = PS_ACTIVE ; - GO_STATE(PC6_JOIN) ; - break ; - } - break ; - - case ACTIONS(PC6_JOIN) : - /* - * prevent mux error when going from WRAP_A to WRAP_B - */ - if (smc->s.sas == SMT_DAS && np == PB && - (smc->y[PA].pc_mode == PM_TREE || - smc->y[PB].pc_mode == PM_TREE)) { - SETMASK(PLC(np,PL_CNTRL_A), - PL_SC_REM_LOOP,PL_SC_REM_LOOP) ; - SETMASK(PLC(np,PL_CNTRL_B), - PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ; - } - SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ; - SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ; - ACTIONS_DONE() ; - cmd = 0 ; - /* fall thru */ - case PC6_JOIN : - switch (plc->p_state) { - case PS_ACTIVE: - /*PC88b*/ - if (!phy->cf_join) { - phy->cf_join = TRUE ; - queue_event(smc,EVENT_CFM,CF_JOIN+np) ; - } - if (cmd == PC_JOIN) - GO_STATE(PC8_ACTIVE) ; - /*PC82*/ - if (cmd == PC_TRACE) { - GO_STATE(PC2_TRACE) ; - break ; - } - break ; - } - break ; - - case PC7_VERIFY : - break ; - - case ACTIONS(PC8_ACTIVE) : - /* - * start LEM for SMT - */ - sm_ph_lem_start(smc,(int)phy->np,LCT_LEM_MAX) ; - - phy->tr_flag = FALSE ; - mib->fddiPORTConnectState = PCM_ACTIVE ; - - /* Set the active interrupt mask register */ - outpw(PLC(np,PL_INTR_MASK),plc_imsk_act) ; - - ACTIONS_DONE() ; - break ; - case PC8_ACTIVE : - /*PC81 is done by PL_TNE_EXPIRED irq */ - /*PC82*/ - if (cmd == PC_TRACE) { - GO_STATE(PC2_TRACE) ; - break ; - } - /*PC88c: is done by TRACE_PROP irq */ - - break ; - case ACTIONS(PC9_MAINT) : - stop_pcm_timer0(smc,phy) ; - CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; - CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; - CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ; /* disable LEM int. */ - sm_ph_lem_stop(smc,np) ; /* disable LEM */ - phy->cf_loop = FALSE ; - phy->cf_join = FALSE ; - queue_event(smc,EVENT_CFM,CF_JOIN+np) ; - plc_go_state(smc,np,PL_PCM_STOP) ; - mib->fddiPORTConnectState = PCM_DISABLED ; - SETMASK(PLC(np,PL_CNTRL_B),PL_MAINT,PL_MAINT) ; - sm_ph_linestate(smc,np,(int) MIB2LS(mib->fddiPORTMaint_LS)) ; - outpw(PLC(np,PL_CNTRL_A),PL_SC_BYPASS) ; - ACTIONS_DONE() ; - break ; - case PC9_MAINT : - DB_PCMN(1,"PCM %c : MAINT\n",phy->phy_name,0) ; - /*PC90*/ - if (cmd == PC_ENABLE) { - GO_STATE(PC0_OFF) ; - break ; - } - break ; - - default: - SMT_PANIC(smc,SMT_E0118, SMT_E0118_MSG) ; - break ; - } -} - -/* - * force line state on a PHY output (only in MAINT state) - */ -static void sm_ph_linestate(struct s_smc *smc, int phy, int ls) -{ - int cntrl ; - - SK_UNUSED(smc) ; - - cntrl = (inpw(PLC(phy,PL_CNTRL_B)) & ~PL_MAINT_LS) | - PL_PCM_STOP | PL_MAINT ; - switch(ls) { - case PC_QLS: /* Force Quiet */ - cntrl |= PL_M_QUI0 ; - break ; - case PC_MLS: /* Force Master */ - cntrl |= PL_M_MASTR ; - break ; - case PC_HLS: /* Force Halt */ - cntrl |= PL_M_HALT ; - break ; - default : - case PC_ILS: /* Force Idle */ - cntrl |= PL_M_IDLE ; - break ; - case PC_LS_PDR: /* Enable repeat filter */ - cntrl |= PL_M_TPDR ; - break ; - } - outpw(PLC(phy,PL_CNTRL_B),cntrl) ; -} - -static void reset_lem_struct(struct s_phy *phy) -{ - struct lem_counter *lem = &phy->lem ; - - phy->mib->fddiPORTLer_Estimate = 15 ; - lem->lem_float_ber = 15 * 100 ; -} - -/* - * link error monitor - */ -static void lem_evaluate(struct s_smc *smc, struct s_phy *phy) -{ - int ber ; - u_long errors ; - struct lem_counter *lem = &phy->lem ; - struct fddi_mib_p *mib ; - int cond ; - - mib = phy->mib ; - - if (!lem->lem_on) - return ; - - errors = inpw(PLC(((int) phy->np),PL_LINK_ERR_CTR)) ; - lem->lem_errors += errors ; - mib->fddiPORTLem_Ct += errors ; - - errors = lem->lem_errors ; - /* - * calculation is called on a intervall of 8 seconds - * -> this means, that one error in 8 sec. is one of 8*125*10E6 - * the same as BER = 10E-9 - * Please note: - * -> 9 errors in 8 seconds mean: - * BER = 9 * 10E-9 and this is - * < 10E-8, so the limit of 10E-8 is not reached! - */ - - if (!errors) ber = 15 ; - else if (errors <= 9) ber = 9 ; - else if (errors <= 99) ber = 8 ; - else if (errors <= 999) ber = 7 ; - else if (errors <= 9999) ber = 6 ; - else if (errors <= 99999) ber = 5 ; - else if (errors <= 999999) ber = 4 ; - else if (errors <= 9999999) ber = 3 ; - else if (errors <= 99999999) ber = 2 ; - else if (errors <= 999999999) ber = 1 ; - else ber = 0 ; - - /* - * weighted average - */ - ber *= 100 ; - lem->lem_float_ber = lem->lem_float_ber * 7 + ber * 3 ; - lem->lem_float_ber /= 10 ; - mib->fddiPORTLer_Estimate = lem->lem_float_ber / 100 ; - if (mib->fddiPORTLer_Estimate < 4) { - mib->fddiPORTLer_Estimate = 4 ; - } - - if (lem->lem_errors) { - DB_PCMN(1,"LEM %c :\n",phy->np == PB? 'B' : 'A',0) ; - DB_PCMN(1,"errors : %ld\n",lem->lem_errors,0) ; - DB_PCMN(1,"sum_errors : %ld\n",mib->fddiPORTLem_Ct,0) ; - DB_PCMN(1,"current BER : 10E-%d\n",ber/100,0) ; - DB_PCMN(1,"float BER : 10E-(%d/100)\n",lem->lem_float_ber,0) ; - DB_PCMN(1,"avg. BER : 10E-%d\n", - mib->fddiPORTLer_Estimate,0) ; - } - - lem->lem_errors = 0L ; - -#ifndef SLIM_SMT - cond = (mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Alarm) ? - TRUE : FALSE ; -#ifdef SMT_EXT_CUTOFF - smt_ler_alarm_check(smc,phy,cond) ; -#endif /* nSMT_EXT_CUTOFF */ - if (cond != mib->fddiPORTLerFlag) { - smt_srf_event(smc,SMT_COND_PORT_LER, - (int) (INDEX_PORT+ phy->np) ,cond) ; - } -#endif - - if ( mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Cutoff) { - phy->pc_lem_fail = TRUE ; /* flag */ - mib->fddiPORTLem_Reject_Ct++ ; - /* - * "forgive 10e-2" if we cutoff so we can come - * up again .. - */ - lem->lem_float_ber += 2*100 ; - - /*PC81b*/ -#ifdef CONCENTRATOR - DB_PCMN(1,"PCM: LER cutoff on port %d cutoff %d\n", - phy->np, mib->fddiPORTLer_Cutoff) ; -#endif -#ifdef SMT_EXT_CUTOFF - smt_port_off_event(smc,phy->np); -#else /* nSMT_EXT_CUTOFF */ - queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ; -#endif /* nSMT_EXT_CUTOFF */ - } -} - -/* - * called by SMT to calculate LEM bit error rate - */ -void sm_lem_evaluate(struct s_smc *smc) -{ - int np ; - - for (np = 0 ; np < NUMPHYS ; np++) - lem_evaluate(smc,&smc->y[np]) ; -} - -static void lem_check_lct(struct s_smc *smc, struct s_phy *phy) -{ - struct lem_counter *lem = &phy->lem ; - struct fddi_mib_p *mib ; - int errors ; - - mib = phy->mib ; - - phy->pc_lem_fail = FALSE ; /* flag */ - errors = inpw(PLC(((int)phy->np),PL_LINK_ERR_CTR)) ; - lem->lem_errors += errors ; - mib->fddiPORTLem_Ct += errors ; - if (lem->lem_errors) { - switch(phy->lc_test) { - case LC_SHORT: - if (lem->lem_errors >= smc->s.lct_short) - phy->pc_lem_fail = TRUE ; - break ; - case LC_MEDIUM: - if (lem->lem_errors >= smc->s.lct_medium) - phy->pc_lem_fail = TRUE ; - break ; - case LC_LONG: - if (lem->lem_errors >= smc->s.lct_long) - phy->pc_lem_fail = TRUE ; - break ; - case LC_EXTENDED: - if (lem->lem_errors >= smc->s.lct_extended) - phy->pc_lem_fail = TRUE ; - break ; - } - DB_PCMN(1," >>errors : %d\n",lem->lem_errors,0) ; - } - if (phy->pc_lem_fail) { - mib->fddiPORTLCTFail_Ct++ ; - mib->fddiPORTLem_Reject_Ct++ ; - } - else - mib->fddiPORTLCTFail_Ct = 0 ; -} - -/* - * LEM functions - */ -static void sm_ph_lem_start(struct s_smc *smc, int np, int threshold) -{ - struct lem_counter *lem = &smc->y[np].lem ; - - lem->lem_on = 1 ; - lem->lem_errors = 0L ; - - /* Do NOT reset mib->fddiPORTLer_Estimate here. It is called too - * often. - */ - - outpw(PLC(np,PL_LE_THRESHOLD),threshold) ; - (void)inpw(PLC(np,PL_LINK_ERR_CTR)) ; /* clear error counter */ - - /* enable LE INT */ - SETMASK(PLC(np,PL_INTR_MASK),PL_LE_CTR,PL_LE_CTR) ; -} - -static void sm_ph_lem_stop(struct s_smc *smc, int np) -{ - struct lem_counter *lem = &smc->y[np].lem ; - - lem->lem_on = 0 ; - CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ; -} - -/* ARGSUSED */ -void sm_pm_ls_latch(struct s_smc *smc, int phy, int on_off) -/* int on_off; en- or disable ident. ls */ -{ - SK_UNUSED(smc) ; - - phy = phy ; on_off = on_off ; -} - - -/* - * PCM pseudo code - * receive actions are called AFTER the bit n is received, - * i.e. if pc_rcode_actions(5) is called, bit 6 is the next bit to be received - */ - -/* - * PCM pseudo code 5.1 .. 6.1 - */ -static void pc_rcode_actions(struct s_smc *smc, int bit, struct s_phy *phy) -{ - struct fddi_mib_p *mib ; - - mib = phy->mib ; - - DB_PCMN(1,"SIG rec %x %x:\n", bit,phy->r_val[bit] ) ; - bit++ ; - - switch(bit) { - case 0: - case 1: - case 2: - break ; - case 3 : - if (phy->r_val[1] == 0 && phy->r_val[2] == 0) - mib->fddiPORTNeighborType = TA ; - else if (phy->r_val[1] == 0 && phy->r_val[2] == 1) - mib->fddiPORTNeighborType = TB ; - else if (phy->r_val[1] == 1 && phy->r_val[2] == 0) - mib->fddiPORTNeighborType = TS ; - else if (phy->r_val[1] == 1 && phy->r_val[2] == 1) - mib->fddiPORTNeighborType = TM ; - break ; - case 4: - if (mib->fddiPORTMy_Type == TM && - mib->fddiPORTNeighborType == TM) { - DB_PCMN(1,"PCM %c : E100 withhold M-M\n", - phy->phy_name,0) ; - mib->fddiPORTPC_Withhold = PC_WH_M_M ; - RS_SET(smc,RS_EVENT) ; - } - else if (phy->t_val[3] || phy->r_val[3]) { - mib->fddiPORTPC_Withhold = PC_WH_NONE ; - if (mib->fddiPORTMy_Type == TM || - mib->fddiPORTNeighborType == TM) - phy->pc_mode = PM_TREE ; - else - phy->pc_mode = PM_PEER ; - - /* reevaluate the selection criteria (wc_flag) */ - all_selection_criteria (smc); - - if (phy->wc_flag) { - mib->fddiPORTPC_Withhold = PC_WH_PATH ; - } - } - else { - mib->fddiPORTPC_Withhold = PC_WH_OTHER ; - RS_SET(smc,RS_EVENT) ; - DB_PCMN(1,"PCM %c : E101 withhold other\n", - phy->phy_name,0) ; - } - phy->twisted = ((mib->fddiPORTMy_Type != TS) && - (mib->fddiPORTMy_Type != TM) && - (mib->fddiPORTNeighborType == - mib->fddiPORTMy_Type)) ; - if (phy->twisted) { - DB_PCMN(1,"PCM %c : E102 !!! TWISTED !!!\n", - phy->phy_name,0) ; - } - break ; - case 5 : - break ; - case 6: - if (phy->t_val[4] || phy->r_val[4]) { - if ((phy->t_val[4] && phy->t_val[5]) || - (phy->r_val[4] && phy->r_val[5]) ) - phy->lc_test = LC_EXTENDED ; - else - phy->lc_test = LC_LONG ; - } - else if (phy->t_val[5] || phy->r_val[5]) - phy->lc_test = LC_MEDIUM ; - else - phy->lc_test = LC_SHORT ; - switch (phy->lc_test) { - case LC_SHORT : /* 50ms */ - outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LENGTH ) ; - phy->t_next[7] = smc->s.pcm_lc_short ; - break ; - case LC_MEDIUM : /* 500ms */ - outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LONGLN ) ; - phy->t_next[7] = smc->s.pcm_lc_medium ; - break ; - case LC_LONG : - SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ; - phy->t_next[7] = smc->s.pcm_lc_long ; - break ; - case LC_EXTENDED : - SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ; - phy->t_next[7] = smc->s.pcm_lc_extended ; - break ; - } - if (phy->t_next[7] > smc->s.pcm_lc_medium) { - start_pcm_timer0(smc,phy->t_next[7],PC_TIMEOUT_LCT,phy); - } - DB_PCMN(1,"LCT timer = %ld us\n", phy->t_next[7], 0) ; - phy->t_next[9] = smc->s.pcm_t_next_9 ; - break ; - case 7: - if (phy->t_val[6]) { - phy->cf_loop = TRUE ; - } - phy->td_flag = TRUE ; - break ; - case 8: - if (phy->t_val[7] || phy->r_val[7]) { - DB_PCMN(1,"PCM %c : E103 LCT fail %s\n", - phy->phy_name,phy->t_val[7]? "local":"remote") ; - queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ; - } - break ; - case 9: - if (phy->t_val[8] || phy->r_val[8]) { - if (phy->t_val[8]) - phy->cf_loop = TRUE ; - phy->td_flag = TRUE ; - } - break ; - case 10: - if (phy->r_val[9]) { - /* neighbor intends to have MAC on output */ ; - mib->fddiPORTMacIndicated.R_val = TRUE ; - } - else { - /* neighbor does not intend to have MAC on output */ ; - mib->fddiPORTMacIndicated.R_val = FALSE ; - } - break ; - } -} - -/* - * PCM pseudo code 5.1 .. 6.1 - */ -static void pc_tcode_actions(struct s_smc *smc, const int bit, struct s_phy *phy) -{ - int np = phy->np ; - struct fddi_mib_p *mib ; - - mib = phy->mib ; - - switch(bit) { - case 0: - phy->t_val[0] = 0 ; /* no escape used */ - break ; - case 1: - if (mib->fddiPORTMy_Type == TS || mib->fddiPORTMy_Type == TM) - phy->t_val[1] = 1 ; - else - phy->t_val[1] = 0 ; - break ; - case 2 : - if (mib->fddiPORTMy_Type == TB || mib->fddiPORTMy_Type == TM) - phy->t_val[2] = 1 ; - else - phy->t_val[2] = 0 ; - break ; - case 3: - { - int type,ne ; - int policy ; - - type = mib->fddiPORTMy_Type ; - ne = mib->fddiPORTNeighborType ; - policy = smc->mib.fddiSMTConnectionPolicy ; - - phy->t_val[3] = 1 ; /* Accept connection */ - switch (type) { - case TA : - if ( - ((policy & POLICY_AA) && ne == TA) || - ((policy & POLICY_AB) && ne == TB) || - ((policy & POLICY_AS) && ne == TS) || - ((policy & POLICY_AM) && ne == TM) ) - phy->t_val[3] = 0 ; /* Reject */ - break ; - case TB : - if ( - ((policy & POLICY_BA) && ne == TA) || - ((policy & POLICY_BB) && ne == TB) || - ((policy & POLICY_BS) && ne == TS) || - ((policy & POLICY_BM) && ne == TM) ) - phy->t_val[3] = 0 ; /* Reject */ - break ; - case TS : - if ( - ((policy & POLICY_SA) && ne == TA) || - ((policy & POLICY_SB) && ne == TB) || - ((policy & POLICY_SS) && ne == TS) || - ((policy & POLICY_SM) && ne == TM) ) - phy->t_val[3] = 0 ; /* Reject */ - break ; - case TM : - if ( ne == TM || - ((policy & POLICY_MA) && ne == TA) || - ((policy & POLICY_MB) && ne == TB) || - ((policy & POLICY_MS) && ne == TS) || - ((policy & POLICY_MM) && ne == TM) ) - phy->t_val[3] = 0 ; /* Reject */ - break ; - } -#ifndef SLIM_SMT - /* - * detect undesirable connection attempt event - */ - if ( (type == TA && ne == TA ) || - (type == TA && ne == TS ) || - (type == TB && ne == TB ) || - (type == TB && ne == TS ) || - (type == TS && ne == TA ) || - (type == TS && ne == TB ) ) { - smt_srf_event(smc,SMT_EVENT_PORT_CONNECTION, - (int) (INDEX_PORT+ phy->np) ,0) ; - } -#endif - } - break ; - case 4: - if (mib->fddiPORTPC_Withhold == PC_WH_NONE) { - if (phy->pc_lem_fail) { - phy->t_val[4] = 1 ; /* long */ - phy->t_val[5] = 0 ; - } - else { - phy->t_val[4] = 0 ; - if (mib->fddiPORTLCTFail_Ct > 0) - phy->t_val[5] = 1 ; /* medium */ - else - phy->t_val[5] = 0 ; /* short */ - - /* - * Implementers choice: use medium - * instead of short when undesired - * connection attempt is made. - */ - if (phy->wc_flag) - phy->t_val[5] = 1 ; /* medium */ - } - mib->fddiPORTConnectState = PCM_CONNECTING ; - } - else { - mib->fddiPORTConnectState = PCM_STANDBY ; - phy->t_val[4] = 1 ; /* extended */ - phy->t_val[5] = 1 ; - } - break ; - case 5: - break ; - case 6: - /* we do NOT have a MAC for LCT */ - phy->t_val[6] = 0 ; - break ; - case 7: - phy->cf_loop = FALSE ; - lem_check_lct(smc,phy) ; - if (phy->pc_lem_fail) { - DB_PCMN(1,"PCM %c : E104 LCT failed\n", - phy->phy_name,0) ; - phy->t_val[7] = 1 ; - } - else - phy->t_val[7] = 0 ; - break ; - case 8: - phy->t_val[8] = 0 ; /* Don't request MAC loopback */ - break ; - case 9: - phy->cf_loop = 0 ; - if ((mib->fddiPORTPC_Withhold != PC_WH_NONE) || - ((smc->s.sas == SMT_DAS) && (phy->wc_flag))) { - queue_event(smc,EVENT_PCM+np,PC_START) ; - break ; - } - phy->t_val[9] = FALSE ; - switch (smc->s.sas) { - case SMT_DAS : - /* - * MAC intended on output - */ - if (phy->pc_mode == PM_TREE) { - if ((np == PB) || ((np == PA) && - (smc->y[PB].mib->fddiPORTConnectState != - PCM_ACTIVE))) - phy->t_val[9] = TRUE ; - } - else { - if (np == PB) - phy->t_val[9] = TRUE ; - } - break ; - case SMT_SAS : - if (np == PS) - phy->t_val[9] = TRUE ; - break ; -#ifdef CONCENTRATOR - case SMT_NAC : - /* - * MAC intended on output - */ - if (np == PB) - phy->t_val[9] = TRUE ; - break ; -#endif - } - mib->fddiPORTMacIndicated.T_val = phy->t_val[9] ; - break ; - } - DB_PCMN(1,"SIG snd %x %x:\n", bit,phy->t_val[bit] ) ; -} - -/* - * return status twisted (called by SMT) - */ -int pcm_status_twisted(struct s_smc *smc) -{ - int twist = 0 ; - if (smc->s.sas != SMT_DAS) - return 0; - if (smc->y[PA].twisted && (smc->y[PA].mib->fddiPORTPCMState == PC8_ACTIVE)) - twist |= 1 ; - if (smc->y[PB].twisted && (smc->y[PB].mib->fddiPORTPCMState == PC8_ACTIVE)) - twist |= 2 ; - return twist; -} - -/* - * return status (called by SMT) - * type - * state - * remote phy type - * remote mac yes/no - */ -void pcm_status_state(struct s_smc *smc, int np, int *type, int *state, - int *remote, int *mac) -{ - struct s_phy *phy = &smc->y[np] ; - struct fddi_mib_p *mib ; - - mib = phy->mib ; - - /* remote PHY type and MAC - set only if active */ - *mac = 0 ; - *type = mib->fddiPORTMy_Type ; /* our PHY type */ - *state = mib->fddiPORTConnectState ; - *remote = mib->fddiPORTNeighborType ; - - switch(mib->fddiPORTPCMState) { - case PC8_ACTIVE : - *mac = mib->fddiPORTMacIndicated.R_val ; - break ; - } -} - -/* - * return rooted station status (called by SMT) - */ -int pcm_rooted_station(struct s_smc *smc) -{ - int n ; - - for (n = 0 ; n < NUMPHYS ; n++) { - if (smc->y[n].mib->fddiPORTPCMState == PC8_ACTIVE && - smc->y[n].mib->fddiPORTNeighborType == TM) - return 0; - } - return 1; -} - -/* - * Interrupt actions for PLC & PCM events - */ -void plc_irq(struct s_smc *smc, int np, unsigned int cmd) -/* int np; PHY index */ -{ - struct s_phy *phy = &smc->y[np] ; - struct s_plc *plc = &phy->plc ; - int n ; -#ifdef SUPERNET_3 - int corr_mask ; -#endif /* SUPERNET_3 */ - int i ; - - if (np >= smc->s.numphys) { - plc->soft_err++ ; - return ; - } - if (cmd & PL_EBUF_ERR) { /* elastic buff. det. over-|underflow*/ - /* - * Check whether the SRF Condition occurred. - */ - if (!plc->ebuf_cont && phy->mib->fddiPORTPCMState == PC8_ACTIVE){ - /* - * This is the real Elasticity Error. - * More than one in a row are treated as a - * single one. - * Only count this in the active state. - */ - phy->mib->fddiPORTEBError_Ct ++ ; - - } - - plc->ebuf_err++ ; - if (plc->ebuf_cont <= 1000) { - /* - * Prevent counter from being wrapped after - * hanging years in that interrupt. - */ - plc->ebuf_cont++ ; /* Ebuf continuous error */ - } - -#ifdef SUPERNET_3 - if (plc->ebuf_cont == 1000 && - ((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) == - PLC_REV_SN3)) { - /* - * This interrupt remeained high for at least - * 1000 consecutive interrupt calls. - * - * This is caused by a hardware error of the - * ORION part of the Supernet III chipset. - * - * Disable this bit from the mask. - */ - corr_mask = (plc_imsk_na & ~PL_EBUF_ERR) ; - outpw(PLC(np,PL_INTR_MASK),corr_mask); - - /* - * Disconnect from the ring. - * Call the driver with the reset indication. - */ - queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; - - /* - * Make an error log entry. - */ - SMT_ERR_LOG(smc,SMT_E0136, SMT_E0136_MSG) ; - - /* - * Indicate the Reset. - */ - drv_reset_indication(smc) ; - } -#endif /* SUPERNET_3 */ - } else { - /* Reset the continuous error variable */ - plc->ebuf_cont = 0 ; /* reset Ebuf continuous error */ - } - if (cmd & PL_PHYINV) { /* physical layer invalid signal */ - plc->phyinv++ ; - } - if (cmd & PL_VSYM_CTR) { /* violation symbol counter has incr.*/ - plc->vsym_ctr++ ; - } - if (cmd & PL_MINI_CTR) { /* dep. on PLC_CNTRL_A's MINI_CTR_INT*/ - plc->mini_ctr++ ; - } - if (cmd & PL_LE_CTR) { /* link error event counter */ - int j ; - - /* - * note: PL_LINK_ERR_CTR MUST be read to clear it - */ - j = inpw(PLC(np,PL_LE_THRESHOLD)) ; - i = inpw(PLC(np,PL_LINK_ERR_CTR)) ; - - if (i < j) { - /* wrapped around */ - i += 256 ; - } - - if (phy->lem.lem_on) { - /* Note: Lem errors shall only be counted when - * link is ACTIVE or LCT is active. - */ - phy->lem.lem_errors += i ; - phy->mib->fddiPORTLem_Ct += i ; - } - } - if (cmd & PL_TPC_EXPIRED) { /* TPC timer reached zero */ - if (plc->p_state == PS_LCT) { - /* - * end of LCT - */ - ; - } - plc->tpc_exp++ ; - } - if (cmd & PL_LS_MATCH) { /* LS == LS in PLC_CNTRL_B's MATCH_LS*/ - switch (inpw(PLC(np,PL_CNTRL_B)) & PL_MATCH_LS) { - case PL_I_IDLE : phy->curr_ls = PC_ILS ; break ; - case PL_I_HALT : phy->curr_ls = PC_HLS ; break ; - case PL_I_MASTR : phy->curr_ls = PC_MLS ; break ; - case PL_I_QUIET : phy->curr_ls = PC_QLS ; break ; - } - } - if (cmd & PL_PCM_BREAK) { /* PCM has entered the BREAK state */ - int reason; - - reason = inpw(PLC(np,PL_STATUS_B)) & PL_BREAK_REASON ; - - switch (reason) { - case PL_B_PCS : plc->b_pcs++ ; break ; - case PL_B_TPC : plc->b_tpc++ ; break ; - case PL_B_TNE : plc->b_tne++ ; break ; - case PL_B_QLS : plc->b_qls++ ; break ; - case PL_B_ILS : plc->b_ils++ ; break ; - case PL_B_HLS : plc->b_hls++ ; break ; - } - - /*jd 05-Aug-1999 changed: Bug #10419 */ - DB_PCMN(1,"PLC %d: MDcF = %x\n", np, smc->e.DisconnectFlag); - if (smc->e.DisconnectFlag == FALSE) { - DB_PCMN(1,"PLC %d: restart (reason %x)\n", np, reason); - queue_event(smc,EVENT_PCM+np,PC_START) ; - } - else { - DB_PCMN(1,"PLC %d: NO!! restart (reason %x)\n", np, reason); - } - return ; - } - /* - * If both CODE & ENABLE are set ignore enable - */ - if (cmd & PL_PCM_CODE) { /* receive last sign.-bit | LCT complete */ - queue_event(smc,EVENT_PCM+np,PC_SIGNAL) ; - n = inpw(PLC(np,PL_RCV_VECTOR)) ; - for (i = 0 ; i < plc->p_bits ; i++) { - phy->r_val[plc->p_start+i] = n & 1 ; - n >>= 1 ; - } - } - else if (cmd & PL_PCM_ENABLED) { /* asserted SC_JOIN, scrub.completed*/ - queue_event(smc,EVENT_PCM+np,PC_JOIN) ; - } - if (cmd & PL_TRACE_PROP) { /* MLS while PC8_ACTIV || PC2_TRACE */ - /*PC22b*/ - if (!phy->tr_flag) { - DB_PCMN(1,"PCM : irq TRACE_PROP %d %d\n", - np,smc->mib.fddiSMTECMState) ; - phy->tr_flag = TRUE ; - smc->e.trace_prop |= ENTITY_BIT(ENTITY_PHY(np)) ; - queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ; - } - } - /* - * filter PLC glitch ??? - * QLS || HLS only while in PC2_TRACE state - */ - if ((cmd & PL_SELF_TEST) && (phy->mib->fddiPORTPCMState == PC2_TRACE)) { - /*PC22a*/ - if (smc->e.path_test == PT_PASSED) { - DB_PCMN(1,"PCM : state = %s %d\n", get_pcmstate(smc,np), - phy->mib->fddiPORTPCMState) ; - - smc->e.path_test = PT_PENDING ; - queue_event(smc,EVENT_ECM,EC_PATH_TEST) ; - } - } - if (cmd & PL_TNE_EXPIRED) { /* TNE: length of noise events */ - /* break_required (TNE > NS_Max) */ - if (phy->mib->fddiPORTPCMState == PC8_ACTIVE) { - if (!phy->tr_flag) { - DB_PCMN(1,"PCM %c : PC81 %s\n",phy->phy_name,"NSE"); - queue_event(smc,EVENT_PCM+np,PC_START) ; - return ; - } - } - } -#if 0 - if (cmd & PL_NP_ERR) { /* NP has requested to r/w an inv reg*/ - /* - * It's a bug by AMD - */ - plc->np_err++ ; - } - /* pin inactiv (GND) */ - if (cmd & PL_PARITY_ERR) { /* p. error dedected on TX9-0 inp */ - plc->parity_err++ ; - } - if (cmd & PL_LSDO) { /* carrier detected */ - ; - } -#endif -} - -#ifdef DEBUG -/* - * fill state struct - */ -void pcm_get_state(struct s_smc *smc, struct smt_state *state) -{ - struct s_phy *phy ; - struct pcm_state *pcs ; - int i ; - int ii ; - short rbits ; - short tbits ; - struct fddi_mib_p *mib ; - - for (i = 0, phy = smc->y, pcs = state->pcm_state ; i < NUMPHYS ; - i++ , phy++, pcs++ ) { - mib = phy->mib ; - pcs->pcm_type = (u_char) mib->fddiPORTMy_Type ; - pcs->pcm_state = (u_char) mib->fddiPORTPCMState ; - pcs->pcm_mode = phy->pc_mode ; - pcs->pcm_neighbor = (u_char) mib->fddiPORTNeighborType ; - pcs->pcm_bsf = mib->fddiPORTBS_Flag ; - pcs->pcm_lsf = phy->ls_flag ; - pcs->pcm_lct_fail = (u_char) mib->fddiPORTLCTFail_Ct ; - pcs->pcm_ls_rx = LS2MIB(sm_pm_get_ls(smc,i)) ; - for (ii = 0, rbits = tbits = 0 ; ii < NUMBITS ; ii++) { - rbits <<= 1 ; - tbits <<= 1 ; - if (phy->r_val[NUMBITS-1-ii]) - rbits |= 1 ; - if (phy->t_val[NUMBITS-1-ii]) - tbits |= 1 ; - } - pcs->pcm_r_val = rbits ; - pcs->pcm_t_val = tbits ; - } -} - -int get_pcm_state(struct s_smc *smc, int np) -{ - int pcs ; - - SK_UNUSED(smc) ; - - switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) { - case PL_PC0 : pcs = PC_STOP ; break ; - case PL_PC1 : pcs = PC_START ; break ; - case PL_PC2 : pcs = PC_TRACE ; break ; - case PL_PC3 : pcs = PC_SIGNAL ; break ; - case PL_PC4 : pcs = PC_SIGNAL ; break ; - case PL_PC5 : pcs = PC_SIGNAL ; break ; - case PL_PC6 : pcs = PC_JOIN ; break ; - case PL_PC7 : pcs = PC_JOIN ; break ; - case PL_PC8 : pcs = PC_ENABLE ; break ; - case PL_PC9 : pcs = PC_MAINT ; break ; - default : pcs = PC_DISABLE ; break ; - } - return pcs; -} - -char *get_linestate(struct s_smc *smc, int np) -{ - char *ls = "" ; - - SK_UNUSED(smc) ; - - switch (inpw(PLC(np,PL_STATUS_A)) & PL_LINE_ST) { - case PL_L_NLS : ls = "NOISE" ; break ; - case PL_L_ALS : ls = "ACTIV" ; break ; - case PL_L_UND : ls = "UNDEF" ; break ; - case PL_L_ILS4: ls = "ILS 4" ; break ; - case PL_L_QLS : ls = "QLS" ; break ; - case PL_L_MLS : ls = "MLS" ; break ; - case PL_L_HLS : ls = "HLS" ; break ; - case PL_L_ILS16:ls = "ILS16" ; break ; -#ifdef lint - default: ls = "unknown" ; break ; -#endif - } - return ls; -} - -char *get_pcmstate(struct s_smc *smc, int np) -{ - char *pcs ; - - SK_UNUSED(smc) ; - - switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) { - case PL_PC0 : pcs = "OFF" ; break ; - case PL_PC1 : pcs = "BREAK" ; break ; - case PL_PC2 : pcs = "TRACE" ; break ; - case PL_PC3 : pcs = "CONNECT"; break ; - case PL_PC4 : pcs = "NEXT" ; break ; - case PL_PC5 : pcs = "SIGNAL" ; break ; - case PL_PC6 : pcs = "JOIN" ; break ; - case PL_PC7 : pcs = "VERIFY" ; break ; - case PL_PC8 : pcs = "ACTIV" ; break ; - case PL_PC9 : pcs = "MAINT" ; break ; - default : pcs = "UNKNOWN" ; break ; - } - return pcs; -} - -void list_phy(struct s_smc *smc) -{ - struct s_plc *plc ; - int np ; - - for (np = 0 ; np < NUMPHYS ; np++) { - plc = &smc->y[np].plc ; - printf("PHY %d:\tERRORS\t\t\tBREAK_REASONS\t\tSTATES:\n",np) ; - printf("\tsoft_error: %ld \t\tPC_Start : %ld\n", - plc->soft_err,plc->b_pcs); - printf("\tparity_err: %ld \t\tTPC exp. : %ld\t\tLine: %s\n", - plc->parity_err,plc->b_tpc,get_linestate(smc,np)) ; - printf("\tebuf_error: %ld \t\tTNE exp. : %ld\n", - plc->ebuf_err,plc->b_tne) ; - printf("\tphyinvalid: %ld \t\tQLS det. : %ld\t\tPCM : %s\n", - plc->phyinv,plc->b_qls,get_pcmstate(smc,np)) ; - printf("\tviosym_ctr: %ld \t\tILS det. : %ld\n", - plc->vsym_ctr,plc->b_ils) ; - printf("\tmingap_ctr: %ld \t\tHLS det. : %ld\n", - plc->mini_ctr,plc->b_hls) ; - printf("\tnodepr_err: %ld\n",plc->np_err) ; - printf("\tTPC_exp : %ld\n",plc->tpc_exp) ; - printf("\tLEM_err : %ld\n",smc->y[np].lem.lem_errors) ; - } -} - - -#ifdef CONCENTRATOR -void pcm_lem_dump(struct s_smc *smc) -{ - int i ; - struct s_phy *phy ; - struct fddi_mib_p *mib ; - - char *entostring() ; - - printf("PHY errors BER\n") ; - printf("----------------------\n") ; - for (i = 0,phy = smc->y ; i < NUMPHYS ; i++,phy++) { - if (!plc_is_installed(smc,i)) - continue ; - mib = phy->mib ; - printf("%s\t%ld\t10E-%d\n", - entostring(smc,ENTITY_PHY(i)), - mib->fddiPORTLem_Ct, - mib->fddiPORTLer_Estimate) ; - } -} -#endif -#endif diff --git a/drivers/net/skfp/pmf.c b/drivers/net/skfp/pmf.c deleted file mode 100644 index 9ac4665..0000000 --- a/drivers/net/skfp/pmf.c +++ /dev/null @@ -1,1663 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - Parameter Management Frame processing for SMT 7.2 -*/ - -#include "h/types.h" -#include "h/fddi.h" -#include "h/smc.h" -#include "h/smt_p.h" - -#define KERNEL -#include "h/smtstate.h" - -#ifndef SLIM_SMT - -#ifndef lint -static const char ID_sccs[] = "@(#)pmf.c 1.37 97/08/04 (C) SK " ; -#endif - -static int smt_authorize(struct s_smc *smc, struct smt_header *sm); -static int smt_check_set_count(struct s_smc *smc, struct smt_header *sm); -static const struct s_p_tab* smt_get_ptab(u_short para); -static int smt_mib_phys(struct s_smc *smc); -static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index, - int local, int set); -void smt_add_para(struct s_smc *smc, struct s_pcon *pcon, u_short para, - int index, int local); -static SMbuf *smt_build_pmf_response(struct s_smc *smc, struct smt_header *req, - int set, int local); -static int port_to_mib(struct s_smc *smc, int p); - -#define MOFFSS(e) offsetof(struct fddi_mib, e) -#define MOFFMS(e) offsetof(struct fddi_mib_m, e) -#define MOFFAS(e) offsetof(struct fddi_mib_a, e) -#define MOFFPS(e) offsetof(struct fddi_mib_p, e) - - -#define AC_G 0x01 /* Get */ -#define AC_GR 0x02 /* Get/Set */ -#define AC_S 0x04 /* Set */ -#define AC_NA 0x08 -#define AC_GROUP 0x10 /* Group */ -#define MS2BCLK(x) ((x)*12500L) -/* - F LFag (byte) - B byte - S u_short 16 bit - C Counter 32 bit - L Long 32 bit - T Timer_2 32 bit - P TimeStamp ; - A LongAddress (6 byte) - E Enum 16 bit - R ResId 16 Bit -*/ -static const struct s_p_tab { - u_short p_num ; /* parameter code */ - u_char p_access ; /* access rights */ - u_short p_offset ; /* offset in mib */ - char p_swap[3] ; /* format string */ -} p_tab[] = { - /* StationIdGrp */ - { SMT_P100A,AC_GROUP } , - { SMT_P100B,AC_G, MOFFSS(fddiSMTStationId), "8" } , - { SMT_P100D,AC_G, MOFFSS(fddiSMTOpVersionId), "S" } , - { SMT_P100E,AC_G, MOFFSS(fddiSMTHiVersionId), "S" } , - { SMT_P100F,AC_G, MOFFSS(fddiSMTLoVersionId), "S" } , - { SMT_P1010,AC_G, MOFFSS(fddiSMTManufacturerData), "D" } , - { SMT_P1011,AC_GR, MOFFSS(fddiSMTUserData), "D" } , - { SMT_P1012,AC_G, MOFFSS(fddiSMTMIBVersionId), "S" } , - - /* StationConfigGrp */ - { SMT_P1014,AC_GROUP } , - { SMT_P1015,AC_G, MOFFSS(fddiSMTMac_Ct), "B" } , - { SMT_P1016,AC_G, MOFFSS(fddiSMTNonMaster_Ct), "B" } , - { SMT_P1017,AC_G, MOFFSS(fddiSMTMaster_Ct), "B" } , - { SMT_P1018,AC_G, MOFFSS(fddiSMTAvailablePaths), "B" } , - { SMT_P1019,AC_G, MOFFSS(fddiSMTConfigCapabilities),"S" } , - { SMT_P101A,AC_GR, MOFFSS(fddiSMTConfigPolicy), "wS" } , - { SMT_P101B,AC_GR, MOFFSS(fddiSMTConnectionPolicy),"wS" } , - { SMT_P101D,AC_GR, MOFFSS(fddiSMTTT_Notify), "wS" } , - { SMT_P101E,AC_GR, MOFFSS(fddiSMTStatRptPolicy), "bB" } , - { SMT_P101F,AC_GR, MOFFSS(fddiSMTTrace_MaxExpiration),"lL" } , - { SMT_P1020,AC_G, MOFFSS(fddiSMTPORTIndexes), "II" } , - { SMT_P1021,AC_G, MOFFSS(fddiSMTMACIndexes), "I" } , - { SMT_P1022,AC_G, MOFFSS(fddiSMTBypassPresent), "F" } , - - /* StatusGrp */ - { SMT_P1028,AC_GROUP } , - { SMT_P1029,AC_G, MOFFSS(fddiSMTECMState), "E" } , - { SMT_P102A,AC_G, MOFFSS(fddiSMTCF_State), "E" } , - { SMT_P102C,AC_G, MOFFSS(fddiSMTRemoteDisconnectFlag),"F" } , - { SMT_P102D,AC_G, MOFFSS(fddiSMTStationStatus), "E" } , - { SMT_P102E,AC_G, MOFFSS(fddiSMTPeerWrapFlag), "F" } , - - /* MIBOperationGrp */ - { SMT_P1032,AC_GROUP } , - { SMT_P1033,AC_G, MOFFSS(fddiSMTTimeStamp),"P" } , - { SMT_P1034,AC_G, MOFFSS(fddiSMTTransitionTimeStamp),"P" } , - /* NOTE : SMT_P1035 is already swapped ! SMT_P_SETCOUNT */ - { SMT_P1035,AC_G, MOFFSS(fddiSMTSetCount),"4P" } , - { SMT_P1036,AC_G, MOFFSS(fddiSMTLastSetStationId),"8" } , - - { SMT_P103C,AC_S, 0, "wS" } , - - /* - * PRIVATE EXTENSIONS - * only accessible locally to get/set passwd - */ - { SMT_P10F0,AC_GR, MOFFSS(fddiPRPMFPasswd), "8" } , - { SMT_P10F1,AC_GR, MOFFSS(fddiPRPMFStation), "8" } , -#ifdef ESS - { SMT_P10F2,AC_GR, MOFFSS(fddiESSPayload), "lL" } , - { SMT_P10F3,AC_GR, MOFFSS(fddiESSOverhead), "lL" } , - { SMT_P10F4,AC_GR, MOFFSS(fddiESSMaxTNeg), "lL" } , - { SMT_P10F5,AC_GR, MOFFSS(fddiESSMinSegmentSize), "lL" } , - { SMT_P10F6,AC_GR, MOFFSS(fddiESSCategory), "lL" } , - { SMT_P10F7,AC_GR, MOFFSS(fddiESSSynchTxMode), "wS" } , -#endif -#ifdef SBA - { SMT_P10F8,AC_GR, MOFFSS(fddiSBACommand), "bF" } , - { SMT_P10F9,AC_GR, MOFFSS(fddiSBAAvailable), "bF" } , -#endif - /* MAC Attributes */ - { SMT_P200A,AC_GROUP } , - { SMT_P200B,AC_G, MOFFMS(fddiMACFrameStatusFunctions),"S" } , - { SMT_P200D,AC_G, MOFFMS(fddiMACT_MaxCapabilitiy),"T" } , - { SMT_P200E,AC_G, MOFFMS(fddiMACTVXCapabilitiy),"T" } , - - /* ConfigGrp */ - { SMT_P2014,AC_GROUP } , - { SMT_P2016,AC_G, MOFFMS(fddiMACAvailablePaths), "B" } , - { SMT_P2017,AC_G, MOFFMS(fddiMACCurrentPath), "S" } , - { SMT_P2018,AC_G, MOFFMS(fddiMACUpstreamNbr), "A" } , - { SMT_P2019,AC_G, MOFFMS(fddiMACDownstreamNbr), "A" } , - { SMT_P201A,AC_G, MOFFMS(fddiMACOldUpstreamNbr), "A" } , - { SMT_P201B,AC_G, MOFFMS(fddiMACOldDownstreamNbr),"A" } , - { SMT_P201D,AC_G, MOFFMS(fddiMACDupAddressTest), "E" } , - { SMT_P2020,AC_GR, MOFFMS(fddiMACRequestedPaths), "wS" } , - { SMT_P2021,AC_G, MOFFMS(fddiMACDownstreamPORTType),"E" } , - { SMT_P2022,AC_G, MOFFMS(fddiMACIndex), "S" } , - - /* AddressGrp */ - { SMT_P2028,AC_GROUP } , - { SMT_P2029,AC_G, MOFFMS(fddiMACSMTAddress), "A" } , - - /* OperationGrp */ - { SMT_P2032,AC_GROUP } , - { SMT_P2033,AC_G, MOFFMS(fddiMACT_Req), "T" } , - { SMT_P2034,AC_G, MOFFMS(fddiMACT_Neg), "T" } , - { SMT_P2035,AC_G, MOFFMS(fddiMACT_Max), "T" } , - { SMT_P2036,AC_G, MOFFMS(fddiMACTvxValue), "T" } , - { SMT_P2038,AC_G, MOFFMS(fddiMACT_Pri0), "T" } , - { SMT_P2039,AC_G, MOFFMS(fddiMACT_Pri1), "T" } , - { SMT_P203A,AC_G, MOFFMS(fddiMACT_Pri2), "T" } , - { SMT_P203B,AC_G, MOFFMS(fddiMACT_Pri3), "T" } , - { SMT_P203C,AC_G, MOFFMS(fddiMACT_Pri4), "T" } , - { SMT_P203D,AC_G, MOFFMS(fddiMACT_Pri5), "T" } , - { SMT_P203E,AC_G, MOFFMS(fddiMACT_Pri6), "T" } , - - - /* CountersGrp */ - { SMT_P2046,AC_GROUP } , - { SMT_P2047,AC_G, MOFFMS(fddiMACFrame_Ct), "C" } , - { SMT_P2048,AC_G, MOFFMS(fddiMACCopied_Ct), "C" } , - { SMT_P2049,AC_G, MOFFMS(fddiMACTransmit_Ct), "C" } , - { SMT_P204A,AC_G, MOFFMS(fddiMACToken_Ct), "C" } , - { SMT_P2051,AC_G, MOFFMS(fddiMACError_Ct), "C" } , - { SMT_P2052,AC_G, MOFFMS(fddiMACLost_Ct), "C" } , - { SMT_P2053,AC_G, MOFFMS(fddiMACTvxExpired_Ct), "C" } , - { SMT_P2054,AC_G, MOFFMS(fddiMACNotCopied_Ct), "C" } , - { SMT_P2056,AC_G, MOFFMS(fddiMACRingOp_Ct), "C" } , - - /* FrameErrorConditionGrp */ - { SMT_P205A,AC_GROUP } , - { SMT_P205F,AC_GR, MOFFMS(fddiMACFrameErrorThreshold),"wS" } , - { SMT_P2060,AC_G, MOFFMS(fddiMACFrameErrorRatio), "S" } , - - /* NotCopiedConditionGrp */ - { SMT_P2064,AC_GROUP } , - { SMT_P2067,AC_GR, MOFFMS(fddiMACNotCopiedThreshold),"wS" } , - { SMT_P2069,AC_G, MOFFMS(fddiMACNotCopiedRatio), "S" } , - - /* StatusGrp */ - { SMT_P206E,AC_GROUP } , - { SMT_P206F,AC_G, MOFFMS(fddiMACRMTState), "S" } , - { SMT_P2070,AC_G, MOFFMS(fddiMACDA_Flag), "F" } , - { SMT_P2071,AC_G, MOFFMS(fddiMACUNDA_Flag), "F" } , - { SMT_P2072,AC_G, MOFFMS(fddiMACFrameErrorFlag), "F" } , - { SMT_P2073,AC_G, MOFFMS(fddiMACNotCopiedFlag), "F" } , - { SMT_P2074,AC_G, MOFFMS(fddiMACMA_UnitdataAvailable),"F" } , - { SMT_P2075,AC_G, MOFFMS(fddiMACHardwarePresent), "F" } , - { SMT_P2076,AC_GR, MOFFMS(fddiMACMA_UnitdataEnable),"bF" } , - - /* - * PRIVATE EXTENSIONS - * only accessible locally to get/set TMIN - */ - { SMT_P20F0,AC_NA } , - { SMT_P20F1,AC_GR, MOFFMS(fddiMACT_Min), "lT" } , - - /* Path Attributes */ - /* - * DON't swap 320B,320F,3210: they are already swapped in swap_para() - */ - { SMT_P320A,AC_GROUP } , - { SMT_P320B,AC_G, MOFFAS(fddiPATHIndex), "r" } , - { SMT_P320F,AC_GR, MOFFAS(fddiPATHSbaPayload), "l4" } , - { SMT_P3210,AC_GR, MOFFAS(fddiPATHSbaOverhead), "l4" } , - /* fddiPATHConfiguration */ - { SMT_P3212,AC_G, 0, "" } , - { SMT_P3213,AC_GR, MOFFAS(fddiPATHT_Rmode), "lT" } , - { SMT_P3214,AC_GR, MOFFAS(fddiPATHSbaAvailable), "lL" } , - { SMT_P3215,AC_GR, MOFFAS(fddiPATHTVXLowerBound), "lT" } , - { SMT_P3216,AC_GR, MOFFAS(fddiPATHT_MaxLowerBound),"lT" } , - { SMT_P3217,AC_GR, MOFFAS(fddiPATHMaxT_Req), "lT" } , - - /* Port Attributes */ - /* ConfigGrp */ - { SMT_P400A,AC_GROUP } , - { SMT_P400C,AC_G, MOFFPS(fddiPORTMy_Type), "E" } , - { SMT_P400D,AC_G, MOFFPS(fddiPORTNeighborType), "E" } , - { SMT_P400E,AC_GR, MOFFPS(fddiPORTConnectionPolicies),"bB" } , - { SMT_P400F,AC_G, MOFFPS(fddiPORTMacIndicated), "2" } , - { SMT_P4010,AC_G, MOFFPS(fddiPORTCurrentPath), "E" } , - { SMT_P4011,AC_GR, MOFFPS(fddiPORTRequestedPaths), "l4" } , - { SMT_P4012,AC_G, MOFFPS(fddiPORTMACPlacement), "S" } , - { SMT_P4013,AC_G, MOFFPS(fddiPORTAvailablePaths), "B" } , - { SMT_P4016,AC_G, MOFFPS(fddiPORTPMDClass), "E" } , - { SMT_P4017,AC_G, MOFFPS(fddiPORTConnectionCapabilities), "B"} , - { SMT_P401D,AC_G, MOFFPS(fddiPORTIndex), "R" } , - - /* OperationGrp */ - { SMT_P401E,AC_GROUP } , - { SMT_P401F,AC_GR, MOFFPS(fddiPORTMaint_LS), "wE" } , - { SMT_P4021,AC_G, MOFFPS(fddiPORTBS_Flag), "F" } , - { SMT_P4022,AC_G, MOFFPS(fddiPORTPC_LS), "E" } , - - /* ErrorCtrsGrp */ - { SMT_P4028,AC_GROUP } , - { SMT_P4029,AC_G, MOFFPS(fddiPORTEBError_Ct), "C" } , - { SMT_P402A,AC_G, MOFFPS(fddiPORTLCTFail_Ct), "C" } , - - /* LerGrp */ - { SMT_P4032,AC_GROUP } , - { SMT_P4033,AC_G, MOFFPS(fddiPORTLer_Estimate), "F" } , - { SMT_P4034,AC_G, MOFFPS(fddiPORTLem_Reject_Ct), "C" } , - { SMT_P4035,AC_G, MOFFPS(fddiPORTLem_Ct), "C" } , - { SMT_P403A,AC_GR, MOFFPS(fddiPORTLer_Cutoff), "bB" } , - { SMT_P403B,AC_GR, MOFFPS(fddiPORTLer_Alarm), "bB" } , - - /* StatusGrp */ - { SMT_P403C,AC_GROUP } , - { SMT_P403D,AC_G, MOFFPS(fddiPORTConnectState), "E" } , - { SMT_P403E,AC_G, MOFFPS(fddiPORTPCMStateX), "E" } , - { SMT_P403F,AC_G, MOFFPS(fddiPORTPC_Withhold), "E" } , - { SMT_P4040,AC_G, MOFFPS(fddiPORTLerFlag), "F" } , - { SMT_P4041,AC_G, MOFFPS(fddiPORTHardwarePresent),"F" } , - - { SMT_P4046,AC_S, 0, "wS" } , - - { 0, AC_GROUP } , - { 0 } -} ; - -void smt_pmf_received_pack(struct s_smc *smc, SMbuf *mb, int local) -{ - struct smt_header *sm ; - SMbuf *reply ; - - sm = smtod(mb,struct smt_header *) ; - DB_SMT("SMT: processing PMF frame at %x len %d\n",sm,mb->sm_len) ; -#ifdef DEBUG - dump_smt(smc,sm,"PMF Received") ; -#endif - /* - * Start the watchdog: It may be a long, long packet and - * maybe the watchdog occurs ... - */ - smt_start_watchdog(smc) ; - - if (sm->smt_class == SMT_PMF_GET || - sm->smt_class == SMT_PMF_SET) { - reply = smt_build_pmf_response(smc,sm, - sm->smt_class == SMT_PMF_SET,local) ; - if (reply) { - sm = smtod(reply,struct smt_header *) ; -#ifdef DEBUG - dump_smt(smc,sm,"PMF Reply") ; -#endif - smt_send_frame(smc,reply,FC_SMT_INFO,local) ; - } - } -} - -static SMbuf *smt_build_pmf_response(struct s_smc *smc, struct smt_header *req, - int set, int local) -{ - SMbuf *mb ; - struct smt_header *smt ; - struct smt_para *pa ; - struct smt_p_reason *res ; - const struct s_p_tab *pt ; - int len ; - int index ; - int idx_end ; - int error ; - int range ; - SK_LOC_DECL(struct s_pcon,pcon) ; - SK_LOC_DECL(struct s_pcon,set_pcon) ; - - /* - * build SMT header - */ - if (!(mb = smt_get_mbuf(smc))) - return mb; - - smt = smtod(mb, struct smt_header *) ; - smt->smt_dest = req->smt_source ; /* DA == source of request */ - smt->smt_class = req->smt_class ; /* same class (GET/SET) */ - smt->smt_type = SMT_REPLY ; - smt->smt_version = SMT_VID_2 ; - smt->smt_tid = req->smt_tid ; /* same TID */ - smt->smt_pad = 0 ; - smt->smt_len = 0 ; - - /* - * setup parameter status - */ - pcon.pc_len = SMT_MAX_INFO_LEN ; /* max para length */ - pcon.pc_err = 0 ; /* no error */ - pcon.pc_badset = 0 ; /* no bad set count */ - pcon.pc_p = (void *) (smt + 1) ; /* paras start here */ - - /* - * check authoriziation and set count - */ - error = 0 ; - if (set) { - if (!local && smt_authorize(smc,req)) - error = SMT_RDF_AUTHOR ; - else if (smt_check_set_count(smc,req)) - pcon.pc_badset = SMT_RDF_BADSET ; - } - /* - * add reason code and all mandatory parameters - */ - res = (struct smt_p_reason *) pcon.pc_p ; - smt_add_para(smc,&pcon,(u_short) SMT_P_REASON,0,0) ; - smt_add_para(smc,&pcon,(u_short) SMT_P1033,0,0) ; - /* update 1035 and 1036 later if set */ - set_pcon = pcon ; - smt_add_para(smc,&pcon,(u_short) SMT_P1035,0,0) ; - smt_add_para(smc,&pcon,(u_short) SMT_P1036,0,0) ; - - pcon.pc_err = error ; - len = req->smt_len ; - pa = (struct smt_para *) (req + 1) ; - /* - * process list of paras - */ - while (!pcon.pc_err && len > 0 ) { - if (((u_short)len < pa->p_len + PARA_LEN) || (pa->p_len & 3)) { - pcon.pc_err = SMT_RDF_LENGTH ; - break ; - } - - if (((range = (pa->p_type & 0xf000)) == 0x2000) || - range == 0x3000 || range == 0x4000) { - /* - * get index for PART,MAC ad PATH group - */ - index = *((u_char *)pa + PARA_LEN + 3) ;/* index */ - idx_end = index ; - if (!set && (pa->p_len != 4)) { - pcon.pc_err = SMT_RDF_LENGTH ; - break ; - } - if (!index && !set) { - switch (range) { - case 0x2000 : - index = INDEX_MAC ; - idx_end = index - 1 + NUMMACS ; - break ; - case 0x3000 : - index = INDEX_PATH ; - idx_end = index - 1 + NUMPATHS ; - break ; - case 0x4000 : - index = INDEX_PORT ; - idx_end = index - 1 + NUMPHYS ; -#ifndef CONCENTRATOR - if (smc->s.sas == SMT_SAS) - idx_end = INDEX_PORT ; -#endif - break ; - } - } - } - else { - /* - * smt group has no index - */ - if (!set && (pa->p_len != 0)) { - pcon.pc_err = SMT_RDF_LENGTH ; - break ; - } - index = 0 ; - idx_end = 0 ; - } - while (index <= idx_end) { - /* - * if group - * add all paras of group - */ - pt = smt_get_ptab(pa->p_type) ; - if (pt && pt->p_access == AC_GROUP && !set) { - pt++ ; - while (pt->p_access == AC_G || - pt->p_access == AC_GR) { - smt_add_para(smc,&pcon,pt->p_num, - index,local); - pt++ ; - } - } - /* - * ignore - * AUTHORIZATION in get/set - * SET COUNT in set - */ - else if (pa->p_type != SMT_P_AUTHOR && - (!set || (pa->p_type != SMT_P1035))) { - int st ; - if (pcon.pc_badset) { - smt_add_para(smc,&pcon,pa->p_type, - index,local) ; - } - else if (set) { - st = smt_set_para(smc,pa,index,local,1); - /* - * return para even if error - */ - smt_add_para(smc,&pcon,pa->p_type, - index,local) ; - pcon.pc_err = st ; - } - else { - if (pt && pt->p_access == AC_S) { - pcon.pc_err = - SMT_RDF_ILLEGAL ; - } - smt_add_para(smc,&pcon,pa->p_type, - index,local) ; - } - } - if (pcon.pc_err) - break ; - index++ ; - } - len -= pa->p_len + PARA_LEN ; - pa = (struct smt_para *) ((char *)pa + pa->p_len + PARA_LEN) ; - } - smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ; - mb->sm_len = smt->smt_len + sizeof(struct smt_header) ; - - /* update reason code */ - res->rdf_reason = pcon.pc_badset ? pcon.pc_badset : - pcon.pc_err ? pcon.pc_err : SMT_RDF_SUCCESS ; - if (set && (res->rdf_reason == SMT_RDF_SUCCESS)) { - /* - * increment set count - * set time stamp - * store station id of last set - */ - smc->mib.fddiSMTSetCount.count++ ; - smt_set_timestamp(smc,smc->mib.fddiSMTSetCount.timestamp) ; - smc->mib.fddiSMTLastSetStationId = req->smt_sid ; - smt_add_para(smc,&set_pcon,(u_short) SMT_P1035,0,0) ; - smt_add_para(smc,&set_pcon,(u_short) SMT_P1036,0,0) ; - } - return mb; -} - -static int smt_authorize(struct s_smc *smc, struct smt_header *sm) -{ - struct smt_para *pa ; - int i ; - char *p ; - - /* - * check source station id if not zero - */ - p = (char *) &smc->mib.fddiPRPMFStation ; - for (i = 0 ; i < 8 && !p[i] ; i++) - ; - if (i != 8) { - if (memcmp((char *) &sm->smt_sid, - (char *) &smc->mib.fddiPRPMFStation,8)) - return 1; - } - /* - * check authoriziation parameter if passwd not zero - */ - p = (char *) smc->mib.fddiPRPMFPasswd ; - for (i = 0 ; i < 8 && !p[i] ; i++) - ; - if (i != 8) { - pa = (struct smt_para *) sm_to_para(smc,sm,SMT_P_AUTHOR) ; - if (!pa) - return 1; - if (pa->p_len != 8) - return 1; - if (memcmp((char *)(pa+1),(char *)smc->mib.fddiPRPMFPasswd,8)) - return 1; - } - return 0; -} - -static int smt_check_set_count(struct s_smc *smc, struct smt_header *sm) -{ - struct smt_para *pa ; - struct smt_p_setcount *sc ; - - pa = (struct smt_para *) sm_to_para(smc,sm,SMT_P1035) ; - if (pa) { - sc = (struct smt_p_setcount *) pa ; - if ((smc->mib.fddiSMTSetCount.count != sc->count) || - memcmp((char *) smc->mib.fddiSMTSetCount.timestamp, - (char *)sc->timestamp,8)) - return 1; - } - return 0; -} - -void smt_add_para(struct s_smc *smc, struct s_pcon *pcon, u_short para, - int index, int local) -{ - struct smt_para *pa ; - const struct s_p_tab *pt ; - struct fddi_mib_m *mib_m = NULL; - struct fddi_mib_p *mib_p = NULL; - int len ; - int plen ; - char *from ; - char *to ; - const char *swap ; - char c ; - int range ; - char *mib_addr ; - int mac ; - int path ; - int port ; - int sp_len ; - - /* - * skip if error - */ - if (pcon->pc_err) - return ; - - /* - * actions don't have a value - */ - pt = smt_get_ptab(para) ; - if (pt && pt->p_access == AC_S) - return ; - - to = (char *) (pcon->pc_p) ; /* destination pointer */ - len = pcon->pc_len ; /* free space */ - plen = len ; /* remember start length */ - pa = (struct smt_para *) to ; /* type/length pointer */ - to += PARA_LEN ; /* skip smt_para */ - len -= PARA_LEN ; - /* - * set index if required - */ - if (((range = (para & 0xf000)) == 0x2000) || - range == 0x3000 || range == 0x4000) { - if (len < 4) - goto wrong_error ; - to[0] = 0 ; - to[1] = 0 ; - to[2] = 0 ; - to[3] = index ; - len -= 4 ; - to += 4 ; - } - mac = index - INDEX_MAC ; - path = index - INDEX_PATH ; - port = index - INDEX_PORT ; - /* - * get pointer to mib - */ - switch (range) { - case 0x1000 : - default : - mib_addr = (char *) (&smc->mib) ; - break ; - case 0x2000 : - if (mac < 0 || mac >= NUMMACS) { - pcon->pc_err = SMT_RDF_NOPARAM ; - return ; - } - mib_addr = (char *) (&smc->mib.m[mac]) ; - mib_m = (struct fddi_mib_m *) mib_addr ; - break ; - case 0x3000 : - if (path < 0 || path >= NUMPATHS) { - pcon->pc_err = SMT_RDF_NOPARAM ; - return ; - } - mib_addr = (char *) (&smc->mib.a[path]) ; - break ; - case 0x4000 : - if (port < 0 || port >= smt_mib_phys(smc)) { - pcon->pc_err = SMT_RDF_NOPARAM ; - return ; - } - mib_addr = (char *) (&smc->mib.p[port_to_mib(smc,port)]) ; - mib_p = (struct fddi_mib_p *) mib_addr ; - break ; - } - /* - * check special paras - */ - swap = NULL; - switch (para) { - case SMT_P10F0 : - case SMT_P10F1 : -#ifdef ESS - case SMT_P10F2 : - case SMT_P10F3 : - case SMT_P10F4 : - case SMT_P10F5 : - case SMT_P10F6 : - case SMT_P10F7 : -#endif -#ifdef SBA - case SMT_P10F8 : - case SMT_P10F9 : -#endif - case SMT_P20F1 : - if (!local) { - pcon->pc_err = SMT_RDF_NOPARAM ; - return ; - } - break ; - case SMT_P2034 : - case SMT_P2046 : - case SMT_P2047 : - case SMT_P204A : - case SMT_P2051 : - case SMT_P2052 : - mac_update_counter(smc) ; - break ; - case SMT_P4022: - mib_p->fddiPORTPC_LS = LS2MIB( - sm_pm_get_ls(smc,port_to_mib(smc,port))) ; - break ; - case SMT_P_REASON : - * (u_long *) to = 0 ; - sp_len = 4 ; - goto sp_done ; - case SMT_P1033 : /* time stamp */ - smt_set_timestamp(smc,smc->mib.fddiSMTTimeStamp) ; - break ; - - case SMT_P1020: /* port indexes */ -#if NUMPHYS == 12 - swap = "IIIIIIIIIIII" ; -#else -#if NUMPHYS == 2 - if (smc->s.sas == SMT_SAS) - swap = "I" ; - else - swap = "II" ; -#else -#if NUMPHYS == 24 - swap = "IIIIIIIIIIIIIIIIIIIIIIII" ; -#else - ???? -#endif -#endif -#endif - break ; - case SMT_P3212 : - { - sp_len = cem_build_path(smc,to,path) ; - goto sp_done ; - } - case SMT_P1048 : /* peer wrap condition */ - { - struct smt_p_1048 *sp ; - sp = (struct smt_p_1048 *) to ; - sp->p1048_flag = smc->mib.fddiSMTPeerWrapFlag ; - sp->p1048_cf_state = smc->mib.fddiSMTCF_State ; - sp_len = sizeof(struct smt_p_1048) ; - goto sp_done ; - } - case SMT_P208C : - { - struct smt_p_208c *sp ; - sp = (struct smt_p_208c *) to ; - sp->p208c_flag = - smc->mib.m[MAC0].fddiMACDuplicateAddressCond ; - sp->p208c_dupcondition = - (mib_m->fddiMACDA_Flag ? SMT_ST_MY_DUPA : 0) | - (mib_m->fddiMACUNDA_Flag ? SMT_ST_UNA_DUPA : 0); - sp->p208c_fddilong = - mib_m->fddiMACSMTAddress ; - sp->p208c_fddiunalong = - mib_m->fddiMACUpstreamNbr ; - sp->p208c_pad = 0 ; - sp_len = sizeof(struct smt_p_208c) ; - goto sp_done ; - } - case SMT_P208D : /* frame error condition */ - { - struct smt_p_208d *sp ; - sp = (struct smt_p_208d *) to ; - sp->p208d_flag = - mib_m->fddiMACFrameErrorFlag ; - sp->p208d_frame_ct = - mib_m->fddiMACFrame_Ct ; - sp->p208d_error_ct = - mib_m->fddiMACError_Ct ; - sp->p208d_lost_ct = - mib_m->fddiMACLost_Ct ; - sp->p208d_ratio = - mib_m->fddiMACFrameErrorRatio ; - sp_len = sizeof(struct smt_p_208d) ; - goto sp_done ; - } - case SMT_P208E : /* not copied condition */ - { - struct smt_p_208e *sp ; - sp = (struct smt_p_208e *) to ; - sp->p208e_flag = - mib_m->fddiMACNotCopiedFlag ; - sp->p208e_not_copied = - mib_m->fddiMACNotCopied_Ct ; - sp->p208e_copied = - mib_m->fddiMACCopied_Ct ; - sp->p208e_not_copied_ratio = - mib_m->fddiMACNotCopiedRatio ; - sp_len = sizeof(struct smt_p_208e) ; - goto sp_done ; - } - case SMT_P208F : /* neighbor change event */ - { - struct smt_p_208f *sp ; - sp = (struct smt_p_208f *) to ; - sp->p208f_multiple = - mib_m->fddiMACMultiple_N ; - sp->p208f_nacondition = - mib_m->fddiMACDuplicateAddressCond ; - sp->p208f_old_una = - mib_m->fddiMACOldUpstreamNbr ; - sp->p208f_new_una = - mib_m->fddiMACUpstreamNbr ; - sp->p208f_old_dna = - mib_m->fddiMACOldDownstreamNbr ; - sp->p208f_new_dna = - mib_m->fddiMACDownstreamNbr ; - sp->p208f_curren_path = - mib_m->fddiMACCurrentPath ; - sp->p208f_smt_address = - mib_m->fddiMACSMTAddress ; - sp_len = sizeof(struct smt_p_208f) ; - goto sp_done ; - } - case SMT_P2090 : - { - struct smt_p_2090 *sp ; - sp = (struct smt_p_2090 *) to ; - sp->p2090_multiple = - mib_m->fddiMACMultiple_P ; - sp->p2090_availablepaths = - mib_m->fddiMACAvailablePaths ; - sp->p2090_currentpath = - mib_m->fddiMACCurrentPath ; - sp->p2090_requestedpaths = - mib_m->fddiMACRequestedPaths ; - sp_len = sizeof(struct smt_p_2090) ; - goto sp_done ; - } - case SMT_P4050 : - { - struct smt_p_4050 *sp ; - sp = (struct smt_p_4050 *) to ; - sp->p4050_flag = - mib_p->fddiPORTLerFlag ; - sp->p4050_pad = 0 ; - sp->p4050_cutoff = - mib_p->fddiPORTLer_Cutoff ; - sp->p4050_alarm = - mib_p->fddiPORTLer_Alarm ; - sp->p4050_estimate = - mib_p->fddiPORTLer_Estimate ; - sp->p4050_reject_ct = - mib_p->fddiPORTLem_Reject_Ct ; - sp->p4050_ct = - mib_p->fddiPORTLem_Ct ; - sp_len = sizeof(struct smt_p_4050) ; - goto sp_done ; - } - - case SMT_P4051 : - { - struct smt_p_4051 *sp ; - sp = (struct smt_p_4051 *) to ; - sp->p4051_multiple = - mib_p->fddiPORTMultiple_U ; - sp->p4051_porttype = - mib_p->fddiPORTMy_Type ; - sp->p4051_connectstate = - mib_p->fddiPORTConnectState ; - sp->p4051_pc_neighbor = - mib_p->fddiPORTNeighborType ; - sp->p4051_pc_withhold = - mib_p->fddiPORTPC_Withhold ; - sp_len = sizeof(struct smt_p_4051) ; - goto sp_done ; - } - case SMT_P4052 : - { - struct smt_p_4052 *sp ; - sp = (struct smt_p_4052 *) to ; - sp->p4052_flag = - mib_p->fddiPORTEB_Condition ; - sp->p4052_eberrorcount = - mib_p->fddiPORTEBError_Ct ; - sp_len = sizeof(struct smt_p_4052) ; - goto sp_done ; - } - case SMT_P4053 : - { - struct smt_p_4053 *sp ; - sp = (struct smt_p_4053 *) to ; - sp->p4053_multiple = - mib_p->fddiPORTMultiple_P ; - sp->p4053_availablepaths = - mib_p->fddiPORTAvailablePaths ; - sp->p4053_currentpath = - mib_p->fddiPORTCurrentPath ; - memcpy( (char *) &sp->p4053_requestedpaths, - (char *) mib_p->fddiPORTRequestedPaths,4) ; - sp->p4053_mytype = - mib_p->fddiPORTMy_Type ; - sp->p4053_neighbortype = - mib_p->fddiPORTNeighborType ; - sp_len = sizeof(struct smt_p_4053) ; - goto sp_done ; - } - default : - break ; - } - /* - * in table ? - */ - if (!pt) { - pcon->pc_err = (para & 0xff00) ? SMT_RDF_NOPARAM : - SMT_RDF_ILLEGAL ; - return ; - } - /* - * check access rights - */ - switch (pt->p_access) { - case AC_G : - case AC_GR : - break ; - default : - pcon->pc_err = SMT_RDF_ILLEGAL ; - return ; - } - from = mib_addr + pt->p_offset ; - if (!swap) - swap = pt->p_swap ; /* pointer to swap string */ - - /* - * copy values - */ - while ((c = *swap++)) { - switch(c) { - case 'b' : - case 'w' : - case 'l' : - break ; - case 'S' : - case 'E' : - case 'R' : - case 'r' : - if (len < 4) - goto len_error ; - to[0] = 0 ; - to[1] = 0 ; -#ifdef LITTLE_ENDIAN - if (c == 'r') { - to[2] = *from++ ; - to[3] = *from++ ; - } - else { - to[3] = *from++ ; - to[2] = *from++ ; - } -#else - to[2] = *from++ ; - to[3] = *from++ ; -#endif - to += 4 ; - len -= 4 ; - break ; - case 'I' : /* for SET of port indexes */ - if (len < 2) - goto len_error ; -#ifdef LITTLE_ENDIAN - to[1] = *from++ ; - to[0] = *from++ ; -#else - to[0] = *from++ ; - to[1] = *from++ ; -#endif - to += 2 ; - len -= 2 ; - break ; - case 'F' : - case 'B' : - if (len < 4) - goto len_error ; - len -= 4 ; - to[0] = 0 ; - to[1] = 0 ; - to[2] = 0 ; - to[3] = *from++ ; - to += 4 ; - break ; - case 'C' : - case 'T' : - case 'L' : - if (len < 4) - goto len_error ; -#ifdef LITTLE_ENDIAN - to[3] = *from++ ; - to[2] = *from++ ; - to[1] = *from++ ; - to[0] = *from++ ; -#else - to[0] = *from++ ; - to[1] = *from++ ; - to[2] = *from++ ; - to[3] = *from++ ; -#endif - len -= 4 ; - to += 4 ; - break ; - case '2' : /* PortMacIndicated */ - if (len < 4) - goto len_error ; - to[0] = 0 ; - to[1] = 0 ; - to[2] = *from++ ; - to[3] = *from++ ; - len -= 4 ; - to += 4 ; - break ; - case '4' : - if (len < 4) - goto len_error ; - to[0] = *from++ ; - to[1] = *from++ ; - to[2] = *from++ ; - to[3] = *from++ ; - len -= 4 ; - to += 4 ; - break ; - case 'A' : - if (len < 8) - goto len_error ; - to[0] = 0 ; - to[1] = 0 ; - memcpy((char *) to+2,(char *) from,6) ; - to += 8 ; - from += 8 ; - len -= 8 ; - break ; - case '8' : - if (len < 8) - goto len_error ; - memcpy((char *) to,(char *) from,8) ; - to += 8 ; - from += 8 ; - len -= 8 ; - break ; - case 'D' : - if (len < 32) - goto len_error ; - memcpy((char *) to,(char *) from,32) ; - to += 32 ; - from += 32 ; - len -= 32 ; - break ; - case 'P' : /* timestamp is NOT swapped */ - if (len < 8) - goto len_error ; - to[0] = *from++ ; - to[1] = *from++ ; - to[2] = *from++ ; - to[3] = *from++ ; - to[4] = *from++ ; - to[5] = *from++ ; - to[6] = *from++ ; - to[7] = *from++ ; - to += 8 ; - len -= 8 ; - break ; - default : - SMT_PANIC(smc,SMT_E0119, SMT_E0119_MSG) ; - break ; - } - } - -done: - /* - * make it even (in case of 'I' encoding) - * note: len is DECREMENTED - */ - if (len & 3) { - to[0] = 0 ; - to[1] = 0 ; - to += 4 - (len & 3 ) ; - len = len & ~ 3 ; - } - - /* set type and length */ - pa->p_type = para ; - pa->p_len = plen - len - PARA_LEN ; - /* return values */ - pcon->pc_p = (void *) to ; - pcon->pc_len = len ; - return ; - -sp_done: - len -= sp_len ; - to += sp_len ; - goto done ; - -len_error: - /* parameter does not fit in frame */ - pcon->pc_err = SMT_RDF_TOOLONG ; - return ; - -wrong_error: - pcon->pc_err = SMT_RDF_LENGTH ; -} - -/* - * set parameter - */ -static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index, - int local, int set) -{ -#define IFSET(x) if (set) (x) - - const struct s_p_tab *pt ; - int len ; - char *from ; - char *to ; - const char *swap ; - char c ; - char *mib_addr ; - struct fddi_mib *mib ; - struct fddi_mib_m *mib_m = NULL; - struct fddi_mib_a *mib_a = NULL; - struct fddi_mib_p *mib_p = NULL; - int mac ; - int path ; - int port ; - SK_LOC_DECL(u_char,byte_val) ; - SK_LOC_DECL(u_short,word_val) ; - SK_LOC_DECL(u_long,long_val) ; - - mac = index - INDEX_MAC ; - path = index - INDEX_PATH ; - port = index - INDEX_PORT ; - len = pa->p_len ; - from = (char *) (pa + 1 ) ; - - mib = &smc->mib ; - switch (pa->p_type & 0xf000) { - case 0x1000 : - default : - mib_addr = (char *) mib ; - break ; - case 0x2000 : - if (mac < 0 || mac >= NUMMACS) { - return SMT_RDF_NOPARAM; - } - mib_m = &smc->mib.m[mac] ; - mib_addr = (char *) mib_m ; - from += 4 ; /* skip index */ - len -= 4 ; - break ; - case 0x3000 : - if (path < 0 || path >= NUMPATHS) { - return SMT_RDF_NOPARAM; - } - mib_a = &smc->mib.a[path] ; - mib_addr = (char *) mib_a ; - from += 4 ; /* skip index */ - len -= 4 ; - break ; - case 0x4000 : - if (port < 0 || port >= smt_mib_phys(smc)) { - return SMT_RDF_NOPARAM; - } - mib_p = &smc->mib.p[port_to_mib(smc,port)] ; - mib_addr = (char *) mib_p ; - from += 4 ; /* skip index */ - len -= 4 ; - break ; - } - switch (pa->p_type) { - case SMT_P10F0 : - case SMT_P10F1 : -#ifdef ESS - case SMT_P10F2 : - case SMT_P10F3 : - case SMT_P10F4 : - case SMT_P10F5 : - case SMT_P10F6 : - case SMT_P10F7 : -#endif -#ifdef SBA - case SMT_P10F8 : - case SMT_P10F9 : -#endif - case SMT_P20F1 : - if (!local) - return SMT_RDF_NOPARAM; - break ; - } - pt = smt_get_ptab(pa->p_type) ; - if (!pt) - return (pa->p_type & 0xff00) ? SMT_RDF_NOPARAM : - SMT_RDF_ILLEGAL; - switch (pt->p_access) { - case AC_GR : - case AC_S : - break ; - default : - return SMT_RDF_ILLEGAL; - } - to = mib_addr + pt->p_offset ; - swap = pt->p_swap ; /* pointer to swap string */ - - while (swap && (c = *swap++)) { - switch(c) { - case 'b' : - to = (char *) &byte_val ; - break ; - case 'w' : - to = (char *) &word_val ; - break ; - case 'l' : - to = (char *) &long_val ; - break ; - case 'S' : - case 'E' : - case 'R' : - case 'r' : - if (len < 4) { - goto len_error ; - } - if (from[0] | from[1]) - goto val_error ; -#ifdef LITTLE_ENDIAN - if (c == 'r') { - to[0] = from[2] ; - to[1] = from[3] ; - } - else { - to[1] = from[2] ; - to[0] = from[3] ; - } -#else - to[0] = from[2] ; - to[1] = from[3] ; -#endif - from += 4 ; - to += 2 ; - len -= 4 ; - break ; - case 'F' : - case 'B' : - if (len < 4) { - goto len_error ; - } - if (from[0] | from[1] | from[2]) - goto val_error ; - to[0] = from[3] ; - len -= 4 ; - from += 4 ; - to += 4 ; - break ; - case 'C' : - case 'T' : - case 'L' : - if (len < 4) { - goto len_error ; - } -#ifdef LITTLE_ENDIAN - to[3] = *from++ ; - to[2] = *from++ ; - to[1] = *from++ ; - to[0] = *from++ ; -#else - to[0] = *from++ ; - to[1] = *from++ ; - to[2] = *from++ ; - to[3] = *from++ ; -#endif - len -= 4 ; - to += 4 ; - break ; - case 'A' : - if (len < 8) - goto len_error ; - if (set) - memcpy((char *) to,(char *) from+2,6) ; - to += 8 ; - from += 8 ; - len -= 8 ; - break ; - case '4' : - if (len < 4) - goto len_error ; - if (set) - memcpy((char *) to,(char *) from,4) ; - to += 4 ; - from += 4 ; - len -= 4 ; - break ; - case '8' : - if (len < 8) - goto len_error ; - if (set) - memcpy((char *) to,(char *) from,8) ; - to += 8 ; - from += 8 ; - len -= 8 ; - break ; - case 'D' : - if (len < 32) - goto len_error ; - if (set) - memcpy((char *) to,(char *) from,32) ; - to += 32 ; - from += 32 ; - len -= 32 ; - break ; - case 'P' : /* timestamp is NOT swapped */ - if (set) { - to[0] = *from++ ; - to[1] = *from++ ; - to[2] = *from++ ; - to[3] = *from++ ; - to[4] = *from++ ; - to[5] = *from++ ; - to[6] = *from++ ; - to[7] = *from++ ; - } - to += 8 ; - len -= 8 ; - break ; - default : - SMT_PANIC(smc,SMT_E0120, SMT_E0120_MSG) ; - return SMT_RDF_ILLEGAL; - } - } - /* - * actions and internal updates - */ - switch (pa->p_type) { - case SMT_P101A: /* fddiSMTConfigPolicy */ - if (word_val & ~1) - goto val_error ; - IFSET(mib->fddiSMTConfigPolicy = word_val) ; - break ; - case SMT_P101B : /* fddiSMTConnectionPolicy */ - if (!(word_val & POLICY_MM)) - goto val_error ; - IFSET(mib->fddiSMTConnectionPolicy = word_val) ; - break ; - case SMT_P101D : /* fddiSMTTT_Notify */ - if (word_val < 2 || word_val > 30) - goto val_error ; - IFSET(mib->fddiSMTTT_Notify = word_val) ; - break ; - case SMT_P101E : /* fddiSMTStatRptPolicy */ - if (byte_val & ~1) - goto val_error ; - IFSET(mib->fddiSMTStatRptPolicy = byte_val) ; - break ; - case SMT_P101F : /* fddiSMTTrace_MaxExpiration */ - /* - * note: lower limit trace_max = 6.001773... s - * NO upper limit - */ - if (long_val < (long)0x478bf51L) - goto val_error ; - IFSET(mib->fddiSMTTrace_MaxExpiration = long_val) ; - break ; -#ifdef ESS - case SMT_P10F2 : /* fddiESSPayload */ - if (long_val > 1562) - goto val_error ; - if (set && smc->mib.fddiESSPayload != long_val) { - smc->ess.raf_act_timer_poll = TRUE ; - smc->mib.fddiESSPayload = long_val ; - } - break ; - case SMT_P10F3 : /* fddiESSOverhead */ - if (long_val < 50 || long_val > 5000) - goto val_error ; - if (set && smc->mib.fddiESSPayload && - smc->mib.fddiESSOverhead != long_val) { - smc->ess.raf_act_timer_poll = TRUE ; - smc->mib.fddiESSOverhead = long_val ; - } - break ; - case SMT_P10F4 : /* fddiESSMaxTNeg */ - if (long_val > -MS2BCLK(5) || long_val < -MS2BCLK(165)) - goto val_error ; - IFSET(mib->fddiESSMaxTNeg = long_val) ; - break ; - case SMT_P10F5 : /* fddiESSMinSegmentSize */ - if (long_val < 1 || long_val > 4478) - goto val_error ; - IFSET(mib->fddiESSMinSegmentSize = long_val) ; - break ; - case SMT_P10F6 : /* fddiESSCategory */ - if ((long_val & 0xffff) != 1) - goto val_error ; - IFSET(mib->fddiESSCategory = long_val) ; - break ; - case SMT_P10F7 : /* fddiESSSyncTxMode */ - if (word_val > 1) - goto val_error ; - IFSET(mib->fddiESSSynchTxMode = word_val) ; - break ; -#endif -#ifdef SBA - case SMT_P10F8 : /* fddiSBACommand */ - if (byte_val != SB_STOP && byte_val != SB_START) - goto val_error ; - IFSET(mib->fddiSBACommand = byte_val) ; - break ; - case SMT_P10F9 : /* fddiSBAAvailable */ - if (byte_val > 100) - goto val_error ; - IFSET(mib->fddiSBAAvailable = byte_val) ; - break ; -#endif - case SMT_P2020 : /* fddiMACRequestedPaths */ - if ((word_val & (MIB_P_PATH_PRIM_PREFER | - MIB_P_PATH_PRIM_ALTER)) == 0 ) - goto val_error ; - IFSET(mib_m->fddiMACRequestedPaths = word_val) ; - break ; - case SMT_P205F : /* fddiMACFrameErrorThreshold */ - /* 0 .. ffff acceptable */ - IFSET(mib_m->fddiMACFrameErrorThreshold = word_val) ; - break ; - case SMT_P2067 : /* fddiMACNotCopiedThreshold */ - /* 0 .. ffff acceptable */ - IFSET(mib_m->fddiMACNotCopiedThreshold = word_val) ; - break ; - case SMT_P2076: /* fddiMACMA_UnitdataEnable */ - if (byte_val & ~1) - goto val_error ; - if (set) { - mib_m->fddiMACMA_UnitdataEnable = byte_val ; - queue_event(smc,EVENT_RMT,RM_ENABLE_FLAG) ; - } - break ; - case SMT_P20F1 : /* fddiMACT_Min */ - IFSET(mib_m->fddiMACT_Min = long_val) ; - break ; - case SMT_P320F : - if (long_val > 1562) - goto val_error ; - IFSET(mib_a->fddiPATHSbaPayload = long_val) ; -#ifdef ESS - if (set) - ess_para_change(smc) ; -#endif - break ; - case SMT_P3210 : - if (long_val > 5000) - goto val_error ; - - if (long_val != 0 && mib_a->fddiPATHSbaPayload == 0) - goto val_error ; - - IFSET(mib_a->fddiPATHSbaOverhead = long_val) ; -#ifdef ESS - if (set) - ess_para_change(smc) ; -#endif - break ; - case SMT_P3213: /* fddiPATHT_Rmode */ - /* no limit : - * 0 .. 343.597 => 0 .. 2e32 * 80nS - */ - if (set) { - mib_a->fddiPATHT_Rmode = long_val ; - rtm_set_timer(smc) ; - } - break ; - case SMT_P3214 : /* fddiPATHSbaAvailable */ - if (long_val > 0x00BEBC20L) - goto val_error ; -#ifdef SBA - if (set && mib->fddiSBACommand == SB_STOP) - goto val_error ; -#endif - IFSET(mib_a->fddiPATHSbaAvailable = long_val) ; - break ; - case SMT_P3215 : /* fddiPATHTVXLowerBound */ - IFSET(mib_a->fddiPATHTVXLowerBound = long_val) ; - goto change_mac_para ; - case SMT_P3216 : /* fddiPATHT_MaxLowerBound */ - IFSET(mib_a->fddiPATHT_MaxLowerBound = long_val) ; - goto change_mac_para ; - case SMT_P3217 : /* fddiPATHMaxT_Req */ - IFSET(mib_a->fddiPATHMaxT_Req = long_val) ; - -change_mac_para: - if (set && smt_set_mac_opvalues(smc)) { - RS_SET(smc,RS_EVENT) ; - smc->sm.please_reconnect = 1 ; - queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; - } - break ; - case SMT_P400E : /* fddiPORTConnectionPolicies */ - if (byte_val > 1) - goto val_error ; - IFSET(mib_p->fddiPORTConnectionPolicies = byte_val) ; - break ; - case SMT_P4011 : /* fddiPORTRequestedPaths */ - /* all 3*8 bits allowed */ - IFSET(memcpy((char *)mib_p->fddiPORTRequestedPaths, - (char *)&long_val,4)) ; - break ; - case SMT_P401F: /* fddiPORTMaint_LS */ - if (word_val > 4) - goto val_error ; - IFSET(mib_p->fddiPORTMaint_LS = word_val) ; - break ; - case SMT_P403A : /* fddiPORTLer_Cutoff */ - if (byte_val < 4 || byte_val > 15) - goto val_error ; - IFSET(mib_p->fddiPORTLer_Cutoff = byte_val) ; - break ; - case SMT_P403B : /* fddiPORTLer_Alarm */ - if (byte_val < 4 || byte_val > 15) - goto val_error ; - IFSET(mib_p->fddiPORTLer_Alarm = byte_val) ; - break ; - - /* - * Actions - */ - case SMT_P103C : /* fddiSMTStationAction */ - if (smt_action(smc,SMT_STATION_ACTION, (int) word_val, 0)) - goto val_error ; - break ; - case SMT_P4046: /* fddiPORTAction */ - if (smt_action(smc,SMT_PORT_ACTION, (int) word_val, - port_to_mib(smc,port))) - goto val_error ; - break ; - default : - break ; - } - return 0; - -val_error: - /* parameter value in frame is out of range */ - return SMT_RDF_RANGE; - -len_error: - /* parameter value in frame is too short */ - return SMT_RDF_LENGTH; - -#if 0 -no_author_error: - /* parameter not setable, because the SBA is not active - * Please note: we give the return code 'not authorizeed - * because SBA denied is not a valid return code in the - * PMF protocol. - */ - return SMT_RDF_AUTHOR; -#endif -} - -static const struct s_p_tab *smt_get_ptab(u_short para) -{ - const struct s_p_tab *pt ; - for (pt = p_tab ; pt->p_num && pt->p_num != para ; pt++) - ; - return pt->p_num ? pt : NULL; -} - -static int smt_mib_phys(struct s_smc *smc) -{ -#ifdef CONCENTRATOR - SK_UNUSED(smc) ; - - return NUMPHYS; -#else - if (smc->s.sas == SMT_SAS) - return 1; - return NUMPHYS; -#endif -} - -static int port_to_mib(struct s_smc *smc, int p) -{ -#ifdef CONCENTRATOR - SK_UNUSED(smc) ; - - return p; -#else - if (smc->s.sas == SMT_SAS) - return PS; - return p; -#endif -} - - -#ifdef DEBUG -#ifndef BOOT -void dump_smt(struct s_smc *smc, struct smt_header *sm, char *text) -{ - int len ; - struct smt_para *pa ; - char *c ; - int n ; - int nn ; -#ifdef LITTLE_ENDIAN - int smtlen ; -#endif - - SK_UNUSED(smc) ; - -#ifdef DEBUG_BRD - if (smc->debug.d_smtf < 2) -#else - if (debug.d_smtf < 2) -#endif - return ; -#ifdef LITTLE_ENDIAN - smtlen = sm->smt_len + sizeof(struct smt_header) ; -#endif - printf("SMT Frame [%s]:\nDA ",text) ; - dump_hex((char *) &sm->smt_dest,6) ; - printf("\tSA ") ; - dump_hex((char *) &sm->smt_source,6) ; - printf(" Class %x Type %x Version %x\n", - sm->smt_class,sm->smt_type,sm->smt_version) ; - printf("TID %lx\t\tSID ",sm->smt_tid) ; - dump_hex((char *) &sm->smt_sid,8) ; - printf(" LEN %x\n",sm->smt_len) ; - - len = sm->smt_len ; - pa = (struct smt_para *) (sm + 1) ; - while (len > 0 ) { - int plen ; -#ifdef UNIX - printf("TYPE %x LEN %x VALUE\t",pa->p_type,pa->p_len) ; -#else - printf("TYPE %04x LEN %2x VALUE\t",pa->p_type,pa->p_len) ; -#endif - n = pa->p_len ; - if ( (n < 0 ) || (n > (int)(len - PARA_LEN))) { - n = len - PARA_LEN ; - printf(" BAD LENGTH\n") ; - break ; - } -#ifdef LITTLE_ENDIAN - smt_swap_para(sm,smtlen,0) ; -#endif - if (n < 24) { - dump_hex((char *)(pa+1),(int) n) ; - printf("\n") ; - } - else { - int first = 0 ; - c = (char *)(pa+1) ; - dump_hex(c,16) ; - printf("\n") ; - n -= 16 ; - c += 16 ; - while (n > 0) { - nn = (n > 16) ? 16 : n ; - if (n > 64) { - if (first == 0) - printf("\t\t\t...\n") ; - first = 1 ; - } - else { - printf("\t\t\t") ; - dump_hex(c,nn) ; - printf("\n") ; - } - n -= nn ; - c += 16 ; - } - } -#ifdef LITTLE_ENDIAN - smt_swap_para(sm,smtlen,1) ; -#endif - plen = (pa->p_len + PARA_LEN + 3) & ~3 ; - len -= plen ; - pa = (struct smt_para *)((char *)pa + plen) ; - } - printf("-------------------------------------------------\n\n") ; -} - -void dump_hex(char *p, int len) -{ - int n = 0 ; - while (len--) { - n++ ; -#ifdef UNIX - printf("%x%s",*p++ & 0xff,len ? ( (n & 7) ? " " : "-") : "") ; -#else - printf("%02x%s",*p++ & 0xff,len ? ( (n & 7) ? " " : "-") : "") ; -#endif - } -} -#endif /* no BOOT */ -#endif /* DEBUG */ - - -#endif /* no SLIM_SMT */ diff --git a/drivers/net/skfp/queue.c b/drivers/net/skfp/queue.c deleted file mode 100644 index c1a0df4..0000000 --- a/drivers/net/skfp/queue.c +++ /dev/null @@ -1,173 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - SMT Event Queue Management -*/ - -#include "h/types.h" -#include "h/fddi.h" -#include "h/smc.h" - -#ifndef lint -static const char ID_sccs[] = "@(#)queue.c 2.9 97/08/04 (C) SK " ; -#endif - -#define PRINTF(a,b,c) - -/* - * init event queue management - */ -void ev_init(struct s_smc *smc) -{ - smc->q.ev_put = smc->q.ev_get = smc->q.ev_queue ; -} - -/* - * add event to queue - */ -void queue_event(struct s_smc *smc, int class, int event) -{ - PRINTF("queue class %d event %d\n",class,event) ; - smc->q.ev_put->class = class ; - smc->q.ev_put->event = event ; - if (++smc->q.ev_put == &smc->q.ev_queue[MAX_EVENT]) - smc->q.ev_put = smc->q.ev_queue ; - - if (smc->q.ev_put == smc->q.ev_get) { - SMT_ERR_LOG(smc,SMT_E0137, SMT_E0137_MSG) ; - } -} - -/* - * timer_event is called from HW timer package. - */ -void timer_event(struct s_smc *smc, u_long token) -{ - PRINTF("timer event class %d token %d\n", - EV_T_CLASS(token), - EV_T_EVENT(token)) ; - queue_event(smc,EV_T_CLASS(token),EV_T_EVENT(token)); -} - -/* - * event dispatcher - * while event queue is not empty - * get event from queue - * send command to state machine - * end - */ -void ev_dispatcher(struct s_smc *smc) -{ - struct event_queue *ev ; /* pointer into queue */ - int class ; - - ev = smc->q.ev_get ; - PRINTF("dispatch get %x put %x\n",ev,smc->q.ev_put) ; - while (ev != smc->q.ev_put) { - PRINTF("dispatch class %d event %d\n",ev->class,ev->event) ; - switch(class = ev->class) { - case EVENT_ECM : /* Entity Corordination Man. */ - ecm(smc,(int)ev->event) ; - break ; - case EVENT_CFM : /* Configuration Man. */ - cfm(smc,(int)ev->event) ; - break ; - case EVENT_RMT : /* Ring Man. */ - rmt(smc,(int)ev->event) ; - break ; - case EVENT_SMT : - smt_event(smc,(int)ev->event) ; - break ; -#ifdef CONCENTRATOR - case 99 : - timer_test_event(smc,(int)ev->event) ; - break ; -#endif - case EVENT_PCMA : /* PHY A */ - case EVENT_PCMB : /* PHY B */ - default : - if (class >= EVENT_PCMA && - class < EVENT_PCMA + NUMPHYS) { - pcm(smc,class - EVENT_PCMA,(int)ev->event) ; - break ; - } - SMT_PANIC(smc,SMT_E0121, SMT_E0121_MSG) ; - return ; - } - - if (++ev == &smc->q.ev_queue[MAX_EVENT]) - ev = smc->q.ev_queue ; - - /* Renew get: it is used in queue_events to detect overruns */ - smc->q.ev_get = ev; - } -} - -/* - * smt_online connects to or disconnects from the ring - * MUST be called to initiate connection establishment - * - * on 0 disconnect - * on 1 connect - */ -u_short smt_online(struct s_smc *smc, int on) -{ - queue_event(smc,EVENT_ECM,on ? EC_CONNECT : EC_DISCONNECT) ; - ev_dispatcher(smc) ; - return smc->mib.fddiSMTCF_State; -} - -/* - * set SMT flag to value - * flag flag name - * value flag value - * dump current flag setting - */ -#ifdef CONCENTRATOR -void do_smt_flag(struct s_smc *smc, char *flag, int value) -{ -#ifdef DEBUG - struct smt_debug *deb; - - SK_UNUSED(smc) ; - -#ifdef DEBUG_BRD - deb = &smc->debug; -#else - deb = &debug; -#endif - if (!strcmp(flag,"smt")) - deb->d_smt = value ; - else if (!strcmp(flag,"smtf")) - deb->d_smtf = value ; - else if (!strcmp(flag,"pcm")) - deb->d_pcm = value ; - else if (!strcmp(flag,"rmt")) - deb->d_rmt = value ; - else if (!strcmp(flag,"cfm")) - deb->d_cfm = value ; - else if (!strcmp(flag,"ecm")) - deb->d_ecm = value ; - printf("smt %d\n",deb->d_smt) ; - printf("smtf %d\n",deb->d_smtf) ; - printf("pcm %d\n",deb->d_pcm) ; - printf("rmt %d\n",deb->d_rmt) ; - printf("cfm %d\n",deb->d_cfm) ; - printf("ecm %d\n",deb->d_ecm) ; -#endif /* DEBUG */ -} -#endif diff --git a/drivers/net/skfp/rmt.c b/drivers/net/skfp/rmt.c deleted file mode 100644 index ef8d567..0000000 --- a/drivers/net/skfp/rmt.c +++ /dev/null @@ -1,654 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - SMT RMT - Ring Management -*/ - -/* - * Hardware independent state machine implemantation - * The following external SMT functions are referenced : - * - * queue_event() - * smt_timer_start() - * smt_timer_stop() - * - * The following external HW dependent functions are referenced : - * sm_ma_control() - * sm_mac_check_beacon_claim() - * - * The following HW dependent events are required : - * RM_RING_OP - * RM_RING_NON_OP - * RM_MY_BEACON - * RM_OTHER_BEACON - * RM_MY_CLAIM - * RM_TRT_EXP - * RM_VALID_CLAIM - * - */ - -#include "h/types.h" -#include "h/fddi.h" -#include "h/smc.h" - -#define KERNEL -#include "h/smtstate.h" - -#ifndef lint -static const char ID_sccs[] = "@(#)rmt.c 2.13 99/07/02 (C) SK " ; -#endif - -/* - * FSM Macros - */ -#define AFLAG 0x10 -#define GO_STATE(x) (smc->mib.m[MAC0].fddiMACRMTState = (x)|AFLAG) -#define ACTIONS_DONE() (smc->mib.m[MAC0].fddiMACRMTState &= ~AFLAG) -#define ACTIONS(x) (x|AFLAG) - -#define RM0_ISOLATED 0 -#define RM1_NON_OP 1 /* not operational */ -#define RM2_RING_OP 2 /* ring operational */ -#define RM3_DETECT 3 /* detect dupl addresses */ -#define RM4_NON_OP_DUP 4 /* dupl. addr detected */ -#define RM5_RING_OP_DUP 5 /* ring oper. with dupl. addr */ -#define RM6_DIRECTED 6 /* sending directed beacons */ -#define RM7_TRACE 7 /* trace initiated */ - -#ifdef DEBUG -/* - * symbolic state names - */ -static const char * const rmt_states[] = { - "RM0_ISOLATED","RM1_NON_OP","RM2_RING_OP","RM3_DETECT", - "RM4_NON_OP_DUP","RM5_RING_OP_DUP","RM6_DIRECTED", - "RM7_TRACE" -} ; - -/* - * symbolic event names - */ -static const char * const rmt_events[] = { - "NONE","RM_RING_OP","RM_RING_NON_OP","RM_MY_BEACON", - "RM_OTHER_BEACON","RM_MY_CLAIM","RM_TRT_EXP","RM_VALID_CLAIM", - "RM_JOIN","RM_LOOP","RM_DUP_ADDR","RM_ENABLE_FLAG", - "RM_TIMEOUT_NON_OP","RM_TIMEOUT_T_STUCK", - "RM_TIMEOUT_ANNOUNCE","RM_TIMEOUT_T_DIRECT", - "RM_TIMEOUT_D_MAX","RM_TIMEOUT_POLL","RM_TX_STATE_CHANGE" -} ; -#endif - -/* - * Globals - * in struct s_rmt - */ - - -/* - * function declarations - */ -static void rmt_fsm(struct s_smc *smc, int cmd); -static void start_rmt_timer0(struct s_smc *smc, u_long value, int event); -static void start_rmt_timer1(struct s_smc *smc, u_long value, int event); -static void start_rmt_timer2(struct s_smc *smc, u_long value, int event); -static void stop_rmt_timer0(struct s_smc *smc); -static void stop_rmt_timer1(struct s_smc *smc); -static void stop_rmt_timer2(struct s_smc *smc); -static void rmt_dup_actions(struct s_smc *smc); -static void rmt_reinsert_actions(struct s_smc *smc); -static void rmt_leave_actions(struct s_smc *smc); -static void rmt_new_dup_actions(struct s_smc *smc); - -#ifndef SUPERNET_3 -extern void restart_trt_for_dbcn() ; -#endif /*SUPERNET_3*/ - -/* - init RMT state machine - clear all RMT vars and flags -*/ -void rmt_init(struct s_smc *smc) -{ - smc->mib.m[MAC0].fddiMACRMTState = ACTIONS(RM0_ISOLATED) ; - smc->r.dup_addr_test = DA_NONE ; - smc->r.da_flag = 0 ; - smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; - smc->r.sm_ma_avail = FALSE ; - smc->r.loop_avail = 0 ; - smc->r.bn_flag = 0 ; - smc->r.jm_flag = 0 ; - smc->r.no_flag = TRUE ; -} - -/* - RMT state machine - called by dispatcher - - do - display state change - process event - until SM is stable -*/ -void rmt(struct s_smc *smc, int event) -{ - int state ; - - do { - DB_RMT("RMT : state %s%s", - (smc->mib.m[MAC0].fddiMACRMTState & AFLAG) ? "ACTIONS " : "", - rmt_states[smc->mib.m[MAC0].fddiMACRMTState & ~AFLAG]) ; - DB_RMT(" event %s\n",rmt_events[event],0) ; - state = smc->mib.m[MAC0].fddiMACRMTState ; - rmt_fsm(smc,event) ; - event = 0 ; - } while (state != smc->mib.m[MAC0].fddiMACRMTState) ; - rmt_state_change(smc,(int)smc->mib.m[MAC0].fddiMACRMTState) ; -} - -/* - process RMT event -*/ -static void rmt_fsm(struct s_smc *smc, int cmd) -{ - /* - * RM00-RM70 : from all states - */ - if (!smc->r.rm_join && !smc->r.rm_loop && - smc->mib.m[MAC0].fddiMACRMTState != ACTIONS(RM0_ISOLATED) && - smc->mib.m[MAC0].fddiMACRMTState != RM0_ISOLATED) { - RS_SET(smc,RS_NORINGOP) ; - rmt_indication(smc,0) ; - GO_STATE(RM0_ISOLATED) ; - return ; - } - - switch(smc->mib.m[MAC0].fddiMACRMTState) { - case ACTIONS(RM0_ISOLATED) : - stop_rmt_timer0(smc) ; - stop_rmt_timer1(smc) ; - stop_rmt_timer2(smc) ; - - /* - * Disable MAC. - */ - sm_ma_control(smc,MA_OFFLINE) ; - smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; - smc->r.loop_avail = FALSE ; - smc->r.sm_ma_avail = FALSE ; - smc->r.no_flag = TRUE ; - DB_RMTN(1,"RMT : ISOLATED\n",0,0) ; - ACTIONS_DONE() ; - break ; - case RM0_ISOLATED : - /*RM01*/ - if (smc->r.rm_join || smc->r.rm_loop) { - /* - * According to the standard the MAC must be reset - * here. The FORMAC will be initialized and Claim - * and Beacon Frames will be uploaded to the MAC. - * So any change of Treq will take effect NOW. - */ - sm_ma_control(smc,MA_RESET) ; - GO_STATE(RM1_NON_OP) ; - break ; - } - break ; - case ACTIONS(RM1_NON_OP) : - start_rmt_timer0(smc,smc->s.rmt_t_non_op,RM_TIMEOUT_NON_OP) ; - stop_rmt_timer1(smc) ; - stop_rmt_timer2(smc) ; - sm_ma_control(smc,MA_BEACON) ; - DB_RMTN(1,"RMT : RING DOWN\n",0,0) ; - RS_SET(smc,RS_NORINGOP) ; - smc->r.sm_ma_avail = FALSE ; - rmt_indication(smc,0) ; - ACTIONS_DONE() ; - break ; - case RM1_NON_OP : - /*RM12*/ - if (cmd == RM_RING_OP) { - RS_SET(smc,RS_RINGOPCHANGE) ; - GO_STATE(RM2_RING_OP) ; - break ; - } - /*RM13*/ - else if (cmd == RM_TIMEOUT_NON_OP) { - smc->r.bn_flag = FALSE ; - smc->r.no_flag = TRUE ; - GO_STATE(RM3_DETECT) ; - break ; - } - break ; - case ACTIONS(RM2_RING_OP) : - stop_rmt_timer0(smc) ; - stop_rmt_timer1(smc) ; - stop_rmt_timer2(smc) ; - smc->r.no_flag = FALSE ; - if (smc->r.rm_loop) - smc->r.loop_avail = TRUE ; - if (smc->r.rm_join) { - smc->r.sm_ma_avail = TRUE ; - if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable) - smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ; - else - smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; - } - DB_RMTN(1,"RMT : RING UP\n",0,0) ; - RS_CLEAR(smc,RS_NORINGOP) ; - RS_SET(smc,RS_RINGOPCHANGE) ; - rmt_indication(smc,1) ; - smt_stat_counter(smc,0) ; - ACTIONS_DONE() ; - break ; - case RM2_RING_OP : - /*RM21*/ - if (cmd == RM_RING_NON_OP) { - smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; - smc->r.loop_avail = FALSE ; - RS_SET(smc,RS_RINGOPCHANGE) ; - GO_STATE(RM1_NON_OP) ; - break ; - } - /*RM22a*/ - else if (cmd == RM_ENABLE_FLAG) { - if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable) - smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ; - else - smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; - } - /*RM25*/ - else if (smc->r.dup_addr_test == DA_FAILED) { - smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; - smc->r.loop_avail = FALSE ; - smc->r.da_flag = TRUE ; - GO_STATE(RM5_RING_OP_DUP) ; - break ; - } - break ; - case ACTIONS(RM3_DETECT) : - start_rmt_timer0(smc,smc->s.mac_d_max*2,RM_TIMEOUT_D_MAX) ; - start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ; - start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ; - sm_mac_check_beacon_claim(smc) ; - DB_RMTN(1,"RMT : RM3_DETECT\n",0,0) ; - ACTIONS_DONE() ; - break ; - case RM3_DETECT : - if (cmd == RM_TIMEOUT_POLL) { - start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL); - sm_mac_check_beacon_claim(smc) ; - break ; - } - if (cmd == RM_TIMEOUT_D_MAX) { - smc->r.timer0_exp = TRUE ; - } - /* - *jd(22-Feb-1999) - * We need a time ">= 2*mac_d_max" since we had finished - * Claim or Beacon state. So we will restart timer0 at - * every state change. - */ - if (cmd == RM_TX_STATE_CHANGE) { - start_rmt_timer0(smc, - smc->s.mac_d_max*2, - RM_TIMEOUT_D_MAX) ; - } - /*RM32*/ - if (cmd == RM_RING_OP) { - GO_STATE(RM2_RING_OP) ; - break ; - } - /*RM33a*/ - else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) - && smc->r.bn_flag) { - smc->r.bn_flag = FALSE ; - } - /*RM33b*/ - else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) { - int tx ; - /* - * set bn_flag only if in state T4 or T5: - * only if we're the beaconer should we start the - * trace ! - */ - if ((tx = sm_mac_get_tx_state(smc)) == 4 || tx == 5) { - DB_RMTN(2,"RMT : DETECT && TRT_EXPIRED && T4/T5\n",0,0); - smc->r.bn_flag = TRUE ; - /* - * If one of the upstream stations beaconed - * and the link to the upstream neighbor is - * lost we need to restart the stuck timer to - * check the "stuck beacon" condition. - */ - start_rmt_timer1(smc,smc->s.rmt_t_stuck, - RM_TIMEOUT_T_STUCK) ; - } - /* - * We do NOT need to clear smc->r.bn_flag in case of - * not being in state T4 or T5, because the flag - * must be cleared in order to get in this condition. - */ - - DB_RMTN(2, - "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n", - tx,smc->r.bn_flag) ; - } - /*RM34a*/ - else if (cmd == RM_MY_CLAIM && smc->r.timer0_exp) { - rmt_new_dup_actions(smc) ; - GO_STATE(RM4_NON_OP_DUP) ; - break ; - } - /*RM34b*/ - else if (cmd == RM_MY_BEACON && smc->r.timer0_exp) { - rmt_new_dup_actions(smc) ; - GO_STATE(RM4_NON_OP_DUP) ; - break ; - } - /*RM34c*/ - else if (cmd == RM_VALID_CLAIM) { - rmt_new_dup_actions(smc) ; - GO_STATE(RM4_NON_OP_DUP) ; - break ; - } - /*RM36*/ - else if (cmd == RM_TIMEOUT_T_STUCK && - smc->r.rm_join && smc->r.bn_flag) { - GO_STATE(RM6_DIRECTED) ; - break ; - } - break ; - case ACTIONS(RM4_NON_OP_DUP) : - start_rmt_timer0(smc,smc->s.rmt_t_announce,RM_TIMEOUT_ANNOUNCE); - start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ; - start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ; - sm_mac_check_beacon_claim(smc) ; - DB_RMTN(1,"RMT : RM4_NON_OP_DUP\n",0,0) ; - ACTIONS_DONE() ; - break ; - case RM4_NON_OP_DUP : - if (cmd == RM_TIMEOUT_POLL) { - start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL); - sm_mac_check_beacon_claim(smc) ; - break ; - } - /*RM41*/ - if (!smc->r.da_flag) { - GO_STATE(RM1_NON_OP) ; - break ; - } - /*RM44a*/ - else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) && - smc->r.bn_flag) { - smc->r.bn_flag = FALSE ; - } - /*RM44b*/ - else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) { - int tx ; - /* - * set bn_flag only if in state T4 or T5: - * only if we're the beaconer should we start the - * trace ! - */ - if ((tx = sm_mac_get_tx_state(smc)) == 4 || tx == 5) { - DB_RMTN(2,"RMT : NOPDUP && TRT_EXPIRED && T4/T5\n",0,0); - smc->r.bn_flag = TRUE ; - /* - * If one of the upstream stations beaconed - * and the link to the upstream neighbor is - * lost we need to restart the stuck timer to - * check the "stuck beacon" condition. - */ - start_rmt_timer1(smc,smc->s.rmt_t_stuck, - RM_TIMEOUT_T_STUCK) ; - } - /* - * We do NOT need to clear smc->r.bn_flag in case of - * not being in state T4 or T5, because the flag - * must be cleared in order to get in this condition. - */ - - DB_RMTN(2, - "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n", - tx,smc->r.bn_flag) ; - } - /*RM44c*/ - else if (cmd == RM_TIMEOUT_ANNOUNCE && !smc->r.bn_flag) { - rmt_dup_actions(smc) ; - } - /*RM45*/ - else if (cmd == RM_RING_OP) { - smc->r.no_flag = FALSE ; - GO_STATE(RM5_RING_OP_DUP) ; - break ; - } - /*RM46*/ - else if (cmd == RM_TIMEOUT_T_STUCK && - smc->r.rm_join && smc->r.bn_flag) { - GO_STATE(RM6_DIRECTED) ; - break ; - } - break ; - case ACTIONS(RM5_RING_OP_DUP) : - stop_rmt_timer0(smc) ; - stop_rmt_timer1(smc) ; - stop_rmt_timer2(smc) ; - DB_RMTN(1,"RMT : RM5_RING_OP_DUP\n",0,0) ; - ACTIONS_DONE() ; - break; - case RM5_RING_OP_DUP : - /*RM52*/ - if (smc->r.dup_addr_test == DA_PASSED) { - smc->r.da_flag = FALSE ; - GO_STATE(RM2_RING_OP) ; - break ; - } - /*RM54*/ - else if (cmd == RM_RING_NON_OP) { - smc->r.jm_flag = FALSE ; - smc->r.bn_flag = FALSE ; - GO_STATE(RM4_NON_OP_DUP) ; - break ; - } - break ; - case ACTIONS(RM6_DIRECTED) : - start_rmt_timer0(smc,smc->s.rmt_t_direct,RM_TIMEOUT_T_DIRECT) ; - stop_rmt_timer1(smc) ; - start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ; - sm_ma_control(smc,MA_DIRECTED) ; - RS_SET(smc,RS_BEACON) ; - DB_RMTN(1,"RMT : RM6_DIRECTED\n",0,0) ; - ACTIONS_DONE() ; - break ; - case RM6_DIRECTED : - /*RM63*/ - if (cmd == RM_TIMEOUT_POLL) { - start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL); - sm_mac_check_beacon_claim(smc) ; -#ifndef SUPERNET_3 - /* Because of problems with the Supernet II chip set - * sending of Directed Beacon will stop after 165ms - * therefore restart_trt_for_dbcn(smc) will be called - * to prevent this. - */ - restart_trt_for_dbcn(smc) ; -#endif /*SUPERNET_3*/ - break ; - } - if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) && - !smc->r.da_flag) { - smc->r.bn_flag = FALSE ; - GO_STATE(RM3_DETECT) ; - break ; - } - /*RM64*/ - else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) && - smc->r.da_flag) { - smc->r.bn_flag = FALSE ; - GO_STATE(RM4_NON_OP_DUP) ; - break ; - } - /*RM67*/ - else if (cmd == RM_TIMEOUT_T_DIRECT) { - GO_STATE(RM7_TRACE) ; - break ; - } - break ; - case ACTIONS(RM7_TRACE) : - stop_rmt_timer0(smc) ; - stop_rmt_timer1(smc) ; - stop_rmt_timer2(smc) ; - smc->e.trace_prop |= ENTITY_BIT(ENTITY_MAC) ; - queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ; - DB_RMTN(1,"RMT : RM7_TRACE\n",0,0) ; - ACTIONS_DONE() ; - break ; - case RM7_TRACE : - break ; - default: - SMT_PANIC(smc,SMT_E0122, SMT_E0122_MSG) ; - break; - } -} - -/* - * (jd) RMT duplicate address actions - * leave the ring or reinsert just as configured - */ -static void rmt_dup_actions(struct s_smc *smc) -{ - if (smc->r.jm_flag) { - } - else { - if (smc->s.rmt_dup_mac_behavior) { - SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ; - rmt_reinsert_actions(smc) ; - } - else { - SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ; - rmt_leave_actions(smc) ; - } - } -} - -/* - * Reconnect to the Ring - */ -static void rmt_reinsert_actions(struct s_smc *smc) -{ - queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; - queue_event(smc,EVENT_ECM,EC_CONNECT) ; -} - -/* - * duplicate address detected - */ -static void rmt_new_dup_actions(struct s_smc *smc) -{ - smc->r.da_flag = TRUE ; - smc->r.bn_flag = FALSE ; - smc->r.jm_flag = FALSE ; - /* - * we have three options : change address, jam or leave - * we leave the ring as default - * Optionally it's possible to reinsert after leaving the Ring - * but this will not conform with SMT Spec. - */ - if (smc->s.rmt_dup_mac_behavior) { - SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ; - rmt_reinsert_actions(smc) ; - } - else { - SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ; - rmt_leave_actions(smc) ; - } -} - - -/* - * leave the ring - */ -static void rmt_leave_actions(struct s_smc *smc) -{ - queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; - /* - * Note: Do NOT try again later. (with please reconnect) - * The station must be left from the ring! - */ -} - -/* - * SMT timer interface - * start RMT timer 0 - */ -static void start_rmt_timer0(struct s_smc *smc, u_long value, int event) -{ - smc->r.timer0_exp = FALSE ; /* clear timer event flag */ - smt_timer_start(smc,&smc->r.rmt_timer0,value,EV_TOKEN(EVENT_RMT,event)); -} - -/* - * SMT timer interface - * start RMT timer 1 - */ -static void start_rmt_timer1(struct s_smc *smc, u_long value, int event) -{ - smc->r.timer1_exp = FALSE ; /* clear timer event flag */ - smt_timer_start(smc,&smc->r.rmt_timer1,value,EV_TOKEN(EVENT_RMT,event)); -} - -/* - * SMT timer interface - * start RMT timer 2 - */ -static void start_rmt_timer2(struct s_smc *smc, u_long value, int event) -{ - smc->r.timer2_exp = FALSE ; /* clear timer event flag */ - smt_timer_start(smc,&smc->r.rmt_timer2,value,EV_TOKEN(EVENT_RMT,event)); -} - -/* - * SMT timer interface - * stop RMT timer 0 - */ -static void stop_rmt_timer0(struct s_smc *smc) -{ - if (smc->r.rmt_timer0.tm_active) - smt_timer_stop(smc,&smc->r.rmt_timer0) ; -} - -/* - * SMT timer interface - * stop RMT timer 1 - */ -static void stop_rmt_timer1(struct s_smc *smc) -{ - if (smc->r.rmt_timer1.tm_active) - smt_timer_stop(smc,&smc->r.rmt_timer1) ; -} - -/* - * SMT timer interface - * stop RMT timer 2 - */ -static void stop_rmt_timer2(struct s_smc *smc) -{ - if (smc->r.rmt_timer2.tm_active) - smt_timer_stop(smc,&smc->r.rmt_timer2) ; -} - diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c deleted file mode 100644 index 3d9a459..0000000 --- a/drivers/net/skfp/skfddi.c +++ /dev/null @@ -1,2260 +0,0 @@ -/* - * File Name: - * skfddi.c - * - * Copyright Information: - * Copyright SysKonnect 1998,1999. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - * Abstract: - * A Linux device driver supporting the SysKonnect FDDI PCI controller - * familie. - * - * Maintainers: - * CG Christoph Goos (cgoos@syskonnect.de) - * - * Contributors: - * DM David S. Miller - * - * Address all question to: - * linux@syskonnect.de - * - * The technical manual for the adapters is available from SysKonnect's - * web pages: www.syskonnect.com - * Goto "Support" and search Knowledge Base for "manual". - * - * Driver Architecture: - * The driver architecture is based on the DEC FDDI driver by - * Lawrence V. Stefani and several ethernet drivers. - * I also used an existing Windows NT miniport driver. - * All hardware dependent functions are handled by the SysKonnect - * Hardware Module. - * The only headerfiles that are directly related to this source - * are skfddi.c, h/types.h, h/osdef1st.h, h/targetos.h. - * The others belong to the SysKonnect FDDI Hardware Module and - * should better not be changed. - * - * Modification History: - * Date Name Description - * 02-Mar-98 CG Created. - * - * 10-Mar-99 CG Support for 2.2.x added. - * 25-Mar-99 CG Corrected IRQ routing for SMP (APIC) - * 26-Oct-99 CG Fixed compilation error on 2.2.13 - * 12-Nov-99 CG Source code release - * 22-Nov-99 CG Included in kernel source. - * 07-May-00 DM 64 bit fixes, new dma interface - * 31-Jul-03 DB Audit copy_*_user in skfp_ioctl - * Daniele Bellucci - * 03-Dec-03 SH Convert to PCI device model - * - * Compilation options (-Dxxx): - * DRIVERDEBUG print lots of messages to log file - * DUMPPACKETS print received/transmitted packets to logfile - * - * Tested cpu architectures: - * - i386 - * - sparc64 - */ - -/* Version information string - should be updated prior to */ -/* each new release!!! */ -#define VERSION "2.07" - -static const char * const boot_msg = - "SysKonnect FDDI PCI Adapter driver v" VERSION " for\n" - " SK-55xx/SK-58xx adapters (SK-NET FDDI-FP/UP/LP)"; - -/* Include files */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "h/types.h" -#undef ADDR // undo Linux definition -#include "h/skfbi.h" -#include "h/fddi.h" -#include "h/smc.h" -#include "h/smtstate.h" - - -// Define module-wide (static) routines -static int skfp_driver_init(struct net_device *dev); -static int skfp_open(struct net_device *dev); -static int skfp_close(struct net_device *dev); -static irqreturn_t skfp_interrupt(int irq, void *dev_id); -static struct net_device_stats *skfp_ctl_get_stats(struct net_device *dev); -static void skfp_ctl_set_multicast_list(struct net_device *dev); -static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev); -static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr); -static int skfp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static netdev_tx_t skfp_send_pkt(struct sk_buff *skb, - struct net_device *dev); -static void send_queued_packets(struct s_smc *smc); -static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr); -static void ResetAdapter(struct s_smc *smc); - - -// Functions needed by the hardware module -void *mac_drv_get_space(struct s_smc *smc, u_int size); -void *mac_drv_get_desc_mem(struct s_smc *smc, u_int size); -unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt); -unsigned long dma_master(struct s_smc *smc, void *virt, int len, int flag); -void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr, - int flag); -void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd); -void llc_restart_tx(struct s_smc *smc); -void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, - int frag_count, int len); -void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, - int frag_count); -void mac_drv_fill_rxd(struct s_smc *smc); -void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, - int frag_count); -int mac_drv_rx_init(struct s_smc *smc, int len, int fc, char *look_ahead, - int la_len); -void dump_data(unsigned char *Data, int length); - -// External functions from the hardware module -extern u_int mac_drv_check_space(void); -extern int mac_drv_init(struct s_smc *smc); -extern void hwm_tx_frag(struct s_smc *smc, char far * virt, u_long phys, - int len, int frame_status); -extern int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, - int frame_len, int frame_status); -extern void fddi_isr(struct s_smc *smc); -extern void hwm_rx_frag(struct s_smc *smc, char far * virt, u_long phys, - int len, int frame_status); -extern void mac_drv_rx_mode(struct s_smc *smc, int mode); -extern void mac_drv_clear_rx_queue(struct s_smc *smc); -extern void enable_tx_irq(struct s_smc *smc, u_short queue); - -static DEFINE_PCI_DEVICE_TABLE(skfddi_pci_tbl) = { - { PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, PCI_ANY_ID, PCI_ANY_ID, }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, skfddi_pci_tbl); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mirko Lindner "); - -// Define module-wide (static) variables - -static int num_boards; /* total number of adapters configured */ - -static const struct net_device_ops skfp_netdev_ops = { - .ndo_open = skfp_open, - .ndo_stop = skfp_close, - .ndo_start_xmit = skfp_send_pkt, - .ndo_get_stats = skfp_ctl_get_stats, - .ndo_change_mtu = fddi_change_mtu, - .ndo_set_rx_mode = skfp_ctl_set_multicast_list, - .ndo_set_mac_address = skfp_ctl_set_mac_address, - .ndo_do_ioctl = skfp_ioctl, -}; - -/* - * ================= - * = skfp_init_one = - * ================= - * - * Overview: - * Probes for supported FDDI PCI controllers - * - * Returns: - * Condition code - * - * Arguments: - * pdev - pointer to PCI device information - * - * Functional Description: - * This is now called by PCI driver registration process - * for each board found. - * - * Return Codes: - * 0 - This device (fddi0, fddi1, etc) configured successfully - * -ENODEV - No devices present, or no SysKonnect FDDI PCI device - * present for this device name - * - * - * Side Effects: - * Device structures for FDDI adapters (fddi0, fddi1, etc) are - * initialized and the board resources are read and stored in - * the device structure. - */ -static int skfp_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct net_device *dev; - struct s_smc *smc; /* board pointer */ - void __iomem *mem; - int err; - - pr_debug("entering skfp_init_one\n"); - - if (num_boards == 0) - printk("%s\n", boot_msg); - - err = pci_enable_device(pdev); - if (err) - return err; - - err = pci_request_regions(pdev, "skfddi"); - if (err) - goto err_out1; - - pci_set_master(pdev); - -#ifdef MEM_MAPPED_IO - if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { - printk(KERN_ERR "skfp: region is not an MMIO resource\n"); - err = -EIO; - goto err_out2; - } - - mem = ioremap(pci_resource_start(pdev, 0), 0x4000); -#else - if (!(pci_resource_flags(pdev, 1) & IO_RESOURCE_IO)) { - printk(KERN_ERR "skfp: region is not PIO resource\n"); - err = -EIO; - goto err_out2; - } - - mem = ioport_map(pci_resource_start(pdev, 1), FP_IO_LEN); -#endif - if (!mem) { - printk(KERN_ERR "skfp: Unable to map register, " - "FDDI adapter will be disabled.\n"); - err = -EIO; - goto err_out2; - } - - dev = alloc_fddidev(sizeof(struct s_smc)); - if (!dev) { - printk(KERN_ERR "skfp: Unable to allocate fddi device, " - "FDDI adapter will be disabled.\n"); - err = -ENOMEM; - goto err_out3; - } - - dev->irq = pdev->irq; - dev->netdev_ops = &skfp_netdev_ops; - - SET_NETDEV_DEV(dev, &pdev->dev); - - /* Initialize board structure with bus-specific info */ - smc = netdev_priv(dev); - smc->os.dev = dev; - smc->os.bus_type = SK_BUS_TYPE_PCI; - smc->os.pdev = *pdev; - smc->os.QueueSkb = MAX_TX_QUEUE_LEN; - smc->os.MaxFrameSize = MAX_FRAME_SIZE; - smc->os.dev = dev; - smc->hw.slot = -1; - smc->hw.iop = mem; - smc->os.ResetRequested = FALSE; - skb_queue_head_init(&smc->os.SendSkbQueue); - - dev->base_addr = (unsigned long)mem; - - err = skfp_driver_init(dev); - if (err) - goto err_out4; - - err = register_netdev(dev); - if (err) - goto err_out5; - - ++num_boards; - pci_set_drvdata(pdev, dev); - - if ((pdev->subsystem_device & 0xff00) == 0x5500 || - (pdev->subsystem_device & 0xff00) == 0x5800) - printk("%s: SysKonnect FDDI PCI adapter" - " found (SK-%04X)\n", dev->name, - pdev->subsystem_device); - else - printk("%s: FDDI PCI adapter found\n", dev->name); - - return 0; -err_out5: - if (smc->os.SharedMemAddr) - pci_free_consistent(pdev, smc->os.SharedMemSize, - smc->os.SharedMemAddr, - smc->os.SharedMemDMA); - pci_free_consistent(pdev, MAX_FRAME_SIZE, - smc->os.LocalRxBuffer, smc->os.LocalRxBufferDMA); -err_out4: - free_netdev(dev); -err_out3: -#ifdef MEM_MAPPED_IO - iounmap(mem); -#else - ioport_unmap(mem); -#endif -err_out2: - pci_release_regions(pdev); -err_out1: - pci_disable_device(pdev); - return err; -} - -/* - * Called for each adapter board from pci_unregister_driver - */ -static void __devexit skfp_remove_one(struct pci_dev *pdev) -{ - struct net_device *p = pci_get_drvdata(pdev); - struct s_smc *lp = netdev_priv(p); - - unregister_netdev(p); - - if (lp->os.SharedMemAddr) { - pci_free_consistent(&lp->os.pdev, - lp->os.SharedMemSize, - lp->os.SharedMemAddr, - lp->os.SharedMemDMA); - lp->os.SharedMemAddr = NULL; - } - if (lp->os.LocalRxBuffer) { - pci_free_consistent(&lp->os.pdev, - MAX_FRAME_SIZE, - lp->os.LocalRxBuffer, - lp->os.LocalRxBufferDMA); - lp->os.LocalRxBuffer = NULL; - } -#ifdef MEM_MAPPED_IO - iounmap(lp->hw.iop); -#else - ioport_unmap(lp->hw.iop); -#endif - pci_release_regions(pdev); - free_netdev(p); - - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); -} - -/* - * ==================== - * = skfp_driver_init = - * ==================== - * - * Overview: - * Initializes remaining adapter board structure information - * and makes sure adapter is in a safe state prior to skfp_open(). - * - * Returns: - * Condition code - * - * Arguments: - * dev - pointer to device information - * - * Functional Description: - * This function allocates additional resources such as the host memory - * blocks needed by the adapter. - * The adapter is also reset. The OS must call skfp_open() to open - * the adapter and bring it on-line. - * - * Return Codes: - * 0 - initialization succeeded - * -1 - initialization failed - */ -static int skfp_driver_init(struct net_device *dev) -{ - struct s_smc *smc = netdev_priv(dev); - skfddi_priv *bp = &smc->os; - int err = -EIO; - - pr_debug("entering skfp_driver_init\n"); - - // set the io address in private structures - bp->base_addr = dev->base_addr; - - // Get the interrupt level from the PCI Configuration Table - smc->hw.irq = dev->irq; - - spin_lock_init(&bp->DriverLock); - - // Allocate invalid frame - bp->LocalRxBuffer = pci_alloc_consistent(&bp->pdev, MAX_FRAME_SIZE, &bp->LocalRxBufferDMA); - if (!bp->LocalRxBuffer) { - printk("could not allocate mem for "); - printk("LocalRxBuffer: %d byte\n", MAX_FRAME_SIZE); - goto fail; - } - - // Determine the required size of the 'shared' memory area. - bp->SharedMemSize = mac_drv_check_space(); - pr_debug("Memory for HWM: %ld\n", bp->SharedMemSize); - if (bp->SharedMemSize > 0) { - bp->SharedMemSize += 16; // for descriptor alignment - - bp->SharedMemAddr = pci_alloc_consistent(&bp->pdev, - bp->SharedMemSize, - &bp->SharedMemDMA); - if (!bp->SharedMemAddr) { - printk("could not allocate mem for "); - printk("hardware module: %ld byte\n", - bp->SharedMemSize); - goto fail; - } - bp->SharedMemHeap = 0; // Nothing used yet. - - } else { - bp->SharedMemAddr = NULL; - bp->SharedMemHeap = 0; - } // SharedMemSize > 0 - - memset(bp->SharedMemAddr, 0, bp->SharedMemSize); - - card_stop(smc); // Reset adapter. - - pr_debug("mac_drv_init()..\n"); - if (mac_drv_init(smc) != 0) { - pr_debug("mac_drv_init() failed\n"); - goto fail; - } - read_address(smc, NULL); - pr_debug("HW-Addr: %pMF\n", smc->hw.fddi_canon_addr.a); - memcpy(dev->dev_addr, smc->hw.fddi_canon_addr.a, 6); - - smt_reset_defaults(smc, 0); - - return 0; - -fail: - if (bp->SharedMemAddr) { - pci_free_consistent(&bp->pdev, - bp->SharedMemSize, - bp->SharedMemAddr, - bp->SharedMemDMA); - bp->SharedMemAddr = NULL; - } - if (bp->LocalRxBuffer) { - pci_free_consistent(&bp->pdev, MAX_FRAME_SIZE, - bp->LocalRxBuffer, bp->LocalRxBufferDMA); - bp->LocalRxBuffer = NULL; - } - return err; -} // skfp_driver_init - - -/* - * ============= - * = skfp_open = - * ============= - * - * Overview: - * Opens the adapter - * - * Returns: - * Condition code - * - * Arguments: - * dev - pointer to device information - * - * Functional Description: - * This function brings the adapter to an operational state. - * - * Return Codes: - * 0 - Adapter was successfully opened - * -EAGAIN - Could not register IRQ - */ -static int skfp_open(struct net_device *dev) -{ - struct s_smc *smc = netdev_priv(dev); - int err; - - pr_debug("entering skfp_open\n"); - /* Register IRQ - support shared interrupts by passing device ptr */ - err = request_irq(dev->irq, skfp_interrupt, IRQF_SHARED, - dev->name, dev); - if (err) - return err; - - /* - * Set current address to factory MAC address - * - * Note: We've already done this step in skfp_driver_init. - * However, it's possible that a user has set a node - * address override, then closed and reopened the - * adapter. Unless we reset the device address field - * now, we'll continue to use the existing modified - * address. - */ - read_address(smc, NULL); - memcpy(dev->dev_addr, smc->hw.fddi_canon_addr.a, 6); - - init_smt(smc, NULL); - smt_online(smc, 1); - STI_FBI(); - - /* Clear local multicast address tables */ - mac_clear_multicast(smc); - - /* Disable promiscuous filter settings */ - mac_drv_rx_mode(smc, RX_DISABLE_PROMISC); - - netif_start_queue(dev); - return 0; -} // skfp_open - - -/* - * ============== - * = skfp_close = - * ============== - * - * Overview: - * Closes the device/module. - * - * Returns: - * Condition code - * - * Arguments: - * dev - pointer to device information - * - * Functional Description: - * This routine closes the adapter and brings it to a safe state. - * The interrupt service routine is deregistered with the OS. - * The adapter can be opened again with another call to skfp_open(). - * - * Return Codes: - * Always return 0. - * - * Assumptions: - * No further requests for this adapter are made after this routine is - * called. skfp_open() can be called to reset and reinitialize the - * adapter. - */ -static int skfp_close(struct net_device *dev) -{ - struct s_smc *smc = netdev_priv(dev); - skfddi_priv *bp = &smc->os; - - CLI_FBI(); - smt_reset_defaults(smc, 1); - card_stop(smc); - mac_drv_clear_tx_queue(smc); - mac_drv_clear_rx_queue(smc); - - netif_stop_queue(dev); - /* Deregister (free) IRQ */ - free_irq(dev->irq, dev); - - skb_queue_purge(&bp->SendSkbQueue); - bp->QueueSkb = MAX_TX_QUEUE_LEN; - - return 0; -} // skfp_close - - -/* - * ================== - * = skfp_interrupt = - * ================== - * - * Overview: - * Interrupt processing routine - * - * Returns: - * None - * - * Arguments: - * irq - interrupt vector - * dev_id - pointer to device information - * - * Functional Description: - * This routine calls the interrupt processing routine for this adapter. It - * disables and reenables adapter interrupts, as appropriate. We can support - * shared interrupts since the incoming dev_id pointer provides our device - * structure context. All the real work is done in the hardware module. - * - * Return Codes: - * None - * - * Assumptions: - * The interrupt acknowledgement at the hardware level (eg. ACKing the PIC - * on Intel-based systems) is done by the operating system outside this - * routine. - * - * System interrupts are enabled through this call. - * - * Side Effects: - * Interrupts are disabled, then reenabled at the adapter. - */ - -static irqreturn_t skfp_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct s_smc *smc; /* private board structure pointer */ - skfddi_priv *bp; - - smc = netdev_priv(dev); - bp = &smc->os; - - // IRQs enabled or disabled ? - if (inpd(ADDR(B0_IMSK)) == 0) { - // IRQs are disabled: must be shared interrupt - return IRQ_NONE; - } - // Note: At this point, IRQs are enabled. - if ((inpd(ISR_A) & smc->hw.is_imask) == 0) { // IRQ? - // Adapter did not issue an IRQ: must be shared interrupt - return IRQ_NONE; - } - CLI_FBI(); // Disable IRQs from our adapter. - spin_lock(&bp->DriverLock); - - // Call interrupt handler in hardware module (HWM). - fddi_isr(smc); - - if (smc->os.ResetRequested) { - ResetAdapter(smc); - smc->os.ResetRequested = FALSE; - } - spin_unlock(&bp->DriverLock); - STI_FBI(); // Enable IRQs from our adapter. - - return IRQ_HANDLED; -} // skfp_interrupt - - -/* - * ====================== - * = skfp_ctl_get_stats = - * ====================== - * - * Overview: - * Get statistics for FDDI adapter - * - * Returns: - * Pointer to FDDI statistics structure - * - * Arguments: - * dev - pointer to device information - * - * Functional Description: - * Gets current MIB objects from adapter, then - * returns FDDI statistics structure as defined - * in if_fddi.h. - * - * Note: Since the FDDI statistics structure is - * still new and the device structure doesn't - * have an FDDI-specific get statistics handler, - * we'll return the FDDI statistics structure as - * a pointer to an Ethernet statistics structure. - * That way, at least the first part of the statistics - * structure can be decoded properly. - * We'll have to pay attention to this routine as the - * device structure becomes more mature and LAN media - * independent. - * - */ -static struct net_device_stats *skfp_ctl_get_stats(struct net_device *dev) -{ - struct s_smc *bp = netdev_priv(dev); - - /* Fill the bp->stats structure with driver-maintained counters */ - - bp->os.MacStat.port_bs_flag[0] = 0x1234; - bp->os.MacStat.port_bs_flag[1] = 0x5678; -// goos: need to fill out fddi statistic -#if 0 - /* Get FDDI SMT MIB objects */ - -/* Fill the bp->stats structure with the SMT MIB object values */ - - memcpy(bp->stats.smt_station_id, &bp->cmd_rsp_virt->smt_mib_get.smt_station_id, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_station_id)); - bp->stats.smt_op_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_op_version_id; - bp->stats.smt_hi_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_hi_version_id; - bp->stats.smt_lo_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_lo_version_id; - memcpy(bp->stats.smt_user_data, &bp->cmd_rsp_virt->smt_mib_get.smt_user_data, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_user_data)); - bp->stats.smt_mib_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_mib_version_id; - bp->stats.smt_mac_cts = bp->cmd_rsp_virt->smt_mib_get.smt_mac_ct; - bp->stats.smt_non_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_non_master_ct; - bp->stats.smt_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_master_ct; - bp->stats.smt_available_paths = bp->cmd_rsp_virt->smt_mib_get.smt_available_paths; - bp->stats.smt_config_capabilities = bp->cmd_rsp_virt->smt_mib_get.smt_config_capabilities; - bp->stats.smt_config_policy = bp->cmd_rsp_virt->smt_mib_get.smt_config_policy; - bp->stats.smt_connection_policy = bp->cmd_rsp_virt->smt_mib_get.smt_connection_policy; - bp->stats.smt_t_notify = bp->cmd_rsp_virt->smt_mib_get.smt_t_notify; - bp->stats.smt_stat_rpt_policy = bp->cmd_rsp_virt->smt_mib_get.smt_stat_rpt_policy; - bp->stats.smt_trace_max_expiration = bp->cmd_rsp_virt->smt_mib_get.smt_trace_max_expiration; - bp->stats.smt_bypass_present = bp->cmd_rsp_virt->smt_mib_get.smt_bypass_present; - bp->stats.smt_ecm_state = bp->cmd_rsp_virt->smt_mib_get.smt_ecm_state; - bp->stats.smt_cf_state = bp->cmd_rsp_virt->smt_mib_get.smt_cf_state; - bp->stats.smt_remote_disconnect_flag = bp->cmd_rsp_virt->smt_mib_get.smt_remote_disconnect_flag; - bp->stats.smt_station_status = bp->cmd_rsp_virt->smt_mib_get.smt_station_status; - bp->stats.smt_peer_wrap_flag = bp->cmd_rsp_virt->smt_mib_get.smt_peer_wrap_flag; - bp->stats.smt_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_msg_time_stamp.ls; - bp->stats.smt_transition_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_transition_time_stamp.ls; - bp->stats.mac_frame_status_functions = bp->cmd_rsp_virt->smt_mib_get.mac_frame_status_functions; - bp->stats.mac_t_max_capability = bp->cmd_rsp_virt->smt_mib_get.mac_t_max_capability; - bp->stats.mac_tvx_capability = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_capability; - bp->stats.mac_available_paths = bp->cmd_rsp_virt->smt_mib_get.mac_available_paths; - bp->stats.mac_current_path = bp->cmd_rsp_virt->smt_mib_get.mac_current_path; - memcpy(bp->stats.mac_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_upstream_nbr, FDDI_K_ALEN); - memcpy(bp->stats.mac_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_downstream_nbr, FDDI_K_ALEN); - memcpy(bp->stats.mac_old_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_upstream_nbr, FDDI_K_ALEN); - memcpy(bp->stats.mac_old_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_downstream_nbr, FDDI_K_ALEN); - bp->stats.mac_dup_address_test = bp->cmd_rsp_virt->smt_mib_get.mac_dup_address_test; - bp->stats.mac_requested_paths = bp->cmd_rsp_virt->smt_mib_get.mac_requested_paths; - bp->stats.mac_downstream_port_type = bp->cmd_rsp_virt->smt_mib_get.mac_downstream_port_type; - memcpy(bp->stats.mac_smt_address, &bp->cmd_rsp_virt->smt_mib_get.mac_smt_address, FDDI_K_ALEN); - bp->stats.mac_t_req = bp->cmd_rsp_virt->smt_mib_get.mac_t_req; - bp->stats.mac_t_neg = bp->cmd_rsp_virt->smt_mib_get.mac_t_neg; - bp->stats.mac_t_max = bp->cmd_rsp_virt->smt_mib_get.mac_t_max; - bp->stats.mac_tvx_value = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_value; - bp->stats.mac_frame_error_threshold = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_threshold; - bp->stats.mac_frame_error_ratio = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_ratio; - bp->stats.mac_rmt_state = bp->cmd_rsp_virt->smt_mib_get.mac_rmt_state; - bp->stats.mac_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_da_flag; - bp->stats.mac_una_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_unda_flag; - bp->stats.mac_frame_error_flag = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_flag; - bp->stats.mac_ma_unitdata_available = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_available; - bp->stats.mac_hardware_present = bp->cmd_rsp_virt->smt_mib_get.mac_hardware_present; - bp->stats.mac_ma_unitdata_enable = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_enable; - bp->stats.path_tvx_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_tvx_lower_bound; - bp->stats.path_t_max_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_t_max_lower_bound; - bp->stats.path_max_t_req = bp->cmd_rsp_virt->smt_mib_get.path_max_t_req; - memcpy(bp->stats.path_configuration, &bp->cmd_rsp_virt->smt_mib_get.path_configuration, sizeof(bp->cmd_rsp_virt->smt_mib_get.path_configuration)); - bp->stats.port_my_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[0]; - bp->stats.port_my_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[1]; - bp->stats.port_neighbor_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[0]; - bp->stats.port_neighbor_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[1]; - bp->stats.port_connection_policies[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[0]; - bp->stats.port_connection_policies[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[1]; - bp->stats.port_mac_indicated[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[0]; - bp->stats.port_mac_indicated[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[1]; - bp->stats.port_current_path[0] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[0]; - bp->stats.port_current_path[1] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[1]; - memcpy(&bp->stats.port_requested_paths[0 * 3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[0], 3); - memcpy(&bp->stats.port_requested_paths[1 * 3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[1], 3); - bp->stats.port_mac_placement[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[0]; - bp->stats.port_mac_placement[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[1]; - bp->stats.port_available_paths[0] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[0]; - bp->stats.port_available_paths[1] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[1]; - bp->stats.port_pmd_class[0] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[0]; - bp->stats.port_pmd_class[1] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[1]; - bp->stats.port_connection_capabilities[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[0]; - bp->stats.port_connection_capabilities[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[1]; - bp->stats.port_bs_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[0]; - bp->stats.port_bs_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[1]; - bp->stats.port_ler_estimate[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[0]; - bp->stats.port_ler_estimate[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[1]; - bp->stats.port_ler_cutoff[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[0]; - bp->stats.port_ler_cutoff[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[1]; - bp->stats.port_ler_alarm[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[0]; - bp->stats.port_ler_alarm[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[1]; - bp->stats.port_connect_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[0]; - bp->stats.port_connect_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[1]; - bp->stats.port_pcm_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[0]; - bp->stats.port_pcm_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[1]; - bp->stats.port_pc_withhold[0] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[0]; - bp->stats.port_pc_withhold[1] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[1]; - bp->stats.port_ler_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[0]; - bp->stats.port_ler_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[1]; - bp->stats.port_hardware_present[0] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[0]; - bp->stats.port_hardware_present[1] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[1]; - - - /* Fill the bp->stats structure with the FDDI counter values */ - - bp->stats.mac_frame_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.frame_cnt.ls; - bp->stats.mac_copied_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.copied_cnt.ls; - bp->stats.mac_transmit_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.transmit_cnt.ls; - bp->stats.mac_error_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.error_cnt.ls; - bp->stats.mac_lost_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.lost_cnt.ls; - bp->stats.port_lct_fail_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[0].ls; - bp->stats.port_lct_fail_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[1].ls; - bp->stats.port_lem_reject_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[0].ls; - bp->stats.port_lem_reject_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[1].ls; - bp->stats.port_lem_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[0].ls; - bp->stats.port_lem_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[1].ls; - -#endif - return (struct net_device_stats *)&bp->os.MacStat; -} // ctl_get_stat - - -/* - * ============================== - * = skfp_ctl_set_multicast_list = - * ============================== - * - * Overview: - * Enable/Disable LLC frame promiscuous mode reception - * on the adapter and/or update multicast address table. - * - * Returns: - * None - * - * Arguments: - * dev - pointer to device information - * - * Functional Description: - * This function acquires the driver lock and only calls - * skfp_ctl_set_multicast_list_wo_lock then. - * This routine follows a fairly simple algorithm for setting the - * adapter filters and CAM: - * - * if IFF_PROMISC flag is set - * enable promiscuous mode - * else - * disable promiscuous mode - * if number of multicast addresses <= max. multicast number - * add mc addresses to adapter table - * else - * enable promiscuous mode - * update adapter filters - * - * Assumptions: - * Multicast addresses are presented in canonical (LSB) format. - * - * Side Effects: - * On-board adapter filters are updated. - */ -static void skfp_ctl_set_multicast_list(struct net_device *dev) -{ - struct s_smc *smc = netdev_priv(dev); - skfddi_priv *bp = &smc->os; - unsigned long Flags; - - spin_lock_irqsave(&bp->DriverLock, Flags); - skfp_ctl_set_multicast_list_wo_lock(dev); - spin_unlock_irqrestore(&bp->DriverLock, Flags); -} // skfp_ctl_set_multicast_list - - - -static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev) -{ - struct s_smc *smc = netdev_priv(dev); - struct netdev_hw_addr *ha; - - /* Enable promiscuous mode, if necessary */ - if (dev->flags & IFF_PROMISC) { - mac_drv_rx_mode(smc, RX_ENABLE_PROMISC); - pr_debug("PROMISCUOUS MODE ENABLED\n"); - } - /* Else, update multicast address table */ - else { - mac_drv_rx_mode(smc, RX_DISABLE_PROMISC); - pr_debug("PROMISCUOUS MODE DISABLED\n"); - - // Reset all MC addresses - mac_clear_multicast(smc); - mac_drv_rx_mode(smc, RX_DISABLE_ALLMULTI); - - if (dev->flags & IFF_ALLMULTI) { - mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI); - pr_debug("ENABLE ALL MC ADDRESSES\n"); - } else if (!netdev_mc_empty(dev)) { - if (netdev_mc_count(dev) <= FPMAX_MULTICAST) { - /* use exact filtering */ - - // point to first multicast addr - netdev_for_each_mc_addr(ha, dev) { - mac_add_multicast(smc, - (struct fddi_addr *)ha->addr, - 1); - - pr_debug("ENABLE MC ADDRESS: %pMF\n", - ha->addr); - } - - } else { // more MC addresses than HW supports - - mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI); - pr_debug("ENABLE ALL MC ADDRESSES\n"); - } - } else { // no MC addresses - - pr_debug("DISABLE ALL MC ADDRESSES\n"); - } - - /* Update adapter filters */ - mac_update_multicast(smc); - } -} // skfp_ctl_set_multicast_list_wo_lock - - -/* - * =========================== - * = skfp_ctl_set_mac_address = - * =========================== - * - * Overview: - * set new mac address on adapter and update dev_addr field in device table. - * - * Returns: - * None - * - * Arguments: - * dev - pointer to device information - * addr - pointer to sockaddr structure containing unicast address to set - * - * Assumptions: - * The address pointed to by addr->sa_data is a valid unicast - * address and is presented in canonical (LSB) format. - */ -static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr) -{ - struct s_smc *smc = netdev_priv(dev); - struct sockaddr *p_sockaddr = (struct sockaddr *) addr; - skfddi_priv *bp = &smc->os; - unsigned long Flags; - - - memcpy(dev->dev_addr, p_sockaddr->sa_data, FDDI_K_ALEN); - spin_lock_irqsave(&bp->DriverLock, Flags); - ResetAdapter(smc); - spin_unlock_irqrestore(&bp->DriverLock, Flags); - - return 0; /* always return zero */ -} // skfp_ctl_set_mac_address - - -/* - * ============== - * = skfp_ioctl = - * ============== - * - * Overview: - * - * Perform IOCTL call functions here. Some are privileged operations and the - * effective uid is checked in those cases. - * - * Returns: - * status value - * 0 - success - * other - failure - * - * Arguments: - * dev - pointer to device information - * rq - pointer to ioctl request structure - * cmd - ? - * - */ - - -static int skfp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct s_smc *smc = netdev_priv(dev); - skfddi_priv *lp = &smc->os; - struct s_skfp_ioctl ioc; - int status = 0; - - if (copy_from_user(&ioc, rq->ifr_data, sizeof(struct s_skfp_ioctl))) - return -EFAULT; - - switch (ioc.cmd) { - case SKFP_GET_STATS: /* Get the driver statistics */ - ioc.len = sizeof(lp->MacStat); - status = copy_to_user(ioc.data, skfp_ctl_get_stats(dev), ioc.len) - ? -EFAULT : 0; - break; - case SKFP_CLR_STATS: /* Zero out the driver statistics */ - if (!capable(CAP_NET_ADMIN)) { - status = -EPERM; - } else { - memset(&lp->MacStat, 0, sizeof(lp->MacStat)); - } - break; - default: - printk("ioctl for %s: unknown cmd: %04x\n", dev->name, ioc.cmd); - status = -EOPNOTSUPP; - - } // switch - - return status; -} // skfp_ioctl - - -/* - * ===================== - * = skfp_send_pkt = - * ===================== - * - * Overview: - * Queues a packet for transmission and try to transmit it. - * - * Returns: - * Condition code - * - * Arguments: - * skb - pointer to sk_buff to queue for transmission - * dev - pointer to device information - * - * Functional Description: - * Here we assume that an incoming skb transmit request - * is contained in a single physically contiguous buffer - * in which the virtual address of the start of packet - * (skb->data) can be converted to a physical address - * by using pci_map_single(). - * - * We have an internal queue for packets we can not send - * immediately. Packets in this queue can be given to the - * adapter if transmit buffers are freed. - * - * We can't free the skb until after it's been DMA'd - * out by the adapter, so we'll keep it in the driver and - * return it in mac_drv_tx_complete. - * - * Return Codes: - * 0 - driver has queued and/or sent packet - * 1 - caller should requeue the sk_buff for later transmission - * - * Assumptions: - * The entire packet is stored in one physically - * contiguous buffer which is not cached and whose - * 32-bit physical address can be determined. - * - * It's vital that this routine is NOT reentered for the - * same board and that the OS is not in another section of - * code (eg. skfp_interrupt) for the same board on a - * different thread. - * - * Side Effects: - * None - */ -static netdev_tx_t skfp_send_pkt(struct sk_buff *skb, - struct net_device *dev) -{ - struct s_smc *smc = netdev_priv(dev); - skfddi_priv *bp = &smc->os; - - pr_debug("skfp_send_pkt\n"); - - /* - * Verify that incoming transmit request is OK - * - * Note: The packet size check is consistent with other - * Linux device drivers, although the correct packet - * size should be verified before calling the - * transmit routine. - */ - - if (!(skb->len >= FDDI_K_LLC_ZLEN && skb->len <= FDDI_K_LLC_LEN)) { - bp->MacStat.gen.tx_errors++; /* bump error counter */ - // dequeue packets from xmt queue and send them - netif_start_queue(dev); - dev_kfree_skb(skb); - return NETDEV_TX_OK; /* return "success" */ - } - if (bp->QueueSkb == 0) { // return with tbusy set: queue full - - netif_stop_queue(dev); - return NETDEV_TX_BUSY; - } - bp->QueueSkb--; - skb_queue_tail(&bp->SendSkbQueue, skb); - send_queued_packets(netdev_priv(dev)); - if (bp->QueueSkb == 0) { - netif_stop_queue(dev); - } - return NETDEV_TX_OK; - -} // skfp_send_pkt - - -/* - * ======================= - * = send_queued_packets = - * ======================= - * - * Overview: - * Send packets from the driver queue as long as there are some and - * transmit resources are available. - * - * Returns: - * None - * - * Arguments: - * smc - pointer to smc (adapter) structure - * - * Functional Description: - * Take a packet from queue if there is any. If not, then we are done. - * Check if there are resources to send the packet. If not, requeue it - * and exit. - * Set packet descriptor flags and give packet to adapter. - * Check if any send resources can be freed (we do not use the - * transmit complete interrupt). - */ -static void send_queued_packets(struct s_smc *smc) -{ - skfddi_priv *bp = &smc->os; - struct sk_buff *skb; - unsigned char fc; - int queue; - struct s_smt_fp_txd *txd; // Current TxD. - dma_addr_t dma_address; - unsigned long Flags; - - int frame_status; // HWM tx frame status. - - pr_debug("send queued packets\n"); - for (;;) { - // send first buffer from queue - skb = skb_dequeue(&bp->SendSkbQueue); - - if (!skb) { - pr_debug("queue empty\n"); - return; - } // queue empty ! - - spin_lock_irqsave(&bp->DriverLock, Flags); - fc = skb->data[0]; - queue = (fc & FC_SYNC_BIT) ? QUEUE_S : QUEUE_A0; -#ifdef ESS - // Check if the frame may/must be sent as a synchronous frame. - - if ((fc & ~(FC_SYNC_BIT | FC_LLC_PRIOR)) == FC_ASYNC_LLC) { - // It's an LLC frame. - if (!smc->ess.sync_bw_available) - fc &= ~FC_SYNC_BIT; // No bandwidth available. - - else { // Bandwidth is available. - - if (smc->mib.fddiESSSynchTxMode) { - // Send as sync. frame. - fc |= FC_SYNC_BIT; - } - } - } -#endif // ESS - frame_status = hwm_tx_init(smc, fc, 1, skb->len, queue); - - if ((frame_status & (LOC_TX | LAN_TX)) == 0) { - // Unable to send the frame. - - if ((frame_status & RING_DOWN) != 0) { - // Ring is down. - pr_debug("Tx attempt while ring down.\n"); - } else if ((frame_status & OUT_OF_TXD) != 0) { - pr_debug("%s: out of TXDs.\n", bp->dev->name); - } else { - pr_debug("%s: out of transmit resources", - bp->dev->name); - } - - // Note: We will retry the operation as soon as - // transmit resources become available. - skb_queue_head(&bp->SendSkbQueue, skb); - spin_unlock_irqrestore(&bp->DriverLock, Flags); - return; // Packet has been queued. - - } // if (unable to send frame) - - bp->QueueSkb++; // one packet less in local queue - - // source address in packet ? - CheckSourceAddress(skb->data, smc->hw.fddi_canon_addr.a); - - txd = (struct s_smt_fp_txd *) HWM_GET_CURR_TXD(smc, queue); - - dma_address = pci_map_single(&bp->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE); - if (frame_status & LAN_TX) { - txd->txd_os.skb = skb; // save skb - txd->txd_os.dma_addr = dma_address; // save dma mapping - } - hwm_tx_frag(smc, skb->data, dma_address, skb->len, - frame_status | FIRST_FRAG | LAST_FRAG | EN_IRQ_EOF); - - if (!(frame_status & LAN_TX)) { // local only frame - pci_unmap_single(&bp->pdev, dma_address, - skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skb); - } - spin_unlock_irqrestore(&bp->DriverLock, Flags); - } // for - - return; // never reached - -} // send_queued_packets - - -/************************ - * - * CheckSourceAddress - * - * Verify if the source address is set. Insert it if necessary. - * - ************************/ -static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr) -{ - unsigned char SRBit; - - if ((((unsigned long) frame[1 + 6]) & ~0x01) != 0) // source routing bit - - return; - if ((unsigned short) frame[1 + 10] != 0) - return; - SRBit = frame[1 + 6] & 0x01; - memcpy(&frame[1 + 6], hw_addr, 6); - frame[8] |= SRBit; -} // CheckSourceAddress - - -/************************ - * - * ResetAdapter - * - * Reset the adapter and bring it back to operational mode. - * Args - * smc - A pointer to the SMT context struct. - * Out - * Nothing. - * - ************************/ -static void ResetAdapter(struct s_smc *smc) -{ - - pr_debug("[fddi: ResetAdapter]\n"); - - // Stop the adapter. - - card_stop(smc); // Stop all activity. - - // Clear the transmit and receive descriptor queues. - mac_drv_clear_tx_queue(smc); - mac_drv_clear_rx_queue(smc); - - // Restart the adapter. - - smt_reset_defaults(smc, 1); // Initialize the SMT module. - - init_smt(smc, (smc->os.dev)->dev_addr); // Initialize the hardware. - - smt_online(smc, 1); // Insert into the ring again. - STI_FBI(); - - // Restore original receive mode (multicasts, promiscuous, etc.). - skfp_ctl_set_multicast_list_wo_lock(smc->os.dev); -} // ResetAdapter - - -//--------------- functions called by hardware module ---------------- - -/************************ - * - * llc_restart_tx - * - * The hardware driver calls this routine when the transmit complete - * interrupt bits (end of frame) for the synchronous or asynchronous - * queue is set. - * - * NOTE The hardware driver calls this function also if no packets are queued. - * The routine must be able to handle this case. - * Args - * smc - A pointer to the SMT context struct. - * Out - * Nothing. - * - ************************/ -void llc_restart_tx(struct s_smc *smc) -{ - skfddi_priv *bp = &smc->os; - - pr_debug("[llc_restart_tx]\n"); - - // Try to send queued packets - spin_unlock(&bp->DriverLock); - send_queued_packets(smc); - spin_lock(&bp->DriverLock); - netif_start_queue(bp->dev);// system may send again if it was blocked - -} // llc_restart_tx - - -/************************ - * - * mac_drv_get_space - * - * The hardware module calls this function to allocate the memory - * for the SMT MBufs if the define MB_OUTSIDE_SMC is specified. - * Args - * smc - A pointer to the SMT context struct. - * - * size - Size of memory in bytes to allocate. - * Out - * != 0 A pointer to the virtual address of the allocated memory. - * == 0 Allocation error. - * - ************************/ -void *mac_drv_get_space(struct s_smc *smc, unsigned int size) -{ - void *virt; - - pr_debug("mac_drv_get_space (%d bytes), ", size); - virt = (void *) (smc->os.SharedMemAddr + smc->os.SharedMemHeap); - - if ((smc->os.SharedMemHeap + size) > smc->os.SharedMemSize) { - printk("Unexpected SMT memory size requested: %d\n", size); - return NULL; - } - smc->os.SharedMemHeap += size; // Move heap pointer. - - pr_debug("mac_drv_get_space end\n"); - pr_debug("virt addr: %lx\n", (ulong) virt); - pr_debug("bus addr: %lx\n", (ulong) - (smc->os.SharedMemDMA + - ((char *) virt - (char *)smc->os.SharedMemAddr))); - return virt; -} // mac_drv_get_space - - -/************************ - * - * mac_drv_get_desc_mem - * - * This function is called by the hardware dependent module. - * It allocates the memory for the RxD and TxD descriptors. - * - * This memory must be non-cached, non-movable and non-swappable. - * This memory should start at a physical page boundary. - * Args - * smc - A pointer to the SMT context struct. - * - * size - Size of memory in bytes to allocate. - * Out - * != 0 A pointer to the virtual address of the allocated memory. - * == 0 Allocation error. - * - ************************/ -void *mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size) -{ - - char *virt; - - pr_debug("mac_drv_get_desc_mem\n"); - - // Descriptor memory must be aligned on 16-byte boundary. - - virt = mac_drv_get_space(smc, size); - - size = (u_int) (16 - (((unsigned long) virt) & 15UL)); - size = size % 16; - - pr_debug("Allocate %u bytes alignment gap ", size); - pr_debug("for descriptor memory.\n"); - - if (!mac_drv_get_space(smc, size)) { - printk("fddi: Unable to align descriptor memory.\n"); - return NULL; - } - return virt + size; -} // mac_drv_get_desc_mem - - -/************************ - * - * mac_drv_virt2phys - * - * Get the physical address of a given virtual address. - * Args - * smc - A pointer to the SMT context struct. - * - * virt - A (virtual) pointer into our 'shared' memory area. - * Out - * Physical address of the given virtual address. - * - ************************/ -unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt) -{ - return smc->os.SharedMemDMA + - ((char *) virt - (char *)smc->os.SharedMemAddr); -} // mac_drv_virt2phys - - -/************************ - * - * dma_master - * - * The HWM calls this function, when the driver leads through a DMA - * transfer. If the OS-specific module must prepare the system hardware - * for the DMA transfer, it should do it in this function. - * - * The hardware module calls this dma_master if it wants to send an SMT - * frame. This means that the virt address passed in here is part of - * the 'shared' memory area. - * Args - * smc - A pointer to the SMT context struct. - * - * virt - The virtual address of the data. - * - * len - The length in bytes of the data. - * - * flag - Indicates the transmit direction and the buffer type: - * DMA_RD (0x01) system RAM ==> adapter buffer memory - * DMA_WR (0x02) adapter buffer memory ==> system RAM - * SMT_BUF (0x80) SMT buffer - * - * >> NOTE: SMT_BUF and DMA_RD are always set for PCI. << - * Out - * Returns the pyhsical address for the DMA transfer. - * - ************************/ -u_long dma_master(struct s_smc * smc, void *virt, int len, int flag) -{ - return smc->os.SharedMemDMA + - ((char *) virt - (char *)smc->os.SharedMemAddr); -} // dma_master - - -/************************ - * - * dma_complete - * - * The hardware module calls this routine when it has completed a DMA - * transfer. If the operating system dependent module has set up the DMA - * channel via dma_master() (e.g. Windows NT or AIX) it should clean up - * the DMA channel. - * Args - * smc - A pointer to the SMT context struct. - * - * descr - A pointer to a TxD or RxD, respectively. - * - * flag - Indicates the DMA transfer direction / SMT buffer: - * DMA_RD (0x01) system RAM ==> adapter buffer memory - * DMA_WR (0x02) adapter buffer memory ==> system RAM - * SMT_BUF (0x80) SMT buffer (managed by HWM) - * Out - * Nothing. - * - ************************/ -void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr, int flag) -{ - /* For TX buffers, there are two cases. If it is an SMT transmit - * buffer, there is nothing to do since we use consistent memory - * for the 'shared' memory area. The other case is for normal - * transmit packets given to us by the networking stack, and in - * that case we cleanup the PCI DMA mapping in mac_drv_tx_complete - * below. - * - * For RX buffers, we have to unmap dynamic PCI DMA mappings here - * because the hardware module is about to potentially look at - * the contents of the buffer. If we did not call the PCI DMA - * unmap first, the hardware module could read inconsistent data. - */ - if (flag & DMA_WR) { - skfddi_priv *bp = &smc->os; - volatile struct s_smt_fp_rxd *r = &descr->r; - - /* If SKB is NULL, we used the local buffer. */ - if (r->rxd_os.skb && r->rxd_os.dma_addr) { - int MaxFrameSize = bp->MaxFrameSize; - - pci_unmap_single(&bp->pdev, r->rxd_os.dma_addr, - MaxFrameSize, PCI_DMA_FROMDEVICE); - r->rxd_os.dma_addr = 0; - } - } -} // dma_complete - - -/************************ - * - * mac_drv_tx_complete - * - * Transmit of a packet is complete. Release the tx staging buffer. - * - * Args - * smc - A pointer to the SMT context struct. - * - * txd - A pointer to the last TxD which is used by the frame. - * Out - * Returns nothing. - * - ************************/ -void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd) -{ - struct sk_buff *skb; - - pr_debug("entering mac_drv_tx_complete\n"); - // Check if this TxD points to a skb - - if (!(skb = txd->txd_os.skb)) { - pr_debug("TXD with no skb assigned.\n"); - return; - } - txd->txd_os.skb = NULL; - - // release the DMA mapping - pci_unmap_single(&smc->os.pdev, txd->txd_os.dma_addr, - skb->len, PCI_DMA_TODEVICE); - txd->txd_os.dma_addr = 0; - - smc->os.MacStat.gen.tx_packets++; // Count transmitted packets. - smc->os.MacStat.gen.tx_bytes+=skb->len; // Count bytes - - // free the skb - dev_kfree_skb_irq(skb); - - pr_debug("leaving mac_drv_tx_complete\n"); -} // mac_drv_tx_complete - - -/************************ - * - * dump packets to logfile - * - ************************/ -#ifdef DUMPPACKETS -void dump_data(unsigned char *Data, int length) -{ - int i, j; - unsigned char s[255], sh[10]; - if (length > 64) { - length = 64; - } - printk(KERN_INFO "---Packet start---\n"); - for (i = 0, j = 0; i < length / 8; i++, j += 8) - printk(KERN_INFO "%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]); - strcpy(s, ""); - for (i = 0; i < length % 8; i++) { - sprintf(sh, "%02x ", Data[j + i]); - strcat(s, sh); - } - printk(KERN_INFO "%s\n", s); - printk(KERN_INFO "------------------\n"); -} // dump_data -#else -#define dump_data(data,len) -#endif // DUMPPACKETS - -/************************ - * - * mac_drv_rx_complete - * - * The hardware module calls this function if an LLC frame is received - * in a receive buffer. Also the SMT, NSA, and directed beacon frames - * from the network will be passed to the LLC layer by this function - * if passing is enabled. - * - * mac_drv_rx_complete forwards the frame to the LLC layer if it should - * be received. It also fills the RxD ring with new receive buffers if - * some can be queued. - * Args - * smc - A pointer to the SMT context struct. - * - * rxd - A pointer to the first RxD which is used by the receive frame. - * - * frag_count - Count of RxDs used by the received frame. - * - * len - Frame length. - * Out - * Nothing. - * - ************************/ -void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, - int frag_count, int len) -{ - skfddi_priv *bp = &smc->os; - struct sk_buff *skb; - unsigned char *virt, *cp; - unsigned short ri; - u_int RifLength; - - pr_debug("entering mac_drv_rx_complete (len=%d)\n", len); - if (frag_count != 1) { // This is not allowed to happen. - - printk("fddi: Multi-fragment receive!\n"); - goto RequeueRxd; // Re-use the given RXD(s). - - } - skb = rxd->rxd_os.skb; - if (!skb) { - pr_debug("No skb in rxd\n"); - smc->os.MacStat.gen.rx_errors++; - goto RequeueRxd; - } - virt = skb->data; - - // The DMA mapping was released in dma_complete above. - - dump_data(skb->data, len); - - /* - * FDDI Frame format: - * +-------+-------+-------+------------+--------+------------+ - * | FC[1] | DA[6] | SA[6] | RIF[0..18] | LLC[3] | Data[0..n] | - * +-------+-------+-------+------------+--------+------------+ - * - * FC = Frame Control - * DA = Destination Address - * SA = Source Address - * RIF = Routing Information Field - * LLC = Logical Link Control - */ - - // Remove Routing Information Field (RIF), if present. - - if ((virt[1 + 6] & FDDI_RII) == 0) - RifLength = 0; - else { - int n; -// goos: RIF removal has still to be tested - pr_debug("RIF found\n"); - // Get RIF length from Routing Control (RC) field. - cp = virt + FDDI_MAC_HDR_LEN; // Point behind MAC header. - - ri = ntohs(*((__be16 *) cp)); - RifLength = ri & FDDI_RCF_LEN_MASK; - if (len < (int) (FDDI_MAC_HDR_LEN + RifLength)) { - printk("fddi: Invalid RIF.\n"); - goto RequeueRxd; // Discard the frame. - - } - virt[1 + 6] &= ~FDDI_RII; // Clear RII bit. - // regions overlap - - virt = cp + RifLength; - for (n = FDDI_MAC_HDR_LEN; n; n--) - *--virt = *--cp; - // adjust sbd->data pointer - skb_pull(skb, RifLength); - len -= RifLength; - RifLength = 0; - } - - // Count statistics. - smc->os.MacStat.gen.rx_packets++; // Count indicated receive - // packets. - smc->os.MacStat.gen.rx_bytes+=len; // Count bytes. - - // virt points to header again - if (virt[1] & 0x01) { // Check group (multicast) bit. - - smc->os.MacStat.gen.multicast++; - } - - // deliver frame to system - rxd->rxd_os.skb = NULL; - skb_trim(skb, len); - skb->protocol = fddi_type_trans(skb, bp->dev); - - netif_rx(skb); - - HWM_RX_CHECK(smc, RX_LOW_WATERMARK); - return; - - RequeueRxd: - pr_debug("Rx: re-queue RXD.\n"); - mac_drv_requeue_rxd(smc, rxd, frag_count); - smc->os.MacStat.gen.rx_errors++; // Count receive packets - // not indicated. - -} // mac_drv_rx_complete - - -/************************ - * - * mac_drv_requeue_rxd - * - * The hardware module calls this function to request the OS-specific - * module to queue the receive buffer(s) represented by the pointer - * to the RxD and the frag_count into the receive queue again. This - * buffer was filled with an invalid frame or an SMT frame. - * Args - * smc - A pointer to the SMT context struct. - * - * rxd - A pointer to the first RxD which is used by the receive frame. - * - * frag_count - Count of RxDs used by the received frame. - * Out - * Nothing. - * - ************************/ -void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, - int frag_count) -{ - volatile struct s_smt_fp_rxd *next_rxd; - volatile struct s_smt_fp_rxd *src_rxd; - struct sk_buff *skb; - int MaxFrameSize; - unsigned char *v_addr; - dma_addr_t b_addr; - - if (frag_count != 1) // This is not allowed to happen. - - printk("fddi: Multi-fragment requeue!\n"); - - MaxFrameSize = smc->os.MaxFrameSize; - src_rxd = rxd; - for (; frag_count > 0; frag_count--) { - next_rxd = src_rxd->rxd_next; - rxd = HWM_GET_CURR_RXD(smc); - - skb = src_rxd->rxd_os.skb; - if (skb == NULL) { // this should not happen - - pr_debug("Requeue with no skb in rxd!\n"); - skb = alloc_skb(MaxFrameSize + 3, GFP_ATOMIC); - if (skb) { - // we got a skb - rxd->rxd_os.skb = skb; - skb_reserve(skb, 3); - skb_put(skb, MaxFrameSize); - v_addr = skb->data; - b_addr = pci_map_single(&smc->os.pdev, - v_addr, - MaxFrameSize, - PCI_DMA_FROMDEVICE); - rxd->rxd_os.dma_addr = b_addr; - } else { - // no skb available, use local buffer - pr_debug("Queueing invalid buffer!\n"); - rxd->rxd_os.skb = NULL; - v_addr = smc->os.LocalRxBuffer; - b_addr = smc->os.LocalRxBufferDMA; - } - } else { - // we use skb from old rxd - rxd->rxd_os.skb = skb; - v_addr = skb->data; - b_addr = pci_map_single(&smc->os.pdev, - v_addr, - MaxFrameSize, - PCI_DMA_FROMDEVICE); - rxd->rxd_os.dma_addr = b_addr; - } - hwm_rx_frag(smc, v_addr, b_addr, MaxFrameSize, - FIRST_FRAG | LAST_FRAG); - - src_rxd = next_rxd; - } -} // mac_drv_requeue_rxd - - -/************************ - * - * mac_drv_fill_rxd - * - * The hardware module calls this function at initialization time - * to fill the RxD ring with receive buffers. It is also called by - * mac_drv_rx_complete if rx_free is large enough to queue some new - * receive buffers into the RxD ring. mac_drv_fill_rxd queues new - * receive buffers as long as enough RxDs and receive buffers are - * available. - * Args - * smc - A pointer to the SMT context struct. - * Out - * Nothing. - * - ************************/ -void mac_drv_fill_rxd(struct s_smc *smc) -{ - int MaxFrameSize; - unsigned char *v_addr; - unsigned long b_addr; - struct sk_buff *skb; - volatile struct s_smt_fp_rxd *rxd; - - pr_debug("entering mac_drv_fill_rxd\n"); - - // Walk through the list of free receive buffers, passing receive - // buffers to the HWM as long as RXDs are available. - - MaxFrameSize = smc->os.MaxFrameSize; - // Check if there is any RXD left. - while (HWM_GET_RX_FREE(smc) > 0) { - pr_debug(".\n"); - - rxd = HWM_GET_CURR_RXD(smc); - skb = alloc_skb(MaxFrameSize + 3, GFP_ATOMIC); - if (skb) { - // we got a skb - skb_reserve(skb, 3); - skb_put(skb, MaxFrameSize); - v_addr = skb->data; - b_addr = pci_map_single(&smc->os.pdev, - v_addr, - MaxFrameSize, - PCI_DMA_FROMDEVICE); - rxd->rxd_os.dma_addr = b_addr; - } else { - // no skb available, use local buffer - // System has run out of buffer memory, but we want to - // keep the receiver running in hope of better times. - // Multiple descriptors may point to this local buffer, - // so data in it must be considered invalid. - pr_debug("Queueing invalid buffer!\n"); - v_addr = smc->os.LocalRxBuffer; - b_addr = smc->os.LocalRxBufferDMA; - } - - rxd->rxd_os.skb = skb; - - // Pass receive buffer to HWM. - hwm_rx_frag(smc, v_addr, b_addr, MaxFrameSize, - FIRST_FRAG | LAST_FRAG); - } - pr_debug("leaving mac_drv_fill_rxd\n"); -} // mac_drv_fill_rxd - - -/************************ - * - * mac_drv_clear_rxd - * - * The hardware module calls this function to release unused - * receive buffers. - * Args - * smc - A pointer to the SMT context struct. - * - * rxd - A pointer to the first RxD which is used by the receive buffer. - * - * frag_count - Count of RxDs used by the receive buffer. - * Out - * Nothing. - * - ************************/ -void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, - int frag_count) -{ - - struct sk_buff *skb; - - pr_debug("entering mac_drv_clear_rxd\n"); - - if (frag_count != 1) // This is not allowed to happen. - - printk("fddi: Multi-fragment clear!\n"); - - for (; frag_count > 0; frag_count--) { - skb = rxd->rxd_os.skb; - if (skb != NULL) { - skfddi_priv *bp = &smc->os; - int MaxFrameSize = bp->MaxFrameSize; - - pci_unmap_single(&bp->pdev, rxd->rxd_os.dma_addr, - MaxFrameSize, PCI_DMA_FROMDEVICE); - - dev_kfree_skb(skb); - rxd->rxd_os.skb = NULL; - } - rxd = rxd->rxd_next; // Next RXD. - - } -} // mac_drv_clear_rxd - - -/************************ - * - * mac_drv_rx_init - * - * The hardware module calls this routine when an SMT or NSA frame of the - * local SMT should be delivered to the LLC layer. - * - * It is necessary to have this function, because there is no other way to - * copy the contents of SMT MBufs into receive buffers. - * - * mac_drv_rx_init allocates the required target memory for this frame, - * and receives the frame fragment by fragment by calling mac_drv_rx_frag. - * Args - * smc - A pointer to the SMT context struct. - * - * len - The length (in bytes) of the received frame (FC, DA, SA, Data). - * - * fc - The Frame Control field of the received frame. - * - * look_ahead - A pointer to the lookahead data buffer (may be NULL). - * - * la_len - The length of the lookahead data stored in the lookahead - * buffer (may be zero). - * Out - * Always returns zero (0). - * - ************************/ -int mac_drv_rx_init(struct s_smc *smc, int len, int fc, - char *look_ahead, int la_len) -{ - struct sk_buff *skb; - - pr_debug("entering mac_drv_rx_init(len=%d)\n", len); - - // "Received" a SMT or NSA frame of the local SMT. - - if (len != la_len || len < FDDI_MAC_HDR_LEN || !look_ahead) { - pr_debug("fddi: Discard invalid local SMT frame\n"); - pr_debug(" len=%d, la_len=%d, (ULONG) look_ahead=%08lXh.\n", - len, la_len, (unsigned long) look_ahead); - return 0; - } - skb = alloc_skb(len + 3, GFP_ATOMIC); - if (!skb) { - pr_debug("fddi: Local SMT: skb memory exhausted.\n"); - return 0; - } - skb_reserve(skb, 3); - skb_put(skb, len); - skb_copy_to_linear_data(skb, look_ahead, len); - - // deliver frame to system - skb->protocol = fddi_type_trans(skb, smc->os.dev); - netif_rx(skb); - - return 0; -} // mac_drv_rx_init - - -/************************ - * - * smt_timer_poll - * - * This routine is called periodically by the SMT module to clean up the - * driver. - * - * Return any queued frames back to the upper protocol layers if the ring - * is down. - * Args - * smc - A pointer to the SMT context struct. - * Out - * Nothing. - * - ************************/ -void smt_timer_poll(struct s_smc *smc) -{ -} // smt_timer_poll - - -/************************ - * - * ring_status_indication - * - * This function indicates a change of the ring state. - * Args - * smc - A pointer to the SMT context struct. - * - * status - The current ring status. - * Out - * Nothing. - * - ************************/ -void ring_status_indication(struct s_smc *smc, u_long status) -{ - pr_debug("ring_status_indication( "); - if (status & RS_RES15) - pr_debug("RS_RES15 "); - if (status & RS_HARDERROR) - pr_debug("RS_HARDERROR "); - if (status & RS_SOFTERROR) - pr_debug("RS_SOFTERROR "); - if (status & RS_BEACON) - pr_debug("RS_BEACON "); - if (status & RS_PATHTEST) - pr_debug("RS_PATHTEST "); - if (status & RS_SELFTEST) - pr_debug("RS_SELFTEST "); - if (status & RS_RES9) - pr_debug("RS_RES9 "); - if (status & RS_DISCONNECT) - pr_debug("RS_DISCONNECT "); - if (status & RS_RES7) - pr_debug("RS_RES7 "); - if (status & RS_DUPADDR) - pr_debug("RS_DUPADDR "); - if (status & RS_NORINGOP) - pr_debug("RS_NORINGOP "); - if (status & RS_VERSION) - pr_debug("RS_VERSION "); - if (status & RS_STUCKBYPASSS) - pr_debug("RS_STUCKBYPASSS "); - if (status & RS_EVENT) - pr_debug("RS_EVENT "); - if (status & RS_RINGOPCHANGE) - pr_debug("RS_RINGOPCHANGE "); - if (status & RS_RES0) - pr_debug("RS_RES0 "); - pr_debug("]\n"); -} // ring_status_indication - - -/************************ - * - * smt_get_time - * - * Gets the current time from the system. - * Args - * None. - * Out - * The current time in TICKS_PER_SECOND. - * - * TICKS_PER_SECOND has the unit 'count of timer ticks per second'. It is - * defined in "targetos.h". The definition of TICKS_PER_SECOND must comply - * to the time returned by smt_get_time(). - * - ************************/ -unsigned long smt_get_time(void) -{ - return jiffies; -} // smt_get_time - - -/************************ - * - * smt_stat_counter - * - * Status counter update (ring_op, fifo full). - * Args - * smc - A pointer to the SMT context struct. - * - * stat - = 0: A ring operational change occurred. - * = 1: The FORMAC FIFO buffer is full / FIFO overflow. - * Out - * Nothing. - * - ************************/ -void smt_stat_counter(struct s_smc *smc, int stat) -{ -// BOOLEAN RingIsUp ; - - pr_debug("smt_stat_counter\n"); - switch (stat) { - case 0: - pr_debug("Ring operational change.\n"); - break; - case 1: - pr_debug("Receive fifo overflow.\n"); - smc->os.MacStat.gen.rx_errors++; - break; - default: - pr_debug("Unknown status (%d).\n", stat); - break; - } -} // smt_stat_counter - - -/************************ - * - * cfm_state_change - * - * Sets CFM state in custom statistics. - * Args - * smc - A pointer to the SMT context struct. - * - * c_state - Possible values are: - * - * EC0_OUT, EC1_IN, EC2_TRACE, EC3_LEAVE, EC4_PATH_TEST, - * EC5_INSERT, EC6_CHECK, EC7_DEINSERT - * Out - * Nothing. - * - ************************/ -void cfm_state_change(struct s_smc *smc, int c_state) -{ -#ifdef DRIVERDEBUG - char *s; - - switch (c_state) { - case SC0_ISOLATED: - s = "SC0_ISOLATED"; - break; - case SC1_WRAP_A: - s = "SC1_WRAP_A"; - break; - case SC2_WRAP_B: - s = "SC2_WRAP_B"; - break; - case SC4_THRU_A: - s = "SC4_THRU_A"; - break; - case SC5_THRU_B: - s = "SC5_THRU_B"; - break; - case SC7_WRAP_S: - s = "SC7_WRAP_S"; - break; - case SC9_C_WRAP_A: - s = "SC9_C_WRAP_A"; - break; - case SC10_C_WRAP_B: - s = "SC10_C_WRAP_B"; - break; - case SC11_C_WRAP_S: - s = "SC11_C_WRAP_S"; - break; - default: - pr_debug("cfm_state_change: unknown %d\n", c_state); - return; - } - pr_debug("cfm_state_change: %s\n", s); -#endif // DRIVERDEBUG -} // cfm_state_change - - -/************************ - * - * ecm_state_change - * - * Sets ECM state in custom statistics. - * Args - * smc - A pointer to the SMT context struct. - * - * e_state - Possible values are: - * - * SC0_ISOLATED, SC1_WRAP_A (5), SC2_WRAP_B (6), SC4_THRU_A (12), - * SC5_THRU_B (7), SC7_WRAP_S (8) - * Out - * Nothing. - * - ************************/ -void ecm_state_change(struct s_smc *smc, int e_state) -{ -#ifdef DRIVERDEBUG - char *s; - - switch (e_state) { - case EC0_OUT: - s = "EC0_OUT"; - break; - case EC1_IN: - s = "EC1_IN"; - break; - case EC2_TRACE: - s = "EC2_TRACE"; - break; - case EC3_LEAVE: - s = "EC3_LEAVE"; - break; - case EC4_PATH_TEST: - s = "EC4_PATH_TEST"; - break; - case EC5_INSERT: - s = "EC5_INSERT"; - break; - case EC6_CHECK: - s = "EC6_CHECK"; - break; - case EC7_DEINSERT: - s = "EC7_DEINSERT"; - break; - default: - s = "unknown"; - break; - } - pr_debug("ecm_state_change: %s\n", s); -#endif //DRIVERDEBUG -} // ecm_state_change - - -/************************ - * - * rmt_state_change - * - * Sets RMT state in custom statistics. - * Args - * smc - A pointer to the SMT context struct. - * - * r_state - Possible values are: - * - * RM0_ISOLATED, RM1_NON_OP, RM2_RING_OP, RM3_DETECT, - * RM4_NON_OP_DUP, RM5_RING_OP_DUP, RM6_DIRECTED, RM7_TRACE - * Out - * Nothing. - * - ************************/ -void rmt_state_change(struct s_smc *smc, int r_state) -{ -#ifdef DRIVERDEBUG - char *s; - - switch (r_state) { - case RM0_ISOLATED: - s = "RM0_ISOLATED"; - break; - case RM1_NON_OP: - s = "RM1_NON_OP - not operational"; - break; - case RM2_RING_OP: - s = "RM2_RING_OP - ring operational"; - break; - case RM3_DETECT: - s = "RM3_DETECT - detect dupl addresses"; - break; - case RM4_NON_OP_DUP: - s = "RM4_NON_OP_DUP - dupl. addr detected"; - break; - case RM5_RING_OP_DUP: - s = "RM5_RING_OP_DUP - ring oper. with dupl. addr"; - break; - case RM6_DIRECTED: - s = "RM6_DIRECTED - sending directed beacons"; - break; - case RM7_TRACE: - s = "RM7_TRACE - trace initiated"; - break; - default: - s = "unknown"; - break; - } - pr_debug("[rmt_state_change: %s]\n", s); -#endif // DRIVERDEBUG -} // rmt_state_change - - -/************************ - * - * drv_reset_indication - * - * This function is called by the SMT when it has detected a severe - * hardware problem. The driver should perform a reset on the adapter - * as soon as possible, but not from within this function. - * Args - * smc - A pointer to the SMT context struct. - * Out - * Nothing. - * - ************************/ -void drv_reset_indication(struct s_smc *smc) -{ - pr_debug("entering drv_reset_indication\n"); - - smc->os.ResetRequested = TRUE; // Set flag. - -} // drv_reset_indication - -static struct pci_driver skfddi_pci_driver = { - .name = "skfddi", - .id_table = skfddi_pci_tbl, - .probe = skfp_init_one, - .remove = __devexit_p(skfp_remove_one), -}; - -static int __init skfd_init(void) -{ - return pci_register_driver(&skfddi_pci_driver); -} - -static void __exit skfd_exit(void) -{ - pci_unregister_driver(&skfddi_pci_driver); -} - -module_init(skfd_init); -module_exit(skfd_exit); diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c deleted file mode 100644 index 08d9432..0000000 --- a/drivers/net/skfp/smt.c +++ /dev/null @@ -1,2046 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -#include "h/types.h" -#include "h/fddi.h" -#include "h/smc.h" -#include "h/smt_p.h" -#include -#include - -#define KERNEL -#include "h/smtstate.h" - -#ifndef lint -static const char ID_sccs[] = "@(#)smt.c 2.43 98/11/23 (C) SK " ; -#endif - -/* - * FC in SMbuf - */ -#define m_fc(mb) ((mb)->sm_data[0]) - -#define SMT_TID_MAGIC 0x1f0a7b3c - -#ifdef DEBUG -static const char *const smt_type_name[] = { - "SMT_00??", "SMT_INFO", "SMT_02??", "SMT_03??", - "SMT_04??", "SMT_05??", "SMT_06??", "SMT_07??", - "SMT_08??", "SMT_09??", "SMT_0A??", "SMT_0B??", - "SMT_0C??", "SMT_0D??", "SMT_0E??", "SMT_NSA" -} ; - -static const char *const smt_class_name[] = { - "UNKNOWN","NIF","SIF_CONFIG","SIF_OPER","ECF","RAF","RDF", - "SRF","PMF_GET","PMF_SET","ESF" -} ; -#endif -#define LAST_CLASS (SMT_PMF_SET) - -static const struct fddi_addr SMT_Unknown = { - { 0,0,0x1f,0,0,0 } -} ; - -/* - * function prototypes - */ -#ifdef LITTLE_ENDIAN -static int smt_swap_short(u_short s); -#endif -static int mac_index(struct s_smc *smc, int mac); -static int phy_index(struct s_smc *smc, int phy); -static int mac_con_resource_index(struct s_smc *smc, int mac); -static int phy_con_resource_index(struct s_smc *smc, int phy); -static void smt_send_rdf(struct s_smc *smc, SMbuf *rej, int fc, int reason, - int local); -static void smt_send_nif(struct s_smc *smc, const struct fddi_addr *dest, - int fc, u_long tid, int type, int local); -static void smt_send_ecf(struct s_smc *smc, struct fddi_addr *dest, int fc, - u_long tid, int type, int len); -static void smt_echo_test(struct s_smc *smc, int dna); -static void smt_send_sif_config(struct s_smc *smc, struct fddi_addr *dest, - u_long tid, int local); -static void smt_send_sif_operation(struct s_smc *smc, struct fddi_addr *dest, - u_long tid, int local); -#ifdef LITTLE_ENDIAN -static void smt_string_swap(char *data, const char *format, int len); -#endif -static void smt_add_frame_len(SMbuf *mb, int len); -static void smt_fill_una(struct s_smc *smc, struct smt_p_una *una); -static void smt_fill_sde(struct s_smc *smc, struct smt_p_sde *sde); -static void smt_fill_state(struct s_smc *smc, struct smt_p_state *state); -static void smt_fill_timestamp(struct s_smc *smc, struct smt_p_timestamp *ts); -static void smt_fill_policy(struct s_smc *smc, struct smt_p_policy *policy); -static void smt_fill_latency(struct s_smc *smc, struct smt_p_latency *latency); -static void smt_fill_neighbor(struct s_smc *smc, struct smt_p_neighbor *neighbor); -static int smt_fill_path(struct s_smc *smc, struct smt_p_path *path); -static void smt_fill_mac_status(struct s_smc *smc, struct smt_p_mac_status *st); -static void smt_fill_lem(struct s_smc *smc, struct smt_p_lem *lem, int phy); -static void smt_fill_version(struct s_smc *smc, struct smt_p_version *vers); -static void smt_fill_fsc(struct s_smc *smc, struct smt_p_fsc *fsc); -static void smt_fill_mac_counter(struct s_smc *smc, struct smt_p_mac_counter *mc); -static void smt_fill_mac_fnc(struct s_smc *smc, struct smt_p_mac_fnc *fnc); -static void smt_fill_manufacturer(struct s_smc *smc, - struct smp_p_manufacturer *man); -static void smt_fill_user(struct s_smc *smc, struct smp_p_user *user); -static void smt_fill_setcount(struct s_smc *smc, struct smt_p_setcount *setcount); -static void smt_fill_echo(struct s_smc *smc, struct smt_p_echo *echo, u_long seed, - int len); - -static void smt_clear_una_dna(struct s_smc *smc); -static void smt_clear_old_una_dna(struct s_smc *smc); -#ifdef CONCENTRATOR -static int entity_to_index(void); -#endif -static void update_dac(struct s_smc *smc, int report); -static int div_ratio(u_long upper, u_long lower); -#ifdef USE_CAN_ADDR -static void hwm_conv_can(struct s_smc *smc, char *data, int len); -#else -#define hwm_conv_can(smc,data,len) -#endif - - -static inline int is_my_addr(const struct s_smc *smc, - const struct fddi_addr *addr) -{ - return(*(short *)(&addr->a[0]) == - *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[0]) - && *(short *)(&addr->a[2]) == - *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[2]) - && *(short *)(&addr->a[4]) == - *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[4])) ; -} - -static inline int is_broadcast(const struct fddi_addr *addr) -{ - return *(u_short *)(&addr->a[0]) == 0xffff && - *(u_short *)(&addr->a[2]) == 0xffff && - *(u_short *)(&addr->a[4]) == 0xffff; -} - -static inline int is_individual(const struct fddi_addr *addr) -{ - return !(addr->a[0] & GROUP_ADDR); -} - -static inline int is_equal(const struct fddi_addr *addr1, - const struct fddi_addr *addr2) -{ - return *(u_short *)(&addr1->a[0]) == *(u_short *)(&addr2->a[0]) && - *(u_short *)(&addr1->a[2]) == *(u_short *)(&addr2->a[2]) && - *(u_short *)(&addr1->a[4]) == *(u_short *)(&addr2->a[4]); -} - -/* - * list of mandatory paras in frames - */ -static const u_short plist_nif[] = { SMT_P_UNA,SMT_P_SDE,SMT_P_STATE,0 } ; - -/* - * init SMT agent - */ -void smt_agent_init(struct s_smc *smc) -{ - int i ; - - /* - * get MAC address - */ - smc->mib.m[MAC0].fddiMACSMTAddress = smc->hw.fddi_home_addr ; - - /* - * get OUI address from driver (bia == built-in-address) - */ - smc->mib.fddiSMTStationId.sid_oem[0] = 0 ; - smc->mib.fddiSMTStationId.sid_oem[1] = 0 ; - driver_get_bia(smc,&smc->mib.fddiSMTStationId.sid_node) ; - for (i = 0 ; i < 6 ; i ++) { - smc->mib.fddiSMTStationId.sid_node.a[i] = - bitrev8(smc->mib.fddiSMTStationId.sid_node.a[i]); - } - smc->mib.fddiSMTManufacturerData[0] = - smc->mib.fddiSMTStationId.sid_node.a[0] ; - smc->mib.fddiSMTManufacturerData[1] = - smc->mib.fddiSMTStationId.sid_node.a[1] ; - smc->mib.fddiSMTManufacturerData[2] = - smc->mib.fddiSMTStationId.sid_node.a[2] ; - smc->sm.smt_tid = 0 ; - smc->mib.m[MAC0].fddiMACDupAddressTest = DA_NONE ; - smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ; -#ifndef SLIM_SMT - smt_clear_una_dna(smc) ; - smt_clear_old_una_dna(smc) ; -#endif - for (i = 0 ; i < SMT_MAX_TEST ; i++) - smc->sm.pend[i] = 0 ; - smc->sm.please_reconnect = 0 ; - smc->sm.uniq_ticks = 0 ; -} - -/* - * SMT task - * forever - * delay 30 seconds - * send NIF - * check tvu & tvd - * end - */ -void smt_agent_task(struct s_smc *smc) -{ - smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L, - EV_TOKEN(EVENT_SMT,SM_TIMER)) ; - DB_SMT("SMT agent task\n",0,0) ; -} - -#ifndef SMT_REAL_TOKEN_CT -void smt_emulate_token_ct(struct s_smc *smc, int mac_index) -{ - u_long count; - u_long time; - - - time = smt_get_time(); - count = ((time - smc->sm.last_tok_time[mac_index]) * - 100)/TICKS_PER_SECOND; - - /* - * Only when ring is up we will have a token count. The - * flag is unfortunately a single instance value. This - * doesn't matter now, because we currently have only - * one MAC instance. - */ - if (smc->hw.mac_ring_is_up){ - smc->mib.m[mac_index].fddiMACToken_Ct += count; - } - - /* Remember current time */ - smc->sm.last_tok_time[mac_index] = time; - -} -#endif - -/*ARGSUSED1*/ -void smt_event(struct s_smc *smc, int event) -{ - u_long time ; -#ifndef SMT_REAL_TOKEN_CT - int i ; -#endif - - - if (smc->sm.please_reconnect) { - smc->sm.please_reconnect -- ; - if (smc->sm.please_reconnect == 0) { - /* Counted down */ - queue_event(smc,EVENT_ECM,EC_CONNECT) ; - } - } - - if (event == SM_FAST) - return ; - - /* - * timer for periodic cleanup in driver - * reset and start the watchdog (FM2) - * ESS timer - * SBA timer - */ - smt_timer_poll(smc) ; - smt_start_watchdog(smc) ; -#ifndef SLIM_SMT -#ifndef BOOT -#ifdef ESS - ess_timer_poll(smc) ; -#endif -#endif -#ifdef SBA - sba_timer_poll(smc) ; -#endif - - smt_srf_event(smc,0,0,0) ; - -#endif /* no SLIM_SMT */ - - time = smt_get_time() ; - - if (time - smc->sm.smt_last_lem >= TICKS_PER_SECOND*8) { - /* - * Use 8 sec. for the time intervall, it simplifies the - * LER estimation. - */ - struct fddi_mib_m *mib ; - u_long upper ; - u_long lower ; - int cond ; - int port; - struct s_phy *phy ; - /* - * calculate LEM bit error rate - */ - sm_lem_evaluate(smc) ; - smc->sm.smt_last_lem = time ; - - /* - * check conditions - */ -#ifndef SLIM_SMT - mac_update_counter(smc) ; - mib = smc->mib.m ; - upper = - (mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) + - (mib->fddiMACError_Ct - mib->fddiMACOld_Error_Ct) ; - lower = - (mib->fddiMACFrame_Ct - mib->fddiMACOld_Frame_Ct) + - (mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) ; - mib->fddiMACFrameErrorRatio = div_ratio(upper,lower) ; - - cond = - ((!mib->fddiMACFrameErrorThreshold && - mib->fddiMACError_Ct != mib->fddiMACOld_Error_Ct) || - (mib->fddiMACFrameErrorRatio > - mib->fddiMACFrameErrorThreshold)) ; - - if (cond != mib->fddiMACFrameErrorFlag) - smt_srf_event(smc,SMT_COND_MAC_FRAME_ERROR, - INDEX_MAC,cond) ; - - upper = - (mib->fddiMACNotCopied_Ct - mib->fddiMACOld_NotCopied_Ct) ; - lower = - upper + - (mib->fddiMACCopied_Ct - mib->fddiMACOld_Copied_Ct) ; - mib->fddiMACNotCopiedRatio = div_ratio(upper,lower) ; - - cond = - ((!mib->fddiMACNotCopiedThreshold && - mib->fddiMACNotCopied_Ct != - mib->fddiMACOld_NotCopied_Ct)|| - (mib->fddiMACNotCopiedRatio > - mib->fddiMACNotCopiedThreshold)) ; - - if (cond != mib->fddiMACNotCopiedFlag) - smt_srf_event(smc,SMT_COND_MAC_NOT_COPIED, - INDEX_MAC,cond) ; - - /* - * set old values - */ - mib->fddiMACOld_Frame_Ct = mib->fddiMACFrame_Ct ; - mib->fddiMACOld_Copied_Ct = mib->fddiMACCopied_Ct ; - mib->fddiMACOld_Error_Ct = mib->fddiMACError_Ct ; - mib->fddiMACOld_Lost_Ct = mib->fddiMACLost_Ct ; - mib->fddiMACOld_NotCopied_Ct = mib->fddiMACNotCopied_Ct ; - - /* - * Check port EBError Condition - */ - for (port = 0; port < NUMPHYS; port ++) { - phy = &smc->y[port] ; - - if (!phy->mib->fddiPORTHardwarePresent) { - continue; - } - - cond = (phy->mib->fddiPORTEBError_Ct - - phy->mib->fddiPORTOldEBError_Ct > 5) ; - - /* If ratio is more than 5 in 8 seconds - * Set the condition. - */ - smt_srf_event(smc,SMT_COND_PORT_EB_ERROR, - (int) (INDEX_PORT+ phy->np) ,cond) ; - - /* - * set old values - */ - phy->mib->fddiPORTOldEBError_Ct = - phy->mib->fddiPORTEBError_Ct ; - } - -#endif /* no SLIM_SMT */ - } - -#ifndef SLIM_SMT - - if (time - smc->sm.smt_last_notify >= (u_long) - (smc->mib.fddiSMTTT_Notify * TICKS_PER_SECOND) ) { - /* - * we can either send an announcement or a request - * a request will trigger a reply so that we can update - * our dna - * note: same tid must be used until reply is received - */ - if (!smc->sm.pend[SMT_TID_NIF]) - smc->sm.pend[SMT_TID_NIF] = smt_get_tid(smc) ; - smt_send_nif(smc,&fddi_broadcast, FC_SMT_NSA, - smc->sm.pend[SMT_TID_NIF], SMT_REQUEST,0) ; - smc->sm.smt_last_notify = time ; - } - - /* - * check timer - */ - if (smc->sm.smt_tvu && - time - smc->sm.smt_tvu > 228*TICKS_PER_SECOND) { - DB_SMT("SMT : UNA expired\n",0,0) ; - smc->sm.smt_tvu = 0 ; - - if (!is_equal(&smc->mib.m[MAC0].fddiMACUpstreamNbr, - &SMT_Unknown)){ - /* Do not update unknown address */ - smc->mib.m[MAC0].fddiMACOldUpstreamNbr= - smc->mib.m[MAC0].fddiMACUpstreamNbr ; - } - smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ; - smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ; - /* - * Make sure the fddiMACUNDA_Flag = FALSE is - * included in the SRF so we don't generate - * a separate SRF for the deassertion of this - * condition - */ - update_dac(smc,0) ; - smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE, - INDEX_MAC,0) ; - } - if (smc->sm.smt_tvd && - time - smc->sm.smt_tvd > 228*TICKS_PER_SECOND) { - DB_SMT("SMT : DNA expired\n",0,0) ; - smc->sm.smt_tvd = 0 ; - if (!is_equal(&smc->mib.m[MAC0].fddiMACDownstreamNbr, - &SMT_Unknown)){ - /* Do not update unknown address */ - smc->mib.m[MAC0].fddiMACOldDownstreamNbr= - smc->mib.m[MAC0].fddiMACDownstreamNbr ; - } - smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ; - smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE, - INDEX_MAC,0) ; - } - -#endif /* no SLIM_SMT */ - -#ifndef SMT_REAL_TOKEN_CT - /* - * Token counter emulation section. If hardware supports the token - * count, the token counter will be updated in mac_update_counter. - */ - for (i = MAC0; i < NUMMACS; i++ ){ - if (time - smc->sm.last_tok_time[i] > 2*TICKS_PER_SECOND ){ - smt_emulate_token_ct( smc, i ); - } - } -#endif - - smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L, - EV_TOKEN(EVENT_SMT,SM_TIMER)) ; -} - -static int div_ratio(u_long upper, u_long lower) -{ - if ((upper<<16L) < upper) - upper = 0xffff0000L ; - else - upper <<= 16L ; - if (!lower) - return 0; - return (int)(upper/lower) ; -} - -#ifndef SLIM_SMT - -/* - * receive packet handler - */ -void smt_received_pack(struct s_smc *smc, SMbuf *mb, int fs) -/* int fs; frame status */ -{ - struct smt_header *sm ; - int local ; - - int illegal = 0 ; - - switch (m_fc(mb)) { - case FC_SMT_INFO : - case FC_SMT_LAN_LOC : - case FC_SMT_LOC : - case FC_SMT_NSA : - break ; - default : - smt_free_mbuf(smc,mb) ; - return ; - } - - smc->mib.m[MAC0].fddiMACSMTCopied_Ct++ ; - sm = smtod(mb,struct smt_header *) ; - local = ((fs & L_INDICATOR) != 0) ; - hwm_conv_can(smc,(char *)sm,12) ; - - /* check destination address */ - if (is_individual(&sm->smt_dest) && !is_my_addr(smc,&sm->smt_dest)) { - smt_free_mbuf(smc,mb) ; - return ; - } -#if 0 /* for DUP recognition, do NOT filter them */ - /* ignore loop back packets */ - if (is_my_addr(smc,&sm->smt_source) && !local) { - smt_free_mbuf(smc,mb) ; - return ; - } -#endif - - smt_swap_para(sm,(int) mb->sm_len,1) ; - DB_SMT("SMT : received packet [%s] at 0x%x\n", - smt_type_name[m_fc(mb) & 0xf],sm) ; - DB_SMT("SMT : version %d, class %s\n",sm->smt_version, - smt_class_name[(sm->smt_class>LAST_CLASS)?0 : sm->smt_class]) ; - -#ifdef SBA - /* - * check if NSA frame - */ - if (m_fc(mb) == FC_SMT_NSA && sm->smt_class == SMT_NIF && - (sm->smt_type == SMT_ANNOUNCE || sm->smt_type == SMT_REQUEST)) { - smc->sba.sm = sm ; - sba(smc,NIF) ; - } -#endif - - /* - * ignore any packet with NSA and A-indicator set - */ - if ( (fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) { - DB_SMT("SMT : ignoring NSA with A-indicator set from %s\n", - addr_to_string(&sm->smt_source),0) ; - smt_free_mbuf(smc,mb) ; - return ; - } - - /* - * ignore frames with illegal length - */ - if (((sm->smt_class == SMT_ECF) && (sm->smt_len > SMT_MAX_ECHO_LEN)) || - ((sm->smt_class != SMT_ECF) && (sm->smt_len > SMT_MAX_INFO_LEN))) { - smt_free_mbuf(smc,mb) ; - return ; - } - - /* - * check SMT version - */ - switch (sm->smt_class) { - case SMT_NIF : - case SMT_SIF_CONFIG : - case SMT_SIF_OPER : - case SMT_ECF : - if (sm->smt_version != SMT_VID) - illegal = 1; - break ; - default : - if (sm->smt_version != SMT_VID_2) - illegal = 1; - break ; - } - if (illegal) { - DB_SMT("SMT : version = %d, dest = %s\n", - sm->smt_version,addr_to_string(&sm->smt_source)) ; - smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_VERSION,local) ; - smt_free_mbuf(smc,mb) ; - return ; - } - if ((sm->smt_len > mb->sm_len - sizeof(struct smt_header)) || - ((sm->smt_len & 3) && (sm->smt_class != SMT_ECF))) { - DB_SMT("SMT: info length error, len = %d\n",sm->smt_len,0) ; - smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH,local) ; - smt_free_mbuf(smc,mb) ; - return ; - } - switch (sm->smt_class) { - case SMT_NIF : - if (smt_check_para(smc,sm,plist_nif)) { - DB_SMT("SMT: NIF with para problem, ignoring\n",0,0) ; - break ; - } - switch (sm->smt_type) { - case SMT_ANNOUNCE : - case SMT_REQUEST : - if (!(fs & C_INDICATOR) && m_fc(mb) == FC_SMT_NSA - && is_broadcast(&sm->smt_dest)) { - struct smt_p_state *st ; - - /* set my UNA */ - if (!is_equal( - &smc->mib.m[MAC0].fddiMACUpstreamNbr, - &sm->smt_source)) { - DB_SMT("SMT : updated my UNA = %s\n", - addr_to_string(&sm->smt_source),0) ; - if (!is_equal(&smc->mib.m[MAC0]. - fddiMACUpstreamNbr,&SMT_Unknown)){ - /* Do not update unknown address */ - smc->mib.m[MAC0].fddiMACOldUpstreamNbr= - smc->mib.m[MAC0].fddiMACUpstreamNbr ; - } - - smc->mib.m[MAC0].fddiMACUpstreamNbr = - sm->smt_source ; - smt_srf_event(smc, - SMT_EVENT_MAC_NEIGHBOR_CHANGE, - INDEX_MAC,0) ; - smt_echo_test(smc,0) ; - } - smc->sm.smt_tvu = smt_get_time() ; - st = (struct smt_p_state *) - sm_to_para(smc,sm,SMT_P_STATE) ; - if (st) { - smc->mib.m[MAC0].fddiMACUNDA_Flag = - (st->st_dupl_addr & SMT_ST_MY_DUPA) ? - TRUE : FALSE ; - update_dac(smc,1) ; - } - } - if ((sm->smt_type == SMT_REQUEST) && - is_individual(&sm->smt_source) && - ((!(fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) || - (m_fc(mb) != FC_SMT_NSA))) { - DB_SMT("SMT : replying to NIF request %s\n", - addr_to_string(&sm->smt_source),0) ; - smt_send_nif(smc,&sm->smt_source, - FC_SMT_INFO, - sm->smt_tid, - SMT_REPLY,local) ; - } - break ; - case SMT_REPLY : - DB_SMT("SMT : received NIF response from %s\n", - addr_to_string(&sm->smt_source),0) ; - if (fs & A_INDICATOR) { - smc->sm.pend[SMT_TID_NIF] = 0 ; - DB_SMT("SMT : duplicate address\n",0,0) ; - smc->mib.m[MAC0].fddiMACDupAddressTest = - DA_FAILED ; - smc->r.dup_addr_test = DA_FAILED ; - queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ; - smc->mib.m[MAC0].fddiMACDA_Flag = TRUE ; - update_dac(smc,1) ; - break ; - } - if (sm->smt_tid == smc->sm.pend[SMT_TID_NIF]) { - smc->sm.pend[SMT_TID_NIF] = 0 ; - /* set my DNA */ - if (!is_equal( - &smc->mib.m[MAC0].fddiMACDownstreamNbr, - &sm->smt_source)) { - DB_SMT("SMT : updated my DNA\n",0,0) ; - if (!is_equal(&smc->mib.m[MAC0]. - fddiMACDownstreamNbr, &SMT_Unknown)){ - /* Do not update unknown address */ - smc->mib.m[MAC0].fddiMACOldDownstreamNbr = - smc->mib.m[MAC0].fddiMACDownstreamNbr ; - } - - smc->mib.m[MAC0].fddiMACDownstreamNbr = - sm->smt_source ; - smt_srf_event(smc, - SMT_EVENT_MAC_NEIGHBOR_CHANGE, - INDEX_MAC,0) ; - smt_echo_test(smc,1) ; - } - smc->mib.m[MAC0].fddiMACDA_Flag = FALSE ; - update_dac(smc,1) ; - smc->sm.smt_tvd = smt_get_time() ; - smc->mib.m[MAC0].fddiMACDupAddressTest = - DA_PASSED ; - if (smc->r.dup_addr_test != DA_PASSED) { - smc->r.dup_addr_test = DA_PASSED ; - queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ; - } - } - else if (sm->smt_tid == - smc->sm.pend[SMT_TID_NIF_TEST]) { - DB_SMT("SMT : NIF test TID ok\n",0,0) ; - } - else { - DB_SMT("SMT : expected TID %lx, got %lx\n", - smc->sm.pend[SMT_TID_NIF],sm->smt_tid) ; - } - break ; - default : - illegal = 2 ; - break ; - } - break ; - case SMT_SIF_CONFIG : /* station information */ - if (sm->smt_type != SMT_REQUEST) - break ; - DB_SMT("SMT : replying to SIF Config request from %s\n", - addr_to_string(&sm->smt_source),0) ; - smt_send_sif_config(smc,&sm->smt_source,sm->smt_tid,local) ; - break ; - case SMT_SIF_OPER : /* station information */ - if (sm->smt_type != SMT_REQUEST) - break ; - DB_SMT("SMT : replying to SIF Operation request from %s\n", - addr_to_string(&sm->smt_source),0) ; - smt_send_sif_operation(smc,&sm->smt_source,sm->smt_tid,local) ; - break ; - case SMT_ECF : /* echo frame */ - switch (sm->smt_type) { - case SMT_REPLY : - smc->mib.priv.fddiPRIVECF_Reply_Rx++ ; - DB_SMT("SMT: received ECF reply from %s\n", - addr_to_string(&sm->smt_source),0) ; - if (sm_to_para(smc,sm,SMT_P_ECHODATA) == NULL) { - DB_SMT("SMT: ECHODATA missing\n",0,0) ; - break ; - } - if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF]) { - DB_SMT("SMT : ECF test TID ok\n",0,0) ; - } - else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_UNA]) { - DB_SMT("SMT : ECF test UNA ok\n",0,0) ; - } - else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_DNA]) { - DB_SMT("SMT : ECF test DNA ok\n",0,0) ; - } - else { - DB_SMT("SMT : expected TID %lx, got %lx\n", - smc->sm.pend[SMT_TID_ECF], - sm->smt_tid) ; - } - break ; - case SMT_REQUEST : - smc->mib.priv.fddiPRIVECF_Req_Rx++ ; - { - if (sm->smt_len && !sm_to_para(smc,sm,SMT_P_ECHODATA)) { - DB_SMT("SMT: ECF with para problem,sending RDF\n",0,0) ; - smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH, - local) ; - break ; - } - DB_SMT("SMT - sending ECF reply to %s\n", - addr_to_string(&sm->smt_source),0) ; - - /* set destination addr. & reply */ - sm->smt_dest = sm->smt_source ; - sm->smt_type = SMT_REPLY ; - dump_smt(smc,sm,"ECF REPLY") ; - smc->mib.priv.fddiPRIVECF_Reply_Tx++ ; - smt_send_frame(smc,mb,FC_SMT_INFO,local) ; - return ; /* DON'T free mbuf */ - } - default : - illegal = 1 ; - break ; - } - break ; -#ifndef BOOT - case SMT_RAF : /* resource allocation */ -#ifdef ESS - DB_ESSN(2,"ESS: RAF frame received\n",0,0) ; - fs = ess_raf_received_pack(smc,mb,sm,fs) ; -#endif - -#ifdef SBA - DB_SBAN(2,"SBA: RAF frame received\n",0,0) ; - sba_raf_received_pack(smc,sm,fs) ; -#endif - break ; - case SMT_RDF : /* request denied */ - smc->mib.priv.fddiPRIVRDF_Rx++ ; - break ; - case SMT_ESF : /* extended service - not supported */ - if (sm->smt_type == SMT_REQUEST) { - DB_SMT("SMT - received ESF, sending RDF\n",0,0) ; - smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ; - } - break ; - case SMT_PMF_GET : - case SMT_PMF_SET : - if (sm->smt_type != SMT_REQUEST) - break ; - /* update statistics */ - if (sm->smt_class == SMT_PMF_GET) - smc->mib.priv.fddiPRIVPMF_Get_Rx++ ; - else - smc->mib.priv.fddiPRIVPMF_Set_Rx++ ; - /* - * ignore PMF SET with I/G set - */ - if ((sm->smt_class == SMT_PMF_SET) && - !is_individual(&sm->smt_dest)) { - DB_SMT("SMT: ignoring PMF-SET with I/G set\n",0,0) ; - break ; - } - smt_pmf_received_pack(smc,mb, local) ; - break ; - case SMT_SRF : - dump_smt(smc,sm,"SRF received") ; - break ; - default : - if (sm->smt_type != SMT_REQUEST) - break ; - /* - * For frames with unknown class: - * we need to send a RDF frame according to 8.1.3.1.1, - * only if it is a REQUEST. - */ - DB_SMT("SMT : class = %d, send RDF to %s\n", - sm->smt_class, addr_to_string(&sm->smt_source)) ; - - smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ; - break ; -#endif - } - if (illegal) { - DB_SMT("SMT: discarding invalid frame, reason = %d\n", - illegal,0) ; - } - smt_free_mbuf(smc,mb) ; -} - -static void update_dac(struct s_smc *smc, int report) -{ - int cond ; - - cond = ( smc->mib.m[MAC0].fddiMACUNDA_Flag | - smc->mib.m[MAC0].fddiMACDA_Flag) != 0 ; - if (report && (cond != smc->mib.m[MAC0].fddiMACDuplicateAddressCond)) - smt_srf_event(smc, SMT_COND_MAC_DUP_ADDR,INDEX_MAC,cond) ; - else - smc->mib.m[MAC0].fddiMACDuplicateAddressCond = cond ; -} - -/* - * send SMT frame - * set source address - * set station ID - * send frame - */ -void smt_send_frame(struct s_smc *smc, SMbuf *mb, int fc, int local) -/* SMbuf *mb; buffer to send */ -/* int fc; FC value */ -{ - struct smt_header *sm ; - - if (!smc->r.sm_ma_avail && !local) { - smt_free_mbuf(smc,mb) ; - return ; - } - sm = smtod(mb,struct smt_header *) ; - sm->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ; - sm->smt_sid = smc->mib.fddiSMTStationId ; - - smt_swap_para(sm,(int) mb->sm_len,0) ; /* swap para & header */ - hwm_conv_can(smc,(char *)sm,12) ; /* convert SA and DA */ - smc->mib.m[MAC0].fddiMACSMTTransmit_Ct++ ; - smt_send_mbuf(smc,mb,local ? FC_SMT_LOC : fc) ; -} - -/* - * generate and send RDF - */ -static void smt_send_rdf(struct s_smc *smc, SMbuf *rej, int fc, int reason, - int local) -/* SMbuf *rej; mbuf of offending frame */ -/* int fc; FC of denied frame */ -/* int reason; reason code */ -{ - SMbuf *mb ; - struct smt_header *sm ; /* header of offending frame */ - struct smt_rdf *rdf ; - int len ; - int frame_len ; - - sm = smtod(rej,struct smt_header *) ; - if (sm->smt_type != SMT_REQUEST) - return ; - - DB_SMT("SMT: sending RDF to %s,reason = 0x%x\n", - addr_to_string(&sm->smt_source),reason) ; - - - /* - * note: get framelength from MAC length, NOT from SMT header - * smt header length is included in sm_len - */ - frame_len = rej->sm_len ; - - if (!(mb=smt_build_frame(smc,SMT_RDF,SMT_REPLY,sizeof(struct smt_rdf)))) - return ; - rdf = smtod(mb,struct smt_rdf *) ; - rdf->smt.smt_tid = sm->smt_tid ; /* use TID from sm */ - rdf->smt.smt_dest = sm->smt_source ; /* set dest = source */ - - /* set P12 */ - rdf->reason.para.p_type = SMT_P_REASON ; - rdf->reason.para.p_len = sizeof(struct smt_p_reason) - PARA_LEN ; - rdf->reason.rdf_reason = reason ; - - /* set P14 */ - rdf->version.para.p_type = SMT_P_VERSION ; - rdf->version.para.p_len = sizeof(struct smt_p_version) - PARA_LEN ; - rdf->version.v_pad = 0 ; - rdf->version.v_n = 1 ; - rdf->version.v_index = 1 ; - rdf->version.v_version[0] = SMT_VID_2 ; - rdf->version.v_pad2 = 0 ; - - /* set P13 */ - if ((unsigned) frame_len <= SMT_MAX_INFO_LEN - sizeof(*rdf) + - 2*sizeof(struct smt_header)) - len = frame_len ; - else - len = SMT_MAX_INFO_LEN - sizeof(*rdf) + - 2*sizeof(struct smt_header) ; - /* make length multiple of 4 */ - len &= ~3 ; - rdf->refused.para.p_type = SMT_P_REFUSED ; - /* length of para is smt_frame + ref_fc */ - rdf->refused.para.p_len = len + 4 ; - rdf->refused.ref_fc = fc ; - - /* swap it back */ - smt_swap_para(sm,frame_len,0) ; - - memcpy((char *) &rdf->refused.ref_header,(char *) sm,len) ; - - len -= sizeof(struct smt_header) ; - mb->sm_len += len ; - rdf->smt.smt_len += len ; - - dump_smt(smc,(struct smt_header *)rdf,"RDF") ; - smc->mib.priv.fddiPRIVRDF_Tx++ ; - smt_send_frame(smc,mb,FC_SMT_INFO,local) ; -} - -/* - * generate and send NIF - */ -static void smt_send_nif(struct s_smc *smc, const struct fddi_addr *dest, - int fc, u_long tid, int type, int local) -/* struct fddi_addr *dest; dest address */ -/* int fc; frame control */ -/* u_long tid; transaction id */ -/* int type; frame type */ -{ - struct smt_nif *nif ; - SMbuf *mb ; - - if (!(mb = smt_build_frame(smc,SMT_NIF,type,sizeof(struct smt_nif)))) - return ; - nif = smtod(mb, struct smt_nif *) ; - smt_fill_una(smc,&nif->una) ; /* set UNA */ - smt_fill_sde(smc,&nif->sde) ; /* set station descriptor */ - smt_fill_state(smc,&nif->state) ; /* set state information */ -#ifdef SMT6_10 - smt_fill_fsc(smc,&nif->fsc) ; /* set frame status cap. */ -#endif - nif->smt.smt_dest = *dest ; /* destination address */ - nif->smt.smt_tid = tid ; /* transaction ID */ - dump_smt(smc,(struct smt_header *)nif,"NIF") ; - smt_send_frame(smc,mb,fc,local) ; -} - -#ifdef DEBUG -/* - * send NIF request (test purpose) - */ -static void smt_send_nif_request(struct s_smc *smc, struct fddi_addr *dest) -{ - smc->sm.pend[SMT_TID_NIF_TEST] = smt_get_tid(smc) ; - smt_send_nif(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_NIF_TEST], - SMT_REQUEST,0) ; -} - -/* - * send ECF request (test purpose) - */ -static void smt_send_ecf_request(struct s_smc *smc, struct fddi_addr *dest, - int len) -{ - smc->sm.pend[SMT_TID_ECF] = smt_get_tid(smc) ; - smt_send_ecf(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_ECF], - SMT_REQUEST,len) ; -} -#endif - -/* - * echo test - */ -static void smt_echo_test(struct s_smc *smc, int dna) -{ - u_long tid ; - - smc->sm.pend[dna ? SMT_TID_ECF_DNA : SMT_TID_ECF_UNA] = - tid = smt_get_tid(smc) ; - smt_send_ecf(smc, dna ? - &smc->mib.m[MAC0].fddiMACDownstreamNbr : - &smc->mib.m[MAC0].fddiMACUpstreamNbr, - FC_SMT_INFO,tid, SMT_REQUEST, (SMT_TEST_ECHO_LEN & ~3)-8) ; -} - -/* - * generate and send ECF - */ -static void smt_send_ecf(struct s_smc *smc, struct fddi_addr *dest, int fc, - u_long tid, int type, int len) -/* struct fddi_addr *dest; dest address */ -/* int fc; frame control */ -/* u_long tid; transaction id */ -/* int type; frame type */ -/* int len; frame length */ -{ - struct smt_ecf *ecf ; - SMbuf *mb ; - - if (!(mb = smt_build_frame(smc,SMT_ECF,type,SMT_ECF_LEN + len))) - return ; - ecf = smtod(mb, struct smt_ecf *) ; - - smt_fill_echo(smc,&ecf->ec_echo,tid,len) ; /* set ECHO */ - ecf->smt.smt_dest = *dest ; /* destination address */ - ecf->smt.smt_tid = tid ; /* transaction ID */ - smc->mib.priv.fddiPRIVECF_Req_Tx++ ; - smt_send_frame(smc,mb,fc,0) ; -} - -/* - * generate and send SIF config response - */ - -static void smt_send_sif_config(struct s_smc *smc, struct fddi_addr *dest, - u_long tid, int local) -/* struct fddi_addr *dest; dest address */ -/* u_long tid; transaction id */ -{ - struct smt_sif_config *sif ; - SMbuf *mb ; - int len ; - if (!(mb = smt_build_frame(smc,SMT_SIF_CONFIG,SMT_REPLY, - SIZEOF_SMT_SIF_CONFIG))) - return ; - - sif = smtod(mb, struct smt_sif_config *) ; - smt_fill_timestamp(smc,&sif->ts) ; /* set time stamp */ - smt_fill_sde(smc,&sif->sde) ; /* set station descriptor */ - smt_fill_version(smc,&sif->version) ; /* set version information */ - smt_fill_state(smc,&sif->state) ; /* set state information */ - smt_fill_policy(smc,&sif->policy) ; /* set station policy */ - smt_fill_latency(smc,&sif->latency); /* set station latency */ - smt_fill_neighbor(smc,&sif->neighbor); /* set station neighbor */ - smt_fill_setcount(smc,&sif->setcount) ; /* set count */ - len = smt_fill_path(smc,&sif->path); /* set station path descriptor*/ - sif->smt.smt_dest = *dest ; /* destination address */ - sif->smt.smt_tid = tid ; /* transaction ID */ - smt_add_frame_len(mb,len) ; /* adjust length fields */ - dump_smt(smc,(struct smt_header *)sif,"SIF Configuration Reply") ; - smt_send_frame(smc,mb,FC_SMT_INFO,local) ; -} - -/* - * generate and send SIF operation response - */ - -static void smt_send_sif_operation(struct s_smc *smc, struct fddi_addr *dest, - u_long tid, int local) -/* struct fddi_addr *dest; dest address */ -/* u_long tid; transaction id */ -{ - struct smt_sif_operation *sif ; - SMbuf *mb ; - int ports ; - int i ; - - ports = NUMPHYS ; -#ifndef CONCENTRATOR - if (smc->s.sas == SMT_SAS) - ports = 1 ; -#endif - - if (!(mb = smt_build_frame(smc,SMT_SIF_OPER,SMT_REPLY, - SIZEOF_SMT_SIF_OPERATION+ports*sizeof(struct smt_p_lem)))) - return ; - sif = smtod(mb, struct smt_sif_operation *) ; - smt_fill_timestamp(smc,&sif->ts) ; /* set time stamp */ - smt_fill_mac_status(smc,&sif->status) ; /* set mac status */ - smt_fill_mac_counter(smc,&sif->mc) ; /* set mac counter field */ - smt_fill_mac_fnc(smc,&sif->fnc) ; /* set frame not copied counter */ - smt_fill_manufacturer(smc,&sif->man) ; /* set manufacturer field */ - smt_fill_user(smc,&sif->user) ; /* set user field */ - smt_fill_setcount(smc,&sif->setcount) ; /* set count */ - /* - * set link error mon information - */ - if (ports == 1) { - smt_fill_lem(smc,sif->lem,PS) ; - } - else { - for (i = 0 ; i < ports ; i++) { - smt_fill_lem(smc,&sif->lem[i],i) ; - } - } - - sif->smt.smt_dest = *dest ; /* destination address */ - sif->smt.smt_tid = tid ; /* transaction ID */ - dump_smt(smc,(struct smt_header *)sif,"SIF Operation Reply") ; - smt_send_frame(smc,mb,FC_SMT_INFO,local) ; -} - -/* - * get and initialize SMT frame - */ -SMbuf *smt_build_frame(struct s_smc *smc, int class, int type, - int length) -{ - SMbuf *mb ; - struct smt_header *smt ; - -#if 0 - if (!smc->r.sm_ma_avail) { - return 0; - } -#endif - if (!(mb = smt_get_mbuf(smc))) - return mb; - - mb->sm_len = length ; - smt = smtod(mb, struct smt_header *) ; - smt->smt_dest = fddi_broadcast ; /* set dest = broadcast */ - smt->smt_class = class ; - smt->smt_type = type ; - switch (class) { - case SMT_NIF : - case SMT_SIF_CONFIG : - case SMT_SIF_OPER : - case SMT_ECF : - smt->smt_version = SMT_VID ; - break ; - default : - smt->smt_version = SMT_VID_2 ; - break ; - } - smt->smt_tid = smt_get_tid(smc) ; /* set transaction ID */ - smt->smt_pad = 0 ; - smt->smt_len = length - sizeof(struct smt_header) ; - return mb; -} - -static void smt_add_frame_len(SMbuf *mb, int len) -{ - struct smt_header *smt ; - - smt = smtod(mb, struct smt_header *) ; - smt->smt_len += len ; - mb->sm_len += len ; -} - - - -/* - * fill values in UNA parameter - */ -static void smt_fill_una(struct s_smc *smc, struct smt_p_una *una) -{ - SMTSETPARA(una,SMT_P_UNA) ; - una->una_pad = 0 ; - una->una_node = smc->mib.m[MAC0].fddiMACUpstreamNbr ; -} - -/* - * fill values in SDE parameter - */ -static void smt_fill_sde(struct s_smc *smc, struct smt_p_sde *sde) -{ - SMTSETPARA(sde,SMT_P_SDE) ; - sde->sde_non_master = smc->mib.fddiSMTNonMaster_Ct ; - sde->sde_master = smc->mib.fddiSMTMaster_Ct ; - sde->sde_mac_count = NUMMACS ; /* only 1 MAC */ -#ifdef CONCENTRATOR - sde->sde_type = SMT_SDE_CONCENTRATOR ; -#else - sde->sde_type = SMT_SDE_STATION ; -#endif -} - -/* - * fill in values in station state parameter - */ -static void smt_fill_state(struct s_smc *smc, struct smt_p_state *state) -{ - int top ; - int twist ; - - SMTSETPARA(state,SMT_P_STATE) ; - state->st_pad = 0 ; - - /* determine topology */ - top = 0 ; - if (smc->mib.fddiSMTPeerWrapFlag) { - top |= SMT_ST_WRAPPED ; /* state wrapped */ - } -#ifdef CONCENTRATOR - if (cfm_status_unattached(smc)) { - top |= SMT_ST_UNATTACHED ; /* unattached concentrator */ - } -#endif - if ((twist = pcm_status_twisted(smc)) & 1) { - top |= SMT_ST_TWISTED_A ; /* twisted cable */ - } - if (twist & 2) { - top |= SMT_ST_TWISTED_B ; /* twisted cable */ - } -#ifdef OPT_SRF - top |= SMT_ST_SRF ; -#endif - if (pcm_rooted_station(smc)) - top |= SMT_ST_ROOTED_S ; - if (smc->mib.a[0].fddiPATHSbaPayload != 0) - top |= SMT_ST_SYNC_SERVICE ; - state->st_topology = top ; - state->st_dupl_addr = - ((smc->mib.m[MAC0].fddiMACDA_Flag ? SMT_ST_MY_DUPA : 0 ) | - (smc->mib.m[MAC0].fddiMACUNDA_Flag ? SMT_ST_UNA_DUPA : 0)) ; -} - -/* - * fill values in timestamp parameter - */ -static void smt_fill_timestamp(struct s_smc *smc, struct smt_p_timestamp *ts) -{ - - SMTSETPARA(ts,SMT_P_TIMESTAMP) ; - smt_set_timestamp(smc,ts->ts_time) ; -} - -void smt_set_timestamp(struct s_smc *smc, u_char *p) -{ - u_long time ; - u_long utime ; - - /* - * timestamp is 64 bits long ; resolution is 80 nS - * our clock resolution is 10mS - * 10mS/80ns = 125000 ~ 2^17 = 131072 - */ - utime = smt_get_time() ; - time = utime * 100 ; - time /= TICKS_PER_SECOND ; - p[0] = 0 ; - p[1] = (u_char)((time>>(8+8+8+8-1)) & 1) ; - p[2] = (u_char)(time>>(8+8+8-1)) ; - p[3] = (u_char)(time>>(8+8-1)) ; - p[4] = (u_char)(time>>(8-1)) ; - p[5] = (u_char)(time<<1) ; - p[6] = (u_char)(smc->sm.uniq_ticks>>8) ; - p[7] = (u_char)smc->sm.uniq_ticks ; - /* - * make sure we don't wrap: restart whenever the upper digits change - */ - if (utime != smc->sm.uniq_time) { - smc->sm.uniq_ticks = 0 ; - } - smc->sm.uniq_ticks++ ; - smc->sm.uniq_time = utime ; -} - -/* - * fill values in station policy parameter - */ -static void smt_fill_policy(struct s_smc *smc, struct smt_p_policy *policy) -{ - int i ; - const u_char *map ; - u_short in ; - u_short out ; - - /* - * MIB para 101b (fddiSMTConnectionPolicy) coding - * is different from 0005 coding - */ - static const u_char ansi_weirdness[16] = { - 0,7,5,3,8,1,6,4,9,10,2,11,12,13,14,15 - } ; - SMTSETPARA(policy,SMT_P_POLICY) ; - - out = 0 ; - in = smc->mib.fddiSMTConnectionPolicy ; - for (i = 0, map = ansi_weirdness ; i < 16 ; i++) { - if (in & 1) - out |= (1<<*map) ; - in >>= 1 ; - map++ ; - } - policy->pl_config = smc->mib.fddiSMTConfigPolicy ; - policy->pl_connect = out ; -} - -/* - * fill values in latency equivalent parameter - */ -static void smt_fill_latency(struct s_smc *smc, struct smt_p_latency *latency) -{ - SMTSETPARA(latency,SMT_P_LATENCY) ; - - latency->lt_phyout_idx1 = phy_index(smc,0) ; - latency->lt_latency1 = 10 ; /* in octets (byte clock) */ - /* - * note: latency has two phy entries by definition - * for a SAS, the 2nd one is null - */ - if (smc->s.sas == SMT_DAS) { - latency->lt_phyout_idx2 = phy_index(smc,1) ; - latency->lt_latency2 = 10 ; /* in octets (byte clock) */ - } - else { - latency->lt_phyout_idx2 = 0 ; - latency->lt_latency2 = 0 ; - } -} - -/* - * fill values in MAC neighbors parameter - */ -static void smt_fill_neighbor(struct s_smc *smc, struct smt_p_neighbor *neighbor) -{ - SMTSETPARA(neighbor,SMT_P_NEIGHBORS) ; - - neighbor->nb_mib_index = INDEX_MAC ; - neighbor->nb_mac_index = mac_index(smc,1) ; - neighbor->nb_una = smc->mib.m[MAC0].fddiMACUpstreamNbr ; - neighbor->nb_dna = smc->mib.m[MAC0].fddiMACDownstreamNbr ; -} - -/* - * fill values in path descriptor - */ -#ifdef CONCENTRATOR -#define ALLPHYS NUMPHYS -#else -#define ALLPHYS ((smc->s.sas == SMT_SAS) ? 1 : 2) -#endif - -static int smt_fill_path(struct s_smc *smc, struct smt_p_path *path) -{ - SK_LOC_DECL(int,type) ; - SK_LOC_DECL(int,state) ; - SK_LOC_DECL(int,remote) ; - SK_LOC_DECL(int,mac) ; - int len ; - int p ; - int physp ; - struct smt_phy_rec *phy ; - struct smt_mac_rec *pd_mac ; - - len = PARA_LEN + - sizeof(struct smt_mac_rec) * NUMMACS + - sizeof(struct smt_phy_rec) * ALLPHYS ; - path->para.p_type = SMT_P_PATH ; - path->para.p_len = len - PARA_LEN ; - - /* PHYs */ - for (p = 0,phy = path->pd_phy ; p < ALLPHYS ; p++, phy++) { - physp = p ; -#ifndef CONCENTRATOR - if (smc->s.sas == SMT_SAS) - physp = PS ; -#endif - pcm_status_state(smc,physp,&type,&state,&remote,&mac) ; -#ifdef LITTLE_ENDIAN - phy->phy_mib_index = smt_swap_short((u_short)p+INDEX_PORT) ; -#else - phy->phy_mib_index = p+INDEX_PORT ; -#endif - phy->phy_type = type ; - phy->phy_connect_state = state ; - phy->phy_remote_type = remote ; - phy->phy_remote_mac = mac ; - phy->phy_resource_idx = phy_con_resource_index(smc,p) ; - } - - /* MAC */ - pd_mac = (struct smt_mac_rec *) phy ; - pd_mac->mac_addr = smc->mib.m[MAC0].fddiMACSMTAddress ; - pd_mac->mac_resource_idx = mac_con_resource_index(smc,1) ; - return len; -} - -/* - * fill values in mac status - */ -static void smt_fill_mac_status(struct s_smc *smc, struct smt_p_mac_status *st) -{ - SMTSETPARA(st,SMT_P_MAC_STATUS) ; - - st->st_mib_index = INDEX_MAC ; - st->st_mac_index = mac_index(smc,1) ; - - mac_update_counter(smc) ; - /* - * timer values are represented in SMT as 2's complement numbers - * units : internal : 2's complement BCLK - */ - st->st_t_req = smc->mib.m[MAC0].fddiMACT_Req ; - st->st_t_neg = smc->mib.m[MAC0].fddiMACT_Neg ; - st->st_t_max = smc->mib.m[MAC0].fddiMACT_Max ; - st->st_tvx_value = smc->mib.m[MAC0].fddiMACTvxValue ; - st->st_t_min = smc->mib.m[MAC0].fddiMACT_Min ; - - st->st_sba = smc->mib.a[PATH0].fddiPATHSbaPayload ; - st->st_frame_ct = smc->mib.m[MAC0].fddiMACFrame_Ct ; - st->st_error_ct = smc->mib.m[MAC0].fddiMACError_Ct ; - st->st_lost_ct = smc->mib.m[MAC0].fddiMACLost_Ct ; -} - -/* - * fill values in LEM status - */ -static void smt_fill_lem(struct s_smc *smc, struct smt_p_lem *lem, int phy) -{ - struct fddi_mib_p *mib ; - - mib = smc->y[phy].mib ; - - SMTSETPARA(lem,SMT_P_LEM) ; - lem->lem_mib_index = phy+INDEX_PORT ; - lem->lem_phy_index = phy_index(smc,phy) ; - lem->lem_pad2 = 0 ; - lem->lem_cutoff = mib->fddiPORTLer_Cutoff ; - lem->lem_alarm = mib->fddiPORTLer_Alarm ; - /* long term bit error rate */ - lem->lem_estimate = mib->fddiPORTLer_Estimate ; - /* # of rejected connections */ - lem->lem_reject_ct = mib->fddiPORTLem_Reject_Ct ; - lem->lem_ct = mib->fddiPORTLem_Ct ; /* total number of errors */ -} - -/* - * fill version parameter - */ -static void smt_fill_version(struct s_smc *smc, struct smt_p_version *vers) -{ - SK_UNUSED(smc) ; - SMTSETPARA(vers,SMT_P_VERSION) ; - vers->v_pad = 0 ; - vers->v_n = 1 ; /* one version is enough .. */ - vers->v_index = 1 ; - vers->v_version[0] = SMT_VID_2 ; - vers->v_pad2 = 0 ; -} - -#ifdef SMT6_10 -/* - * fill frame status capabilities - */ -/* - * note: this para 200B is NOT in swap table, because it's also set in - * PMF add_para - */ -static void smt_fill_fsc(struct s_smc *smc, struct smt_p_fsc *fsc) -{ - SK_UNUSED(smc) ; - SMTSETPARA(fsc,SMT_P_FSC) ; - fsc->fsc_pad0 = 0 ; - fsc->fsc_mac_index = INDEX_MAC ; /* this is MIB ; MIB is NOT - * mac_index ()i ! - */ - fsc->fsc_pad1 = 0 ; - fsc->fsc_value = FSC_TYPE0 ; /* "normal" node */ -#ifdef LITTLE_ENDIAN - fsc->fsc_mac_index = smt_swap_short(INDEX_MAC) ; - fsc->fsc_value = smt_swap_short(FSC_TYPE0) ; -#endif -} -#endif - -/* - * fill mac counter field - */ -static void smt_fill_mac_counter(struct s_smc *smc, struct smt_p_mac_counter *mc) -{ - SMTSETPARA(mc,SMT_P_MAC_COUNTER) ; - mc->mc_mib_index = INDEX_MAC ; - mc->mc_index = mac_index(smc,1) ; - mc->mc_receive_ct = smc->mib.m[MAC0].fddiMACCopied_Ct ; - mc->mc_transmit_ct = smc->mib.m[MAC0].fddiMACTransmit_Ct ; -} - -/* - * fill mac frame not copied counter - */ -static void smt_fill_mac_fnc(struct s_smc *smc, struct smt_p_mac_fnc *fnc) -{ - SMTSETPARA(fnc,SMT_P_MAC_FNC) ; - fnc->nc_mib_index = INDEX_MAC ; - fnc->nc_index = mac_index(smc,1) ; - fnc->nc_counter = smc->mib.m[MAC0].fddiMACNotCopied_Ct ; -} - - -/* - * fill manufacturer field - */ -static void smt_fill_manufacturer(struct s_smc *smc, - struct smp_p_manufacturer *man) -{ - SMTSETPARA(man,SMT_P_MANUFACTURER) ; - memcpy((char *) man->mf_data, - (char *) smc->mib.fddiSMTManufacturerData, - sizeof(man->mf_data)) ; -} - -/* - * fill user field - */ -static void smt_fill_user(struct s_smc *smc, struct smp_p_user *user) -{ - SMTSETPARA(user,SMT_P_USER) ; - memcpy((char *) user->us_data, - (char *) smc->mib.fddiSMTUserData, - sizeof(user->us_data)) ; -} - -/* - * fill set count - */ -static void smt_fill_setcount(struct s_smc *smc, struct smt_p_setcount *setcount) -{ - SK_UNUSED(smc) ; - SMTSETPARA(setcount,SMT_P_SETCOUNT) ; - setcount->count = smc->mib.fddiSMTSetCount.count ; - memcpy((char *)setcount->timestamp, - (char *)smc->mib.fddiSMTSetCount.timestamp,8) ; -} - -/* - * fill echo data - */ -static void smt_fill_echo(struct s_smc *smc, struct smt_p_echo *echo, u_long seed, - int len) -{ - u_char *p ; - - SK_UNUSED(smc) ; - SMTSETPARA(echo,SMT_P_ECHODATA) ; - echo->para.p_len = len ; - for (p = echo->ec_data ; len ; len--) { - *p++ = (u_char) seed ; - seed += 13 ; - } -} - -/* - * clear DNA and UNA - * called from CFM if configuration changes - */ -static void smt_clear_una_dna(struct s_smc *smc) -{ - smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ; - smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ; -} - -static void smt_clear_old_una_dna(struct s_smc *smc) -{ - smc->mib.m[MAC0].fddiMACOldUpstreamNbr = SMT_Unknown ; - smc->mib.m[MAC0].fddiMACOldDownstreamNbr = SMT_Unknown ; -} - -u_long smt_get_tid(struct s_smc *smc) -{ - u_long tid ; - while ((tid = ++(smc->sm.smt_tid) ^ SMT_TID_MAGIC) == 0) - ; - return tid & 0x3fffffffL; -} - - -/* - * table of parameter lengths - */ -static const struct smt_pdef { - int ptype ; - int plen ; - const char *pswap ; -} smt_pdef[] = { - { SMT_P_UNA, sizeof(struct smt_p_una) , - SWAP_SMT_P_UNA } , - { SMT_P_SDE, sizeof(struct smt_p_sde) , - SWAP_SMT_P_SDE } , - { SMT_P_STATE, sizeof(struct smt_p_state) , - SWAP_SMT_P_STATE } , - { SMT_P_TIMESTAMP,sizeof(struct smt_p_timestamp) , - SWAP_SMT_P_TIMESTAMP } , - { SMT_P_POLICY, sizeof(struct smt_p_policy) , - SWAP_SMT_P_POLICY } , - { SMT_P_LATENCY, sizeof(struct smt_p_latency) , - SWAP_SMT_P_LATENCY } , - { SMT_P_NEIGHBORS,sizeof(struct smt_p_neighbor) , - SWAP_SMT_P_NEIGHBORS } , - { SMT_P_PATH, sizeof(struct smt_p_path) , - SWAP_SMT_P_PATH } , - { SMT_P_MAC_STATUS,sizeof(struct smt_p_mac_status) , - SWAP_SMT_P_MAC_STATUS } , - { SMT_P_LEM, sizeof(struct smt_p_lem) , - SWAP_SMT_P_LEM } , - { SMT_P_MAC_COUNTER,sizeof(struct smt_p_mac_counter) , - SWAP_SMT_P_MAC_COUNTER } , - { SMT_P_MAC_FNC,sizeof(struct smt_p_mac_fnc) , - SWAP_SMT_P_MAC_FNC } , - { SMT_P_PRIORITY,sizeof(struct smt_p_priority) , - SWAP_SMT_P_PRIORITY } , - { SMT_P_EB,sizeof(struct smt_p_eb) , - SWAP_SMT_P_EB } , - { SMT_P_MANUFACTURER,sizeof(struct smp_p_manufacturer) , - SWAP_SMT_P_MANUFACTURER } , - { SMT_P_REASON, sizeof(struct smt_p_reason) , - SWAP_SMT_P_REASON } , - { SMT_P_REFUSED, sizeof(struct smt_p_refused) , - SWAP_SMT_P_REFUSED } , - { SMT_P_VERSION, sizeof(struct smt_p_version) , - SWAP_SMT_P_VERSION } , -#ifdef ESS - { SMT_P0015, sizeof(struct smt_p_0015) , SWAP_SMT_P0015 } , - { SMT_P0016, sizeof(struct smt_p_0016) , SWAP_SMT_P0016 } , - { SMT_P0017, sizeof(struct smt_p_0017) , SWAP_SMT_P0017 } , - { SMT_P0018, sizeof(struct smt_p_0018) , SWAP_SMT_P0018 } , - { SMT_P0019, sizeof(struct smt_p_0019) , SWAP_SMT_P0019 } , - { SMT_P001A, sizeof(struct smt_p_001a) , SWAP_SMT_P001A } , - { SMT_P001B, sizeof(struct smt_p_001b) , SWAP_SMT_P001B } , - { SMT_P001C, sizeof(struct smt_p_001c) , SWAP_SMT_P001C } , - { SMT_P001D, sizeof(struct smt_p_001d) , SWAP_SMT_P001D } , -#endif -#if 0 - { SMT_P_FSC, sizeof(struct smt_p_fsc) , - SWAP_SMT_P_FSC } , -#endif - - { SMT_P_SETCOUNT,0, SWAP_SMT_P_SETCOUNT } , - { SMT_P1048, 0, SWAP_SMT_P1048 } , - { SMT_P208C, 0, SWAP_SMT_P208C } , - { SMT_P208D, 0, SWAP_SMT_P208D } , - { SMT_P208E, 0, SWAP_SMT_P208E } , - { SMT_P208F, 0, SWAP_SMT_P208F } , - { SMT_P2090, 0, SWAP_SMT_P2090 } , -#ifdef ESS - { SMT_P320B, sizeof(struct smt_p_320b) , SWAP_SMT_P320B } , - { SMT_P320F, sizeof(struct smt_p_320f) , SWAP_SMT_P320F } , - { SMT_P3210, sizeof(struct smt_p_3210) , SWAP_SMT_P3210 } , -#endif - { SMT_P4050, 0, SWAP_SMT_P4050 } , - { SMT_P4051, 0, SWAP_SMT_P4051 } , - { SMT_P4052, 0, SWAP_SMT_P4052 } , - { SMT_P4053, 0, SWAP_SMT_P4053 } , -} ; - -#define N_SMT_PLEN ARRAY_SIZE(smt_pdef) - -int smt_check_para(struct s_smc *smc, struct smt_header *sm, - const u_short list[]) -{ - const u_short *p = list ; - while (*p) { - if (!sm_to_para(smc,sm,(int) *p)) { - DB_SMT("SMT: smt_check_para - missing para %x\n",*p,0); - return -1; - } - p++ ; - } - return 0; -} - -void *sm_to_para(struct s_smc *smc, struct smt_header *sm, int para) -{ - char *p ; - int len ; - int plen ; - void *found = NULL; - - SK_UNUSED(smc) ; - - len = sm->smt_len ; - p = (char *)(sm+1) ; /* pointer to info */ - while (len > 0 ) { - if (((struct smt_para *)p)->p_type == para) - found = (void *) p ; - plen = ((struct smt_para *)p)->p_len + PARA_LEN ; - p += plen ; - len -= plen ; - if (len < 0) { - DB_SMT("SMT : sm_to_para - length error %d\n",plen,0) ; - return NULL; - } - if ((plen & 3) && (para != SMT_P_ECHODATA)) { - DB_SMT("SMT : sm_to_para - odd length %d\n",plen,0) ; - return NULL; - } - if (found) - return found; - } - return NULL; -} - -#if 0 -/* - * send ANTC data test frame - */ -void fddi_send_antc(struct s_smc *smc, struct fddi_addr *dest) -{ - SK_UNUSED(smc) ; - SK_UNUSED(dest) ; -#if 0 - SMbuf *mb ; - struct smt_header *smt ; - int i ; - char *p ; - - mb = smt_get_mbuf() ; - mb->sm_len = 3000+12 ; - p = smtod(mb, char *) + 12 ; - for (i = 0 ; i < 3000 ; i++) - *p++ = 1 << (i&7) ; - - smt = smtod(mb, struct smt_header *) ; - smt->smt_dest = *dest ; - smt->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ; - smt_send_mbuf(smc,mb,FC_ASYNC_LLC) ; -#endif -} -#endif - -#ifdef DEBUG -char *addr_to_string(struct fddi_addr *addr) -{ - int i ; - static char string[6*3] = "****" ; - - for (i = 0 ; i < 6 ; i++) { - string[i * 3] = hex_asc_hi(addr->a[i]); - string[i * 3 + 1] = hex_asc_lo(addr->a[i]); - string[i * 3 + 2] = ':'; - } - string[5 * 3 + 2] = 0; - return string; -} -#endif - -#ifdef AM29K -int smt_ifconfig(int argc, char *argv[]) -{ - if (argc >= 2 && !strcmp(argv[0],"opt_bypass") && - !strcmp(argv[1],"yes")) { - smc->mib.fddiSMTBypassPresent = 1 ; - return 0; - } - return amdfddi_config(0, argc, argv); -} -#endif - -/* - * return static mac index - */ -static int mac_index(struct s_smc *smc, int mac) -{ - SK_UNUSED(mac) ; -#ifdef CONCENTRATOR - SK_UNUSED(smc) ; - return NUMPHYS + 1; -#else - return (smc->s.sas == SMT_SAS) ? 2 : 3; -#endif -} - -/* - * return static phy index - */ -static int phy_index(struct s_smc *smc, int phy) -{ - SK_UNUSED(smc) ; - return phy + 1; -} - -/* - * return dynamic mac connection resource index - */ -static int mac_con_resource_index(struct s_smc *smc, int mac) -{ -#ifdef CONCENTRATOR - SK_UNUSED(smc) ; - SK_UNUSED(mac) ; - return entity_to_index(smc, cem_get_downstream(smc, ENTITY_MAC)); -#else - SK_UNUSED(mac) ; - switch (smc->mib.fddiSMTCF_State) { - case SC9_C_WRAP_A : - case SC5_THRU_B : - case SC11_C_WRAP_S : - return 1; - case SC10_C_WRAP_B : - case SC4_THRU_A : - return 2; - } - return smc->s.sas == SMT_SAS ? 2 : 3; -#endif -} - -/* - * return dynamic phy connection resource index - */ -static int phy_con_resource_index(struct s_smc *smc, int phy) -{ -#ifdef CONCENTRATOR - return entity_to_index(smc, cem_get_downstream(smc, ENTITY_PHY(phy))) ; -#else - switch (smc->mib.fddiSMTCF_State) { - case SC9_C_WRAP_A : - return phy == PA ? 3 : 2; - case SC10_C_WRAP_B : - return phy == PA ? 1 : 3; - case SC4_THRU_A : - return phy == PA ? 3 : 1; - case SC5_THRU_B : - return phy == PA ? 2 : 3; - case SC11_C_WRAP_S : - return 2; - } - return phy; -#endif -} - -#ifdef CONCENTRATOR -static int entity_to_index(struct s_smc *smc, int e) -{ - if (e == ENTITY_MAC) - return mac_index(smc, 1); - else - return phy_index(smc, e - ENTITY_PHY(0)); -} -#endif - -#ifdef LITTLE_ENDIAN -static int smt_swap_short(u_short s) -{ - return ((s>>8)&0xff) | ((s&0xff)<<8); -} - -void smt_swap_para(struct smt_header *sm, int len, int direction) -/* int direction; 0 encode 1 decode */ -{ - struct smt_para *pa ; - const struct smt_pdef *pd ; - char *p ; - int plen ; - int type ; - int i ; - -/* printf("smt_swap_para sm %x len %d dir %d\n", - sm,len,direction) ; - */ - smt_string_swap((char *)sm,SWAP_SMTHEADER,len) ; - - /* swap args */ - len -= sizeof(struct smt_header) ; - - p = (char *) (sm + 1) ; - while (len > 0) { - pa = (struct smt_para *) p ; - plen = pa->p_len ; - type = pa->p_type ; - pa->p_type = smt_swap_short(pa->p_type) ; - pa->p_len = smt_swap_short(pa->p_len) ; - if (direction) { - plen = pa->p_len ; - type = pa->p_type ; - } - /* - * note: paras can have 0 length ! - */ - if (plen < 0) - break ; - plen += PARA_LEN ; - for (i = N_SMT_PLEN, pd = smt_pdef; i ; i--,pd++) { - if (pd->ptype == type) - break ; - } - if (i && pd->pswap) { - smt_string_swap(p+PARA_LEN,pd->pswap,len) ; - } - len -= plen ; - p += plen ; - } -} - -static void smt_string_swap(char *data, const char *format, int len) -{ - const char *open_paren = NULL ; - int x ; - - while (len > 0 && *format) { - switch (*format) { - case '[' : - open_paren = format ; - break ; - case ']' : - format = open_paren ; - break ; - case '1' : - case '2' : - case '3' : - case '4' : - case '5' : - case '6' : - case '7' : - case '8' : - case '9' : - data += *format - '0' ; - len -= *format - '0' ; - break ; - case 'c': - data++ ; - len-- ; - break ; - case 's' : - x = data[0] ; - data[0] = data[1] ; - data[1] = x ; - data += 2 ; - len -= 2 ; - break ; - case 'l' : - x = data[0] ; - data[0] = data[3] ; - data[3] = x ; - x = data[1] ; - data[1] = data[2] ; - data[2] = x ; - data += 4 ; - len -= 4 ; - break ; - } - format++ ; - } -} -#else -void smt_swap_para(struct smt_header *sm, int len, int direction) -/* int direction; 0 encode 1 decode */ -{ - SK_UNUSED(sm) ; - SK_UNUSED(len) ; - SK_UNUSED(direction) ; -} -#endif - -/* - * PMF actions - */ -int smt_action(struct s_smc *smc, int class, int code, int index) -{ - int event ; - int port ; - DB_SMT("SMT: action %d code %d\n",class,code) ; - switch(class) { - case SMT_STATION_ACTION : - switch(code) { - case SMT_STATION_ACTION_CONNECT : - smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ; - queue_event(smc,EVENT_ECM,EC_CONNECT) ; - break ; - case SMT_STATION_ACTION_DISCONNECT : - queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; - smc->mib.fddiSMTRemoteDisconnectFlag = TRUE ; - RS_SET(smc,RS_DISCONNECT) ; - AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) - FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_DISCONNECT, - smt_get_event_word(smc)); - break ; - case SMT_STATION_ACTION_PATHTEST : - AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) - FDDI_SMT_EVENT, (u_long) FDDI_PATH_TEST, - smt_get_event_word(smc)); - break ; - case SMT_STATION_ACTION_SELFTEST : - AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) - FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_SELF_TEST, - smt_get_event_word(smc)); - break ; - case SMT_STATION_ACTION_DISABLE_A : - if (smc->y[PA].pc_mode == PM_PEER) { - RS_SET(smc,RS_EVENT) ; - queue_event(smc,EVENT_PCM+PA,PC_DISABLE) ; - } - break ; - case SMT_STATION_ACTION_DISABLE_B : - if (smc->y[PB].pc_mode == PM_PEER) { - RS_SET(smc,RS_EVENT) ; - queue_event(smc,EVENT_PCM+PB,PC_DISABLE) ; - } - break ; - case SMT_STATION_ACTION_DISABLE_M : - for (port = 0 ; port < NUMPHYS ; port++) { - if (smc->mib.p[port].fddiPORTMy_Type != TM) - continue ; - RS_SET(smc,RS_EVENT) ; - queue_event(smc,EVENT_PCM+port,PC_DISABLE) ; - } - break ; - default : - return 1; - } - break ; - case SMT_PORT_ACTION : - switch(code) { - case SMT_PORT_ACTION_ENABLE : - event = PC_ENABLE ; - break ; - case SMT_PORT_ACTION_DISABLE : - event = PC_DISABLE ; - break ; - case SMT_PORT_ACTION_MAINT : - event = PC_MAINT ; - break ; - case SMT_PORT_ACTION_START : - event = PC_START ; - break ; - case SMT_PORT_ACTION_STOP : - event = PC_STOP ; - break ; - default : - return 1; - } - queue_event(smc,EVENT_PCM+index,event) ; - break ; - default : - return 1; - } - return 0; -} - -/* - * canonical conversion of bytes beginning form *data - */ -#ifdef USE_CAN_ADDR -static void hwm_conv_can(struct s_smc *smc, char *data, int len) -{ - int i ; - - SK_UNUSED(smc) ; - - for (i = len; i ; i--, data++) - *data = bitrev8(*data); -} -#endif - -#endif /* no SLIM_SMT */ - diff --git a/drivers/net/skfp/smtdef.c b/drivers/net/skfp/smtdef.c deleted file mode 100644 index 1acab0b..0000000 --- a/drivers/net/skfp/smtdef.c +++ /dev/null @@ -1,355 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - SMT/CMT defaults -*/ - -#include "h/types.h" -#include "h/fddi.h" -#include "h/smc.h" - -#ifndef OEM_USER_DATA -#define OEM_USER_DATA "SK-NET FDDI V2.0 Userdata" -#endif - -#ifndef lint -static const char ID_sccs[] = "@(#)smtdef.c 2.53 99/08/11 (C) SK " ; -#endif - -/* - * defaults - */ -#define TTMS(x) ((u_long)(x)*1000L) -#define TTS(x) ((u_long)(x)*1000000L) -#define TTUS(x) ((u_long)(x)) - -#define DEFAULT_TB_MIN TTMS(5) -#define DEFAULT_TB_MAX TTMS(50) -#define DEFAULT_C_MIN TTUS(1600) -#define DEFAULT_T_OUT TTMS(100+5) -#define DEFAULT_TL_MIN TTUS(30) -#define DEFAULT_LC_SHORT TTMS(50+5) -#define DEFAULT_LC_MEDIUM TTMS(500+20) -#define DEFAULT_LC_LONG TTS(5)+TTMS(50) -#define DEFAULT_LC_EXTENDED TTS(50)+TTMS(50) -#define DEFAULT_T_NEXT_9 TTMS(200+10) -#define DEFAULT_NS_MAX TTUS(1310) -#define DEFAULT_I_MAX TTMS(25) -#define DEFAULT_IN_MAX TTMS(40) -#define DEFAULT_TD_MIN TTMS(5) -#define DEFAULT_T_NON_OP TTS(1) -#define DEFAULT_T_STUCK TTS(8) -#define DEFAULT_T_DIRECT TTMS(370) -#define DEFAULT_T_JAM TTMS(370) -#define DEFAULT_T_ANNOUNCE TTMS(2500) -#define DEFAULT_D_MAX TTUS(1617) -#define DEFAULT_LEM_ALARM (8) -#define DEFAULT_LEM_CUTOFF (7) -#define DEFAULT_TEST_DONE TTS(1) -#define DEFAULT_CHECK_POLL TTS(1) -#define DEFAULT_POLL TTMS(50) - -/* - * LCT errors threshold - */ -#define DEFAULT_LCT_SHORT 1 -#define DEFAULT_LCT_MEDIUM 3 -#define DEFAULT_LCT_LONG 5 -#define DEFAULT_LCT_EXTEND 50 - -/* Forward declarations */ -void smt_reset_defaults(struct s_smc *smc, int level); -static void smt_init_mib(struct s_smc *smc, int level); -static int set_min_max(int maxflag, u_long mib, u_long limit, u_long *oper); - -#define MS2BCLK(x) ((x)*12500L) -#define US2BCLK(x) ((x)*1250L) - -void smt_reset_defaults(struct s_smc *smc, int level) -{ - struct smt_config *smt ; - int i ; - u_long smt_boot_time; - - - smt_init_mib(smc,level) ; - - smc->os.smc_version = SMC_VERSION ; - smt_boot_time = smt_get_time(); - for( i = 0; i < NUMMACS; i++ ) - smc->sm.last_tok_time[i] = smt_boot_time ; - smt = &smc->s ; - smt->attach_s = 0 ; - smt->build_ring_map = 1 ; - smt->sas = SMT_DAS ; - smt->numphys = NUMPHYS ; - smt->pcm_tb_min = DEFAULT_TB_MIN ; - smt->pcm_tb_max = DEFAULT_TB_MAX ; - smt->pcm_c_min = DEFAULT_C_MIN ; - smt->pcm_t_out = DEFAULT_T_OUT ; - smt->pcm_tl_min = DEFAULT_TL_MIN ; - smt->pcm_lc_short = DEFAULT_LC_SHORT ; - smt->pcm_lc_medium = DEFAULT_LC_MEDIUM ; - smt->pcm_lc_long = DEFAULT_LC_LONG ; - smt->pcm_lc_extended = DEFAULT_LC_EXTENDED ; - smt->pcm_t_next_9 = DEFAULT_T_NEXT_9 ; - smt->pcm_ns_max = DEFAULT_NS_MAX ; - smt->ecm_i_max = DEFAULT_I_MAX ; - smt->ecm_in_max = DEFAULT_IN_MAX ; - smt->ecm_td_min = DEFAULT_TD_MIN ; - smt->ecm_test_done = DEFAULT_TEST_DONE ; - smt->ecm_check_poll = DEFAULT_CHECK_POLL ; - smt->rmt_t_non_op = DEFAULT_T_NON_OP ; - smt->rmt_t_stuck = DEFAULT_T_STUCK ; - smt->rmt_t_direct = DEFAULT_T_DIRECT ; - smt->rmt_t_jam = DEFAULT_T_JAM ; - smt->rmt_t_announce = DEFAULT_T_ANNOUNCE ; - smt->rmt_t_poll = DEFAULT_POLL ; - smt->rmt_dup_mac_behavior = FALSE ; /* See Struct smt_config */ - smt->mac_d_max = DEFAULT_D_MAX ; - - smt->lct_short = DEFAULT_LCT_SHORT ; - smt->lct_medium = DEFAULT_LCT_MEDIUM ; - smt->lct_long = DEFAULT_LCT_LONG ; - smt->lct_extended = DEFAULT_LCT_EXTEND ; - -#ifndef SLIM_SMT -#ifdef ESS - if (level == 0) { - smc->ess.sync_bw_available = FALSE ; - smc->mib.fddiESSPayload = 0 ; - smc->mib.fddiESSOverhead = 0 ; - smc->mib.fddiESSMaxTNeg = (u_long)(- MS2BCLK(25)) ; - smc->mib.fddiESSMinSegmentSize = 1 ; - smc->mib.fddiESSCategory = SB_STATIC ; - smc->mib.fddiESSSynchTxMode = FALSE ; - smc->ess.raf_act_timer_poll = FALSE ; - smc->ess.timer_count = 7 ; /* first RAF alc req after 3s */ - } - smc->ess.local_sba_active = FALSE ; - smc->ess.sba_reply_pend = NULL ; -#endif -#ifdef SBA - smt_init_sba(smc,level) ; -#endif -#endif /* no SLIM_SMT */ -#ifdef TAG_MODE - if (level == 0) { - smc->hw.pci_fix_value = 0 ; - } -#endif -} - -/* - * manufacturer data - */ -static const char man_data[32] = -/* 01234567890123456789012345678901 */ - "xxxSK-NET FDDI SMT 7.3 - V2.8.8" ; - -static void smt_init_mib(struct s_smc *smc, int level) -{ - struct fddi_mib *mib ; - struct fddi_mib_p *pm ; - int port ; - int path ; - - mib = &smc->mib ; - if (level == 0) { - /* - * set EVERYTHING to ZERO - * EXCEPT hw and os - */ - memset(((char *)smc)+ - sizeof(struct s_smt_os)+sizeof(struct s_smt_hw), 0, - sizeof(struct s_smc) - - sizeof(struct s_smt_os) - sizeof(struct s_smt_hw)) ; - } - else { - mib->fddiSMTRemoteDisconnectFlag = 0 ; - mib->fddiSMTPeerWrapFlag = 0 ; - } - - mib->fddiSMTOpVersionId = 2 ; - mib->fddiSMTHiVersionId = 2 ; - mib->fddiSMTLoVersionId = 2 ; - memcpy((char *) mib->fddiSMTManufacturerData,man_data,32) ; - if (level == 0) { - strcpy(mib->fddiSMTUserData,OEM_USER_DATA) ; - } - mib->fddiSMTMIBVersionId = 1 ; - mib->fddiSMTMac_Ct = NUMMACS ; - mib->fddiSMTConnectionPolicy = POLICY_MM | POLICY_AA | POLICY_BB ; - - /* - * fddiSMTNonMaster_Ct and fddiSMTMaster_Ct are set in smt_fixup_mib - * s.sas is not set yet (is set in init driver) - */ - mib->fddiSMTAvailablePaths = MIB_PATH_P | MIB_PATH_S ; - - mib->fddiSMTConfigCapabilities = 0 ; /* no hold,no wrap_ab*/ - mib->fddiSMTTT_Notify = 10 ; - mib->fddiSMTStatRptPolicy = TRUE ; - mib->fddiSMTTrace_MaxExpiration = SEC2MIB(7) ; - mib->fddiSMTMACIndexes = INDEX_MAC ; - mib->fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ; /* separated */ - - mib->m[MAC0].fddiMACIndex = INDEX_MAC ; - mib->m[MAC0].fddiMACFrameStatusFunctions = FSC_TYPE0 ; - mib->m[MAC0].fddiMACRequestedPaths = - MIB_P_PATH_LOCAL | - MIB_P_PATH_SEC_ALTER | - MIB_P_PATH_PRIM_ALTER ; - mib->m[MAC0].fddiMACAvailablePaths = MIB_PATH_P ; - mib->m[MAC0].fddiMACCurrentPath = MIB_PATH_PRIMARY ; - mib->m[MAC0].fddiMACT_MaxCapabilitiy = (u_long)(- MS2BCLK(165)) ; - mib->m[MAC0].fddiMACTVXCapabilitiy = (u_long)(- US2BCLK(52)) ; - if (level == 0) { - mib->m[MAC0].fddiMACTvxValue = (u_long)(- US2BCLK(27)) ; - mib->m[MAC0].fddiMACTvxValueMIB = (u_long)(- US2BCLK(27)) ; - mib->m[MAC0].fddiMACT_Req = (u_long)(- MS2BCLK(165)) ; - mib->m[MAC0].fddiMACT_ReqMIB = (u_long)(- MS2BCLK(165)) ; - mib->m[MAC0].fddiMACT_Max = (u_long)(- MS2BCLK(165)) ; - mib->m[MAC0].fddiMACT_MaxMIB = (u_long)(- MS2BCLK(165)) ; - mib->m[MAC0].fddiMACT_Min = (u_long)(- MS2BCLK(4)) ; - } - mib->m[MAC0].fddiMACHardwarePresent = TRUE ; - mib->m[MAC0].fddiMACMA_UnitdataEnable = TRUE ; - mib->m[MAC0].fddiMACFrameErrorThreshold = 1 ; - mib->m[MAC0].fddiMACNotCopiedThreshold = 1 ; - /* - * Path attributes - */ - for (path = 0 ; path < NUMPATHS ; path++) { - mib->a[path].fddiPATHIndex = INDEX_PATH + path ; - if (level == 0) { - mib->a[path].fddiPATHTVXLowerBound = - (u_long)(- US2BCLK(27)) ; - mib->a[path].fddiPATHT_MaxLowerBound = - (u_long)(- MS2BCLK(165)) ; - mib->a[path].fddiPATHMaxT_Req = - (u_long)(- MS2BCLK(165)) ; - } - } - - - /* - * Port attributes - */ - pm = mib->p ; - for (port = 0 ; port < NUMPHYS ; port++) { - /* - * set MIB pointer in phy - */ - /* Attention: don't initialize mib pointer here! */ - /* It must be initialized during phase 2 */ - smc->y[port].mib = NULL; - mib->fddiSMTPORTIndexes[port] = port+INDEX_PORT ; - - pm->fddiPORTIndex = port+INDEX_PORT ; - pm->fddiPORTHardwarePresent = TRUE ; - if (level == 0) { - pm->fddiPORTLer_Alarm = DEFAULT_LEM_ALARM ; - pm->fddiPORTLer_Cutoff = DEFAULT_LEM_CUTOFF ; - } - /* - * fddiPORTRequestedPaths are set in pcmplc.c - * we don't know the port type yet ! - */ - pm->fddiPORTRequestedPaths[1] = 0 ; - pm->fddiPORTRequestedPaths[2] = 0 ; - pm->fddiPORTRequestedPaths[3] = 0 ; - pm->fddiPORTAvailablePaths = MIB_PATH_P ; - pm->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ; - pm++ ; - } - - (void) smt_set_mac_opvalues(smc) ; -} - -int smt_set_mac_opvalues(struct s_smc *smc) -{ - int st ; - int st2 ; - - st = set_min_max(1,smc->mib.m[MAC0].fddiMACTvxValueMIB, - smc->mib.a[PATH0].fddiPATHTVXLowerBound, - &smc->mib.m[MAC0].fddiMACTvxValue) ; - st |= set_min_max(0,smc->mib.m[MAC0].fddiMACT_MaxMIB, - smc->mib.a[PATH0].fddiPATHT_MaxLowerBound, - &smc->mib.m[MAC0].fddiMACT_Max) ; - st |= (st2 = set_min_max(0,smc->mib.m[MAC0].fddiMACT_ReqMIB, - smc->mib.a[PATH0].fddiPATHMaxT_Req, - &smc->mib.m[MAC0].fddiMACT_Req)) ; - if (st2) { - /* Treq attribute changed remotely. So send an AIX_EVENT to the - * user - */ - AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) - FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_T_REQ, - smt_get_event_word(smc)); - } - return st; -} - -void smt_fixup_mib(struct s_smc *smc) -{ -#ifdef CONCENTRATOR - switch (smc->s.sas) { - case SMT_SAS : - smc->mib.fddiSMTNonMaster_Ct = 1 ; - break ; - case SMT_DAS : - smc->mib.fddiSMTNonMaster_Ct = 2 ; - break ; - case SMT_NAC : - smc->mib.fddiSMTNonMaster_Ct = 0 ; - break ; - } - smc->mib.fddiSMTMaster_Ct = NUMPHYS - smc->mib.fddiSMTNonMaster_Ct ; -#else - switch (smc->s.sas) { - case SMT_SAS : - smc->mib.fddiSMTNonMaster_Ct = 1 ; - break ; - case SMT_DAS : - smc->mib.fddiSMTNonMaster_Ct = 2 ; - break ; - } - smc->mib.fddiSMTMaster_Ct = 0 ; -#endif -} - -/* - * determine new setting for operational value - * if limit is lower than mib - * use limit - * else - * use mib - * NOTE : numbers are negative, negate comparison ! - */ -static int set_min_max(int maxflag, u_long mib, u_long limit, u_long *oper) -{ - u_long old ; - old = *oper ; - if ((limit > mib) ^ maxflag) - *oper = limit ; - else - *oper = mib ; - return old != *oper; -} - diff --git a/drivers/net/skfp/smtinit.c b/drivers/net/skfp/smtinit.c deleted file mode 100644 index e3a0c0b..0000000 --- a/drivers/net/skfp/smtinit.c +++ /dev/null @@ -1,125 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - Init SMT - call all module level initialization routines -*/ - -#include "h/types.h" -#include "h/fddi.h" -#include "h/smc.h" - -#ifndef lint -static const char ID_sccs[] = "@(#)smtinit.c 1.15 97/05/06 (C) SK " ; -#endif - -void init_fddi_driver(struct s_smc *smc, u_char *mac_addr); - -/* define global debug variable */ -#if defined(DEBUG) && !defined(DEBUG_BRD) -struct smt_debug debug; -#endif - -#ifndef MULT_OEM -#define OEMID(smc,i) oem_id[i] - extern u_char oem_id[] ; -#else /* MULT_OEM */ -#define OEMID(smc,i) smc->hw.oem_id->oi_mark[i] - extern struct s_oem_ids oem_ids[] ; -#endif /* MULT_OEM */ - -/* - * Set OEM specific values - * - * Can not be called in smt_reset_defaults, because it is not sure that - * the OEM ID is already defined. - */ -static void set_oem_spec_val(struct s_smc *smc) -{ - struct fddi_mib *mib ; - - mib = &smc->mib ; - - /* - * set IBM specific values - */ - if (OEMID(smc,0) == 'I') { - mib->fddiSMTConnectionPolicy = POLICY_MM ; - } -} - -/* - * Init SMT - */ -int init_smt(struct s_smc *smc, u_char *mac_addr) -/* u_char *mac_addr; canonical address or NULL */ -{ - int p ; - -#if defined(DEBUG) && !defined(DEBUG_BRD) - debug.d_smt = 0 ; - debug.d_smtf = 0 ; - debug.d_rmt = 0 ; - debug.d_ecm = 0 ; - debug.d_pcm = 0 ; - debug.d_cfm = 0 ; - - debug.d_plc = 0 ; -#ifdef ESS - debug.d_ess = 0 ; -#endif -#ifdef SBA - debug.d_sba = 0 ; -#endif -#endif /* DEBUG && !DEBUG_BRD */ - - /* First initialize the ports mib->pointers */ - for ( p = 0; p < NUMPHYS; p ++ ) { - smc->y[p].mib = & smc->mib.p[p] ; - } - - set_oem_spec_val(smc) ; - (void) smt_set_mac_opvalues(smc) ; - init_fddi_driver(smc,mac_addr) ; /* HW driver */ - smt_fixup_mib(smc) ; /* update values that depend on s.sas */ - - ev_init(smc) ; /* event queue */ -#ifndef SLIM_SMT - smt_init_evc(smc) ; /* evcs in MIB */ -#endif /* no SLIM_SMT */ - smt_timer_init(smc) ; /* timer package */ - smt_agent_init(smc) ; /* SMT frame manager */ - - pcm_init(smc) ; /* PCM state machine */ - ecm_init(smc) ; /* ECM state machine */ - cfm_init(smc) ; /* CFM state machine */ - rmt_init(smc) ; /* RMT state machine */ - - for (p = 0 ; p < NUMPHYS ; p++) { - pcm(smc,p,0) ; /* PCM A state machine */ - } - ecm(smc,0) ; /* ECM state machine */ - cfm(smc,0) ; /* CFM state machine */ - rmt(smc,0) ; /* RMT state machine */ - - smt_agent_task(smc) ; /* NIF FSM etc */ - - PNMI_INIT(smc) ; /* PNMI initialization */ - - return 0; -} - diff --git a/drivers/net/skfp/smttimer.c b/drivers/net/skfp/smttimer.c deleted file mode 100644 index 531795e..0000000 --- a/drivers/net/skfp/smttimer.c +++ /dev/null @@ -1,156 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - SMT timer -*/ - -#include "h/types.h" -#include "h/fddi.h" -#include "h/smc.h" - -#ifndef lint -static const char ID_sccs[] = "@(#)smttimer.c 2.4 97/08/04 (C) SK " ; -#endif - -static void timer_done(struct s_smc *smc, int restart); - -void smt_timer_init(struct s_smc *smc) -{ - smc->t.st_queue = NULL; - smc->t.st_fast.tm_active = FALSE ; - smc->t.st_fast.tm_next = NULL; - hwt_init(smc) ; -} - -void smt_timer_stop(struct s_smc *smc, struct smt_timer *timer) -{ - struct smt_timer **prev ; - struct smt_timer *tm ; - - /* - * remove timer from queue - */ - timer->tm_active = FALSE ; - if (smc->t.st_queue == timer && !timer->tm_next) { - hwt_stop(smc) ; - } - for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) { - if (tm == timer) { - *prev = tm->tm_next ; - if (tm->tm_next) { - tm->tm_next->tm_delta += tm->tm_delta ; - } - return ; - } - } -} - -void smt_timer_start(struct s_smc *smc, struct smt_timer *timer, u_long time, - u_long token) -{ - struct smt_timer **prev ; - struct smt_timer *tm ; - u_long delta = 0 ; - - time /= 16 ; /* input is uS, clock ticks are 16uS */ - if (!time) - time = 1 ; - smt_timer_stop(smc,timer) ; - timer->tm_smc = smc ; - timer->tm_token = token ; - timer->tm_active = TRUE ; - if (!smc->t.st_queue) { - smc->t.st_queue = timer ; - timer->tm_next = NULL; - timer->tm_delta = time ; - hwt_start(smc,time) ; - return ; - } - /* - * timer correction - */ - timer_done(smc,0) ; - - /* - * find position in queue - */ - delta = 0 ; - for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) { - if (delta + tm->tm_delta > time) { - break ; - } - delta += tm->tm_delta ; - } - /* insert in queue */ - *prev = timer ; - timer->tm_next = tm ; - timer->tm_delta = time - delta ; - if (tm) - tm->tm_delta -= timer->tm_delta ; - /* - * start new with first - */ - hwt_start(smc,smc->t.st_queue->tm_delta) ; -} - -void smt_force_irq(struct s_smc *smc) -{ - smt_timer_start(smc,&smc->t.st_fast,32L, EV_TOKEN(EVENT_SMT,SM_FAST)); -} - -void smt_timer_done(struct s_smc *smc) -{ - timer_done(smc,1) ; -} - -static void timer_done(struct s_smc *smc, int restart) -{ - u_long delta ; - struct smt_timer *tm ; - struct smt_timer *next ; - struct smt_timer **last ; - int done = 0 ; - - delta = hwt_read(smc) ; - last = &smc->t.st_queue ; - tm = smc->t.st_queue ; - while (tm && !done) { - if (delta >= tm->tm_delta) { - tm->tm_active = FALSE ; - delta -= tm->tm_delta ; - last = &tm->tm_next ; - tm = tm->tm_next ; - } - else { - tm->tm_delta -= delta ; - delta = 0 ; - done = 1 ; - } - } - *last = NULL; - next = smc->t.st_queue ; - smc->t.st_queue = tm ; - - for ( tm = next ; tm ; tm = next) { - next = tm->tm_next ; - timer_event(smc,tm->tm_token) ; - } - - if (restart && smc->t.st_queue) - hwt_start(smc,smc->t.st_queue->tm_delta) ; -} - diff --git a/drivers/net/skfp/srf.c b/drivers/net/skfp/srf.c deleted file mode 100644 index f6f7baf..0000000 --- a/drivers/net/skfp/srf.c +++ /dev/null @@ -1,429 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -/* - SMT 7.2 Status Response Frame Implementation - SRF state machine and frame generation -*/ - -#include "h/types.h" -#include "h/fddi.h" -#include "h/smc.h" -#include "h/smt_p.h" - -#define KERNEL -#include "h/smtstate.h" - -#ifndef SLIM_SMT -#ifndef BOOT - -#ifndef lint -static const char ID_sccs[] = "@(#)srf.c 1.18 97/08/04 (C) SK " ; -#endif - - -/* - * function declarations - */ -static void clear_all_rep(struct s_smc *smc); -static void clear_reported(struct s_smc *smc); -static void smt_send_srf(struct s_smc *smc); -static struct s_srf_evc *smt_get_evc(struct s_smc *smc, int code, int index); - -#define MAX_EVCS ARRAY_SIZE(smc->evcs) - -struct evc_init { - u_char code ; - u_char index ; - u_char n ; - u_short para ; -} ; - -static const struct evc_init evc_inits[] = { - { SMT_COND_SMT_PEER_WRAP, 0,1,SMT_P1048 } , - - { SMT_COND_MAC_DUP_ADDR, INDEX_MAC, NUMMACS,SMT_P208C } , - { SMT_COND_MAC_FRAME_ERROR, INDEX_MAC, NUMMACS,SMT_P208D } , - { SMT_COND_MAC_NOT_COPIED, INDEX_MAC, NUMMACS,SMT_P208E } , - { SMT_EVENT_MAC_NEIGHBOR_CHANGE, INDEX_MAC, NUMMACS,SMT_P208F } , - { SMT_EVENT_MAC_PATH_CHANGE, INDEX_MAC, NUMMACS,SMT_P2090 } , - - { SMT_COND_PORT_LER, INDEX_PORT,NUMPHYS,SMT_P4050 } , - { SMT_COND_PORT_EB_ERROR, INDEX_PORT,NUMPHYS,SMT_P4052 } , - { SMT_EVENT_PORT_CONNECTION, INDEX_PORT,NUMPHYS,SMT_P4051 } , - { SMT_EVENT_PORT_PATH_CHANGE, INDEX_PORT,NUMPHYS,SMT_P4053 } , -} ; - -#define MAX_INIT_EVC ARRAY_SIZE(evc_inits) - -void smt_init_evc(struct s_smc *smc) -{ - struct s_srf_evc *evc ; - const struct evc_init *init ; - int i ; - int index ; - int offset ; - - static u_char fail_safe = FALSE ; - - memset((char *)smc->evcs,0,sizeof(smc->evcs)) ; - - evc = smc->evcs ; - init = evc_inits ; - - for (i = 0 ; (unsigned) i < MAX_INIT_EVC ; i++) { - for (index = 0 ; index < init->n ; index++) { - evc->evc_code = init->code ; - evc->evc_para = init->para ; - evc->evc_index = init->index + index ; -#ifndef DEBUG - evc->evc_multiple = &fail_safe ; - evc->evc_cond_state = &fail_safe ; -#endif - evc++ ; - } - init++ ; - } - - if ((unsigned) (evc - smc->evcs) > MAX_EVCS) { - SMT_PANIC(smc,SMT_E0127, SMT_E0127_MSG) ; - } - - /* - * conditions - */ - smc->evcs[0].evc_cond_state = &smc->mib.fddiSMTPeerWrapFlag ; - smc->evcs[1].evc_cond_state = - &smc->mib.m[MAC0].fddiMACDuplicateAddressCond ; - smc->evcs[2].evc_cond_state = - &smc->mib.m[MAC0].fddiMACFrameErrorFlag ; - smc->evcs[3].evc_cond_state = - &smc->mib.m[MAC0].fddiMACNotCopiedFlag ; - - /* - * events - */ - smc->evcs[4].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_N ; - smc->evcs[5].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_P ; - - offset = 6 ; - for (i = 0 ; i < NUMPHYS ; i++) { - /* - * conditions - */ - smc->evcs[offset + 0*NUMPHYS].evc_cond_state = - &smc->mib.p[i].fddiPORTLerFlag ; - smc->evcs[offset + 1*NUMPHYS].evc_cond_state = - &smc->mib.p[i].fddiPORTEB_Condition ; - - /* - * events - */ - smc->evcs[offset + 2*NUMPHYS].evc_multiple = - &smc->mib.p[i].fddiPORTMultiple_U ; - smc->evcs[offset + 3*NUMPHYS].evc_multiple = - &smc->mib.p[i].fddiPORTMultiple_P ; - offset++ ; - } -#ifdef DEBUG - for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { - if (SMT_IS_CONDITION(evc->evc_code)) { - if (!evc->evc_cond_state) { - SMT_PANIC(smc,SMT_E0128, SMT_E0128_MSG) ; - } - evc->evc_multiple = &fail_safe ; - } - else { - if (!evc->evc_multiple) { - SMT_PANIC(smc,SMT_E0129, SMT_E0129_MSG) ; - } - evc->evc_cond_state = &fail_safe ; - } - } -#endif - smc->srf.TSR = smt_get_time() ; - smc->srf.sr_state = SR0_WAIT ; -} - -static struct s_srf_evc *smt_get_evc(struct s_smc *smc, int code, int index) -{ - int i ; - struct s_srf_evc *evc ; - - for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { - if (evc->evc_code == code && evc->evc_index == index) - return evc; - } - return NULL; -} - -#define THRESHOLD_2 (2*TICKS_PER_SECOND) -#define THRESHOLD_32 (32*TICKS_PER_SECOND) - -#ifdef DEBUG -static const char * const srf_names[] = { - "None","MACPathChangeEvent", "MACNeighborChangeEvent", - "PORTPathChangeEvent", "PORTUndesiredConnectionAttemptEvent", - "SMTPeerWrapCondition", "SMTHoldCondition", - "MACFrameErrorCondition", "MACDuplicateAddressCondition", - "MACNotCopiedCondition", "PORTEBErrorCondition", - "PORTLerCondition" -} ; -#endif - -void smt_srf_event(struct s_smc *smc, int code, int index, int cond) -{ - struct s_srf_evc *evc ; - int cond_asserted = 0 ; - int cond_deasserted = 0 ; - int event_occurred = 0 ; - int tsr ; - int T_Limit = 2*TICKS_PER_SECOND ; - - if (code == SMT_COND_MAC_DUP_ADDR && cond) { - RS_SET(smc,RS_DUPADDR) ; - } - - if (code) { - DB_SMT("SRF: %s index %d\n",srf_names[code],index) ; - - if (!(evc = smt_get_evc(smc,code,index))) { - DB_SMT("SRF : smt_get_evc() failed\n",0,0) ; - return ; - } - /* - * ignore condition if no change - */ - if (SMT_IS_CONDITION(code)) { - if (*evc->evc_cond_state == cond) - return ; - } - - /* - * set transition time stamp - */ - smt_set_timestamp(smc,smc->mib.fddiSMTTransitionTimeStamp) ; - if (SMT_IS_CONDITION(code)) { - DB_SMT("SRF: condition is %s\n",cond ? "ON":"OFF",0) ; - if (cond) { - *evc->evc_cond_state = TRUE ; - evc->evc_rep_required = TRUE ; - smc->srf.any_report = TRUE ; - cond_asserted = TRUE ; - } - else { - *evc->evc_cond_state = FALSE ; - cond_deasserted = TRUE ; - } - } - else { - if (evc->evc_rep_required) { - *evc->evc_multiple = TRUE ; - } - else { - evc->evc_rep_required = TRUE ; - *evc->evc_multiple = FALSE ; - } - smc->srf.any_report = TRUE ; - event_occurred = TRUE ; - } -#ifdef FDDI_MIB - snmp_srf_event(smc,evc) ; -#endif /* FDDI_MIB */ - } - tsr = smt_get_time() - smc->srf.TSR ; - - switch (smc->srf.sr_state) { - case SR0_WAIT : - /* SR01a */ - if (cond_asserted && tsr < T_Limit) { - smc->srf.SRThreshold = THRESHOLD_2 ; - smc->srf.sr_state = SR1_HOLDOFF ; - break ; - } - /* SR01b */ - if (cond_deasserted && tsr < T_Limit) { - smc->srf.sr_state = SR1_HOLDOFF ; - break ; - } - /* SR01c */ - if (event_occurred && tsr < T_Limit) { - smc->srf.sr_state = SR1_HOLDOFF ; - break ; - } - /* SR00b */ - if (cond_asserted && tsr >= T_Limit) { - smc->srf.SRThreshold = THRESHOLD_2 ; - smc->srf.TSR = smt_get_time() ; - smt_send_srf(smc) ; - break ; - } - /* SR00c */ - if (cond_deasserted && tsr >= T_Limit) { - smc->srf.TSR = smt_get_time() ; - smt_send_srf(smc) ; - break ; - } - /* SR00d */ - if (event_occurred && tsr >= T_Limit) { - smc->srf.TSR = smt_get_time() ; - smt_send_srf(smc) ; - break ; - } - /* SR00e */ - if (smc->srf.any_report && (u_long) tsr >= - smc->srf.SRThreshold) { - smc->srf.SRThreshold *= 2 ; - if (smc->srf.SRThreshold > THRESHOLD_32) - smc->srf.SRThreshold = THRESHOLD_32 ; - smc->srf.TSR = smt_get_time() ; - smt_send_srf(smc) ; - break ; - } - /* SR02 */ - if (!smc->mib.fddiSMTStatRptPolicy) { - smc->srf.sr_state = SR2_DISABLED ; - break ; - } - break ; - case SR1_HOLDOFF : - /* SR10b */ - if (tsr >= T_Limit) { - smc->srf.sr_state = SR0_WAIT ; - smc->srf.TSR = smt_get_time() ; - smt_send_srf(smc) ; - break ; - } - /* SR11a */ - if (cond_asserted) { - smc->srf.SRThreshold = THRESHOLD_2 ; - } - /* SR11b */ - /* SR11c */ - /* handled above */ - /* SR12 */ - if (!smc->mib.fddiSMTStatRptPolicy) { - smc->srf.sr_state = SR2_DISABLED ; - break ; - } - break ; - case SR2_DISABLED : - if (smc->mib.fddiSMTStatRptPolicy) { - smc->srf.sr_state = SR0_WAIT ; - smc->srf.TSR = smt_get_time() ; - smc->srf.SRThreshold = THRESHOLD_2 ; - clear_all_rep(smc) ; - break ; - } - break ; - } -} - -static void clear_all_rep(struct s_smc *smc) -{ - struct s_srf_evc *evc ; - int i ; - - for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { - evc->evc_rep_required = FALSE ; - if (SMT_IS_CONDITION(evc->evc_code)) - *evc->evc_cond_state = FALSE ; - } - smc->srf.any_report = FALSE ; -} - -static void clear_reported(struct s_smc *smc) -{ - struct s_srf_evc *evc ; - int i ; - - smc->srf.any_report = FALSE ; - for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { - if (SMT_IS_CONDITION(evc->evc_code)) { - if (*evc->evc_cond_state == FALSE) - evc->evc_rep_required = FALSE ; - else - smc->srf.any_report = TRUE ; - } - else { - evc->evc_rep_required = FALSE ; - *evc->evc_multiple = FALSE ; - } - } -} - -/* - * build and send SMT SRF frame - */ -static void smt_send_srf(struct s_smc *smc) -{ - - struct smt_header *smt ; - struct s_srf_evc *evc ; - SK_LOC_DECL(struct s_pcon,pcon) ; - SMbuf *mb ; - int i ; - - static const struct fddi_addr SMT_SRF_DA = { - { 0x80, 0x01, 0x43, 0x00, 0x80, 0x08 } - } ; - - /* - * build SMT header - */ - if (!smc->r.sm_ma_avail) - return ; - if (!(mb = smt_build_frame(smc,SMT_SRF,SMT_ANNOUNCE,0))) - return ; - - RS_SET(smc,RS_SOFTERROR) ; - - smt = smtod(mb, struct smt_header *) ; - smt->smt_dest = SMT_SRF_DA ; /* DA == SRF multicast */ - - /* - * setup parameter status - */ - pcon.pc_len = SMT_MAX_INFO_LEN ; /* max para length */ - pcon.pc_err = 0 ; /* no error */ - pcon.pc_badset = 0 ; /* no bad set count */ - pcon.pc_p = (void *) (smt + 1) ; /* paras start here */ - - smt_add_para(smc,&pcon,(u_short) SMT_P1033,0,0) ; - smt_add_para(smc,&pcon,(u_short) SMT_P1034,0,0) ; - - for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { - if (evc->evc_rep_required) { - smt_add_para(smc,&pcon,evc->evc_para, - (int)evc->evc_index,0) ; - } - } - smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ; - mb->sm_len = smt->smt_len + sizeof(struct smt_header) ; - - DB_SMT("SRF: sending SRF at %x, len %d\n",smt,mb->sm_len) ; - DB_SMT("SRF: state SR%d Threshold %d\n", - smc->srf.sr_state,smc->srf.SRThreshold/TICKS_PER_SECOND) ; -#ifdef DEBUG - dump_smt(smc,smt,"SRF Send") ; -#endif - smt_send_frame(smc,mb,FC_SMT_INFO,0) ; - clear_reported(smc) ; -} - -#endif /* no BOOT */ -#endif /* no SLIM_SMT */ - -- cgit v0.10.2 From aab3ac26108642eaa06efa4697dab595c7de2bbd Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Wed, 24 Aug 2011 01:34:35 -0700 Subject: skfp: Fix SysKonnect FDDI driver compile issues After moving the skfp driver, issues with the #include pathing to their locel headers was somehow exposed. Several headers had the incorrect path, so they were not able to be found during compile time. This patch fixes up the path issues to the local headers that need to be included. CC: "Maciej W. Rozycki" CC: Christoph Goos CC: Signed-off-by: Jeff Kirsher diff --git a/drivers/net/fddi/skfp/h/cmtdef.h b/drivers/net/fddi/skfp/h/cmtdef.h index 5a6c612..f5bc90f 100644 --- a/drivers/net/fddi/skfp/h/cmtdef.h +++ b/drivers/net/fddi/skfp/h/cmtdef.h @@ -477,8 +477,8 @@ struct s_plc { /* * function prototypes */ -#include "h/mbuf.h" /* Type definitions for MBUFs */ -#include "h/smtstate.h" /* struct smt_state */ +#include "mbuf.h" /* Type definitions for MBUFs */ +#include "smtstate.h" /* struct smt_state */ void hwt_restart(struct s_smc *smc); /* hwt.c */ SMbuf *smt_build_frame(struct s_smc *smc, int class, int type, diff --git a/drivers/net/fddi/skfp/h/hwmtm.h b/drivers/net/fddi/skfp/h/hwmtm.h index e1a7e5f..5924d42 100644 --- a/drivers/net/fddi/skfp/h/hwmtm.h +++ b/drivers/net/fddi/skfp/h/hwmtm.h @@ -15,7 +15,7 @@ #ifndef _HWM_ #define _HWM_ -#include "h/mbuf.h" +#include "mbuf.h" /* * MACRO for DMA synchronization: diff --git a/drivers/net/fddi/skfp/h/sba.h b/drivers/net/fddi/skfp/h/sba.h index 638cf02..35ddb44 100644 --- a/drivers/net/fddi/skfp/h/sba.h +++ b/drivers/net/fddi/skfp/h/sba.h @@ -19,8 +19,8 @@ #ifndef _SBA_ #define _SBA_ -#include "h/mbuf.h" -#include "h/sba_def.h" +#include "mbuf.h" +#include "sba_def.h" #ifdef SBA diff --git a/drivers/net/fddi/skfp/h/skfbiinc.h b/drivers/net/fddi/skfp/h/skfbiinc.h index ac2d719..ce72557 100644 --- a/drivers/net/fddi/skfp/h/skfbiinc.h +++ b/drivers/net/fddi/skfp/h/skfbiinc.h @@ -15,7 +15,7 @@ #ifndef _SKFBIINC_ #define _SKFBIINC_ -#include "h/supern_2.h" +#include "supern_2.h" /* * special defines for use into .asm files diff --git a/drivers/net/fddi/skfp/h/smc.h b/drivers/net/fddi/skfp/h/smc.h index c774a95..3ca308b 100644 --- a/drivers/net/fddi/skfp/h/smc.h +++ b/drivers/net/fddi/skfp/h/smc.h @@ -38,18 +38,18 @@ * fddi.h */ #ifdef OSDEF -#include "h/osdef1st.h" +#include "osdef1st.h" #endif /* OSDEF */ #ifdef OEM_CONCEPT #include "oemdef.h" #endif /* OEM_CONCEPT */ -#include "h/smt.h" -#include "h/cmtdef.h" -#include "h/fddimib.h" -#include "h/targethw.h" /* all target hw dependencies */ -#include "h/targetos.h" /* all target os dependencies */ +#include "smt.h" +#include "cmtdef.h" +#include "fddimib.h" +#include "targethw.h" /* all target hw dependencies */ +#include "targetos.h" /* all target os dependencies */ #ifdef ESS -#include "h/sba.h" +#include "sba.h" #endif /* diff --git a/drivers/net/fddi/skfp/h/targethw.h b/drivers/net/fddi/skfp/h/targethw.h index 626dc72..842a690 100644 --- a/drivers/net/fddi/skfp/h/targethw.h +++ b/drivers/net/fddi/skfp/h/targethw.h @@ -25,11 +25,11 @@ #define SK_ML_ID_2 0x30 #endif -#include "h/skfbi.h" +#include "skfbi.h" #ifndef TAG_MODE -#include "h/fplus.h" +#include "fplus.h" #else -#include "h/fplustm.h" +#include "fplustm.h" #endif #ifndef HW_PTR diff --git a/drivers/net/fddi/skfp/h/targetos.h b/drivers/net/fddi/skfp/h/targetos.h index 5d940e7..53bacc1 100644 --- a/drivers/net/fddi/skfp/h/targetos.h +++ b/drivers/net/fddi/skfp/h/targetos.h @@ -58,7 +58,7 @@ #define ADDR(a) (((a)>>7) ? (outp(smc->hw.iop+B0_RAP,(a)>>7), (smc->hw.iop+( ((a)&0x7F) | ((a)>>7 ? 0x80:0)) )) : (smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) #endif -#include "h/hwmtm.h" +#include "hwmtm.h" #define TRUE 1 #define FALSE 0 -- cgit v0.10.2 From 224cf5ad14c038b13c119dff29422f178a306f54 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Sun, 31 Jul 2011 02:38:19 -0700 Subject: ppp: Move the PPP drivers Move the PPP drivers into drivers/net/ppp/ and make the necessary Kconfig and Makefile changes. CC: Paul Mackerras CC: Frank Cusack CC: Michal Ostrowski CC: Michal Ostrowski CC: Dmitry Kozlov Signed-off-by: Jeff Kirsher diff --git a/MAINTAINERS b/MAINTAINERS index 2777088..c5ec925 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5066,7 +5066,7 @@ PPP PROTOCOL DRIVERS AND COMPRESSORS M: Paul Mackerras L: linux-ppp@vger.kernel.org S: Maintained -F: drivers/net/ppp_* +F: drivers/net/ppp/ppp_* PPP OVER ATM (RFC 2364) M: Mitchell Blank Jr @@ -5077,8 +5077,8 @@ F: include/linux/atmppp.h PPP OVER ETHERNET M: Michal Ostrowski S: Maintained -F: drivers/net/pppoe.c -F: drivers/net/pppox.c +F: drivers/net/ppp/pppoe.c +F: drivers/net/ppp/pppox.c PPP OVER L2TP M: James Chapman @@ -5099,7 +5099,7 @@ PPTP DRIVER M: Dmitry Kozlov L: netdev@vger.kernel.org S: Maintained -F: drivers/net/pptp.c +F: drivers/net/ppp/pptp.c W: http://sourceforge.net/projects/accel-pptp PREEMPTIBLE KERNEL diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 7bdc22b..c5e2a38 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -207,6 +207,8 @@ source "drivers/net/usb/Kconfig" source "drivers/net/pcmcia/Kconfig" +source "drivers/net/ppp/Kconfig" + source "drivers/net/wan/Kconfig" source "drivers/atm/Kconfig" @@ -337,174 +339,6 @@ config PLIP will be called plip. If unsure, say Y or M, in case you buy a laptop later. -config PPP - tristate "PPP (point-to-point protocol) support" - select SLHC - ---help--- - PPP (Point to Point Protocol) is a newer and better SLIP. It serves - the same purpose: sending Internet traffic over telephone (and other - serial) lines. Ask your access provider if they support it, because - otherwise you can't use it; most Internet access providers these - days support PPP rather than SLIP. - - To use PPP, you need an additional program called pppd as described - in the PPP-HOWTO, available at - . Make sure that you have - the version of pppd recommended in . - The PPP option enlarges your kernel by about 16 KB. - - There are actually two versions of PPP: the traditional PPP for - asynchronous lines, such as regular analog phone lines, and - synchronous PPP which can be used over digital ISDN lines for - example. If you want to use PPP over phone lines or other - asynchronous serial lines, you need to say Y (or M) here and also to - the next option, "PPP support for async serial ports". For PPP over - synchronous lines, you should say Y (or M) here and to "Support - synchronous PPP", below. - - If you said Y to "Version information on all symbols" above, then - you cannot compile the PPP driver into the kernel; you can then only - compile it as a module. To compile this driver as a module, choose M - here. The module will be called ppp_generic. - -config PPP_MULTILINK - bool "PPP multilink support (EXPERIMENTAL)" - depends on PPP && EXPERIMENTAL - help - PPP multilink is a protocol (defined in RFC 1990) which allows you - to combine several (logical or physical) lines into one logical PPP - connection, so that you can utilize your full bandwidth. - - This has to be supported at the other end as well and you need a - version of the pppd daemon which understands the multilink protocol. - - If unsure, say N. - -config PPP_FILTER - bool "PPP filtering" - depends on PPP - help - Say Y here if you want to be able to filter the packets passing over - PPP interfaces. This allows you to control which packets count as - activity (i.e. which packets will reset the idle timer or bring up - a demand-dialed link) and which packets are to be dropped entirely. - You need to say Y here if you wish to use the pass-filter and - active-filter options to pppd. - - If unsure, say N. - -config PPP_ASYNC - tristate "PPP support for async serial ports" - depends on PPP - select CRC_CCITT - ---help--- - Say Y (or M) here if you want to be able to use PPP over standard - asynchronous serial ports, such as COM1 or COM2 on a PC. If you use - a modem (not a synchronous or ISDN modem) to contact your ISP, you - need this option. - - To compile this driver as a module, choose M here. - - If unsure, say Y. - -config PPP_SYNC_TTY - tristate "PPP support for sync tty ports" - depends on PPP - help - Say Y (or M) here if you want to be able to use PPP over synchronous - (HDLC) tty devices, such as the SyncLink adapter. These devices - are often used for high-speed leased lines like T1/E1. - - To compile this driver as a module, choose M here. - -config PPP_DEFLATE - tristate "PPP Deflate compression" - depends on PPP - select ZLIB_INFLATE - select ZLIB_DEFLATE - ---help--- - Support for the Deflate compression method for PPP, which uses the - Deflate algorithm (the same algorithm that gzip uses) to compress - each PPP packet before it is sent over the wire. The machine at the - other end of the PPP link (usually your ISP) has to support the - Deflate compression method as well for this to be useful. Even if - they don't support it, it is safe to say Y here. - - To compile this driver as a module, choose M here. - -config PPP_BSDCOMP - tristate "PPP BSD-Compress compression" - depends on PPP - ---help--- - Support for the BSD-Compress compression method for PPP, which uses - the LZW compression method to compress each PPP packet before it is - sent over the wire. The machine at the other end of the PPP link - (usually your ISP) has to support the BSD-Compress compression - method as well for this to be useful. Even if they don't support it, - it is safe to say Y here. - - The PPP Deflate compression method ("PPP Deflate compression", - above) is preferable to BSD-Compress, because it compresses better - and is patent-free. - - Note that the BSD compression code will always be compiled as a - module; it is called bsd_comp and will show up in the directory - modules once you have said "make modules". If unsure, say N. - -config PPP_MPPE - tristate "PPP MPPE compression (encryption) (EXPERIMENTAL)" - depends on PPP && EXPERIMENTAL - select CRYPTO - select CRYPTO_SHA1 - select CRYPTO_ARC4 - select CRYPTO_ECB - ---help--- - Support for the MPPE Encryption protocol, as employed by the - Microsoft Point-to-Point Tunneling Protocol. - - See http://pptpclient.sourceforge.net/ for information on - configuring PPTP clients and servers to utilize this method. - -config PPPOE - tristate "PPP over Ethernet (EXPERIMENTAL)" - depends on EXPERIMENTAL && PPP - help - Support for PPP over Ethernet. - - This driver requires the latest version of pppd from the CVS - repository at cvs.samba.org. Alternatively, see the - RoaringPenguin package () - which contains instruction on how to use this driver (under - the heading "Kernel mode PPPoE"). - -config PPTP - tristate "PPP over IPv4 (PPTP) (EXPERIMENTAL)" - depends on EXPERIMENTAL && PPP && NET_IPGRE_DEMUX - help - Support for PPP over IPv4.(Point-to-Point Tunneling Protocol) - - This driver requires pppd plugin to work in client mode or - modified pptpd (poptop) to work in server mode. - See http://accel-pptp.sourceforge.net/ for information how to - utilize this module. - -config PPPOATM - tristate "PPP over ATM" - depends on ATM && PPP - help - Support PPP (Point to Point Protocol) encapsulated in ATM frames. - This implementation does not yet comply with section 8 of RFC2364, - which can lead to bad results if the ATM peer loses state and - changes its encapsulation unilaterally. - -config PPPOL2TP - tristate "PPP over L2TP (EXPERIMENTAL)" - depends on EXPERIMENTAL && L2TP && PPP - help - Support for PPP-over-L2TP socket family. L2TP is a protocol - used by ISPs and enterprises to tunnel PPP traffic over UDP - tunnels. L2TP is replacing PPTP for VPN uses. - config SLIP tristate "SLIP (serial line) support" ---help--- diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 3087b27..a397f1e 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -22,15 +22,6 @@ obj-$(CONFIG_RIONET) += rionet.o obj-$(CONFIG_NET) += Space.o loopback.o obj-$(CONFIG_NET_SB1000) += sb1000.o -obj-$(CONFIG_PPP) += ppp_generic.o -obj-$(CONFIG_PPP_ASYNC) += ppp_async.o -obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o -obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o -obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o -obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o -obj-$(CONFIG_PPPOE) += pppox.o pppoe.o -obj-$(CONFIG_PPPOL2TP) += pppox.o -obj-$(CONFIG_PPTP) += pppox.o pptp.o obj-$(CONFIG_SLIP) += slip.o obj-$(CONFIG_SLHC) += slhc.o @@ -48,6 +39,15 @@ obj-$(CONFIG_VETH) += veth.o obj-$(CONFIG_DEV_APPLETALK) += appletalk/ obj-$(CONFIG_ETHERNET) += ethernet/ obj-$(CONFIG_FDDI) += fddi/ +onj-$(CONFIG_PPP) += ppp/ +obj-$(CONFIG_PPP_ASYNC) += ppp/ +obj-$(CONFIG_PPP_BSDCOMP) += ppp/ +obj-$(CONFIG_PPP_DEFLATE) += ppp/ +obj-$(CONFIG_PPP_MPPE) += ppp/ +obj-$(CONFIG_PPP_SYNC_TTY) += ppp/ +obj-$(CONFIG_PPPOE) += ppp/ +obj-$(CONFIG_PPPOL2TP) += ppp/ +obj-$(CONFIG_PPTP) += ppp/ obj-$(CONFIG_TR) += tokenring/ obj-$(CONFIG_WAN) += wan/ obj-$(CONFIG_ARCNET) += arcnet/ diff --git a/drivers/net/bsd_comp.c b/drivers/net/bsd_comp.c deleted file mode 100644 index a9b759a..0000000 --- a/drivers/net/bsd_comp.c +++ /dev/null @@ -1,1170 +0,0 @@ -/* - * Update: The Berkeley copyright was changed, and the change - * is retroactive to all "true" BSD software (ie everything - * from UCB as opposed to other peoples code that just carried - * the same license). The new copyright doesn't clash with the - * GPL, so the module-only restriction has been removed.. - */ - -/* Because this code is derived from the 4.3BSD compress source: - * - * Copyright (c) 1985, 1986 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * James A. Woods, derived from original work by Spencer Thomas - * and Joseph Orost. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * This version is for use with contiguous buffers on Linux-derived systems. - * - * ==FILEVERSION 20000226== - * - * NOTE TO MAINTAINERS: - * If you modify this file at all, please set the number above to the - * date of the modification as YYMMDD (year month day). - * bsd_comp.c is shipped with a PPP distribution as well as with - * the kernel; if everyone increases the FILEVERSION number above, - * then scripts can do the right thing when deciding whether to - * install a new bsd_comp.c file. Don't change the format of that - * line otherwise, so the installation script can recognize it. - * - * From: bsd_comp.c,v 1.3 1994/12/08 01:59:58 paulus Exp - */ - -#include -#include -#include -#include -#include - -#include - -#undef PACKETPTR -#define PACKETPTR 1 -#include -#undef PACKETPTR - -#include - -/* - * PPP "BSD compress" compression - * The differences between this compression and the classic BSD LZW - * source are obvious from the requirement that the classic code worked - * with files while this handles arbitrarily long streams that - * are broken into packets. They are: - * - * When the code size expands, a block of junk is not emitted by - * the compressor and not expected by the decompressor. - * - * New codes are not necessarily assigned every time an old - * code is output by the compressor. This is because a packet - * end forces a code to be emitted, but does not imply that a - * new sequence has been seen. - * - * The compression ratio is checked at the first end of a packet - * after the appropriate gap. Besides simplifying and speeding - * things up, this makes it more likely that the transmitter - * and receiver will agree when the dictionary is cleared when - * compression is not going well. - */ - -/* - * Macros to extract protocol version and number of bits - * from the third byte of the BSD Compress CCP configuration option. - */ - -#define BSD_VERSION(x) ((x) >> 5) -#define BSD_NBITS(x) ((x) & 0x1F) - -#define BSD_CURRENT_VERSION 1 - -/* - * A dictionary for doing BSD compress. - */ - -struct bsd_dict { - union { /* hash value */ - unsigned long fcode; - struct { -#if defined(__LITTLE_ENDIAN) /* Little endian order */ - unsigned short prefix; /* preceding code */ - unsigned char suffix; /* last character of new code */ - unsigned char pad; -#elif defined(__BIG_ENDIAN) /* Big endian order */ - unsigned char pad; - unsigned char suffix; /* last character of new code */ - unsigned short prefix; /* preceding code */ -#else -#error Endianness not defined... -#endif - } hs; - } f; - unsigned short codem1; /* output of hash table -1 */ - unsigned short cptr; /* map code to hash table entry */ -}; - -struct bsd_db { - int totlen; /* length of this structure */ - unsigned int hsize; /* size of the hash table */ - unsigned char hshift; /* used in hash function */ - unsigned char n_bits; /* current bits/code */ - unsigned char maxbits; /* maximum bits/code */ - unsigned char debug; /* non-zero if debug desired */ - unsigned char unit; /* ppp unit number */ - unsigned short seqno; /* sequence # of next packet */ - unsigned int mru; /* size of receive (decompress) bufr */ - unsigned int maxmaxcode; /* largest valid code */ - unsigned int max_ent; /* largest code in use */ - unsigned int in_count; /* uncompressed bytes, aged */ - unsigned int bytes_out; /* compressed bytes, aged */ - unsigned int ratio; /* recent compression ratio */ - unsigned int checkpoint; /* when to next check the ratio */ - unsigned int clear_count; /* times dictionary cleared */ - unsigned int incomp_count; /* incompressible packets */ - unsigned int incomp_bytes; /* incompressible bytes */ - unsigned int uncomp_count; /* uncompressed packets */ - unsigned int uncomp_bytes; /* uncompressed bytes */ - unsigned int comp_count; /* compressed packets */ - unsigned int comp_bytes; /* compressed bytes */ - unsigned short *lens; /* array of lengths of codes */ - struct bsd_dict *dict; /* dictionary */ -}; - -#define BSD_OVHD 2 /* BSD compress overhead/packet */ -#define MIN_BSD_BITS 9 -#define BSD_INIT_BITS MIN_BSD_BITS -#define MAX_BSD_BITS 15 - -static void bsd_free (void *state); -static void *bsd_alloc(unsigned char *options, int opt_len, int decomp); -static void *bsd_comp_alloc (unsigned char *options, int opt_len); -static void *bsd_decomp_alloc (unsigned char *options, int opt_len); - -static int bsd_init (void *db, unsigned char *options, - int opt_len, int unit, int debug, int decomp); -static int bsd_comp_init (void *state, unsigned char *options, - int opt_len, int unit, int opthdr, int debug); -static int bsd_decomp_init (void *state, unsigned char *options, - int opt_len, int unit, int opthdr, int mru, - int debug); - -static void bsd_reset (void *state); -static void bsd_comp_stats (void *state, struct compstat *stats); - -static int bsd_compress (void *state, unsigned char *rptr, - unsigned char *obuf, int isize, int osize); -static void bsd_incomp (void *state, unsigned char *ibuf, int icnt); - -static int bsd_decompress (void *state, unsigned char *ibuf, int isize, - unsigned char *obuf, int osize); - -/* These are in ppp_generic.c */ -extern int ppp_register_compressor (struct compressor *cp); -extern void ppp_unregister_compressor (struct compressor *cp); - -/* - * the next two codes should not be changed lightly, as they must not - * lie within the contiguous general code space. - */ -#define CLEAR 256 /* table clear output code */ -#define FIRST 257 /* first free entry */ -#define LAST 255 - -#define MAXCODE(b) ((1 << (b)) - 1) -#define BADCODEM1 MAXCODE(MAX_BSD_BITS) - -#define BSD_HASH(prefix,suffix,hshift) ((((unsigned long)(suffix))<<(hshift)) \ - ^ (unsigned long)(prefix)) -#define BSD_KEY(prefix,suffix) ((((unsigned long)(suffix)) << 16) \ - + (unsigned long)(prefix)) - -#define CHECK_GAP 10000 /* Ratio check interval */ - -#define RATIO_SCALE_LOG 8 -#define RATIO_SCALE (1<>RATIO_SCALE_LOG) - -/* - * clear the dictionary - */ - -static void -bsd_clear(struct bsd_db *db) -{ - db->clear_count++; - db->max_ent = FIRST-1; - db->n_bits = BSD_INIT_BITS; - db->bytes_out = 0; - db->in_count = 0; - db->ratio = 0; - db->checkpoint = CHECK_GAP; -} - -/* - * If the dictionary is full, then see if it is time to reset it. - * - * Compute the compression ratio using fixed-point arithmetic - * with 8 fractional bits. - * - * Since we have an infinite stream instead of a single file, - * watch only the local compression ratio. - * - * Since both peers must reset the dictionary at the same time even in - * the absence of CLEAR codes (while packets are incompressible), they - * must compute the same ratio. - */ - -static int bsd_check (struct bsd_db *db) /* 1=output CLEAR */ - { - unsigned int new_ratio; - - if (db->in_count >= db->checkpoint) - { - /* age the ratio by limiting the size of the counts */ - if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX) - { - db->in_count -= (db->in_count >> 2); - db->bytes_out -= (db->bytes_out >> 2); - } - - db->checkpoint = db->in_count + CHECK_GAP; - - if (db->max_ent >= db->maxmaxcode) - { - /* Reset the dictionary only if the ratio is worse, - * or if it looks as if it has been poisoned - * by incompressible data. - * - * This does not overflow, because - * db->in_count <= RATIO_MAX. - */ - - new_ratio = db->in_count << RATIO_SCALE_LOG; - if (db->bytes_out != 0) - { - new_ratio /= db->bytes_out; - } - - if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) - { - bsd_clear (db); - return 1; - } - db->ratio = new_ratio; - } - } - return 0; - } - -/* - * Return statistics. - */ - -static void bsd_comp_stats (void *state, struct compstat *stats) - { - struct bsd_db *db = (struct bsd_db *) state; - - stats->unc_bytes = db->uncomp_bytes; - stats->unc_packets = db->uncomp_count; - stats->comp_bytes = db->comp_bytes; - stats->comp_packets = db->comp_count; - stats->inc_bytes = db->incomp_bytes; - stats->inc_packets = db->incomp_count; - stats->in_count = db->in_count; - stats->bytes_out = db->bytes_out; - } - -/* - * Reset state, as on a CCP ResetReq. - */ - -static void bsd_reset (void *state) - { - struct bsd_db *db = (struct bsd_db *) state; - - bsd_clear(db); - - db->seqno = 0; - db->clear_count = 0; - } - -/* - * Release the compression structure - */ - -static void bsd_free (void *state) -{ - struct bsd_db *db = state; - - if (!db) - return; - -/* - * Release the dictionary - */ - vfree(db->dict); - db->dict = NULL; -/* - * Release the string buffer - */ - vfree(db->lens); - db->lens = NULL; -/* - * Finally release the structure itself. - */ - kfree(db); -} - -/* - * Allocate space for a (de) compressor. - */ - -static void *bsd_alloc (unsigned char *options, int opt_len, int decomp) - { - int bits; - unsigned int hsize, hshift, maxmaxcode; - struct bsd_db *db; - - if (opt_len != 3 || options[0] != CI_BSD_COMPRESS || options[1] != 3 - || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION) - { - return NULL; - } - - bits = BSD_NBITS(options[2]); - - switch (bits) - { - case 9: /* needs 82152 for both directions */ - case 10: /* needs 84144 */ - case 11: /* needs 88240 */ - case 12: /* needs 96432 */ - hsize = 5003; - hshift = 4; - break; - case 13: /* needs 176784 */ - hsize = 9001; - hshift = 5; - break; - case 14: /* needs 353744 */ - hsize = 18013; - hshift = 6; - break; - case 15: /* needs 691440 */ - hsize = 35023; - hshift = 7; - break; - case 16: /* needs 1366160--far too much, */ - /* hsize = 69001; */ /* and 69001 is too big for cptr */ - /* hshift = 8; */ /* in struct bsd_db */ - /* break; */ - default: - return NULL; - } -/* - * Allocate the main control structure for this instance. - */ - maxmaxcode = MAXCODE(bits); - db = kzalloc(sizeof (struct bsd_db), - GFP_KERNEL); - if (!db) - { - return NULL; - } - -/* - * Allocate space for the dictionary. This may be more than one page in - * length. - */ - db->dict = vmalloc(hsize * sizeof(struct bsd_dict)); - if (!db->dict) - { - bsd_free (db); - return NULL; - } - -/* - * If this is the compression buffer then there is no length data. - */ - if (!decomp) - { - db->lens = NULL; - } -/* - * For decompression, the length information is needed as well. - */ - else - { - db->lens = vmalloc((maxmaxcode + 1) * sizeof(db->lens[0])); - if (!db->lens) - { - bsd_free (db); - return NULL; - } - } -/* - * Initialize the data information for the compression code - */ - db->totlen = sizeof (struct bsd_db) + - (sizeof (struct bsd_dict) * hsize); - - db->hsize = hsize; - db->hshift = hshift; - db->maxmaxcode = maxmaxcode; - db->maxbits = bits; - - return (void *) db; - } - -static void *bsd_comp_alloc (unsigned char *options, int opt_len) - { - return bsd_alloc (options, opt_len, 0); - } - -static void *bsd_decomp_alloc (unsigned char *options, int opt_len) - { - return bsd_alloc (options, opt_len, 1); - } - -/* - * Initialize the database. - */ - -static int bsd_init (void *state, unsigned char *options, - int opt_len, int unit, int debug, int decomp) - { - struct bsd_db *db = state; - int indx; - - if ((opt_len != 3) || (options[0] != CI_BSD_COMPRESS) || (options[1] != 3) - || (BSD_VERSION(options[2]) != BSD_CURRENT_VERSION) - || (BSD_NBITS(options[2]) != db->maxbits) - || (decomp && db->lens == NULL)) - { - return 0; - } - - if (decomp) - { - indx = LAST; - do - { - db->lens[indx] = 1; - } - while (indx-- > 0); - } - - indx = db->hsize; - while (indx-- != 0) - { - db->dict[indx].codem1 = BADCODEM1; - db->dict[indx].cptr = 0; - } - - db->unit = unit; - db->mru = 0; -#ifndef DEBUG - if (debug) -#endif - db->debug = 1; - - bsd_reset(db); - - return 1; - } - -static int bsd_comp_init (void *state, unsigned char *options, - int opt_len, int unit, int opthdr, int debug) - { - return bsd_init (state, options, opt_len, unit, debug, 0); - } - -static int bsd_decomp_init (void *state, unsigned char *options, - int opt_len, int unit, int opthdr, int mru, - int debug) - { - return bsd_init (state, options, opt_len, unit, debug, 1); - } - -/* - * Obtain pointers to the various structures in the compression tables - */ - -#define dict_ptrx(p,idx) &(p->dict[idx]) -#define lens_ptrx(p,idx) &(p->lens[idx]) - -#ifdef DEBUG -static unsigned short *lens_ptr(struct bsd_db *db, int idx) - { - if ((unsigned int) idx > (unsigned int) db->maxmaxcode) - { - printk ("<9>ppp: lens_ptr(%d) > max\n", idx); - idx = 0; - } - return lens_ptrx (db, idx); - } - -static struct bsd_dict *dict_ptr(struct bsd_db *db, int idx) - { - if ((unsigned int) idx >= (unsigned int) db->hsize) - { - printk ("<9>ppp: dict_ptr(%d) > max\n", idx); - idx = 0; - } - return dict_ptrx (db, idx); - } - -#else -#define lens_ptr(db,idx) lens_ptrx(db,idx) -#define dict_ptr(db,idx) dict_ptrx(db,idx) -#endif - -/* - * compress a packet - * - * The result of this function is the size of the compressed - * packet. A zero is returned if the packet was not compressed - * for some reason, such as the size being larger than uncompressed. - * - * One change from the BSD compress command is that when the - * code size expands, we do not output a bunch of padding. - */ - -static int bsd_compress (void *state, unsigned char *rptr, unsigned char *obuf, - int isize, int osize) - { - struct bsd_db *db; - int hshift; - unsigned int max_ent; - unsigned int n_bits; - unsigned int bitno; - unsigned long accm; - int ent; - unsigned long fcode; - struct bsd_dict *dictp; - unsigned char c; - int hval; - int disp; - int ilen; - int mxcode; - unsigned char *wptr; - int olen; - -#define PUTBYTE(v) \ - { \ - ++olen; \ - if (wptr) \ - { \ - *wptr++ = (unsigned char) (v); \ - if (olen >= osize) \ - { \ - wptr = NULL; \ - } \ - } \ - } - -#define OUTPUT(ent) \ - { \ - bitno -= n_bits; \ - accm |= ((ent) << bitno); \ - do \ - { \ - PUTBYTE(accm >> 24); \ - accm <<= 8; \ - bitno += 8; \ - } \ - while (bitno <= 24); \ - } - - /* - * If the protocol is not in the range we're interested in, - * just return without compressing the packet. If it is, - * the protocol becomes the first byte to compress. - */ - - ent = PPP_PROTOCOL(rptr); - if (ent < 0x21 || ent > 0xf9) - { - return 0; - } - - db = (struct bsd_db *) state; - hshift = db->hshift; - max_ent = db->max_ent; - n_bits = db->n_bits; - bitno = 32; - accm = 0; - mxcode = MAXCODE (n_bits); - - /* Initialize the output pointers */ - wptr = obuf; - olen = PPP_HDRLEN + BSD_OVHD; - - if (osize > isize) - { - osize = isize; - } - - /* This is the PPP header information */ - if (wptr) - { - *wptr++ = PPP_ADDRESS(rptr); - *wptr++ = PPP_CONTROL(rptr); - *wptr++ = 0; - *wptr++ = PPP_COMP; - *wptr++ = db->seqno >> 8; - *wptr++ = db->seqno; - } - - /* Skip the input header */ - rptr += PPP_HDRLEN; - isize -= PPP_HDRLEN; - ilen = ++isize; /* Low byte of protocol is counted as input */ - - while (--ilen > 0) - { - c = *rptr++; - fcode = BSD_KEY (ent, c); - hval = BSD_HASH (ent, c, hshift); - dictp = dict_ptr (db, hval); - - /* Validate and then check the entry. */ - if (dictp->codem1 >= max_ent) - { - goto nomatch; - } - - if (dictp->f.fcode == fcode) - { - ent = dictp->codem1 + 1; - continue; /* found (prefix,suffix) */ - } - - /* continue probing until a match or invalid entry */ - disp = (hval == 0) ? 1 : hval; - - do - { - hval += disp; - if (hval >= db->hsize) - { - hval -= db->hsize; - } - dictp = dict_ptr (db, hval); - if (dictp->codem1 >= max_ent) - { - goto nomatch; - } - } - while (dictp->f.fcode != fcode); - - ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */ - continue; - -nomatch: - OUTPUT(ent); /* output the prefix */ - - /* code -> hashtable */ - if (max_ent < db->maxmaxcode) - { - struct bsd_dict *dictp2; - struct bsd_dict *dictp3; - int indx; - - /* expand code size if needed */ - if (max_ent >= mxcode) - { - db->n_bits = ++n_bits; - mxcode = MAXCODE (n_bits); - } - - /* Invalidate old hash table entry using - * this code, and then take it over. - */ - - dictp2 = dict_ptr (db, max_ent + 1); - indx = dictp2->cptr; - dictp3 = dict_ptr (db, indx); - - if (dictp3->codem1 == max_ent) - { - dictp3->codem1 = BADCODEM1; - } - - dictp2->cptr = hval; - dictp->codem1 = max_ent; - dictp->f.fcode = fcode; - db->max_ent = ++max_ent; - - if (db->lens) - { - unsigned short *len1 = lens_ptr (db, max_ent); - unsigned short *len2 = lens_ptr (db, ent); - *len1 = *len2 + 1; - } - } - ent = c; - } - - OUTPUT(ent); /* output the last code */ - - db->bytes_out += olen - PPP_HDRLEN - BSD_OVHD; - db->uncomp_bytes += isize; - db->in_count += isize; - ++db->uncomp_count; - ++db->seqno; - - if (bitno < 32) - { - ++db->bytes_out; /* must be set before calling bsd_check */ - } - - /* - * Generate the clear command if needed - */ - - if (bsd_check(db)) - { - OUTPUT (CLEAR); - } - - /* - * Pad dribble bits of last code with ones. - * Do not emit a completely useless byte of ones. - */ - - if (bitno != 32) - { - PUTBYTE((accm | (0xff << (bitno-8))) >> 24); - } - - /* - * Increase code size if we would have without the packet - * boundary because the decompressor will do so. - */ - - if (max_ent >= mxcode && max_ent < db->maxmaxcode) - { - db->n_bits++; - } - - /* If output length is too large then this is an incomplete frame. */ - if (wptr == NULL) - { - ++db->incomp_count; - db->incomp_bytes += isize; - olen = 0; - } - else /* Count the number of compressed frames */ - { - ++db->comp_count; - db->comp_bytes += olen; - } - - /* Return the resulting output length */ - return olen; -#undef OUTPUT -#undef PUTBYTE - } - -/* - * Update the "BSD Compress" dictionary on the receiver for - * incompressible data by pretending to compress the incoming data. - */ - -static void bsd_incomp (void *state, unsigned char *ibuf, int icnt) - { - (void) bsd_compress (state, ibuf, (char *) 0, icnt, 0); - } - -/* - * Decompress "BSD Compress". - * - * Because of patent problems, we return DECOMP_ERROR for errors - * found by inspecting the input data and for system problems, but - * DECOMP_FATALERROR for any errors which could possibly be said to - * be being detected "after" decompression. For DECOMP_ERROR, - * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be - * infringing a patent of Motorola's if we do, so we take CCP down - * instead. - * - * Given that the frame has the correct sequence number and a good FCS, - * errors such as invalid codes in the input most likely indicate a - * bug, so we return DECOMP_FATALERROR for them in order to turn off - * compression, even though they are detected by inspecting the input. - */ - -static int bsd_decompress (void *state, unsigned char *ibuf, int isize, - unsigned char *obuf, int osize) - { - struct bsd_db *db; - unsigned int max_ent; - unsigned long accm; - unsigned int bitno; /* 1st valid bit in accm */ - unsigned int n_bits; - unsigned int tgtbitno; /* bitno when we have a code */ - struct bsd_dict *dictp; - int explen; - int seq; - unsigned int incode; - unsigned int oldcode; - unsigned int finchar; - unsigned char *p; - unsigned char *wptr; - int adrs; - int ctrl; - int ilen; - int codelen; - int extra; - - db = (struct bsd_db *) state; - max_ent = db->max_ent; - accm = 0; - bitno = 32; /* 1st valid bit in accm */ - n_bits = db->n_bits; - tgtbitno = 32 - n_bits; /* bitno when we have a code */ - - /* - * Save the address/control from the PPP header - * and then get the sequence number. - */ - - adrs = PPP_ADDRESS (ibuf); - ctrl = PPP_CONTROL (ibuf); - - seq = (ibuf[4] << 8) + ibuf[5]; - - ibuf += (PPP_HDRLEN + 2); - ilen = isize - (PPP_HDRLEN + 2); - - /* - * Check the sequence number and give up if it differs from - * the value we're expecting. - */ - - if (seq != db->seqno) - { - if (db->debug) - { - printk("bsd_decomp%d: bad sequence # %d, expected %d\n", - db->unit, seq, db->seqno - 1); - } - return DECOMP_ERROR; - } - - ++db->seqno; - db->bytes_out += ilen; - - /* - * Fill in the ppp header, but not the last byte of the protocol - * (that comes from the decompressed data). - */ - - wptr = obuf; - *wptr++ = adrs; - *wptr++ = ctrl; - *wptr++ = 0; - - oldcode = CLEAR; - explen = 3; - - /* - * Keep the checkpoint correctly so that incompressible packets - * clear the dictionary at the proper times. - */ - - for (;;) - { - if (ilen-- <= 0) - { - db->in_count += (explen - 3); /* don't count the header */ - break; - } - - /* - * Accumulate bytes until we have a complete code. - * Then get the next code, relying on the 32-bit, - * unsigned accm to mask the result. - */ - - bitno -= 8; - accm |= *ibuf++ << bitno; - if (tgtbitno < bitno) - { - continue; - } - - incode = accm >> tgtbitno; - accm <<= n_bits; - bitno += n_bits; - - /* - * The dictionary must only be cleared at the end of a packet. - */ - - if (incode == CLEAR) - { - if (ilen > 0) - { - if (db->debug) - { - printk("bsd_decomp%d: bad CLEAR\n", db->unit); - } - return DECOMP_FATALERROR; /* probably a bug */ - } - - bsd_clear(db); - break; - } - - if ((incode > max_ent + 2) || (incode > db->maxmaxcode) - || (incode > max_ent && oldcode == CLEAR)) - { - if (db->debug) - { - printk("bsd_decomp%d: bad code 0x%x oldcode=0x%x ", - db->unit, incode, oldcode); - printk("max_ent=0x%x explen=%d seqno=%d\n", - max_ent, explen, db->seqno); - } - return DECOMP_FATALERROR; /* probably a bug */ - } - - /* Special case for KwKwK string. */ - if (incode > max_ent) - { - finchar = oldcode; - extra = 1; - } - else - { - finchar = incode; - extra = 0; - } - - codelen = *(lens_ptr (db, finchar)); - explen += codelen + extra; - if (explen > osize) - { - if (db->debug) - { - printk("bsd_decomp%d: ran out of mru\n", db->unit); -#ifdef DEBUG - printk(" len=%d, finchar=0x%x, codelen=%d, explen=%d\n", - ilen, finchar, codelen, explen); -#endif - } - return DECOMP_FATALERROR; - } - - /* - * Decode this code and install it in the decompressed buffer. - */ - - wptr += codelen; - p = wptr; - while (finchar > LAST) - { - struct bsd_dict *dictp2 = dict_ptr (db, finchar); - - dictp = dict_ptr (db, dictp2->cptr); -#ifdef DEBUG - if (--codelen <= 0 || dictp->codem1 != finchar-1) - { - if (codelen <= 0) - { - printk("bsd_decomp%d: fell off end of chain ", db->unit); - printk("0x%x at 0x%x by 0x%x, max_ent=0x%x\n", - incode, finchar, dictp2->cptr, max_ent); - } - else - { - if (dictp->codem1 != finchar-1) - { - printk("bsd_decomp%d: bad code chain 0x%x " - "finchar=0x%x ", - db->unit, incode, finchar); - - printk("oldcode=0x%x cptr=0x%x codem1=0x%x\n", - oldcode, dictp2->cptr, dictp->codem1); - } - } - return DECOMP_FATALERROR; - } -#endif - *--p = dictp->f.hs.suffix; - finchar = dictp->f.hs.prefix; - } - *--p = finchar; - -#ifdef DEBUG - if (--codelen != 0) - { - printk("bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n", - db->unit, codelen, incode, max_ent); - } -#endif - - if (extra) /* the KwKwK case again */ - { - *wptr++ = finchar; - } - - /* - * If not first code in a packet, and - * if not out of code space, then allocate a new code. - * - * Keep the hash table correct so it can be used - * with uncompressed packets. - */ - - if (oldcode != CLEAR && max_ent < db->maxmaxcode) - { - struct bsd_dict *dictp2, *dictp3; - unsigned short *lens1, *lens2; - unsigned long fcode; - int hval, disp, indx; - - fcode = BSD_KEY(oldcode,finchar); - hval = BSD_HASH(oldcode,finchar,db->hshift); - dictp = dict_ptr (db, hval); - - /* look for a free hash table entry */ - if (dictp->codem1 < max_ent) - { - disp = (hval == 0) ? 1 : hval; - do - { - hval += disp; - if (hval >= db->hsize) - { - hval -= db->hsize; - } - dictp = dict_ptr (db, hval); - } - while (dictp->codem1 < max_ent); - } - - /* - * Invalidate previous hash table entry - * assigned this code, and then take it over - */ - - dictp2 = dict_ptr (db, max_ent + 1); - indx = dictp2->cptr; - dictp3 = dict_ptr (db, indx); - - if (dictp3->codem1 == max_ent) - { - dictp3->codem1 = BADCODEM1; - } - - dictp2->cptr = hval; - dictp->codem1 = max_ent; - dictp->f.fcode = fcode; - db->max_ent = ++max_ent; - - /* Update the length of this string. */ - lens1 = lens_ptr (db, max_ent); - lens2 = lens_ptr (db, oldcode); - *lens1 = *lens2 + 1; - - /* Expand code size if needed. */ - if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) - { - db->n_bits = ++n_bits; - tgtbitno = 32-n_bits; - } - } - oldcode = incode; - } - - ++db->comp_count; - ++db->uncomp_count; - db->comp_bytes += isize - BSD_OVHD - PPP_HDRLEN; - db->uncomp_bytes += explen; - - if (bsd_check(db)) - { - if (db->debug) - { - printk("bsd_decomp%d: peer should have cleared dictionary on %d\n", - db->unit, db->seqno - 1); - } - } - return explen; - } - -/************************************************************* - * Table of addresses for the BSD compression module - *************************************************************/ - -static struct compressor ppp_bsd_compress = { - .compress_proto = CI_BSD_COMPRESS, - .comp_alloc = bsd_comp_alloc, - .comp_free = bsd_free, - .comp_init = bsd_comp_init, - .comp_reset = bsd_reset, - .compress = bsd_compress, - .comp_stat = bsd_comp_stats, - .decomp_alloc = bsd_decomp_alloc, - .decomp_free = bsd_free, - .decomp_init = bsd_decomp_init, - .decomp_reset = bsd_reset, - .decompress = bsd_decompress, - .incomp = bsd_incomp, - .decomp_stat = bsd_comp_stats, - .owner = THIS_MODULE -}; - -/************************************************************* - * Module support routines - *************************************************************/ - -static int __init bsdcomp_init(void) -{ - int answer = ppp_register_compressor(&ppp_bsd_compress); - if (answer == 0) - printk(KERN_INFO "PPP BSD Compression module registered\n"); - return answer; -} - -static void __exit bsdcomp_cleanup(void) -{ - ppp_unregister_compressor(&ppp_bsd_compress); -} - -module_init(bsdcomp_init); -module_exit(bsdcomp_cleanup); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS("ppp-compress-" __stringify(CI_BSD_COMPRESS)); diff --git a/drivers/net/ppp/Kconfig b/drivers/net/ppp/Kconfig new file mode 100644 index 0000000..872df3e --- /dev/null +++ b/drivers/net/ppp/Kconfig @@ -0,0 +1,175 @@ +# +# PPP network device configuration +# + +config PPP + tristate "PPP (point-to-point protocol) support" + select SLHC + ---help--- + PPP (Point to Point Protocol) is a newer and better SLIP. It serves + the same purpose: sending Internet traffic over telephone (and other + serial) lines. Ask your access provider if they support it, because + otherwise you can't use it; most Internet access providers these + days support PPP rather than SLIP. + + To use PPP, you need an additional program called pppd as described + in the PPP-HOWTO, available at + . Make sure that you have + the version of pppd recommended in . + The PPP option enlarges your kernel by about 16 KB. + + There are actually two versions of PPP: the traditional PPP for + asynchronous lines, such as regular analog phone lines, and + synchronous PPP which can be used over digital ISDN lines for + example. If you want to use PPP over phone lines or other + asynchronous serial lines, you need to say Y (or M) here and also to + the next option, "PPP support for async serial ports". For PPP over + synchronous lines, you should say Y (or M) here and to "Support + synchronous PPP", below. + + If you said Y to "Version information on all symbols" above, then + you cannot compile the PPP driver into the kernel; you can then only + compile it as a module. To compile this driver as a module, choose M + here. The module will be called ppp_generic. + +if PPP + +config PPP_BSDCOMP + tristate "PPP BSD-Compress compression" + depends on PPP + ---help--- + Support for the BSD-Compress compression method for PPP, which uses + the LZW compression method to compress each PPP packet before it is + sent over the wire. The machine at the other end of the PPP link + (usually your ISP) has to support the BSD-Compress compression + method as well for this to be useful. Even if they don't support it, + it is safe to say Y here. + + The PPP Deflate compression method ("PPP Deflate compression", + above) is preferable to BSD-Compress, because it compresses better + and is patent-free. + + Note that the BSD compression code will always be compiled as a + module; it is called bsd_comp and will show up in the directory + modules once you have said "make modules". If unsure, say N. + +config PPP_DEFLATE + tristate "PPP Deflate compression" + depends on PPP + select ZLIB_INFLATE + select ZLIB_DEFLATE + ---help--- + Support for the Deflate compression method for PPP, which uses the + Deflate algorithm (the same algorithm that gzip uses) to compress + each PPP packet before it is sent over the wire. The machine at the + other end of the PPP link (usually your ISP) has to support the + Deflate compression method as well for this to be useful. Even if + they don't support it, it is safe to say Y here. + + To compile this driver as a module, choose M here. + +config PPP_FILTER + bool "PPP filtering" + depends on PPP + ---help--- + Say Y here if you want to be able to filter the packets passing over + PPP interfaces. This allows you to control which packets count as + activity (i.e. which packets will reset the idle timer or bring up + a demand-dialed link) and which packets are to be dropped entirely. + You need to say Y here if you wish to use the pass-filter and + active-filter options to pppd. + + If unsure, say N. + +config PPP_MPPE + tristate "PPP MPPE compression (encryption) (EXPERIMENTAL)" + depends on PPP && EXPERIMENTAL + select CRYPTO + select CRYPTO_SHA1 + select CRYPTO_ARC4 + select CRYPTO_ECB + ---help--- + Support for the MPPE Encryption protocol, as employed by the + Microsoft Point-to-Point Tunneling Protocol. + + See http://pptpclient.sourceforge.net/ for information on + configuring PPTP clients and servers to utilize this method. + +config PPP_MULTILINK + bool "PPP multilink support (EXPERIMENTAL)" + depends on PPP && EXPERIMENTAL + ---help--- + PPP multilink is a protocol (defined in RFC 1990) which allows you + to combine several (logical or physical) lines into one logical PPP + connection, so that you can utilize your full bandwidth. + + This has to be supported at the other end as well and you need a + version of the pppd daemon which understands the multilink protocol. + + If unsure, say N. + +config PPPOATM + tristate "PPP over ATM" + depends on ATM && PPP + ---help--- + Support PPP (Point to Point Protocol) encapsulated in ATM frames. + This implementation does not yet comply with section 8 of RFC2364, + which can lead to bad results if the ATM peer loses state and + changes its encapsulation unilaterally. + +config PPPOE + tristate "PPP over Ethernet (EXPERIMENTAL)" + depends on EXPERIMENTAL && PPP + ---help--- + Support for PPP over Ethernet. + + This driver requires the latest version of pppd from the CVS + repository at cvs.samba.org. Alternatively, see the + RoaringPenguin package () + which contains instruction on how to use this driver (under + the heading "Kernel mode PPPoE"). + +config PPTP + tristate "PPP over IPv4 (PPTP) (EXPERIMENTAL)" + depends on EXPERIMENTAL && PPP && NET_IPGRE_DEMUX + ---help--- + Support for PPP over IPv4.(Point-to-Point Tunneling Protocol) + + This driver requires pppd plugin to work in client mode or + modified pptpd (poptop) to work in server mode. + See http://accel-pptp.sourceforge.net/ for information how to + utilize this module. + +config PPPOL2TP + tristate "PPP over L2TP (EXPERIMENTAL)" + depends on EXPERIMENTAL && L2TP && PPP + ---help--- + Support for PPP-over-L2TP socket family. L2TP is a protocol + used by ISPs and enterprises to tunnel PPP traffic over UDP + tunnels. L2TP is replacing PPTP for VPN uses. + +config PPP_ASYNC + tristate "PPP support for async serial ports" + depends on PPP + select CRC_CCITT + ---help--- + Say Y (or M) here if you want to be able to use PPP over standard + asynchronous serial ports, such as COM1 or COM2 on a PC. If you use + a modem (not a synchronous or ISDN modem) to contact your ISP, you + need this option. + + To compile this driver as a module, choose M here. + + If unsure, say Y. + +config PPP_SYNC_TTY + tristate "PPP support for sync tty ports" + depends on PPP + ---help--- + Say Y (or M) here if you want to be able to use PPP over synchronous + (HDLC) tty devices, such as the SyncLink adapter. These devices + are often used for high-speed leased lines like T1/E1. + + To compile this driver as a module, choose M here. + +endif # PPP diff --git a/drivers/net/ppp/Makefile b/drivers/net/ppp/Makefile new file mode 100644 index 0000000..a6b6297 --- /dev/null +++ b/drivers/net/ppp/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for the Linux PPP network device drivers. +# + +obj-$(CONFIG_PPP) += ppp_generic.o +obj-$(CONFIG_PPP_ASYNC) += ppp_async.o +obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o +obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o +obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o +obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o +obj-$(CONFIG_PPPOE) += pppox.o pppoe.o +obj-$(CONFIG_PPPOL2TP) += pppox.o +obj-$(CONFIG_PPTP) += pppox.o pptp.o diff --git a/drivers/net/ppp/bsd_comp.c b/drivers/net/ppp/bsd_comp.c new file mode 100644 index 0000000..a9b759a --- /dev/null +++ b/drivers/net/ppp/bsd_comp.c @@ -0,0 +1,1170 @@ +/* + * Update: The Berkeley copyright was changed, and the change + * is retroactive to all "true" BSD software (ie everything + * from UCB as opposed to other peoples code that just carried + * the same license). The new copyright doesn't clash with the + * GPL, so the module-only restriction has been removed.. + */ + +/* Because this code is derived from the 4.3BSD compress source: + * + * Copyright (c) 1985, 1986 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * James A. Woods, derived from original work by Spencer Thomas + * and Joseph Orost. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This version is for use with contiguous buffers on Linux-derived systems. + * + * ==FILEVERSION 20000226== + * + * NOTE TO MAINTAINERS: + * If you modify this file at all, please set the number above to the + * date of the modification as YYMMDD (year month day). + * bsd_comp.c is shipped with a PPP distribution as well as with + * the kernel; if everyone increases the FILEVERSION number above, + * then scripts can do the right thing when deciding whether to + * install a new bsd_comp.c file. Don't change the format of that + * line otherwise, so the installation script can recognize it. + * + * From: bsd_comp.c,v 1.3 1994/12/08 01:59:58 paulus Exp + */ + +#include +#include +#include +#include +#include + +#include + +#undef PACKETPTR +#define PACKETPTR 1 +#include +#undef PACKETPTR + +#include + +/* + * PPP "BSD compress" compression + * The differences between this compression and the classic BSD LZW + * source are obvious from the requirement that the classic code worked + * with files while this handles arbitrarily long streams that + * are broken into packets. They are: + * + * When the code size expands, a block of junk is not emitted by + * the compressor and not expected by the decompressor. + * + * New codes are not necessarily assigned every time an old + * code is output by the compressor. This is because a packet + * end forces a code to be emitted, but does not imply that a + * new sequence has been seen. + * + * The compression ratio is checked at the first end of a packet + * after the appropriate gap. Besides simplifying and speeding + * things up, this makes it more likely that the transmitter + * and receiver will agree when the dictionary is cleared when + * compression is not going well. + */ + +/* + * Macros to extract protocol version and number of bits + * from the third byte of the BSD Compress CCP configuration option. + */ + +#define BSD_VERSION(x) ((x) >> 5) +#define BSD_NBITS(x) ((x) & 0x1F) + +#define BSD_CURRENT_VERSION 1 + +/* + * A dictionary for doing BSD compress. + */ + +struct bsd_dict { + union { /* hash value */ + unsigned long fcode; + struct { +#if defined(__LITTLE_ENDIAN) /* Little endian order */ + unsigned short prefix; /* preceding code */ + unsigned char suffix; /* last character of new code */ + unsigned char pad; +#elif defined(__BIG_ENDIAN) /* Big endian order */ + unsigned char pad; + unsigned char suffix; /* last character of new code */ + unsigned short prefix; /* preceding code */ +#else +#error Endianness not defined... +#endif + } hs; + } f; + unsigned short codem1; /* output of hash table -1 */ + unsigned short cptr; /* map code to hash table entry */ +}; + +struct bsd_db { + int totlen; /* length of this structure */ + unsigned int hsize; /* size of the hash table */ + unsigned char hshift; /* used in hash function */ + unsigned char n_bits; /* current bits/code */ + unsigned char maxbits; /* maximum bits/code */ + unsigned char debug; /* non-zero if debug desired */ + unsigned char unit; /* ppp unit number */ + unsigned short seqno; /* sequence # of next packet */ + unsigned int mru; /* size of receive (decompress) bufr */ + unsigned int maxmaxcode; /* largest valid code */ + unsigned int max_ent; /* largest code in use */ + unsigned int in_count; /* uncompressed bytes, aged */ + unsigned int bytes_out; /* compressed bytes, aged */ + unsigned int ratio; /* recent compression ratio */ + unsigned int checkpoint; /* when to next check the ratio */ + unsigned int clear_count; /* times dictionary cleared */ + unsigned int incomp_count; /* incompressible packets */ + unsigned int incomp_bytes; /* incompressible bytes */ + unsigned int uncomp_count; /* uncompressed packets */ + unsigned int uncomp_bytes; /* uncompressed bytes */ + unsigned int comp_count; /* compressed packets */ + unsigned int comp_bytes; /* compressed bytes */ + unsigned short *lens; /* array of lengths of codes */ + struct bsd_dict *dict; /* dictionary */ +}; + +#define BSD_OVHD 2 /* BSD compress overhead/packet */ +#define MIN_BSD_BITS 9 +#define BSD_INIT_BITS MIN_BSD_BITS +#define MAX_BSD_BITS 15 + +static void bsd_free (void *state); +static void *bsd_alloc(unsigned char *options, int opt_len, int decomp); +static void *bsd_comp_alloc (unsigned char *options, int opt_len); +static void *bsd_decomp_alloc (unsigned char *options, int opt_len); + +static int bsd_init (void *db, unsigned char *options, + int opt_len, int unit, int debug, int decomp); +static int bsd_comp_init (void *state, unsigned char *options, + int opt_len, int unit, int opthdr, int debug); +static int bsd_decomp_init (void *state, unsigned char *options, + int opt_len, int unit, int opthdr, int mru, + int debug); + +static void bsd_reset (void *state); +static void bsd_comp_stats (void *state, struct compstat *stats); + +static int bsd_compress (void *state, unsigned char *rptr, + unsigned char *obuf, int isize, int osize); +static void bsd_incomp (void *state, unsigned char *ibuf, int icnt); + +static int bsd_decompress (void *state, unsigned char *ibuf, int isize, + unsigned char *obuf, int osize); + +/* These are in ppp_generic.c */ +extern int ppp_register_compressor (struct compressor *cp); +extern void ppp_unregister_compressor (struct compressor *cp); + +/* + * the next two codes should not be changed lightly, as they must not + * lie within the contiguous general code space. + */ +#define CLEAR 256 /* table clear output code */ +#define FIRST 257 /* first free entry */ +#define LAST 255 + +#define MAXCODE(b) ((1 << (b)) - 1) +#define BADCODEM1 MAXCODE(MAX_BSD_BITS) + +#define BSD_HASH(prefix,suffix,hshift) ((((unsigned long)(suffix))<<(hshift)) \ + ^ (unsigned long)(prefix)) +#define BSD_KEY(prefix,suffix) ((((unsigned long)(suffix)) << 16) \ + + (unsigned long)(prefix)) + +#define CHECK_GAP 10000 /* Ratio check interval */ + +#define RATIO_SCALE_LOG 8 +#define RATIO_SCALE (1<>RATIO_SCALE_LOG) + +/* + * clear the dictionary + */ + +static void +bsd_clear(struct bsd_db *db) +{ + db->clear_count++; + db->max_ent = FIRST-1; + db->n_bits = BSD_INIT_BITS; + db->bytes_out = 0; + db->in_count = 0; + db->ratio = 0; + db->checkpoint = CHECK_GAP; +} + +/* + * If the dictionary is full, then see if it is time to reset it. + * + * Compute the compression ratio using fixed-point arithmetic + * with 8 fractional bits. + * + * Since we have an infinite stream instead of a single file, + * watch only the local compression ratio. + * + * Since both peers must reset the dictionary at the same time even in + * the absence of CLEAR codes (while packets are incompressible), they + * must compute the same ratio. + */ + +static int bsd_check (struct bsd_db *db) /* 1=output CLEAR */ + { + unsigned int new_ratio; + + if (db->in_count >= db->checkpoint) + { + /* age the ratio by limiting the size of the counts */ + if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX) + { + db->in_count -= (db->in_count >> 2); + db->bytes_out -= (db->bytes_out >> 2); + } + + db->checkpoint = db->in_count + CHECK_GAP; + + if (db->max_ent >= db->maxmaxcode) + { + /* Reset the dictionary only if the ratio is worse, + * or if it looks as if it has been poisoned + * by incompressible data. + * + * This does not overflow, because + * db->in_count <= RATIO_MAX. + */ + + new_ratio = db->in_count << RATIO_SCALE_LOG; + if (db->bytes_out != 0) + { + new_ratio /= db->bytes_out; + } + + if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) + { + bsd_clear (db); + return 1; + } + db->ratio = new_ratio; + } + } + return 0; + } + +/* + * Return statistics. + */ + +static void bsd_comp_stats (void *state, struct compstat *stats) + { + struct bsd_db *db = (struct bsd_db *) state; + + stats->unc_bytes = db->uncomp_bytes; + stats->unc_packets = db->uncomp_count; + stats->comp_bytes = db->comp_bytes; + stats->comp_packets = db->comp_count; + stats->inc_bytes = db->incomp_bytes; + stats->inc_packets = db->incomp_count; + stats->in_count = db->in_count; + stats->bytes_out = db->bytes_out; + } + +/* + * Reset state, as on a CCP ResetReq. + */ + +static void bsd_reset (void *state) + { + struct bsd_db *db = (struct bsd_db *) state; + + bsd_clear(db); + + db->seqno = 0; + db->clear_count = 0; + } + +/* + * Release the compression structure + */ + +static void bsd_free (void *state) +{ + struct bsd_db *db = state; + + if (!db) + return; + +/* + * Release the dictionary + */ + vfree(db->dict); + db->dict = NULL; +/* + * Release the string buffer + */ + vfree(db->lens); + db->lens = NULL; +/* + * Finally release the structure itself. + */ + kfree(db); +} + +/* + * Allocate space for a (de) compressor. + */ + +static void *bsd_alloc (unsigned char *options, int opt_len, int decomp) + { + int bits; + unsigned int hsize, hshift, maxmaxcode; + struct bsd_db *db; + + if (opt_len != 3 || options[0] != CI_BSD_COMPRESS || options[1] != 3 + || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION) + { + return NULL; + } + + bits = BSD_NBITS(options[2]); + + switch (bits) + { + case 9: /* needs 82152 for both directions */ + case 10: /* needs 84144 */ + case 11: /* needs 88240 */ + case 12: /* needs 96432 */ + hsize = 5003; + hshift = 4; + break; + case 13: /* needs 176784 */ + hsize = 9001; + hshift = 5; + break; + case 14: /* needs 353744 */ + hsize = 18013; + hshift = 6; + break; + case 15: /* needs 691440 */ + hsize = 35023; + hshift = 7; + break; + case 16: /* needs 1366160--far too much, */ + /* hsize = 69001; */ /* and 69001 is too big for cptr */ + /* hshift = 8; */ /* in struct bsd_db */ + /* break; */ + default: + return NULL; + } +/* + * Allocate the main control structure for this instance. + */ + maxmaxcode = MAXCODE(bits); + db = kzalloc(sizeof (struct bsd_db), + GFP_KERNEL); + if (!db) + { + return NULL; + } + +/* + * Allocate space for the dictionary. This may be more than one page in + * length. + */ + db->dict = vmalloc(hsize * sizeof(struct bsd_dict)); + if (!db->dict) + { + bsd_free (db); + return NULL; + } + +/* + * If this is the compression buffer then there is no length data. + */ + if (!decomp) + { + db->lens = NULL; + } +/* + * For decompression, the length information is needed as well. + */ + else + { + db->lens = vmalloc((maxmaxcode + 1) * sizeof(db->lens[0])); + if (!db->lens) + { + bsd_free (db); + return NULL; + } + } +/* + * Initialize the data information for the compression code + */ + db->totlen = sizeof (struct bsd_db) + + (sizeof (struct bsd_dict) * hsize); + + db->hsize = hsize; + db->hshift = hshift; + db->maxmaxcode = maxmaxcode; + db->maxbits = bits; + + return (void *) db; + } + +static void *bsd_comp_alloc (unsigned char *options, int opt_len) + { + return bsd_alloc (options, opt_len, 0); + } + +static void *bsd_decomp_alloc (unsigned char *options, int opt_len) + { + return bsd_alloc (options, opt_len, 1); + } + +/* + * Initialize the database. + */ + +static int bsd_init (void *state, unsigned char *options, + int opt_len, int unit, int debug, int decomp) + { + struct bsd_db *db = state; + int indx; + + if ((opt_len != 3) || (options[0] != CI_BSD_COMPRESS) || (options[1] != 3) + || (BSD_VERSION(options[2]) != BSD_CURRENT_VERSION) + || (BSD_NBITS(options[2]) != db->maxbits) + || (decomp && db->lens == NULL)) + { + return 0; + } + + if (decomp) + { + indx = LAST; + do + { + db->lens[indx] = 1; + } + while (indx-- > 0); + } + + indx = db->hsize; + while (indx-- != 0) + { + db->dict[indx].codem1 = BADCODEM1; + db->dict[indx].cptr = 0; + } + + db->unit = unit; + db->mru = 0; +#ifndef DEBUG + if (debug) +#endif + db->debug = 1; + + bsd_reset(db); + + return 1; + } + +static int bsd_comp_init (void *state, unsigned char *options, + int opt_len, int unit, int opthdr, int debug) + { + return bsd_init (state, options, opt_len, unit, debug, 0); + } + +static int bsd_decomp_init (void *state, unsigned char *options, + int opt_len, int unit, int opthdr, int mru, + int debug) + { + return bsd_init (state, options, opt_len, unit, debug, 1); + } + +/* + * Obtain pointers to the various structures in the compression tables + */ + +#define dict_ptrx(p,idx) &(p->dict[idx]) +#define lens_ptrx(p,idx) &(p->lens[idx]) + +#ifdef DEBUG +static unsigned short *lens_ptr(struct bsd_db *db, int idx) + { + if ((unsigned int) idx > (unsigned int) db->maxmaxcode) + { + printk ("<9>ppp: lens_ptr(%d) > max\n", idx); + idx = 0; + } + return lens_ptrx (db, idx); + } + +static struct bsd_dict *dict_ptr(struct bsd_db *db, int idx) + { + if ((unsigned int) idx >= (unsigned int) db->hsize) + { + printk ("<9>ppp: dict_ptr(%d) > max\n", idx); + idx = 0; + } + return dict_ptrx (db, idx); + } + +#else +#define lens_ptr(db,idx) lens_ptrx(db,idx) +#define dict_ptr(db,idx) dict_ptrx(db,idx) +#endif + +/* + * compress a packet + * + * The result of this function is the size of the compressed + * packet. A zero is returned if the packet was not compressed + * for some reason, such as the size being larger than uncompressed. + * + * One change from the BSD compress command is that when the + * code size expands, we do not output a bunch of padding. + */ + +static int bsd_compress (void *state, unsigned char *rptr, unsigned char *obuf, + int isize, int osize) + { + struct bsd_db *db; + int hshift; + unsigned int max_ent; + unsigned int n_bits; + unsigned int bitno; + unsigned long accm; + int ent; + unsigned long fcode; + struct bsd_dict *dictp; + unsigned char c; + int hval; + int disp; + int ilen; + int mxcode; + unsigned char *wptr; + int olen; + +#define PUTBYTE(v) \ + { \ + ++olen; \ + if (wptr) \ + { \ + *wptr++ = (unsigned char) (v); \ + if (olen >= osize) \ + { \ + wptr = NULL; \ + } \ + } \ + } + +#define OUTPUT(ent) \ + { \ + bitno -= n_bits; \ + accm |= ((ent) << bitno); \ + do \ + { \ + PUTBYTE(accm >> 24); \ + accm <<= 8; \ + bitno += 8; \ + } \ + while (bitno <= 24); \ + } + + /* + * If the protocol is not in the range we're interested in, + * just return without compressing the packet. If it is, + * the protocol becomes the first byte to compress. + */ + + ent = PPP_PROTOCOL(rptr); + if (ent < 0x21 || ent > 0xf9) + { + return 0; + } + + db = (struct bsd_db *) state; + hshift = db->hshift; + max_ent = db->max_ent; + n_bits = db->n_bits; + bitno = 32; + accm = 0; + mxcode = MAXCODE (n_bits); + + /* Initialize the output pointers */ + wptr = obuf; + olen = PPP_HDRLEN + BSD_OVHD; + + if (osize > isize) + { + osize = isize; + } + + /* This is the PPP header information */ + if (wptr) + { + *wptr++ = PPP_ADDRESS(rptr); + *wptr++ = PPP_CONTROL(rptr); + *wptr++ = 0; + *wptr++ = PPP_COMP; + *wptr++ = db->seqno >> 8; + *wptr++ = db->seqno; + } + + /* Skip the input header */ + rptr += PPP_HDRLEN; + isize -= PPP_HDRLEN; + ilen = ++isize; /* Low byte of protocol is counted as input */ + + while (--ilen > 0) + { + c = *rptr++; + fcode = BSD_KEY (ent, c); + hval = BSD_HASH (ent, c, hshift); + dictp = dict_ptr (db, hval); + + /* Validate and then check the entry. */ + if (dictp->codem1 >= max_ent) + { + goto nomatch; + } + + if (dictp->f.fcode == fcode) + { + ent = dictp->codem1 + 1; + continue; /* found (prefix,suffix) */ + } + + /* continue probing until a match or invalid entry */ + disp = (hval == 0) ? 1 : hval; + + do + { + hval += disp; + if (hval >= db->hsize) + { + hval -= db->hsize; + } + dictp = dict_ptr (db, hval); + if (dictp->codem1 >= max_ent) + { + goto nomatch; + } + } + while (dictp->f.fcode != fcode); + + ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */ + continue; + +nomatch: + OUTPUT(ent); /* output the prefix */ + + /* code -> hashtable */ + if (max_ent < db->maxmaxcode) + { + struct bsd_dict *dictp2; + struct bsd_dict *dictp3; + int indx; + + /* expand code size if needed */ + if (max_ent >= mxcode) + { + db->n_bits = ++n_bits; + mxcode = MAXCODE (n_bits); + } + + /* Invalidate old hash table entry using + * this code, and then take it over. + */ + + dictp2 = dict_ptr (db, max_ent + 1); + indx = dictp2->cptr; + dictp3 = dict_ptr (db, indx); + + if (dictp3->codem1 == max_ent) + { + dictp3->codem1 = BADCODEM1; + } + + dictp2->cptr = hval; + dictp->codem1 = max_ent; + dictp->f.fcode = fcode; + db->max_ent = ++max_ent; + + if (db->lens) + { + unsigned short *len1 = lens_ptr (db, max_ent); + unsigned short *len2 = lens_ptr (db, ent); + *len1 = *len2 + 1; + } + } + ent = c; + } + + OUTPUT(ent); /* output the last code */ + + db->bytes_out += olen - PPP_HDRLEN - BSD_OVHD; + db->uncomp_bytes += isize; + db->in_count += isize; + ++db->uncomp_count; + ++db->seqno; + + if (bitno < 32) + { + ++db->bytes_out; /* must be set before calling bsd_check */ + } + + /* + * Generate the clear command if needed + */ + + if (bsd_check(db)) + { + OUTPUT (CLEAR); + } + + /* + * Pad dribble bits of last code with ones. + * Do not emit a completely useless byte of ones. + */ + + if (bitno != 32) + { + PUTBYTE((accm | (0xff << (bitno-8))) >> 24); + } + + /* + * Increase code size if we would have without the packet + * boundary because the decompressor will do so. + */ + + if (max_ent >= mxcode && max_ent < db->maxmaxcode) + { + db->n_bits++; + } + + /* If output length is too large then this is an incomplete frame. */ + if (wptr == NULL) + { + ++db->incomp_count; + db->incomp_bytes += isize; + olen = 0; + } + else /* Count the number of compressed frames */ + { + ++db->comp_count; + db->comp_bytes += olen; + } + + /* Return the resulting output length */ + return olen; +#undef OUTPUT +#undef PUTBYTE + } + +/* + * Update the "BSD Compress" dictionary on the receiver for + * incompressible data by pretending to compress the incoming data. + */ + +static void bsd_incomp (void *state, unsigned char *ibuf, int icnt) + { + (void) bsd_compress (state, ibuf, (char *) 0, icnt, 0); + } + +/* + * Decompress "BSD Compress". + * + * Because of patent problems, we return DECOMP_ERROR for errors + * found by inspecting the input data and for system problems, but + * DECOMP_FATALERROR for any errors which could possibly be said to + * be being detected "after" decompression. For DECOMP_ERROR, + * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be + * infringing a patent of Motorola's if we do, so we take CCP down + * instead. + * + * Given that the frame has the correct sequence number and a good FCS, + * errors such as invalid codes in the input most likely indicate a + * bug, so we return DECOMP_FATALERROR for them in order to turn off + * compression, even though they are detected by inspecting the input. + */ + +static int bsd_decompress (void *state, unsigned char *ibuf, int isize, + unsigned char *obuf, int osize) + { + struct bsd_db *db; + unsigned int max_ent; + unsigned long accm; + unsigned int bitno; /* 1st valid bit in accm */ + unsigned int n_bits; + unsigned int tgtbitno; /* bitno when we have a code */ + struct bsd_dict *dictp; + int explen; + int seq; + unsigned int incode; + unsigned int oldcode; + unsigned int finchar; + unsigned char *p; + unsigned char *wptr; + int adrs; + int ctrl; + int ilen; + int codelen; + int extra; + + db = (struct bsd_db *) state; + max_ent = db->max_ent; + accm = 0; + bitno = 32; /* 1st valid bit in accm */ + n_bits = db->n_bits; + tgtbitno = 32 - n_bits; /* bitno when we have a code */ + + /* + * Save the address/control from the PPP header + * and then get the sequence number. + */ + + adrs = PPP_ADDRESS (ibuf); + ctrl = PPP_CONTROL (ibuf); + + seq = (ibuf[4] << 8) + ibuf[5]; + + ibuf += (PPP_HDRLEN + 2); + ilen = isize - (PPP_HDRLEN + 2); + + /* + * Check the sequence number and give up if it differs from + * the value we're expecting. + */ + + if (seq != db->seqno) + { + if (db->debug) + { + printk("bsd_decomp%d: bad sequence # %d, expected %d\n", + db->unit, seq, db->seqno - 1); + } + return DECOMP_ERROR; + } + + ++db->seqno; + db->bytes_out += ilen; + + /* + * Fill in the ppp header, but not the last byte of the protocol + * (that comes from the decompressed data). + */ + + wptr = obuf; + *wptr++ = adrs; + *wptr++ = ctrl; + *wptr++ = 0; + + oldcode = CLEAR; + explen = 3; + + /* + * Keep the checkpoint correctly so that incompressible packets + * clear the dictionary at the proper times. + */ + + for (;;) + { + if (ilen-- <= 0) + { + db->in_count += (explen - 3); /* don't count the header */ + break; + } + + /* + * Accumulate bytes until we have a complete code. + * Then get the next code, relying on the 32-bit, + * unsigned accm to mask the result. + */ + + bitno -= 8; + accm |= *ibuf++ << bitno; + if (tgtbitno < bitno) + { + continue; + } + + incode = accm >> tgtbitno; + accm <<= n_bits; + bitno += n_bits; + + /* + * The dictionary must only be cleared at the end of a packet. + */ + + if (incode == CLEAR) + { + if (ilen > 0) + { + if (db->debug) + { + printk("bsd_decomp%d: bad CLEAR\n", db->unit); + } + return DECOMP_FATALERROR; /* probably a bug */ + } + + bsd_clear(db); + break; + } + + if ((incode > max_ent + 2) || (incode > db->maxmaxcode) + || (incode > max_ent && oldcode == CLEAR)) + { + if (db->debug) + { + printk("bsd_decomp%d: bad code 0x%x oldcode=0x%x ", + db->unit, incode, oldcode); + printk("max_ent=0x%x explen=%d seqno=%d\n", + max_ent, explen, db->seqno); + } + return DECOMP_FATALERROR; /* probably a bug */ + } + + /* Special case for KwKwK string. */ + if (incode > max_ent) + { + finchar = oldcode; + extra = 1; + } + else + { + finchar = incode; + extra = 0; + } + + codelen = *(lens_ptr (db, finchar)); + explen += codelen + extra; + if (explen > osize) + { + if (db->debug) + { + printk("bsd_decomp%d: ran out of mru\n", db->unit); +#ifdef DEBUG + printk(" len=%d, finchar=0x%x, codelen=%d, explen=%d\n", + ilen, finchar, codelen, explen); +#endif + } + return DECOMP_FATALERROR; + } + + /* + * Decode this code and install it in the decompressed buffer. + */ + + wptr += codelen; + p = wptr; + while (finchar > LAST) + { + struct bsd_dict *dictp2 = dict_ptr (db, finchar); + + dictp = dict_ptr (db, dictp2->cptr); +#ifdef DEBUG + if (--codelen <= 0 || dictp->codem1 != finchar-1) + { + if (codelen <= 0) + { + printk("bsd_decomp%d: fell off end of chain ", db->unit); + printk("0x%x at 0x%x by 0x%x, max_ent=0x%x\n", + incode, finchar, dictp2->cptr, max_ent); + } + else + { + if (dictp->codem1 != finchar-1) + { + printk("bsd_decomp%d: bad code chain 0x%x " + "finchar=0x%x ", + db->unit, incode, finchar); + + printk("oldcode=0x%x cptr=0x%x codem1=0x%x\n", + oldcode, dictp2->cptr, dictp->codem1); + } + } + return DECOMP_FATALERROR; + } +#endif + *--p = dictp->f.hs.suffix; + finchar = dictp->f.hs.prefix; + } + *--p = finchar; + +#ifdef DEBUG + if (--codelen != 0) + { + printk("bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n", + db->unit, codelen, incode, max_ent); + } +#endif + + if (extra) /* the KwKwK case again */ + { + *wptr++ = finchar; + } + + /* + * If not first code in a packet, and + * if not out of code space, then allocate a new code. + * + * Keep the hash table correct so it can be used + * with uncompressed packets. + */ + + if (oldcode != CLEAR && max_ent < db->maxmaxcode) + { + struct bsd_dict *dictp2, *dictp3; + unsigned short *lens1, *lens2; + unsigned long fcode; + int hval, disp, indx; + + fcode = BSD_KEY(oldcode,finchar); + hval = BSD_HASH(oldcode,finchar,db->hshift); + dictp = dict_ptr (db, hval); + + /* look for a free hash table entry */ + if (dictp->codem1 < max_ent) + { + disp = (hval == 0) ? 1 : hval; + do + { + hval += disp; + if (hval >= db->hsize) + { + hval -= db->hsize; + } + dictp = dict_ptr (db, hval); + } + while (dictp->codem1 < max_ent); + } + + /* + * Invalidate previous hash table entry + * assigned this code, and then take it over + */ + + dictp2 = dict_ptr (db, max_ent + 1); + indx = dictp2->cptr; + dictp3 = dict_ptr (db, indx); + + if (dictp3->codem1 == max_ent) + { + dictp3->codem1 = BADCODEM1; + } + + dictp2->cptr = hval; + dictp->codem1 = max_ent; + dictp->f.fcode = fcode; + db->max_ent = ++max_ent; + + /* Update the length of this string. */ + lens1 = lens_ptr (db, max_ent); + lens2 = lens_ptr (db, oldcode); + *lens1 = *lens2 + 1; + + /* Expand code size if needed. */ + if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) + { + db->n_bits = ++n_bits; + tgtbitno = 32-n_bits; + } + } + oldcode = incode; + } + + ++db->comp_count; + ++db->uncomp_count; + db->comp_bytes += isize - BSD_OVHD - PPP_HDRLEN; + db->uncomp_bytes += explen; + + if (bsd_check(db)) + { + if (db->debug) + { + printk("bsd_decomp%d: peer should have cleared dictionary on %d\n", + db->unit, db->seqno - 1); + } + } + return explen; + } + +/************************************************************* + * Table of addresses for the BSD compression module + *************************************************************/ + +static struct compressor ppp_bsd_compress = { + .compress_proto = CI_BSD_COMPRESS, + .comp_alloc = bsd_comp_alloc, + .comp_free = bsd_free, + .comp_init = bsd_comp_init, + .comp_reset = bsd_reset, + .compress = bsd_compress, + .comp_stat = bsd_comp_stats, + .decomp_alloc = bsd_decomp_alloc, + .decomp_free = bsd_free, + .decomp_init = bsd_decomp_init, + .decomp_reset = bsd_reset, + .decompress = bsd_decompress, + .incomp = bsd_incomp, + .decomp_stat = bsd_comp_stats, + .owner = THIS_MODULE +}; + +/************************************************************* + * Module support routines + *************************************************************/ + +static int __init bsdcomp_init(void) +{ + int answer = ppp_register_compressor(&ppp_bsd_compress); + if (answer == 0) + printk(KERN_INFO "PPP BSD Compression module registered\n"); + return answer; +} + +static void __exit bsdcomp_cleanup(void) +{ + ppp_unregister_compressor(&ppp_bsd_compress); +} + +module_init(bsdcomp_init); +module_exit(bsdcomp_cleanup); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("ppp-compress-" __stringify(CI_BSD_COMPRESS)); diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c new file mode 100644 index 0000000..c6ba643 --- /dev/null +++ b/drivers/net/ppp/ppp_async.c @@ -0,0 +1,1028 @@ +/* + * PPP async serial channel driver for Linux. + * + * Copyright 1999 Paul Mackerras. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * This driver provides the encapsulation and framing for sending + * and receiving PPP frames over async serial lines. It relies on + * the generic PPP layer to give it frames to send and to process + * received frames. It implements the PPP line discipline. + * + * Part of the code in this driver was inspired by the old async-only + * PPP driver, written by Michael Callahan and Al Longyear, and + * subsequently hacked by Paul Mackerras. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PPP_VERSION "2.4.2" + +#define OBUFSIZE 4096 + +/* Structure for storing local state. */ +struct asyncppp { + struct tty_struct *tty; + unsigned int flags; + unsigned int state; + unsigned int rbits; + int mru; + spinlock_t xmit_lock; + spinlock_t recv_lock; + unsigned long xmit_flags; + u32 xaccm[8]; + u32 raccm; + unsigned int bytes_sent; + unsigned int bytes_rcvd; + + struct sk_buff *tpkt; + int tpkt_pos; + u16 tfcs; + unsigned char *optr; + unsigned char *olim; + unsigned long last_xmit; + + struct sk_buff *rpkt; + int lcp_fcs; + struct sk_buff_head rqueue; + + struct tasklet_struct tsk; + + atomic_t refcnt; + struct semaphore dead_sem; + struct ppp_channel chan; /* interface to generic ppp layer */ + unsigned char obuf[OBUFSIZE]; +}; + +/* Bit numbers in xmit_flags */ +#define XMIT_WAKEUP 0 +#define XMIT_FULL 1 +#define XMIT_BUSY 2 + +/* State bits */ +#define SC_TOSS 1 +#define SC_ESCAPE 2 +#define SC_PREV_ERROR 4 + +/* Bits in rbits */ +#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) + +static int flag_time = HZ; +module_param(flag_time, int, 0); +MODULE_PARM_DESC(flag_time, "ppp_async: interval between flagged packets (in clock ticks)"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_LDISC(N_PPP); + +/* + * Prototypes. + */ +static int ppp_async_encode(struct asyncppp *ap); +static int ppp_async_send(struct ppp_channel *chan, struct sk_buff *skb); +static int ppp_async_push(struct asyncppp *ap); +static void ppp_async_flush_output(struct asyncppp *ap); +static void ppp_async_input(struct asyncppp *ap, const unsigned char *buf, + char *flags, int count); +static int ppp_async_ioctl(struct ppp_channel *chan, unsigned int cmd, + unsigned long arg); +static void ppp_async_process(unsigned long arg); + +static void async_lcp_peek(struct asyncppp *ap, unsigned char *data, + int len, int inbound); + +static const struct ppp_channel_ops async_ops = { + .start_xmit = ppp_async_send, + .ioctl = ppp_async_ioctl, +}; + +/* + * Routines implementing the PPP line discipline. + */ + +/* + * We have a potential race on dereferencing tty->disc_data, + * because the tty layer provides no locking at all - thus one + * cpu could be running ppp_asynctty_receive while another + * calls ppp_asynctty_close, which zeroes tty->disc_data and + * frees the memory that ppp_asynctty_receive is using. The best + * way to fix this is to use a rwlock in the tty struct, but for now + * we use a single global rwlock for all ttys in ppp line discipline. + * + * FIXME: this is no longer true. The _close path for the ldisc is + * now guaranteed to be sane. + */ +static DEFINE_RWLOCK(disc_data_lock); + +static struct asyncppp *ap_get(struct tty_struct *tty) +{ + struct asyncppp *ap; + + read_lock(&disc_data_lock); + ap = tty->disc_data; + if (ap != NULL) + atomic_inc(&ap->refcnt); + read_unlock(&disc_data_lock); + return ap; +} + +static void ap_put(struct asyncppp *ap) +{ + if (atomic_dec_and_test(&ap->refcnt)) + up(&ap->dead_sem); +} + +/* + * Called when a tty is put into PPP line discipline. Called in process + * context. + */ +static int +ppp_asynctty_open(struct tty_struct *tty) +{ + struct asyncppp *ap; + int err; + int speed; + + if (tty->ops->write == NULL) + return -EOPNOTSUPP; + + err = -ENOMEM; + ap = kzalloc(sizeof(*ap), GFP_KERNEL); + if (!ap) + goto out; + + /* initialize the asyncppp structure */ + ap->tty = tty; + ap->mru = PPP_MRU; + spin_lock_init(&ap->xmit_lock); + spin_lock_init(&ap->recv_lock); + ap->xaccm[0] = ~0U; + ap->xaccm[3] = 0x60000000U; + ap->raccm = ~0U; + ap->optr = ap->obuf; + ap->olim = ap->obuf; + ap->lcp_fcs = -1; + + skb_queue_head_init(&ap->rqueue); + tasklet_init(&ap->tsk, ppp_async_process, (unsigned long) ap); + + atomic_set(&ap->refcnt, 1); + sema_init(&ap->dead_sem, 0); + + ap->chan.private = ap; + ap->chan.ops = &async_ops; + ap->chan.mtu = PPP_MRU; + speed = tty_get_baud_rate(tty); + ap->chan.speed = speed; + err = ppp_register_channel(&ap->chan); + if (err) + goto out_free; + + tty->disc_data = ap; + tty->receive_room = 65536; + return 0; + + out_free: + kfree(ap); + out: + return err; +} + +/* + * Called when the tty is put into another line discipline + * or it hangs up. We have to wait for any cpu currently + * executing in any of the other ppp_asynctty_* routines to + * finish before we can call ppp_unregister_channel and free + * the asyncppp struct. This routine must be called from + * process context, not interrupt or softirq context. + */ +static void +ppp_asynctty_close(struct tty_struct *tty) +{ + struct asyncppp *ap; + + write_lock_irq(&disc_data_lock); + ap = tty->disc_data; + tty->disc_data = NULL; + write_unlock_irq(&disc_data_lock); + if (!ap) + return; + + /* + * We have now ensured that nobody can start using ap from now + * on, but we have to wait for all existing users to finish. + * Note that ppp_unregister_channel ensures that no calls to + * our channel ops (i.e. ppp_async_send/ioctl) are in progress + * by the time it returns. + */ + if (!atomic_dec_and_test(&ap->refcnt)) + down(&ap->dead_sem); + tasklet_kill(&ap->tsk); + + ppp_unregister_channel(&ap->chan); + kfree_skb(ap->rpkt); + skb_queue_purge(&ap->rqueue); + kfree_skb(ap->tpkt); + kfree(ap); +} + +/* + * Called on tty hangup in process context. + * + * Wait for I/O to driver to complete and unregister PPP channel. + * This is already done by the close routine, so just call that. + */ +static int ppp_asynctty_hangup(struct tty_struct *tty) +{ + ppp_asynctty_close(tty); + return 0; +} + +/* + * Read does nothing - no data is ever available this way. + * Pppd reads and writes packets via /dev/ppp instead. + */ +static ssize_t +ppp_asynctty_read(struct tty_struct *tty, struct file *file, + unsigned char __user *buf, size_t count) +{ + return -EAGAIN; +} + +/* + * Write on the tty does nothing, the packets all come in + * from the ppp generic stuff. + */ +static ssize_t +ppp_asynctty_write(struct tty_struct *tty, struct file *file, + const unsigned char *buf, size_t count) +{ + return -EAGAIN; +} + +/* + * Called in process context only. May be re-entered by multiple + * ioctl calling threads. + */ + +static int +ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct asyncppp *ap = ap_get(tty); + int err, val; + int __user *p = (int __user *)arg; + + if (!ap) + return -ENXIO; + err = -EFAULT; + switch (cmd) { + case PPPIOCGCHAN: + err = -EFAULT; + if (put_user(ppp_channel_index(&ap->chan), p)) + break; + err = 0; + break; + + case PPPIOCGUNIT: + err = -EFAULT; + if (put_user(ppp_unit_number(&ap->chan), p)) + break; + err = 0; + break; + + case TCFLSH: + /* flush our buffers and the serial port's buffer */ + if (arg == TCIOFLUSH || arg == TCOFLUSH) + ppp_async_flush_output(ap); + err = tty_perform_flush(tty, arg); + break; + + case FIONREAD: + val = 0; + if (put_user(val, p)) + break; + err = 0; + break; + + default: + /* Try the various mode ioctls */ + err = tty_mode_ioctl(tty, file, cmd, arg); + } + + ap_put(ap); + return err; +} + +/* No kernel lock - fine */ +static unsigned int +ppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait) +{ + return 0; +} + +/* May sleep, don't call from interrupt level or with interrupts disabled */ +static void +ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf, + char *cflags, int count) +{ + struct asyncppp *ap = ap_get(tty); + unsigned long flags; + + if (!ap) + return; + spin_lock_irqsave(&ap->recv_lock, flags); + ppp_async_input(ap, buf, cflags, count); + spin_unlock_irqrestore(&ap->recv_lock, flags); + if (!skb_queue_empty(&ap->rqueue)) + tasklet_schedule(&ap->tsk); + ap_put(ap); + tty_unthrottle(tty); +} + +static void +ppp_asynctty_wakeup(struct tty_struct *tty) +{ + struct asyncppp *ap = ap_get(tty); + + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + if (!ap) + return; + set_bit(XMIT_WAKEUP, &ap->xmit_flags); + tasklet_schedule(&ap->tsk); + ap_put(ap); +} + + +static struct tty_ldisc_ops ppp_ldisc = { + .owner = THIS_MODULE, + .magic = TTY_LDISC_MAGIC, + .name = "ppp", + .open = ppp_asynctty_open, + .close = ppp_asynctty_close, + .hangup = ppp_asynctty_hangup, + .read = ppp_asynctty_read, + .write = ppp_asynctty_write, + .ioctl = ppp_asynctty_ioctl, + .poll = ppp_asynctty_poll, + .receive_buf = ppp_asynctty_receive, + .write_wakeup = ppp_asynctty_wakeup, +}; + +static int __init +ppp_async_init(void) +{ + int err; + + err = tty_register_ldisc(N_PPP, &ppp_ldisc); + if (err != 0) + printk(KERN_ERR "PPP_async: error %d registering line disc.\n", + err); + return err; +} + +/* + * The following routines provide the PPP channel interface. + */ +static int +ppp_async_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg) +{ + struct asyncppp *ap = chan->private; + void __user *argp = (void __user *)arg; + int __user *p = argp; + int err, val; + u32 accm[8]; + + err = -EFAULT; + switch (cmd) { + case PPPIOCGFLAGS: + val = ap->flags | ap->rbits; + if (put_user(val, p)) + break; + err = 0; + break; + case PPPIOCSFLAGS: + if (get_user(val, p)) + break; + ap->flags = val & ~SC_RCV_BITS; + spin_lock_irq(&ap->recv_lock); + ap->rbits = val & SC_RCV_BITS; + spin_unlock_irq(&ap->recv_lock); + err = 0; + break; + + case PPPIOCGASYNCMAP: + if (put_user(ap->xaccm[0], (u32 __user *)argp)) + break; + err = 0; + break; + case PPPIOCSASYNCMAP: + if (get_user(ap->xaccm[0], (u32 __user *)argp)) + break; + err = 0; + break; + + case PPPIOCGRASYNCMAP: + if (put_user(ap->raccm, (u32 __user *)argp)) + break; + err = 0; + break; + case PPPIOCSRASYNCMAP: + if (get_user(ap->raccm, (u32 __user *)argp)) + break; + err = 0; + break; + + case PPPIOCGXASYNCMAP: + if (copy_to_user(argp, ap->xaccm, sizeof(ap->xaccm))) + break; + err = 0; + break; + case PPPIOCSXASYNCMAP: + if (copy_from_user(accm, argp, sizeof(accm))) + break; + accm[2] &= ~0x40000000U; /* can't escape 0x5e */ + accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */ + memcpy(ap->xaccm, accm, sizeof(ap->xaccm)); + err = 0; + break; + + case PPPIOCGMRU: + if (put_user(ap->mru, p)) + break; + err = 0; + break; + case PPPIOCSMRU: + if (get_user(val, p)) + break; + if (val < PPP_MRU) + val = PPP_MRU; + ap->mru = val; + err = 0; + break; + + default: + err = -ENOTTY; + } + + return err; +} + +/* + * This is called at softirq level to deliver received packets + * to the ppp_generic code, and to tell the ppp_generic code + * if we can accept more output now. + */ +static void ppp_async_process(unsigned long arg) +{ + struct asyncppp *ap = (struct asyncppp *) arg; + struct sk_buff *skb; + + /* process received packets */ + while ((skb = skb_dequeue(&ap->rqueue)) != NULL) { + if (skb->cb[0]) + ppp_input_error(&ap->chan, 0); + ppp_input(&ap->chan, skb); + } + + /* try to push more stuff out */ + if (test_bit(XMIT_WAKEUP, &ap->xmit_flags) && ppp_async_push(ap)) + ppp_output_wakeup(&ap->chan); +} + +/* + * Procedures for encapsulation and framing. + */ + +/* + * Procedure to encode the data for async serial transmission. + * Does octet stuffing (escaping), puts the address/control bytes + * on if A/C compression is disabled, and does protocol compression. + * Assumes ap->tpkt != 0 on entry. + * Returns 1 if we finished the current frame, 0 otherwise. + */ + +#define PUT_BYTE(ap, buf, c, islcp) do { \ + if ((islcp && c < 0x20) || (ap->xaccm[c >> 5] & (1 << (c & 0x1f)))) {\ + *buf++ = PPP_ESCAPE; \ + *buf++ = c ^ PPP_TRANS; \ + } else \ + *buf++ = c; \ +} while (0) + +static int +ppp_async_encode(struct asyncppp *ap) +{ + int fcs, i, count, c, proto; + unsigned char *buf, *buflim; + unsigned char *data; + int islcp; + + buf = ap->obuf; + ap->olim = buf; + ap->optr = buf; + i = ap->tpkt_pos; + data = ap->tpkt->data; + count = ap->tpkt->len; + fcs = ap->tfcs; + proto = get_unaligned_be16(data); + + /* + * LCP packets with code values between 1 (configure-reqest) + * and 7 (code-reject) must be sent as though no options + * had been negotiated. + */ + islcp = proto == PPP_LCP && 1 <= data[2] && data[2] <= 7; + + if (i == 0) { + if (islcp) + async_lcp_peek(ap, data, count, 0); + + /* + * Start of a new packet - insert the leading FLAG + * character if necessary. + */ + if (islcp || flag_time == 0 || + time_after_eq(jiffies, ap->last_xmit + flag_time)) + *buf++ = PPP_FLAG; + ap->last_xmit = jiffies; + fcs = PPP_INITFCS; + + /* + * Put in the address/control bytes if necessary + */ + if ((ap->flags & SC_COMP_AC) == 0 || islcp) { + PUT_BYTE(ap, buf, 0xff, islcp); + fcs = PPP_FCS(fcs, 0xff); + PUT_BYTE(ap, buf, 0x03, islcp); + fcs = PPP_FCS(fcs, 0x03); + } + } + + /* + * Once we put in the last byte, we need to put in the FCS + * and closing flag, so make sure there is at least 7 bytes + * of free space in the output buffer. + */ + buflim = ap->obuf + OBUFSIZE - 6; + while (i < count && buf < buflim) { + c = data[i++]; + if (i == 1 && c == 0 && (ap->flags & SC_COMP_PROT)) + continue; /* compress protocol field */ + fcs = PPP_FCS(fcs, c); + PUT_BYTE(ap, buf, c, islcp); + } + + if (i < count) { + /* + * Remember where we are up to in this packet. + */ + ap->olim = buf; + ap->tpkt_pos = i; + ap->tfcs = fcs; + return 0; + } + + /* + * We have finished the packet. Add the FCS and flag. + */ + fcs = ~fcs; + c = fcs & 0xff; + PUT_BYTE(ap, buf, c, islcp); + c = (fcs >> 8) & 0xff; + PUT_BYTE(ap, buf, c, islcp); + *buf++ = PPP_FLAG; + ap->olim = buf; + + kfree_skb(ap->tpkt); + ap->tpkt = NULL; + return 1; +} + +/* + * Transmit-side routines. + */ + +/* + * Send a packet to the peer over an async tty line. + * Returns 1 iff the packet was accepted. + * If the packet was not accepted, we will call ppp_output_wakeup + * at some later time. + */ +static int +ppp_async_send(struct ppp_channel *chan, struct sk_buff *skb) +{ + struct asyncppp *ap = chan->private; + + ppp_async_push(ap); + + if (test_and_set_bit(XMIT_FULL, &ap->xmit_flags)) + return 0; /* already full */ + ap->tpkt = skb; + ap->tpkt_pos = 0; + + ppp_async_push(ap); + return 1; +} + +/* + * Push as much data as possible out to the tty. + */ +static int +ppp_async_push(struct asyncppp *ap) +{ + int avail, sent, done = 0; + struct tty_struct *tty = ap->tty; + int tty_stuffed = 0; + + /* + * We can get called recursively here if the tty write + * function calls our wakeup function. This can happen + * for example on a pty with both the master and slave + * set to PPP line discipline. + * We use the XMIT_BUSY bit to detect this and get out, + * leaving the XMIT_WAKEUP bit set to tell the other + * instance that it may now be able to write more now. + */ + if (test_and_set_bit(XMIT_BUSY, &ap->xmit_flags)) + return 0; + spin_lock_bh(&ap->xmit_lock); + for (;;) { + if (test_and_clear_bit(XMIT_WAKEUP, &ap->xmit_flags)) + tty_stuffed = 0; + if (!tty_stuffed && ap->optr < ap->olim) { + avail = ap->olim - ap->optr; + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + sent = tty->ops->write(tty, ap->optr, avail); + if (sent < 0) + goto flush; /* error, e.g. loss of CD */ + ap->optr += sent; + if (sent < avail) + tty_stuffed = 1; + continue; + } + if (ap->optr >= ap->olim && ap->tpkt) { + if (ppp_async_encode(ap)) { + /* finished processing ap->tpkt */ + clear_bit(XMIT_FULL, &ap->xmit_flags); + done = 1; + } + continue; + } + /* + * We haven't made any progress this time around. + * Clear XMIT_BUSY to let other callers in, but + * after doing so we have to check if anyone set + * XMIT_WAKEUP since we last checked it. If they + * did, we should try again to set XMIT_BUSY and go + * around again in case XMIT_BUSY was still set when + * the other caller tried. + */ + clear_bit(XMIT_BUSY, &ap->xmit_flags); + /* any more work to do? if not, exit the loop */ + if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags) || + (!tty_stuffed && ap->tpkt))) + break; + /* more work to do, see if we can do it now */ + if (test_and_set_bit(XMIT_BUSY, &ap->xmit_flags)) + break; + } + spin_unlock_bh(&ap->xmit_lock); + return done; + +flush: + clear_bit(XMIT_BUSY, &ap->xmit_flags); + if (ap->tpkt) { + kfree_skb(ap->tpkt); + ap->tpkt = NULL; + clear_bit(XMIT_FULL, &ap->xmit_flags); + done = 1; + } + ap->optr = ap->olim; + spin_unlock_bh(&ap->xmit_lock); + return done; +} + +/* + * Flush output from our internal buffers. + * Called for the TCFLSH ioctl. Can be entered in parallel + * but this is covered by the xmit_lock. + */ +static void +ppp_async_flush_output(struct asyncppp *ap) +{ + int done = 0; + + spin_lock_bh(&ap->xmit_lock); + ap->optr = ap->olim; + if (ap->tpkt != NULL) { + kfree_skb(ap->tpkt); + ap->tpkt = NULL; + clear_bit(XMIT_FULL, &ap->xmit_flags); + done = 1; + } + spin_unlock_bh(&ap->xmit_lock); + if (done) + ppp_output_wakeup(&ap->chan); +} + +/* + * Receive-side routines. + */ + +/* see how many ordinary chars there are at the start of buf */ +static inline int +scan_ordinary(struct asyncppp *ap, const unsigned char *buf, int count) +{ + int i, c; + + for (i = 0; i < count; ++i) { + c = buf[i]; + if (c == PPP_ESCAPE || c == PPP_FLAG || + (c < 0x20 && (ap->raccm & (1 << c)) != 0)) + break; + } + return i; +} + +/* called when a flag is seen - do end-of-packet processing */ +static void +process_input_packet(struct asyncppp *ap) +{ + struct sk_buff *skb; + unsigned char *p; + unsigned int len, fcs, proto; + + skb = ap->rpkt; + if (ap->state & (SC_TOSS | SC_ESCAPE)) + goto err; + + if (skb == NULL) + return; /* 0-length packet */ + + /* check the FCS */ + p = skb->data; + len = skb->len; + if (len < 3) + goto err; /* too short */ + fcs = PPP_INITFCS; + for (; len > 0; --len) + fcs = PPP_FCS(fcs, *p++); + if (fcs != PPP_GOODFCS) + goto err; /* bad FCS */ + skb_trim(skb, skb->len - 2); + + /* check for address/control and protocol compression */ + p = skb->data; + if (p[0] == PPP_ALLSTATIONS) { + /* chop off address/control */ + if (p[1] != PPP_UI || skb->len < 3) + goto err; + p = skb_pull(skb, 2); + } + proto = p[0]; + if (proto & 1) { + /* protocol is compressed */ + skb_push(skb, 1)[0] = 0; + } else { + if (skb->len < 2) + goto err; + proto = (proto << 8) + p[1]; + if (proto == PPP_LCP) + async_lcp_peek(ap, p, skb->len, 1); + } + + /* queue the frame to be processed */ + skb->cb[0] = ap->state; + skb_queue_tail(&ap->rqueue, skb); + ap->rpkt = NULL; + ap->state = 0; + return; + + err: + /* frame had an error, remember that, reset SC_TOSS & SC_ESCAPE */ + ap->state = SC_PREV_ERROR; + if (skb) { + /* make skb appear as freshly allocated */ + skb_trim(skb, 0); + skb_reserve(skb, - skb_headroom(skb)); + } +} + +/* Called when the tty driver has data for us. Runs parallel with the + other ldisc functions but will not be re-entered */ + +static void +ppp_async_input(struct asyncppp *ap, const unsigned char *buf, + char *flags, int count) +{ + struct sk_buff *skb; + int c, i, j, n, s, f; + unsigned char *sp; + + /* update bits used for 8-bit cleanness detection */ + if (~ap->rbits & SC_RCV_BITS) { + s = 0; + for (i = 0; i < count; ++i) { + c = buf[i]; + if (flags && flags[i] != 0) + continue; + s |= (c & 0x80)? SC_RCV_B7_1: SC_RCV_B7_0; + c = ((c >> 4) ^ c) & 0xf; + s |= (0x6996 & (1 << c))? SC_RCV_ODDP: SC_RCV_EVNP; + } + ap->rbits |= s; + } + + while (count > 0) { + /* scan through and see how many chars we can do in bulk */ + if ((ap->state & SC_ESCAPE) && buf[0] == PPP_ESCAPE) + n = 1; + else + n = scan_ordinary(ap, buf, count); + + f = 0; + if (flags && (ap->state & SC_TOSS) == 0) { + /* check the flags to see if any char had an error */ + for (j = 0; j < n; ++j) + if ((f = flags[j]) != 0) + break; + } + if (f != 0) { + /* start tossing */ + ap->state |= SC_TOSS; + + } else if (n > 0 && (ap->state & SC_TOSS) == 0) { + /* stuff the chars in the skb */ + skb = ap->rpkt; + if (!skb) { + skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2); + if (!skb) + goto nomem; + ap->rpkt = skb; + } + if (skb->len == 0) { + /* Try to get the payload 4-byte aligned. + * This should match the + * PPP_ALLSTATIONS/PPP_UI/compressed tests in + * process_input_packet, but we do not have + * enough chars here to test buf[1] and buf[2]. + */ + if (buf[0] != PPP_ALLSTATIONS) + skb_reserve(skb, 2 + (buf[0] & 1)); + } + if (n > skb_tailroom(skb)) { + /* packet overflowed MRU */ + ap->state |= SC_TOSS; + } else { + sp = skb_put(skb, n); + memcpy(sp, buf, n); + if (ap->state & SC_ESCAPE) { + sp[0] ^= PPP_TRANS; + ap->state &= ~SC_ESCAPE; + } + } + } + + if (n >= count) + break; + + c = buf[n]; + if (flags != NULL && flags[n] != 0) { + ap->state |= SC_TOSS; + } else if (c == PPP_FLAG) { + process_input_packet(ap); + } else if (c == PPP_ESCAPE) { + ap->state |= SC_ESCAPE; + } else if (I_IXON(ap->tty)) { + if (c == START_CHAR(ap->tty)) + start_tty(ap->tty); + else if (c == STOP_CHAR(ap->tty)) + stop_tty(ap->tty); + } + /* otherwise it's a char in the recv ACCM */ + ++n; + + buf += n; + if (flags) + flags += n; + count -= n; + } + return; + + nomem: + printk(KERN_ERR "PPPasync: no memory (input pkt)\n"); + ap->state |= SC_TOSS; +} + +/* + * We look at LCP frames going past so that we can notice + * and react to the LCP configure-ack from the peer. + * In the situation where the peer has been sent a configure-ack + * already, LCP is up once it has sent its configure-ack + * so the immediately following packet can be sent with the + * configured LCP options. This allows us to process the following + * packet correctly without pppd needing to respond quickly. + * + * We only respond to the received configure-ack if we have just + * sent a configure-request, and the configure-ack contains the + * same data (this is checked using a 16-bit crc of the data). + */ +#define CONFREQ 1 /* LCP code field values */ +#define CONFACK 2 +#define LCP_MRU 1 /* LCP option numbers */ +#define LCP_ASYNCMAP 2 + +static void async_lcp_peek(struct asyncppp *ap, unsigned char *data, + int len, int inbound) +{ + int dlen, fcs, i, code; + u32 val; + + data += 2; /* skip protocol bytes */ + len -= 2; + if (len < 4) /* 4 = code, ID, length */ + return; + code = data[0]; + if (code != CONFACK && code != CONFREQ) + return; + dlen = get_unaligned_be16(data + 2); + if (len < dlen) + return; /* packet got truncated or length is bogus */ + + if (code == (inbound? CONFACK: CONFREQ)) { + /* + * sent confreq or received confack: + * calculate the crc of the data from the ID field on. + */ + fcs = PPP_INITFCS; + for (i = 1; i < dlen; ++i) + fcs = PPP_FCS(fcs, data[i]); + + if (!inbound) { + /* outbound confreq - remember the crc for later */ + ap->lcp_fcs = fcs; + return; + } + + /* received confack, check the crc */ + fcs ^= ap->lcp_fcs; + ap->lcp_fcs = -1; + if (fcs != 0) + return; + } else if (inbound) + return; /* not interested in received confreq */ + + /* process the options in the confack */ + data += 4; + dlen -= 4; + /* data[0] is code, data[1] is length */ + while (dlen >= 2 && dlen >= data[1] && data[1] >= 2) { + switch (data[0]) { + case LCP_MRU: + val = get_unaligned_be16(data + 2); + if (inbound) + ap->mru = val; + else + ap->chan.mtu = val; + break; + case LCP_ASYNCMAP: + val = get_unaligned_be32(data + 2); + if (inbound) + ap->raccm = val; + else + ap->xaccm[0] = val; + break; + } + dlen -= data[1]; + data += data[1]; + } +} + +static void __exit ppp_async_cleanup(void) +{ + if (tty_unregister_ldisc(N_PPP) != 0) + printk(KERN_ERR "failed to unregister PPP line discipline\n"); +} + +module_init(ppp_async_init); +module_exit(ppp_async_cleanup); diff --git a/drivers/net/ppp/ppp_deflate.c b/drivers/net/ppp/ppp_deflate.c new file mode 100644 index 0000000..1dbdf82 --- /dev/null +++ b/drivers/net/ppp/ppp_deflate.c @@ -0,0 +1,653 @@ +/* + * ==FILEVERSION 980319== + * + * ppp_deflate.c - interface the zlib procedures for Deflate compression + * and decompression (as used by gzip) to the PPP code. + * This version is for use with Linux kernel 1.3.X. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + * + * From: deflate.c,v 1.1 1996/01/18 03:17:48 paulus Exp + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +/* + * State for a Deflate (de)compressor. + */ +struct ppp_deflate_state { + int seqno; + int w_size; + int unit; + int mru; + int debug; + z_stream strm; + struct compstat stats; +}; + +#define DEFLATE_OVHD 2 /* Deflate overhead/packet */ + +static void *z_comp_alloc(unsigned char *options, int opt_len); +static void *z_decomp_alloc(unsigned char *options, int opt_len); +static void z_comp_free(void *state); +static void z_decomp_free(void *state); +static int z_comp_init(void *state, unsigned char *options, + int opt_len, + int unit, int hdrlen, int debug); +static int z_decomp_init(void *state, unsigned char *options, + int opt_len, + int unit, int hdrlen, int mru, int debug); +static int z_compress(void *state, unsigned char *rptr, + unsigned char *obuf, + int isize, int osize); +static void z_incomp(void *state, unsigned char *ibuf, int icnt); +static int z_decompress(void *state, unsigned char *ibuf, + int isize, unsigned char *obuf, int osize); +static void z_comp_reset(void *state); +static void z_decomp_reset(void *state); +static void z_comp_stats(void *state, struct compstat *stats); + +/** + * z_comp_free - free the memory used by a compressor + * @arg: pointer to the private state for the compressor. + */ +static void z_comp_free(void *arg) +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + + if (state) { + zlib_deflateEnd(&state->strm); + vfree(state->strm.workspace); + kfree(state); + } +} + +/** + * z_comp_alloc - allocate space for a compressor. + * @options: pointer to CCP option data + * @opt_len: length of the CCP option at @options. + * + * The @options pointer points to the a buffer containing the + * CCP option data for the compression being negotiated. It is + * formatted according to RFC1979, and describes the window + * size that the peer is requesting that we use in compressing + * data to be sent to it. + * + * Returns the pointer to the private state for the compressor, + * or NULL if we could not allocate enough memory. + */ +static void *z_comp_alloc(unsigned char *options, int opt_len) +{ + struct ppp_deflate_state *state; + int w_size; + + 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) + return NULL; + w_size = DEFLATE_SIZE(options[2]); + if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) + return NULL; + + state = kzalloc(sizeof(*state), + GFP_KERNEL); + if (state == NULL) + return NULL; + + state->strm.next_in = NULL; + state->w_size = w_size; + state->strm.workspace = vmalloc(zlib_deflate_workspacesize(-w_size, 8)); + if (state->strm.workspace == NULL) + goto out_free; + + if (zlib_deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION, + DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY) + != Z_OK) + goto out_free; + return (void *) state; + +out_free: + z_comp_free(state); + return NULL; +} + +/** + * z_comp_init - initialize a previously-allocated compressor. + * @arg: pointer to the private state for the compressor + * @options: pointer to the CCP option data describing the + * compression that was negotiated with the peer + * @opt_len: length of the CCP option data at @options + * @unit: PPP unit number for diagnostic messages + * @hdrlen: ignored (present for backwards compatibility) + * @debug: debug flag; if non-zero, debug messages are printed. + * + * The CCP options described by @options must match the options + * specified when the compressor was allocated. The compressor + * history is reset. Returns 0 for failure (CCP options don't + * match) or 1 for success. + */ +static int z_comp_init(void *arg, unsigned char *options, int opt_len, + int unit, int hdrlen, int debug) +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + + 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 || + options[3] != DEFLATE_CHK_SEQUENCE) + return 0; + + state->seqno = 0; + state->unit = unit; + state->debug = debug; + + zlib_deflateReset(&state->strm); + + return 1; +} + +/** + * z_comp_reset - reset a previously-allocated compressor. + * @arg: pointer to private state for the compressor. + * + * This clears the history for the compressor and makes it + * ready to start emitting a new compressed stream. + */ +static void z_comp_reset(void *arg) +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + + state->seqno = 0; + zlib_deflateReset(&state->strm); +} + +/** + * z_compress - compress a PPP packet with Deflate compression. + * @arg: pointer to private state for the compressor + * @rptr: uncompressed packet (input) + * @obuf: compressed packet (output) + * @isize: size of uncompressed packet + * @osize: space available at @obuf + * + * Returns the length of the compressed packet, or 0 if the + * packet is incompressible. + */ +static int z_compress(void *arg, unsigned char *rptr, unsigned char *obuf, + int isize, int osize) +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + int r, proto, off, olen, oavail; + unsigned char *wptr; + + /* + * Check that the protocol is in the range we handle. + */ + proto = PPP_PROTOCOL(rptr); + if (proto > 0x3fff || proto == 0xfd || proto == 0xfb) + return 0; + + /* Don't generate compressed packets which are larger than + the uncompressed packet. */ + if (osize > isize) + osize = isize; + + wptr = obuf; + + /* + * Copy over the PPP header and store the 2-byte sequence number. + */ + wptr[0] = PPP_ADDRESS(rptr); + wptr[1] = PPP_CONTROL(rptr); + put_unaligned_be16(PPP_COMP, wptr + 2); + wptr += PPP_HDRLEN; + put_unaligned_be16(state->seqno, wptr); + wptr += DEFLATE_OVHD; + olen = PPP_HDRLEN + DEFLATE_OVHD; + state->strm.next_out = wptr; + state->strm.avail_out = oavail = osize - olen; + ++state->seqno; + + off = (proto > 0xff) ? 2 : 3; /* skip 1st proto byte if 0 */ + rptr += off; + state->strm.next_in = rptr; + state->strm.avail_in = (isize - off); + + for (;;) { + r = zlib_deflate(&state->strm, Z_PACKET_FLUSH); + if (r != Z_OK) { + if (state->debug) + printk(KERN_ERR + "z_compress: deflate returned %d\n", r); + break; + } + if (state->strm.avail_out == 0) { + olen += oavail; + state->strm.next_out = NULL; + state->strm.avail_out = oavail = 1000000; + } else { + break; /* all done */ + } + } + olen += oavail - state->strm.avail_out; + + /* + * See if we managed to reduce the size of the packet. + */ + if (olen < isize) { + state->stats.comp_bytes += olen; + state->stats.comp_packets++; + } else { + state->stats.inc_bytes += isize; + state->stats.inc_packets++; + olen = 0; + } + state->stats.unc_bytes += isize; + state->stats.unc_packets++; + + return olen; +} + +/** + * z_comp_stats - return compression statistics for a compressor + * or decompressor. + * @arg: pointer to private space for the (de)compressor + * @stats: pointer to a struct compstat to receive the result. + */ +static void z_comp_stats(void *arg, struct compstat *stats) +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + + *stats = state->stats; +} + +/** + * z_decomp_free - Free the memory used by a decompressor. + * @arg: pointer to private space for the decompressor. + */ +static void z_decomp_free(void *arg) +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + + if (state) { + zlib_inflateEnd(&state->strm); + vfree(state->strm.workspace); + kfree(state); + } +} + +/** + * z_decomp_alloc - allocate space for a decompressor. + * @options: pointer to CCP option data + * @opt_len: length of the CCP option at @options. + * + * The @options pointer points to the a buffer containing the + * CCP option data for the compression being negotiated. It is + * formatted according to RFC1979, and describes the window + * size that we are requesting the peer to use in compressing + * data to be sent to us. + * + * Returns the pointer to the private state for the decompressor, + * or NULL if we could not allocate enough memory. + */ +static void *z_decomp_alloc(unsigned char *options, int opt_len) +{ + struct ppp_deflate_state *state; + int w_size; + + 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) + return NULL; + w_size = DEFLATE_SIZE(options[2]); + if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) + return NULL; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (state == NULL) + return NULL; + + state->w_size = w_size; + state->strm.next_out = NULL; + state->strm.workspace = vmalloc(zlib_inflate_workspacesize()); + if (state->strm.workspace == NULL) + goto out_free; + + if (zlib_inflateInit2(&state->strm, -w_size) != Z_OK) + goto out_free; + return (void *) state; + +out_free: + z_decomp_free(state); + return NULL; +} + +/** + * z_decomp_init - initialize a previously-allocated decompressor. + * @arg: pointer to the private state for the decompressor + * @options: pointer to the CCP option data describing the + * compression that was negotiated with the peer + * @opt_len: length of the CCP option data at @options + * @unit: PPP unit number for diagnostic messages + * @hdrlen: ignored (present for backwards compatibility) + * @mru: maximum length of decompressed packets + * @debug: debug flag; if non-zero, debug messages are printed. + * + * The CCP options described by @options must match the options + * specified when the decompressor was allocated. The decompressor + * history is reset. Returns 0 for failure (CCP options don't + * match) or 1 for success. + */ +static int z_decomp_init(void *arg, unsigned char *options, int opt_len, + int unit, int hdrlen, int mru, int debug) +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + + 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 || + options[3] != DEFLATE_CHK_SEQUENCE) + return 0; + + state->seqno = 0; + state->unit = unit; + state->debug = debug; + state->mru = mru; + + zlib_inflateReset(&state->strm); + + return 1; +} + +/** + * z_decomp_reset - reset a previously-allocated decompressor. + * @arg: pointer to private state for the decompressor. + * + * This clears the history for the decompressor and makes it + * ready to receive a new compressed stream. + */ +static void z_decomp_reset(void *arg) +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + + state->seqno = 0; + zlib_inflateReset(&state->strm); +} + +/** + * z_decompress - decompress a Deflate-compressed packet. + * @arg: pointer to private state for the decompressor + * @ibuf: pointer to input (compressed) packet data + * @isize: length of input packet + * @obuf: pointer to space for output (decompressed) packet + * @osize: amount of space available at @obuf + * + * Because of patent problems, we return DECOMP_ERROR for errors + * found by inspecting the input data and for system problems, but + * DECOMP_FATALERROR for any errors which could possibly be said to + * be being detected "after" decompression. For DECOMP_ERROR, + * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be + * infringing a patent of Motorola's if we do, so we take CCP down + * instead. + * + * Given that the frame has the correct sequence number and a good FCS, + * errors such as invalid codes in the input most likely indicate a + * bug, so we return DECOMP_FATALERROR for them in order to turn off + * compression, even though they are detected by inspecting the input. + */ +static int z_decompress(void *arg, unsigned char *ibuf, int isize, + unsigned char *obuf, int osize) +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + int olen, seq, r; + int decode_proto, overflow; + unsigned char overflow_buf[1]; + + if (isize <= PPP_HDRLEN + DEFLATE_OVHD) { + if (state->debug) + printk(KERN_DEBUG "z_decompress%d: short pkt (%d)\n", + state->unit, isize); + return DECOMP_ERROR; + } + + /* Check the sequence number. */ + seq = get_unaligned_be16(ibuf + PPP_HDRLEN); + if (seq != (state->seqno & 0xffff)) { + if (state->debug) + printk(KERN_DEBUG "z_decompress%d: bad seq # %d, expected %d\n", + state->unit, seq, state->seqno & 0xffff); + return DECOMP_ERROR; + } + ++state->seqno; + + /* + * Fill in the first part of the PPP header. The protocol field + * comes from the decompressed data. + */ + obuf[0] = PPP_ADDRESS(ibuf); + obuf[1] = PPP_CONTROL(ibuf); + obuf[2] = 0; + + /* + * Set up to call inflate. We set avail_out to 1 initially so we can + * look at the first byte of the output and decide whether we have + * a 1-byte or 2-byte protocol field. + */ + state->strm.next_in = ibuf + PPP_HDRLEN + DEFLATE_OVHD; + state->strm.avail_in = isize - (PPP_HDRLEN + DEFLATE_OVHD); + state->strm.next_out = obuf + 3; + state->strm.avail_out = 1; + decode_proto = 1; + overflow = 0; + + /* + * Call inflate, supplying more input or output as needed. + */ + for (;;) { + r = zlib_inflate(&state->strm, Z_PACKET_FLUSH); + if (r != Z_OK) { + if (state->debug) + printk(KERN_DEBUG "z_decompress%d: inflate returned %d (%s)\n", + state->unit, r, (state->strm.msg? state->strm.msg: "")); + return DECOMP_FATALERROR; + } + if (state->strm.avail_out != 0) + break; /* all done */ + if (decode_proto) { + state->strm.avail_out = osize - PPP_HDRLEN; + if ((obuf[3] & 1) == 0) { + /* 2-byte protocol field */ + obuf[2] = obuf[3]; + --state->strm.next_out; + ++state->strm.avail_out; + } + decode_proto = 0; + } else if (!overflow) { + /* + * We've filled up the output buffer; the only way to + * find out whether inflate has any more characters + * left is to give it another byte of output space. + */ + state->strm.next_out = overflow_buf; + state->strm.avail_out = 1; + overflow = 1; + } else { + if (state->debug) + printk(KERN_DEBUG "z_decompress%d: ran out of mru\n", + state->unit); + return DECOMP_FATALERROR; + } + } + + 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; + state->stats.unc_packets++; + state->stats.comp_bytes += isize; + state->stats.comp_packets++; + + return olen; +} + +/** + * z_incomp - add incompressible input data to the history. + * @arg: pointer to private state for the decompressor + * @ibuf: pointer to input packet data + * @icnt: length of input data. + */ +static void z_incomp(void *arg, unsigned char *ibuf, int icnt) +{ + struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; + int proto, r; + + /* + * Check that the protocol is one we handle. + */ + proto = PPP_PROTOCOL(ibuf); + if (proto > 0x3fff || proto == 0xfd || proto == 0xfb) + return; + + ++state->seqno; + + /* + * We start at the either the 1st or 2nd byte of the protocol field, + * depending on whether the protocol value is compressible. + */ + state->strm.next_in = ibuf + 3; + state->strm.avail_in = icnt - 3; + if (proto > 0xff) { + --state->strm.next_in; + ++state->strm.avail_in; + } + + r = zlib_inflateIncomp(&state->strm); + if (r != Z_OK) { + /* gak! */ + if (state->debug) { + printk(KERN_DEBUG "z_incomp%d: inflateIncomp returned %d (%s)\n", + state->unit, r, (state->strm.msg? state->strm.msg: "")); + } + return; + } + + /* + * Update stats. + */ + state->stats.inc_bytes += icnt; + state->stats.inc_packets++; + state->stats.unc_bytes += icnt; + state->stats.unc_packets++; +} + +/************************************************************* + * Module interface table + *************************************************************/ + +/* These are in ppp_generic.c */ +extern int ppp_register_compressor (struct compressor *cp); +extern void ppp_unregister_compressor (struct compressor *cp); + +/* + * Procedures exported to if_ppp.c. + */ +static struct compressor ppp_deflate = { + .compress_proto = CI_DEFLATE, + .comp_alloc = z_comp_alloc, + .comp_free = z_comp_free, + .comp_init = z_comp_init, + .comp_reset = z_comp_reset, + .compress = z_compress, + .comp_stat = z_comp_stats, + .decomp_alloc = z_decomp_alloc, + .decomp_free = z_decomp_free, + .decomp_init = z_decomp_init, + .decomp_reset = z_decomp_reset, + .decompress = z_decompress, + .incomp = z_incomp, + .decomp_stat = z_comp_stats, + .owner = THIS_MODULE +}; + +static struct compressor ppp_deflate_draft = { + .compress_proto = CI_DEFLATE_DRAFT, + .comp_alloc = z_comp_alloc, + .comp_free = z_comp_free, + .comp_init = z_comp_init, + .comp_reset = z_comp_reset, + .compress = z_compress, + .comp_stat = z_comp_stats, + .decomp_alloc = z_decomp_alloc, + .decomp_free = z_decomp_free, + .decomp_init = z_decomp_init, + .decomp_reset = z_decomp_reset, + .decompress = z_decompress, + .incomp = z_incomp, + .decomp_stat = z_comp_stats, + .owner = THIS_MODULE +}; + +static int __init deflate_init(void) +{ + int answer = ppp_register_compressor(&ppp_deflate); + if (answer == 0) + printk(KERN_INFO + "PPP Deflate Compression module registered\n"); + ppp_register_compressor(&ppp_deflate_draft); + return answer; +} + +static void __exit deflate_cleanup(void) +{ + ppp_unregister_compressor(&ppp_deflate); + ppp_unregister_compressor(&ppp_deflate_draft); +} + +module_init(deflate_init); +module_exit(deflate_cleanup); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE)); +MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE_DRAFT)); diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c new file mode 100644 index 0000000..10e5d98 --- /dev/null +++ b/drivers/net/ppp/ppp_generic.c @@ -0,0 +1,2954 @@ +/* + * Generic PPP layer for Linux. + * + * Copyright 1999-2002 Paul Mackerras. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * The generic PPP layer handles the PPP network interfaces, the + * /dev/ppp device, packet and VJ compression, and multilink. + * It talks to PPP `channels' via the interface defined in + * include/linux/ppp_channel.h. Channels provide the basic means for + * sending and receiving PPP frames on some kind of communications + * channel. + * + * Part of the code in this driver was inspired by the old async-only + * PPP driver, written by Michael Callahan and Al Longyear, and + * subsequently hacked by Paul Mackerras. + * + * ==FILEVERSION 20041108== + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define PPP_VERSION "2.4.2" + +/* + * Network protocols we support. + */ +#define NP_IP 0 /* Internet Protocol V4 */ +#define NP_IPV6 1 /* Internet Protocol V6 */ +#define NP_IPX 2 /* IPX protocol */ +#define NP_AT 3 /* Appletalk protocol */ +#define NP_MPLS_UC 4 /* MPLS unicast */ +#define NP_MPLS_MC 5 /* MPLS multicast */ +#define NUM_NP 6 /* Number of NPs. */ + +#define MPHDRLEN 6 /* multilink protocol header length */ +#define MPHDRLEN_SSN 4 /* ditto with short sequence numbers */ + +/* + * An instance of /dev/ppp can be associated with either a ppp + * interface unit or a ppp channel. In both cases, file->private_data + * points to one of these. + */ +struct ppp_file { + enum { + INTERFACE=1, CHANNEL + } kind; + struct sk_buff_head xq; /* pppd transmit queue */ + struct sk_buff_head rq; /* receive queue for pppd */ + wait_queue_head_t rwait; /* for poll on reading /dev/ppp */ + atomic_t refcnt; /* # refs (incl /dev/ppp attached) */ + int hdrlen; /* space to leave for headers */ + int index; /* interface unit / channel number */ + int dead; /* unit/channel has been shut down */ +}; + +#define PF_TO_X(pf, X) container_of(pf, X, file) + +#define PF_TO_PPP(pf) PF_TO_X(pf, struct ppp) +#define PF_TO_CHANNEL(pf) PF_TO_X(pf, struct channel) + +/* + * Data structure describing one ppp unit. + * A ppp unit corresponds to a ppp network interface device + * and represents a multilink bundle. + * It can have 0 or more ppp channels connected to it. + */ +struct ppp { + struct ppp_file file; /* stuff for read/write/poll 0 */ + struct file *owner; /* file that owns this unit 48 */ + struct list_head channels; /* list of attached channels 4c */ + int n_channels; /* how many channels are attached 54 */ + spinlock_t rlock; /* lock for receive side 58 */ + spinlock_t wlock; /* lock for transmit side 5c */ + int mru; /* max receive unit 60 */ + unsigned int flags; /* control bits 64 */ + unsigned int xstate; /* transmit state bits 68 */ + unsigned int rstate; /* receive state bits 6c */ + int debug; /* debug flags 70 */ + struct slcompress *vj; /* state for VJ header compression */ + enum NPmode npmode[NUM_NP]; /* what to do with each net proto 78 */ + struct sk_buff *xmit_pending; /* a packet ready to go out 88 */ + struct compressor *xcomp; /* transmit packet compressor 8c */ + void *xc_state; /* its internal state 90 */ + struct compressor *rcomp; /* receive decompressor 94 */ + void *rc_state; /* its internal state 98 */ + unsigned long last_xmit; /* jiffies when last pkt sent 9c */ + unsigned long last_recv; /* jiffies when last pkt rcvd a0 */ + struct net_device *dev; /* network interface device a4 */ + int closing; /* is device closing down? a8 */ +#ifdef CONFIG_PPP_MULTILINK + int nxchan; /* next channel to send something on */ + u32 nxseq; /* next sequence number to send */ + int mrru; /* MP: max reconst. receive unit */ + u32 nextseq; /* MP: seq no of next packet */ + u32 minseq; /* MP: min of most recent seqnos */ + struct sk_buff_head mrq; /* MP: receive reconstruction queue */ +#endif /* CONFIG_PPP_MULTILINK */ +#ifdef CONFIG_PPP_FILTER + struct sock_filter *pass_filter; /* filter for packets to pass */ + struct sock_filter *active_filter;/* filter for pkts to reset idle */ + unsigned pass_len, active_len; +#endif /* CONFIG_PPP_FILTER */ + struct net *ppp_net; /* the net we belong to */ +}; + +/* + * Bits in flags: SC_NO_TCP_CCID, SC_CCP_OPEN, SC_CCP_UP, SC_LOOP_TRAFFIC, + * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP, + * SC_MUST_COMP + * Bits in rstate: SC_DECOMP_RUN, SC_DC_ERROR, SC_DC_FERROR. + * Bits in xstate: SC_COMP_RUN + */ +#define SC_FLAG_BITS (SC_NO_TCP_CCID|SC_CCP_OPEN|SC_CCP_UP|SC_LOOP_TRAFFIC \ + |SC_MULTILINK|SC_MP_SHORTSEQ|SC_MP_XSHORTSEQ \ + |SC_COMP_TCP|SC_REJ_COMP_TCP|SC_MUST_COMP) + +/* + * Private data structure for each channel. + * This includes the data structure used for multilink. + */ +struct channel { + struct ppp_file file; /* stuff for read/write/poll */ + struct list_head list; /* link in all/new_channels list */ + struct ppp_channel *chan; /* public channel data structure */ + struct rw_semaphore chan_sem; /* protects `chan' during chan ioctl */ + spinlock_t downl; /* protects `chan', file.xq dequeue */ + struct ppp *ppp; /* ppp unit we're connected to */ + struct net *chan_net; /* the net channel belongs to */ + struct list_head clist; /* link in list of channels per unit */ + rwlock_t upl; /* protects `ppp' */ +#ifdef CONFIG_PPP_MULTILINK + u8 avail; /* flag used in multilink stuff */ + u8 had_frag; /* >= 1 fragments have been sent */ + u32 lastseq; /* MP: last sequence # received */ + int speed; /* speed of the corresponding ppp channel*/ +#endif /* CONFIG_PPP_MULTILINK */ +}; + +/* + * SMP locking issues: + * Both the ppp.rlock and ppp.wlock locks protect the ppp.channels + * list and the ppp.n_channels field, you need to take both locks + * before you modify them. + * The lock ordering is: channel.upl -> ppp.wlock -> ppp.rlock -> + * channel.downl. + */ + +static DEFINE_MUTEX(ppp_mutex); +static atomic_t ppp_unit_count = ATOMIC_INIT(0); +static atomic_t channel_count = ATOMIC_INIT(0); + +/* per-net private data for this module */ +static int ppp_net_id __read_mostly; +struct ppp_net { + /* units to ppp mapping */ + struct idr units_idr; + + /* + * all_ppp_mutex protects the units_idr mapping. + * It also ensures that finding a ppp unit in the units_idr + * map and updating its file.refcnt field is atomic. + */ + struct mutex all_ppp_mutex; + + /* channels */ + struct list_head all_channels; + struct list_head new_channels; + int last_channel_index; + + /* + * all_channels_lock protects all_channels and + * last_channel_index, and the atomicity of find + * a channel and updating its file.refcnt field. + */ + spinlock_t all_channels_lock; +}; + +/* Get the PPP protocol number from a skb */ +#define PPP_PROTO(skb) get_unaligned_be16((skb)->data) + +/* We limit the length of ppp->file.rq to this (arbitrary) value */ +#define PPP_MAX_RQLEN 32 + +/* + * Maximum number of multilink fragments queued up. + * This has to be large enough to cope with the maximum latency of + * the slowest channel relative to the others. Strictly it should + * depend on the number of channels and their characteristics. + */ +#define PPP_MP_MAX_QLEN 128 + +/* Multilink header bits. */ +#define B 0x80 /* this fragment begins a packet */ +#define E 0x40 /* this fragment ends a packet */ + +/* Compare multilink sequence numbers (assumed to be 32 bits wide) */ +#define seq_before(a, b) ((s32)((a) - (b)) < 0) +#define seq_after(a, b) ((s32)((a) - (b)) > 0) + +/* Prototypes. */ +static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, + struct file *file, unsigned int cmd, unsigned long arg); +static void ppp_xmit_process(struct ppp *ppp); +static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb); +static void ppp_push(struct ppp *ppp); +static void ppp_channel_push(struct channel *pch); +static void ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, + struct channel *pch); +static void ppp_receive_error(struct ppp *ppp); +static void ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb); +static struct sk_buff *ppp_decompress_frame(struct ppp *ppp, + struct sk_buff *skb); +#ifdef CONFIG_PPP_MULTILINK +static void ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, + struct channel *pch); +static void ppp_mp_insert(struct ppp *ppp, struct sk_buff *skb); +static struct sk_buff *ppp_mp_reconstruct(struct ppp *ppp); +static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb); +#endif /* CONFIG_PPP_MULTILINK */ +static int ppp_set_compress(struct ppp *ppp, unsigned long arg); +static void ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound); +static void ppp_ccp_closed(struct ppp *ppp); +static struct compressor *find_compressor(int type); +static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st); +static struct ppp *ppp_create_interface(struct net *net, int unit, int *retp); +static void init_ppp_file(struct ppp_file *pf, int kind); +static void ppp_shutdown_interface(struct ppp *ppp); +static void ppp_destroy_interface(struct ppp *ppp); +static struct ppp *ppp_find_unit(struct ppp_net *pn, int unit); +static struct channel *ppp_find_channel(struct ppp_net *pn, int unit); +static int ppp_connect_channel(struct channel *pch, int unit); +static int ppp_disconnect_channel(struct channel *pch); +static void ppp_destroy_channel(struct channel *pch); +static int unit_get(struct idr *p, void *ptr); +static int unit_set(struct idr *p, void *ptr, int n); +static void unit_put(struct idr *p, int n); +static void *unit_find(struct idr *p, int n); + +static struct class *ppp_class; + +/* per net-namespace data */ +static inline struct ppp_net *ppp_pernet(struct net *net) +{ + BUG_ON(!net); + + return net_generic(net, ppp_net_id); +} + +/* Translates a PPP protocol number to a NP index (NP == network protocol) */ +static inline int proto_to_npindex(int proto) +{ + switch (proto) { + case PPP_IP: + return NP_IP; + case PPP_IPV6: + return NP_IPV6; + case PPP_IPX: + return NP_IPX; + case PPP_AT: + return NP_AT; + case PPP_MPLS_UC: + return NP_MPLS_UC; + case PPP_MPLS_MC: + return NP_MPLS_MC; + } + return -EINVAL; +} + +/* Translates an NP index into a PPP protocol number */ +static const int npindex_to_proto[NUM_NP] = { + PPP_IP, + PPP_IPV6, + PPP_IPX, + PPP_AT, + PPP_MPLS_UC, + PPP_MPLS_MC, +}; + +/* Translates an ethertype into an NP index */ +static inline int ethertype_to_npindex(int ethertype) +{ + switch (ethertype) { + case ETH_P_IP: + return NP_IP; + case ETH_P_IPV6: + return NP_IPV6; + case ETH_P_IPX: + return NP_IPX; + case ETH_P_PPPTALK: + case ETH_P_ATALK: + return NP_AT; + case ETH_P_MPLS_UC: + return NP_MPLS_UC; + case ETH_P_MPLS_MC: + return NP_MPLS_MC; + } + return -1; +} + +/* Translates an NP index into an ethertype */ +static const int npindex_to_ethertype[NUM_NP] = { + ETH_P_IP, + ETH_P_IPV6, + ETH_P_IPX, + ETH_P_PPPTALK, + ETH_P_MPLS_UC, + ETH_P_MPLS_MC, +}; + +/* + * Locking shorthand. + */ +#define ppp_xmit_lock(ppp) spin_lock_bh(&(ppp)->wlock) +#define ppp_xmit_unlock(ppp) spin_unlock_bh(&(ppp)->wlock) +#define ppp_recv_lock(ppp) spin_lock_bh(&(ppp)->rlock) +#define ppp_recv_unlock(ppp) spin_unlock_bh(&(ppp)->rlock) +#define ppp_lock(ppp) do { ppp_xmit_lock(ppp); \ + ppp_recv_lock(ppp); } while (0) +#define ppp_unlock(ppp) do { ppp_recv_unlock(ppp); \ + ppp_xmit_unlock(ppp); } while (0) + +/* + * /dev/ppp device routines. + * The /dev/ppp device is used by pppd to control the ppp unit. + * It supports the read, write, ioctl and poll functions. + * Open instances of /dev/ppp can be in one of three states: + * unattached, attached to a ppp unit, or attached to a ppp channel. + */ +static int ppp_open(struct inode *inode, struct file *file) +{ + /* + * This could (should?) be enforced by the permissions on /dev/ppp. + */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + return 0; +} + +static int ppp_release(struct inode *unused, struct file *file) +{ + struct ppp_file *pf = file->private_data; + struct ppp *ppp; + + if (pf) { + file->private_data = NULL; + if (pf->kind == INTERFACE) { + ppp = PF_TO_PPP(pf); + if (file == ppp->owner) + ppp_shutdown_interface(ppp); + } + if (atomic_dec_and_test(&pf->refcnt)) { + switch (pf->kind) { + case INTERFACE: + ppp_destroy_interface(PF_TO_PPP(pf)); + break; + case CHANNEL: + ppp_destroy_channel(PF_TO_CHANNEL(pf)); + break; + } + } + } + return 0; +} + +static ssize_t ppp_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct ppp_file *pf = file->private_data; + DECLARE_WAITQUEUE(wait, current); + ssize_t ret; + struct sk_buff *skb = NULL; + struct iovec iov; + + ret = count; + + if (!pf) + return -ENXIO; + add_wait_queue(&pf->rwait, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + skb = skb_dequeue(&pf->rq); + if (skb) + break; + ret = 0; + if (pf->dead) + break; + if (pf->kind == INTERFACE) { + /* + * Return 0 (EOF) on an interface that has no + * channels connected, unless it is looping + * network traffic (demand mode). + */ + struct ppp *ppp = PF_TO_PPP(pf); + if (ppp->n_channels == 0 && + (ppp->flags & SC_LOOP_TRAFFIC) == 0) + break; + } + ret = -EAGAIN; + if (file->f_flags & O_NONBLOCK) + break; + ret = -ERESTARTSYS; + if (signal_pending(current)) + break; + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&pf->rwait, &wait); + + if (!skb) + goto out; + + ret = -EOVERFLOW; + if (skb->len > count) + goto outf; + ret = -EFAULT; + iov.iov_base = buf; + iov.iov_len = count; + if (skb_copy_datagram_iovec(skb, 0, &iov, skb->len)) + goto outf; + ret = skb->len; + + outf: + kfree_skb(skb); + out: + return ret; +} + +static ssize_t ppp_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct ppp_file *pf = file->private_data; + struct sk_buff *skb; + ssize_t ret; + + if (!pf) + return -ENXIO; + ret = -ENOMEM; + skb = alloc_skb(count + pf->hdrlen, GFP_KERNEL); + if (!skb) + goto out; + skb_reserve(skb, pf->hdrlen); + ret = -EFAULT; + if (copy_from_user(skb_put(skb, count), buf, count)) { + kfree_skb(skb); + goto out; + } + + skb_queue_tail(&pf->xq, skb); + + switch (pf->kind) { + case INTERFACE: + ppp_xmit_process(PF_TO_PPP(pf)); + break; + case CHANNEL: + ppp_channel_push(PF_TO_CHANNEL(pf)); + break; + } + + ret = count; + + out: + return ret; +} + +/* No kernel lock - fine */ +static unsigned int ppp_poll(struct file *file, poll_table *wait) +{ + struct ppp_file *pf = file->private_data; + unsigned int mask; + + if (!pf) + return 0; + poll_wait(file, &pf->rwait, wait); + mask = POLLOUT | POLLWRNORM; + if (skb_peek(&pf->rq)) + mask |= POLLIN | POLLRDNORM; + if (pf->dead) + mask |= POLLHUP; + else if (pf->kind == INTERFACE) { + /* see comment in ppp_read */ + struct ppp *ppp = PF_TO_PPP(pf); + if (ppp->n_channels == 0 && + (ppp->flags & SC_LOOP_TRAFFIC) == 0) + mask |= POLLIN | POLLRDNORM; + } + + return mask; +} + +#ifdef CONFIG_PPP_FILTER +static int get_filter(void __user *arg, struct sock_filter **p) +{ + struct sock_fprog uprog; + struct sock_filter *code = NULL; + int len, err; + + if (copy_from_user(&uprog, arg, sizeof(uprog))) + return -EFAULT; + + if (!uprog.len) { + *p = NULL; + return 0; + } + + len = uprog.len * sizeof(struct sock_filter); + code = memdup_user(uprog.filter, len); + if (IS_ERR(code)) + return PTR_ERR(code); + + err = sk_chk_filter(code, uprog.len); + if (err) { + kfree(code); + return err; + } + + *p = code; + return uprog.len; +} +#endif /* CONFIG_PPP_FILTER */ + +static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct ppp_file *pf = file->private_data; + struct ppp *ppp; + int err = -EFAULT, val, val2, i; + struct ppp_idle idle; + struct npioctl npi; + int unit, cflags; + struct slcompress *vj; + void __user *argp = (void __user *)arg; + int __user *p = argp; + + if (!pf) + return ppp_unattached_ioctl(current->nsproxy->net_ns, + pf, file, cmd, arg); + + if (cmd == PPPIOCDETACH) { + /* + * We have to be careful here... if the file descriptor + * has been dup'd, we could have another process in the + * middle of a poll using the same file *, so we had + * better not free the interface data structures - + * instead we fail the ioctl. Even in this case, we + * shut down the interface if we are the owner of it. + * Actually, we should get rid of PPPIOCDETACH, userland + * (i.e. pppd) could achieve the same effect by closing + * this fd and reopening /dev/ppp. + */ + err = -EINVAL; + mutex_lock(&ppp_mutex); + if (pf->kind == INTERFACE) { + ppp = PF_TO_PPP(pf); + if (file == ppp->owner) + ppp_shutdown_interface(ppp); + } + if (atomic_long_read(&file->f_count) <= 2) { + ppp_release(NULL, file); + err = 0; + } else + pr_warn("PPPIOCDETACH file->f_count=%ld\n", + atomic_long_read(&file->f_count)); + mutex_unlock(&ppp_mutex); + return err; + } + + if (pf->kind == CHANNEL) { + struct channel *pch; + struct ppp_channel *chan; + + mutex_lock(&ppp_mutex); + pch = PF_TO_CHANNEL(pf); + + switch (cmd) { + case PPPIOCCONNECT: + if (get_user(unit, p)) + break; + err = ppp_connect_channel(pch, unit); + break; + + case PPPIOCDISCONN: + err = ppp_disconnect_channel(pch); + break; + + default: + down_read(&pch->chan_sem); + chan = pch->chan; + err = -ENOTTY; + if (chan && chan->ops->ioctl) + err = chan->ops->ioctl(chan, cmd, arg); + up_read(&pch->chan_sem); + } + mutex_unlock(&ppp_mutex); + return err; + } + + if (pf->kind != INTERFACE) { + /* can't happen */ + pr_err("PPP: not interface or channel??\n"); + return -EINVAL; + } + + mutex_lock(&ppp_mutex); + ppp = PF_TO_PPP(pf); + switch (cmd) { + case PPPIOCSMRU: + if (get_user(val, p)) + break; + ppp->mru = val; + err = 0; + break; + + case PPPIOCSFLAGS: + if (get_user(val, p)) + break; + ppp_lock(ppp); + cflags = ppp->flags & ~val; + ppp->flags = val & SC_FLAG_BITS; + ppp_unlock(ppp); + if (cflags & SC_CCP_OPEN) + ppp_ccp_closed(ppp); + err = 0; + break; + + case PPPIOCGFLAGS: + val = ppp->flags | ppp->xstate | ppp->rstate; + if (put_user(val, p)) + break; + err = 0; + break; + + case PPPIOCSCOMPRESS: + err = ppp_set_compress(ppp, arg); + break; + + case PPPIOCGUNIT: + if (put_user(ppp->file.index, p)) + break; + err = 0; + break; + + case PPPIOCSDEBUG: + if (get_user(val, p)) + break; + ppp->debug = val; + err = 0; + break; + + case PPPIOCGDEBUG: + if (put_user(ppp->debug, p)) + break; + err = 0; + break; + + case PPPIOCGIDLE: + idle.xmit_idle = (jiffies - ppp->last_xmit) / HZ; + idle.recv_idle = (jiffies - ppp->last_recv) / HZ; + if (copy_to_user(argp, &idle, sizeof(idle))) + break; + err = 0; + break; + + case PPPIOCSMAXCID: + if (get_user(val, p)) + break; + val2 = 15; + if ((val >> 16) != 0) { + val2 = val >> 16; + val &= 0xffff; + } + vj = slhc_init(val2+1, val+1); + if (!vj) { + netdev_err(ppp->dev, + "PPP: no memory (VJ compressor)\n"); + err = -ENOMEM; + break; + } + ppp_lock(ppp); + if (ppp->vj) + slhc_free(ppp->vj); + ppp->vj = vj; + ppp_unlock(ppp); + err = 0; + break; + + case PPPIOCGNPMODE: + case PPPIOCSNPMODE: + if (copy_from_user(&npi, argp, sizeof(npi))) + break; + err = proto_to_npindex(npi.protocol); + if (err < 0) + break; + i = err; + if (cmd == PPPIOCGNPMODE) { + err = -EFAULT; + npi.mode = ppp->npmode[i]; + if (copy_to_user(argp, &npi, sizeof(npi))) + break; + } else { + ppp->npmode[i] = npi.mode; + /* we may be able to transmit more packets now (??) */ + netif_wake_queue(ppp->dev); + } + err = 0; + break; + +#ifdef CONFIG_PPP_FILTER + case PPPIOCSPASS: + { + struct sock_filter *code; + err = get_filter(argp, &code); + if (err >= 0) { + ppp_lock(ppp); + kfree(ppp->pass_filter); + ppp->pass_filter = code; + ppp->pass_len = err; + ppp_unlock(ppp); + err = 0; + } + break; + } + case PPPIOCSACTIVE: + { + struct sock_filter *code; + err = get_filter(argp, &code); + if (err >= 0) { + ppp_lock(ppp); + kfree(ppp->active_filter); + ppp->active_filter = code; + ppp->active_len = err; + ppp_unlock(ppp); + err = 0; + } + break; + } +#endif /* CONFIG_PPP_FILTER */ + +#ifdef CONFIG_PPP_MULTILINK + case PPPIOCSMRRU: + if (get_user(val, p)) + break; + ppp_recv_lock(ppp); + ppp->mrru = val; + ppp_recv_unlock(ppp); + err = 0; + break; +#endif /* CONFIG_PPP_MULTILINK */ + + default: + err = -ENOTTY; + } + mutex_unlock(&ppp_mutex); + return err; +} + +static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, + struct file *file, unsigned int cmd, unsigned long arg) +{ + int unit, err = -EFAULT; + struct ppp *ppp; + struct channel *chan; + struct ppp_net *pn; + int __user *p = (int __user *)arg; + + mutex_lock(&ppp_mutex); + switch (cmd) { + case PPPIOCNEWUNIT: + /* Create a new ppp unit */ + if (get_user(unit, p)) + break; + ppp = ppp_create_interface(net, unit, &err); + if (!ppp) + break; + file->private_data = &ppp->file; + ppp->owner = file; + err = -EFAULT; + if (put_user(ppp->file.index, p)) + break; + err = 0; + break; + + case PPPIOCATTACH: + /* Attach to an existing ppp unit */ + if (get_user(unit, p)) + break; + err = -ENXIO; + pn = ppp_pernet(net); + mutex_lock(&pn->all_ppp_mutex); + ppp = ppp_find_unit(pn, unit); + if (ppp) { + atomic_inc(&ppp->file.refcnt); + file->private_data = &ppp->file; + err = 0; + } + mutex_unlock(&pn->all_ppp_mutex); + break; + + case PPPIOCATTCHAN: + if (get_user(unit, p)) + break; + err = -ENXIO; + pn = ppp_pernet(net); + spin_lock_bh(&pn->all_channels_lock); + chan = ppp_find_channel(pn, unit); + if (chan) { + atomic_inc(&chan->file.refcnt); + file->private_data = &chan->file; + err = 0; + } + spin_unlock_bh(&pn->all_channels_lock); + break; + + default: + err = -ENOTTY; + } + mutex_unlock(&ppp_mutex); + return err; +} + +static const struct file_operations ppp_device_fops = { + .owner = THIS_MODULE, + .read = ppp_read, + .write = ppp_write, + .poll = ppp_poll, + .unlocked_ioctl = ppp_ioctl, + .open = ppp_open, + .release = ppp_release, + .llseek = noop_llseek, +}; + +static __net_init int ppp_init_net(struct net *net) +{ + struct ppp_net *pn = net_generic(net, ppp_net_id); + + idr_init(&pn->units_idr); + mutex_init(&pn->all_ppp_mutex); + + INIT_LIST_HEAD(&pn->all_channels); + INIT_LIST_HEAD(&pn->new_channels); + + spin_lock_init(&pn->all_channels_lock); + + return 0; +} + +static __net_exit void ppp_exit_net(struct net *net) +{ + struct ppp_net *pn = net_generic(net, ppp_net_id); + + idr_destroy(&pn->units_idr); +} + +static struct pernet_operations ppp_net_ops = { + .init = ppp_init_net, + .exit = ppp_exit_net, + .id = &ppp_net_id, + .size = sizeof(struct ppp_net), +}; + +#define PPP_MAJOR 108 + +/* Called at boot time if ppp is compiled into the kernel, + or at module load time (from init_module) if compiled as a module. */ +static int __init ppp_init(void) +{ + int err; + + pr_info("PPP generic driver version " PPP_VERSION "\n"); + + err = register_pernet_device(&ppp_net_ops); + if (err) { + pr_err("failed to register PPP pernet device (%d)\n", err); + goto out; + } + + err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops); + if (err) { + pr_err("failed to register PPP device (%d)\n", err); + goto out_net; + } + + ppp_class = class_create(THIS_MODULE, "ppp"); + if (IS_ERR(ppp_class)) { + err = PTR_ERR(ppp_class); + goto out_chrdev; + } + + /* not a big deal if we fail here :-) */ + device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); + + return 0; + +out_chrdev: + unregister_chrdev(PPP_MAJOR, "ppp"); +out_net: + unregister_pernet_device(&ppp_net_ops); +out: + return err; +} + +/* + * Network interface unit routines. + */ +static netdev_tx_t +ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct ppp *ppp = netdev_priv(dev); + int npi, proto; + unsigned char *pp; + + npi = ethertype_to_npindex(ntohs(skb->protocol)); + if (npi < 0) + goto outf; + + /* Drop, accept or reject the packet */ + switch (ppp->npmode[npi]) { + case NPMODE_PASS: + break; + case NPMODE_QUEUE: + /* it would be nice to have a way to tell the network + system to queue this one up for later. */ + goto outf; + case NPMODE_DROP: + case NPMODE_ERROR: + goto outf; + } + + /* Put the 2-byte PPP protocol number on the front, + making sure there is room for the address and control fields. */ + if (skb_cow_head(skb, PPP_HDRLEN)) + goto outf; + + pp = skb_push(skb, 2); + proto = npindex_to_proto[npi]; + put_unaligned_be16(proto, pp); + + netif_stop_queue(dev); + skb_queue_tail(&ppp->file.xq, skb); + ppp_xmit_process(ppp); + return NETDEV_TX_OK; + + outf: + kfree_skb(skb); + ++dev->stats.tx_dropped; + return NETDEV_TX_OK; +} + +static int +ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct ppp *ppp = netdev_priv(dev); + int err = -EFAULT; + void __user *addr = (void __user *) ifr->ifr_ifru.ifru_data; + struct ppp_stats stats; + struct ppp_comp_stats cstats; + char *vers; + + switch (cmd) { + case SIOCGPPPSTATS: + ppp_get_stats(ppp, &stats); + if (copy_to_user(addr, &stats, sizeof(stats))) + break; + err = 0; + break; + + case SIOCGPPPCSTATS: + memset(&cstats, 0, sizeof(cstats)); + if (ppp->xc_state) + ppp->xcomp->comp_stat(ppp->xc_state, &cstats.c); + if (ppp->rc_state) + ppp->rcomp->decomp_stat(ppp->rc_state, &cstats.d); + if (copy_to_user(addr, &cstats, sizeof(cstats))) + break; + err = 0; + break; + + case SIOCGPPPVER: + vers = PPP_VERSION; + if (copy_to_user(addr, vers, strlen(vers) + 1)) + break; + err = 0; + break; + + default: + err = -EINVAL; + } + + return err; +} + +static const struct net_device_ops ppp_netdev_ops = { + .ndo_start_xmit = ppp_start_xmit, + .ndo_do_ioctl = ppp_net_ioctl, +}; + +static void ppp_setup(struct net_device *dev) +{ + dev->netdev_ops = &ppp_netdev_ops; + dev->hard_header_len = PPP_HDRLEN; + dev->mtu = PPP_MTU; + dev->addr_len = 0; + dev->tx_queue_len = 3; + dev->type = ARPHRD_PPP; + dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; + dev->features |= NETIF_F_NETNS_LOCAL; + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; +} + +/* + * Transmit-side routines. + */ + +/* + * Called to do any work queued up on the transmit side + * that can now be done. + */ +static void +ppp_xmit_process(struct ppp *ppp) +{ + struct sk_buff *skb; + + ppp_xmit_lock(ppp); + if (!ppp->closing) { + ppp_push(ppp); + while (!ppp->xmit_pending && + (skb = skb_dequeue(&ppp->file.xq))) + ppp_send_frame(ppp, skb); + /* If there's no work left to do, tell the core net + code that we can accept some more. */ + if (!ppp->xmit_pending && !skb_peek(&ppp->file.xq)) + netif_wake_queue(ppp->dev); + } + ppp_xmit_unlock(ppp); +} + +static inline struct sk_buff * +pad_compress_skb(struct ppp *ppp, struct sk_buff *skb) +{ + struct sk_buff *new_skb; + int len; + int new_skb_size = ppp->dev->mtu + + ppp->xcomp->comp_extra + ppp->dev->hard_header_len; + int compressor_skb_size = ppp->dev->mtu + + ppp->xcomp->comp_extra + PPP_HDRLEN; + new_skb = alloc_skb(new_skb_size, GFP_ATOMIC); + if (!new_skb) { + if (net_ratelimit()) + netdev_err(ppp->dev, "PPP: no memory (comp pkt)\n"); + return NULL; + } + if (ppp->dev->hard_header_len > PPP_HDRLEN) + skb_reserve(new_skb, + ppp->dev->hard_header_len - PPP_HDRLEN); + + /* compressor still expects A/C bytes in hdr */ + len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2, + new_skb->data, skb->len + 2, + compressor_skb_size); + if (len > 0 && (ppp->flags & SC_CCP_UP)) { + kfree_skb(skb); + skb = new_skb; + skb_put(skb, len); + skb_pull(skb, 2); /* pull off A/C bytes */ + } else if (len == 0) { + /* didn't compress, or CCP not up yet */ + kfree_skb(new_skb); + new_skb = skb; + } else { + /* + * (len < 0) + * MPPE requires that we do not send unencrypted + * frames. The compressor will return -1 if we + * should drop the frame. We cannot simply test + * the compress_proto because MPPE and MPPC share + * the same number. + */ + if (net_ratelimit()) + netdev_err(ppp->dev, "ppp: compressor dropped pkt\n"); + kfree_skb(skb); + kfree_skb(new_skb); + new_skb = NULL; + } + return new_skb; +} + +/* + * Compress and send a frame. + * The caller should have locked the xmit path, + * and xmit_pending should be 0. + */ +static void +ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) +{ + int proto = PPP_PROTO(skb); + struct sk_buff *new_skb; + int len; + unsigned char *cp; + + if (proto < 0x8000) { +#ifdef CONFIG_PPP_FILTER + /* check if we should pass this packet */ + /* the filter instructions are constructed assuming + a four-byte PPP header on each packet */ + *skb_push(skb, 2) = 1; + if (ppp->pass_filter && + sk_run_filter(skb, ppp->pass_filter) == 0) { + if (ppp->debug & 1) + netdev_printk(KERN_DEBUG, ppp->dev, + "PPP: outbound frame " + "not passed\n"); + kfree_skb(skb); + return; + } + /* if this packet passes the active filter, record the time */ + if (!(ppp->active_filter && + sk_run_filter(skb, ppp->active_filter) == 0)) + ppp->last_xmit = jiffies; + skb_pull(skb, 2); +#else + /* for data packets, record the time */ + ppp->last_xmit = jiffies; +#endif /* CONFIG_PPP_FILTER */ + } + + ++ppp->dev->stats.tx_packets; + ppp->dev->stats.tx_bytes += skb->len - 2; + + switch (proto) { + case PPP_IP: + if (!ppp->vj || (ppp->flags & SC_COMP_TCP) == 0) + break; + /* try to do VJ TCP header compression */ + new_skb = alloc_skb(skb->len + ppp->dev->hard_header_len - 2, + GFP_ATOMIC); + if (!new_skb) { + netdev_err(ppp->dev, "PPP: no memory (VJ comp pkt)\n"); + goto drop; + } + skb_reserve(new_skb, ppp->dev->hard_header_len - 2); + cp = skb->data + 2; + len = slhc_compress(ppp->vj, cp, skb->len - 2, + new_skb->data + 2, &cp, + !(ppp->flags & SC_NO_TCP_CCID)); + if (cp == skb->data + 2) { + /* didn't compress */ + kfree_skb(new_skb); + } else { + if (cp[0] & SL_TYPE_COMPRESSED_TCP) { + proto = PPP_VJC_COMP; + cp[0] &= ~SL_TYPE_COMPRESSED_TCP; + } else { + proto = PPP_VJC_UNCOMP; + cp[0] = skb->data[2]; + } + kfree_skb(skb); + skb = new_skb; + cp = skb_put(skb, len + 2); + cp[0] = 0; + cp[1] = proto; + } + break; + + case PPP_CCP: + /* peek at outbound CCP frames */ + ppp_ccp_peek(ppp, skb, 0); + break; + } + + /* try to do packet compression */ + if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state && + proto != PPP_LCP && proto != PPP_CCP) { + if (!(ppp->flags & SC_CCP_UP) && (ppp->flags & SC_MUST_COMP)) { + if (net_ratelimit()) + netdev_err(ppp->dev, + "ppp: compression required but " + "down - pkt dropped.\n"); + goto drop; + } + skb = pad_compress_skb(ppp, skb); + if (!skb) + goto drop; + } + + /* + * If we are waiting for traffic (demand dialling), + * queue it up for pppd to receive. + */ + if (ppp->flags & SC_LOOP_TRAFFIC) { + if (ppp->file.rq.qlen > PPP_MAX_RQLEN) + goto drop; + skb_queue_tail(&ppp->file.rq, skb); + wake_up_interruptible(&ppp->file.rwait); + return; + } + + ppp->xmit_pending = skb; + ppp_push(ppp); + return; + + drop: + kfree_skb(skb); + ++ppp->dev->stats.tx_errors; +} + +/* + * Try to send the frame in xmit_pending. + * The caller should have the xmit path locked. + */ +static void +ppp_push(struct ppp *ppp) +{ + struct list_head *list; + struct channel *pch; + struct sk_buff *skb = ppp->xmit_pending; + + if (!skb) + return; + + list = &ppp->channels; + if (list_empty(list)) { + /* nowhere to send the packet, just drop it */ + ppp->xmit_pending = NULL; + kfree_skb(skb); + return; + } + + if ((ppp->flags & SC_MULTILINK) == 0) { + /* not doing multilink: send it down the first channel */ + list = list->next; + pch = list_entry(list, struct channel, clist); + + spin_lock_bh(&pch->downl); + if (pch->chan) { + if (pch->chan->ops->start_xmit(pch->chan, skb)) + ppp->xmit_pending = NULL; + } else { + /* channel got unregistered */ + kfree_skb(skb); + ppp->xmit_pending = NULL; + } + spin_unlock_bh(&pch->downl); + return; + } + +#ifdef CONFIG_PPP_MULTILINK + /* Multilink: fragment the packet over as many links + as can take the packet at the moment. */ + if (!ppp_mp_explode(ppp, skb)) + return; +#endif /* CONFIG_PPP_MULTILINK */ + + ppp->xmit_pending = NULL; + kfree_skb(skb); +} + +#ifdef CONFIG_PPP_MULTILINK +static bool mp_protocol_compress __read_mostly = true; +module_param(mp_protocol_compress, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(mp_protocol_compress, + "compress protocol id in multilink fragments"); + +/* + * Divide a packet to be transmitted into fragments and + * send them out the individual links. + */ +static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) +{ + int len, totlen; + int i, bits, hdrlen, mtu; + int flen; + int navail, nfree, nzero; + int nbigger; + int totspeed; + int totfree; + unsigned char *p, *q; + struct list_head *list; + struct channel *pch; + struct sk_buff *frag; + struct ppp_channel *chan; + + totspeed = 0; /*total bitrate of the bundle*/ + nfree = 0; /* # channels which have no packet already queued */ + navail = 0; /* total # of usable channels (not deregistered) */ + nzero = 0; /* number of channels with zero speed associated*/ + totfree = 0; /*total # of channels available and + *having no queued packets before + *starting the fragmentation*/ + + hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; + i = 0; + list_for_each_entry(pch, &ppp->channels, clist) { + if (pch->chan) { + pch->avail = 1; + navail++; + pch->speed = pch->chan->speed; + } else { + pch->avail = 0; + } + if (pch->avail) { + if (skb_queue_empty(&pch->file.xq) || + !pch->had_frag) { + if (pch->speed == 0) + nzero++; + else + totspeed += pch->speed; + + pch->avail = 2; + ++nfree; + ++totfree; + } + if (!pch->had_frag && i < ppp->nxchan) + ppp->nxchan = i; + } + ++i; + } + /* + * Don't start sending this packet unless at least half of + * the channels are free. This gives much better TCP + * performance if we have a lot of channels. + */ + if (nfree == 0 || nfree < navail / 2) + return 0; /* can't take now, leave it in xmit_pending */ + + /* Do protocol field compression */ + p = skb->data; + len = skb->len; + if (*p == 0 && mp_protocol_compress) { + ++p; + --len; + } + + totlen = len; + nbigger = len % nfree; + + /* skip to the channel after the one we last used + and start at that one */ + list = &ppp->channels; + for (i = 0; i < ppp->nxchan; ++i) { + list = list->next; + if (list == &ppp->channels) { + i = 0; + break; + } + } + + /* create a fragment for each channel */ + bits = B; + while (len > 0) { + list = list->next; + if (list == &ppp->channels) { + i = 0; + continue; + } + pch = list_entry(list, struct channel, clist); + ++i; + if (!pch->avail) + continue; + + /* + * Skip this channel if it has a fragment pending already and + * we haven't given a fragment to all of the free channels. + */ + if (pch->avail == 1) { + if (nfree > 0) + continue; + } else { + pch->avail = 1; + } + + /* check the channel's mtu and whether it is still attached. */ + spin_lock_bh(&pch->downl); + if (pch->chan == NULL) { + /* can't use this channel, it's being deregistered */ + if (pch->speed == 0) + nzero--; + else + totspeed -= pch->speed; + + spin_unlock_bh(&pch->downl); + pch->avail = 0; + totlen = len; + totfree--; + nfree--; + if (--navail == 0) + break; + continue; + } + + /* + *if the channel speed is not set divide + *the packet evenly among the free channels; + *otherwise divide it according to the speed + *of the channel we are going to transmit on + */ + flen = len; + if (nfree > 0) { + if (pch->speed == 0) { + flen = len/nfree; + if (nbigger > 0) { + flen++; + nbigger--; + } + } else { + flen = (((totfree - nzero)*(totlen + hdrlen*totfree)) / + ((totspeed*totfree)/pch->speed)) - hdrlen; + if (nbigger > 0) { + flen += ((totfree - nzero)*pch->speed)/totspeed; + nbigger -= ((totfree - nzero)*pch->speed)/ + totspeed; + } + } + nfree--; + } + + /* + *check if we are on the last channel or + *we exceded the length of the data to + *fragment + */ + if ((nfree <= 0) || (flen > len)) + flen = len; + /* + *it is not worth to tx on slow channels: + *in that case from the resulting flen according to the + *above formula will be equal or less than zero. + *Skip the channel in this case + */ + if (flen <= 0) { + pch->avail = 2; + spin_unlock_bh(&pch->downl); + continue; + } + + mtu = pch->chan->mtu - hdrlen; + if (mtu < 4) + mtu = 4; + if (flen > mtu) + flen = mtu; + if (flen == len) + bits |= E; + frag = alloc_skb(flen + hdrlen + (flen == 0), GFP_ATOMIC); + if (!frag) + goto noskb; + q = skb_put(frag, flen + hdrlen); + + /* make the MP header */ + put_unaligned_be16(PPP_MP, q); + if (ppp->flags & SC_MP_XSHORTSEQ) { + q[2] = bits + ((ppp->nxseq >> 8) & 0xf); + q[3] = ppp->nxseq; + } else { + q[2] = bits; + q[3] = ppp->nxseq >> 16; + q[4] = ppp->nxseq >> 8; + q[5] = ppp->nxseq; + } + + memcpy(q + hdrlen, p, flen); + + /* try to send it down the channel */ + chan = pch->chan; + if (!skb_queue_empty(&pch->file.xq) || + !chan->ops->start_xmit(chan, frag)) + skb_queue_tail(&pch->file.xq, frag); + pch->had_frag = 1; + p += flen; + len -= flen; + ++ppp->nxseq; + bits = 0; + spin_unlock_bh(&pch->downl); + } + ppp->nxchan = i; + + return 1; + + noskb: + spin_unlock_bh(&pch->downl); + if (ppp->debug & 1) + netdev_err(ppp->dev, "PPP: no memory (fragment)\n"); + ++ppp->dev->stats.tx_errors; + ++ppp->nxseq; + return 1; /* abandon the frame */ +} +#endif /* CONFIG_PPP_MULTILINK */ + +/* + * Try to send data out on a channel. + */ +static void +ppp_channel_push(struct channel *pch) +{ + struct sk_buff *skb; + struct ppp *ppp; + + spin_lock_bh(&pch->downl); + if (pch->chan) { + while (!skb_queue_empty(&pch->file.xq)) { + skb = skb_dequeue(&pch->file.xq); + if (!pch->chan->ops->start_xmit(pch->chan, skb)) { + /* put the packet back and try again later */ + skb_queue_head(&pch->file.xq, skb); + break; + } + } + } else { + /* channel got deregistered */ + skb_queue_purge(&pch->file.xq); + } + spin_unlock_bh(&pch->downl); + /* see if there is anything from the attached unit to be sent */ + if (skb_queue_empty(&pch->file.xq)) { + read_lock_bh(&pch->upl); + ppp = pch->ppp; + if (ppp) + ppp_xmit_process(ppp); + read_unlock_bh(&pch->upl); + } +} + +/* + * Receive-side routines. + */ + +struct ppp_mp_skb_parm { + u32 sequence; + u8 BEbits; +}; +#define PPP_MP_CB(skb) ((struct ppp_mp_skb_parm *)((skb)->cb)) + +static inline void +ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) +{ + ppp_recv_lock(ppp); + if (!ppp->closing) + ppp_receive_frame(ppp, skb, pch); + else + kfree_skb(skb); + ppp_recv_unlock(ppp); +} + +void +ppp_input(struct ppp_channel *chan, struct sk_buff *skb) +{ + struct channel *pch = chan->ppp; + int proto; + + if (!pch) { + kfree_skb(skb); + return; + } + + read_lock_bh(&pch->upl); + if (!pskb_may_pull(skb, 2)) { + kfree_skb(skb); + if (pch->ppp) { + ++pch->ppp->dev->stats.rx_length_errors; + ppp_receive_error(pch->ppp); + } + goto done; + } + + proto = PPP_PROTO(skb); + if (!pch->ppp || proto >= 0xc000 || proto == PPP_CCPFRAG) { + /* put it on the channel queue */ + skb_queue_tail(&pch->file.rq, skb); + /* drop old frames if queue too long */ + while (pch->file.rq.qlen > PPP_MAX_RQLEN && + (skb = skb_dequeue(&pch->file.rq))) + kfree_skb(skb); + wake_up_interruptible(&pch->file.rwait); + } else { + ppp_do_recv(pch->ppp, skb, pch); + } + +done: + read_unlock_bh(&pch->upl); +} + +/* Put a 0-length skb in the receive queue as an error indication */ +void +ppp_input_error(struct ppp_channel *chan, int code) +{ + struct channel *pch = chan->ppp; + struct sk_buff *skb; + + if (!pch) + return; + + read_lock_bh(&pch->upl); + if (pch->ppp) { + skb = alloc_skb(0, GFP_ATOMIC); + if (skb) { + skb->len = 0; /* probably unnecessary */ + skb->cb[0] = code; + ppp_do_recv(pch->ppp, skb, pch); + } + } + read_unlock_bh(&pch->upl); +} + +/* + * We come in here to process a received frame. + * The receive side of the ppp unit is locked. + */ +static void +ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) +{ + /* note: a 0-length skb is used as an error indication */ + if (skb->len > 0) { +#ifdef CONFIG_PPP_MULTILINK + /* XXX do channel-level decompression here */ + if (PPP_PROTO(skb) == PPP_MP) + ppp_receive_mp_frame(ppp, skb, pch); + else +#endif /* CONFIG_PPP_MULTILINK */ + ppp_receive_nonmp_frame(ppp, skb); + } else { + kfree_skb(skb); + ppp_receive_error(ppp); + } +} + +static void +ppp_receive_error(struct ppp *ppp) +{ + ++ppp->dev->stats.rx_errors; + if (ppp->vj) + slhc_toss(ppp->vj); +} + +static void +ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) +{ + struct sk_buff *ns; + int proto, len, npi; + + /* + * Decompress the frame, if compressed. + * Note that some decompressors need to see uncompressed frames + * that come in as well as compressed frames. + */ + if (ppp->rc_state && (ppp->rstate & SC_DECOMP_RUN) && + (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0) + skb = ppp_decompress_frame(ppp, skb); + + if (ppp->flags & SC_MUST_COMP && ppp->rstate & SC_DC_FERROR) + goto err; + + proto = PPP_PROTO(skb); + switch (proto) { + case PPP_VJC_COMP: + /* decompress VJ compressed packets */ + if (!ppp->vj || (ppp->flags & SC_REJ_COMP_TCP)) + goto err; + + if (skb_tailroom(skb) < 124 || skb_cloned(skb)) { + /* copy to a new sk_buff with more tailroom */ + ns = dev_alloc_skb(skb->len + 128); + if (!ns) { + netdev_err(ppp->dev, "PPP: no memory " + "(VJ decomp)\n"); + goto err; + } + skb_reserve(ns, 2); + skb_copy_bits(skb, 0, skb_put(ns, skb->len), skb->len); + kfree_skb(skb); + skb = ns; + } + else + skb->ip_summed = CHECKSUM_NONE; + + len = slhc_uncompress(ppp->vj, skb->data + 2, skb->len - 2); + if (len <= 0) { + netdev_printk(KERN_DEBUG, ppp->dev, + "PPP: VJ decompression error\n"); + goto err; + } + len += 2; + if (len > skb->len) + skb_put(skb, len - skb->len); + else if (len < skb->len) + skb_trim(skb, len); + proto = PPP_IP; + break; + + case PPP_VJC_UNCOMP: + if (!ppp->vj || (ppp->flags & SC_REJ_COMP_TCP)) + goto err; + + /* Until we fix the decompressor need to make sure + * data portion is linear. + */ + if (!pskb_may_pull(skb, skb->len)) + goto err; + + if (slhc_remember(ppp->vj, skb->data + 2, skb->len - 2) <= 0) { + netdev_err(ppp->dev, "PPP: VJ uncompressed error\n"); + goto err; + } + proto = PPP_IP; + break; + + case PPP_CCP: + ppp_ccp_peek(ppp, skb, 1); + break; + } + + ++ppp->dev->stats.rx_packets; + ppp->dev->stats.rx_bytes += skb->len - 2; + + npi = proto_to_npindex(proto); + if (npi < 0) { + /* control or unknown frame - pass it to pppd */ + skb_queue_tail(&ppp->file.rq, skb); + /* limit queue length by dropping old frames */ + while (ppp->file.rq.qlen > PPP_MAX_RQLEN && + (skb = skb_dequeue(&ppp->file.rq))) + kfree_skb(skb); + /* wake up any process polling or blocking on read */ + wake_up_interruptible(&ppp->file.rwait); + + } else { + /* network protocol frame - give it to the kernel */ + +#ifdef CONFIG_PPP_FILTER + /* check if the packet passes the pass and active filters */ + /* the filter instructions are constructed assuming + a four-byte PPP header on each packet */ + if (ppp->pass_filter || ppp->active_filter) { + if (skb_cloned(skb) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + goto err; + + *skb_push(skb, 2) = 0; + if (ppp->pass_filter && + sk_run_filter(skb, ppp->pass_filter) == 0) { + if (ppp->debug & 1) + netdev_printk(KERN_DEBUG, ppp->dev, + "PPP: inbound frame " + "not passed\n"); + kfree_skb(skb); + return; + } + if (!(ppp->active_filter && + sk_run_filter(skb, ppp->active_filter) == 0)) + ppp->last_recv = jiffies; + __skb_pull(skb, 2); + } else +#endif /* CONFIG_PPP_FILTER */ + ppp->last_recv = jiffies; + + if ((ppp->dev->flags & IFF_UP) == 0 || + ppp->npmode[npi] != NPMODE_PASS) { + kfree_skb(skb); + } else { + /* chop off protocol */ + skb_pull_rcsum(skb, 2); + skb->dev = ppp->dev; + skb->protocol = htons(npindex_to_ethertype[npi]); + skb_reset_mac_header(skb); + netif_rx(skb); + } + } + return; + + err: + kfree_skb(skb); + ppp_receive_error(ppp); +} + +static struct sk_buff * +ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb) +{ + int proto = PPP_PROTO(skb); + struct sk_buff *ns; + int len; + + /* Until we fix all the decompressor's need to make sure + * data portion is linear. + */ + if (!pskb_may_pull(skb, skb->len)) + goto err; + + if (proto == PPP_COMP) { + int obuff_size; + + switch(ppp->rcomp->compress_proto) { + case CI_MPPE: + obuff_size = ppp->mru + PPP_HDRLEN + 1; + break; + default: + obuff_size = ppp->mru + PPP_HDRLEN; + break; + } + + ns = dev_alloc_skb(obuff_size); + if (!ns) { + netdev_err(ppp->dev, "ppp_decompress_frame: " + "no memory\n"); + goto err; + } + /* the decompressor still expects the A/C bytes in the hdr */ + len = ppp->rcomp->decompress(ppp->rc_state, skb->data - 2, + skb->len + 2, ns->data, obuff_size); + if (len < 0) { + /* Pass the compressed frame to pppd as an + error indication. */ + if (len == DECOMP_FATALERROR) + ppp->rstate |= SC_DC_FERROR; + kfree_skb(ns); + goto err; + } + + kfree_skb(skb); + skb = ns; + skb_put(skb, len); + skb_pull(skb, 2); /* pull off the A/C bytes */ + + } else { + /* Uncompressed frame - pass to decompressor so it + can update its dictionary if necessary. */ + if (ppp->rcomp->incomp) + ppp->rcomp->incomp(ppp->rc_state, skb->data - 2, + skb->len + 2); + } + + return skb; + + err: + ppp->rstate |= SC_DC_ERROR; + ppp_receive_error(ppp); + return skb; +} + +#ifdef CONFIG_PPP_MULTILINK +/* + * Receive a multilink frame. + * We put it on the reconstruction queue and then pull off + * as many completed frames as we can. + */ +static void +ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) +{ + u32 mask, seq; + struct channel *ch; + int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; + + if (!pskb_may_pull(skb, mphdrlen + 1) || ppp->mrru == 0) + goto err; /* no good, throw it away */ + + /* Decode sequence number and begin/end bits */ + if (ppp->flags & SC_MP_SHORTSEQ) { + seq = ((skb->data[2] & 0x0f) << 8) | skb->data[3]; + mask = 0xfff; + } else { + seq = (skb->data[3] << 16) | (skb->data[4] << 8)| skb->data[5]; + mask = 0xffffff; + } + PPP_MP_CB(skb)->BEbits = skb->data[2]; + skb_pull(skb, mphdrlen); /* pull off PPP and MP headers */ + + /* + * Do protocol ID decompression on the first fragment of each packet. + */ + if ((PPP_MP_CB(skb)->BEbits & B) && (skb->data[0] & 1)) + *skb_push(skb, 1) = 0; + + /* + * Expand sequence number to 32 bits, making it as close + * as possible to ppp->minseq. + */ + seq |= ppp->minseq & ~mask; + if ((int)(ppp->minseq - seq) > (int)(mask >> 1)) + seq += mask + 1; + else if ((int)(seq - ppp->minseq) > (int)(mask >> 1)) + seq -= mask + 1; /* should never happen */ + PPP_MP_CB(skb)->sequence = seq; + pch->lastseq = seq; + + /* + * If this packet comes before the next one we were expecting, + * drop it. + */ + if (seq_before(seq, ppp->nextseq)) { + kfree_skb(skb); + ++ppp->dev->stats.rx_dropped; + ppp_receive_error(ppp); + return; + } + + /* + * Reevaluate minseq, the minimum over all channels of the + * last sequence number received on each channel. Because of + * the increasing sequence number rule, we know that any fragment + * before `minseq' which hasn't arrived is never going to arrive. + * The list of channels can't change because we have the receive + * side of the ppp unit locked. + */ + list_for_each_entry(ch, &ppp->channels, clist) { + if (seq_before(ch->lastseq, seq)) + seq = ch->lastseq; + } + if (seq_before(ppp->minseq, seq)) + ppp->minseq = seq; + + /* Put the fragment on the reconstruction queue */ + ppp_mp_insert(ppp, skb); + + /* If the queue is getting long, don't wait any longer for packets + before the start of the queue. */ + if (skb_queue_len(&ppp->mrq) >= PPP_MP_MAX_QLEN) { + struct sk_buff *mskb = skb_peek(&ppp->mrq); + if (seq_before(ppp->minseq, PPP_MP_CB(mskb)->sequence)) + ppp->minseq = PPP_MP_CB(mskb)->sequence; + } + + /* Pull completed packets off the queue and receive them. */ + while ((skb = ppp_mp_reconstruct(ppp))) { + if (pskb_may_pull(skb, 2)) + ppp_receive_nonmp_frame(ppp, skb); + else { + ++ppp->dev->stats.rx_length_errors; + kfree_skb(skb); + ppp_receive_error(ppp); + } + } + + return; + + err: + kfree_skb(skb); + ppp_receive_error(ppp); +} + +/* + * Insert a fragment on the MP reconstruction queue. + * The queue is ordered by increasing sequence number. + */ +static void +ppp_mp_insert(struct ppp *ppp, struct sk_buff *skb) +{ + struct sk_buff *p; + struct sk_buff_head *list = &ppp->mrq; + u32 seq = PPP_MP_CB(skb)->sequence; + + /* N.B. we don't need to lock the list lock because we have the + ppp unit receive-side lock. */ + skb_queue_walk(list, p) { + if (seq_before(seq, PPP_MP_CB(p)->sequence)) + break; + } + __skb_queue_before(list, p, skb); +} + +/* + * Reconstruct a packet from the MP fragment queue. + * We go through increasing sequence numbers until we find a + * complete packet, or we get to the sequence number for a fragment + * which hasn't arrived but might still do so. + */ +static struct sk_buff * +ppp_mp_reconstruct(struct ppp *ppp) +{ + u32 seq = ppp->nextseq; + u32 minseq = ppp->minseq; + struct sk_buff_head *list = &ppp->mrq; + struct sk_buff *p, *tmp; + struct sk_buff *head, *tail; + struct sk_buff *skb = NULL; + int lost = 0, len = 0; + + if (ppp->mrru == 0) /* do nothing until mrru is set */ + return NULL; + head = list->next; + tail = NULL; + skb_queue_walk_safe(list, p, tmp) { + again: + if (seq_before(PPP_MP_CB(p)->sequence, seq)) { + /* this can't happen, anyway ignore the skb */ + netdev_err(ppp->dev, "ppp_mp_reconstruct bad " + "seq %u < %u\n", + PPP_MP_CB(p)->sequence, seq); + __skb_unlink(p, list); + kfree_skb(p); + continue; + } + if (PPP_MP_CB(p)->sequence != seq) { + /* Fragment `seq' is missing. If it is after + minseq, it might arrive later, so stop here. */ + if (seq_after(seq, minseq)) + break; + /* Fragment `seq' is lost, keep going. */ + lost = 1; + seq = seq_before(minseq, PPP_MP_CB(p)->sequence)? + minseq + 1: PPP_MP_CB(p)->sequence; + goto again; + } + + /* + * At this point we know that all the fragments from + * ppp->nextseq to seq are either present or lost. + * Also, there are no complete packets in the queue + * that have no missing fragments and end before this + * fragment. + */ + + /* B bit set indicates this fragment starts a packet */ + if (PPP_MP_CB(p)->BEbits & B) { + head = p; + lost = 0; + len = 0; + } + + len += p->len; + + /* Got a complete packet yet? */ + if (lost == 0 && (PPP_MP_CB(p)->BEbits & E) && + (PPP_MP_CB(head)->BEbits & B)) { + if (len > ppp->mrru + 2) { + ++ppp->dev->stats.rx_length_errors; + netdev_printk(KERN_DEBUG, ppp->dev, + "PPP: reconstructed packet" + " is too long (%d)\n", len); + } else { + tail = p; + break; + } + ppp->nextseq = seq + 1; + } + + /* + * If this is the ending fragment of a packet, + * and we haven't found a complete valid packet yet, + * we can discard up to and including this fragment. + */ + if (PPP_MP_CB(p)->BEbits & E) { + struct sk_buff *tmp2; + + skb_queue_reverse_walk_from_safe(list, p, tmp2) { + __skb_unlink(p, list); + kfree_skb(p); + } + head = skb_peek(list); + if (!head) + break; + } + ++seq; + } + + /* If we have a complete packet, copy it all into one skb. */ + if (tail != NULL) { + /* If we have discarded any fragments, + signal a receive error. */ + if (PPP_MP_CB(head)->sequence != ppp->nextseq) { + if (ppp->debug & 1) + netdev_printk(KERN_DEBUG, ppp->dev, + " missed pkts %u..%u\n", + ppp->nextseq, + PPP_MP_CB(head)->sequence-1); + ++ppp->dev->stats.rx_dropped; + ppp_receive_error(ppp); + } + + skb = head; + if (head != tail) { + struct sk_buff **fragpp = &skb_shinfo(skb)->frag_list; + p = skb_queue_next(list, head); + __skb_unlink(skb, list); + skb_queue_walk_from_safe(list, p, tmp) { + __skb_unlink(p, list); + *fragpp = p; + p->next = NULL; + fragpp = &p->next; + + skb->len += p->len; + skb->data_len += p->len; + skb->truesize += p->len; + + if (p == tail) + break; + } + } else { + __skb_unlink(skb, list); + } + + ppp->nextseq = PPP_MP_CB(tail)->sequence + 1; + } + + return skb; +} +#endif /* CONFIG_PPP_MULTILINK */ + +/* + * Channel interface. + */ + +/* Create a new, unattached ppp channel. */ +int ppp_register_channel(struct ppp_channel *chan) +{ + return ppp_register_net_channel(current->nsproxy->net_ns, chan); +} + +/* Create a new, unattached ppp channel for specified net. */ +int ppp_register_net_channel(struct net *net, struct ppp_channel *chan) +{ + struct channel *pch; + struct ppp_net *pn; + + pch = kzalloc(sizeof(struct channel), GFP_KERNEL); + if (!pch) + return -ENOMEM; + + pn = ppp_pernet(net); + + pch->ppp = NULL; + pch->chan = chan; + pch->chan_net = net; + chan->ppp = pch; + init_ppp_file(&pch->file, CHANNEL); + pch->file.hdrlen = chan->hdrlen; +#ifdef CONFIG_PPP_MULTILINK + pch->lastseq = -1; +#endif /* CONFIG_PPP_MULTILINK */ + init_rwsem(&pch->chan_sem); + spin_lock_init(&pch->downl); + rwlock_init(&pch->upl); + + spin_lock_bh(&pn->all_channels_lock); + pch->file.index = ++pn->last_channel_index; + list_add(&pch->list, &pn->new_channels); + atomic_inc(&channel_count); + spin_unlock_bh(&pn->all_channels_lock); + + return 0; +} + +/* + * Return the index of a channel. + */ +int ppp_channel_index(struct ppp_channel *chan) +{ + struct channel *pch = chan->ppp; + + if (pch) + return pch->file.index; + return -1; +} + +/* + * Return the PPP unit number to which a channel is connected. + */ +int ppp_unit_number(struct ppp_channel *chan) +{ + struct channel *pch = chan->ppp; + int unit = -1; + + if (pch) { + read_lock_bh(&pch->upl); + if (pch->ppp) + unit = pch->ppp->file.index; + read_unlock_bh(&pch->upl); + } + return unit; +} + +/* + * Return the PPP device interface name of a channel. + */ +char *ppp_dev_name(struct ppp_channel *chan) +{ + struct channel *pch = chan->ppp; + char *name = NULL; + + if (pch) { + read_lock_bh(&pch->upl); + if (pch->ppp && pch->ppp->dev) + name = pch->ppp->dev->name; + read_unlock_bh(&pch->upl); + } + return name; +} + + +/* + * Disconnect a channel from the generic layer. + * This must be called in process context. + */ +void +ppp_unregister_channel(struct ppp_channel *chan) +{ + struct channel *pch = chan->ppp; + struct ppp_net *pn; + + if (!pch) + return; /* should never happen */ + + chan->ppp = NULL; + + /* + * This ensures that we have returned from any calls into the + * the channel's start_xmit or ioctl routine before we proceed. + */ + down_write(&pch->chan_sem); + spin_lock_bh(&pch->downl); + pch->chan = NULL; + spin_unlock_bh(&pch->downl); + up_write(&pch->chan_sem); + ppp_disconnect_channel(pch); + + pn = ppp_pernet(pch->chan_net); + spin_lock_bh(&pn->all_channels_lock); + list_del(&pch->list); + spin_unlock_bh(&pn->all_channels_lock); + + pch->file.dead = 1; + wake_up_interruptible(&pch->file.rwait); + if (atomic_dec_and_test(&pch->file.refcnt)) + ppp_destroy_channel(pch); +} + +/* + * Callback from a channel when it can accept more to transmit. + * This should be called at BH/softirq level, not interrupt level. + */ +void +ppp_output_wakeup(struct ppp_channel *chan) +{ + struct channel *pch = chan->ppp; + + if (!pch) + return; + ppp_channel_push(pch); +} + +/* + * Compression control. + */ + +/* Process the PPPIOCSCOMPRESS ioctl. */ +static int +ppp_set_compress(struct ppp *ppp, unsigned long arg) +{ + int err; + struct compressor *cp, *ocomp; + struct ppp_option_data data; + void *state, *ostate; + unsigned char ccp_option[CCP_MAX_OPTION_LENGTH]; + + err = -EFAULT; + if (copy_from_user(&data, (void __user *) arg, sizeof(data)) || + (data.length <= CCP_MAX_OPTION_LENGTH && + copy_from_user(ccp_option, (void __user *) data.ptr, data.length))) + goto out; + err = -EINVAL; + if (data.length > CCP_MAX_OPTION_LENGTH || + ccp_option[1] < 2 || ccp_option[1] > data.length) + goto out; + + cp = try_then_request_module( + find_compressor(ccp_option[0]), + "ppp-compress-%d", ccp_option[0]); + if (!cp) + goto out; + + err = -ENOBUFS; + if (data.transmit) { + state = cp->comp_alloc(ccp_option, data.length); + if (state) { + ppp_xmit_lock(ppp); + ppp->xstate &= ~SC_COMP_RUN; + ocomp = ppp->xcomp; + ostate = ppp->xc_state; + ppp->xcomp = cp; + ppp->xc_state = state; + ppp_xmit_unlock(ppp); + if (ostate) { + ocomp->comp_free(ostate); + module_put(ocomp->owner); + } + err = 0; + } else + module_put(cp->owner); + + } else { + state = cp->decomp_alloc(ccp_option, data.length); + if (state) { + ppp_recv_lock(ppp); + ppp->rstate &= ~SC_DECOMP_RUN; + ocomp = ppp->rcomp; + ostate = ppp->rc_state; + ppp->rcomp = cp; + ppp->rc_state = state; + ppp_recv_unlock(ppp); + if (ostate) { + ocomp->decomp_free(ostate); + module_put(ocomp->owner); + } + err = 0; + } else + module_put(cp->owner); + } + + out: + return err; +} + +/* + * Look at a CCP packet and update our state accordingly. + * We assume the caller has the xmit or recv path locked. + */ +static void +ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound) +{ + unsigned char *dp; + int len; + + if (!pskb_may_pull(skb, CCP_HDRLEN + 2)) + return; /* no header */ + dp = skb->data + 2; + + switch (CCP_CODE(dp)) { + case CCP_CONFREQ: + + /* A ConfReq starts negotiation of compression + * in one direction of transmission, + * and hence brings it down...but which way? + * + * Remember: + * A ConfReq indicates what the sender would like to receive + */ + if(inbound) + /* He is proposing what I should send */ + ppp->xstate &= ~SC_COMP_RUN; + else + /* I am proposing to what he should send */ + ppp->rstate &= ~SC_DECOMP_RUN; + + break; + + case CCP_TERMREQ: + case CCP_TERMACK: + /* + * CCP is going down, both directions of transmission + */ + ppp->rstate &= ~SC_DECOMP_RUN; + ppp->xstate &= ~SC_COMP_RUN; + break; + + case CCP_CONFACK: + if ((ppp->flags & (SC_CCP_OPEN | SC_CCP_UP)) != SC_CCP_OPEN) + break; + len = CCP_LENGTH(dp); + if (!pskb_may_pull(skb, len + 2)) + return; /* too short */ + dp += CCP_HDRLEN; + len -= CCP_HDRLEN; + if (len < CCP_OPT_MINLEN || len < CCP_OPT_LENGTH(dp)) + break; + if (inbound) { + /* we will start receiving compressed packets */ + if (!ppp->rc_state) + break; + if (ppp->rcomp->decomp_init(ppp->rc_state, dp, len, + ppp->file.index, 0, ppp->mru, ppp->debug)) { + ppp->rstate |= SC_DECOMP_RUN; + ppp->rstate &= ~(SC_DC_ERROR | SC_DC_FERROR); + } + } else { + /* we will soon start sending compressed packets */ + if (!ppp->xc_state) + break; + if (ppp->xcomp->comp_init(ppp->xc_state, dp, len, + ppp->file.index, 0, ppp->debug)) + ppp->xstate |= SC_COMP_RUN; + } + break; + + case CCP_RESETACK: + /* reset the [de]compressor */ + if ((ppp->flags & SC_CCP_UP) == 0) + break; + if (inbound) { + if (ppp->rc_state && (ppp->rstate & SC_DECOMP_RUN)) { + ppp->rcomp->decomp_reset(ppp->rc_state); + ppp->rstate &= ~SC_DC_ERROR; + } + } else { + if (ppp->xc_state && (ppp->xstate & SC_COMP_RUN)) + ppp->xcomp->comp_reset(ppp->xc_state); + } + break; + } +} + +/* Free up compression resources. */ +static void +ppp_ccp_closed(struct ppp *ppp) +{ + void *xstate, *rstate; + struct compressor *xcomp, *rcomp; + + ppp_lock(ppp); + ppp->flags &= ~(SC_CCP_OPEN | SC_CCP_UP); + ppp->xstate = 0; + xcomp = ppp->xcomp; + xstate = ppp->xc_state; + ppp->xc_state = NULL; + ppp->rstate = 0; + rcomp = ppp->rcomp; + rstate = ppp->rc_state; + ppp->rc_state = NULL; + ppp_unlock(ppp); + + if (xstate) { + xcomp->comp_free(xstate); + module_put(xcomp->owner); + } + if (rstate) { + rcomp->decomp_free(rstate); + module_put(rcomp->owner); + } +} + +/* List of compressors. */ +static LIST_HEAD(compressor_list); +static DEFINE_SPINLOCK(compressor_list_lock); + +struct compressor_entry { + struct list_head list; + struct compressor *comp; +}; + +static struct compressor_entry * +find_comp_entry(int proto) +{ + struct compressor_entry *ce; + + list_for_each_entry(ce, &compressor_list, list) { + if (ce->comp->compress_proto == proto) + return ce; + } + return NULL; +} + +/* Register a compressor */ +int +ppp_register_compressor(struct compressor *cp) +{ + struct compressor_entry *ce; + int ret; + spin_lock(&compressor_list_lock); + ret = -EEXIST; + if (find_comp_entry(cp->compress_proto)) + goto out; + ret = -ENOMEM; + ce = kmalloc(sizeof(struct compressor_entry), GFP_ATOMIC); + if (!ce) + goto out; + ret = 0; + ce->comp = cp; + list_add(&ce->list, &compressor_list); + out: + spin_unlock(&compressor_list_lock); + return ret; +} + +/* Unregister a compressor */ +void +ppp_unregister_compressor(struct compressor *cp) +{ + struct compressor_entry *ce; + + spin_lock(&compressor_list_lock); + ce = find_comp_entry(cp->compress_proto); + if (ce && ce->comp == cp) { + list_del(&ce->list); + kfree(ce); + } + spin_unlock(&compressor_list_lock); +} + +/* Find a compressor. */ +static struct compressor * +find_compressor(int type) +{ + struct compressor_entry *ce; + struct compressor *cp = NULL; + + spin_lock(&compressor_list_lock); + ce = find_comp_entry(type); + if (ce) { + cp = ce->comp; + if (!try_module_get(cp->owner)) + cp = NULL; + } + spin_unlock(&compressor_list_lock); + return cp; +} + +/* + * Miscelleneous stuff. + */ + +static void +ppp_get_stats(struct ppp *ppp, struct ppp_stats *st) +{ + struct slcompress *vj = ppp->vj; + + memset(st, 0, sizeof(*st)); + st->p.ppp_ipackets = ppp->dev->stats.rx_packets; + st->p.ppp_ierrors = ppp->dev->stats.rx_errors; + st->p.ppp_ibytes = ppp->dev->stats.rx_bytes; + st->p.ppp_opackets = ppp->dev->stats.tx_packets; + st->p.ppp_oerrors = ppp->dev->stats.tx_errors; + st->p.ppp_obytes = ppp->dev->stats.tx_bytes; + if (!vj) + return; + st->vj.vjs_packets = vj->sls_o_compressed + vj->sls_o_uncompressed; + st->vj.vjs_compressed = vj->sls_o_compressed; + st->vj.vjs_searches = vj->sls_o_searches; + st->vj.vjs_misses = vj->sls_o_misses; + st->vj.vjs_errorin = vj->sls_i_error; + st->vj.vjs_tossed = vj->sls_i_tossed; + st->vj.vjs_uncompressedin = vj->sls_i_uncompressed; + st->vj.vjs_compressedin = vj->sls_i_compressed; +} + +/* + * Stuff for handling the lists of ppp units and channels + * and for initialization. + */ + +/* + * Create a new ppp interface unit. Fails if it can't allocate memory + * or if there is already a unit with the requested number. + * unit == -1 means allocate a new number. + */ +static struct ppp * +ppp_create_interface(struct net *net, int unit, int *retp) +{ + struct ppp *ppp; + struct ppp_net *pn; + struct net_device *dev = NULL; + int ret = -ENOMEM; + int i; + + dev = alloc_netdev(sizeof(struct ppp), "", ppp_setup); + if (!dev) + goto out1; + + pn = ppp_pernet(net); + + ppp = netdev_priv(dev); + ppp->dev = dev; + ppp->mru = PPP_MRU; + init_ppp_file(&ppp->file, INTERFACE); + ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */ + for (i = 0; i < NUM_NP; ++i) + ppp->npmode[i] = NPMODE_PASS; + INIT_LIST_HEAD(&ppp->channels); + spin_lock_init(&ppp->rlock); + spin_lock_init(&ppp->wlock); +#ifdef CONFIG_PPP_MULTILINK + ppp->minseq = -1; + skb_queue_head_init(&ppp->mrq); +#endif /* CONFIG_PPP_MULTILINK */ + + /* + * drum roll: don't forget to set + * the net device is belong to + */ + dev_net_set(dev, net); + + mutex_lock(&pn->all_ppp_mutex); + + if (unit < 0) { + unit = unit_get(&pn->units_idr, ppp); + if (unit < 0) { + ret = unit; + goto out2; + } + } else { + ret = -EEXIST; + if (unit_find(&pn->units_idr, unit)) + goto out2; /* unit already exists */ + /* + * if caller need a specified unit number + * lets try to satisfy him, otherwise -- + * he should better ask us for new unit number + * + * NOTE: yes I know that returning EEXIST it's not + * fair but at least pppd will ask us to allocate + * new unit in this case so user is happy :) + */ + unit = unit_set(&pn->units_idr, ppp, unit); + if (unit < 0) + goto out2; + } + + /* Initialize the new ppp unit */ + ppp->file.index = unit; + sprintf(dev->name, "ppp%d", unit); + + ret = register_netdev(dev); + if (ret != 0) { + unit_put(&pn->units_idr, unit); + netdev_err(ppp->dev, "PPP: couldn't register device %s (%d)\n", + dev->name, ret); + goto out2; + } + + ppp->ppp_net = net; + + atomic_inc(&ppp_unit_count); + mutex_unlock(&pn->all_ppp_mutex); + + *retp = 0; + return ppp; + +out2: + mutex_unlock(&pn->all_ppp_mutex); + free_netdev(dev); +out1: + *retp = ret; + return NULL; +} + +/* + * Initialize a ppp_file structure. + */ +static void +init_ppp_file(struct ppp_file *pf, int kind) +{ + pf->kind = kind; + skb_queue_head_init(&pf->xq); + skb_queue_head_init(&pf->rq); + atomic_set(&pf->refcnt, 1); + init_waitqueue_head(&pf->rwait); +} + +/* + * Take down a ppp interface unit - called when the owning file + * (the one that created the unit) is closed or detached. + */ +static void ppp_shutdown_interface(struct ppp *ppp) +{ + struct ppp_net *pn; + + pn = ppp_pernet(ppp->ppp_net); + mutex_lock(&pn->all_ppp_mutex); + + /* This will call dev_close() for us. */ + ppp_lock(ppp); + if (!ppp->closing) { + ppp->closing = 1; + ppp_unlock(ppp); + unregister_netdev(ppp->dev); + unit_put(&pn->units_idr, ppp->file.index); + } else + ppp_unlock(ppp); + + ppp->file.dead = 1; + ppp->owner = NULL; + wake_up_interruptible(&ppp->file.rwait); + + mutex_unlock(&pn->all_ppp_mutex); +} + +/* + * Free the memory used by a ppp unit. This is only called once + * there are no channels connected to the unit and no file structs + * that reference the unit. + */ +static void ppp_destroy_interface(struct ppp *ppp) +{ + atomic_dec(&ppp_unit_count); + + if (!ppp->file.dead || ppp->n_channels) { + /* "can't happen" */ + netdev_err(ppp->dev, "ppp: destroying ppp struct %p " + "but dead=%d n_channels=%d !\n", + ppp, ppp->file.dead, ppp->n_channels); + return; + } + + ppp_ccp_closed(ppp); + if (ppp->vj) { + slhc_free(ppp->vj); + ppp->vj = NULL; + } + skb_queue_purge(&ppp->file.xq); + skb_queue_purge(&ppp->file.rq); +#ifdef CONFIG_PPP_MULTILINK + skb_queue_purge(&ppp->mrq); +#endif /* CONFIG_PPP_MULTILINK */ +#ifdef CONFIG_PPP_FILTER + kfree(ppp->pass_filter); + ppp->pass_filter = NULL; + kfree(ppp->active_filter); + ppp->active_filter = NULL; +#endif /* CONFIG_PPP_FILTER */ + + kfree_skb(ppp->xmit_pending); + + free_netdev(ppp->dev); +} + +/* + * Locate an existing ppp unit. + * The caller should have locked the all_ppp_mutex. + */ +static struct ppp * +ppp_find_unit(struct ppp_net *pn, int unit) +{ + return unit_find(&pn->units_idr, unit); +} + +/* + * Locate an existing ppp channel. + * The caller should have locked the all_channels_lock. + * First we look in the new_channels list, then in the + * all_channels list. If found in the new_channels list, + * we move it to the all_channels list. This is for speed + * when we have a lot of channels in use. + */ +static struct channel * +ppp_find_channel(struct ppp_net *pn, int unit) +{ + struct channel *pch; + + list_for_each_entry(pch, &pn->new_channels, list) { + if (pch->file.index == unit) { + list_move(&pch->list, &pn->all_channels); + return pch; + } + } + + list_for_each_entry(pch, &pn->all_channels, list) { + if (pch->file.index == unit) + return pch; + } + + return NULL; +} + +/* + * Connect a PPP channel to a PPP interface unit. + */ +static int +ppp_connect_channel(struct channel *pch, int unit) +{ + struct ppp *ppp; + struct ppp_net *pn; + int ret = -ENXIO; + int hdrlen; + + pn = ppp_pernet(pch->chan_net); + + mutex_lock(&pn->all_ppp_mutex); + ppp = ppp_find_unit(pn, unit); + if (!ppp) + goto out; + write_lock_bh(&pch->upl); + ret = -EINVAL; + if (pch->ppp) + goto outl; + + ppp_lock(ppp); + if (pch->file.hdrlen > ppp->file.hdrlen) + ppp->file.hdrlen = pch->file.hdrlen; + hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */ + if (hdrlen > ppp->dev->hard_header_len) + ppp->dev->hard_header_len = hdrlen; + list_add_tail(&pch->clist, &ppp->channels); + ++ppp->n_channels; + pch->ppp = ppp; + atomic_inc(&ppp->file.refcnt); + ppp_unlock(ppp); + ret = 0; + + outl: + write_unlock_bh(&pch->upl); + out: + mutex_unlock(&pn->all_ppp_mutex); + return ret; +} + +/* + * Disconnect a channel from its ppp unit. + */ +static int +ppp_disconnect_channel(struct channel *pch) +{ + struct ppp *ppp; + int err = -EINVAL; + + write_lock_bh(&pch->upl); + ppp = pch->ppp; + pch->ppp = NULL; + write_unlock_bh(&pch->upl); + if (ppp) { + /* remove it from the ppp unit's list */ + ppp_lock(ppp); + list_del(&pch->clist); + if (--ppp->n_channels == 0) + wake_up_interruptible(&ppp->file.rwait); + ppp_unlock(ppp); + if (atomic_dec_and_test(&ppp->file.refcnt)) + ppp_destroy_interface(ppp); + err = 0; + } + return err; +} + +/* + * Free up the resources used by a ppp channel. + */ +static void ppp_destroy_channel(struct channel *pch) +{ + atomic_dec(&channel_count); + + if (!pch->file.dead) { + /* "can't happen" */ + pr_err("ppp: destroying undead channel %p !\n", pch); + return; + } + skb_queue_purge(&pch->file.xq); + skb_queue_purge(&pch->file.rq); + kfree(pch); +} + +static void __exit ppp_cleanup(void) +{ + /* should never happen */ + if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count)) + pr_err("PPP: removing module but units remain!\n"); + unregister_chrdev(PPP_MAJOR, "ppp"); + device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); + class_destroy(ppp_class); + unregister_pernet_device(&ppp_net_ops); +} + +/* + * Units handling. Caller must protect concurrent access + * by holding all_ppp_mutex + */ + +static int __unit_alloc(struct idr *p, void *ptr, int n) +{ + int unit, err; + +again: + if (!idr_pre_get(p, GFP_KERNEL)) { + pr_err("PPP: No free memory for idr\n"); + return -ENOMEM; + } + + err = idr_get_new_above(p, ptr, n, &unit); + if (err < 0) { + if (err == -EAGAIN) + goto again; + return err; + } + + return unit; +} + +/* associate pointer with specified number */ +static int unit_set(struct idr *p, void *ptr, int n) +{ + int unit; + + unit = __unit_alloc(p, ptr, n); + if (unit < 0) + return unit; + else if (unit != n) { + idr_remove(p, unit); + return -EINVAL; + } + + return unit; +} + +/* get new free unit number and associate pointer with it */ +static int unit_get(struct idr *p, void *ptr) +{ + return __unit_alloc(p, ptr, 0); +} + +/* put unit number back to a pool */ +static void unit_put(struct idr *p, int n) +{ + idr_remove(p, n); +} + +/* get pointer associated with the number */ +static void *unit_find(struct idr *p, int n) +{ + return idr_find(p, n); +} + +/* Module/initialization stuff */ + +module_init(ppp_init); +module_exit(ppp_cleanup); + +EXPORT_SYMBOL(ppp_register_net_channel); +EXPORT_SYMBOL(ppp_register_channel); +EXPORT_SYMBOL(ppp_unregister_channel); +EXPORT_SYMBOL(ppp_channel_index); +EXPORT_SYMBOL(ppp_unit_number); +EXPORT_SYMBOL(ppp_dev_name); +EXPORT_SYMBOL(ppp_input); +EXPORT_SYMBOL(ppp_input_error); +EXPORT_SYMBOL(ppp_output_wakeup); +EXPORT_SYMBOL(ppp_register_compressor); +EXPORT_SYMBOL(ppp_unregister_compressor); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV(PPP_MAJOR, 0); +MODULE_ALIAS("devname:ppp"); diff --git a/drivers/net/ppp/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c new file mode 100644 index 0000000..9a1849a --- /dev/null +++ b/drivers/net/ppp/ppp_mppe.c @@ -0,0 +1,740 @@ +/* + * ppp_mppe.c - interface MPPE to the PPP code. + * This version is for use with Linux kernel 2.6.14+ + * + * By Frank Cusack . + * Copyright (c) 2002,2003,2004 Google, Inc. + * All rights reserved. + * + * License: + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. + * + * ALTERNATIVELY, provided that this notice is retained in full, this product + * may be distributed under the terms of the GNU General Public License (GPL), + * in which case the provisions of the GPL apply INSTEAD OF those given above. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * Changelog: + * 08/12/05 - Matt Domsch + * Only need extra skb padding on transmit, not receive. + * 06/18/04 - Matt Domsch , Oleg Makarenko + * Use Linux kernel 2.6 arc4 and sha1 routines rather than + * providing our own. + * 2/15/04 - TS: added #include and testing for Kernel + * version before using + * MOD_DEC_USAGE_COUNT/MOD_INC_USAGE_COUNT which are + * deprecated in 2.6 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ppp_mppe.h" + +MODULE_AUTHOR("Frank Cusack "); +MODULE_DESCRIPTION("Point-to-Point Protocol Microsoft Point-to-Point Encryption support"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE)); +MODULE_VERSION("1.0.2"); + +static unsigned int +setup_sg(struct scatterlist *sg, const void *address, unsigned int length) +{ + sg_set_buf(sg, address, length); + return length; +} + +#define SHA1_PAD_SIZE 40 + +/* + * kernel crypto API needs its arguments to be in kmalloc'd memory, not in the module + * static data area. That means sha_pad needs to be kmalloc'd. + */ + +struct sha_pad { + unsigned char sha_pad1[SHA1_PAD_SIZE]; + unsigned char sha_pad2[SHA1_PAD_SIZE]; +}; +static struct sha_pad *sha_pad; + +static inline void sha_pad_init(struct sha_pad *shapad) +{ + memset(shapad->sha_pad1, 0x00, sizeof(shapad->sha_pad1)); + memset(shapad->sha_pad2, 0xF2, sizeof(shapad->sha_pad2)); +} + +/* + * State for an MPPE (de)compressor. + */ +struct ppp_mppe_state { + struct crypto_blkcipher *arc4; + struct crypto_hash *sha1; + unsigned char *sha1_digest; + unsigned char master_key[MPPE_MAX_KEY_LEN]; + unsigned char session_key[MPPE_MAX_KEY_LEN]; + unsigned keylen; /* key length in bytes */ + /* NB: 128-bit == 16, 40-bit == 8! */ + /* If we want to support 56-bit, */ + /* the unit has to change to bits */ + unsigned char bits; /* MPPE control bits */ + unsigned ccount; /* 12-bit coherency count (seqno) */ + unsigned stateful; /* stateful mode flag */ + int discard; /* stateful mode packet loss flag */ + int sanity_errors; /* take down LCP if too many */ + int unit; + int debug; + struct compstat stats; +}; + +/* struct ppp_mppe_state.bits definitions */ +#define MPPE_BIT_A 0x80 /* Encryption table were (re)inititalized */ +#define MPPE_BIT_B 0x40 /* MPPC only (not implemented) */ +#define MPPE_BIT_C 0x20 /* MPPC only (not implemented) */ +#define MPPE_BIT_D 0x10 /* This is an encrypted frame */ + +#define MPPE_BIT_FLUSHED MPPE_BIT_A +#define MPPE_BIT_ENCRYPTED MPPE_BIT_D + +#define MPPE_BITS(p) ((p)[4] & 0xf0) +#define MPPE_CCOUNT(p) ((((p)[4] & 0x0f) << 8) + (p)[5]) +#define MPPE_CCOUNT_SPACE 0x1000 /* The size of the ccount space */ + +#define MPPE_OVHD 2 /* MPPE overhead/packet */ +#define SANITY_MAX 1600 /* Max bogon factor we will tolerate */ + +/* + * Key Derivation, from RFC 3078, RFC 3079. + * Equivalent to Get_Key() for MS-CHAP as described in RFC 3079. + */ +static void get_new_key_from_sha(struct ppp_mppe_state * state) +{ + struct hash_desc desc; + struct scatterlist sg[4]; + unsigned int nbytes; + + sg_init_table(sg, 4); + + nbytes = setup_sg(&sg[0], state->master_key, state->keylen); + nbytes += setup_sg(&sg[1], sha_pad->sha_pad1, + sizeof(sha_pad->sha_pad1)); + nbytes += setup_sg(&sg[2], state->session_key, state->keylen); + nbytes += setup_sg(&sg[3], sha_pad->sha_pad2, + sizeof(sha_pad->sha_pad2)); + + desc.tfm = state->sha1; + desc.flags = 0; + + crypto_hash_digest(&desc, sg, nbytes, state->sha1_digest); +} + +/* + * Perform the MPPE rekey algorithm, from RFC 3078, sec. 7.3. + * Well, not what's written there, but rather what they meant. + */ +static void mppe_rekey(struct ppp_mppe_state * state, int initial_key) +{ + struct scatterlist sg_in[1], sg_out[1]; + struct blkcipher_desc desc = { .tfm = state->arc4 }; + + get_new_key_from_sha(state); + if (!initial_key) { + crypto_blkcipher_setkey(state->arc4, state->sha1_digest, + state->keylen); + sg_init_table(sg_in, 1); + sg_init_table(sg_out, 1); + setup_sg(sg_in, state->sha1_digest, state->keylen); + setup_sg(sg_out, state->session_key, state->keylen); + if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in, + state->keylen) != 0) { + printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n"); + } + } else { + memcpy(state->session_key, state->sha1_digest, state->keylen); + } + if (state->keylen == 8) { + /* See RFC 3078 */ + state->session_key[0] = 0xd1; + state->session_key[1] = 0x26; + state->session_key[2] = 0x9e; + } + crypto_blkcipher_setkey(state->arc4, state->session_key, state->keylen); +} + +/* + * Allocate space for a (de)compressor. + */ +static void *mppe_alloc(unsigned char *options, int optlen) +{ + struct ppp_mppe_state *state; + unsigned int digestsize; + + if (optlen != CILEN_MPPE + sizeof(state->master_key) || + options[0] != CI_MPPE || options[1] != CILEN_MPPE) + goto out; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (state == NULL) + goto out; + + + state->arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(state->arc4)) { + state->arc4 = NULL; + goto out_free; + } + + state->sha1 = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(state->sha1)) { + state->sha1 = NULL; + goto out_free; + } + + digestsize = crypto_hash_digestsize(state->sha1); + if (digestsize < MPPE_MAX_KEY_LEN) + goto out_free; + + state->sha1_digest = kmalloc(digestsize, GFP_KERNEL); + if (!state->sha1_digest) + goto out_free; + + /* Save keys. */ + memcpy(state->master_key, &options[CILEN_MPPE], + sizeof(state->master_key)); + memcpy(state->session_key, state->master_key, + sizeof(state->master_key)); + + /* + * We defer initial key generation until mppe_init(), as mppe_alloc() + * is called frequently during negotiation. + */ + + return (void *)state; + + out_free: + if (state->sha1_digest) + kfree(state->sha1_digest); + if (state->sha1) + crypto_free_hash(state->sha1); + if (state->arc4) + crypto_free_blkcipher(state->arc4); + kfree(state); + out: + return NULL; +} + +/* + * Deallocate space for a (de)compressor. + */ +static void mppe_free(void *arg) +{ + struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; + if (state) { + if (state->sha1_digest) + kfree(state->sha1_digest); + if (state->sha1) + crypto_free_hash(state->sha1); + if (state->arc4) + crypto_free_blkcipher(state->arc4); + kfree(state); + } +} + +/* + * Initialize (de)compressor state. + */ +static int +mppe_init(void *arg, unsigned char *options, int optlen, int unit, int debug, + const char *debugstr) +{ + struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; + unsigned char mppe_opts; + + if (optlen != CILEN_MPPE || + options[0] != CI_MPPE || options[1] != CILEN_MPPE) + return 0; + + MPPE_CI_TO_OPTS(&options[2], mppe_opts); + if (mppe_opts & MPPE_OPT_128) + state->keylen = 16; + else if (mppe_opts & MPPE_OPT_40) + state->keylen = 8; + else { + printk(KERN_WARNING "%s[%d]: unknown key length\n", debugstr, + unit); + return 0; + } + if (mppe_opts & MPPE_OPT_STATEFUL) + state->stateful = 1; + + /* Generate the initial session key. */ + mppe_rekey(state, 1); + + if (debug) { + int i; + char mkey[sizeof(state->master_key) * 2 + 1]; + char skey[sizeof(state->session_key) * 2 + 1]; + + printk(KERN_DEBUG "%s[%d]: initialized with %d-bit %s mode\n", + debugstr, unit, (state->keylen == 16) ? 128 : 40, + (state->stateful) ? "stateful" : "stateless"); + + for (i = 0; i < sizeof(state->master_key); i++) + sprintf(mkey + i * 2, "%02x", state->master_key[i]); + for (i = 0; i < sizeof(state->session_key); i++) + sprintf(skey + i * 2, "%02x", state->session_key[i]); + printk(KERN_DEBUG + "%s[%d]: keys: master: %s initial session: %s\n", + debugstr, unit, mkey, skey); + } + + /* + * Initialize the coherency count. The initial value is not specified + * in RFC 3078, but we can make a reasonable assumption that it will + * start at 0. Setting it to the max here makes the comp/decomp code + * do the right thing (determined through experiment). + */ + state->ccount = MPPE_CCOUNT_SPACE - 1; + + /* + * Note that even though we have initialized the key table, we don't + * set the FLUSHED bit. This is contrary to RFC 3078, sec. 3.1. + */ + state->bits = MPPE_BIT_ENCRYPTED; + + state->unit = unit; + state->debug = debug; + + return 1; +} + +static int +mppe_comp_init(void *arg, unsigned char *options, int optlen, int unit, + int hdrlen, int debug) +{ + /* ARGSUSED */ + return mppe_init(arg, options, optlen, unit, debug, "mppe_comp_init"); +} + +/* + * We received a CCP Reset-Request (actually, we are sending a Reset-Ack), + * tell the compressor to rekey. Note that we MUST NOT rekey for + * every CCP Reset-Request; we only rekey on the next xmit packet. + * We might get multiple CCP Reset-Requests if our CCP Reset-Ack is lost. + * So, rekeying for every CCP Reset-Request is broken as the peer will not + * know how many times we've rekeyed. (If we rekey and THEN get another + * CCP Reset-Request, we must rekey again.) + */ +static void mppe_comp_reset(void *arg) +{ + struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; + + state->bits |= MPPE_BIT_FLUSHED; +} + +/* + * Compress (encrypt) a packet. + * It's strange to call this a compressor, since the output is always + * MPPE_OVHD + 2 bytes larger than the input. + */ +static int +mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf, + int isize, int osize) +{ + struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; + struct blkcipher_desc desc = { .tfm = state->arc4 }; + int proto; + struct scatterlist sg_in[1], sg_out[1]; + + /* + * Check that the protocol is in the range we handle. + */ + proto = PPP_PROTOCOL(ibuf); + if (proto < 0x0021 || proto > 0x00fa) + return 0; + + /* Make sure we have enough room to generate an encrypted packet. */ + if (osize < isize + MPPE_OVHD + 2) { + /* Drop the packet if we should encrypt it, but can't. */ + printk(KERN_DEBUG "mppe_compress[%d]: osize too small! " + "(have: %d need: %d)\n", state->unit, + osize, osize + MPPE_OVHD + 2); + return -1; + } + + osize = isize + MPPE_OVHD + 2; + + /* + * Copy over the PPP header and set control bits. + */ + obuf[0] = PPP_ADDRESS(ibuf); + obuf[1] = PPP_CONTROL(ibuf); + put_unaligned_be16(PPP_COMP, obuf + 2); + obuf += PPP_HDRLEN; + + state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; + if (state->debug >= 7) + printk(KERN_DEBUG "mppe_compress[%d]: ccount %d\n", state->unit, + state->ccount); + put_unaligned_be16(state->ccount, obuf); + + if (!state->stateful || /* stateless mode */ + ((state->ccount & 0xff) == 0xff) || /* "flag" packet */ + (state->bits & MPPE_BIT_FLUSHED)) { /* CCP Reset-Request */ + /* We must rekey */ + if (state->debug && state->stateful) + printk(KERN_DEBUG "mppe_compress[%d]: rekeying\n", + state->unit); + mppe_rekey(state, 0); + state->bits |= MPPE_BIT_FLUSHED; + } + obuf[0] |= state->bits; + state->bits &= ~MPPE_BIT_FLUSHED; /* reset for next xmit */ + + obuf += MPPE_OVHD; + ibuf += 2; /* skip to proto field */ + isize -= 2; + + /* Encrypt packet */ + sg_init_table(sg_in, 1); + sg_init_table(sg_out, 1); + setup_sg(sg_in, ibuf, isize); + setup_sg(sg_out, obuf, osize); + if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in, isize) != 0) { + printk(KERN_DEBUG "crypto_cypher_encrypt failed\n"); + return -1; + } + + state->stats.unc_bytes += isize; + state->stats.unc_packets++; + state->stats.comp_bytes += osize; + state->stats.comp_packets++; + + return osize; +} + +/* + * Since every frame grows by MPPE_OVHD + 2 bytes, this is always going + * to look bad ... and the longer the link is up the worse it will get. + */ +static void mppe_comp_stats(void *arg, struct compstat *stats) +{ + struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; + + *stats = state->stats; +} + +static int +mppe_decomp_init(void *arg, unsigned char *options, int optlen, int unit, + int hdrlen, int mru, int debug) +{ + /* ARGSUSED */ + return mppe_init(arg, options, optlen, unit, debug, "mppe_decomp_init"); +} + +/* + * We received a CCP Reset-Ack. Just ignore it. + */ +static void mppe_decomp_reset(void *arg) +{ + /* ARGSUSED */ + return; +} + +/* + * Decompress (decrypt) an MPPE packet. + */ +static int +mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf, + int osize) +{ + struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; + struct blkcipher_desc desc = { .tfm = state->arc4 }; + unsigned ccount; + int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED; + int sanity = 0; + struct scatterlist sg_in[1], sg_out[1]; + + if (isize <= PPP_HDRLEN + MPPE_OVHD) { + if (state->debug) + printk(KERN_DEBUG + "mppe_decompress[%d]: short pkt (%d)\n", + state->unit, isize); + return DECOMP_ERROR; + } + + /* + * Make sure we have enough room to decrypt the packet. + * Note that for our test we only subtract 1 byte whereas in + * mppe_compress() we added 2 bytes (+MPPE_OVHD); + * this is to account for possible PFC. + */ + if (osize < isize - MPPE_OVHD - 1) { + printk(KERN_DEBUG "mppe_decompress[%d]: osize too small! " + "(have: %d need: %d)\n", state->unit, + osize, isize - MPPE_OVHD - 1); + return DECOMP_ERROR; + } + osize = isize - MPPE_OVHD - 2; /* assume no PFC */ + + ccount = MPPE_CCOUNT(ibuf); + if (state->debug >= 7) + printk(KERN_DEBUG "mppe_decompress[%d]: ccount %d\n", + state->unit, ccount); + + /* sanity checks -- terminate with extreme prejudice */ + if (!(MPPE_BITS(ibuf) & MPPE_BIT_ENCRYPTED)) { + printk(KERN_DEBUG + "mppe_decompress[%d]: ENCRYPTED bit not set!\n", + state->unit); + state->sanity_errors += 100; + sanity = 1; + } + if (!state->stateful && !flushed) { + printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set in " + "stateless mode!\n", state->unit); + state->sanity_errors += 100; + sanity = 1; + } + if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) { + printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set on " + "flag packet!\n", state->unit); + state->sanity_errors += 100; + sanity = 1; + } + + if (sanity) { + if (state->sanity_errors < SANITY_MAX) + return DECOMP_ERROR; + else + /* + * Take LCP down if the peer is sending too many bogons. + * We don't want to do this for a single or just a few + * instances since it could just be due to packet corruption. + */ + return DECOMP_FATALERROR; + } + + /* + * Check the coherency count. + */ + + if (!state->stateful) { + /* RFC 3078, sec 8.1. Rekey for every packet. */ + while (state->ccount != ccount) { + mppe_rekey(state, 0); + state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; + } + } else { + /* RFC 3078, sec 8.2. */ + if (!state->discard) { + /* normal state */ + state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; + if (ccount != state->ccount) { + /* + * (ccount > state->ccount) + * Packet loss detected, enter the discard state. + * Signal the peer to rekey (by sending a CCP Reset-Request). + */ + state->discard = 1; + return DECOMP_ERROR; + } + } else { + /* discard state */ + if (!flushed) { + /* ccp.c will be silent (no additional CCP Reset-Requests). */ + return DECOMP_ERROR; + } else { + /* Rekey for every missed "flag" packet. */ + while ((ccount & ~0xff) != + (state->ccount & ~0xff)) { + mppe_rekey(state, 0); + state->ccount = + (state->ccount + + 256) % MPPE_CCOUNT_SPACE; + } + + /* reset */ + state->discard = 0; + state->ccount = ccount; + /* + * Another problem with RFC 3078 here. It implies that the + * peer need not send a Reset-Ack packet. But RFC 1962 + * requires it. Hopefully, M$ does send a Reset-Ack; even + * though it isn't required for MPPE synchronization, it is + * required to reset CCP state. + */ + } + } + if (flushed) + mppe_rekey(state, 0); + } + + /* + * Fill in the first part of the PPP header. The protocol field + * comes from the decrypted data. + */ + obuf[0] = PPP_ADDRESS(ibuf); /* +1 */ + obuf[1] = PPP_CONTROL(ibuf); /* +1 */ + obuf += 2; + ibuf += PPP_HDRLEN + MPPE_OVHD; + isize -= PPP_HDRLEN + MPPE_OVHD; /* -6 */ + /* net osize: isize-4 */ + + /* + * Decrypt the first byte in order to check if it is + * a compressed or uncompressed protocol field. + */ + sg_init_table(sg_in, 1); + sg_init_table(sg_out, 1); + setup_sg(sg_in, ibuf, 1); + setup_sg(sg_out, obuf, 1); + if (crypto_blkcipher_decrypt(&desc, sg_out, sg_in, 1) != 0) { + printk(KERN_DEBUG "crypto_cypher_decrypt failed\n"); + return DECOMP_ERROR; + } + + /* + * Do PFC decompression. + * This would be nicer if we were given the actual sk_buff + * instead of a char *. + */ + if ((obuf[0] & 0x01) != 0) { + obuf[1] = obuf[0]; + obuf[0] = 0; + obuf++; + osize++; + } + + /* And finally, decrypt the rest of the packet. */ + setup_sg(sg_in, ibuf + 1, isize - 1); + setup_sg(sg_out, obuf + 1, osize - 1); + if (crypto_blkcipher_decrypt(&desc, sg_out, sg_in, isize - 1)) { + printk(KERN_DEBUG "crypto_cypher_decrypt failed\n"); + return DECOMP_ERROR; + } + + state->stats.unc_bytes += osize; + state->stats.unc_packets++; + state->stats.comp_bytes += isize; + state->stats.comp_packets++; + + /* good packet credit */ + state->sanity_errors >>= 1; + + return osize; +} + +/* + * Incompressible data has arrived (this should never happen!). + * We should probably drop the link if the protocol is in the range + * of what should be encrypted. At the least, we should drop this + * packet. (How to do this?) + */ +static void mppe_incomp(void *arg, unsigned char *ibuf, int icnt) +{ + struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; + + if (state->debug && + (PPP_PROTOCOL(ibuf) >= 0x0021 && PPP_PROTOCOL(ibuf) <= 0x00fa)) + printk(KERN_DEBUG + "mppe_incomp[%d]: incompressible (unencrypted) data! " + "(proto %04x)\n", state->unit, PPP_PROTOCOL(ibuf)); + + state->stats.inc_bytes += icnt; + state->stats.inc_packets++; + state->stats.unc_bytes += icnt; + state->stats.unc_packets++; +} + +/************************************************************* + * Module interface table + *************************************************************/ + +/* + * Procedures exported to if_ppp.c. + */ +static struct compressor ppp_mppe = { + .compress_proto = CI_MPPE, + .comp_alloc = mppe_alloc, + .comp_free = mppe_free, + .comp_init = mppe_comp_init, + .comp_reset = mppe_comp_reset, + .compress = mppe_compress, + .comp_stat = mppe_comp_stats, + .decomp_alloc = mppe_alloc, + .decomp_free = mppe_free, + .decomp_init = mppe_decomp_init, + .decomp_reset = mppe_decomp_reset, + .decompress = mppe_decompress, + .incomp = mppe_incomp, + .decomp_stat = mppe_comp_stats, + .owner = THIS_MODULE, + .comp_extra = MPPE_PAD, +}; + +/* + * ppp_mppe_init() + * + * Prior to allowing load, try to load the arc4 and sha1 crypto + * libraries. The actual use will be allocated later, but + * this way the module will fail to insmod if they aren't available. + */ + +static int __init ppp_mppe_init(void) +{ + int answer; + if (!(crypto_has_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC) && + crypto_has_hash("sha1", 0, CRYPTO_ALG_ASYNC))) + return -ENODEV; + + sha_pad = kmalloc(sizeof(struct sha_pad), GFP_KERNEL); + if (!sha_pad) + return -ENOMEM; + sha_pad_init(sha_pad); + + answer = ppp_register_compressor(&ppp_mppe); + + if (answer == 0) + printk(KERN_INFO "PPP MPPE Compression module registered\n"); + else + kfree(sha_pad); + + return answer; +} + +static void __exit ppp_mppe_cleanup(void) +{ + ppp_unregister_compressor(&ppp_mppe); + kfree(sha_pad); +} + +module_init(ppp_mppe_init); +module_exit(ppp_mppe_cleanup); diff --git a/drivers/net/ppp/ppp_mppe.h b/drivers/net/ppp/ppp_mppe.h new file mode 100644 index 0000000..7a14e05 --- /dev/null +++ b/drivers/net/ppp/ppp_mppe.h @@ -0,0 +1,86 @@ +#define MPPE_PAD 4 /* MPPE growth per frame */ +#define MPPE_MAX_KEY_LEN 16 /* largest key length (128-bit) */ + +/* option bits for ccp_options.mppe */ +#define MPPE_OPT_40 0x01 /* 40 bit */ +#define MPPE_OPT_128 0x02 /* 128 bit */ +#define MPPE_OPT_STATEFUL 0x04 /* stateful mode */ +/* unsupported opts */ +#define MPPE_OPT_56 0x08 /* 56 bit */ +#define MPPE_OPT_MPPC 0x10 /* MPPC compression */ +#define MPPE_OPT_D 0x20 /* Unknown */ +#define MPPE_OPT_UNSUPPORTED (MPPE_OPT_56|MPPE_OPT_MPPC|MPPE_OPT_D) +#define MPPE_OPT_UNKNOWN 0x40 /* Bits !defined in RFC 3078 were set */ + +/* + * This is not nice ... the alternative is a bitfield struct though. + * And unfortunately, we cannot share the same bits for the option + * names above since C and H are the same bit. We could do a u_int32 + * but then we have to do a htonl() all the time and/or we still need + * to know which octet is which. + */ +#define MPPE_C_BIT 0x01 /* MPPC */ +#define MPPE_D_BIT 0x10 /* Obsolete, usage unknown */ +#define MPPE_L_BIT 0x20 /* 40-bit */ +#define MPPE_S_BIT 0x40 /* 128-bit */ +#define MPPE_M_BIT 0x80 /* 56-bit, not supported */ +#define MPPE_H_BIT 0x01 /* Stateless (in a different byte) */ + +/* Does not include H bit; used for least significant octet only. */ +#define MPPE_ALL_BITS (MPPE_D_BIT|MPPE_L_BIT|MPPE_S_BIT|MPPE_M_BIT|MPPE_H_BIT) + +/* Build a CI from mppe opts (see RFC 3078) */ +#define MPPE_OPTS_TO_CI(opts, ci) \ + do { \ + u_char *ptr = ci; /* u_char[4] */ \ + \ + /* H bit */ \ + if (opts & MPPE_OPT_STATEFUL) \ + *ptr++ = 0x0; \ + else \ + *ptr++ = MPPE_H_BIT; \ + *ptr++ = 0; \ + *ptr++ = 0; \ + \ + /* S,L bits */ \ + *ptr = 0; \ + if (opts & MPPE_OPT_128) \ + *ptr |= MPPE_S_BIT; \ + if (opts & MPPE_OPT_40) \ + *ptr |= MPPE_L_BIT; \ + /* M,D,C bits not supported */ \ + } while (/* CONSTCOND */ 0) + +/* The reverse of the above */ +#define MPPE_CI_TO_OPTS(ci, opts) \ + do { \ + u_char *ptr = ci; /* u_char[4] */ \ + \ + opts = 0; \ + \ + /* H bit */ \ + if (!(ptr[0] & MPPE_H_BIT)) \ + opts |= MPPE_OPT_STATEFUL; \ + \ + /* S,L bits */ \ + if (ptr[3] & MPPE_S_BIT) \ + opts |= MPPE_OPT_128; \ + if (ptr[3] & MPPE_L_BIT) \ + opts |= MPPE_OPT_40; \ + \ + /* M,D,C bits */ \ + if (ptr[3] & MPPE_M_BIT) \ + opts |= MPPE_OPT_56; \ + if (ptr[3] & MPPE_D_BIT) \ + opts |= MPPE_OPT_D; \ + if (ptr[3] & MPPE_C_BIT) \ + opts |= MPPE_OPT_MPPC; \ + \ + /* Other bits */ \ + if (ptr[0] & ~MPPE_H_BIT) \ + opts |= MPPE_OPT_UNKNOWN; \ + if (ptr[1] || ptr[2]) \ + opts |= MPPE_OPT_UNKNOWN; \ + if (ptr[3] & ~MPPE_ALL_BITS) \ + opts |= MPPE_OPT_UNKNOWN; \ + } while (/* CONSTCOND */ 0) diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c new file mode 100644 index 0000000..736a39e --- /dev/null +++ b/drivers/net/ppp/ppp_synctty.c @@ -0,0 +1,790 @@ +/* + * PPP synchronous tty channel driver for Linux. + * + * This is a ppp channel driver that can be used with tty device drivers + * that are frame oriented, such as synchronous HDLC devices. + * + * Complete PPP frames without encoding/decoding are exchanged between + * the channel driver and the device driver. + * + * The async map IOCTL codes are implemented to keep the user mode + * applications happy if they call them. Synchronous PPP does not use + * the async maps. + * + * Copyright 1999 Paul Mackerras. + * + * Also touched by the grubby hands of Paul Fulghum paulkf@microgate.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * This driver provides the encapsulation and framing for sending + * and receiving PPP frames over sync serial lines. It relies on + * the generic PPP layer to give it frames to send and to process + * received frames. It implements the PPP line discipline. + * + * Part of the code in this driver was inspired by the old async-only + * PPP driver, written by Michael Callahan and Al Longyear, and + * subsequently hacked by Paul Mackerras. + * + * ==FILEVERSION 20040616== + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PPP_VERSION "2.4.2" + +/* Structure for storing local state. */ +struct syncppp { + struct tty_struct *tty; + unsigned int flags; + unsigned int rbits; + int mru; + spinlock_t xmit_lock; + spinlock_t recv_lock; + unsigned long xmit_flags; + u32 xaccm[8]; + u32 raccm; + unsigned int bytes_sent; + unsigned int bytes_rcvd; + + struct sk_buff *tpkt; + unsigned long last_xmit; + + struct sk_buff_head rqueue; + + struct tasklet_struct tsk; + + atomic_t refcnt; + struct completion dead_cmp; + struct ppp_channel chan; /* interface to generic ppp layer */ +}; + +/* Bit numbers in xmit_flags */ +#define XMIT_WAKEUP 0 +#define XMIT_FULL 1 + +/* Bits in rbits */ +#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) + +#define PPPSYNC_MAX_RQLEN 32 /* arbitrary */ + +/* + * Prototypes. + */ +static struct sk_buff* ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *); +static int ppp_sync_send(struct ppp_channel *chan, struct sk_buff *skb); +static int ppp_sync_ioctl(struct ppp_channel *chan, unsigned int cmd, + unsigned long arg); +static void ppp_sync_process(unsigned long arg); +static int ppp_sync_push(struct syncppp *ap); +static void ppp_sync_flush_output(struct syncppp *ap); +static void ppp_sync_input(struct syncppp *ap, const unsigned char *buf, + char *flags, int count); + +static const struct ppp_channel_ops sync_ops = { + .start_xmit = ppp_sync_send, + .ioctl = ppp_sync_ioctl, +}; + +/* + * Utility procedures to print a buffer in hex/ascii + */ +static void +ppp_print_hex (register __u8 * out, const __u8 * in, int count) +{ + register __u8 next_ch; + static const char hex[] = "0123456789ABCDEF"; + + while (count-- > 0) { + next_ch = *in++; + *out++ = hex[(next_ch >> 4) & 0x0F]; + *out++ = hex[next_ch & 0x0F]; + ++out; + } +} + +static void +ppp_print_char (register __u8 * out, const __u8 * in, int count) +{ + register __u8 next_ch; + + while (count-- > 0) { + next_ch = *in++; + + if (next_ch < 0x20 || next_ch > 0x7e) + *out++ = '.'; + else { + *out++ = next_ch; + if (next_ch == '%') /* printk/syslogd has a bug !! */ + *out++ = '%'; + } + } + *out = '\0'; +} + +static void +ppp_print_buffer (const char *name, const __u8 *buf, int count) +{ + __u8 line[44]; + + if (name != NULL) + printk(KERN_DEBUG "ppp_synctty: %s, count = %d\n", name, count); + + while (count > 8) { + memset (line, 32, 44); + ppp_print_hex (line, buf, 8); + ppp_print_char (&line[8 * 3], buf, 8); + printk(KERN_DEBUG "%s\n", line); + count -= 8; + buf += 8; + } + + if (count > 0) { + memset (line, 32, 44); + ppp_print_hex (line, buf, count); + ppp_print_char (&line[8 * 3], buf, count); + printk(KERN_DEBUG "%s\n", line); + } +} + + +/* + * Routines implementing the synchronous PPP line discipline. + */ + +/* + * We have a potential race on dereferencing tty->disc_data, + * because the tty layer provides no locking at all - thus one + * cpu could be running ppp_synctty_receive while another + * calls ppp_synctty_close, which zeroes tty->disc_data and + * frees the memory that ppp_synctty_receive is using. The best + * way to fix this is to use a rwlock in the tty struct, but for now + * we use a single global rwlock for all ttys in ppp line discipline. + * + * FIXME: Fixed in tty_io nowadays. + */ +static DEFINE_RWLOCK(disc_data_lock); + +static struct syncppp *sp_get(struct tty_struct *tty) +{ + struct syncppp *ap; + + read_lock(&disc_data_lock); + ap = tty->disc_data; + if (ap != NULL) + atomic_inc(&ap->refcnt); + read_unlock(&disc_data_lock); + return ap; +} + +static void sp_put(struct syncppp *ap) +{ + if (atomic_dec_and_test(&ap->refcnt)) + complete(&ap->dead_cmp); +} + +/* + * Called when a tty is put into sync-PPP line discipline. + */ +static int +ppp_sync_open(struct tty_struct *tty) +{ + struct syncppp *ap; + int err; + int speed; + + if (tty->ops->write == NULL) + return -EOPNOTSUPP; + + ap = kzalloc(sizeof(*ap), GFP_KERNEL); + err = -ENOMEM; + if (!ap) + goto out; + + /* initialize the syncppp structure */ + ap->tty = tty; + ap->mru = PPP_MRU; + spin_lock_init(&ap->xmit_lock); + spin_lock_init(&ap->recv_lock); + ap->xaccm[0] = ~0U; + ap->xaccm[3] = 0x60000000U; + ap->raccm = ~0U; + + skb_queue_head_init(&ap->rqueue); + tasklet_init(&ap->tsk, ppp_sync_process, (unsigned long) ap); + + atomic_set(&ap->refcnt, 1); + init_completion(&ap->dead_cmp); + + ap->chan.private = ap; + ap->chan.ops = &sync_ops; + ap->chan.mtu = PPP_MRU; + ap->chan.hdrlen = 2; /* for A/C bytes */ + speed = tty_get_baud_rate(tty); + ap->chan.speed = speed; + err = ppp_register_channel(&ap->chan); + if (err) + goto out_free; + + tty->disc_data = ap; + tty->receive_room = 65536; + return 0; + + out_free: + kfree(ap); + out: + return err; +} + +/* + * Called when the tty is put into another line discipline + * or it hangs up. We have to wait for any cpu currently + * executing in any of the other ppp_synctty_* routines to + * finish before we can call ppp_unregister_channel and free + * the syncppp struct. This routine must be called from + * process context, not interrupt or softirq context. + */ +static void +ppp_sync_close(struct tty_struct *tty) +{ + struct syncppp *ap; + + write_lock_irq(&disc_data_lock); + ap = tty->disc_data; + tty->disc_data = NULL; + write_unlock_irq(&disc_data_lock); + if (!ap) + return; + + /* + * We have now ensured that nobody can start using ap from now + * on, but we have to wait for all existing users to finish. + * Note that ppp_unregister_channel ensures that no calls to + * our channel ops (i.e. ppp_sync_send/ioctl) are in progress + * by the time it returns. + */ + if (!atomic_dec_and_test(&ap->refcnt)) + wait_for_completion(&ap->dead_cmp); + tasklet_kill(&ap->tsk); + + ppp_unregister_channel(&ap->chan); + skb_queue_purge(&ap->rqueue); + kfree_skb(ap->tpkt); + kfree(ap); +} + +/* + * Called on tty hangup in process context. + * + * Wait for I/O to driver to complete and unregister PPP channel. + * This is already done by the close routine, so just call that. + */ +static int ppp_sync_hangup(struct tty_struct *tty) +{ + ppp_sync_close(tty); + return 0; +} + +/* + * Read does nothing - no data is ever available this way. + * Pppd reads and writes packets via /dev/ppp instead. + */ +static ssize_t +ppp_sync_read(struct tty_struct *tty, struct file *file, + unsigned char __user *buf, size_t count) +{ + return -EAGAIN; +} + +/* + * Write on the tty does nothing, the packets all come in + * from the ppp generic stuff. + */ +static ssize_t +ppp_sync_write(struct tty_struct *tty, struct file *file, + const unsigned char *buf, size_t count) +{ + return -EAGAIN; +} + +static int +ppp_synctty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct syncppp *ap = sp_get(tty); + int __user *p = (int __user *)arg; + int err, val; + + if (!ap) + return -ENXIO; + err = -EFAULT; + switch (cmd) { + case PPPIOCGCHAN: + err = -EFAULT; + if (put_user(ppp_channel_index(&ap->chan), p)) + break; + err = 0; + break; + + case PPPIOCGUNIT: + err = -EFAULT; + if (put_user(ppp_unit_number(&ap->chan), p)) + break; + err = 0; + break; + + case TCFLSH: + /* flush our buffers and the serial port's buffer */ + if (arg == TCIOFLUSH || arg == TCOFLUSH) + ppp_sync_flush_output(ap); + err = tty_perform_flush(tty, arg); + break; + + case FIONREAD: + val = 0; + if (put_user(val, p)) + break; + err = 0; + break; + + default: + err = tty_mode_ioctl(tty, file, cmd, arg); + break; + } + + sp_put(ap); + return err; +} + +/* No kernel lock - fine */ +static unsigned int +ppp_sync_poll(struct tty_struct *tty, struct file *file, poll_table *wait) +{ + return 0; +} + +/* May sleep, don't call from interrupt level or with interrupts disabled */ +static void +ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf, + char *cflags, int count) +{ + struct syncppp *ap = sp_get(tty); + unsigned long flags; + + if (!ap) + return; + spin_lock_irqsave(&ap->recv_lock, flags); + ppp_sync_input(ap, buf, cflags, count); + spin_unlock_irqrestore(&ap->recv_lock, flags); + if (!skb_queue_empty(&ap->rqueue)) + tasklet_schedule(&ap->tsk); + sp_put(ap); + tty_unthrottle(tty); +} + +static void +ppp_sync_wakeup(struct tty_struct *tty) +{ + struct syncppp *ap = sp_get(tty); + + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + if (!ap) + return; + set_bit(XMIT_WAKEUP, &ap->xmit_flags); + tasklet_schedule(&ap->tsk); + sp_put(ap); +} + + +static struct tty_ldisc_ops ppp_sync_ldisc = { + .owner = THIS_MODULE, + .magic = TTY_LDISC_MAGIC, + .name = "pppsync", + .open = ppp_sync_open, + .close = ppp_sync_close, + .hangup = ppp_sync_hangup, + .read = ppp_sync_read, + .write = ppp_sync_write, + .ioctl = ppp_synctty_ioctl, + .poll = ppp_sync_poll, + .receive_buf = ppp_sync_receive, + .write_wakeup = ppp_sync_wakeup, +}; + +static int __init +ppp_sync_init(void) +{ + int err; + + err = tty_register_ldisc(N_SYNC_PPP, &ppp_sync_ldisc); + if (err != 0) + printk(KERN_ERR "PPP_sync: error %d registering line disc.\n", + err); + return err; +} + +/* + * The following routines provide the PPP channel interface. + */ +static int +ppp_sync_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg) +{ + struct syncppp *ap = chan->private; + int err, val; + u32 accm[8]; + void __user *argp = (void __user *)arg; + u32 __user *p = argp; + + err = -EFAULT; + switch (cmd) { + case PPPIOCGFLAGS: + val = ap->flags | ap->rbits; + if (put_user(val, (int __user *) argp)) + break; + err = 0; + break; + case PPPIOCSFLAGS: + if (get_user(val, (int __user *) argp)) + break; + ap->flags = val & ~SC_RCV_BITS; + spin_lock_irq(&ap->recv_lock); + ap->rbits = val & SC_RCV_BITS; + spin_unlock_irq(&ap->recv_lock); + err = 0; + break; + + case PPPIOCGASYNCMAP: + if (put_user(ap->xaccm[0], p)) + break; + err = 0; + break; + case PPPIOCSASYNCMAP: + if (get_user(ap->xaccm[0], p)) + break; + err = 0; + break; + + case PPPIOCGRASYNCMAP: + if (put_user(ap->raccm, p)) + break; + err = 0; + break; + case PPPIOCSRASYNCMAP: + if (get_user(ap->raccm, p)) + break; + err = 0; + break; + + case PPPIOCGXASYNCMAP: + if (copy_to_user(argp, ap->xaccm, sizeof(ap->xaccm))) + break; + err = 0; + break; + case PPPIOCSXASYNCMAP: + if (copy_from_user(accm, argp, sizeof(accm))) + break; + accm[2] &= ~0x40000000U; /* can't escape 0x5e */ + accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */ + memcpy(ap->xaccm, accm, sizeof(ap->xaccm)); + err = 0; + break; + + case PPPIOCGMRU: + if (put_user(ap->mru, (int __user *) argp)) + break; + err = 0; + break; + case PPPIOCSMRU: + if (get_user(val, (int __user *) argp)) + break; + if (val < PPP_MRU) + val = PPP_MRU; + ap->mru = val; + err = 0; + break; + + default: + err = -ENOTTY; + } + return err; +} + +/* + * This is called at softirq level to deliver received packets + * to the ppp_generic code, and to tell the ppp_generic code + * if we can accept more output now. + */ +static void ppp_sync_process(unsigned long arg) +{ + struct syncppp *ap = (struct syncppp *) arg; + struct sk_buff *skb; + + /* process received packets */ + while ((skb = skb_dequeue(&ap->rqueue)) != NULL) { + if (skb->len == 0) { + /* zero length buffers indicate error */ + ppp_input_error(&ap->chan, 0); + kfree_skb(skb); + } + else + ppp_input(&ap->chan, skb); + } + + /* try to push more stuff out */ + if (test_bit(XMIT_WAKEUP, &ap->xmit_flags) && ppp_sync_push(ap)) + ppp_output_wakeup(&ap->chan); +} + +/* + * Procedures for encapsulation and framing. + */ + +static struct sk_buff* +ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb) +{ + int proto; + unsigned char *data; + int islcp; + + data = skb->data; + proto = get_unaligned_be16(data); + + /* LCP packets with codes between 1 (configure-request) + * and 7 (code-reject) must be sent as though no options + * have been negotiated. + */ + islcp = proto == PPP_LCP && 1 <= data[2] && data[2] <= 7; + + /* compress protocol field if option enabled */ + if (data[0] == 0 && (ap->flags & SC_COMP_PROT) && !islcp) + skb_pull(skb,1); + + /* prepend address/control fields if necessary */ + if ((ap->flags & SC_COMP_AC) == 0 || islcp) { + if (skb_headroom(skb) < 2) { + struct sk_buff *npkt = dev_alloc_skb(skb->len + 2); + if (npkt == NULL) { + kfree_skb(skb); + return NULL; + } + skb_reserve(npkt,2); + skb_copy_from_linear_data(skb, + skb_put(npkt, skb->len), skb->len); + kfree_skb(skb); + skb = npkt; + } + skb_push(skb,2); + skb->data[0] = PPP_ALLSTATIONS; + skb->data[1] = PPP_UI; + } + + ap->last_xmit = jiffies; + + if (skb && ap->flags & SC_LOG_OUTPKT) + ppp_print_buffer ("send buffer", skb->data, skb->len); + + return skb; +} + +/* + * Transmit-side routines. + */ + +/* + * Send a packet to the peer over an sync tty line. + * Returns 1 iff the packet was accepted. + * If the packet was not accepted, we will call ppp_output_wakeup + * at some later time. + */ +static int +ppp_sync_send(struct ppp_channel *chan, struct sk_buff *skb) +{ + struct syncppp *ap = chan->private; + + ppp_sync_push(ap); + + if (test_and_set_bit(XMIT_FULL, &ap->xmit_flags)) + return 0; /* already full */ + skb = ppp_sync_txmunge(ap, skb); + if (skb != NULL) + ap->tpkt = skb; + else + clear_bit(XMIT_FULL, &ap->xmit_flags); + + ppp_sync_push(ap); + return 1; +} + +/* + * Push as much data as possible out to the tty. + */ +static int +ppp_sync_push(struct syncppp *ap) +{ + int sent, done = 0; + struct tty_struct *tty = ap->tty; + int tty_stuffed = 0; + + if (!spin_trylock_bh(&ap->xmit_lock)) + return 0; + for (;;) { + if (test_and_clear_bit(XMIT_WAKEUP, &ap->xmit_flags)) + tty_stuffed = 0; + if (!tty_stuffed && ap->tpkt) { + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + sent = tty->ops->write(tty, ap->tpkt->data, ap->tpkt->len); + if (sent < 0) + goto flush; /* error, e.g. loss of CD */ + if (sent < ap->tpkt->len) { + tty_stuffed = 1; + } else { + kfree_skb(ap->tpkt); + ap->tpkt = NULL; + clear_bit(XMIT_FULL, &ap->xmit_flags); + done = 1; + } + continue; + } + /* haven't made any progress */ + spin_unlock_bh(&ap->xmit_lock); + if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags) || + (!tty_stuffed && ap->tpkt))) + break; + if (!spin_trylock_bh(&ap->xmit_lock)) + break; + } + return done; + +flush: + if (ap->tpkt) { + kfree_skb(ap->tpkt); + ap->tpkt = NULL; + clear_bit(XMIT_FULL, &ap->xmit_flags); + done = 1; + } + spin_unlock_bh(&ap->xmit_lock); + return done; +} + +/* + * Flush output from our internal buffers. + * Called for the TCFLSH ioctl. + */ +static void +ppp_sync_flush_output(struct syncppp *ap) +{ + int done = 0; + + spin_lock_bh(&ap->xmit_lock); + if (ap->tpkt != NULL) { + kfree_skb(ap->tpkt); + ap->tpkt = NULL; + clear_bit(XMIT_FULL, &ap->xmit_flags); + done = 1; + } + spin_unlock_bh(&ap->xmit_lock); + if (done) + ppp_output_wakeup(&ap->chan); +} + +/* + * Receive-side routines. + */ + +/* called when the tty driver has data for us. + * + * Data is frame oriented: each call to ppp_sync_input is considered + * a whole frame. If the 1st flag byte is non-zero then the whole + * frame is considered to be in error and is tossed. + */ +static void +ppp_sync_input(struct syncppp *ap, const unsigned char *buf, + char *flags, int count) +{ + struct sk_buff *skb; + unsigned char *p; + + if (count == 0) + return; + + if (ap->flags & SC_LOG_INPKT) + ppp_print_buffer ("receive buffer", buf, count); + + /* stuff the chars in the skb */ + skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2); + if (!skb) { + printk(KERN_ERR "PPPsync: no memory (input pkt)\n"); + goto err; + } + /* Try to get the payload 4-byte aligned */ + if (buf[0] != PPP_ALLSTATIONS) + skb_reserve(skb, 2 + (buf[0] & 1)); + + if (flags && *flags) { + /* error flag set, ignore frame */ + goto err; + } else if (count > skb_tailroom(skb)) { + /* packet overflowed MRU */ + goto err; + } + + p = skb_put(skb, count); + memcpy(p, buf, count); + + /* strip address/control field if present */ + p = skb->data; + if (p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) { + /* chop off address/control */ + if (skb->len < 3) + goto err; + p = skb_pull(skb, 2); + } + + /* decompress protocol field if compressed */ + if (p[0] & 1) { + /* protocol is compressed */ + skb_push(skb, 1)[0] = 0; + } else if (skb->len < 2) + goto err; + + /* queue the frame to be processed */ + skb_queue_tail(&ap->rqueue, skb); + return; + +err: + /* queue zero length packet as error indication */ + if (skb || (skb = dev_alloc_skb(0))) { + skb_trim(skb, 0); + skb_queue_tail(&ap->rqueue, skb); + } +} + +static void __exit +ppp_sync_cleanup(void) +{ + if (tty_unregister_ldisc(N_SYNC_PPP) != 0) + printk(KERN_ERR "failed to unregister Sync PPP line discipline\n"); +} + +module_init(ppp_sync_init); +module_exit(ppp_sync_cleanup); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_LDISC(N_SYNC_PPP); diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c new file mode 100644 index 0000000..bc9a4bb --- /dev/null +++ b/drivers/net/ppp/pppoe.c @@ -0,0 +1,1208 @@ +/** -*- linux-c -*- *********************************************************** + * Linux PPP over Ethernet (PPPoX/PPPoE) Sockets + * + * PPPoX --- Generic PPP encapsulation socket family + * PPPoE --- PPP over Ethernet (RFC 2516) + * + * + * Version: 0.7.0 + * + * 070228 : Fix to allow multiple sessions with same remote MAC and same + * session id by including the local device ifindex in the + * tuple identifying a session. This also ensures packets can't + * be injected into a session from interfaces other than the one + * specified by userspace. Florian Zumbiehl + * (Oh, BTW, this one is YYMMDD, in case you were wondering ...) + * 220102 : Fix module use count on failure in pppoe_create, pppox_sk -acme + * 030700 : Fixed connect logic to allow for disconnect. + * 270700 : Fixed potential SMP problems; we must protect against + * simultaneous invocation of ppp_input + * and ppp_unregister_channel. + * 040800 : Respect reference count mechanisms on net-devices. + * 200800 : fix kfree(skb) in pppoe_rcv (acme) + * Module reference count is decremented in the right spot now, + * guards against sock_put not actually freeing the sk + * in pppoe_release. + * 051000 : Initialization cleanup. + * 111100 : Fix recvmsg. + * 050101 : Fix PADT procesing. + * 140501 : Use pppoe_rcv_core to handle all backlog. (Alexey) + * 170701 : Do not lock_sock with rwlock held. (DaveM) + * Ignore discovery frames if user has socket + * locked. (DaveM) + * Ignore return value of dev_queue_xmit in __pppoe_xmit + * or else we may kfree an SKB twice. (DaveM) + * 190701 : When doing copies of skb's in __pppoe_xmit, always delete + * the original skb that was passed in on success, never on + * failure. Delete the copy of the skb on failure to avoid + * a memory leak. + * 081001 : Misc. cleanup (licence string, non-blocking, prevent + * reference of device on close). + * 121301 : New ppp channels interface; cannot unregister a channel + * from interrupts. Thus, we mark the socket as a ZOMBIE + * and do the unregistration later. + * 081002 : seq_file support for proc stuff -acme + * 111602 : Merge all 2.4 fixes into 2.5/2.6 tree. Label 2.5/2.6 + * as version 0.7. Spacing cleanup. + * Author: Michal Ostrowski + * Contributors: + * Arnaldo Carvalho de Melo + * David S. Miller (davem@redhat.com) + * + * License: + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define PPPOE_HASH_BITS 4 +#define PPPOE_HASH_SIZE (1 << PPPOE_HASH_BITS) +#define PPPOE_HASH_MASK (PPPOE_HASH_SIZE - 1) + +static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb); + +static const struct proto_ops pppoe_ops; +static const struct ppp_channel_ops pppoe_chan_ops; + +/* per-net private data for this module */ +static int pppoe_net_id __read_mostly; +struct pppoe_net { + /* + * we could use _single_ hash table for all + * nets by injecting net id into the hash but + * it would increase hash chains and add + * a few additional math comparations messy + * as well, moreover in case of SMP less locking + * controversy here + */ + struct pppox_sock *hash_table[PPPOE_HASH_SIZE]; + rwlock_t hash_lock; +}; + +/* + * PPPoE could be in the following stages: + * 1) Discovery stage (to obtain remote MAC and Session ID) + * 2) Session stage (MAC and SID are known) + * + * Ethernet frames have a special tag for this but + * we use simpler approach based on session id + */ +static inline bool stage_session(__be16 sid) +{ + return sid != 0; +} + +static inline struct pppoe_net *pppoe_pernet(struct net *net) +{ + BUG_ON(!net); + + return net_generic(net, pppoe_net_id); +} + +static inline int cmp_2_addr(struct pppoe_addr *a, struct pppoe_addr *b) +{ + return a->sid == b->sid && !memcmp(a->remote, b->remote, ETH_ALEN); +} + +static inline int cmp_addr(struct pppoe_addr *a, __be16 sid, char *addr) +{ + return a->sid == sid && !memcmp(a->remote, addr, ETH_ALEN); +} + +#if 8 % PPPOE_HASH_BITS +#error 8 must be a multiple of PPPOE_HASH_BITS +#endif + +static int hash_item(__be16 sid, unsigned char *addr) +{ + unsigned char hash = 0; + unsigned int i; + + for (i = 0; i < ETH_ALEN; i++) + hash ^= addr[i]; + for (i = 0; i < sizeof(sid_t) * 8; i += 8) + hash ^= (__force __u32)sid >> i; + for (i = 8; (i >>= 1) >= PPPOE_HASH_BITS;) + hash ^= hash >> i; + + return hash & PPPOE_HASH_MASK; +} + +/********************************************************************** + * + * Set/get/delete/rehash items (internal versions) + * + **********************************************************************/ +static struct pppox_sock *__get_item(struct pppoe_net *pn, __be16 sid, + unsigned char *addr, int ifindex) +{ + int hash = hash_item(sid, addr); + struct pppox_sock *ret; + + ret = pn->hash_table[hash]; + while (ret) { + if (cmp_addr(&ret->pppoe_pa, sid, addr) && + ret->pppoe_ifindex == ifindex) + return ret; + + ret = ret->next; + } + + return NULL; +} + +static int __set_item(struct pppoe_net *pn, struct pppox_sock *po) +{ + int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote); + struct pppox_sock *ret; + + ret = pn->hash_table[hash]; + while (ret) { + if (cmp_2_addr(&ret->pppoe_pa, &po->pppoe_pa) && + ret->pppoe_ifindex == po->pppoe_ifindex) + return -EALREADY; + + ret = ret->next; + } + + po->next = pn->hash_table[hash]; + pn->hash_table[hash] = po; + + return 0; +} + +static struct pppox_sock *__delete_item(struct pppoe_net *pn, __be16 sid, + char *addr, int ifindex) +{ + int hash = hash_item(sid, addr); + struct pppox_sock *ret, **src; + + ret = pn->hash_table[hash]; + src = &pn->hash_table[hash]; + + while (ret) { + if (cmp_addr(&ret->pppoe_pa, sid, addr) && + ret->pppoe_ifindex == ifindex) { + *src = ret->next; + break; + } + + src = &ret->next; + ret = ret->next; + } + + return ret; +} + +/********************************************************************** + * + * Set/get/delete/rehash items + * + **********************************************************************/ +static inline struct pppox_sock *get_item(struct pppoe_net *pn, __be16 sid, + unsigned char *addr, int ifindex) +{ + struct pppox_sock *po; + + read_lock_bh(&pn->hash_lock); + po = __get_item(pn, sid, addr, ifindex); + if (po) + sock_hold(sk_pppox(po)); + read_unlock_bh(&pn->hash_lock); + + return po; +} + +static inline struct pppox_sock *get_item_by_addr(struct net *net, + struct sockaddr_pppox *sp) +{ + struct net_device *dev; + struct pppoe_net *pn; + struct pppox_sock *pppox_sock = NULL; + + int ifindex; + + rcu_read_lock(); + dev = dev_get_by_name_rcu(net, sp->sa_addr.pppoe.dev); + if (dev) { + ifindex = dev->ifindex; + pn = pppoe_pernet(net); + pppox_sock = get_item(pn, sp->sa_addr.pppoe.sid, + sp->sa_addr.pppoe.remote, ifindex); + } + rcu_read_unlock(); + return pppox_sock; +} + +static inline struct pppox_sock *delete_item(struct pppoe_net *pn, __be16 sid, + char *addr, int ifindex) +{ + struct pppox_sock *ret; + + write_lock_bh(&pn->hash_lock); + ret = __delete_item(pn, sid, addr, ifindex); + write_unlock_bh(&pn->hash_lock); + + return ret; +} + +/*************************************************************************** + * + * Handler for device events. + * Certain device events require that sockets be unconnected. + * + **************************************************************************/ + +static void pppoe_flush_dev(struct net_device *dev) +{ + struct pppoe_net *pn; + int i; + + pn = pppoe_pernet(dev_net(dev)); + write_lock_bh(&pn->hash_lock); + for (i = 0; i < PPPOE_HASH_SIZE; i++) { + struct pppox_sock *po = pn->hash_table[i]; + struct sock *sk; + + while (po) { + while (po && po->pppoe_dev != dev) { + po = po->next; + } + + if (!po) + break; + + sk = sk_pppox(po); + + /* We always grab the socket lock, followed by the + * hash_lock, in that order. Since we should hold the + * sock lock while doing any unbinding, we need to + * release the lock we're holding. Hold a reference to + * the sock so it doesn't disappear as we're jumping + * between locks. + */ + + sock_hold(sk); + write_unlock_bh(&pn->hash_lock); + lock_sock(sk); + + if (po->pppoe_dev == dev && + sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) { + pppox_unbind_sock(sk); + sk->sk_state = PPPOX_ZOMBIE; + sk->sk_state_change(sk); + po->pppoe_dev = NULL; + dev_put(dev); + } + + release_sock(sk); + sock_put(sk); + + /* Restart the process from the start of the current + * hash chain. We dropped locks so the world may have + * change from underneath us. + */ + + BUG_ON(pppoe_pernet(dev_net(dev)) == NULL); + write_lock_bh(&pn->hash_lock); + po = pn->hash_table[i]; + } + } + write_unlock_bh(&pn->hash_lock); +} + +static int pppoe_device_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct net_device *dev = (struct net_device *)ptr; + + /* Only look at sockets that are using this specific device. */ + switch (event) { + case NETDEV_CHANGEADDR: + case NETDEV_CHANGEMTU: + /* A change in mtu or address is a bad thing, requiring + * LCP re-negotiation. + */ + + case NETDEV_GOING_DOWN: + case NETDEV_DOWN: + /* Find every socket on this device and kill it. */ + pppoe_flush_dev(dev); + break; + + default: + break; + } + + return NOTIFY_DONE; +} + +static struct notifier_block pppoe_notifier = { + .notifier_call = pppoe_device_event, +}; + +/************************************************************************ + * + * Do the real work of receiving a PPPoE Session frame. + * + ***********************************************************************/ +static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb) +{ + struct pppox_sock *po = pppox_sk(sk); + struct pppox_sock *relay_po; + + /* Backlog receive. Semantics of backlog rcv preclude any code from + * executing in lock_sock()/release_sock() bounds; meaning sk->sk_state + * can't change. + */ + + if (sk->sk_state & PPPOX_BOUND) { + ppp_input(&po->chan, skb); + } else if (sk->sk_state & PPPOX_RELAY) { + relay_po = get_item_by_addr(sock_net(sk), + &po->pppoe_relay); + if (relay_po == NULL) + goto abort_kfree; + + if ((sk_pppox(relay_po)->sk_state & PPPOX_CONNECTED) == 0) + goto abort_put; + + if (!__pppoe_xmit(sk_pppox(relay_po), skb)) + goto abort_put; + } else { + if (sock_queue_rcv_skb(sk, skb)) + goto abort_kfree; + } + + return NET_RX_SUCCESS; + +abort_put: + sock_put(sk_pppox(relay_po)); + +abort_kfree: + kfree_skb(skb); + return NET_RX_DROP; +} + +/************************************************************************ + * + * Receive wrapper called in BH context. + * + ***********************************************************************/ +static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev) +{ + struct pppoe_hdr *ph; + struct pppox_sock *po; + struct pppoe_net *pn; + int len; + + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + goto out; + + if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) + goto drop; + + ph = pppoe_hdr(skb); + len = ntohs(ph->length); + + skb_pull_rcsum(skb, sizeof(*ph)); + if (skb->len < len) + goto drop; + + if (pskb_trim_rcsum(skb, len)) + goto drop; + + pn = pppoe_pernet(dev_net(dev)); + + /* Note that get_item does a sock_hold(), so sk_pppox(po) + * is known to be safe. + */ + po = get_item(pn, ph->sid, eth_hdr(skb)->h_source, dev->ifindex); + if (!po) + goto drop; + + return sk_receive_skb(sk_pppox(po), skb, 0); + +drop: + kfree_skb(skb); +out: + return NET_RX_DROP; +} + +/************************************************************************ + * + * Receive a PPPoE Discovery frame. + * This is solely for detection of PADT frames + * + ***********************************************************************/ +static int pppoe_disc_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev) + +{ + struct pppoe_hdr *ph; + struct pppox_sock *po; + struct pppoe_net *pn; + + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + goto out; + + if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) + goto abort; + + ph = pppoe_hdr(skb); + if (ph->code != PADT_CODE) + goto abort; + + pn = pppoe_pernet(dev_net(dev)); + po = get_item(pn, ph->sid, eth_hdr(skb)->h_source, dev->ifindex); + if (po) { + struct sock *sk = sk_pppox(po); + + bh_lock_sock(sk); + + /* If the user has locked the socket, just ignore + * the packet. With the way two rcv protocols hook into + * one socket family type, we cannot (easily) distinguish + * what kind of SKB it is during backlog rcv. + */ + if (sock_owned_by_user(sk) == 0) { + /* We're no longer connect at the PPPOE layer, + * and must wait for ppp channel to disconnect us. + */ + sk->sk_state = PPPOX_ZOMBIE; + } + + bh_unlock_sock(sk); + sock_put(sk); + } + +abort: + kfree_skb(skb); +out: + return NET_RX_SUCCESS; /* Lies... :-) */ +} + +static struct packet_type pppoes_ptype __read_mostly = { + .type = cpu_to_be16(ETH_P_PPP_SES), + .func = pppoe_rcv, +}; + +static struct packet_type pppoed_ptype __read_mostly = { + .type = cpu_to_be16(ETH_P_PPP_DISC), + .func = pppoe_disc_rcv, +}; + +static struct proto pppoe_sk_proto __read_mostly = { + .name = "PPPOE", + .owner = THIS_MODULE, + .obj_size = sizeof(struct pppox_sock), +}; + +/*********************************************************************** + * + * Initialize a new struct sock. + * + **********************************************************************/ +static int pppoe_create(struct net *net, struct socket *sock) +{ + struct sock *sk; + + sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto); + if (!sk) + return -ENOMEM; + + sock_init_data(sock, sk); + + sock->state = SS_UNCONNECTED; + sock->ops = &pppoe_ops; + + sk->sk_backlog_rcv = pppoe_rcv_core; + sk->sk_state = PPPOX_NONE; + sk->sk_type = SOCK_STREAM; + sk->sk_family = PF_PPPOX; + sk->sk_protocol = PX_PROTO_OE; + + return 0; +} + +static int pppoe_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + struct pppox_sock *po; + struct pppoe_net *pn; + struct net *net = NULL; + + if (!sk) + return 0; + + lock_sock(sk); + if (sock_flag(sk, SOCK_DEAD)) { + release_sock(sk); + return -EBADF; + } + + po = pppox_sk(sk); + + if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { + dev_put(po->pppoe_dev); + po->pppoe_dev = NULL; + } + + pppox_unbind_sock(sk); + + /* Signal the death of the socket. */ + sk->sk_state = PPPOX_DEAD; + + net = sock_net(sk); + pn = pppoe_pernet(net); + + /* + * protect "po" from concurrent updates + * on pppoe_flush_dev + */ + delete_item(pn, po->pppoe_pa.sid, po->pppoe_pa.remote, + po->pppoe_ifindex); + + sock_orphan(sk); + sock->sk = NULL; + + skb_queue_purge(&sk->sk_receive_queue); + release_sock(sk); + sock_put(sk); + + return 0; +} + +static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, + int sockaddr_len, int flags) +{ + struct sock *sk = sock->sk; + struct sockaddr_pppox *sp = (struct sockaddr_pppox *)uservaddr; + struct pppox_sock *po = pppox_sk(sk); + struct net_device *dev = NULL; + struct pppoe_net *pn; + struct net *net = NULL; + int error; + + lock_sock(sk); + + error = -EINVAL; + if (sp->sa_protocol != PX_PROTO_OE) + goto end; + + /* Check for already bound sockets */ + error = -EBUSY; + if ((sk->sk_state & PPPOX_CONNECTED) && + stage_session(sp->sa_addr.pppoe.sid)) + goto end; + + /* Check for already disconnected sockets, on attempts to disconnect */ + error = -EALREADY; + if ((sk->sk_state & PPPOX_DEAD) && + !stage_session(sp->sa_addr.pppoe.sid)) + goto end; + + error = 0; + + /* Delete the old binding */ + if (stage_session(po->pppoe_pa.sid)) { + pppox_unbind_sock(sk); + pn = pppoe_pernet(sock_net(sk)); + delete_item(pn, po->pppoe_pa.sid, + po->pppoe_pa.remote, po->pppoe_ifindex); + if (po->pppoe_dev) { + dev_put(po->pppoe_dev); + po->pppoe_dev = NULL; + } + + memset(sk_pppox(po) + 1, 0, + sizeof(struct pppox_sock) - sizeof(struct sock)); + sk->sk_state = PPPOX_NONE; + } + + /* Re-bind in session stage only */ + if (stage_session(sp->sa_addr.pppoe.sid)) { + error = -ENODEV; + net = sock_net(sk); + dev = dev_get_by_name(net, sp->sa_addr.pppoe.dev); + if (!dev) + goto err_put; + + po->pppoe_dev = dev; + po->pppoe_ifindex = dev->ifindex; + pn = pppoe_pernet(net); + if (!(dev->flags & IFF_UP)) { + goto err_put; + } + + memcpy(&po->pppoe_pa, + &sp->sa_addr.pppoe, + sizeof(struct pppoe_addr)); + + write_lock_bh(&pn->hash_lock); + error = __set_item(pn, po); + write_unlock_bh(&pn->hash_lock); + if (error < 0) + goto err_put; + + po->chan.hdrlen = (sizeof(struct pppoe_hdr) + + dev->hard_header_len); + + po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr); + po->chan.private = sk; + po->chan.ops = &pppoe_chan_ops; + + error = ppp_register_net_channel(dev_net(dev), &po->chan); + if (error) { + delete_item(pn, po->pppoe_pa.sid, + po->pppoe_pa.remote, po->pppoe_ifindex); + goto err_put; + } + + sk->sk_state = PPPOX_CONNECTED; + } + + po->num = sp->sa_addr.pppoe.sid; + +end: + release_sock(sk); + return error; +err_put: + if (po->pppoe_dev) { + dev_put(po->pppoe_dev); + po->pppoe_dev = NULL; + } + goto end; +} + +static int pppoe_getname(struct socket *sock, struct sockaddr *uaddr, + int *usockaddr_len, int peer) +{ + int len = sizeof(struct sockaddr_pppox); + struct sockaddr_pppox sp; + + sp.sa_family = AF_PPPOX; + sp.sa_protocol = PX_PROTO_OE; + memcpy(&sp.sa_addr.pppoe, &pppox_sk(sock->sk)->pppoe_pa, + sizeof(struct pppoe_addr)); + + memcpy(uaddr, &sp, len); + + *usockaddr_len = len; + + return 0; +} + +static int pppoe_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg) +{ + struct sock *sk = sock->sk; + struct pppox_sock *po = pppox_sk(sk); + int val; + int err; + + switch (cmd) { + case PPPIOCGMRU: + err = -ENXIO; + if (!(sk->sk_state & PPPOX_CONNECTED)) + break; + + err = -EFAULT; + if (put_user(po->pppoe_dev->mtu - + sizeof(struct pppoe_hdr) - + PPP_HDRLEN, + (int __user *)arg)) + break; + err = 0; + break; + + case PPPIOCSMRU: + err = -ENXIO; + if (!(sk->sk_state & PPPOX_CONNECTED)) + break; + + err = -EFAULT; + if (get_user(val, (int __user *)arg)) + break; + + if (val < (po->pppoe_dev->mtu + - sizeof(struct pppoe_hdr) + - PPP_HDRLEN)) + err = 0; + else + err = -EINVAL; + break; + + case PPPIOCSFLAGS: + err = -EFAULT; + if (get_user(val, (int __user *)arg)) + break; + err = 0; + break; + + case PPPOEIOCSFWD: + { + struct pppox_sock *relay_po; + + err = -EBUSY; + if (sk->sk_state & (PPPOX_BOUND | PPPOX_ZOMBIE | PPPOX_DEAD)) + break; + + err = -ENOTCONN; + if (!(sk->sk_state & PPPOX_CONNECTED)) + break; + + /* PPPoE address from the user specifies an outbound + PPPoE address which frames are forwarded to */ + err = -EFAULT; + if (copy_from_user(&po->pppoe_relay, + (void __user *)arg, + sizeof(struct sockaddr_pppox))) + break; + + err = -EINVAL; + if (po->pppoe_relay.sa_family != AF_PPPOX || + po->pppoe_relay.sa_protocol != PX_PROTO_OE) + break; + + /* Check that the socket referenced by the address + actually exists. */ + relay_po = get_item_by_addr(sock_net(sk), &po->pppoe_relay); + if (!relay_po) + break; + + sock_put(sk_pppox(relay_po)); + sk->sk_state |= PPPOX_RELAY; + err = 0; + break; + } + + case PPPOEIOCDFWD: + err = -EALREADY; + if (!(sk->sk_state & PPPOX_RELAY)) + break; + + sk->sk_state &= ~PPPOX_RELAY; + err = 0; + break; + + default: + err = -ENOTTY; + } + + return err; +} + +static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *m, size_t total_len) +{ + struct sk_buff *skb; + struct sock *sk = sock->sk; + struct pppox_sock *po = pppox_sk(sk); + int error; + struct pppoe_hdr hdr; + struct pppoe_hdr *ph; + struct net_device *dev; + char *start; + + lock_sock(sk); + if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) { + error = -ENOTCONN; + goto end; + } + + hdr.ver = 1; + hdr.type = 1; + hdr.code = 0; + hdr.sid = po->num; + + dev = po->pppoe_dev; + + error = -EMSGSIZE; + if (total_len > (dev->mtu + dev->hard_header_len)) + goto end; + + + skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32, + 0, GFP_KERNEL); + if (!skb) { + error = -ENOMEM; + goto end; + } + + /* Reserve space for headers. */ + skb_reserve(skb, dev->hard_header_len); + skb_reset_network_header(skb); + + skb->dev = dev; + + skb->priority = sk->sk_priority; + skb->protocol = cpu_to_be16(ETH_P_PPP_SES); + + ph = (struct pppoe_hdr *)skb_put(skb, total_len + sizeof(struct pppoe_hdr)); + start = (char *)&ph->tag[0]; + + error = memcpy_fromiovec(start, m->msg_iov, total_len); + if (error < 0) { + kfree_skb(skb); + goto end; + } + + error = total_len; + dev_hard_header(skb, dev, ETH_P_PPP_SES, + po->pppoe_pa.remote, NULL, total_len); + + memcpy(ph, &hdr, sizeof(struct pppoe_hdr)); + + ph->length = htons(total_len); + + dev_queue_xmit(skb); + +end: + release_sock(sk); + return error; +} + +/************************************************************************ + * + * xmit function for internal use. + * + ***********************************************************************/ +static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) +{ + struct pppox_sock *po = pppox_sk(sk); + struct net_device *dev = po->pppoe_dev; + struct pppoe_hdr *ph; + int data_len = skb->len; + + /* The higher-level PPP code (ppp_unregister_channel()) ensures the PPP + * xmit operations conclude prior to an unregistration call. Thus + * sk->sk_state cannot change, so we don't need to do lock_sock(). + * But, we also can't do a lock_sock since that introduces a potential + * deadlock as we'd reverse the lock ordering used when calling + * ppp_unregister_channel(). + */ + + if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) + goto abort; + + if (!dev) + goto abort; + + /* Copy the data if there is no space for the header or if it's + * read-only. + */ + if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len)) + goto abort; + + __skb_push(skb, sizeof(*ph)); + skb_reset_network_header(skb); + + ph = pppoe_hdr(skb); + ph->ver = 1; + ph->type = 1; + ph->code = 0; + ph->sid = po->num; + ph->length = htons(data_len); + + skb->protocol = cpu_to_be16(ETH_P_PPP_SES); + skb->dev = dev; + + dev_hard_header(skb, dev, ETH_P_PPP_SES, + po->pppoe_pa.remote, NULL, data_len); + + dev_queue_xmit(skb); + return 1; + +abort: + kfree_skb(skb); + return 1; +} + +/************************************************************************ + * + * xmit function called by generic PPP driver + * sends PPP frame over PPPoE socket + * + ***********************************************************************/ +static int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb) +{ + struct sock *sk = (struct sock *)chan->private; + return __pppoe_xmit(sk, skb); +} + +static const struct ppp_channel_ops pppoe_chan_ops = { + .start_xmit = pppoe_xmit, +}; + +static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *m, size_t total_len, int flags) +{ + struct sock *sk = sock->sk; + struct sk_buff *skb; + int error = 0; + + if (sk->sk_state & PPPOX_BOUND) { + error = -EIO; + goto end; + } + + skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, + flags & MSG_DONTWAIT, &error); + if (error < 0) + goto end; + + m->msg_namelen = 0; + + if (skb) { + total_len = min_t(size_t, total_len, skb->len); + error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len); + if (error == 0) + error = total_len; + } + + kfree_skb(skb); +end: + return error; +} + +#ifdef CONFIG_PROC_FS +static int pppoe_seq_show(struct seq_file *seq, void *v) +{ + struct pppox_sock *po; + char *dev_name; + + if (v == SEQ_START_TOKEN) { + seq_puts(seq, "Id Address Device\n"); + goto out; + } + + po = v; + dev_name = po->pppoe_pa.dev; + + seq_printf(seq, "%08X %pM %8s\n", + po->pppoe_pa.sid, po->pppoe_pa.remote, dev_name); +out: + return 0; +} + +static inline struct pppox_sock *pppoe_get_idx(struct pppoe_net *pn, loff_t pos) +{ + struct pppox_sock *po; + int i; + + for (i = 0; i < PPPOE_HASH_SIZE; i++) { + po = pn->hash_table[i]; + while (po) { + if (!pos--) + goto out; + po = po->next; + } + } + +out: + return po; +} + +static void *pppoe_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(pn->hash_lock) +{ + struct pppoe_net *pn = pppoe_pernet(seq_file_net(seq)); + loff_t l = *pos; + + read_lock_bh(&pn->hash_lock); + return l ? pppoe_get_idx(pn, --l) : SEQ_START_TOKEN; +} + +static void *pppoe_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct pppoe_net *pn = pppoe_pernet(seq_file_net(seq)); + struct pppox_sock *po; + + ++*pos; + if (v == SEQ_START_TOKEN) { + po = pppoe_get_idx(pn, 0); + goto out; + } + po = v; + if (po->next) + po = po->next; + else { + int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote); + + po = NULL; + while (++hash < PPPOE_HASH_SIZE) { + po = pn->hash_table[hash]; + if (po) + break; + } + } + +out: + return po; +} + +static void pppoe_seq_stop(struct seq_file *seq, void *v) + __releases(pn->hash_lock) +{ + struct pppoe_net *pn = pppoe_pernet(seq_file_net(seq)); + read_unlock_bh(&pn->hash_lock); +} + +static const struct seq_operations pppoe_seq_ops = { + .start = pppoe_seq_start, + .next = pppoe_seq_next, + .stop = pppoe_seq_stop, + .show = pppoe_seq_show, +}; + +static int pppoe_seq_open(struct inode *inode, struct file *file) +{ + return seq_open_net(inode, file, &pppoe_seq_ops, + sizeof(struct seq_net_private)); +} + +static const struct file_operations pppoe_seq_fops = { + .owner = THIS_MODULE, + .open = pppoe_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_net, +}; + +#endif /* CONFIG_PROC_FS */ + +static const struct proto_ops pppoe_ops = { + .family = AF_PPPOX, + .owner = THIS_MODULE, + .release = pppoe_release, + .bind = sock_no_bind, + .connect = pppoe_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = pppoe_getname, + .poll = datagram_poll, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .setsockopt = sock_no_setsockopt, + .getsockopt = sock_no_getsockopt, + .sendmsg = pppoe_sendmsg, + .recvmsg = pppoe_recvmsg, + .mmap = sock_no_mmap, + .ioctl = pppox_ioctl, +}; + +static const struct pppox_proto pppoe_proto = { + .create = pppoe_create, + .ioctl = pppoe_ioctl, + .owner = THIS_MODULE, +}; + +static __net_init int pppoe_init_net(struct net *net) +{ + struct pppoe_net *pn = pppoe_pernet(net); + struct proc_dir_entry *pde; + + rwlock_init(&pn->hash_lock); + + pde = proc_net_fops_create(net, "pppoe", S_IRUGO, &pppoe_seq_fops); +#ifdef CONFIG_PROC_FS + if (!pde) + return -ENOMEM; +#endif + + return 0; +} + +static __net_exit void pppoe_exit_net(struct net *net) +{ + proc_net_remove(net, "pppoe"); +} + +static struct pernet_operations pppoe_net_ops = { + .init = pppoe_init_net, + .exit = pppoe_exit_net, + .id = &pppoe_net_id, + .size = sizeof(struct pppoe_net), +}; + +static int __init pppoe_init(void) +{ + int err; + + err = register_pernet_device(&pppoe_net_ops); + if (err) + goto out; + + err = proto_register(&pppoe_sk_proto, 0); + if (err) + goto out_unregister_net_ops; + + err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto); + if (err) + goto out_unregister_pppoe_proto; + + dev_add_pack(&pppoes_ptype); + dev_add_pack(&pppoed_ptype); + register_netdevice_notifier(&pppoe_notifier); + + return 0; + +out_unregister_pppoe_proto: + proto_unregister(&pppoe_sk_proto); +out_unregister_net_ops: + unregister_pernet_device(&pppoe_net_ops); +out: + return err; +} + +static void __exit pppoe_exit(void) +{ + unregister_netdevice_notifier(&pppoe_notifier); + dev_remove_pack(&pppoed_ptype); + dev_remove_pack(&pppoes_ptype); + unregister_pppox_proto(PX_PROTO_OE); + proto_unregister(&pppoe_sk_proto); + unregister_pernet_device(&pppoe_net_ops); +} + +module_init(pppoe_init); +module_exit(pppoe_exit); + +MODULE_AUTHOR("Michal Ostrowski "); +MODULE_DESCRIPTION("PPP over Ethernet driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_PPPOX); diff --git a/drivers/net/ppp/pppox.c b/drivers/net/ppp/pppox.c new file mode 100644 index 0000000..8c0d170 --- /dev/null +++ b/drivers/net/ppp/pppox.c @@ -0,0 +1,149 @@ +/** -*- linux-c -*- *********************************************************** + * Linux PPP over X/Ethernet (PPPoX/PPPoE) Sockets + * + * PPPoX --- Generic PPP encapsulation socket family + * PPPoE --- PPP over Ethernet (RFC 2516) + * + * + * Version: 0.5.2 + * + * Author: Michal Ostrowski + * + * 051000 : Initialization cleanup + * + * License: + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +static const struct pppox_proto *pppox_protos[PX_MAX_PROTO + 1]; + +int register_pppox_proto(int proto_num, const struct pppox_proto *pp) +{ + if (proto_num < 0 || proto_num > PX_MAX_PROTO) + return -EINVAL; + if (pppox_protos[proto_num]) + return -EALREADY; + pppox_protos[proto_num] = pp; + return 0; +} + +void unregister_pppox_proto(int proto_num) +{ + if (proto_num >= 0 && proto_num <= PX_MAX_PROTO) + pppox_protos[proto_num] = NULL; +} + +void pppox_unbind_sock(struct sock *sk) +{ + /* Clear connection to ppp device, if attached. */ + + if (sk->sk_state & (PPPOX_BOUND | PPPOX_CONNECTED | PPPOX_ZOMBIE)) { + ppp_unregister_channel(&pppox_sk(sk)->chan); + sk->sk_state = PPPOX_DEAD; + } +} + +EXPORT_SYMBOL(register_pppox_proto); +EXPORT_SYMBOL(unregister_pppox_proto); +EXPORT_SYMBOL(pppox_unbind_sock); + +int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + struct sock *sk = sock->sk; + struct pppox_sock *po = pppox_sk(sk); + int rc; + + lock_sock(sk); + + switch (cmd) { + case PPPIOCGCHAN: { + int index; + rc = -ENOTCONN; + if (!(sk->sk_state & PPPOX_CONNECTED)) + break; + + rc = -EINVAL; + index = ppp_channel_index(&po->chan); + if (put_user(index , (int __user *) arg)) + break; + + rc = 0; + sk->sk_state |= PPPOX_BOUND; + break; + } + default: + rc = pppox_protos[sk->sk_protocol]->ioctl ? + pppox_protos[sk->sk_protocol]->ioctl(sock, cmd, arg) : -ENOTTY; + } + + release_sock(sk); + return rc; +} + +EXPORT_SYMBOL(pppox_ioctl); + +static int pppox_create(struct net *net, struct socket *sock, int protocol, + int kern) +{ + int rc = -EPROTOTYPE; + + if (protocol < 0 || protocol > PX_MAX_PROTO) + goto out; + + rc = -EPROTONOSUPPORT; + if (!pppox_protos[protocol]) + request_module("pppox-proto-%d", protocol); + if (!pppox_protos[protocol] || + !try_module_get(pppox_protos[protocol]->owner)) + goto out; + + rc = pppox_protos[protocol]->create(net, sock); + + module_put(pppox_protos[protocol]->owner); +out: + return rc; +} + +static const struct net_proto_family pppox_proto_family = { + .family = PF_PPPOX, + .create = pppox_create, + .owner = THIS_MODULE, +}; + +static int __init pppox_init(void) +{ + return sock_register(&pppox_proto_family); +} + +static void __exit pppox_exit(void) +{ + sock_unregister(PF_PPPOX); +} + +module_init(pppox_init); +module_exit(pppox_exit); + +MODULE_AUTHOR("Michal Ostrowski "); +MODULE_DESCRIPTION("PPP over Ethernet driver (generic socket layer)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c new file mode 100644 index 0000000..eae542a --- /dev/null +++ b/drivers/net/ppp/pptp.c @@ -0,0 +1,717 @@ +/* + * Point-to-Point Tunneling Protocol for Linux + * + * Authors: Dmitry Kozlov + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define PPTP_DRIVER_VERSION "0.8.5" + +#define MAX_CALLID 65535 + +static DECLARE_BITMAP(callid_bitmap, MAX_CALLID + 1); +static struct pppox_sock **callid_sock; + +static DEFINE_SPINLOCK(chan_lock); + +static struct proto pptp_sk_proto __read_mostly; +static const struct ppp_channel_ops pptp_chan_ops; +static const struct proto_ops pptp_ops; + +#define PPP_LCP_ECHOREQ 0x09 +#define PPP_LCP_ECHOREP 0x0A +#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) + +#define MISSING_WINDOW 20 +#define WRAPPED(curseq, lastseq)\ + ((((curseq) & 0xffffff00) == 0) &&\ + (((lastseq) & 0xffffff00) == 0xffffff00)) + +#define PPTP_GRE_PROTO 0x880B +#define PPTP_GRE_VER 0x1 + +#define PPTP_GRE_FLAG_C 0x80 +#define PPTP_GRE_FLAG_R 0x40 +#define PPTP_GRE_FLAG_K 0x20 +#define PPTP_GRE_FLAG_S 0x10 +#define PPTP_GRE_FLAG_A 0x80 + +#define PPTP_GRE_IS_C(f) ((f)&PPTP_GRE_FLAG_C) +#define PPTP_GRE_IS_R(f) ((f)&PPTP_GRE_FLAG_R) +#define PPTP_GRE_IS_K(f) ((f)&PPTP_GRE_FLAG_K) +#define PPTP_GRE_IS_S(f) ((f)&PPTP_GRE_FLAG_S) +#define PPTP_GRE_IS_A(f) ((f)&PPTP_GRE_FLAG_A) + +#define PPTP_HEADER_OVERHEAD (2+sizeof(struct pptp_gre_header)) +struct pptp_gre_header { + u8 flags; + u8 ver; + u16 protocol; + u16 payload_len; + u16 call_id; + u32 seq; + u32 ack; +} __packed; + +static struct pppox_sock *lookup_chan(u16 call_id, __be32 s_addr) +{ + struct pppox_sock *sock; + struct pptp_opt *opt; + + rcu_read_lock(); + sock = rcu_dereference(callid_sock[call_id]); + if (sock) { + opt = &sock->proto.pptp; + if (opt->dst_addr.sin_addr.s_addr != s_addr) + sock = NULL; + else + sock_hold(sk_pppox(sock)); + } + rcu_read_unlock(); + + return sock; +} + +static int lookup_chan_dst(u16 call_id, __be32 d_addr) +{ + struct pppox_sock *sock; + struct pptp_opt *opt; + int i; + + rcu_read_lock(); + for (i = find_next_bit(callid_bitmap, MAX_CALLID, 1); i < MAX_CALLID; + i = find_next_bit(callid_bitmap, MAX_CALLID, i + 1)) { + sock = rcu_dereference(callid_sock[i]); + if (!sock) + continue; + opt = &sock->proto.pptp; + if (opt->dst_addr.call_id == call_id && + opt->dst_addr.sin_addr.s_addr == d_addr) + break; + } + rcu_read_unlock(); + + return i < MAX_CALLID; +} + +static int add_chan(struct pppox_sock *sock) +{ + static int call_id; + + spin_lock(&chan_lock); + if (!sock->proto.pptp.src_addr.call_id) { + call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, call_id + 1); + if (call_id == MAX_CALLID) { + call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, 1); + if (call_id == MAX_CALLID) + goto out_err; + } + sock->proto.pptp.src_addr.call_id = call_id; + } else if (test_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap)) + goto out_err; + + set_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap); + rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id], sock); + spin_unlock(&chan_lock); + + return 0; + +out_err: + spin_unlock(&chan_lock); + return -1; +} + +static void del_chan(struct pppox_sock *sock) +{ + spin_lock(&chan_lock); + clear_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap); + rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id], NULL); + spin_unlock(&chan_lock); + synchronize_rcu(); +} + +static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) +{ + struct sock *sk = (struct sock *) chan->private; + struct pppox_sock *po = pppox_sk(sk); + struct pptp_opt *opt = &po->proto.pptp; + struct pptp_gre_header *hdr; + unsigned int header_len = sizeof(*hdr); + struct flowi4 fl4; + int islcp; + int len; + unsigned char *data; + __u32 seq_recv; + + + struct rtable *rt; + struct net_device *tdev; + struct iphdr *iph; + int max_headroom; + + if (sk_pppox(po)->sk_state & PPPOX_DEAD) + goto tx_error; + + rt = ip_route_output_ports(&init_net, &fl4, NULL, + opt->dst_addr.sin_addr.s_addr, + opt->src_addr.sin_addr.s_addr, + 0, 0, IPPROTO_GRE, + RT_TOS(0), 0); + if (IS_ERR(rt)) + goto tx_error; + + tdev = rt->dst.dev; + + max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(*iph) + sizeof(*hdr) + 2; + + if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) { + struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); + if (!new_skb) { + ip_rt_put(rt); + goto tx_error; + } + if (skb->sk) + skb_set_owner_w(new_skb, skb->sk); + kfree_skb(skb); + skb = new_skb; + } + + data = skb->data; + islcp = ((data[0] << 8) + data[1]) == PPP_LCP && 1 <= data[2] && data[2] <= 7; + + /* compress protocol field */ + if ((opt->ppp_flags & SC_COMP_PROT) && data[0] == 0 && !islcp) + skb_pull(skb, 1); + + /* Put in the address/control bytes if necessary */ + if ((opt->ppp_flags & SC_COMP_AC) == 0 || islcp) { + data = skb_push(skb, 2); + data[0] = PPP_ALLSTATIONS; + data[1] = PPP_UI; + } + + len = skb->len; + + seq_recv = opt->seq_recv; + + if (opt->ack_sent == seq_recv) + header_len -= sizeof(hdr->ack); + + /* Push down and install GRE header */ + skb_push(skb, header_len); + hdr = (struct pptp_gre_header *)(skb->data); + + hdr->flags = PPTP_GRE_FLAG_K; + hdr->ver = PPTP_GRE_VER; + hdr->protocol = htons(PPTP_GRE_PROTO); + hdr->call_id = htons(opt->dst_addr.call_id); + + hdr->flags |= PPTP_GRE_FLAG_S; + hdr->seq = htonl(++opt->seq_sent); + if (opt->ack_sent != seq_recv) { + /* send ack with this message */ + hdr->ver |= PPTP_GRE_FLAG_A; + hdr->ack = htonl(seq_recv); + opt->ack_sent = seq_recv; + } + hdr->payload_len = htons(len); + + /* Push down and install the IP header. */ + + skb_reset_transport_header(skb); + skb_push(skb, sizeof(*iph)); + skb_reset_network_header(skb); + memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); + IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED); + + iph = ip_hdr(skb); + iph->version = 4; + iph->ihl = sizeof(struct iphdr) >> 2; + if (ip_dont_fragment(sk, &rt->dst)) + iph->frag_off = htons(IP_DF); + else + iph->frag_off = 0; + iph->protocol = IPPROTO_GRE; + iph->tos = 0; + iph->daddr = fl4.daddr; + iph->saddr = fl4.saddr; + iph->ttl = ip4_dst_hoplimit(&rt->dst); + iph->tot_len = htons(skb->len); + + skb_dst_drop(skb); + skb_dst_set(skb, &rt->dst); + + nf_reset(skb); + + skb->ip_summed = CHECKSUM_NONE; + ip_select_ident(iph, &rt->dst, NULL); + ip_send_check(iph); + + ip_local_out(skb); + +tx_error: + return 1; +} + +static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb) +{ + struct pppox_sock *po = pppox_sk(sk); + struct pptp_opt *opt = &po->proto.pptp; + int headersize, payload_len, seq; + __u8 *payload; + struct pptp_gre_header *header; + + if (!(sk->sk_state & PPPOX_CONNECTED)) { + if (sock_queue_rcv_skb(sk, skb)) + goto drop; + return NET_RX_SUCCESS; + } + + header = (struct pptp_gre_header *)(skb->data); + + /* test if acknowledgement present */ + if (PPTP_GRE_IS_A(header->ver)) { + __u32 ack = (PPTP_GRE_IS_S(header->flags)) ? + header->ack : header->seq; /* ack in different place if S = 0 */ + + ack = ntohl(ack); + + if (ack > opt->ack_recv) + opt->ack_recv = ack; + /* also handle sequence number wrap-around */ + if (WRAPPED(ack, opt->ack_recv)) + opt->ack_recv = ack; + } + + /* test if payload present */ + if (!PPTP_GRE_IS_S(header->flags)) + goto drop; + + headersize = sizeof(*header); + payload_len = ntohs(header->payload_len); + seq = ntohl(header->seq); + + /* no ack present? */ + if (!PPTP_GRE_IS_A(header->ver)) + headersize -= sizeof(header->ack); + /* check for incomplete packet (length smaller than expected) */ + if (skb->len - headersize < payload_len) + goto drop; + + payload = skb->data + headersize; + /* check for expected sequence number */ + if (seq < opt->seq_recv + 1 || WRAPPED(opt->seq_recv, seq)) { + if ((payload[0] == PPP_ALLSTATIONS) && (payload[1] == PPP_UI) && + (PPP_PROTOCOL(payload) == PPP_LCP) && + ((payload[4] == PPP_LCP_ECHOREQ) || (payload[4] == PPP_LCP_ECHOREP))) + goto allow_packet; + } else { + opt->seq_recv = seq; +allow_packet: + skb_pull(skb, headersize); + + if (payload[0] == PPP_ALLSTATIONS && payload[1] == PPP_UI) { + /* chop off address/control */ + if (skb->len < 3) + goto drop; + skb_pull(skb, 2); + } + + if ((*skb->data) & 1) { + /* protocol is compressed */ + skb_push(skb, 1)[0] = 0; + } + + skb->ip_summed = CHECKSUM_NONE; + skb_set_network_header(skb, skb->head-skb->data); + ppp_input(&po->chan, skb); + + return NET_RX_SUCCESS; + } +drop: + kfree_skb(skb); + return NET_RX_DROP; +} + +static int pptp_rcv(struct sk_buff *skb) +{ + struct pppox_sock *po; + struct pptp_gre_header *header; + struct iphdr *iph; + + if (skb->pkt_type != PACKET_HOST) + goto drop; + + if (!pskb_may_pull(skb, 12)) + goto drop; + + iph = ip_hdr(skb); + + header = (struct pptp_gre_header *)skb->data; + + if (ntohs(header->protocol) != PPTP_GRE_PROTO || /* PPTP-GRE protocol for PPTP */ + PPTP_GRE_IS_C(header->flags) || /* flag C should be clear */ + PPTP_GRE_IS_R(header->flags) || /* flag R should be clear */ + !PPTP_GRE_IS_K(header->flags) || /* flag K should be set */ + (header->flags&0xF) != 0) /* routing and recursion ctrl = 0 */ + /* if invalid, discard this packet */ + goto drop; + + po = lookup_chan(htons(header->call_id), iph->saddr); + if (po) { + skb_dst_drop(skb); + nf_reset(skb); + return sk_receive_skb(sk_pppox(po), skb, 0); + } +drop: + kfree_skb(skb); + return NET_RX_DROP; +} + +static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr, + int sockaddr_len) +{ + struct sock *sk = sock->sk; + struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr; + struct pppox_sock *po = pppox_sk(sk); + struct pptp_opt *opt = &po->proto.pptp; + int error = 0; + + lock_sock(sk); + + opt->src_addr = sp->sa_addr.pptp; + if (add_chan(po)) { + release_sock(sk); + error = -EBUSY; + } + + release_sock(sk); + return error; +} + +static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, + int sockaddr_len, int flags) +{ + struct sock *sk = sock->sk; + struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr; + struct pppox_sock *po = pppox_sk(sk); + struct pptp_opt *opt = &po->proto.pptp; + struct rtable *rt; + struct flowi4 fl4; + int error = 0; + + if (sp->sa_protocol != PX_PROTO_PPTP) + return -EINVAL; + + if (lookup_chan_dst(sp->sa_addr.pptp.call_id, sp->sa_addr.pptp.sin_addr.s_addr)) + return -EALREADY; + + lock_sock(sk); + /* Check for already bound sockets */ + if (sk->sk_state & PPPOX_CONNECTED) { + error = -EBUSY; + goto end; + } + + /* Check for already disconnected sockets, on attempts to disconnect */ + if (sk->sk_state & PPPOX_DEAD) { + error = -EALREADY; + goto end; + } + + if (!opt->src_addr.sin_addr.s_addr || !sp->sa_addr.pptp.sin_addr.s_addr) { + error = -EINVAL; + goto end; + } + + po->chan.private = sk; + po->chan.ops = &pptp_chan_ops; + + rt = ip_route_output_ports(&init_net, &fl4, sk, + opt->dst_addr.sin_addr.s_addr, + opt->src_addr.sin_addr.s_addr, + 0, 0, + IPPROTO_GRE, RT_CONN_FLAGS(sk), 0); + if (IS_ERR(rt)) { + error = -EHOSTUNREACH; + goto end; + } + sk_setup_caps(sk, &rt->dst); + + po->chan.mtu = dst_mtu(&rt->dst); + if (!po->chan.mtu) + po->chan.mtu = PPP_MTU; + ip_rt_put(rt); + po->chan.mtu -= PPTP_HEADER_OVERHEAD; + + po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header); + error = ppp_register_channel(&po->chan); + if (error) { + pr_err("PPTP: failed to register PPP channel (%d)\n", error); + goto end; + } + + opt->dst_addr = sp->sa_addr.pptp; + sk->sk_state = PPPOX_CONNECTED; + + end: + release_sock(sk); + return error; +} + +static int pptp_getname(struct socket *sock, struct sockaddr *uaddr, + int *usockaddr_len, int peer) +{ + int len = sizeof(struct sockaddr_pppox); + struct sockaddr_pppox sp; + + sp.sa_family = AF_PPPOX; + sp.sa_protocol = PX_PROTO_PPTP; + sp.sa_addr.pptp = pppox_sk(sock->sk)->proto.pptp.src_addr; + + memcpy(uaddr, &sp, len); + + *usockaddr_len = len; + + return 0; +} + +static int pptp_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + struct pppox_sock *po; + struct pptp_opt *opt; + int error = 0; + + if (!sk) + return 0; + + lock_sock(sk); + + if (sock_flag(sk, SOCK_DEAD)) { + release_sock(sk); + return -EBADF; + } + + po = pppox_sk(sk); + opt = &po->proto.pptp; + del_chan(po); + + pppox_unbind_sock(sk); + sk->sk_state = PPPOX_DEAD; + + sock_orphan(sk); + sock->sk = NULL; + + release_sock(sk); + sock_put(sk); + + return error; +} + +static void pptp_sock_destruct(struct sock *sk) +{ + if (!(sk->sk_state & PPPOX_DEAD)) { + del_chan(pppox_sk(sk)); + pppox_unbind_sock(sk); + } + skb_queue_purge(&sk->sk_receive_queue); +} + +static int pptp_create(struct net *net, struct socket *sock) +{ + int error = -ENOMEM; + struct sock *sk; + struct pppox_sock *po; + struct pptp_opt *opt; + + sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pptp_sk_proto); + if (!sk) + goto out; + + sock_init_data(sock, sk); + + sock->state = SS_UNCONNECTED; + sock->ops = &pptp_ops; + + sk->sk_backlog_rcv = pptp_rcv_core; + sk->sk_state = PPPOX_NONE; + sk->sk_type = SOCK_STREAM; + sk->sk_family = PF_PPPOX; + sk->sk_protocol = PX_PROTO_PPTP; + sk->sk_destruct = pptp_sock_destruct; + + po = pppox_sk(sk); + opt = &po->proto.pptp; + + opt->seq_sent = 0; opt->seq_recv = 0; + opt->ack_recv = 0; opt->ack_sent = 0; + + error = 0; +out: + return error; +} + +static int pptp_ppp_ioctl(struct ppp_channel *chan, unsigned int cmd, + unsigned long arg) +{ + struct sock *sk = (struct sock *) chan->private; + struct pppox_sock *po = pppox_sk(sk); + struct pptp_opt *opt = &po->proto.pptp; + void __user *argp = (void __user *)arg; + int __user *p = argp; + int err, val; + + err = -EFAULT; + switch (cmd) { + case PPPIOCGFLAGS: + val = opt->ppp_flags; + if (put_user(val, p)) + break; + err = 0; + break; + case PPPIOCSFLAGS: + if (get_user(val, p)) + break; + opt->ppp_flags = val & ~SC_RCV_BITS; + err = 0; + break; + default: + err = -ENOTTY; + } + + return err; +} + +static const struct ppp_channel_ops pptp_chan_ops = { + .start_xmit = pptp_xmit, + .ioctl = pptp_ppp_ioctl, +}; + +static struct proto pptp_sk_proto __read_mostly = { + .name = "PPTP", + .owner = THIS_MODULE, + .obj_size = sizeof(struct pppox_sock), +}; + +static const struct proto_ops pptp_ops = { + .family = AF_PPPOX, + .owner = THIS_MODULE, + .release = pptp_release, + .bind = pptp_bind, + .connect = pptp_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = pptp_getname, + .poll = sock_no_poll, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .setsockopt = sock_no_setsockopt, + .getsockopt = sock_no_getsockopt, + .sendmsg = sock_no_sendmsg, + .recvmsg = sock_no_recvmsg, + .mmap = sock_no_mmap, + .ioctl = pppox_ioctl, +}; + +static const struct pppox_proto pppox_pptp_proto = { + .create = pptp_create, + .owner = THIS_MODULE, +}; + +static const struct gre_protocol gre_pptp_protocol = { + .handler = pptp_rcv, +}; + +static int __init pptp_init_module(void) +{ + int err = 0; + pr_info("PPTP driver version " PPTP_DRIVER_VERSION "\n"); + + callid_sock = vzalloc((MAX_CALLID + 1) * sizeof(void *)); + if (!callid_sock) { + pr_err("PPTP: cann't allocate memory\n"); + return -ENOMEM; + } + + err = gre_add_protocol(&gre_pptp_protocol, GREPROTO_PPTP); + if (err) { + pr_err("PPTP: can't add gre protocol\n"); + goto out_mem_free; + } + + err = proto_register(&pptp_sk_proto, 0); + if (err) { + pr_err("PPTP: can't register sk_proto\n"); + goto out_gre_del_protocol; + } + + err = register_pppox_proto(PX_PROTO_PPTP, &pppox_pptp_proto); + if (err) { + pr_err("PPTP: can't register pppox_proto\n"); + goto out_unregister_sk_proto; + } + + return 0; + +out_unregister_sk_proto: + proto_unregister(&pptp_sk_proto); +out_gre_del_protocol: + gre_del_protocol(&gre_pptp_protocol, GREPROTO_PPTP); +out_mem_free: + vfree(callid_sock); + + return err; +} + +static void __exit pptp_exit_module(void) +{ + unregister_pppox_proto(PX_PROTO_PPTP); + proto_unregister(&pptp_sk_proto); + gre_del_protocol(&gre_pptp_protocol, GREPROTO_PPTP); + vfree(callid_sock); +} + +module_init(pptp_init_module); +module_exit(pptp_exit_module); + +MODULE_DESCRIPTION("Point-to-Point Tunneling Protocol"); +MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c deleted file mode 100644 index c6ba643..0000000 --- a/drivers/net/ppp_async.c +++ /dev/null @@ -1,1028 +0,0 @@ -/* - * PPP async serial channel driver for Linux. - * - * Copyright 1999 Paul Mackerras. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * This driver provides the encapsulation and framing for sending - * and receiving PPP frames over async serial lines. It relies on - * the generic PPP layer to give it frames to send and to process - * received frames. It implements the PPP line discipline. - * - * Part of the code in this driver was inspired by the old async-only - * PPP driver, written by Michael Callahan and Al Longyear, and - * subsequently hacked by Paul Mackerras. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PPP_VERSION "2.4.2" - -#define OBUFSIZE 4096 - -/* Structure for storing local state. */ -struct asyncppp { - struct tty_struct *tty; - unsigned int flags; - unsigned int state; - unsigned int rbits; - int mru; - spinlock_t xmit_lock; - spinlock_t recv_lock; - unsigned long xmit_flags; - u32 xaccm[8]; - u32 raccm; - unsigned int bytes_sent; - unsigned int bytes_rcvd; - - struct sk_buff *tpkt; - int tpkt_pos; - u16 tfcs; - unsigned char *optr; - unsigned char *olim; - unsigned long last_xmit; - - struct sk_buff *rpkt; - int lcp_fcs; - struct sk_buff_head rqueue; - - struct tasklet_struct tsk; - - atomic_t refcnt; - struct semaphore dead_sem; - struct ppp_channel chan; /* interface to generic ppp layer */ - unsigned char obuf[OBUFSIZE]; -}; - -/* Bit numbers in xmit_flags */ -#define XMIT_WAKEUP 0 -#define XMIT_FULL 1 -#define XMIT_BUSY 2 - -/* State bits */ -#define SC_TOSS 1 -#define SC_ESCAPE 2 -#define SC_PREV_ERROR 4 - -/* Bits in rbits */ -#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) - -static int flag_time = HZ; -module_param(flag_time, int, 0); -MODULE_PARM_DESC(flag_time, "ppp_async: interval between flagged packets (in clock ticks)"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_LDISC(N_PPP); - -/* - * Prototypes. - */ -static int ppp_async_encode(struct asyncppp *ap); -static int ppp_async_send(struct ppp_channel *chan, struct sk_buff *skb); -static int ppp_async_push(struct asyncppp *ap); -static void ppp_async_flush_output(struct asyncppp *ap); -static void ppp_async_input(struct asyncppp *ap, const unsigned char *buf, - char *flags, int count); -static int ppp_async_ioctl(struct ppp_channel *chan, unsigned int cmd, - unsigned long arg); -static void ppp_async_process(unsigned long arg); - -static void async_lcp_peek(struct asyncppp *ap, unsigned char *data, - int len, int inbound); - -static const struct ppp_channel_ops async_ops = { - .start_xmit = ppp_async_send, - .ioctl = ppp_async_ioctl, -}; - -/* - * Routines implementing the PPP line discipline. - */ - -/* - * We have a potential race on dereferencing tty->disc_data, - * because the tty layer provides no locking at all - thus one - * cpu could be running ppp_asynctty_receive while another - * calls ppp_asynctty_close, which zeroes tty->disc_data and - * frees the memory that ppp_asynctty_receive is using. The best - * way to fix this is to use a rwlock in the tty struct, but for now - * we use a single global rwlock for all ttys in ppp line discipline. - * - * FIXME: this is no longer true. The _close path for the ldisc is - * now guaranteed to be sane. - */ -static DEFINE_RWLOCK(disc_data_lock); - -static struct asyncppp *ap_get(struct tty_struct *tty) -{ - struct asyncppp *ap; - - read_lock(&disc_data_lock); - ap = tty->disc_data; - if (ap != NULL) - atomic_inc(&ap->refcnt); - read_unlock(&disc_data_lock); - return ap; -} - -static void ap_put(struct asyncppp *ap) -{ - if (atomic_dec_and_test(&ap->refcnt)) - up(&ap->dead_sem); -} - -/* - * Called when a tty is put into PPP line discipline. Called in process - * context. - */ -static int -ppp_asynctty_open(struct tty_struct *tty) -{ - struct asyncppp *ap; - int err; - int speed; - - if (tty->ops->write == NULL) - return -EOPNOTSUPP; - - err = -ENOMEM; - ap = kzalloc(sizeof(*ap), GFP_KERNEL); - if (!ap) - goto out; - - /* initialize the asyncppp structure */ - ap->tty = tty; - ap->mru = PPP_MRU; - spin_lock_init(&ap->xmit_lock); - spin_lock_init(&ap->recv_lock); - ap->xaccm[0] = ~0U; - ap->xaccm[3] = 0x60000000U; - ap->raccm = ~0U; - ap->optr = ap->obuf; - ap->olim = ap->obuf; - ap->lcp_fcs = -1; - - skb_queue_head_init(&ap->rqueue); - tasklet_init(&ap->tsk, ppp_async_process, (unsigned long) ap); - - atomic_set(&ap->refcnt, 1); - sema_init(&ap->dead_sem, 0); - - ap->chan.private = ap; - ap->chan.ops = &async_ops; - ap->chan.mtu = PPP_MRU; - speed = tty_get_baud_rate(tty); - ap->chan.speed = speed; - err = ppp_register_channel(&ap->chan); - if (err) - goto out_free; - - tty->disc_data = ap; - tty->receive_room = 65536; - return 0; - - out_free: - kfree(ap); - out: - return err; -} - -/* - * Called when the tty is put into another line discipline - * or it hangs up. We have to wait for any cpu currently - * executing in any of the other ppp_asynctty_* routines to - * finish before we can call ppp_unregister_channel and free - * the asyncppp struct. This routine must be called from - * process context, not interrupt or softirq context. - */ -static void -ppp_asynctty_close(struct tty_struct *tty) -{ - struct asyncppp *ap; - - write_lock_irq(&disc_data_lock); - ap = tty->disc_data; - tty->disc_data = NULL; - write_unlock_irq(&disc_data_lock); - if (!ap) - return; - - /* - * We have now ensured that nobody can start using ap from now - * on, but we have to wait for all existing users to finish. - * Note that ppp_unregister_channel ensures that no calls to - * our channel ops (i.e. ppp_async_send/ioctl) are in progress - * by the time it returns. - */ - if (!atomic_dec_and_test(&ap->refcnt)) - down(&ap->dead_sem); - tasklet_kill(&ap->tsk); - - ppp_unregister_channel(&ap->chan); - kfree_skb(ap->rpkt); - skb_queue_purge(&ap->rqueue); - kfree_skb(ap->tpkt); - kfree(ap); -} - -/* - * Called on tty hangup in process context. - * - * Wait for I/O to driver to complete and unregister PPP channel. - * This is already done by the close routine, so just call that. - */ -static int ppp_asynctty_hangup(struct tty_struct *tty) -{ - ppp_asynctty_close(tty); - return 0; -} - -/* - * Read does nothing - no data is ever available this way. - * Pppd reads and writes packets via /dev/ppp instead. - */ -static ssize_t -ppp_asynctty_read(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t count) -{ - return -EAGAIN; -} - -/* - * Write on the tty does nothing, the packets all come in - * from the ppp generic stuff. - */ -static ssize_t -ppp_asynctty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t count) -{ - return -EAGAIN; -} - -/* - * Called in process context only. May be re-entered by multiple - * ioctl calling threads. - */ - -static int -ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct asyncppp *ap = ap_get(tty); - int err, val; - int __user *p = (int __user *)arg; - - if (!ap) - return -ENXIO; - err = -EFAULT; - switch (cmd) { - case PPPIOCGCHAN: - err = -EFAULT; - if (put_user(ppp_channel_index(&ap->chan), p)) - break; - err = 0; - break; - - case PPPIOCGUNIT: - err = -EFAULT; - if (put_user(ppp_unit_number(&ap->chan), p)) - break; - err = 0; - break; - - case TCFLSH: - /* flush our buffers and the serial port's buffer */ - if (arg == TCIOFLUSH || arg == TCOFLUSH) - ppp_async_flush_output(ap); - err = tty_perform_flush(tty, arg); - break; - - case FIONREAD: - val = 0; - if (put_user(val, p)) - break; - err = 0; - break; - - default: - /* Try the various mode ioctls */ - err = tty_mode_ioctl(tty, file, cmd, arg); - } - - ap_put(ap); - return err; -} - -/* No kernel lock - fine */ -static unsigned int -ppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait) -{ - return 0; -} - -/* May sleep, don't call from interrupt level or with interrupts disabled */ -static void -ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf, - char *cflags, int count) -{ - struct asyncppp *ap = ap_get(tty); - unsigned long flags; - - if (!ap) - return; - spin_lock_irqsave(&ap->recv_lock, flags); - ppp_async_input(ap, buf, cflags, count); - spin_unlock_irqrestore(&ap->recv_lock, flags); - if (!skb_queue_empty(&ap->rqueue)) - tasklet_schedule(&ap->tsk); - ap_put(ap); - tty_unthrottle(tty); -} - -static void -ppp_asynctty_wakeup(struct tty_struct *tty) -{ - struct asyncppp *ap = ap_get(tty); - - clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - if (!ap) - return; - set_bit(XMIT_WAKEUP, &ap->xmit_flags); - tasklet_schedule(&ap->tsk); - ap_put(ap); -} - - -static struct tty_ldisc_ops ppp_ldisc = { - .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, - .name = "ppp", - .open = ppp_asynctty_open, - .close = ppp_asynctty_close, - .hangup = ppp_asynctty_hangup, - .read = ppp_asynctty_read, - .write = ppp_asynctty_write, - .ioctl = ppp_asynctty_ioctl, - .poll = ppp_asynctty_poll, - .receive_buf = ppp_asynctty_receive, - .write_wakeup = ppp_asynctty_wakeup, -}; - -static int __init -ppp_async_init(void) -{ - int err; - - err = tty_register_ldisc(N_PPP, &ppp_ldisc); - if (err != 0) - printk(KERN_ERR "PPP_async: error %d registering line disc.\n", - err); - return err; -} - -/* - * The following routines provide the PPP channel interface. - */ -static int -ppp_async_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg) -{ - struct asyncppp *ap = chan->private; - void __user *argp = (void __user *)arg; - int __user *p = argp; - int err, val; - u32 accm[8]; - - err = -EFAULT; - switch (cmd) { - case PPPIOCGFLAGS: - val = ap->flags | ap->rbits; - if (put_user(val, p)) - break; - err = 0; - break; - case PPPIOCSFLAGS: - if (get_user(val, p)) - break; - ap->flags = val & ~SC_RCV_BITS; - spin_lock_irq(&ap->recv_lock); - ap->rbits = val & SC_RCV_BITS; - spin_unlock_irq(&ap->recv_lock); - err = 0; - break; - - case PPPIOCGASYNCMAP: - if (put_user(ap->xaccm[0], (u32 __user *)argp)) - break; - err = 0; - break; - case PPPIOCSASYNCMAP: - if (get_user(ap->xaccm[0], (u32 __user *)argp)) - break; - err = 0; - break; - - case PPPIOCGRASYNCMAP: - if (put_user(ap->raccm, (u32 __user *)argp)) - break; - err = 0; - break; - case PPPIOCSRASYNCMAP: - if (get_user(ap->raccm, (u32 __user *)argp)) - break; - err = 0; - break; - - case PPPIOCGXASYNCMAP: - if (copy_to_user(argp, ap->xaccm, sizeof(ap->xaccm))) - break; - err = 0; - break; - case PPPIOCSXASYNCMAP: - if (copy_from_user(accm, argp, sizeof(accm))) - break; - accm[2] &= ~0x40000000U; /* can't escape 0x5e */ - accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */ - memcpy(ap->xaccm, accm, sizeof(ap->xaccm)); - err = 0; - break; - - case PPPIOCGMRU: - if (put_user(ap->mru, p)) - break; - err = 0; - break; - case PPPIOCSMRU: - if (get_user(val, p)) - break; - if (val < PPP_MRU) - val = PPP_MRU; - ap->mru = val; - err = 0; - break; - - default: - err = -ENOTTY; - } - - return err; -} - -/* - * This is called at softirq level to deliver received packets - * to the ppp_generic code, and to tell the ppp_generic code - * if we can accept more output now. - */ -static void ppp_async_process(unsigned long arg) -{ - struct asyncppp *ap = (struct asyncppp *) arg; - struct sk_buff *skb; - - /* process received packets */ - while ((skb = skb_dequeue(&ap->rqueue)) != NULL) { - if (skb->cb[0]) - ppp_input_error(&ap->chan, 0); - ppp_input(&ap->chan, skb); - } - - /* try to push more stuff out */ - if (test_bit(XMIT_WAKEUP, &ap->xmit_flags) && ppp_async_push(ap)) - ppp_output_wakeup(&ap->chan); -} - -/* - * Procedures for encapsulation and framing. - */ - -/* - * Procedure to encode the data for async serial transmission. - * Does octet stuffing (escaping), puts the address/control bytes - * on if A/C compression is disabled, and does protocol compression. - * Assumes ap->tpkt != 0 on entry. - * Returns 1 if we finished the current frame, 0 otherwise. - */ - -#define PUT_BYTE(ap, buf, c, islcp) do { \ - if ((islcp && c < 0x20) || (ap->xaccm[c >> 5] & (1 << (c & 0x1f)))) {\ - *buf++ = PPP_ESCAPE; \ - *buf++ = c ^ PPP_TRANS; \ - } else \ - *buf++ = c; \ -} while (0) - -static int -ppp_async_encode(struct asyncppp *ap) -{ - int fcs, i, count, c, proto; - unsigned char *buf, *buflim; - unsigned char *data; - int islcp; - - buf = ap->obuf; - ap->olim = buf; - ap->optr = buf; - i = ap->tpkt_pos; - data = ap->tpkt->data; - count = ap->tpkt->len; - fcs = ap->tfcs; - proto = get_unaligned_be16(data); - - /* - * LCP packets with code values between 1 (configure-reqest) - * and 7 (code-reject) must be sent as though no options - * had been negotiated. - */ - islcp = proto == PPP_LCP && 1 <= data[2] && data[2] <= 7; - - if (i == 0) { - if (islcp) - async_lcp_peek(ap, data, count, 0); - - /* - * Start of a new packet - insert the leading FLAG - * character if necessary. - */ - if (islcp || flag_time == 0 || - time_after_eq(jiffies, ap->last_xmit + flag_time)) - *buf++ = PPP_FLAG; - ap->last_xmit = jiffies; - fcs = PPP_INITFCS; - - /* - * Put in the address/control bytes if necessary - */ - if ((ap->flags & SC_COMP_AC) == 0 || islcp) { - PUT_BYTE(ap, buf, 0xff, islcp); - fcs = PPP_FCS(fcs, 0xff); - PUT_BYTE(ap, buf, 0x03, islcp); - fcs = PPP_FCS(fcs, 0x03); - } - } - - /* - * Once we put in the last byte, we need to put in the FCS - * and closing flag, so make sure there is at least 7 bytes - * of free space in the output buffer. - */ - buflim = ap->obuf + OBUFSIZE - 6; - while (i < count && buf < buflim) { - c = data[i++]; - if (i == 1 && c == 0 && (ap->flags & SC_COMP_PROT)) - continue; /* compress protocol field */ - fcs = PPP_FCS(fcs, c); - PUT_BYTE(ap, buf, c, islcp); - } - - if (i < count) { - /* - * Remember where we are up to in this packet. - */ - ap->olim = buf; - ap->tpkt_pos = i; - ap->tfcs = fcs; - return 0; - } - - /* - * We have finished the packet. Add the FCS and flag. - */ - fcs = ~fcs; - c = fcs & 0xff; - PUT_BYTE(ap, buf, c, islcp); - c = (fcs >> 8) & 0xff; - PUT_BYTE(ap, buf, c, islcp); - *buf++ = PPP_FLAG; - ap->olim = buf; - - kfree_skb(ap->tpkt); - ap->tpkt = NULL; - return 1; -} - -/* - * Transmit-side routines. - */ - -/* - * Send a packet to the peer over an async tty line. - * Returns 1 iff the packet was accepted. - * If the packet was not accepted, we will call ppp_output_wakeup - * at some later time. - */ -static int -ppp_async_send(struct ppp_channel *chan, struct sk_buff *skb) -{ - struct asyncppp *ap = chan->private; - - ppp_async_push(ap); - - if (test_and_set_bit(XMIT_FULL, &ap->xmit_flags)) - return 0; /* already full */ - ap->tpkt = skb; - ap->tpkt_pos = 0; - - ppp_async_push(ap); - return 1; -} - -/* - * Push as much data as possible out to the tty. - */ -static int -ppp_async_push(struct asyncppp *ap) -{ - int avail, sent, done = 0; - struct tty_struct *tty = ap->tty; - int tty_stuffed = 0; - - /* - * We can get called recursively here if the tty write - * function calls our wakeup function. This can happen - * for example on a pty with both the master and slave - * set to PPP line discipline. - * We use the XMIT_BUSY bit to detect this and get out, - * leaving the XMIT_WAKEUP bit set to tell the other - * instance that it may now be able to write more now. - */ - if (test_and_set_bit(XMIT_BUSY, &ap->xmit_flags)) - return 0; - spin_lock_bh(&ap->xmit_lock); - for (;;) { - if (test_and_clear_bit(XMIT_WAKEUP, &ap->xmit_flags)) - tty_stuffed = 0; - if (!tty_stuffed && ap->optr < ap->olim) { - avail = ap->olim - ap->optr; - set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - sent = tty->ops->write(tty, ap->optr, avail); - if (sent < 0) - goto flush; /* error, e.g. loss of CD */ - ap->optr += sent; - if (sent < avail) - tty_stuffed = 1; - continue; - } - if (ap->optr >= ap->olim && ap->tpkt) { - if (ppp_async_encode(ap)) { - /* finished processing ap->tpkt */ - clear_bit(XMIT_FULL, &ap->xmit_flags); - done = 1; - } - continue; - } - /* - * We haven't made any progress this time around. - * Clear XMIT_BUSY to let other callers in, but - * after doing so we have to check if anyone set - * XMIT_WAKEUP since we last checked it. If they - * did, we should try again to set XMIT_BUSY and go - * around again in case XMIT_BUSY was still set when - * the other caller tried. - */ - clear_bit(XMIT_BUSY, &ap->xmit_flags); - /* any more work to do? if not, exit the loop */ - if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags) || - (!tty_stuffed && ap->tpkt))) - break; - /* more work to do, see if we can do it now */ - if (test_and_set_bit(XMIT_BUSY, &ap->xmit_flags)) - break; - } - spin_unlock_bh(&ap->xmit_lock); - return done; - -flush: - clear_bit(XMIT_BUSY, &ap->xmit_flags); - if (ap->tpkt) { - kfree_skb(ap->tpkt); - ap->tpkt = NULL; - clear_bit(XMIT_FULL, &ap->xmit_flags); - done = 1; - } - ap->optr = ap->olim; - spin_unlock_bh(&ap->xmit_lock); - return done; -} - -/* - * Flush output from our internal buffers. - * Called for the TCFLSH ioctl. Can be entered in parallel - * but this is covered by the xmit_lock. - */ -static void -ppp_async_flush_output(struct asyncppp *ap) -{ - int done = 0; - - spin_lock_bh(&ap->xmit_lock); - ap->optr = ap->olim; - if (ap->tpkt != NULL) { - kfree_skb(ap->tpkt); - ap->tpkt = NULL; - clear_bit(XMIT_FULL, &ap->xmit_flags); - done = 1; - } - spin_unlock_bh(&ap->xmit_lock); - if (done) - ppp_output_wakeup(&ap->chan); -} - -/* - * Receive-side routines. - */ - -/* see how many ordinary chars there are at the start of buf */ -static inline int -scan_ordinary(struct asyncppp *ap, const unsigned char *buf, int count) -{ - int i, c; - - for (i = 0; i < count; ++i) { - c = buf[i]; - if (c == PPP_ESCAPE || c == PPP_FLAG || - (c < 0x20 && (ap->raccm & (1 << c)) != 0)) - break; - } - return i; -} - -/* called when a flag is seen - do end-of-packet processing */ -static void -process_input_packet(struct asyncppp *ap) -{ - struct sk_buff *skb; - unsigned char *p; - unsigned int len, fcs, proto; - - skb = ap->rpkt; - if (ap->state & (SC_TOSS | SC_ESCAPE)) - goto err; - - if (skb == NULL) - return; /* 0-length packet */ - - /* check the FCS */ - p = skb->data; - len = skb->len; - if (len < 3) - goto err; /* too short */ - fcs = PPP_INITFCS; - for (; len > 0; --len) - fcs = PPP_FCS(fcs, *p++); - if (fcs != PPP_GOODFCS) - goto err; /* bad FCS */ - skb_trim(skb, skb->len - 2); - - /* check for address/control and protocol compression */ - p = skb->data; - if (p[0] == PPP_ALLSTATIONS) { - /* chop off address/control */ - if (p[1] != PPP_UI || skb->len < 3) - goto err; - p = skb_pull(skb, 2); - } - proto = p[0]; - if (proto & 1) { - /* protocol is compressed */ - skb_push(skb, 1)[0] = 0; - } else { - if (skb->len < 2) - goto err; - proto = (proto << 8) + p[1]; - if (proto == PPP_LCP) - async_lcp_peek(ap, p, skb->len, 1); - } - - /* queue the frame to be processed */ - skb->cb[0] = ap->state; - skb_queue_tail(&ap->rqueue, skb); - ap->rpkt = NULL; - ap->state = 0; - return; - - err: - /* frame had an error, remember that, reset SC_TOSS & SC_ESCAPE */ - ap->state = SC_PREV_ERROR; - if (skb) { - /* make skb appear as freshly allocated */ - skb_trim(skb, 0); - skb_reserve(skb, - skb_headroom(skb)); - } -} - -/* Called when the tty driver has data for us. Runs parallel with the - other ldisc functions but will not be re-entered */ - -static void -ppp_async_input(struct asyncppp *ap, const unsigned char *buf, - char *flags, int count) -{ - struct sk_buff *skb; - int c, i, j, n, s, f; - unsigned char *sp; - - /* update bits used for 8-bit cleanness detection */ - if (~ap->rbits & SC_RCV_BITS) { - s = 0; - for (i = 0; i < count; ++i) { - c = buf[i]; - if (flags && flags[i] != 0) - continue; - s |= (c & 0x80)? SC_RCV_B7_1: SC_RCV_B7_0; - c = ((c >> 4) ^ c) & 0xf; - s |= (0x6996 & (1 << c))? SC_RCV_ODDP: SC_RCV_EVNP; - } - ap->rbits |= s; - } - - while (count > 0) { - /* scan through and see how many chars we can do in bulk */ - if ((ap->state & SC_ESCAPE) && buf[0] == PPP_ESCAPE) - n = 1; - else - n = scan_ordinary(ap, buf, count); - - f = 0; - if (flags && (ap->state & SC_TOSS) == 0) { - /* check the flags to see if any char had an error */ - for (j = 0; j < n; ++j) - if ((f = flags[j]) != 0) - break; - } - if (f != 0) { - /* start tossing */ - ap->state |= SC_TOSS; - - } else if (n > 0 && (ap->state & SC_TOSS) == 0) { - /* stuff the chars in the skb */ - skb = ap->rpkt; - if (!skb) { - skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2); - if (!skb) - goto nomem; - ap->rpkt = skb; - } - if (skb->len == 0) { - /* Try to get the payload 4-byte aligned. - * This should match the - * PPP_ALLSTATIONS/PPP_UI/compressed tests in - * process_input_packet, but we do not have - * enough chars here to test buf[1] and buf[2]. - */ - if (buf[0] != PPP_ALLSTATIONS) - skb_reserve(skb, 2 + (buf[0] & 1)); - } - if (n > skb_tailroom(skb)) { - /* packet overflowed MRU */ - ap->state |= SC_TOSS; - } else { - sp = skb_put(skb, n); - memcpy(sp, buf, n); - if (ap->state & SC_ESCAPE) { - sp[0] ^= PPP_TRANS; - ap->state &= ~SC_ESCAPE; - } - } - } - - if (n >= count) - break; - - c = buf[n]; - if (flags != NULL && flags[n] != 0) { - ap->state |= SC_TOSS; - } else if (c == PPP_FLAG) { - process_input_packet(ap); - } else if (c == PPP_ESCAPE) { - ap->state |= SC_ESCAPE; - } else if (I_IXON(ap->tty)) { - if (c == START_CHAR(ap->tty)) - start_tty(ap->tty); - else if (c == STOP_CHAR(ap->tty)) - stop_tty(ap->tty); - } - /* otherwise it's a char in the recv ACCM */ - ++n; - - buf += n; - if (flags) - flags += n; - count -= n; - } - return; - - nomem: - printk(KERN_ERR "PPPasync: no memory (input pkt)\n"); - ap->state |= SC_TOSS; -} - -/* - * We look at LCP frames going past so that we can notice - * and react to the LCP configure-ack from the peer. - * In the situation where the peer has been sent a configure-ack - * already, LCP is up once it has sent its configure-ack - * so the immediately following packet can be sent with the - * configured LCP options. This allows us to process the following - * packet correctly without pppd needing to respond quickly. - * - * We only respond to the received configure-ack if we have just - * sent a configure-request, and the configure-ack contains the - * same data (this is checked using a 16-bit crc of the data). - */ -#define CONFREQ 1 /* LCP code field values */ -#define CONFACK 2 -#define LCP_MRU 1 /* LCP option numbers */ -#define LCP_ASYNCMAP 2 - -static void async_lcp_peek(struct asyncppp *ap, unsigned char *data, - int len, int inbound) -{ - int dlen, fcs, i, code; - u32 val; - - data += 2; /* skip protocol bytes */ - len -= 2; - if (len < 4) /* 4 = code, ID, length */ - return; - code = data[0]; - if (code != CONFACK && code != CONFREQ) - return; - dlen = get_unaligned_be16(data + 2); - if (len < dlen) - return; /* packet got truncated or length is bogus */ - - if (code == (inbound? CONFACK: CONFREQ)) { - /* - * sent confreq or received confack: - * calculate the crc of the data from the ID field on. - */ - fcs = PPP_INITFCS; - for (i = 1; i < dlen; ++i) - fcs = PPP_FCS(fcs, data[i]); - - if (!inbound) { - /* outbound confreq - remember the crc for later */ - ap->lcp_fcs = fcs; - return; - } - - /* received confack, check the crc */ - fcs ^= ap->lcp_fcs; - ap->lcp_fcs = -1; - if (fcs != 0) - return; - } else if (inbound) - return; /* not interested in received confreq */ - - /* process the options in the confack */ - data += 4; - dlen -= 4; - /* data[0] is code, data[1] is length */ - while (dlen >= 2 && dlen >= data[1] && data[1] >= 2) { - switch (data[0]) { - case LCP_MRU: - val = get_unaligned_be16(data + 2); - if (inbound) - ap->mru = val; - else - ap->chan.mtu = val; - break; - case LCP_ASYNCMAP: - val = get_unaligned_be32(data + 2); - if (inbound) - ap->raccm = val; - else - ap->xaccm[0] = val; - break; - } - dlen -= data[1]; - data += data[1]; - } -} - -static void __exit ppp_async_cleanup(void) -{ - if (tty_unregister_ldisc(N_PPP) != 0) - printk(KERN_ERR "failed to unregister PPP line discipline\n"); -} - -module_init(ppp_async_init); -module_exit(ppp_async_cleanup); diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c deleted file mode 100644 index 1dbdf82..0000000 --- a/drivers/net/ppp_deflate.c +++ /dev/null @@ -1,653 +0,0 @@ -/* - * ==FILEVERSION 980319== - * - * ppp_deflate.c - interface the zlib procedures for Deflate compression - * and decompression (as used by gzip) to the PPP code. - * This version is for use with Linux kernel 1.3.X. - * - * Copyright (c) 1994 The Australian National University. - * All rights reserved. - * - * Permission to use, copy, modify, and distribute this software and its - * documentation is hereby granted, provided that the above copyright - * notice appears in all copies. This software is provided without any - * warranty, express or implied. The Australian National University - * makes no representations about the suitability of this software for - * any purpose. - * - * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY - * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF - * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO - * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, - * OR MODIFICATIONS. - * - * From: deflate.c,v 1.1 1996/01/18 03:17:48 paulus Exp - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -/* - * State for a Deflate (de)compressor. - */ -struct ppp_deflate_state { - int seqno; - int w_size; - int unit; - int mru; - int debug; - z_stream strm; - struct compstat stats; -}; - -#define DEFLATE_OVHD 2 /* Deflate overhead/packet */ - -static void *z_comp_alloc(unsigned char *options, int opt_len); -static void *z_decomp_alloc(unsigned char *options, int opt_len); -static void z_comp_free(void *state); -static void z_decomp_free(void *state); -static int z_comp_init(void *state, unsigned char *options, - int opt_len, - int unit, int hdrlen, int debug); -static int z_decomp_init(void *state, unsigned char *options, - int opt_len, - int unit, int hdrlen, int mru, int debug); -static int z_compress(void *state, unsigned char *rptr, - unsigned char *obuf, - int isize, int osize); -static void z_incomp(void *state, unsigned char *ibuf, int icnt); -static int z_decompress(void *state, unsigned char *ibuf, - int isize, unsigned char *obuf, int osize); -static void z_comp_reset(void *state); -static void z_decomp_reset(void *state); -static void z_comp_stats(void *state, struct compstat *stats); - -/** - * z_comp_free - free the memory used by a compressor - * @arg: pointer to the private state for the compressor. - */ -static void z_comp_free(void *arg) -{ - struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; - - if (state) { - zlib_deflateEnd(&state->strm); - vfree(state->strm.workspace); - kfree(state); - } -} - -/** - * z_comp_alloc - allocate space for a compressor. - * @options: pointer to CCP option data - * @opt_len: length of the CCP option at @options. - * - * The @options pointer points to the a buffer containing the - * CCP option data for the compression being negotiated. It is - * formatted according to RFC1979, and describes the window - * size that the peer is requesting that we use in compressing - * data to be sent to it. - * - * Returns the pointer to the private state for the compressor, - * or NULL if we could not allocate enough memory. - */ -static void *z_comp_alloc(unsigned char *options, int opt_len) -{ - struct ppp_deflate_state *state; - int w_size; - - 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) - return NULL; - w_size = DEFLATE_SIZE(options[2]); - if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) - return NULL; - - state = kzalloc(sizeof(*state), - GFP_KERNEL); - if (state == NULL) - return NULL; - - state->strm.next_in = NULL; - state->w_size = w_size; - state->strm.workspace = vmalloc(zlib_deflate_workspacesize(-w_size, 8)); - if (state->strm.workspace == NULL) - goto out_free; - - if (zlib_deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION, - DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY) - != Z_OK) - goto out_free; - return (void *) state; - -out_free: - z_comp_free(state); - return NULL; -} - -/** - * z_comp_init - initialize a previously-allocated compressor. - * @arg: pointer to the private state for the compressor - * @options: pointer to the CCP option data describing the - * compression that was negotiated with the peer - * @opt_len: length of the CCP option data at @options - * @unit: PPP unit number for diagnostic messages - * @hdrlen: ignored (present for backwards compatibility) - * @debug: debug flag; if non-zero, debug messages are printed. - * - * The CCP options described by @options must match the options - * specified when the compressor was allocated. The compressor - * history is reset. Returns 0 for failure (CCP options don't - * match) or 1 for success. - */ -static int z_comp_init(void *arg, unsigned char *options, int opt_len, - int unit, int hdrlen, int debug) -{ - struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; - - 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 || - options[3] != DEFLATE_CHK_SEQUENCE) - return 0; - - state->seqno = 0; - state->unit = unit; - state->debug = debug; - - zlib_deflateReset(&state->strm); - - return 1; -} - -/** - * z_comp_reset - reset a previously-allocated compressor. - * @arg: pointer to private state for the compressor. - * - * This clears the history for the compressor and makes it - * ready to start emitting a new compressed stream. - */ -static void z_comp_reset(void *arg) -{ - struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; - - state->seqno = 0; - zlib_deflateReset(&state->strm); -} - -/** - * z_compress - compress a PPP packet with Deflate compression. - * @arg: pointer to private state for the compressor - * @rptr: uncompressed packet (input) - * @obuf: compressed packet (output) - * @isize: size of uncompressed packet - * @osize: space available at @obuf - * - * Returns the length of the compressed packet, or 0 if the - * packet is incompressible. - */ -static int z_compress(void *arg, unsigned char *rptr, unsigned char *obuf, - int isize, int osize) -{ - struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; - int r, proto, off, olen, oavail; - unsigned char *wptr; - - /* - * Check that the protocol is in the range we handle. - */ - proto = PPP_PROTOCOL(rptr); - if (proto > 0x3fff || proto == 0xfd || proto == 0xfb) - return 0; - - /* Don't generate compressed packets which are larger than - the uncompressed packet. */ - if (osize > isize) - osize = isize; - - wptr = obuf; - - /* - * Copy over the PPP header and store the 2-byte sequence number. - */ - wptr[0] = PPP_ADDRESS(rptr); - wptr[1] = PPP_CONTROL(rptr); - put_unaligned_be16(PPP_COMP, wptr + 2); - wptr += PPP_HDRLEN; - put_unaligned_be16(state->seqno, wptr); - wptr += DEFLATE_OVHD; - olen = PPP_HDRLEN + DEFLATE_OVHD; - state->strm.next_out = wptr; - state->strm.avail_out = oavail = osize - olen; - ++state->seqno; - - off = (proto > 0xff) ? 2 : 3; /* skip 1st proto byte if 0 */ - rptr += off; - state->strm.next_in = rptr; - state->strm.avail_in = (isize - off); - - for (;;) { - r = zlib_deflate(&state->strm, Z_PACKET_FLUSH); - if (r != Z_OK) { - if (state->debug) - printk(KERN_ERR - "z_compress: deflate returned %d\n", r); - break; - } - if (state->strm.avail_out == 0) { - olen += oavail; - state->strm.next_out = NULL; - state->strm.avail_out = oavail = 1000000; - } else { - break; /* all done */ - } - } - olen += oavail - state->strm.avail_out; - - /* - * See if we managed to reduce the size of the packet. - */ - if (olen < isize) { - state->stats.comp_bytes += olen; - state->stats.comp_packets++; - } else { - state->stats.inc_bytes += isize; - state->stats.inc_packets++; - olen = 0; - } - state->stats.unc_bytes += isize; - state->stats.unc_packets++; - - return olen; -} - -/** - * z_comp_stats - return compression statistics for a compressor - * or decompressor. - * @arg: pointer to private space for the (de)compressor - * @stats: pointer to a struct compstat to receive the result. - */ -static void z_comp_stats(void *arg, struct compstat *stats) -{ - struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; - - *stats = state->stats; -} - -/** - * z_decomp_free - Free the memory used by a decompressor. - * @arg: pointer to private space for the decompressor. - */ -static void z_decomp_free(void *arg) -{ - struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; - - if (state) { - zlib_inflateEnd(&state->strm); - vfree(state->strm.workspace); - kfree(state); - } -} - -/** - * z_decomp_alloc - allocate space for a decompressor. - * @options: pointer to CCP option data - * @opt_len: length of the CCP option at @options. - * - * The @options pointer points to the a buffer containing the - * CCP option data for the compression being negotiated. It is - * formatted according to RFC1979, and describes the window - * size that we are requesting the peer to use in compressing - * data to be sent to us. - * - * Returns the pointer to the private state for the decompressor, - * or NULL if we could not allocate enough memory. - */ -static void *z_decomp_alloc(unsigned char *options, int opt_len) -{ - struct ppp_deflate_state *state; - int w_size; - - 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) - return NULL; - w_size = DEFLATE_SIZE(options[2]); - if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) - return NULL; - - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (state == NULL) - return NULL; - - state->w_size = w_size; - state->strm.next_out = NULL; - state->strm.workspace = vmalloc(zlib_inflate_workspacesize()); - if (state->strm.workspace == NULL) - goto out_free; - - if (zlib_inflateInit2(&state->strm, -w_size) != Z_OK) - goto out_free; - return (void *) state; - -out_free: - z_decomp_free(state); - return NULL; -} - -/** - * z_decomp_init - initialize a previously-allocated decompressor. - * @arg: pointer to the private state for the decompressor - * @options: pointer to the CCP option data describing the - * compression that was negotiated with the peer - * @opt_len: length of the CCP option data at @options - * @unit: PPP unit number for diagnostic messages - * @hdrlen: ignored (present for backwards compatibility) - * @mru: maximum length of decompressed packets - * @debug: debug flag; if non-zero, debug messages are printed. - * - * The CCP options described by @options must match the options - * specified when the decompressor was allocated. The decompressor - * history is reset. Returns 0 for failure (CCP options don't - * match) or 1 for success. - */ -static int z_decomp_init(void *arg, unsigned char *options, int opt_len, - int unit, int hdrlen, int mru, int debug) -{ - struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; - - 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 || - options[3] != DEFLATE_CHK_SEQUENCE) - return 0; - - state->seqno = 0; - state->unit = unit; - state->debug = debug; - state->mru = mru; - - zlib_inflateReset(&state->strm); - - return 1; -} - -/** - * z_decomp_reset - reset a previously-allocated decompressor. - * @arg: pointer to private state for the decompressor. - * - * This clears the history for the decompressor and makes it - * ready to receive a new compressed stream. - */ -static void z_decomp_reset(void *arg) -{ - struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; - - state->seqno = 0; - zlib_inflateReset(&state->strm); -} - -/** - * z_decompress - decompress a Deflate-compressed packet. - * @arg: pointer to private state for the decompressor - * @ibuf: pointer to input (compressed) packet data - * @isize: length of input packet - * @obuf: pointer to space for output (decompressed) packet - * @osize: amount of space available at @obuf - * - * Because of patent problems, we return DECOMP_ERROR for errors - * found by inspecting the input data and for system problems, but - * DECOMP_FATALERROR for any errors which could possibly be said to - * be being detected "after" decompression. For DECOMP_ERROR, - * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be - * infringing a patent of Motorola's if we do, so we take CCP down - * instead. - * - * Given that the frame has the correct sequence number and a good FCS, - * errors such as invalid codes in the input most likely indicate a - * bug, so we return DECOMP_FATALERROR for them in order to turn off - * compression, even though they are detected by inspecting the input. - */ -static int z_decompress(void *arg, unsigned char *ibuf, int isize, - unsigned char *obuf, int osize) -{ - struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; - int olen, seq, r; - int decode_proto, overflow; - unsigned char overflow_buf[1]; - - if (isize <= PPP_HDRLEN + DEFLATE_OVHD) { - if (state->debug) - printk(KERN_DEBUG "z_decompress%d: short pkt (%d)\n", - state->unit, isize); - return DECOMP_ERROR; - } - - /* Check the sequence number. */ - seq = get_unaligned_be16(ibuf + PPP_HDRLEN); - if (seq != (state->seqno & 0xffff)) { - if (state->debug) - printk(KERN_DEBUG "z_decompress%d: bad seq # %d, expected %d\n", - state->unit, seq, state->seqno & 0xffff); - return DECOMP_ERROR; - } - ++state->seqno; - - /* - * Fill in the first part of the PPP header. The protocol field - * comes from the decompressed data. - */ - obuf[0] = PPP_ADDRESS(ibuf); - obuf[1] = PPP_CONTROL(ibuf); - obuf[2] = 0; - - /* - * Set up to call inflate. We set avail_out to 1 initially so we can - * look at the first byte of the output and decide whether we have - * a 1-byte or 2-byte protocol field. - */ - state->strm.next_in = ibuf + PPP_HDRLEN + DEFLATE_OVHD; - state->strm.avail_in = isize - (PPP_HDRLEN + DEFLATE_OVHD); - state->strm.next_out = obuf + 3; - state->strm.avail_out = 1; - decode_proto = 1; - overflow = 0; - - /* - * Call inflate, supplying more input or output as needed. - */ - for (;;) { - r = zlib_inflate(&state->strm, Z_PACKET_FLUSH); - if (r != Z_OK) { - if (state->debug) - printk(KERN_DEBUG "z_decompress%d: inflate returned %d (%s)\n", - state->unit, r, (state->strm.msg? state->strm.msg: "")); - return DECOMP_FATALERROR; - } - if (state->strm.avail_out != 0) - break; /* all done */ - if (decode_proto) { - state->strm.avail_out = osize - PPP_HDRLEN; - if ((obuf[3] & 1) == 0) { - /* 2-byte protocol field */ - obuf[2] = obuf[3]; - --state->strm.next_out; - ++state->strm.avail_out; - } - decode_proto = 0; - } else if (!overflow) { - /* - * We've filled up the output buffer; the only way to - * find out whether inflate has any more characters - * left is to give it another byte of output space. - */ - state->strm.next_out = overflow_buf; - state->strm.avail_out = 1; - overflow = 1; - } else { - if (state->debug) - printk(KERN_DEBUG "z_decompress%d: ran out of mru\n", - state->unit); - return DECOMP_FATALERROR; - } - } - - 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; - state->stats.unc_packets++; - state->stats.comp_bytes += isize; - state->stats.comp_packets++; - - return olen; -} - -/** - * z_incomp - add incompressible input data to the history. - * @arg: pointer to private state for the decompressor - * @ibuf: pointer to input packet data - * @icnt: length of input data. - */ -static void z_incomp(void *arg, unsigned char *ibuf, int icnt) -{ - struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; - int proto, r; - - /* - * Check that the protocol is one we handle. - */ - proto = PPP_PROTOCOL(ibuf); - if (proto > 0x3fff || proto == 0xfd || proto == 0xfb) - return; - - ++state->seqno; - - /* - * We start at the either the 1st or 2nd byte of the protocol field, - * depending on whether the protocol value is compressible. - */ - state->strm.next_in = ibuf + 3; - state->strm.avail_in = icnt - 3; - if (proto > 0xff) { - --state->strm.next_in; - ++state->strm.avail_in; - } - - r = zlib_inflateIncomp(&state->strm); - if (r != Z_OK) { - /* gak! */ - if (state->debug) { - printk(KERN_DEBUG "z_incomp%d: inflateIncomp returned %d (%s)\n", - state->unit, r, (state->strm.msg? state->strm.msg: "")); - } - return; - } - - /* - * Update stats. - */ - state->stats.inc_bytes += icnt; - state->stats.inc_packets++; - state->stats.unc_bytes += icnt; - state->stats.unc_packets++; -} - -/************************************************************* - * Module interface table - *************************************************************/ - -/* These are in ppp_generic.c */ -extern int ppp_register_compressor (struct compressor *cp); -extern void ppp_unregister_compressor (struct compressor *cp); - -/* - * Procedures exported to if_ppp.c. - */ -static struct compressor ppp_deflate = { - .compress_proto = CI_DEFLATE, - .comp_alloc = z_comp_alloc, - .comp_free = z_comp_free, - .comp_init = z_comp_init, - .comp_reset = z_comp_reset, - .compress = z_compress, - .comp_stat = z_comp_stats, - .decomp_alloc = z_decomp_alloc, - .decomp_free = z_decomp_free, - .decomp_init = z_decomp_init, - .decomp_reset = z_decomp_reset, - .decompress = z_decompress, - .incomp = z_incomp, - .decomp_stat = z_comp_stats, - .owner = THIS_MODULE -}; - -static struct compressor ppp_deflate_draft = { - .compress_proto = CI_DEFLATE_DRAFT, - .comp_alloc = z_comp_alloc, - .comp_free = z_comp_free, - .comp_init = z_comp_init, - .comp_reset = z_comp_reset, - .compress = z_compress, - .comp_stat = z_comp_stats, - .decomp_alloc = z_decomp_alloc, - .decomp_free = z_decomp_free, - .decomp_init = z_decomp_init, - .decomp_reset = z_decomp_reset, - .decompress = z_decompress, - .incomp = z_incomp, - .decomp_stat = z_comp_stats, - .owner = THIS_MODULE -}; - -static int __init deflate_init(void) -{ - int answer = ppp_register_compressor(&ppp_deflate); - if (answer == 0) - printk(KERN_INFO - "PPP Deflate Compression module registered\n"); - ppp_register_compressor(&ppp_deflate_draft); - return answer; -} - -static void __exit deflate_cleanup(void) -{ - ppp_unregister_compressor(&ppp_deflate); - ppp_unregister_compressor(&ppp_deflate_draft); -} - -module_init(deflate_init); -module_exit(deflate_cleanup); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE)); -MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE_DRAFT)); diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c deleted file mode 100644 index 10e5d98..0000000 --- a/drivers/net/ppp_generic.c +++ /dev/null @@ -1,2954 +0,0 @@ -/* - * Generic PPP layer for Linux. - * - * Copyright 1999-2002 Paul Mackerras. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * The generic PPP layer handles the PPP network interfaces, the - * /dev/ppp device, packet and VJ compression, and multilink. - * It talks to PPP `channels' via the interface defined in - * include/linux/ppp_channel.h. Channels provide the basic means for - * sending and receiving PPP frames on some kind of communications - * channel. - * - * Part of the code in this driver was inspired by the old async-only - * PPP driver, written by Michael Callahan and Al Longyear, and - * subsequently hacked by Paul Mackerras. - * - * ==FILEVERSION 20041108== - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define PPP_VERSION "2.4.2" - -/* - * Network protocols we support. - */ -#define NP_IP 0 /* Internet Protocol V4 */ -#define NP_IPV6 1 /* Internet Protocol V6 */ -#define NP_IPX 2 /* IPX protocol */ -#define NP_AT 3 /* Appletalk protocol */ -#define NP_MPLS_UC 4 /* MPLS unicast */ -#define NP_MPLS_MC 5 /* MPLS multicast */ -#define NUM_NP 6 /* Number of NPs. */ - -#define MPHDRLEN 6 /* multilink protocol header length */ -#define MPHDRLEN_SSN 4 /* ditto with short sequence numbers */ - -/* - * An instance of /dev/ppp can be associated with either a ppp - * interface unit or a ppp channel. In both cases, file->private_data - * points to one of these. - */ -struct ppp_file { - enum { - INTERFACE=1, CHANNEL - } kind; - struct sk_buff_head xq; /* pppd transmit queue */ - struct sk_buff_head rq; /* receive queue for pppd */ - wait_queue_head_t rwait; /* for poll on reading /dev/ppp */ - atomic_t refcnt; /* # refs (incl /dev/ppp attached) */ - int hdrlen; /* space to leave for headers */ - int index; /* interface unit / channel number */ - int dead; /* unit/channel has been shut down */ -}; - -#define PF_TO_X(pf, X) container_of(pf, X, file) - -#define PF_TO_PPP(pf) PF_TO_X(pf, struct ppp) -#define PF_TO_CHANNEL(pf) PF_TO_X(pf, struct channel) - -/* - * Data structure describing one ppp unit. - * A ppp unit corresponds to a ppp network interface device - * and represents a multilink bundle. - * It can have 0 or more ppp channels connected to it. - */ -struct ppp { - struct ppp_file file; /* stuff for read/write/poll 0 */ - struct file *owner; /* file that owns this unit 48 */ - struct list_head channels; /* list of attached channels 4c */ - int n_channels; /* how many channels are attached 54 */ - spinlock_t rlock; /* lock for receive side 58 */ - spinlock_t wlock; /* lock for transmit side 5c */ - int mru; /* max receive unit 60 */ - unsigned int flags; /* control bits 64 */ - unsigned int xstate; /* transmit state bits 68 */ - unsigned int rstate; /* receive state bits 6c */ - int debug; /* debug flags 70 */ - struct slcompress *vj; /* state for VJ header compression */ - enum NPmode npmode[NUM_NP]; /* what to do with each net proto 78 */ - struct sk_buff *xmit_pending; /* a packet ready to go out 88 */ - struct compressor *xcomp; /* transmit packet compressor 8c */ - void *xc_state; /* its internal state 90 */ - struct compressor *rcomp; /* receive decompressor 94 */ - void *rc_state; /* its internal state 98 */ - unsigned long last_xmit; /* jiffies when last pkt sent 9c */ - unsigned long last_recv; /* jiffies when last pkt rcvd a0 */ - struct net_device *dev; /* network interface device a4 */ - int closing; /* is device closing down? a8 */ -#ifdef CONFIG_PPP_MULTILINK - int nxchan; /* next channel to send something on */ - u32 nxseq; /* next sequence number to send */ - int mrru; /* MP: max reconst. receive unit */ - u32 nextseq; /* MP: seq no of next packet */ - u32 minseq; /* MP: min of most recent seqnos */ - struct sk_buff_head mrq; /* MP: receive reconstruction queue */ -#endif /* CONFIG_PPP_MULTILINK */ -#ifdef CONFIG_PPP_FILTER - struct sock_filter *pass_filter; /* filter for packets to pass */ - struct sock_filter *active_filter;/* filter for pkts to reset idle */ - unsigned pass_len, active_len; -#endif /* CONFIG_PPP_FILTER */ - struct net *ppp_net; /* the net we belong to */ -}; - -/* - * Bits in flags: SC_NO_TCP_CCID, SC_CCP_OPEN, SC_CCP_UP, SC_LOOP_TRAFFIC, - * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP, - * SC_MUST_COMP - * Bits in rstate: SC_DECOMP_RUN, SC_DC_ERROR, SC_DC_FERROR. - * Bits in xstate: SC_COMP_RUN - */ -#define SC_FLAG_BITS (SC_NO_TCP_CCID|SC_CCP_OPEN|SC_CCP_UP|SC_LOOP_TRAFFIC \ - |SC_MULTILINK|SC_MP_SHORTSEQ|SC_MP_XSHORTSEQ \ - |SC_COMP_TCP|SC_REJ_COMP_TCP|SC_MUST_COMP) - -/* - * Private data structure for each channel. - * This includes the data structure used for multilink. - */ -struct channel { - struct ppp_file file; /* stuff for read/write/poll */ - struct list_head list; /* link in all/new_channels list */ - struct ppp_channel *chan; /* public channel data structure */ - struct rw_semaphore chan_sem; /* protects `chan' during chan ioctl */ - spinlock_t downl; /* protects `chan', file.xq dequeue */ - struct ppp *ppp; /* ppp unit we're connected to */ - struct net *chan_net; /* the net channel belongs to */ - struct list_head clist; /* link in list of channels per unit */ - rwlock_t upl; /* protects `ppp' */ -#ifdef CONFIG_PPP_MULTILINK - u8 avail; /* flag used in multilink stuff */ - u8 had_frag; /* >= 1 fragments have been sent */ - u32 lastseq; /* MP: last sequence # received */ - int speed; /* speed of the corresponding ppp channel*/ -#endif /* CONFIG_PPP_MULTILINK */ -}; - -/* - * SMP locking issues: - * Both the ppp.rlock and ppp.wlock locks protect the ppp.channels - * list and the ppp.n_channels field, you need to take both locks - * before you modify them. - * The lock ordering is: channel.upl -> ppp.wlock -> ppp.rlock -> - * channel.downl. - */ - -static DEFINE_MUTEX(ppp_mutex); -static atomic_t ppp_unit_count = ATOMIC_INIT(0); -static atomic_t channel_count = ATOMIC_INIT(0); - -/* per-net private data for this module */ -static int ppp_net_id __read_mostly; -struct ppp_net { - /* units to ppp mapping */ - struct idr units_idr; - - /* - * all_ppp_mutex protects the units_idr mapping. - * It also ensures that finding a ppp unit in the units_idr - * map and updating its file.refcnt field is atomic. - */ - struct mutex all_ppp_mutex; - - /* channels */ - struct list_head all_channels; - struct list_head new_channels; - int last_channel_index; - - /* - * all_channels_lock protects all_channels and - * last_channel_index, and the atomicity of find - * a channel and updating its file.refcnt field. - */ - spinlock_t all_channels_lock; -}; - -/* Get the PPP protocol number from a skb */ -#define PPP_PROTO(skb) get_unaligned_be16((skb)->data) - -/* We limit the length of ppp->file.rq to this (arbitrary) value */ -#define PPP_MAX_RQLEN 32 - -/* - * Maximum number of multilink fragments queued up. - * This has to be large enough to cope with the maximum latency of - * the slowest channel relative to the others. Strictly it should - * depend on the number of channels and their characteristics. - */ -#define PPP_MP_MAX_QLEN 128 - -/* Multilink header bits. */ -#define B 0x80 /* this fragment begins a packet */ -#define E 0x40 /* this fragment ends a packet */ - -/* Compare multilink sequence numbers (assumed to be 32 bits wide) */ -#define seq_before(a, b) ((s32)((a) - (b)) < 0) -#define seq_after(a, b) ((s32)((a) - (b)) > 0) - -/* Prototypes. */ -static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, - struct file *file, unsigned int cmd, unsigned long arg); -static void ppp_xmit_process(struct ppp *ppp); -static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb); -static void ppp_push(struct ppp *ppp); -static void ppp_channel_push(struct channel *pch); -static void ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, - struct channel *pch); -static void ppp_receive_error(struct ppp *ppp); -static void ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb); -static struct sk_buff *ppp_decompress_frame(struct ppp *ppp, - struct sk_buff *skb); -#ifdef CONFIG_PPP_MULTILINK -static void ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, - struct channel *pch); -static void ppp_mp_insert(struct ppp *ppp, struct sk_buff *skb); -static struct sk_buff *ppp_mp_reconstruct(struct ppp *ppp); -static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb); -#endif /* CONFIG_PPP_MULTILINK */ -static int ppp_set_compress(struct ppp *ppp, unsigned long arg); -static void ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound); -static void ppp_ccp_closed(struct ppp *ppp); -static struct compressor *find_compressor(int type); -static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st); -static struct ppp *ppp_create_interface(struct net *net, int unit, int *retp); -static void init_ppp_file(struct ppp_file *pf, int kind); -static void ppp_shutdown_interface(struct ppp *ppp); -static void ppp_destroy_interface(struct ppp *ppp); -static struct ppp *ppp_find_unit(struct ppp_net *pn, int unit); -static struct channel *ppp_find_channel(struct ppp_net *pn, int unit); -static int ppp_connect_channel(struct channel *pch, int unit); -static int ppp_disconnect_channel(struct channel *pch); -static void ppp_destroy_channel(struct channel *pch); -static int unit_get(struct idr *p, void *ptr); -static int unit_set(struct idr *p, void *ptr, int n); -static void unit_put(struct idr *p, int n); -static void *unit_find(struct idr *p, int n); - -static struct class *ppp_class; - -/* per net-namespace data */ -static inline struct ppp_net *ppp_pernet(struct net *net) -{ - BUG_ON(!net); - - return net_generic(net, ppp_net_id); -} - -/* Translates a PPP protocol number to a NP index (NP == network protocol) */ -static inline int proto_to_npindex(int proto) -{ - switch (proto) { - case PPP_IP: - return NP_IP; - case PPP_IPV6: - return NP_IPV6; - case PPP_IPX: - return NP_IPX; - case PPP_AT: - return NP_AT; - case PPP_MPLS_UC: - return NP_MPLS_UC; - case PPP_MPLS_MC: - return NP_MPLS_MC; - } - return -EINVAL; -} - -/* Translates an NP index into a PPP protocol number */ -static const int npindex_to_proto[NUM_NP] = { - PPP_IP, - PPP_IPV6, - PPP_IPX, - PPP_AT, - PPP_MPLS_UC, - PPP_MPLS_MC, -}; - -/* Translates an ethertype into an NP index */ -static inline int ethertype_to_npindex(int ethertype) -{ - switch (ethertype) { - case ETH_P_IP: - return NP_IP; - case ETH_P_IPV6: - return NP_IPV6; - case ETH_P_IPX: - return NP_IPX; - case ETH_P_PPPTALK: - case ETH_P_ATALK: - return NP_AT; - case ETH_P_MPLS_UC: - return NP_MPLS_UC; - case ETH_P_MPLS_MC: - return NP_MPLS_MC; - } - return -1; -} - -/* Translates an NP index into an ethertype */ -static const int npindex_to_ethertype[NUM_NP] = { - ETH_P_IP, - ETH_P_IPV6, - ETH_P_IPX, - ETH_P_PPPTALK, - ETH_P_MPLS_UC, - ETH_P_MPLS_MC, -}; - -/* - * Locking shorthand. - */ -#define ppp_xmit_lock(ppp) spin_lock_bh(&(ppp)->wlock) -#define ppp_xmit_unlock(ppp) spin_unlock_bh(&(ppp)->wlock) -#define ppp_recv_lock(ppp) spin_lock_bh(&(ppp)->rlock) -#define ppp_recv_unlock(ppp) spin_unlock_bh(&(ppp)->rlock) -#define ppp_lock(ppp) do { ppp_xmit_lock(ppp); \ - ppp_recv_lock(ppp); } while (0) -#define ppp_unlock(ppp) do { ppp_recv_unlock(ppp); \ - ppp_xmit_unlock(ppp); } while (0) - -/* - * /dev/ppp device routines. - * The /dev/ppp device is used by pppd to control the ppp unit. - * It supports the read, write, ioctl and poll functions. - * Open instances of /dev/ppp can be in one of three states: - * unattached, attached to a ppp unit, or attached to a ppp channel. - */ -static int ppp_open(struct inode *inode, struct file *file) -{ - /* - * This could (should?) be enforced by the permissions on /dev/ppp. - */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - return 0; -} - -static int ppp_release(struct inode *unused, struct file *file) -{ - struct ppp_file *pf = file->private_data; - struct ppp *ppp; - - if (pf) { - file->private_data = NULL; - if (pf->kind == INTERFACE) { - ppp = PF_TO_PPP(pf); - if (file == ppp->owner) - ppp_shutdown_interface(ppp); - } - if (atomic_dec_and_test(&pf->refcnt)) { - switch (pf->kind) { - case INTERFACE: - ppp_destroy_interface(PF_TO_PPP(pf)); - break; - case CHANNEL: - ppp_destroy_channel(PF_TO_CHANNEL(pf)); - break; - } - } - } - return 0; -} - -static ssize_t ppp_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct ppp_file *pf = file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - struct sk_buff *skb = NULL; - struct iovec iov; - - ret = count; - - if (!pf) - return -ENXIO; - add_wait_queue(&pf->rwait, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - skb = skb_dequeue(&pf->rq); - if (skb) - break; - ret = 0; - if (pf->dead) - break; - if (pf->kind == INTERFACE) { - /* - * Return 0 (EOF) on an interface that has no - * channels connected, unless it is looping - * network traffic (demand mode). - */ - struct ppp *ppp = PF_TO_PPP(pf); - if (ppp->n_channels == 0 && - (ppp->flags & SC_LOOP_TRAFFIC) == 0) - break; - } - ret = -EAGAIN; - if (file->f_flags & O_NONBLOCK) - break; - ret = -ERESTARTSYS; - if (signal_pending(current)) - break; - schedule(); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&pf->rwait, &wait); - - if (!skb) - goto out; - - ret = -EOVERFLOW; - if (skb->len > count) - goto outf; - ret = -EFAULT; - iov.iov_base = buf; - iov.iov_len = count; - if (skb_copy_datagram_iovec(skb, 0, &iov, skb->len)) - goto outf; - ret = skb->len; - - outf: - kfree_skb(skb); - out: - return ret; -} - -static ssize_t ppp_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct ppp_file *pf = file->private_data; - struct sk_buff *skb; - ssize_t ret; - - if (!pf) - return -ENXIO; - ret = -ENOMEM; - skb = alloc_skb(count + pf->hdrlen, GFP_KERNEL); - if (!skb) - goto out; - skb_reserve(skb, pf->hdrlen); - ret = -EFAULT; - if (copy_from_user(skb_put(skb, count), buf, count)) { - kfree_skb(skb); - goto out; - } - - skb_queue_tail(&pf->xq, skb); - - switch (pf->kind) { - case INTERFACE: - ppp_xmit_process(PF_TO_PPP(pf)); - break; - case CHANNEL: - ppp_channel_push(PF_TO_CHANNEL(pf)); - break; - } - - ret = count; - - out: - return ret; -} - -/* No kernel lock - fine */ -static unsigned int ppp_poll(struct file *file, poll_table *wait) -{ - struct ppp_file *pf = file->private_data; - unsigned int mask; - - if (!pf) - return 0; - poll_wait(file, &pf->rwait, wait); - mask = POLLOUT | POLLWRNORM; - if (skb_peek(&pf->rq)) - mask |= POLLIN | POLLRDNORM; - if (pf->dead) - mask |= POLLHUP; - else if (pf->kind == INTERFACE) { - /* see comment in ppp_read */ - struct ppp *ppp = PF_TO_PPP(pf); - if (ppp->n_channels == 0 && - (ppp->flags & SC_LOOP_TRAFFIC) == 0) - mask |= POLLIN | POLLRDNORM; - } - - return mask; -} - -#ifdef CONFIG_PPP_FILTER -static int get_filter(void __user *arg, struct sock_filter **p) -{ - struct sock_fprog uprog; - struct sock_filter *code = NULL; - int len, err; - - if (copy_from_user(&uprog, arg, sizeof(uprog))) - return -EFAULT; - - if (!uprog.len) { - *p = NULL; - return 0; - } - - len = uprog.len * sizeof(struct sock_filter); - code = memdup_user(uprog.filter, len); - if (IS_ERR(code)) - return PTR_ERR(code); - - err = sk_chk_filter(code, uprog.len); - if (err) { - kfree(code); - return err; - } - - *p = code; - return uprog.len; -} -#endif /* CONFIG_PPP_FILTER */ - -static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct ppp_file *pf = file->private_data; - struct ppp *ppp; - int err = -EFAULT, val, val2, i; - struct ppp_idle idle; - struct npioctl npi; - int unit, cflags; - struct slcompress *vj; - void __user *argp = (void __user *)arg; - int __user *p = argp; - - if (!pf) - return ppp_unattached_ioctl(current->nsproxy->net_ns, - pf, file, cmd, arg); - - if (cmd == PPPIOCDETACH) { - /* - * We have to be careful here... if the file descriptor - * has been dup'd, we could have another process in the - * middle of a poll using the same file *, so we had - * better not free the interface data structures - - * instead we fail the ioctl. Even in this case, we - * shut down the interface if we are the owner of it. - * Actually, we should get rid of PPPIOCDETACH, userland - * (i.e. pppd) could achieve the same effect by closing - * this fd and reopening /dev/ppp. - */ - err = -EINVAL; - mutex_lock(&ppp_mutex); - if (pf->kind == INTERFACE) { - ppp = PF_TO_PPP(pf); - if (file == ppp->owner) - ppp_shutdown_interface(ppp); - } - if (atomic_long_read(&file->f_count) <= 2) { - ppp_release(NULL, file); - err = 0; - } else - pr_warn("PPPIOCDETACH file->f_count=%ld\n", - atomic_long_read(&file->f_count)); - mutex_unlock(&ppp_mutex); - return err; - } - - if (pf->kind == CHANNEL) { - struct channel *pch; - struct ppp_channel *chan; - - mutex_lock(&ppp_mutex); - pch = PF_TO_CHANNEL(pf); - - switch (cmd) { - case PPPIOCCONNECT: - if (get_user(unit, p)) - break; - err = ppp_connect_channel(pch, unit); - break; - - case PPPIOCDISCONN: - err = ppp_disconnect_channel(pch); - break; - - default: - down_read(&pch->chan_sem); - chan = pch->chan; - err = -ENOTTY; - if (chan && chan->ops->ioctl) - err = chan->ops->ioctl(chan, cmd, arg); - up_read(&pch->chan_sem); - } - mutex_unlock(&ppp_mutex); - return err; - } - - if (pf->kind != INTERFACE) { - /* can't happen */ - pr_err("PPP: not interface or channel??\n"); - return -EINVAL; - } - - mutex_lock(&ppp_mutex); - ppp = PF_TO_PPP(pf); - switch (cmd) { - case PPPIOCSMRU: - if (get_user(val, p)) - break; - ppp->mru = val; - err = 0; - break; - - case PPPIOCSFLAGS: - if (get_user(val, p)) - break; - ppp_lock(ppp); - cflags = ppp->flags & ~val; - ppp->flags = val & SC_FLAG_BITS; - ppp_unlock(ppp); - if (cflags & SC_CCP_OPEN) - ppp_ccp_closed(ppp); - err = 0; - break; - - case PPPIOCGFLAGS: - val = ppp->flags | ppp->xstate | ppp->rstate; - if (put_user(val, p)) - break; - err = 0; - break; - - case PPPIOCSCOMPRESS: - err = ppp_set_compress(ppp, arg); - break; - - case PPPIOCGUNIT: - if (put_user(ppp->file.index, p)) - break; - err = 0; - break; - - case PPPIOCSDEBUG: - if (get_user(val, p)) - break; - ppp->debug = val; - err = 0; - break; - - case PPPIOCGDEBUG: - if (put_user(ppp->debug, p)) - break; - err = 0; - break; - - case PPPIOCGIDLE: - idle.xmit_idle = (jiffies - ppp->last_xmit) / HZ; - idle.recv_idle = (jiffies - ppp->last_recv) / HZ; - if (copy_to_user(argp, &idle, sizeof(idle))) - break; - err = 0; - break; - - case PPPIOCSMAXCID: - if (get_user(val, p)) - break; - val2 = 15; - if ((val >> 16) != 0) { - val2 = val >> 16; - val &= 0xffff; - } - vj = slhc_init(val2+1, val+1); - if (!vj) { - netdev_err(ppp->dev, - "PPP: no memory (VJ compressor)\n"); - err = -ENOMEM; - break; - } - ppp_lock(ppp); - if (ppp->vj) - slhc_free(ppp->vj); - ppp->vj = vj; - ppp_unlock(ppp); - err = 0; - break; - - case PPPIOCGNPMODE: - case PPPIOCSNPMODE: - if (copy_from_user(&npi, argp, sizeof(npi))) - break; - err = proto_to_npindex(npi.protocol); - if (err < 0) - break; - i = err; - if (cmd == PPPIOCGNPMODE) { - err = -EFAULT; - npi.mode = ppp->npmode[i]; - if (copy_to_user(argp, &npi, sizeof(npi))) - break; - } else { - ppp->npmode[i] = npi.mode; - /* we may be able to transmit more packets now (??) */ - netif_wake_queue(ppp->dev); - } - err = 0; - break; - -#ifdef CONFIG_PPP_FILTER - case PPPIOCSPASS: - { - struct sock_filter *code; - err = get_filter(argp, &code); - if (err >= 0) { - ppp_lock(ppp); - kfree(ppp->pass_filter); - ppp->pass_filter = code; - ppp->pass_len = err; - ppp_unlock(ppp); - err = 0; - } - break; - } - case PPPIOCSACTIVE: - { - struct sock_filter *code; - err = get_filter(argp, &code); - if (err >= 0) { - ppp_lock(ppp); - kfree(ppp->active_filter); - ppp->active_filter = code; - ppp->active_len = err; - ppp_unlock(ppp); - err = 0; - } - break; - } -#endif /* CONFIG_PPP_FILTER */ - -#ifdef CONFIG_PPP_MULTILINK - case PPPIOCSMRRU: - if (get_user(val, p)) - break; - ppp_recv_lock(ppp); - ppp->mrru = val; - ppp_recv_unlock(ppp); - err = 0; - break; -#endif /* CONFIG_PPP_MULTILINK */ - - default: - err = -ENOTTY; - } - mutex_unlock(&ppp_mutex); - return err; -} - -static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, - struct file *file, unsigned int cmd, unsigned long arg) -{ - int unit, err = -EFAULT; - struct ppp *ppp; - struct channel *chan; - struct ppp_net *pn; - int __user *p = (int __user *)arg; - - mutex_lock(&ppp_mutex); - switch (cmd) { - case PPPIOCNEWUNIT: - /* Create a new ppp unit */ - if (get_user(unit, p)) - break; - ppp = ppp_create_interface(net, unit, &err); - if (!ppp) - break; - file->private_data = &ppp->file; - ppp->owner = file; - err = -EFAULT; - if (put_user(ppp->file.index, p)) - break; - err = 0; - break; - - case PPPIOCATTACH: - /* Attach to an existing ppp unit */ - if (get_user(unit, p)) - break; - err = -ENXIO; - pn = ppp_pernet(net); - mutex_lock(&pn->all_ppp_mutex); - ppp = ppp_find_unit(pn, unit); - if (ppp) { - atomic_inc(&ppp->file.refcnt); - file->private_data = &ppp->file; - err = 0; - } - mutex_unlock(&pn->all_ppp_mutex); - break; - - case PPPIOCATTCHAN: - if (get_user(unit, p)) - break; - err = -ENXIO; - pn = ppp_pernet(net); - spin_lock_bh(&pn->all_channels_lock); - chan = ppp_find_channel(pn, unit); - if (chan) { - atomic_inc(&chan->file.refcnt); - file->private_data = &chan->file; - err = 0; - } - spin_unlock_bh(&pn->all_channels_lock); - break; - - default: - err = -ENOTTY; - } - mutex_unlock(&ppp_mutex); - return err; -} - -static const struct file_operations ppp_device_fops = { - .owner = THIS_MODULE, - .read = ppp_read, - .write = ppp_write, - .poll = ppp_poll, - .unlocked_ioctl = ppp_ioctl, - .open = ppp_open, - .release = ppp_release, - .llseek = noop_llseek, -}; - -static __net_init int ppp_init_net(struct net *net) -{ - struct ppp_net *pn = net_generic(net, ppp_net_id); - - idr_init(&pn->units_idr); - mutex_init(&pn->all_ppp_mutex); - - INIT_LIST_HEAD(&pn->all_channels); - INIT_LIST_HEAD(&pn->new_channels); - - spin_lock_init(&pn->all_channels_lock); - - return 0; -} - -static __net_exit void ppp_exit_net(struct net *net) -{ - struct ppp_net *pn = net_generic(net, ppp_net_id); - - idr_destroy(&pn->units_idr); -} - -static struct pernet_operations ppp_net_ops = { - .init = ppp_init_net, - .exit = ppp_exit_net, - .id = &ppp_net_id, - .size = sizeof(struct ppp_net), -}; - -#define PPP_MAJOR 108 - -/* Called at boot time if ppp is compiled into the kernel, - or at module load time (from init_module) if compiled as a module. */ -static int __init ppp_init(void) -{ - int err; - - pr_info("PPP generic driver version " PPP_VERSION "\n"); - - err = register_pernet_device(&ppp_net_ops); - if (err) { - pr_err("failed to register PPP pernet device (%d)\n", err); - goto out; - } - - err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops); - if (err) { - pr_err("failed to register PPP device (%d)\n", err); - goto out_net; - } - - ppp_class = class_create(THIS_MODULE, "ppp"); - if (IS_ERR(ppp_class)) { - err = PTR_ERR(ppp_class); - goto out_chrdev; - } - - /* not a big deal if we fail here :-) */ - device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); - - return 0; - -out_chrdev: - unregister_chrdev(PPP_MAJOR, "ppp"); -out_net: - unregister_pernet_device(&ppp_net_ops); -out: - return err; -} - -/* - * Network interface unit routines. - */ -static netdev_tx_t -ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct ppp *ppp = netdev_priv(dev); - int npi, proto; - unsigned char *pp; - - npi = ethertype_to_npindex(ntohs(skb->protocol)); - if (npi < 0) - goto outf; - - /* Drop, accept or reject the packet */ - switch (ppp->npmode[npi]) { - case NPMODE_PASS: - break; - case NPMODE_QUEUE: - /* it would be nice to have a way to tell the network - system to queue this one up for later. */ - goto outf; - case NPMODE_DROP: - case NPMODE_ERROR: - goto outf; - } - - /* Put the 2-byte PPP protocol number on the front, - making sure there is room for the address and control fields. */ - if (skb_cow_head(skb, PPP_HDRLEN)) - goto outf; - - pp = skb_push(skb, 2); - proto = npindex_to_proto[npi]; - put_unaligned_be16(proto, pp); - - netif_stop_queue(dev); - skb_queue_tail(&ppp->file.xq, skb); - ppp_xmit_process(ppp); - return NETDEV_TX_OK; - - outf: - kfree_skb(skb); - ++dev->stats.tx_dropped; - return NETDEV_TX_OK; -} - -static int -ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct ppp *ppp = netdev_priv(dev); - int err = -EFAULT; - void __user *addr = (void __user *) ifr->ifr_ifru.ifru_data; - struct ppp_stats stats; - struct ppp_comp_stats cstats; - char *vers; - - switch (cmd) { - case SIOCGPPPSTATS: - ppp_get_stats(ppp, &stats); - if (copy_to_user(addr, &stats, sizeof(stats))) - break; - err = 0; - break; - - case SIOCGPPPCSTATS: - memset(&cstats, 0, sizeof(cstats)); - if (ppp->xc_state) - ppp->xcomp->comp_stat(ppp->xc_state, &cstats.c); - if (ppp->rc_state) - ppp->rcomp->decomp_stat(ppp->rc_state, &cstats.d); - if (copy_to_user(addr, &cstats, sizeof(cstats))) - break; - err = 0; - break; - - case SIOCGPPPVER: - vers = PPP_VERSION; - if (copy_to_user(addr, vers, strlen(vers) + 1)) - break; - err = 0; - break; - - default: - err = -EINVAL; - } - - return err; -} - -static const struct net_device_ops ppp_netdev_ops = { - .ndo_start_xmit = ppp_start_xmit, - .ndo_do_ioctl = ppp_net_ioctl, -}; - -static void ppp_setup(struct net_device *dev) -{ - dev->netdev_ops = &ppp_netdev_ops; - dev->hard_header_len = PPP_HDRLEN; - dev->mtu = PPP_MTU; - dev->addr_len = 0; - dev->tx_queue_len = 3; - dev->type = ARPHRD_PPP; - dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; - dev->features |= NETIF_F_NETNS_LOCAL; - dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; -} - -/* - * Transmit-side routines. - */ - -/* - * Called to do any work queued up on the transmit side - * that can now be done. - */ -static void -ppp_xmit_process(struct ppp *ppp) -{ - struct sk_buff *skb; - - ppp_xmit_lock(ppp); - if (!ppp->closing) { - ppp_push(ppp); - while (!ppp->xmit_pending && - (skb = skb_dequeue(&ppp->file.xq))) - ppp_send_frame(ppp, skb); - /* If there's no work left to do, tell the core net - code that we can accept some more. */ - if (!ppp->xmit_pending && !skb_peek(&ppp->file.xq)) - netif_wake_queue(ppp->dev); - } - ppp_xmit_unlock(ppp); -} - -static inline struct sk_buff * -pad_compress_skb(struct ppp *ppp, struct sk_buff *skb) -{ - struct sk_buff *new_skb; - int len; - int new_skb_size = ppp->dev->mtu + - ppp->xcomp->comp_extra + ppp->dev->hard_header_len; - int compressor_skb_size = ppp->dev->mtu + - ppp->xcomp->comp_extra + PPP_HDRLEN; - new_skb = alloc_skb(new_skb_size, GFP_ATOMIC); - if (!new_skb) { - if (net_ratelimit()) - netdev_err(ppp->dev, "PPP: no memory (comp pkt)\n"); - return NULL; - } - if (ppp->dev->hard_header_len > PPP_HDRLEN) - skb_reserve(new_skb, - ppp->dev->hard_header_len - PPP_HDRLEN); - - /* compressor still expects A/C bytes in hdr */ - len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2, - new_skb->data, skb->len + 2, - compressor_skb_size); - if (len > 0 && (ppp->flags & SC_CCP_UP)) { - kfree_skb(skb); - skb = new_skb; - skb_put(skb, len); - skb_pull(skb, 2); /* pull off A/C bytes */ - } else if (len == 0) { - /* didn't compress, or CCP not up yet */ - kfree_skb(new_skb); - new_skb = skb; - } else { - /* - * (len < 0) - * MPPE requires that we do not send unencrypted - * frames. The compressor will return -1 if we - * should drop the frame. We cannot simply test - * the compress_proto because MPPE and MPPC share - * the same number. - */ - if (net_ratelimit()) - netdev_err(ppp->dev, "ppp: compressor dropped pkt\n"); - kfree_skb(skb); - kfree_skb(new_skb); - new_skb = NULL; - } - return new_skb; -} - -/* - * Compress and send a frame. - * The caller should have locked the xmit path, - * and xmit_pending should be 0. - */ -static void -ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) -{ - int proto = PPP_PROTO(skb); - struct sk_buff *new_skb; - int len; - unsigned char *cp; - - if (proto < 0x8000) { -#ifdef CONFIG_PPP_FILTER - /* check if we should pass this packet */ - /* the filter instructions are constructed assuming - a four-byte PPP header on each packet */ - *skb_push(skb, 2) = 1; - if (ppp->pass_filter && - sk_run_filter(skb, ppp->pass_filter) == 0) { - if (ppp->debug & 1) - netdev_printk(KERN_DEBUG, ppp->dev, - "PPP: outbound frame " - "not passed\n"); - kfree_skb(skb); - return; - } - /* if this packet passes the active filter, record the time */ - if (!(ppp->active_filter && - sk_run_filter(skb, ppp->active_filter) == 0)) - ppp->last_xmit = jiffies; - skb_pull(skb, 2); -#else - /* for data packets, record the time */ - ppp->last_xmit = jiffies; -#endif /* CONFIG_PPP_FILTER */ - } - - ++ppp->dev->stats.tx_packets; - ppp->dev->stats.tx_bytes += skb->len - 2; - - switch (proto) { - case PPP_IP: - if (!ppp->vj || (ppp->flags & SC_COMP_TCP) == 0) - break; - /* try to do VJ TCP header compression */ - new_skb = alloc_skb(skb->len + ppp->dev->hard_header_len - 2, - GFP_ATOMIC); - if (!new_skb) { - netdev_err(ppp->dev, "PPP: no memory (VJ comp pkt)\n"); - goto drop; - } - skb_reserve(new_skb, ppp->dev->hard_header_len - 2); - cp = skb->data + 2; - len = slhc_compress(ppp->vj, cp, skb->len - 2, - new_skb->data + 2, &cp, - !(ppp->flags & SC_NO_TCP_CCID)); - if (cp == skb->data + 2) { - /* didn't compress */ - kfree_skb(new_skb); - } else { - if (cp[0] & SL_TYPE_COMPRESSED_TCP) { - proto = PPP_VJC_COMP; - cp[0] &= ~SL_TYPE_COMPRESSED_TCP; - } else { - proto = PPP_VJC_UNCOMP; - cp[0] = skb->data[2]; - } - kfree_skb(skb); - skb = new_skb; - cp = skb_put(skb, len + 2); - cp[0] = 0; - cp[1] = proto; - } - break; - - case PPP_CCP: - /* peek at outbound CCP frames */ - ppp_ccp_peek(ppp, skb, 0); - break; - } - - /* try to do packet compression */ - if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state && - proto != PPP_LCP && proto != PPP_CCP) { - if (!(ppp->flags & SC_CCP_UP) && (ppp->flags & SC_MUST_COMP)) { - if (net_ratelimit()) - netdev_err(ppp->dev, - "ppp: compression required but " - "down - pkt dropped.\n"); - goto drop; - } - skb = pad_compress_skb(ppp, skb); - if (!skb) - goto drop; - } - - /* - * If we are waiting for traffic (demand dialling), - * queue it up for pppd to receive. - */ - if (ppp->flags & SC_LOOP_TRAFFIC) { - if (ppp->file.rq.qlen > PPP_MAX_RQLEN) - goto drop; - skb_queue_tail(&ppp->file.rq, skb); - wake_up_interruptible(&ppp->file.rwait); - return; - } - - ppp->xmit_pending = skb; - ppp_push(ppp); - return; - - drop: - kfree_skb(skb); - ++ppp->dev->stats.tx_errors; -} - -/* - * Try to send the frame in xmit_pending. - * The caller should have the xmit path locked. - */ -static void -ppp_push(struct ppp *ppp) -{ - struct list_head *list; - struct channel *pch; - struct sk_buff *skb = ppp->xmit_pending; - - if (!skb) - return; - - list = &ppp->channels; - if (list_empty(list)) { - /* nowhere to send the packet, just drop it */ - ppp->xmit_pending = NULL; - kfree_skb(skb); - return; - } - - if ((ppp->flags & SC_MULTILINK) == 0) { - /* not doing multilink: send it down the first channel */ - list = list->next; - pch = list_entry(list, struct channel, clist); - - spin_lock_bh(&pch->downl); - if (pch->chan) { - if (pch->chan->ops->start_xmit(pch->chan, skb)) - ppp->xmit_pending = NULL; - } else { - /* channel got unregistered */ - kfree_skb(skb); - ppp->xmit_pending = NULL; - } - spin_unlock_bh(&pch->downl); - return; - } - -#ifdef CONFIG_PPP_MULTILINK - /* Multilink: fragment the packet over as many links - as can take the packet at the moment. */ - if (!ppp_mp_explode(ppp, skb)) - return; -#endif /* CONFIG_PPP_MULTILINK */ - - ppp->xmit_pending = NULL; - kfree_skb(skb); -} - -#ifdef CONFIG_PPP_MULTILINK -static bool mp_protocol_compress __read_mostly = true; -module_param(mp_protocol_compress, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(mp_protocol_compress, - "compress protocol id in multilink fragments"); - -/* - * Divide a packet to be transmitted into fragments and - * send them out the individual links. - */ -static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) -{ - int len, totlen; - int i, bits, hdrlen, mtu; - int flen; - int navail, nfree, nzero; - int nbigger; - int totspeed; - int totfree; - unsigned char *p, *q; - struct list_head *list; - struct channel *pch; - struct sk_buff *frag; - struct ppp_channel *chan; - - totspeed = 0; /*total bitrate of the bundle*/ - nfree = 0; /* # channels which have no packet already queued */ - navail = 0; /* total # of usable channels (not deregistered) */ - nzero = 0; /* number of channels with zero speed associated*/ - totfree = 0; /*total # of channels available and - *having no queued packets before - *starting the fragmentation*/ - - hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; - i = 0; - list_for_each_entry(pch, &ppp->channels, clist) { - if (pch->chan) { - pch->avail = 1; - navail++; - pch->speed = pch->chan->speed; - } else { - pch->avail = 0; - } - if (pch->avail) { - if (skb_queue_empty(&pch->file.xq) || - !pch->had_frag) { - if (pch->speed == 0) - nzero++; - else - totspeed += pch->speed; - - pch->avail = 2; - ++nfree; - ++totfree; - } - if (!pch->had_frag && i < ppp->nxchan) - ppp->nxchan = i; - } - ++i; - } - /* - * Don't start sending this packet unless at least half of - * the channels are free. This gives much better TCP - * performance if we have a lot of channels. - */ - if (nfree == 0 || nfree < navail / 2) - return 0; /* can't take now, leave it in xmit_pending */ - - /* Do protocol field compression */ - p = skb->data; - len = skb->len; - if (*p == 0 && mp_protocol_compress) { - ++p; - --len; - } - - totlen = len; - nbigger = len % nfree; - - /* skip to the channel after the one we last used - and start at that one */ - list = &ppp->channels; - for (i = 0; i < ppp->nxchan; ++i) { - list = list->next; - if (list == &ppp->channels) { - i = 0; - break; - } - } - - /* create a fragment for each channel */ - bits = B; - while (len > 0) { - list = list->next; - if (list == &ppp->channels) { - i = 0; - continue; - } - pch = list_entry(list, struct channel, clist); - ++i; - if (!pch->avail) - continue; - - /* - * Skip this channel if it has a fragment pending already and - * we haven't given a fragment to all of the free channels. - */ - if (pch->avail == 1) { - if (nfree > 0) - continue; - } else { - pch->avail = 1; - } - - /* check the channel's mtu and whether it is still attached. */ - spin_lock_bh(&pch->downl); - if (pch->chan == NULL) { - /* can't use this channel, it's being deregistered */ - if (pch->speed == 0) - nzero--; - else - totspeed -= pch->speed; - - spin_unlock_bh(&pch->downl); - pch->avail = 0; - totlen = len; - totfree--; - nfree--; - if (--navail == 0) - break; - continue; - } - - /* - *if the channel speed is not set divide - *the packet evenly among the free channels; - *otherwise divide it according to the speed - *of the channel we are going to transmit on - */ - flen = len; - if (nfree > 0) { - if (pch->speed == 0) { - flen = len/nfree; - if (nbigger > 0) { - flen++; - nbigger--; - } - } else { - flen = (((totfree - nzero)*(totlen + hdrlen*totfree)) / - ((totspeed*totfree)/pch->speed)) - hdrlen; - if (nbigger > 0) { - flen += ((totfree - nzero)*pch->speed)/totspeed; - nbigger -= ((totfree - nzero)*pch->speed)/ - totspeed; - } - } - nfree--; - } - - /* - *check if we are on the last channel or - *we exceded the length of the data to - *fragment - */ - if ((nfree <= 0) || (flen > len)) - flen = len; - /* - *it is not worth to tx on slow channels: - *in that case from the resulting flen according to the - *above formula will be equal or less than zero. - *Skip the channel in this case - */ - if (flen <= 0) { - pch->avail = 2; - spin_unlock_bh(&pch->downl); - continue; - } - - mtu = pch->chan->mtu - hdrlen; - if (mtu < 4) - mtu = 4; - if (flen > mtu) - flen = mtu; - if (flen == len) - bits |= E; - frag = alloc_skb(flen + hdrlen + (flen == 0), GFP_ATOMIC); - if (!frag) - goto noskb; - q = skb_put(frag, flen + hdrlen); - - /* make the MP header */ - put_unaligned_be16(PPP_MP, q); - if (ppp->flags & SC_MP_XSHORTSEQ) { - q[2] = bits + ((ppp->nxseq >> 8) & 0xf); - q[3] = ppp->nxseq; - } else { - q[2] = bits; - q[3] = ppp->nxseq >> 16; - q[4] = ppp->nxseq >> 8; - q[5] = ppp->nxseq; - } - - memcpy(q + hdrlen, p, flen); - - /* try to send it down the channel */ - chan = pch->chan; - if (!skb_queue_empty(&pch->file.xq) || - !chan->ops->start_xmit(chan, frag)) - skb_queue_tail(&pch->file.xq, frag); - pch->had_frag = 1; - p += flen; - len -= flen; - ++ppp->nxseq; - bits = 0; - spin_unlock_bh(&pch->downl); - } - ppp->nxchan = i; - - return 1; - - noskb: - spin_unlock_bh(&pch->downl); - if (ppp->debug & 1) - netdev_err(ppp->dev, "PPP: no memory (fragment)\n"); - ++ppp->dev->stats.tx_errors; - ++ppp->nxseq; - return 1; /* abandon the frame */ -} -#endif /* CONFIG_PPP_MULTILINK */ - -/* - * Try to send data out on a channel. - */ -static void -ppp_channel_push(struct channel *pch) -{ - struct sk_buff *skb; - struct ppp *ppp; - - spin_lock_bh(&pch->downl); - if (pch->chan) { - while (!skb_queue_empty(&pch->file.xq)) { - skb = skb_dequeue(&pch->file.xq); - if (!pch->chan->ops->start_xmit(pch->chan, skb)) { - /* put the packet back and try again later */ - skb_queue_head(&pch->file.xq, skb); - break; - } - } - } else { - /* channel got deregistered */ - skb_queue_purge(&pch->file.xq); - } - spin_unlock_bh(&pch->downl); - /* see if there is anything from the attached unit to be sent */ - if (skb_queue_empty(&pch->file.xq)) { - read_lock_bh(&pch->upl); - ppp = pch->ppp; - if (ppp) - ppp_xmit_process(ppp); - read_unlock_bh(&pch->upl); - } -} - -/* - * Receive-side routines. - */ - -struct ppp_mp_skb_parm { - u32 sequence; - u8 BEbits; -}; -#define PPP_MP_CB(skb) ((struct ppp_mp_skb_parm *)((skb)->cb)) - -static inline void -ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) -{ - ppp_recv_lock(ppp); - if (!ppp->closing) - ppp_receive_frame(ppp, skb, pch); - else - kfree_skb(skb); - ppp_recv_unlock(ppp); -} - -void -ppp_input(struct ppp_channel *chan, struct sk_buff *skb) -{ - struct channel *pch = chan->ppp; - int proto; - - if (!pch) { - kfree_skb(skb); - return; - } - - read_lock_bh(&pch->upl); - if (!pskb_may_pull(skb, 2)) { - kfree_skb(skb); - if (pch->ppp) { - ++pch->ppp->dev->stats.rx_length_errors; - ppp_receive_error(pch->ppp); - } - goto done; - } - - proto = PPP_PROTO(skb); - if (!pch->ppp || proto >= 0xc000 || proto == PPP_CCPFRAG) { - /* put it on the channel queue */ - skb_queue_tail(&pch->file.rq, skb); - /* drop old frames if queue too long */ - while (pch->file.rq.qlen > PPP_MAX_RQLEN && - (skb = skb_dequeue(&pch->file.rq))) - kfree_skb(skb); - wake_up_interruptible(&pch->file.rwait); - } else { - ppp_do_recv(pch->ppp, skb, pch); - } - -done: - read_unlock_bh(&pch->upl); -} - -/* Put a 0-length skb in the receive queue as an error indication */ -void -ppp_input_error(struct ppp_channel *chan, int code) -{ - struct channel *pch = chan->ppp; - struct sk_buff *skb; - - if (!pch) - return; - - read_lock_bh(&pch->upl); - if (pch->ppp) { - skb = alloc_skb(0, GFP_ATOMIC); - if (skb) { - skb->len = 0; /* probably unnecessary */ - skb->cb[0] = code; - ppp_do_recv(pch->ppp, skb, pch); - } - } - read_unlock_bh(&pch->upl); -} - -/* - * We come in here to process a received frame. - * The receive side of the ppp unit is locked. - */ -static void -ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) -{ - /* note: a 0-length skb is used as an error indication */ - if (skb->len > 0) { -#ifdef CONFIG_PPP_MULTILINK - /* XXX do channel-level decompression here */ - if (PPP_PROTO(skb) == PPP_MP) - ppp_receive_mp_frame(ppp, skb, pch); - else -#endif /* CONFIG_PPP_MULTILINK */ - ppp_receive_nonmp_frame(ppp, skb); - } else { - kfree_skb(skb); - ppp_receive_error(ppp); - } -} - -static void -ppp_receive_error(struct ppp *ppp) -{ - ++ppp->dev->stats.rx_errors; - if (ppp->vj) - slhc_toss(ppp->vj); -} - -static void -ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) -{ - struct sk_buff *ns; - int proto, len, npi; - - /* - * Decompress the frame, if compressed. - * Note that some decompressors need to see uncompressed frames - * that come in as well as compressed frames. - */ - if (ppp->rc_state && (ppp->rstate & SC_DECOMP_RUN) && - (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0) - skb = ppp_decompress_frame(ppp, skb); - - if (ppp->flags & SC_MUST_COMP && ppp->rstate & SC_DC_FERROR) - goto err; - - proto = PPP_PROTO(skb); - switch (proto) { - case PPP_VJC_COMP: - /* decompress VJ compressed packets */ - if (!ppp->vj || (ppp->flags & SC_REJ_COMP_TCP)) - goto err; - - if (skb_tailroom(skb) < 124 || skb_cloned(skb)) { - /* copy to a new sk_buff with more tailroom */ - ns = dev_alloc_skb(skb->len + 128); - if (!ns) { - netdev_err(ppp->dev, "PPP: no memory " - "(VJ decomp)\n"); - goto err; - } - skb_reserve(ns, 2); - skb_copy_bits(skb, 0, skb_put(ns, skb->len), skb->len); - kfree_skb(skb); - skb = ns; - } - else - skb->ip_summed = CHECKSUM_NONE; - - len = slhc_uncompress(ppp->vj, skb->data + 2, skb->len - 2); - if (len <= 0) { - netdev_printk(KERN_DEBUG, ppp->dev, - "PPP: VJ decompression error\n"); - goto err; - } - len += 2; - if (len > skb->len) - skb_put(skb, len - skb->len); - else if (len < skb->len) - skb_trim(skb, len); - proto = PPP_IP; - break; - - case PPP_VJC_UNCOMP: - if (!ppp->vj || (ppp->flags & SC_REJ_COMP_TCP)) - goto err; - - /* Until we fix the decompressor need to make sure - * data portion is linear. - */ - if (!pskb_may_pull(skb, skb->len)) - goto err; - - if (slhc_remember(ppp->vj, skb->data + 2, skb->len - 2) <= 0) { - netdev_err(ppp->dev, "PPP: VJ uncompressed error\n"); - goto err; - } - proto = PPP_IP; - break; - - case PPP_CCP: - ppp_ccp_peek(ppp, skb, 1); - break; - } - - ++ppp->dev->stats.rx_packets; - ppp->dev->stats.rx_bytes += skb->len - 2; - - npi = proto_to_npindex(proto); - if (npi < 0) { - /* control or unknown frame - pass it to pppd */ - skb_queue_tail(&ppp->file.rq, skb); - /* limit queue length by dropping old frames */ - while (ppp->file.rq.qlen > PPP_MAX_RQLEN && - (skb = skb_dequeue(&ppp->file.rq))) - kfree_skb(skb); - /* wake up any process polling or blocking on read */ - wake_up_interruptible(&ppp->file.rwait); - - } else { - /* network protocol frame - give it to the kernel */ - -#ifdef CONFIG_PPP_FILTER - /* check if the packet passes the pass and active filters */ - /* the filter instructions are constructed assuming - a four-byte PPP header on each packet */ - if (ppp->pass_filter || ppp->active_filter) { - if (skb_cloned(skb) && - pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) - goto err; - - *skb_push(skb, 2) = 0; - if (ppp->pass_filter && - sk_run_filter(skb, ppp->pass_filter) == 0) { - if (ppp->debug & 1) - netdev_printk(KERN_DEBUG, ppp->dev, - "PPP: inbound frame " - "not passed\n"); - kfree_skb(skb); - return; - } - if (!(ppp->active_filter && - sk_run_filter(skb, ppp->active_filter) == 0)) - ppp->last_recv = jiffies; - __skb_pull(skb, 2); - } else -#endif /* CONFIG_PPP_FILTER */ - ppp->last_recv = jiffies; - - if ((ppp->dev->flags & IFF_UP) == 0 || - ppp->npmode[npi] != NPMODE_PASS) { - kfree_skb(skb); - } else { - /* chop off protocol */ - skb_pull_rcsum(skb, 2); - skb->dev = ppp->dev; - skb->protocol = htons(npindex_to_ethertype[npi]); - skb_reset_mac_header(skb); - netif_rx(skb); - } - } - return; - - err: - kfree_skb(skb); - ppp_receive_error(ppp); -} - -static struct sk_buff * -ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb) -{ - int proto = PPP_PROTO(skb); - struct sk_buff *ns; - int len; - - /* Until we fix all the decompressor's need to make sure - * data portion is linear. - */ - if (!pskb_may_pull(skb, skb->len)) - goto err; - - if (proto == PPP_COMP) { - int obuff_size; - - switch(ppp->rcomp->compress_proto) { - case CI_MPPE: - obuff_size = ppp->mru + PPP_HDRLEN + 1; - break; - default: - obuff_size = ppp->mru + PPP_HDRLEN; - break; - } - - ns = dev_alloc_skb(obuff_size); - if (!ns) { - netdev_err(ppp->dev, "ppp_decompress_frame: " - "no memory\n"); - goto err; - } - /* the decompressor still expects the A/C bytes in the hdr */ - len = ppp->rcomp->decompress(ppp->rc_state, skb->data - 2, - skb->len + 2, ns->data, obuff_size); - if (len < 0) { - /* Pass the compressed frame to pppd as an - error indication. */ - if (len == DECOMP_FATALERROR) - ppp->rstate |= SC_DC_FERROR; - kfree_skb(ns); - goto err; - } - - kfree_skb(skb); - skb = ns; - skb_put(skb, len); - skb_pull(skb, 2); /* pull off the A/C bytes */ - - } else { - /* Uncompressed frame - pass to decompressor so it - can update its dictionary if necessary. */ - if (ppp->rcomp->incomp) - ppp->rcomp->incomp(ppp->rc_state, skb->data - 2, - skb->len + 2); - } - - return skb; - - err: - ppp->rstate |= SC_DC_ERROR; - ppp_receive_error(ppp); - return skb; -} - -#ifdef CONFIG_PPP_MULTILINK -/* - * Receive a multilink frame. - * We put it on the reconstruction queue and then pull off - * as many completed frames as we can. - */ -static void -ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) -{ - u32 mask, seq; - struct channel *ch; - int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; - - if (!pskb_may_pull(skb, mphdrlen + 1) || ppp->mrru == 0) - goto err; /* no good, throw it away */ - - /* Decode sequence number and begin/end bits */ - if (ppp->flags & SC_MP_SHORTSEQ) { - seq = ((skb->data[2] & 0x0f) << 8) | skb->data[3]; - mask = 0xfff; - } else { - seq = (skb->data[3] << 16) | (skb->data[4] << 8)| skb->data[5]; - mask = 0xffffff; - } - PPP_MP_CB(skb)->BEbits = skb->data[2]; - skb_pull(skb, mphdrlen); /* pull off PPP and MP headers */ - - /* - * Do protocol ID decompression on the first fragment of each packet. - */ - if ((PPP_MP_CB(skb)->BEbits & B) && (skb->data[0] & 1)) - *skb_push(skb, 1) = 0; - - /* - * Expand sequence number to 32 bits, making it as close - * as possible to ppp->minseq. - */ - seq |= ppp->minseq & ~mask; - if ((int)(ppp->minseq - seq) > (int)(mask >> 1)) - seq += mask + 1; - else if ((int)(seq - ppp->minseq) > (int)(mask >> 1)) - seq -= mask + 1; /* should never happen */ - PPP_MP_CB(skb)->sequence = seq; - pch->lastseq = seq; - - /* - * If this packet comes before the next one we were expecting, - * drop it. - */ - if (seq_before(seq, ppp->nextseq)) { - kfree_skb(skb); - ++ppp->dev->stats.rx_dropped; - ppp_receive_error(ppp); - return; - } - - /* - * Reevaluate minseq, the minimum over all channels of the - * last sequence number received on each channel. Because of - * the increasing sequence number rule, we know that any fragment - * before `minseq' which hasn't arrived is never going to arrive. - * The list of channels can't change because we have the receive - * side of the ppp unit locked. - */ - list_for_each_entry(ch, &ppp->channels, clist) { - if (seq_before(ch->lastseq, seq)) - seq = ch->lastseq; - } - if (seq_before(ppp->minseq, seq)) - ppp->minseq = seq; - - /* Put the fragment on the reconstruction queue */ - ppp_mp_insert(ppp, skb); - - /* If the queue is getting long, don't wait any longer for packets - before the start of the queue. */ - if (skb_queue_len(&ppp->mrq) >= PPP_MP_MAX_QLEN) { - struct sk_buff *mskb = skb_peek(&ppp->mrq); - if (seq_before(ppp->minseq, PPP_MP_CB(mskb)->sequence)) - ppp->minseq = PPP_MP_CB(mskb)->sequence; - } - - /* Pull completed packets off the queue and receive them. */ - while ((skb = ppp_mp_reconstruct(ppp))) { - if (pskb_may_pull(skb, 2)) - ppp_receive_nonmp_frame(ppp, skb); - else { - ++ppp->dev->stats.rx_length_errors; - kfree_skb(skb); - ppp_receive_error(ppp); - } - } - - return; - - err: - kfree_skb(skb); - ppp_receive_error(ppp); -} - -/* - * Insert a fragment on the MP reconstruction queue. - * The queue is ordered by increasing sequence number. - */ -static void -ppp_mp_insert(struct ppp *ppp, struct sk_buff *skb) -{ - struct sk_buff *p; - struct sk_buff_head *list = &ppp->mrq; - u32 seq = PPP_MP_CB(skb)->sequence; - - /* N.B. we don't need to lock the list lock because we have the - ppp unit receive-side lock. */ - skb_queue_walk(list, p) { - if (seq_before(seq, PPP_MP_CB(p)->sequence)) - break; - } - __skb_queue_before(list, p, skb); -} - -/* - * Reconstruct a packet from the MP fragment queue. - * We go through increasing sequence numbers until we find a - * complete packet, or we get to the sequence number for a fragment - * which hasn't arrived but might still do so. - */ -static struct sk_buff * -ppp_mp_reconstruct(struct ppp *ppp) -{ - u32 seq = ppp->nextseq; - u32 minseq = ppp->minseq; - struct sk_buff_head *list = &ppp->mrq; - struct sk_buff *p, *tmp; - struct sk_buff *head, *tail; - struct sk_buff *skb = NULL; - int lost = 0, len = 0; - - if (ppp->mrru == 0) /* do nothing until mrru is set */ - return NULL; - head = list->next; - tail = NULL; - skb_queue_walk_safe(list, p, tmp) { - again: - if (seq_before(PPP_MP_CB(p)->sequence, seq)) { - /* this can't happen, anyway ignore the skb */ - netdev_err(ppp->dev, "ppp_mp_reconstruct bad " - "seq %u < %u\n", - PPP_MP_CB(p)->sequence, seq); - __skb_unlink(p, list); - kfree_skb(p); - continue; - } - if (PPP_MP_CB(p)->sequence != seq) { - /* Fragment `seq' is missing. If it is after - minseq, it might arrive later, so stop here. */ - if (seq_after(seq, minseq)) - break; - /* Fragment `seq' is lost, keep going. */ - lost = 1; - seq = seq_before(minseq, PPP_MP_CB(p)->sequence)? - minseq + 1: PPP_MP_CB(p)->sequence; - goto again; - } - - /* - * At this point we know that all the fragments from - * ppp->nextseq to seq are either present or lost. - * Also, there are no complete packets in the queue - * that have no missing fragments and end before this - * fragment. - */ - - /* B bit set indicates this fragment starts a packet */ - if (PPP_MP_CB(p)->BEbits & B) { - head = p; - lost = 0; - len = 0; - } - - len += p->len; - - /* Got a complete packet yet? */ - if (lost == 0 && (PPP_MP_CB(p)->BEbits & E) && - (PPP_MP_CB(head)->BEbits & B)) { - if (len > ppp->mrru + 2) { - ++ppp->dev->stats.rx_length_errors; - netdev_printk(KERN_DEBUG, ppp->dev, - "PPP: reconstructed packet" - " is too long (%d)\n", len); - } else { - tail = p; - break; - } - ppp->nextseq = seq + 1; - } - - /* - * If this is the ending fragment of a packet, - * and we haven't found a complete valid packet yet, - * we can discard up to and including this fragment. - */ - if (PPP_MP_CB(p)->BEbits & E) { - struct sk_buff *tmp2; - - skb_queue_reverse_walk_from_safe(list, p, tmp2) { - __skb_unlink(p, list); - kfree_skb(p); - } - head = skb_peek(list); - if (!head) - break; - } - ++seq; - } - - /* If we have a complete packet, copy it all into one skb. */ - if (tail != NULL) { - /* If we have discarded any fragments, - signal a receive error. */ - if (PPP_MP_CB(head)->sequence != ppp->nextseq) { - if (ppp->debug & 1) - netdev_printk(KERN_DEBUG, ppp->dev, - " missed pkts %u..%u\n", - ppp->nextseq, - PPP_MP_CB(head)->sequence-1); - ++ppp->dev->stats.rx_dropped; - ppp_receive_error(ppp); - } - - skb = head; - if (head != tail) { - struct sk_buff **fragpp = &skb_shinfo(skb)->frag_list; - p = skb_queue_next(list, head); - __skb_unlink(skb, list); - skb_queue_walk_from_safe(list, p, tmp) { - __skb_unlink(p, list); - *fragpp = p; - p->next = NULL; - fragpp = &p->next; - - skb->len += p->len; - skb->data_len += p->len; - skb->truesize += p->len; - - if (p == tail) - break; - } - } else { - __skb_unlink(skb, list); - } - - ppp->nextseq = PPP_MP_CB(tail)->sequence + 1; - } - - return skb; -} -#endif /* CONFIG_PPP_MULTILINK */ - -/* - * Channel interface. - */ - -/* Create a new, unattached ppp channel. */ -int ppp_register_channel(struct ppp_channel *chan) -{ - return ppp_register_net_channel(current->nsproxy->net_ns, chan); -} - -/* Create a new, unattached ppp channel for specified net. */ -int ppp_register_net_channel(struct net *net, struct ppp_channel *chan) -{ - struct channel *pch; - struct ppp_net *pn; - - pch = kzalloc(sizeof(struct channel), GFP_KERNEL); - if (!pch) - return -ENOMEM; - - pn = ppp_pernet(net); - - pch->ppp = NULL; - pch->chan = chan; - pch->chan_net = net; - chan->ppp = pch; - init_ppp_file(&pch->file, CHANNEL); - pch->file.hdrlen = chan->hdrlen; -#ifdef CONFIG_PPP_MULTILINK - pch->lastseq = -1; -#endif /* CONFIG_PPP_MULTILINK */ - init_rwsem(&pch->chan_sem); - spin_lock_init(&pch->downl); - rwlock_init(&pch->upl); - - spin_lock_bh(&pn->all_channels_lock); - pch->file.index = ++pn->last_channel_index; - list_add(&pch->list, &pn->new_channels); - atomic_inc(&channel_count); - spin_unlock_bh(&pn->all_channels_lock); - - return 0; -} - -/* - * Return the index of a channel. - */ -int ppp_channel_index(struct ppp_channel *chan) -{ - struct channel *pch = chan->ppp; - - if (pch) - return pch->file.index; - return -1; -} - -/* - * Return the PPP unit number to which a channel is connected. - */ -int ppp_unit_number(struct ppp_channel *chan) -{ - struct channel *pch = chan->ppp; - int unit = -1; - - if (pch) { - read_lock_bh(&pch->upl); - if (pch->ppp) - unit = pch->ppp->file.index; - read_unlock_bh(&pch->upl); - } - return unit; -} - -/* - * Return the PPP device interface name of a channel. - */ -char *ppp_dev_name(struct ppp_channel *chan) -{ - struct channel *pch = chan->ppp; - char *name = NULL; - - if (pch) { - read_lock_bh(&pch->upl); - if (pch->ppp && pch->ppp->dev) - name = pch->ppp->dev->name; - read_unlock_bh(&pch->upl); - } - return name; -} - - -/* - * Disconnect a channel from the generic layer. - * This must be called in process context. - */ -void -ppp_unregister_channel(struct ppp_channel *chan) -{ - struct channel *pch = chan->ppp; - struct ppp_net *pn; - - if (!pch) - return; /* should never happen */ - - chan->ppp = NULL; - - /* - * This ensures that we have returned from any calls into the - * the channel's start_xmit or ioctl routine before we proceed. - */ - down_write(&pch->chan_sem); - spin_lock_bh(&pch->downl); - pch->chan = NULL; - spin_unlock_bh(&pch->downl); - up_write(&pch->chan_sem); - ppp_disconnect_channel(pch); - - pn = ppp_pernet(pch->chan_net); - spin_lock_bh(&pn->all_channels_lock); - list_del(&pch->list); - spin_unlock_bh(&pn->all_channels_lock); - - pch->file.dead = 1; - wake_up_interruptible(&pch->file.rwait); - if (atomic_dec_and_test(&pch->file.refcnt)) - ppp_destroy_channel(pch); -} - -/* - * Callback from a channel when it can accept more to transmit. - * This should be called at BH/softirq level, not interrupt level. - */ -void -ppp_output_wakeup(struct ppp_channel *chan) -{ - struct channel *pch = chan->ppp; - - if (!pch) - return; - ppp_channel_push(pch); -} - -/* - * Compression control. - */ - -/* Process the PPPIOCSCOMPRESS ioctl. */ -static int -ppp_set_compress(struct ppp *ppp, unsigned long arg) -{ - int err; - struct compressor *cp, *ocomp; - struct ppp_option_data data; - void *state, *ostate; - unsigned char ccp_option[CCP_MAX_OPTION_LENGTH]; - - err = -EFAULT; - if (copy_from_user(&data, (void __user *) arg, sizeof(data)) || - (data.length <= CCP_MAX_OPTION_LENGTH && - copy_from_user(ccp_option, (void __user *) data.ptr, data.length))) - goto out; - err = -EINVAL; - if (data.length > CCP_MAX_OPTION_LENGTH || - ccp_option[1] < 2 || ccp_option[1] > data.length) - goto out; - - cp = try_then_request_module( - find_compressor(ccp_option[0]), - "ppp-compress-%d", ccp_option[0]); - if (!cp) - goto out; - - err = -ENOBUFS; - if (data.transmit) { - state = cp->comp_alloc(ccp_option, data.length); - if (state) { - ppp_xmit_lock(ppp); - ppp->xstate &= ~SC_COMP_RUN; - ocomp = ppp->xcomp; - ostate = ppp->xc_state; - ppp->xcomp = cp; - ppp->xc_state = state; - ppp_xmit_unlock(ppp); - if (ostate) { - ocomp->comp_free(ostate); - module_put(ocomp->owner); - } - err = 0; - } else - module_put(cp->owner); - - } else { - state = cp->decomp_alloc(ccp_option, data.length); - if (state) { - ppp_recv_lock(ppp); - ppp->rstate &= ~SC_DECOMP_RUN; - ocomp = ppp->rcomp; - ostate = ppp->rc_state; - ppp->rcomp = cp; - ppp->rc_state = state; - ppp_recv_unlock(ppp); - if (ostate) { - ocomp->decomp_free(ostate); - module_put(ocomp->owner); - } - err = 0; - } else - module_put(cp->owner); - } - - out: - return err; -} - -/* - * Look at a CCP packet and update our state accordingly. - * We assume the caller has the xmit or recv path locked. - */ -static void -ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound) -{ - unsigned char *dp; - int len; - - if (!pskb_may_pull(skb, CCP_HDRLEN + 2)) - return; /* no header */ - dp = skb->data + 2; - - switch (CCP_CODE(dp)) { - case CCP_CONFREQ: - - /* A ConfReq starts negotiation of compression - * in one direction of transmission, - * and hence brings it down...but which way? - * - * Remember: - * A ConfReq indicates what the sender would like to receive - */ - if(inbound) - /* He is proposing what I should send */ - ppp->xstate &= ~SC_COMP_RUN; - else - /* I am proposing to what he should send */ - ppp->rstate &= ~SC_DECOMP_RUN; - - break; - - case CCP_TERMREQ: - case CCP_TERMACK: - /* - * CCP is going down, both directions of transmission - */ - ppp->rstate &= ~SC_DECOMP_RUN; - ppp->xstate &= ~SC_COMP_RUN; - break; - - case CCP_CONFACK: - if ((ppp->flags & (SC_CCP_OPEN | SC_CCP_UP)) != SC_CCP_OPEN) - break; - len = CCP_LENGTH(dp); - if (!pskb_may_pull(skb, len + 2)) - return; /* too short */ - dp += CCP_HDRLEN; - len -= CCP_HDRLEN; - if (len < CCP_OPT_MINLEN || len < CCP_OPT_LENGTH(dp)) - break; - if (inbound) { - /* we will start receiving compressed packets */ - if (!ppp->rc_state) - break; - if (ppp->rcomp->decomp_init(ppp->rc_state, dp, len, - ppp->file.index, 0, ppp->mru, ppp->debug)) { - ppp->rstate |= SC_DECOMP_RUN; - ppp->rstate &= ~(SC_DC_ERROR | SC_DC_FERROR); - } - } else { - /* we will soon start sending compressed packets */ - if (!ppp->xc_state) - break; - if (ppp->xcomp->comp_init(ppp->xc_state, dp, len, - ppp->file.index, 0, ppp->debug)) - ppp->xstate |= SC_COMP_RUN; - } - break; - - case CCP_RESETACK: - /* reset the [de]compressor */ - if ((ppp->flags & SC_CCP_UP) == 0) - break; - if (inbound) { - if (ppp->rc_state && (ppp->rstate & SC_DECOMP_RUN)) { - ppp->rcomp->decomp_reset(ppp->rc_state); - ppp->rstate &= ~SC_DC_ERROR; - } - } else { - if (ppp->xc_state && (ppp->xstate & SC_COMP_RUN)) - ppp->xcomp->comp_reset(ppp->xc_state); - } - break; - } -} - -/* Free up compression resources. */ -static void -ppp_ccp_closed(struct ppp *ppp) -{ - void *xstate, *rstate; - struct compressor *xcomp, *rcomp; - - ppp_lock(ppp); - ppp->flags &= ~(SC_CCP_OPEN | SC_CCP_UP); - ppp->xstate = 0; - xcomp = ppp->xcomp; - xstate = ppp->xc_state; - ppp->xc_state = NULL; - ppp->rstate = 0; - rcomp = ppp->rcomp; - rstate = ppp->rc_state; - ppp->rc_state = NULL; - ppp_unlock(ppp); - - if (xstate) { - xcomp->comp_free(xstate); - module_put(xcomp->owner); - } - if (rstate) { - rcomp->decomp_free(rstate); - module_put(rcomp->owner); - } -} - -/* List of compressors. */ -static LIST_HEAD(compressor_list); -static DEFINE_SPINLOCK(compressor_list_lock); - -struct compressor_entry { - struct list_head list; - struct compressor *comp; -}; - -static struct compressor_entry * -find_comp_entry(int proto) -{ - struct compressor_entry *ce; - - list_for_each_entry(ce, &compressor_list, list) { - if (ce->comp->compress_proto == proto) - return ce; - } - return NULL; -} - -/* Register a compressor */ -int -ppp_register_compressor(struct compressor *cp) -{ - struct compressor_entry *ce; - int ret; - spin_lock(&compressor_list_lock); - ret = -EEXIST; - if (find_comp_entry(cp->compress_proto)) - goto out; - ret = -ENOMEM; - ce = kmalloc(sizeof(struct compressor_entry), GFP_ATOMIC); - if (!ce) - goto out; - ret = 0; - ce->comp = cp; - list_add(&ce->list, &compressor_list); - out: - spin_unlock(&compressor_list_lock); - return ret; -} - -/* Unregister a compressor */ -void -ppp_unregister_compressor(struct compressor *cp) -{ - struct compressor_entry *ce; - - spin_lock(&compressor_list_lock); - ce = find_comp_entry(cp->compress_proto); - if (ce && ce->comp == cp) { - list_del(&ce->list); - kfree(ce); - } - spin_unlock(&compressor_list_lock); -} - -/* Find a compressor. */ -static struct compressor * -find_compressor(int type) -{ - struct compressor_entry *ce; - struct compressor *cp = NULL; - - spin_lock(&compressor_list_lock); - ce = find_comp_entry(type); - if (ce) { - cp = ce->comp; - if (!try_module_get(cp->owner)) - cp = NULL; - } - spin_unlock(&compressor_list_lock); - return cp; -} - -/* - * Miscelleneous stuff. - */ - -static void -ppp_get_stats(struct ppp *ppp, struct ppp_stats *st) -{ - struct slcompress *vj = ppp->vj; - - memset(st, 0, sizeof(*st)); - st->p.ppp_ipackets = ppp->dev->stats.rx_packets; - st->p.ppp_ierrors = ppp->dev->stats.rx_errors; - st->p.ppp_ibytes = ppp->dev->stats.rx_bytes; - st->p.ppp_opackets = ppp->dev->stats.tx_packets; - st->p.ppp_oerrors = ppp->dev->stats.tx_errors; - st->p.ppp_obytes = ppp->dev->stats.tx_bytes; - if (!vj) - return; - st->vj.vjs_packets = vj->sls_o_compressed + vj->sls_o_uncompressed; - st->vj.vjs_compressed = vj->sls_o_compressed; - st->vj.vjs_searches = vj->sls_o_searches; - st->vj.vjs_misses = vj->sls_o_misses; - st->vj.vjs_errorin = vj->sls_i_error; - st->vj.vjs_tossed = vj->sls_i_tossed; - st->vj.vjs_uncompressedin = vj->sls_i_uncompressed; - st->vj.vjs_compressedin = vj->sls_i_compressed; -} - -/* - * Stuff for handling the lists of ppp units and channels - * and for initialization. - */ - -/* - * Create a new ppp interface unit. Fails if it can't allocate memory - * or if there is already a unit with the requested number. - * unit == -1 means allocate a new number. - */ -static struct ppp * -ppp_create_interface(struct net *net, int unit, int *retp) -{ - struct ppp *ppp; - struct ppp_net *pn; - struct net_device *dev = NULL; - int ret = -ENOMEM; - int i; - - dev = alloc_netdev(sizeof(struct ppp), "", ppp_setup); - if (!dev) - goto out1; - - pn = ppp_pernet(net); - - ppp = netdev_priv(dev); - ppp->dev = dev; - ppp->mru = PPP_MRU; - init_ppp_file(&ppp->file, INTERFACE); - ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */ - for (i = 0; i < NUM_NP; ++i) - ppp->npmode[i] = NPMODE_PASS; - INIT_LIST_HEAD(&ppp->channels); - spin_lock_init(&ppp->rlock); - spin_lock_init(&ppp->wlock); -#ifdef CONFIG_PPP_MULTILINK - ppp->minseq = -1; - skb_queue_head_init(&ppp->mrq); -#endif /* CONFIG_PPP_MULTILINK */ - - /* - * drum roll: don't forget to set - * the net device is belong to - */ - dev_net_set(dev, net); - - mutex_lock(&pn->all_ppp_mutex); - - if (unit < 0) { - unit = unit_get(&pn->units_idr, ppp); - if (unit < 0) { - ret = unit; - goto out2; - } - } else { - ret = -EEXIST; - if (unit_find(&pn->units_idr, unit)) - goto out2; /* unit already exists */ - /* - * if caller need a specified unit number - * lets try to satisfy him, otherwise -- - * he should better ask us for new unit number - * - * NOTE: yes I know that returning EEXIST it's not - * fair but at least pppd will ask us to allocate - * new unit in this case so user is happy :) - */ - unit = unit_set(&pn->units_idr, ppp, unit); - if (unit < 0) - goto out2; - } - - /* Initialize the new ppp unit */ - ppp->file.index = unit; - sprintf(dev->name, "ppp%d", unit); - - ret = register_netdev(dev); - if (ret != 0) { - unit_put(&pn->units_idr, unit); - netdev_err(ppp->dev, "PPP: couldn't register device %s (%d)\n", - dev->name, ret); - goto out2; - } - - ppp->ppp_net = net; - - atomic_inc(&ppp_unit_count); - mutex_unlock(&pn->all_ppp_mutex); - - *retp = 0; - return ppp; - -out2: - mutex_unlock(&pn->all_ppp_mutex); - free_netdev(dev); -out1: - *retp = ret; - return NULL; -} - -/* - * Initialize a ppp_file structure. - */ -static void -init_ppp_file(struct ppp_file *pf, int kind) -{ - pf->kind = kind; - skb_queue_head_init(&pf->xq); - skb_queue_head_init(&pf->rq); - atomic_set(&pf->refcnt, 1); - init_waitqueue_head(&pf->rwait); -} - -/* - * Take down a ppp interface unit - called when the owning file - * (the one that created the unit) is closed or detached. - */ -static void ppp_shutdown_interface(struct ppp *ppp) -{ - struct ppp_net *pn; - - pn = ppp_pernet(ppp->ppp_net); - mutex_lock(&pn->all_ppp_mutex); - - /* This will call dev_close() for us. */ - ppp_lock(ppp); - if (!ppp->closing) { - ppp->closing = 1; - ppp_unlock(ppp); - unregister_netdev(ppp->dev); - unit_put(&pn->units_idr, ppp->file.index); - } else - ppp_unlock(ppp); - - ppp->file.dead = 1; - ppp->owner = NULL; - wake_up_interruptible(&ppp->file.rwait); - - mutex_unlock(&pn->all_ppp_mutex); -} - -/* - * Free the memory used by a ppp unit. This is only called once - * there are no channels connected to the unit and no file structs - * that reference the unit. - */ -static void ppp_destroy_interface(struct ppp *ppp) -{ - atomic_dec(&ppp_unit_count); - - if (!ppp->file.dead || ppp->n_channels) { - /* "can't happen" */ - netdev_err(ppp->dev, "ppp: destroying ppp struct %p " - "but dead=%d n_channels=%d !\n", - ppp, ppp->file.dead, ppp->n_channels); - return; - } - - ppp_ccp_closed(ppp); - if (ppp->vj) { - slhc_free(ppp->vj); - ppp->vj = NULL; - } - skb_queue_purge(&ppp->file.xq); - skb_queue_purge(&ppp->file.rq); -#ifdef CONFIG_PPP_MULTILINK - skb_queue_purge(&ppp->mrq); -#endif /* CONFIG_PPP_MULTILINK */ -#ifdef CONFIG_PPP_FILTER - kfree(ppp->pass_filter); - ppp->pass_filter = NULL; - kfree(ppp->active_filter); - ppp->active_filter = NULL; -#endif /* CONFIG_PPP_FILTER */ - - kfree_skb(ppp->xmit_pending); - - free_netdev(ppp->dev); -} - -/* - * Locate an existing ppp unit. - * The caller should have locked the all_ppp_mutex. - */ -static struct ppp * -ppp_find_unit(struct ppp_net *pn, int unit) -{ - return unit_find(&pn->units_idr, unit); -} - -/* - * Locate an existing ppp channel. - * The caller should have locked the all_channels_lock. - * First we look in the new_channels list, then in the - * all_channels list. If found in the new_channels list, - * we move it to the all_channels list. This is for speed - * when we have a lot of channels in use. - */ -static struct channel * -ppp_find_channel(struct ppp_net *pn, int unit) -{ - struct channel *pch; - - list_for_each_entry(pch, &pn->new_channels, list) { - if (pch->file.index == unit) { - list_move(&pch->list, &pn->all_channels); - return pch; - } - } - - list_for_each_entry(pch, &pn->all_channels, list) { - if (pch->file.index == unit) - return pch; - } - - return NULL; -} - -/* - * Connect a PPP channel to a PPP interface unit. - */ -static int -ppp_connect_channel(struct channel *pch, int unit) -{ - struct ppp *ppp; - struct ppp_net *pn; - int ret = -ENXIO; - int hdrlen; - - pn = ppp_pernet(pch->chan_net); - - mutex_lock(&pn->all_ppp_mutex); - ppp = ppp_find_unit(pn, unit); - if (!ppp) - goto out; - write_lock_bh(&pch->upl); - ret = -EINVAL; - if (pch->ppp) - goto outl; - - ppp_lock(ppp); - if (pch->file.hdrlen > ppp->file.hdrlen) - ppp->file.hdrlen = pch->file.hdrlen; - hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */ - if (hdrlen > ppp->dev->hard_header_len) - ppp->dev->hard_header_len = hdrlen; - list_add_tail(&pch->clist, &ppp->channels); - ++ppp->n_channels; - pch->ppp = ppp; - atomic_inc(&ppp->file.refcnt); - ppp_unlock(ppp); - ret = 0; - - outl: - write_unlock_bh(&pch->upl); - out: - mutex_unlock(&pn->all_ppp_mutex); - return ret; -} - -/* - * Disconnect a channel from its ppp unit. - */ -static int -ppp_disconnect_channel(struct channel *pch) -{ - struct ppp *ppp; - int err = -EINVAL; - - write_lock_bh(&pch->upl); - ppp = pch->ppp; - pch->ppp = NULL; - write_unlock_bh(&pch->upl); - if (ppp) { - /* remove it from the ppp unit's list */ - ppp_lock(ppp); - list_del(&pch->clist); - if (--ppp->n_channels == 0) - wake_up_interruptible(&ppp->file.rwait); - ppp_unlock(ppp); - if (atomic_dec_and_test(&ppp->file.refcnt)) - ppp_destroy_interface(ppp); - err = 0; - } - return err; -} - -/* - * Free up the resources used by a ppp channel. - */ -static void ppp_destroy_channel(struct channel *pch) -{ - atomic_dec(&channel_count); - - if (!pch->file.dead) { - /* "can't happen" */ - pr_err("ppp: destroying undead channel %p !\n", pch); - return; - } - skb_queue_purge(&pch->file.xq); - skb_queue_purge(&pch->file.rq); - kfree(pch); -} - -static void __exit ppp_cleanup(void) -{ - /* should never happen */ - if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count)) - pr_err("PPP: removing module but units remain!\n"); - unregister_chrdev(PPP_MAJOR, "ppp"); - device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); - class_destroy(ppp_class); - unregister_pernet_device(&ppp_net_ops); -} - -/* - * Units handling. Caller must protect concurrent access - * by holding all_ppp_mutex - */ - -static int __unit_alloc(struct idr *p, void *ptr, int n) -{ - int unit, err; - -again: - if (!idr_pre_get(p, GFP_KERNEL)) { - pr_err("PPP: No free memory for idr\n"); - return -ENOMEM; - } - - err = idr_get_new_above(p, ptr, n, &unit); - if (err < 0) { - if (err == -EAGAIN) - goto again; - return err; - } - - return unit; -} - -/* associate pointer with specified number */ -static int unit_set(struct idr *p, void *ptr, int n) -{ - int unit; - - unit = __unit_alloc(p, ptr, n); - if (unit < 0) - return unit; - else if (unit != n) { - idr_remove(p, unit); - return -EINVAL; - } - - return unit; -} - -/* get new free unit number and associate pointer with it */ -static int unit_get(struct idr *p, void *ptr) -{ - return __unit_alloc(p, ptr, 0); -} - -/* put unit number back to a pool */ -static void unit_put(struct idr *p, int n) -{ - idr_remove(p, n); -} - -/* get pointer associated with the number */ -static void *unit_find(struct idr *p, int n) -{ - return idr_find(p, n); -} - -/* Module/initialization stuff */ - -module_init(ppp_init); -module_exit(ppp_cleanup); - -EXPORT_SYMBOL(ppp_register_net_channel); -EXPORT_SYMBOL(ppp_register_channel); -EXPORT_SYMBOL(ppp_unregister_channel); -EXPORT_SYMBOL(ppp_channel_index); -EXPORT_SYMBOL(ppp_unit_number); -EXPORT_SYMBOL(ppp_dev_name); -EXPORT_SYMBOL(ppp_input); -EXPORT_SYMBOL(ppp_input_error); -EXPORT_SYMBOL(ppp_output_wakeup); -EXPORT_SYMBOL(ppp_register_compressor); -EXPORT_SYMBOL(ppp_unregister_compressor); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV(PPP_MAJOR, 0); -MODULE_ALIAS("devname:ppp"); diff --git a/drivers/net/ppp_mppe.c b/drivers/net/ppp_mppe.c deleted file mode 100644 index 9a1849a..0000000 --- a/drivers/net/ppp_mppe.c +++ /dev/null @@ -1,740 +0,0 @@ -/* - * ppp_mppe.c - interface MPPE to the PPP code. - * This version is for use with Linux kernel 2.6.14+ - * - * By Frank Cusack . - * Copyright (c) 2002,2003,2004 Google, Inc. - * All rights reserved. - * - * License: - * Permission to use, copy, modify, and distribute this software and its - * documentation is hereby granted, provided that the above copyright - * notice appears in all copies. This software is provided without any - * warranty, express or implied. - * - * ALTERNATIVELY, provided that this notice is retained in full, this product - * may be distributed under the terms of the GNU General Public License (GPL), - * in which case the provisions of the GPL apply INSTEAD OF those given above. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * - * Changelog: - * 08/12/05 - Matt Domsch - * Only need extra skb padding on transmit, not receive. - * 06/18/04 - Matt Domsch , Oleg Makarenko - * Use Linux kernel 2.6 arc4 and sha1 routines rather than - * providing our own. - * 2/15/04 - TS: added #include and testing for Kernel - * version before using - * MOD_DEC_USAGE_COUNT/MOD_INC_USAGE_COUNT which are - * deprecated in 2.6 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ppp_mppe.h" - -MODULE_AUTHOR("Frank Cusack "); -MODULE_DESCRIPTION("Point-to-Point Protocol Microsoft Point-to-Point Encryption support"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE)); -MODULE_VERSION("1.0.2"); - -static unsigned int -setup_sg(struct scatterlist *sg, const void *address, unsigned int length) -{ - sg_set_buf(sg, address, length); - return length; -} - -#define SHA1_PAD_SIZE 40 - -/* - * kernel crypto API needs its arguments to be in kmalloc'd memory, not in the module - * static data area. That means sha_pad needs to be kmalloc'd. - */ - -struct sha_pad { - unsigned char sha_pad1[SHA1_PAD_SIZE]; - unsigned char sha_pad2[SHA1_PAD_SIZE]; -}; -static struct sha_pad *sha_pad; - -static inline void sha_pad_init(struct sha_pad *shapad) -{ - memset(shapad->sha_pad1, 0x00, sizeof(shapad->sha_pad1)); - memset(shapad->sha_pad2, 0xF2, sizeof(shapad->sha_pad2)); -} - -/* - * State for an MPPE (de)compressor. - */ -struct ppp_mppe_state { - struct crypto_blkcipher *arc4; - struct crypto_hash *sha1; - unsigned char *sha1_digest; - unsigned char master_key[MPPE_MAX_KEY_LEN]; - unsigned char session_key[MPPE_MAX_KEY_LEN]; - unsigned keylen; /* key length in bytes */ - /* NB: 128-bit == 16, 40-bit == 8! */ - /* If we want to support 56-bit, */ - /* the unit has to change to bits */ - unsigned char bits; /* MPPE control bits */ - unsigned ccount; /* 12-bit coherency count (seqno) */ - unsigned stateful; /* stateful mode flag */ - int discard; /* stateful mode packet loss flag */ - int sanity_errors; /* take down LCP if too many */ - int unit; - int debug; - struct compstat stats; -}; - -/* struct ppp_mppe_state.bits definitions */ -#define MPPE_BIT_A 0x80 /* Encryption table were (re)inititalized */ -#define MPPE_BIT_B 0x40 /* MPPC only (not implemented) */ -#define MPPE_BIT_C 0x20 /* MPPC only (not implemented) */ -#define MPPE_BIT_D 0x10 /* This is an encrypted frame */ - -#define MPPE_BIT_FLUSHED MPPE_BIT_A -#define MPPE_BIT_ENCRYPTED MPPE_BIT_D - -#define MPPE_BITS(p) ((p)[4] & 0xf0) -#define MPPE_CCOUNT(p) ((((p)[4] & 0x0f) << 8) + (p)[5]) -#define MPPE_CCOUNT_SPACE 0x1000 /* The size of the ccount space */ - -#define MPPE_OVHD 2 /* MPPE overhead/packet */ -#define SANITY_MAX 1600 /* Max bogon factor we will tolerate */ - -/* - * Key Derivation, from RFC 3078, RFC 3079. - * Equivalent to Get_Key() for MS-CHAP as described in RFC 3079. - */ -static void get_new_key_from_sha(struct ppp_mppe_state * state) -{ - struct hash_desc desc; - struct scatterlist sg[4]; - unsigned int nbytes; - - sg_init_table(sg, 4); - - nbytes = setup_sg(&sg[0], state->master_key, state->keylen); - nbytes += setup_sg(&sg[1], sha_pad->sha_pad1, - sizeof(sha_pad->sha_pad1)); - nbytes += setup_sg(&sg[2], state->session_key, state->keylen); - nbytes += setup_sg(&sg[3], sha_pad->sha_pad2, - sizeof(sha_pad->sha_pad2)); - - desc.tfm = state->sha1; - desc.flags = 0; - - crypto_hash_digest(&desc, sg, nbytes, state->sha1_digest); -} - -/* - * Perform the MPPE rekey algorithm, from RFC 3078, sec. 7.3. - * Well, not what's written there, but rather what they meant. - */ -static void mppe_rekey(struct ppp_mppe_state * state, int initial_key) -{ - struct scatterlist sg_in[1], sg_out[1]; - struct blkcipher_desc desc = { .tfm = state->arc4 }; - - get_new_key_from_sha(state); - if (!initial_key) { - crypto_blkcipher_setkey(state->arc4, state->sha1_digest, - state->keylen); - sg_init_table(sg_in, 1); - sg_init_table(sg_out, 1); - setup_sg(sg_in, state->sha1_digest, state->keylen); - setup_sg(sg_out, state->session_key, state->keylen); - if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in, - state->keylen) != 0) { - printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n"); - } - } else { - memcpy(state->session_key, state->sha1_digest, state->keylen); - } - if (state->keylen == 8) { - /* See RFC 3078 */ - state->session_key[0] = 0xd1; - state->session_key[1] = 0x26; - state->session_key[2] = 0x9e; - } - crypto_blkcipher_setkey(state->arc4, state->session_key, state->keylen); -} - -/* - * Allocate space for a (de)compressor. - */ -static void *mppe_alloc(unsigned char *options, int optlen) -{ - struct ppp_mppe_state *state; - unsigned int digestsize; - - if (optlen != CILEN_MPPE + sizeof(state->master_key) || - options[0] != CI_MPPE || options[1] != CILEN_MPPE) - goto out; - - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (state == NULL) - goto out; - - - state->arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(state->arc4)) { - state->arc4 = NULL; - goto out_free; - } - - state->sha1 = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(state->sha1)) { - state->sha1 = NULL; - goto out_free; - } - - digestsize = crypto_hash_digestsize(state->sha1); - if (digestsize < MPPE_MAX_KEY_LEN) - goto out_free; - - state->sha1_digest = kmalloc(digestsize, GFP_KERNEL); - if (!state->sha1_digest) - goto out_free; - - /* Save keys. */ - memcpy(state->master_key, &options[CILEN_MPPE], - sizeof(state->master_key)); - memcpy(state->session_key, state->master_key, - sizeof(state->master_key)); - - /* - * We defer initial key generation until mppe_init(), as mppe_alloc() - * is called frequently during negotiation. - */ - - return (void *)state; - - out_free: - if (state->sha1_digest) - kfree(state->sha1_digest); - if (state->sha1) - crypto_free_hash(state->sha1); - if (state->arc4) - crypto_free_blkcipher(state->arc4); - kfree(state); - out: - return NULL; -} - -/* - * Deallocate space for a (de)compressor. - */ -static void mppe_free(void *arg) -{ - struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; - if (state) { - if (state->sha1_digest) - kfree(state->sha1_digest); - if (state->sha1) - crypto_free_hash(state->sha1); - if (state->arc4) - crypto_free_blkcipher(state->arc4); - kfree(state); - } -} - -/* - * Initialize (de)compressor state. - */ -static int -mppe_init(void *arg, unsigned char *options, int optlen, int unit, int debug, - const char *debugstr) -{ - struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; - unsigned char mppe_opts; - - if (optlen != CILEN_MPPE || - options[0] != CI_MPPE || options[1] != CILEN_MPPE) - return 0; - - MPPE_CI_TO_OPTS(&options[2], mppe_opts); - if (mppe_opts & MPPE_OPT_128) - state->keylen = 16; - else if (mppe_opts & MPPE_OPT_40) - state->keylen = 8; - else { - printk(KERN_WARNING "%s[%d]: unknown key length\n", debugstr, - unit); - return 0; - } - if (mppe_opts & MPPE_OPT_STATEFUL) - state->stateful = 1; - - /* Generate the initial session key. */ - mppe_rekey(state, 1); - - if (debug) { - int i; - char mkey[sizeof(state->master_key) * 2 + 1]; - char skey[sizeof(state->session_key) * 2 + 1]; - - printk(KERN_DEBUG "%s[%d]: initialized with %d-bit %s mode\n", - debugstr, unit, (state->keylen == 16) ? 128 : 40, - (state->stateful) ? "stateful" : "stateless"); - - for (i = 0; i < sizeof(state->master_key); i++) - sprintf(mkey + i * 2, "%02x", state->master_key[i]); - for (i = 0; i < sizeof(state->session_key); i++) - sprintf(skey + i * 2, "%02x", state->session_key[i]); - printk(KERN_DEBUG - "%s[%d]: keys: master: %s initial session: %s\n", - debugstr, unit, mkey, skey); - } - - /* - * Initialize the coherency count. The initial value is not specified - * in RFC 3078, but we can make a reasonable assumption that it will - * start at 0. Setting it to the max here makes the comp/decomp code - * do the right thing (determined through experiment). - */ - state->ccount = MPPE_CCOUNT_SPACE - 1; - - /* - * Note that even though we have initialized the key table, we don't - * set the FLUSHED bit. This is contrary to RFC 3078, sec. 3.1. - */ - state->bits = MPPE_BIT_ENCRYPTED; - - state->unit = unit; - state->debug = debug; - - return 1; -} - -static int -mppe_comp_init(void *arg, unsigned char *options, int optlen, int unit, - int hdrlen, int debug) -{ - /* ARGSUSED */ - return mppe_init(arg, options, optlen, unit, debug, "mppe_comp_init"); -} - -/* - * We received a CCP Reset-Request (actually, we are sending a Reset-Ack), - * tell the compressor to rekey. Note that we MUST NOT rekey for - * every CCP Reset-Request; we only rekey on the next xmit packet. - * We might get multiple CCP Reset-Requests if our CCP Reset-Ack is lost. - * So, rekeying for every CCP Reset-Request is broken as the peer will not - * know how many times we've rekeyed. (If we rekey and THEN get another - * CCP Reset-Request, we must rekey again.) - */ -static void mppe_comp_reset(void *arg) -{ - struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; - - state->bits |= MPPE_BIT_FLUSHED; -} - -/* - * Compress (encrypt) a packet. - * It's strange to call this a compressor, since the output is always - * MPPE_OVHD + 2 bytes larger than the input. - */ -static int -mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf, - int isize, int osize) -{ - struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; - struct blkcipher_desc desc = { .tfm = state->arc4 }; - int proto; - struct scatterlist sg_in[1], sg_out[1]; - - /* - * Check that the protocol is in the range we handle. - */ - proto = PPP_PROTOCOL(ibuf); - if (proto < 0x0021 || proto > 0x00fa) - return 0; - - /* Make sure we have enough room to generate an encrypted packet. */ - if (osize < isize + MPPE_OVHD + 2) { - /* Drop the packet if we should encrypt it, but can't. */ - printk(KERN_DEBUG "mppe_compress[%d]: osize too small! " - "(have: %d need: %d)\n", state->unit, - osize, osize + MPPE_OVHD + 2); - return -1; - } - - osize = isize + MPPE_OVHD + 2; - - /* - * Copy over the PPP header and set control bits. - */ - obuf[0] = PPP_ADDRESS(ibuf); - obuf[1] = PPP_CONTROL(ibuf); - put_unaligned_be16(PPP_COMP, obuf + 2); - obuf += PPP_HDRLEN; - - state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; - if (state->debug >= 7) - printk(KERN_DEBUG "mppe_compress[%d]: ccount %d\n", state->unit, - state->ccount); - put_unaligned_be16(state->ccount, obuf); - - if (!state->stateful || /* stateless mode */ - ((state->ccount & 0xff) == 0xff) || /* "flag" packet */ - (state->bits & MPPE_BIT_FLUSHED)) { /* CCP Reset-Request */ - /* We must rekey */ - if (state->debug && state->stateful) - printk(KERN_DEBUG "mppe_compress[%d]: rekeying\n", - state->unit); - mppe_rekey(state, 0); - state->bits |= MPPE_BIT_FLUSHED; - } - obuf[0] |= state->bits; - state->bits &= ~MPPE_BIT_FLUSHED; /* reset for next xmit */ - - obuf += MPPE_OVHD; - ibuf += 2; /* skip to proto field */ - isize -= 2; - - /* Encrypt packet */ - sg_init_table(sg_in, 1); - sg_init_table(sg_out, 1); - setup_sg(sg_in, ibuf, isize); - setup_sg(sg_out, obuf, osize); - if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in, isize) != 0) { - printk(KERN_DEBUG "crypto_cypher_encrypt failed\n"); - return -1; - } - - state->stats.unc_bytes += isize; - state->stats.unc_packets++; - state->stats.comp_bytes += osize; - state->stats.comp_packets++; - - return osize; -} - -/* - * Since every frame grows by MPPE_OVHD + 2 bytes, this is always going - * to look bad ... and the longer the link is up the worse it will get. - */ -static void mppe_comp_stats(void *arg, struct compstat *stats) -{ - struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; - - *stats = state->stats; -} - -static int -mppe_decomp_init(void *arg, unsigned char *options, int optlen, int unit, - int hdrlen, int mru, int debug) -{ - /* ARGSUSED */ - return mppe_init(arg, options, optlen, unit, debug, "mppe_decomp_init"); -} - -/* - * We received a CCP Reset-Ack. Just ignore it. - */ -static void mppe_decomp_reset(void *arg) -{ - /* ARGSUSED */ - return; -} - -/* - * Decompress (decrypt) an MPPE packet. - */ -static int -mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf, - int osize) -{ - struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; - struct blkcipher_desc desc = { .tfm = state->arc4 }; - unsigned ccount; - int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED; - int sanity = 0; - struct scatterlist sg_in[1], sg_out[1]; - - if (isize <= PPP_HDRLEN + MPPE_OVHD) { - if (state->debug) - printk(KERN_DEBUG - "mppe_decompress[%d]: short pkt (%d)\n", - state->unit, isize); - return DECOMP_ERROR; - } - - /* - * Make sure we have enough room to decrypt the packet. - * Note that for our test we only subtract 1 byte whereas in - * mppe_compress() we added 2 bytes (+MPPE_OVHD); - * this is to account for possible PFC. - */ - if (osize < isize - MPPE_OVHD - 1) { - printk(KERN_DEBUG "mppe_decompress[%d]: osize too small! " - "(have: %d need: %d)\n", state->unit, - osize, isize - MPPE_OVHD - 1); - return DECOMP_ERROR; - } - osize = isize - MPPE_OVHD - 2; /* assume no PFC */ - - ccount = MPPE_CCOUNT(ibuf); - if (state->debug >= 7) - printk(KERN_DEBUG "mppe_decompress[%d]: ccount %d\n", - state->unit, ccount); - - /* sanity checks -- terminate with extreme prejudice */ - if (!(MPPE_BITS(ibuf) & MPPE_BIT_ENCRYPTED)) { - printk(KERN_DEBUG - "mppe_decompress[%d]: ENCRYPTED bit not set!\n", - state->unit); - state->sanity_errors += 100; - sanity = 1; - } - if (!state->stateful && !flushed) { - printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set in " - "stateless mode!\n", state->unit); - state->sanity_errors += 100; - sanity = 1; - } - if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) { - printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set on " - "flag packet!\n", state->unit); - state->sanity_errors += 100; - sanity = 1; - } - - if (sanity) { - if (state->sanity_errors < SANITY_MAX) - return DECOMP_ERROR; - else - /* - * Take LCP down if the peer is sending too many bogons. - * We don't want to do this for a single or just a few - * instances since it could just be due to packet corruption. - */ - return DECOMP_FATALERROR; - } - - /* - * Check the coherency count. - */ - - if (!state->stateful) { - /* RFC 3078, sec 8.1. Rekey for every packet. */ - while (state->ccount != ccount) { - mppe_rekey(state, 0); - state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; - } - } else { - /* RFC 3078, sec 8.2. */ - if (!state->discard) { - /* normal state */ - state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; - if (ccount != state->ccount) { - /* - * (ccount > state->ccount) - * Packet loss detected, enter the discard state. - * Signal the peer to rekey (by sending a CCP Reset-Request). - */ - state->discard = 1; - return DECOMP_ERROR; - } - } else { - /* discard state */ - if (!flushed) { - /* ccp.c will be silent (no additional CCP Reset-Requests). */ - return DECOMP_ERROR; - } else { - /* Rekey for every missed "flag" packet. */ - while ((ccount & ~0xff) != - (state->ccount & ~0xff)) { - mppe_rekey(state, 0); - state->ccount = - (state->ccount + - 256) % MPPE_CCOUNT_SPACE; - } - - /* reset */ - state->discard = 0; - state->ccount = ccount; - /* - * Another problem with RFC 3078 here. It implies that the - * peer need not send a Reset-Ack packet. But RFC 1962 - * requires it. Hopefully, M$ does send a Reset-Ack; even - * though it isn't required for MPPE synchronization, it is - * required to reset CCP state. - */ - } - } - if (flushed) - mppe_rekey(state, 0); - } - - /* - * Fill in the first part of the PPP header. The protocol field - * comes from the decrypted data. - */ - obuf[0] = PPP_ADDRESS(ibuf); /* +1 */ - obuf[1] = PPP_CONTROL(ibuf); /* +1 */ - obuf += 2; - ibuf += PPP_HDRLEN + MPPE_OVHD; - isize -= PPP_HDRLEN + MPPE_OVHD; /* -6 */ - /* net osize: isize-4 */ - - /* - * Decrypt the first byte in order to check if it is - * a compressed or uncompressed protocol field. - */ - sg_init_table(sg_in, 1); - sg_init_table(sg_out, 1); - setup_sg(sg_in, ibuf, 1); - setup_sg(sg_out, obuf, 1); - if (crypto_blkcipher_decrypt(&desc, sg_out, sg_in, 1) != 0) { - printk(KERN_DEBUG "crypto_cypher_decrypt failed\n"); - return DECOMP_ERROR; - } - - /* - * Do PFC decompression. - * This would be nicer if we were given the actual sk_buff - * instead of a char *. - */ - if ((obuf[0] & 0x01) != 0) { - obuf[1] = obuf[0]; - obuf[0] = 0; - obuf++; - osize++; - } - - /* And finally, decrypt the rest of the packet. */ - setup_sg(sg_in, ibuf + 1, isize - 1); - setup_sg(sg_out, obuf + 1, osize - 1); - if (crypto_blkcipher_decrypt(&desc, sg_out, sg_in, isize - 1)) { - printk(KERN_DEBUG "crypto_cypher_decrypt failed\n"); - return DECOMP_ERROR; - } - - state->stats.unc_bytes += osize; - state->stats.unc_packets++; - state->stats.comp_bytes += isize; - state->stats.comp_packets++; - - /* good packet credit */ - state->sanity_errors >>= 1; - - return osize; -} - -/* - * Incompressible data has arrived (this should never happen!). - * We should probably drop the link if the protocol is in the range - * of what should be encrypted. At the least, we should drop this - * packet. (How to do this?) - */ -static void mppe_incomp(void *arg, unsigned char *ibuf, int icnt) -{ - struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; - - if (state->debug && - (PPP_PROTOCOL(ibuf) >= 0x0021 && PPP_PROTOCOL(ibuf) <= 0x00fa)) - printk(KERN_DEBUG - "mppe_incomp[%d]: incompressible (unencrypted) data! " - "(proto %04x)\n", state->unit, PPP_PROTOCOL(ibuf)); - - state->stats.inc_bytes += icnt; - state->stats.inc_packets++; - state->stats.unc_bytes += icnt; - state->stats.unc_packets++; -} - -/************************************************************* - * Module interface table - *************************************************************/ - -/* - * Procedures exported to if_ppp.c. - */ -static struct compressor ppp_mppe = { - .compress_proto = CI_MPPE, - .comp_alloc = mppe_alloc, - .comp_free = mppe_free, - .comp_init = mppe_comp_init, - .comp_reset = mppe_comp_reset, - .compress = mppe_compress, - .comp_stat = mppe_comp_stats, - .decomp_alloc = mppe_alloc, - .decomp_free = mppe_free, - .decomp_init = mppe_decomp_init, - .decomp_reset = mppe_decomp_reset, - .decompress = mppe_decompress, - .incomp = mppe_incomp, - .decomp_stat = mppe_comp_stats, - .owner = THIS_MODULE, - .comp_extra = MPPE_PAD, -}; - -/* - * ppp_mppe_init() - * - * Prior to allowing load, try to load the arc4 and sha1 crypto - * libraries. The actual use will be allocated later, but - * this way the module will fail to insmod if they aren't available. - */ - -static int __init ppp_mppe_init(void) -{ - int answer; - if (!(crypto_has_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC) && - crypto_has_hash("sha1", 0, CRYPTO_ALG_ASYNC))) - return -ENODEV; - - sha_pad = kmalloc(sizeof(struct sha_pad), GFP_KERNEL); - if (!sha_pad) - return -ENOMEM; - sha_pad_init(sha_pad); - - answer = ppp_register_compressor(&ppp_mppe); - - if (answer == 0) - printk(KERN_INFO "PPP MPPE Compression module registered\n"); - else - kfree(sha_pad); - - return answer; -} - -static void __exit ppp_mppe_cleanup(void) -{ - ppp_unregister_compressor(&ppp_mppe); - kfree(sha_pad); -} - -module_init(ppp_mppe_init); -module_exit(ppp_mppe_cleanup); diff --git a/drivers/net/ppp_mppe.h b/drivers/net/ppp_mppe.h deleted file mode 100644 index 7a14e05..0000000 --- a/drivers/net/ppp_mppe.h +++ /dev/null @@ -1,86 +0,0 @@ -#define MPPE_PAD 4 /* MPPE growth per frame */ -#define MPPE_MAX_KEY_LEN 16 /* largest key length (128-bit) */ - -/* option bits for ccp_options.mppe */ -#define MPPE_OPT_40 0x01 /* 40 bit */ -#define MPPE_OPT_128 0x02 /* 128 bit */ -#define MPPE_OPT_STATEFUL 0x04 /* stateful mode */ -/* unsupported opts */ -#define MPPE_OPT_56 0x08 /* 56 bit */ -#define MPPE_OPT_MPPC 0x10 /* MPPC compression */ -#define MPPE_OPT_D 0x20 /* Unknown */ -#define MPPE_OPT_UNSUPPORTED (MPPE_OPT_56|MPPE_OPT_MPPC|MPPE_OPT_D) -#define MPPE_OPT_UNKNOWN 0x40 /* Bits !defined in RFC 3078 were set */ - -/* - * This is not nice ... the alternative is a bitfield struct though. - * And unfortunately, we cannot share the same bits for the option - * names above since C and H are the same bit. We could do a u_int32 - * but then we have to do a htonl() all the time and/or we still need - * to know which octet is which. - */ -#define MPPE_C_BIT 0x01 /* MPPC */ -#define MPPE_D_BIT 0x10 /* Obsolete, usage unknown */ -#define MPPE_L_BIT 0x20 /* 40-bit */ -#define MPPE_S_BIT 0x40 /* 128-bit */ -#define MPPE_M_BIT 0x80 /* 56-bit, not supported */ -#define MPPE_H_BIT 0x01 /* Stateless (in a different byte) */ - -/* Does not include H bit; used for least significant octet only. */ -#define MPPE_ALL_BITS (MPPE_D_BIT|MPPE_L_BIT|MPPE_S_BIT|MPPE_M_BIT|MPPE_H_BIT) - -/* Build a CI from mppe opts (see RFC 3078) */ -#define MPPE_OPTS_TO_CI(opts, ci) \ - do { \ - u_char *ptr = ci; /* u_char[4] */ \ - \ - /* H bit */ \ - if (opts & MPPE_OPT_STATEFUL) \ - *ptr++ = 0x0; \ - else \ - *ptr++ = MPPE_H_BIT; \ - *ptr++ = 0; \ - *ptr++ = 0; \ - \ - /* S,L bits */ \ - *ptr = 0; \ - if (opts & MPPE_OPT_128) \ - *ptr |= MPPE_S_BIT; \ - if (opts & MPPE_OPT_40) \ - *ptr |= MPPE_L_BIT; \ - /* M,D,C bits not supported */ \ - } while (/* CONSTCOND */ 0) - -/* The reverse of the above */ -#define MPPE_CI_TO_OPTS(ci, opts) \ - do { \ - u_char *ptr = ci; /* u_char[4] */ \ - \ - opts = 0; \ - \ - /* H bit */ \ - if (!(ptr[0] & MPPE_H_BIT)) \ - opts |= MPPE_OPT_STATEFUL; \ - \ - /* S,L bits */ \ - if (ptr[3] & MPPE_S_BIT) \ - opts |= MPPE_OPT_128; \ - if (ptr[3] & MPPE_L_BIT) \ - opts |= MPPE_OPT_40; \ - \ - /* M,D,C bits */ \ - if (ptr[3] & MPPE_M_BIT) \ - opts |= MPPE_OPT_56; \ - if (ptr[3] & MPPE_D_BIT) \ - opts |= MPPE_OPT_D; \ - if (ptr[3] & MPPE_C_BIT) \ - opts |= MPPE_OPT_MPPC; \ - \ - /* Other bits */ \ - if (ptr[0] & ~MPPE_H_BIT) \ - opts |= MPPE_OPT_UNKNOWN; \ - if (ptr[1] || ptr[2]) \ - opts |= MPPE_OPT_UNKNOWN; \ - if (ptr[3] & ~MPPE_ALL_BITS) \ - opts |= MPPE_OPT_UNKNOWN; \ - } while (/* CONSTCOND */ 0) diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c deleted file mode 100644 index 736a39e..0000000 --- a/drivers/net/ppp_synctty.c +++ /dev/null @@ -1,790 +0,0 @@ -/* - * PPP synchronous tty channel driver for Linux. - * - * This is a ppp channel driver that can be used with tty device drivers - * that are frame oriented, such as synchronous HDLC devices. - * - * Complete PPP frames without encoding/decoding are exchanged between - * the channel driver and the device driver. - * - * The async map IOCTL codes are implemented to keep the user mode - * applications happy if they call them. Synchronous PPP does not use - * the async maps. - * - * Copyright 1999 Paul Mackerras. - * - * Also touched by the grubby hands of Paul Fulghum paulkf@microgate.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * This driver provides the encapsulation and framing for sending - * and receiving PPP frames over sync serial lines. It relies on - * the generic PPP layer to give it frames to send and to process - * received frames. It implements the PPP line discipline. - * - * Part of the code in this driver was inspired by the old async-only - * PPP driver, written by Michael Callahan and Al Longyear, and - * subsequently hacked by Paul Mackerras. - * - * ==FILEVERSION 20040616== - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PPP_VERSION "2.4.2" - -/* Structure for storing local state. */ -struct syncppp { - struct tty_struct *tty; - unsigned int flags; - unsigned int rbits; - int mru; - spinlock_t xmit_lock; - spinlock_t recv_lock; - unsigned long xmit_flags; - u32 xaccm[8]; - u32 raccm; - unsigned int bytes_sent; - unsigned int bytes_rcvd; - - struct sk_buff *tpkt; - unsigned long last_xmit; - - struct sk_buff_head rqueue; - - struct tasklet_struct tsk; - - atomic_t refcnt; - struct completion dead_cmp; - struct ppp_channel chan; /* interface to generic ppp layer */ -}; - -/* Bit numbers in xmit_flags */ -#define XMIT_WAKEUP 0 -#define XMIT_FULL 1 - -/* Bits in rbits */ -#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) - -#define PPPSYNC_MAX_RQLEN 32 /* arbitrary */ - -/* - * Prototypes. - */ -static struct sk_buff* ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *); -static int ppp_sync_send(struct ppp_channel *chan, struct sk_buff *skb); -static int ppp_sync_ioctl(struct ppp_channel *chan, unsigned int cmd, - unsigned long arg); -static void ppp_sync_process(unsigned long arg); -static int ppp_sync_push(struct syncppp *ap); -static void ppp_sync_flush_output(struct syncppp *ap); -static void ppp_sync_input(struct syncppp *ap, const unsigned char *buf, - char *flags, int count); - -static const struct ppp_channel_ops sync_ops = { - .start_xmit = ppp_sync_send, - .ioctl = ppp_sync_ioctl, -}; - -/* - * Utility procedures to print a buffer in hex/ascii - */ -static void -ppp_print_hex (register __u8 * out, const __u8 * in, int count) -{ - register __u8 next_ch; - static const char hex[] = "0123456789ABCDEF"; - - while (count-- > 0) { - next_ch = *in++; - *out++ = hex[(next_ch >> 4) & 0x0F]; - *out++ = hex[next_ch & 0x0F]; - ++out; - } -} - -static void -ppp_print_char (register __u8 * out, const __u8 * in, int count) -{ - register __u8 next_ch; - - while (count-- > 0) { - next_ch = *in++; - - if (next_ch < 0x20 || next_ch > 0x7e) - *out++ = '.'; - else { - *out++ = next_ch; - if (next_ch == '%') /* printk/syslogd has a bug !! */ - *out++ = '%'; - } - } - *out = '\0'; -} - -static void -ppp_print_buffer (const char *name, const __u8 *buf, int count) -{ - __u8 line[44]; - - if (name != NULL) - printk(KERN_DEBUG "ppp_synctty: %s, count = %d\n", name, count); - - while (count > 8) { - memset (line, 32, 44); - ppp_print_hex (line, buf, 8); - ppp_print_char (&line[8 * 3], buf, 8); - printk(KERN_DEBUG "%s\n", line); - count -= 8; - buf += 8; - } - - if (count > 0) { - memset (line, 32, 44); - ppp_print_hex (line, buf, count); - ppp_print_char (&line[8 * 3], buf, count); - printk(KERN_DEBUG "%s\n", line); - } -} - - -/* - * Routines implementing the synchronous PPP line discipline. - */ - -/* - * We have a potential race on dereferencing tty->disc_data, - * because the tty layer provides no locking at all - thus one - * cpu could be running ppp_synctty_receive while another - * calls ppp_synctty_close, which zeroes tty->disc_data and - * frees the memory that ppp_synctty_receive is using. The best - * way to fix this is to use a rwlock in the tty struct, but for now - * we use a single global rwlock for all ttys in ppp line discipline. - * - * FIXME: Fixed in tty_io nowadays. - */ -static DEFINE_RWLOCK(disc_data_lock); - -static struct syncppp *sp_get(struct tty_struct *tty) -{ - struct syncppp *ap; - - read_lock(&disc_data_lock); - ap = tty->disc_data; - if (ap != NULL) - atomic_inc(&ap->refcnt); - read_unlock(&disc_data_lock); - return ap; -} - -static void sp_put(struct syncppp *ap) -{ - if (atomic_dec_and_test(&ap->refcnt)) - complete(&ap->dead_cmp); -} - -/* - * Called when a tty is put into sync-PPP line discipline. - */ -static int -ppp_sync_open(struct tty_struct *tty) -{ - struct syncppp *ap; - int err; - int speed; - - if (tty->ops->write == NULL) - return -EOPNOTSUPP; - - ap = kzalloc(sizeof(*ap), GFP_KERNEL); - err = -ENOMEM; - if (!ap) - goto out; - - /* initialize the syncppp structure */ - ap->tty = tty; - ap->mru = PPP_MRU; - spin_lock_init(&ap->xmit_lock); - spin_lock_init(&ap->recv_lock); - ap->xaccm[0] = ~0U; - ap->xaccm[3] = 0x60000000U; - ap->raccm = ~0U; - - skb_queue_head_init(&ap->rqueue); - tasklet_init(&ap->tsk, ppp_sync_process, (unsigned long) ap); - - atomic_set(&ap->refcnt, 1); - init_completion(&ap->dead_cmp); - - ap->chan.private = ap; - ap->chan.ops = &sync_ops; - ap->chan.mtu = PPP_MRU; - ap->chan.hdrlen = 2; /* for A/C bytes */ - speed = tty_get_baud_rate(tty); - ap->chan.speed = speed; - err = ppp_register_channel(&ap->chan); - if (err) - goto out_free; - - tty->disc_data = ap; - tty->receive_room = 65536; - return 0; - - out_free: - kfree(ap); - out: - return err; -} - -/* - * Called when the tty is put into another line discipline - * or it hangs up. We have to wait for any cpu currently - * executing in any of the other ppp_synctty_* routines to - * finish before we can call ppp_unregister_channel and free - * the syncppp struct. This routine must be called from - * process context, not interrupt or softirq context. - */ -static void -ppp_sync_close(struct tty_struct *tty) -{ - struct syncppp *ap; - - write_lock_irq(&disc_data_lock); - ap = tty->disc_data; - tty->disc_data = NULL; - write_unlock_irq(&disc_data_lock); - if (!ap) - return; - - /* - * We have now ensured that nobody can start using ap from now - * on, but we have to wait for all existing users to finish. - * Note that ppp_unregister_channel ensures that no calls to - * our channel ops (i.e. ppp_sync_send/ioctl) are in progress - * by the time it returns. - */ - if (!atomic_dec_and_test(&ap->refcnt)) - wait_for_completion(&ap->dead_cmp); - tasklet_kill(&ap->tsk); - - ppp_unregister_channel(&ap->chan); - skb_queue_purge(&ap->rqueue); - kfree_skb(ap->tpkt); - kfree(ap); -} - -/* - * Called on tty hangup in process context. - * - * Wait for I/O to driver to complete and unregister PPP channel. - * This is already done by the close routine, so just call that. - */ -static int ppp_sync_hangup(struct tty_struct *tty) -{ - ppp_sync_close(tty); - return 0; -} - -/* - * Read does nothing - no data is ever available this way. - * Pppd reads and writes packets via /dev/ppp instead. - */ -static ssize_t -ppp_sync_read(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t count) -{ - return -EAGAIN; -} - -/* - * Write on the tty does nothing, the packets all come in - * from the ppp generic stuff. - */ -static ssize_t -ppp_sync_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t count) -{ - return -EAGAIN; -} - -static int -ppp_synctty_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct syncppp *ap = sp_get(tty); - int __user *p = (int __user *)arg; - int err, val; - - if (!ap) - return -ENXIO; - err = -EFAULT; - switch (cmd) { - case PPPIOCGCHAN: - err = -EFAULT; - if (put_user(ppp_channel_index(&ap->chan), p)) - break; - err = 0; - break; - - case PPPIOCGUNIT: - err = -EFAULT; - if (put_user(ppp_unit_number(&ap->chan), p)) - break; - err = 0; - break; - - case TCFLSH: - /* flush our buffers and the serial port's buffer */ - if (arg == TCIOFLUSH || arg == TCOFLUSH) - ppp_sync_flush_output(ap); - err = tty_perform_flush(tty, arg); - break; - - case FIONREAD: - val = 0; - if (put_user(val, p)) - break; - err = 0; - break; - - default: - err = tty_mode_ioctl(tty, file, cmd, arg); - break; - } - - sp_put(ap); - return err; -} - -/* No kernel lock - fine */ -static unsigned int -ppp_sync_poll(struct tty_struct *tty, struct file *file, poll_table *wait) -{ - return 0; -} - -/* May sleep, don't call from interrupt level or with interrupts disabled */ -static void -ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf, - char *cflags, int count) -{ - struct syncppp *ap = sp_get(tty); - unsigned long flags; - - if (!ap) - return; - spin_lock_irqsave(&ap->recv_lock, flags); - ppp_sync_input(ap, buf, cflags, count); - spin_unlock_irqrestore(&ap->recv_lock, flags); - if (!skb_queue_empty(&ap->rqueue)) - tasklet_schedule(&ap->tsk); - sp_put(ap); - tty_unthrottle(tty); -} - -static void -ppp_sync_wakeup(struct tty_struct *tty) -{ - struct syncppp *ap = sp_get(tty); - - clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - if (!ap) - return; - set_bit(XMIT_WAKEUP, &ap->xmit_flags); - tasklet_schedule(&ap->tsk); - sp_put(ap); -} - - -static struct tty_ldisc_ops ppp_sync_ldisc = { - .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, - .name = "pppsync", - .open = ppp_sync_open, - .close = ppp_sync_close, - .hangup = ppp_sync_hangup, - .read = ppp_sync_read, - .write = ppp_sync_write, - .ioctl = ppp_synctty_ioctl, - .poll = ppp_sync_poll, - .receive_buf = ppp_sync_receive, - .write_wakeup = ppp_sync_wakeup, -}; - -static int __init -ppp_sync_init(void) -{ - int err; - - err = tty_register_ldisc(N_SYNC_PPP, &ppp_sync_ldisc); - if (err != 0) - printk(KERN_ERR "PPP_sync: error %d registering line disc.\n", - err); - return err; -} - -/* - * The following routines provide the PPP channel interface. - */ -static int -ppp_sync_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg) -{ - struct syncppp *ap = chan->private; - int err, val; - u32 accm[8]; - void __user *argp = (void __user *)arg; - u32 __user *p = argp; - - err = -EFAULT; - switch (cmd) { - case PPPIOCGFLAGS: - val = ap->flags | ap->rbits; - if (put_user(val, (int __user *) argp)) - break; - err = 0; - break; - case PPPIOCSFLAGS: - if (get_user(val, (int __user *) argp)) - break; - ap->flags = val & ~SC_RCV_BITS; - spin_lock_irq(&ap->recv_lock); - ap->rbits = val & SC_RCV_BITS; - spin_unlock_irq(&ap->recv_lock); - err = 0; - break; - - case PPPIOCGASYNCMAP: - if (put_user(ap->xaccm[0], p)) - break; - err = 0; - break; - case PPPIOCSASYNCMAP: - if (get_user(ap->xaccm[0], p)) - break; - err = 0; - break; - - case PPPIOCGRASYNCMAP: - if (put_user(ap->raccm, p)) - break; - err = 0; - break; - case PPPIOCSRASYNCMAP: - if (get_user(ap->raccm, p)) - break; - err = 0; - break; - - case PPPIOCGXASYNCMAP: - if (copy_to_user(argp, ap->xaccm, sizeof(ap->xaccm))) - break; - err = 0; - break; - case PPPIOCSXASYNCMAP: - if (copy_from_user(accm, argp, sizeof(accm))) - break; - accm[2] &= ~0x40000000U; /* can't escape 0x5e */ - accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */ - memcpy(ap->xaccm, accm, sizeof(ap->xaccm)); - err = 0; - break; - - case PPPIOCGMRU: - if (put_user(ap->mru, (int __user *) argp)) - break; - err = 0; - break; - case PPPIOCSMRU: - if (get_user(val, (int __user *) argp)) - break; - if (val < PPP_MRU) - val = PPP_MRU; - ap->mru = val; - err = 0; - break; - - default: - err = -ENOTTY; - } - return err; -} - -/* - * This is called at softirq level to deliver received packets - * to the ppp_generic code, and to tell the ppp_generic code - * if we can accept more output now. - */ -static void ppp_sync_process(unsigned long arg) -{ - struct syncppp *ap = (struct syncppp *) arg; - struct sk_buff *skb; - - /* process received packets */ - while ((skb = skb_dequeue(&ap->rqueue)) != NULL) { - if (skb->len == 0) { - /* zero length buffers indicate error */ - ppp_input_error(&ap->chan, 0); - kfree_skb(skb); - } - else - ppp_input(&ap->chan, skb); - } - - /* try to push more stuff out */ - if (test_bit(XMIT_WAKEUP, &ap->xmit_flags) && ppp_sync_push(ap)) - ppp_output_wakeup(&ap->chan); -} - -/* - * Procedures for encapsulation and framing. - */ - -static struct sk_buff* -ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb) -{ - int proto; - unsigned char *data; - int islcp; - - data = skb->data; - proto = get_unaligned_be16(data); - - /* LCP packets with codes between 1 (configure-request) - * and 7 (code-reject) must be sent as though no options - * have been negotiated. - */ - islcp = proto == PPP_LCP && 1 <= data[2] && data[2] <= 7; - - /* compress protocol field if option enabled */ - if (data[0] == 0 && (ap->flags & SC_COMP_PROT) && !islcp) - skb_pull(skb,1); - - /* prepend address/control fields if necessary */ - if ((ap->flags & SC_COMP_AC) == 0 || islcp) { - if (skb_headroom(skb) < 2) { - struct sk_buff *npkt = dev_alloc_skb(skb->len + 2); - if (npkt == NULL) { - kfree_skb(skb); - return NULL; - } - skb_reserve(npkt,2); - skb_copy_from_linear_data(skb, - skb_put(npkt, skb->len), skb->len); - kfree_skb(skb); - skb = npkt; - } - skb_push(skb,2); - skb->data[0] = PPP_ALLSTATIONS; - skb->data[1] = PPP_UI; - } - - ap->last_xmit = jiffies; - - if (skb && ap->flags & SC_LOG_OUTPKT) - ppp_print_buffer ("send buffer", skb->data, skb->len); - - return skb; -} - -/* - * Transmit-side routines. - */ - -/* - * Send a packet to the peer over an sync tty line. - * Returns 1 iff the packet was accepted. - * If the packet was not accepted, we will call ppp_output_wakeup - * at some later time. - */ -static int -ppp_sync_send(struct ppp_channel *chan, struct sk_buff *skb) -{ - struct syncppp *ap = chan->private; - - ppp_sync_push(ap); - - if (test_and_set_bit(XMIT_FULL, &ap->xmit_flags)) - return 0; /* already full */ - skb = ppp_sync_txmunge(ap, skb); - if (skb != NULL) - ap->tpkt = skb; - else - clear_bit(XMIT_FULL, &ap->xmit_flags); - - ppp_sync_push(ap); - return 1; -} - -/* - * Push as much data as possible out to the tty. - */ -static int -ppp_sync_push(struct syncppp *ap) -{ - int sent, done = 0; - struct tty_struct *tty = ap->tty; - int tty_stuffed = 0; - - if (!spin_trylock_bh(&ap->xmit_lock)) - return 0; - for (;;) { - if (test_and_clear_bit(XMIT_WAKEUP, &ap->xmit_flags)) - tty_stuffed = 0; - if (!tty_stuffed && ap->tpkt) { - set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - sent = tty->ops->write(tty, ap->tpkt->data, ap->tpkt->len); - if (sent < 0) - goto flush; /* error, e.g. loss of CD */ - if (sent < ap->tpkt->len) { - tty_stuffed = 1; - } else { - kfree_skb(ap->tpkt); - ap->tpkt = NULL; - clear_bit(XMIT_FULL, &ap->xmit_flags); - done = 1; - } - continue; - } - /* haven't made any progress */ - spin_unlock_bh(&ap->xmit_lock); - if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags) || - (!tty_stuffed && ap->tpkt))) - break; - if (!spin_trylock_bh(&ap->xmit_lock)) - break; - } - return done; - -flush: - if (ap->tpkt) { - kfree_skb(ap->tpkt); - ap->tpkt = NULL; - clear_bit(XMIT_FULL, &ap->xmit_flags); - done = 1; - } - spin_unlock_bh(&ap->xmit_lock); - return done; -} - -/* - * Flush output from our internal buffers. - * Called for the TCFLSH ioctl. - */ -static void -ppp_sync_flush_output(struct syncppp *ap) -{ - int done = 0; - - spin_lock_bh(&ap->xmit_lock); - if (ap->tpkt != NULL) { - kfree_skb(ap->tpkt); - ap->tpkt = NULL; - clear_bit(XMIT_FULL, &ap->xmit_flags); - done = 1; - } - spin_unlock_bh(&ap->xmit_lock); - if (done) - ppp_output_wakeup(&ap->chan); -} - -/* - * Receive-side routines. - */ - -/* called when the tty driver has data for us. - * - * Data is frame oriented: each call to ppp_sync_input is considered - * a whole frame. If the 1st flag byte is non-zero then the whole - * frame is considered to be in error and is tossed. - */ -static void -ppp_sync_input(struct syncppp *ap, const unsigned char *buf, - char *flags, int count) -{ - struct sk_buff *skb; - unsigned char *p; - - if (count == 0) - return; - - if (ap->flags & SC_LOG_INPKT) - ppp_print_buffer ("receive buffer", buf, count); - - /* stuff the chars in the skb */ - skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2); - if (!skb) { - printk(KERN_ERR "PPPsync: no memory (input pkt)\n"); - goto err; - } - /* Try to get the payload 4-byte aligned */ - if (buf[0] != PPP_ALLSTATIONS) - skb_reserve(skb, 2 + (buf[0] & 1)); - - if (flags && *flags) { - /* error flag set, ignore frame */ - goto err; - } else if (count > skb_tailroom(skb)) { - /* packet overflowed MRU */ - goto err; - } - - p = skb_put(skb, count); - memcpy(p, buf, count); - - /* strip address/control field if present */ - p = skb->data; - if (p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) { - /* chop off address/control */ - if (skb->len < 3) - goto err; - p = skb_pull(skb, 2); - } - - /* decompress protocol field if compressed */ - if (p[0] & 1) { - /* protocol is compressed */ - skb_push(skb, 1)[0] = 0; - } else if (skb->len < 2) - goto err; - - /* queue the frame to be processed */ - skb_queue_tail(&ap->rqueue, skb); - return; - -err: - /* queue zero length packet as error indication */ - if (skb || (skb = dev_alloc_skb(0))) { - skb_trim(skb, 0); - skb_queue_tail(&ap->rqueue, skb); - } -} - -static void __exit -ppp_sync_cleanup(void) -{ - if (tty_unregister_ldisc(N_SYNC_PPP) != 0) - printk(KERN_ERR "failed to unregister Sync PPP line discipline\n"); -} - -module_init(ppp_sync_init); -module_exit(ppp_sync_cleanup); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_LDISC(N_SYNC_PPP); diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c deleted file mode 100644 index bc9a4bb..0000000 --- a/drivers/net/pppoe.c +++ /dev/null @@ -1,1208 +0,0 @@ -/** -*- linux-c -*- *********************************************************** - * Linux PPP over Ethernet (PPPoX/PPPoE) Sockets - * - * PPPoX --- Generic PPP encapsulation socket family - * PPPoE --- PPP over Ethernet (RFC 2516) - * - * - * Version: 0.7.0 - * - * 070228 : Fix to allow multiple sessions with same remote MAC and same - * session id by including the local device ifindex in the - * tuple identifying a session. This also ensures packets can't - * be injected into a session from interfaces other than the one - * specified by userspace. Florian Zumbiehl - * (Oh, BTW, this one is YYMMDD, in case you were wondering ...) - * 220102 : Fix module use count on failure in pppoe_create, pppox_sk -acme - * 030700 : Fixed connect logic to allow for disconnect. - * 270700 : Fixed potential SMP problems; we must protect against - * simultaneous invocation of ppp_input - * and ppp_unregister_channel. - * 040800 : Respect reference count mechanisms on net-devices. - * 200800 : fix kfree(skb) in pppoe_rcv (acme) - * Module reference count is decremented in the right spot now, - * guards against sock_put not actually freeing the sk - * in pppoe_release. - * 051000 : Initialization cleanup. - * 111100 : Fix recvmsg. - * 050101 : Fix PADT procesing. - * 140501 : Use pppoe_rcv_core to handle all backlog. (Alexey) - * 170701 : Do not lock_sock with rwlock held. (DaveM) - * Ignore discovery frames if user has socket - * locked. (DaveM) - * Ignore return value of dev_queue_xmit in __pppoe_xmit - * or else we may kfree an SKB twice. (DaveM) - * 190701 : When doing copies of skb's in __pppoe_xmit, always delete - * the original skb that was passed in on success, never on - * failure. Delete the copy of the skb on failure to avoid - * a memory leak. - * 081001 : Misc. cleanup (licence string, non-blocking, prevent - * reference of device on close). - * 121301 : New ppp channels interface; cannot unregister a channel - * from interrupts. Thus, we mark the socket as a ZOMBIE - * and do the unregistration later. - * 081002 : seq_file support for proc stuff -acme - * 111602 : Merge all 2.4 fixes into 2.5/2.6 tree. Label 2.5/2.6 - * as version 0.7. Spacing cleanup. - * Author: Michal Ostrowski - * Contributors: - * Arnaldo Carvalho de Melo - * David S. Miller (davem@redhat.com) - * - * License: - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#define PPPOE_HASH_BITS 4 -#define PPPOE_HASH_SIZE (1 << PPPOE_HASH_BITS) -#define PPPOE_HASH_MASK (PPPOE_HASH_SIZE - 1) - -static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb); - -static const struct proto_ops pppoe_ops; -static const struct ppp_channel_ops pppoe_chan_ops; - -/* per-net private data for this module */ -static int pppoe_net_id __read_mostly; -struct pppoe_net { - /* - * we could use _single_ hash table for all - * nets by injecting net id into the hash but - * it would increase hash chains and add - * a few additional math comparations messy - * as well, moreover in case of SMP less locking - * controversy here - */ - struct pppox_sock *hash_table[PPPOE_HASH_SIZE]; - rwlock_t hash_lock; -}; - -/* - * PPPoE could be in the following stages: - * 1) Discovery stage (to obtain remote MAC and Session ID) - * 2) Session stage (MAC and SID are known) - * - * Ethernet frames have a special tag for this but - * we use simpler approach based on session id - */ -static inline bool stage_session(__be16 sid) -{ - return sid != 0; -} - -static inline struct pppoe_net *pppoe_pernet(struct net *net) -{ - BUG_ON(!net); - - return net_generic(net, pppoe_net_id); -} - -static inline int cmp_2_addr(struct pppoe_addr *a, struct pppoe_addr *b) -{ - return a->sid == b->sid && !memcmp(a->remote, b->remote, ETH_ALEN); -} - -static inline int cmp_addr(struct pppoe_addr *a, __be16 sid, char *addr) -{ - return a->sid == sid && !memcmp(a->remote, addr, ETH_ALEN); -} - -#if 8 % PPPOE_HASH_BITS -#error 8 must be a multiple of PPPOE_HASH_BITS -#endif - -static int hash_item(__be16 sid, unsigned char *addr) -{ - unsigned char hash = 0; - unsigned int i; - - for (i = 0; i < ETH_ALEN; i++) - hash ^= addr[i]; - for (i = 0; i < sizeof(sid_t) * 8; i += 8) - hash ^= (__force __u32)sid >> i; - for (i = 8; (i >>= 1) >= PPPOE_HASH_BITS;) - hash ^= hash >> i; - - return hash & PPPOE_HASH_MASK; -} - -/********************************************************************** - * - * Set/get/delete/rehash items (internal versions) - * - **********************************************************************/ -static struct pppox_sock *__get_item(struct pppoe_net *pn, __be16 sid, - unsigned char *addr, int ifindex) -{ - int hash = hash_item(sid, addr); - struct pppox_sock *ret; - - ret = pn->hash_table[hash]; - while (ret) { - if (cmp_addr(&ret->pppoe_pa, sid, addr) && - ret->pppoe_ifindex == ifindex) - return ret; - - ret = ret->next; - } - - return NULL; -} - -static int __set_item(struct pppoe_net *pn, struct pppox_sock *po) -{ - int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote); - struct pppox_sock *ret; - - ret = pn->hash_table[hash]; - while (ret) { - if (cmp_2_addr(&ret->pppoe_pa, &po->pppoe_pa) && - ret->pppoe_ifindex == po->pppoe_ifindex) - return -EALREADY; - - ret = ret->next; - } - - po->next = pn->hash_table[hash]; - pn->hash_table[hash] = po; - - return 0; -} - -static struct pppox_sock *__delete_item(struct pppoe_net *pn, __be16 sid, - char *addr, int ifindex) -{ - int hash = hash_item(sid, addr); - struct pppox_sock *ret, **src; - - ret = pn->hash_table[hash]; - src = &pn->hash_table[hash]; - - while (ret) { - if (cmp_addr(&ret->pppoe_pa, sid, addr) && - ret->pppoe_ifindex == ifindex) { - *src = ret->next; - break; - } - - src = &ret->next; - ret = ret->next; - } - - return ret; -} - -/********************************************************************** - * - * Set/get/delete/rehash items - * - **********************************************************************/ -static inline struct pppox_sock *get_item(struct pppoe_net *pn, __be16 sid, - unsigned char *addr, int ifindex) -{ - struct pppox_sock *po; - - read_lock_bh(&pn->hash_lock); - po = __get_item(pn, sid, addr, ifindex); - if (po) - sock_hold(sk_pppox(po)); - read_unlock_bh(&pn->hash_lock); - - return po; -} - -static inline struct pppox_sock *get_item_by_addr(struct net *net, - struct sockaddr_pppox *sp) -{ - struct net_device *dev; - struct pppoe_net *pn; - struct pppox_sock *pppox_sock = NULL; - - int ifindex; - - rcu_read_lock(); - dev = dev_get_by_name_rcu(net, sp->sa_addr.pppoe.dev); - if (dev) { - ifindex = dev->ifindex; - pn = pppoe_pernet(net); - pppox_sock = get_item(pn, sp->sa_addr.pppoe.sid, - sp->sa_addr.pppoe.remote, ifindex); - } - rcu_read_unlock(); - return pppox_sock; -} - -static inline struct pppox_sock *delete_item(struct pppoe_net *pn, __be16 sid, - char *addr, int ifindex) -{ - struct pppox_sock *ret; - - write_lock_bh(&pn->hash_lock); - ret = __delete_item(pn, sid, addr, ifindex); - write_unlock_bh(&pn->hash_lock); - - return ret; -} - -/*************************************************************************** - * - * Handler for device events. - * Certain device events require that sockets be unconnected. - * - **************************************************************************/ - -static void pppoe_flush_dev(struct net_device *dev) -{ - struct pppoe_net *pn; - int i; - - pn = pppoe_pernet(dev_net(dev)); - write_lock_bh(&pn->hash_lock); - for (i = 0; i < PPPOE_HASH_SIZE; i++) { - struct pppox_sock *po = pn->hash_table[i]; - struct sock *sk; - - while (po) { - while (po && po->pppoe_dev != dev) { - po = po->next; - } - - if (!po) - break; - - sk = sk_pppox(po); - - /* We always grab the socket lock, followed by the - * hash_lock, in that order. Since we should hold the - * sock lock while doing any unbinding, we need to - * release the lock we're holding. Hold a reference to - * the sock so it doesn't disappear as we're jumping - * between locks. - */ - - sock_hold(sk); - write_unlock_bh(&pn->hash_lock); - lock_sock(sk); - - if (po->pppoe_dev == dev && - sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) { - pppox_unbind_sock(sk); - sk->sk_state = PPPOX_ZOMBIE; - sk->sk_state_change(sk); - po->pppoe_dev = NULL; - dev_put(dev); - } - - release_sock(sk); - sock_put(sk); - - /* Restart the process from the start of the current - * hash chain. We dropped locks so the world may have - * change from underneath us. - */ - - BUG_ON(pppoe_pernet(dev_net(dev)) == NULL); - write_lock_bh(&pn->hash_lock); - po = pn->hash_table[i]; - } - } - write_unlock_bh(&pn->hash_lock); -} - -static int pppoe_device_event(struct notifier_block *this, - unsigned long event, void *ptr) -{ - struct net_device *dev = (struct net_device *)ptr; - - /* Only look at sockets that are using this specific device. */ - switch (event) { - case NETDEV_CHANGEADDR: - case NETDEV_CHANGEMTU: - /* A change in mtu or address is a bad thing, requiring - * LCP re-negotiation. - */ - - case NETDEV_GOING_DOWN: - case NETDEV_DOWN: - /* Find every socket on this device and kill it. */ - pppoe_flush_dev(dev); - break; - - default: - break; - } - - return NOTIFY_DONE; -} - -static struct notifier_block pppoe_notifier = { - .notifier_call = pppoe_device_event, -}; - -/************************************************************************ - * - * Do the real work of receiving a PPPoE Session frame. - * - ***********************************************************************/ -static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb) -{ - struct pppox_sock *po = pppox_sk(sk); - struct pppox_sock *relay_po; - - /* Backlog receive. Semantics of backlog rcv preclude any code from - * executing in lock_sock()/release_sock() bounds; meaning sk->sk_state - * can't change. - */ - - if (sk->sk_state & PPPOX_BOUND) { - ppp_input(&po->chan, skb); - } else if (sk->sk_state & PPPOX_RELAY) { - relay_po = get_item_by_addr(sock_net(sk), - &po->pppoe_relay); - if (relay_po == NULL) - goto abort_kfree; - - if ((sk_pppox(relay_po)->sk_state & PPPOX_CONNECTED) == 0) - goto abort_put; - - if (!__pppoe_xmit(sk_pppox(relay_po), skb)) - goto abort_put; - } else { - if (sock_queue_rcv_skb(sk, skb)) - goto abort_kfree; - } - - return NET_RX_SUCCESS; - -abort_put: - sock_put(sk_pppox(relay_po)); - -abort_kfree: - kfree_skb(skb); - return NET_RX_DROP; -} - -/************************************************************************ - * - * Receive wrapper called in BH context. - * - ***********************************************************************/ -static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *pt, struct net_device *orig_dev) -{ - struct pppoe_hdr *ph; - struct pppox_sock *po; - struct pppoe_net *pn; - int len; - - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - goto out; - - if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) - goto drop; - - ph = pppoe_hdr(skb); - len = ntohs(ph->length); - - skb_pull_rcsum(skb, sizeof(*ph)); - if (skb->len < len) - goto drop; - - if (pskb_trim_rcsum(skb, len)) - goto drop; - - pn = pppoe_pernet(dev_net(dev)); - - /* Note that get_item does a sock_hold(), so sk_pppox(po) - * is known to be safe. - */ - po = get_item(pn, ph->sid, eth_hdr(skb)->h_source, dev->ifindex); - if (!po) - goto drop; - - return sk_receive_skb(sk_pppox(po), skb, 0); - -drop: - kfree_skb(skb); -out: - return NET_RX_DROP; -} - -/************************************************************************ - * - * Receive a PPPoE Discovery frame. - * This is solely for detection of PADT frames - * - ***********************************************************************/ -static int pppoe_disc_rcv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *pt, struct net_device *orig_dev) - -{ - struct pppoe_hdr *ph; - struct pppox_sock *po; - struct pppoe_net *pn; - - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - goto out; - - if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) - goto abort; - - ph = pppoe_hdr(skb); - if (ph->code != PADT_CODE) - goto abort; - - pn = pppoe_pernet(dev_net(dev)); - po = get_item(pn, ph->sid, eth_hdr(skb)->h_source, dev->ifindex); - if (po) { - struct sock *sk = sk_pppox(po); - - bh_lock_sock(sk); - - /* If the user has locked the socket, just ignore - * the packet. With the way two rcv protocols hook into - * one socket family type, we cannot (easily) distinguish - * what kind of SKB it is during backlog rcv. - */ - if (sock_owned_by_user(sk) == 0) { - /* We're no longer connect at the PPPOE layer, - * and must wait for ppp channel to disconnect us. - */ - sk->sk_state = PPPOX_ZOMBIE; - } - - bh_unlock_sock(sk); - sock_put(sk); - } - -abort: - kfree_skb(skb); -out: - return NET_RX_SUCCESS; /* Lies... :-) */ -} - -static struct packet_type pppoes_ptype __read_mostly = { - .type = cpu_to_be16(ETH_P_PPP_SES), - .func = pppoe_rcv, -}; - -static struct packet_type pppoed_ptype __read_mostly = { - .type = cpu_to_be16(ETH_P_PPP_DISC), - .func = pppoe_disc_rcv, -}; - -static struct proto pppoe_sk_proto __read_mostly = { - .name = "PPPOE", - .owner = THIS_MODULE, - .obj_size = sizeof(struct pppox_sock), -}; - -/*********************************************************************** - * - * Initialize a new struct sock. - * - **********************************************************************/ -static int pppoe_create(struct net *net, struct socket *sock) -{ - struct sock *sk; - - sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto); - if (!sk) - return -ENOMEM; - - sock_init_data(sock, sk); - - sock->state = SS_UNCONNECTED; - sock->ops = &pppoe_ops; - - sk->sk_backlog_rcv = pppoe_rcv_core; - sk->sk_state = PPPOX_NONE; - sk->sk_type = SOCK_STREAM; - sk->sk_family = PF_PPPOX; - sk->sk_protocol = PX_PROTO_OE; - - return 0; -} - -static int pppoe_release(struct socket *sock) -{ - struct sock *sk = sock->sk; - struct pppox_sock *po; - struct pppoe_net *pn; - struct net *net = NULL; - - if (!sk) - return 0; - - lock_sock(sk); - if (sock_flag(sk, SOCK_DEAD)) { - release_sock(sk); - return -EBADF; - } - - po = pppox_sk(sk); - - if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { - dev_put(po->pppoe_dev); - po->pppoe_dev = NULL; - } - - pppox_unbind_sock(sk); - - /* Signal the death of the socket. */ - sk->sk_state = PPPOX_DEAD; - - net = sock_net(sk); - pn = pppoe_pernet(net); - - /* - * protect "po" from concurrent updates - * on pppoe_flush_dev - */ - delete_item(pn, po->pppoe_pa.sid, po->pppoe_pa.remote, - po->pppoe_ifindex); - - sock_orphan(sk); - sock->sk = NULL; - - skb_queue_purge(&sk->sk_receive_queue); - release_sock(sk); - sock_put(sk); - - return 0; -} - -static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, - int sockaddr_len, int flags) -{ - struct sock *sk = sock->sk; - struct sockaddr_pppox *sp = (struct sockaddr_pppox *)uservaddr; - struct pppox_sock *po = pppox_sk(sk); - struct net_device *dev = NULL; - struct pppoe_net *pn; - struct net *net = NULL; - int error; - - lock_sock(sk); - - error = -EINVAL; - if (sp->sa_protocol != PX_PROTO_OE) - goto end; - - /* Check for already bound sockets */ - error = -EBUSY; - if ((sk->sk_state & PPPOX_CONNECTED) && - stage_session(sp->sa_addr.pppoe.sid)) - goto end; - - /* Check for already disconnected sockets, on attempts to disconnect */ - error = -EALREADY; - if ((sk->sk_state & PPPOX_DEAD) && - !stage_session(sp->sa_addr.pppoe.sid)) - goto end; - - error = 0; - - /* Delete the old binding */ - if (stage_session(po->pppoe_pa.sid)) { - pppox_unbind_sock(sk); - pn = pppoe_pernet(sock_net(sk)); - delete_item(pn, po->pppoe_pa.sid, - po->pppoe_pa.remote, po->pppoe_ifindex); - if (po->pppoe_dev) { - dev_put(po->pppoe_dev); - po->pppoe_dev = NULL; - } - - memset(sk_pppox(po) + 1, 0, - sizeof(struct pppox_sock) - sizeof(struct sock)); - sk->sk_state = PPPOX_NONE; - } - - /* Re-bind in session stage only */ - if (stage_session(sp->sa_addr.pppoe.sid)) { - error = -ENODEV; - net = sock_net(sk); - dev = dev_get_by_name(net, sp->sa_addr.pppoe.dev); - if (!dev) - goto err_put; - - po->pppoe_dev = dev; - po->pppoe_ifindex = dev->ifindex; - pn = pppoe_pernet(net); - if (!(dev->flags & IFF_UP)) { - goto err_put; - } - - memcpy(&po->pppoe_pa, - &sp->sa_addr.pppoe, - sizeof(struct pppoe_addr)); - - write_lock_bh(&pn->hash_lock); - error = __set_item(pn, po); - write_unlock_bh(&pn->hash_lock); - if (error < 0) - goto err_put; - - po->chan.hdrlen = (sizeof(struct pppoe_hdr) + - dev->hard_header_len); - - po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr); - po->chan.private = sk; - po->chan.ops = &pppoe_chan_ops; - - error = ppp_register_net_channel(dev_net(dev), &po->chan); - if (error) { - delete_item(pn, po->pppoe_pa.sid, - po->pppoe_pa.remote, po->pppoe_ifindex); - goto err_put; - } - - sk->sk_state = PPPOX_CONNECTED; - } - - po->num = sp->sa_addr.pppoe.sid; - -end: - release_sock(sk); - return error; -err_put: - if (po->pppoe_dev) { - dev_put(po->pppoe_dev); - po->pppoe_dev = NULL; - } - goto end; -} - -static int pppoe_getname(struct socket *sock, struct sockaddr *uaddr, - int *usockaddr_len, int peer) -{ - int len = sizeof(struct sockaddr_pppox); - struct sockaddr_pppox sp; - - sp.sa_family = AF_PPPOX; - sp.sa_protocol = PX_PROTO_OE; - memcpy(&sp.sa_addr.pppoe, &pppox_sk(sock->sk)->pppoe_pa, - sizeof(struct pppoe_addr)); - - memcpy(uaddr, &sp, len); - - *usockaddr_len = len; - - return 0; -} - -static int pppoe_ioctl(struct socket *sock, unsigned int cmd, - unsigned long arg) -{ - struct sock *sk = sock->sk; - struct pppox_sock *po = pppox_sk(sk); - int val; - int err; - - switch (cmd) { - case PPPIOCGMRU: - err = -ENXIO; - if (!(sk->sk_state & PPPOX_CONNECTED)) - break; - - err = -EFAULT; - if (put_user(po->pppoe_dev->mtu - - sizeof(struct pppoe_hdr) - - PPP_HDRLEN, - (int __user *)arg)) - break; - err = 0; - break; - - case PPPIOCSMRU: - err = -ENXIO; - if (!(sk->sk_state & PPPOX_CONNECTED)) - break; - - err = -EFAULT; - if (get_user(val, (int __user *)arg)) - break; - - if (val < (po->pppoe_dev->mtu - - sizeof(struct pppoe_hdr) - - PPP_HDRLEN)) - err = 0; - else - err = -EINVAL; - break; - - case PPPIOCSFLAGS: - err = -EFAULT; - if (get_user(val, (int __user *)arg)) - break; - err = 0; - break; - - case PPPOEIOCSFWD: - { - struct pppox_sock *relay_po; - - err = -EBUSY; - if (sk->sk_state & (PPPOX_BOUND | PPPOX_ZOMBIE | PPPOX_DEAD)) - break; - - err = -ENOTCONN; - if (!(sk->sk_state & PPPOX_CONNECTED)) - break; - - /* PPPoE address from the user specifies an outbound - PPPoE address which frames are forwarded to */ - err = -EFAULT; - if (copy_from_user(&po->pppoe_relay, - (void __user *)arg, - sizeof(struct sockaddr_pppox))) - break; - - err = -EINVAL; - if (po->pppoe_relay.sa_family != AF_PPPOX || - po->pppoe_relay.sa_protocol != PX_PROTO_OE) - break; - - /* Check that the socket referenced by the address - actually exists. */ - relay_po = get_item_by_addr(sock_net(sk), &po->pppoe_relay); - if (!relay_po) - break; - - sock_put(sk_pppox(relay_po)); - sk->sk_state |= PPPOX_RELAY; - err = 0; - break; - } - - case PPPOEIOCDFWD: - err = -EALREADY; - if (!(sk->sk_state & PPPOX_RELAY)) - break; - - sk->sk_state &= ~PPPOX_RELAY; - err = 0; - break; - - default: - err = -ENOTTY; - } - - return err; -} - -static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *m, size_t total_len) -{ - struct sk_buff *skb; - struct sock *sk = sock->sk; - struct pppox_sock *po = pppox_sk(sk); - int error; - struct pppoe_hdr hdr; - struct pppoe_hdr *ph; - struct net_device *dev; - char *start; - - lock_sock(sk); - if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) { - error = -ENOTCONN; - goto end; - } - - hdr.ver = 1; - hdr.type = 1; - hdr.code = 0; - hdr.sid = po->num; - - dev = po->pppoe_dev; - - error = -EMSGSIZE; - if (total_len > (dev->mtu + dev->hard_header_len)) - goto end; - - - skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32, - 0, GFP_KERNEL); - if (!skb) { - error = -ENOMEM; - goto end; - } - - /* Reserve space for headers. */ - skb_reserve(skb, dev->hard_header_len); - skb_reset_network_header(skb); - - skb->dev = dev; - - skb->priority = sk->sk_priority; - skb->protocol = cpu_to_be16(ETH_P_PPP_SES); - - ph = (struct pppoe_hdr *)skb_put(skb, total_len + sizeof(struct pppoe_hdr)); - start = (char *)&ph->tag[0]; - - error = memcpy_fromiovec(start, m->msg_iov, total_len); - if (error < 0) { - kfree_skb(skb); - goto end; - } - - error = total_len; - dev_hard_header(skb, dev, ETH_P_PPP_SES, - po->pppoe_pa.remote, NULL, total_len); - - memcpy(ph, &hdr, sizeof(struct pppoe_hdr)); - - ph->length = htons(total_len); - - dev_queue_xmit(skb); - -end: - release_sock(sk); - return error; -} - -/************************************************************************ - * - * xmit function for internal use. - * - ***********************************************************************/ -static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) -{ - struct pppox_sock *po = pppox_sk(sk); - struct net_device *dev = po->pppoe_dev; - struct pppoe_hdr *ph; - int data_len = skb->len; - - /* The higher-level PPP code (ppp_unregister_channel()) ensures the PPP - * xmit operations conclude prior to an unregistration call. Thus - * sk->sk_state cannot change, so we don't need to do lock_sock(). - * But, we also can't do a lock_sock since that introduces a potential - * deadlock as we'd reverse the lock ordering used when calling - * ppp_unregister_channel(). - */ - - if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) - goto abort; - - if (!dev) - goto abort; - - /* Copy the data if there is no space for the header or if it's - * read-only. - */ - if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len)) - goto abort; - - __skb_push(skb, sizeof(*ph)); - skb_reset_network_header(skb); - - ph = pppoe_hdr(skb); - ph->ver = 1; - ph->type = 1; - ph->code = 0; - ph->sid = po->num; - ph->length = htons(data_len); - - skb->protocol = cpu_to_be16(ETH_P_PPP_SES); - skb->dev = dev; - - dev_hard_header(skb, dev, ETH_P_PPP_SES, - po->pppoe_pa.remote, NULL, data_len); - - dev_queue_xmit(skb); - return 1; - -abort: - kfree_skb(skb); - return 1; -} - -/************************************************************************ - * - * xmit function called by generic PPP driver - * sends PPP frame over PPPoE socket - * - ***********************************************************************/ -static int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb) -{ - struct sock *sk = (struct sock *)chan->private; - return __pppoe_xmit(sk, skb); -} - -static const struct ppp_channel_ops pppoe_chan_ops = { - .start_xmit = pppoe_xmit, -}; - -static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *m, size_t total_len, int flags) -{ - struct sock *sk = sock->sk; - struct sk_buff *skb; - int error = 0; - - if (sk->sk_state & PPPOX_BOUND) { - error = -EIO; - goto end; - } - - skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, - flags & MSG_DONTWAIT, &error); - if (error < 0) - goto end; - - m->msg_namelen = 0; - - if (skb) { - total_len = min_t(size_t, total_len, skb->len); - error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len); - if (error == 0) - error = total_len; - } - - kfree_skb(skb); -end: - return error; -} - -#ifdef CONFIG_PROC_FS -static int pppoe_seq_show(struct seq_file *seq, void *v) -{ - struct pppox_sock *po; - char *dev_name; - - if (v == SEQ_START_TOKEN) { - seq_puts(seq, "Id Address Device\n"); - goto out; - } - - po = v; - dev_name = po->pppoe_pa.dev; - - seq_printf(seq, "%08X %pM %8s\n", - po->pppoe_pa.sid, po->pppoe_pa.remote, dev_name); -out: - return 0; -} - -static inline struct pppox_sock *pppoe_get_idx(struct pppoe_net *pn, loff_t pos) -{ - struct pppox_sock *po; - int i; - - for (i = 0; i < PPPOE_HASH_SIZE; i++) { - po = pn->hash_table[i]; - while (po) { - if (!pos--) - goto out; - po = po->next; - } - } - -out: - return po; -} - -static void *pppoe_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(pn->hash_lock) -{ - struct pppoe_net *pn = pppoe_pernet(seq_file_net(seq)); - loff_t l = *pos; - - read_lock_bh(&pn->hash_lock); - return l ? pppoe_get_idx(pn, --l) : SEQ_START_TOKEN; -} - -static void *pppoe_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct pppoe_net *pn = pppoe_pernet(seq_file_net(seq)); - struct pppox_sock *po; - - ++*pos; - if (v == SEQ_START_TOKEN) { - po = pppoe_get_idx(pn, 0); - goto out; - } - po = v; - if (po->next) - po = po->next; - else { - int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote); - - po = NULL; - while (++hash < PPPOE_HASH_SIZE) { - po = pn->hash_table[hash]; - if (po) - break; - } - } - -out: - return po; -} - -static void pppoe_seq_stop(struct seq_file *seq, void *v) - __releases(pn->hash_lock) -{ - struct pppoe_net *pn = pppoe_pernet(seq_file_net(seq)); - read_unlock_bh(&pn->hash_lock); -} - -static const struct seq_operations pppoe_seq_ops = { - .start = pppoe_seq_start, - .next = pppoe_seq_next, - .stop = pppoe_seq_stop, - .show = pppoe_seq_show, -}; - -static int pppoe_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &pppoe_seq_ops, - sizeof(struct seq_net_private)); -} - -static const struct file_operations pppoe_seq_fops = { - .owner = THIS_MODULE, - .open = pppoe_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -#endif /* CONFIG_PROC_FS */ - -static const struct proto_ops pppoe_ops = { - .family = AF_PPPOX, - .owner = THIS_MODULE, - .release = pppoe_release, - .bind = sock_no_bind, - .connect = pppoe_connect, - .socketpair = sock_no_socketpair, - .accept = sock_no_accept, - .getname = pppoe_getname, - .poll = datagram_poll, - .listen = sock_no_listen, - .shutdown = sock_no_shutdown, - .setsockopt = sock_no_setsockopt, - .getsockopt = sock_no_getsockopt, - .sendmsg = pppoe_sendmsg, - .recvmsg = pppoe_recvmsg, - .mmap = sock_no_mmap, - .ioctl = pppox_ioctl, -}; - -static const struct pppox_proto pppoe_proto = { - .create = pppoe_create, - .ioctl = pppoe_ioctl, - .owner = THIS_MODULE, -}; - -static __net_init int pppoe_init_net(struct net *net) -{ - struct pppoe_net *pn = pppoe_pernet(net); - struct proc_dir_entry *pde; - - rwlock_init(&pn->hash_lock); - - pde = proc_net_fops_create(net, "pppoe", S_IRUGO, &pppoe_seq_fops); -#ifdef CONFIG_PROC_FS - if (!pde) - return -ENOMEM; -#endif - - return 0; -} - -static __net_exit void pppoe_exit_net(struct net *net) -{ - proc_net_remove(net, "pppoe"); -} - -static struct pernet_operations pppoe_net_ops = { - .init = pppoe_init_net, - .exit = pppoe_exit_net, - .id = &pppoe_net_id, - .size = sizeof(struct pppoe_net), -}; - -static int __init pppoe_init(void) -{ - int err; - - err = register_pernet_device(&pppoe_net_ops); - if (err) - goto out; - - err = proto_register(&pppoe_sk_proto, 0); - if (err) - goto out_unregister_net_ops; - - err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto); - if (err) - goto out_unregister_pppoe_proto; - - dev_add_pack(&pppoes_ptype); - dev_add_pack(&pppoed_ptype); - register_netdevice_notifier(&pppoe_notifier); - - return 0; - -out_unregister_pppoe_proto: - proto_unregister(&pppoe_sk_proto); -out_unregister_net_ops: - unregister_pernet_device(&pppoe_net_ops); -out: - return err; -} - -static void __exit pppoe_exit(void) -{ - unregister_netdevice_notifier(&pppoe_notifier); - dev_remove_pack(&pppoed_ptype); - dev_remove_pack(&pppoes_ptype); - unregister_pppox_proto(PX_PROTO_OE); - proto_unregister(&pppoe_sk_proto); - unregister_pernet_device(&pppoe_net_ops); -} - -module_init(pppoe_init); -module_exit(pppoe_exit); - -MODULE_AUTHOR("Michal Ostrowski "); -MODULE_DESCRIPTION("PPP over Ethernet driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_NETPROTO(PF_PPPOX); diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c deleted file mode 100644 index 8c0d170..0000000 --- a/drivers/net/pppox.c +++ /dev/null @@ -1,149 +0,0 @@ -/** -*- linux-c -*- *********************************************************** - * Linux PPP over X/Ethernet (PPPoX/PPPoE) Sockets - * - * PPPoX --- Generic PPP encapsulation socket family - * PPPoE --- PPP over Ethernet (RFC 2516) - * - * - * Version: 0.5.2 - * - * Author: Michal Ostrowski - * - * 051000 : Initialization cleanup - * - * License: - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -static const struct pppox_proto *pppox_protos[PX_MAX_PROTO + 1]; - -int register_pppox_proto(int proto_num, const struct pppox_proto *pp) -{ - if (proto_num < 0 || proto_num > PX_MAX_PROTO) - return -EINVAL; - if (pppox_protos[proto_num]) - return -EALREADY; - pppox_protos[proto_num] = pp; - return 0; -} - -void unregister_pppox_proto(int proto_num) -{ - if (proto_num >= 0 && proto_num <= PX_MAX_PROTO) - pppox_protos[proto_num] = NULL; -} - -void pppox_unbind_sock(struct sock *sk) -{ - /* Clear connection to ppp device, if attached. */ - - if (sk->sk_state & (PPPOX_BOUND | PPPOX_CONNECTED | PPPOX_ZOMBIE)) { - ppp_unregister_channel(&pppox_sk(sk)->chan); - sk->sk_state = PPPOX_DEAD; - } -} - -EXPORT_SYMBOL(register_pppox_proto); -EXPORT_SYMBOL(unregister_pppox_proto); -EXPORT_SYMBOL(pppox_unbind_sock); - -int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - struct sock *sk = sock->sk; - struct pppox_sock *po = pppox_sk(sk); - int rc; - - lock_sock(sk); - - switch (cmd) { - case PPPIOCGCHAN: { - int index; - rc = -ENOTCONN; - if (!(sk->sk_state & PPPOX_CONNECTED)) - break; - - rc = -EINVAL; - index = ppp_channel_index(&po->chan); - if (put_user(index , (int __user *) arg)) - break; - - rc = 0; - sk->sk_state |= PPPOX_BOUND; - break; - } - default: - rc = pppox_protos[sk->sk_protocol]->ioctl ? - pppox_protos[sk->sk_protocol]->ioctl(sock, cmd, arg) : -ENOTTY; - } - - release_sock(sk); - return rc; -} - -EXPORT_SYMBOL(pppox_ioctl); - -static int pppox_create(struct net *net, struct socket *sock, int protocol, - int kern) -{ - int rc = -EPROTOTYPE; - - if (protocol < 0 || protocol > PX_MAX_PROTO) - goto out; - - rc = -EPROTONOSUPPORT; - if (!pppox_protos[protocol]) - request_module("pppox-proto-%d", protocol); - if (!pppox_protos[protocol] || - !try_module_get(pppox_protos[protocol]->owner)) - goto out; - - rc = pppox_protos[protocol]->create(net, sock); - - module_put(pppox_protos[protocol]->owner); -out: - return rc; -} - -static const struct net_proto_family pppox_proto_family = { - .family = PF_PPPOX, - .create = pppox_create, - .owner = THIS_MODULE, -}; - -static int __init pppox_init(void) -{ - return sock_register(&pppox_proto_family); -} - -static void __exit pppox_exit(void) -{ - sock_unregister(PF_PPPOX); -} - -module_init(pppox_init); -module_exit(pppox_exit); - -MODULE_AUTHOR("Michal Ostrowski "); -MODULE_DESCRIPTION("PPP over Ethernet driver (generic socket layer)"); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/pptp.c b/drivers/net/pptp.c deleted file mode 100644 index eae542a..0000000 --- a/drivers/net/pptp.c +++ /dev/null @@ -1,717 +0,0 @@ -/* - * Point-to-Point Tunneling Protocol for Linux - * - * Authors: Dmitry Kozlov - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#define PPTP_DRIVER_VERSION "0.8.5" - -#define MAX_CALLID 65535 - -static DECLARE_BITMAP(callid_bitmap, MAX_CALLID + 1); -static struct pppox_sock **callid_sock; - -static DEFINE_SPINLOCK(chan_lock); - -static struct proto pptp_sk_proto __read_mostly; -static const struct ppp_channel_ops pptp_chan_ops; -static const struct proto_ops pptp_ops; - -#define PPP_LCP_ECHOREQ 0x09 -#define PPP_LCP_ECHOREP 0x0A -#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) - -#define MISSING_WINDOW 20 -#define WRAPPED(curseq, lastseq)\ - ((((curseq) & 0xffffff00) == 0) &&\ - (((lastseq) & 0xffffff00) == 0xffffff00)) - -#define PPTP_GRE_PROTO 0x880B -#define PPTP_GRE_VER 0x1 - -#define PPTP_GRE_FLAG_C 0x80 -#define PPTP_GRE_FLAG_R 0x40 -#define PPTP_GRE_FLAG_K 0x20 -#define PPTP_GRE_FLAG_S 0x10 -#define PPTP_GRE_FLAG_A 0x80 - -#define PPTP_GRE_IS_C(f) ((f)&PPTP_GRE_FLAG_C) -#define PPTP_GRE_IS_R(f) ((f)&PPTP_GRE_FLAG_R) -#define PPTP_GRE_IS_K(f) ((f)&PPTP_GRE_FLAG_K) -#define PPTP_GRE_IS_S(f) ((f)&PPTP_GRE_FLAG_S) -#define PPTP_GRE_IS_A(f) ((f)&PPTP_GRE_FLAG_A) - -#define PPTP_HEADER_OVERHEAD (2+sizeof(struct pptp_gre_header)) -struct pptp_gre_header { - u8 flags; - u8 ver; - u16 protocol; - u16 payload_len; - u16 call_id; - u32 seq; - u32 ack; -} __packed; - -static struct pppox_sock *lookup_chan(u16 call_id, __be32 s_addr) -{ - struct pppox_sock *sock; - struct pptp_opt *opt; - - rcu_read_lock(); - sock = rcu_dereference(callid_sock[call_id]); - if (sock) { - opt = &sock->proto.pptp; - if (opt->dst_addr.sin_addr.s_addr != s_addr) - sock = NULL; - else - sock_hold(sk_pppox(sock)); - } - rcu_read_unlock(); - - return sock; -} - -static int lookup_chan_dst(u16 call_id, __be32 d_addr) -{ - struct pppox_sock *sock; - struct pptp_opt *opt; - int i; - - rcu_read_lock(); - for (i = find_next_bit(callid_bitmap, MAX_CALLID, 1); i < MAX_CALLID; - i = find_next_bit(callid_bitmap, MAX_CALLID, i + 1)) { - sock = rcu_dereference(callid_sock[i]); - if (!sock) - continue; - opt = &sock->proto.pptp; - if (opt->dst_addr.call_id == call_id && - opt->dst_addr.sin_addr.s_addr == d_addr) - break; - } - rcu_read_unlock(); - - return i < MAX_CALLID; -} - -static int add_chan(struct pppox_sock *sock) -{ - static int call_id; - - spin_lock(&chan_lock); - if (!sock->proto.pptp.src_addr.call_id) { - call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, call_id + 1); - if (call_id == MAX_CALLID) { - call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, 1); - if (call_id == MAX_CALLID) - goto out_err; - } - sock->proto.pptp.src_addr.call_id = call_id; - } else if (test_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap)) - goto out_err; - - set_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap); - rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id], sock); - spin_unlock(&chan_lock); - - return 0; - -out_err: - spin_unlock(&chan_lock); - return -1; -} - -static void del_chan(struct pppox_sock *sock) -{ - spin_lock(&chan_lock); - clear_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap); - rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id], NULL); - spin_unlock(&chan_lock); - synchronize_rcu(); -} - -static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) -{ - struct sock *sk = (struct sock *) chan->private; - struct pppox_sock *po = pppox_sk(sk); - struct pptp_opt *opt = &po->proto.pptp; - struct pptp_gre_header *hdr; - unsigned int header_len = sizeof(*hdr); - struct flowi4 fl4; - int islcp; - int len; - unsigned char *data; - __u32 seq_recv; - - - struct rtable *rt; - struct net_device *tdev; - struct iphdr *iph; - int max_headroom; - - if (sk_pppox(po)->sk_state & PPPOX_DEAD) - goto tx_error; - - rt = ip_route_output_ports(&init_net, &fl4, NULL, - opt->dst_addr.sin_addr.s_addr, - opt->src_addr.sin_addr.s_addr, - 0, 0, IPPROTO_GRE, - RT_TOS(0), 0); - if (IS_ERR(rt)) - goto tx_error; - - tdev = rt->dst.dev; - - max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(*iph) + sizeof(*hdr) + 2; - - if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) { - struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); - if (!new_skb) { - ip_rt_put(rt); - goto tx_error; - } - if (skb->sk) - skb_set_owner_w(new_skb, skb->sk); - kfree_skb(skb); - skb = new_skb; - } - - data = skb->data; - islcp = ((data[0] << 8) + data[1]) == PPP_LCP && 1 <= data[2] && data[2] <= 7; - - /* compress protocol field */ - if ((opt->ppp_flags & SC_COMP_PROT) && data[0] == 0 && !islcp) - skb_pull(skb, 1); - - /* Put in the address/control bytes if necessary */ - if ((opt->ppp_flags & SC_COMP_AC) == 0 || islcp) { - data = skb_push(skb, 2); - data[0] = PPP_ALLSTATIONS; - data[1] = PPP_UI; - } - - len = skb->len; - - seq_recv = opt->seq_recv; - - if (opt->ack_sent == seq_recv) - header_len -= sizeof(hdr->ack); - - /* Push down and install GRE header */ - skb_push(skb, header_len); - hdr = (struct pptp_gre_header *)(skb->data); - - hdr->flags = PPTP_GRE_FLAG_K; - hdr->ver = PPTP_GRE_VER; - hdr->protocol = htons(PPTP_GRE_PROTO); - hdr->call_id = htons(opt->dst_addr.call_id); - - hdr->flags |= PPTP_GRE_FLAG_S; - hdr->seq = htonl(++opt->seq_sent); - if (opt->ack_sent != seq_recv) { - /* send ack with this message */ - hdr->ver |= PPTP_GRE_FLAG_A; - hdr->ack = htonl(seq_recv); - opt->ack_sent = seq_recv; - } - hdr->payload_len = htons(len); - - /* Push down and install the IP header. */ - - skb_reset_transport_header(skb); - skb_push(skb, sizeof(*iph)); - skb_reset_network_header(skb); - memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); - IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED); - - iph = ip_hdr(skb); - iph->version = 4; - iph->ihl = sizeof(struct iphdr) >> 2; - if (ip_dont_fragment(sk, &rt->dst)) - iph->frag_off = htons(IP_DF); - else - iph->frag_off = 0; - iph->protocol = IPPROTO_GRE; - iph->tos = 0; - iph->daddr = fl4.daddr; - iph->saddr = fl4.saddr; - iph->ttl = ip4_dst_hoplimit(&rt->dst); - iph->tot_len = htons(skb->len); - - skb_dst_drop(skb); - skb_dst_set(skb, &rt->dst); - - nf_reset(skb); - - skb->ip_summed = CHECKSUM_NONE; - ip_select_ident(iph, &rt->dst, NULL); - ip_send_check(iph); - - ip_local_out(skb); - -tx_error: - return 1; -} - -static int pptp_rcv_core(struct sock *sk, struct sk_buff *skb) -{ - struct pppox_sock *po = pppox_sk(sk); - struct pptp_opt *opt = &po->proto.pptp; - int headersize, payload_len, seq; - __u8 *payload; - struct pptp_gre_header *header; - - if (!(sk->sk_state & PPPOX_CONNECTED)) { - if (sock_queue_rcv_skb(sk, skb)) - goto drop; - return NET_RX_SUCCESS; - } - - header = (struct pptp_gre_header *)(skb->data); - - /* test if acknowledgement present */ - if (PPTP_GRE_IS_A(header->ver)) { - __u32 ack = (PPTP_GRE_IS_S(header->flags)) ? - header->ack : header->seq; /* ack in different place if S = 0 */ - - ack = ntohl(ack); - - if (ack > opt->ack_recv) - opt->ack_recv = ack; - /* also handle sequence number wrap-around */ - if (WRAPPED(ack, opt->ack_recv)) - opt->ack_recv = ack; - } - - /* test if payload present */ - if (!PPTP_GRE_IS_S(header->flags)) - goto drop; - - headersize = sizeof(*header); - payload_len = ntohs(header->payload_len); - seq = ntohl(header->seq); - - /* no ack present? */ - if (!PPTP_GRE_IS_A(header->ver)) - headersize -= sizeof(header->ack); - /* check for incomplete packet (length smaller than expected) */ - if (skb->len - headersize < payload_len) - goto drop; - - payload = skb->data + headersize; - /* check for expected sequence number */ - if (seq < opt->seq_recv + 1 || WRAPPED(opt->seq_recv, seq)) { - if ((payload[0] == PPP_ALLSTATIONS) && (payload[1] == PPP_UI) && - (PPP_PROTOCOL(payload) == PPP_LCP) && - ((payload[4] == PPP_LCP_ECHOREQ) || (payload[4] == PPP_LCP_ECHOREP))) - goto allow_packet; - } else { - opt->seq_recv = seq; -allow_packet: - skb_pull(skb, headersize); - - if (payload[0] == PPP_ALLSTATIONS && payload[1] == PPP_UI) { - /* chop off address/control */ - if (skb->len < 3) - goto drop; - skb_pull(skb, 2); - } - - if ((*skb->data) & 1) { - /* protocol is compressed */ - skb_push(skb, 1)[0] = 0; - } - - skb->ip_summed = CHECKSUM_NONE; - skb_set_network_header(skb, skb->head-skb->data); - ppp_input(&po->chan, skb); - - return NET_RX_SUCCESS; - } -drop: - kfree_skb(skb); - return NET_RX_DROP; -} - -static int pptp_rcv(struct sk_buff *skb) -{ - struct pppox_sock *po; - struct pptp_gre_header *header; - struct iphdr *iph; - - if (skb->pkt_type != PACKET_HOST) - goto drop; - - if (!pskb_may_pull(skb, 12)) - goto drop; - - iph = ip_hdr(skb); - - header = (struct pptp_gre_header *)skb->data; - - if (ntohs(header->protocol) != PPTP_GRE_PROTO || /* PPTP-GRE protocol for PPTP */ - PPTP_GRE_IS_C(header->flags) || /* flag C should be clear */ - PPTP_GRE_IS_R(header->flags) || /* flag R should be clear */ - !PPTP_GRE_IS_K(header->flags) || /* flag K should be set */ - (header->flags&0xF) != 0) /* routing and recursion ctrl = 0 */ - /* if invalid, discard this packet */ - goto drop; - - po = lookup_chan(htons(header->call_id), iph->saddr); - if (po) { - skb_dst_drop(skb); - nf_reset(skb); - return sk_receive_skb(sk_pppox(po), skb, 0); - } -drop: - kfree_skb(skb); - return NET_RX_DROP; -} - -static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr, - int sockaddr_len) -{ - struct sock *sk = sock->sk; - struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr; - struct pppox_sock *po = pppox_sk(sk); - struct pptp_opt *opt = &po->proto.pptp; - int error = 0; - - lock_sock(sk); - - opt->src_addr = sp->sa_addr.pptp; - if (add_chan(po)) { - release_sock(sk); - error = -EBUSY; - } - - release_sock(sk); - return error; -} - -static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, - int sockaddr_len, int flags) -{ - struct sock *sk = sock->sk; - struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr; - struct pppox_sock *po = pppox_sk(sk); - struct pptp_opt *opt = &po->proto.pptp; - struct rtable *rt; - struct flowi4 fl4; - int error = 0; - - if (sp->sa_protocol != PX_PROTO_PPTP) - return -EINVAL; - - if (lookup_chan_dst(sp->sa_addr.pptp.call_id, sp->sa_addr.pptp.sin_addr.s_addr)) - return -EALREADY; - - lock_sock(sk); - /* Check for already bound sockets */ - if (sk->sk_state & PPPOX_CONNECTED) { - error = -EBUSY; - goto end; - } - - /* Check for already disconnected sockets, on attempts to disconnect */ - if (sk->sk_state & PPPOX_DEAD) { - error = -EALREADY; - goto end; - } - - if (!opt->src_addr.sin_addr.s_addr || !sp->sa_addr.pptp.sin_addr.s_addr) { - error = -EINVAL; - goto end; - } - - po->chan.private = sk; - po->chan.ops = &pptp_chan_ops; - - rt = ip_route_output_ports(&init_net, &fl4, sk, - opt->dst_addr.sin_addr.s_addr, - opt->src_addr.sin_addr.s_addr, - 0, 0, - IPPROTO_GRE, RT_CONN_FLAGS(sk), 0); - if (IS_ERR(rt)) { - error = -EHOSTUNREACH; - goto end; - } - sk_setup_caps(sk, &rt->dst); - - po->chan.mtu = dst_mtu(&rt->dst); - if (!po->chan.mtu) - po->chan.mtu = PPP_MTU; - ip_rt_put(rt); - po->chan.mtu -= PPTP_HEADER_OVERHEAD; - - po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header); - error = ppp_register_channel(&po->chan); - if (error) { - pr_err("PPTP: failed to register PPP channel (%d)\n", error); - goto end; - } - - opt->dst_addr = sp->sa_addr.pptp; - sk->sk_state = PPPOX_CONNECTED; - - end: - release_sock(sk); - return error; -} - -static int pptp_getname(struct socket *sock, struct sockaddr *uaddr, - int *usockaddr_len, int peer) -{ - int len = sizeof(struct sockaddr_pppox); - struct sockaddr_pppox sp; - - sp.sa_family = AF_PPPOX; - sp.sa_protocol = PX_PROTO_PPTP; - sp.sa_addr.pptp = pppox_sk(sock->sk)->proto.pptp.src_addr; - - memcpy(uaddr, &sp, len); - - *usockaddr_len = len; - - return 0; -} - -static int pptp_release(struct socket *sock) -{ - struct sock *sk = sock->sk; - struct pppox_sock *po; - struct pptp_opt *opt; - int error = 0; - - if (!sk) - return 0; - - lock_sock(sk); - - if (sock_flag(sk, SOCK_DEAD)) { - release_sock(sk); - return -EBADF; - } - - po = pppox_sk(sk); - opt = &po->proto.pptp; - del_chan(po); - - pppox_unbind_sock(sk); - sk->sk_state = PPPOX_DEAD; - - sock_orphan(sk); - sock->sk = NULL; - - release_sock(sk); - sock_put(sk); - - return error; -} - -static void pptp_sock_destruct(struct sock *sk) -{ - if (!(sk->sk_state & PPPOX_DEAD)) { - del_chan(pppox_sk(sk)); - pppox_unbind_sock(sk); - } - skb_queue_purge(&sk->sk_receive_queue); -} - -static int pptp_create(struct net *net, struct socket *sock) -{ - int error = -ENOMEM; - struct sock *sk; - struct pppox_sock *po; - struct pptp_opt *opt; - - sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pptp_sk_proto); - if (!sk) - goto out; - - sock_init_data(sock, sk); - - sock->state = SS_UNCONNECTED; - sock->ops = &pptp_ops; - - sk->sk_backlog_rcv = pptp_rcv_core; - sk->sk_state = PPPOX_NONE; - sk->sk_type = SOCK_STREAM; - sk->sk_family = PF_PPPOX; - sk->sk_protocol = PX_PROTO_PPTP; - sk->sk_destruct = pptp_sock_destruct; - - po = pppox_sk(sk); - opt = &po->proto.pptp; - - opt->seq_sent = 0; opt->seq_recv = 0; - opt->ack_recv = 0; opt->ack_sent = 0; - - error = 0; -out: - return error; -} - -static int pptp_ppp_ioctl(struct ppp_channel *chan, unsigned int cmd, - unsigned long arg) -{ - struct sock *sk = (struct sock *) chan->private; - struct pppox_sock *po = pppox_sk(sk); - struct pptp_opt *opt = &po->proto.pptp; - void __user *argp = (void __user *)arg; - int __user *p = argp; - int err, val; - - err = -EFAULT; - switch (cmd) { - case PPPIOCGFLAGS: - val = opt->ppp_flags; - if (put_user(val, p)) - break; - err = 0; - break; - case PPPIOCSFLAGS: - if (get_user(val, p)) - break; - opt->ppp_flags = val & ~SC_RCV_BITS; - err = 0; - break; - default: - err = -ENOTTY; - } - - return err; -} - -static const struct ppp_channel_ops pptp_chan_ops = { - .start_xmit = pptp_xmit, - .ioctl = pptp_ppp_ioctl, -}; - -static struct proto pptp_sk_proto __read_mostly = { - .name = "PPTP", - .owner = THIS_MODULE, - .obj_size = sizeof(struct pppox_sock), -}; - -static const struct proto_ops pptp_ops = { - .family = AF_PPPOX, - .owner = THIS_MODULE, - .release = pptp_release, - .bind = pptp_bind, - .connect = pptp_connect, - .socketpair = sock_no_socketpair, - .accept = sock_no_accept, - .getname = pptp_getname, - .poll = sock_no_poll, - .listen = sock_no_listen, - .shutdown = sock_no_shutdown, - .setsockopt = sock_no_setsockopt, - .getsockopt = sock_no_getsockopt, - .sendmsg = sock_no_sendmsg, - .recvmsg = sock_no_recvmsg, - .mmap = sock_no_mmap, - .ioctl = pppox_ioctl, -}; - -static const struct pppox_proto pppox_pptp_proto = { - .create = pptp_create, - .owner = THIS_MODULE, -}; - -static const struct gre_protocol gre_pptp_protocol = { - .handler = pptp_rcv, -}; - -static int __init pptp_init_module(void) -{ - int err = 0; - pr_info("PPTP driver version " PPTP_DRIVER_VERSION "\n"); - - callid_sock = vzalloc((MAX_CALLID + 1) * sizeof(void *)); - if (!callid_sock) { - pr_err("PPTP: cann't allocate memory\n"); - return -ENOMEM; - } - - err = gre_add_protocol(&gre_pptp_protocol, GREPROTO_PPTP); - if (err) { - pr_err("PPTP: can't add gre protocol\n"); - goto out_mem_free; - } - - err = proto_register(&pptp_sk_proto, 0); - if (err) { - pr_err("PPTP: can't register sk_proto\n"); - goto out_gre_del_protocol; - } - - err = register_pppox_proto(PX_PROTO_PPTP, &pppox_pptp_proto); - if (err) { - pr_err("PPTP: can't register pppox_proto\n"); - goto out_unregister_sk_proto; - } - - return 0; - -out_unregister_sk_proto: - proto_unregister(&pptp_sk_proto); -out_gre_del_protocol: - gre_del_protocol(&gre_pptp_protocol, GREPROTO_PPTP); -out_mem_free: - vfree(callid_sock); - - return err; -} - -static void __exit pptp_exit_module(void) -{ - unregister_pppox_proto(PX_PROTO_PPTP); - proto_unregister(&pptp_sk_proto); - gre_del_protocol(&gre_pptp_protocol, GREPROTO_PPTP); - vfree(callid_sock); -} - -module_init(pptp_init_module); -module_exit(pptp_exit_module); - -MODULE_DESCRIPTION("Point-to-Point Tunneling Protocol"); -MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); -MODULE_LICENSE("GPL"); -- cgit v0.10.2 From ff5a3b509e4ec96a2a4c57052a2d96e855778a24 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Mon, 1 Aug 2011 22:48:13 -0700 Subject: hippi: Move the HIPPI driver Move the HIPPI driver into drivers/net/hippi/ and make the necessary Kconfig and Makefile changes. CC: Jes Sorensen CC: Jes Sorensen Signed-off-by: Jeff Kirsher diff --git a/MAINTAINERS b/MAINTAINERS index c5ec925..194095a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3049,6 +3049,7 @@ S: Maintained F: include/linux/hippidevice.h F: include/linux/if_hippi.h F: net/802/hippi.c +F: drivers/net/hippi/ HOST AP DRIVER M: Jouni Malinen diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index c5e2a38..1d8fa95 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -272,38 +272,6 @@ config RIONET_RX_SIZE depends on RIONET default "128" -config HIPPI - bool "HIPPI driver support (EXPERIMENTAL)" - depends on EXPERIMENTAL && INET && PCI - help - HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and - 1600Mbit/sec dual-simplex switched or point-to-point network. HIPPI - can run over copper (25m) or fiber (300m on multi-mode or 10km on - single-mode). HIPPI networks are commonly used for clusters and to - connect to super computers. If you are connected to a HIPPI network - and have a HIPPI network card in your computer that you want to use - under Linux, say Y here (you must also remember to enable the driver - for your HIPPI card below). Most people will say N here. - -config ROADRUNNER - tristate "Essential RoadRunner HIPPI PCI adapter support (EXPERIMENTAL)" - depends on HIPPI && PCI - help - Say Y here if this is your PCI HIPPI network card. - - To compile this driver as a module, choose M here: the module - will be called rrunner. If unsure, say N. - -config ROADRUNNER_LARGE_RINGS - bool "Use large TX/RX rings (EXPERIMENTAL)" - depends on ROADRUNNER - help - If you say Y here, the RoadRunner driver will preallocate up to 2 MB - of additional memory to allow for fastest operation, both for - transmitting and receiving. This memory cannot be used by any other - kernel code or by user space programs. Say Y here only if you have - the memory. - config PLIP tristate "PLIP (parallel port) support" depends on PARPORT diff --git a/drivers/net/Makefile b/drivers/net/Makefile index a397f1e..f64d02c 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_VMXNET3) += vmxnet3/ # link order important here # obj-$(CONFIG_PLIP) += plip.o -obj-$(CONFIG_ROADRUNNER) += rrunner.o obj-$(CONFIG_RIONET) += rionet.o # @@ -39,6 +38,7 @@ obj-$(CONFIG_VETH) += veth.o obj-$(CONFIG_DEV_APPLETALK) += appletalk/ obj-$(CONFIG_ETHERNET) += ethernet/ obj-$(CONFIG_FDDI) += fddi/ +obj-$(CONFIG_HIPPI) += hippi/ onj-$(CONFIG_PPP) += ppp/ obj-$(CONFIG_PPP_ASYNC) += ppp/ obj-$(CONFIG_PPP_BSDCOMP) += ppp/ diff --git a/drivers/net/hippi/Kconfig b/drivers/net/hippi/Kconfig new file mode 100644 index 0000000..7393eb7 --- /dev/null +++ b/drivers/net/hippi/Kconfig @@ -0,0 +1,39 @@ +# +# HIPPI network device configuration +# + +config HIPPI + bool "HIPPI driver support (EXPERIMENTAL)" + depends on EXPERIMENTAL && INET && PCI + ---help--- + HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and + 1600Mbit/sec dual-simplex switched or point-to-point network. HIPPI + can run over copper (25m) or fiber (300m on multi-mode or 10km on + single-mode). HIPPI networks are commonly used for clusters and to + connect to super computers. If you are connected to a HIPPI network + and have a HIPPI network card in your computer that you want to use + under Linux, say Y here (you must also remember to enable the driver + for your HIPPI card below). Most people will say N here. + +if HIPPI + +config ROADRUNNER + tristate "Essential RoadRunner HIPPI PCI adapter support (EXPERIMENTAL)" + depends on PCI + ---help--- + Say Y here if this is your PCI HIPPI network card. + + To compile this driver as a module, choose M here: the module + will be called rrunner. If unsure, say N. + +config ROADRUNNER_LARGE_RINGS + bool "Use large TX/RX rings (EXPERIMENTAL)" + depends on ROADRUNNER + ---help--- + If you say Y here, the RoadRunner driver will preallocate up to 2 MB + of additional memory to allow for fastest operation, both for + transmitting and receiving. This memory cannot be used by any other + kernel code or by user space programs. Say Y here only if you have + the memory. + +endif /* HIPPI */ diff --git a/drivers/net/hippi/Makefile b/drivers/net/hippi/Makefile new file mode 100644 index 0000000..b95d629 --- /dev/null +++ b/drivers/net/hippi/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the HIPPI network device drivers. +# + +obj-$(CONFIG_ROADRUNNER) += rrunner.o diff --git a/drivers/net/hippi/rrunner.c b/drivers/net/hippi/rrunner.c new file mode 100644 index 0000000..e68c941 --- /dev/null +++ b/drivers/net/hippi/rrunner.c @@ -0,0 +1,1716 @@ +/* + * rrunner.c: Linux driver for the Essential RoadRunner HIPPI board. + * + * Copyright (C) 1998-2002 by Jes Sorensen, . + * + * Thanks to Essential Communication for providing us with hardware + * and very comprehensive documentation without which I would not have + * been able to write this driver. A special thank you to John Gibbon + * for sorting out the legal issues, with the NDA, allowing the code to + * be released under the GPL. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Thanks to Jayaram Bhat from ODS/Essential for fixing some of the + * stupid bugs in my code. + * + * Softnet support and various other patches from Val Henson of + * ODS/Essential. + * + * PCI DMA mapping code partly based on work by Francois Romieu. + */ + + +#define DEBUG 1 +#define RX_DMA_SKBUFF 1 +#define PKT_COPY_THRESHOLD 512 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define rr_if_busy(dev) netif_queue_stopped(dev) +#define rr_if_running(dev) netif_running(dev) + +#include "rrunner.h" + +#define RUN_AT(x) (jiffies + (x)) + + +MODULE_AUTHOR("Jes Sorensen "); +MODULE_DESCRIPTION("Essential RoadRunner HIPPI driver"); +MODULE_LICENSE("GPL"); + +static char version[] __devinitdata = "rrunner.c: v0.50 11/11/2002 Jes Sorensen (jes@wildopensource.com)\n"; + + +static const struct net_device_ops rr_netdev_ops = { + .ndo_open = rr_open, + .ndo_stop = rr_close, + .ndo_do_ioctl = rr_ioctl, + .ndo_start_xmit = rr_start_xmit, + .ndo_change_mtu = hippi_change_mtu, + .ndo_set_mac_address = hippi_mac_addr, +}; + +/* + * Implementation notes: + * + * The DMA engine only allows for DMA within physical 64KB chunks of + * memory. The current approach of the driver (and stack) is to use + * linear blocks of memory for the skbuffs. However, as the data block + * is always the first part of the skb and skbs are 2^n aligned so we + * are guarantted to get the whole block within one 64KB align 64KB + * chunk. + * + * On the long term, relying on being able to allocate 64KB linear + * chunks of memory is not feasible and the skb handling code and the + * stack will need to know about I/O vectors or something similar. + */ + +static int __devinit rr_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev; + static int version_disp; + u8 pci_latency; + struct rr_private *rrpriv; + void *tmpptr; + dma_addr_t ring_dma; + int ret = -ENOMEM; + + dev = alloc_hippi_dev(sizeof(struct rr_private)); + if (!dev) + goto out3; + + ret = pci_enable_device(pdev); + if (ret) { + ret = -ENODEV; + goto out2; + } + + rrpriv = netdev_priv(dev); + + SET_NETDEV_DEV(dev, &pdev->dev); + + if (pci_request_regions(pdev, "rrunner")) { + ret = -EIO; + goto out; + } + + pci_set_drvdata(pdev, dev); + + rrpriv->pci_dev = pdev; + + spin_lock_init(&rrpriv->lock); + + dev->irq = pdev->irq; + dev->netdev_ops = &rr_netdev_ops; + + dev->base_addr = pci_resource_start(pdev, 0); + + /* display version info if adapter is found */ + if (!version_disp) { + /* set display flag to TRUE so that */ + /* we only display this string ONCE */ + version_disp = 1; + printk(version); + } + + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency <= 0x58){ + pci_latency = 0x58; + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, pci_latency); + } + + pci_set_master(pdev); + + printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI " + "at 0x%08lx, irq %i, PCI latency %i\n", dev->name, + dev->base_addr, dev->irq, pci_latency); + + /* + * Remap the regs into kernel space. + */ + + rrpriv->regs = ioremap(dev->base_addr, 0x1000); + + if (!rrpriv->regs){ + printk(KERN_ERR "%s: Unable to map I/O register, " + "RoadRunner will be disabled.\n", dev->name); + ret = -EIO; + goto out; + } + + tmpptr = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma); + rrpriv->tx_ring = tmpptr; + rrpriv->tx_ring_dma = ring_dma; + + if (!tmpptr) { + ret = -ENOMEM; + goto out; + } + + tmpptr = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma); + rrpriv->rx_ring = tmpptr; + rrpriv->rx_ring_dma = ring_dma; + + if (!tmpptr) { + ret = -ENOMEM; + goto out; + } + + tmpptr = pci_alloc_consistent(pdev, EVT_RING_SIZE, &ring_dma); + rrpriv->evt_ring = tmpptr; + rrpriv->evt_ring_dma = ring_dma; + + if (!tmpptr) { + ret = -ENOMEM; + goto out; + } + + /* + * Don't access any register before this point! + */ +#ifdef __BIG_ENDIAN + writel(readl(&rrpriv->regs->HostCtrl) | NO_SWAP, + &rrpriv->regs->HostCtrl); +#endif + /* + * Need to add a case for little-endian 64-bit hosts here. + */ + + rr_init(dev); + + dev->base_addr = 0; + + ret = register_netdev(dev); + if (ret) + goto out; + return 0; + + out: + if (rrpriv->rx_ring) + pci_free_consistent(pdev, RX_TOTAL_SIZE, rrpriv->rx_ring, + rrpriv->rx_ring_dma); + if (rrpriv->tx_ring) + pci_free_consistent(pdev, TX_TOTAL_SIZE, rrpriv->tx_ring, + rrpriv->tx_ring_dma); + if (rrpriv->regs) + iounmap(rrpriv->regs); + if (pdev) { + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); + } + out2: + free_netdev(dev); + out3: + return ret; +} + +static void __devexit rr_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (dev) { + struct rr_private *rr = netdev_priv(dev); + + if (!(readl(&rr->regs->HostCtrl) & NIC_HALTED)){ + printk(KERN_ERR "%s: trying to unload running NIC\n", + dev->name); + writel(HALT_NIC, &rr->regs->HostCtrl); + } + + pci_free_consistent(pdev, EVT_RING_SIZE, rr->evt_ring, + rr->evt_ring_dma); + pci_free_consistent(pdev, RX_TOTAL_SIZE, rr->rx_ring, + rr->rx_ring_dma); + pci_free_consistent(pdev, TX_TOTAL_SIZE, rr->tx_ring, + rr->tx_ring_dma); + unregister_netdev(dev); + iounmap(rr->regs); + free_netdev(dev); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + } +} + + +/* + * Commands are considered to be slow, thus there is no reason to + * inline this. + */ +static void rr_issue_cmd(struct rr_private *rrpriv, struct cmd *cmd) +{ + struct rr_regs __iomem *regs; + u32 idx; + + regs = rrpriv->regs; + /* + * This is temporary - it will go away in the final version. + * We probably also want to make this function inline. + */ + if (readl(®s->HostCtrl) & NIC_HALTED){ + printk("issuing command for halted NIC, code 0x%x, " + "HostCtrl %08x\n", cmd->code, readl(®s->HostCtrl)); + if (readl(®s->Mode) & FATAL_ERR) + printk("error codes Fail1 %02x, Fail2 %02x\n", + readl(®s->Fail1), readl(®s->Fail2)); + } + + idx = rrpriv->info->cmd_ctrl.pi; + + writel(*(u32*)(cmd), ®s->CmdRing[idx]); + wmb(); + + idx = (idx - 1) % CMD_RING_ENTRIES; + rrpriv->info->cmd_ctrl.pi = idx; + wmb(); + + if (readl(®s->Mode) & FATAL_ERR) + printk("error code %02x\n", readl(®s->Fail1)); +} + + +/* + * Reset the board in a sensible manner. The NIC is already halted + * when we get here and a spin-lock is held. + */ +static int rr_reset(struct net_device *dev) +{ + struct rr_private *rrpriv; + struct rr_regs __iomem *regs; + u32 start_pc; + int i; + + rrpriv = netdev_priv(dev); + regs = rrpriv->regs; + + rr_load_firmware(dev); + + writel(0x01000000, ®s->TX_state); + writel(0xff800000, ®s->RX_state); + writel(0, ®s->AssistState); + writel(CLEAR_INTA, ®s->LocalCtrl); + writel(0x01, ®s->BrkPt); + writel(0, ®s->Timer); + writel(0, ®s->TimerRef); + writel(RESET_DMA, ®s->DmaReadState); + writel(RESET_DMA, ®s->DmaWriteState); + writel(0, ®s->DmaWriteHostHi); + writel(0, ®s->DmaWriteHostLo); + writel(0, ®s->DmaReadHostHi); + writel(0, ®s->DmaReadHostLo); + writel(0, ®s->DmaReadLen); + writel(0, ®s->DmaWriteLen); + writel(0, ®s->DmaWriteLcl); + writel(0, ®s->DmaWriteIPchecksum); + writel(0, ®s->DmaReadLcl); + writel(0, ®s->DmaReadIPchecksum); + writel(0, ®s->PciState); +#if (BITS_PER_LONG == 64) && defined __LITTLE_ENDIAN + writel(SWAP_DATA | PTR64BIT | PTR_WD_SWAP, ®s->Mode); +#elif (BITS_PER_LONG == 64) + writel(SWAP_DATA | PTR64BIT | PTR_WD_NOSWAP, ®s->Mode); +#else + writel(SWAP_DATA | PTR32BIT | PTR_WD_NOSWAP, ®s->Mode); +#endif + +#if 0 + /* + * Don't worry, this is just black magic. + */ + writel(0xdf000, ®s->RxBase); + writel(0xdf000, ®s->RxPrd); + writel(0xdf000, ®s->RxCon); + writel(0xce000, ®s->TxBase); + writel(0xce000, ®s->TxPrd); + writel(0xce000, ®s->TxCon); + writel(0, ®s->RxIndPro); + writel(0, ®s->RxIndCon); + writel(0, ®s->RxIndRef); + writel(0, ®s->TxIndPro); + writel(0, ®s->TxIndCon); + writel(0, ®s->TxIndRef); + writel(0xcc000, ®s->pad10[0]); + writel(0, ®s->DrCmndPro); + writel(0, ®s->DrCmndCon); + writel(0, ®s->DwCmndPro); + writel(0, ®s->DwCmndCon); + writel(0, ®s->DwCmndRef); + writel(0, ®s->DrDataPro); + writel(0, ®s->DrDataCon); + writel(0, ®s->DrDataRef); + writel(0, ®s->DwDataPro); + writel(0, ®s->DwDataCon); + writel(0, ®s->DwDataRef); +#endif + + writel(0xffffffff, ®s->MbEvent); + writel(0, ®s->Event); + + writel(0, ®s->TxPi); + writel(0, ®s->IpRxPi); + + writel(0, ®s->EvtCon); + writel(0, ®s->EvtPrd); + + rrpriv->info->evt_ctrl.pi = 0; + + for (i = 0; i < CMD_RING_ENTRIES; i++) + writel(0, ®s->CmdRing[i]); + +/* + * Why 32 ? is this not cache line size dependent? + */ + writel(RBURST_64|WBURST_64, ®s->PciState); + wmb(); + + start_pc = rr_read_eeprom_word(rrpriv, + offsetof(struct eeprom, rncd_info.FwStart)); + +#if (DEBUG > 1) + printk("%s: Executing firmware at address 0x%06x\n", + dev->name, start_pc); +#endif + + writel(start_pc + 0x800, ®s->Pc); + wmb(); + udelay(5); + + writel(start_pc, ®s->Pc); + wmb(); + + return 0; +} + + +/* + * Read a string from the EEPROM. + */ +static unsigned int rr_read_eeprom(struct rr_private *rrpriv, + unsigned long offset, + unsigned char *buf, + unsigned long length) +{ + struct rr_regs __iomem *regs = rrpriv->regs; + u32 misc, io, host, i; + + io = readl(®s->ExtIo); + writel(0, ®s->ExtIo); + misc = readl(®s->LocalCtrl); + writel(0, ®s->LocalCtrl); + host = readl(®s->HostCtrl); + writel(host | HALT_NIC, ®s->HostCtrl); + mb(); + + for (i = 0; i < length; i++){ + writel((EEPROM_BASE + ((offset+i) << 3)), ®s->WinBase); + mb(); + buf[i] = (readl(®s->WinData) >> 24) & 0xff; + mb(); + } + + writel(host, ®s->HostCtrl); + writel(misc, ®s->LocalCtrl); + writel(io, ®s->ExtIo); + mb(); + return i; +} + + +/* + * Shortcut to read one word (4 bytes) out of the EEPROM and convert + * it to our CPU byte-order. + */ +static u32 rr_read_eeprom_word(struct rr_private *rrpriv, + size_t offset) +{ + __be32 word; + + if ((rr_read_eeprom(rrpriv, offset, + (unsigned char *)&word, 4) == 4)) + return be32_to_cpu(word); + return 0; +} + + +/* + * Write a string to the EEPROM. + * + * This is only called when the firmware is not running. + */ +static unsigned int write_eeprom(struct rr_private *rrpriv, + unsigned long offset, + unsigned char *buf, + unsigned long length) +{ + struct rr_regs __iomem *regs = rrpriv->regs; + u32 misc, io, data, i, j, ready, error = 0; + + io = readl(®s->ExtIo); + writel(0, ®s->ExtIo); + misc = readl(®s->LocalCtrl); + writel(ENABLE_EEPROM_WRITE, ®s->LocalCtrl); + mb(); + + for (i = 0; i < length; i++){ + writel((EEPROM_BASE + ((offset+i) << 3)), ®s->WinBase); + mb(); + data = buf[i] << 24; + /* + * Only try to write the data if it is not the same + * value already. + */ + if ((readl(®s->WinData) & 0xff000000) != data){ + writel(data, ®s->WinData); + ready = 0; + j = 0; + mb(); + while(!ready){ + udelay(20); + if ((readl(®s->WinData) & 0xff000000) == + data) + ready = 1; + mb(); + if (j++ > 5000){ + printk("data mismatch: %08x, " + "WinData %08x\n", data, + readl(®s->WinData)); + ready = 1; + error = 1; + } + } + } + } + + writel(misc, ®s->LocalCtrl); + writel(io, ®s->ExtIo); + mb(); + + return error; +} + + +static int __devinit rr_init(struct net_device *dev) +{ + struct rr_private *rrpriv; + struct rr_regs __iomem *regs; + u32 sram_size, rev; + + rrpriv = netdev_priv(dev); + regs = rrpriv->regs; + + rev = readl(®s->FwRev); + rrpriv->fw_rev = rev; + if (rev > 0x00020024) + printk(" Firmware revision: %i.%i.%i\n", (rev >> 16), + ((rev >> 8) & 0xff), (rev & 0xff)); + else if (rev >= 0x00020000) { + printk(" Firmware revision: %i.%i.%i (2.0.37 or " + "later is recommended)\n", (rev >> 16), + ((rev >> 8) & 0xff), (rev & 0xff)); + }else{ + printk(" Firmware revision too old: %i.%i.%i, please " + "upgrade to 2.0.37 or later.\n", + (rev >> 16), ((rev >> 8) & 0xff), (rev & 0xff)); + } + +#if (DEBUG > 2) + printk(" Maximum receive rings %i\n", readl(®s->MaxRxRng)); +#endif + + /* + * Read the hardware address from the eeprom. The HW address + * is not really necessary for HIPPI but awfully convenient. + * The pointer arithmetic to put it in dev_addr is ugly, but + * Donald Becker does it this way for the GigE version of this + * card and it's shorter and more portable than any + * other method I've seen. -VAL + */ + + *(__be16 *)(dev->dev_addr) = + htons(rr_read_eeprom_word(rrpriv, offsetof(struct eeprom, manf.BoardULA))); + *(__be32 *)(dev->dev_addr+2) = + htonl(rr_read_eeprom_word(rrpriv, offsetof(struct eeprom, manf.BoardULA[4]))); + + printk(" MAC: %pM\n", dev->dev_addr); + + sram_size = rr_read_eeprom_word(rrpriv, 8); + printk(" SRAM size 0x%06x\n", sram_size); + + return 0; +} + + +static int rr_init1(struct net_device *dev) +{ + struct rr_private *rrpriv; + struct rr_regs __iomem *regs; + unsigned long myjif, flags; + struct cmd cmd; + u32 hostctrl; + int ecode = 0; + short i; + + rrpriv = netdev_priv(dev); + regs = rrpriv->regs; + + spin_lock_irqsave(&rrpriv->lock, flags); + + hostctrl = readl(®s->HostCtrl); + writel(hostctrl | HALT_NIC | RR_CLEAR_INT, ®s->HostCtrl); + wmb(); + + if (hostctrl & PARITY_ERR){ + printk("%s: Parity error halting NIC - this is serious!\n", + dev->name); + spin_unlock_irqrestore(&rrpriv->lock, flags); + ecode = -EFAULT; + goto error; + } + + set_rxaddr(regs, rrpriv->rx_ctrl_dma); + set_infoaddr(regs, rrpriv->info_dma); + + rrpriv->info->evt_ctrl.entry_size = sizeof(struct event); + rrpriv->info->evt_ctrl.entries = EVT_RING_ENTRIES; + rrpriv->info->evt_ctrl.mode = 0; + rrpriv->info->evt_ctrl.pi = 0; + set_rraddr(&rrpriv->info->evt_ctrl.rngptr, rrpriv->evt_ring_dma); + + rrpriv->info->cmd_ctrl.entry_size = sizeof(struct cmd); + rrpriv->info->cmd_ctrl.entries = CMD_RING_ENTRIES; + rrpriv->info->cmd_ctrl.mode = 0; + rrpriv->info->cmd_ctrl.pi = 15; + + for (i = 0; i < CMD_RING_ENTRIES; i++) { + writel(0, ®s->CmdRing[i]); + } + + for (i = 0; i < TX_RING_ENTRIES; i++) { + rrpriv->tx_ring[i].size = 0; + set_rraddr(&rrpriv->tx_ring[i].addr, 0); + rrpriv->tx_skbuff[i] = NULL; + } + rrpriv->info->tx_ctrl.entry_size = sizeof(struct tx_desc); + rrpriv->info->tx_ctrl.entries = TX_RING_ENTRIES; + rrpriv->info->tx_ctrl.mode = 0; + rrpriv->info->tx_ctrl.pi = 0; + set_rraddr(&rrpriv->info->tx_ctrl.rngptr, rrpriv->tx_ring_dma); + + /* + * Set dirty_tx before we start receiving interrupts, otherwise + * the interrupt handler might think it is supposed to process + * tx ints before we are up and running, which may cause a null + * pointer access in the int handler. + */ + rrpriv->tx_full = 0; + rrpriv->cur_rx = 0; + rrpriv->dirty_rx = rrpriv->dirty_tx = 0; + + rr_reset(dev); + + /* Tuning values */ + writel(0x5000, ®s->ConRetry); + writel(0x100, ®s->ConRetryTmr); + writel(0x500000, ®s->ConTmout); + writel(0x60, ®s->IntrTmr); + writel(0x500000, ®s->TxDataMvTimeout); + writel(0x200000, ®s->RxDataMvTimeout); + writel(0x80, ®s->WriteDmaThresh); + writel(0x80, ®s->ReadDmaThresh); + + rrpriv->fw_running = 0; + wmb(); + + hostctrl &= ~(HALT_NIC | INVALID_INST_B | PARITY_ERR); + writel(hostctrl, ®s->HostCtrl); + wmb(); + + spin_unlock_irqrestore(&rrpriv->lock, flags); + + for (i = 0; i < RX_RING_ENTRIES; i++) { + struct sk_buff *skb; + dma_addr_t addr; + + rrpriv->rx_ring[i].mode = 0; + skb = alloc_skb(dev->mtu + HIPPI_HLEN, GFP_ATOMIC); + if (!skb) { + printk(KERN_WARNING "%s: Unable to allocate memory " + "for receive ring - halting NIC\n", dev->name); + ecode = -ENOMEM; + goto error; + } + rrpriv->rx_skbuff[i] = skb; + addr = pci_map_single(rrpriv->pci_dev, skb->data, + dev->mtu + HIPPI_HLEN, PCI_DMA_FROMDEVICE); + /* + * Sanity test to see if we conflict with the DMA + * limitations of the Roadrunner. + */ + if ((((unsigned long)skb->data) & 0xfff) > ~65320) + printk("skb alloc error\n"); + + set_rraddr(&rrpriv->rx_ring[i].addr, addr); + rrpriv->rx_ring[i].size = dev->mtu + HIPPI_HLEN; + } + + rrpriv->rx_ctrl[4].entry_size = sizeof(struct rx_desc); + rrpriv->rx_ctrl[4].entries = RX_RING_ENTRIES; + rrpriv->rx_ctrl[4].mode = 8; + rrpriv->rx_ctrl[4].pi = 0; + wmb(); + set_rraddr(&rrpriv->rx_ctrl[4].rngptr, rrpriv->rx_ring_dma); + + udelay(1000); + + /* + * Now start the FirmWare. + */ + cmd.code = C_START_FW; + cmd.ring = 0; + cmd.index = 0; + + rr_issue_cmd(rrpriv, &cmd); + + /* + * Give the FirmWare time to chew on the `get running' command. + */ + myjif = jiffies + 5 * HZ; + while (time_before(jiffies, myjif) && !rrpriv->fw_running) + cpu_relax(); + + netif_start_queue(dev); + + return ecode; + + error: + /* + * We might have gotten here because we are out of memory, + * make sure we release everything we allocated before failing + */ + for (i = 0; i < RX_RING_ENTRIES; i++) { + struct sk_buff *skb = rrpriv->rx_skbuff[i]; + + if (skb) { + pci_unmap_single(rrpriv->pci_dev, + rrpriv->rx_ring[i].addr.addrlo, + dev->mtu + HIPPI_HLEN, + PCI_DMA_FROMDEVICE); + rrpriv->rx_ring[i].size = 0; + set_rraddr(&rrpriv->rx_ring[i].addr, 0); + dev_kfree_skb(skb); + rrpriv->rx_skbuff[i] = NULL; + } + } + return ecode; +} + + +/* + * All events are considered to be slow (RX/TX ints do not generate + * events) and are handled here, outside the main interrupt handler, + * to reduce the size of the handler. + */ +static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx) +{ + struct rr_private *rrpriv; + struct rr_regs __iomem *regs; + u32 tmp; + + rrpriv = netdev_priv(dev); + regs = rrpriv->regs; + + while (prodidx != eidx){ + switch (rrpriv->evt_ring[eidx].code){ + case E_NIC_UP: + tmp = readl(®s->FwRev); + printk(KERN_INFO "%s: Firmware revision %i.%i.%i " + "up and running\n", dev->name, + (tmp >> 16), ((tmp >> 8) & 0xff), (tmp & 0xff)); + rrpriv->fw_running = 1; + writel(RX_RING_ENTRIES - 1, ®s->IpRxPi); + wmb(); + break; + case E_LINK_ON: + printk(KERN_INFO "%s: Optical link ON\n", dev->name); + break; + case E_LINK_OFF: + printk(KERN_INFO "%s: Optical link OFF\n", dev->name); + break; + case E_RX_IDLE: + printk(KERN_WARNING "%s: RX data not moving\n", + dev->name); + goto drop; + case E_WATCHDOG: + printk(KERN_INFO "%s: The watchdog is here to see " + "us\n", dev->name); + break; + case E_INTERN_ERR: + printk(KERN_ERR "%s: HIPPI Internal NIC error\n", + dev->name); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, + ®s->HostCtrl); + wmb(); + break; + case E_HOST_ERR: + printk(KERN_ERR "%s: Host software error\n", + dev->name); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, + ®s->HostCtrl); + wmb(); + break; + /* + * TX events. + */ + case E_CON_REJ: + printk(KERN_WARNING "%s: Connection rejected\n", + dev->name); + dev->stats.tx_aborted_errors++; + break; + case E_CON_TMOUT: + printk(KERN_WARNING "%s: Connection timeout\n", + dev->name); + break; + case E_DISC_ERR: + printk(KERN_WARNING "%s: HIPPI disconnect error\n", + dev->name); + dev->stats.tx_aborted_errors++; + break; + case E_INT_PRTY: + printk(KERN_ERR "%s: HIPPI Internal Parity error\n", + dev->name); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, + ®s->HostCtrl); + wmb(); + break; + case E_TX_IDLE: + printk(KERN_WARNING "%s: Transmitter idle\n", + dev->name); + break; + case E_TX_LINK_DROP: + printk(KERN_WARNING "%s: Link lost during transmit\n", + dev->name); + dev->stats.tx_aborted_errors++; + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, + ®s->HostCtrl); + wmb(); + break; + case E_TX_INV_RNG: + printk(KERN_ERR "%s: Invalid send ring block\n", + dev->name); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, + ®s->HostCtrl); + wmb(); + break; + case E_TX_INV_BUF: + printk(KERN_ERR "%s: Invalid send buffer address\n", + dev->name); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, + ®s->HostCtrl); + wmb(); + break; + case E_TX_INV_DSC: + printk(KERN_ERR "%s: Invalid descriptor address\n", + dev->name); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, + ®s->HostCtrl); + wmb(); + break; + /* + * RX events. + */ + case E_RX_RNG_OUT: + printk(KERN_INFO "%s: Receive ring full\n", dev->name); + break; + + case E_RX_PAR_ERR: + printk(KERN_WARNING "%s: Receive parity error\n", + dev->name); + goto drop; + case E_RX_LLRC_ERR: + printk(KERN_WARNING "%s: Receive LLRC error\n", + dev->name); + goto drop; + case E_PKT_LN_ERR: + printk(KERN_WARNING "%s: Receive packet length " + "error\n", dev->name); + goto drop; + case E_DTA_CKSM_ERR: + printk(KERN_WARNING "%s: Data checksum error\n", + dev->name); + goto drop; + case E_SHT_BST: + printk(KERN_WARNING "%s: Unexpected short burst " + "error\n", dev->name); + goto drop; + case E_STATE_ERR: + printk(KERN_WARNING "%s: Recv. state transition" + " error\n", dev->name); + goto drop; + case E_UNEXP_DATA: + printk(KERN_WARNING "%s: Unexpected data error\n", + dev->name); + goto drop; + case E_LST_LNK_ERR: + printk(KERN_WARNING "%s: Link lost error\n", + dev->name); + goto drop; + case E_FRM_ERR: + printk(KERN_WARNING "%s: Framming Error\n", + dev->name); + goto drop; + case E_FLG_SYN_ERR: + printk(KERN_WARNING "%s: Flag sync. lost during " + "packet\n", dev->name); + goto drop; + case E_RX_INV_BUF: + printk(KERN_ERR "%s: Invalid receive buffer " + "address\n", dev->name); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, + ®s->HostCtrl); + wmb(); + break; + case E_RX_INV_DSC: + printk(KERN_ERR "%s: Invalid receive descriptor " + "address\n", dev->name); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, + ®s->HostCtrl); + wmb(); + break; + case E_RNG_BLK: + printk(KERN_ERR "%s: Invalid ring block\n", + dev->name); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, + ®s->HostCtrl); + wmb(); + break; + drop: + /* Label packet to be dropped. + * Actual dropping occurs in rx + * handling. + * + * The index of packet we get to drop is + * the index of the packet following + * the bad packet. -kbf + */ + { + u16 index = rrpriv->evt_ring[eidx].index; + index = (index + (RX_RING_ENTRIES - 1)) % + RX_RING_ENTRIES; + rrpriv->rx_ring[index].mode |= + (PACKET_BAD | PACKET_END); + } + break; + default: + printk(KERN_WARNING "%s: Unhandled event 0x%02x\n", + dev->name, rrpriv->evt_ring[eidx].code); + } + eidx = (eidx + 1) % EVT_RING_ENTRIES; + } + + rrpriv->info->evt_ctrl.pi = eidx; + wmb(); + return eidx; +} + + +static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) +{ + struct rr_private *rrpriv = netdev_priv(dev); + struct rr_regs __iomem *regs = rrpriv->regs; + + do { + struct rx_desc *desc; + u32 pkt_len; + + desc = &(rrpriv->rx_ring[index]); + pkt_len = desc->size; +#if (DEBUG > 2) + printk("index %i, rxlimit %i\n", index, rxlimit); + printk("len %x, mode %x\n", pkt_len, desc->mode); +#endif + if ( (rrpriv->rx_ring[index].mode & PACKET_BAD) == PACKET_BAD){ + dev->stats.rx_dropped++; + goto defer; + } + + if (pkt_len > 0){ + struct sk_buff *skb, *rx_skb; + + rx_skb = rrpriv->rx_skbuff[index]; + + if (pkt_len < PKT_COPY_THRESHOLD) { + skb = alloc_skb(pkt_len, GFP_ATOMIC); + if (skb == NULL){ + printk(KERN_WARNING "%s: Unable to allocate skb (%i bytes), deferring packet\n", dev->name, pkt_len); + dev->stats.rx_dropped++; + goto defer; + } else { + pci_dma_sync_single_for_cpu(rrpriv->pci_dev, + desc->addr.addrlo, + pkt_len, + PCI_DMA_FROMDEVICE); + + memcpy(skb_put(skb, pkt_len), + rx_skb->data, pkt_len); + + pci_dma_sync_single_for_device(rrpriv->pci_dev, + desc->addr.addrlo, + pkt_len, + PCI_DMA_FROMDEVICE); + } + }else{ + struct sk_buff *newskb; + + newskb = alloc_skb(dev->mtu + HIPPI_HLEN, + GFP_ATOMIC); + if (newskb){ + dma_addr_t addr; + + pci_unmap_single(rrpriv->pci_dev, + desc->addr.addrlo, dev->mtu + + HIPPI_HLEN, PCI_DMA_FROMDEVICE); + skb = rx_skb; + skb_put(skb, pkt_len); + rrpriv->rx_skbuff[index] = newskb; + addr = pci_map_single(rrpriv->pci_dev, + newskb->data, + dev->mtu + HIPPI_HLEN, + PCI_DMA_FROMDEVICE); + set_rraddr(&desc->addr, addr); + } else { + printk("%s: Out of memory, deferring " + "packet\n", dev->name); + dev->stats.rx_dropped++; + goto defer; + } + } + skb->protocol = hippi_type_trans(skb, dev); + + netif_rx(skb); /* send it up */ + + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; + } + defer: + desc->mode = 0; + desc->size = dev->mtu + HIPPI_HLEN; + + if ((index & 7) == 7) + writel(index, ®s->IpRxPi); + + index = (index + 1) % RX_RING_ENTRIES; + } while(index != rxlimit); + + rrpriv->cur_rx = index; + wmb(); +} + + +static irqreturn_t rr_interrupt(int irq, void *dev_id) +{ + struct rr_private *rrpriv; + struct rr_regs __iomem *regs; + struct net_device *dev = (struct net_device *)dev_id; + u32 prodidx, rxindex, eidx, txcsmr, rxlimit, txcon; + + rrpriv = netdev_priv(dev); + regs = rrpriv->regs; + + if (!(readl(®s->HostCtrl) & RR_INT)) + return IRQ_NONE; + + spin_lock(&rrpriv->lock); + + prodidx = readl(®s->EvtPrd); + txcsmr = (prodidx >> 8) & 0xff; + rxlimit = (prodidx >> 16) & 0xff; + prodidx &= 0xff; + +#if (DEBUG > 2) + printk("%s: interrupt, prodidx = %i, eidx = %i\n", dev->name, + prodidx, rrpriv->info->evt_ctrl.pi); +#endif + /* + * Order here is important. We must handle events + * before doing anything else in order to catch + * such things as LLRC errors, etc -kbf + */ + + eidx = rrpriv->info->evt_ctrl.pi; + if (prodidx != eidx) + eidx = rr_handle_event(dev, prodidx, eidx); + + rxindex = rrpriv->cur_rx; + if (rxindex != rxlimit) + rx_int(dev, rxlimit, rxindex); + + txcon = rrpriv->dirty_tx; + if (txcsmr != txcon) { + do { + /* Due to occational firmware TX producer/consumer out + * of sync. error need to check entry in ring -kbf + */ + if(rrpriv->tx_skbuff[txcon]){ + struct tx_desc *desc; + struct sk_buff *skb; + + desc = &(rrpriv->tx_ring[txcon]); + skb = rrpriv->tx_skbuff[txcon]; + + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + + pci_unmap_single(rrpriv->pci_dev, + desc->addr.addrlo, skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + + rrpriv->tx_skbuff[txcon] = NULL; + desc->size = 0; + set_rraddr(&rrpriv->tx_ring[txcon].addr, 0); + desc->mode = 0; + } + txcon = (txcon + 1) % TX_RING_ENTRIES; + } while (txcsmr != txcon); + wmb(); + + rrpriv->dirty_tx = txcon; + if (rrpriv->tx_full && rr_if_busy(dev) && + (((rrpriv->info->tx_ctrl.pi + 1) % TX_RING_ENTRIES) + != rrpriv->dirty_tx)){ + rrpriv->tx_full = 0; + netif_wake_queue(dev); + } + } + + eidx |= ((txcsmr << 8) | (rxlimit << 16)); + writel(eidx, ®s->EvtCon); + wmb(); + + spin_unlock(&rrpriv->lock); + return IRQ_HANDLED; +} + +static inline void rr_raz_tx(struct rr_private *rrpriv, + struct net_device *dev) +{ + int i; + + for (i = 0; i < TX_RING_ENTRIES; i++) { + struct sk_buff *skb = rrpriv->tx_skbuff[i]; + + if (skb) { + struct tx_desc *desc = &(rrpriv->tx_ring[i]); + + pci_unmap_single(rrpriv->pci_dev, desc->addr.addrlo, + skb->len, PCI_DMA_TODEVICE); + desc->size = 0; + set_rraddr(&desc->addr, 0); + dev_kfree_skb(skb); + rrpriv->tx_skbuff[i] = NULL; + } + } +} + + +static inline void rr_raz_rx(struct rr_private *rrpriv, + struct net_device *dev) +{ + int i; + + for (i = 0; i < RX_RING_ENTRIES; i++) { + struct sk_buff *skb = rrpriv->rx_skbuff[i]; + + if (skb) { + struct rx_desc *desc = &(rrpriv->rx_ring[i]); + + pci_unmap_single(rrpriv->pci_dev, desc->addr.addrlo, + dev->mtu + HIPPI_HLEN, PCI_DMA_FROMDEVICE); + desc->size = 0; + set_rraddr(&desc->addr, 0); + dev_kfree_skb(skb); + rrpriv->rx_skbuff[i] = NULL; + } + } +} + +static void rr_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct rr_private *rrpriv = netdev_priv(dev); + struct rr_regs __iomem *regs = rrpriv->regs; + unsigned long flags; + + if (readl(®s->HostCtrl) & NIC_HALTED){ + printk("%s: Restarting nic\n", dev->name); + memset(rrpriv->rx_ctrl, 0, 256 * sizeof(struct ring_ctrl)); + memset(rrpriv->info, 0, sizeof(struct rr_info)); + wmb(); + + rr_raz_tx(rrpriv, dev); + rr_raz_rx(rrpriv, dev); + + if (rr_init1(dev)) { + spin_lock_irqsave(&rrpriv->lock, flags); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, + ®s->HostCtrl); + spin_unlock_irqrestore(&rrpriv->lock, flags); + } + } + rrpriv->timer.expires = RUN_AT(5*HZ); + add_timer(&rrpriv->timer); +} + + +static int rr_open(struct net_device *dev) +{ + struct rr_private *rrpriv = netdev_priv(dev); + struct pci_dev *pdev = rrpriv->pci_dev; + struct rr_regs __iomem *regs; + int ecode = 0; + unsigned long flags; + dma_addr_t dma_addr; + + regs = rrpriv->regs; + + if (rrpriv->fw_rev < 0x00020000) { + printk(KERN_WARNING "%s: trying to configure device with " + "obsolete firmware\n", dev->name); + ecode = -EBUSY; + goto error; + } + + rrpriv->rx_ctrl = pci_alloc_consistent(pdev, + 256 * sizeof(struct ring_ctrl), + &dma_addr); + if (!rrpriv->rx_ctrl) { + ecode = -ENOMEM; + goto error; + } + rrpriv->rx_ctrl_dma = dma_addr; + memset(rrpriv->rx_ctrl, 0, 256*sizeof(struct ring_ctrl)); + + rrpriv->info = pci_alloc_consistent(pdev, sizeof(struct rr_info), + &dma_addr); + if (!rrpriv->info) { + ecode = -ENOMEM; + goto error; + } + rrpriv->info_dma = dma_addr; + memset(rrpriv->info, 0, sizeof(struct rr_info)); + wmb(); + + spin_lock_irqsave(&rrpriv->lock, flags); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->HostCtrl); + readl(®s->HostCtrl); + spin_unlock_irqrestore(&rrpriv->lock, flags); + + if (request_irq(dev->irq, rr_interrupt, IRQF_SHARED, dev->name, dev)) { + printk(KERN_WARNING "%s: Requested IRQ %d is busy\n", + dev->name, dev->irq); + ecode = -EAGAIN; + goto error; + } + + if ((ecode = rr_init1(dev))) + goto error; + + /* Set the timer to switch to check for link beat and perhaps switch + to an alternate media type. */ + init_timer(&rrpriv->timer); + rrpriv->timer.expires = RUN_AT(5*HZ); /* 5 sec. watchdog */ + rrpriv->timer.data = (unsigned long)dev; + rrpriv->timer.function = rr_timer; /* timer handler */ + add_timer(&rrpriv->timer); + + netif_start_queue(dev); + + return ecode; + + error: + spin_lock_irqsave(&rrpriv->lock, flags); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->HostCtrl); + spin_unlock_irqrestore(&rrpriv->lock, flags); + + if (rrpriv->info) { + pci_free_consistent(pdev, sizeof(struct rr_info), rrpriv->info, + rrpriv->info_dma); + rrpriv->info = NULL; + } + if (rrpriv->rx_ctrl) { + pci_free_consistent(pdev, sizeof(struct ring_ctrl), + rrpriv->rx_ctrl, rrpriv->rx_ctrl_dma); + rrpriv->rx_ctrl = NULL; + } + + netif_stop_queue(dev); + + return ecode; +} + + +static void rr_dump(struct net_device *dev) +{ + struct rr_private *rrpriv; + struct rr_regs __iomem *regs; + u32 index, cons; + short i; + int len; + + rrpriv = netdev_priv(dev); + regs = rrpriv->regs; + + printk("%s: dumping NIC TX rings\n", dev->name); + + printk("RxPrd %08x, TxPrd %02x, EvtPrd %08x, TxPi %02x, TxCtrlPi %02x\n", + readl(®s->RxPrd), readl(®s->TxPrd), + readl(®s->EvtPrd), readl(®s->TxPi), + rrpriv->info->tx_ctrl.pi); + + printk("Error code 0x%x\n", readl(®s->Fail1)); + + index = (((readl(®s->EvtPrd) >> 8) & 0xff) - 1) % TX_RING_ENTRIES; + cons = rrpriv->dirty_tx; + printk("TX ring index %i, TX consumer %i\n", + index, cons); + + if (rrpriv->tx_skbuff[index]){ + len = min_t(int, 0x80, rrpriv->tx_skbuff[index]->len); + printk("skbuff for index %i is valid - dumping data (0x%x bytes - DMA len 0x%x)\n", index, len, rrpriv->tx_ring[index].size); + for (i = 0; i < len; i++){ + if (!(i & 7)) + printk("\n"); + printk("%02x ", (unsigned char) rrpriv->tx_skbuff[index]->data[i]); + } + printk("\n"); + } + + if (rrpriv->tx_skbuff[cons]){ + len = min_t(int, 0x80, rrpriv->tx_skbuff[cons]->len); + printk("skbuff for cons %i is valid - dumping data (0x%x bytes - skbuff len 0x%x)\n", cons, len, rrpriv->tx_skbuff[cons]->len); + printk("mode 0x%x, size 0x%x,\n phys %08Lx, skbuff-addr %08lx, truesize 0x%x\n", + rrpriv->tx_ring[cons].mode, + rrpriv->tx_ring[cons].size, + (unsigned long long) rrpriv->tx_ring[cons].addr.addrlo, + (unsigned long)rrpriv->tx_skbuff[cons]->data, + (unsigned int)rrpriv->tx_skbuff[cons]->truesize); + for (i = 0; i < len; i++){ + if (!(i & 7)) + printk("\n"); + printk("%02x ", (unsigned char)rrpriv->tx_ring[cons].size); + } + printk("\n"); + } + + printk("dumping TX ring info:\n"); + for (i = 0; i < TX_RING_ENTRIES; i++) + printk("mode 0x%x, size 0x%x, phys-addr %08Lx\n", + rrpriv->tx_ring[i].mode, + rrpriv->tx_ring[i].size, + (unsigned long long) rrpriv->tx_ring[i].addr.addrlo); + +} + + +static int rr_close(struct net_device *dev) +{ + struct rr_private *rrpriv; + struct rr_regs __iomem *regs; + unsigned long flags; + u32 tmp; + short i; + + netif_stop_queue(dev); + + rrpriv = netdev_priv(dev); + regs = rrpriv->regs; + + /* + * Lock to make sure we are not cleaning up while another CPU + * is handling interrupts. + */ + spin_lock_irqsave(&rrpriv->lock, flags); + + tmp = readl(®s->HostCtrl); + if (tmp & NIC_HALTED){ + printk("%s: NIC already halted\n", dev->name); + rr_dump(dev); + }else{ + tmp |= HALT_NIC | RR_CLEAR_INT; + writel(tmp, ®s->HostCtrl); + readl(®s->HostCtrl); + } + + rrpriv->fw_running = 0; + + del_timer_sync(&rrpriv->timer); + + writel(0, ®s->TxPi); + writel(0, ®s->IpRxPi); + + writel(0, ®s->EvtCon); + writel(0, ®s->EvtPrd); + + for (i = 0; i < CMD_RING_ENTRIES; i++) + writel(0, ®s->CmdRing[i]); + + rrpriv->info->tx_ctrl.entries = 0; + rrpriv->info->cmd_ctrl.pi = 0; + rrpriv->info->evt_ctrl.pi = 0; + rrpriv->rx_ctrl[4].entries = 0; + + rr_raz_tx(rrpriv, dev); + rr_raz_rx(rrpriv, dev); + + pci_free_consistent(rrpriv->pci_dev, 256 * sizeof(struct ring_ctrl), + rrpriv->rx_ctrl, rrpriv->rx_ctrl_dma); + rrpriv->rx_ctrl = NULL; + + pci_free_consistent(rrpriv->pci_dev, sizeof(struct rr_info), + rrpriv->info, rrpriv->info_dma); + rrpriv->info = NULL; + + free_irq(dev->irq, dev); + spin_unlock_irqrestore(&rrpriv->lock, flags); + + return 0; +} + + +static netdev_tx_t rr_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct rr_private *rrpriv = netdev_priv(dev); + struct rr_regs __iomem *regs = rrpriv->regs; + struct hippi_cb *hcb = (struct hippi_cb *) skb->cb; + struct ring_ctrl *txctrl; + unsigned long flags; + u32 index, len = skb->len; + u32 *ifield; + struct sk_buff *new_skb; + + if (readl(®s->Mode) & FATAL_ERR) + printk("error codes Fail1 %02x, Fail2 %02x\n", + readl(®s->Fail1), readl(®s->Fail2)); + + /* + * We probably need to deal with tbusy here to prevent overruns. + */ + + if (skb_headroom(skb) < 8){ + printk("incoming skb too small - reallocating\n"); + if (!(new_skb = dev_alloc_skb(len + 8))) { + dev_kfree_skb(skb); + netif_wake_queue(dev); + return NETDEV_TX_OK; + } + skb_reserve(new_skb, 8); + skb_put(new_skb, len); + skb_copy_from_linear_data(skb, new_skb->data, len); + dev_kfree_skb(skb); + skb = new_skb; + } + + ifield = (u32 *)skb_push(skb, 8); + + ifield[0] = 0; + ifield[1] = hcb->ifield; + + /* + * We don't need the lock before we are actually going to start + * fiddling with the control blocks. + */ + spin_lock_irqsave(&rrpriv->lock, flags); + + txctrl = &rrpriv->info->tx_ctrl; + + index = txctrl->pi; + + rrpriv->tx_skbuff[index] = skb; + set_rraddr(&rrpriv->tx_ring[index].addr, pci_map_single( + rrpriv->pci_dev, skb->data, len + 8, PCI_DMA_TODEVICE)); + rrpriv->tx_ring[index].size = len + 8; /* include IFIELD */ + rrpriv->tx_ring[index].mode = PACKET_START | PACKET_END; + txctrl->pi = (index + 1) % TX_RING_ENTRIES; + wmb(); + writel(txctrl->pi, ®s->TxPi); + + if (txctrl->pi == rrpriv->dirty_tx){ + rrpriv->tx_full = 1; + netif_stop_queue(dev); + } + + spin_unlock_irqrestore(&rrpriv->lock, flags); + + return NETDEV_TX_OK; +} + + +/* + * Read the firmware out of the EEPROM and put it into the SRAM + * (or from user space - later) + * + * This operation requires the NIC to be halted and is performed with + * interrupts disabled and with the spinlock hold. + */ +static int rr_load_firmware(struct net_device *dev) +{ + struct rr_private *rrpriv; + struct rr_regs __iomem *regs; + size_t eptr, segptr; + int i, j; + u32 localctrl, sptr, len, tmp; + u32 p2len, p2size, nr_seg, revision, io, sram_size; + + rrpriv = netdev_priv(dev); + regs = rrpriv->regs; + + if (dev->flags & IFF_UP) + return -EBUSY; + + if (!(readl(®s->HostCtrl) & NIC_HALTED)){ + printk("%s: Trying to load firmware to a running NIC.\n", + dev->name); + return -EBUSY; + } + + localctrl = readl(®s->LocalCtrl); + writel(0, ®s->LocalCtrl); + + writel(0, ®s->EvtPrd); + writel(0, ®s->RxPrd); + writel(0, ®s->TxPrd); + + /* + * First wipe the entire SRAM, otherwise we might run into all + * kinds of trouble ... sigh, this took almost all afternoon + * to track down ;-( + */ + io = readl(®s->ExtIo); + writel(0, ®s->ExtIo); + sram_size = rr_read_eeprom_word(rrpriv, 8); + + for (i = 200; i < sram_size / 4; i++){ + writel(i * 4, ®s->WinBase); + mb(); + writel(0, ®s->WinData); + mb(); + } + writel(io, ®s->ExtIo); + mb(); + + eptr = rr_read_eeprom_word(rrpriv, + offsetof(struct eeprom, rncd_info.AddrRunCodeSegs)); + eptr = ((eptr & 0x1fffff) >> 3); + + p2len = rr_read_eeprom_word(rrpriv, 0x83*4); + p2len = (p2len << 2); + p2size = rr_read_eeprom_word(rrpriv, 0x84*4); + p2size = ((p2size & 0x1fffff) >> 3); + + if ((eptr < p2size) || (eptr > (p2size + p2len))){ + printk("%s: eptr is invalid\n", dev->name); + goto out; + } + + revision = rr_read_eeprom_word(rrpriv, + offsetof(struct eeprom, manf.HeaderFmt)); + + if (revision != 1){ + printk("%s: invalid firmware format (%i)\n", + dev->name, revision); + goto out; + } + + nr_seg = rr_read_eeprom_word(rrpriv, eptr); + eptr +=4; +#if (DEBUG > 1) + printk("%s: nr_seg %i\n", dev->name, nr_seg); +#endif + + for (i = 0; i < nr_seg; i++){ + sptr = rr_read_eeprom_word(rrpriv, eptr); + eptr += 4; + len = rr_read_eeprom_word(rrpriv, eptr); + eptr += 4; + segptr = rr_read_eeprom_word(rrpriv, eptr); + segptr = ((segptr & 0x1fffff) >> 3); + eptr += 4; +#if (DEBUG > 1) + printk("%s: segment %i, sram address %06x, length %04x, segptr %06x\n", + dev->name, i, sptr, len, segptr); +#endif + for (j = 0; j < len; j++){ + tmp = rr_read_eeprom_word(rrpriv, segptr); + writel(sptr, ®s->WinBase); + mb(); + writel(tmp, ®s->WinData); + mb(); + segptr += 4; + sptr += 4; + } + } + +out: + writel(localctrl, ®s->LocalCtrl); + mb(); + return 0; +} + + +static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct rr_private *rrpriv; + unsigned char *image, *oldimage; + unsigned long flags; + unsigned int i; + int error = -EOPNOTSUPP; + + rrpriv = netdev_priv(dev); + + switch(cmd){ + case SIOCRRGFW: + if (!capable(CAP_SYS_RAWIO)){ + return -EPERM; + } + + image = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL); + if (!image){ + printk(KERN_ERR "%s: Unable to allocate memory " + "for EEPROM image\n", dev->name); + return -ENOMEM; + } + + + if (rrpriv->fw_running){ + printk("%s: Firmware already running\n", dev->name); + error = -EPERM; + goto gf_out; + } + + spin_lock_irqsave(&rrpriv->lock, flags); + i = rr_read_eeprom(rrpriv, 0, image, EEPROM_BYTES); + spin_unlock_irqrestore(&rrpriv->lock, flags); + if (i != EEPROM_BYTES){ + printk(KERN_ERR "%s: Error reading EEPROM\n", + dev->name); + error = -EFAULT; + goto gf_out; + } + error = copy_to_user(rq->ifr_data, image, EEPROM_BYTES); + if (error) + error = -EFAULT; + gf_out: + kfree(image); + return error; + + case SIOCRRPFW: + if (!capable(CAP_SYS_RAWIO)){ + return -EPERM; + } + + image = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL); + oldimage = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL); + if (!image || !oldimage) { + printk(KERN_ERR "%s: Unable to allocate memory " + "for EEPROM image\n", dev->name); + error = -ENOMEM; + goto wf_out; + } + + error = copy_from_user(image, rq->ifr_data, EEPROM_BYTES); + if (error) { + error = -EFAULT; + goto wf_out; + } + + if (rrpriv->fw_running){ + printk("%s: Firmware already running\n", dev->name); + error = -EPERM; + goto wf_out; + } + + printk("%s: Updating EEPROM firmware\n", dev->name); + + spin_lock_irqsave(&rrpriv->lock, flags); + error = write_eeprom(rrpriv, 0, image, EEPROM_BYTES); + if (error) + printk(KERN_ERR "%s: Error writing EEPROM\n", + dev->name); + + i = rr_read_eeprom(rrpriv, 0, oldimage, EEPROM_BYTES); + spin_unlock_irqrestore(&rrpriv->lock, flags); + + if (i != EEPROM_BYTES) + printk(KERN_ERR "%s: Error reading back EEPROM " + "image\n", dev->name); + + error = memcmp(image, oldimage, EEPROM_BYTES); + if (error){ + printk(KERN_ERR "%s: Error verifying EEPROM image\n", + dev->name); + error = -EFAULT; + } + wf_out: + kfree(oldimage); + kfree(image); + return error; + + case SIOCRRID: + return put_user(0x52523032, (int __user *)rq->ifr_data); + default: + return error; + } +} + +static DEFINE_PCI_DEVICE_TABLE(rr_pci_tbl) = { + { PCI_VENDOR_ID_ESSENTIAL, PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER, + PCI_ANY_ID, PCI_ANY_ID, }, + { 0,} +}; +MODULE_DEVICE_TABLE(pci, rr_pci_tbl); + +static struct pci_driver rr_driver = { + .name = "rrunner", + .id_table = rr_pci_tbl, + .probe = rr_init_one, + .remove = __devexit_p(rr_remove_one), +}; + +static int __init rr_init_module(void) +{ + return pci_register_driver(&rr_driver); +} + +static void __exit rr_cleanup_module(void) +{ + pci_unregister_driver(&rr_driver); +} + +module_init(rr_init_module); +module_exit(rr_cleanup_module); diff --git a/drivers/net/hippi/rrunner.h b/drivers/net/hippi/rrunner.h new file mode 100644 index 0000000..2816904 --- /dev/null +++ b/drivers/net/hippi/rrunner.h @@ -0,0 +1,846 @@ +#ifndef _RRUNNER_H_ +#define _RRUNNER_H_ + +#include + +#if ((BITS_PER_LONG != 32) && (BITS_PER_LONG != 64)) +#error "BITS_PER_LONG not defined or not valid" +#endif + + +struct rr_regs { + + u32 pad0[16]; + + u32 HostCtrl; + u32 LocalCtrl; + u32 Pc; + u32 BrkPt; + +/* Timer increments every 0.97 micro-seconds (unsigned int) */ + u32 Timer_Hi; + u32 Timer; + u32 TimerRef; + u32 PciState; + + u32 Event; + u32 MbEvent; + + u32 WinBase; + u32 WinData; + u32 RX_state; + u32 TX_state; + + u32 Overhead; + u32 ExtIo; + + u32 DmaWriteHostHi; + u32 DmaWriteHostLo; + + u32 pad1[2]; + + u32 DmaReadHostHi; + u32 DmaReadHostLo; + + u32 pad2; + + u32 DmaReadLen; + u32 DmaWriteState; + + u32 DmaWriteLcl; + u32 DmaWriteIPchecksum; + u32 DmaWriteLen; + u32 DmaReadState; + u32 DmaReadLcl; + u32 DmaReadIPchecksum; + u32 pad3; + + u32 RxBase; + u32 RxPrd; + u32 RxCon; + + u32 pad4; + + u32 TxBase; + u32 TxPrd; + u32 TxCon; + + u32 pad5; + + u32 RxIndPro; + u32 RxIndCon; + u32 RxIndRef; + + u32 pad6; + + u32 TxIndPro; + u32 TxIndCon; + u32 TxIndRef; + + u32 pad7[17]; + + u32 DrCmndPro; + u32 DrCmndCon; + u32 DrCmndRef; + + u32 pad8; + + u32 DwCmndPro; + u32 DwCmndCon; + u32 DwCmndRef; + + u32 AssistState; + + u32 DrDataPro; + u32 DrDataCon; + u32 DrDataRef; + + u32 pad9; + + u32 DwDataPro; + u32 DwDataCon; + u32 DwDataRef; + + u32 pad10[33]; + + u32 EvtCon; + + u32 pad11[5]; + + u32 TxPi; + u32 IpRxPi; + + u32 pad11a[8]; + + u32 CmdRing[16]; + +/* The ULA is in two registers the high order two bytes of the first + * word contain the RunCode features. + * ula0 res res byte0 byte1 + * ula1 byte2 byte3 byte4 byte5 + */ + u32 Ula0; + u32 Ula1; + + u32 RxRingHi; + u32 RxRingLo; + + u32 InfoPtrHi; + u32 InfoPtrLo; + + u32 Mode; + + u32 ConRetry; + u32 ConRetryTmr; + + u32 ConTmout; + u32 CtatTmr; + + u32 MaxRxRng; + + u32 IntrTmr; + u32 TxDataMvTimeout; + u32 RxDataMvTimeout; + + u32 EvtPrd; + u32 TraceIdx; + + u32 Fail1; + u32 Fail2; + + u32 DrvPrm; + + u32 FilterLA; + + u32 FwRev; + u32 FwRes1; + u32 FwRes2; + u32 FwRes3; + + u32 WriteDmaThresh; + u32 ReadDmaThresh; + + u32 pad12[325]; + u32 Window[512]; +}; + +/* + * Host control register bits. + */ + +#define RR_INT 0x01 +#define RR_CLEAR_INT 0x02 +#define NO_SWAP 0x04000004 +#define NO_SWAP1 0x00000004 +#define PCI_RESET_NIC 0x08 +#define HALT_NIC 0x10 +#define SSTEP_NIC 0x20 +#define MEM_READ_MULTI 0x40 +#define NIC_HALTED 0x100 +#define HALT_INST 0x200 +#define PARITY_ERR 0x400 +#define INVALID_INST_B 0x800 +#define RR_REV_2 0x20000000 +#define RR_REV_MASK 0xf0000000 + +/* + * Local control register bits. + */ + +#define INTA_STATE 0x01 +#define CLEAR_INTA 0x02 +#define FAST_EEPROM_ACCESS 0x08 +#define ENABLE_EXTRA_SRAM 0x100 +#define ENABLE_EXTRA_DESC 0x200 +#define ENABLE_PARITY 0x400 +#define FORCE_DMA_PARITY_ERROR 0x800 +#define ENABLE_EEPROM_WRITE 0x1000 +#define ENABLE_DATA_CACHE 0x2000 +#define SRAM_LO_PARITY_ERR 0x4000 +#define SRAM_HI_PARITY_ERR 0x8000 + +/* + * PCI state bits. + */ + +#define FORCE_PCI_RESET 0x01 +#define PROVIDE_LENGTH 0x02 +#define MASK_DMA_READ_MAX 0x1C +#define RBURST_DISABLE 0x00 +#define RBURST_4 0x04 +#define RBURST_16 0x08 +#define RBURST_32 0x0C +#define RBURST_64 0x10 +#define RBURST_128 0x14 +#define RBURST_256 0x18 +#define RBURST_1024 0x1C +#define MASK_DMA_WRITE_MAX 0xE0 +#define WBURST_DISABLE 0x00 +#define WBURST_4 0x20 +#define WBURST_16 0x40 +#define WBURST_32 0x60 +#define WBURST_64 0x80 +#define WBURST_128 0xa0 +#define WBURST_256 0xc0 +#define WBURST_1024 0xe0 +#define MASK_MIN_DMA 0xFF00 +#define FIFO_RETRY_ENABLE 0x10000 + +/* + * Event register + */ + +#define DMA_WRITE_DONE 0x10000 +#define DMA_READ_DONE 0x20000 +#define DMA_WRITE_ERR 0x40000 +#define DMA_READ_ERR 0x80000 + +/* + * Receive state + * + * RoadRunner HIPPI Receive State Register controls and monitors the + * HIPPI receive interface in the NIC. Look at err bits when a HIPPI + * receive Error Event occurs. + */ + +#define ENABLE_NEW_CON 0x01 +#define RESET_RECV 0x02 +#define RECV_ALL 0x00 +#define RECV_1K 0x20 +#define RECV_2K 0x40 +#define RECV_4K 0x60 +#define RECV_8K 0x80 +#define RECV_16K 0xa0 +#define RECV_32K 0xc0 +#define RECV_64K 0xe0 + +/* + * Transmit status. + */ + +#define ENA_XMIT 0x01 +#define PERM_CON 0x02 + +/* + * DMA write state + */ + +#define RESET_DMA 0x01 +#define NO_SWAP_DMA 0x02 +#define DMA_ACTIVE 0x04 +#define THRESH_MASK 0x1F +#define DMA_ERROR_MASK 0xff000000 + +/* + * Gooddies stored in the ULA registers. + */ + +#define TRACE_ON_WHAT_BIT 0x00020000 /* Traces on */ +#define ONEM_BUF_WHAT_BIT 0x00040000 /* 1Meg vs 256K */ +#define CHAR_API_WHAT_BIT 0x00080000 /* Char API vs network only */ +#define CMD_EVT_WHAT_BIT 0x00200000 /* Command event */ +#define LONG_TX_WHAT_BIT 0x00400000 +#define LONG_RX_WHAT_BIT 0x00800000 +#define WHAT_BIT_MASK 0xFFFD0000 /* Feature bit mask */ + +/* + * Mode status + */ + +#define EVENT_OVFL 0x80000000 +#define FATAL_ERR 0x40000000 +#define LOOP_BACK 0x01 +#define MODE_PH 0x02 +#define MODE_FP 0x00 +#define PTR64BIT 0x04 +#define PTR32BIT 0x00 +#define PTR_WD_SWAP 0x08 +#define PTR_WD_NOSWAP 0x00 +#define POST_WARN_EVENT 0x10 +#define ERR_TERM 0x20 +#define DIRECT_CONN 0x40 +#define NO_NIC_WATCHDOG 0x80 +#define SWAP_DATA 0x100 +#define SWAP_CONTROL 0x200 +#define NIC_HALT_ON_ERR 0x400 +#define NIC_NO_RESTART 0x800 +#define HALF_DUP_TX 0x1000 +#define HALF_DUP_RX 0x2000 + + +/* + * Error codes + */ + +/* Host Error Codes - values of fail1 */ +#define ERR_UNKNOWN_MBOX 0x1001 +#define ERR_UNKNOWN_CMD 0x1002 +#define ERR_MAX_RING 0x1003 +#define ERR_RING_CLOSED 0x1004 +#define ERR_RING_OPEN 0x1005 +/* Firmware internal errors */ +#define ERR_EVENT_RING_FULL 0x01 +#define ERR_DW_PEND_CMND_FULL 0x02 +#define ERR_DR_PEND_CMND_FULL 0x03 +#define ERR_DW_PEND_DATA_FULL 0x04 +#define ERR_DR_PEND_DATA_FULL 0x05 +#define ERR_ILLEGAL_JUMP 0x06 +#define ERR_UNIMPLEMENTED 0x07 +#define ERR_TX_INFO_FULL 0x08 +#define ERR_RX_INFO_FULL 0x09 +#define ERR_ILLEGAL_MODE 0x0A +#define ERR_MAIN_TIMEOUT 0x0B +#define ERR_EVENT_BITS 0x0C +#define ERR_UNPEND_FULL 0x0D +#define ERR_TIMER_QUEUE_FULL 0x0E +#define ERR_TIMER_QUEUE_EMPTY 0x0F +#define ERR_TIMER_NO_FREE 0x10 +#define ERR_INTR_START 0x11 +#define ERR_BAD_STARTUP 0x12 +#define ERR_NO_PKT_END 0x13 +#define ERR_HALTED_ON_ERR 0x14 +/* Hardware NIC Errors */ +#define ERR_WRITE_DMA 0x0101 +#define ERR_READ_DMA 0x0102 +#define ERR_EXT_SERIAL 0x0103 +#define ERR_TX_INT_PARITY 0x0104 + + +/* + * Event definitions + */ + +#define EVT_RING_ENTRIES 64 +#define EVT_RING_SIZE (EVT_RING_ENTRIES * sizeof(struct event)) + +struct event { +#ifdef __LITTLE_ENDIAN + u16 index; + u8 ring; + u8 code; +#else + u8 code; + u8 ring; + u16 index; +#endif + u32 timestamp; +}; + +/* + * General Events + */ + +#define E_NIC_UP 0x01 +#define E_WATCHDOG 0x02 + +#define E_STAT_UPD 0x04 +#define E_INVAL_CMD 0x05 +#define E_SET_CMD_CONS 0x06 +#define E_LINK_ON 0x07 +#define E_LINK_OFF 0x08 +#define E_INTERN_ERR 0x09 +#define E_HOST_ERR 0x0A +#define E_STATS_UPDATE 0x0B +#define E_REJECTING 0x0C + +/* + * Send Events + */ +#define E_CON_REJ 0x13 +#define E_CON_TMOUT 0x14 +#define E_CON_NC_TMOUT 0x15 /* I , Connection No Campon Timeout */ +#define E_DISC_ERR 0x16 +#define E_INT_PRTY 0x17 +#define E_TX_IDLE 0x18 +#define E_TX_LINK_DROP 0x19 +#define E_TX_INV_RNG 0x1A +#define E_TX_INV_BUF 0x1B +#define E_TX_INV_DSC 0x1C + +/* + * Destination Events + */ +/* + * General Receive events + */ +#define E_VAL_RNG 0x20 +#define E_RX_RNG_ENER 0x21 +#define E_INV_RNG 0x22 +#define E_RX_RNG_SPC 0x23 +#define E_RX_RNG_OUT 0x24 +#define E_PKT_DISCARD 0x25 +#define E_INFO_EVT 0x27 + +/* + * Data corrupted events + */ +#define E_RX_PAR_ERR 0x2B +#define E_RX_LLRC_ERR 0x2C +#define E_IP_CKSM_ERR 0x2D +#define E_DTA_CKSM_ERR 0x2E +#define E_SHT_BST 0x2F + +/* + * Data lost events + */ +#define E_LST_LNK_ERR 0x30 +#define E_FLG_SYN_ERR 0x31 +#define E_FRM_ERR 0x32 +#define E_RX_IDLE 0x33 +#define E_PKT_LN_ERR 0x34 +#define E_STATE_ERR 0x35 +#define E_UNEXP_DATA 0x3C + +/* + * Fatal events + */ +#define E_RX_INV_BUF 0x36 +#define E_RX_INV_DSC 0x37 +#define E_RNG_BLK 0x38 + +/* + * Warning events + */ +#define E_RX_TO 0x39 +#define E_BFR_SPC 0x3A +#define E_INV_ULP 0x3B + +#define E_NOT_IMPLEMENTED 0x40 + + +/* + * Commands + */ + +#define CMD_RING_ENTRIES 16 + +struct cmd { +#ifdef __LITTLE_ENDIAN + u16 index; + u8 ring; + u8 code; +#else + u8 code; + u8 ring; + u16 index; +#endif +}; + +#define C_START_FW 0x01 +#define C_UPD_STAT 0x02 +#define C_WATCHDOG 0x05 +#define C_DEL_RNG 0x09 +#define C_NEW_RNG 0x0A +#define C_CONN 0x0D + + +/* + * Mode bits + */ + +#define PACKET_BAD 0x01 /* Packet had link-layer error */ +#define INTERRUPT 0x02 +#define TX_IP_CKSUM 0x04 +#define PACKET_END 0x08 +#define PACKET_START 0x10 +#define SAME_IFIELD 0x80 + + +typedef struct { +#if (BITS_PER_LONG == 64) + u64 addrlo; +#else + u32 addrhi; + u32 addrlo; +#endif +} rraddr; + + +static inline void set_rraddr(rraddr *ra, dma_addr_t addr) +{ + unsigned long baddr = addr; +#if (BITS_PER_LONG == 64) + ra->addrlo = baddr; +#else + /* Don't bother setting zero every time */ + ra->addrlo = baddr; +#endif + mb(); +} + + +static inline void set_rxaddr(struct rr_regs __iomem *regs, volatile dma_addr_t addr) +{ + unsigned long baddr = addr; +#if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN) + writel(baddr & 0xffffffff, ®s->RxRingHi); + writel(baddr >> 32, ®s->RxRingLo); +#elif (BITS_PER_LONG == 64) + writel(baddr >> 32, ®s->RxRingHi); + writel(baddr & 0xffffffff, ®s->RxRingLo); +#else + writel(0, ®s->RxRingHi); + writel(baddr, ®s->RxRingLo); +#endif + mb(); +} + + +static inline void set_infoaddr(struct rr_regs __iomem *regs, volatile dma_addr_t addr) +{ + unsigned long baddr = addr; +#if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN) + writel(baddr & 0xffffffff, ®s->InfoPtrHi); + writel(baddr >> 32, ®s->InfoPtrLo); +#elif (BITS_PER_LONG == 64) + writel(baddr >> 32, ®s->InfoPtrHi); + writel(baddr & 0xffffffff, ®s->InfoPtrLo); +#else + writel(0, ®s->InfoPtrHi); + writel(baddr, ®s->InfoPtrLo); +#endif + mb(); +} + + +/* + * TX ring + */ + +#ifdef CONFIG_ROADRUNNER_LARGE_RINGS +#define TX_RING_ENTRIES 32 +#else +#define TX_RING_ENTRIES 16 +#endif +#define TX_TOTAL_SIZE (TX_RING_ENTRIES * sizeof(struct tx_desc)) + +struct tx_desc{ + rraddr addr; + u32 res; +#ifdef __LITTLE_ENDIAN + u16 size; + u8 pad; + u8 mode; +#else + u8 mode; + u8 pad; + u16 size; +#endif +}; + + +#ifdef CONFIG_ROADRUNNER_LARGE_RINGS +#define RX_RING_ENTRIES 32 +#else +#define RX_RING_ENTRIES 16 +#endif +#define RX_TOTAL_SIZE (RX_RING_ENTRIES * sizeof(struct rx_desc)) + +struct rx_desc{ + rraddr addr; + u32 res; +#ifdef __LITTLE_ENDIAN + u16 size; + u8 pad; + u8 mode; +#else + u8 mode; + u8 pad; + u16 size; +#endif +}; + + +/* + * ioctl's + */ + +#define SIOCRRPFW SIOCDEVPRIVATE /* put firmware */ +#define SIOCRRGFW SIOCDEVPRIVATE+1 /* get firmware */ +#define SIOCRRID SIOCDEVPRIVATE+2 /* identify */ + + +struct seg_hdr { + u32 seg_start; + u32 seg_len; + u32 seg_eestart; +}; + + +#define EEPROM_BASE 0x80000000 +#define EEPROM_WORDS 8192 +#define EEPROM_BYTES (EEPROM_WORDS * sizeof(u32)) + +struct eeprom_boot { + u32 key1; + u32 key2; + u32 sram_size; + struct seg_hdr loader; + u32 init_chksum; + u32 reserved1; +}; + +struct eeprom_manf { + u32 HeaderFmt; + u32 Firmware; + u32 BoardRevision; + u32 RoadrunnerRev; + char OpticsPart[8]; + u32 OpticsRev; + u32 pad1; + char SramPart[8]; + u32 SramRev; + u32 pad2; + char EepromPart[8]; + u32 EepromRev; + u32 EepromSize; + char PalPart[8]; + u32 PalRev; + u32 pad3; + char PalCodeFile[12]; + u32 PalCodeRev; + char BoardULA[8]; + char SerialNo[8]; + char MfgDate[8]; + char MfgTime[8]; + char ModifyDate[8]; + u32 ModCount; + u32 pad4[13]; +}; + + +struct eeprom_phase_info { + char phase1File[12]; + u32 phase1Rev; + char phase1Date[8]; + char phase2File[12]; + u32 phase2Rev; + char phase2Date[8]; + u32 reserved7[4]; +}; + +struct eeprom_rncd_info { + u32 FwStart; + u32 FwRev; + char FwDate[8]; + u32 AddrRunCodeSegs; + u32 FileNames; + char File[13][8]; +}; + + +/* Phase 1 region (starts are word offset 0x80) */ +struct phase1_hdr{ + u32 jump; + u32 noop; + struct seg_hdr phase2Seg; +}; + +struct eeprom { + struct eeprom_boot boot; + u32 pad1[8]; + struct eeprom_manf manf; + struct eeprom_phase_info phase_info; + struct eeprom_rncd_info rncd_info; + u32 pad2[15]; + u32 hdr_checksum; + struct phase1_hdr phase1; +}; + + +struct rr_stats { + u32 NicTimeStamp; + u32 RngCreated; + u32 RngDeleted; + u32 IntrGen; + u32 NEvtOvfl; + u32 InvCmd; + u32 DmaReadErrs; + u32 DmaWriteErrs; + u32 StatUpdtT; + u32 StatUpdtC; + u32 WatchDog; + u32 Trace; + + /* Serial HIPPI */ + u32 LnkRdyEst; + u32 GLinkErr; + u32 AltFlgErr; + u32 OvhdBit8Sync; + u32 RmtSerPrtyErr; + u32 RmtParPrtyErr; + u32 RmtLoopBk; + u32 pad1; + + /* HIPPI tx */ + u32 ConEst; + u32 ConRejS; + u32 ConRetry; + u32 ConTmOut; + u32 SndConDiscon; + u32 SndParErr; + u32 PktSnt; + u32 pad2[2]; + u32 ShFBstSnt; + u64 BytSent; + u32 TxTimeout; + u32 pad3[3]; + + /* HIPPI rx */ + u32 ConAcc; + u32 ConRejdiPrty; + u32 ConRejd64b; + u32 ConRejdBuf; + u32 RxConDiscon; + u32 RxConNoData; + u32 PktRx; + u32 pad4[2]; + u32 ShFBstRx; + u64 BytRx; + u32 RxParErr; + u32 RxLLRCerr; + u32 RxBstSZerr; + u32 RxStateErr; + u32 RxRdyErr; + u32 RxInvULP; + u32 RxSpcBuf; + u32 RxSpcDesc; + u32 RxRngSpc; + u32 RxRngFull; + u32 RxPktLenErr; + u32 RxCksmErr; + u32 RxPktDrp; + u32 RngLowSpc; + u32 RngDataClose; + u32 RxTimeout; + u32 RxIdle; +}; + + +/* + * This struct is shared with the NIC firmware. + */ +struct ring_ctrl { + rraddr rngptr; +#ifdef __LITTLE_ENDIAN + u16 entries; + u8 pad; + u8 entry_size; + u16 pi; + u16 mode; +#else + u8 entry_size; + u8 pad; + u16 entries; + u16 mode; + u16 pi; +#endif +}; + +struct rr_info { + union { + struct rr_stats stats; + u32 stati[128]; + } s; + struct ring_ctrl evt_ctrl; + struct ring_ctrl cmd_ctrl; + struct ring_ctrl tx_ctrl; + u8 pad[464]; + u8 trace[3072]; +}; + +/* + * The linux structure for the RoadRunner. + * + * RX/TX descriptors are put first to make sure they are properly + * aligned and do not cross cache-line boundaries. + */ + +struct rr_private +{ + struct rx_desc *rx_ring; + struct tx_desc *tx_ring; + struct event *evt_ring; + dma_addr_t tx_ring_dma; + dma_addr_t rx_ring_dma; + dma_addr_t evt_ring_dma; + /* Alignment ok ? */ + struct sk_buff *rx_skbuff[RX_RING_ENTRIES]; + struct sk_buff *tx_skbuff[TX_RING_ENTRIES]; + struct rr_regs __iomem *regs; /* Register base */ + struct ring_ctrl *rx_ctrl; /* Receive ring control */ + struct rr_info *info; /* Shared info page */ + dma_addr_t rx_ctrl_dma; + dma_addr_t info_dma; + spinlock_t lock; + struct timer_list timer; + u32 cur_rx, cur_cmd, cur_evt; + u32 dirty_rx, dirty_tx; + u32 tx_full; + u32 fw_rev; + volatile short fw_running; + struct pci_dev *pci_dev; +}; + + +/* + * Prototypes + */ +static int rr_init(struct net_device *dev); +static int rr_init1(struct net_device *dev); +static irqreturn_t rr_interrupt(int irq, void *dev_id); + +static int rr_open(struct net_device *dev); +static netdev_tx_t rr_start_xmit(struct sk_buff *skb, + struct net_device *dev); +static int rr_close(struct net_device *dev); +static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static unsigned int rr_read_eeprom(struct rr_private *rrpriv, + unsigned long offset, + unsigned char *buf, + unsigned long length); +static u32 rr_read_eeprom_word(struct rr_private *rrpriv, size_t offset); +static int rr_load_firmware(struct net_device *dev); +static inline void rr_raz_tx(struct rr_private *, struct net_device *); +static inline void rr_raz_rx(struct rr_private *, struct net_device *); +#endif /* _RRUNNER_H_ */ diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c deleted file mode 100644 index e68c941..0000000 --- a/drivers/net/rrunner.c +++ /dev/null @@ -1,1716 +0,0 @@ -/* - * rrunner.c: Linux driver for the Essential RoadRunner HIPPI board. - * - * Copyright (C) 1998-2002 by Jes Sorensen, . - * - * Thanks to Essential Communication for providing us with hardware - * and very comprehensive documentation without which I would not have - * been able to write this driver. A special thank you to John Gibbon - * for sorting out the legal issues, with the NDA, allowing the code to - * be released under the GPL. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Thanks to Jayaram Bhat from ODS/Essential for fixing some of the - * stupid bugs in my code. - * - * Softnet support and various other patches from Val Henson of - * ODS/Essential. - * - * PCI DMA mapping code partly based on work by Francois Romieu. - */ - - -#define DEBUG 1 -#define RX_DMA_SKBUFF 1 -#define PKT_COPY_THRESHOLD 512 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define rr_if_busy(dev) netif_queue_stopped(dev) -#define rr_if_running(dev) netif_running(dev) - -#include "rrunner.h" - -#define RUN_AT(x) (jiffies + (x)) - - -MODULE_AUTHOR("Jes Sorensen "); -MODULE_DESCRIPTION("Essential RoadRunner HIPPI driver"); -MODULE_LICENSE("GPL"); - -static char version[] __devinitdata = "rrunner.c: v0.50 11/11/2002 Jes Sorensen (jes@wildopensource.com)\n"; - - -static const struct net_device_ops rr_netdev_ops = { - .ndo_open = rr_open, - .ndo_stop = rr_close, - .ndo_do_ioctl = rr_ioctl, - .ndo_start_xmit = rr_start_xmit, - .ndo_change_mtu = hippi_change_mtu, - .ndo_set_mac_address = hippi_mac_addr, -}; - -/* - * Implementation notes: - * - * The DMA engine only allows for DMA within physical 64KB chunks of - * memory. The current approach of the driver (and stack) is to use - * linear blocks of memory for the skbuffs. However, as the data block - * is always the first part of the skb and skbs are 2^n aligned so we - * are guarantted to get the whole block within one 64KB align 64KB - * chunk. - * - * On the long term, relying on being able to allocate 64KB linear - * chunks of memory is not feasible and the skb handling code and the - * stack will need to know about I/O vectors or something similar. - */ - -static int __devinit rr_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct net_device *dev; - static int version_disp; - u8 pci_latency; - struct rr_private *rrpriv; - void *tmpptr; - dma_addr_t ring_dma; - int ret = -ENOMEM; - - dev = alloc_hippi_dev(sizeof(struct rr_private)); - if (!dev) - goto out3; - - ret = pci_enable_device(pdev); - if (ret) { - ret = -ENODEV; - goto out2; - } - - rrpriv = netdev_priv(dev); - - SET_NETDEV_DEV(dev, &pdev->dev); - - if (pci_request_regions(pdev, "rrunner")) { - ret = -EIO; - goto out; - } - - pci_set_drvdata(pdev, dev); - - rrpriv->pci_dev = pdev; - - spin_lock_init(&rrpriv->lock); - - dev->irq = pdev->irq; - dev->netdev_ops = &rr_netdev_ops; - - dev->base_addr = pci_resource_start(pdev, 0); - - /* display version info if adapter is found */ - if (!version_disp) { - /* set display flag to TRUE so that */ - /* we only display this string ONCE */ - version_disp = 1; - printk(version); - } - - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency <= 0x58){ - pci_latency = 0x58; - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, pci_latency); - } - - pci_set_master(pdev); - - printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI " - "at 0x%08lx, irq %i, PCI latency %i\n", dev->name, - dev->base_addr, dev->irq, pci_latency); - - /* - * Remap the regs into kernel space. - */ - - rrpriv->regs = ioremap(dev->base_addr, 0x1000); - - if (!rrpriv->regs){ - printk(KERN_ERR "%s: Unable to map I/O register, " - "RoadRunner will be disabled.\n", dev->name); - ret = -EIO; - goto out; - } - - tmpptr = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma); - rrpriv->tx_ring = tmpptr; - rrpriv->tx_ring_dma = ring_dma; - - if (!tmpptr) { - ret = -ENOMEM; - goto out; - } - - tmpptr = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma); - rrpriv->rx_ring = tmpptr; - rrpriv->rx_ring_dma = ring_dma; - - if (!tmpptr) { - ret = -ENOMEM; - goto out; - } - - tmpptr = pci_alloc_consistent(pdev, EVT_RING_SIZE, &ring_dma); - rrpriv->evt_ring = tmpptr; - rrpriv->evt_ring_dma = ring_dma; - - if (!tmpptr) { - ret = -ENOMEM; - goto out; - } - - /* - * Don't access any register before this point! - */ -#ifdef __BIG_ENDIAN - writel(readl(&rrpriv->regs->HostCtrl) | NO_SWAP, - &rrpriv->regs->HostCtrl); -#endif - /* - * Need to add a case for little-endian 64-bit hosts here. - */ - - rr_init(dev); - - dev->base_addr = 0; - - ret = register_netdev(dev); - if (ret) - goto out; - return 0; - - out: - if (rrpriv->rx_ring) - pci_free_consistent(pdev, RX_TOTAL_SIZE, rrpriv->rx_ring, - rrpriv->rx_ring_dma); - if (rrpriv->tx_ring) - pci_free_consistent(pdev, TX_TOTAL_SIZE, rrpriv->tx_ring, - rrpriv->tx_ring_dma); - if (rrpriv->regs) - iounmap(rrpriv->regs); - if (pdev) { - pci_release_regions(pdev); - pci_set_drvdata(pdev, NULL); - } - out2: - free_netdev(dev); - out3: - return ret; -} - -static void __devexit rr_remove_one (struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - - if (dev) { - struct rr_private *rr = netdev_priv(dev); - - if (!(readl(&rr->regs->HostCtrl) & NIC_HALTED)){ - printk(KERN_ERR "%s: trying to unload running NIC\n", - dev->name); - writel(HALT_NIC, &rr->regs->HostCtrl); - } - - pci_free_consistent(pdev, EVT_RING_SIZE, rr->evt_ring, - rr->evt_ring_dma); - pci_free_consistent(pdev, RX_TOTAL_SIZE, rr->rx_ring, - rr->rx_ring_dma); - pci_free_consistent(pdev, TX_TOTAL_SIZE, rr->tx_ring, - rr->tx_ring_dma); - unregister_netdev(dev); - iounmap(rr->regs); - free_netdev(dev); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - } -} - - -/* - * Commands are considered to be slow, thus there is no reason to - * inline this. - */ -static void rr_issue_cmd(struct rr_private *rrpriv, struct cmd *cmd) -{ - struct rr_regs __iomem *regs; - u32 idx; - - regs = rrpriv->regs; - /* - * This is temporary - it will go away in the final version. - * We probably also want to make this function inline. - */ - if (readl(®s->HostCtrl) & NIC_HALTED){ - printk("issuing command for halted NIC, code 0x%x, " - "HostCtrl %08x\n", cmd->code, readl(®s->HostCtrl)); - if (readl(®s->Mode) & FATAL_ERR) - printk("error codes Fail1 %02x, Fail2 %02x\n", - readl(®s->Fail1), readl(®s->Fail2)); - } - - idx = rrpriv->info->cmd_ctrl.pi; - - writel(*(u32*)(cmd), ®s->CmdRing[idx]); - wmb(); - - idx = (idx - 1) % CMD_RING_ENTRIES; - rrpriv->info->cmd_ctrl.pi = idx; - wmb(); - - if (readl(®s->Mode) & FATAL_ERR) - printk("error code %02x\n", readl(®s->Fail1)); -} - - -/* - * Reset the board in a sensible manner. The NIC is already halted - * when we get here and a spin-lock is held. - */ -static int rr_reset(struct net_device *dev) -{ - struct rr_private *rrpriv; - struct rr_regs __iomem *regs; - u32 start_pc; - int i; - - rrpriv = netdev_priv(dev); - regs = rrpriv->regs; - - rr_load_firmware(dev); - - writel(0x01000000, ®s->TX_state); - writel(0xff800000, ®s->RX_state); - writel(0, ®s->AssistState); - writel(CLEAR_INTA, ®s->LocalCtrl); - writel(0x01, ®s->BrkPt); - writel(0, ®s->Timer); - writel(0, ®s->TimerRef); - writel(RESET_DMA, ®s->DmaReadState); - writel(RESET_DMA, ®s->DmaWriteState); - writel(0, ®s->DmaWriteHostHi); - writel(0, ®s->DmaWriteHostLo); - writel(0, ®s->DmaReadHostHi); - writel(0, ®s->DmaReadHostLo); - writel(0, ®s->DmaReadLen); - writel(0, ®s->DmaWriteLen); - writel(0, ®s->DmaWriteLcl); - writel(0, ®s->DmaWriteIPchecksum); - writel(0, ®s->DmaReadLcl); - writel(0, ®s->DmaReadIPchecksum); - writel(0, ®s->PciState); -#if (BITS_PER_LONG == 64) && defined __LITTLE_ENDIAN - writel(SWAP_DATA | PTR64BIT | PTR_WD_SWAP, ®s->Mode); -#elif (BITS_PER_LONG == 64) - writel(SWAP_DATA | PTR64BIT | PTR_WD_NOSWAP, ®s->Mode); -#else - writel(SWAP_DATA | PTR32BIT | PTR_WD_NOSWAP, ®s->Mode); -#endif - -#if 0 - /* - * Don't worry, this is just black magic. - */ - writel(0xdf000, ®s->RxBase); - writel(0xdf000, ®s->RxPrd); - writel(0xdf000, ®s->RxCon); - writel(0xce000, ®s->TxBase); - writel(0xce000, ®s->TxPrd); - writel(0xce000, ®s->TxCon); - writel(0, ®s->RxIndPro); - writel(0, ®s->RxIndCon); - writel(0, ®s->RxIndRef); - writel(0, ®s->TxIndPro); - writel(0, ®s->TxIndCon); - writel(0, ®s->TxIndRef); - writel(0xcc000, ®s->pad10[0]); - writel(0, ®s->DrCmndPro); - writel(0, ®s->DrCmndCon); - writel(0, ®s->DwCmndPro); - writel(0, ®s->DwCmndCon); - writel(0, ®s->DwCmndRef); - writel(0, ®s->DrDataPro); - writel(0, ®s->DrDataCon); - writel(0, ®s->DrDataRef); - writel(0, ®s->DwDataPro); - writel(0, ®s->DwDataCon); - writel(0, ®s->DwDataRef); -#endif - - writel(0xffffffff, ®s->MbEvent); - writel(0, ®s->Event); - - writel(0, ®s->TxPi); - writel(0, ®s->IpRxPi); - - writel(0, ®s->EvtCon); - writel(0, ®s->EvtPrd); - - rrpriv->info->evt_ctrl.pi = 0; - - for (i = 0; i < CMD_RING_ENTRIES; i++) - writel(0, ®s->CmdRing[i]); - -/* - * Why 32 ? is this not cache line size dependent? - */ - writel(RBURST_64|WBURST_64, ®s->PciState); - wmb(); - - start_pc = rr_read_eeprom_word(rrpriv, - offsetof(struct eeprom, rncd_info.FwStart)); - -#if (DEBUG > 1) - printk("%s: Executing firmware at address 0x%06x\n", - dev->name, start_pc); -#endif - - writel(start_pc + 0x800, ®s->Pc); - wmb(); - udelay(5); - - writel(start_pc, ®s->Pc); - wmb(); - - return 0; -} - - -/* - * Read a string from the EEPROM. - */ -static unsigned int rr_read_eeprom(struct rr_private *rrpriv, - unsigned long offset, - unsigned char *buf, - unsigned long length) -{ - struct rr_regs __iomem *regs = rrpriv->regs; - u32 misc, io, host, i; - - io = readl(®s->ExtIo); - writel(0, ®s->ExtIo); - misc = readl(®s->LocalCtrl); - writel(0, ®s->LocalCtrl); - host = readl(®s->HostCtrl); - writel(host | HALT_NIC, ®s->HostCtrl); - mb(); - - for (i = 0; i < length; i++){ - writel((EEPROM_BASE + ((offset+i) << 3)), ®s->WinBase); - mb(); - buf[i] = (readl(®s->WinData) >> 24) & 0xff; - mb(); - } - - writel(host, ®s->HostCtrl); - writel(misc, ®s->LocalCtrl); - writel(io, ®s->ExtIo); - mb(); - return i; -} - - -/* - * Shortcut to read one word (4 bytes) out of the EEPROM and convert - * it to our CPU byte-order. - */ -static u32 rr_read_eeprom_word(struct rr_private *rrpriv, - size_t offset) -{ - __be32 word; - - if ((rr_read_eeprom(rrpriv, offset, - (unsigned char *)&word, 4) == 4)) - return be32_to_cpu(word); - return 0; -} - - -/* - * Write a string to the EEPROM. - * - * This is only called when the firmware is not running. - */ -static unsigned int write_eeprom(struct rr_private *rrpriv, - unsigned long offset, - unsigned char *buf, - unsigned long length) -{ - struct rr_regs __iomem *regs = rrpriv->regs; - u32 misc, io, data, i, j, ready, error = 0; - - io = readl(®s->ExtIo); - writel(0, ®s->ExtIo); - misc = readl(®s->LocalCtrl); - writel(ENABLE_EEPROM_WRITE, ®s->LocalCtrl); - mb(); - - for (i = 0; i < length; i++){ - writel((EEPROM_BASE + ((offset+i) << 3)), ®s->WinBase); - mb(); - data = buf[i] << 24; - /* - * Only try to write the data if it is not the same - * value already. - */ - if ((readl(®s->WinData) & 0xff000000) != data){ - writel(data, ®s->WinData); - ready = 0; - j = 0; - mb(); - while(!ready){ - udelay(20); - if ((readl(®s->WinData) & 0xff000000) == - data) - ready = 1; - mb(); - if (j++ > 5000){ - printk("data mismatch: %08x, " - "WinData %08x\n", data, - readl(®s->WinData)); - ready = 1; - error = 1; - } - } - } - } - - writel(misc, ®s->LocalCtrl); - writel(io, ®s->ExtIo); - mb(); - - return error; -} - - -static int __devinit rr_init(struct net_device *dev) -{ - struct rr_private *rrpriv; - struct rr_regs __iomem *regs; - u32 sram_size, rev; - - rrpriv = netdev_priv(dev); - regs = rrpriv->regs; - - rev = readl(®s->FwRev); - rrpriv->fw_rev = rev; - if (rev > 0x00020024) - printk(" Firmware revision: %i.%i.%i\n", (rev >> 16), - ((rev >> 8) & 0xff), (rev & 0xff)); - else if (rev >= 0x00020000) { - printk(" Firmware revision: %i.%i.%i (2.0.37 or " - "later is recommended)\n", (rev >> 16), - ((rev >> 8) & 0xff), (rev & 0xff)); - }else{ - printk(" Firmware revision too old: %i.%i.%i, please " - "upgrade to 2.0.37 or later.\n", - (rev >> 16), ((rev >> 8) & 0xff), (rev & 0xff)); - } - -#if (DEBUG > 2) - printk(" Maximum receive rings %i\n", readl(®s->MaxRxRng)); -#endif - - /* - * Read the hardware address from the eeprom. The HW address - * is not really necessary for HIPPI but awfully convenient. - * The pointer arithmetic to put it in dev_addr is ugly, but - * Donald Becker does it this way for the GigE version of this - * card and it's shorter and more portable than any - * other method I've seen. -VAL - */ - - *(__be16 *)(dev->dev_addr) = - htons(rr_read_eeprom_word(rrpriv, offsetof(struct eeprom, manf.BoardULA))); - *(__be32 *)(dev->dev_addr+2) = - htonl(rr_read_eeprom_word(rrpriv, offsetof(struct eeprom, manf.BoardULA[4]))); - - printk(" MAC: %pM\n", dev->dev_addr); - - sram_size = rr_read_eeprom_word(rrpriv, 8); - printk(" SRAM size 0x%06x\n", sram_size); - - return 0; -} - - -static int rr_init1(struct net_device *dev) -{ - struct rr_private *rrpriv; - struct rr_regs __iomem *regs; - unsigned long myjif, flags; - struct cmd cmd; - u32 hostctrl; - int ecode = 0; - short i; - - rrpriv = netdev_priv(dev); - regs = rrpriv->regs; - - spin_lock_irqsave(&rrpriv->lock, flags); - - hostctrl = readl(®s->HostCtrl); - writel(hostctrl | HALT_NIC | RR_CLEAR_INT, ®s->HostCtrl); - wmb(); - - if (hostctrl & PARITY_ERR){ - printk("%s: Parity error halting NIC - this is serious!\n", - dev->name); - spin_unlock_irqrestore(&rrpriv->lock, flags); - ecode = -EFAULT; - goto error; - } - - set_rxaddr(regs, rrpriv->rx_ctrl_dma); - set_infoaddr(regs, rrpriv->info_dma); - - rrpriv->info->evt_ctrl.entry_size = sizeof(struct event); - rrpriv->info->evt_ctrl.entries = EVT_RING_ENTRIES; - rrpriv->info->evt_ctrl.mode = 0; - rrpriv->info->evt_ctrl.pi = 0; - set_rraddr(&rrpriv->info->evt_ctrl.rngptr, rrpriv->evt_ring_dma); - - rrpriv->info->cmd_ctrl.entry_size = sizeof(struct cmd); - rrpriv->info->cmd_ctrl.entries = CMD_RING_ENTRIES; - rrpriv->info->cmd_ctrl.mode = 0; - rrpriv->info->cmd_ctrl.pi = 15; - - for (i = 0; i < CMD_RING_ENTRIES; i++) { - writel(0, ®s->CmdRing[i]); - } - - for (i = 0; i < TX_RING_ENTRIES; i++) { - rrpriv->tx_ring[i].size = 0; - set_rraddr(&rrpriv->tx_ring[i].addr, 0); - rrpriv->tx_skbuff[i] = NULL; - } - rrpriv->info->tx_ctrl.entry_size = sizeof(struct tx_desc); - rrpriv->info->tx_ctrl.entries = TX_RING_ENTRIES; - rrpriv->info->tx_ctrl.mode = 0; - rrpriv->info->tx_ctrl.pi = 0; - set_rraddr(&rrpriv->info->tx_ctrl.rngptr, rrpriv->tx_ring_dma); - - /* - * Set dirty_tx before we start receiving interrupts, otherwise - * the interrupt handler might think it is supposed to process - * tx ints before we are up and running, which may cause a null - * pointer access in the int handler. - */ - rrpriv->tx_full = 0; - rrpriv->cur_rx = 0; - rrpriv->dirty_rx = rrpriv->dirty_tx = 0; - - rr_reset(dev); - - /* Tuning values */ - writel(0x5000, ®s->ConRetry); - writel(0x100, ®s->ConRetryTmr); - writel(0x500000, ®s->ConTmout); - writel(0x60, ®s->IntrTmr); - writel(0x500000, ®s->TxDataMvTimeout); - writel(0x200000, ®s->RxDataMvTimeout); - writel(0x80, ®s->WriteDmaThresh); - writel(0x80, ®s->ReadDmaThresh); - - rrpriv->fw_running = 0; - wmb(); - - hostctrl &= ~(HALT_NIC | INVALID_INST_B | PARITY_ERR); - writel(hostctrl, ®s->HostCtrl); - wmb(); - - spin_unlock_irqrestore(&rrpriv->lock, flags); - - for (i = 0; i < RX_RING_ENTRIES; i++) { - struct sk_buff *skb; - dma_addr_t addr; - - rrpriv->rx_ring[i].mode = 0; - skb = alloc_skb(dev->mtu + HIPPI_HLEN, GFP_ATOMIC); - if (!skb) { - printk(KERN_WARNING "%s: Unable to allocate memory " - "for receive ring - halting NIC\n", dev->name); - ecode = -ENOMEM; - goto error; - } - rrpriv->rx_skbuff[i] = skb; - addr = pci_map_single(rrpriv->pci_dev, skb->data, - dev->mtu + HIPPI_HLEN, PCI_DMA_FROMDEVICE); - /* - * Sanity test to see if we conflict with the DMA - * limitations of the Roadrunner. - */ - if ((((unsigned long)skb->data) & 0xfff) > ~65320) - printk("skb alloc error\n"); - - set_rraddr(&rrpriv->rx_ring[i].addr, addr); - rrpriv->rx_ring[i].size = dev->mtu + HIPPI_HLEN; - } - - rrpriv->rx_ctrl[4].entry_size = sizeof(struct rx_desc); - rrpriv->rx_ctrl[4].entries = RX_RING_ENTRIES; - rrpriv->rx_ctrl[4].mode = 8; - rrpriv->rx_ctrl[4].pi = 0; - wmb(); - set_rraddr(&rrpriv->rx_ctrl[4].rngptr, rrpriv->rx_ring_dma); - - udelay(1000); - - /* - * Now start the FirmWare. - */ - cmd.code = C_START_FW; - cmd.ring = 0; - cmd.index = 0; - - rr_issue_cmd(rrpriv, &cmd); - - /* - * Give the FirmWare time to chew on the `get running' command. - */ - myjif = jiffies + 5 * HZ; - while (time_before(jiffies, myjif) && !rrpriv->fw_running) - cpu_relax(); - - netif_start_queue(dev); - - return ecode; - - error: - /* - * We might have gotten here because we are out of memory, - * make sure we release everything we allocated before failing - */ - for (i = 0; i < RX_RING_ENTRIES; i++) { - struct sk_buff *skb = rrpriv->rx_skbuff[i]; - - if (skb) { - pci_unmap_single(rrpriv->pci_dev, - rrpriv->rx_ring[i].addr.addrlo, - dev->mtu + HIPPI_HLEN, - PCI_DMA_FROMDEVICE); - rrpriv->rx_ring[i].size = 0; - set_rraddr(&rrpriv->rx_ring[i].addr, 0); - dev_kfree_skb(skb); - rrpriv->rx_skbuff[i] = NULL; - } - } - return ecode; -} - - -/* - * All events are considered to be slow (RX/TX ints do not generate - * events) and are handled here, outside the main interrupt handler, - * to reduce the size of the handler. - */ -static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx) -{ - struct rr_private *rrpriv; - struct rr_regs __iomem *regs; - u32 tmp; - - rrpriv = netdev_priv(dev); - regs = rrpriv->regs; - - while (prodidx != eidx){ - switch (rrpriv->evt_ring[eidx].code){ - case E_NIC_UP: - tmp = readl(®s->FwRev); - printk(KERN_INFO "%s: Firmware revision %i.%i.%i " - "up and running\n", dev->name, - (tmp >> 16), ((tmp >> 8) & 0xff), (tmp & 0xff)); - rrpriv->fw_running = 1; - writel(RX_RING_ENTRIES - 1, ®s->IpRxPi); - wmb(); - break; - case E_LINK_ON: - printk(KERN_INFO "%s: Optical link ON\n", dev->name); - break; - case E_LINK_OFF: - printk(KERN_INFO "%s: Optical link OFF\n", dev->name); - break; - case E_RX_IDLE: - printk(KERN_WARNING "%s: RX data not moving\n", - dev->name); - goto drop; - case E_WATCHDOG: - printk(KERN_INFO "%s: The watchdog is here to see " - "us\n", dev->name); - break; - case E_INTERN_ERR: - printk(KERN_ERR "%s: HIPPI Internal NIC error\n", - dev->name); - writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, - ®s->HostCtrl); - wmb(); - break; - case E_HOST_ERR: - printk(KERN_ERR "%s: Host software error\n", - dev->name); - writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, - ®s->HostCtrl); - wmb(); - break; - /* - * TX events. - */ - case E_CON_REJ: - printk(KERN_WARNING "%s: Connection rejected\n", - dev->name); - dev->stats.tx_aborted_errors++; - break; - case E_CON_TMOUT: - printk(KERN_WARNING "%s: Connection timeout\n", - dev->name); - break; - case E_DISC_ERR: - printk(KERN_WARNING "%s: HIPPI disconnect error\n", - dev->name); - dev->stats.tx_aborted_errors++; - break; - case E_INT_PRTY: - printk(KERN_ERR "%s: HIPPI Internal Parity error\n", - dev->name); - writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, - ®s->HostCtrl); - wmb(); - break; - case E_TX_IDLE: - printk(KERN_WARNING "%s: Transmitter idle\n", - dev->name); - break; - case E_TX_LINK_DROP: - printk(KERN_WARNING "%s: Link lost during transmit\n", - dev->name); - dev->stats.tx_aborted_errors++; - writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, - ®s->HostCtrl); - wmb(); - break; - case E_TX_INV_RNG: - printk(KERN_ERR "%s: Invalid send ring block\n", - dev->name); - writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, - ®s->HostCtrl); - wmb(); - break; - case E_TX_INV_BUF: - printk(KERN_ERR "%s: Invalid send buffer address\n", - dev->name); - writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, - ®s->HostCtrl); - wmb(); - break; - case E_TX_INV_DSC: - printk(KERN_ERR "%s: Invalid descriptor address\n", - dev->name); - writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, - ®s->HostCtrl); - wmb(); - break; - /* - * RX events. - */ - case E_RX_RNG_OUT: - printk(KERN_INFO "%s: Receive ring full\n", dev->name); - break; - - case E_RX_PAR_ERR: - printk(KERN_WARNING "%s: Receive parity error\n", - dev->name); - goto drop; - case E_RX_LLRC_ERR: - printk(KERN_WARNING "%s: Receive LLRC error\n", - dev->name); - goto drop; - case E_PKT_LN_ERR: - printk(KERN_WARNING "%s: Receive packet length " - "error\n", dev->name); - goto drop; - case E_DTA_CKSM_ERR: - printk(KERN_WARNING "%s: Data checksum error\n", - dev->name); - goto drop; - case E_SHT_BST: - printk(KERN_WARNING "%s: Unexpected short burst " - "error\n", dev->name); - goto drop; - case E_STATE_ERR: - printk(KERN_WARNING "%s: Recv. state transition" - " error\n", dev->name); - goto drop; - case E_UNEXP_DATA: - printk(KERN_WARNING "%s: Unexpected data error\n", - dev->name); - goto drop; - case E_LST_LNK_ERR: - printk(KERN_WARNING "%s: Link lost error\n", - dev->name); - goto drop; - case E_FRM_ERR: - printk(KERN_WARNING "%s: Framming Error\n", - dev->name); - goto drop; - case E_FLG_SYN_ERR: - printk(KERN_WARNING "%s: Flag sync. lost during " - "packet\n", dev->name); - goto drop; - case E_RX_INV_BUF: - printk(KERN_ERR "%s: Invalid receive buffer " - "address\n", dev->name); - writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, - ®s->HostCtrl); - wmb(); - break; - case E_RX_INV_DSC: - printk(KERN_ERR "%s: Invalid receive descriptor " - "address\n", dev->name); - writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, - ®s->HostCtrl); - wmb(); - break; - case E_RNG_BLK: - printk(KERN_ERR "%s: Invalid ring block\n", - dev->name); - writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, - ®s->HostCtrl); - wmb(); - break; - drop: - /* Label packet to be dropped. - * Actual dropping occurs in rx - * handling. - * - * The index of packet we get to drop is - * the index of the packet following - * the bad packet. -kbf - */ - { - u16 index = rrpriv->evt_ring[eidx].index; - index = (index + (RX_RING_ENTRIES - 1)) % - RX_RING_ENTRIES; - rrpriv->rx_ring[index].mode |= - (PACKET_BAD | PACKET_END); - } - break; - default: - printk(KERN_WARNING "%s: Unhandled event 0x%02x\n", - dev->name, rrpriv->evt_ring[eidx].code); - } - eidx = (eidx + 1) % EVT_RING_ENTRIES; - } - - rrpriv->info->evt_ctrl.pi = eidx; - wmb(); - return eidx; -} - - -static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) -{ - struct rr_private *rrpriv = netdev_priv(dev); - struct rr_regs __iomem *regs = rrpriv->regs; - - do { - struct rx_desc *desc; - u32 pkt_len; - - desc = &(rrpriv->rx_ring[index]); - pkt_len = desc->size; -#if (DEBUG > 2) - printk("index %i, rxlimit %i\n", index, rxlimit); - printk("len %x, mode %x\n", pkt_len, desc->mode); -#endif - if ( (rrpriv->rx_ring[index].mode & PACKET_BAD) == PACKET_BAD){ - dev->stats.rx_dropped++; - goto defer; - } - - if (pkt_len > 0){ - struct sk_buff *skb, *rx_skb; - - rx_skb = rrpriv->rx_skbuff[index]; - - if (pkt_len < PKT_COPY_THRESHOLD) { - skb = alloc_skb(pkt_len, GFP_ATOMIC); - if (skb == NULL){ - printk(KERN_WARNING "%s: Unable to allocate skb (%i bytes), deferring packet\n", dev->name, pkt_len); - dev->stats.rx_dropped++; - goto defer; - } else { - pci_dma_sync_single_for_cpu(rrpriv->pci_dev, - desc->addr.addrlo, - pkt_len, - PCI_DMA_FROMDEVICE); - - memcpy(skb_put(skb, pkt_len), - rx_skb->data, pkt_len); - - pci_dma_sync_single_for_device(rrpriv->pci_dev, - desc->addr.addrlo, - pkt_len, - PCI_DMA_FROMDEVICE); - } - }else{ - struct sk_buff *newskb; - - newskb = alloc_skb(dev->mtu + HIPPI_HLEN, - GFP_ATOMIC); - if (newskb){ - dma_addr_t addr; - - pci_unmap_single(rrpriv->pci_dev, - desc->addr.addrlo, dev->mtu + - HIPPI_HLEN, PCI_DMA_FROMDEVICE); - skb = rx_skb; - skb_put(skb, pkt_len); - rrpriv->rx_skbuff[index] = newskb; - addr = pci_map_single(rrpriv->pci_dev, - newskb->data, - dev->mtu + HIPPI_HLEN, - PCI_DMA_FROMDEVICE); - set_rraddr(&desc->addr, addr); - } else { - printk("%s: Out of memory, deferring " - "packet\n", dev->name); - dev->stats.rx_dropped++; - goto defer; - } - } - skb->protocol = hippi_type_trans(skb, dev); - - netif_rx(skb); /* send it up */ - - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - } - defer: - desc->mode = 0; - desc->size = dev->mtu + HIPPI_HLEN; - - if ((index & 7) == 7) - writel(index, ®s->IpRxPi); - - index = (index + 1) % RX_RING_ENTRIES; - } while(index != rxlimit); - - rrpriv->cur_rx = index; - wmb(); -} - - -static irqreturn_t rr_interrupt(int irq, void *dev_id) -{ - struct rr_private *rrpriv; - struct rr_regs __iomem *regs; - struct net_device *dev = (struct net_device *)dev_id; - u32 prodidx, rxindex, eidx, txcsmr, rxlimit, txcon; - - rrpriv = netdev_priv(dev); - regs = rrpriv->regs; - - if (!(readl(®s->HostCtrl) & RR_INT)) - return IRQ_NONE; - - spin_lock(&rrpriv->lock); - - prodidx = readl(®s->EvtPrd); - txcsmr = (prodidx >> 8) & 0xff; - rxlimit = (prodidx >> 16) & 0xff; - prodidx &= 0xff; - -#if (DEBUG > 2) - printk("%s: interrupt, prodidx = %i, eidx = %i\n", dev->name, - prodidx, rrpriv->info->evt_ctrl.pi); -#endif - /* - * Order here is important. We must handle events - * before doing anything else in order to catch - * such things as LLRC errors, etc -kbf - */ - - eidx = rrpriv->info->evt_ctrl.pi; - if (prodidx != eidx) - eidx = rr_handle_event(dev, prodidx, eidx); - - rxindex = rrpriv->cur_rx; - if (rxindex != rxlimit) - rx_int(dev, rxlimit, rxindex); - - txcon = rrpriv->dirty_tx; - if (txcsmr != txcon) { - do { - /* Due to occational firmware TX producer/consumer out - * of sync. error need to check entry in ring -kbf - */ - if(rrpriv->tx_skbuff[txcon]){ - struct tx_desc *desc; - struct sk_buff *skb; - - desc = &(rrpriv->tx_ring[txcon]); - skb = rrpriv->tx_skbuff[txcon]; - - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - - pci_unmap_single(rrpriv->pci_dev, - desc->addr.addrlo, skb->len, - PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skb); - - rrpriv->tx_skbuff[txcon] = NULL; - desc->size = 0; - set_rraddr(&rrpriv->tx_ring[txcon].addr, 0); - desc->mode = 0; - } - txcon = (txcon + 1) % TX_RING_ENTRIES; - } while (txcsmr != txcon); - wmb(); - - rrpriv->dirty_tx = txcon; - if (rrpriv->tx_full && rr_if_busy(dev) && - (((rrpriv->info->tx_ctrl.pi + 1) % TX_RING_ENTRIES) - != rrpriv->dirty_tx)){ - rrpriv->tx_full = 0; - netif_wake_queue(dev); - } - } - - eidx |= ((txcsmr << 8) | (rxlimit << 16)); - writel(eidx, ®s->EvtCon); - wmb(); - - spin_unlock(&rrpriv->lock); - return IRQ_HANDLED; -} - -static inline void rr_raz_tx(struct rr_private *rrpriv, - struct net_device *dev) -{ - int i; - - for (i = 0; i < TX_RING_ENTRIES; i++) { - struct sk_buff *skb = rrpriv->tx_skbuff[i]; - - if (skb) { - struct tx_desc *desc = &(rrpriv->tx_ring[i]); - - pci_unmap_single(rrpriv->pci_dev, desc->addr.addrlo, - skb->len, PCI_DMA_TODEVICE); - desc->size = 0; - set_rraddr(&desc->addr, 0); - dev_kfree_skb(skb); - rrpriv->tx_skbuff[i] = NULL; - } - } -} - - -static inline void rr_raz_rx(struct rr_private *rrpriv, - struct net_device *dev) -{ - int i; - - for (i = 0; i < RX_RING_ENTRIES; i++) { - struct sk_buff *skb = rrpriv->rx_skbuff[i]; - - if (skb) { - struct rx_desc *desc = &(rrpriv->rx_ring[i]); - - pci_unmap_single(rrpriv->pci_dev, desc->addr.addrlo, - dev->mtu + HIPPI_HLEN, PCI_DMA_FROMDEVICE); - desc->size = 0; - set_rraddr(&desc->addr, 0); - dev_kfree_skb(skb); - rrpriv->rx_skbuff[i] = NULL; - } - } -} - -static void rr_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct rr_private *rrpriv = netdev_priv(dev); - struct rr_regs __iomem *regs = rrpriv->regs; - unsigned long flags; - - if (readl(®s->HostCtrl) & NIC_HALTED){ - printk("%s: Restarting nic\n", dev->name); - memset(rrpriv->rx_ctrl, 0, 256 * sizeof(struct ring_ctrl)); - memset(rrpriv->info, 0, sizeof(struct rr_info)); - wmb(); - - rr_raz_tx(rrpriv, dev); - rr_raz_rx(rrpriv, dev); - - if (rr_init1(dev)) { - spin_lock_irqsave(&rrpriv->lock, flags); - writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, - ®s->HostCtrl); - spin_unlock_irqrestore(&rrpriv->lock, flags); - } - } - rrpriv->timer.expires = RUN_AT(5*HZ); - add_timer(&rrpriv->timer); -} - - -static int rr_open(struct net_device *dev) -{ - struct rr_private *rrpriv = netdev_priv(dev); - struct pci_dev *pdev = rrpriv->pci_dev; - struct rr_regs __iomem *regs; - int ecode = 0; - unsigned long flags; - dma_addr_t dma_addr; - - regs = rrpriv->regs; - - if (rrpriv->fw_rev < 0x00020000) { - printk(KERN_WARNING "%s: trying to configure device with " - "obsolete firmware\n", dev->name); - ecode = -EBUSY; - goto error; - } - - rrpriv->rx_ctrl = pci_alloc_consistent(pdev, - 256 * sizeof(struct ring_ctrl), - &dma_addr); - if (!rrpriv->rx_ctrl) { - ecode = -ENOMEM; - goto error; - } - rrpriv->rx_ctrl_dma = dma_addr; - memset(rrpriv->rx_ctrl, 0, 256*sizeof(struct ring_ctrl)); - - rrpriv->info = pci_alloc_consistent(pdev, sizeof(struct rr_info), - &dma_addr); - if (!rrpriv->info) { - ecode = -ENOMEM; - goto error; - } - rrpriv->info_dma = dma_addr; - memset(rrpriv->info, 0, sizeof(struct rr_info)); - wmb(); - - spin_lock_irqsave(&rrpriv->lock, flags); - writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->HostCtrl); - readl(®s->HostCtrl); - spin_unlock_irqrestore(&rrpriv->lock, flags); - - if (request_irq(dev->irq, rr_interrupt, IRQF_SHARED, dev->name, dev)) { - printk(KERN_WARNING "%s: Requested IRQ %d is busy\n", - dev->name, dev->irq); - ecode = -EAGAIN; - goto error; - } - - if ((ecode = rr_init1(dev))) - goto error; - - /* Set the timer to switch to check for link beat and perhaps switch - to an alternate media type. */ - init_timer(&rrpriv->timer); - rrpriv->timer.expires = RUN_AT(5*HZ); /* 5 sec. watchdog */ - rrpriv->timer.data = (unsigned long)dev; - rrpriv->timer.function = rr_timer; /* timer handler */ - add_timer(&rrpriv->timer); - - netif_start_queue(dev); - - return ecode; - - error: - spin_lock_irqsave(&rrpriv->lock, flags); - writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->HostCtrl); - spin_unlock_irqrestore(&rrpriv->lock, flags); - - if (rrpriv->info) { - pci_free_consistent(pdev, sizeof(struct rr_info), rrpriv->info, - rrpriv->info_dma); - rrpriv->info = NULL; - } - if (rrpriv->rx_ctrl) { - pci_free_consistent(pdev, sizeof(struct ring_ctrl), - rrpriv->rx_ctrl, rrpriv->rx_ctrl_dma); - rrpriv->rx_ctrl = NULL; - } - - netif_stop_queue(dev); - - return ecode; -} - - -static void rr_dump(struct net_device *dev) -{ - struct rr_private *rrpriv; - struct rr_regs __iomem *regs; - u32 index, cons; - short i; - int len; - - rrpriv = netdev_priv(dev); - regs = rrpriv->regs; - - printk("%s: dumping NIC TX rings\n", dev->name); - - printk("RxPrd %08x, TxPrd %02x, EvtPrd %08x, TxPi %02x, TxCtrlPi %02x\n", - readl(®s->RxPrd), readl(®s->TxPrd), - readl(®s->EvtPrd), readl(®s->TxPi), - rrpriv->info->tx_ctrl.pi); - - printk("Error code 0x%x\n", readl(®s->Fail1)); - - index = (((readl(®s->EvtPrd) >> 8) & 0xff) - 1) % TX_RING_ENTRIES; - cons = rrpriv->dirty_tx; - printk("TX ring index %i, TX consumer %i\n", - index, cons); - - if (rrpriv->tx_skbuff[index]){ - len = min_t(int, 0x80, rrpriv->tx_skbuff[index]->len); - printk("skbuff for index %i is valid - dumping data (0x%x bytes - DMA len 0x%x)\n", index, len, rrpriv->tx_ring[index].size); - for (i = 0; i < len; i++){ - if (!(i & 7)) - printk("\n"); - printk("%02x ", (unsigned char) rrpriv->tx_skbuff[index]->data[i]); - } - printk("\n"); - } - - if (rrpriv->tx_skbuff[cons]){ - len = min_t(int, 0x80, rrpriv->tx_skbuff[cons]->len); - printk("skbuff for cons %i is valid - dumping data (0x%x bytes - skbuff len 0x%x)\n", cons, len, rrpriv->tx_skbuff[cons]->len); - printk("mode 0x%x, size 0x%x,\n phys %08Lx, skbuff-addr %08lx, truesize 0x%x\n", - rrpriv->tx_ring[cons].mode, - rrpriv->tx_ring[cons].size, - (unsigned long long) rrpriv->tx_ring[cons].addr.addrlo, - (unsigned long)rrpriv->tx_skbuff[cons]->data, - (unsigned int)rrpriv->tx_skbuff[cons]->truesize); - for (i = 0; i < len; i++){ - if (!(i & 7)) - printk("\n"); - printk("%02x ", (unsigned char)rrpriv->tx_ring[cons].size); - } - printk("\n"); - } - - printk("dumping TX ring info:\n"); - for (i = 0; i < TX_RING_ENTRIES; i++) - printk("mode 0x%x, size 0x%x, phys-addr %08Lx\n", - rrpriv->tx_ring[i].mode, - rrpriv->tx_ring[i].size, - (unsigned long long) rrpriv->tx_ring[i].addr.addrlo); - -} - - -static int rr_close(struct net_device *dev) -{ - struct rr_private *rrpriv; - struct rr_regs __iomem *regs; - unsigned long flags; - u32 tmp; - short i; - - netif_stop_queue(dev); - - rrpriv = netdev_priv(dev); - regs = rrpriv->regs; - - /* - * Lock to make sure we are not cleaning up while another CPU - * is handling interrupts. - */ - spin_lock_irqsave(&rrpriv->lock, flags); - - tmp = readl(®s->HostCtrl); - if (tmp & NIC_HALTED){ - printk("%s: NIC already halted\n", dev->name); - rr_dump(dev); - }else{ - tmp |= HALT_NIC | RR_CLEAR_INT; - writel(tmp, ®s->HostCtrl); - readl(®s->HostCtrl); - } - - rrpriv->fw_running = 0; - - del_timer_sync(&rrpriv->timer); - - writel(0, ®s->TxPi); - writel(0, ®s->IpRxPi); - - writel(0, ®s->EvtCon); - writel(0, ®s->EvtPrd); - - for (i = 0; i < CMD_RING_ENTRIES; i++) - writel(0, ®s->CmdRing[i]); - - rrpriv->info->tx_ctrl.entries = 0; - rrpriv->info->cmd_ctrl.pi = 0; - rrpriv->info->evt_ctrl.pi = 0; - rrpriv->rx_ctrl[4].entries = 0; - - rr_raz_tx(rrpriv, dev); - rr_raz_rx(rrpriv, dev); - - pci_free_consistent(rrpriv->pci_dev, 256 * sizeof(struct ring_ctrl), - rrpriv->rx_ctrl, rrpriv->rx_ctrl_dma); - rrpriv->rx_ctrl = NULL; - - pci_free_consistent(rrpriv->pci_dev, sizeof(struct rr_info), - rrpriv->info, rrpriv->info_dma); - rrpriv->info = NULL; - - free_irq(dev->irq, dev); - spin_unlock_irqrestore(&rrpriv->lock, flags); - - return 0; -} - - -static netdev_tx_t rr_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct rr_private *rrpriv = netdev_priv(dev); - struct rr_regs __iomem *regs = rrpriv->regs; - struct hippi_cb *hcb = (struct hippi_cb *) skb->cb; - struct ring_ctrl *txctrl; - unsigned long flags; - u32 index, len = skb->len; - u32 *ifield; - struct sk_buff *new_skb; - - if (readl(®s->Mode) & FATAL_ERR) - printk("error codes Fail1 %02x, Fail2 %02x\n", - readl(®s->Fail1), readl(®s->Fail2)); - - /* - * We probably need to deal with tbusy here to prevent overruns. - */ - - if (skb_headroom(skb) < 8){ - printk("incoming skb too small - reallocating\n"); - if (!(new_skb = dev_alloc_skb(len + 8))) { - dev_kfree_skb(skb); - netif_wake_queue(dev); - return NETDEV_TX_OK; - } - skb_reserve(new_skb, 8); - skb_put(new_skb, len); - skb_copy_from_linear_data(skb, new_skb->data, len); - dev_kfree_skb(skb); - skb = new_skb; - } - - ifield = (u32 *)skb_push(skb, 8); - - ifield[0] = 0; - ifield[1] = hcb->ifield; - - /* - * We don't need the lock before we are actually going to start - * fiddling with the control blocks. - */ - spin_lock_irqsave(&rrpriv->lock, flags); - - txctrl = &rrpriv->info->tx_ctrl; - - index = txctrl->pi; - - rrpriv->tx_skbuff[index] = skb; - set_rraddr(&rrpriv->tx_ring[index].addr, pci_map_single( - rrpriv->pci_dev, skb->data, len + 8, PCI_DMA_TODEVICE)); - rrpriv->tx_ring[index].size = len + 8; /* include IFIELD */ - rrpriv->tx_ring[index].mode = PACKET_START | PACKET_END; - txctrl->pi = (index + 1) % TX_RING_ENTRIES; - wmb(); - writel(txctrl->pi, ®s->TxPi); - - if (txctrl->pi == rrpriv->dirty_tx){ - rrpriv->tx_full = 1; - netif_stop_queue(dev); - } - - spin_unlock_irqrestore(&rrpriv->lock, flags); - - return NETDEV_TX_OK; -} - - -/* - * Read the firmware out of the EEPROM and put it into the SRAM - * (or from user space - later) - * - * This operation requires the NIC to be halted and is performed with - * interrupts disabled and with the spinlock hold. - */ -static int rr_load_firmware(struct net_device *dev) -{ - struct rr_private *rrpriv; - struct rr_regs __iomem *regs; - size_t eptr, segptr; - int i, j; - u32 localctrl, sptr, len, tmp; - u32 p2len, p2size, nr_seg, revision, io, sram_size; - - rrpriv = netdev_priv(dev); - regs = rrpriv->regs; - - if (dev->flags & IFF_UP) - return -EBUSY; - - if (!(readl(®s->HostCtrl) & NIC_HALTED)){ - printk("%s: Trying to load firmware to a running NIC.\n", - dev->name); - return -EBUSY; - } - - localctrl = readl(®s->LocalCtrl); - writel(0, ®s->LocalCtrl); - - writel(0, ®s->EvtPrd); - writel(0, ®s->RxPrd); - writel(0, ®s->TxPrd); - - /* - * First wipe the entire SRAM, otherwise we might run into all - * kinds of trouble ... sigh, this took almost all afternoon - * to track down ;-( - */ - io = readl(®s->ExtIo); - writel(0, ®s->ExtIo); - sram_size = rr_read_eeprom_word(rrpriv, 8); - - for (i = 200; i < sram_size / 4; i++){ - writel(i * 4, ®s->WinBase); - mb(); - writel(0, ®s->WinData); - mb(); - } - writel(io, ®s->ExtIo); - mb(); - - eptr = rr_read_eeprom_word(rrpriv, - offsetof(struct eeprom, rncd_info.AddrRunCodeSegs)); - eptr = ((eptr & 0x1fffff) >> 3); - - p2len = rr_read_eeprom_word(rrpriv, 0x83*4); - p2len = (p2len << 2); - p2size = rr_read_eeprom_word(rrpriv, 0x84*4); - p2size = ((p2size & 0x1fffff) >> 3); - - if ((eptr < p2size) || (eptr > (p2size + p2len))){ - printk("%s: eptr is invalid\n", dev->name); - goto out; - } - - revision = rr_read_eeprom_word(rrpriv, - offsetof(struct eeprom, manf.HeaderFmt)); - - if (revision != 1){ - printk("%s: invalid firmware format (%i)\n", - dev->name, revision); - goto out; - } - - nr_seg = rr_read_eeprom_word(rrpriv, eptr); - eptr +=4; -#if (DEBUG > 1) - printk("%s: nr_seg %i\n", dev->name, nr_seg); -#endif - - for (i = 0; i < nr_seg; i++){ - sptr = rr_read_eeprom_word(rrpriv, eptr); - eptr += 4; - len = rr_read_eeprom_word(rrpriv, eptr); - eptr += 4; - segptr = rr_read_eeprom_word(rrpriv, eptr); - segptr = ((segptr & 0x1fffff) >> 3); - eptr += 4; -#if (DEBUG > 1) - printk("%s: segment %i, sram address %06x, length %04x, segptr %06x\n", - dev->name, i, sptr, len, segptr); -#endif - for (j = 0; j < len; j++){ - tmp = rr_read_eeprom_word(rrpriv, segptr); - writel(sptr, ®s->WinBase); - mb(); - writel(tmp, ®s->WinData); - mb(); - segptr += 4; - sptr += 4; - } - } - -out: - writel(localctrl, ®s->LocalCtrl); - mb(); - return 0; -} - - -static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct rr_private *rrpriv; - unsigned char *image, *oldimage; - unsigned long flags; - unsigned int i; - int error = -EOPNOTSUPP; - - rrpriv = netdev_priv(dev); - - switch(cmd){ - case SIOCRRGFW: - if (!capable(CAP_SYS_RAWIO)){ - return -EPERM; - } - - image = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL); - if (!image){ - printk(KERN_ERR "%s: Unable to allocate memory " - "for EEPROM image\n", dev->name); - return -ENOMEM; - } - - - if (rrpriv->fw_running){ - printk("%s: Firmware already running\n", dev->name); - error = -EPERM; - goto gf_out; - } - - spin_lock_irqsave(&rrpriv->lock, flags); - i = rr_read_eeprom(rrpriv, 0, image, EEPROM_BYTES); - spin_unlock_irqrestore(&rrpriv->lock, flags); - if (i != EEPROM_BYTES){ - printk(KERN_ERR "%s: Error reading EEPROM\n", - dev->name); - error = -EFAULT; - goto gf_out; - } - error = copy_to_user(rq->ifr_data, image, EEPROM_BYTES); - if (error) - error = -EFAULT; - gf_out: - kfree(image); - return error; - - case SIOCRRPFW: - if (!capable(CAP_SYS_RAWIO)){ - return -EPERM; - } - - image = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL); - oldimage = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL); - if (!image || !oldimage) { - printk(KERN_ERR "%s: Unable to allocate memory " - "for EEPROM image\n", dev->name); - error = -ENOMEM; - goto wf_out; - } - - error = copy_from_user(image, rq->ifr_data, EEPROM_BYTES); - if (error) { - error = -EFAULT; - goto wf_out; - } - - if (rrpriv->fw_running){ - printk("%s: Firmware already running\n", dev->name); - error = -EPERM; - goto wf_out; - } - - printk("%s: Updating EEPROM firmware\n", dev->name); - - spin_lock_irqsave(&rrpriv->lock, flags); - error = write_eeprom(rrpriv, 0, image, EEPROM_BYTES); - if (error) - printk(KERN_ERR "%s: Error writing EEPROM\n", - dev->name); - - i = rr_read_eeprom(rrpriv, 0, oldimage, EEPROM_BYTES); - spin_unlock_irqrestore(&rrpriv->lock, flags); - - if (i != EEPROM_BYTES) - printk(KERN_ERR "%s: Error reading back EEPROM " - "image\n", dev->name); - - error = memcmp(image, oldimage, EEPROM_BYTES); - if (error){ - printk(KERN_ERR "%s: Error verifying EEPROM image\n", - dev->name); - error = -EFAULT; - } - wf_out: - kfree(oldimage); - kfree(image); - return error; - - case SIOCRRID: - return put_user(0x52523032, (int __user *)rq->ifr_data); - default: - return error; - } -} - -static DEFINE_PCI_DEVICE_TABLE(rr_pci_tbl) = { - { PCI_VENDOR_ID_ESSENTIAL, PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER, - PCI_ANY_ID, PCI_ANY_ID, }, - { 0,} -}; -MODULE_DEVICE_TABLE(pci, rr_pci_tbl); - -static struct pci_driver rr_driver = { - .name = "rrunner", - .id_table = rr_pci_tbl, - .probe = rr_init_one, - .remove = __devexit_p(rr_remove_one), -}; - -static int __init rr_init_module(void) -{ - return pci_register_driver(&rr_driver); -} - -static void __exit rr_cleanup_module(void) -{ - pci_unregister_driver(&rr_driver); -} - -module_init(rr_init_module); -module_exit(rr_cleanup_module); diff --git a/drivers/net/rrunner.h b/drivers/net/rrunner.h deleted file mode 100644 index 2816904..0000000 --- a/drivers/net/rrunner.h +++ /dev/null @@ -1,846 +0,0 @@ -#ifndef _RRUNNER_H_ -#define _RRUNNER_H_ - -#include - -#if ((BITS_PER_LONG != 32) && (BITS_PER_LONG != 64)) -#error "BITS_PER_LONG not defined or not valid" -#endif - - -struct rr_regs { - - u32 pad0[16]; - - u32 HostCtrl; - u32 LocalCtrl; - u32 Pc; - u32 BrkPt; - -/* Timer increments every 0.97 micro-seconds (unsigned int) */ - u32 Timer_Hi; - u32 Timer; - u32 TimerRef; - u32 PciState; - - u32 Event; - u32 MbEvent; - - u32 WinBase; - u32 WinData; - u32 RX_state; - u32 TX_state; - - u32 Overhead; - u32 ExtIo; - - u32 DmaWriteHostHi; - u32 DmaWriteHostLo; - - u32 pad1[2]; - - u32 DmaReadHostHi; - u32 DmaReadHostLo; - - u32 pad2; - - u32 DmaReadLen; - u32 DmaWriteState; - - u32 DmaWriteLcl; - u32 DmaWriteIPchecksum; - u32 DmaWriteLen; - u32 DmaReadState; - u32 DmaReadLcl; - u32 DmaReadIPchecksum; - u32 pad3; - - u32 RxBase; - u32 RxPrd; - u32 RxCon; - - u32 pad4; - - u32 TxBase; - u32 TxPrd; - u32 TxCon; - - u32 pad5; - - u32 RxIndPro; - u32 RxIndCon; - u32 RxIndRef; - - u32 pad6; - - u32 TxIndPro; - u32 TxIndCon; - u32 TxIndRef; - - u32 pad7[17]; - - u32 DrCmndPro; - u32 DrCmndCon; - u32 DrCmndRef; - - u32 pad8; - - u32 DwCmndPro; - u32 DwCmndCon; - u32 DwCmndRef; - - u32 AssistState; - - u32 DrDataPro; - u32 DrDataCon; - u32 DrDataRef; - - u32 pad9; - - u32 DwDataPro; - u32 DwDataCon; - u32 DwDataRef; - - u32 pad10[33]; - - u32 EvtCon; - - u32 pad11[5]; - - u32 TxPi; - u32 IpRxPi; - - u32 pad11a[8]; - - u32 CmdRing[16]; - -/* The ULA is in two registers the high order two bytes of the first - * word contain the RunCode features. - * ula0 res res byte0 byte1 - * ula1 byte2 byte3 byte4 byte5 - */ - u32 Ula0; - u32 Ula1; - - u32 RxRingHi; - u32 RxRingLo; - - u32 InfoPtrHi; - u32 InfoPtrLo; - - u32 Mode; - - u32 ConRetry; - u32 ConRetryTmr; - - u32 ConTmout; - u32 CtatTmr; - - u32 MaxRxRng; - - u32 IntrTmr; - u32 TxDataMvTimeout; - u32 RxDataMvTimeout; - - u32 EvtPrd; - u32 TraceIdx; - - u32 Fail1; - u32 Fail2; - - u32 DrvPrm; - - u32 FilterLA; - - u32 FwRev; - u32 FwRes1; - u32 FwRes2; - u32 FwRes3; - - u32 WriteDmaThresh; - u32 ReadDmaThresh; - - u32 pad12[325]; - u32 Window[512]; -}; - -/* - * Host control register bits. - */ - -#define RR_INT 0x01 -#define RR_CLEAR_INT 0x02 -#define NO_SWAP 0x04000004 -#define NO_SWAP1 0x00000004 -#define PCI_RESET_NIC 0x08 -#define HALT_NIC 0x10 -#define SSTEP_NIC 0x20 -#define MEM_READ_MULTI 0x40 -#define NIC_HALTED 0x100 -#define HALT_INST 0x200 -#define PARITY_ERR 0x400 -#define INVALID_INST_B 0x800 -#define RR_REV_2 0x20000000 -#define RR_REV_MASK 0xf0000000 - -/* - * Local control register bits. - */ - -#define INTA_STATE 0x01 -#define CLEAR_INTA 0x02 -#define FAST_EEPROM_ACCESS 0x08 -#define ENABLE_EXTRA_SRAM 0x100 -#define ENABLE_EXTRA_DESC 0x200 -#define ENABLE_PARITY 0x400 -#define FORCE_DMA_PARITY_ERROR 0x800 -#define ENABLE_EEPROM_WRITE 0x1000 -#define ENABLE_DATA_CACHE 0x2000 -#define SRAM_LO_PARITY_ERR 0x4000 -#define SRAM_HI_PARITY_ERR 0x8000 - -/* - * PCI state bits. - */ - -#define FORCE_PCI_RESET 0x01 -#define PROVIDE_LENGTH 0x02 -#define MASK_DMA_READ_MAX 0x1C -#define RBURST_DISABLE 0x00 -#define RBURST_4 0x04 -#define RBURST_16 0x08 -#define RBURST_32 0x0C -#define RBURST_64 0x10 -#define RBURST_128 0x14 -#define RBURST_256 0x18 -#define RBURST_1024 0x1C -#define MASK_DMA_WRITE_MAX 0xE0 -#define WBURST_DISABLE 0x00 -#define WBURST_4 0x20 -#define WBURST_16 0x40 -#define WBURST_32 0x60 -#define WBURST_64 0x80 -#define WBURST_128 0xa0 -#define WBURST_256 0xc0 -#define WBURST_1024 0xe0 -#define MASK_MIN_DMA 0xFF00 -#define FIFO_RETRY_ENABLE 0x10000 - -/* - * Event register - */ - -#define DMA_WRITE_DONE 0x10000 -#define DMA_READ_DONE 0x20000 -#define DMA_WRITE_ERR 0x40000 -#define DMA_READ_ERR 0x80000 - -/* - * Receive state - * - * RoadRunner HIPPI Receive State Register controls and monitors the - * HIPPI receive interface in the NIC. Look at err bits when a HIPPI - * receive Error Event occurs. - */ - -#define ENABLE_NEW_CON 0x01 -#define RESET_RECV 0x02 -#define RECV_ALL 0x00 -#define RECV_1K 0x20 -#define RECV_2K 0x40 -#define RECV_4K 0x60 -#define RECV_8K 0x80 -#define RECV_16K 0xa0 -#define RECV_32K 0xc0 -#define RECV_64K 0xe0 - -/* - * Transmit status. - */ - -#define ENA_XMIT 0x01 -#define PERM_CON 0x02 - -/* - * DMA write state - */ - -#define RESET_DMA 0x01 -#define NO_SWAP_DMA 0x02 -#define DMA_ACTIVE 0x04 -#define THRESH_MASK 0x1F -#define DMA_ERROR_MASK 0xff000000 - -/* - * Gooddies stored in the ULA registers. - */ - -#define TRACE_ON_WHAT_BIT 0x00020000 /* Traces on */ -#define ONEM_BUF_WHAT_BIT 0x00040000 /* 1Meg vs 256K */ -#define CHAR_API_WHAT_BIT 0x00080000 /* Char API vs network only */ -#define CMD_EVT_WHAT_BIT 0x00200000 /* Command event */ -#define LONG_TX_WHAT_BIT 0x00400000 -#define LONG_RX_WHAT_BIT 0x00800000 -#define WHAT_BIT_MASK 0xFFFD0000 /* Feature bit mask */ - -/* - * Mode status - */ - -#define EVENT_OVFL 0x80000000 -#define FATAL_ERR 0x40000000 -#define LOOP_BACK 0x01 -#define MODE_PH 0x02 -#define MODE_FP 0x00 -#define PTR64BIT 0x04 -#define PTR32BIT 0x00 -#define PTR_WD_SWAP 0x08 -#define PTR_WD_NOSWAP 0x00 -#define POST_WARN_EVENT 0x10 -#define ERR_TERM 0x20 -#define DIRECT_CONN 0x40 -#define NO_NIC_WATCHDOG 0x80 -#define SWAP_DATA 0x100 -#define SWAP_CONTROL 0x200 -#define NIC_HALT_ON_ERR 0x400 -#define NIC_NO_RESTART 0x800 -#define HALF_DUP_TX 0x1000 -#define HALF_DUP_RX 0x2000 - - -/* - * Error codes - */ - -/* Host Error Codes - values of fail1 */ -#define ERR_UNKNOWN_MBOX 0x1001 -#define ERR_UNKNOWN_CMD 0x1002 -#define ERR_MAX_RING 0x1003 -#define ERR_RING_CLOSED 0x1004 -#define ERR_RING_OPEN 0x1005 -/* Firmware internal errors */ -#define ERR_EVENT_RING_FULL 0x01 -#define ERR_DW_PEND_CMND_FULL 0x02 -#define ERR_DR_PEND_CMND_FULL 0x03 -#define ERR_DW_PEND_DATA_FULL 0x04 -#define ERR_DR_PEND_DATA_FULL 0x05 -#define ERR_ILLEGAL_JUMP 0x06 -#define ERR_UNIMPLEMENTED 0x07 -#define ERR_TX_INFO_FULL 0x08 -#define ERR_RX_INFO_FULL 0x09 -#define ERR_ILLEGAL_MODE 0x0A -#define ERR_MAIN_TIMEOUT 0x0B -#define ERR_EVENT_BITS 0x0C -#define ERR_UNPEND_FULL 0x0D -#define ERR_TIMER_QUEUE_FULL 0x0E -#define ERR_TIMER_QUEUE_EMPTY 0x0F -#define ERR_TIMER_NO_FREE 0x10 -#define ERR_INTR_START 0x11 -#define ERR_BAD_STARTUP 0x12 -#define ERR_NO_PKT_END 0x13 -#define ERR_HALTED_ON_ERR 0x14 -/* Hardware NIC Errors */ -#define ERR_WRITE_DMA 0x0101 -#define ERR_READ_DMA 0x0102 -#define ERR_EXT_SERIAL 0x0103 -#define ERR_TX_INT_PARITY 0x0104 - - -/* - * Event definitions - */ - -#define EVT_RING_ENTRIES 64 -#define EVT_RING_SIZE (EVT_RING_ENTRIES * sizeof(struct event)) - -struct event { -#ifdef __LITTLE_ENDIAN - u16 index; - u8 ring; - u8 code; -#else - u8 code; - u8 ring; - u16 index; -#endif - u32 timestamp; -}; - -/* - * General Events - */ - -#define E_NIC_UP 0x01 -#define E_WATCHDOG 0x02 - -#define E_STAT_UPD 0x04 -#define E_INVAL_CMD 0x05 -#define E_SET_CMD_CONS 0x06 -#define E_LINK_ON 0x07 -#define E_LINK_OFF 0x08 -#define E_INTERN_ERR 0x09 -#define E_HOST_ERR 0x0A -#define E_STATS_UPDATE 0x0B -#define E_REJECTING 0x0C - -/* - * Send Events - */ -#define E_CON_REJ 0x13 -#define E_CON_TMOUT 0x14 -#define E_CON_NC_TMOUT 0x15 /* I , Connection No Campon Timeout */ -#define E_DISC_ERR 0x16 -#define E_INT_PRTY 0x17 -#define E_TX_IDLE 0x18 -#define E_TX_LINK_DROP 0x19 -#define E_TX_INV_RNG 0x1A -#define E_TX_INV_BUF 0x1B -#define E_TX_INV_DSC 0x1C - -/* - * Destination Events - */ -/* - * General Receive events - */ -#define E_VAL_RNG 0x20 -#define E_RX_RNG_ENER 0x21 -#define E_INV_RNG 0x22 -#define E_RX_RNG_SPC 0x23 -#define E_RX_RNG_OUT 0x24 -#define E_PKT_DISCARD 0x25 -#define E_INFO_EVT 0x27 - -/* - * Data corrupted events - */ -#define E_RX_PAR_ERR 0x2B -#define E_RX_LLRC_ERR 0x2C -#define E_IP_CKSM_ERR 0x2D -#define E_DTA_CKSM_ERR 0x2E -#define E_SHT_BST 0x2F - -/* - * Data lost events - */ -#define E_LST_LNK_ERR 0x30 -#define E_FLG_SYN_ERR 0x31 -#define E_FRM_ERR 0x32 -#define E_RX_IDLE 0x33 -#define E_PKT_LN_ERR 0x34 -#define E_STATE_ERR 0x35 -#define E_UNEXP_DATA 0x3C - -/* - * Fatal events - */ -#define E_RX_INV_BUF 0x36 -#define E_RX_INV_DSC 0x37 -#define E_RNG_BLK 0x38 - -/* - * Warning events - */ -#define E_RX_TO 0x39 -#define E_BFR_SPC 0x3A -#define E_INV_ULP 0x3B - -#define E_NOT_IMPLEMENTED 0x40 - - -/* - * Commands - */ - -#define CMD_RING_ENTRIES 16 - -struct cmd { -#ifdef __LITTLE_ENDIAN - u16 index; - u8 ring; - u8 code; -#else - u8 code; - u8 ring; - u16 index; -#endif -}; - -#define C_START_FW 0x01 -#define C_UPD_STAT 0x02 -#define C_WATCHDOG 0x05 -#define C_DEL_RNG 0x09 -#define C_NEW_RNG 0x0A -#define C_CONN 0x0D - - -/* - * Mode bits - */ - -#define PACKET_BAD 0x01 /* Packet had link-layer error */ -#define INTERRUPT 0x02 -#define TX_IP_CKSUM 0x04 -#define PACKET_END 0x08 -#define PACKET_START 0x10 -#define SAME_IFIELD 0x80 - - -typedef struct { -#if (BITS_PER_LONG == 64) - u64 addrlo; -#else - u32 addrhi; - u32 addrlo; -#endif -} rraddr; - - -static inline void set_rraddr(rraddr *ra, dma_addr_t addr) -{ - unsigned long baddr = addr; -#if (BITS_PER_LONG == 64) - ra->addrlo = baddr; -#else - /* Don't bother setting zero every time */ - ra->addrlo = baddr; -#endif - mb(); -} - - -static inline void set_rxaddr(struct rr_regs __iomem *regs, volatile dma_addr_t addr) -{ - unsigned long baddr = addr; -#if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN) - writel(baddr & 0xffffffff, ®s->RxRingHi); - writel(baddr >> 32, ®s->RxRingLo); -#elif (BITS_PER_LONG == 64) - writel(baddr >> 32, ®s->RxRingHi); - writel(baddr & 0xffffffff, ®s->RxRingLo); -#else - writel(0, ®s->RxRingHi); - writel(baddr, ®s->RxRingLo); -#endif - mb(); -} - - -static inline void set_infoaddr(struct rr_regs __iomem *regs, volatile dma_addr_t addr) -{ - unsigned long baddr = addr; -#if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN) - writel(baddr & 0xffffffff, ®s->InfoPtrHi); - writel(baddr >> 32, ®s->InfoPtrLo); -#elif (BITS_PER_LONG == 64) - writel(baddr >> 32, ®s->InfoPtrHi); - writel(baddr & 0xffffffff, ®s->InfoPtrLo); -#else - writel(0, ®s->InfoPtrHi); - writel(baddr, ®s->InfoPtrLo); -#endif - mb(); -} - - -/* - * TX ring - */ - -#ifdef CONFIG_ROADRUNNER_LARGE_RINGS -#define TX_RING_ENTRIES 32 -#else -#define TX_RING_ENTRIES 16 -#endif -#define TX_TOTAL_SIZE (TX_RING_ENTRIES * sizeof(struct tx_desc)) - -struct tx_desc{ - rraddr addr; - u32 res; -#ifdef __LITTLE_ENDIAN - u16 size; - u8 pad; - u8 mode; -#else - u8 mode; - u8 pad; - u16 size; -#endif -}; - - -#ifdef CONFIG_ROADRUNNER_LARGE_RINGS -#define RX_RING_ENTRIES 32 -#else -#define RX_RING_ENTRIES 16 -#endif -#define RX_TOTAL_SIZE (RX_RING_ENTRIES * sizeof(struct rx_desc)) - -struct rx_desc{ - rraddr addr; - u32 res; -#ifdef __LITTLE_ENDIAN - u16 size; - u8 pad; - u8 mode; -#else - u8 mode; - u8 pad; - u16 size; -#endif -}; - - -/* - * ioctl's - */ - -#define SIOCRRPFW SIOCDEVPRIVATE /* put firmware */ -#define SIOCRRGFW SIOCDEVPRIVATE+1 /* get firmware */ -#define SIOCRRID SIOCDEVPRIVATE+2 /* identify */ - - -struct seg_hdr { - u32 seg_start; - u32 seg_len; - u32 seg_eestart; -}; - - -#define EEPROM_BASE 0x80000000 -#define EEPROM_WORDS 8192 -#define EEPROM_BYTES (EEPROM_WORDS * sizeof(u32)) - -struct eeprom_boot { - u32 key1; - u32 key2; - u32 sram_size; - struct seg_hdr loader; - u32 init_chksum; - u32 reserved1; -}; - -struct eeprom_manf { - u32 HeaderFmt; - u32 Firmware; - u32 BoardRevision; - u32 RoadrunnerRev; - char OpticsPart[8]; - u32 OpticsRev; - u32 pad1; - char SramPart[8]; - u32 SramRev; - u32 pad2; - char EepromPart[8]; - u32 EepromRev; - u32 EepromSize; - char PalPart[8]; - u32 PalRev; - u32 pad3; - char PalCodeFile[12]; - u32 PalCodeRev; - char BoardULA[8]; - char SerialNo[8]; - char MfgDate[8]; - char MfgTime[8]; - char ModifyDate[8]; - u32 ModCount; - u32 pad4[13]; -}; - - -struct eeprom_phase_info { - char phase1File[12]; - u32 phase1Rev; - char phase1Date[8]; - char phase2File[12]; - u32 phase2Rev; - char phase2Date[8]; - u32 reserved7[4]; -}; - -struct eeprom_rncd_info { - u32 FwStart; - u32 FwRev; - char FwDate[8]; - u32 AddrRunCodeSegs; - u32 FileNames; - char File[13][8]; -}; - - -/* Phase 1 region (starts are word offset 0x80) */ -struct phase1_hdr{ - u32 jump; - u32 noop; - struct seg_hdr phase2Seg; -}; - -struct eeprom { - struct eeprom_boot boot; - u32 pad1[8]; - struct eeprom_manf manf; - struct eeprom_phase_info phase_info; - struct eeprom_rncd_info rncd_info; - u32 pad2[15]; - u32 hdr_checksum; - struct phase1_hdr phase1; -}; - - -struct rr_stats { - u32 NicTimeStamp; - u32 RngCreated; - u32 RngDeleted; - u32 IntrGen; - u32 NEvtOvfl; - u32 InvCmd; - u32 DmaReadErrs; - u32 DmaWriteErrs; - u32 StatUpdtT; - u32 StatUpdtC; - u32 WatchDog; - u32 Trace; - - /* Serial HIPPI */ - u32 LnkRdyEst; - u32 GLinkErr; - u32 AltFlgErr; - u32 OvhdBit8Sync; - u32 RmtSerPrtyErr; - u32 RmtParPrtyErr; - u32 RmtLoopBk; - u32 pad1; - - /* HIPPI tx */ - u32 ConEst; - u32 ConRejS; - u32 ConRetry; - u32 ConTmOut; - u32 SndConDiscon; - u32 SndParErr; - u32 PktSnt; - u32 pad2[2]; - u32 ShFBstSnt; - u64 BytSent; - u32 TxTimeout; - u32 pad3[3]; - - /* HIPPI rx */ - u32 ConAcc; - u32 ConRejdiPrty; - u32 ConRejd64b; - u32 ConRejdBuf; - u32 RxConDiscon; - u32 RxConNoData; - u32 PktRx; - u32 pad4[2]; - u32 ShFBstRx; - u64 BytRx; - u32 RxParErr; - u32 RxLLRCerr; - u32 RxBstSZerr; - u32 RxStateErr; - u32 RxRdyErr; - u32 RxInvULP; - u32 RxSpcBuf; - u32 RxSpcDesc; - u32 RxRngSpc; - u32 RxRngFull; - u32 RxPktLenErr; - u32 RxCksmErr; - u32 RxPktDrp; - u32 RngLowSpc; - u32 RngDataClose; - u32 RxTimeout; - u32 RxIdle; -}; - - -/* - * This struct is shared with the NIC firmware. - */ -struct ring_ctrl { - rraddr rngptr; -#ifdef __LITTLE_ENDIAN - u16 entries; - u8 pad; - u8 entry_size; - u16 pi; - u16 mode; -#else - u8 entry_size; - u8 pad; - u16 entries; - u16 mode; - u16 pi; -#endif -}; - -struct rr_info { - union { - struct rr_stats stats; - u32 stati[128]; - } s; - struct ring_ctrl evt_ctrl; - struct ring_ctrl cmd_ctrl; - struct ring_ctrl tx_ctrl; - u8 pad[464]; - u8 trace[3072]; -}; - -/* - * The linux structure for the RoadRunner. - * - * RX/TX descriptors are put first to make sure they are properly - * aligned and do not cross cache-line boundaries. - */ - -struct rr_private -{ - struct rx_desc *rx_ring; - struct tx_desc *tx_ring; - struct event *evt_ring; - dma_addr_t tx_ring_dma; - dma_addr_t rx_ring_dma; - dma_addr_t evt_ring_dma; - /* Alignment ok ? */ - struct sk_buff *rx_skbuff[RX_RING_ENTRIES]; - struct sk_buff *tx_skbuff[TX_RING_ENTRIES]; - struct rr_regs __iomem *regs; /* Register base */ - struct ring_ctrl *rx_ctrl; /* Receive ring control */ - struct rr_info *info; /* Shared info page */ - dma_addr_t rx_ctrl_dma; - dma_addr_t info_dma; - spinlock_t lock; - struct timer_list timer; - u32 cur_rx, cur_cmd, cur_evt; - u32 dirty_rx, dirty_tx; - u32 tx_full; - u32 fw_rev; - volatile short fw_running; - struct pci_dev *pci_dev; -}; - - -/* - * Prototypes - */ -static int rr_init(struct net_device *dev); -static int rr_init1(struct net_device *dev); -static irqreturn_t rr_interrupt(int irq, void *dev_id); - -static int rr_open(struct net_device *dev); -static netdev_tx_t rr_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static int rr_close(struct net_device *dev); -static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static unsigned int rr_read_eeprom(struct rr_private *rrpriv, - unsigned long offset, - unsigned char *buf, - unsigned long length); -static u32 rr_read_eeprom_word(struct rr_private *rrpriv, size_t offset); -static int rr_load_firmware(struct net_device *dev); -static inline void rr_raz_tx(struct rr_private *, struct net_device *); -static inline void rr_raz_rx(struct rr_private *, struct net_device *); -#endif /* _RRUNNER_H_ */ -- cgit v0.10.2 From 18e635f4b3e1e1b43cb239321f6120918ba38d46 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Wed, 3 Aug 2011 03:01:58 -0700 Subject: plip: Move the PLIP driver Move the Parallel Line Internet Protocol (PLIP) driver into drivers/net/plip/ and make the necessary Kconfig and Makefile changes. CC: Niibe Yutaka Signed-off-by: Jeff Kirsher Acked-by: Alan Cox diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 1d8fa95..3f72686 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -197,6 +197,8 @@ source "drivers/net/ethernet/Kconfig" source "drivers/net/fddi/Kconfig" +source "drivers/net/plip/Kconfig" + source "drivers/net/tokenring/Kconfig" source "drivers/net/wireless/Kconfig" @@ -272,41 +274,6 @@ config RIONET_RX_SIZE depends on RIONET default "128" -config PLIP - tristate "PLIP (parallel port) support" - depends on PARPORT - ---help--- - PLIP (Parallel Line Internet Protocol) is used to create a - reasonably fast mini network consisting of two (or, rarely, more) - local machines. A PLIP link from a Linux box is a popular means to - install a Linux distribution on a machine which doesn't have a - CD-ROM drive (a minimal system has to be transferred with floppies - first). The kernels on both machines need to have this PLIP option - enabled for this to work. - - The PLIP driver has two modes, mode 0 and mode 1. The parallel - ports (the connectors at the computers with 25 holes) are connected - with "null printer" or "Turbo Laplink" cables which can transmit 4 - bits at a time (mode 0) or with special PLIP cables, to be used on - bidirectional parallel ports only, which can transmit 8 bits at a - time (mode 1); you can find the wiring of these cables in - . The cables can be up to - 15m long. Mode 0 works also if one of the machines runs DOS/Windows - and has some PLIP software installed, e.g. the Crynwr PLIP packet - driver () - and winsock or NCSA's telnet. - - If you want to use PLIP, say Y and read the PLIP mini-HOWTO as well - as the NET-3-HOWTO, both available from - . Note that the PLIP - protocol has been changed and this PLIP driver won't work together - with the PLIP support in Linux versions 1.0.x. This option enlarges - your kernel by about 8 KB. - - To compile this driver as a module, choose M here. The module - will be called plip. If unsure, say Y or M, in case you buy - a laptop later. - config SLIP tristate "SLIP (serial line) support" ---help--- diff --git a/drivers/net/Makefile b/drivers/net/Makefile index f64d02c..52dae95 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -12,7 +12,6 @@ obj-$(CONFIG_VMXNET3) += vmxnet3/ # # link order important here # -obj-$(CONFIG_PLIP) += plip.o obj-$(CONFIG_RIONET) += rionet.o # @@ -39,6 +38,7 @@ obj-$(CONFIG_DEV_APPLETALK) += appletalk/ obj-$(CONFIG_ETHERNET) += ethernet/ obj-$(CONFIG_FDDI) += fddi/ obj-$(CONFIG_HIPPI) += hippi/ +obj-$(CONFIG_PLIP) += plip/ onj-$(CONFIG_PPP) += ppp/ obj-$(CONFIG_PPP_ASYNC) += ppp/ obj-$(CONFIG_PPP_BSDCOMP) += ppp/ diff --git a/drivers/net/plip.c b/drivers/net/plip.c deleted file mode 100644 index a9e9ca8..0000000 --- a/drivers/net/plip.c +++ /dev/null @@ -1,1403 +0,0 @@ -/* $Id: plip.c,v 1.3.6.2 1997/04/16 15:07:56 phil Exp $ */ -/* PLIP: A parallel port "network" driver for Linux. */ -/* This driver is for parallel port with 5-bit cable (LapLink (R) cable). */ -/* - * Authors: Donald Becker - * Tommy Thorn - * Tanabe Hiroyasu - * Alan Cox - * Peter Bauer <100136.3530@compuserve.com> - * Niibe Yutaka - * Nimrod Zimerman - * - * Enhancements: - * Modularization and ifreq/ifmap support by Alan Cox. - * Rewritten by Niibe Yutaka. - * parport-sharing awareness code by Philip Blundell. - * SMP locking by Niibe Yutaka. - * Support for parallel ports with no IRQ (poll mode), - * Modifications to use the parallel port API - * by Nimrod Zimerman. - * - * Fixes: - * Niibe Yutaka - * - Module initialization. - * - MTU fix. - * - Make sure other end is OK, before sending a packet. - * - Fix immediate timer problem. - * - * Al Viro - * - Changed {enable,disable}_irq handling to make it work - * with new ("stack") semantics. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* - * Original version and the name 'PLIP' from Donald Becker - * inspired by Russ Nelson's parallel port packet driver. - * - * NOTE: - * Tanabe Hiroyasu had changed the protocol, and it was in Linux v1.0. - * Because of the necessity to communicate to DOS machines with the - * Crynwr packet driver, Peter Bauer changed the protocol again - * back to original protocol. - * - * This version follows original PLIP protocol. - * So, this PLIP can't communicate the PLIP of Linux v1.0. - */ - -/* - * To use with DOS box, please do (Turn on ARP switch): - * # ifconfig plip[0-2] arp - */ -static const char version[] = "NET3 PLIP version 2.4-parport gniibe@mri.co.jp\n"; - -/* - Sources: - Ideas and protocols came from Russ Nelson's - "parallel.asm" parallel port packet driver. - - The "Crynwr" parallel port standard specifies the following protocol: - Trigger by sending nibble '0x8' (this causes interrupt on other end) - count-low octet - count-high octet - ... data octets - checksum octet - Each octet is sent as - >4)&0x0F)> - - The packet is encapsulated as if it were ethernet. - - The cable used is a de facto standard parallel null cable -- sold as - a "LapLink" cable by various places. You'll need a 12-conductor cable to - make one yourself. The wiring is: - SLCTIN 17 - 17 - GROUND 25 - 25 - D0->ERROR 2 - 15 15 - 2 - D1->SLCT 3 - 13 13 - 3 - D2->PAPOUT 4 - 12 12 - 4 - D3->ACK 5 - 10 10 - 5 - D4->BUSY 6 - 11 11 - 6 - Do not connect the other pins. They are - D5,D6,D7 are 7,8,9 - STROBE is 1, FEED is 14, INIT is 16 - extra grounds are 18,19,20,21,22,23,24 -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -/* Maximum number of devices to support. */ -#define PLIP_MAX 8 - -/* Use 0 for production, 1 for verification, >2 for debug */ -#ifndef NET_DEBUG -#define NET_DEBUG 1 -#endif -static const unsigned int net_debug = NET_DEBUG; - -#define ENABLE(irq) if (irq != -1) enable_irq(irq) -#define DISABLE(irq) if (irq != -1) disable_irq(irq) - -/* In micro second */ -#define PLIP_DELAY_UNIT 1 - -/* Connection time out = PLIP_TRIGGER_WAIT * PLIP_DELAY_UNIT usec */ -#define PLIP_TRIGGER_WAIT 500 - -/* Nibble time out = PLIP_NIBBLE_WAIT * PLIP_DELAY_UNIT usec */ -#define PLIP_NIBBLE_WAIT 3000 - -/* Bottom halves */ -static void plip_kick_bh(struct work_struct *work); -static void plip_bh(struct work_struct *work); -static void plip_timer_bh(struct work_struct *work); - -/* Interrupt handler */ -static void plip_interrupt(void *dev_id); - -/* Functions for DEV methods */ -static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev); -static int plip_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, const void *daddr, - const void *saddr, unsigned len); -static int plip_hard_header_cache(const struct neighbour *neigh, - struct hh_cache *hh, __be16 type); -static int plip_open(struct net_device *dev); -static int plip_close(struct net_device *dev); -static int plip_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -static int plip_preempt(void *handle); -static void plip_wakeup(void *handle); - -enum plip_connection_state { - PLIP_CN_NONE=0, - PLIP_CN_RECEIVE, - PLIP_CN_SEND, - PLIP_CN_CLOSING, - PLIP_CN_ERROR -}; - -enum plip_packet_state { - PLIP_PK_DONE=0, - PLIP_PK_TRIGGER, - PLIP_PK_LENGTH_LSB, - PLIP_PK_LENGTH_MSB, - PLIP_PK_DATA, - PLIP_PK_CHECKSUM -}; - -enum plip_nibble_state { - PLIP_NB_BEGIN, - PLIP_NB_1, - PLIP_NB_2, -}; - -struct plip_local { - enum plip_packet_state state; - enum plip_nibble_state nibble; - union { - struct { -#if defined(__LITTLE_ENDIAN) - unsigned char lsb; - unsigned char msb; -#elif defined(__BIG_ENDIAN) - unsigned char msb; - unsigned char lsb; -#else -#error "Please fix the endianness defines in " -#endif - } b; - unsigned short h; - } length; - unsigned short byte; - unsigned char checksum; - unsigned char data; - struct sk_buff *skb; -}; - -struct net_local { - struct net_device *dev; - struct work_struct immediate; - struct delayed_work deferred; - struct delayed_work timer; - struct plip_local snd_data; - struct plip_local rcv_data; - struct pardevice *pardev; - unsigned long trigger; - unsigned long nibble; - enum plip_connection_state connection; - unsigned short timeout_count; - int is_deferred; - int port_owner; - int should_relinquish; - spinlock_t lock; - atomic_t kill_timer; - struct completion killed_timer_cmp; -}; - -static inline void enable_parport_interrupts (struct net_device *dev) -{ - if (dev->irq != -1) - { - struct parport *port = - ((struct net_local *)netdev_priv(dev))->pardev->port; - port->ops->enable_irq (port); - } -} - -static inline void disable_parport_interrupts (struct net_device *dev) -{ - if (dev->irq != -1) - { - struct parport *port = - ((struct net_local *)netdev_priv(dev))->pardev->port; - port->ops->disable_irq (port); - } -} - -static inline void write_data (struct net_device *dev, unsigned char data) -{ - struct parport *port = - ((struct net_local *)netdev_priv(dev))->pardev->port; - - port->ops->write_data (port, data); -} - -static inline unsigned char read_status (struct net_device *dev) -{ - struct parport *port = - ((struct net_local *)netdev_priv(dev))->pardev->port; - - return port->ops->read_status (port); -} - -static const struct header_ops plip_header_ops = { - .create = plip_hard_header, - .cache = plip_hard_header_cache, -}; - -static const struct net_device_ops plip_netdev_ops = { - .ndo_open = plip_open, - .ndo_stop = plip_close, - .ndo_start_xmit = plip_tx_packet, - .ndo_do_ioctl = plip_ioctl, - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -/* Entry point of PLIP driver. - Probe the hardware, and register/initialize the driver. - - PLIP is rather weird, because of the way it interacts with the parport - system. It is _not_ initialised from Space.c. Instead, plip_init() - is called, and that function makes up a "struct net_device" for each port, and - then calls us here. - - */ -static void -plip_init_netdev(struct net_device *dev) -{ - struct net_local *nl = netdev_priv(dev); - - /* Then, override parts of it */ - dev->tx_queue_len = 10; - dev->flags = IFF_POINTOPOINT|IFF_NOARP; - memset(dev->dev_addr, 0xfc, ETH_ALEN); - - dev->netdev_ops = &plip_netdev_ops; - dev->header_ops = &plip_header_ops; - - - nl->port_owner = 0; - - /* Initialize constants */ - nl->trigger = PLIP_TRIGGER_WAIT; - nl->nibble = PLIP_NIBBLE_WAIT; - - /* Initialize task queue structures */ - INIT_WORK(&nl->immediate, plip_bh); - INIT_DELAYED_WORK(&nl->deferred, plip_kick_bh); - - if (dev->irq == -1) - INIT_DELAYED_WORK(&nl->timer, plip_timer_bh); - - spin_lock_init(&nl->lock); -} - -/* Bottom half handler for the delayed request. - This routine is kicked by do_timer(). - Request `plip_bh' to be invoked. */ -static void -plip_kick_bh(struct work_struct *work) -{ - struct net_local *nl = - container_of(work, struct net_local, deferred.work); - - if (nl->is_deferred) - schedule_work(&nl->immediate); -} - -/* Forward declarations of internal routines */ -static int plip_none(struct net_device *, struct net_local *, - struct plip_local *, struct plip_local *); -static int plip_receive_packet(struct net_device *, struct net_local *, - struct plip_local *, struct plip_local *); -static int plip_send_packet(struct net_device *, struct net_local *, - struct plip_local *, struct plip_local *); -static int plip_connection_close(struct net_device *, struct net_local *, - struct plip_local *, struct plip_local *); -static int plip_error(struct net_device *, struct net_local *, - struct plip_local *, struct plip_local *); -static int plip_bh_timeout_error(struct net_device *dev, struct net_local *nl, - struct plip_local *snd, - struct plip_local *rcv, - int error); - -#define OK 0 -#define TIMEOUT 1 -#define ERROR 2 -#define HS_TIMEOUT 3 - -typedef int (*plip_func)(struct net_device *dev, struct net_local *nl, - struct plip_local *snd, struct plip_local *rcv); - -static const plip_func connection_state_table[] = -{ - plip_none, - plip_receive_packet, - plip_send_packet, - plip_connection_close, - plip_error -}; - -/* Bottom half handler of PLIP. */ -static void -plip_bh(struct work_struct *work) -{ - struct net_local *nl = container_of(work, struct net_local, immediate); - struct plip_local *snd = &nl->snd_data; - struct plip_local *rcv = &nl->rcv_data; - plip_func f; - int r; - - nl->is_deferred = 0; - f = connection_state_table[nl->connection]; - if ((r = (*f)(nl->dev, nl, snd, rcv)) != OK && - (r = plip_bh_timeout_error(nl->dev, nl, snd, rcv, r)) != OK) { - nl->is_deferred = 1; - schedule_delayed_work(&nl->deferred, 1); - } -} - -static void -plip_timer_bh(struct work_struct *work) -{ - struct net_local *nl = - container_of(work, struct net_local, timer.work); - - if (!(atomic_read (&nl->kill_timer))) { - plip_interrupt (nl->dev); - - schedule_delayed_work(&nl->timer, 1); - } - else { - complete(&nl->killed_timer_cmp); - } -} - -static int -plip_bh_timeout_error(struct net_device *dev, struct net_local *nl, - struct plip_local *snd, struct plip_local *rcv, - int error) -{ - unsigned char c0; - /* - * This is tricky. If we got here from the beginning of send (either - * with ERROR or HS_TIMEOUT) we have IRQ enabled. Otherwise it's - * already disabled. With the old variant of {enable,disable}_irq() - * extra disable_irq() was a no-op. Now it became mortal - it's - * unbalanced and thus we'll never re-enable IRQ (until rmmod plip, - * that is). So we have to treat HS_TIMEOUT and ERROR from send - * in a special way. - */ - - spin_lock_irq(&nl->lock); - if (nl->connection == PLIP_CN_SEND) { - - if (error != ERROR) { /* Timeout */ - nl->timeout_count++; - if ((error == HS_TIMEOUT && nl->timeout_count <= 10) || - nl->timeout_count <= 3) { - spin_unlock_irq(&nl->lock); - /* Try again later */ - return TIMEOUT; - } - c0 = read_status(dev); - printk(KERN_WARNING "%s: transmit timeout(%d,%02x)\n", - dev->name, snd->state, c0); - } else - error = HS_TIMEOUT; - dev->stats.tx_errors++; - dev->stats.tx_aborted_errors++; - } else if (nl->connection == PLIP_CN_RECEIVE) { - if (rcv->state == PLIP_PK_TRIGGER) { - /* Transmission was interrupted. */ - spin_unlock_irq(&nl->lock); - return OK; - } - if (error != ERROR) { /* Timeout */ - if (++nl->timeout_count <= 3) { - spin_unlock_irq(&nl->lock); - /* Try again later */ - return TIMEOUT; - } - c0 = read_status(dev); - printk(KERN_WARNING "%s: receive timeout(%d,%02x)\n", - dev->name, rcv->state, c0); - } - dev->stats.rx_dropped++; - } - rcv->state = PLIP_PK_DONE; - if (rcv->skb) { - kfree_skb(rcv->skb); - rcv->skb = NULL; - } - snd->state = PLIP_PK_DONE; - if (snd->skb) { - dev_kfree_skb(snd->skb); - snd->skb = NULL; - } - spin_unlock_irq(&nl->lock); - if (error == HS_TIMEOUT) { - DISABLE(dev->irq); - synchronize_irq(dev->irq); - } - disable_parport_interrupts (dev); - netif_stop_queue (dev); - nl->connection = PLIP_CN_ERROR; - write_data (dev, 0x00); - - return TIMEOUT; -} - -static int -plip_none(struct net_device *dev, struct net_local *nl, - struct plip_local *snd, struct plip_local *rcv) -{ - return OK; -} - -/* PLIP_RECEIVE --- receive a byte(two nibbles) - Returns OK on success, TIMEOUT on timeout */ -static inline int -plip_receive(unsigned short nibble_timeout, struct net_device *dev, - enum plip_nibble_state *ns_p, unsigned char *data_p) -{ - unsigned char c0, c1; - unsigned int cx; - - switch (*ns_p) { - case PLIP_NB_BEGIN: - cx = nibble_timeout; - while (1) { - c0 = read_status(dev); - udelay(PLIP_DELAY_UNIT); - if ((c0 & 0x80) == 0) { - c1 = read_status(dev); - if (c0 == c1) - break; - } - if (--cx == 0) - return TIMEOUT; - } - *data_p = (c0 >> 3) & 0x0f; - write_data (dev, 0x10); /* send ACK */ - *ns_p = PLIP_NB_1; - - case PLIP_NB_1: - cx = nibble_timeout; - while (1) { - c0 = read_status(dev); - udelay(PLIP_DELAY_UNIT); - if (c0 & 0x80) { - c1 = read_status(dev); - if (c0 == c1) - break; - } - if (--cx == 0) - return TIMEOUT; - } - *data_p |= (c0 << 1) & 0xf0; - write_data (dev, 0x00); /* send ACK */ - *ns_p = PLIP_NB_BEGIN; - case PLIP_NB_2: - break; - } - return OK; -} - -/* - * Determine the packet's protocol ID. The rule here is that we - * assume 802.3 if the type field is short enough to be a length. - * This is normal practice and works for any 'now in use' protocol. - * - * PLIP is ethernet ish but the daddr might not be valid if unicast. - * PLIP fortunately has no bus architecture (its Point-to-point). - * - * We can't fix the daddr thing as that quirk (more bug) is embedded - * in far too many old systems not all even running Linux. - */ - -static __be16 plip_type_trans(struct sk_buff *skb, struct net_device *dev) -{ - struct ethhdr *eth; - unsigned char *rawp; - - skb_reset_mac_header(skb); - skb_pull(skb,dev->hard_header_len); - eth = eth_hdr(skb); - - if(*eth->h_dest&1) - { - if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) - skb->pkt_type=PACKET_BROADCAST; - else - skb->pkt_type=PACKET_MULTICAST; - } - - /* - * This ALLMULTI check should be redundant by 1.4 - * so don't forget to remove it. - */ - - if (ntohs(eth->h_proto) >= 1536) - return eth->h_proto; - - rawp = skb->data; - - /* - * This is a magic hack to spot IPX packets. Older Novell breaks - * the protocol design and runs IPX over 802.3 without an 802.2 LLC - * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This - * won't work for fault tolerant netware but does for the rest. - */ - if (*(unsigned short *)rawp == 0xFFFF) - return htons(ETH_P_802_3); - - /* - * Real 802.2 LLC - */ - return htons(ETH_P_802_2); -} - -/* PLIP_RECEIVE_PACKET --- receive a packet */ -static int -plip_receive_packet(struct net_device *dev, struct net_local *nl, - struct plip_local *snd, struct plip_local *rcv) -{ - unsigned short nibble_timeout = nl->nibble; - unsigned char *lbuf; - - switch (rcv->state) { - case PLIP_PK_TRIGGER: - DISABLE(dev->irq); - /* Don't need to synchronize irq, as we can safely ignore it */ - disable_parport_interrupts (dev); - write_data (dev, 0x01); /* send ACK */ - if (net_debug > 2) - printk(KERN_DEBUG "%s: receive start\n", dev->name); - rcv->state = PLIP_PK_LENGTH_LSB; - rcv->nibble = PLIP_NB_BEGIN; - - case PLIP_PK_LENGTH_LSB: - if (snd->state != PLIP_PK_DONE) { - if (plip_receive(nl->trigger, dev, - &rcv->nibble, &rcv->length.b.lsb)) { - /* collision, here dev->tbusy == 1 */ - rcv->state = PLIP_PK_DONE; - nl->is_deferred = 1; - nl->connection = PLIP_CN_SEND; - schedule_delayed_work(&nl->deferred, 1); - enable_parport_interrupts (dev); - ENABLE(dev->irq); - return OK; - } - } else { - if (plip_receive(nibble_timeout, dev, - &rcv->nibble, &rcv->length.b.lsb)) - return TIMEOUT; - } - rcv->state = PLIP_PK_LENGTH_MSB; - - case PLIP_PK_LENGTH_MSB: - if (plip_receive(nibble_timeout, dev, - &rcv->nibble, &rcv->length.b.msb)) - return TIMEOUT; - if (rcv->length.h > dev->mtu + dev->hard_header_len || - rcv->length.h < 8) { - printk(KERN_WARNING "%s: bogus packet size %d.\n", dev->name, rcv->length.h); - return ERROR; - } - /* Malloc up new buffer. */ - rcv->skb = dev_alloc_skb(rcv->length.h + 2); - if (rcv->skb == NULL) { - printk(KERN_ERR "%s: Memory squeeze.\n", dev->name); - return ERROR; - } - skb_reserve(rcv->skb, 2); /* Align IP on 16 byte boundaries */ - skb_put(rcv->skb,rcv->length.h); - rcv->skb->dev = dev; - rcv->state = PLIP_PK_DATA; - rcv->byte = 0; - rcv->checksum = 0; - - case PLIP_PK_DATA: - lbuf = rcv->skb->data; - do { - if (plip_receive(nibble_timeout, dev, - &rcv->nibble, &lbuf[rcv->byte])) - return TIMEOUT; - } while (++rcv->byte < rcv->length.h); - do { - rcv->checksum += lbuf[--rcv->byte]; - } while (rcv->byte); - rcv->state = PLIP_PK_CHECKSUM; - - case PLIP_PK_CHECKSUM: - if (plip_receive(nibble_timeout, dev, - &rcv->nibble, &rcv->data)) - return TIMEOUT; - if (rcv->data != rcv->checksum) { - dev->stats.rx_crc_errors++; - if (net_debug) - printk(KERN_DEBUG "%s: checksum error\n", dev->name); - return ERROR; - } - rcv->state = PLIP_PK_DONE; - - case PLIP_PK_DONE: - /* Inform the upper layer for the arrival of a packet. */ - rcv->skb->protocol=plip_type_trans(rcv->skb, dev); - netif_rx_ni(rcv->skb); - dev->stats.rx_bytes += rcv->length.h; - dev->stats.rx_packets++; - rcv->skb = NULL; - if (net_debug > 2) - printk(KERN_DEBUG "%s: receive end\n", dev->name); - - /* Close the connection. */ - write_data (dev, 0x00); - spin_lock_irq(&nl->lock); - if (snd->state != PLIP_PK_DONE) { - nl->connection = PLIP_CN_SEND; - spin_unlock_irq(&nl->lock); - schedule_work(&nl->immediate); - enable_parport_interrupts (dev); - ENABLE(dev->irq); - return OK; - } else { - nl->connection = PLIP_CN_NONE; - spin_unlock_irq(&nl->lock); - enable_parport_interrupts (dev); - ENABLE(dev->irq); - return OK; - } - } - return OK; -} - -/* PLIP_SEND --- send a byte (two nibbles) - Returns OK on success, TIMEOUT when timeout */ -static inline int -plip_send(unsigned short nibble_timeout, struct net_device *dev, - enum plip_nibble_state *ns_p, unsigned char data) -{ - unsigned char c0; - unsigned int cx; - - switch (*ns_p) { - case PLIP_NB_BEGIN: - write_data (dev, data & 0x0f); - *ns_p = PLIP_NB_1; - - case PLIP_NB_1: - write_data (dev, 0x10 | (data & 0x0f)); - cx = nibble_timeout; - while (1) { - c0 = read_status(dev); - if ((c0 & 0x80) == 0) - break; - if (--cx == 0) - return TIMEOUT; - udelay(PLIP_DELAY_UNIT); - } - write_data (dev, 0x10 | (data >> 4)); - *ns_p = PLIP_NB_2; - - case PLIP_NB_2: - write_data (dev, (data >> 4)); - cx = nibble_timeout; - while (1) { - c0 = read_status(dev); - if (c0 & 0x80) - break; - if (--cx == 0) - return TIMEOUT; - udelay(PLIP_DELAY_UNIT); - } - *ns_p = PLIP_NB_BEGIN; - return OK; - } - return OK; -} - -/* PLIP_SEND_PACKET --- send a packet */ -static int -plip_send_packet(struct net_device *dev, struct net_local *nl, - struct plip_local *snd, struct plip_local *rcv) -{ - unsigned short nibble_timeout = nl->nibble; - unsigned char *lbuf; - unsigned char c0; - unsigned int cx; - - if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) { - printk(KERN_DEBUG "%s: send skb lost\n", dev->name); - snd->state = PLIP_PK_DONE; - snd->skb = NULL; - return ERROR; - } - - switch (snd->state) { - case PLIP_PK_TRIGGER: - if ((read_status(dev) & 0xf8) != 0x80) - return HS_TIMEOUT; - - /* Trigger remote rx interrupt. */ - write_data (dev, 0x08); - cx = nl->trigger; - while (1) { - udelay(PLIP_DELAY_UNIT); - spin_lock_irq(&nl->lock); - if (nl->connection == PLIP_CN_RECEIVE) { - spin_unlock_irq(&nl->lock); - /* Interrupted. */ - dev->stats.collisions++; - return OK; - } - c0 = read_status(dev); - if (c0 & 0x08) { - spin_unlock_irq(&nl->lock); - DISABLE(dev->irq); - synchronize_irq(dev->irq); - if (nl->connection == PLIP_CN_RECEIVE) { - /* Interrupted. - We don't need to enable irq, - as it is soon disabled. */ - /* Yes, we do. New variant of - {enable,disable}_irq *counts* - them. -- AV */ - ENABLE(dev->irq); - dev->stats.collisions++; - return OK; - } - disable_parport_interrupts (dev); - if (net_debug > 2) - printk(KERN_DEBUG "%s: send start\n", dev->name); - snd->state = PLIP_PK_LENGTH_LSB; - snd->nibble = PLIP_NB_BEGIN; - nl->timeout_count = 0; - break; - } - spin_unlock_irq(&nl->lock); - if (--cx == 0) { - write_data (dev, 0x00); - return HS_TIMEOUT; - } - } - - case PLIP_PK_LENGTH_LSB: - if (plip_send(nibble_timeout, dev, - &snd->nibble, snd->length.b.lsb)) - return TIMEOUT; - snd->state = PLIP_PK_LENGTH_MSB; - - case PLIP_PK_LENGTH_MSB: - if (plip_send(nibble_timeout, dev, - &snd->nibble, snd->length.b.msb)) - return TIMEOUT; - snd->state = PLIP_PK_DATA; - snd->byte = 0; - snd->checksum = 0; - - case PLIP_PK_DATA: - do { - if (plip_send(nibble_timeout, dev, - &snd->nibble, lbuf[snd->byte])) - return TIMEOUT; - } while (++snd->byte < snd->length.h); - do { - snd->checksum += lbuf[--snd->byte]; - } while (snd->byte); - snd->state = PLIP_PK_CHECKSUM; - - case PLIP_PK_CHECKSUM: - if (plip_send(nibble_timeout, dev, - &snd->nibble, snd->checksum)) - return TIMEOUT; - - dev->stats.tx_bytes += snd->skb->len; - dev_kfree_skb(snd->skb); - dev->stats.tx_packets++; - snd->state = PLIP_PK_DONE; - - case PLIP_PK_DONE: - /* Close the connection */ - write_data (dev, 0x00); - snd->skb = NULL; - if (net_debug > 2) - printk(KERN_DEBUG "%s: send end\n", dev->name); - nl->connection = PLIP_CN_CLOSING; - nl->is_deferred = 1; - schedule_delayed_work(&nl->deferred, 1); - enable_parport_interrupts (dev); - ENABLE(dev->irq); - return OK; - } - return OK; -} - -static int -plip_connection_close(struct net_device *dev, struct net_local *nl, - struct plip_local *snd, struct plip_local *rcv) -{ - spin_lock_irq(&nl->lock); - if (nl->connection == PLIP_CN_CLOSING) { - nl->connection = PLIP_CN_NONE; - netif_wake_queue (dev); - } - spin_unlock_irq(&nl->lock); - if (nl->should_relinquish) { - nl->should_relinquish = nl->port_owner = 0; - parport_release(nl->pardev); - } - return OK; -} - -/* PLIP_ERROR --- wait till other end settled */ -static int -plip_error(struct net_device *dev, struct net_local *nl, - struct plip_local *snd, struct plip_local *rcv) -{ - unsigned char status; - - status = read_status(dev); - if ((status & 0xf8) == 0x80) { - if (net_debug > 2) - printk(KERN_DEBUG "%s: reset interface.\n", dev->name); - nl->connection = PLIP_CN_NONE; - nl->should_relinquish = 0; - netif_start_queue (dev); - enable_parport_interrupts (dev); - ENABLE(dev->irq); - netif_wake_queue (dev); - } else { - nl->is_deferred = 1; - schedule_delayed_work(&nl->deferred, 1); - } - - return OK; -} - -/* Handle the parallel port interrupts. */ -static void -plip_interrupt(void *dev_id) -{ - struct net_device *dev = dev_id; - struct net_local *nl; - struct plip_local *rcv; - unsigned char c0; - unsigned long flags; - - nl = netdev_priv(dev); - rcv = &nl->rcv_data; - - spin_lock_irqsave (&nl->lock, flags); - - c0 = read_status(dev); - if ((c0 & 0xf8) != 0xc0) { - if ((dev->irq != -1) && (net_debug > 1)) - printk(KERN_DEBUG "%s: spurious interrupt\n", dev->name); - spin_unlock_irqrestore (&nl->lock, flags); - return; - } - - if (net_debug > 3) - printk(KERN_DEBUG "%s: interrupt.\n", dev->name); - - switch (nl->connection) { - case PLIP_CN_CLOSING: - netif_wake_queue (dev); - case PLIP_CN_NONE: - case PLIP_CN_SEND: - rcv->state = PLIP_PK_TRIGGER; - nl->connection = PLIP_CN_RECEIVE; - nl->timeout_count = 0; - schedule_work(&nl->immediate); - break; - - case PLIP_CN_RECEIVE: - /* May occur because there is race condition - around test and set of dev->interrupt. - Ignore this interrupt. */ - break; - - case PLIP_CN_ERROR: - printk(KERN_ERR "%s: receive interrupt in error state\n", dev->name); - break; - } - - spin_unlock_irqrestore(&nl->lock, flags); -} - -static int -plip_tx_packet(struct sk_buff *skb, struct net_device *dev) -{ - struct net_local *nl = netdev_priv(dev); - struct plip_local *snd = &nl->snd_data; - - if (netif_queue_stopped(dev)) - return NETDEV_TX_BUSY; - - /* We may need to grab the bus */ - if (!nl->port_owner) { - if (parport_claim(nl->pardev)) - return NETDEV_TX_BUSY; - nl->port_owner = 1; - } - - netif_stop_queue (dev); - - if (skb->len > dev->mtu + dev->hard_header_len) { - printk(KERN_WARNING "%s: packet too big, %d.\n", dev->name, (int)skb->len); - netif_start_queue (dev); - return NETDEV_TX_BUSY; - } - - if (net_debug > 2) - printk(KERN_DEBUG "%s: send request\n", dev->name); - - spin_lock_irq(&nl->lock); - snd->skb = skb; - snd->length.h = skb->len; - snd->state = PLIP_PK_TRIGGER; - if (nl->connection == PLIP_CN_NONE) { - nl->connection = PLIP_CN_SEND; - nl->timeout_count = 0; - } - schedule_work(&nl->immediate); - spin_unlock_irq(&nl->lock); - - return NETDEV_TX_OK; -} - -static void -plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth) -{ - const struct in_device *in_dev; - - rcu_read_lock(); - in_dev = __in_dev_get_rcu(dev); - if (in_dev) { - /* Any address will do - we take the first */ - const struct in_ifaddr *ifa = in_dev->ifa_list; - if (ifa) { - memcpy(eth->h_source, dev->dev_addr, 6); - memset(eth->h_dest, 0xfc, 2); - memcpy(eth->h_dest+2, &ifa->ifa_address, 4); - } - } - rcu_read_unlock(); -} - -static int -plip_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, const void *daddr, - const void *saddr, unsigned len) -{ - int ret; - - ret = eth_header(skb, dev, type, daddr, saddr, len); - if (ret >= 0) - plip_rewrite_address (dev, (struct ethhdr *)skb->data); - - return ret; -} - -static int plip_hard_header_cache(const struct neighbour *neigh, - struct hh_cache *hh, __be16 type) -{ - int ret; - - ret = eth_header_cache(neigh, hh, type); - if (ret == 0) { - struct ethhdr *eth; - - eth = (struct ethhdr*)(((u8*)hh->hh_data) + - HH_DATA_OFF(sizeof(*eth))); - plip_rewrite_address (neigh->dev, eth); - } - - return ret; -} - -/* Open/initialize the board. This is called (in the current kernel) - sometime after booting when the 'ifconfig' program is run. - - This routine gets exclusive access to the parallel port by allocating - its IRQ line. - */ -static int -plip_open(struct net_device *dev) -{ - struct net_local *nl = netdev_priv(dev); - struct in_device *in_dev; - - /* Grab the port */ - if (!nl->port_owner) { - if (parport_claim(nl->pardev)) return -EAGAIN; - nl->port_owner = 1; - } - - nl->should_relinquish = 0; - - /* Clear the data port. */ - write_data (dev, 0x00); - - /* Enable rx interrupt. */ - enable_parport_interrupts (dev); - if (dev->irq == -1) - { - atomic_set (&nl->kill_timer, 0); - schedule_delayed_work(&nl->timer, 1); - } - - /* Initialize the state machine. */ - nl->rcv_data.state = nl->snd_data.state = PLIP_PK_DONE; - nl->rcv_data.skb = nl->snd_data.skb = NULL; - nl->connection = PLIP_CN_NONE; - nl->is_deferred = 0; - - /* Fill in the MAC-level header. - We used to abuse dev->broadcast to store the point-to-point - MAC address, but we no longer do it. Instead, we fetch the - interface address whenever it is needed, which is cheap enough - because we use the hh_cache. Actually, abusing dev->broadcast - didn't work, because when using plip_open the point-to-point - address isn't yet known. - PLIP doesn't have a real MAC address, but we need it to be - DOS compatible, and to properly support taps (otherwise, - when the device address isn't identical to the address of a - received frame, the kernel incorrectly drops it). */ - - in_dev=__in_dev_get_rtnl(dev); - if (in_dev) { - /* Any address will do - we take the first. We already - have the first two bytes filled with 0xfc, from - plip_init_dev(). */ - struct in_ifaddr *ifa=in_dev->ifa_list; - if (ifa != NULL) { - memcpy(dev->dev_addr+2, &ifa->ifa_local, 4); - } - } - - netif_start_queue (dev); - - return 0; -} - -/* The inverse routine to plip_open (). */ -static int -plip_close(struct net_device *dev) -{ - struct net_local *nl = netdev_priv(dev); - struct plip_local *snd = &nl->snd_data; - struct plip_local *rcv = &nl->rcv_data; - - netif_stop_queue (dev); - DISABLE(dev->irq); - synchronize_irq(dev->irq); - - if (dev->irq == -1) - { - init_completion(&nl->killed_timer_cmp); - atomic_set (&nl->kill_timer, 1); - wait_for_completion(&nl->killed_timer_cmp); - } - -#ifdef NOTDEF - outb(0x00, PAR_DATA(dev)); -#endif - nl->is_deferred = 0; - nl->connection = PLIP_CN_NONE; - if (nl->port_owner) { - parport_release(nl->pardev); - nl->port_owner = 0; - } - - snd->state = PLIP_PK_DONE; - if (snd->skb) { - dev_kfree_skb(snd->skb); - snd->skb = NULL; - } - rcv->state = PLIP_PK_DONE; - if (rcv->skb) { - kfree_skb(rcv->skb); - rcv->skb = NULL; - } - -#ifdef NOTDEF - /* Reset. */ - outb(0x00, PAR_CONTROL(dev)); -#endif - return 0; -} - -static int -plip_preempt(void *handle) -{ - struct net_device *dev = (struct net_device *)handle; - struct net_local *nl = netdev_priv(dev); - - /* Stand our ground if a datagram is on the wire */ - if (nl->connection != PLIP_CN_NONE) { - nl->should_relinquish = 1; - return 1; - } - - nl->port_owner = 0; /* Remember that we released the bus */ - return 0; -} - -static void -plip_wakeup(void *handle) -{ - struct net_device *dev = (struct net_device *)handle; - struct net_local *nl = netdev_priv(dev); - - if (nl->port_owner) { - /* Why are we being woken up? */ - printk(KERN_DEBUG "%s: why am I being woken up?\n", dev->name); - if (!parport_claim(nl->pardev)) - /* bus_owner is already set (but why?) */ - printk(KERN_DEBUG "%s: I'm broken.\n", dev->name); - else - return; - } - - if (!(dev->flags & IFF_UP)) - /* Don't need the port when the interface is down */ - return; - - if (!parport_claim(nl->pardev)) { - nl->port_owner = 1; - /* Clear the data port. */ - write_data (dev, 0x00); - } -} - -static int -plip_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct net_local *nl = netdev_priv(dev); - struct plipconf *pc = (struct plipconf *) &rq->ifr_ifru; - - if (cmd != SIOCDEVPLIP) - return -EOPNOTSUPP; - - switch(pc->pcmd) { - case PLIP_GET_TIMEOUT: - pc->trigger = nl->trigger; - pc->nibble = nl->nibble; - break; - case PLIP_SET_TIMEOUT: - if(!capable(CAP_NET_ADMIN)) - return -EPERM; - nl->trigger = pc->trigger; - nl->nibble = pc->nibble; - break; - default: - return -EOPNOTSUPP; - } - return 0; -} - -static int parport[PLIP_MAX] = { [0 ... PLIP_MAX-1] = -1 }; -static int timid; - -module_param_array(parport, int, NULL, 0); -module_param(timid, int, 0); -MODULE_PARM_DESC(parport, "List of parport device numbers to use by plip"); - -static struct net_device *dev_plip[PLIP_MAX] = { NULL, }; - -static inline int -plip_searchfor(int list[], int a) -{ - int i; - for (i = 0; i < PLIP_MAX && list[i] != -1; i++) { - if (list[i] == a) return 1; - } - return 0; -} - -/* plip_attach() is called (by the parport code) when a port is - * available to use. */ -static void plip_attach (struct parport *port) -{ - static int unit; - struct net_device *dev; - struct net_local *nl; - char name[IFNAMSIZ]; - - if ((parport[0] == -1 && (!timid || !port->devices)) || - plip_searchfor(parport, port->number)) { - if (unit == PLIP_MAX) { - printk(KERN_ERR "plip: too many devices\n"); - return; - } - - sprintf(name, "plip%d", unit); - dev = alloc_etherdev(sizeof(struct net_local)); - if (!dev) { - printk(KERN_ERR "plip: memory squeeze\n"); - return; - } - - strcpy(dev->name, name); - - dev->irq = port->irq; - dev->base_addr = port->base; - if (port->irq == -1) { - printk(KERN_INFO "plip: %s has no IRQ. Using IRQ-less mode," - "which is fairly inefficient!\n", port->name); - } - - nl = netdev_priv(dev); - nl->dev = dev; - nl->pardev = parport_register_device(port, dev->name, plip_preempt, - plip_wakeup, plip_interrupt, - 0, dev); - - if (!nl->pardev) { - printk(KERN_ERR "%s: parport_register failed\n", name); - goto err_free_dev; - } - - plip_init_netdev(dev); - - if (register_netdev(dev)) { - printk(KERN_ERR "%s: network register failed\n", name); - goto err_parport_unregister; - } - - printk(KERN_INFO "%s", version); - if (dev->irq != -1) - printk(KERN_INFO "%s: Parallel port at %#3lx, " - "using IRQ %d.\n", - dev->name, dev->base_addr, dev->irq); - else - printk(KERN_INFO "%s: Parallel port at %#3lx, " - "not using IRQ.\n", - dev->name, dev->base_addr); - dev_plip[unit++] = dev; - } - return; - -err_parport_unregister: - parport_unregister_device(nl->pardev); -err_free_dev: - free_netdev(dev); -} - -/* plip_detach() is called (by the parport code) when a port is - * no longer available to use. */ -static void plip_detach (struct parport *port) -{ - /* Nothing to do */ -} - -static struct parport_driver plip_driver = { - .name = "plip", - .attach = plip_attach, - .detach = plip_detach -}; - -static void __exit plip_cleanup_module (void) -{ - struct net_device *dev; - int i; - - parport_unregister_driver (&plip_driver); - - for (i=0; i < PLIP_MAX; i++) { - if ((dev = dev_plip[i])) { - struct net_local *nl = netdev_priv(dev); - unregister_netdev(dev); - if (nl->port_owner) - parport_release(nl->pardev); - parport_unregister_device(nl->pardev); - free_netdev(dev); - dev_plip[i] = NULL; - } - } -} - -#ifndef MODULE - -static int parport_ptr; - -static int __init plip_setup(char *str) -{ - int ints[4]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - /* Ugh. */ - if (!strncmp(str, "parport", 7)) { - int n = simple_strtoul(str+7, NULL, 10); - if (parport_ptr < PLIP_MAX) - parport[parport_ptr++] = n; - else - printk(KERN_INFO "plip: too many ports, %s ignored.\n", - str); - } else if (!strcmp(str, "timid")) { - timid = 1; - } else { - if (ints[0] == 0 || ints[1] == 0) { - /* disable driver on "plip=" or "plip=0" */ - parport[0] = -2; - } else { - printk(KERN_WARNING "warning: 'plip=0x%x' ignored\n", - ints[1]); - } - } - return 1; -} - -__setup("plip=", plip_setup); - -#endif /* !MODULE */ - -static int __init plip_init (void) -{ - if (parport[0] == -2) - return 0; - - if (parport[0] != -1 && timid) { - printk(KERN_WARNING "plip: warning, ignoring `timid' since specific ports given.\n"); - timid = 0; - } - - if (parport_register_driver (&plip_driver)) { - printk (KERN_WARNING "plip: couldn't register driver\n"); - return 1; - } - - return 0; -} - -module_init(plip_init); -module_exit(plip_cleanup_module); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/plip/Kconfig b/drivers/net/plip/Kconfig new file mode 100644 index 0000000..80c4a33 --- /dev/null +++ b/drivers/net/plip/Kconfig @@ -0,0 +1,38 @@ +# +# Parallel Line Internet Protocol (PLIP) network device configuration +# + +config PLIP + tristate "PLIP (parallel port) support" + depends on PARPORT + ---help--- + PLIP (Parallel Line Internet Protocol) is used to create a + reasonably fast mini network consisting of two (or, rarely, more) + local machines. A PLIP link from a Linux box is a popular means to + install a Linux distribution on a machine which doesn't have a + CD-ROM drive (a minimal system has to be transferred with floppies + first). The kernels on both machines need to have this PLIP option + enabled for this to work. + + The PLIP driver has two modes, mode 0 and mode 1. The parallel + ports (the connectors at the computers with 25 holes) are connected + with "null printer" or "Turbo Laplink" cables which can transmit 4 + bits at a time (mode 0) or with special PLIP cables, to be used on + bidirectional parallel ports only, which can transmit 8 bits at a + time (mode 1); you can find the wiring of these cables in + . The cables can be up to + 15m long. Mode 0 works also if one of the machines runs DOS/Windows + and has some PLIP software installed, e.g. the Crynwr PLIP packet + driver () + and winsock or NCSA's telnet. + + If you want to use PLIP, say Y and read the PLIP mini-HOWTO as well + as the NET-3-HOWTO, both available from + . Note that the PLIP + protocol has been changed and this PLIP driver won't work together + with the PLIP support in Linux versions 1.0.x. This option enlarges + your kernel by about 8 KB. + + To compile this driver as a module, choose M here. The module + will be called plip. If unsure, say Y or M, in case you buy + a laptop later. diff --git a/drivers/net/plip/Makefile b/drivers/net/plip/Makefile new file mode 100644 index 0000000..ed95879 --- /dev/null +++ b/drivers/net/plip/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the PLIP network device drivers. +# + +obj-$(CONFIG_PLIP) += plip.o diff --git a/drivers/net/plip/plip.c b/drivers/net/plip/plip.c new file mode 100644 index 0000000..a9e9ca8 --- /dev/null +++ b/drivers/net/plip/plip.c @@ -0,0 +1,1403 @@ +/* $Id: plip.c,v 1.3.6.2 1997/04/16 15:07:56 phil Exp $ */ +/* PLIP: A parallel port "network" driver for Linux. */ +/* This driver is for parallel port with 5-bit cable (LapLink (R) cable). */ +/* + * Authors: Donald Becker + * Tommy Thorn + * Tanabe Hiroyasu + * Alan Cox + * Peter Bauer <100136.3530@compuserve.com> + * Niibe Yutaka + * Nimrod Zimerman + * + * Enhancements: + * Modularization and ifreq/ifmap support by Alan Cox. + * Rewritten by Niibe Yutaka. + * parport-sharing awareness code by Philip Blundell. + * SMP locking by Niibe Yutaka. + * Support for parallel ports with no IRQ (poll mode), + * Modifications to use the parallel port API + * by Nimrod Zimerman. + * + * Fixes: + * Niibe Yutaka + * - Module initialization. + * - MTU fix. + * - Make sure other end is OK, before sending a packet. + * - Fix immediate timer problem. + * + * Al Viro + * - Changed {enable,disable}_irq handling to make it work + * with new ("stack") semantics. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/* + * Original version and the name 'PLIP' from Donald Becker + * inspired by Russ Nelson's parallel port packet driver. + * + * NOTE: + * Tanabe Hiroyasu had changed the protocol, and it was in Linux v1.0. + * Because of the necessity to communicate to DOS machines with the + * Crynwr packet driver, Peter Bauer changed the protocol again + * back to original protocol. + * + * This version follows original PLIP protocol. + * So, this PLIP can't communicate the PLIP of Linux v1.0. + */ + +/* + * To use with DOS box, please do (Turn on ARP switch): + * # ifconfig plip[0-2] arp + */ +static const char version[] = "NET3 PLIP version 2.4-parport gniibe@mri.co.jp\n"; + +/* + Sources: + Ideas and protocols came from Russ Nelson's + "parallel.asm" parallel port packet driver. + + The "Crynwr" parallel port standard specifies the following protocol: + Trigger by sending nibble '0x8' (this causes interrupt on other end) + count-low octet + count-high octet + ... data octets + checksum octet + Each octet is sent as + >4)&0x0F)> + + The packet is encapsulated as if it were ethernet. + + The cable used is a de facto standard parallel null cable -- sold as + a "LapLink" cable by various places. You'll need a 12-conductor cable to + make one yourself. The wiring is: + SLCTIN 17 - 17 + GROUND 25 - 25 + D0->ERROR 2 - 15 15 - 2 + D1->SLCT 3 - 13 13 - 3 + D2->PAPOUT 4 - 12 12 - 4 + D3->ACK 5 - 10 10 - 5 + D4->BUSY 6 - 11 11 - 6 + Do not connect the other pins. They are + D5,D6,D7 are 7,8,9 + STROBE is 1, FEED is 14, INIT is 16 + extra grounds are 18,19,20,21,22,23,24 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +/* Maximum number of devices to support. */ +#define PLIP_MAX 8 + +/* Use 0 for production, 1 for verification, >2 for debug */ +#ifndef NET_DEBUG +#define NET_DEBUG 1 +#endif +static const unsigned int net_debug = NET_DEBUG; + +#define ENABLE(irq) if (irq != -1) enable_irq(irq) +#define DISABLE(irq) if (irq != -1) disable_irq(irq) + +/* In micro second */ +#define PLIP_DELAY_UNIT 1 + +/* Connection time out = PLIP_TRIGGER_WAIT * PLIP_DELAY_UNIT usec */ +#define PLIP_TRIGGER_WAIT 500 + +/* Nibble time out = PLIP_NIBBLE_WAIT * PLIP_DELAY_UNIT usec */ +#define PLIP_NIBBLE_WAIT 3000 + +/* Bottom halves */ +static void plip_kick_bh(struct work_struct *work); +static void plip_bh(struct work_struct *work); +static void plip_timer_bh(struct work_struct *work); + +/* Interrupt handler */ +static void plip_interrupt(void *dev_id); + +/* Functions for DEV methods */ +static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev); +static int plip_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned len); +static int plip_hard_header_cache(const struct neighbour *neigh, + struct hh_cache *hh, __be16 type); +static int plip_open(struct net_device *dev); +static int plip_close(struct net_device *dev); +static int plip_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +static int plip_preempt(void *handle); +static void plip_wakeup(void *handle); + +enum plip_connection_state { + PLIP_CN_NONE=0, + PLIP_CN_RECEIVE, + PLIP_CN_SEND, + PLIP_CN_CLOSING, + PLIP_CN_ERROR +}; + +enum plip_packet_state { + PLIP_PK_DONE=0, + PLIP_PK_TRIGGER, + PLIP_PK_LENGTH_LSB, + PLIP_PK_LENGTH_MSB, + PLIP_PK_DATA, + PLIP_PK_CHECKSUM +}; + +enum plip_nibble_state { + PLIP_NB_BEGIN, + PLIP_NB_1, + PLIP_NB_2, +}; + +struct plip_local { + enum plip_packet_state state; + enum plip_nibble_state nibble; + union { + struct { +#if defined(__LITTLE_ENDIAN) + unsigned char lsb; + unsigned char msb; +#elif defined(__BIG_ENDIAN) + unsigned char msb; + unsigned char lsb; +#else +#error "Please fix the endianness defines in " +#endif + } b; + unsigned short h; + } length; + unsigned short byte; + unsigned char checksum; + unsigned char data; + struct sk_buff *skb; +}; + +struct net_local { + struct net_device *dev; + struct work_struct immediate; + struct delayed_work deferred; + struct delayed_work timer; + struct plip_local snd_data; + struct plip_local rcv_data; + struct pardevice *pardev; + unsigned long trigger; + unsigned long nibble; + enum plip_connection_state connection; + unsigned short timeout_count; + int is_deferred; + int port_owner; + int should_relinquish; + spinlock_t lock; + atomic_t kill_timer; + struct completion killed_timer_cmp; +}; + +static inline void enable_parport_interrupts (struct net_device *dev) +{ + if (dev->irq != -1) + { + struct parport *port = + ((struct net_local *)netdev_priv(dev))->pardev->port; + port->ops->enable_irq (port); + } +} + +static inline void disable_parport_interrupts (struct net_device *dev) +{ + if (dev->irq != -1) + { + struct parport *port = + ((struct net_local *)netdev_priv(dev))->pardev->port; + port->ops->disable_irq (port); + } +} + +static inline void write_data (struct net_device *dev, unsigned char data) +{ + struct parport *port = + ((struct net_local *)netdev_priv(dev))->pardev->port; + + port->ops->write_data (port, data); +} + +static inline unsigned char read_status (struct net_device *dev) +{ + struct parport *port = + ((struct net_local *)netdev_priv(dev))->pardev->port; + + return port->ops->read_status (port); +} + +static const struct header_ops plip_header_ops = { + .create = plip_hard_header, + .cache = plip_hard_header_cache, +}; + +static const struct net_device_ops plip_netdev_ops = { + .ndo_open = plip_open, + .ndo_stop = plip_close, + .ndo_start_xmit = plip_tx_packet, + .ndo_do_ioctl = plip_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + +/* Entry point of PLIP driver. + Probe the hardware, and register/initialize the driver. + + PLIP is rather weird, because of the way it interacts with the parport + system. It is _not_ initialised from Space.c. Instead, plip_init() + is called, and that function makes up a "struct net_device" for each port, and + then calls us here. + + */ +static void +plip_init_netdev(struct net_device *dev) +{ + struct net_local *nl = netdev_priv(dev); + + /* Then, override parts of it */ + dev->tx_queue_len = 10; + dev->flags = IFF_POINTOPOINT|IFF_NOARP; + memset(dev->dev_addr, 0xfc, ETH_ALEN); + + dev->netdev_ops = &plip_netdev_ops; + dev->header_ops = &plip_header_ops; + + + nl->port_owner = 0; + + /* Initialize constants */ + nl->trigger = PLIP_TRIGGER_WAIT; + nl->nibble = PLIP_NIBBLE_WAIT; + + /* Initialize task queue structures */ + INIT_WORK(&nl->immediate, plip_bh); + INIT_DELAYED_WORK(&nl->deferred, plip_kick_bh); + + if (dev->irq == -1) + INIT_DELAYED_WORK(&nl->timer, plip_timer_bh); + + spin_lock_init(&nl->lock); +} + +/* Bottom half handler for the delayed request. + This routine is kicked by do_timer(). + Request `plip_bh' to be invoked. */ +static void +plip_kick_bh(struct work_struct *work) +{ + struct net_local *nl = + container_of(work, struct net_local, deferred.work); + + if (nl->is_deferred) + schedule_work(&nl->immediate); +} + +/* Forward declarations of internal routines */ +static int plip_none(struct net_device *, struct net_local *, + struct plip_local *, struct plip_local *); +static int plip_receive_packet(struct net_device *, struct net_local *, + struct plip_local *, struct plip_local *); +static int plip_send_packet(struct net_device *, struct net_local *, + struct plip_local *, struct plip_local *); +static int plip_connection_close(struct net_device *, struct net_local *, + struct plip_local *, struct plip_local *); +static int plip_error(struct net_device *, struct net_local *, + struct plip_local *, struct plip_local *); +static int plip_bh_timeout_error(struct net_device *dev, struct net_local *nl, + struct plip_local *snd, + struct plip_local *rcv, + int error); + +#define OK 0 +#define TIMEOUT 1 +#define ERROR 2 +#define HS_TIMEOUT 3 + +typedef int (*plip_func)(struct net_device *dev, struct net_local *nl, + struct plip_local *snd, struct plip_local *rcv); + +static const plip_func connection_state_table[] = +{ + plip_none, + plip_receive_packet, + plip_send_packet, + plip_connection_close, + plip_error +}; + +/* Bottom half handler of PLIP. */ +static void +plip_bh(struct work_struct *work) +{ + struct net_local *nl = container_of(work, struct net_local, immediate); + struct plip_local *snd = &nl->snd_data; + struct plip_local *rcv = &nl->rcv_data; + plip_func f; + int r; + + nl->is_deferred = 0; + f = connection_state_table[nl->connection]; + if ((r = (*f)(nl->dev, nl, snd, rcv)) != OK && + (r = plip_bh_timeout_error(nl->dev, nl, snd, rcv, r)) != OK) { + nl->is_deferred = 1; + schedule_delayed_work(&nl->deferred, 1); + } +} + +static void +plip_timer_bh(struct work_struct *work) +{ + struct net_local *nl = + container_of(work, struct net_local, timer.work); + + if (!(atomic_read (&nl->kill_timer))) { + plip_interrupt (nl->dev); + + schedule_delayed_work(&nl->timer, 1); + } + else { + complete(&nl->killed_timer_cmp); + } +} + +static int +plip_bh_timeout_error(struct net_device *dev, struct net_local *nl, + struct plip_local *snd, struct plip_local *rcv, + int error) +{ + unsigned char c0; + /* + * This is tricky. If we got here from the beginning of send (either + * with ERROR or HS_TIMEOUT) we have IRQ enabled. Otherwise it's + * already disabled. With the old variant of {enable,disable}_irq() + * extra disable_irq() was a no-op. Now it became mortal - it's + * unbalanced and thus we'll never re-enable IRQ (until rmmod plip, + * that is). So we have to treat HS_TIMEOUT and ERROR from send + * in a special way. + */ + + spin_lock_irq(&nl->lock); + if (nl->connection == PLIP_CN_SEND) { + + if (error != ERROR) { /* Timeout */ + nl->timeout_count++; + if ((error == HS_TIMEOUT && nl->timeout_count <= 10) || + nl->timeout_count <= 3) { + spin_unlock_irq(&nl->lock); + /* Try again later */ + return TIMEOUT; + } + c0 = read_status(dev); + printk(KERN_WARNING "%s: transmit timeout(%d,%02x)\n", + dev->name, snd->state, c0); + } else + error = HS_TIMEOUT; + dev->stats.tx_errors++; + dev->stats.tx_aborted_errors++; + } else if (nl->connection == PLIP_CN_RECEIVE) { + if (rcv->state == PLIP_PK_TRIGGER) { + /* Transmission was interrupted. */ + spin_unlock_irq(&nl->lock); + return OK; + } + if (error != ERROR) { /* Timeout */ + if (++nl->timeout_count <= 3) { + spin_unlock_irq(&nl->lock); + /* Try again later */ + return TIMEOUT; + } + c0 = read_status(dev); + printk(KERN_WARNING "%s: receive timeout(%d,%02x)\n", + dev->name, rcv->state, c0); + } + dev->stats.rx_dropped++; + } + rcv->state = PLIP_PK_DONE; + if (rcv->skb) { + kfree_skb(rcv->skb); + rcv->skb = NULL; + } + snd->state = PLIP_PK_DONE; + if (snd->skb) { + dev_kfree_skb(snd->skb); + snd->skb = NULL; + } + spin_unlock_irq(&nl->lock); + if (error == HS_TIMEOUT) { + DISABLE(dev->irq); + synchronize_irq(dev->irq); + } + disable_parport_interrupts (dev); + netif_stop_queue (dev); + nl->connection = PLIP_CN_ERROR; + write_data (dev, 0x00); + + return TIMEOUT; +} + +static int +plip_none(struct net_device *dev, struct net_local *nl, + struct plip_local *snd, struct plip_local *rcv) +{ + return OK; +} + +/* PLIP_RECEIVE --- receive a byte(two nibbles) + Returns OK on success, TIMEOUT on timeout */ +static inline int +plip_receive(unsigned short nibble_timeout, struct net_device *dev, + enum plip_nibble_state *ns_p, unsigned char *data_p) +{ + unsigned char c0, c1; + unsigned int cx; + + switch (*ns_p) { + case PLIP_NB_BEGIN: + cx = nibble_timeout; + while (1) { + c0 = read_status(dev); + udelay(PLIP_DELAY_UNIT); + if ((c0 & 0x80) == 0) { + c1 = read_status(dev); + if (c0 == c1) + break; + } + if (--cx == 0) + return TIMEOUT; + } + *data_p = (c0 >> 3) & 0x0f; + write_data (dev, 0x10); /* send ACK */ + *ns_p = PLIP_NB_1; + + case PLIP_NB_1: + cx = nibble_timeout; + while (1) { + c0 = read_status(dev); + udelay(PLIP_DELAY_UNIT); + if (c0 & 0x80) { + c1 = read_status(dev); + if (c0 == c1) + break; + } + if (--cx == 0) + return TIMEOUT; + } + *data_p |= (c0 << 1) & 0xf0; + write_data (dev, 0x00); /* send ACK */ + *ns_p = PLIP_NB_BEGIN; + case PLIP_NB_2: + break; + } + return OK; +} + +/* + * Determine the packet's protocol ID. The rule here is that we + * assume 802.3 if the type field is short enough to be a length. + * This is normal practice and works for any 'now in use' protocol. + * + * PLIP is ethernet ish but the daddr might not be valid if unicast. + * PLIP fortunately has no bus architecture (its Point-to-point). + * + * We can't fix the daddr thing as that quirk (more bug) is embedded + * in far too many old systems not all even running Linux. + */ + +static __be16 plip_type_trans(struct sk_buff *skb, struct net_device *dev) +{ + struct ethhdr *eth; + unsigned char *rawp; + + skb_reset_mac_header(skb); + skb_pull(skb,dev->hard_header_len); + eth = eth_hdr(skb); + + if(*eth->h_dest&1) + { + if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) + skb->pkt_type=PACKET_BROADCAST; + else + skb->pkt_type=PACKET_MULTICAST; + } + + /* + * This ALLMULTI check should be redundant by 1.4 + * so don't forget to remove it. + */ + + if (ntohs(eth->h_proto) >= 1536) + return eth->h_proto; + + rawp = skb->data; + + /* + * This is a magic hack to spot IPX packets. Older Novell breaks + * the protocol design and runs IPX over 802.3 without an 802.2 LLC + * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This + * won't work for fault tolerant netware but does for the rest. + */ + if (*(unsigned short *)rawp == 0xFFFF) + return htons(ETH_P_802_3); + + /* + * Real 802.2 LLC + */ + return htons(ETH_P_802_2); +} + +/* PLIP_RECEIVE_PACKET --- receive a packet */ +static int +plip_receive_packet(struct net_device *dev, struct net_local *nl, + struct plip_local *snd, struct plip_local *rcv) +{ + unsigned short nibble_timeout = nl->nibble; + unsigned char *lbuf; + + switch (rcv->state) { + case PLIP_PK_TRIGGER: + DISABLE(dev->irq); + /* Don't need to synchronize irq, as we can safely ignore it */ + disable_parport_interrupts (dev); + write_data (dev, 0x01); /* send ACK */ + if (net_debug > 2) + printk(KERN_DEBUG "%s: receive start\n", dev->name); + rcv->state = PLIP_PK_LENGTH_LSB; + rcv->nibble = PLIP_NB_BEGIN; + + case PLIP_PK_LENGTH_LSB: + if (snd->state != PLIP_PK_DONE) { + if (plip_receive(nl->trigger, dev, + &rcv->nibble, &rcv->length.b.lsb)) { + /* collision, here dev->tbusy == 1 */ + rcv->state = PLIP_PK_DONE; + nl->is_deferred = 1; + nl->connection = PLIP_CN_SEND; + schedule_delayed_work(&nl->deferred, 1); + enable_parport_interrupts (dev); + ENABLE(dev->irq); + return OK; + } + } else { + if (plip_receive(nibble_timeout, dev, + &rcv->nibble, &rcv->length.b.lsb)) + return TIMEOUT; + } + rcv->state = PLIP_PK_LENGTH_MSB; + + case PLIP_PK_LENGTH_MSB: + if (plip_receive(nibble_timeout, dev, + &rcv->nibble, &rcv->length.b.msb)) + return TIMEOUT; + if (rcv->length.h > dev->mtu + dev->hard_header_len || + rcv->length.h < 8) { + printk(KERN_WARNING "%s: bogus packet size %d.\n", dev->name, rcv->length.h); + return ERROR; + } + /* Malloc up new buffer. */ + rcv->skb = dev_alloc_skb(rcv->length.h + 2); + if (rcv->skb == NULL) { + printk(KERN_ERR "%s: Memory squeeze.\n", dev->name); + return ERROR; + } + skb_reserve(rcv->skb, 2); /* Align IP on 16 byte boundaries */ + skb_put(rcv->skb,rcv->length.h); + rcv->skb->dev = dev; + rcv->state = PLIP_PK_DATA; + rcv->byte = 0; + rcv->checksum = 0; + + case PLIP_PK_DATA: + lbuf = rcv->skb->data; + do { + if (plip_receive(nibble_timeout, dev, + &rcv->nibble, &lbuf[rcv->byte])) + return TIMEOUT; + } while (++rcv->byte < rcv->length.h); + do { + rcv->checksum += lbuf[--rcv->byte]; + } while (rcv->byte); + rcv->state = PLIP_PK_CHECKSUM; + + case PLIP_PK_CHECKSUM: + if (plip_receive(nibble_timeout, dev, + &rcv->nibble, &rcv->data)) + return TIMEOUT; + if (rcv->data != rcv->checksum) { + dev->stats.rx_crc_errors++; + if (net_debug) + printk(KERN_DEBUG "%s: checksum error\n", dev->name); + return ERROR; + } + rcv->state = PLIP_PK_DONE; + + case PLIP_PK_DONE: + /* Inform the upper layer for the arrival of a packet. */ + rcv->skb->protocol=plip_type_trans(rcv->skb, dev); + netif_rx_ni(rcv->skb); + dev->stats.rx_bytes += rcv->length.h; + dev->stats.rx_packets++; + rcv->skb = NULL; + if (net_debug > 2) + printk(KERN_DEBUG "%s: receive end\n", dev->name); + + /* Close the connection. */ + write_data (dev, 0x00); + spin_lock_irq(&nl->lock); + if (snd->state != PLIP_PK_DONE) { + nl->connection = PLIP_CN_SEND; + spin_unlock_irq(&nl->lock); + schedule_work(&nl->immediate); + enable_parport_interrupts (dev); + ENABLE(dev->irq); + return OK; + } else { + nl->connection = PLIP_CN_NONE; + spin_unlock_irq(&nl->lock); + enable_parport_interrupts (dev); + ENABLE(dev->irq); + return OK; + } + } + return OK; +} + +/* PLIP_SEND --- send a byte (two nibbles) + Returns OK on success, TIMEOUT when timeout */ +static inline int +plip_send(unsigned short nibble_timeout, struct net_device *dev, + enum plip_nibble_state *ns_p, unsigned char data) +{ + unsigned char c0; + unsigned int cx; + + switch (*ns_p) { + case PLIP_NB_BEGIN: + write_data (dev, data & 0x0f); + *ns_p = PLIP_NB_1; + + case PLIP_NB_1: + write_data (dev, 0x10 | (data & 0x0f)); + cx = nibble_timeout; + while (1) { + c0 = read_status(dev); + if ((c0 & 0x80) == 0) + break; + if (--cx == 0) + return TIMEOUT; + udelay(PLIP_DELAY_UNIT); + } + write_data (dev, 0x10 | (data >> 4)); + *ns_p = PLIP_NB_2; + + case PLIP_NB_2: + write_data (dev, (data >> 4)); + cx = nibble_timeout; + while (1) { + c0 = read_status(dev); + if (c0 & 0x80) + break; + if (--cx == 0) + return TIMEOUT; + udelay(PLIP_DELAY_UNIT); + } + *ns_p = PLIP_NB_BEGIN; + return OK; + } + return OK; +} + +/* PLIP_SEND_PACKET --- send a packet */ +static int +plip_send_packet(struct net_device *dev, struct net_local *nl, + struct plip_local *snd, struct plip_local *rcv) +{ + unsigned short nibble_timeout = nl->nibble; + unsigned char *lbuf; + unsigned char c0; + unsigned int cx; + + if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) { + printk(KERN_DEBUG "%s: send skb lost\n", dev->name); + snd->state = PLIP_PK_DONE; + snd->skb = NULL; + return ERROR; + } + + switch (snd->state) { + case PLIP_PK_TRIGGER: + if ((read_status(dev) & 0xf8) != 0x80) + return HS_TIMEOUT; + + /* Trigger remote rx interrupt. */ + write_data (dev, 0x08); + cx = nl->trigger; + while (1) { + udelay(PLIP_DELAY_UNIT); + spin_lock_irq(&nl->lock); + if (nl->connection == PLIP_CN_RECEIVE) { + spin_unlock_irq(&nl->lock); + /* Interrupted. */ + dev->stats.collisions++; + return OK; + } + c0 = read_status(dev); + if (c0 & 0x08) { + spin_unlock_irq(&nl->lock); + DISABLE(dev->irq); + synchronize_irq(dev->irq); + if (nl->connection == PLIP_CN_RECEIVE) { + /* Interrupted. + We don't need to enable irq, + as it is soon disabled. */ + /* Yes, we do. New variant of + {enable,disable}_irq *counts* + them. -- AV */ + ENABLE(dev->irq); + dev->stats.collisions++; + return OK; + } + disable_parport_interrupts (dev); + if (net_debug > 2) + printk(KERN_DEBUG "%s: send start\n", dev->name); + snd->state = PLIP_PK_LENGTH_LSB; + snd->nibble = PLIP_NB_BEGIN; + nl->timeout_count = 0; + break; + } + spin_unlock_irq(&nl->lock); + if (--cx == 0) { + write_data (dev, 0x00); + return HS_TIMEOUT; + } + } + + case PLIP_PK_LENGTH_LSB: + if (plip_send(nibble_timeout, dev, + &snd->nibble, snd->length.b.lsb)) + return TIMEOUT; + snd->state = PLIP_PK_LENGTH_MSB; + + case PLIP_PK_LENGTH_MSB: + if (plip_send(nibble_timeout, dev, + &snd->nibble, snd->length.b.msb)) + return TIMEOUT; + snd->state = PLIP_PK_DATA; + snd->byte = 0; + snd->checksum = 0; + + case PLIP_PK_DATA: + do { + if (plip_send(nibble_timeout, dev, + &snd->nibble, lbuf[snd->byte])) + return TIMEOUT; + } while (++snd->byte < snd->length.h); + do { + snd->checksum += lbuf[--snd->byte]; + } while (snd->byte); + snd->state = PLIP_PK_CHECKSUM; + + case PLIP_PK_CHECKSUM: + if (plip_send(nibble_timeout, dev, + &snd->nibble, snd->checksum)) + return TIMEOUT; + + dev->stats.tx_bytes += snd->skb->len; + dev_kfree_skb(snd->skb); + dev->stats.tx_packets++; + snd->state = PLIP_PK_DONE; + + case PLIP_PK_DONE: + /* Close the connection */ + write_data (dev, 0x00); + snd->skb = NULL; + if (net_debug > 2) + printk(KERN_DEBUG "%s: send end\n", dev->name); + nl->connection = PLIP_CN_CLOSING; + nl->is_deferred = 1; + schedule_delayed_work(&nl->deferred, 1); + enable_parport_interrupts (dev); + ENABLE(dev->irq); + return OK; + } + return OK; +} + +static int +plip_connection_close(struct net_device *dev, struct net_local *nl, + struct plip_local *snd, struct plip_local *rcv) +{ + spin_lock_irq(&nl->lock); + if (nl->connection == PLIP_CN_CLOSING) { + nl->connection = PLIP_CN_NONE; + netif_wake_queue (dev); + } + spin_unlock_irq(&nl->lock); + if (nl->should_relinquish) { + nl->should_relinquish = nl->port_owner = 0; + parport_release(nl->pardev); + } + return OK; +} + +/* PLIP_ERROR --- wait till other end settled */ +static int +plip_error(struct net_device *dev, struct net_local *nl, + struct plip_local *snd, struct plip_local *rcv) +{ + unsigned char status; + + status = read_status(dev); + if ((status & 0xf8) == 0x80) { + if (net_debug > 2) + printk(KERN_DEBUG "%s: reset interface.\n", dev->name); + nl->connection = PLIP_CN_NONE; + nl->should_relinquish = 0; + netif_start_queue (dev); + enable_parport_interrupts (dev); + ENABLE(dev->irq); + netif_wake_queue (dev); + } else { + nl->is_deferred = 1; + schedule_delayed_work(&nl->deferred, 1); + } + + return OK; +} + +/* Handle the parallel port interrupts. */ +static void +plip_interrupt(void *dev_id) +{ + struct net_device *dev = dev_id; + struct net_local *nl; + struct plip_local *rcv; + unsigned char c0; + unsigned long flags; + + nl = netdev_priv(dev); + rcv = &nl->rcv_data; + + spin_lock_irqsave (&nl->lock, flags); + + c0 = read_status(dev); + if ((c0 & 0xf8) != 0xc0) { + if ((dev->irq != -1) && (net_debug > 1)) + printk(KERN_DEBUG "%s: spurious interrupt\n", dev->name); + spin_unlock_irqrestore (&nl->lock, flags); + return; + } + + if (net_debug > 3) + printk(KERN_DEBUG "%s: interrupt.\n", dev->name); + + switch (nl->connection) { + case PLIP_CN_CLOSING: + netif_wake_queue (dev); + case PLIP_CN_NONE: + case PLIP_CN_SEND: + rcv->state = PLIP_PK_TRIGGER; + nl->connection = PLIP_CN_RECEIVE; + nl->timeout_count = 0; + schedule_work(&nl->immediate); + break; + + case PLIP_CN_RECEIVE: + /* May occur because there is race condition + around test and set of dev->interrupt. + Ignore this interrupt. */ + break; + + case PLIP_CN_ERROR: + printk(KERN_ERR "%s: receive interrupt in error state\n", dev->name); + break; + } + + spin_unlock_irqrestore(&nl->lock, flags); +} + +static int +plip_tx_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct net_local *nl = netdev_priv(dev); + struct plip_local *snd = &nl->snd_data; + + if (netif_queue_stopped(dev)) + return NETDEV_TX_BUSY; + + /* We may need to grab the bus */ + if (!nl->port_owner) { + if (parport_claim(nl->pardev)) + return NETDEV_TX_BUSY; + nl->port_owner = 1; + } + + netif_stop_queue (dev); + + if (skb->len > dev->mtu + dev->hard_header_len) { + printk(KERN_WARNING "%s: packet too big, %d.\n", dev->name, (int)skb->len); + netif_start_queue (dev); + return NETDEV_TX_BUSY; + } + + if (net_debug > 2) + printk(KERN_DEBUG "%s: send request\n", dev->name); + + spin_lock_irq(&nl->lock); + snd->skb = skb; + snd->length.h = skb->len; + snd->state = PLIP_PK_TRIGGER; + if (nl->connection == PLIP_CN_NONE) { + nl->connection = PLIP_CN_SEND; + nl->timeout_count = 0; + } + schedule_work(&nl->immediate); + spin_unlock_irq(&nl->lock); + + return NETDEV_TX_OK; +} + +static void +plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth) +{ + const struct in_device *in_dev; + + rcu_read_lock(); + in_dev = __in_dev_get_rcu(dev); + if (in_dev) { + /* Any address will do - we take the first */ + const struct in_ifaddr *ifa = in_dev->ifa_list; + if (ifa) { + memcpy(eth->h_source, dev->dev_addr, 6); + memset(eth->h_dest, 0xfc, 2); + memcpy(eth->h_dest+2, &ifa->ifa_address, 4); + } + } + rcu_read_unlock(); +} + +static int +plip_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned len) +{ + int ret; + + ret = eth_header(skb, dev, type, daddr, saddr, len); + if (ret >= 0) + plip_rewrite_address (dev, (struct ethhdr *)skb->data); + + return ret; +} + +static int plip_hard_header_cache(const struct neighbour *neigh, + struct hh_cache *hh, __be16 type) +{ + int ret; + + ret = eth_header_cache(neigh, hh, type); + if (ret == 0) { + struct ethhdr *eth; + + eth = (struct ethhdr*)(((u8*)hh->hh_data) + + HH_DATA_OFF(sizeof(*eth))); + plip_rewrite_address (neigh->dev, eth); + } + + return ret; +} + +/* Open/initialize the board. This is called (in the current kernel) + sometime after booting when the 'ifconfig' program is run. + + This routine gets exclusive access to the parallel port by allocating + its IRQ line. + */ +static int +plip_open(struct net_device *dev) +{ + struct net_local *nl = netdev_priv(dev); + struct in_device *in_dev; + + /* Grab the port */ + if (!nl->port_owner) { + if (parport_claim(nl->pardev)) return -EAGAIN; + nl->port_owner = 1; + } + + nl->should_relinquish = 0; + + /* Clear the data port. */ + write_data (dev, 0x00); + + /* Enable rx interrupt. */ + enable_parport_interrupts (dev); + if (dev->irq == -1) + { + atomic_set (&nl->kill_timer, 0); + schedule_delayed_work(&nl->timer, 1); + } + + /* Initialize the state machine. */ + nl->rcv_data.state = nl->snd_data.state = PLIP_PK_DONE; + nl->rcv_data.skb = nl->snd_data.skb = NULL; + nl->connection = PLIP_CN_NONE; + nl->is_deferred = 0; + + /* Fill in the MAC-level header. + We used to abuse dev->broadcast to store the point-to-point + MAC address, but we no longer do it. Instead, we fetch the + interface address whenever it is needed, which is cheap enough + because we use the hh_cache. Actually, abusing dev->broadcast + didn't work, because when using plip_open the point-to-point + address isn't yet known. + PLIP doesn't have a real MAC address, but we need it to be + DOS compatible, and to properly support taps (otherwise, + when the device address isn't identical to the address of a + received frame, the kernel incorrectly drops it). */ + + in_dev=__in_dev_get_rtnl(dev); + if (in_dev) { + /* Any address will do - we take the first. We already + have the first two bytes filled with 0xfc, from + plip_init_dev(). */ + struct in_ifaddr *ifa=in_dev->ifa_list; + if (ifa != NULL) { + memcpy(dev->dev_addr+2, &ifa->ifa_local, 4); + } + } + + netif_start_queue (dev); + + return 0; +} + +/* The inverse routine to plip_open (). */ +static int +plip_close(struct net_device *dev) +{ + struct net_local *nl = netdev_priv(dev); + struct plip_local *snd = &nl->snd_data; + struct plip_local *rcv = &nl->rcv_data; + + netif_stop_queue (dev); + DISABLE(dev->irq); + synchronize_irq(dev->irq); + + if (dev->irq == -1) + { + init_completion(&nl->killed_timer_cmp); + atomic_set (&nl->kill_timer, 1); + wait_for_completion(&nl->killed_timer_cmp); + } + +#ifdef NOTDEF + outb(0x00, PAR_DATA(dev)); +#endif + nl->is_deferred = 0; + nl->connection = PLIP_CN_NONE; + if (nl->port_owner) { + parport_release(nl->pardev); + nl->port_owner = 0; + } + + snd->state = PLIP_PK_DONE; + if (snd->skb) { + dev_kfree_skb(snd->skb); + snd->skb = NULL; + } + rcv->state = PLIP_PK_DONE; + if (rcv->skb) { + kfree_skb(rcv->skb); + rcv->skb = NULL; + } + +#ifdef NOTDEF + /* Reset. */ + outb(0x00, PAR_CONTROL(dev)); +#endif + return 0; +} + +static int +plip_preempt(void *handle) +{ + struct net_device *dev = (struct net_device *)handle; + struct net_local *nl = netdev_priv(dev); + + /* Stand our ground if a datagram is on the wire */ + if (nl->connection != PLIP_CN_NONE) { + nl->should_relinquish = 1; + return 1; + } + + nl->port_owner = 0; /* Remember that we released the bus */ + return 0; +} + +static void +plip_wakeup(void *handle) +{ + struct net_device *dev = (struct net_device *)handle; + struct net_local *nl = netdev_priv(dev); + + if (nl->port_owner) { + /* Why are we being woken up? */ + printk(KERN_DEBUG "%s: why am I being woken up?\n", dev->name); + if (!parport_claim(nl->pardev)) + /* bus_owner is already set (but why?) */ + printk(KERN_DEBUG "%s: I'm broken.\n", dev->name); + else + return; + } + + if (!(dev->flags & IFF_UP)) + /* Don't need the port when the interface is down */ + return; + + if (!parport_claim(nl->pardev)) { + nl->port_owner = 1; + /* Clear the data port. */ + write_data (dev, 0x00); + } +} + +static int +plip_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct net_local *nl = netdev_priv(dev); + struct plipconf *pc = (struct plipconf *) &rq->ifr_ifru; + + if (cmd != SIOCDEVPLIP) + return -EOPNOTSUPP; + + switch(pc->pcmd) { + case PLIP_GET_TIMEOUT: + pc->trigger = nl->trigger; + pc->nibble = nl->nibble; + break; + case PLIP_SET_TIMEOUT: + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + nl->trigger = pc->trigger; + nl->nibble = pc->nibble; + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int parport[PLIP_MAX] = { [0 ... PLIP_MAX-1] = -1 }; +static int timid; + +module_param_array(parport, int, NULL, 0); +module_param(timid, int, 0); +MODULE_PARM_DESC(parport, "List of parport device numbers to use by plip"); + +static struct net_device *dev_plip[PLIP_MAX] = { NULL, }; + +static inline int +plip_searchfor(int list[], int a) +{ + int i; + for (i = 0; i < PLIP_MAX && list[i] != -1; i++) { + if (list[i] == a) return 1; + } + return 0; +} + +/* plip_attach() is called (by the parport code) when a port is + * available to use. */ +static void plip_attach (struct parport *port) +{ + static int unit; + struct net_device *dev; + struct net_local *nl; + char name[IFNAMSIZ]; + + if ((parport[0] == -1 && (!timid || !port->devices)) || + plip_searchfor(parport, port->number)) { + if (unit == PLIP_MAX) { + printk(KERN_ERR "plip: too many devices\n"); + return; + } + + sprintf(name, "plip%d", unit); + dev = alloc_etherdev(sizeof(struct net_local)); + if (!dev) { + printk(KERN_ERR "plip: memory squeeze\n"); + return; + } + + strcpy(dev->name, name); + + dev->irq = port->irq; + dev->base_addr = port->base; + if (port->irq == -1) { + printk(KERN_INFO "plip: %s has no IRQ. Using IRQ-less mode," + "which is fairly inefficient!\n", port->name); + } + + nl = netdev_priv(dev); + nl->dev = dev; + nl->pardev = parport_register_device(port, dev->name, plip_preempt, + plip_wakeup, plip_interrupt, + 0, dev); + + if (!nl->pardev) { + printk(KERN_ERR "%s: parport_register failed\n", name); + goto err_free_dev; + } + + plip_init_netdev(dev); + + if (register_netdev(dev)) { + printk(KERN_ERR "%s: network register failed\n", name); + goto err_parport_unregister; + } + + printk(KERN_INFO "%s", version); + if (dev->irq != -1) + printk(KERN_INFO "%s: Parallel port at %#3lx, " + "using IRQ %d.\n", + dev->name, dev->base_addr, dev->irq); + else + printk(KERN_INFO "%s: Parallel port at %#3lx, " + "not using IRQ.\n", + dev->name, dev->base_addr); + dev_plip[unit++] = dev; + } + return; + +err_parport_unregister: + parport_unregister_device(nl->pardev); +err_free_dev: + free_netdev(dev); +} + +/* plip_detach() is called (by the parport code) when a port is + * no longer available to use. */ +static void plip_detach (struct parport *port) +{ + /* Nothing to do */ +} + +static struct parport_driver plip_driver = { + .name = "plip", + .attach = plip_attach, + .detach = plip_detach +}; + +static void __exit plip_cleanup_module (void) +{ + struct net_device *dev; + int i; + + parport_unregister_driver (&plip_driver); + + for (i=0; i < PLIP_MAX; i++) { + if ((dev = dev_plip[i])) { + struct net_local *nl = netdev_priv(dev); + unregister_netdev(dev); + if (nl->port_owner) + parport_release(nl->pardev); + parport_unregister_device(nl->pardev); + free_netdev(dev); + dev_plip[i] = NULL; + } + } +} + +#ifndef MODULE + +static int parport_ptr; + +static int __init plip_setup(char *str) +{ + int ints[4]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + /* Ugh. */ + if (!strncmp(str, "parport", 7)) { + int n = simple_strtoul(str+7, NULL, 10); + if (parport_ptr < PLIP_MAX) + parport[parport_ptr++] = n; + else + printk(KERN_INFO "plip: too many ports, %s ignored.\n", + str); + } else if (!strcmp(str, "timid")) { + timid = 1; + } else { + if (ints[0] == 0 || ints[1] == 0) { + /* disable driver on "plip=" or "plip=0" */ + parport[0] = -2; + } else { + printk(KERN_WARNING "warning: 'plip=0x%x' ignored\n", + ints[1]); + } + } + return 1; +} + +__setup("plip=", plip_setup); + +#endif /* !MODULE */ + +static int __init plip_init (void) +{ + if (parport[0] == -2) + return 0; + + if (parport[0] != -1 && timid) { + printk(KERN_WARNING "plip: warning, ignoring `timid' since specific ports given.\n"); + timid = 0; + } + + if (parport_register_driver (&plip_driver)) { + printk (KERN_WARNING "plip: couldn't register driver\n"); + return 1; + } + + return 0; +} + +module_init(plip_init); +module_exit(plip_cleanup_module); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From b5451d783ade99308dfccdf5ca284ed07affa4ff Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Wed, 3 Aug 2011 03:17:13 -0700 Subject: slip: Move the SLIP drivers Move the Serial Line Internet Protocol (SLIP) drivers into drivers/net/slip/ and make the necessary Kconfig and Makefile changes. Signed-off-by: Jeff Kirsher Acked-by: Alan Cox diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 3f72686..b3206c9 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -199,6 +199,8 @@ source "drivers/net/fddi/Kconfig" source "drivers/net/plip/Kconfig" +source "drivers/net/slip/Kconfig" + source "drivers/net/tokenring/Kconfig" source "drivers/net/wireless/Kconfig" @@ -274,78 +276,6 @@ config RIONET_RX_SIZE depends on RIONET default "128" -config SLIP - tristate "SLIP (serial line) support" - ---help--- - Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to - connect to your Internet service provider or to connect to some - other local Unix box or if you want to configure your Linux box as a - Slip/CSlip server for other people to dial in. SLIP (Serial Line - Internet Protocol) is a protocol used to send Internet traffic over - serial connections such as telephone lines or null modem cables; - nowadays, the protocol PPP is more commonly used for this same - purpose. - - Normally, your access provider has to support SLIP in order for you - to be able to use it, but there is now a SLIP emulator called SLiRP - around (available from - ) which - allows you to use SLIP over a regular dial up shell connection. If - you plan to use SLiRP, make sure to say Y to CSLIP, below. The - NET-3-HOWTO, available from - , explains how to - configure SLIP. Note that you don't need this option if you just - want to run term (term is a program which gives you almost full - Internet connectivity if you have a regular dial up shell account on - some Internet connected Unix computer. Read - ). SLIP - support will enlarge your kernel by about 4 KB. If unsure, say N. - - To compile this driver as a module, choose M here. The module - will be called slip. - -config SLIP_COMPRESSED - bool "CSLIP compressed headers" - depends on SLIP - select SLHC - ---help--- - This protocol is faster than SLIP because it uses compression on the - TCP/IP headers (not on the data itself), but it has to be supported - on both ends. Ask your access provider if you are not sure and - answer Y, just in case. You will still be able to use plain SLIP. If - you plan to use SLiRP, the SLIP emulator (available from - ) which - allows you to use SLIP over a regular dial up shell connection, you - definitely want to say Y here. The NET-3-HOWTO, available from - , explains how to configure - CSLIP. This won't enlarge your kernel. - -config SLHC - tristate - help - This option enables Van Jacobsen serial line header compression - routines. - -config SLIP_SMART - bool "Keepalive and linefill" - depends on SLIP - help - Adds additional capabilities to the SLIP driver to support the - RELCOM line fill and keepalive monitoring. Ideal on poor quality - analogue lines. - -config SLIP_MODE_SLIP6 - bool "Six bit SLIP encapsulation" - depends on SLIP - help - Just occasionally you may need to run IP over hostile serial - networks that don't pass all control characters or are only seven - bit. Saying Y here adds an extra mode you can use with SLIP: - "slip6". In this mode, SLIP will only send normal ASCII symbols over - the serial device. Naturally, this has to be supported at the other - end of the link as well. It's good enough, for example, to run IP - over the async ports of a Camtec JNT Pad. If unsure, say N. - config NET_FC bool "Fibre Channel driver support" depends on SCSI && PCI diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 52dae95..e6a183e 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -20,8 +20,6 @@ obj-$(CONFIG_RIONET) += rionet.o obj-$(CONFIG_NET) += Space.o loopback.o obj-$(CONFIG_NET_SB1000) += sb1000.o -obj-$(CONFIG_SLIP) += slip.o -obj-$(CONFIG_SLHC) += slhc.o obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o obj-$(CONFIG_XEN_NETDEV_BACKEND) += xen-netback/ @@ -48,6 +46,8 @@ obj-$(CONFIG_PPP_SYNC_TTY) += ppp/ obj-$(CONFIG_PPPOE) += ppp/ obj-$(CONFIG_PPPOL2TP) += ppp/ obj-$(CONFIG_PPTP) += ppp/ +onj-$(CONFIG_SLIP) += slip/ +obj-$(CONFIG_SLHC) += slip/ obj-$(CONFIG_TR) += tokenring/ obj-$(CONFIG_WAN) += wan/ obj-$(CONFIG_ARCNET) += arcnet/ diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c deleted file mode 100644 index 0a0a664..0000000 --- a/drivers/net/slhc.c +++ /dev/null @@ -1,742 +0,0 @@ -/* - * Routines to compress and uncompress tcp packets (for transmission - * over low speed serial lines). - * - * Copyright (c) 1989 Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: - * - Initial distribution. - * - * - * modified for KA9Q Internet Software Package by - * Katie Stevens (dkstevens@ucdavis.edu) - * University of California, Davis - * Computing Services - * - 01-31-90 initial adaptation (from 1.19) - * PPP.05 02-15-90 [ks] - * PPP.08 05-02-90 [ks] use PPP protocol field to signal compression - * PPP.15 09-90 [ks] improve mbuf handling - * PPP.16 11-02 [karn] substantially rewritten to use NOS facilities - * - * - Feb 1991 Bill_Simpson@um.cc.umich.edu - * variable number of conversation slots - * allow zero or one slots - * separate routines - * status display - * - Jul 1994 Dmitry Gorodchanin - * Fixes for memory leaks. - * - Oct 1994 Dmitry Gorodchanin - * Modularization. - * - Jan 1995 Bjorn Ekwall - * Use ip_fast_csum from ip.h - * - July 1995 Christos A. Polyzols - * Spotted bug in tcp option checking - * - * - * This module is a difficult issue. It's clearly inet code but it's also clearly - * driver code belonging close to PPP and SLIP - */ - -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_INET -/* Entire module is for IP only */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned char *encode(unsigned char *cp, unsigned short n); -static long decode(unsigned char **cpp); -static unsigned char * put16(unsigned char *cp, unsigned short x); -static unsigned short pull16(unsigned char **cpp); - -/* Initialize compression data structure - * slots must be in range 0 to 255 (zero meaning no compression) - */ -struct slcompress * -slhc_init(int rslots, int tslots) -{ - register short i; - register struct cstate *ts; - struct slcompress *comp; - - comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); - if (! comp) - goto out_fail; - - if ( rslots > 0 && rslots < 256 ) { - size_t rsize = rslots * sizeof(struct cstate); - comp->rstate = kzalloc(rsize, GFP_KERNEL); - if (! comp->rstate) - goto out_free; - comp->rslot_limit = rslots - 1; - } - - if ( tslots > 0 && tslots < 256 ) { - size_t tsize = tslots * sizeof(struct cstate); - comp->tstate = kzalloc(tsize, GFP_KERNEL); - if (! comp->tstate) - goto out_free2; - comp->tslot_limit = tslots - 1; - } - - comp->xmit_oldest = 0; - comp->xmit_current = 255; - comp->recv_current = 255; - /* - * don't accept any packets with implicit index until we get - * one with an explicit index. Otherwise the uncompress code - * will try to use connection 255, which is almost certainly - * out of range - */ - comp->flags |= SLF_TOSS; - - if ( tslots > 0 ) { - ts = comp->tstate; - for(i = comp->tslot_limit; i > 0; --i){ - ts[i].cs_this = i; - ts[i].next = &(ts[i - 1]); - } - ts[0].next = &(ts[comp->tslot_limit]); - ts[0].cs_this = 0; - } - return comp; - -out_free2: - kfree(comp->rstate); -out_free: - kfree(comp); -out_fail: - return NULL; -} - - -/* Free a compression data structure */ -void -slhc_free(struct slcompress *comp) -{ - if ( comp == NULLSLCOMPR ) - return; - - if ( comp->tstate != NULLSLSTATE ) - kfree( comp->tstate ); - - if ( comp->rstate != NULLSLSTATE ) - kfree( comp->rstate ); - - kfree( comp ); -} - - -/* Put a short in host order into a char array in network order */ -static inline unsigned char * -put16(unsigned char *cp, unsigned short x) -{ - *cp++ = x >> 8; - *cp++ = x; - - return cp; -} - - -/* Encode a number */ -static unsigned char * -encode(unsigned char *cp, unsigned short n) -{ - if(n >= 256 || n == 0){ - *cp++ = 0; - cp = put16(cp,n); - } else { - *cp++ = n; - } - return cp; -} - -/* Pull a 16-bit integer in host order from buffer in network byte order */ -static unsigned short -pull16(unsigned char **cpp) -{ - short rval; - - rval = *(*cpp)++; - rval <<= 8; - rval |= *(*cpp)++; - return rval; -} - -/* Decode a number */ -static long -decode(unsigned char **cpp) -{ - register int x; - - x = *(*cpp)++; - if(x == 0){ - return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ - } else { - return x & 0xff; /* -1 if PULLCHAR returned error */ - } -} - -/* - * icp and isize are the original packet. - * ocp is a place to put a copy if necessary. - * cpp is initially a pointer to icp. If the copy is used, - * change it to ocp. - */ - -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) -{ - register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]); - register struct cstate *lcs = ocs; - register struct cstate *cs = lcs->next; - register unsigned long deltaS, deltaA; - register short changes = 0; - int hlen; - unsigned char new_seq[16]; - register unsigned char *cp = new_seq; - struct iphdr *ip; - struct tcphdr *th, *oth; - __sum16 csum; - - - /* - * Don't play with runt packets. - */ - - if(isizeprotocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) { - /* Send as regular IP */ - if(ip->protocol != IPPROTO_TCP) - comp->sls_o_nontcp++; - else - comp->sls_o_tcp++; - return isize; - } - /* Extract TCP header */ - - th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4); - hlen = ip->ihl*4 + th->doff*4; - - /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or - * some other control bit is set). Also uncompressible if - * it's a runt. - */ - if(hlen > isize || th->syn || th->fin || th->rst || - ! (th->ack)){ - /* TCP connection stuff; send as regular IP */ - comp->sls_o_tcp++; - return isize; - } - /* - * Packet is compressible -- we're going to send either a - * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way, - * we need to locate (or create) the connection state. - * - * States are kept in a circularly linked list with - * xmit_oldest pointing to the end of the list. The - * list is kept in lru order by moving a state to the - * head of the list whenever it is referenced. Since - * the list is short and, empirically, the connection - * we want is almost always near the front, we locate - * states via linear search. If we don't find a state - * for the datagram, the oldest state is (re-)used. - */ - for ( ; ; ) { - if( ip->saddr == cs->cs_ip.saddr - && ip->daddr == cs->cs_ip.daddr - && th->source == cs->cs_tcp.source - && th->dest == cs->cs_tcp.dest) - goto found; - - /* if current equal oldest, at end of list */ - if ( cs == ocs ) - break; - lcs = cs; - cs = cs->next; - comp->sls_o_searches++; - } - /* - * Didn't find it -- re-use oldest cstate. Send an - * uncompressed packet that tells the other side what - * connection number we're using for this conversation. - * - * Note that since the state list is circular, the oldest - * state points to the newest and we only need to set - * xmit_oldest to update the lru linkage. - */ - comp->sls_o_misses++; - comp->xmit_oldest = lcs->cs_this; - goto uncompressed; - -found: - /* - * Found it -- move to the front on the connection list. - */ - if(lcs == ocs) { - /* found at most recently used */ - } else if (cs == ocs) { - /* found at least recently used */ - comp->xmit_oldest = lcs->cs_this; - } else { - /* more than 2 elements */ - lcs->next = cs->next; - cs->next = ocs->next; - ocs->next = cs; - } - - /* - * Make sure that only what we expect to change changed. - * Check the following: - * IP protocol version, header length & type of service. - * The "Don't fragment" bit. - * The time-to-live field. - * The TCP header length. - * IP options, if any. - * TCP options, if any. - * If any of these things are different between the previous & - * current datagram, we send the current datagram `uncompressed'. - */ - oth = &cs->cs_tcp; - - if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl - || ip->tos != cs->cs_ip.tos - || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) - || ip->ttl != cs->cs_ip.ttl - || th->doff != cs->cs_tcp.doff - || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) - || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ - goto uncompressed; - } - - /* - * Figure out which of the changing fields changed. The - * receiver expects changes in the order: urgent, window, - * ack, seq (the order minimizes the number of temporaries - * needed in this section of code). - */ - if(th->urg){ - deltaS = ntohs(th->urg_ptr); - cp = encode(cp,deltaS); - changes |= NEW_U; - } else if(th->urg_ptr != oth->urg_ptr){ - /* argh! URG not set but urp changed -- a sensible - * implementation should never do this but RFC793 - * doesn't prohibit the change so we have to deal - * with it. */ - goto uncompressed; - } - if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ - cp = encode(cp,deltaS); - changes |= NEW_W; - } - if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ - if(deltaA > 0x0000ffff) - goto uncompressed; - cp = encode(cp,deltaA); - changes |= NEW_A; - } - if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ - if(deltaS > 0x0000ffff) - goto uncompressed; - cp = encode(cp,deltaS); - changes |= NEW_S; - } - - switch(changes){ - case 0: /* Nothing changed. If this packet contains data and the - * last one didn't, this is probably a data packet following - * an ack (normal on an interactive connection) and we send - * it compressed. Otherwise it's probably a retransmit, - * retransmitted ack or window probe. Send it uncompressed - * in case the other side missed the compressed version. - */ - if(ip->tot_len != cs->cs_ip.tot_len && - ntohs(cs->cs_ip.tot_len) == hlen) - break; - goto uncompressed; - break; - case SPECIAL_I: - case SPECIAL_D: - /* actual changes match one of our special case encodings -- - * send packet uncompressed. - */ - goto uncompressed; - case NEW_S|NEW_A: - if(deltaS == deltaA && - deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ - /* special case for echoed terminal traffic */ - changes = SPECIAL_I; - cp = new_seq; - } - break; - case NEW_S: - if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ - /* special case for data xfer */ - changes = SPECIAL_D; - cp = new_seq; - } - break; - } - deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); - if(deltaS != 1){ - cp = encode(cp,deltaS); - changes |= NEW_I; - } - if(th->psh) - changes |= TCP_PUSH_BIT; - /* Grab the cksum before we overwrite it below. Then update our - * state with this packet's header. - */ - csum = th->check; - memcpy(&cs->cs_ip,ip,20); - memcpy(&cs->cs_tcp,th,20); - /* We want to use the original packet as our compressed packet. - * (cp - new_seq) is the number of bytes we need for compressed - * sequence numbers. In addition we need one byte for the change - * mask, one for the connection id and two for the tcp checksum. - * So, (cp - new_seq) + 4 bytes of header are needed. - */ - deltaS = cp - new_seq; - if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ - cp = ocp; - *cpp = ocp; - *cp++ = changes | NEW_C; - *cp++ = cs->cs_this; - comp->xmit_current = cs->cs_this; - } else { - cp = ocp; - *cpp = ocp; - *cp++ = changes; - } - *(__sum16 *)cp = csum; - cp += 2; -/* deltaS is now the size of the change section of the compressed header */ - memcpy(cp,new_seq,deltaS); /* Write list of deltas */ - memcpy(cp+deltaS,icp+hlen,isize-hlen); - comp->sls_o_compressed++; - ocp[0] |= SL_TYPE_COMPRESSED_TCP; - return isize - hlen + deltaS + (cp - ocp); - - /* Update connection state cs & send uncompressed packet (i.e., - * a regular ip/tcp packet but with the 'conversation id' we hope - * to use on future compressed packets in the protocol field). - */ -uncompressed: - memcpy(&cs->cs_ip,ip,20); - memcpy(&cs->cs_tcp,th,20); - if (ip->ihl > 5) - memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4); - if (th->doff > 5) - memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4); - comp->xmit_current = cs->cs_this; - comp->sls_o_uncompressed++; - memcpy(ocp, icp, isize); - *cpp = ocp; - ocp[9] = cs->cs_this; - ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP; - return isize; -} - - -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) -{ - register int changes; - long x; - register struct tcphdr *thp; - register struct iphdr *ip; - register struct cstate *cs; - int len, hdrlen; - unsigned char *cp = icp; - - /* We've got a compressed packet; read the change byte */ - comp->sls_i_compressed++; - if(isize < 3){ - comp->sls_i_error++; - return 0; - } - changes = *cp++; - if(changes & NEW_C){ - /* Make sure the state index is in range, then grab the state. - * If we have a good state index, clear the 'discard' flag. - */ - x = *cp++; /* Read conn index */ - if(x < 0 || x > comp->rslot_limit) - goto bad; - - comp->flags &=~ SLF_TOSS; - comp->recv_current = x; - } else { - /* this packet has an implicit state index. If we've - * had a line error since the last time we got an - * explicit state index, we have to toss the packet. */ - if(comp->flags & SLF_TOSS){ - comp->sls_i_tossed++; - return 0; - } - } - cs = &comp->rstate[comp->recv_current]; - thp = &cs->cs_tcp; - ip = &cs->cs_ip; - - thp->check = *(__sum16 *)cp; - cp += 2; - - thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0; -/* - * we can use the same number for the length of the saved header and - * the current one, because the packet wouldn't have been sent - * as compressed unless the options were the same as the previous one - */ - - hdrlen = ip->ihl * 4 + thp->doff * 4; - - switch(changes & SPECIALS_MASK){ - case SPECIAL_I: /* Echoed terminal traffic */ - { - register short i; - i = ntohs(ip->tot_len) - hdrlen; - thp->ack_seq = htonl( ntohl(thp->ack_seq) + i); - thp->seq = htonl( ntohl(thp->seq) + i); - } - break; - - case SPECIAL_D: /* Unidirectional data */ - thp->seq = htonl( ntohl(thp->seq) + - ntohs(ip->tot_len) - hdrlen); - break; - - default: - if(changes & NEW_U){ - thp->urg = 1; - if((x = decode(&cp)) == -1) { - goto bad; - } - thp->urg_ptr = htons(x); - } else - thp->urg = 0; - if(changes & NEW_W){ - if((x = decode(&cp)) == -1) { - goto bad; - } - thp->window = htons( ntohs(thp->window) + x); - } - if(changes & NEW_A){ - if((x = decode(&cp)) == -1) { - goto bad; - } - thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); - } - if(changes & NEW_S){ - if((x = decode(&cp)) == -1) { - goto bad; - } - thp->seq = htonl( ntohl(thp->seq) + x); - } - break; - } - if(changes & NEW_I){ - if((x = decode(&cp)) == -1) { - goto bad; - } - ip->id = htons (ntohs (ip->id) + x); - } else - ip->id = htons (ntohs (ip->id) + 1); - - /* - * At this point, cp points to the first byte of data in the - * packet. Put the reconstructed TCP and IP headers back on the - * packet. Recalculate IP checksum (but not TCP checksum). - */ - - len = isize - (cp - icp); - if (len < 0) - goto bad; - len += hdrlen; - ip->tot_len = htons(len); - ip->check = 0; - - memmove(icp + hdrlen, cp, len - hdrlen); - - cp = icp; - memcpy(cp, ip, 20); - cp += 20; - - if (ip->ihl > 5) { - memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4); - cp += (ip->ihl - 5) * 4; - } - - put_unaligned(ip_fast_csum(icp, ip->ihl), - &((struct iphdr *)icp)->check); - - memcpy(cp, thp, 20); - cp += 20; - - if (thp->doff > 5) { - memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4); - cp += ((thp->doff) - 5) * 4; - } - - return len; -bad: - comp->sls_i_error++; - return slhc_toss( comp ); -} - - -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) -{ - register struct cstate *cs; - unsigned ihl; - - unsigned char index; - - if(isize < 20) { - /* The packet is shorter than a legal IP header */ - comp->sls_i_runt++; - return slhc_toss( comp ); - } - /* Peek at the IP header's IHL field to find its length */ - ihl = icp[0] & 0xf; - if(ihl < 20 / 4){ - /* The IP header length field is too small */ - comp->sls_i_runt++; - return slhc_toss( comp ); - } - index = icp[9]; - icp[9] = IPPROTO_TCP; - - if (ip_fast_csum(icp, ihl)) { - /* Bad IP header checksum; discard */ - comp->sls_i_badcheck++; - return slhc_toss( comp ); - } - if(index > comp->rslot_limit) { - comp->sls_i_error++; - return slhc_toss(comp); - } - - /* Update local state */ - cs = &comp->rstate[comp->recv_current = index]; - comp->flags &=~ SLF_TOSS; - memcpy(&cs->cs_ip,icp,20); - memcpy(&cs->cs_tcp,icp + ihl*4,20); - if (ihl > 5) - memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4); - if (cs->cs_tcp.doff > 5) - memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4); - cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2; - /* Put headers back on packet - * Neither header checksum is recalculated - */ - comp->sls_i_uncompressed++; - return isize; -} - -int -slhc_toss(struct slcompress *comp) -{ - if ( comp == NULLSLCOMPR ) - return 0; - - comp->flags |= SLF_TOSS; - return 0; -} - -#else /* CONFIG_INET */ - -int -slhc_toss(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); - return -EINVAL; -} -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); - return -EINVAL; -} -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); - return -EINVAL; -} - -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); - return -EINVAL; -} - -void -slhc_free(struct slcompress *comp) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); -} -struct slcompress * -slhc_init(int rslots, int tslots) -{ - printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); - return NULL; -} - -#endif /* CONFIG_INET */ - -/* VJ header compression */ -EXPORT_SYMBOL(slhc_init); -EXPORT_SYMBOL(slhc_free); -EXPORT_SYMBOL(slhc_remember); -EXPORT_SYMBOL(slhc_compress); -EXPORT_SYMBOL(slhc_uncompress); -EXPORT_SYMBOL(slhc_toss); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/slip.c b/drivers/net/slip.c deleted file mode 100644 index ba08341..0000000 --- a/drivers/net/slip.c +++ /dev/null @@ -1,1444 +0,0 @@ -/* - * slip.c This module implements the SLIP protocol for kernel-based - * devices like TTY. It interfaces between a raw TTY, and the - * kernel's INET protocol layers. - * - * Version: @(#)slip.c 0.8.3 12/24/94 - * - * Authors: Laurence Culhane, - * Fred N. van Kempen, - * - * Fixes: - * Alan Cox : Sanity checks and avoid tx overruns. - * Has a new sl->mtu field. - * Alan Cox : Found cause of overrun. ifconfig sl0 - * mtu upwards. Driver now spots this - * and grows/shrinks its buffers(hack!). - * Memory leak if you run out of memory - * setting up a slip driver fixed. - * Matt Dillon : Printable slip (borrowed from NET2E) - * Pauline Middelink : Slip driver fixes. - * Alan Cox : Honours the old SL_COMPRESSED flag - * Alan Cox : KISS AX.25 and AXUI IP support - * Michael Riepe : Automatic CSLIP recognition added - * Charles Hedrick : CSLIP header length problem fix. - * Alan Cox : Corrected non-IP cases of the above. - * Alan Cox : Now uses hardware type as per FvK. - * Alan Cox : Default to 192.168.0.0 (RFC 1597) - * A.N.Kuznetsov : dev_tint() recursion fix. - * Dmitry Gorodchanin : SLIP memory leaks - * Dmitry Gorodchanin : Code cleanup. Reduce tty driver - * buffering from 4096 to 256 bytes. - * Improving SLIP response time. - * CONFIG_SLIP_MODE_SLIP6. - * ifconfig sl? up & down now works - * correctly. - * Modularization. - * Alan Cox : Oops - fix AX.25 buffer lengths - * Dmitry Gorodchanin : Even more cleanups. Preserve CSLIP - * statistics. Include CSLIP code only - * if it really needed. - * Alan Cox : Free slhc buffers in the right place. - * Alan Cox : Allow for digipeated IP over AX.25 - * Matti Aarnio : Dynamic SLIP devices, with ideas taken - * from Jim Freeman's - * dynamic PPP devices. We do NOT kfree() - * device entries, just reg./unreg. them - * as they are needed. We kfree() them - * at module cleanup. - * With MODULE-loading ``insmod'', user - * can issue parameter: slip_maxdev=1024 - * (Or how much he/she wants.. Default - * is 256) - * Stanislav Voronyi : Slip line checking, with ideas taken - * from multislip BSDI driver which was - * written by Igor Chechik, RELCOM Corp. - * Only algorithms have been ported to - * Linux SLIP driver. - * Vitaly E. Lavrov : Sane behaviour on tty hangup. - * Alexey Kuznetsov : Cleanup interfaces to tty & netdevice - * modules. - */ - -#define SL_CHECK_TRANSMIT -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "slip.h" -#ifdef CONFIG_INET -#include -#include -#include -#endif - -#define SLIP_VERSION "0.8.4-NET3.019-NEWTTY" - -static struct net_device **slip_devs; - -static int slip_maxdev = SL_NRUNIT; -module_param(slip_maxdev, int, 0); -MODULE_PARM_DESC(slip_maxdev, "Maximum number of slip devices"); - -static int slip_esc(unsigned char *p, unsigned char *d, int len); -static void slip_unesc(struct slip *sl, unsigned char c); -#ifdef CONFIG_SLIP_MODE_SLIP6 -static int slip_esc6(unsigned char *p, unsigned char *d, int len); -static void slip_unesc6(struct slip *sl, unsigned char c); -#endif -#ifdef CONFIG_SLIP_SMART -static void sl_keepalive(unsigned long sls); -static void sl_outfill(unsigned long sls); -static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -#endif - -/******************************** -* Buffer administration routines: -* sl_alloc_bufs() -* sl_free_bufs() -* sl_realloc_bufs() -* -* NOTE: sl_realloc_bufs != sl_free_bufs + sl_alloc_bufs, because -* sl_realloc_bufs provides strong atomicity and reallocation -* on actively running device. -*********************************/ - -/* - Allocate channel buffers. - */ - -static int sl_alloc_bufs(struct slip *sl, int mtu) -{ - int err = -ENOBUFS; - unsigned long len; - char *rbuff = NULL; - char *xbuff = NULL; -#ifdef SL_INCLUDE_CSLIP - char *cbuff = NULL; - struct slcompress *slcomp = NULL; -#endif - - /* - * Allocate the SLIP frame buffers: - * - * rbuff Receive buffer. - * xbuff Transmit buffer. - * cbuff Temporary compression buffer. - */ - len = mtu * 2; - - /* - * allow for arrival of larger UDP packets, even if we say not to - * also fixes a bug in which SunOS sends 512-byte packets even with - * an MSS of 128 - */ - if (len < 576 * 2) - len = 576 * 2; - rbuff = kmalloc(len + 4, GFP_KERNEL); - if (rbuff == NULL) - goto err_exit; - xbuff = kmalloc(len + 4, GFP_KERNEL); - if (xbuff == NULL) - goto err_exit; -#ifdef SL_INCLUDE_CSLIP - cbuff = kmalloc(len + 4, GFP_KERNEL); - if (cbuff == NULL) - goto err_exit; - slcomp = slhc_init(16, 16); - if (slcomp == NULL) - goto err_exit; -#endif - spin_lock_bh(&sl->lock); - if (sl->tty == NULL) { - spin_unlock_bh(&sl->lock); - err = -ENODEV; - goto err_exit; - } - sl->mtu = mtu; - sl->buffsize = len; - sl->rcount = 0; - sl->xleft = 0; - rbuff = xchg(&sl->rbuff, rbuff); - xbuff = xchg(&sl->xbuff, xbuff); -#ifdef SL_INCLUDE_CSLIP - cbuff = xchg(&sl->cbuff, cbuff); - slcomp = xchg(&sl->slcomp, slcomp); -#endif -#ifdef CONFIG_SLIP_MODE_SLIP6 - sl->xdata = 0; - sl->xbits = 0; -#endif - spin_unlock_bh(&sl->lock); - err = 0; - - /* Cleanup */ -err_exit: -#ifdef SL_INCLUDE_CSLIP - kfree(cbuff); - slhc_free(slcomp); -#endif - kfree(xbuff); - kfree(rbuff); - return err; -} - -/* Free a SLIP channel buffers. */ -static void sl_free_bufs(struct slip *sl) -{ - /* Free all SLIP frame buffers. */ - kfree(xchg(&sl->rbuff, NULL)); - kfree(xchg(&sl->xbuff, NULL)); -#ifdef SL_INCLUDE_CSLIP - kfree(xchg(&sl->cbuff, NULL)); - slhc_free(xchg(&sl->slcomp, NULL)); -#endif -} - -/* - Reallocate slip channel buffers. - */ - -static int sl_realloc_bufs(struct slip *sl, int mtu) -{ - int err = 0; - struct net_device *dev = sl->dev; - unsigned char *xbuff, *rbuff; -#ifdef SL_INCLUDE_CSLIP - unsigned char *cbuff; -#endif - int len = mtu * 2; - -/* - * allow for arrival of larger UDP packets, even if we say not to - * also fixes a bug in which SunOS sends 512-byte packets even with - * an MSS of 128 - */ - if (len < 576 * 2) - len = 576 * 2; - - xbuff = kmalloc(len + 4, GFP_ATOMIC); - rbuff = kmalloc(len + 4, GFP_ATOMIC); -#ifdef SL_INCLUDE_CSLIP - cbuff = kmalloc(len + 4, GFP_ATOMIC); -#endif - - -#ifdef SL_INCLUDE_CSLIP - if (xbuff == NULL || rbuff == NULL || cbuff == NULL) { -#else - if (xbuff == NULL || rbuff == NULL) { -#endif - if (mtu > sl->mtu) { - printk(KERN_WARNING "%s: unable to grow slip buffers, MTU change cancelled.\n", - dev->name); - err = -ENOBUFS; - } - goto done; - } - spin_lock_bh(&sl->lock); - - err = -ENODEV; - if (sl->tty == NULL) - goto done_on_bh; - - xbuff = xchg(&sl->xbuff, xbuff); - rbuff = xchg(&sl->rbuff, rbuff); -#ifdef SL_INCLUDE_CSLIP - cbuff = xchg(&sl->cbuff, cbuff); -#endif - if (sl->xleft) { - if (sl->xleft <= len) { - memcpy(sl->xbuff, sl->xhead, sl->xleft); - } else { - sl->xleft = 0; - dev->stats.tx_dropped++; - } - } - sl->xhead = sl->xbuff; - - if (sl->rcount) { - if (sl->rcount <= len) { - memcpy(sl->rbuff, rbuff, sl->rcount); - } else { - sl->rcount = 0; - dev->stats.rx_over_errors++; - set_bit(SLF_ERROR, &sl->flags); - } - } - sl->mtu = mtu; - dev->mtu = mtu; - sl->buffsize = len; - err = 0; - -done_on_bh: - spin_unlock_bh(&sl->lock); - -done: - kfree(xbuff); - kfree(rbuff); -#ifdef SL_INCLUDE_CSLIP - kfree(cbuff); -#endif - return err; -} - - -/* Set the "sending" flag. This must be atomic hence the set_bit. */ -static inline void sl_lock(struct slip *sl) -{ - netif_stop_queue(sl->dev); -} - - -/* Clear the "sending" flag. This must be atomic, hence the ASM. */ -static inline void sl_unlock(struct slip *sl) -{ - netif_wake_queue(sl->dev); -} - -/* Send one completely decapsulated IP datagram to the IP layer. */ -static void sl_bump(struct slip *sl) -{ - struct net_device *dev = sl->dev; - struct sk_buff *skb; - int count; - - count = sl->rcount; -#ifdef SL_INCLUDE_CSLIP - if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) { - unsigned char c = sl->rbuff[0]; - if (c & SL_TYPE_COMPRESSED_TCP) { - /* ignore compressed packets when CSLIP is off */ - if (!(sl->mode & SL_MODE_CSLIP)) { - printk(KERN_WARNING "%s: compressed packet ignored\n", dev->name); - return; - } - /* make sure we've reserved enough space for uncompress - to use */ - if (count + 80 > sl->buffsize) { - dev->stats.rx_over_errors++; - return; - } - count = slhc_uncompress(sl->slcomp, sl->rbuff, count); - if (count <= 0) - return; - } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) { - if (!(sl->mode & SL_MODE_CSLIP)) { - /* turn on header compression */ - sl->mode |= SL_MODE_CSLIP; - sl->mode &= ~SL_MODE_ADAPTIVE; - printk(KERN_INFO "%s: header compression turned on\n", dev->name); - } - sl->rbuff[0] &= 0x4f; - if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0) - return; - } - } -#endif /* SL_INCLUDE_CSLIP */ - - dev->stats.rx_bytes += count; - - skb = dev_alloc_skb(count); - if (skb == NULL) { - printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name); - dev->stats.rx_dropped++; - return; - } - skb->dev = dev; - memcpy(skb_put(skb, count), sl->rbuff, count); - skb_reset_mac_header(skb); - skb->protocol = htons(ETH_P_IP); - netif_rx_ni(skb); - dev->stats.rx_packets++; -} - -/* Encapsulate one IP datagram and stuff into a TTY queue. */ -static void sl_encaps(struct slip *sl, unsigned char *icp, int len) -{ - unsigned char *p; - int actual, count; - - if (len > sl->mtu) { /* Sigh, shouldn't occur BUT ... */ - printk(KERN_WARNING "%s: truncating oversized transmit packet!\n", sl->dev->name); - sl->dev->stats.tx_dropped++; - sl_unlock(sl); - return; - } - - p = icp; -#ifdef SL_INCLUDE_CSLIP - if (sl->mode & SL_MODE_CSLIP) - len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1); -#endif -#ifdef CONFIG_SLIP_MODE_SLIP6 - if (sl->mode & SL_MODE_SLIP6) - count = slip_esc6(p, (unsigned char *) sl->xbuff, len); - else -#endif - count = slip_esc(p, (unsigned char *) sl->xbuff, len); - - /* Order of next two lines is *very* important. - * When we are sending a little amount of data, - * the transfer may be completed inside the ops->write() - * routine, because it's running with interrupts enabled. - * In this case we *never* got WRITE_WAKEUP event, - * if we did not request it before write operation. - * 14 Oct 1994 Dmitry Gorodchanin. - */ - set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); - actual = sl->tty->ops->write(sl->tty, sl->xbuff, count); -#ifdef SL_CHECK_TRANSMIT - sl->dev->trans_start = jiffies; -#endif - sl->xleft = count - actual; - sl->xhead = sl->xbuff + actual; -#ifdef CONFIG_SLIP_SMART - /* VSV */ - clear_bit(SLF_OUTWAIT, &sl->flags); /* reset outfill flag */ -#endif -} - -/* - * Called by the driver when there's room for more data. If we have - * more packets to send, we send them here. - */ -static void slip_write_wakeup(struct tty_struct *tty) -{ - int actual; - struct slip *sl = tty->disc_data; - - /* First make sure we're connected. */ - if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev)) - return; - - if (sl->xleft <= 0) { - /* Now serial buffer is almost free & we can start - * transmission of another packet */ - sl->dev->stats.tx_packets++; - clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - sl_unlock(sl); - return; - } - - actual = tty->ops->write(tty, sl->xhead, sl->xleft); - sl->xleft -= actual; - sl->xhead += actual; -} - -static void sl_tx_timeout(struct net_device *dev) -{ - struct slip *sl = netdev_priv(dev); - - spin_lock(&sl->lock); - - if (netif_queue_stopped(dev)) { - if (!netif_running(dev)) - goto out; - - /* May be we must check transmitter timeout here ? - * 14 Oct 1994 Dmitry Gorodchanin. - */ -#ifdef SL_CHECK_TRANSMIT - if (time_before(jiffies, dev_trans_start(dev) + 20 * HZ)) { - /* 20 sec timeout not reached */ - goto out; - } - printk(KERN_WARNING "%s: transmit timed out, %s?\n", - dev->name, - (tty_chars_in_buffer(sl->tty) || sl->xleft) ? - "bad line quality" : "driver error"); - sl->xleft = 0; - clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); - sl_unlock(sl); -#endif - } -out: - spin_unlock(&sl->lock); -} - - -/* Encapsulate an IP datagram and kick it into a TTY queue. */ -static netdev_tx_t -sl_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct slip *sl = netdev_priv(dev); - - spin_lock(&sl->lock); - if (!netif_running(dev)) { - spin_unlock(&sl->lock); - printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - if (sl->tty == NULL) { - spin_unlock(&sl->lock); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - sl_lock(sl); - dev->stats.tx_bytes += skb->len; - sl_encaps(sl, skb->data, skb->len); - spin_unlock(&sl->lock); - - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - - -/****************************************** - * Routines looking at netdevice side. - ******************************************/ - -/* Netdevice UP -> DOWN routine */ - -static int -sl_close(struct net_device *dev) -{ - struct slip *sl = netdev_priv(dev); - - spin_lock_bh(&sl->lock); - if (sl->tty) - /* TTY discipline is running. */ - clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); - netif_stop_queue(dev); - sl->rcount = 0; - sl->xleft = 0; - spin_unlock_bh(&sl->lock); - - return 0; -} - -/* Netdevice DOWN -> UP routine */ - -static int sl_open(struct net_device *dev) -{ - struct slip *sl = netdev_priv(dev); - - if (sl->tty == NULL) - return -ENODEV; - - sl->flags &= (1 << SLF_INUSE); - netif_start_queue(dev); - return 0; -} - -/* Netdevice change MTU request */ - -static int sl_change_mtu(struct net_device *dev, int new_mtu) -{ - struct slip *sl = netdev_priv(dev); - - if (new_mtu < 68 || new_mtu > 65534) - return -EINVAL; - - if (new_mtu != dev->mtu) - return sl_realloc_bufs(sl, new_mtu); - return 0; -} - -/* Netdevice get statistics request */ - -static struct rtnl_link_stats64 * -sl_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) -{ - struct net_device_stats *devstats = &dev->stats; -#ifdef SL_INCLUDE_CSLIP - struct slip *sl = netdev_priv(dev); - struct slcompress *comp = sl->slcomp; -#endif - stats->rx_packets = devstats->rx_packets; - stats->tx_packets = devstats->tx_packets; - stats->rx_bytes = devstats->rx_bytes; - stats->tx_bytes = devstats->tx_bytes; - stats->rx_dropped = devstats->rx_dropped; - stats->tx_dropped = devstats->tx_dropped; - stats->tx_errors = devstats->tx_errors; - stats->rx_errors = devstats->rx_errors; - stats->rx_over_errors = devstats->rx_over_errors; - -#ifdef SL_INCLUDE_CSLIP - if (comp) { - /* Generic compressed statistics */ - stats->rx_compressed = comp->sls_i_compressed; - stats->tx_compressed = comp->sls_o_compressed; - - /* Are we really still needs this? */ - stats->rx_fifo_errors += comp->sls_i_compressed; - stats->rx_dropped += comp->sls_i_tossed; - stats->tx_fifo_errors += comp->sls_o_compressed; - stats->collisions += comp->sls_o_misses; - } -#endif - return stats; -} - -/* Netdevice register callback */ - -static int sl_init(struct net_device *dev) -{ - struct slip *sl = netdev_priv(dev); - - /* - * Finish setting up the DEVICE info. - */ - - dev->mtu = sl->mtu; - dev->type = ARPHRD_SLIP + sl->mode; -#ifdef SL_CHECK_TRANSMIT - dev->watchdog_timeo = 20*HZ; -#endif - return 0; -} - - -static void sl_uninit(struct net_device *dev) -{ - struct slip *sl = netdev_priv(dev); - - sl_free_bufs(sl); -} - -/* Hook the destructor so we can free slip devices at the right point in time */ -static void sl_free_netdev(struct net_device *dev) -{ - int i = dev->base_addr; - free_netdev(dev); - slip_devs[i] = NULL; -} - -static const struct net_device_ops sl_netdev_ops = { - .ndo_init = sl_init, - .ndo_uninit = sl_uninit, - .ndo_open = sl_open, - .ndo_stop = sl_close, - .ndo_start_xmit = sl_xmit, - .ndo_get_stats64 = sl_get_stats64, - .ndo_change_mtu = sl_change_mtu, - .ndo_tx_timeout = sl_tx_timeout, -#ifdef CONFIG_SLIP_SMART - .ndo_do_ioctl = sl_ioctl, -#endif -}; - - -static void sl_setup(struct net_device *dev) -{ - dev->netdev_ops = &sl_netdev_ops; - dev->destructor = sl_free_netdev; - - dev->hard_header_len = 0; - dev->addr_len = 0; - dev->tx_queue_len = 10; - - /* New-style flags. */ - dev->flags = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST; -} - -/****************************************** - Routines looking at TTY side. - ******************************************/ - - -/* - * Handle the 'receiver data ready' interrupt. - * This function is called by the 'tty_io' module in the kernel when - * a block of SLIP data has been received, which can now be decapsulated - * and sent on to some IP layer for further processing. This will not - * be re-entered while running but other ldisc functions may be called - * in parallel - */ - -static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) -{ - struct slip *sl = tty->disc_data; - - if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev)) - return; - - /* Read the characters out of the buffer */ - while (count--) { - if (fp && *fp++) { - if (!test_and_set_bit(SLF_ERROR, &sl->flags)) - sl->dev->stats.rx_errors++; - cp++; - continue; - } -#ifdef CONFIG_SLIP_MODE_SLIP6 - if (sl->mode & SL_MODE_SLIP6) - slip_unesc6(sl, *cp++); - else -#endif - slip_unesc(sl, *cp++); - } -} - -/************************************ - * slip_open helper routines. - ************************************/ - -/* Collect hanged up channels */ -static void sl_sync(void) -{ - int i; - struct net_device *dev; - struct slip *sl; - - for (i = 0; i < slip_maxdev; i++) { - dev = slip_devs[i]; - if (dev == NULL) - break; - - sl = netdev_priv(dev); - if (sl->tty || sl->leased) - continue; - if (dev->flags & IFF_UP) - dev_close(dev); - } -} - - -/* Find a free SLIP channel, and link in this `tty' line. */ -static struct slip *sl_alloc(dev_t line) -{ - int i; - char name[IFNAMSIZ]; - struct net_device *dev = NULL; - struct slip *sl; - - for (i = 0; i < slip_maxdev; i++) { - dev = slip_devs[i]; - if (dev == NULL) - break; - } - /* Sorry, too many, all slots in use */ - if (i >= slip_maxdev) - return NULL; - - sprintf(name, "sl%d", i); - dev = alloc_netdev(sizeof(*sl), name, sl_setup); - if (!dev) - return NULL; - - dev->base_addr = i; - sl = netdev_priv(dev); - - /* Initialize channel control data */ - sl->magic = SLIP_MAGIC; - sl->dev = dev; - spin_lock_init(&sl->lock); - sl->mode = SL_MODE_DEFAULT; -#ifdef CONFIG_SLIP_SMART - /* initialize timer_list struct */ - init_timer(&sl->keepalive_timer); - sl->keepalive_timer.data = (unsigned long)sl; - sl->keepalive_timer.function = sl_keepalive; - init_timer(&sl->outfill_timer); - sl->outfill_timer.data = (unsigned long)sl; - sl->outfill_timer.function = sl_outfill; -#endif - slip_devs[i] = dev; - return sl; -} - -/* - * Open the high-level part of the SLIP channel. - * This function is called by the TTY module when the - * SLIP line discipline is called for. Because we are - * sure the tty line exists, we only have to link it to - * a free SLIP channel... - * - * Called in process context serialized from other ldisc calls. - */ - -static int slip_open(struct tty_struct *tty) -{ - struct slip *sl; - int err; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (tty->ops->write == NULL) - return -EOPNOTSUPP; - - /* RTnetlink lock is misused here to serialize concurrent - opens of slip channels. There are better ways, but it is - the simplest one. - */ - rtnl_lock(); - - /* Collect hanged up channels. */ - sl_sync(); - - sl = tty->disc_data; - - err = -EEXIST; - /* First make sure we're not already connected. */ - if (sl && sl->magic == SLIP_MAGIC) - goto err_exit; - - /* OK. Find a free SLIP channel to use. */ - err = -ENFILE; - sl = sl_alloc(tty_devnum(tty)); - if (sl == NULL) - goto err_exit; - - sl->tty = tty; - tty->disc_data = sl; - sl->pid = current->pid; - - if (!test_bit(SLF_INUSE, &sl->flags)) { - /* Perform the low-level SLIP initialization. */ - err = sl_alloc_bufs(sl, SL_MTU); - if (err) - goto err_free_chan; - - set_bit(SLF_INUSE, &sl->flags); - - err = register_netdevice(sl->dev); - if (err) - goto err_free_bufs; - } - -#ifdef CONFIG_SLIP_SMART - if (sl->keepalive) { - sl->keepalive_timer.expires = jiffies + sl->keepalive * HZ; - add_timer(&sl->keepalive_timer); - } - if (sl->outfill) { - sl->outfill_timer.expires = jiffies + sl->outfill * HZ; - add_timer(&sl->outfill_timer); - } -#endif - - /* Done. We have linked the TTY line to a channel. */ - rtnl_unlock(); - tty->receive_room = 65536; /* We don't flow control */ - - /* TTY layer expects 0 on success */ - return 0; - -err_free_bufs: - sl_free_bufs(sl); - -err_free_chan: - sl->tty = NULL; - tty->disc_data = NULL; - clear_bit(SLF_INUSE, &sl->flags); - -err_exit: - rtnl_unlock(); - - /* Count references from TTY module */ - return err; -} - -/* - * Close down a SLIP channel. - * This means flushing out any pending queues, and then returning. This - * call is serialized against other ldisc functions. - * - * We also use this method fo a hangup event - */ - -static void slip_close(struct tty_struct *tty) -{ - struct slip *sl = tty->disc_data; - - /* First make sure we're connected. */ - if (!sl || sl->magic != SLIP_MAGIC || sl->tty != tty) - return; - - tty->disc_data = NULL; - sl->tty = NULL; - - /* VSV = very important to remove timers */ -#ifdef CONFIG_SLIP_SMART - del_timer_sync(&sl->keepalive_timer); - del_timer_sync(&sl->outfill_timer); -#endif - /* Flush network side */ - unregister_netdev(sl->dev); - /* This will complete via sl_free_netdev */ -} - -static int slip_hangup(struct tty_struct *tty) -{ - slip_close(tty); - return 0; -} - /************************************************************************ - * STANDARD SLIP ENCAPSULATION * - ************************************************************************/ - -static int slip_esc(unsigned char *s, unsigned char *d, int len) -{ - unsigned char *ptr = d; - unsigned char c; - - /* - * Send an initial END character to flush out any - * data that may have accumulated in the receiver - * due to line noise. - */ - - *ptr++ = END; - - /* - * For each byte in the packet, send the appropriate - * character sequence, according to the SLIP protocol. - */ - - while (len-- > 0) { - switch (c = *s++) { - case END: - *ptr++ = ESC; - *ptr++ = ESC_END; - break; - case ESC: - *ptr++ = ESC; - *ptr++ = ESC_ESC; - break; - default: - *ptr++ = c; - break; - } - } - *ptr++ = END; - return ptr - d; -} - -static void slip_unesc(struct slip *sl, unsigned char s) -{ - - switch (s) { - case END: -#ifdef CONFIG_SLIP_SMART - /* drop keeptest bit = VSV */ - if (test_bit(SLF_KEEPTEST, &sl->flags)) - clear_bit(SLF_KEEPTEST, &sl->flags); -#endif - - if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && - (sl->rcount > 2)) - sl_bump(sl); - clear_bit(SLF_ESCAPE, &sl->flags); - sl->rcount = 0; - return; - - case ESC: - set_bit(SLF_ESCAPE, &sl->flags); - return; - case ESC_ESC: - if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) - s = ESC; - break; - case ESC_END: - if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) - s = END; - break; - } - if (!test_bit(SLF_ERROR, &sl->flags)) { - if (sl->rcount < sl->buffsize) { - sl->rbuff[sl->rcount++] = s; - return; - } - sl->dev->stats.rx_over_errors++; - set_bit(SLF_ERROR, &sl->flags); - } -} - - -#ifdef CONFIG_SLIP_MODE_SLIP6 -/************************************************************************ - * 6 BIT SLIP ENCAPSULATION * - ************************************************************************/ - -static int slip_esc6(unsigned char *s, unsigned char *d, int len) -{ - unsigned char *ptr = d; - unsigned char c; - int i; - unsigned short v = 0; - short bits = 0; - - /* - * Send an initial END character to flush out any - * data that may have accumulated in the receiver - * due to line noise. - */ - - *ptr++ = 0x70; - - /* - * Encode the packet into printable ascii characters - */ - - for (i = 0; i < len; ++i) { - v = (v << 8) | s[i]; - bits += 8; - while (bits >= 6) { - bits -= 6; - c = 0x30 + ((v >> bits) & 0x3F); - *ptr++ = c; - } - } - if (bits) { - c = 0x30 + ((v << (6 - bits)) & 0x3F); - *ptr++ = c; - } - *ptr++ = 0x70; - return ptr - d; -} - -static void slip_unesc6(struct slip *sl, unsigned char s) -{ - unsigned char c; - - if (s == 0x70) { -#ifdef CONFIG_SLIP_SMART - /* drop keeptest bit = VSV */ - if (test_bit(SLF_KEEPTEST, &sl->flags)) - clear_bit(SLF_KEEPTEST, &sl->flags); -#endif - - if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && - (sl->rcount > 2)) - sl_bump(sl); - sl->rcount = 0; - sl->xbits = 0; - sl->xdata = 0; - } else if (s >= 0x30 && s < 0x70) { - sl->xdata = (sl->xdata << 6) | ((s - 0x30) & 0x3F); - sl->xbits += 6; - if (sl->xbits >= 8) { - sl->xbits -= 8; - c = (unsigned char)(sl->xdata >> sl->xbits); - if (!test_bit(SLF_ERROR, &sl->flags)) { - if (sl->rcount < sl->buffsize) { - sl->rbuff[sl->rcount++] = c; - return; - } - sl->dev->stats.rx_over_errors++; - set_bit(SLF_ERROR, &sl->flags); - } - } - } -} -#endif /* CONFIG_SLIP_MODE_SLIP6 */ - -/* Perform I/O control on an active SLIP channel. */ -static int slip_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct slip *sl = tty->disc_data; - unsigned int tmp; - int __user *p = (int __user *)arg; - - /* First make sure we're connected. */ - if (!sl || sl->magic != SLIP_MAGIC) - return -EINVAL; - - switch (cmd) { - case SIOCGIFNAME: - tmp = strlen(sl->dev->name) + 1; - if (copy_to_user((void __user *)arg, sl->dev->name, tmp)) - return -EFAULT; - return 0; - - case SIOCGIFENCAP: - if (put_user(sl->mode, p)) - return -EFAULT; - return 0; - - case SIOCSIFENCAP: - if (get_user(tmp, p)) - return -EFAULT; -#ifndef SL_INCLUDE_CSLIP - if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE)) - return -EINVAL; -#else - if ((tmp & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) == - (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) - /* return -EINVAL; */ - tmp &= ~SL_MODE_ADAPTIVE; -#endif -#ifndef CONFIG_SLIP_MODE_SLIP6 - if (tmp & SL_MODE_SLIP6) - return -EINVAL; -#endif - sl->mode = tmp; - sl->dev->type = ARPHRD_SLIP + sl->mode; - return 0; - - case SIOCSIFHWADDR: - return -EINVAL; - -#ifdef CONFIG_SLIP_SMART - /* VSV changes start here */ - case SIOCSKEEPALIVE: - if (get_user(tmp, p)) - return -EFAULT; - if (tmp > 255) /* max for unchar */ - return -EINVAL; - - spin_lock_bh(&sl->lock); - if (!sl->tty) { - spin_unlock_bh(&sl->lock); - return -ENODEV; - } - sl->keepalive = (u8)tmp; - if (sl->keepalive != 0) { - mod_timer(&sl->keepalive_timer, - jiffies + sl->keepalive * HZ); - set_bit(SLF_KEEPTEST, &sl->flags); - } else - del_timer(&sl->keepalive_timer); - spin_unlock_bh(&sl->lock); - return 0; - - case SIOCGKEEPALIVE: - if (put_user(sl->keepalive, p)) - return -EFAULT; - return 0; - - case SIOCSOUTFILL: - if (get_user(tmp, p)) - return -EFAULT; - if (tmp > 255) /* max for unchar */ - return -EINVAL; - spin_lock_bh(&sl->lock); - if (!sl->tty) { - spin_unlock_bh(&sl->lock); - return -ENODEV; - } - sl->outfill = (u8)tmp; - if (sl->outfill != 0) { - mod_timer(&sl->outfill_timer, - jiffies + sl->outfill * HZ); - set_bit(SLF_OUTWAIT, &sl->flags); - } else - del_timer(&sl->outfill_timer); - spin_unlock_bh(&sl->lock); - return 0; - - case SIOCGOUTFILL: - if (put_user(sl->outfill, p)) - return -EFAULT; - return 0; - /* VSV changes end */ -#endif - default: - return tty_mode_ioctl(tty, file, cmd, arg); - } -} - -#ifdef CONFIG_COMPAT -static long slip_compat_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case SIOCGIFNAME: - case SIOCGIFENCAP: - case SIOCSIFENCAP: - case SIOCSIFHWADDR: - case SIOCSKEEPALIVE: - case SIOCGKEEPALIVE: - case SIOCSOUTFILL: - case SIOCGOUTFILL: - return slip_ioctl(tty, file, cmd, - (unsigned long)compat_ptr(arg)); - } - - return -ENOIOCTLCMD; -} -#endif - -/* VSV changes start here */ -#ifdef CONFIG_SLIP_SMART -/* function do_ioctl called from net/core/dev.c - to allow get/set outfill/keepalive parameter - by ifconfig */ - -static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct slip *sl = netdev_priv(dev); - unsigned long *p = (unsigned long *)&rq->ifr_ifru; - - if (sl == NULL) /* Allocation failed ?? */ - return -ENODEV; - - spin_lock_bh(&sl->lock); - - if (!sl->tty) { - spin_unlock_bh(&sl->lock); - return -ENODEV; - } - - switch (cmd) { - case SIOCSKEEPALIVE: - /* max for unchar */ - if ((unsigned)*p > 255) { - spin_unlock_bh(&sl->lock); - return -EINVAL; - } - sl->keepalive = (u8)*p; - if (sl->keepalive != 0) { - sl->keepalive_timer.expires = - jiffies + sl->keepalive * HZ; - mod_timer(&sl->keepalive_timer, - jiffies + sl->keepalive * HZ); - set_bit(SLF_KEEPTEST, &sl->flags); - } else - del_timer(&sl->keepalive_timer); - break; - - case SIOCGKEEPALIVE: - *p = sl->keepalive; - break; - - case SIOCSOUTFILL: - if ((unsigned)*p > 255) { /* max for unchar */ - spin_unlock_bh(&sl->lock); - return -EINVAL; - } - sl->outfill = (u8)*p; - if (sl->outfill != 0) { - mod_timer(&sl->outfill_timer, - jiffies + sl->outfill * HZ); - set_bit(SLF_OUTWAIT, &sl->flags); - } else - del_timer(&sl->outfill_timer); - break; - - case SIOCGOUTFILL: - *p = sl->outfill; - break; - - case SIOCSLEASE: - /* Resolve race condition, when ioctl'ing hanged up - and opened by another process device. - */ - if (sl->tty != current->signal->tty && - sl->pid != current->pid) { - spin_unlock_bh(&sl->lock); - return -EPERM; - } - sl->leased = 0; - if (*p) - sl->leased = 1; - break; - - case SIOCGLEASE: - *p = sl->leased; - } - spin_unlock_bh(&sl->lock); - return 0; -} -#endif -/* VSV changes end */ - -static struct tty_ldisc_ops sl_ldisc = { - .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, - .name = "slip", - .open = slip_open, - .close = slip_close, - .hangup = slip_hangup, - .ioctl = slip_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = slip_compat_ioctl, -#endif - .receive_buf = slip_receive_buf, - .write_wakeup = slip_write_wakeup, -}; - -static int __init slip_init(void) -{ - int status; - - if (slip_maxdev < 4) - slip_maxdev = 4; /* Sanity */ - - printk(KERN_INFO "SLIP: version %s (dynamic channels, max=%d)" -#ifdef CONFIG_SLIP_MODE_SLIP6 - " (6 bit encapsulation enabled)" -#endif - ".\n", - SLIP_VERSION, slip_maxdev); -#if defined(SL_INCLUDE_CSLIP) - printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California.\n"); -#endif -#ifdef CONFIG_SLIP_SMART - printk(KERN_INFO "SLIP linefill/keepalive option.\n"); -#endif - - slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev, - GFP_KERNEL); - if (!slip_devs) { - printk(KERN_ERR "SLIP: Can't allocate slip devices array.\n"); - return -ENOMEM; - } - - /* Fill in our line protocol discipline, and register it */ - status = tty_register_ldisc(N_SLIP, &sl_ldisc); - if (status != 0) { - printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status); - kfree(slip_devs); - } - return status; -} - -static void __exit slip_exit(void) -{ - int i; - struct net_device *dev; - struct slip *sl; - unsigned long timeout = jiffies + HZ; - int busy = 0; - - if (slip_devs == NULL) - return; - - /* First of all: check for active disciplines and hangup them. - */ - do { - if (busy) - msleep_interruptible(100); - - busy = 0; - for (i = 0; i < slip_maxdev; i++) { - dev = slip_devs[i]; - if (!dev) - continue; - sl = netdev_priv(dev); - spin_lock_bh(&sl->lock); - if (sl->tty) { - busy++; - tty_hangup(sl->tty); - } - spin_unlock_bh(&sl->lock); - } - } while (busy && time_before(jiffies, timeout)); - - /* FIXME: hangup is async so we should wait when doing this second - phase */ - - for (i = 0; i < slip_maxdev; i++) { - dev = slip_devs[i]; - if (!dev) - continue; - slip_devs[i] = NULL; - - sl = netdev_priv(dev); - if (sl->tty) { - printk(KERN_ERR "%s: tty discipline still running\n", - dev->name); - /* Intentionally leak the control block. */ - dev->destructor = NULL; - } - - unregister_netdev(dev); - } - - kfree(slip_devs); - slip_devs = NULL; - - i = tty_unregister_ldisc(N_SLIP); - if (i != 0) - printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)\n", i); -} - -module_init(slip_init); -module_exit(slip_exit); - -#ifdef CONFIG_SLIP_SMART -/* - * This is start of the code for multislip style line checking - * added by Stanislav Voronyi. All changes before marked VSV - */ - -static void sl_outfill(unsigned long sls) -{ - struct slip *sl = (struct slip *)sls; - - spin_lock(&sl->lock); - - if (sl->tty == NULL) - goto out; - - if (sl->outfill) { - if (test_bit(SLF_OUTWAIT, &sl->flags)) { - /* no packets were transmitted, do outfill */ -#ifdef CONFIG_SLIP_MODE_SLIP6 - unsigned char s = (sl->mode & SL_MODE_SLIP6)?0x70:END; -#else - unsigned char s = END; -#endif - /* put END into tty queue. Is it right ??? */ - if (!netif_queue_stopped(sl->dev)) { - /* if device busy no outfill */ - sl->tty->ops->write(sl->tty, &s, 1); - } - } else - set_bit(SLF_OUTWAIT, &sl->flags); - - mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ); - } -out: - spin_unlock(&sl->lock); -} - -static void sl_keepalive(unsigned long sls) -{ - struct slip *sl = (struct slip *)sls; - - spin_lock(&sl->lock); - - if (sl->tty == NULL) - goto out; - - if (sl->keepalive) { - if (test_bit(SLF_KEEPTEST, &sl->flags)) { - /* keepalive still high :(, we must hangup */ - if (sl->outfill) - /* outfill timer must be deleted too */ - (void)del_timer(&sl->outfill_timer); - printk(KERN_DEBUG "%s: no packets received during keepalive timeout, hangup.\n", sl->dev->name); - /* this must hangup tty & close slip */ - tty_hangup(sl->tty); - /* I think we need not something else */ - goto out; - } else - set_bit(SLF_KEEPTEST, &sl->flags); - - mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ); - } -out: - spin_unlock(&sl->lock); -} - -#endif -MODULE_LICENSE("GPL"); -MODULE_ALIAS_LDISC(N_SLIP); diff --git a/drivers/net/slip.h b/drivers/net/slip.h deleted file mode 100644 index 67673cf..0000000 --- a/drivers/net/slip.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * slip.h Define the SLIP device driver interface and constants. - * - * NOTE: THIS FILE WILL BE MOVED TO THE LINUX INCLUDE DIRECTORY - * AS SOON AS POSSIBLE! - * - * Version: @(#)slip.h 1.2.0 03/28/93 - * - * Fixes: - * Alan Cox : Added slip mtu field. - * Matt Dillon : Printable slip (borrowed from net2e) - * Alan Cox : Added SL_SLIP_LOTS - * Dmitry Gorodchanin : A lot of changes in the 'struct slip' - * Dmitry Gorodchanin : Added CSLIP statistics. - * Stanislav Voronyi : Make line checking as created by - * Igor Chechik, RELCOM Corp. - * Craig Schlenter : Fixed #define bug that caused - * CSLIP telnets to hang in 1.3.61-6 - * - * Author: Fred N. van Kempen, - */ -#ifndef _LINUX_SLIP_H -#define _LINUX_SLIP_H - - -#if defined(CONFIG_INET) && defined(CONFIG_SLIP_COMPRESSED) -# define SL_INCLUDE_CSLIP -#endif - -#ifdef SL_INCLUDE_CSLIP -# define SL_MODE_DEFAULT SL_MODE_ADAPTIVE -#else -# define SL_MODE_DEFAULT SL_MODE_SLIP -#endif - -/* SLIP configuration. */ -#define SL_NRUNIT 256 /* MAX number of SLIP channels; - This can be overridden with - insmod -oslip_maxdev=nnn */ -#define SL_MTU 296 /* 296; I am used to 600- FvK */ - -/* SLIP protocol characters. */ -#define END 0300 /* indicates end of frame */ -#define ESC 0333 /* indicates byte stuffing */ -#define ESC_END 0334 /* ESC ESC_END means END 'data' */ -#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ - - -struct slip { - int magic; - - /* Various fields. */ - struct tty_struct *tty; /* ptr to TTY structure */ - struct net_device *dev; /* easy for intr handling */ - spinlock_t lock; - -#ifdef SL_INCLUDE_CSLIP - struct slcompress *slcomp; /* for header compression */ - unsigned char *cbuff; /* compression buffer */ -#endif - - /* 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 */ - int mtu; /* Our mtu (to spot changes!) */ - int buffsize; /* Max buffers sizes */ - -#ifdef CONFIG_SLIP_MODE_SLIP6 - int xdata, xbits; /* 6 bit slip controls */ -#endif - - unsigned long flags; /* Flag values/ mode etc */ -#define SLF_INUSE 0 /* Channel in use */ -#define SLF_ESCAPE 1 /* ESC received */ -#define SLF_ERROR 2 /* Parity, etc. error */ -#define SLF_KEEPTEST 3 /* Keepalive test flag */ -#define SLF_OUTWAIT 4 /* is outpacket was flag */ - - unsigned char mode; /* SLIP mode */ - unsigned char leased; - pid_t pid; -#define SL_MODE_SLIP 0 -#define SL_MODE_CSLIP 1 -#define SL_MODE_SLIP6 2 /* Matt Dillon's printable slip */ -#define SL_MODE_CSLIP6 (SL_MODE_SLIP6|SL_MODE_CSLIP) -#define SL_MODE_AX25 4 -#define SL_MODE_ADAPTIVE 8 -#ifdef CONFIG_SLIP_SMART - unsigned char outfill; /* # of sec between outfill packet */ - unsigned char keepalive; /* keepalive seconds */ - struct timer_list outfill_timer; - struct timer_list keepalive_timer; -#endif -}; - -#define SLIP_MAGIC 0x5302 - -#endif /* _LINUX_SLIP.H */ diff --git a/drivers/net/slip/Kconfig b/drivers/net/slip/Kconfig new file mode 100644 index 0000000..211b160 --- /dev/null +++ b/drivers/net/slip/Kconfig @@ -0,0 +1,79 @@ +# +# SLIP network device configuration +# + +config SLIP + tristate "SLIP (serial line) support" + ---help--- + Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to + connect to your Internet service provider or to connect to some + other local Unix box or if you want to configure your Linux box as a + Slip/CSlip server for other people to dial in. SLIP (Serial Line + Internet Protocol) is a protocol used to send Internet traffic over + serial connections such as telephone lines or null modem cables; + nowadays, the protocol PPP is more commonly used for this same + purpose. + + Normally, your access provider has to support SLIP in order for you + to be able to use it, but there is now a SLIP emulator called SLiRP + around (available from + ) which + allows you to use SLIP over a regular dial up shell connection. If + you plan to use SLiRP, make sure to say Y to CSLIP, below. The + NET-3-HOWTO, available from + , explains how to + configure SLIP. Note that you don't need this option if you just + want to run term (term is a program which gives you almost full + Internet connectivity if you have a regular dial up shell account on + some Internet connected Unix computer. Read + ). SLIP + support will enlarge your kernel by about 4 KB. If unsure, say N. + + To compile this driver as a module, choose M here. The module + will be called slip. + +config SLHC + tristate + ---help--- + This option enables Van Jacobsen serial line header compression + routines. + +if SLIP + +config SLIP_COMPRESSED + bool "CSLIP compressed headers" + depends on SLIP + select SLHC + ---help--- + This protocol is faster than SLIP because it uses compression on the + TCP/IP headers (not on the data itself), but it has to be supported + on both ends. Ask your access provider if you are not sure and + answer Y, just in case. You will still be able to use plain SLIP. If + you plan to use SLiRP, the SLIP emulator (available from + ) which + allows you to use SLIP over a regular dial up shell connection, you + definitely want to say Y here. The NET-3-HOWTO, available from + , explains how to configure + CSLIP. This won't enlarge your kernel. + +config SLIP_SMART + bool "Keepalive and linefill" + depends on SLIP + ---help--- + Adds additional capabilities to the SLIP driver to support the + RELCOM line fill and keepalive monitoring. Ideal on poor quality + analogue lines. + +config SLIP_MODE_SLIP6 + bool "Six bit SLIP encapsulation" + depends on SLIP + ---help--- + Just occasionally you may need to run IP over hostile serial + networks that don't pass all control characters or are only seven + bit. Saying Y here adds an extra mode you can use with SLIP: + "slip6". In this mode, SLIP will only send normal ASCII symbols over + the serial device. Naturally, this has to be supported at the other + end of the link as well. It's good enough, for example, to run IP + over the async ports of a Camtec JNT Pad. If unsure, say N. + +endif # SLIP diff --git a/drivers/net/slip/Makefile b/drivers/net/slip/Makefile new file mode 100644 index 0000000..e3ebc59 --- /dev/null +++ b/drivers/net/slip/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the SLIP network device drivers. +# + +obj-$(CONFIG_SLIP) += slip.o +obj-$(CONFIG_SLHC) += slhc.o diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c new file mode 100644 index 0000000..0a0a664 --- /dev/null +++ b/drivers/net/slip/slhc.c @@ -0,0 +1,742 @@ +/* + * Routines to compress and uncompress tcp packets (for transmission + * over low speed serial lines). + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens@ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation (from 1.19) + * PPP.05 02-15-90 [ks] + * PPP.08 05-02-90 [ks] use PPP protocol field to signal compression + * PPP.15 09-90 [ks] improve mbuf handling + * PPP.16 11-02 [karn] substantially rewritten to use NOS facilities + * + * - Feb 1991 Bill_Simpson@um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + * - Jul 1994 Dmitry Gorodchanin + * Fixes for memory leaks. + * - Oct 1994 Dmitry Gorodchanin + * Modularization. + * - Jan 1995 Bjorn Ekwall + * Use ip_fast_csum from ip.h + * - July 1995 Christos A. Polyzols + * Spotted bug in tcp option checking + * + * + * This module is a difficult issue. It's clearly inet code but it's also clearly + * driver code belonging close to PPP and SLIP + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_INET +/* Entire module is for IP only */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned char *encode(unsigned char *cp, unsigned short n); +static long decode(unsigned char **cpp); +static unsigned char * put16(unsigned char *cp, unsigned short x); +static unsigned short pull16(unsigned char **cpp); + +/* Initialize compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) + */ +struct slcompress * +slhc_init(int rslots, int tslots) +{ + register short i; + register struct cstate *ts; + struct slcompress *comp; + + comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + if (! comp) + goto out_fail; + + if ( rslots > 0 && rslots < 256 ) { + size_t rsize = rslots * sizeof(struct cstate); + comp->rstate = kzalloc(rsize, GFP_KERNEL); + if (! comp->rstate) + goto out_free; + comp->rslot_limit = rslots - 1; + } + + if ( tslots > 0 && tslots < 256 ) { + size_t tsize = tslots * sizeof(struct cstate); + comp->tstate = kzalloc(tsize, GFP_KERNEL); + if (! comp->tstate) + goto out_free2; + comp->tslot_limit = tslots - 1; + } + + comp->xmit_oldest = 0; + comp->xmit_current = 255; + comp->recv_current = 255; + /* + * don't accept any packets with implicit index until we get + * one with an explicit index. Otherwise the uncompress code + * will try to use connection 255, which is almost certainly + * out of range + */ + comp->flags |= SLF_TOSS; + + if ( tslots > 0 ) { + ts = comp->tstate; + for(i = comp->tslot_limit; i > 0; --i){ + ts[i].cs_this = i; + ts[i].next = &(ts[i - 1]); + } + ts[0].next = &(ts[comp->tslot_limit]); + ts[0].cs_this = 0; + } + return comp; + +out_free2: + kfree(comp->rstate); +out_free: + kfree(comp); +out_fail: + return NULL; +} + + +/* Free a compression data structure */ +void +slhc_free(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return; + + if ( comp->tstate != NULLSLSTATE ) + kfree( comp->tstate ); + + if ( comp->rstate != NULLSLSTATE ) + kfree( comp->rstate ); + + kfree( comp ); +} + + +/* Put a short in host order into a char array in network order */ +static inline unsigned char * +put16(unsigned char *cp, unsigned short x) +{ + *cp++ = x >> 8; + *cp++ = x; + + return cp; +} + + +/* Encode a number */ +static unsigned char * +encode(unsigned char *cp, unsigned short n) +{ + if(n >= 256 || n == 0){ + *cp++ = 0; + cp = put16(cp,n); + } else { + *cp++ = n; + } + return cp; +} + +/* Pull a 16-bit integer in host order from buffer in network byte order */ +static unsigned short +pull16(unsigned char **cpp) +{ + short rval; + + rval = *(*cpp)++; + rval <<= 8; + rval |= *(*cpp)++; + return rval; +} + +/* Decode a number */ +static long +decode(unsigned char **cpp) +{ + register int x; + + x = *(*cpp)++; + if(x == 0){ + return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ + } else { + return x & 0xff; /* -1 if PULLCHAR returned error */ + } +} + +/* + * icp and isize are the original packet. + * ocp is a place to put a copy if necessary. + * cpp is initially a pointer to icp. If the copy is used, + * change it to ocp. + */ + +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]); + register struct cstate *lcs = ocs; + register struct cstate *cs = lcs->next; + register unsigned long deltaS, deltaA; + register short changes = 0; + int hlen; + unsigned char new_seq[16]; + register unsigned char *cp = new_seq; + struct iphdr *ip; + struct tcphdr *th, *oth; + __sum16 csum; + + + /* + * Don't play with runt packets. + */ + + if(isizeprotocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) { + /* Send as regular IP */ + if(ip->protocol != IPPROTO_TCP) + comp->sls_o_nontcp++; + else + comp->sls_o_tcp++; + return isize; + } + /* Extract TCP header */ + + th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4); + hlen = ip->ihl*4 + th->doff*4; + + /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or + * some other control bit is set). Also uncompressible if + * it's a runt. + */ + if(hlen > isize || th->syn || th->fin || th->rst || + ! (th->ack)){ + /* TCP connection stuff; send as regular IP */ + comp->sls_o_tcp++; + return isize; + } + /* + * Packet is compressible -- we're going to send either a + * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way, + * we need to locate (or create) the connection state. + * + * States are kept in a circularly linked list with + * xmit_oldest pointing to the end of the list. The + * list is kept in lru order by moving a state to the + * head of the list whenever it is referenced. Since + * the list is short and, empirically, the connection + * we want is almost always near the front, we locate + * states via linear search. If we don't find a state + * for the datagram, the oldest state is (re-)used. + */ + for ( ; ; ) { + if( ip->saddr == cs->cs_ip.saddr + && ip->daddr == cs->cs_ip.daddr + && th->source == cs->cs_tcp.source + && th->dest == cs->cs_tcp.dest) + goto found; + + /* if current equal oldest, at end of list */ + if ( cs == ocs ) + break; + lcs = cs; + cs = cs->next; + comp->sls_o_searches++; + } + /* + * Didn't find it -- re-use oldest cstate. Send an + * uncompressed packet that tells the other side what + * connection number we're using for this conversation. + * + * Note that since the state list is circular, the oldest + * state points to the newest and we only need to set + * xmit_oldest to update the lru linkage. + */ + comp->sls_o_misses++; + comp->xmit_oldest = lcs->cs_this; + goto uncompressed; + +found: + /* + * Found it -- move to the front on the connection list. + */ + if(lcs == ocs) { + /* found at most recently used */ + } else if (cs == ocs) { + /* found at least recently used */ + comp->xmit_oldest = lcs->cs_this; + } else { + /* more than 2 elements */ + lcs->next = cs->next; + cs->next = ocs->next; + ocs->next = cs; + } + + /* + * Make sure that only what we expect to change changed. + * Check the following: + * IP protocol version, header length & type of service. + * The "Don't fragment" bit. + * The time-to-live field. + * The TCP header length. + * IP options, if any. + * TCP options, if any. + * If any of these things are different between the previous & + * current datagram, we send the current datagram `uncompressed'. + */ + oth = &cs->cs_tcp; + + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl + || ip->tos != cs->cs_ip.tos + || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) + || ip->ttl != cs->cs_ip.ttl + || th->doff != cs->cs_tcp.doff + || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) + || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ + goto uncompressed; + } + + /* + * Figure out which of the changing fields changed. The + * receiver expects changes in the order: urgent, window, + * ack, seq (the order minimizes the number of temporaries + * needed in this section of code). + */ + if(th->urg){ + deltaS = ntohs(th->urg_ptr); + cp = encode(cp,deltaS); + changes |= NEW_U; + } else if(th->urg_ptr != oth->urg_ptr){ + /* argh! URG not set but urp changed -- a sensible + * implementation should never do this but RFC793 + * doesn't prohibit the change so we have to deal + * with it. */ + goto uncompressed; + } + if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + cp = encode(cp,deltaS); + changes |= NEW_W; + } + if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ + if(deltaA > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaA); + changes |= NEW_A; + } + if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ + if(deltaS > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaS); + changes |= NEW_S; + } + + switch(changes){ + case 0: /* Nothing changed. If this packet contains data and the + * last one didn't, this is probably a data packet following + * an ack (normal on an interactive connection) and we send + * it compressed. Otherwise it's probably a retransmit, + * retransmitted ack or window probe. Send it uncompressed + * in case the other side missed the compressed version. + */ + if(ip->tot_len != cs->cs_ip.tot_len && + ntohs(cs->cs_ip.tot_len) == hlen) + break; + goto uncompressed; + break; + case SPECIAL_I: + case SPECIAL_D: + /* actual changes match one of our special case encodings -- + * send packet uncompressed. + */ + goto uncompressed; + case NEW_S|NEW_A: + if(deltaS == deltaA && + deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for echoed terminal traffic */ + changes = SPECIAL_I; + cp = new_seq; + } + break; + case NEW_S: + if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for data xfer */ + changes = SPECIAL_D; + cp = new_seq; + } + break; + } + deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); + if(deltaS != 1){ + cp = encode(cp,deltaS); + changes |= NEW_I; + } + if(th->psh) + changes |= TCP_PUSH_BIT; + /* Grab the cksum before we overwrite it below. Then update our + * state with this packet's header. + */ + csum = th->check; + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + /* We want to use the original packet as our compressed packet. + * (cp - new_seq) is the number of bytes we need for compressed + * sequence numbers. In addition we need one byte for the change + * mask, one for the connection id and two for the tcp checksum. + * So, (cp - new_seq) + 4 bytes of header are needed. + */ + deltaS = cp - new_seq; + if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ + cp = ocp; + *cpp = ocp; + *cp++ = changes | NEW_C; + *cp++ = cs->cs_this; + comp->xmit_current = cs->cs_this; + } else { + cp = ocp; + *cpp = ocp; + *cp++ = changes; + } + *(__sum16 *)cp = csum; + cp += 2; +/* deltaS is now the size of the change section of the compressed header */ + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ + memcpy(cp+deltaS,icp+hlen,isize-hlen); + comp->sls_o_compressed++; + ocp[0] |= SL_TYPE_COMPRESSED_TCP; + return isize - hlen + deltaS + (cp - ocp); + + /* Update connection state cs & send uncompressed packet (i.e., + * a regular ip/tcp packet but with the 'conversation id' we hope + * to use on future compressed packets in the protocol field). + */ +uncompressed: + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + if (ip->ihl > 5) + memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4); + if (th->doff > 5) + memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4); + comp->xmit_current = cs->cs_this; + comp->sls_o_uncompressed++; + memcpy(ocp, icp, isize); + *cpp = ocp; + ocp[9] = cs->cs_this; + ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP; + return isize; +} + + +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + register int changes; + long x; + register struct tcphdr *thp; + register struct iphdr *ip; + register struct cstate *cs; + int len, hdrlen; + unsigned char *cp = icp; + + /* We've got a compressed packet; read the change byte */ + comp->sls_i_compressed++; + if(isize < 3){ + comp->sls_i_error++; + return 0; + } + changes = *cp++; + if(changes & NEW_C){ + /* Make sure the state index is in range, then grab the state. + * If we have a good state index, clear the 'discard' flag. + */ + x = *cp++; /* Read conn index */ + if(x < 0 || x > comp->rslot_limit) + goto bad; + + comp->flags &=~ SLF_TOSS; + comp->recv_current = x; + } else { + /* this packet has an implicit state index. If we've + * had a line error since the last time we got an + * explicit state index, we have to toss the packet. */ + if(comp->flags & SLF_TOSS){ + comp->sls_i_tossed++; + return 0; + } + } + cs = &comp->rstate[comp->recv_current]; + thp = &cs->cs_tcp; + ip = &cs->cs_ip; + + thp->check = *(__sum16 *)cp; + cp += 2; + + thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0; +/* + * we can use the same number for the length of the saved header and + * the current one, because the packet wouldn't have been sent + * as compressed unless the options were the same as the previous one + */ + + hdrlen = ip->ihl * 4 + thp->doff * 4; + + switch(changes & SPECIALS_MASK){ + case SPECIAL_I: /* Echoed terminal traffic */ + { + register short i; + i = ntohs(ip->tot_len) - hdrlen; + thp->ack_seq = htonl( ntohl(thp->ack_seq) + i); + thp->seq = htonl( ntohl(thp->seq) + i); + } + break; + + case SPECIAL_D: /* Unidirectional data */ + thp->seq = htonl( ntohl(thp->seq) + + ntohs(ip->tot_len) - hdrlen); + break; + + default: + if(changes & NEW_U){ + thp->urg = 1; + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->urg_ptr = htons(x); + } else + thp->urg = 0; + if(changes & NEW_W){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->window = htons( ntohs(thp->window) + x); + } + if(changes & NEW_A){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); + } + if(changes & NEW_S){ + if((x = decode(&cp)) == -1) { + goto bad; + } + thp->seq = htonl( ntohl(thp->seq) + x); + } + break; + } + if(changes & NEW_I){ + if((x = decode(&cp)) == -1) { + goto bad; + } + ip->id = htons (ntohs (ip->id) + x); + } else + ip->id = htons (ntohs (ip->id) + 1); + + /* + * At this point, cp points to the first byte of data in the + * packet. Put the reconstructed TCP and IP headers back on the + * packet. Recalculate IP checksum (but not TCP checksum). + */ + + len = isize - (cp - icp); + if (len < 0) + goto bad; + len += hdrlen; + ip->tot_len = htons(len); + ip->check = 0; + + memmove(icp + hdrlen, cp, len - hdrlen); + + cp = icp; + memcpy(cp, ip, 20); + cp += 20; + + if (ip->ihl > 5) { + memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4); + cp += (ip->ihl - 5) * 4; + } + + put_unaligned(ip_fast_csum(icp, ip->ihl), + &((struct iphdr *)icp)->check); + + memcpy(cp, thp, 20); + cp += 20; + + if (thp->doff > 5) { + memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4); + cp += ((thp->doff) - 5) * 4; + } + + return len; +bad: + comp->sls_i_error++; + return slhc_toss( comp ); +} + + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + register struct cstate *cs; + unsigned ihl; + + unsigned char index; + + if(isize < 20) { + /* The packet is shorter than a legal IP header */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + /* Peek at the IP header's IHL field to find its length */ + ihl = icp[0] & 0xf; + if(ihl < 20 / 4){ + /* The IP header length field is too small */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + index = icp[9]; + icp[9] = IPPROTO_TCP; + + if (ip_fast_csum(icp, ihl)) { + /* Bad IP header checksum; discard */ + comp->sls_i_badcheck++; + return slhc_toss( comp ); + } + if(index > comp->rslot_limit) { + comp->sls_i_error++; + return slhc_toss(comp); + } + + /* Update local state */ + cs = &comp->rstate[comp->recv_current = index]; + comp->flags &=~ SLF_TOSS; + memcpy(&cs->cs_ip,icp,20); + memcpy(&cs->cs_tcp,icp + ihl*4,20); + if (ihl > 5) + memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4); + if (cs->cs_tcp.doff > 5) + memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4); + cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2; + /* Put headers back on packet + * Neither header checksum is recalculated + */ + comp->sls_i_uncompressed++; + return isize; +} + +int +slhc_toss(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return 0; + + comp->flags |= SLF_TOSS; + return 0; +} + +#else /* CONFIG_INET */ + +int +slhc_toss(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss"); + return -EINVAL; +} +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress"); + return -EINVAL; +} +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress"); + return -EINVAL; +} + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember"); + return -EINVAL; +} + +void +slhc_free(struct slcompress *comp) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free"); +} +struct slcompress * +slhc_init(int rslots, int tslots) +{ + printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init"); + return NULL; +} + +#endif /* CONFIG_INET */ + +/* VJ header compression */ +EXPORT_SYMBOL(slhc_init); +EXPORT_SYMBOL(slhc_free); +EXPORT_SYMBOL(slhc_remember); +EXPORT_SYMBOL(slhc_compress); +EXPORT_SYMBOL(slhc_uncompress); +EXPORT_SYMBOL(slhc_toss); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c new file mode 100644 index 0000000..ba08341 --- /dev/null +++ b/drivers/net/slip/slip.c @@ -0,0 +1,1444 @@ +/* + * slip.c This module implements the SLIP protocol for kernel-based + * devices like TTY. It interfaces between a raw TTY, and the + * kernel's INET protocol layers. + * + * Version: @(#)slip.c 0.8.3 12/24/94 + * + * Authors: Laurence Culhane, + * Fred N. van Kempen, + * + * Fixes: + * Alan Cox : Sanity checks and avoid tx overruns. + * Has a new sl->mtu field. + * Alan Cox : Found cause of overrun. ifconfig sl0 + * mtu upwards. Driver now spots this + * and grows/shrinks its buffers(hack!). + * Memory leak if you run out of memory + * setting up a slip driver fixed. + * Matt Dillon : Printable slip (borrowed from NET2E) + * Pauline Middelink : Slip driver fixes. + * Alan Cox : Honours the old SL_COMPRESSED flag + * Alan Cox : KISS AX.25 and AXUI IP support + * Michael Riepe : Automatic CSLIP recognition added + * Charles Hedrick : CSLIP header length problem fix. + * Alan Cox : Corrected non-IP cases of the above. + * Alan Cox : Now uses hardware type as per FvK. + * Alan Cox : Default to 192.168.0.0 (RFC 1597) + * A.N.Kuznetsov : dev_tint() recursion fix. + * Dmitry Gorodchanin : SLIP memory leaks + * Dmitry Gorodchanin : Code cleanup. Reduce tty driver + * buffering from 4096 to 256 bytes. + * Improving SLIP response time. + * CONFIG_SLIP_MODE_SLIP6. + * ifconfig sl? up & down now works + * correctly. + * Modularization. + * Alan Cox : Oops - fix AX.25 buffer lengths + * Dmitry Gorodchanin : Even more cleanups. Preserve CSLIP + * statistics. Include CSLIP code only + * if it really needed. + * Alan Cox : Free slhc buffers in the right place. + * Alan Cox : Allow for digipeated IP over AX.25 + * Matti Aarnio : Dynamic SLIP devices, with ideas taken + * from Jim Freeman's + * dynamic PPP devices. We do NOT kfree() + * device entries, just reg./unreg. them + * as they are needed. We kfree() them + * at module cleanup. + * With MODULE-loading ``insmod'', user + * can issue parameter: slip_maxdev=1024 + * (Or how much he/she wants.. Default + * is 256) + * Stanislav Voronyi : Slip line checking, with ideas taken + * from multislip BSDI driver which was + * written by Igor Chechik, RELCOM Corp. + * Only algorithms have been ported to + * Linux SLIP driver. + * Vitaly E. Lavrov : Sane behaviour on tty hangup. + * Alexey Kuznetsov : Cleanup interfaces to tty & netdevice + * modules. + */ + +#define SL_CHECK_TRANSMIT +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "slip.h" +#ifdef CONFIG_INET +#include +#include +#include +#endif + +#define SLIP_VERSION "0.8.4-NET3.019-NEWTTY" + +static struct net_device **slip_devs; + +static int slip_maxdev = SL_NRUNIT; +module_param(slip_maxdev, int, 0); +MODULE_PARM_DESC(slip_maxdev, "Maximum number of slip devices"); + +static int slip_esc(unsigned char *p, unsigned char *d, int len); +static void slip_unesc(struct slip *sl, unsigned char c); +#ifdef CONFIG_SLIP_MODE_SLIP6 +static int slip_esc6(unsigned char *p, unsigned char *d, int len); +static void slip_unesc6(struct slip *sl, unsigned char c); +#endif +#ifdef CONFIG_SLIP_SMART +static void sl_keepalive(unsigned long sls); +static void sl_outfill(unsigned long sls); +static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +#endif + +/******************************** +* Buffer administration routines: +* sl_alloc_bufs() +* sl_free_bufs() +* sl_realloc_bufs() +* +* NOTE: sl_realloc_bufs != sl_free_bufs + sl_alloc_bufs, because +* sl_realloc_bufs provides strong atomicity and reallocation +* on actively running device. +*********************************/ + +/* + Allocate channel buffers. + */ + +static int sl_alloc_bufs(struct slip *sl, int mtu) +{ + int err = -ENOBUFS; + unsigned long len; + char *rbuff = NULL; + char *xbuff = NULL; +#ifdef SL_INCLUDE_CSLIP + char *cbuff = NULL; + struct slcompress *slcomp = NULL; +#endif + + /* + * Allocate the SLIP frame buffers: + * + * rbuff Receive buffer. + * xbuff Transmit buffer. + * cbuff Temporary compression buffer. + */ + len = mtu * 2; + + /* + * allow for arrival of larger UDP packets, even if we say not to + * also fixes a bug in which SunOS sends 512-byte packets even with + * an MSS of 128 + */ + if (len < 576 * 2) + len = 576 * 2; + rbuff = kmalloc(len + 4, GFP_KERNEL); + if (rbuff == NULL) + goto err_exit; + xbuff = kmalloc(len + 4, GFP_KERNEL); + if (xbuff == NULL) + goto err_exit; +#ifdef SL_INCLUDE_CSLIP + cbuff = kmalloc(len + 4, GFP_KERNEL); + if (cbuff == NULL) + goto err_exit; + slcomp = slhc_init(16, 16); + if (slcomp == NULL) + goto err_exit; +#endif + spin_lock_bh(&sl->lock); + if (sl->tty == NULL) { + spin_unlock_bh(&sl->lock); + err = -ENODEV; + goto err_exit; + } + sl->mtu = mtu; + sl->buffsize = len; + sl->rcount = 0; + sl->xleft = 0; + rbuff = xchg(&sl->rbuff, rbuff); + xbuff = xchg(&sl->xbuff, xbuff); +#ifdef SL_INCLUDE_CSLIP + cbuff = xchg(&sl->cbuff, cbuff); + slcomp = xchg(&sl->slcomp, slcomp); +#endif +#ifdef CONFIG_SLIP_MODE_SLIP6 + sl->xdata = 0; + sl->xbits = 0; +#endif + spin_unlock_bh(&sl->lock); + err = 0; + + /* Cleanup */ +err_exit: +#ifdef SL_INCLUDE_CSLIP + kfree(cbuff); + slhc_free(slcomp); +#endif + kfree(xbuff); + kfree(rbuff); + return err; +} + +/* Free a SLIP channel buffers. */ +static void sl_free_bufs(struct slip *sl) +{ + /* Free all SLIP frame buffers. */ + kfree(xchg(&sl->rbuff, NULL)); + kfree(xchg(&sl->xbuff, NULL)); +#ifdef SL_INCLUDE_CSLIP + kfree(xchg(&sl->cbuff, NULL)); + slhc_free(xchg(&sl->slcomp, NULL)); +#endif +} + +/* + Reallocate slip channel buffers. + */ + +static int sl_realloc_bufs(struct slip *sl, int mtu) +{ + int err = 0; + struct net_device *dev = sl->dev; + unsigned char *xbuff, *rbuff; +#ifdef SL_INCLUDE_CSLIP + unsigned char *cbuff; +#endif + int len = mtu * 2; + +/* + * allow for arrival of larger UDP packets, even if we say not to + * also fixes a bug in which SunOS sends 512-byte packets even with + * an MSS of 128 + */ + if (len < 576 * 2) + len = 576 * 2; + + xbuff = kmalloc(len + 4, GFP_ATOMIC); + rbuff = kmalloc(len + 4, GFP_ATOMIC); +#ifdef SL_INCLUDE_CSLIP + cbuff = kmalloc(len + 4, GFP_ATOMIC); +#endif + + +#ifdef SL_INCLUDE_CSLIP + if (xbuff == NULL || rbuff == NULL || cbuff == NULL) { +#else + if (xbuff == NULL || rbuff == NULL) { +#endif + if (mtu > sl->mtu) { + printk(KERN_WARNING "%s: unable to grow slip buffers, MTU change cancelled.\n", + dev->name); + err = -ENOBUFS; + } + goto done; + } + spin_lock_bh(&sl->lock); + + err = -ENODEV; + if (sl->tty == NULL) + goto done_on_bh; + + xbuff = xchg(&sl->xbuff, xbuff); + rbuff = xchg(&sl->rbuff, rbuff); +#ifdef SL_INCLUDE_CSLIP + cbuff = xchg(&sl->cbuff, cbuff); +#endif + if (sl->xleft) { + if (sl->xleft <= len) { + memcpy(sl->xbuff, sl->xhead, sl->xleft); + } else { + sl->xleft = 0; + dev->stats.tx_dropped++; + } + } + sl->xhead = sl->xbuff; + + if (sl->rcount) { + if (sl->rcount <= len) { + memcpy(sl->rbuff, rbuff, sl->rcount); + } else { + sl->rcount = 0; + dev->stats.rx_over_errors++; + set_bit(SLF_ERROR, &sl->flags); + } + } + sl->mtu = mtu; + dev->mtu = mtu; + sl->buffsize = len; + err = 0; + +done_on_bh: + spin_unlock_bh(&sl->lock); + +done: + kfree(xbuff); + kfree(rbuff); +#ifdef SL_INCLUDE_CSLIP + kfree(cbuff); +#endif + return err; +} + + +/* Set the "sending" flag. This must be atomic hence the set_bit. */ +static inline void sl_lock(struct slip *sl) +{ + netif_stop_queue(sl->dev); +} + + +/* Clear the "sending" flag. This must be atomic, hence the ASM. */ +static inline void sl_unlock(struct slip *sl) +{ + netif_wake_queue(sl->dev); +} + +/* Send one completely decapsulated IP datagram to the IP layer. */ +static void sl_bump(struct slip *sl) +{ + struct net_device *dev = sl->dev; + struct sk_buff *skb; + int count; + + count = sl->rcount; +#ifdef SL_INCLUDE_CSLIP + if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) { + unsigned char c = sl->rbuff[0]; + if (c & SL_TYPE_COMPRESSED_TCP) { + /* ignore compressed packets when CSLIP is off */ + if (!(sl->mode & SL_MODE_CSLIP)) { + printk(KERN_WARNING "%s: compressed packet ignored\n", dev->name); + return; + } + /* make sure we've reserved enough space for uncompress + to use */ + if (count + 80 > sl->buffsize) { + dev->stats.rx_over_errors++; + return; + } + count = slhc_uncompress(sl->slcomp, sl->rbuff, count); + if (count <= 0) + return; + } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) { + if (!(sl->mode & SL_MODE_CSLIP)) { + /* turn on header compression */ + sl->mode |= SL_MODE_CSLIP; + sl->mode &= ~SL_MODE_ADAPTIVE; + printk(KERN_INFO "%s: header compression turned on\n", dev->name); + } + sl->rbuff[0] &= 0x4f; + if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0) + return; + } + } +#endif /* SL_INCLUDE_CSLIP */ + + dev->stats.rx_bytes += count; + + skb = dev_alloc_skb(count); + if (skb == NULL) { + printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name); + dev->stats.rx_dropped++; + return; + } + skb->dev = dev; + memcpy(skb_put(skb, count), sl->rbuff, count); + skb_reset_mac_header(skb); + skb->protocol = htons(ETH_P_IP); + netif_rx_ni(skb); + dev->stats.rx_packets++; +} + +/* Encapsulate one IP datagram and stuff into a TTY queue. */ +static void sl_encaps(struct slip *sl, unsigned char *icp, int len) +{ + unsigned char *p; + int actual, count; + + if (len > sl->mtu) { /* Sigh, shouldn't occur BUT ... */ + printk(KERN_WARNING "%s: truncating oversized transmit packet!\n", sl->dev->name); + sl->dev->stats.tx_dropped++; + sl_unlock(sl); + return; + } + + p = icp; +#ifdef SL_INCLUDE_CSLIP + if (sl->mode & SL_MODE_CSLIP) + len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1); +#endif +#ifdef CONFIG_SLIP_MODE_SLIP6 + if (sl->mode & SL_MODE_SLIP6) + count = slip_esc6(p, (unsigned char *) sl->xbuff, len); + else +#endif + count = slip_esc(p, (unsigned char *) sl->xbuff, len); + + /* Order of next two lines is *very* important. + * When we are sending a little amount of data, + * the transfer may be completed inside the ops->write() + * routine, because it's running with interrupts enabled. + * In this case we *never* got WRITE_WAKEUP event, + * if we did not request it before write operation. + * 14 Oct 1994 Dmitry Gorodchanin. + */ + set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); + actual = sl->tty->ops->write(sl->tty, sl->xbuff, count); +#ifdef SL_CHECK_TRANSMIT + sl->dev->trans_start = jiffies; +#endif + sl->xleft = count - actual; + sl->xhead = sl->xbuff + actual; +#ifdef CONFIG_SLIP_SMART + /* VSV */ + clear_bit(SLF_OUTWAIT, &sl->flags); /* reset outfill flag */ +#endif +} + +/* + * Called by the driver when there's room for more data. If we have + * more packets to send, we send them here. + */ +static void slip_write_wakeup(struct tty_struct *tty) +{ + int actual; + struct slip *sl = tty->disc_data; + + /* First make sure we're connected. */ + if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev)) + return; + + if (sl->xleft <= 0) { + /* Now serial buffer is almost free & we can start + * transmission of another packet */ + sl->dev->stats.tx_packets++; + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + sl_unlock(sl); + return; + } + + actual = tty->ops->write(tty, sl->xhead, sl->xleft); + sl->xleft -= actual; + sl->xhead += actual; +} + +static void sl_tx_timeout(struct net_device *dev) +{ + struct slip *sl = netdev_priv(dev); + + spin_lock(&sl->lock); + + if (netif_queue_stopped(dev)) { + if (!netif_running(dev)) + goto out; + + /* May be we must check transmitter timeout here ? + * 14 Oct 1994 Dmitry Gorodchanin. + */ +#ifdef SL_CHECK_TRANSMIT + if (time_before(jiffies, dev_trans_start(dev) + 20 * HZ)) { + /* 20 sec timeout not reached */ + goto out; + } + printk(KERN_WARNING "%s: transmit timed out, %s?\n", + dev->name, + (tty_chars_in_buffer(sl->tty) || sl->xleft) ? + "bad line quality" : "driver error"); + sl->xleft = 0; + clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); + sl_unlock(sl); +#endif + } +out: + spin_unlock(&sl->lock); +} + + +/* Encapsulate an IP datagram and kick it into a TTY queue. */ +static netdev_tx_t +sl_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct slip *sl = netdev_priv(dev); + + spin_lock(&sl->lock); + if (!netif_running(dev)) { + spin_unlock(&sl->lock); + printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + if (sl->tty == NULL) { + spin_unlock(&sl->lock); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + sl_lock(sl); + dev->stats.tx_bytes += skb->len; + sl_encaps(sl, skb->data, skb->len); + spin_unlock(&sl->lock); + + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + + +/****************************************** + * Routines looking at netdevice side. + ******************************************/ + +/* Netdevice UP -> DOWN routine */ + +static int +sl_close(struct net_device *dev) +{ + struct slip *sl = netdev_priv(dev); + + spin_lock_bh(&sl->lock); + if (sl->tty) + /* TTY discipline is running. */ + clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); + netif_stop_queue(dev); + sl->rcount = 0; + sl->xleft = 0; + spin_unlock_bh(&sl->lock); + + return 0; +} + +/* Netdevice DOWN -> UP routine */ + +static int sl_open(struct net_device *dev) +{ + struct slip *sl = netdev_priv(dev); + + if (sl->tty == NULL) + return -ENODEV; + + sl->flags &= (1 << SLF_INUSE); + netif_start_queue(dev); + return 0; +} + +/* Netdevice change MTU request */ + +static int sl_change_mtu(struct net_device *dev, int new_mtu) +{ + struct slip *sl = netdev_priv(dev); + + if (new_mtu < 68 || new_mtu > 65534) + return -EINVAL; + + if (new_mtu != dev->mtu) + return sl_realloc_bufs(sl, new_mtu); + return 0; +} + +/* Netdevice get statistics request */ + +static struct rtnl_link_stats64 * +sl_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) +{ + struct net_device_stats *devstats = &dev->stats; +#ifdef SL_INCLUDE_CSLIP + struct slip *sl = netdev_priv(dev); + struct slcompress *comp = sl->slcomp; +#endif + stats->rx_packets = devstats->rx_packets; + stats->tx_packets = devstats->tx_packets; + stats->rx_bytes = devstats->rx_bytes; + stats->tx_bytes = devstats->tx_bytes; + stats->rx_dropped = devstats->rx_dropped; + stats->tx_dropped = devstats->tx_dropped; + stats->tx_errors = devstats->tx_errors; + stats->rx_errors = devstats->rx_errors; + stats->rx_over_errors = devstats->rx_over_errors; + +#ifdef SL_INCLUDE_CSLIP + if (comp) { + /* Generic compressed statistics */ + stats->rx_compressed = comp->sls_i_compressed; + stats->tx_compressed = comp->sls_o_compressed; + + /* Are we really still needs this? */ + stats->rx_fifo_errors += comp->sls_i_compressed; + stats->rx_dropped += comp->sls_i_tossed; + stats->tx_fifo_errors += comp->sls_o_compressed; + stats->collisions += comp->sls_o_misses; + } +#endif + return stats; +} + +/* Netdevice register callback */ + +static int sl_init(struct net_device *dev) +{ + struct slip *sl = netdev_priv(dev); + + /* + * Finish setting up the DEVICE info. + */ + + dev->mtu = sl->mtu; + dev->type = ARPHRD_SLIP + sl->mode; +#ifdef SL_CHECK_TRANSMIT + dev->watchdog_timeo = 20*HZ; +#endif + return 0; +} + + +static void sl_uninit(struct net_device *dev) +{ + struct slip *sl = netdev_priv(dev); + + sl_free_bufs(sl); +} + +/* Hook the destructor so we can free slip devices at the right point in time */ +static void sl_free_netdev(struct net_device *dev) +{ + int i = dev->base_addr; + free_netdev(dev); + slip_devs[i] = NULL; +} + +static const struct net_device_ops sl_netdev_ops = { + .ndo_init = sl_init, + .ndo_uninit = sl_uninit, + .ndo_open = sl_open, + .ndo_stop = sl_close, + .ndo_start_xmit = sl_xmit, + .ndo_get_stats64 = sl_get_stats64, + .ndo_change_mtu = sl_change_mtu, + .ndo_tx_timeout = sl_tx_timeout, +#ifdef CONFIG_SLIP_SMART + .ndo_do_ioctl = sl_ioctl, +#endif +}; + + +static void sl_setup(struct net_device *dev) +{ + dev->netdev_ops = &sl_netdev_ops; + dev->destructor = sl_free_netdev; + + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->tx_queue_len = 10; + + /* New-style flags. */ + dev->flags = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST; +} + +/****************************************** + Routines looking at TTY side. + ******************************************/ + + +/* + * Handle the 'receiver data ready' interrupt. + * This function is called by the 'tty_io' module in the kernel when + * a block of SLIP data has been received, which can now be decapsulated + * and sent on to some IP layer for further processing. This will not + * be re-entered while running but other ldisc functions may be called + * in parallel + */ + +static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count) +{ + struct slip *sl = tty->disc_data; + + if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev)) + return; + + /* Read the characters out of the buffer */ + while (count--) { + if (fp && *fp++) { + if (!test_and_set_bit(SLF_ERROR, &sl->flags)) + sl->dev->stats.rx_errors++; + cp++; + continue; + } +#ifdef CONFIG_SLIP_MODE_SLIP6 + if (sl->mode & SL_MODE_SLIP6) + slip_unesc6(sl, *cp++); + else +#endif + slip_unesc(sl, *cp++); + } +} + +/************************************ + * slip_open helper routines. + ************************************/ + +/* Collect hanged up channels */ +static void sl_sync(void) +{ + int i; + struct net_device *dev; + struct slip *sl; + + for (i = 0; i < slip_maxdev; i++) { + dev = slip_devs[i]; + if (dev == NULL) + break; + + sl = netdev_priv(dev); + if (sl->tty || sl->leased) + continue; + if (dev->flags & IFF_UP) + dev_close(dev); + } +} + + +/* Find a free SLIP channel, and link in this `tty' line. */ +static struct slip *sl_alloc(dev_t line) +{ + int i; + char name[IFNAMSIZ]; + struct net_device *dev = NULL; + struct slip *sl; + + for (i = 0; i < slip_maxdev; i++) { + dev = slip_devs[i]; + if (dev == NULL) + break; + } + /* Sorry, too many, all slots in use */ + if (i >= slip_maxdev) + return NULL; + + sprintf(name, "sl%d", i); + dev = alloc_netdev(sizeof(*sl), name, sl_setup); + if (!dev) + return NULL; + + dev->base_addr = i; + sl = netdev_priv(dev); + + /* Initialize channel control data */ + sl->magic = SLIP_MAGIC; + sl->dev = dev; + spin_lock_init(&sl->lock); + sl->mode = SL_MODE_DEFAULT; +#ifdef CONFIG_SLIP_SMART + /* initialize timer_list struct */ + init_timer(&sl->keepalive_timer); + sl->keepalive_timer.data = (unsigned long)sl; + sl->keepalive_timer.function = sl_keepalive; + init_timer(&sl->outfill_timer); + sl->outfill_timer.data = (unsigned long)sl; + sl->outfill_timer.function = sl_outfill; +#endif + slip_devs[i] = dev; + return sl; +} + +/* + * Open the high-level part of the SLIP channel. + * This function is called by the TTY module when the + * SLIP line discipline is called for. Because we are + * sure the tty line exists, we only have to link it to + * a free SLIP channel... + * + * Called in process context serialized from other ldisc calls. + */ + +static int slip_open(struct tty_struct *tty) +{ + struct slip *sl; + int err; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (tty->ops->write == NULL) + return -EOPNOTSUPP; + + /* RTnetlink lock is misused here to serialize concurrent + opens of slip channels. There are better ways, but it is + the simplest one. + */ + rtnl_lock(); + + /* Collect hanged up channels. */ + sl_sync(); + + sl = tty->disc_data; + + err = -EEXIST; + /* First make sure we're not already connected. */ + if (sl && sl->magic == SLIP_MAGIC) + goto err_exit; + + /* OK. Find a free SLIP channel to use. */ + err = -ENFILE; + sl = sl_alloc(tty_devnum(tty)); + if (sl == NULL) + goto err_exit; + + sl->tty = tty; + tty->disc_data = sl; + sl->pid = current->pid; + + if (!test_bit(SLF_INUSE, &sl->flags)) { + /* Perform the low-level SLIP initialization. */ + err = sl_alloc_bufs(sl, SL_MTU); + if (err) + goto err_free_chan; + + set_bit(SLF_INUSE, &sl->flags); + + err = register_netdevice(sl->dev); + if (err) + goto err_free_bufs; + } + +#ifdef CONFIG_SLIP_SMART + if (sl->keepalive) { + sl->keepalive_timer.expires = jiffies + sl->keepalive * HZ; + add_timer(&sl->keepalive_timer); + } + if (sl->outfill) { + sl->outfill_timer.expires = jiffies + sl->outfill * HZ; + add_timer(&sl->outfill_timer); + } +#endif + + /* Done. We have linked the TTY line to a channel. */ + rtnl_unlock(); + tty->receive_room = 65536; /* We don't flow control */ + + /* TTY layer expects 0 on success */ + return 0; + +err_free_bufs: + sl_free_bufs(sl); + +err_free_chan: + sl->tty = NULL; + tty->disc_data = NULL; + clear_bit(SLF_INUSE, &sl->flags); + +err_exit: + rtnl_unlock(); + + /* Count references from TTY module */ + return err; +} + +/* + * Close down a SLIP channel. + * This means flushing out any pending queues, and then returning. This + * call is serialized against other ldisc functions. + * + * We also use this method fo a hangup event + */ + +static void slip_close(struct tty_struct *tty) +{ + struct slip *sl = tty->disc_data; + + /* First make sure we're connected. */ + if (!sl || sl->magic != SLIP_MAGIC || sl->tty != tty) + return; + + tty->disc_data = NULL; + sl->tty = NULL; + + /* VSV = very important to remove timers */ +#ifdef CONFIG_SLIP_SMART + del_timer_sync(&sl->keepalive_timer); + del_timer_sync(&sl->outfill_timer); +#endif + /* Flush network side */ + unregister_netdev(sl->dev); + /* This will complete via sl_free_netdev */ +} + +static int slip_hangup(struct tty_struct *tty) +{ + slip_close(tty); + return 0; +} + /************************************************************************ + * STANDARD SLIP ENCAPSULATION * + ************************************************************************/ + +static int slip_esc(unsigned char *s, unsigned char *d, int len) +{ + unsigned char *ptr = d; + unsigned char c; + + /* + * Send an initial END character to flush out any + * data that may have accumulated in the receiver + * due to line noise. + */ + + *ptr++ = END; + + /* + * For each byte in the packet, send the appropriate + * character sequence, according to the SLIP protocol. + */ + + while (len-- > 0) { + switch (c = *s++) { + case END: + *ptr++ = ESC; + *ptr++ = ESC_END; + break; + case ESC: + *ptr++ = ESC; + *ptr++ = ESC_ESC; + break; + default: + *ptr++ = c; + break; + } + } + *ptr++ = END; + return ptr - d; +} + +static void slip_unesc(struct slip *sl, unsigned char s) +{ + + switch (s) { + case END: +#ifdef CONFIG_SLIP_SMART + /* drop keeptest bit = VSV */ + if (test_bit(SLF_KEEPTEST, &sl->flags)) + clear_bit(SLF_KEEPTEST, &sl->flags); +#endif + + if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && + (sl->rcount > 2)) + sl_bump(sl); + clear_bit(SLF_ESCAPE, &sl->flags); + sl->rcount = 0; + return; + + case ESC: + set_bit(SLF_ESCAPE, &sl->flags); + return; + case ESC_ESC: + if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) + s = ESC; + break; + case ESC_END: + if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) + s = END; + break; + } + if (!test_bit(SLF_ERROR, &sl->flags)) { + if (sl->rcount < sl->buffsize) { + sl->rbuff[sl->rcount++] = s; + return; + } + sl->dev->stats.rx_over_errors++; + set_bit(SLF_ERROR, &sl->flags); + } +} + + +#ifdef CONFIG_SLIP_MODE_SLIP6 +/************************************************************************ + * 6 BIT SLIP ENCAPSULATION * + ************************************************************************/ + +static int slip_esc6(unsigned char *s, unsigned char *d, int len) +{ + unsigned char *ptr = d; + unsigned char c; + int i; + unsigned short v = 0; + short bits = 0; + + /* + * Send an initial END character to flush out any + * data that may have accumulated in the receiver + * due to line noise. + */ + + *ptr++ = 0x70; + + /* + * Encode the packet into printable ascii characters + */ + + for (i = 0; i < len; ++i) { + v = (v << 8) | s[i]; + bits += 8; + while (bits >= 6) { + bits -= 6; + c = 0x30 + ((v >> bits) & 0x3F); + *ptr++ = c; + } + } + if (bits) { + c = 0x30 + ((v << (6 - bits)) & 0x3F); + *ptr++ = c; + } + *ptr++ = 0x70; + return ptr - d; +} + +static void slip_unesc6(struct slip *sl, unsigned char s) +{ + unsigned char c; + + if (s == 0x70) { +#ifdef CONFIG_SLIP_SMART + /* drop keeptest bit = VSV */ + if (test_bit(SLF_KEEPTEST, &sl->flags)) + clear_bit(SLF_KEEPTEST, &sl->flags); +#endif + + if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && + (sl->rcount > 2)) + sl_bump(sl); + sl->rcount = 0; + sl->xbits = 0; + sl->xdata = 0; + } else if (s >= 0x30 && s < 0x70) { + sl->xdata = (sl->xdata << 6) | ((s - 0x30) & 0x3F); + sl->xbits += 6; + if (sl->xbits >= 8) { + sl->xbits -= 8; + c = (unsigned char)(sl->xdata >> sl->xbits); + if (!test_bit(SLF_ERROR, &sl->flags)) { + if (sl->rcount < sl->buffsize) { + sl->rbuff[sl->rcount++] = c; + return; + } + sl->dev->stats.rx_over_errors++; + set_bit(SLF_ERROR, &sl->flags); + } + } + } +} +#endif /* CONFIG_SLIP_MODE_SLIP6 */ + +/* Perform I/O control on an active SLIP channel. */ +static int slip_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct slip *sl = tty->disc_data; + unsigned int tmp; + int __user *p = (int __user *)arg; + + /* First make sure we're connected. */ + if (!sl || sl->magic != SLIP_MAGIC) + return -EINVAL; + + switch (cmd) { + case SIOCGIFNAME: + tmp = strlen(sl->dev->name) + 1; + if (copy_to_user((void __user *)arg, sl->dev->name, tmp)) + return -EFAULT; + return 0; + + case SIOCGIFENCAP: + if (put_user(sl->mode, p)) + return -EFAULT; + return 0; + + case SIOCSIFENCAP: + if (get_user(tmp, p)) + return -EFAULT; +#ifndef SL_INCLUDE_CSLIP + if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE)) + return -EINVAL; +#else + if ((tmp & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) == + (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) + /* return -EINVAL; */ + tmp &= ~SL_MODE_ADAPTIVE; +#endif +#ifndef CONFIG_SLIP_MODE_SLIP6 + if (tmp & SL_MODE_SLIP6) + return -EINVAL; +#endif + sl->mode = tmp; + sl->dev->type = ARPHRD_SLIP + sl->mode; + return 0; + + case SIOCSIFHWADDR: + return -EINVAL; + +#ifdef CONFIG_SLIP_SMART + /* VSV changes start here */ + case SIOCSKEEPALIVE: + if (get_user(tmp, p)) + return -EFAULT; + if (tmp > 255) /* max for unchar */ + return -EINVAL; + + spin_lock_bh(&sl->lock); + if (!sl->tty) { + spin_unlock_bh(&sl->lock); + return -ENODEV; + } + sl->keepalive = (u8)tmp; + if (sl->keepalive != 0) { + mod_timer(&sl->keepalive_timer, + jiffies + sl->keepalive * HZ); + set_bit(SLF_KEEPTEST, &sl->flags); + } else + del_timer(&sl->keepalive_timer); + spin_unlock_bh(&sl->lock); + return 0; + + case SIOCGKEEPALIVE: + if (put_user(sl->keepalive, p)) + return -EFAULT; + return 0; + + case SIOCSOUTFILL: + if (get_user(tmp, p)) + return -EFAULT; + if (tmp > 255) /* max for unchar */ + return -EINVAL; + spin_lock_bh(&sl->lock); + if (!sl->tty) { + spin_unlock_bh(&sl->lock); + return -ENODEV; + } + sl->outfill = (u8)tmp; + if (sl->outfill != 0) { + mod_timer(&sl->outfill_timer, + jiffies + sl->outfill * HZ); + set_bit(SLF_OUTWAIT, &sl->flags); + } else + del_timer(&sl->outfill_timer); + spin_unlock_bh(&sl->lock); + return 0; + + case SIOCGOUTFILL: + if (put_user(sl->outfill, p)) + return -EFAULT; + return 0; + /* VSV changes end */ +#endif + default: + return tty_mode_ioctl(tty, file, cmd, arg); + } +} + +#ifdef CONFIG_COMPAT +static long slip_compat_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case SIOCGIFNAME: + case SIOCGIFENCAP: + case SIOCSIFENCAP: + case SIOCSIFHWADDR: + case SIOCSKEEPALIVE: + case SIOCGKEEPALIVE: + case SIOCSOUTFILL: + case SIOCGOUTFILL: + return slip_ioctl(tty, file, cmd, + (unsigned long)compat_ptr(arg)); + } + + return -ENOIOCTLCMD; +} +#endif + +/* VSV changes start here */ +#ifdef CONFIG_SLIP_SMART +/* function do_ioctl called from net/core/dev.c + to allow get/set outfill/keepalive parameter + by ifconfig */ + +static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct slip *sl = netdev_priv(dev); + unsigned long *p = (unsigned long *)&rq->ifr_ifru; + + if (sl == NULL) /* Allocation failed ?? */ + return -ENODEV; + + spin_lock_bh(&sl->lock); + + if (!sl->tty) { + spin_unlock_bh(&sl->lock); + return -ENODEV; + } + + switch (cmd) { + case SIOCSKEEPALIVE: + /* max for unchar */ + if ((unsigned)*p > 255) { + spin_unlock_bh(&sl->lock); + return -EINVAL; + } + sl->keepalive = (u8)*p; + if (sl->keepalive != 0) { + sl->keepalive_timer.expires = + jiffies + sl->keepalive * HZ; + mod_timer(&sl->keepalive_timer, + jiffies + sl->keepalive * HZ); + set_bit(SLF_KEEPTEST, &sl->flags); + } else + del_timer(&sl->keepalive_timer); + break; + + case SIOCGKEEPALIVE: + *p = sl->keepalive; + break; + + case SIOCSOUTFILL: + if ((unsigned)*p > 255) { /* max for unchar */ + spin_unlock_bh(&sl->lock); + return -EINVAL; + } + sl->outfill = (u8)*p; + if (sl->outfill != 0) { + mod_timer(&sl->outfill_timer, + jiffies + sl->outfill * HZ); + set_bit(SLF_OUTWAIT, &sl->flags); + } else + del_timer(&sl->outfill_timer); + break; + + case SIOCGOUTFILL: + *p = sl->outfill; + break; + + case SIOCSLEASE: + /* Resolve race condition, when ioctl'ing hanged up + and opened by another process device. + */ + if (sl->tty != current->signal->tty && + sl->pid != current->pid) { + spin_unlock_bh(&sl->lock); + return -EPERM; + } + sl->leased = 0; + if (*p) + sl->leased = 1; + break; + + case SIOCGLEASE: + *p = sl->leased; + } + spin_unlock_bh(&sl->lock); + return 0; +} +#endif +/* VSV changes end */ + +static struct tty_ldisc_ops sl_ldisc = { + .owner = THIS_MODULE, + .magic = TTY_LDISC_MAGIC, + .name = "slip", + .open = slip_open, + .close = slip_close, + .hangup = slip_hangup, + .ioctl = slip_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = slip_compat_ioctl, +#endif + .receive_buf = slip_receive_buf, + .write_wakeup = slip_write_wakeup, +}; + +static int __init slip_init(void) +{ + int status; + + if (slip_maxdev < 4) + slip_maxdev = 4; /* Sanity */ + + printk(KERN_INFO "SLIP: version %s (dynamic channels, max=%d)" +#ifdef CONFIG_SLIP_MODE_SLIP6 + " (6 bit encapsulation enabled)" +#endif + ".\n", + SLIP_VERSION, slip_maxdev); +#if defined(SL_INCLUDE_CSLIP) + printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California.\n"); +#endif +#ifdef CONFIG_SLIP_SMART + printk(KERN_INFO "SLIP linefill/keepalive option.\n"); +#endif + + slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev, + GFP_KERNEL); + if (!slip_devs) { + printk(KERN_ERR "SLIP: Can't allocate slip devices array.\n"); + return -ENOMEM; + } + + /* Fill in our line protocol discipline, and register it */ + status = tty_register_ldisc(N_SLIP, &sl_ldisc); + if (status != 0) { + printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status); + kfree(slip_devs); + } + return status; +} + +static void __exit slip_exit(void) +{ + int i; + struct net_device *dev; + struct slip *sl; + unsigned long timeout = jiffies + HZ; + int busy = 0; + + if (slip_devs == NULL) + return; + + /* First of all: check for active disciplines and hangup them. + */ + do { + if (busy) + msleep_interruptible(100); + + busy = 0; + for (i = 0; i < slip_maxdev; i++) { + dev = slip_devs[i]; + if (!dev) + continue; + sl = netdev_priv(dev); + spin_lock_bh(&sl->lock); + if (sl->tty) { + busy++; + tty_hangup(sl->tty); + } + spin_unlock_bh(&sl->lock); + } + } while (busy && time_before(jiffies, timeout)); + + /* FIXME: hangup is async so we should wait when doing this second + phase */ + + for (i = 0; i < slip_maxdev; i++) { + dev = slip_devs[i]; + if (!dev) + continue; + slip_devs[i] = NULL; + + sl = netdev_priv(dev); + if (sl->tty) { + printk(KERN_ERR "%s: tty discipline still running\n", + dev->name); + /* Intentionally leak the control block. */ + dev->destructor = NULL; + } + + unregister_netdev(dev); + } + + kfree(slip_devs); + slip_devs = NULL; + + i = tty_unregister_ldisc(N_SLIP); + if (i != 0) + printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)\n", i); +} + +module_init(slip_init); +module_exit(slip_exit); + +#ifdef CONFIG_SLIP_SMART +/* + * This is start of the code for multislip style line checking + * added by Stanislav Voronyi. All changes before marked VSV + */ + +static void sl_outfill(unsigned long sls) +{ + struct slip *sl = (struct slip *)sls; + + spin_lock(&sl->lock); + + if (sl->tty == NULL) + goto out; + + if (sl->outfill) { + if (test_bit(SLF_OUTWAIT, &sl->flags)) { + /* no packets were transmitted, do outfill */ +#ifdef CONFIG_SLIP_MODE_SLIP6 + unsigned char s = (sl->mode & SL_MODE_SLIP6)?0x70:END; +#else + unsigned char s = END; +#endif + /* put END into tty queue. Is it right ??? */ + if (!netif_queue_stopped(sl->dev)) { + /* if device busy no outfill */ + sl->tty->ops->write(sl->tty, &s, 1); + } + } else + set_bit(SLF_OUTWAIT, &sl->flags); + + mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ); + } +out: + spin_unlock(&sl->lock); +} + +static void sl_keepalive(unsigned long sls) +{ + struct slip *sl = (struct slip *)sls; + + spin_lock(&sl->lock); + + if (sl->tty == NULL) + goto out; + + if (sl->keepalive) { + if (test_bit(SLF_KEEPTEST, &sl->flags)) { + /* keepalive still high :(, we must hangup */ + if (sl->outfill) + /* outfill timer must be deleted too */ + (void)del_timer(&sl->outfill_timer); + printk(KERN_DEBUG "%s: no packets received during keepalive timeout, hangup.\n", sl->dev->name); + /* this must hangup tty & close slip */ + tty_hangup(sl->tty); + /* I think we need not something else */ + goto out; + } else + set_bit(SLF_KEEPTEST, &sl->flags); + + mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ); + } +out: + spin_unlock(&sl->lock); +} + +#endif +MODULE_LICENSE("GPL"); +MODULE_ALIAS_LDISC(N_SLIP); diff --git a/drivers/net/slip/slip.h b/drivers/net/slip/slip.h new file mode 100644 index 0000000..67673cf --- /dev/null +++ b/drivers/net/slip/slip.h @@ -0,0 +1,101 @@ +/* + * slip.h Define the SLIP device driver interface and constants. + * + * NOTE: THIS FILE WILL BE MOVED TO THE LINUX INCLUDE DIRECTORY + * AS SOON AS POSSIBLE! + * + * Version: @(#)slip.h 1.2.0 03/28/93 + * + * Fixes: + * Alan Cox : Added slip mtu field. + * Matt Dillon : Printable slip (borrowed from net2e) + * Alan Cox : Added SL_SLIP_LOTS + * Dmitry Gorodchanin : A lot of changes in the 'struct slip' + * Dmitry Gorodchanin : Added CSLIP statistics. + * Stanislav Voronyi : Make line checking as created by + * Igor Chechik, RELCOM Corp. + * Craig Schlenter : Fixed #define bug that caused + * CSLIP telnets to hang in 1.3.61-6 + * + * Author: Fred N. van Kempen, + */ +#ifndef _LINUX_SLIP_H +#define _LINUX_SLIP_H + + +#if defined(CONFIG_INET) && defined(CONFIG_SLIP_COMPRESSED) +# define SL_INCLUDE_CSLIP +#endif + +#ifdef SL_INCLUDE_CSLIP +# define SL_MODE_DEFAULT SL_MODE_ADAPTIVE +#else +# define SL_MODE_DEFAULT SL_MODE_SLIP +#endif + +/* SLIP configuration. */ +#define SL_NRUNIT 256 /* MAX number of SLIP channels; + This can be overridden with + insmod -oslip_maxdev=nnn */ +#define SL_MTU 296 /* 296; I am used to 600- FvK */ + +/* SLIP protocol characters. */ +#define END 0300 /* indicates end of frame */ +#define ESC 0333 /* indicates byte stuffing */ +#define ESC_END 0334 /* ESC ESC_END means END 'data' */ +#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ + + +struct slip { + int magic; + + /* Various fields. */ + struct tty_struct *tty; /* ptr to TTY structure */ + struct net_device *dev; /* easy for intr handling */ + spinlock_t lock; + +#ifdef SL_INCLUDE_CSLIP + struct slcompress *slcomp; /* for header compression */ + unsigned char *cbuff; /* compression buffer */ +#endif + + /* 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 */ + int mtu; /* Our mtu (to spot changes!) */ + int buffsize; /* Max buffers sizes */ + +#ifdef CONFIG_SLIP_MODE_SLIP6 + int xdata, xbits; /* 6 bit slip controls */ +#endif + + unsigned long flags; /* Flag values/ mode etc */ +#define SLF_INUSE 0 /* Channel in use */ +#define SLF_ESCAPE 1 /* ESC received */ +#define SLF_ERROR 2 /* Parity, etc. error */ +#define SLF_KEEPTEST 3 /* Keepalive test flag */ +#define SLF_OUTWAIT 4 /* is outpacket was flag */ + + unsigned char mode; /* SLIP mode */ + unsigned char leased; + pid_t pid; +#define SL_MODE_SLIP 0 +#define SL_MODE_CSLIP 1 +#define SL_MODE_SLIP6 2 /* Matt Dillon's printable slip */ +#define SL_MODE_CSLIP6 (SL_MODE_SLIP6|SL_MODE_CSLIP) +#define SL_MODE_AX25 4 +#define SL_MODE_ADAPTIVE 8 +#ifdef CONFIG_SLIP_SMART + unsigned char outfill; /* # of sec between outfill packet */ + unsigned char keepalive; /* keepalive seconds */ + struct timer_list outfill_timer; + struct timer_list keepalive_timer; +#endif +}; + +#define SLIP_MAGIC 0x5302 + +#endif /* _LINUX_SLIP.H */ -- cgit v0.10.2 From c0153225a0e86013b8b8267ffd94e5484d83b916 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Mon, 22 Aug 2011 17:37:03 -0700 Subject: ixbmtr_cs: Move the IBM PCMCIA Token Ring driver Move the IBM PCMCIA Token Ring driver into drivers/net/tokenring/ with the other Token Ring drivers. Made the necessary Kconfig and Makefile changes as well. CC: Mike Phillips CC: Burt Silverman Signed-off-by: Jeff Kirsher diff --git a/drivers/net/pcmcia/Kconfig b/drivers/net/pcmcia/Kconfig index 12e7ae4..ff4deb0 100644 --- a/drivers/net/pcmcia/Kconfig +++ b/drivers/net/pcmcia/Kconfig @@ -31,15 +31,4 @@ config ARCNET_COM20020_CS To compile this driver as a module, choose M here: the module will be called com20020_cs. If unsure, say N. -config PCMCIA_IBMTR - tristate "IBM PCMCIA tokenring adapter support" - depends on IBMTR!=y && TR - help - Say Y here if you intend to attach this type of Token Ring PCMCIA - card to your computer. You then also need to say Y to "Token Ring - driver support". - - To compile this driver as a module, choose M here: the module will be - called ibmtr_cs. - endif # NET_PCMCIA diff --git a/drivers/net/pcmcia/Makefile b/drivers/net/pcmcia/Makefile index 618e816..b98a0a4 100644 --- a/drivers/net/pcmcia/Makefile +++ b/drivers/net/pcmcia/Makefile @@ -4,5 +4,3 @@ # 16-bit client drivers obj-$(CONFIG_ARCNET_COM20020_CS)+= com20020_cs.o - -obj-$(CONFIG_PCMCIA_IBMTR) += ibmtr_cs.o diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c deleted file mode 100644 index 6006d54..0000000 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ /dev/null @@ -1,371 +0,0 @@ -/*====================================================================== - - A PCMCIA token-ring driver for IBM-based cards - - This driver supports the IBM PCMCIA Token-Ring Card. - Written by Steve Kipisz, kipisz@vnet.ibm.com or - bungy@ibm.net - - Written 1995,1996. - - This code is based on pcnet_cs.c from David Hinds. - - V2.2.0 February 1999 - Mike Phillips phillim@amtrak.com - - Linux V2.2.x presented significant changes to the underlying - ibmtr.c code. Mainly the code became a lot more organized and - modular. - - This caused the old PCMCIA Token Ring driver to give up and go - home early. Instead of just patching the old code to make it - work, the PCMCIA code has been streamlined, updated and possibly - improved. - - This code now only contains code required for the Card Services. - All we do here is set the card up enough so that the real ibmtr.c - driver can find it and work with it properly. - - i.e. We set up the io port, irq, mmio memory and shared ram - memory. This enables ibmtr_probe in ibmtr.c to find the card and - configure it as though it was a normal ISA and/or PnP card. - - CHANGES - - v2.2.5 April 1999 Mike Phillips (phillim@amtrak.com) - Obscure bug fix, required changed to ibmtr.c not ibmtr_cs.c - - v2.2.7 May 1999 Mike Phillips (phillim@amtrak.com) - Updated to version 2.2.7 to match the first version of the kernel - that the modification to ibmtr.c were incorporated into. - - v2.2.17 July 2000 Burt Silverman (burts@us.ibm.com) - Address translation feature of PCMCIA controller is usable so - memory windows can be placed in High memory (meaning above - 0xFFFFF.) - -======================================================================*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#define PCMCIA -#include "../tokenring/ibmtr.c" - - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -/* MMIO base address */ -static u_long mmiobase = 0xce000; - -/* SRAM base address */ -static u_long srambase = 0xd0000; - -/* SRAM size 8,16,32,64 */ -static u_long sramsize = 64; - -/* Ringspeed 4,16 */ -static int ringspeed = 16; - -module_param(mmiobase, ulong, 0); -module_param(srambase, ulong, 0); -module_param(sramsize, ulong, 0); -module_param(ringspeed, int, 0); -MODULE_LICENSE("GPL"); - -/*====================================================================*/ - -static int ibmtr_config(struct pcmcia_device *link); -static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase); -static void ibmtr_release(struct pcmcia_device *link); -static void ibmtr_detach(struct pcmcia_device *p_dev); - -/*====================================================================*/ - -typedef struct ibmtr_dev_t { - struct pcmcia_device *p_dev; - struct net_device *dev; - struct tok_info *ti; -} ibmtr_dev_t; - -static irqreturn_t ibmtr_interrupt(int irq, void *dev_id) { - ibmtr_dev_t *info = dev_id; - struct net_device *dev = info->dev; - return tok_interrupt(irq, dev); -}; - -static int __devinit ibmtr_attach(struct pcmcia_device *link) -{ - ibmtr_dev_t *info; - struct net_device *dev; - - dev_dbg(&link->dev, "ibmtr_attach()\n"); - - /* Create new token-ring device */ - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) return -ENOMEM; - dev = alloc_trdev(sizeof(struct tok_info)); - if (!dev) { - kfree(info); - return -ENOMEM; - } - - info->p_dev = link; - link->priv = info; - info->ti = netdev_priv(dev); - - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - link->resource[0]->end = 4; - link->config_flags |= CONF_ENABLE_IRQ; - link->config_regs = PRESENT_OPTION; - - info->dev = dev; - - return ibmtr_config(link); -} /* ibmtr_attach */ - -static void ibmtr_detach(struct pcmcia_device *link) -{ - struct ibmtr_dev_t *info = link->priv; - struct net_device *dev = info->dev; - struct tok_info *ti = netdev_priv(dev); - - dev_dbg(&link->dev, "ibmtr_detach\n"); - - /* - * When the card removal interrupt hits tok_interrupt(), - * bail out early, so we don't crash the machine - */ - ti->sram_phys |= 1; - - unregister_netdev(dev); - - del_timer_sync(&(ti->tr_timer)); - - ibmtr_release(link); - - free_netdev(dev); - kfree(info); -} /* ibmtr_detach */ - -static int __devinit ibmtr_config(struct pcmcia_device *link) -{ - ibmtr_dev_t *info = link->priv; - struct net_device *dev = info->dev; - struct tok_info *ti = netdev_priv(dev); - int i, ret; - - dev_dbg(&link->dev, "ibmtr_config\n"); - - link->io_lines = 16; - link->config_index = 0x61; - - /* Determine if this is PRIMARY or ALTERNATE. */ - - /* Try PRIMARY card at 0xA20-0xA23 */ - link->resource[0]->start = 0xA20; - i = pcmcia_request_io(link); - if (i != 0) { - /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */ - link->resource[0]->start = 0xA24; - ret = pcmcia_request_io(link); - if (ret) - goto failed; - } - dev->base_addr = link->resource[0]->start; - - ret = pcmcia_request_exclusive_irq(link, ibmtr_interrupt); - if (ret) - goto failed; - dev->irq = link->irq; - ti->irq = link->irq; - ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq); - - /* Allocate the MMIO memory window */ - link->resource[2]->flags |= WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; - link->resource[2]->flags |= WIN_USE_WAIT; - link->resource[2]->start = 0; - link->resource[2]->end = 0x2000; - ret = pcmcia_request_window(link, link->resource[2], 250); - if (ret) - goto failed; - - ret = pcmcia_map_mem_page(link, link->resource[2], mmiobase); - if (ret) - goto failed; - ti->mmio = ioremap(link->resource[2]->start, - resource_size(link->resource[2])); - - /* Allocate the SRAM memory window */ - link->resource[3]->flags = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; - link->resource[3]->flags |= WIN_USE_WAIT; - link->resource[3]->start = 0; - link->resource[3]->end = sramsize * 1024; - ret = pcmcia_request_window(link, link->resource[3], 250); - if (ret) - goto failed; - - ret = pcmcia_map_mem_page(link, link->resource[3], srambase); - if (ret) - goto failed; - - ti->sram_base = srambase >> 12; - ti->sram_virt = ioremap(link->resource[3]->start, - resource_size(link->resource[3])); - ti->sram_phys = link->resource[3]->start; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - /* Set up the Token-Ring Controller Configuration Register and - turn on the card. Check the "Local Area Network Credit Card - Adapters Technical Reference" SC30-3585 for this info. */ - ibmtr_hw_setup(dev, mmiobase); - - SET_NETDEV_DEV(dev, &link->dev); - - i = ibmtr_probe_card(dev); - if (i != 0) { - pr_notice("register_netdev() failed\n"); - goto failed; - } - - netdev_info(dev, "port %#3lx, irq %d, mmio %#5lx, sram %#5lx, hwaddr=%pM\n", - dev->base_addr, dev->irq, - (u_long)ti->mmio, (u_long)(ti->sram_base << 12), - dev->dev_addr); - return 0; - -failed: - ibmtr_release(link); - return -ENODEV; -} /* ibmtr_config */ - -static void ibmtr_release(struct pcmcia_device *link) -{ - ibmtr_dev_t *info = link->priv; - struct net_device *dev = info->dev; - - dev_dbg(&link->dev, "ibmtr_release\n"); - - if (link->resource[2]->end) { - struct tok_info *ti = netdev_priv(dev); - iounmap(ti->mmio); - } - pcmcia_disable_device(link); -} - -static int ibmtr_suspend(struct pcmcia_device *link) -{ - ibmtr_dev_t *info = link->priv; - struct net_device *dev = info->dev; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int __devinit ibmtr_resume(struct pcmcia_device *link) -{ - ibmtr_dev_t *info = link->priv; - struct net_device *dev = info->dev; - - if (link->open) { - ibmtr_probe(dev); /* really? */ - netif_device_attach(dev); - } - - return 0; -} - - -/*====================================================================*/ - -static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase) -{ - int i; - - /* Bizarre IBM behavior, there are 16 bits of information we - need to set, but the card only allows us to send 4 bits at a - time. For each byte sent to base_addr, bits 7-4 tell the - card which part of the 16 bits we are setting, bits 3-0 contain - the actual information */ - - /* First nibble provides 4 bits of mmio */ - i = (mmiobase >> 16) & 0x0F; - outb(i, dev->base_addr); - - /* Second nibble provides 3 bits of mmio */ - i = 0x10 | ((mmiobase >> 12) & 0x0E); - outb(i, dev->base_addr); - - /* Third nibble, hard-coded values */ - i = 0x26; - outb(i, dev->base_addr); - - /* Fourth nibble sets shared ram page size */ - - /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */ - i = (sramsize >> 4) & 0x07; - i = ((i == 4) ? 3 : i) << 2; - i |= 0x30; - - if (ringspeed == 16) - i |= 2; - if (dev->base_addr == 0xA24) - i |= 1; - outb(i, dev->base_addr); - - /* 0x40 will release the card for use */ - outb(0x40, dev->base_addr); -} - -static const struct pcmcia_device_id ibmtr_ids[] = { - PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e), - PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids); - -static struct pcmcia_driver ibmtr_cs_driver = { - .owner = THIS_MODULE, - .name = "ibmtr_cs", - .probe = ibmtr_attach, - .remove = ibmtr_detach, - .id_table = ibmtr_ids, - .suspend = ibmtr_suspend, - .resume = ibmtr_resume, -}; - -static int __init init_ibmtr_cs(void) -{ - return pcmcia_register_driver(&ibmtr_cs_driver); -} - -static void __exit exit_ibmtr_cs(void) -{ - pcmcia_unregister_driver(&ibmtr_cs_driver); -} - -module_init(init_ibmtr_cs); -module_exit(exit_ibmtr_cs); diff --git a/drivers/net/tokenring/Kconfig b/drivers/net/tokenring/Kconfig index c4137b0..0f70158 100644 --- a/drivers/net/tokenring/Kconfig +++ b/drivers/net/tokenring/Kconfig @@ -6,7 +6,7 @@ menuconfig TR tristate "Token Ring driver support" depends on NETDEVICES && !UML - depends on (PCI || ISA || MCA || CCW) + depends on (PCI || ISA || MCA || CCW || PCMCIA) select LLC help Token Ring is IBM's way of communication on a local network; the @@ -20,6 +20,17 @@ menuconfig TR if TR +config PCMCIA_IBMTR + tristate "IBM PCMCIA tokenring adapter support" + depends on IBMTR!=y && PCMCIA + ---help--- + Say Y here if you intend to attach this type of Token Ring PCMCIA + card to your computer. You then also need to say Y to "Token Ring + driver support". + + To compile this driver as a module, choose M here: the module will be + called ibmtr_cs. + config IBMTR tristate "IBM Tropic chipset based adapter support" depends on ISA || MCA diff --git a/drivers/net/tokenring/Makefile b/drivers/net/tokenring/Makefile index c88b0a5..f1be8d9 100644 --- a/drivers/net/tokenring/Makefile +++ b/drivers/net/tokenring/Makefile @@ -2,14 +2,15 @@ # Makefile for drivers/net/tokenring # -obj-$(CONFIG_IBMTR) += ibmtr.o -obj-$(CONFIG_IBMOL) += olympic.o -obj-$(CONFIG_IBMLS) += lanstreamer.o -obj-$(CONFIG_TMS380TR) += tms380tr.o -obj-$(CONFIG_ABYSS) += abyss.o -obj-$(CONFIG_MADGEMC) += madgemc.o -obj-$(CONFIG_PROTEON) += proteon.o -obj-$(CONFIG_TMSPCI) += tmspci.o -obj-$(CONFIG_SKISA) += skisa.o -obj-$(CONFIG_SMCTR) += smctr.o +obj-$(CONFIG_PCMCIA_IBMTR) += ibmtr_cs.o +obj-$(CONFIG_IBMTR) += ibmtr.o +obj-$(CONFIG_IBMOL) += olympic.o +obj-$(CONFIG_IBMLS) += lanstreamer.o +obj-$(CONFIG_TMS380TR) += tms380tr.o +obj-$(CONFIG_ABYSS) += abyss.o +obj-$(CONFIG_MADGEMC) += madgemc.o +obj-$(CONFIG_PROTEON) += proteon.o +obj-$(CONFIG_TMSPCI) += tmspci.o +obj-$(CONFIG_SKISA) += skisa.o +obj-$(CONFIG_SMCTR) += smctr.o obj-$(CONFIG_3C359) += 3c359.o diff --git a/drivers/net/tokenring/ibmtr_cs.c b/drivers/net/tokenring/ibmtr_cs.c new file mode 100644 index 0000000..91b6846 --- /dev/null +++ b/drivers/net/tokenring/ibmtr_cs.c @@ -0,0 +1,371 @@ +/*====================================================================== + + A PCMCIA token-ring driver for IBM-based cards + + This driver supports the IBM PCMCIA Token-Ring Card. + Written by Steve Kipisz, kipisz@vnet.ibm.com or + bungy@ibm.net + + Written 1995,1996. + + This code is based on pcnet_cs.c from David Hinds. + + V2.2.0 February 1999 - Mike Phillips phillim@amtrak.com + + Linux V2.2.x presented significant changes to the underlying + ibmtr.c code. Mainly the code became a lot more organized and + modular. + + This caused the old PCMCIA Token Ring driver to give up and go + home early. Instead of just patching the old code to make it + work, the PCMCIA code has been streamlined, updated and possibly + improved. + + This code now only contains code required for the Card Services. + All we do here is set the card up enough so that the real ibmtr.c + driver can find it and work with it properly. + + i.e. We set up the io port, irq, mmio memory and shared ram + memory. This enables ibmtr_probe in ibmtr.c to find the card and + configure it as though it was a normal ISA and/or PnP card. + + CHANGES + + v2.2.5 April 1999 Mike Phillips (phillim@amtrak.com) + Obscure bug fix, required changed to ibmtr.c not ibmtr_cs.c + + v2.2.7 May 1999 Mike Phillips (phillim@amtrak.com) + Updated to version 2.2.7 to match the first version of the kernel + that the modification to ibmtr.c were incorporated into. + + v2.2.17 July 2000 Burt Silverman (burts@us.ibm.com) + Address translation feature of PCMCIA controller is usable so + memory windows can be placed in High memory (meaning above + 0xFFFFF.) + +======================================================================*/ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#define PCMCIA +#include "ibmtr.c" + + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* MMIO base address */ +static u_long mmiobase = 0xce000; + +/* SRAM base address */ +static u_long srambase = 0xd0000; + +/* SRAM size 8,16,32,64 */ +static u_long sramsize = 64; + +/* Ringspeed 4,16 */ +static int ringspeed = 16; + +module_param(mmiobase, ulong, 0); +module_param(srambase, ulong, 0); +module_param(sramsize, ulong, 0); +module_param(ringspeed, int, 0); +MODULE_LICENSE("GPL"); + +/*====================================================================*/ + +static int ibmtr_config(struct pcmcia_device *link); +static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase); +static void ibmtr_release(struct pcmcia_device *link); +static void ibmtr_detach(struct pcmcia_device *p_dev); + +/*====================================================================*/ + +typedef struct ibmtr_dev_t { + struct pcmcia_device *p_dev; + struct net_device *dev; + struct tok_info *ti; +} ibmtr_dev_t; + +static irqreturn_t ibmtr_interrupt(int irq, void *dev_id) { + ibmtr_dev_t *info = dev_id; + struct net_device *dev = info->dev; + return tok_interrupt(irq, dev); +}; + +static int __devinit ibmtr_attach(struct pcmcia_device *link) +{ + ibmtr_dev_t *info; + struct net_device *dev; + + dev_dbg(&link->dev, "ibmtr_attach()\n"); + + /* Create new token-ring device */ + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) return -ENOMEM; + dev = alloc_trdev(sizeof(struct tok_info)); + if (!dev) { + kfree(info); + return -ENOMEM; + } + + info->p_dev = link; + link->priv = info; + info->ti = netdev_priv(dev); + + link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + link->resource[0]->end = 4; + link->config_flags |= CONF_ENABLE_IRQ; + link->config_regs = PRESENT_OPTION; + + info->dev = dev; + + return ibmtr_config(link); +} /* ibmtr_attach */ + +static void ibmtr_detach(struct pcmcia_device *link) +{ + struct ibmtr_dev_t *info = link->priv; + struct net_device *dev = info->dev; + struct tok_info *ti = netdev_priv(dev); + + dev_dbg(&link->dev, "ibmtr_detach\n"); + + /* + * When the card removal interrupt hits tok_interrupt(), + * bail out early, so we don't crash the machine + */ + ti->sram_phys |= 1; + + unregister_netdev(dev); + + del_timer_sync(&(ti->tr_timer)); + + ibmtr_release(link); + + free_netdev(dev); + kfree(info); +} /* ibmtr_detach */ + +static int __devinit ibmtr_config(struct pcmcia_device *link) +{ + ibmtr_dev_t *info = link->priv; + struct net_device *dev = info->dev; + struct tok_info *ti = netdev_priv(dev); + int i, ret; + + dev_dbg(&link->dev, "ibmtr_config\n"); + + link->io_lines = 16; + link->config_index = 0x61; + + /* Determine if this is PRIMARY or ALTERNATE. */ + + /* Try PRIMARY card at 0xA20-0xA23 */ + link->resource[0]->start = 0xA20; + i = pcmcia_request_io(link); + if (i != 0) { + /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */ + link->resource[0]->start = 0xA24; + ret = pcmcia_request_io(link); + if (ret) + goto failed; + } + dev->base_addr = link->resource[0]->start; + + ret = pcmcia_request_exclusive_irq(link, ibmtr_interrupt); + if (ret) + goto failed; + dev->irq = link->irq; + ti->irq = link->irq; + ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq); + + /* Allocate the MMIO memory window */ + link->resource[2]->flags |= WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; + link->resource[2]->flags |= WIN_USE_WAIT; + link->resource[2]->start = 0; + link->resource[2]->end = 0x2000; + ret = pcmcia_request_window(link, link->resource[2], 250); + if (ret) + goto failed; + + ret = pcmcia_map_mem_page(link, link->resource[2], mmiobase); + if (ret) + goto failed; + ti->mmio = ioremap(link->resource[2]->start, + resource_size(link->resource[2])); + + /* Allocate the SRAM memory window */ + link->resource[3]->flags = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; + link->resource[3]->flags |= WIN_USE_WAIT; + link->resource[3]->start = 0; + link->resource[3]->end = sramsize * 1024; + ret = pcmcia_request_window(link, link->resource[3], 250); + if (ret) + goto failed; + + ret = pcmcia_map_mem_page(link, link->resource[3], srambase); + if (ret) + goto failed; + + ti->sram_base = srambase >> 12; + ti->sram_virt = ioremap(link->resource[3]->start, + resource_size(link->resource[3])); + ti->sram_phys = link->resource[3]->start; + + ret = pcmcia_enable_device(link); + if (ret) + goto failed; + + /* Set up the Token-Ring Controller Configuration Register and + turn on the card. Check the "Local Area Network Credit Card + Adapters Technical Reference" SC30-3585 for this info. */ + ibmtr_hw_setup(dev, mmiobase); + + SET_NETDEV_DEV(dev, &link->dev); + + i = ibmtr_probe_card(dev); + if (i != 0) { + pr_notice("register_netdev() failed\n"); + goto failed; + } + + netdev_info(dev, "port %#3lx, irq %d, mmio %#5lx, sram %#5lx, hwaddr=%pM\n", + dev->base_addr, dev->irq, + (u_long)ti->mmio, (u_long)(ti->sram_base << 12), + dev->dev_addr); + return 0; + +failed: + ibmtr_release(link); + return -ENODEV; +} /* ibmtr_config */ + +static void ibmtr_release(struct pcmcia_device *link) +{ + ibmtr_dev_t *info = link->priv; + struct net_device *dev = info->dev; + + dev_dbg(&link->dev, "ibmtr_release\n"); + + if (link->resource[2]->end) { + struct tok_info *ti = netdev_priv(dev); + iounmap(ti->mmio); + } + pcmcia_disable_device(link); +} + +static int ibmtr_suspend(struct pcmcia_device *link) +{ + ibmtr_dev_t *info = link->priv; + struct net_device *dev = info->dev; + + if (link->open) + netif_device_detach(dev); + + return 0; +} + +static int __devinit ibmtr_resume(struct pcmcia_device *link) +{ + ibmtr_dev_t *info = link->priv; + struct net_device *dev = info->dev; + + if (link->open) { + ibmtr_probe(dev); /* really? */ + netif_device_attach(dev); + } + + return 0; +} + + +/*====================================================================*/ + +static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase) +{ + int i; + + /* Bizarre IBM behavior, there are 16 bits of information we + need to set, but the card only allows us to send 4 bits at a + time. For each byte sent to base_addr, bits 7-4 tell the + card which part of the 16 bits we are setting, bits 3-0 contain + the actual information */ + + /* First nibble provides 4 bits of mmio */ + i = (mmiobase >> 16) & 0x0F; + outb(i, dev->base_addr); + + /* Second nibble provides 3 bits of mmio */ + i = 0x10 | ((mmiobase >> 12) & 0x0E); + outb(i, dev->base_addr); + + /* Third nibble, hard-coded values */ + i = 0x26; + outb(i, dev->base_addr); + + /* Fourth nibble sets shared ram page size */ + + /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */ + i = (sramsize >> 4) & 0x07; + i = ((i == 4) ? 3 : i) << 2; + i |= 0x30; + + if (ringspeed == 16) + i |= 2; + if (dev->base_addr == 0xA24) + i |= 1; + outb(i, dev->base_addr); + + /* 0x40 will release the card for use */ + outb(0x40, dev->base_addr); +} + +static const struct pcmcia_device_id ibmtr_ids[] = { + PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e), + PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47), + PCMCIA_DEVICE_NULL, +}; +MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids); + +static struct pcmcia_driver ibmtr_cs_driver = { + .owner = THIS_MODULE, + .name = "ibmtr_cs", + .probe = ibmtr_attach, + .remove = ibmtr_detach, + .id_table = ibmtr_ids, + .suspend = ibmtr_suspend, + .resume = ibmtr_resume, +}; + +static int __init init_ibmtr_cs(void) +{ + return pcmcia_register_driver(&ibmtr_cs_driver); +} + +static void __exit exit_ibmtr_cs(void) +{ + pcmcia_unregister_driver(&ibmtr_cs_driver); +} + +module_init(init_ibmtr_cs); +module_exit(exit_ibmtr_cs); -- cgit v0.10.2 From 330278cde612888e79fc4ab13d8f725258e903dd Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Mon, 22 Aug 2011 18:04:50 -0700 Subject: com20020_cs: Move the PCMCIA Arcnet driver Move the COM20020 PCMICA Arcnet driver into drivers/net/arcnet/ with the other Arcnet drivers. Made the necessary Kconfig and Makefile changes as well. Since this was the "last" PCMCIA driver in drivers/net/pcmcia/, this patch also cleans up the references to drivers/net/pcmcia. CC: Arnaldo Carvalho de Melo Signed-off-by: Jeff Kirsher diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index b3206c9..5762370 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -209,8 +209,6 @@ source "drivers/net/wimax/Kconfig" source "drivers/net/usb/Kconfig" -source "drivers/net/pcmcia/Kconfig" - source "drivers/net/ppp/Kconfig" source "drivers/net/wan/Kconfig" diff --git a/drivers/net/Makefile b/drivers/net/Makefile index e6a183e..99327a4 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -51,7 +51,6 @@ obj-$(CONFIG_SLHC) += slip/ obj-$(CONFIG_TR) += tokenring/ obj-$(CONFIG_WAN) += wan/ obj-$(CONFIG_ARCNET) += arcnet/ -obj-$(CONFIG_NET_PCMCIA) += pcmcia/ obj-$(CONFIG_USB_CATC) += usb/ obj-$(CONFIG_USB_KAWETH) += usb/ diff --git a/drivers/net/arcnet/Kconfig b/drivers/net/arcnet/Kconfig index 3b2f7f1..84fb634 100644 --- a/drivers/net/arcnet/Kconfig +++ b/drivers/net/arcnet/Kconfig @@ -3,7 +3,7 @@ # menuconfig ARCNET - depends on NETDEVICES && (ISA || PCI) + depends on NETDEVICES && (ISA || PCI || PCMCIA) tristate "ARCnet support" ---help--- If you have a network card of this type, say Y and check out the @@ -123,4 +123,14 @@ config ARCNET_COM20020_PCI tristate "Support for COM20020 on PCI" depends on ARCNET_COM20020 && PCI +config ARCNET_COM20020_CS + tristate "COM20020 ARCnet PCMCIA support" + depends on ARCNET_COM20020 && PCMCIA + help + Say Y here if you intend to attach this type of ARCnet PCMCIA card + to your computer. + + To compile this driver as a module, choose M here: the module will be + called com20020_cs. If unsure, say N. + endif # ARCNET diff --git a/drivers/net/arcnet/Makefile b/drivers/net/arcnet/Makefile index 5861af5..5ce8ee6 100644 --- a/drivers/net/arcnet/Makefile +++ b/drivers/net/arcnet/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_ARCNET_RIM_I) += arc-rimi.o obj-$(CONFIG_ARCNET_COM20020) += com20020.o obj-$(CONFIG_ARCNET_COM20020_ISA) += com20020-isa.o obj-$(CONFIG_ARCNET_COM20020_PCI) += com20020-pci.o +obj-$(CONFIG_ARCNET_COM20020_CS) += com20020_cs.o diff --git a/drivers/net/arcnet/com20020_cs.c b/drivers/net/arcnet/com20020_cs.c new file mode 100644 index 0000000..980e65c --- /dev/null +++ b/drivers/net/arcnet/com20020_cs.c @@ -0,0 +1,349 @@ +/* + * Linux ARCnet driver - COM20020 PCMCIA support + * + * Written 1994-1999 by Avery Pennarun, + * based on an ISA version by David Woodhouse. + * Derived from ibmtr_cs.c by Steve Kipisz (pcmcia-cs 3.1.4) + * which was derived from pcnet_cs.c by David Hinds. + * Some additional portions derived from skeleton.c by Donald Becker. + * + * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) + * for sponsoring the further development of this driver. + * + * ********************** + * + * The original copyright of skeleton.c was as follows: + * + * skeleton.c Written 1993 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may only be used + * and distributed according to the terms of the GNU General Public License as + * modified by SRC, incorporated herein by reference. + * + * ********************** + * Changes: + * Arnaldo Carvalho de Melo - 08/08/2000 + * - reorganize kmallocs in com20020_attach, checking all for failure + * and releasing the previous allocations if one fails + * ********************** + * + * For more details, see drivers/net/arcnet.c + * + * ********************** + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define VERSION "arcnet: COM20020 PCMCIA support loaded.\n" + + +static void regdump(struct net_device *dev) +{ +#ifdef DEBUG + int ioaddr = dev->base_addr; + int count; + + netdev_dbg(dev, "register dump:\n"); + for (count = ioaddr; count < ioaddr + 16; count++) + { + if (!(count % 16)) + pr_cont("%04X:", count); + pr_cont(" %02X", inb(count)); + } + pr_cont("\n"); + + netdev_dbg(dev, "buffer0 dump:\n"); + /* set up the address register */ + count = 0; + outb((count >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI); + outb(count & 0xff, _ADDR_LO); + + for (count = 0; count < 256+32; count++) + { + if (!(count % 16)) + pr_cont("%04X:", count); + + /* copy the data */ + pr_cont(" %02X", inb(_MEMDATA)); + } + pr_cont("\n"); +#endif +} + + + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +static int node; +static int timeout = 3; +static int backplane; +static int clockp; +static int clockm; + +module_param(node, int, 0); +module_param(timeout, int, 0); +module_param(backplane, int, 0); +module_param(clockp, int, 0); +module_param(clockm, int, 0); + +MODULE_LICENSE("GPL"); + +/*====================================================================*/ + +static int com20020_config(struct pcmcia_device *link); +static void com20020_release(struct pcmcia_device *link); + +static void com20020_detach(struct pcmcia_device *p_dev); + +/*====================================================================*/ + +typedef struct com20020_dev_t { + struct net_device *dev; +} com20020_dev_t; + +static int com20020_probe(struct pcmcia_device *p_dev) +{ + com20020_dev_t *info; + struct net_device *dev; + struct arcnet_local *lp; + + dev_dbg(&p_dev->dev, "com20020_attach()\n"); + + /* Create new network device */ + info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL); + if (!info) + goto fail_alloc_info; + + dev = alloc_arcdev(""); + if (!dev) + goto fail_alloc_dev; + + lp = netdev_priv(dev); + lp->timeout = timeout; + lp->backplane = backplane; + lp->clockp = clockp; + lp->clockm = clockm & 3; + lp->hw.owner = THIS_MODULE; + + /* fill in our module parameters as defaults */ + dev->dev_addr[0] = node; + + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + p_dev->resource[0]->end = 16; + p_dev->config_flags |= CONF_ENABLE_IRQ; + + info->dev = dev; + p_dev->priv = info; + + return com20020_config(p_dev); + +fail_alloc_dev: + kfree(info); +fail_alloc_info: + return -ENOMEM; +} /* com20020_attach */ + +static void com20020_detach(struct pcmcia_device *link) +{ + struct com20020_dev_t *info = link->priv; + struct net_device *dev = info->dev; + + dev_dbg(&link->dev, "detach...\n"); + + dev_dbg(&link->dev, "com20020_detach\n"); + + dev_dbg(&link->dev, "unregister...\n"); + + unregister_netdev(dev); + + /* + * this is necessary because we register our IRQ separately + * from card services. + */ + if (dev->irq) + free_irq(dev->irq, dev); + + com20020_release(link); + + /* Unlink device structure, free bits */ + dev_dbg(&link->dev, "unlinking...\n"); + if (link->priv) + { + dev = info->dev; + if (dev) + { + dev_dbg(&link->dev, "kfree...\n"); + free_netdev(dev); + } + dev_dbg(&link->dev, "kfree2...\n"); + kfree(info); + } + +} /* com20020_detach */ + +static int com20020_config(struct pcmcia_device *link) +{ + struct arcnet_local *lp; + com20020_dev_t *info; + struct net_device *dev; + int i, ret; + int ioaddr; + + info = link->priv; + dev = info->dev; + + dev_dbg(&link->dev, "config...\n"); + + dev_dbg(&link->dev, "com20020_config\n"); + + dev_dbg(&link->dev, "baseport1 is %Xh\n", + (unsigned int) link->resource[0]->start); + + i = -ENODEV; + link->io_lines = 16; + + if (!link->resource[0]->start) + { + for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10) + { + link->resource[0]->start = ioaddr; + i = pcmcia_request_io(link); + if (i == 0) + break; + } + } + else + i = pcmcia_request_io(link); + + if (i != 0) + { + dev_dbg(&link->dev, "requestIO failed totally!\n"); + goto failed; + } + + ioaddr = dev->base_addr = link->resource[0]->start; + dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr); + + dev_dbg(&link->dev, "request IRQ %d\n", + link->irq); + if (!link->irq) + { + dev_dbg(&link->dev, "requestIRQ failed totally!\n"); + goto failed; + } + + dev->irq = link->irq; + + ret = pcmcia_enable_device(link); + if (ret) + goto failed; + + if (com20020_check(dev)) + { + regdump(dev); + goto failed; + } + + lp = netdev_priv(dev); + lp->card_name = "PCMCIA COM20020"; + lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */ + + SET_NETDEV_DEV(dev, &link->dev); + + i = com20020_found(dev, 0); /* calls register_netdev */ + + if (i != 0) { + dev_notice(&link->dev, + "com20020_found() failed\n"); + goto failed; + } + + netdev_dbg(dev, "port %#3lx, irq %d\n", + dev->base_addr, dev->irq); + return 0; + +failed: + dev_dbg(&link->dev, "com20020_config failed...\n"); + com20020_release(link); + return -ENODEV; +} /* com20020_config */ + +static void com20020_release(struct pcmcia_device *link) +{ + dev_dbg(&link->dev, "com20020_release\n"); + pcmcia_disable_device(link); +} + +static int com20020_suspend(struct pcmcia_device *link) +{ + com20020_dev_t *info = link->priv; + struct net_device *dev = info->dev; + + if (link->open) + netif_device_detach(dev); + + return 0; +} + +static int com20020_resume(struct pcmcia_device *link) +{ + com20020_dev_t *info = link->priv; + struct net_device *dev = info->dev; + + if (link->open) { + int ioaddr = dev->base_addr; + struct arcnet_local *lp = netdev_priv(dev); + ARCRESET; + } + + return 0; +} + +static const struct pcmcia_device_id com20020_ids[] = { + PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.", + "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf), + PCMCIA_DEVICE_PROD_ID12("SoHard AG", + "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7), + PCMCIA_DEVICE_NULL +}; +MODULE_DEVICE_TABLE(pcmcia, com20020_ids); + +static struct pcmcia_driver com20020_cs_driver = { + .owner = THIS_MODULE, + .name = "com20020_cs", + .probe = com20020_probe, + .remove = com20020_detach, + .id_table = com20020_ids, + .suspend = com20020_suspend, + .resume = com20020_resume, +}; + +static int __init init_com20020_cs(void) +{ + return pcmcia_register_driver(&com20020_cs_driver); +} + +static void __exit exit_com20020_cs(void) +{ + pcmcia_unregister_driver(&com20020_cs_driver); +} + +module_init(init_com20020_cs); +module_exit(exit_com20020_cs); diff --git a/drivers/net/pcmcia/Kconfig b/drivers/net/pcmcia/Kconfig deleted file mode 100644 index ff4deb0..0000000 --- a/drivers/net/pcmcia/Kconfig +++ /dev/null @@ -1,34 +0,0 @@ -# -# PCMCIA Network device configuration -# - -menuconfig NET_PCMCIA - bool "PCMCIA network device support" - depends on PCMCIA - ---help--- - Say Y if you would like to include support for any PCMCIA or CardBus - network adapters, then say Y to the driver for your particular card - below. PCMCIA- or PC-cards are credit-card size devices often used - with laptops computers; CardBus is the newer and faster version of - PCMCIA. - - To use your PC-cards, you will need supporting software from David - Hinds' pcmcia-cs package (see the file - for location). You also want to check out the PCMCIA-HOWTO, - available from . - - If unsure, say N. - -if NET_PCMCIA && PCMCIA - -config ARCNET_COM20020_CS - tristate "COM20020 ARCnet PCMCIA support" - depends on ARCNET_COM20020 - help - Say Y here if you intend to attach this type of ARCnet PCMCIA card - to your computer. - - To compile this driver as a module, choose M here: the module will be - called com20020_cs. If unsure, say N. - -endif # NET_PCMCIA diff --git a/drivers/net/pcmcia/Makefile b/drivers/net/pcmcia/Makefile deleted file mode 100644 index b98a0a4..0000000 --- a/drivers/net/pcmcia/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# -# Makefile for the Linux PCMCIA network device drivers. -# - -# 16-bit client drivers -obj-$(CONFIG_ARCNET_COM20020_CS)+= com20020_cs.o diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c deleted file mode 100644 index 980e65c..0000000 --- a/drivers/net/pcmcia/com20020_cs.c +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Linux ARCnet driver - COM20020 PCMCIA support - * - * Written 1994-1999 by Avery Pennarun, - * based on an ISA version by David Woodhouse. - * Derived from ibmtr_cs.c by Steve Kipisz (pcmcia-cs 3.1.4) - * which was derived from pcnet_cs.c by David Hinds. - * Some additional portions derived from skeleton.c by Donald Becker. - * - * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) - * for sponsoring the further development of this driver. - * - * ********************** - * - * The original copyright of skeleton.c was as follows: - * - * skeleton.c Written 1993 by Donald Becker. - * Copyright 1993 United States Government as represented by the - * Director, National Security Agency. This software may only be used - * and distributed according to the terms of the GNU General Public License as - * modified by SRC, incorporated herein by reference. - * - * ********************** - * Changes: - * Arnaldo Carvalho de Melo - 08/08/2000 - * - reorganize kmallocs in com20020_attach, checking all for failure - * and releasing the previous allocations if one fails - * ********************** - * - * For more details, see drivers/net/arcnet.c - * - * ********************** - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#define VERSION "arcnet: COM20020 PCMCIA support loaded.\n" - - -static void regdump(struct net_device *dev) -{ -#ifdef DEBUG - int ioaddr = dev->base_addr; - int count; - - netdev_dbg(dev, "register dump:\n"); - for (count = ioaddr; count < ioaddr + 16; count++) - { - if (!(count % 16)) - pr_cont("%04X:", count); - pr_cont(" %02X", inb(count)); - } - pr_cont("\n"); - - netdev_dbg(dev, "buffer0 dump:\n"); - /* set up the address register */ - count = 0; - outb((count >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI); - outb(count & 0xff, _ADDR_LO); - - for (count = 0; count < 256+32; count++) - { - if (!(count % 16)) - pr_cont("%04X:", count); - - /* copy the data */ - pr_cont(" %02X", inb(_MEMDATA)); - } - pr_cont("\n"); -#endif -} - - - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -static int node; -static int timeout = 3; -static int backplane; -static int clockp; -static int clockm; - -module_param(node, int, 0); -module_param(timeout, int, 0); -module_param(backplane, int, 0); -module_param(clockp, int, 0); -module_param(clockm, int, 0); - -MODULE_LICENSE("GPL"); - -/*====================================================================*/ - -static int com20020_config(struct pcmcia_device *link); -static void com20020_release(struct pcmcia_device *link); - -static void com20020_detach(struct pcmcia_device *p_dev); - -/*====================================================================*/ - -typedef struct com20020_dev_t { - struct net_device *dev; -} com20020_dev_t; - -static int com20020_probe(struct pcmcia_device *p_dev) -{ - com20020_dev_t *info; - struct net_device *dev; - struct arcnet_local *lp; - - dev_dbg(&p_dev->dev, "com20020_attach()\n"); - - /* Create new network device */ - info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL); - if (!info) - goto fail_alloc_info; - - dev = alloc_arcdev(""); - if (!dev) - goto fail_alloc_dev; - - lp = netdev_priv(dev); - lp->timeout = timeout; - lp->backplane = backplane; - lp->clockp = clockp; - lp->clockm = clockm & 3; - lp->hw.owner = THIS_MODULE; - - /* fill in our module parameters as defaults */ - dev->dev_addr[0] = node; - - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - p_dev->resource[0]->end = 16; - p_dev->config_flags |= CONF_ENABLE_IRQ; - - info->dev = dev; - p_dev->priv = info; - - return com20020_config(p_dev); - -fail_alloc_dev: - kfree(info); -fail_alloc_info: - return -ENOMEM; -} /* com20020_attach */ - -static void com20020_detach(struct pcmcia_device *link) -{ - struct com20020_dev_t *info = link->priv; - struct net_device *dev = info->dev; - - dev_dbg(&link->dev, "detach...\n"); - - dev_dbg(&link->dev, "com20020_detach\n"); - - dev_dbg(&link->dev, "unregister...\n"); - - unregister_netdev(dev); - - /* - * this is necessary because we register our IRQ separately - * from card services. - */ - if (dev->irq) - free_irq(dev->irq, dev); - - com20020_release(link); - - /* Unlink device structure, free bits */ - dev_dbg(&link->dev, "unlinking...\n"); - if (link->priv) - { - dev = info->dev; - if (dev) - { - dev_dbg(&link->dev, "kfree...\n"); - free_netdev(dev); - } - dev_dbg(&link->dev, "kfree2...\n"); - kfree(info); - } - -} /* com20020_detach */ - -static int com20020_config(struct pcmcia_device *link) -{ - struct arcnet_local *lp; - com20020_dev_t *info; - struct net_device *dev; - int i, ret; - int ioaddr; - - info = link->priv; - dev = info->dev; - - dev_dbg(&link->dev, "config...\n"); - - dev_dbg(&link->dev, "com20020_config\n"); - - dev_dbg(&link->dev, "baseport1 is %Xh\n", - (unsigned int) link->resource[0]->start); - - i = -ENODEV; - link->io_lines = 16; - - if (!link->resource[0]->start) - { - for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10) - { - link->resource[0]->start = ioaddr; - i = pcmcia_request_io(link); - if (i == 0) - break; - } - } - else - i = pcmcia_request_io(link); - - if (i != 0) - { - dev_dbg(&link->dev, "requestIO failed totally!\n"); - goto failed; - } - - ioaddr = dev->base_addr = link->resource[0]->start; - dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr); - - dev_dbg(&link->dev, "request IRQ %d\n", - link->irq); - if (!link->irq) - { - dev_dbg(&link->dev, "requestIRQ failed totally!\n"); - goto failed; - } - - dev->irq = link->irq; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - if (com20020_check(dev)) - { - regdump(dev); - goto failed; - } - - lp = netdev_priv(dev); - lp->card_name = "PCMCIA COM20020"; - lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */ - - SET_NETDEV_DEV(dev, &link->dev); - - i = com20020_found(dev, 0); /* calls register_netdev */ - - if (i != 0) { - dev_notice(&link->dev, - "com20020_found() failed\n"); - goto failed; - } - - netdev_dbg(dev, "port %#3lx, irq %d\n", - dev->base_addr, dev->irq); - return 0; - -failed: - dev_dbg(&link->dev, "com20020_config failed...\n"); - com20020_release(link); - return -ENODEV; -} /* com20020_config */ - -static void com20020_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "com20020_release\n"); - pcmcia_disable_device(link); -} - -static int com20020_suspend(struct pcmcia_device *link) -{ - com20020_dev_t *info = link->priv; - struct net_device *dev = info->dev; - - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int com20020_resume(struct pcmcia_device *link) -{ - com20020_dev_t *info = link->priv; - struct net_device *dev = info->dev; - - if (link->open) { - int ioaddr = dev->base_addr; - struct arcnet_local *lp = netdev_priv(dev); - ARCRESET; - } - - return 0; -} - -static const struct pcmcia_device_id com20020_ids[] = { - PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.", - "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf), - PCMCIA_DEVICE_PROD_ID12("SoHard AG", - "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, com20020_ids); - -static struct pcmcia_driver com20020_cs_driver = { - .owner = THIS_MODULE, - .name = "com20020_cs", - .probe = com20020_probe, - .remove = com20020_detach, - .id_table = com20020_ids, - .suspend = com20020_suspend, - .resume = com20020_resume, -}; - -static int __init init_com20020_cs(void) -{ - return pcmcia_register_driver(&com20020_cs_driver); -} - -static void __exit exit_com20020_cs(void) -{ - pcmcia_unregister_driver(&com20020_cs_driver); -} - -module_init(init_com20020_cs); -module_exit(exit_com20020_cs); -- cgit v0.10.2 From 88491d8103498a6166f70d5999902fec70924314 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Tue, 23 Aug 2011 00:42:10 -0700 Subject: drivers/net: Kconfig & Makefile cleanup The is does a general cleanup of the drivers/net/ Kconfig and Makefile. This patch create a "core" option and places all the networking core drivers into this option (default is yes for this option). In addition, it alphabitizes the Kconfig driver options. As a side cleanup, found that the arcnet, token ring, and PHY Kconfig options were a tri-state option and should have been a bool option. Signed-off-by: Jeff Kirsher diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 5762370..583f66c 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -25,18 +25,32 @@ menuconfig NETDEVICES # that for each of the symbols. if NETDEVICES -config IFB - tristate "Intermediate Functional Block support" - depends on NET_CLS_ACT +config NET_CORE + default y + bool "Network core driver support" ---help--- - This is an intermediate driver that allows sharing of - resources. + You can say N here if you do not intend to use any of the + networking core drivers (i.e. VLAN, bridging, bonding, etc.) + +if NET_CORE + +config BONDING + tristate "Bonding driver support" + depends on INET + depends on IPV6 || IPV6=n + ---help--- + Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet + Channels together. This is called 'Etherchannel' by Cisco, + 'Trunking' by Sun, 802.3ad by the IEEE, and 'Bonding' in Linux. + + The driver supports multiple bonding modes to allow for both high + performance and high availability operation. + + Refer to for more + information. + To compile this driver as a module, choose M here: the module - will be called ifb. If you want to use more than one ifb - device at a time, you need to compile this driver as a module. - Instead of 'ifb', the devices will then be called 'ifb0', - 'ifb1' etc. - Look at the iproute2 documentation directory for usage etc + will be called bonding. config DUMMY tristate "Dummy net driver support" @@ -57,23 +71,59 @@ config DUMMY Instead of 'dummy', the devices will then be called 'dummy0', 'dummy1' etc. -config BONDING - tristate "Bonding driver support" - depends on INET - depends on IPV6 || IPV6=n +config EQUALIZER + tristate "EQL (serial line load balancing) support" ---help--- - Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet - Channels together. This is called 'Etherchannel' by Cisco, - 'Trunking' by Sun, 802.3ad by the IEEE, and 'Bonding' in Linux. + If you have two serial connections to some other computer (this + usually requires two modems and two telephone lines) and you use + SLIP (the protocol for sending Internet traffic over telephone + lines) or PPP (a better SLIP) on them, you can make them behave like + one double speed connection using this driver. Naturally, this has + to be supported at the other end as well, either with a similar EQL + Linux driver or with a Livingston Portmaster 2e. - The driver supports multiple bonding modes to allow for both high - performance and high availability operation. + Say Y if you want this and read + . You may also want to read + section 6.2 of the NET-3-HOWTO, available from + . - Refer to for more - information. + To compile this driver as a module, choose M here: the module + will be called eql. If unsure, say N. + +config NET_FC + bool "Fibre Channel driver support" + depends on SCSI && PCI + help + Fibre Channel is a high speed serial protocol mainly used to connect + large storage devices to the computer; it is compatible with and + intended to replace SCSI. + + If you intend to use Fibre Channel, you need to have a Fibre channel + adaptor card in your computer; say Y here and to the driver for your + adaptor below. You also should have said Y to "SCSI support" and + "SCSI generic support". +config MII + tristate "Generic Media Independent Interface device support" + help + Most ethernet controllers have MII transceiver either as an external + or internal device. It is safe to say Y or M here even if your + ethernet card lacks MII. + +source "drivers/ieee802154/Kconfig" + +config IFB + tristate "Intermediate Functional Block support" + depends on NET_CLS_ACT + ---help--- + This is an intermediate driver that allows sharing of + resources. To compile this driver as a module, choose M here: the module - will be called bonding. + will be called ifb. If you want to use more than one ifb + device at a time, you need to compile this driver as a module. + Instead of 'ifb', the devices will then be called 'ifb0', + 'ifb1' etc. + Look at the iproute2 documentation directory for usage etc config MACVLAN tristate "MAC-VLAN support (EXPERIMENTAL)" @@ -102,24 +152,46 @@ config MACVTAP To compile this driver as a module, choose M here: the module will be called macvtap. -config EQUALIZER - tristate "EQL (serial line load balancing) support" +config NETCONSOLE + tristate "Network console logging support" ---help--- - If you have two serial connections to some other computer (this - usually requires two modems and two telephone lines) and you use - SLIP (the protocol for sending Internet traffic over telephone - lines) or PPP (a better SLIP) on them, you can make them behave like - one double speed connection using this driver. Naturally, this has - to be supported at the other end as well, either with a similar EQL - Linux driver or with a Livingston Portmaster 2e. + If you want to log kernel messages over the network, enable this. + See for details. - Say Y if you want this and read - . You may also want to read - section 6.2 of the NET-3-HOWTO, available from - . +config NETCONSOLE_DYNAMIC + bool "Dynamic reconfiguration of logging targets" + depends on NETCONSOLE && SYSFS && CONFIGFS_FS && \ + !(NETCONSOLE=y && CONFIGFS_FS=m) + help + This option enables the ability to dynamically reconfigure target + parameters (interface, IP addresses, port numbers, MAC addresses) + at runtime through a userspace interface exported using configfs. + See for details. - To compile this driver as a module, choose M here: the module - will be called eql. If unsure, say N. +config NETPOLL + def_bool NETCONSOLE + +config NETPOLL_TRAP + bool "Netpoll traffic trapping" + default n + depends on NETPOLL + +config NET_POLL_CONTROLLER + def_bool NETPOLL + +config RIONET + tristate "RapidIO Ethernet over messaging driver support" + depends on RAPIDIO + +config RIONET_TX_SIZE + int "Number of outbound queue entries" + depends on RIONET + default "128" + +config RIONET_RX_SIZE + int "Number of inbound queue entries" + depends on RIONET + default "128" config TUN tristate "Universal TUN/TAP device driver support" @@ -151,6 +223,28 @@ config VETH When one end receives the packet it appears on its pair and vice versa. +config VIRTIO_NET + tristate "Virtio network driver (EXPERIMENTAL)" + depends on EXPERIMENTAL && VIRTIO + ---help--- + This is the virtual network driver for virtio. It can be used with + lguest or QEMU based VMMs (like KVM or Xen). Say Y or M. + +endif # NET_CORE + +config SUNGEM_PHY + tristate + +source "drivers/net/arcnet/Kconfig" + +source "drivers/atm/Kconfig" + +source "drivers/net/caif/Kconfig" + +source "drivers/net/ethernet/Kconfig" + +source "drivers/net/fddi/Kconfig" + config NET_SB1000 tristate "General Instruments Surfboard 1000" depends on PNP @@ -175,52 +269,26 @@ config NET_SB1000 If you don't have this card, of course say N. -source "drivers/net/arcnet/Kconfig" - -config MII - tristate "Generic Media Independent Interface device support" - help - Most ethernet controllers have MII transceiver either as an external - or internal device. It is safe to say Y or M here even if your - ethernet card lacks MII. - source "drivers/net/phy/Kconfig" -config SUNGEM_PHY - tristate - -# -# Ethernet -# - -source "drivers/net/ethernet/Kconfig" - -source "drivers/net/fddi/Kconfig" - source "drivers/net/plip/Kconfig" +source "drivers/net/ppp/Kconfig" + source "drivers/net/slip/Kconfig" +source "drivers/s390/net/Kconfig" + source "drivers/net/tokenring/Kconfig" +source "drivers/net/usb/Kconfig" + source "drivers/net/wireless/Kconfig" source "drivers/net/wimax/Kconfig" -source "drivers/net/usb/Kconfig" - -source "drivers/net/ppp/Kconfig" - source "drivers/net/wan/Kconfig" -source "drivers/atm/Kconfig" - -source "drivers/ieee802154/Kconfig" - -source "drivers/s390/net/Kconfig" - -source "drivers/net/caif/Kconfig" - config XEN_NETDEV_FRONTEND tristate "Xen network device frontend driver" depends on XEN @@ -260,67 +328,6 @@ config XEN_NETDEV_BACKEND compile this driver as a module, chose M here: the module will be called xen-netback. -config RIONET - tristate "RapidIO Ethernet over messaging driver support" - depends on RAPIDIO - -config RIONET_TX_SIZE - int "Number of outbound queue entries" - depends on RIONET - default "128" - -config RIONET_RX_SIZE - int "Number of inbound queue entries" - depends on RIONET - default "128" - -config NET_FC - bool "Fibre Channel driver support" - depends on SCSI && PCI - help - Fibre Channel is a high speed serial protocol mainly used to connect - large storage devices to the computer; it is compatible with and - intended to replace SCSI. - - If you intend to use Fibre Channel, you need to have a Fibre channel - adaptor card in your computer; say Y here and to the driver for your - adaptor below. You also should have said Y to "SCSI support" and - "SCSI generic support". - -config NETCONSOLE - tristate "Network console logging support" - ---help--- - If you want to log kernel messages over the network, enable this. - See for details. - -config NETCONSOLE_DYNAMIC - bool "Dynamic reconfiguration of logging targets" - depends on NETCONSOLE && SYSFS && CONFIGFS_FS && \ - !(NETCONSOLE=y && CONFIGFS_FS=m) - help - This option enables the ability to dynamically reconfigure target - parameters (interface, IP addresses, port numbers, MAC addresses) - at runtime through a userspace interface exported using configfs. - See for details. - -config NETPOLL - def_bool NETCONSOLE - -config NETPOLL_TRAP - bool "Netpoll traffic trapping" - default n - depends on NETPOLL - -config NET_POLL_CONTROLLER - def_bool NETPOLL - -config VIRTIO_NET - tristate "Virtio network driver (EXPERIMENTAL)" - depends on EXPERIMENTAL && VIRTIO - ---help--- - This is the virtual network driver for virtio. It can be used with - lguest or QEMU based VMMs (like KVM or Xen). Say Y or M. - config VMXNET3 tristate "VMware VMXNET3 ethernet driver" depends on PCI && INET diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 99327a4..1f52e73 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -2,40 +2,38 @@ # Makefile for the Linux network device drivers. # -obj-$(CONFIG_MII) += mii.o -obj-$(CONFIG_MDIO) += mdio.o -obj-$(CONFIG_PHYLIB) += phy/ -obj-$(CONFIG_CAN) += can/ -obj-$(CONFIG_BONDING) += bonding/ -obj-$(CONFIG_VMXNET3) += vmxnet3/ - # -# link order important here +# Networking Core Drivers # -obj-$(CONFIG_RIONET) += rionet.o - -# -# end link order section -# - -obj-$(CONFIG_NET) += Space.o loopback.o -obj-$(CONFIG_NET_SB1000) += sb1000.o - -obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o -obj-$(CONFIG_XEN_NETDEV_BACKEND) += xen-netback/ - +obj-$(CONFIG_BONDING) += bonding/ obj-$(CONFIG_DUMMY) += dummy.o +obj-$(CONFIG_EQUALIZER) += eql.o obj-$(CONFIG_IFB) += ifb.o obj-$(CONFIG_MACVLAN) += macvlan.o obj-$(CONFIG_MACVTAP) += macvtap.o -obj-$(CONFIG_EQUALIZER) += eql.o +obj-$(CONFIG_MII) += mii.o +obj-$(CONFIG_MDIO) += mdio.o +obj-$(CONFIG_NET) += Space.o loopback.o +obj-$(CONFIG_NETCONSOLE) += netconsole.o +obj-$(CONFIG_PHYLIB) += phy/ +obj-$(CONFIG_RIONET) += rionet.o obj-$(CONFIG_TUN) += tun.o obj-$(CONFIG_VETH) += veth.o +obj-$(CONFIG_VIRTIO_NET) += virtio_net.o +# +# Networking Drivers +# +obj-$(CONFIG_ARCNET) += arcnet/ obj-$(CONFIG_DEV_APPLETALK) += appletalk/ +obj-$(CONFIG_CAIF) += caif/ +obj-$(CONFIG_CAN) += can/ +obj-$(CONFIG_ETRAX_ETHERNET) += cris/ obj-$(CONFIG_ETHERNET) += ethernet/ obj-$(CONFIG_FDDI) += fddi/ obj-$(CONFIG_HIPPI) += hippi/ +obj-$(CONFIG_HAMRADIO) += hamradio/ +obj-$(CONFIG_IRDA) += irda/ obj-$(CONFIG_PLIP) += plip/ onj-$(CONFIG_PPP) += ppp/ obj-$(CONFIG_PPP_ASYNC) += ppp/ @@ -48,9 +46,17 @@ obj-$(CONFIG_PPPOL2TP) += ppp/ obj-$(CONFIG_PPTP) += ppp/ onj-$(CONFIG_SLIP) += slip/ obj-$(CONFIG_SLHC) += slip/ +obj-$(CONFIG_NET_SB1000) += sb1000.o +onj-$(CONFIG_SLIP) += slip/ +obj-$(CONFIG_SUNGEM_PHY) += sungem_phy.o obj-$(CONFIG_TR) += tokenring/ obj-$(CONFIG_WAN) += wan/ -obj-$(CONFIG_ARCNET) += arcnet/ +obj-$(CONFIG_WLAN) += wireless/ +obj-$(CONFIG_WIMAX) += wimax/ + +obj-$(CONFIG_VMXNET3) += vmxnet3/ +obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o +obj-$(CONFIG_XEN_NETDEV_BACKEND) += xen-netback/ obj-$(CONFIG_USB_CATC) += usb/ obj-$(CONFIG_USB_KAWETH) += usb/ @@ -61,17 +67,3 @@ obj-$(CONFIG_USB_USBNET) += usb/ obj-$(CONFIG_USB_ZD1201) += usb/ obj-$(CONFIG_USB_IPHETH) += usb/ obj-$(CONFIG_USB_CDC_PHONET) += usb/ - -obj-$(CONFIG_WLAN) += wireless/ -obj-$(CONFIG_HAMRADIO) += hamradio/ -obj-$(CONFIG_IRDA) += irda/ -obj-$(CONFIG_ETRAX_ETHERNET) += cris/ - -obj-$(CONFIG_NETCONSOLE) += netconsole.o - -obj-$(CONFIG_VIRTIO_NET) += virtio_net.o - -obj-$(CONFIG_WIMAX) += wimax/ -obj-$(CONFIG_CAIF) += caif/ - -obj-$(CONFIG_SUNGEM_PHY) += sungem_phy.o diff --git a/drivers/net/arcnet/Kconfig b/drivers/net/arcnet/Kconfig index 84fb634..a73d9dc 100644 --- a/drivers/net/arcnet/Kconfig +++ b/drivers/net/arcnet/Kconfig @@ -4,7 +4,7 @@ menuconfig ARCNET depends on NETDEVICES && (ISA || PCI || PCMCIA) - tristate "ARCnet support" + bool "ARCnet support" ---help--- If you have a network card of this type, say Y and check out the (arguably) beautiful poetry in diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index a702443..bb88e12 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -3,7 +3,7 @@ # menuconfig PHYLIB - tristate "PHY Device support and infrastructure" + bool "PHY Device support and infrastructure" depends on !S390 depends on NETDEVICES help diff --git a/drivers/net/tokenring/Kconfig b/drivers/net/tokenring/Kconfig index 0f70158..c7e0149 100644 --- a/drivers/net/tokenring/Kconfig +++ b/drivers/net/tokenring/Kconfig @@ -4,7 +4,7 @@ # So far, we only have PCI, ISA, and MCA token ring devices menuconfig TR - tristate "Token Ring driver support" + bool "Token Ring driver support" depends on NETDEVICES && !UML depends on (PCI || ISA || MCA || CCW || PCMCIA) select LLC -- cgit v0.10.2 From 88f07484ccdf08e58dc462ed1ac7eb2e84d88a17 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Tue, 23 Aug 2011 01:29:52 -0700 Subject: drivers/net/ethernet/*: Enabled vendor Kconfig options Based on finds for Stephen Rothwell, where current defconfig's enable a ethernet driver and it is not compiled due to the newly added NET_VENDOR_* component of Kconfig. This patch enables all the "new" Kconfig options so that current defconfig's will continue to compile the expected drivers. In addition, by enabling all the new Kconfig options does not add any un-expected options. CC: Stephen Rothwll Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/Kconfig index 65cc129..a439cbd 100644 --- a/drivers/net/ethernet/3com/Kconfig +++ b/drivers/net/ethernet/3com/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_3COM bool "3Com devices" + default y depends on ISA || EISA || MCA || PCI || PCMCIA ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig index 5d21698..e04ade4 100644 --- a/drivers/net/ethernet/8390/Kconfig +++ b/drivers/net/ethernet/8390/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_8390 bool "National Semi-conductor 8390 devices" + default y depends on NET_VENDOR_NATSEMI && (AMIGA_PCMCIA || PCI || SUPERH || \ ISA || MCA || EISA || MAC || M32R || MACH_TX49XX || \ MCA_LEGACY || H8300 || ARM || MIPS || ZORRO || PCMCIA || \ diff --git a/drivers/net/ethernet/adaptec/Kconfig b/drivers/net/ethernet/adaptec/Kconfig index 5e9dbe9..5c804bb 100644 --- a/drivers/net/ethernet/adaptec/Kconfig +++ b/drivers/net/ethernet/adaptec/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_ADAPTEC bool "Adaptec devices" + default y depends on PCI ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/alteon/Kconfig b/drivers/net/ethernet/alteon/Kconfig index 68862e4..799a852 100644 --- a/drivers/net/ethernet/alteon/Kconfig +++ b/drivers/net/ethernet/alteon/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_ALTEON bool "Alteon devices" + default y depends on PCI ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig index 0513940..8af1c93 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_AMD bool "AMD devices" + default y depends on DIO || MACH_DECSTATION || MVME147 || ATARI || SUN3 || \ SUN3X || SBUS || PCI || ZORRO || (ISA && ISA_DMA_API) || \ (ARM && ARCH_EBSA110) || ISA || EISA || MCA || PCMCIA diff --git a/drivers/net/ethernet/apple/Kconfig b/drivers/net/ethernet/apple/Kconfig index fc796bc..59d5c26 100644 --- a/drivers/net/ethernet/apple/Kconfig +++ b/drivers/net/ethernet/apple/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_APPLE bool "Apple devices" + default y depends on (PPC_PMAC && PPC32) || MAC || ISA || EISA || MACH_IXDP2351 \ || ARCH_IXDP2X01 || MACH_MX31ADS || MACH_QQ2440 ---help--- diff --git a/drivers/net/ethernet/atheros/Kconfig b/drivers/net/ethernet/atheros/Kconfig index 966c6c7..26ab8ca 100644 --- a/drivers/net/ethernet/atheros/Kconfig +++ b/drivers/net/ethernet/atheros/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_ATHEROS bool "Atheros devices" + default y depends on PCI ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index 8986e57..d82ad22 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_BROADCOM bool "Broadcom devices" + default y depends on (SSB_POSSIBLE && HAS_DMA) || PCI || BCM63XX || \ SIBYTE_SB1xxx_SOC ---help--- diff --git a/drivers/net/ethernet/brocade/Kconfig b/drivers/net/ethernet/brocade/Kconfig index 03f0b17..2641557 100644 --- a/drivers/net/ethernet/brocade/Kconfig +++ b/drivers/net/ethernet/brocade/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_BROCADE bool "Brocade devices" + default y depends on PCI ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/chelsio/Kconfig b/drivers/net/ethernet/chelsio/Kconfig index 7b54574..2de50f9 100644 --- a/drivers/net/ethernet/chelsio/Kconfig +++ b/drivers/net/ethernet/chelsio/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_CHELSIO bool "Chelsio devices" + default y depends on PCI || INET ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/cirrus/Kconfig b/drivers/net/ethernet/cirrus/Kconfig index 53ebe78..e0cacf6 100644 --- a/drivers/net/ethernet/cirrus/Kconfig +++ b/drivers/net/ethernet/cirrus/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_CIRRUS bool "Cirrus devices" + default y depends on ARM && ARCH_EP93XX ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/cisco/Kconfig b/drivers/net/ethernet/cisco/Kconfig index bbd5348..94606f7 100644 --- a/drivers/net/ethernet/cisco/Kconfig +++ b/drivers/net/ethernet/cisco/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_CISCO bool "Cisco devices" + default y depends on PCI && INET ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/dec/Kconfig b/drivers/net/ethernet/dec/Kconfig index 40e8df9..3794027 100644 --- a/drivers/net/ethernet/dec/Kconfig +++ b/drivers/net/ethernet/dec/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_DEC bool "Digital Equipment devices" + default y depends on PCI || EISA || CARDBUS ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/dlink/Kconfig b/drivers/net/ethernet/dlink/Kconfig index 9fdb66b..84a28a6 100644 --- a/drivers/net/ethernet/dlink/Kconfig +++ b/drivers/net/ethernet/dlink/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_DLINK bool "D-Link devices" + default y depends on PCI || PARPORT ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/emulex/Kconfig b/drivers/net/ethernet/emulex/Kconfig index 018ac94..7a28a64 100644 --- a/drivers/net/ethernet/emulex/Kconfig +++ b/drivers/net/ethernet/emulex/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_EMULEX bool "Emulex devices" + default y depends on PCI && INET ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/faraday/Kconfig b/drivers/net/ethernet/faraday/Kconfig index b0d76f0..5918c68 100644 --- a/drivers/net/ethernet/faraday/Kconfig +++ b/drivers/net/ethernet/faraday/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_FARADAY bool "Faraday devices" + default y depends on ARM ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig index 2fd2c61..4dbe41f 100644 --- a/drivers/net/ethernet/freescale/Kconfig +++ b/drivers/net/ethernet/freescale/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_FREESCALE bool "Freescale devices" + default y depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \ M523x || M527x || M5272 || M528x || M520x || M532x || \ IMX_HAVE_PLATFORM_FEC || MXS_HAVE_PLATFORM_FEC || \ diff --git a/drivers/net/ethernet/fujitsu/Kconfig b/drivers/net/ethernet/fujitsu/Kconfig index 2cd968e..dffee9d 100644 --- a/drivers/net/ethernet/fujitsu/Kconfig +++ b/drivers/net/ethernet/fujitsu/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_FUJITSU bool "Fujitsu devices" + default y depends on ISA || PCMCIA || ((ISA || MCA_LEGACY) && EXPERIMENTAL) ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/hp/Kconfig b/drivers/net/ethernet/hp/Kconfig index 07b42e9..a0b8ece 100644 --- a/drivers/net/ethernet/hp/Kconfig +++ b/drivers/net/ethernet/hp/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_HP bool "HP devices" + default y depends on ISA || EISA || PCI ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/i825xx/Kconfig b/drivers/net/ethernet/i825xx/Kconfig index 5c30a5b..2be4698 100644 --- a/drivers/net/ethernet/i825xx/Kconfig +++ b/drivers/net/ethernet/i825xx/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_I825XX bool "Intel (82586/82593/82596) devices" + default y depends on NET_VENDOR_INTEL && (ISA || ISA_DMA_API || ARM || \ ARCH_ACORN || MCA || MCA_LEGACY || SNI_RM || SUN3 || \ GSC || BVME6000 || MVME16x || EXPERIMENTAL) diff --git a/drivers/net/ethernet/ibm/Kconfig b/drivers/net/ethernet/ibm/Kconfig index 4c7ef98..9e16f3f 100644 --- a/drivers/net/ethernet/ibm/Kconfig +++ b/drivers/net/ethernet/ibm/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_IBM bool "IBM devices" + default y depends on MCA || PPC_PSERIES || PPC_PSERIES || PPC_DCR || \ (IBMEBUS && INET && SPARSEMEM) ---help--- diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 5fe185b..4a98e83 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_INTEL bool "Intel devices" + default y depends on PCI || PCI_MSI ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig index e525408..0029934 100644 --- a/drivers/net/ethernet/marvell/Kconfig +++ b/drivers/net/ethernet/marvell/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_MARVELL bool "Marvell devices" + default y depends on PCI || CPU_PXA168 || MV64X60 || PPC32 || PLAT_ORION || INET ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/mellanox/Kconfig b/drivers/net/ethernet/mellanox/Kconfig index e069491..d8099a7 100644 --- a/drivers/net/ethernet/mellanox/Kconfig +++ b/drivers/net/ethernet/mellanox/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_MELLANOX bool "Mellanox devices" + default y depends on PCI && INET ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/micrel/Kconfig b/drivers/net/ethernet/micrel/Kconfig index 4227de6..bd090db 100644 --- a/drivers/net/ethernet/micrel/Kconfig +++ b/drivers/net/ethernet/micrel/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_MICREL bool "Micrel devices" + default y depends on (HAS_IOMEM && DMA_ENGINE) || SPI || PCI || HAS_IOMEM || \ (ARM && ARCH_KS8695) ---help--- diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig index 53b0b04..8163fd0 100644 --- a/drivers/net/ethernet/microchip/Kconfig +++ b/drivers/net/ethernet/microchip/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_MICROCHIP bool "Microchip devices" + default y depends on SPI && EXPERIMENTAL ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/myricom/Kconfig b/drivers/net/ethernet/myricom/Kconfig index 1816ae1..540f0c6 100644 --- a/drivers/net/ethernet/myricom/Kconfig +++ b/drivers/net/ethernet/myricom/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_MYRI bool "Myricom devices" + default y depends on PCI && INET ---help--- If you have a network (Ethernet) card belonging to this class, say diff --git a/drivers/net/ethernet/natsemi/Kconfig b/drivers/net/ethernet/natsemi/Kconfig index 1e5c1e1..4a6b9fd 100644 --- a/drivers/net/ethernet/natsemi/Kconfig +++ b/drivers/net/ethernet/natsemi/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_NATSEMI bool "National Semi-conductor devices" + default y depends on MCA || MAC || MACH_JAZZ || PCI || XTENSA_PLATFORM_XT2000 ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/neterion/Kconfig b/drivers/net/ethernet/neterion/Kconfig index 3d98e62..ff26b54 100644 --- a/drivers/net/ethernet/neterion/Kconfig +++ b/drivers/net/ethernet/neterion/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_EXAR bool "Exar devices" + default y depends on PCI ---help--- If you have a network (Ethernet) card belonging to this class, say diff --git a/drivers/net/ethernet/nuvoton/Kconfig b/drivers/net/ethernet/nuvoton/Kconfig index 3b91c3b..01182b5 100644 --- a/drivers/net/ethernet/nuvoton/Kconfig +++ b/drivers/net/ethernet/nuvoton/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_NUVOTON bool "Nuvoton devices" + default y depends on ARM && ARCH_W90X900 ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/nvidia/Kconfig b/drivers/net/ethernet/nvidia/Kconfig index 0a18e73..ace19e7 100644 --- a/drivers/net/ethernet/nvidia/Kconfig +++ b/drivers/net/ethernet/nvidia/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_NVIDIA bool "NVIDIA devices" + default y depends on PCI ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/oki-semi/Kconfig b/drivers/net/ethernet/oki-semi/Kconfig index 97f5e72..ecd45f9 100644 --- a/drivers/net/ethernet/oki-semi/Kconfig +++ b/drivers/net/ethernet/oki-semi/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_OKI bool "OKI Semiconductor devices" + default y depends on PCI ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/pasemi/Kconfig b/drivers/net/ethernet/pasemi/Kconfig index ccb79b8..01e6c32 100644 --- a/drivers/net/ethernet/pasemi/Kconfig +++ b/drivers/net/ethernet/pasemi/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_PASEMI bool "PA Semi devices" + default y depends on PPC_PASEMI && PCI && INET ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig index a7c4424..a8669ad 100644 --- a/drivers/net/ethernet/qlogic/Kconfig +++ b/drivers/net/ethernet/qlogic/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_QLOGIC bool "QLogic devices" + default y depends on PCI ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/racal/Kconfig b/drivers/net/ethernet/racal/Kconfig index 45d4930..01969e0 100644 --- a/drivers/net/ethernet/racal/Kconfig +++ b/drivers/net/ethernet/racal/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_RACAL bool "Racal-Interlan (Micom) NI devices" + default y depends on ISA ---help--- If you have a network (Ethernet) card belonging to this class, such diff --git a/drivers/net/ethernet/rdc/Kconfig b/drivers/net/ethernet/rdc/Kconfig index b15ebac..2055f7e 100644 --- a/drivers/net/ethernet/rdc/Kconfig +++ b/drivers/net/ethernet/rdc/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_RDC bool "RDC devices" + default y depends on PCI ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig index a5f67a09..d8df67a 100644 --- a/drivers/net/ethernet/realtek/Kconfig +++ b/drivers/net/ethernet/realtek/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_REALTEK bool "Realtek devices" + default y depends on PCI || (PARPORT && X86) ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/seeq/Kconfig b/drivers/net/ethernet/seeq/Kconfig index 0266791..49b6d5b 100644 --- a/drivers/net/ethernet/seeq/Kconfig +++ b/drivers/net/ethernet/seeq/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_SEEQ bool "SEEQ devices" + default y depends on (ARM && ARCH_ACORN) || SGI_HAS_SEEQ || EXPERIMENTAL ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/sgi/Kconfig b/drivers/net/ethernet/sgi/Kconfig index 3098594..e832f46 100644 --- a/drivers/net/ethernet/sgi/Kconfig +++ b/drivers/net/ethernet/sgi/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_SGI bool "SGI devices" + default y depends on (PCI && SGI_IP27) || SGI_IP32 ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/sis/Kconfig b/drivers/net/ethernet/sis/Kconfig index 01d43e8..68d052b 100644 --- a/drivers/net/ethernet/sis/Kconfig +++ b/drivers/net/ethernet/sis/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_SIS bool "Silicon Integrated Systems (SiS) devices" + default y depends on PCI ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig index 702efe6..f961928 100644 --- a/drivers/net/ethernet/smsc/Kconfig +++ b/drivers/net/ethernet/smsc/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_SMSC bool "SMC (SMSC)/Western Digital devices" + default y depends on ARM || ISA || MAC || ARM || MIPS || M32R || SUPERH || \ BLACKFIN || MN10300 || COLDFIRE || PCI || PCMCIA ---help--- diff --git a/drivers/net/ethernet/stmicro/Kconfig b/drivers/net/ethernet/stmicro/Kconfig index e40df64..f4a80da 100644 --- a/drivers/net/ethernet/stmicro/Kconfig +++ b/drivers/net/ethernet/stmicro/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_STMICRO bool "STMicroelectronics devices" + default y depends on HAS_IOMEM ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/sun/Kconfig b/drivers/net/ethernet/sun/Kconfig index 5132fa6..57bfd85 100644 --- a/drivers/net/ethernet/sun/Kconfig +++ b/drivers/net/ethernet/sun/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_SUN bool "Sun devices" + default y depends on SUN3 || SBUS || PCI || SUN_LDOMS ---help--- If you have a network (Ethernet) card belonging to this class, say diff --git a/drivers/net/ethernet/tehuti/Kconfig b/drivers/net/ethernet/tehuti/Kconfig index 914ad4059..1fc027e 100644 --- a/drivers/net/ethernet/tehuti/Kconfig +++ b/drivers/net/ethernet/tehuti/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_TEHUTI bool "Tehuti devices" + default y depends on PCI ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig index 1284319..de76c70 100644 --- a/drivers/net/ethernet/ti/Kconfig +++ b/drivers/net/ethernet/ti/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_TI bool "Texas Instruments (TI) devices" + default y depends on PCI || EISA || AR7 || (ARM && (ARCH_DAVINCI || ARCH_OMAP3)) ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/toshiba/Kconfig b/drivers/net/ethernet/toshiba/Kconfig index 6ef2ce2..0517647 100644 --- a/drivers/net/ethernet/toshiba/Kconfig +++ b/drivers/net/ethernet/toshiba/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_TOSHIBA bool "Toshiba devices" + default y depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB) || PPC_PS3 ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/tundra/Kconfig b/drivers/net/ethernet/tundra/Kconfig index 03925d1..cf7d69b 100644 --- a/drivers/net/ethernet/tundra/Kconfig +++ b/drivers/net/ethernet/tundra/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_TUNDRA bool "Tundra devices" + default y depends on TSI108_BRIDGE ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/via/Kconfig b/drivers/net/ethernet/via/Kconfig index 7199194..e5d82a5 100644 --- a/drivers/net/ethernet/via/Kconfig +++ b/drivers/net/ethernet/via/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_VIA bool "VIA devices" + default y depends on PCI ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig index 4e3aad4..d5a8260 100644 --- a/drivers/net/ethernet/xilinx/Kconfig +++ b/drivers/net/ethernet/xilinx/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_XILINX bool "Xilinx devices" + default y depends on PPC || PPC32 || MICROBLAZE ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/xircom/Kconfig b/drivers/net/ethernet/xircom/Kconfig index 3d64e58..69f56a6 100644 --- a/drivers/net/ethernet/xircom/Kconfig +++ b/drivers/net/ethernet/xircom/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_XIRCOM bool "Xircom devices" + default y depends on PCMCIA ---help--- If you have a network (Ethernet) card belonging to this class, say Y diff --git a/drivers/net/ethernet/xscale/Kconfig b/drivers/net/ethernet/xscale/Kconfig index 6bbcc54..cf67352 100644 --- a/drivers/net/ethernet/xscale/Kconfig +++ b/drivers/net/ethernet/xscale/Kconfig @@ -4,6 +4,7 @@ config NET_VENDOR_XSCALE bool "Intel XScale IXP devices" + default y depends on NET_VENDOR_INTEL && ((ARM && ARCH_IXP4XX && \ IXP4XX_NPE && IXP4XX_QMGR) || ARCH_ENP2611) ---help--- -- cgit v0.10.2