/drivers/net/defxx.c
C | 1649 lines | 664 code | 224 blank | 761 comment | 85 complexity | b04de96eee3e4727f21c049dff707e21 MD5 | raw file
- /*
- * 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 <lstefani@yahoo.com>
- *
- * Maintainers:
- * macro Maciej W. Rozycki <macro@linux-mips.org>
- *
- * 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 <linux/bitops.h>
- #include <linux/compiler.h>
- #include <linux/delay.h>
- #include <linux/dma-mapping.h>
- #include <linux/eisa.h>
- #include <linux/errno.h>
- #include <linux/fddidevice.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/ioport.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/netdevice.h>
- #include <linux/pci.h>
- #include <linux/skbuff.h>
- #include <linux/slab.h>
- #include <linux/string.h>
- #include <linux/tc.h>
- #include <asm/byteorder.h>
- #include <asm/io.h>
- #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_multicast_list = 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 ...