📄 defxx.c
字号:
/* * 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 Public License, incorporated herein by reference. * * Abstract: * A Linux device driver supporting the Digital Equipment Corporation * FDDI EISA and PCI controller families. Supported adapters include: * * DEC FDDIcontroller/EISA (DEFEA) * DEC FDDIcontroller/PCI (DEFPA) * * Maintainers: * LVS Lawrence V. Stefani * * Contact: * The author may be reached at: * * Inet: stefani@lkg.dec.com * Mail: Digital Equipment Corporation * 550 King Street * M/S: LKG1-3/M07 * Littleton, MA 01460 * * 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. The supported PCI adapters are * discovered using successive calls to pcibios_find_device. * The first time the probe routine is called, all supported * devices are discovered and initialized. The adapters aren't * brought up to an operational state until the open routine is * called. * * 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. *//* Version information string - should be updated prior to each new release!!! */static const char *version = "defxx.c:v1.04 09/16/96 Lawrence V. Stefani (stefani@lkg.dec.com)\n";/* Include files */#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/malloc.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/init.h>#include <asm/byteorder.h>#include <asm/bitops.h>#include <asm/io.h>#include <linux/netdevice.h>#include <linux/fddidevice.h>#include <linux/skbuff.h>#include "defxx.h"#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)/* Define global routines */int dfx_probe(struct device *dev);/* Define module-wide (static) routines */static struct device *dfx_alloc_device(struct device *dev, u16 iobase);static void dfx_bus_init(struct device *dev);static void dfx_bus_config_check(DFX_board_t *bp);static int dfx_driver_init(struct device *dev);static int dfx_adap_init(DFX_board_t *bp);static int dfx_open(struct device *dev);static int dfx_close(struct 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(DFX_board_t *bp);static void dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs);static struct net_device_stats *dfx_ctl_get_stats(struct device *dev);static void dfx_ctl_set_multicast_list(struct device *dev);static int dfx_ctl_set_mac_address(struct 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 void dfx_rcv_init(DFX_board_t *bp);static void dfx_rcv_queue_process(DFX_board_t *bp);static int dfx_xmt_queue_pkt(struct sk_buff *skb, struct device *dev);static void dfx_xmt_done(DFX_board_t *bp);static void dfx_xmt_flush(DFX_board_t *bp);/* Define module-wide (static) variables */static int num_boards = 0; /* total number of adapters configured */static int already_probed = 0; /* have we already entered dfx_probe? *//* * ======================= * = dfx_port_write_byte = * = dfx_port_read_byte = * = 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_byte and dfx_port_write_long, this * is a value to write. * for dfx_port_read_byte and dfx_port_read_byte, 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_addr 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_port_write_byte( DFX_board_t *bp, int offset, u8 data ) { u16 port = bp->base_addr + offset; outb(data, port); return; }static inline void dfx_port_read_byte( DFX_board_t *bp, int offset, u8 *data ) { u16 port = bp->base_addr + offset; *data = inb(port); return; }static inline void dfx_port_write_long( DFX_board_t *bp, int offset, u32 data ) { u16 port = bp->base_addr + offset; outl(data, port); return; }static inline void dfx_port_read_long( DFX_board_t *bp, int offset, u32 *data ) { u16 port = bp->base_addr + offset; *data = inl(port); return; }/* * ============= * = dfx_probe = * ============= * * Overview: * Probes for supported FDDI EISA and PCI controllers * * Returns: * Condition code * * Arguments: * dev - pointer to device information * * Functional Description: * This routine is called by the OS for each FDDI device name (fddi0, * fddi1,...,fddi6, fddi7) specified in drivers/net/Space.c. Since * the DEFXX.C driver currently does not support being loaded as a * module, dfx_probe() will initialize all devices the first time * it is called. * * Let's say that dfx_probe() is getting called to initialize fddi0. * Furthermore, let's say there are three supported controllers in the * system. Before dfx_probe() leaves, devices fddi0, fddi1, and fddi2
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -