defxx.c
来自「linux 内核源代码」· C语言 代码 · 共 2,079 行 · 第 1/5 页
C
2,079 行
/* * 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 int 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 = * ================ *
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?