/* * 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 <[email protected]> * * Maintainers: * macro Maciej W. Rozycki <[email protected]> * * 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. * 01 Jul 2014 macro Fixes for DMA on 64-bit hosts. * 10 Mar 2021 macro Dynamic MMIO vs port I/O. */ /* 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/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 … #define DRV_VERSION … #define DRV_RELDATE … static const char version[] = …; #define DYNAMIC_BUFFERS … #define SKBUFF_RX_COPYBREAK … /* * 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 … #ifdef CONFIG_EISA #define DFX_BUS_EISA(dev) … #else #define DFX_BUS_EISA … #endif #ifdef CONFIG_TC #define DFX_BUS_TC … #else #define DFX_BUS_TC(dev) … #endif #ifdef CONFIG_HAS_IOPORT #define dfx_use_mmio … #else #define dfx_use_mmio … #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); #ifdef DYNAMIC_BUFFERS static void dfx_rcv_flush(DFX_board_t *bp); #else static inline void dfx_rcv_flush(DFX_board_t *bp) {} #endif 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) { … } static inline void dfx_outl(DFX_board_t *bp, int offset, u32 data) { … } static void dfx_port_write_long(DFX_board_t *bp, int offset, u32 data) { … } static inline void dfx_readl(DFX_board_t *bp, int offset, u32 *data) { … } static inline void dfx_inl(DFX_board_t *bp, int offset, u32 *data) { … } static void dfx_port_read_long(DFX_board_t *bp, int offset, u32 *data) { … } /* * ================ * = dfx_get_bars = * ================ * * Overview: * Retrieves the address ranges used to access control and status * registers. * * Returns: * None * * Arguments: * bp - pointer to board information * bar_start - pointer to store the start addresses * bar_len - pointer to store the lengths of the areas * * Assumptions: * I am sure there are some. * * Side Effects: * None */ static void dfx_get_bars(DFX_board_t *bp, resource_size_t *bar_start, resource_size_t *bar_len) { … } static const struct net_device_ops dfx_netdev_ops = …; static void dfx_register_res_err(const char *print_name, bool mmio, unsigned long start, unsigned long len) { … } /* * ================ * = 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 dfx_register(struct device *bdev) { … } /* * ================ * = 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 dfx_bus_init(struct net_device *dev) { … } /* * ================== * = 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 dfx_bus_uninit(struct net_device *dev) { … } /* * ======================== * = 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 dfx_bus_config_check(DFX_board_t *bp) { … } /* * =================== * = 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 dma_alloc_coherent() 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 dfx_driver_init(struct net_device *dev, const char *print_name, resource_size_t bar_start) { … } /* * ================= * = 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) { … } /* * ============ * = 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_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_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) { … } /* * ========================== * = 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) { … } /* * ================== * = 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_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) { … } /* * ===================== * = 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_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_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) { … } /* * ====================== * = 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) { … } /* * ========================== * = 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) { … } /* * ====================== * = 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) { … } /* * ======================== * = 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 ) { … } /* * ===================== * = 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 ) { … } /* * ======================== * = 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) { … } /* * ===================== * = 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) { … } /* * Align an sk_buff to a boundary power of 2 * */ #ifdef DYNAMIC_BUFFERS static void my_skb_align(struct sk_buff *skb, int n) { … } #endif /* * ================ * = 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) { … } /* * ========================= * = 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 ) { … } /* * ===================== * = 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 dma_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_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) { … } /* * ================= * = 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 ) { … } #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 ) { … } /* * ================== * = 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 dfx_unregister(struct device *bdev) { … } static int __maybe_unused dfx_dev_register(struct device *); static int __maybe_unused dfx_dev_unregister(struct device *); #ifdef CONFIG_PCI static int dfx_pci_register(struct pci_dev *, const struct pci_device_id *); static void dfx_pci_unregister(struct pci_dev *); static const struct pci_device_id dfx_pci_table[] = …; MODULE_DEVICE_TABLE(pci, dfx_pci_table); static struct pci_driver dfx_pci_driver = …; static int dfx_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) { … } static void dfx_pci_unregister(struct pci_dev *pdev) { … } #endif /* CONFIG_PCI */ #ifdef CONFIG_EISA static const struct eisa_device_id dfx_eisa_table[] = …; MODULE_DEVICE_TABLE(eisa, dfx_eisa_table); static struct eisa_driver dfx_eisa_driver = …; #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 = DRV_NAME, .bus = &tc_bus_type, .probe = dfx_dev_register, .remove = dfx_dev_unregister, }, }; #endif /* CONFIG_TC */ static int __maybe_unused dfx_dev_register(struct device *dev) { … } static int __maybe_unused dfx_dev_unregister(struct device *dev) { … } static int dfx_init(void) { … } static void dfx_cleanup(void) { … } module_init(…) …; module_exit(dfx_cleanup); MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;