18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * File Name: 38c2ecf20Sopenharmony_ci * defxx.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright Information: 68c2ecf20Sopenharmony_ci * Copyright Digital Equipment Corporation 1996. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This software may be used and distributed according to the terms of 98c2ecf20Sopenharmony_ci * the GNU General Public License, incorporated herein by reference. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Abstract: 128c2ecf20Sopenharmony_ci * A Linux device driver supporting the Digital Equipment Corporation 138c2ecf20Sopenharmony_ci * FDDI TURBOchannel, EISA and PCI controller families. Supported 148c2ecf20Sopenharmony_ci * adapters include: 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * DEC FDDIcontroller/TURBOchannel (DEFTA) 178c2ecf20Sopenharmony_ci * DEC FDDIcontroller/EISA (DEFEA) 188c2ecf20Sopenharmony_ci * DEC FDDIcontroller/PCI (DEFPA) 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * The original author: 218c2ecf20Sopenharmony_ci * LVS Lawrence V. Stefani <lstefani@yahoo.com> 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Maintainers: 248c2ecf20Sopenharmony_ci * macro Maciej W. Rozycki <macro@linux-mips.org> 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * Credits: 278c2ecf20Sopenharmony_ci * I'd like to thank Patricia Cross for helping me get started with 288c2ecf20Sopenharmony_ci * Linux, David Davies for a lot of help upgrading and configuring 298c2ecf20Sopenharmony_ci * my development system and for answering many OS and driver 308c2ecf20Sopenharmony_ci * development questions, and Alan Cox for recommendations and 318c2ecf20Sopenharmony_ci * integration help on getting FDDI support into Linux. LVS 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * Driver Architecture: 348c2ecf20Sopenharmony_ci * The driver architecture is largely based on previous driver work 358c2ecf20Sopenharmony_ci * for other operating systems. The upper edge interface and 368c2ecf20Sopenharmony_ci * functions were largely taken from existing Linux device drivers 378c2ecf20Sopenharmony_ci * such as David Davies' DE4X5.C driver and Donald Becker's TULIP.C 388c2ecf20Sopenharmony_ci * driver. 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * Adapter Probe - 418c2ecf20Sopenharmony_ci * The driver scans for supported EISA adapters by reading the 428c2ecf20Sopenharmony_ci * SLOT ID register for each EISA slot and making a match 438c2ecf20Sopenharmony_ci * against the expected value. 448c2ecf20Sopenharmony_ci * 458c2ecf20Sopenharmony_ci * Bus-Specific Initialization - 468c2ecf20Sopenharmony_ci * This driver currently supports both EISA and PCI controller 478c2ecf20Sopenharmony_ci * families. While the custom DMA chip and FDDI logic is similar 488c2ecf20Sopenharmony_ci * or identical, the bus logic is very different. After 498c2ecf20Sopenharmony_ci * initialization, the only bus-specific differences is in how the 508c2ecf20Sopenharmony_ci * driver enables and disables interrupts. Other than that, the 518c2ecf20Sopenharmony_ci * run-time critical code behaves the same on both families. 528c2ecf20Sopenharmony_ci * It's important to note that both adapter families are configured 538c2ecf20Sopenharmony_ci * to I/O map, rather than memory map, the adapter registers. 548c2ecf20Sopenharmony_ci * 558c2ecf20Sopenharmony_ci * Driver Open/Close - 568c2ecf20Sopenharmony_ci * In the driver open routine, the driver ISR (interrupt service 578c2ecf20Sopenharmony_ci * routine) is registered and the adapter is brought to an 588c2ecf20Sopenharmony_ci * operational state. In the driver close routine, the opposite 598c2ecf20Sopenharmony_ci * occurs; the driver ISR is deregistered and the adapter is 608c2ecf20Sopenharmony_ci * brought to a safe, but closed state. Users may use consecutive 618c2ecf20Sopenharmony_ci * commands to bring the adapter up and down as in the following 628c2ecf20Sopenharmony_ci * example: 638c2ecf20Sopenharmony_ci * ifconfig fddi0 up 648c2ecf20Sopenharmony_ci * ifconfig fddi0 down 658c2ecf20Sopenharmony_ci * ifconfig fddi0 up 668c2ecf20Sopenharmony_ci * 678c2ecf20Sopenharmony_ci * Driver Shutdown - 688c2ecf20Sopenharmony_ci * Apparently, there is no shutdown or halt routine support under 698c2ecf20Sopenharmony_ci * Linux. This routine would be called during "reboot" or 708c2ecf20Sopenharmony_ci * "shutdown" to allow the driver to place the adapter in a safe 718c2ecf20Sopenharmony_ci * state before a warm reboot occurs. To be really safe, the user 728c2ecf20Sopenharmony_ci * should close the adapter before shutdown (eg. ifconfig fddi0 down) 738c2ecf20Sopenharmony_ci * to ensure that the adapter DMA engine is taken off-line. However, 748c2ecf20Sopenharmony_ci * the current driver code anticipates this problem and always issues 758c2ecf20Sopenharmony_ci * a soft reset of the adapter at the beginning of driver initialization. 768c2ecf20Sopenharmony_ci * A future driver enhancement in this area may occur in 2.1.X where 778c2ecf20Sopenharmony_ci * Alan indicated that a shutdown handler may be implemented. 788c2ecf20Sopenharmony_ci * 798c2ecf20Sopenharmony_ci * Interrupt Service Routine - 808c2ecf20Sopenharmony_ci * The driver supports shared interrupts, so the ISR is registered for 818c2ecf20Sopenharmony_ci * each board with the appropriate flag and the pointer to that board's 828c2ecf20Sopenharmony_ci * device structure. This provides the context during interrupt 838c2ecf20Sopenharmony_ci * processing to support shared interrupts and multiple boards. 848c2ecf20Sopenharmony_ci * 858c2ecf20Sopenharmony_ci * Interrupt enabling/disabling can occur at many levels. At the host 868c2ecf20Sopenharmony_ci * end, you can disable system interrupts, or disable interrupts at the 878c2ecf20Sopenharmony_ci * PIC (on Intel systems). Across the bus, both EISA and PCI adapters 888c2ecf20Sopenharmony_ci * have a bus-logic chip interrupt enable/disable as well as a DMA 898c2ecf20Sopenharmony_ci * controller interrupt enable/disable. 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * The driver currently enables and disables adapter interrupts at the 928c2ecf20Sopenharmony_ci * bus-logic chip and assumes that Linux will take care of clearing or 938c2ecf20Sopenharmony_ci * acknowledging any host-based interrupt chips. 948c2ecf20Sopenharmony_ci * 958c2ecf20Sopenharmony_ci * Control Functions - 968c2ecf20Sopenharmony_ci * Control functions are those used to support functions such as adding 978c2ecf20Sopenharmony_ci * or deleting multicast addresses, enabling or disabling packet 988c2ecf20Sopenharmony_ci * reception filters, or other custom/proprietary commands. Presently, 998c2ecf20Sopenharmony_ci * the driver supports the "get statistics", "set multicast list", and 1008c2ecf20Sopenharmony_ci * "set mac address" functions defined by Linux. A list of possible 1018c2ecf20Sopenharmony_ci * enhancements include: 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * - Custom ioctl interface for executing port interface commands 1048c2ecf20Sopenharmony_ci * - Custom ioctl interface for adding unicast addresses to 1058c2ecf20Sopenharmony_ci * adapter CAM (to support bridge functions). 1068c2ecf20Sopenharmony_ci * - Custom ioctl interface for supporting firmware upgrades. 1078c2ecf20Sopenharmony_ci * 1088c2ecf20Sopenharmony_ci * Hardware (port interface) Support Routines - 1098c2ecf20Sopenharmony_ci * The driver function names that start with "dfx_hw_" represent 1108c2ecf20Sopenharmony_ci * low-level port interface routines that are called frequently. They 1118c2ecf20Sopenharmony_ci * include issuing a DMA or port control command to the adapter, 1128c2ecf20Sopenharmony_ci * resetting the adapter, or reading the adapter state. Since the 1138c2ecf20Sopenharmony_ci * driver initialization and run-time code must make calls into the 1148c2ecf20Sopenharmony_ci * port interface, these routines were written to be as generic and 1158c2ecf20Sopenharmony_ci * usable as possible. 1168c2ecf20Sopenharmony_ci * 1178c2ecf20Sopenharmony_ci * Receive Path - 1188c2ecf20Sopenharmony_ci * The adapter DMA engine supports a 256 entry receive descriptor block 1198c2ecf20Sopenharmony_ci * of which up to 255 entries can be used at any given time. The 1208c2ecf20Sopenharmony_ci * architecture is a standard producer, consumer, completion model in 1218c2ecf20Sopenharmony_ci * which the driver "produces" receive buffers to the adapter, the 1228c2ecf20Sopenharmony_ci * adapter "consumes" the receive buffers by DMAing incoming packet data, 1238c2ecf20Sopenharmony_ci * and the driver "completes" the receive buffers by servicing the 1248c2ecf20Sopenharmony_ci * incoming packet, then "produces" a new buffer and starts the cycle 1258c2ecf20Sopenharmony_ci * again. Receive buffers can be fragmented in up to 16 fragments 1268c2ecf20Sopenharmony_ci * (descriptor entries). For simplicity, this driver posts 1278c2ecf20Sopenharmony_ci * single-fragment receive buffers of 4608 bytes, then allocates a 1288c2ecf20Sopenharmony_ci * sk_buff, copies the data, then reposts the buffer. To reduce CPU 1298c2ecf20Sopenharmony_ci * utilization, a better approach would be to pass up the receive 1308c2ecf20Sopenharmony_ci * buffer (no extra copy) then allocate and post a replacement buffer. 1318c2ecf20Sopenharmony_ci * This is a performance enhancement that should be looked into at 1328c2ecf20Sopenharmony_ci * some point. 1338c2ecf20Sopenharmony_ci * 1348c2ecf20Sopenharmony_ci * Transmit Path - 1358c2ecf20Sopenharmony_ci * Like the receive path, the adapter DMA engine supports a 256 entry 1368c2ecf20Sopenharmony_ci * transmit descriptor block of which up to 255 entries can be used at 1378c2ecf20Sopenharmony_ci * any given time. Transmit buffers can be fragmented in up to 255 1388c2ecf20Sopenharmony_ci * fragments (descriptor entries). This driver always posts one 1398c2ecf20Sopenharmony_ci * fragment per transmit packet request. 1408c2ecf20Sopenharmony_ci * 1418c2ecf20Sopenharmony_ci * The fragment contains the entire packet from FC to end of data. 1428c2ecf20Sopenharmony_ci * Before posting the buffer to the adapter, the driver sets a three-byte 1438c2ecf20Sopenharmony_ci * packet request header (PRH) which is required by the Motorola MAC chip 1448c2ecf20Sopenharmony_ci * used on the adapters. The PRH tells the MAC the type of token to 1458c2ecf20Sopenharmony_ci * receive/send, whether or not to generate and append the CRC, whether 1468c2ecf20Sopenharmony_ci * synchronous or asynchronous framing is used, etc. Since the PRH 1478c2ecf20Sopenharmony_ci * definition is not necessarily consistent across all FDDI chipsets, 1488c2ecf20Sopenharmony_ci * the driver, rather than the common FDDI packet handler routines, 1498c2ecf20Sopenharmony_ci * sets these bytes. 1508c2ecf20Sopenharmony_ci * 1518c2ecf20Sopenharmony_ci * To reduce the amount of descriptor fetches needed per transmit request, 1528c2ecf20Sopenharmony_ci * the driver takes advantage of the fact that there are at least three 1538c2ecf20Sopenharmony_ci * bytes available before the skb->data field on the outgoing transmit 1548c2ecf20Sopenharmony_ci * request. This is guaranteed by having fddi_setup() in net_init.c set 1558c2ecf20Sopenharmony_ci * dev->hard_header_len to 24 bytes. 21 bytes accounts for the largest 1568c2ecf20Sopenharmony_ci * header in an 802.2 SNAP frame. The other 3 bytes are the extra "pad" 1578c2ecf20Sopenharmony_ci * bytes which we'll use to store the PRH. 1588c2ecf20Sopenharmony_ci * 1598c2ecf20Sopenharmony_ci * There's a subtle advantage to adding these pad bytes to the 1608c2ecf20Sopenharmony_ci * hard_header_len, it ensures that the data portion of the packet for 1618c2ecf20Sopenharmony_ci * an 802.2 SNAP frame is longword aligned. Other FDDI driver 1628c2ecf20Sopenharmony_ci * implementations may not need the extra padding and can start copying 1638c2ecf20Sopenharmony_ci * or DMAing directly from the FC byte which starts at skb->data. Should 1648c2ecf20Sopenharmony_ci * another driver implementation need ADDITIONAL padding, the net_init.c 1658c2ecf20Sopenharmony_ci * module should be updated and dev->hard_header_len should be increased. 1668c2ecf20Sopenharmony_ci * NOTE: To maintain the alignment on the data portion of the packet, 1678c2ecf20Sopenharmony_ci * dev->hard_header_len should always be evenly divisible by 4 and at 1688c2ecf20Sopenharmony_ci * least 24 bytes in size. 1698c2ecf20Sopenharmony_ci * 1708c2ecf20Sopenharmony_ci * Modification History: 1718c2ecf20Sopenharmony_ci * Date Name Description 1728c2ecf20Sopenharmony_ci * 16-Aug-96 LVS Created. 1738c2ecf20Sopenharmony_ci * 20-Aug-96 LVS Updated dfx_probe so that version information 1748c2ecf20Sopenharmony_ci * string is only displayed if 1 or more cards are 1758c2ecf20Sopenharmony_ci * found. Changed dfx_rcv_queue_process to copy 1768c2ecf20Sopenharmony_ci * 3 NULL bytes before FC to ensure that data is 1778c2ecf20Sopenharmony_ci * longword aligned in receive buffer. 1788c2ecf20Sopenharmony_ci * 09-Sep-96 LVS Updated dfx_ctl_set_multicast_list to enable 1798c2ecf20Sopenharmony_ci * LLC group promiscuous mode if multicast list 1808c2ecf20Sopenharmony_ci * is too large. LLC individual/group promiscuous 1818c2ecf20Sopenharmony_ci * mode is now disabled if IFF_PROMISC flag not set. 1828c2ecf20Sopenharmony_ci * dfx_xmt_queue_pkt no longer checks for NULL skb 1838c2ecf20Sopenharmony_ci * on Alan Cox recommendation. Added node address 1848c2ecf20Sopenharmony_ci * override support. 1858c2ecf20Sopenharmony_ci * 12-Sep-96 LVS Reset current address to factory address during 1868c2ecf20Sopenharmony_ci * device open. Updated transmit path to post a 1878c2ecf20Sopenharmony_ci * single fragment which includes PRH->end of data. 1888c2ecf20Sopenharmony_ci * Mar 2000 AC Did various cleanups for 2.3.x 1898c2ecf20Sopenharmony_ci * Jun 2000 jgarzik PCI and resource alloc cleanups 1908c2ecf20Sopenharmony_ci * Jul 2000 tjeerd Much cleanup and some bug fixes 1918c2ecf20Sopenharmony_ci * Sep 2000 tjeerd Fix leak on unload, cosmetic code cleanup 1928c2ecf20Sopenharmony_ci * Feb 2001 Skb allocation fixes 1938c2ecf20Sopenharmony_ci * Feb 2001 davej PCI enable cleanups. 1948c2ecf20Sopenharmony_ci * 04 Aug 2003 macro Converted to the DMA API. 1958c2ecf20Sopenharmony_ci * 14 Aug 2004 macro Fix device names reported. 1968c2ecf20Sopenharmony_ci * 14 Jun 2005 macro Use irqreturn_t. 1978c2ecf20Sopenharmony_ci * 23 Oct 2006 macro Big-endian host support. 1988c2ecf20Sopenharmony_ci * 14 Dec 2006 macro TURBOchannel support. 1998c2ecf20Sopenharmony_ci * 01 Jul 2014 macro Fixes for DMA on 64-bit hosts. 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/* Include files */ 2038c2ecf20Sopenharmony_ci#include <linux/bitops.h> 2048c2ecf20Sopenharmony_ci#include <linux/compiler.h> 2058c2ecf20Sopenharmony_ci#include <linux/delay.h> 2068c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 2078c2ecf20Sopenharmony_ci#include <linux/eisa.h> 2088c2ecf20Sopenharmony_ci#include <linux/errno.h> 2098c2ecf20Sopenharmony_ci#include <linux/fddidevice.h> 2108c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 2118c2ecf20Sopenharmony_ci#include <linux/ioport.h> 2128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 2138c2ecf20Sopenharmony_ci#include <linux/module.h> 2148c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 2158c2ecf20Sopenharmony_ci#include <linux/pci.h> 2168c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 2178c2ecf20Sopenharmony_ci#include <linux/slab.h> 2188c2ecf20Sopenharmony_ci#include <linux/string.h> 2198c2ecf20Sopenharmony_ci#include <linux/tc.h> 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 2228c2ecf20Sopenharmony_ci#include <asm/io.h> 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci#include "defxx.h" 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci/* Version information string should be updated prior to each new release! */ 2278c2ecf20Sopenharmony_ci#define DRV_NAME "defxx" 2288c2ecf20Sopenharmony_ci#define DRV_VERSION "v1.11" 2298c2ecf20Sopenharmony_ci#define DRV_RELDATE "2014/07/01" 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic const char version[] = 2328c2ecf20Sopenharmony_ci DRV_NAME ": " DRV_VERSION " " DRV_RELDATE 2338c2ecf20Sopenharmony_ci " Lawrence V. Stefani and others\n"; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci#define DYNAMIC_BUFFERS 1 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci#define SKBUFF_RX_COPYBREAK 200 2388c2ecf20Sopenharmony_ci/* 2398c2ecf20Sopenharmony_ci * NEW_SKB_SIZE = PI_RCV_DATA_K_SIZE_MAX+128 to allow 128 byte 2408c2ecf20Sopenharmony_ci * alignment for compatibility with old EISA boards. 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_ci#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128) 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci#ifdef CONFIG_EISA 2458c2ecf20Sopenharmony_ci#define DFX_BUS_EISA(dev) (dev->bus == &eisa_bus_type) 2468c2ecf20Sopenharmony_ci#else 2478c2ecf20Sopenharmony_ci#define DFX_BUS_EISA(dev) 0 2488c2ecf20Sopenharmony_ci#endif 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci#ifdef CONFIG_TC 2518c2ecf20Sopenharmony_ci#define DFX_BUS_TC(dev) (dev->bus == &tc_bus_type) 2528c2ecf20Sopenharmony_ci#else 2538c2ecf20Sopenharmony_ci#define DFX_BUS_TC(dev) 0 2548c2ecf20Sopenharmony_ci#endif 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci#ifdef CONFIG_DEFXX_MMIO 2578c2ecf20Sopenharmony_ci#define DFX_MMIO 1 2588c2ecf20Sopenharmony_ci#else 2598c2ecf20Sopenharmony_ci#define DFX_MMIO 0 2608c2ecf20Sopenharmony_ci#endif 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci/* Define module-wide (static) routines */ 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic void dfx_bus_init(struct net_device *dev); 2658c2ecf20Sopenharmony_cistatic void dfx_bus_uninit(struct net_device *dev); 2668c2ecf20Sopenharmony_cistatic void dfx_bus_config_check(DFX_board_t *bp); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic int dfx_driver_init(struct net_device *dev, 2698c2ecf20Sopenharmony_ci const char *print_name, 2708c2ecf20Sopenharmony_ci resource_size_t bar_start); 2718c2ecf20Sopenharmony_cistatic int dfx_adap_init(DFX_board_t *bp, int get_buffers); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic int dfx_open(struct net_device *dev); 2748c2ecf20Sopenharmony_cistatic int dfx_close(struct net_device *dev); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic void dfx_int_pr_halt_id(DFX_board_t *bp); 2778c2ecf20Sopenharmony_cistatic void dfx_int_type_0_process(DFX_board_t *bp); 2788c2ecf20Sopenharmony_cistatic void dfx_int_common(struct net_device *dev); 2798c2ecf20Sopenharmony_cistatic irqreturn_t dfx_interrupt(int irq, void *dev_id); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev); 2828c2ecf20Sopenharmony_cistatic void dfx_ctl_set_multicast_list(struct net_device *dev); 2838c2ecf20Sopenharmony_cistatic int dfx_ctl_set_mac_address(struct net_device *dev, void *addr); 2848c2ecf20Sopenharmony_cistatic int dfx_ctl_update_cam(DFX_board_t *bp); 2858c2ecf20Sopenharmony_cistatic int dfx_ctl_update_filters(DFX_board_t *bp); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic int dfx_hw_dma_cmd_req(DFX_board_t *bp); 2888c2ecf20Sopenharmony_cistatic 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); 2898c2ecf20Sopenharmony_cistatic void dfx_hw_adap_reset(DFX_board_t *bp, PI_UINT32 type); 2908c2ecf20Sopenharmony_cistatic int dfx_hw_adap_state_rd(DFX_board_t *bp); 2918c2ecf20Sopenharmony_cistatic int dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic int dfx_rcv_init(DFX_board_t *bp, int get_buffers); 2948c2ecf20Sopenharmony_cistatic void dfx_rcv_queue_process(DFX_board_t *bp); 2958c2ecf20Sopenharmony_ci#ifdef DYNAMIC_BUFFERS 2968c2ecf20Sopenharmony_cistatic void dfx_rcv_flush(DFX_board_t *bp); 2978c2ecf20Sopenharmony_ci#else 2988c2ecf20Sopenharmony_cistatic inline void dfx_rcv_flush(DFX_board_t *bp) {} 2998c2ecf20Sopenharmony_ci#endif 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, 3028c2ecf20Sopenharmony_ci struct net_device *dev); 3038c2ecf20Sopenharmony_cistatic int dfx_xmt_done(DFX_board_t *bp); 3048c2ecf20Sopenharmony_cistatic void dfx_xmt_flush(DFX_board_t *bp); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci/* Define module-wide (static) variables */ 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic struct pci_driver dfx_pci_driver; 3098c2ecf20Sopenharmony_cistatic struct eisa_driver dfx_eisa_driver; 3108c2ecf20Sopenharmony_cistatic struct tc_driver dfx_tc_driver; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci/* 3148c2ecf20Sopenharmony_ci * ======================= 3158c2ecf20Sopenharmony_ci * = dfx_port_write_long = 3168c2ecf20Sopenharmony_ci * = dfx_port_read_long = 3178c2ecf20Sopenharmony_ci * ======================= 3188c2ecf20Sopenharmony_ci * 3198c2ecf20Sopenharmony_ci * Overview: 3208c2ecf20Sopenharmony_ci * Routines for reading and writing values from/to adapter 3218c2ecf20Sopenharmony_ci * 3228c2ecf20Sopenharmony_ci * Returns: 3238c2ecf20Sopenharmony_ci * None 3248c2ecf20Sopenharmony_ci * 3258c2ecf20Sopenharmony_ci * Arguments: 3268c2ecf20Sopenharmony_ci * bp - pointer to board information 3278c2ecf20Sopenharmony_ci * offset - register offset from base I/O address 3288c2ecf20Sopenharmony_ci * data - for dfx_port_write_long, this is a value to write; 3298c2ecf20Sopenharmony_ci * for dfx_port_read_long, this is a pointer to store 3308c2ecf20Sopenharmony_ci * the read value 3318c2ecf20Sopenharmony_ci * 3328c2ecf20Sopenharmony_ci * Functional Description: 3338c2ecf20Sopenharmony_ci * These routines perform the correct operation to read or write 3348c2ecf20Sopenharmony_ci * the adapter register. 3358c2ecf20Sopenharmony_ci * 3368c2ecf20Sopenharmony_ci * EISA port block base addresses are based on the slot number in which the 3378c2ecf20Sopenharmony_ci * controller is installed. For example, if the EISA controller is installed 3388c2ecf20Sopenharmony_ci * in slot 4, the port block base address is 0x4000. If the controller is 3398c2ecf20Sopenharmony_ci * installed in slot 2, the port block base address is 0x2000, and so on. 3408c2ecf20Sopenharmony_ci * This port block can be used to access PDQ, ESIC, and DEFEA on-board 3418c2ecf20Sopenharmony_ci * registers using the register offsets defined in DEFXX.H. 3428c2ecf20Sopenharmony_ci * 3438c2ecf20Sopenharmony_ci * PCI port block base addresses are assigned by the PCI BIOS or system 3448c2ecf20Sopenharmony_ci * firmware. There is one 128 byte port block which can be accessed. It 3458c2ecf20Sopenharmony_ci * allows for I/O mapping of both PDQ and PFI registers using the register 3468c2ecf20Sopenharmony_ci * offsets defined in DEFXX.H. 3478c2ecf20Sopenharmony_ci * 3488c2ecf20Sopenharmony_ci * Return Codes: 3498c2ecf20Sopenharmony_ci * None 3508c2ecf20Sopenharmony_ci * 3518c2ecf20Sopenharmony_ci * Assumptions: 3528c2ecf20Sopenharmony_ci * bp->base is a valid base I/O address for this adapter. 3538c2ecf20Sopenharmony_ci * offset is a valid register offset for this adapter. 3548c2ecf20Sopenharmony_ci * 3558c2ecf20Sopenharmony_ci * Side Effects: 3568c2ecf20Sopenharmony_ci * Rather than produce macros for these functions, these routines 3578c2ecf20Sopenharmony_ci * are defined using "inline" to ensure that the compiler will 3588c2ecf20Sopenharmony_ci * generate inline code and not waste a procedure call and return. 3598c2ecf20Sopenharmony_ci * This provides all the benefits of macros, but with the 3608c2ecf20Sopenharmony_ci * advantage of strict data type checking. 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic inline void dfx_writel(DFX_board_t *bp, int offset, u32 data) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci writel(data, bp->base.mem + offset); 3668c2ecf20Sopenharmony_ci mb(); 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic inline void dfx_outl(DFX_board_t *bp, int offset, u32 data) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci outl(data, bp->base.port + offset); 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic void dfx_port_write_long(DFX_board_t *bp, int offset, u32 data) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci struct device __maybe_unused *bdev = bp->bus_dev; 3778c2ecf20Sopenharmony_ci int dfx_bus_tc = DFX_BUS_TC(bdev); 3788c2ecf20Sopenharmony_ci int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (dfx_use_mmio) 3818c2ecf20Sopenharmony_ci dfx_writel(bp, offset, data); 3828c2ecf20Sopenharmony_ci else 3838c2ecf20Sopenharmony_ci dfx_outl(bp, offset, data); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic inline void dfx_readl(DFX_board_t *bp, int offset, u32 *data) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci mb(); 3908c2ecf20Sopenharmony_ci *data = readl(bp->base.mem + offset); 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic inline void dfx_inl(DFX_board_t *bp, int offset, u32 *data) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci *data = inl(bp->base.port + offset); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic void dfx_port_read_long(DFX_board_t *bp, int offset, u32 *data) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct device __maybe_unused *bdev = bp->bus_dev; 4018c2ecf20Sopenharmony_ci int dfx_bus_tc = DFX_BUS_TC(bdev); 4028c2ecf20Sopenharmony_ci int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (dfx_use_mmio) 4058c2ecf20Sopenharmony_ci dfx_readl(bp, offset, data); 4068c2ecf20Sopenharmony_ci else 4078c2ecf20Sopenharmony_ci dfx_inl(bp, offset, data); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci/* 4128c2ecf20Sopenharmony_ci * ================ 4138c2ecf20Sopenharmony_ci * = dfx_get_bars = 4148c2ecf20Sopenharmony_ci * ================ 4158c2ecf20Sopenharmony_ci * 4168c2ecf20Sopenharmony_ci * Overview: 4178c2ecf20Sopenharmony_ci * Retrieves the address ranges used to access control and status 4188c2ecf20Sopenharmony_ci * registers. 4198c2ecf20Sopenharmony_ci * 4208c2ecf20Sopenharmony_ci * Returns: 4218c2ecf20Sopenharmony_ci * None 4228c2ecf20Sopenharmony_ci * 4238c2ecf20Sopenharmony_ci * Arguments: 4248c2ecf20Sopenharmony_ci * bdev - pointer to device information 4258c2ecf20Sopenharmony_ci * bar_start - pointer to store the start addresses 4268c2ecf20Sopenharmony_ci * bar_len - pointer to store the lengths of the areas 4278c2ecf20Sopenharmony_ci * 4288c2ecf20Sopenharmony_ci * Assumptions: 4298c2ecf20Sopenharmony_ci * I am sure there are some. 4308c2ecf20Sopenharmony_ci * 4318c2ecf20Sopenharmony_ci * Side Effects: 4328c2ecf20Sopenharmony_ci * None 4338c2ecf20Sopenharmony_ci */ 4348c2ecf20Sopenharmony_cistatic void dfx_get_bars(struct device *bdev, 4358c2ecf20Sopenharmony_ci resource_size_t *bar_start, resource_size_t *bar_len) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci int dfx_bus_pci = dev_is_pci(bdev); 4388c2ecf20Sopenharmony_ci int dfx_bus_eisa = DFX_BUS_EISA(bdev); 4398c2ecf20Sopenharmony_ci int dfx_bus_tc = DFX_BUS_TC(bdev); 4408c2ecf20Sopenharmony_ci int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci if (dfx_bus_pci) { 4438c2ecf20Sopenharmony_ci int num = dfx_use_mmio ? 0 : 1; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci bar_start[0] = pci_resource_start(to_pci_dev(bdev), num); 4468c2ecf20Sopenharmony_ci bar_len[0] = pci_resource_len(to_pci_dev(bdev), num); 4478c2ecf20Sopenharmony_ci bar_start[2] = bar_start[1] = 0; 4488c2ecf20Sopenharmony_ci bar_len[2] = bar_len[1] = 0; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci if (dfx_bus_eisa) { 4518c2ecf20Sopenharmony_ci unsigned long base_addr = to_eisa_device(bdev)->base_addr; 4528c2ecf20Sopenharmony_ci resource_size_t bar_lo; 4538c2ecf20Sopenharmony_ci resource_size_t bar_hi; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (dfx_use_mmio) { 4568c2ecf20Sopenharmony_ci bar_lo = inb(base_addr + PI_ESIC_K_MEM_ADD_LO_CMP_2); 4578c2ecf20Sopenharmony_ci bar_lo <<= 8; 4588c2ecf20Sopenharmony_ci bar_lo |= inb(base_addr + PI_ESIC_K_MEM_ADD_LO_CMP_1); 4598c2ecf20Sopenharmony_ci bar_lo <<= 8; 4608c2ecf20Sopenharmony_ci bar_lo |= inb(base_addr + PI_ESIC_K_MEM_ADD_LO_CMP_0); 4618c2ecf20Sopenharmony_ci bar_lo <<= 8; 4628c2ecf20Sopenharmony_ci bar_start[0] = bar_lo; 4638c2ecf20Sopenharmony_ci bar_hi = inb(base_addr + PI_ESIC_K_MEM_ADD_HI_CMP_2); 4648c2ecf20Sopenharmony_ci bar_hi <<= 8; 4658c2ecf20Sopenharmony_ci bar_hi |= inb(base_addr + PI_ESIC_K_MEM_ADD_HI_CMP_1); 4668c2ecf20Sopenharmony_ci bar_hi <<= 8; 4678c2ecf20Sopenharmony_ci bar_hi |= inb(base_addr + PI_ESIC_K_MEM_ADD_HI_CMP_0); 4688c2ecf20Sopenharmony_ci bar_hi <<= 8; 4698c2ecf20Sopenharmony_ci bar_len[0] = ((bar_hi - bar_lo) | PI_MEM_ADD_MASK_M) + 4708c2ecf20Sopenharmony_ci 1; 4718c2ecf20Sopenharmony_ci } else { 4728c2ecf20Sopenharmony_ci bar_start[0] = base_addr; 4738c2ecf20Sopenharmony_ci bar_len[0] = PI_ESIC_K_CSR_IO_LEN; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci bar_start[1] = base_addr + PI_DEFEA_K_BURST_HOLDOFF; 4768c2ecf20Sopenharmony_ci bar_len[1] = PI_ESIC_K_BURST_HOLDOFF_LEN; 4778c2ecf20Sopenharmony_ci bar_start[2] = base_addr + PI_ESIC_K_ESIC_CSR; 4788c2ecf20Sopenharmony_ci bar_len[2] = PI_ESIC_K_ESIC_CSR_LEN; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci if (dfx_bus_tc) { 4818c2ecf20Sopenharmony_ci bar_start[0] = to_tc_dev(bdev)->resource.start + 4828c2ecf20Sopenharmony_ci PI_TC_K_CSR_OFFSET; 4838c2ecf20Sopenharmony_ci bar_len[0] = PI_TC_K_CSR_LEN; 4848c2ecf20Sopenharmony_ci bar_start[2] = bar_start[1] = 0; 4858c2ecf20Sopenharmony_ci bar_len[2] = bar_len[1] = 0; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic const struct net_device_ops dfx_netdev_ops = { 4908c2ecf20Sopenharmony_ci .ndo_open = dfx_open, 4918c2ecf20Sopenharmony_ci .ndo_stop = dfx_close, 4928c2ecf20Sopenharmony_ci .ndo_start_xmit = dfx_xmt_queue_pkt, 4938c2ecf20Sopenharmony_ci .ndo_get_stats = dfx_ctl_get_stats, 4948c2ecf20Sopenharmony_ci .ndo_set_rx_mode = dfx_ctl_set_multicast_list, 4958c2ecf20Sopenharmony_ci .ndo_set_mac_address = dfx_ctl_set_mac_address, 4968c2ecf20Sopenharmony_ci}; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic void dfx_register_res_alloc_err(const char *print_name, bool mmio, 4998c2ecf20Sopenharmony_ci bool eisa) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci pr_err("%s: Cannot use %s, no address set, aborting\n", 5028c2ecf20Sopenharmony_ci print_name, mmio ? "MMIO" : "I/O"); 5038c2ecf20Sopenharmony_ci pr_err("%s: Recompile driver with \"CONFIG_DEFXX_MMIO=%c\"\n", 5048c2ecf20Sopenharmony_ci print_name, mmio ? 'n' : 'y'); 5058c2ecf20Sopenharmony_ci if (eisa && mmio) 5068c2ecf20Sopenharmony_ci pr_err("%s: Or run ECU and set adapter's MMIO location\n", 5078c2ecf20Sopenharmony_ci print_name); 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic void dfx_register_res_err(const char *print_name, bool mmio, 5118c2ecf20Sopenharmony_ci unsigned long start, unsigned long len) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci pr_err("%s: Cannot reserve %s resource 0x%lx @ 0x%lx, aborting\n", 5148c2ecf20Sopenharmony_ci print_name, mmio ? "MMIO" : "I/O", len, start); 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci/* 5188c2ecf20Sopenharmony_ci * ================ 5198c2ecf20Sopenharmony_ci * = dfx_register = 5208c2ecf20Sopenharmony_ci * ================ 5218c2ecf20Sopenharmony_ci * 5228c2ecf20Sopenharmony_ci * Overview: 5238c2ecf20Sopenharmony_ci * Initializes a supported FDDI controller 5248c2ecf20Sopenharmony_ci * 5258c2ecf20Sopenharmony_ci * Returns: 5268c2ecf20Sopenharmony_ci * Condition code 5278c2ecf20Sopenharmony_ci * 5288c2ecf20Sopenharmony_ci * Arguments: 5298c2ecf20Sopenharmony_ci * bdev - pointer to device information 5308c2ecf20Sopenharmony_ci * 5318c2ecf20Sopenharmony_ci * Functional Description: 5328c2ecf20Sopenharmony_ci * 5338c2ecf20Sopenharmony_ci * Return Codes: 5348c2ecf20Sopenharmony_ci * 0 - This device (fddi0, fddi1, etc) configured successfully 5358c2ecf20Sopenharmony_ci * -EBUSY - Failed to get resources, or dfx_driver_init failed. 5368c2ecf20Sopenharmony_ci * 5378c2ecf20Sopenharmony_ci * Assumptions: 5388c2ecf20Sopenharmony_ci * It compiles so it should work :-( (PCI cards do :-) 5398c2ecf20Sopenharmony_ci * 5408c2ecf20Sopenharmony_ci * Side Effects: 5418c2ecf20Sopenharmony_ci * Device structures for FDDI adapters (fddi0, fddi1, etc) are 5428c2ecf20Sopenharmony_ci * initialized and the board resources are read and stored in 5438c2ecf20Sopenharmony_ci * the device structure. 5448c2ecf20Sopenharmony_ci */ 5458c2ecf20Sopenharmony_cistatic int dfx_register(struct device *bdev) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci static int version_disp; 5488c2ecf20Sopenharmony_ci int dfx_bus_pci = dev_is_pci(bdev); 5498c2ecf20Sopenharmony_ci int dfx_bus_eisa = DFX_BUS_EISA(bdev); 5508c2ecf20Sopenharmony_ci int dfx_bus_tc = DFX_BUS_TC(bdev); 5518c2ecf20Sopenharmony_ci int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; 5528c2ecf20Sopenharmony_ci const char *print_name = dev_name(bdev); 5538c2ecf20Sopenharmony_ci struct net_device *dev; 5548c2ecf20Sopenharmony_ci DFX_board_t *bp; /* board pointer */ 5558c2ecf20Sopenharmony_ci resource_size_t bar_start[3] = {0}; /* pointers to ports */ 5568c2ecf20Sopenharmony_ci resource_size_t bar_len[3] = {0}; /* resource length */ 5578c2ecf20Sopenharmony_ci int alloc_size; /* total buffer size used */ 5588c2ecf20Sopenharmony_ci struct resource *region; 5598c2ecf20Sopenharmony_ci int err = 0; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (!version_disp) { /* display version info if adapter is found */ 5628c2ecf20Sopenharmony_ci version_disp = 1; /* set display flag to TRUE so that */ 5638c2ecf20Sopenharmony_ci printk(version); /* we only display this string ONCE */ 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci dev = alloc_fddidev(sizeof(*bp)); 5678c2ecf20Sopenharmony_ci if (!dev) { 5688c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Unable to allocate fddidev, aborting\n", 5698c2ecf20Sopenharmony_ci print_name); 5708c2ecf20Sopenharmony_ci return -ENOMEM; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* Enable PCI device. */ 5748c2ecf20Sopenharmony_ci if (dfx_bus_pci) { 5758c2ecf20Sopenharmony_ci err = pci_enable_device(to_pci_dev(bdev)); 5768c2ecf20Sopenharmony_ci if (err) { 5778c2ecf20Sopenharmony_ci pr_err("%s: Cannot enable PCI device, aborting\n", 5788c2ecf20Sopenharmony_ci print_name); 5798c2ecf20Sopenharmony_ci goto err_out; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, bdev); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci bp = netdev_priv(dev); 5868c2ecf20Sopenharmony_ci bp->bus_dev = bdev; 5878c2ecf20Sopenharmony_ci dev_set_drvdata(bdev, dev); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci dfx_get_bars(bdev, bar_start, bar_len); 5908c2ecf20Sopenharmony_ci if (bar_len[0] == 0 || 5918c2ecf20Sopenharmony_ci (dfx_bus_eisa && dfx_use_mmio && bar_start[0] == 0)) { 5928c2ecf20Sopenharmony_ci dfx_register_res_alloc_err(print_name, dfx_use_mmio, 5938c2ecf20Sopenharmony_ci dfx_bus_eisa); 5948c2ecf20Sopenharmony_ci err = -ENXIO; 5958c2ecf20Sopenharmony_ci goto err_out_disable; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (dfx_use_mmio) 5998c2ecf20Sopenharmony_ci region = request_mem_region(bar_start[0], bar_len[0], 6008c2ecf20Sopenharmony_ci print_name); 6018c2ecf20Sopenharmony_ci else 6028c2ecf20Sopenharmony_ci region = request_region(bar_start[0], bar_len[0], print_name); 6038c2ecf20Sopenharmony_ci if (!region) { 6048c2ecf20Sopenharmony_ci dfx_register_res_err(print_name, dfx_use_mmio, 6058c2ecf20Sopenharmony_ci bar_start[0], bar_len[0]); 6068c2ecf20Sopenharmony_ci err = -EBUSY; 6078c2ecf20Sopenharmony_ci goto err_out_disable; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci if (bar_start[1] != 0) { 6108c2ecf20Sopenharmony_ci region = request_region(bar_start[1], bar_len[1], print_name); 6118c2ecf20Sopenharmony_ci if (!region) { 6128c2ecf20Sopenharmony_ci dfx_register_res_err(print_name, 0, 6138c2ecf20Sopenharmony_ci bar_start[1], bar_len[1]); 6148c2ecf20Sopenharmony_ci err = -EBUSY; 6158c2ecf20Sopenharmony_ci goto err_out_csr_region; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci if (bar_start[2] != 0) { 6198c2ecf20Sopenharmony_ci region = request_region(bar_start[2], bar_len[2], print_name); 6208c2ecf20Sopenharmony_ci if (!region) { 6218c2ecf20Sopenharmony_ci dfx_register_res_err(print_name, 0, 6228c2ecf20Sopenharmony_ci bar_start[2], bar_len[2]); 6238c2ecf20Sopenharmony_ci err = -EBUSY; 6248c2ecf20Sopenharmony_ci goto err_out_bh_region; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* Set up I/O base address. */ 6298c2ecf20Sopenharmony_ci if (dfx_use_mmio) { 6308c2ecf20Sopenharmony_ci bp->base.mem = ioremap(bar_start[0], bar_len[0]); 6318c2ecf20Sopenharmony_ci if (!bp->base.mem) { 6328c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Cannot map MMIO\n", print_name); 6338c2ecf20Sopenharmony_ci err = -ENOMEM; 6348c2ecf20Sopenharmony_ci goto err_out_esic_region; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci } else { 6378c2ecf20Sopenharmony_ci bp->base.port = bar_start[0]; 6388c2ecf20Sopenharmony_ci dev->base_addr = bar_start[0]; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci /* Initialize new device structure */ 6428c2ecf20Sopenharmony_ci dev->netdev_ops = &dfx_netdev_ops; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (dfx_bus_pci) 6458c2ecf20Sopenharmony_ci pci_set_master(to_pci_dev(bdev)); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci if (dfx_driver_init(dev, print_name, bar_start[0]) != DFX_K_SUCCESS) { 6488c2ecf20Sopenharmony_ci err = -ENODEV; 6498c2ecf20Sopenharmony_ci goto err_out_unmap; 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci err = register_netdev(dev); 6538c2ecf20Sopenharmony_ci if (err) 6548c2ecf20Sopenharmony_ci goto err_out_kfree; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci printk("%s: registered as %s\n", print_name, dev->name); 6578c2ecf20Sopenharmony_ci return 0; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cierr_out_kfree: 6608c2ecf20Sopenharmony_ci alloc_size = sizeof(PI_DESCR_BLOCK) + 6618c2ecf20Sopenharmony_ci PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX + 6628c2ecf20Sopenharmony_ci#ifndef DYNAMIC_BUFFERS 6638c2ecf20Sopenharmony_ci (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) + 6648c2ecf20Sopenharmony_ci#endif 6658c2ecf20Sopenharmony_ci sizeof(PI_CONSUMER_BLOCK) + 6668c2ecf20Sopenharmony_ci (PI_ALIGN_K_DESC_BLK - 1); 6678c2ecf20Sopenharmony_ci if (bp->kmalloced) 6688c2ecf20Sopenharmony_ci dma_free_coherent(bdev, alloc_size, 6698c2ecf20Sopenharmony_ci bp->kmalloced, bp->kmalloced_dma); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cierr_out_unmap: 6728c2ecf20Sopenharmony_ci if (dfx_use_mmio) 6738c2ecf20Sopenharmony_ci iounmap(bp->base.mem); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cierr_out_esic_region: 6768c2ecf20Sopenharmony_ci if (bar_start[2] != 0) 6778c2ecf20Sopenharmony_ci release_region(bar_start[2], bar_len[2]); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_cierr_out_bh_region: 6808c2ecf20Sopenharmony_ci if (bar_start[1] != 0) 6818c2ecf20Sopenharmony_ci release_region(bar_start[1], bar_len[1]); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cierr_out_csr_region: 6848c2ecf20Sopenharmony_ci if (dfx_use_mmio) 6858c2ecf20Sopenharmony_ci release_mem_region(bar_start[0], bar_len[0]); 6868c2ecf20Sopenharmony_ci else 6878c2ecf20Sopenharmony_ci release_region(bar_start[0], bar_len[0]); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cierr_out_disable: 6908c2ecf20Sopenharmony_ci if (dfx_bus_pci) 6918c2ecf20Sopenharmony_ci pci_disable_device(to_pci_dev(bdev)); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_cierr_out: 6948c2ecf20Sopenharmony_ci free_netdev(dev); 6958c2ecf20Sopenharmony_ci return err; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci/* 7008c2ecf20Sopenharmony_ci * ================ 7018c2ecf20Sopenharmony_ci * = dfx_bus_init = 7028c2ecf20Sopenharmony_ci * ================ 7038c2ecf20Sopenharmony_ci * 7048c2ecf20Sopenharmony_ci * Overview: 7058c2ecf20Sopenharmony_ci * Initializes the bus-specific controller logic. 7068c2ecf20Sopenharmony_ci * 7078c2ecf20Sopenharmony_ci * Returns: 7088c2ecf20Sopenharmony_ci * None 7098c2ecf20Sopenharmony_ci * 7108c2ecf20Sopenharmony_ci * Arguments: 7118c2ecf20Sopenharmony_ci * dev - pointer to device information 7128c2ecf20Sopenharmony_ci * 7138c2ecf20Sopenharmony_ci * Functional Description: 7148c2ecf20Sopenharmony_ci * Determine and save adapter IRQ in device table, 7158c2ecf20Sopenharmony_ci * then perform bus-specific logic initialization. 7168c2ecf20Sopenharmony_ci * 7178c2ecf20Sopenharmony_ci * Return Codes: 7188c2ecf20Sopenharmony_ci * None 7198c2ecf20Sopenharmony_ci * 7208c2ecf20Sopenharmony_ci * Assumptions: 7218c2ecf20Sopenharmony_ci * bp->base has already been set with the proper 7228c2ecf20Sopenharmony_ci * base I/O address for this device. 7238c2ecf20Sopenharmony_ci * 7248c2ecf20Sopenharmony_ci * Side Effects: 7258c2ecf20Sopenharmony_ci * Interrupts are enabled at the adapter bus-specific logic. 7268c2ecf20Sopenharmony_ci * Note: Interrupts at the DMA engine (PDQ chip) are not 7278c2ecf20Sopenharmony_ci * enabled yet. 7288c2ecf20Sopenharmony_ci */ 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic void dfx_bus_init(struct net_device *dev) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci DFX_board_t *bp = netdev_priv(dev); 7338c2ecf20Sopenharmony_ci struct device *bdev = bp->bus_dev; 7348c2ecf20Sopenharmony_ci int dfx_bus_pci = dev_is_pci(bdev); 7358c2ecf20Sopenharmony_ci int dfx_bus_eisa = DFX_BUS_EISA(bdev); 7368c2ecf20Sopenharmony_ci int dfx_bus_tc = DFX_BUS_TC(bdev); 7378c2ecf20Sopenharmony_ci int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; 7388c2ecf20Sopenharmony_ci u8 val; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci DBG_printk("In dfx_bus_init...\n"); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* Initialize a pointer back to the net_device struct */ 7438c2ecf20Sopenharmony_ci bp->dev = dev; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* Initialize adapter based on bus type */ 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci if (dfx_bus_tc) 7488c2ecf20Sopenharmony_ci dev->irq = to_tc_dev(bdev)->interrupt; 7498c2ecf20Sopenharmony_ci if (dfx_bus_eisa) { 7508c2ecf20Sopenharmony_ci unsigned long base_addr = to_eisa_device(bdev)->base_addr; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* Disable the board before fiddling with the decoders. */ 7538c2ecf20Sopenharmony_ci outb(0, base_addr + PI_ESIC_K_SLOT_CNTRL); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci /* Get the interrupt level from the ESIC chip. */ 7568c2ecf20Sopenharmony_ci val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); 7578c2ecf20Sopenharmony_ci val &= PI_CONFIG_STAT_0_M_IRQ; 7588c2ecf20Sopenharmony_ci val >>= PI_CONFIG_STAT_0_V_IRQ; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci switch (val) { 7618c2ecf20Sopenharmony_ci case PI_CONFIG_STAT_0_IRQ_K_9: 7628c2ecf20Sopenharmony_ci dev->irq = 9; 7638c2ecf20Sopenharmony_ci break; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci case PI_CONFIG_STAT_0_IRQ_K_10: 7668c2ecf20Sopenharmony_ci dev->irq = 10; 7678c2ecf20Sopenharmony_ci break; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci case PI_CONFIG_STAT_0_IRQ_K_11: 7708c2ecf20Sopenharmony_ci dev->irq = 11; 7718c2ecf20Sopenharmony_ci break; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci case PI_CONFIG_STAT_0_IRQ_K_15: 7748c2ecf20Sopenharmony_ci dev->irq = 15; 7758c2ecf20Sopenharmony_ci break; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci /* 7798c2ecf20Sopenharmony_ci * Enable memory decoding (MEMCS1) and/or port decoding 7808c2ecf20Sopenharmony_ci * (IOCS1/IOCS0) as appropriate in Function Control 7818c2ecf20Sopenharmony_ci * Register. MEMCS1 or IOCS0 is used for PDQ registers, 7828c2ecf20Sopenharmony_ci * taking 16 32-bit words, while IOCS1 is used for the 7838c2ecf20Sopenharmony_ci * Burst Holdoff register, taking a single 32-bit word 7848c2ecf20Sopenharmony_ci * only. We use the slot-specific I/O range as per the 7858c2ecf20Sopenharmony_ci * ESIC spec, that is set bits 15:12 in the mask registers 7868c2ecf20Sopenharmony_ci * to mask them out. 7878c2ecf20Sopenharmony_ci */ 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci /* Set the decode range of the board. */ 7908c2ecf20Sopenharmony_ci val = 0; 7918c2ecf20Sopenharmony_ci outb(val, base_addr + PI_ESIC_K_IO_ADD_CMP_0_1); 7928c2ecf20Sopenharmony_ci val = PI_DEFEA_K_CSR_IO; 7938c2ecf20Sopenharmony_ci outb(val, base_addr + PI_ESIC_K_IO_ADD_CMP_0_0); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci val = PI_IO_CMP_M_SLOT; 7968c2ecf20Sopenharmony_ci outb(val, base_addr + PI_ESIC_K_IO_ADD_MASK_0_1); 7978c2ecf20Sopenharmony_ci val = (PI_ESIC_K_CSR_IO_LEN - 1) & ~3; 7988c2ecf20Sopenharmony_ci outb(val, base_addr + PI_ESIC_K_IO_ADD_MASK_0_0); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci val = 0; 8018c2ecf20Sopenharmony_ci outb(val, base_addr + PI_ESIC_K_IO_ADD_CMP_1_1); 8028c2ecf20Sopenharmony_ci val = PI_DEFEA_K_BURST_HOLDOFF; 8038c2ecf20Sopenharmony_ci outb(val, base_addr + PI_ESIC_K_IO_ADD_CMP_1_0); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci val = PI_IO_CMP_M_SLOT; 8068c2ecf20Sopenharmony_ci outb(val, base_addr + PI_ESIC_K_IO_ADD_MASK_1_1); 8078c2ecf20Sopenharmony_ci val = (PI_ESIC_K_BURST_HOLDOFF_LEN - 1) & ~3; 8088c2ecf20Sopenharmony_ci outb(val, base_addr + PI_ESIC_K_IO_ADD_MASK_1_0); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci /* Enable the decoders. */ 8118c2ecf20Sopenharmony_ci val = PI_FUNCTION_CNTRL_M_IOCS1; 8128c2ecf20Sopenharmony_ci if (dfx_use_mmio) 8138c2ecf20Sopenharmony_ci val |= PI_FUNCTION_CNTRL_M_MEMCS1; 8148c2ecf20Sopenharmony_ci else 8158c2ecf20Sopenharmony_ci val |= PI_FUNCTION_CNTRL_M_IOCS0; 8168c2ecf20Sopenharmony_ci outb(val, base_addr + PI_ESIC_K_FUNCTION_CNTRL); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci /* 8198c2ecf20Sopenharmony_ci * Enable access to the rest of the module 8208c2ecf20Sopenharmony_ci * (including PDQ and packet memory). 8218c2ecf20Sopenharmony_ci */ 8228c2ecf20Sopenharmony_ci val = PI_SLOT_CNTRL_M_ENB; 8238c2ecf20Sopenharmony_ci outb(val, base_addr + PI_ESIC_K_SLOT_CNTRL); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci /* 8268c2ecf20Sopenharmony_ci * Map PDQ registers into memory or port space. This is 8278c2ecf20Sopenharmony_ci * done with a bit in the Burst Holdoff register. 8288c2ecf20Sopenharmony_ci */ 8298c2ecf20Sopenharmony_ci val = inb(base_addr + PI_DEFEA_K_BURST_HOLDOFF); 8308c2ecf20Sopenharmony_ci if (dfx_use_mmio) 8318c2ecf20Sopenharmony_ci val |= PI_BURST_HOLDOFF_M_MEM_MAP; 8328c2ecf20Sopenharmony_ci else 8338c2ecf20Sopenharmony_ci val &= ~PI_BURST_HOLDOFF_M_MEM_MAP; 8348c2ecf20Sopenharmony_ci outb(val, base_addr + PI_DEFEA_K_BURST_HOLDOFF); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci /* Enable interrupts at EISA bus interface chip (ESIC) */ 8378c2ecf20Sopenharmony_ci val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); 8388c2ecf20Sopenharmony_ci val |= PI_CONFIG_STAT_0_M_INT_ENB; 8398c2ecf20Sopenharmony_ci outb(val, base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci if (dfx_bus_pci) { 8428c2ecf20Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(bdev); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci /* Get the interrupt level from the PCI Configuration Table */ 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci dev->irq = pdev->irq; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci /* Check Latency Timer and set if less than minimal */ 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &val); 8518c2ecf20Sopenharmony_ci if (val < PFI_K_LAT_TIMER_MIN) { 8528c2ecf20Sopenharmony_ci val = PFI_K_LAT_TIMER_DEF; 8538c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, PCI_LATENCY_TIMER, val); 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci /* Enable interrupts at PCI bus interface chip (PFI) */ 8578c2ecf20Sopenharmony_ci val = PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB; 8588c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, val); 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci/* 8638c2ecf20Sopenharmony_ci * ================== 8648c2ecf20Sopenharmony_ci * = dfx_bus_uninit = 8658c2ecf20Sopenharmony_ci * ================== 8668c2ecf20Sopenharmony_ci * 8678c2ecf20Sopenharmony_ci * Overview: 8688c2ecf20Sopenharmony_ci * Uninitializes the bus-specific controller logic. 8698c2ecf20Sopenharmony_ci * 8708c2ecf20Sopenharmony_ci * Returns: 8718c2ecf20Sopenharmony_ci * None 8728c2ecf20Sopenharmony_ci * 8738c2ecf20Sopenharmony_ci * Arguments: 8748c2ecf20Sopenharmony_ci * dev - pointer to device information 8758c2ecf20Sopenharmony_ci * 8768c2ecf20Sopenharmony_ci * Functional Description: 8778c2ecf20Sopenharmony_ci * Perform bus-specific logic uninitialization. 8788c2ecf20Sopenharmony_ci * 8798c2ecf20Sopenharmony_ci * Return Codes: 8808c2ecf20Sopenharmony_ci * None 8818c2ecf20Sopenharmony_ci * 8828c2ecf20Sopenharmony_ci * Assumptions: 8838c2ecf20Sopenharmony_ci * bp->base has already been set with the proper 8848c2ecf20Sopenharmony_ci * base I/O address for this device. 8858c2ecf20Sopenharmony_ci * 8868c2ecf20Sopenharmony_ci * Side Effects: 8878c2ecf20Sopenharmony_ci * Interrupts are disabled at the adapter bus-specific logic. 8888c2ecf20Sopenharmony_ci */ 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic void dfx_bus_uninit(struct net_device *dev) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci DFX_board_t *bp = netdev_priv(dev); 8938c2ecf20Sopenharmony_ci struct device *bdev = bp->bus_dev; 8948c2ecf20Sopenharmony_ci int dfx_bus_pci = dev_is_pci(bdev); 8958c2ecf20Sopenharmony_ci int dfx_bus_eisa = DFX_BUS_EISA(bdev); 8968c2ecf20Sopenharmony_ci u8 val; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci DBG_printk("In dfx_bus_uninit...\n"); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci /* Uninitialize adapter based on bus type */ 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (dfx_bus_eisa) { 9038c2ecf20Sopenharmony_ci unsigned long base_addr = to_eisa_device(bdev)->base_addr; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci /* Disable interrupts at EISA bus interface chip (ESIC) */ 9068c2ecf20Sopenharmony_ci val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); 9078c2ecf20Sopenharmony_ci val &= ~PI_CONFIG_STAT_0_M_INT_ENB; 9088c2ecf20Sopenharmony_ci outb(val, base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci /* Disable the board. */ 9118c2ecf20Sopenharmony_ci outb(0, base_addr + PI_ESIC_K_SLOT_CNTRL); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* Disable memory and port decoders. */ 9148c2ecf20Sopenharmony_ci outb(0, base_addr + PI_ESIC_K_FUNCTION_CNTRL); 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci if (dfx_bus_pci) { 9178c2ecf20Sopenharmony_ci /* Disable interrupts at PCI bus interface chip (PFI) */ 9188c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, 0); 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci/* 9248c2ecf20Sopenharmony_ci * ======================== 9258c2ecf20Sopenharmony_ci * = dfx_bus_config_check = 9268c2ecf20Sopenharmony_ci * ======================== 9278c2ecf20Sopenharmony_ci * 9288c2ecf20Sopenharmony_ci * Overview: 9298c2ecf20Sopenharmony_ci * Checks the configuration (burst size, full-duplex, etc.) If any parameters 9308c2ecf20Sopenharmony_ci * are illegal, then this routine will set new defaults. 9318c2ecf20Sopenharmony_ci * 9328c2ecf20Sopenharmony_ci * Returns: 9338c2ecf20Sopenharmony_ci * None 9348c2ecf20Sopenharmony_ci * 9358c2ecf20Sopenharmony_ci * Arguments: 9368c2ecf20Sopenharmony_ci * bp - pointer to board information 9378c2ecf20Sopenharmony_ci * 9388c2ecf20Sopenharmony_ci * Functional Description: 9398c2ecf20Sopenharmony_ci * For Revision 1 FDDI EISA, Revision 2 or later FDDI EISA with rev E or later 9408c2ecf20Sopenharmony_ci * PDQ, and all FDDI PCI controllers, all values are legal. 9418c2ecf20Sopenharmony_ci * 9428c2ecf20Sopenharmony_ci * Return Codes: 9438c2ecf20Sopenharmony_ci * None 9448c2ecf20Sopenharmony_ci * 9458c2ecf20Sopenharmony_ci * Assumptions: 9468c2ecf20Sopenharmony_ci * dfx_adap_init has NOT been called yet so burst size and other items have 9478c2ecf20Sopenharmony_ci * not been set. 9488c2ecf20Sopenharmony_ci * 9498c2ecf20Sopenharmony_ci * Side Effects: 9508c2ecf20Sopenharmony_ci * None 9518c2ecf20Sopenharmony_ci */ 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_cistatic void dfx_bus_config_check(DFX_board_t *bp) 9548c2ecf20Sopenharmony_ci{ 9558c2ecf20Sopenharmony_ci struct device __maybe_unused *bdev = bp->bus_dev; 9568c2ecf20Sopenharmony_ci int dfx_bus_eisa = DFX_BUS_EISA(bdev); 9578c2ecf20Sopenharmony_ci int status; /* return code from adapter port control call */ 9588c2ecf20Sopenharmony_ci u32 host_data; /* LW data returned from port control call */ 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci DBG_printk("In dfx_bus_config_check...\n"); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci /* Configuration check only valid for EISA adapter */ 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci if (dfx_bus_eisa) { 9658c2ecf20Sopenharmony_ci /* 9668c2ecf20Sopenharmony_ci * First check if revision 2 EISA controller. Rev. 1 cards used 9678c2ecf20Sopenharmony_ci * PDQ revision B, so no workaround needed in this case. Rev. 3 9688c2ecf20Sopenharmony_ci * cards used PDQ revision E, so no workaround needed in this 9698c2ecf20Sopenharmony_ci * case, either. Only Rev. 2 cards used either Rev. D or E 9708c2ecf20Sopenharmony_ci * chips, so we must verify the chip revision on Rev. 2 cards. 9718c2ecf20Sopenharmony_ci */ 9728c2ecf20Sopenharmony_ci if (to_eisa_device(bdev)->id.driver_data == DEFEA_PROD_ID_2) { 9738c2ecf20Sopenharmony_ci /* 9748c2ecf20Sopenharmony_ci * Revision 2 FDDI EISA controller found, 9758c2ecf20Sopenharmony_ci * so let's check PDQ revision of adapter. 9768c2ecf20Sopenharmony_ci */ 9778c2ecf20Sopenharmony_ci status = dfx_hw_port_ctrl_req(bp, 9788c2ecf20Sopenharmony_ci PI_PCTRL_M_SUB_CMD, 9798c2ecf20Sopenharmony_ci PI_SUB_CMD_K_PDQ_REV_GET, 9808c2ecf20Sopenharmony_ci 0, 9818c2ecf20Sopenharmony_ci &host_data); 9828c2ecf20Sopenharmony_ci if ((status != DFX_K_SUCCESS) || (host_data == 2)) 9838c2ecf20Sopenharmony_ci { 9848c2ecf20Sopenharmony_ci /* 9858c2ecf20Sopenharmony_ci * Either we couldn't determine the PDQ revision, or 9868c2ecf20Sopenharmony_ci * we determined that it is at revision D. In either case, 9878c2ecf20Sopenharmony_ci * we need to implement the workaround. 9888c2ecf20Sopenharmony_ci */ 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* Ensure that the burst size is set to 8 longwords or less */ 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci switch (bp->burst_size) 9938c2ecf20Sopenharmony_ci { 9948c2ecf20Sopenharmony_ci case PI_PDATA_B_DMA_BURST_SIZE_32: 9958c2ecf20Sopenharmony_ci case PI_PDATA_B_DMA_BURST_SIZE_16: 9968c2ecf20Sopenharmony_ci bp->burst_size = PI_PDATA_B_DMA_BURST_SIZE_8; 9978c2ecf20Sopenharmony_ci break; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci default: 10008c2ecf20Sopenharmony_ci break; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci /* Ensure that full-duplex mode is not enabled */ 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci bp->full_duplex_enb = PI_SNMP_K_FALSE; 10068c2ecf20Sopenharmony_ci } 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci } 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci/* 10138c2ecf20Sopenharmony_ci * =================== 10148c2ecf20Sopenharmony_ci * = dfx_driver_init = 10158c2ecf20Sopenharmony_ci * =================== 10168c2ecf20Sopenharmony_ci * 10178c2ecf20Sopenharmony_ci * Overview: 10188c2ecf20Sopenharmony_ci * Initializes remaining adapter board structure information 10198c2ecf20Sopenharmony_ci * and makes sure adapter is in a safe state prior to dfx_open(). 10208c2ecf20Sopenharmony_ci * 10218c2ecf20Sopenharmony_ci * Returns: 10228c2ecf20Sopenharmony_ci * Condition code 10238c2ecf20Sopenharmony_ci * 10248c2ecf20Sopenharmony_ci * Arguments: 10258c2ecf20Sopenharmony_ci * dev - pointer to device information 10268c2ecf20Sopenharmony_ci * print_name - printable device name 10278c2ecf20Sopenharmony_ci * 10288c2ecf20Sopenharmony_ci * Functional Description: 10298c2ecf20Sopenharmony_ci * This function allocates additional resources such as the host memory 10308c2ecf20Sopenharmony_ci * blocks needed by the adapter (eg. descriptor and consumer blocks). 10318c2ecf20Sopenharmony_ci * Remaining bus initialization steps are also completed. The adapter 10328c2ecf20Sopenharmony_ci * is also reset so that it is in the DMA_UNAVAILABLE state. The OS 10338c2ecf20Sopenharmony_ci * must call dfx_open() to open the adapter and bring it on-line. 10348c2ecf20Sopenharmony_ci * 10358c2ecf20Sopenharmony_ci * Return Codes: 10368c2ecf20Sopenharmony_ci * DFX_K_SUCCESS - initialization succeeded 10378c2ecf20Sopenharmony_ci * DFX_K_FAILURE - initialization failed - could not allocate memory 10388c2ecf20Sopenharmony_ci * or read adapter MAC address 10398c2ecf20Sopenharmony_ci * 10408c2ecf20Sopenharmony_ci * Assumptions: 10418c2ecf20Sopenharmony_ci * Memory allocated from pci_alloc_consistent() call is physically 10428c2ecf20Sopenharmony_ci * contiguous, locked memory. 10438c2ecf20Sopenharmony_ci * 10448c2ecf20Sopenharmony_ci * Side Effects: 10458c2ecf20Sopenharmony_ci * Adapter is reset and should be in DMA_UNAVAILABLE state before 10468c2ecf20Sopenharmony_ci * returning from this routine. 10478c2ecf20Sopenharmony_ci */ 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_cistatic int dfx_driver_init(struct net_device *dev, const char *print_name, 10508c2ecf20Sopenharmony_ci resource_size_t bar_start) 10518c2ecf20Sopenharmony_ci{ 10528c2ecf20Sopenharmony_ci DFX_board_t *bp = netdev_priv(dev); 10538c2ecf20Sopenharmony_ci struct device *bdev = bp->bus_dev; 10548c2ecf20Sopenharmony_ci int dfx_bus_pci = dev_is_pci(bdev); 10558c2ecf20Sopenharmony_ci int dfx_bus_eisa = DFX_BUS_EISA(bdev); 10568c2ecf20Sopenharmony_ci int dfx_bus_tc = DFX_BUS_TC(bdev); 10578c2ecf20Sopenharmony_ci int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; 10588c2ecf20Sopenharmony_ci int alloc_size; /* total buffer size needed */ 10598c2ecf20Sopenharmony_ci char *top_v, *curr_v; /* virtual addrs into memory block */ 10608c2ecf20Sopenharmony_ci dma_addr_t top_p, curr_p; /* physical addrs into memory block */ 10618c2ecf20Sopenharmony_ci u32 data; /* host data register value */ 10628c2ecf20Sopenharmony_ci __le32 le32; 10638c2ecf20Sopenharmony_ci char *board_name = NULL; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci DBG_printk("In dfx_driver_init...\n"); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci /* Initialize bus-specific hardware registers */ 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci dfx_bus_init(dev); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci /* 10728c2ecf20Sopenharmony_ci * Initialize default values for configurable parameters 10738c2ecf20Sopenharmony_ci * 10748c2ecf20Sopenharmony_ci * Note: All of these parameters are ones that a user may 10758c2ecf20Sopenharmony_ci * want to customize. It'd be nice to break these 10768c2ecf20Sopenharmony_ci * out into Space.c or someplace else that's more 10778c2ecf20Sopenharmony_ci * accessible/understandable than this file. 10788c2ecf20Sopenharmony_ci */ 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci bp->full_duplex_enb = PI_SNMP_K_FALSE; 10818c2ecf20Sopenharmony_ci bp->req_ttrt = 8 * 12500; /* 8ms in 80 nanosec units */ 10828c2ecf20Sopenharmony_ci bp->burst_size = PI_PDATA_B_DMA_BURST_SIZE_DEF; 10838c2ecf20Sopenharmony_ci bp->rcv_bufs_to_post = RCV_BUFS_DEF; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci /* 10868c2ecf20Sopenharmony_ci * Ensure that HW configuration is OK 10878c2ecf20Sopenharmony_ci * 10888c2ecf20Sopenharmony_ci * Note: Depending on the hardware revision, we may need to modify 10898c2ecf20Sopenharmony_ci * some of the configurable parameters to workaround hardware 10908c2ecf20Sopenharmony_ci * limitations. We'll perform this configuration check AFTER 10918c2ecf20Sopenharmony_ci * setting the parameters to their default values. 10928c2ecf20Sopenharmony_ci */ 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci dfx_bus_config_check(bp); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci /* Disable PDQ interrupts first */ 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci /* Place adapter in DMA_UNAVAILABLE state by resetting adapter */ 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci (void) dfx_hw_dma_uninit(bp, PI_PDATA_A_RESET_M_SKIP_ST); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci /* Read the factory MAC address from the adapter then save it */ 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_LO, 0, 11078c2ecf20Sopenharmony_ci &data) != DFX_K_SUCCESS) { 11088c2ecf20Sopenharmony_ci printk("%s: Could not read adapter factory MAC address!\n", 11098c2ecf20Sopenharmony_ci print_name); 11108c2ecf20Sopenharmony_ci return DFX_K_FAILURE; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci le32 = cpu_to_le32(data); 11138c2ecf20Sopenharmony_ci memcpy(&bp->factory_mac_addr[0], &le32, sizeof(u32)); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_HI, 0, 11168c2ecf20Sopenharmony_ci &data) != DFX_K_SUCCESS) { 11178c2ecf20Sopenharmony_ci printk("%s: Could not read adapter factory MAC address!\n", 11188c2ecf20Sopenharmony_ci print_name); 11198c2ecf20Sopenharmony_ci return DFX_K_FAILURE; 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci le32 = cpu_to_le32(data); 11228c2ecf20Sopenharmony_ci memcpy(&bp->factory_mac_addr[4], &le32, sizeof(u16)); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci /* 11258c2ecf20Sopenharmony_ci * Set current address to factory address 11268c2ecf20Sopenharmony_ci * 11278c2ecf20Sopenharmony_ci * Note: Node address override support is handled through 11288c2ecf20Sopenharmony_ci * dfx_ctl_set_mac_address. 11298c2ecf20Sopenharmony_ci */ 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN); 11328c2ecf20Sopenharmony_ci if (dfx_bus_tc) 11338c2ecf20Sopenharmony_ci board_name = "DEFTA"; 11348c2ecf20Sopenharmony_ci if (dfx_bus_eisa) 11358c2ecf20Sopenharmony_ci board_name = "DEFEA"; 11368c2ecf20Sopenharmony_ci if (dfx_bus_pci) 11378c2ecf20Sopenharmony_ci board_name = "DEFPA"; 11388c2ecf20Sopenharmony_ci pr_info("%s: %s at %s addr = 0x%llx, IRQ = %d, Hardware addr = %pMF\n", 11398c2ecf20Sopenharmony_ci print_name, board_name, dfx_use_mmio ? "MMIO" : "I/O", 11408c2ecf20Sopenharmony_ci (long long)bar_start, dev->irq, dev->dev_addr); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci /* 11438c2ecf20Sopenharmony_ci * Get memory for descriptor block, consumer block, and other buffers 11448c2ecf20Sopenharmony_ci * that need to be DMA read or written to by the adapter. 11458c2ecf20Sopenharmony_ci */ 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci alloc_size = sizeof(PI_DESCR_BLOCK) + 11488c2ecf20Sopenharmony_ci PI_CMD_REQ_K_SIZE_MAX + 11498c2ecf20Sopenharmony_ci PI_CMD_RSP_K_SIZE_MAX + 11508c2ecf20Sopenharmony_ci#ifndef DYNAMIC_BUFFERS 11518c2ecf20Sopenharmony_ci (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) + 11528c2ecf20Sopenharmony_ci#endif 11538c2ecf20Sopenharmony_ci sizeof(PI_CONSUMER_BLOCK) + 11548c2ecf20Sopenharmony_ci (PI_ALIGN_K_DESC_BLK - 1); 11558c2ecf20Sopenharmony_ci bp->kmalloced = top_v = dma_alloc_coherent(bp->bus_dev, alloc_size, 11568c2ecf20Sopenharmony_ci &bp->kmalloced_dma, 11578c2ecf20Sopenharmony_ci GFP_ATOMIC); 11588c2ecf20Sopenharmony_ci if (top_v == NULL) 11598c2ecf20Sopenharmony_ci return DFX_K_FAILURE; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci top_p = bp->kmalloced_dma; /* get physical address of buffer */ 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci /* 11648c2ecf20Sopenharmony_ci * To guarantee the 8K alignment required for the descriptor block, 8K - 1 11658c2ecf20Sopenharmony_ci * plus the amount of memory needed was allocated. The physical address 11668c2ecf20Sopenharmony_ci * is now 8K aligned. By carving up the memory in a specific order, 11678c2ecf20Sopenharmony_ci * we'll guarantee the alignment requirements for all other structures. 11688c2ecf20Sopenharmony_ci * 11698c2ecf20Sopenharmony_ci * Note: If the assumptions change regarding the non-paged, non-cached, 11708c2ecf20Sopenharmony_ci * physically contiguous nature of the memory block or the address 11718c2ecf20Sopenharmony_ci * alignments, then we'll need to implement a different algorithm 11728c2ecf20Sopenharmony_ci * for allocating the needed memory. 11738c2ecf20Sopenharmony_ci */ 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci curr_p = ALIGN(top_p, PI_ALIGN_K_DESC_BLK); 11768c2ecf20Sopenharmony_ci curr_v = top_v + (curr_p - top_p); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci /* Reserve space for descriptor block */ 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci bp->descr_block_virt = (PI_DESCR_BLOCK *) curr_v; 11818c2ecf20Sopenharmony_ci bp->descr_block_phys = curr_p; 11828c2ecf20Sopenharmony_ci curr_v += sizeof(PI_DESCR_BLOCK); 11838c2ecf20Sopenharmony_ci curr_p += sizeof(PI_DESCR_BLOCK); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci /* Reserve space for command request buffer */ 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci bp->cmd_req_virt = (PI_DMA_CMD_REQ *) curr_v; 11888c2ecf20Sopenharmony_ci bp->cmd_req_phys = curr_p; 11898c2ecf20Sopenharmony_ci curr_v += PI_CMD_REQ_K_SIZE_MAX; 11908c2ecf20Sopenharmony_ci curr_p += PI_CMD_REQ_K_SIZE_MAX; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci /* Reserve space for command response buffer */ 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci bp->cmd_rsp_virt = (PI_DMA_CMD_RSP *) curr_v; 11958c2ecf20Sopenharmony_ci bp->cmd_rsp_phys = curr_p; 11968c2ecf20Sopenharmony_ci curr_v += PI_CMD_RSP_K_SIZE_MAX; 11978c2ecf20Sopenharmony_ci curr_p += PI_CMD_RSP_K_SIZE_MAX; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci /* Reserve space for the LLC host receive queue buffers */ 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci bp->rcv_block_virt = curr_v; 12028c2ecf20Sopenharmony_ci bp->rcv_block_phys = curr_p; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci#ifndef DYNAMIC_BUFFERS 12058c2ecf20Sopenharmony_ci curr_v += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX); 12068c2ecf20Sopenharmony_ci curr_p += (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX); 12078c2ecf20Sopenharmony_ci#endif 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci /* Reserve space for the consumer block */ 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci bp->cons_block_virt = (PI_CONSUMER_BLOCK *) curr_v; 12128c2ecf20Sopenharmony_ci bp->cons_block_phys = curr_p; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci /* Display virtual and physical addresses if debug driver */ 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci DBG_printk("%s: Descriptor block virt = %p, phys = %pad\n", 12178c2ecf20Sopenharmony_ci print_name, bp->descr_block_virt, &bp->descr_block_phys); 12188c2ecf20Sopenharmony_ci DBG_printk("%s: Command Request buffer virt = %p, phys = %pad\n", 12198c2ecf20Sopenharmony_ci print_name, bp->cmd_req_virt, &bp->cmd_req_phys); 12208c2ecf20Sopenharmony_ci DBG_printk("%s: Command Response buffer virt = %p, phys = %pad\n", 12218c2ecf20Sopenharmony_ci print_name, bp->cmd_rsp_virt, &bp->cmd_rsp_phys); 12228c2ecf20Sopenharmony_ci DBG_printk("%s: Receive buffer block virt = %p, phys = %pad\n", 12238c2ecf20Sopenharmony_ci print_name, bp->rcv_block_virt, &bp->rcv_block_phys); 12248c2ecf20Sopenharmony_ci DBG_printk("%s: Consumer block virt = %p, phys = %pad\n", 12258c2ecf20Sopenharmony_ci print_name, bp->cons_block_virt, &bp->cons_block_phys); 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci return DFX_K_SUCCESS; 12288c2ecf20Sopenharmony_ci} 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci/* 12328c2ecf20Sopenharmony_ci * ================= 12338c2ecf20Sopenharmony_ci * = dfx_adap_init = 12348c2ecf20Sopenharmony_ci * ================= 12358c2ecf20Sopenharmony_ci * 12368c2ecf20Sopenharmony_ci * Overview: 12378c2ecf20Sopenharmony_ci * Brings the adapter to the link avail/link unavailable state. 12388c2ecf20Sopenharmony_ci * 12398c2ecf20Sopenharmony_ci * Returns: 12408c2ecf20Sopenharmony_ci * Condition code 12418c2ecf20Sopenharmony_ci * 12428c2ecf20Sopenharmony_ci * Arguments: 12438c2ecf20Sopenharmony_ci * bp - pointer to board information 12448c2ecf20Sopenharmony_ci * get_buffers - non-zero if buffers to be allocated 12458c2ecf20Sopenharmony_ci * 12468c2ecf20Sopenharmony_ci * Functional Description: 12478c2ecf20Sopenharmony_ci * Issues the low-level firmware/hardware calls necessary to bring 12488c2ecf20Sopenharmony_ci * the adapter up, or to properly reset and restore adapter during 12498c2ecf20Sopenharmony_ci * run-time. 12508c2ecf20Sopenharmony_ci * 12518c2ecf20Sopenharmony_ci * Return Codes: 12528c2ecf20Sopenharmony_ci * DFX_K_SUCCESS - Adapter brought up successfully 12538c2ecf20Sopenharmony_ci * DFX_K_FAILURE - Adapter initialization failed 12548c2ecf20Sopenharmony_ci * 12558c2ecf20Sopenharmony_ci * Assumptions: 12568c2ecf20Sopenharmony_ci * bp->reset_type should be set to a valid reset type value before 12578c2ecf20Sopenharmony_ci * calling this routine. 12588c2ecf20Sopenharmony_ci * 12598c2ecf20Sopenharmony_ci * Side Effects: 12608c2ecf20Sopenharmony_ci * Adapter should be in LINK_AVAILABLE or LINK_UNAVAILABLE state 12618c2ecf20Sopenharmony_ci * upon a successful return of this routine. 12628c2ecf20Sopenharmony_ci */ 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_cistatic int dfx_adap_init(DFX_board_t *bp, int get_buffers) 12658c2ecf20Sopenharmony_ci { 12668c2ecf20Sopenharmony_ci DBG_printk("In dfx_adap_init...\n"); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci /* Disable PDQ interrupts first */ 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci /* Place adapter in DMA_UNAVAILABLE state by resetting adapter */ 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci if (dfx_hw_dma_uninit(bp, bp->reset_type) != DFX_K_SUCCESS) 12758c2ecf20Sopenharmony_ci { 12768c2ecf20Sopenharmony_ci printk("%s: Could not uninitialize/reset adapter!\n", bp->dev->name); 12778c2ecf20Sopenharmony_ci return DFX_K_FAILURE; 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci /* 12818c2ecf20Sopenharmony_ci * When the PDQ is reset, some false Type 0 interrupts may be pending, 12828c2ecf20Sopenharmony_ci * so we'll acknowledge all Type 0 interrupts now before continuing. 12838c2ecf20Sopenharmony_ci */ 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, PI_HOST_INT_K_ACK_ALL_TYPE_0); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci /* 12888c2ecf20Sopenharmony_ci * Clear Type 1 and Type 2 registers before going to DMA_AVAILABLE state 12898c2ecf20Sopenharmony_ci * 12908c2ecf20Sopenharmony_ci * Note: We only need to clear host copies of these registers. The PDQ reset 12918c2ecf20Sopenharmony_ci * takes care of the on-board register values. 12928c2ecf20Sopenharmony_ci */ 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci bp->cmd_req_reg.lword = 0; 12958c2ecf20Sopenharmony_ci bp->cmd_rsp_reg.lword = 0; 12968c2ecf20Sopenharmony_ci bp->rcv_xmt_reg.lword = 0; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci /* Clear consumer block before going to DMA_AVAILABLE state */ 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci memset(bp->cons_block_virt, 0, sizeof(PI_CONSUMER_BLOCK)); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci /* Initialize the DMA Burst Size */ 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci if (dfx_hw_port_ctrl_req(bp, 13058c2ecf20Sopenharmony_ci PI_PCTRL_M_SUB_CMD, 13068c2ecf20Sopenharmony_ci PI_SUB_CMD_K_BURST_SIZE_SET, 13078c2ecf20Sopenharmony_ci bp->burst_size, 13088c2ecf20Sopenharmony_ci NULL) != DFX_K_SUCCESS) 13098c2ecf20Sopenharmony_ci { 13108c2ecf20Sopenharmony_ci printk("%s: Could not set adapter burst size!\n", bp->dev->name); 13118c2ecf20Sopenharmony_ci return DFX_K_FAILURE; 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci /* 13158c2ecf20Sopenharmony_ci * Set base address of Consumer Block 13168c2ecf20Sopenharmony_ci * 13178c2ecf20Sopenharmony_ci * Assumption: 32-bit physical address of consumer block is 64 byte 13188c2ecf20Sopenharmony_ci * aligned. That is, bits 0-5 of the address must be zero. 13198c2ecf20Sopenharmony_ci */ 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci if (dfx_hw_port_ctrl_req(bp, 13228c2ecf20Sopenharmony_ci PI_PCTRL_M_CONS_BLOCK, 13238c2ecf20Sopenharmony_ci bp->cons_block_phys, 13248c2ecf20Sopenharmony_ci 0, 13258c2ecf20Sopenharmony_ci NULL) != DFX_K_SUCCESS) 13268c2ecf20Sopenharmony_ci { 13278c2ecf20Sopenharmony_ci printk("%s: Could not set consumer block address!\n", bp->dev->name); 13288c2ecf20Sopenharmony_ci return DFX_K_FAILURE; 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci /* 13328c2ecf20Sopenharmony_ci * Set the base address of Descriptor Block and bring adapter 13338c2ecf20Sopenharmony_ci * to DMA_AVAILABLE state. 13348c2ecf20Sopenharmony_ci * 13358c2ecf20Sopenharmony_ci * Note: We also set the literal and data swapping requirements 13368c2ecf20Sopenharmony_ci * in this command. 13378c2ecf20Sopenharmony_ci * 13388c2ecf20Sopenharmony_ci * Assumption: 32-bit physical address of descriptor block 13398c2ecf20Sopenharmony_ci * is 8Kbyte aligned. 13408c2ecf20Sopenharmony_ci */ 13418c2ecf20Sopenharmony_ci if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_INIT, 13428c2ecf20Sopenharmony_ci (u32)(bp->descr_block_phys | 13438c2ecf20Sopenharmony_ci PI_PDATA_A_INIT_M_BSWAP_INIT), 13448c2ecf20Sopenharmony_ci 0, NULL) != DFX_K_SUCCESS) { 13458c2ecf20Sopenharmony_ci printk("%s: Could not set descriptor block address!\n", 13468c2ecf20Sopenharmony_ci bp->dev->name); 13478c2ecf20Sopenharmony_ci return DFX_K_FAILURE; 13488c2ecf20Sopenharmony_ci } 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci /* Set transmit flush timeout value */ 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci bp->cmd_req_virt->cmd_type = PI_CMD_K_CHARS_SET; 13538c2ecf20Sopenharmony_ci bp->cmd_req_virt->char_set.item[0].item_code = PI_ITEM_K_FLUSH_TIME; 13548c2ecf20Sopenharmony_ci bp->cmd_req_virt->char_set.item[0].value = 3; /* 3 seconds */ 13558c2ecf20Sopenharmony_ci bp->cmd_req_virt->char_set.item[0].item_index = 0; 13568c2ecf20Sopenharmony_ci bp->cmd_req_virt->char_set.item[1].item_code = PI_ITEM_K_EOL; 13578c2ecf20Sopenharmony_ci if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) 13588c2ecf20Sopenharmony_ci { 13598c2ecf20Sopenharmony_ci printk("%s: DMA command request failed!\n", bp->dev->name); 13608c2ecf20Sopenharmony_ci return DFX_K_FAILURE; 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci /* Set the initial values for eFDXEnable and MACTReq MIB objects */ 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci bp->cmd_req_virt->cmd_type = PI_CMD_K_SNMP_SET; 13668c2ecf20Sopenharmony_ci bp->cmd_req_virt->snmp_set.item[0].item_code = PI_ITEM_K_FDX_ENB_DIS; 13678c2ecf20Sopenharmony_ci bp->cmd_req_virt->snmp_set.item[0].value = bp->full_duplex_enb; 13688c2ecf20Sopenharmony_ci bp->cmd_req_virt->snmp_set.item[0].item_index = 0; 13698c2ecf20Sopenharmony_ci bp->cmd_req_virt->snmp_set.item[1].item_code = PI_ITEM_K_MAC_T_REQ; 13708c2ecf20Sopenharmony_ci bp->cmd_req_virt->snmp_set.item[1].value = bp->req_ttrt; 13718c2ecf20Sopenharmony_ci bp->cmd_req_virt->snmp_set.item[1].item_index = 0; 13728c2ecf20Sopenharmony_ci bp->cmd_req_virt->snmp_set.item[2].item_code = PI_ITEM_K_EOL; 13738c2ecf20Sopenharmony_ci if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) 13748c2ecf20Sopenharmony_ci { 13758c2ecf20Sopenharmony_ci printk("%s: DMA command request failed!\n", bp->dev->name); 13768c2ecf20Sopenharmony_ci return DFX_K_FAILURE; 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci /* Initialize adapter CAM */ 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS) 13828c2ecf20Sopenharmony_ci { 13838c2ecf20Sopenharmony_ci printk("%s: Adapter CAM update failed!\n", bp->dev->name); 13848c2ecf20Sopenharmony_ci return DFX_K_FAILURE; 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci /* Initialize adapter filters */ 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS) 13908c2ecf20Sopenharmony_ci { 13918c2ecf20Sopenharmony_ci printk("%s: Adapter filters update failed!\n", bp->dev->name); 13928c2ecf20Sopenharmony_ci return DFX_K_FAILURE; 13938c2ecf20Sopenharmony_ci } 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci /* 13968c2ecf20Sopenharmony_ci * Remove any existing dynamic buffers (i.e. if the adapter is being 13978c2ecf20Sopenharmony_ci * reinitialized) 13988c2ecf20Sopenharmony_ci */ 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if (get_buffers) 14018c2ecf20Sopenharmony_ci dfx_rcv_flush(bp); 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci /* Initialize receive descriptor block and produce buffers */ 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci if (dfx_rcv_init(bp, get_buffers)) 14068c2ecf20Sopenharmony_ci { 14078c2ecf20Sopenharmony_ci printk("%s: Receive buffer allocation failed\n", bp->dev->name); 14088c2ecf20Sopenharmony_ci if (get_buffers) 14098c2ecf20Sopenharmony_ci dfx_rcv_flush(bp); 14108c2ecf20Sopenharmony_ci return DFX_K_FAILURE; 14118c2ecf20Sopenharmony_ci } 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci /* Issue START command and bring adapter to LINK_(UN)AVAILABLE state */ 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci bp->cmd_req_virt->cmd_type = PI_CMD_K_START; 14168c2ecf20Sopenharmony_ci if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) 14178c2ecf20Sopenharmony_ci { 14188c2ecf20Sopenharmony_ci printk("%s: Start command failed\n", bp->dev->name); 14198c2ecf20Sopenharmony_ci if (get_buffers) 14208c2ecf20Sopenharmony_ci dfx_rcv_flush(bp); 14218c2ecf20Sopenharmony_ci return DFX_K_FAILURE; 14228c2ecf20Sopenharmony_ci } 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci /* Initialization succeeded, reenable PDQ interrupts */ 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_ENABLE_DEF_INTS); 14278c2ecf20Sopenharmony_ci return DFX_K_SUCCESS; 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci/* 14328c2ecf20Sopenharmony_ci * ============ 14338c2ecf20Sopenharmony_ci * = dfx_open = 14348c2ecf20Sopenharmony_ci * ============ 14358c2ecf20Sopenharmony_ci * 14368c2ecf20Sopenharmony_ci * Overview: 14378c2ecf20Sopenharmony_ci * Opens the adapter 14388c2ecf20Sopenharmony_ci * 14398c2ecf20Sopenharmony_ci * Returns: 14408c2ecf20Sopenharmony_ci * Condition code 14418c2ecf20Sopenharmony_ci * 14428c2ecf20Sopenharmony_ci * Arguments: 14438c2ecf20Sopenharmony_ci * dev - pointer to device information 14448c2ecf20Sopenharmony_ci * 14458c2ecf20Sopenharmony_ci * Functional Description: 14468c2ecf20Sopenharmony_ci * This function brings the adapter to an operational state. 14478c2ecf20Sopenharmony_ci * 14488c2ecf20Sopenharmony_ci * Return Codes: 14498c2ecf20Sopenharmony_ci * 0 - Adapter was successfully opened 14508c2ecf20Sopenharmony_ci * -EAGAIN - Could not register IRQ or adapter initialization failed 14518c2ecf20Sopenharmony_ci * 14528c2ecf20Sopenharmony_ci * Assumptions: 14538c2ecf20Sopenharmony_ci * This routine should only be called for a device that was 14548c2ecf20Sopenharmony_ci * initialized successfully. 14558c2ecf20Sopenharmony_ci * 14568c2ecf20Sopenharmony_ci * Side Effects: 14578c2ecf20Sopenharmony_ci * Adapter should be in LINK_AVAILABLE or LINK_UNAVAILABLE state 14588c2ecf20Sopenharmony_ci * if the open is successful. 14598c2ecf20Sopenharmony_ci */ 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_cistatic int dfx_open(struct net_device *dev) 14628c2ecf20Sopenharmony_ci{ 14638c2ecf20Sopenharmony_ci DFX_board_t *bp = netdev_priv(dev); 14648c2ecf20Sopenharmony_ci int ret; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci DBG_printk("In dfx_open...\n"); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci /* Register IRQ - support shared interrupts by passing device ptr */ 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name, 14718c2ecf20Sopenharmony_ci dev); 14728c2ecf20Sopenharmony_ci if (ret) { 14738c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq); 14748c2ecf20Sopenharmony_ci return ret; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci /* 14788c2ecf20Sopenharmony_ci * Set current address to factory MAC address 14798c2ecf20Sopenharmony_ci * 14808c2ecf20Sopenharmony_ci * Note: We've already done this step in dfx_driver_init. 14818c2ecf20Sopenharmony_ci * However, it's possible that a user has set a node 14828c2ecf20Sopenharmony_ci * address override, then closed and reopened the 14838c2ecf20Sopenharmony_ci * adapter. Unless we reset the device address field 14848c2ecf20Sopenharmony_ci * now, we'll continue to use the existing modified 14858c2ecf20Sopenharmony_ci * address. 14868c2ecf20Sopenharmony_ci */ 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci /* Clear local unicast/multicast address tables and counts */ 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci memset(bp->uc_table, 0, sizeof(bp->uc_table)); 14938c2ecf20Sopenharmony_ci memset(bp->mc_table, 0, sizeof(bp->mc_table)); 14948c2ecf20Sopenharmony_ci bp->uc_count = 0; 14958c2ecf20Sopenharmony_ci bp->mc_count = 0; 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci /* Disable promiscuous filter settings */ 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci bp->ind_group_prom = PI_FSTATE_K_BLOCK; 15008c2ecf20Sopenharmony_ci bp->group_prom = PI_FSTATE_K_BLOCK; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci spin_lock_init(&bp->lock); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci /* Reset and initialize adapter */ 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci bp->reset_type = PI_PDATA_A_RESET_M_SKIP_ST; /* skip self-test */ 15078c2ecf20Sopenharmony_ci if (dfx_adap_init(bp, 1) != DFX_K_SUCCESS) 15088c2ecf20Sopenharmony_ci { 15098c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Adapter open failed!\n", dev->name); 15108c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 15118c2ecf20Sopenharmony_ci return -EAGAIN; 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci /* Set device structure info */ 15158c2ecf20Sopenharmony_ci netif_start_queue(dev); 15168c2ecf20Sopenharmony_ci return 0; 15178c2ecf20Sopenharmony_ci} 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci/* 15218c2ecf20Sopenharmony_ci * ============= 15228c2ecf20Sopenharmony_ci * = dfx_close = 15238c2ecf20Sopenharmony_ci * ============= 15248c2ecf20Sopenharmony_ci * 15258c2ecf20Sopenharmony_ci * Overview: 15268c2ecf20Sopenharmony_ci * Closes the device/module. 15278c2ecf20Sopenharmony_ci * 15288c2ecf20Sopenharmony_ci * Returns: 15298c2ecf20Sopenharmony_ci * Condition code 15308c2ecf20Sopenharmony_ci * 15318c2ecf20Sopenharmony_ci * Arguments: 15328c2ecf20Sopenharmony_ci * dev - pointer to device information 15338c2ecf20Sopenharmony_ci * 15348c2ecf20Sopenharmony_ci * Functional Description: 15358c2ecf20Sopenharmony_ci * This routine closes the adapter and brings it to a safe state. 15368c2ecf20Sopenharmony_ci * The interrupt service routine is deregistered with the OS. 15378c2ecf20Sopenharmony_ci * The adapter can be opened again with another call to dfx_open(). 15388c2ecf20Sopenharmony_ci * 15398c2ecf20Sopenharmony_ci * Return Codes: 15408c2ecf20Sopenharmony_ci * Always return 0. 15418c2ecf20Sopenharmony_ci * 15428c2ecf20Sopenharmony_ci * Assumptions: 15438c2ecf20Sopenharmony_ci * No further requests for this adapter are made after this routine is 15448c2ecf20Sopenharmony_ci * called. dfx_open() can be called to reset and reinitialize the 15458c2ecf20Sopenharmony_ci * adapter. 15468c2ecf20Sopenharmony_ci * 15478c2ecf20Sopenharmony_ci * Side Effects: 15488c2ecf20Sopenharmony_ci * Adapter should be in DMA_UNAVAILABLE state upon completion of this 15498c2ecf20Sopenharmony_ci * routine. 15508c2ecf20Sopenharmony_ci */ 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_cistatic int dfx_close(struct net_device *dev) 15538c2ecf20Sopenharmony_ci{ 15548c2ecf20Sopenharmony_ci DFX_board_t *bp = netdev_priv(dev); 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci DBG_printk("In dfx_close...\n"); 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci /* Disable PDQ interrupts first */ 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci /* Place adapter in DMA_UNAVAILABLE state by resetting adapter */ 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci (void) dfx_hw_dma_uninit(bp, PI_PDATA_A_RESET_M_SKIP_ST); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci /* 15678c2ecf20Sopenharmony_ci * Flush any pending transmit buffers 15688c2ecf20Sopenharmony_ci * 15698c2ecf20Sopenharmony_ci * Note: It's important that we flush the transmit buffers 15708c2ecf20Sopenharmony_ci * BEFORE we clear our copy of the Type 2 register. 15718c2ecf20Sopenharmony_ci * Otherwise, we'll have no idea how many buffers 15728c2ecf20Sopenharmony_ci * we need to free. 15738c2ecf20Sopenharmony_ci */ 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci dfx_xmt_flush(bp); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci /* 15788c2ecf20Sopenharmony_ci * Clear Type 1 and Type 2 registers after adapter reset 15798c2ecf20Sopenharmony_ci * 15808c2ecf20Sopenharmony_ci * Note: Even though we're closing the adapter, it's 15818c2ecf20Sopenharmony_ci * possible that an interrupt will occur after 15828c2ecf20Sopenharmony_ci * dfx_close is called. Without some assurance to 15838c2ecf20Sopenharmony_ci * the contrary we want to make sure that we don't 15848c2ecf20Sopenharmony_ci * process receive and transmit LLC frames and update 15858c2ecf20Sopenharmony_ci * the Type 2 register with bad information. 15868c2ecf20Sopenharmony_ci */ 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci bp->cmd_req_reg.lword = 0; 15898c2ecf20Sopenharmony_ci bp->cmd_rsp_reg.lword = 0; 15908c2ecf20Sopenharmony_ci bp->rcv_xmt_reg.lword = 0; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci /* Clear consumer block for the same reason given above */ 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci memset(bp->cons_block_virt, 0, sizeof(PI_CONSUMER_BLOCK)); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci /* Release all dynamically allocate skb in the receive ring. */ 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci dfx_rcv_flush(bp); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci /* Clear device structure flags */ 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci netif_stop_queue(dev); 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci /* Deregister (free) IRQ */ 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci return 0; 16098c2ecf20Sopenharmony_ci} 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci/* 16138c2ecf20Sopenharmony_ci * ====================== 16148c2ecf20Sopenharmony_ci * = dfx_int_pr_halt_id = 16158c2ecf20Sopenharmony_ci * ====================== 16168c2ecf20Sopenharmony_ci * 16178c2ecf20Sopenharmony_ci * Overview: 16188c2ecf20Sopenharmony_ci * Displays halt id's in string form. 16198c2ecf20Sopenharmony_ci * 16208c2ecf20Sopenharmony_ci * Returns: 16218c2ecf20Sopenharmony_ci * None 16228c2ecf20Sopenharmony_ci * 16238c2ecf20Sopenharmony_ci * Arguments: 16248c2ecf20Sopenharmony_ci * bp - pointer to board information 16258c2ecf20Sopenharmony_ci * 16268c2ecf20Sopenharmony_ci * Functional Description: 16278c2ecf20Sopenharmony_ci * Determine current halt id and display appropriate string. 16288c2ecf20Sopenharmony_ci * 16298c2ecf20Sopenharmony_ci * Return Codes: 16308c2ecf20Sopenharmony_ci * None 16318c2ecf20Sopenharmony_ci * 16328c2ecf20Sopenharmony_ci * Assumptions: 16338c2ecf20Sopenharmony_ci * None 16348c2ecf20Sopenharmony_ci * 16358c2ecf20Sopenharmony_ci * Side Effects: 16368c2ecf20Sopenharmony_ci * None 16378c2ecf20Sopenharmony_ci */ 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_cistatic void dfx_int_pr_halt_id(DFX_board_t *bp) 16408c2ecf20Sopenharmony_ci { 16418c2ecf20Sopenharmony_ci PI_UINT32 port_status; /* PDQ port status register value */ 16428c2ecf20Sopenharmony_ci PI_UINT32 halt_id; /* PDQ port status halt ID */ 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci /* Read the latest port status */ 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status); 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci /* Display halt state transition information */ 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci halt_id = (port_status & PI_PSTATUS_M_HALT_ID) >> PI_PSTATUS_V_HALT_ID; 16518c2ecf20Sopenharmony_ci switch (halt_id) 16528c2ecf20Sopenharmony_ci { 16538c2ecf20Sopenharmony_ci case PI_HALT_ID_K_SELFTEST_TIMEOUT: 16548c2ecf20Sopenharmony_ci printk("%s: Halt ID: Selftest Timeout\n", bp->dev->name); 16558c2ecf20Sopenharmony_ci break; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci case PI_HALT_ID_K_PARITY_ERROR: 16588c2ecf20Sopenharmony_ci printk("%s: Halt ID: Host Bus Parity Error\n", bp->dev->name); 16598c2ecf20Sopenharmony_ci break; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci case PI_HALT_ID_K_HOST_DIR_HALT: 16628c2ecf20Sopenharmony_ci printk("%s: Halt ID: Host-Directed Halt\n", bp->dev->name); 16638c2ecf20Sopenharmony_ci break; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci case PI_HALT_ID_K_SW_FAULT: 16668c2ecf20Sopenharmony_ci printk("%s: Halt ID: Adapter Software Fault\n", bp->dev->name); 16678c2ecf20Sopenharmony_ci break; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci case PI_HALT_ID_K_HW_FAULT: 16708c2ecf20Sopenharmony_ci printk("%s: Halt ID: Adapter Hardware Fault\n", bp->dev->name); 16718c2ecf20Sopenharmony_ci break; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci case PI_HALT_ID_K_PC_TRACE: 16748c2ecf20Sopenharmony_ci printk("%s: Halt ID: FDDI Network PC Trace Path Test\n", bp->dev->name); 16758c2ecf20Sopenharmony_ci break; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci case PI_HALT_ID_K_DMA_ERROR: 16788c2ecf20Sopenharmony_ci printk("%s: Halt ID: Adapter DMA Error\n", bp->dev->name); 16798c2ecf20Sopenharmony_ci break; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci case PI_HALT_ID_K_IMAGE_CRC_ERROR: 16828c2ecf20Sopenharmony_ci printk("%s: Halt ID: Firmware Image CRC Error\n", bp->dev->name); 16838c2ecf20Sopenharmony_ci break; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci case PI_HALT_ID_K_BUS_EXCEPTION: 16868c2ecf20Sopenharmony_ci printk("%s: Halt ID: 68000 Bus Exception\n", bp->dev->name); 16878c2ecf20Sopenharmony_ci break; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci default: 16908c2ecf20Sopenharmony_ci printk("%s: Halt ID: Unknown (code = %X)\n", bp->dev->name, halt_id); 16918c2ecf20Sopenharmony_ci break; 16928c2ecf20Sopenharmony_ci } 16938c2ecf20Sopenharmony_ci } 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci/* 16978c2ecf20Sopenharmony_ci * ========================== 16988c2ecf20Sopenharmony_ci * = dfx_int_type_0_process = 16998c2ecf20Sopenharmony_ci * ========================== 17008c2ecf20Sopenharmony_ci * 17018c2ecf20Sopenharmony_ci * Overview: 17028c2ecf20Sopenharmony_ci * Processes Type 0 interrupts. 17038c2ecf20Sopenharmony_ci * 17048c2ecf20Sopenharmony_ci * Returns: 17058c2ecf20Sopenharmony_ci * None 17068c2ecf20Sopenharmony_ci * 17078c2ecf20Sopenharmony_ci * Arguments: 17088c2ecf20Sopenharmony_ci * bp - pointer to board information 17098c2ecf20Sopenharmony_ci * 17108c2ecf20Sopenharmony_ci * Functional Description: 17118c2ecf20Sopenharmony_ci * Processes all enabled Type 0 interrupts. If the reason for the interrupt 17128c2ecf20Sopenharmony_ci * is a serious fault on the adapter, then an error message is displayed 17138c2ecf20Sopenharmony_ci * and the adapter is reset. 17148c2ecf20Sopenharmony_ci * 17158c2ecf20Sopenharmony_ci * One tricky potential timing window is the rapid succession of "link avail" 17168c2ecf20Sopenharmony_ci * "link unavail" state change interrupts. The acknowledgement of the Type 0 17178c2ecf20Sopenharmony_ci * interrupt must be done before reading the state from the Port Status 17188c2ecf20Sopenharmony_ci * register. This is true because a state change could occur after reading 17198c2ecf20Sopenharmony_ci * the data, but before acknowledging the interrupt. If this state change 17208c2ecf20Sopenharmony_ci * does happen, it would be lost because the driver is using the old state, 17218c2ecf20Sopenharmony_ci * and it will never know about the new state because it subsequently 17228c2ecf20Sopenharmony_ci * acknowledges the state change interrupt. 17238c2ecf20Sopenharmony_ci * 17248c2ecf20Sopenharmony_ci * INCORRECT CORRECT 17258c2ecf20Sopenharmony_ci * read type 0 int reasons read type 0 int reasons 17268c2ecf20Sopenharmony_ci * read adapter state ack type 0 interrupts 17278c2ecf20Sopenharmony_ci * ack type 0 interrupts read adapter state 17288c2ecf20Sopenharmony_ci * ... process interrupt ... ... process interrupt ... 17298c2ecf20Sopenharmony_ci * 17308c2ecf20Sopenharmony_ci * Return Codes: 17318c2ecf20Sopenharmony_ci * None 17328c2ecf20Sopenharmony_ci * 17338c2ecf20Sopenharmony_ci * Assumptions: 17348c2ecf20Sopenharmony_ci * None 17358c2ecf20Sopenharmony_ci * 17368c2ecf20Sopenharmony_ci * Side Effects: 17378c2ecf20Sopenharmony_ci * An adapter reset may occur if the adapter has any Type 0 error interrupts 17388c2ecf20Sopenharmony_ci * or if the port status indicates that the adapter is halted. The driver 17398c2ecf20Sopenharmony_ci * is responsible for reinitializing the adapter with the current CAM 17408c2ecf20Sopenharmony_ci * contents and adapter filter settings. 17418c2ecf20Sopenharmony_ci */ 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_cistatic void dfx_int_type_0_process(DFX_board_t *bp) 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci { 17468c2ecf20Sopenharmony_ci PI_UINT32 type_0_status; /* Host Interrupt Type 0 register */ 17478c2ecf20Sopenharmony_ci PI_UINT32 state; /* current adap state (from port status) */ 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci /* 17508c2ecf20Sopenharmony_ci * Read host interrupt Type 0 register to determine which Type 0 17518c2ecf20Sopenharmony_ci * interrupts are pending. Immediately write it back out to clear 17528c2ecf20Sopenharmony_ci * those interrupts. 17538c2ecf20Sopenharmony_ci */ 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci dfx_port_read_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, &type_0_status); 17568c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_0_STATUS, type_0_status); 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci /* Check for Type 0 error interrupts */ 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci if (type_0_status & (PI_TYPE_0_STAT_M_NXM | 17618c2ecf20Sopenharmony_ci PI_TYPE_0_STAT_M_PM_PAR_ERR | 17628c2ecf20Sopenharmony_ci PI_TYPE_0_STAT_M_BUS_PAR_ERR)) 17638c2ecf20Sopenharmony_ci { 17648c2ecf20Sopenharmony_ci /* Check for Non-Existent Memory error */ 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci if (type_0_status & PI_TYPE_0_STAT_M_NXM) 17678c2ecf20Sopenharmony_ci printk("%s: Non-Existent Memory Access Error\n", bp->dev->name); 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci /* Check for Packet Memory Parity error */ 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci if (type_0_status & PI_TYPE_0_STAT_M_PM_PAR_ERR) 17728c2ecf20Sopenharmony_ci printk("%s: Packet Memory Parity Error\n", bp->dev->name); 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci /* Check for Host Bus Parity error */ 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci if (type_0_status & PI_TYPE_0_STAT_M_BUS_PAR_ERR) 17778c2ecf20Sopenharmony_ci printk("%s: Host Bus Parity Error\n", bp->dev->name); 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci /* Reset adapter and bring it back on-line */ 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci bp->link_available = PI_K_FALSE; /* link is no longer available */ 17828c2ecf20Sopenharmony_ci bp->reset_type = 0; /* rerun on-board diagnostics */ 17838c2ecf20Sopenharmony_ci printk("%s: Resetting adapter...\n", bp->dev->name); 17848c2ecf20Sopenharmony_ci if (dfx_adap_init(bp, 0) != DFX_K_SUCCESS) 17858c2ecf20Sopenharmony_ci { 17868c2ecf20Sopenharmony_ci printk("%s: Adapter reset failed! Disabling adapter interrupts.\n", bp->dev->name); 17878c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); 17888c2ecf20Sopenharmony_ci return; 17898c2ecf20Sopenharmony_ci } 17908c2ecf20Sopenharmony_ci printk("%s: Adapter reset successful!\n", bp->dev->name); 17918c2ecf20Sopenharmony_ci return; 17928c2ecf20Sopenharmony_ci } 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci /* Check for transmit flush interrupt */ 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci if (type_0_status & PI_TYPE_0_STAT_M_XMT_FLUSH) 17978c2ecf20Sopenharmony_ci { 17988c2ecf20Sopenharmony_ci /* Flush any pending xmt's and acknowledge the flush interrupt */ 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci bp->link_available = PI_K_FALSE; /* link is no longer available */ 18018c2ecf20Sopenharmony_ci dfx_xmt_flush(bp); /* flush any outstanding packets */ 18028c2ecf20Sopenharmony_ci (void) dfx_hw_port_ctrl_req(bp, 18038c2ecf20Sopenharmony_ci PI_PCTRL_M_XMT_DATA_FLUSH_DONE, 18048c2ecf20Sopenharmony_ci 0, 18058c2ecf20Sopenharmony_ci 0, 18068c2ecf20Sopenharmony_ci NULL); 18078c2ecf20Sopenharmony_ci } 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci /* Check for adapter state change */ 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci if (type_0_status & PI_TYPE_0_STAT_M_STATE_CHANGE) 18128c2ecf20Sopenharmony_ci { 18138c2ecf20Sopenharmony_ci /* Get latest adapter state */ 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci state = dfx_hw_adap_state_rd(bp); /* get adapter state */ 18168c2ecf20Sopenharmony_ci if (state == PI_STATE_K_HALTED) 18178c2ecf20Sopenharmony_ci { 18188c2ecf20Sopenharmony_ci /* 18198c2ecf20Sopenharmony_ci * Adapter has transitioned to HALTED state, try to reset 18208c2ecf20Sopenharmony_ci * adapter to bring it back on-line. If reset fails, 18218c2ecf20Sopenharmony_ci * leave the adapter in the broken state. 18228c2ecf20Sopenharmony_ci */ 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci printk("%s: Controller has transitioned to HALTED state!\n", bp->dev->name); 18258c2ecf20Sopenharmony_ci dfx_int_pr_halt_id(bp); /* display halt id as string */ 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci /* Reset adapter and bring it back on-line */ 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci bp->link_available = PI_K_FALSE; /* link is no longer available */ 18308c2ecf20Sopenharmony_ci bp->reset_type = 0; /* rerun on-board diagnostics */ 18318c2ecf20Sopenharmony_ci printk("%s: Resetting adapter...\n", bp->dev->name); 18328c2ecf20Sopenharmony_ci if (dfx_adap_init(bp, 0) != DFX_K_SUCCESS) 18338c2ecf20Sopenharmony_ci { 18348c2ecf20Sopenharmony_ci printk("%s: Adapter reset failed! Disabling adapter interrupts.\n", bp->dev->name); 18358c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); 18368c2ecf20Sopenharmony_ci return; 18378c2ecf20Sopenharmony_ci } 18388c2ecf20Sopenharmony_ci printk("%s: Adapter reset successful!\n", bp->dev->name); 18398c2ecf20Sopenharmony_ci } 18408c2ecf20Sopenharmony_ci else if (state == PI_STATE_K_LINK_AVAIL) 18418c2ecf20Sopenharmony_ci { 18428c2ecf20Sopenharmony_ci bp->link_available = PI_K_TRUE; /* set link available flag */ 18438c2ecf20Sopenharmony_ci } 18448c2ecf20Sopenharmony_ci } 18458c2ecf20Sopenharmony_ci } 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci/* 18498c2ecf20Sopenharmony_ci * ================== 18508c2ecf20Sopenharmony_ci * = dfx_int_common = 18518c2ecf20Sopenharmony_ci * ================== 18528c2ecf20Sopenharmony_ci * 18538c2ecf20Sopenharmony_ci * Overview: 18548c2ecf20Sopenharmony_ci * Interrupt service routine (ISR) 18558c2ecf20Sopenharmony_ci * 18568c2ecf20Sopenharmony_ci * Returns: 18578c2ecf20Sopenharmony_ci * None 18588c2ecf20Sopenharmony_ci * 18598c2ecf20Sopenharmony_ci * Arguments: 18608c2ecf20Sopenharmony_ci * bp - pointer to board information 18618c2ecf20Sopenharmony_ci * 18628c2ecf20Sopenharmony_ci * Functional Description: 18638c2ecf20Sopenharmony_ci * This is the ISR which processes incoming adapter interrupts. 18648c2ecf20Sopenharmony_ci * 18658c2ecf20Sopenharmony_ci * Return Codes: 18668c2ecf20Sopenharmony_ci * None 18678c2ecf20Sopenharmony_ci * 18688c2ecf20Sopenharmony_ci * Assumptions: 18698c2ecf20Sopenharmony_ci * This routine assumes PDQ interrupts have not been disabled. 18708c2ecf20Sopenharmony_ci * When interrupts are disabled at the PDQ, the Port Status register 18718c2ecf20Sopenharmony_ci * is automatically cleared. This routine uses the Port Status 18728c2ecf20Sopenharmony_ci * register value to determine whether a Type 0 interrupt occurred, 18738c2ecf20Sopenharmony_ci * so it's important that adapter interrupts are not normally 18748c2ecf20Sopenharmony_ci * enabled/disabled at the PDQ. 18758c2ecf20Sopenharmony_ci * 18768c2ecf20Sopenharmony_ci * It's vital that this routine is NOT reentered for the 18778c2ecf20Sopenharmony_ci * same board and that the OS is not in another section of 18788c2ecf20Sopenharmony_ci * code (eg. dfx_xmt_queue_pkt) for the same board on a 18798c2ecf20Sopenharmony_ci * different thread. 18808c2ecf20Sopenharmony_ci * 18818c2ecf20Sopenharmony_ci * Side Effects: 18828c2ecf20Sopenharmony_ci * Pending interrupts are serviced. Depending on the type of 18838c2ecf20Sopenharmony_ci * interrupt, acknowledging and clearing the interrupt at the 18848c2ecf20Sopenharmony_ci * PDQ involves writing a register to clear the interrupt bit 18858c2ecf20Sopenharmony_ci * or updating completion indices. 18868c2ecf20Sopenharmony_ci */ 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_cistatic void dfx_int_common(struct net_device *dev) 18898c2ecf20Sopenharmony_ci{ 18908c2ecf20Sopenharmony_ci DFX_board_t *bp = netdev_priv(dev); 18918c2ecf20Sopenharmony_ci PI_UINT32 port_status; /* Port Status register */ 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci /* Process xmt interrupts - frequent case, so always call this routine */ 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci if(dfx_xmt_done(bp)) /* free consumed xmt packets */ 18968c2ecf20Sopenharmony_ci netif_wake_queue(dev); 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci /* Process rcv interrupts - frequent case, so always call this routine */ 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci dfx_rcv_queue_process(bp); /* service received LLC frames */ 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci /* 19038c2ecf20Sopenharmony_ci * Transmit and receive producer and completion indices are updated on the 19048c2ecf20Sopenharmony_ci * adapter by writing to the Type 2 Producer register. Since the frequent 19058c2ecf20Sopenharmony_ci * case is that we'll be processing either LLC transmit or receive buffers, 19068c2ecf20Sopenharmony_ci * we'll optimize I/O writes by doing a single register write here. 19078c2ecf20Sopenharmony_ci */ 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci /* Read PDQ Port Status register to find out which interrupts need processing */ 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status); 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci /* Process Type 0 interrupts (if any) - infrequent, so only call when needed */ 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci if (port_status & PI_PSTATUS_M_TYPE_0_PENDING) 19188c2ecf20Sopenharmony_ci dfx_int_type_0_process(bp); /* process Type 0 interrupts */ 19198c2ecf20Sopenharmony_ci } 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci/* 19238c2ecf20Sopenharmony_ci * ================= 19248c2ecf20Sopenharmony_ci * = dfx_interrupt = 19258c2ecf20Sopenharmony_ci * ================= 19268c2ecf20Sopenharmony_ci * 19278c2ecf20Sopenharmony_ci * Overview: 19288c2ecf20Sopenharmony_ci * Interrupt processing routine 19298c2ecf20Sopenharmony_ci * 19308c2ecf20Sopenharmony_ci * Returns: 19318c2ecf20Sopenharmony_ci * Whether a valid interrupt was seen. 19328c2ecf20Sopenharmony_ci * 19338c2ecf20Sopenharmony_ci * Arguments: 19348c2ecf20Sopenharmony_ci * irq - interrupt vector 19358c2ecf20Sopenharmony_ci * dev_id - pointer to device information 19368c2ecf20Sopenharmony_ci * 19378c2ecf20Sopenharmony_ci * Functional Description: 19388c2ecf20Sopenharmony_ci * This routine calls the interrupt processing routine for this adapter. It 19398c2ecf20Sopenharmony_ci * disables and reenables adapter interrupts, as appropriate. We can support 19408c2ecf20Sopenharmony_ci * shared interrupts since the incoming dev_id pointer provides our device 19418c2ecf20Sopenharmony_ci * structure context. 19428c2ecf20Sopenharmony_ci * 19438c2ecf20Sopenharmony_ci * Return Codes: 19448c2ecf20Sopenharmony_ci * IRQ_HANDLED - an IRQ was handled. 19458c2ecf20Sopenharmony_ci * IRQ_NONE - no IRQ was handled. 19468c2ecf20Sopenharmony_ci * 19478c2ecf20Sopenharmony_ci * Assumptions: 19488c2ecf20Sopenharmony_ci * The interrupt acknowledgement at the hardware level (eg. ACKing the PIC 19498c2ecf20Sopenharmony_ci * on Intel-based systems) is done by the operating system outside this 19508c2ecf20Sopenharmony_ci * routine. 19518c2ecf20Sopenharmony_ci * 19528c2ecf20Sopenharmony_ci * System interrupts are enabled through this call. 19538c2ecf20Sopenharmony_ci * 19548c2ecf20Sopenharmony_ci * Side Effects: 19558c2ecf20Sopenharmony_ci * Interrupts are disabled, then reenabled at the adapter. 19568c2ecf20Sopenharmony_ci */ 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_cistatic irqreturn_t dfx_interrupt(int irq, void *dev_id) 19598c2ecf20Sopenharmony_ci{ 19608c2ecf20Sopenharmony_ci struct net_device *dev = dev_id; 19618c2ecf20Sopenharmony_ci DFX_board_t *bp = netdev_priv(dev); 19628c2ecf20Sopenharmony_ci struct device *bdev = bp->bus_dev; 19638c2ecf20Sopenharmony_ci int dfx_bus_pci = dev_is_pci(bdev); 19648c2ecf20Sopenharmony_ci int dfx_bus_eisa = DFX_BUS_EISA(bdev); 19658c2ecf20Sopenharmony_ci int dfx_bus_tc = DFX_BUS_TC(bdev); 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci /* Service adapter interrupts */ 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci if (dfx_bus_pci) { 19708c2ecf20Sopenharmony_ci u32 status; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci dfx_port_read_long(bp, PFI_K_REG_STATUS, &status); 19738c2ecf20Sopenharmony_ci if (!(status & PFI_STATUS_M_PDQ_INT)) 19748c2ecf20Sopenharmony_ci return IRQ_NONE; 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci spin_lock(&bp->lock); 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci /* Disable PDQ-PFI interrupts at PFI */ 19798c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, 19808c2ecf20Sopenharmony_ci PFI_MODE_M_DMA_ENB); 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci /* Call interrupt service routine for this adapter */ 19838c2ecf20Sopenharmony_ci dfx_int_common(dev); 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci /* Clear PDQ interrupt status bit and reenable interrupts */ 19868c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PFI_K_REG_STATUS, 19878c2ecf20Sopenharmony_ci PFI_STATUS_M_PDQ_INT); 19888c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, 19898c2ecf20Sopenharmony_ci (PFI_MODE_M_PDQ_INT_ENB | 19908c2ecf20Sopenharmony_ci PFI_MODE_M_DMA_ENB)); 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci spin_unlock(&bp->lock); 19938c2ecf20Sopenharmony_ci } 19948c2ecf20Sopenharmony_ci if (dfx_bus_eisa) { 19958c2ecf20Sopenharmony_ci unsigned long base_addr = to_eisa_device(bdev)->base_addr; 19968c2ecf20Sopenharmony_ci u8 status; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); 19998c2ecf20Sopenharmony_ci if (!(status & PI_CONFIG_STAT_0_M_PEND)) 20008c2ecf20Sopenharmony_ci return IRQ_NONE; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci spin_lock(&bp->lock); 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci /* Disable interrupts at the ESIC */ 20058c2ecf20Sopenharmony_ci status &= ~PI_CONFIG_STAT_0_M_INT_ENB; 20068c2ecf20Sopenharmony_ci outb(status, base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci /* Call interrupt service routine for this adapter */ 20098c2ecf20Sopenharmony_ci dfx_int_common(dev); 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci /* Reenable interrupts at the ESIC */ 20128c2ecf20Sopenharmony_ci status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); 20138c2ecf20Sopenharmony_ci status |= PI_CONFIG_STAT_0_M_INT_ENB; 20148c2ecf20Sopenharmony_ci outb(status, base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci spin_unlock(&bp->lock); 20178c2ecf20Sopenharmony_ci } 20188c2ecf20Sopenharmony_ci if (dfx_bus_tc) { 20198c2ecf20Sopenharmony_ci u32 status; 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &status); 20228c2ecf20Sopenharmony_ci if (!(status & (PI_PSTATUS_M_RCV_DATA_PENDING | 20238c2ecf20Sopenharmony_ci PI_PSTATUS_M_XMT_DATA_PENDING | 20248c2ecf20Sopenharmony_ci PI_PSTATUS_M_SMT_HOST_PENDING | 20258c2ecf20Sopenharmony_ci PI_PSTATUS_M_UNSOL_PENDING | 20268c2ecf20Sopenharmony_ci PI_PSTATUS_M_CMD_RSP_PENDING | 20278c2ecf20Sopenharmony_ci PI_PSTATUS_M_CMD_REQ_PENDING | 20288c2ecf20Sopenharmony_ci PI_PSTATUS_M_TYPE_0_PENDING))) 20298c2ecf20Sopenharmony_ci return IRQ_NONE; 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci spin_lock(&bp->lock); 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci /* Call interrupt service routine for this adapter */ 20348c2ecf20Sopenharmony_ci dfx_int_common(dev); 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci spin_unlock(&bp->lock); 20378c2ecf20Sopenharmony_ci } 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci return IRQ_HANDLED; 20408c2ecf20Sopenharmony_ci} 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci/* 20448c2ecf20Sopenharmony_ci * ===================== 20458c2ecf20Sopenharmony_ci * = dfx_ctl_get_stats = 20468c2ecf20Sopenharmony_ci * ===================== 20478c2ecf20Sopenharmony_ci * 20488c2ecf20Sopenharmony_ci * Overview: 20498c2ecf20Sopenharmony_ci * Get statistics for FDDI adapter 20508c2ecf20Sopenharmony_ci * 20518c2ecf20Sopenharmony_ci * Returns: 20528c2ecf20Sopenharmony_ci * Pointer to FDDI statistics structure 20538c2ecf20Sopenharmony_ci * 20548c2ecf20Sopenharmony_ci * Arguments: 20558c2ecf20Sopenharmony_ci * dev - pointer to device information 20568c2ecf20Sopenharmony_ci * 20578c2ecf20Sopenharmony_ci * Functional Description: 20588c2ecf20Sopenharmony_ci * Gets current MIB objects from adapter, then 20598c2ecf20Sopenharmony_ci * returns FDDI statistics structure as defined 20608c2ecf20Sopenharmony_ci * in if_fddi.h. 20618c2ecf20Sopenharmony_ci * 20628c2ecf20Sopenharmony_ci * Note: Since the FDDI statistics structure is 20638c2ecf20Sopenharmony_ci * still new and the device structure doesn't 20648c2ecf20Sopenharmony_ci * have an FDDI-specific get statistics handler, 20658c2ecf20Sopenharmony_ci * we'll return the FDDI statistics structure as 20668c2ecf20Sopenharmony_ci * a pointer to an Ethernet statistics structure. 20678c2ecf20Sopenharmony_ci * That way, at least the first part of the statistics 20688c2ecf20Sopenharmony_ci * structure can be decoded properly, and it allows 20698c2ecf20Sopenharmony_ci * "smart" applications to perform a second cast to 20708c2ecf20Sopenharmony_ci * decode the FDDI-specific statistics. 20718c2ecf20Sopenharmony_ci * 20728c2ecf20Sopenharmony_ci * We'll have to pay attention to this routine as the 20738c2ecf20Sopenharmony_ci * device structure becomes more mature and LAN media 20748c2ecf20Sopenharmony_ci * independent. 20758c2ecf20Sopenharmony_ci * 20768c2ecf20Sopenharmony_ci * Return Codes: 20778c2ecf20Sopenharmony_ci * None 20788c2ecf20Sopenharmony_ci * 20798c2ecf20Sopenharmony_ci * Assumptions: 20808c2ecf20Sopenharmony_ci * None 20818c2ecf20Sopenharmony_ci * 20828c2ecf20Sopenharmony_ci * Side Effects: 20838c2ecf20Sopenharmony_ci * None 20848c2ecf20Sopenharmony_ci */ 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_cistatic struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev) 20878c2ecf20Sopenharmony_ci { 20888c2ecf20Sopenharmony_ci DFX_board_t *bp = netdev_priv(dev); 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci /* Fill the bp->stats structure with driver-maintained counters */ 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci bp->stats.gen.rx_packets = bp->rcv_total_frames; 20938c2ecf20Sopenharmony_ci bp->stats.gen.tx_packets = bp->xmt_total_frames; 20948c2ecf20Sopenharmony_ci bp->stats.gen.rx_bytes = bp->rcv_total_bytes; 20958c2ecf20Sopenharmony_ci bp->stats.gen.tx_bytes = bp->xmt_total_bytes; 20968c2ecf20Sopenharmony_ci bp->stats.gen.rx_errors = bp->rcv_crc_errors + 20978c2ecf20Sopenharmony_ci bp->rcv_frame_status_errors + 20988c2ecf20Sopenharmony_ci bp->rcv_length_errors; 20998c2ecf20Sopenharmony_ci bp->stats.gen.tx_errors = bp->xmt_length_errors; 21008c2ecf20Sopenharmony_ci bp->stats.gen.rx_dropped = bp->rcv_discards; 21018c2ecf20Sopenharmony_ci bp->stats.gen.tx_dropped = bp->xmt_discards; 21028c2ecf20Sopenharmony_ci bp->stats.gen.multicast = bp->rcv_multicast_frames; 21038c2ecf20Sopenharmony_ci bp->stats.gen.collisions = 0; /* always zero (0) for FDDI */ 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci /* Get FDDI SMT MIB objects */ 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci bp->cmd_req_virt->cmd_type = PI_CMD_K_SMT_MIB_GET; 21088c2ecf20Sopenharmony_ci if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) 21098c2ecf20Sopenharmony_ci return (struct net_device_stats *)&bp->stats; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci /* Fill the bp->stats structure with the SMT MIB object values */ 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci memcpy(bp->stats.smt_station_id, &bp->cmd_rsp_virt->smt_mib_get.smt_station_id, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_station_id)); 21148c2ecf20Sopenharmony_ci bp->stats.smt_op_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_op_version_id; 21158c2ecf20Sopenharmony_ci bp->stats.smt_hi_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_hi_version_id; 21168c2ecf20Sopenharmony_ci bp->stats.smt_lo_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_lo_version_id; 21178c2ecf20Sopenharmony_ci memcpy(bp->stats.smt_user_data, &bp->cmd_rsp_virt->smt_mib_get.smt_user_data, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_user_data)); 21188c2ecf20Sopenharmony_ci bp->stats.smt_mib_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_mib_version_id; 21198c2ecf20Sopenharmony_ci bp->stats.smt_mac_cts = bp->cmd_rsp_virt->smt_mib_get.smt_mac_ct; 21208c2ecf20Sopenharmony_ci bp->stats.smt_non_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_non_master_ct; 21218c2ecf20Sopenharmony_ci bp->stats.smt_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_master_ct; 21228c2ecf20Sopenharmony_ci bp->stats.smt_available_paths = bp->cmd_rsp_virt->smt_mib_get.smt_available_paths; 21238c2ecf20Sopenharmony_ci bp->stats.smt_config_capabilities = bp->cmd_rsp_virt->smt_mib_get.smt_config_capabilities; 21248c2ecf20Sopenharmony_ci bp->stats.smt_config_policy = bp->cmd_rsp_virt->smt_mib_get.smt_config_policy; 21258c2ecf20Sopenharmony_ci bp->stats.smt_connection_policy = bp->cmd_rsp_virt->smt_mib_get.smt_connection_policy; 21268c2ecf20Sopenharmony_ci bp->stats.smt_t_notify = bp->cmd_rsp_virt->smt_mib_get.smt_t_notify; 21278c2ecf20Sopenharmony_ci bp->stats.smt_stat_rpt_policy = bp->cmd_rsp_virt->smt_mib_get.smt_stat_rpt_policy; 21288c2ecf20Sopenharmony_ci bp->stats.smt_trace_max_expiration = bp->cmd_rsp_virt->smt_mib_get.smt_trace_max_expiration; 21298c2ecf20Sopenharmony_ci bp->stats.smt_bypass_present = bp->cmd_rsp_virt->smt_mib_get.smt_bypass_present; 21308c2ecf20Sopenharmony_ci bp->stats.smt_ecm_state = bp->cmd_rsp_virt->smt_mib_get.smt_ecm_state; 21318c2ecf20Sopenharmony_ci bp->stats.smt_cf_state = bp->cmd_rsp_virt->smt_mib_get.smt_cf_state; 21328c2ecf20Sopenharmony_ci bp->stats.smt_remote_disconnect_flag = bp->cmd_rsp_virt->smt_mib_get.smt_remote_disconnect_flag; 21338c2ecf20Sopenharmony_ci bp->stats.smt_station_status = bp->cmd_rsp_virt->smt_mib_get.smt_station_status; 21348c2ecf20Sopenharmony_ci bp->stats.smt_peer_wrap_flag = bp->cmd_rsp_virt->smt_mib_get.smt_peer_wrap_flag; 21358c2ecf20Sopenharmony_ci bp->stats.smt_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_msg_time_stamp.ls; 21368c2ecf20Sopenharmony_ci bp->stats.smt_transition_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_transition_time_stamp.ls; 21378c2ecf20Sopenharmony_ci bp->stats.mac_frame_status_functions = bp->cmd_rsp_virt->smt_mib_get.mac_frame_status_functions; 21388c2ecf20Sopenharmony_ci bp->stats.mac_t_max_capability = bp->cmd_rsp_virt->smt_mib_get.mac_t_max_capability; 21398c2ecf20Sopenharmony_ci bp->stats.mac_tvx_capability = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_capability; 21408c2ecf20Sopenharmony_ci bp->stats.mac_available_paths = bp->cmd_rsp_virt->smt_mib_get.mac_available_paths; 21418c2ecf20Sopenharmony_ci bp->stats.mac_current_path = bp->cmd_rsp_virt->smt_mib_get.mac_current_path; 21428c2ecf20Sopenharmony_ci memcpy(bp->stats.mac_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_upstream_nbr, FDDI_K_ALEN); 21438c2ecf20Sopenharmony_ci memcpy(bp->stats.mac_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_downstream_nbr, FDDI_K_ALEN); 21448c2ecf20Sopenharmony_ci memcpy(bp->stats.mac_old_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_upstream_nbr, FDDI_K_ALEN); 21458c2ecf20Sopenharmony_ci memcpy(bp->stats.mac_old_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_downstream_nbr, FDDI_K_ALEN); 21468c2ecf20Sopenharmony_ci bp->stats.mac_dup_address_test = bp->cmd_rsp_virt->smt_mib_get.mac_dup_address_test; 21478c2ecf20Sopenharmony_ci bp->stats.mac_requested_paths = bp->cmd_rsp_virt->smt_mib_get.mac_requested_paths; 21488c2ecf20Sopenharmony_ci bp->stats.mac_downstream_port_type = bp->cmd_rsp_virt->smt_mib_get.mac_downstream_port_type; 21498c2ecf20Sopenharmony_ci memcpy(bp->stats.mac_smt_address, &bp->cmd_rsp_virt->smt_mib_get.mac_smt_address, FDDI_K_ALEN); 21508c2ecf20Sopenharmony_ci bp->stats.mac_t_req = bp->cmd_rsp_virt->smt_mib_get.mac_t_req; 21518c2ecf20Sopenharmony_ci bp->stats.mac_t_neg = bp->cmd_rsp_virt->smt_mib_get.mac_t_neg; 21528c2ecf20Sopenharmony_ci bp->stats.mac_t_max = bp->cmd_rsp_virt->smt_mib_get.mac_t_max; 21538c2ecf20Sopenharmony_ci bp->stats.mac_tvx_value = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_value; 21548c2ecf20Sopenharmony_ci bp->stats.mac_frame_error_threshold = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_threshold; 21558c2ecf20Sopenharmony_ci bp->stats.mac_frame_error_ratio = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_ratio; 21568c2ecf20Sopenharmony_ci bp->stats.mac_rmt_state = bp->cmd_rsp_virt->smt_mib_get.mac_rmt_state; 21578c2ecf20Sopenharmony_ci bp->stats.mac_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_da_flag; 21588c2ecf20Sopenharmony_ci bp->stats.mac_una_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_unda_flag; 21598c2ecf20Sopenharmony_ci bp->stats.mac_frame_error_flag = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_flag; 21608c2ecf20Sopenharmony_ci bp->stats.mac_ma_unitdata_available = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_available; 21618c2ecf20Sopenharmony_ci bp->stats.mac_hardware_present = bp->cmd_rsp_virt->smt_mib_get.mac_hardware_present; 21628c2ecf20Sopenharmony_ci bp->stats.mac_ma_unitdata_enable = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_enable; 21638c2ecf20Sopenharmony_ci bp->stats.path_tvx_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_tvx_lower_bound; 21648c2ecf20Sopenharmony_ci bp->stats.path_t_max_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_t_max_lower_bound; 21658c2ecf20Sopenharmony_ci bp->stats.path_max_t_req = bp->cmd_rsp_virt->smt_mib_get.path_max_t_req; 21668c2ecf20Sopenharmony_ci memcpy(bp->stats.path_configuration, &bp->cmd_rsp_virt->smt_mib_get.path_configuration, sizeof(bp->cmd_rsp_virt->smt_mib_get.path_configuration)); 21678c2ecf20Sopenharmony_ci bp->stats.port_my_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[0]; 21688c2ecf20Sopenharmony_ci bp->stats.port_my_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[1]; 21698c2ecf20Sopenharmony_ci bp->stats.port_neighbor_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[0]; 21708c2ecf20Sopenharmony_ci bp->stats.port_neighbor_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[1]; 21718c2ecf20Sopenharmony_ci bp->stats.port_connection_policies[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[0]; 21728c2ecf20Sopenharmony_ci bp->stats.port_connection_policies[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[1]; 21738c2ecf20Sopenharmony_ci bp->stats.port_mac_indicated[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[0]; 21748c2ecf20Sopenharmony_ci bp->stats.port_mac_indicated[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[1]; 21758c2ecf20Sopenharmony_ci bp->stats.port_current_path[0] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[0]; 21768c2ecf20Sopenharmony_ci bp->stats.port_current_path[1] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[1]; 21778c2ecf20Sopenharmony_ci memcpy(&bp->stats.port_requested_paths[0*3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[0], 3); 21788c2ecf20Sopenharmony_ci memcpy(&bp->stats.port_requested_paths[1*3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[1], 3); 21798c2ecf20Sopenharmony_ci bp->stats.port_mac_placement[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[0]; 21808c2ecf20Sopenharmony_ci bp->stats.port_mac_placement[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[1]; 21818c2ecf20Sopenharmony_ci bp->stats.port_available_paths[0] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[0]; 21828c2ecf20Sopenharmony_ci bp->stats.port_available_paths[1] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[1]; 21838c2ecf20Sopenharmony_ci bp->stats.port_pmd_class[0] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[0]; 21848c2ecf20Sopenharmony_ci bp->stats.port_pmd_class[1] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[1]; 21858c2ecf20Sopenharmony_ci bp->stats.port_connection_capabilities[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[0]; 21868c2ecf20Sopenharmony_ci bp->stats.port_connection_capabilities[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[1]; 21878c2ecf20Sopenharmony_ci bp->stats.port_bs_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[0]; 21888c2ecf20Sopenharmony_ci bp->stats.port_bs_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[1]; 21898c2ecf20Sopenharmony_ci bp->stats.port_ler_estimate[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[0]; 21908c2ecf20Sopenharmony_ci bp->stats.port_ler_estimate[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[1]; 21918c2ecf20Sopenharmony_ci bp->stats.port_ler_cutoff[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[0]; 21928c2ecf20Sopenharmony_ci bp->stats.port_ler_cutoff[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[1]; 21938c2ecf20Sopenharmony_ci bp->stats.port_ler_alarm[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[0]; 21948c2ecf20Sopenharmony_ci bp->stats.port_ler_alarm[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[1]; 21958c2ecf20Sopenharmony_ci bp->stats.port_connect_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[0]; 21968c2ecf20Sopenharmony_ci bp->stats.port_connect_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[1]; 21978c2ecf20Sopenharmony_ci bp->stats.port_pcm_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[0]; 21988c2ecf20Sopenharmony_ci bp->stats.port_pcm_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[1]; 21998c2ecf20Sopenharmony_ci bp->stats.port_pc_withhold[0] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[0]; 22008c2ecf20Sopenharmony_ci bp->stats.port_pc_withhold[1] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[1]; 22018c2ecf20Sopenharmony_ci bp->stats.port_ler_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[0]; 22028c2ecf20Sopenharmony_ci bp->stats.port_ler_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[1]; 22038c2ecf20Sopenharmony_ci bp->stats.port_hardware_present[0] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[0]; 22048c2ecf20Sopenharmony_ci bp->stats.port_hardware_present[1] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[1]; 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci /* Get FDDI counters */ 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci bp->cmd_req_virt->cmd_type = PI_CMD_K_CNTRS_GET; 22098c2ecf20Sopenharmony_ci if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) 22108c2ecf20Sopenharmony_ci return (struct net_device_stats *)&bp->stats; 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci /* Fill the bp->stats structure with the FDDI counter values */ 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci bp->stats.mac_frame_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.frame_cnt.ls; 22158c2ecf20Sopenharmony_ci bp->stats.mac_copied_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.copied_cnt.ls; 22168c2ecf20Sopenharmony_ci bp->stats.mac_transmit_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.transmit_cnt.ls; 22178c2ecf20Sopenharmony_ci bp->stats.mac_error_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.error_cnt.ls; 22188c2ecf20Sopenharmony_ci bp->stats.mac_lost_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.lost_cnt.ls; 22198c2ecf20Sopenharmony_ci bp->stats.port_lct_fail_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[0].ls; 22208c2ecf20Sopenharmony_ci bp->stats.port_lct_fail_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[1].ls; 22218c2ecf20Sopenharmony_ci bp->stats.port_lem_reject_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[0].ls; 22228c2ecf20Sopenharmony_ci bp->stats.port_lem_reject_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[1].ls; 22238c2ecf20Sopenharmony_ci bp->stats.port_lem_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[0].ls; 22248c2ecf20Sopenharmony_ci bp->stats.port_lem_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[1].ls; 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci return (struct net_device_stats *)&bp->stats; 22278c2ecf20Sopenharmony_ci } 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci/* 22318c2ecf20Sopenharmony_ci * ============================== 22328c2ecf20Sopenharmony_ci * = dfx_ctl_set_multicast_list = 22338c2ecf20Sopenharmony_ci * ============================== 22348c2ecf20Sopenharmony_ci * 22358c2ecf20Sopenharmony_ci * Overview: 22368c2ecf20Sopenharmony_ci * Enable/Disable LLC frame promiscuous mode reception 22378c2ecf20Sopenharmony_ci * on the adapter and/or update multicast address table. 22388c2ecf20Sopenharmony_ci * 22398c2ecf20Sopenharmony_ci * Returns: 22408c2ecf20Sopenharmony_ci * None 22418c2ecf20Sopenharmony_ci * 22428c2ecf20Sopenharmony_ci * Arguments: 22438c2ecf20Sopenharmony_ci * dev - pointer to device information 22448c2ecf20Sopenharmony_ci * 22458c2ecf20Sopenharmony_ci * Functional Description: 22468c2ecf20Sopenharmony_ci * This routine follows a fairly simple algorithm for setting the 22478c2ecf20Sopenharmony_ci * adapter filters and CAM: 22488c2ecf20Sopenharmony_ci * 22498c2ecf20Sopenharmony_ci * if IFF_PROMISC flag is set 22508c2ecf20Sopenharmony_ci * enable LLC individual/group promiscuous mode 22518c2ecf20Sopenharmony_ci * else 22528c2ecf20Sopenharmony_ci * disable LLC individual/group promiscuous mode 22538c2ecf20Sopenharmony_ci * if number of incoming multicast addresses > 22548c2ecf20Sopenharmony_ci * (CAM max size - number of unicast addresses in CAM) 22558c2ecf20Sopenharmony_ci * enable LLC group promiscuous mode 22568c2ecf20Sopenharmony_ci * set driver-maintained multicast address count to zero 22578c2ecf20Sopenharmony_ci * else 22588c2ecf20Sopenharmony_ci * disable LLC group promiscuous mode 22598c2ecf20Sopenharmony_ci * set driver-maintained multicast address count to incoming count 22608c2ecf20Sopenharmony_ci * update adapter CAM 22618c2ecf20Sopenharmony_ci * update adapter filters 22628c2ecf20Sopenharmony_ci * 22638c2ecf20Sopenharmony_ci * Return Codes: 22648c2ecf20Sopenharmony_ci * None 22658c2ecf20Sopenharmony_ci * 22668c2ecf20Sopenharmony_ci * Assumptions: 22678c2ecf20Sopenharmony_ci * Multicast addresses are presented in canonical (LSB) format. 22688c2ecf20Sopenharmony_ci * 22698c2ecf20Sopenharmony_ci * Side Effects: 22708c2ecf20Sopenharmony_ci * On-board adapter CAM and filters are updated. 22718c2ecf20Sopenharmony_ci */ 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_cistatic void dfx_ctl_set_multicast_list(struct net_device *dev) 22748c2ecf20Sopenharmony_ci{ 22758c2ecf20Sopenharmony_ci DFX_board_t *bp = netdev_priv(dev); 22768c2ecf20Sopenharmony_ci int i; /* used as index in for loop */ 22778c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci /* Enable LLC frame promiscuous mode, if necessary */ 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci if (dev->flags & IFF_PROMISC) 22828c2ecf20Sopenharmony_ci bp->ind_group_prom = PI_FSTATE_K_PASS; /* Enable LLC ind/group prom mode */ 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci /* Else, update multicast address table */ 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci else 22878c2ecf20Sopenharmony_ci { 22888c2ecf20Sopenharmony_ci bp->ind_group_prom = PI_FSTATE_K_BLOCK; /* Disable LLC ind/group prom mode */ 22898c2ecf20Sopenharmony_ci /* 22908c2ecf20Sopenharmony_ci * Check whether incoming multicast address count exceeds table size 22918c2ecf20Sopenharmony_ci * 22928c2ecf20Sopenharmony_ci * Note: The adapters utilize an on-board 64 entry CAM for 22938c2ecf20Sopenharmony_ci * supporting perfect filtering of multicast packets 22948c2ecf20Sopenharmony_ci * and bridge functions when adding unicast addresses. 22958c2ecf20Sopenharmony_ci * There is no hash function available. To support 22968c2ecf20Sopenharmony_ci * additional multicast addresses, the all multicast 22978c2ecf20Sopenharmony_ci * filter (LLC group promiscuous mode) must be enabled. 22988c2ecf20Sopenharmony_ci * 22998c2ecf20Sopenharmony_ci * The firmware reserves two CAM entries for SMT-related 23008c2ecf20Sopenharmony_ci * multicast addresses, which leaves 62 entries available. 23018c2ecf20Sopenharmony_ci * The following code ensures that we're not being asked 23028c2ecf20Sopenharmony_ci * to add more than 62 addresses to the CAM. If we are, 23038c2ecf20Sopenharmony_ci * the driver will enable the all multicast filter. 23048c2ecf20Sopenharmony_ci * Should the number of multicast addresses drop below 23058c2ecf20Sopenharmony_ci * the high water mark, the filter will be disabled and 23068c2ecf20Sopenharmony_ci * perfect filtering will be used. 23078c2ecf20Sopenharmony_ci */ 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci if (netdev_mc_count(dev) > (PI_CMD_ADDR_FILTER_K_SIZE - bp->uc_count)) 23108c2ecf20Sopenharmony_ci { 23118c2ecf20Sopenharmony_ci bp->group_prom = PI_FSTATE_K_PASS; /* Enable LLC group prom mode */ 23128c2ecf20Sopenharmony_ci bp->mc_count = 0; /* Don't add mc addrs to CAM */ 23138c2ecf20Sopenharmony_ci } 23148c2ecf20Sopenharmony_ci else 23158c2ecf20Sopenharmony_ci { 23168c2ecf20Sopenharmony_ci bp->group_prom = PI_FSTATE_K_BLOCK; /* Disable LLC group prom mode */ 23178c2ecf20Sopenharmony_ci bp->mc_count = netdev_mc_count(dev); /* Add mc addrs to CAM */ 23188c2ecf20Sopenharmony_ci } 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci /* Copy addresses to multicast address table, then update adapter CAM */ 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci i = 0; 23238c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) 23248c2ecf20Sopenharmony_ci memcpy(&bp->mc_table[i++ * FDDI_K_ALEN], 23258c2ecf20Sopenharmony_ci ha->addr, FDDI_K_ALEN); 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS) 23288c2ecf20Sopenharmony_ci { 23298c2ecf20Sopenharmony_ci DBG_printk("%s: Could not update multicast address table!\n", dev->name); 23308c2ecf20Sopenharmony_ci } 23318c2ecf20Sopenharmony_ci else 23328c2ecf20Sopenharmony_ci { 23338c2ecf20Sopenharmony_ci DBG_printk("%s: Multicast address table updated! Added %d addresses.\n", dev->name, bp->mc_count); 23348c2ecf20Sopenharmony_ci } 23358c2ecf20Sopenharmony_ci } 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci /* Update adapter filters */ 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS) 23408c2ecf20Sopenharmony_ci { 23418c2ecf20Sopenharmony_ci DBG_printk("%s: Could not update adapter filters!\n", dev->name); 23428c2ecf20Sopenharmony_ci } 23438c2ecf20Sopenharmony_ci else 23448c2ecf20Sopenharmony_ci { 23458c2ecf20Sopenharmony_ci DBG_printk("%s: Adapter filters updated!\n", dev->name); 23468c2ecf20Sopenharmony_ci } 23478c2ecf20Sopenharmony_ci } 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci/* 23518c2ecf20Sopenharmony_ci * =========================== 23528c2ecf20Sopenharmony_ci * = dfx_ctl_set_mac_address = 23538c2ecf20Sopenharmony_ci * =========================== 23548c2ecf20Sopenharmony_ci * 23558c2ecf20Sopenharmony_ci * Overview: 23568c2ecf20Sopenharmony_ci * Add node address override (unicast address) to adapter 23578c2ecf20Sopenharmony_ci * CAM and update dev_addr field in device table. 23588c2ecf20Sopenharmony_ci * 23598c2ecf20Sopenharmony_ci * Returns: 23608c2ecf20Sopenharmony_ci * None 23618c2ecf20Sopenharmony_ci * 23628c2ecf20Sopenharmony_ci * Arguments: 23638c2ecf20Sopenharmony_ci * dev - pointer to device information 23648c2ecf20Sopenharmony_ci * addr - pointer to sockaddr structure containing unicast address to add 23658c2ecf20Sopenharmony_ci * 23668c2ecf20Sopenharmony_ci * Functional Description: 23678c2ecf20Sopenharmony_ci * The adapter supports node address overrides by adding one or more 23688c2ecf20Sopenharmony_ci * unicast addresses to the adapter CAM. This is similar to adding 23698c2ecf20Sopenharmony_ci * multicast addresses. In this routine we'll update the driver and 23708c2ecf20Sopenharmony_ci * device structures with the new address, then update the adapter CAM 23718c2ecf20Sopenharmony_ci * to ensure that the adapter will copy and strip frames destined and 23728c2ecf20Sopenharmony_ci * sourced by that address. 23738c2ecf20Sopenharmony_ci * 23748c2ecf20Sopenharmony_ci * Return Codes: 23758c2ecf20Sopenharmony_ci * Always returns zero. 23768c2ecf20Sopenharmony_ci * 23778c2ecf20Sopenharmony_ci * Assumptions: 23788c2ecf20Sopenharmony_ci * The address pointed to by addr->sa_data is a valid unicast 23798c2ecf20Sopenharmony_ci * address and is presented in canonical (LSB) format. 23808c2ecf20Sopenharmony_ci * 23818c2ecf20Sopenharmony_ci * Side Effects: 23828c2ecf20Sopenharmony_ci * On-board adapter CAM is updated. On-board adapter filters 23838c2ecf20Sopenharmony_ci * may be updated. 23848c2ecf20Sopenharmony_ci */ 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_cistatic int dfx_ctl_set_mac_address(struct net_device *dev, void *addr) 23878c2ecf20Sopenharmony_ci { 23888c2ecf20Sopenharmony_ci struct sockaddr *p_sockaddr = (struct sockaddr *)addr; 23898c2ecf20Sopenharmony_ci DFX_board_t *bp = netdev_priv(dev); 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci /* Copy unicast address to driver-maintained structs and update count */ 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, p_sockaddr->sa_data, FDDI_K_ALEN); /* update device struct */ 23948c2ecf20Sopenharmony_ci memcpy(&bp->uc_table[0], p_sockaddr->sa_data, FDDI_K_ALEN); /* update driver struct */ 23958c2ecf20Sopenharmony_ci bp->uc_count = 1; 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci /* 23988c2ecf20Sopenharmony_ci * Verify we're not exceeding the CAM size by adding unicast address 23998c2ecf20Sopenharmony_ci * 24008c2ecf20Sopenharmony_ci * Note: It's possible that before entering this routine we've 24018c2ecf20Sopenharmony_ci * already filled the CAM with 62 multicast addresses. 24028c2ecf20Sopenharmony_ci * Since we need to place the node address override into 24038c2ecf20Sopenharmony_ci * the CAM, we have to check to see that we're not 24048c2ecf20Sopenharmony_ci * exceeding the CAM size. If we are, we have to enable 24058c2ecf20Sopenharmony_ci * the LLC group (multicast) promiscuous mode filter as 24068c2ecf20Sopenharmony_ci * in dfx_ctl_set_multicast_list. 24078c2ecf20Sopenharmony_ci */ 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci if ((bp->uc_count + bp->mc_count) > PI_CMD_ADDR_FILTER_K_SIZE) 24108c2ecf20Sopenharmony_ci { 24118c2ecf20Sopenharmony_ci bp->group_prom = PI_FSTATE_K_PASS; /* Enable LLC group prom mode */ 24128c2ecf20Sopenharmony_ci bp->mc_count = 0; /* Don't add mc addrs to CAM */ 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci /* Update adapter filters */ 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci if (dfx_ctl_update_filters(bp) != DFX_K_SUCCESS) 24178c2ecf20Sopenharmony_ci { 24188c2ecf20Sopenharmony_ci DBG_printk("%s: Could not update adapter filters!\n", dev->name); 24198c2ecf20Sopenharmony_ci } 24208c2ecf20Sopenharmony_ci else 24218c2ecf20Sopenharmony_ci { 24228c2ecf20Sopenharmony_ci DBG_printk("%s: Adapter filters updated!\n", dev->name); 24238c2ecf20Sopenharmony_ci } 24248c2ecf20Sopenharmony_ci } 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci /* Update adapter CAM with new unicast address */ 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS) 24298c2ecf20Sopenharmony_ci { 24308c2ecf20Sopenharmony_ci DBG_printk("%s: Could not set new MAC address!\n", dev->name); 24318c2ecf20Sopenharmony_ci } 24328c2ecf20Sopenharmony_ci else 24338c2ecf20Sopenharmony_ci { 24348c2ecf20Sopenharmony_ci DBG_printk("%s: Adapter CAM updated with new MAC address\n", dev->name); 24358c2ecf20Sopenharmony_ci } 24368c2ecf20Sopenharmony_ci return 0; /* always return zero */ 24378c2ecf20Sopenharmony_ci } 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci/* 24418c2ecf20Sopenharmony_ci * ====================== 24428c2ecf20Sopenharmony_ci * = dfx_ctl_update_cam = 24438c2ecf20Sopenharmony_ci * ====================== 24448c2ecf20Sopenharmony_ci * 24458c2ecf20Sopenharmony_ci * Overview: 24468c2ecf20Sopenharmony_ci * Procedure to update adapter CAM (Content Addressable Memory) 24478c2ecf20Sopenharmony_ci * with desired unicast and multicast address entries. 24488c2ecf20Sopenharmony_ci * 24498c2ecf20Sopenharmony_ci * Returns: 24508c2ecf20Sopenharmony_ci * Condition code 24518c2ecf20Sopenharmony_ci * 24528c2ecf20Sopenharmony_ci * Arguments: 24538c2ecf20Sopenharmony_ci * bp - pointer to board information 24548c2ecf20Sopenharmony_ci * 24558c2ecf20Sopenharmony_ci * Functional Description: 24568c2ecf20Sopenharmony_ci * Updates adapter CAM with current contents of board structure 24578c2ecf20Sopenharmony_ci * unicast and multicast address tables. Since there are only 62 24588c2ecf20Sopenharmony_ci * free entries in CAM, this routine ensures that the command 24598c2ecf20Sopenharmony_ci * request buffer is not overrun. 24608c2ecf20Sopenharmony_ci * 24618c2ecf20Sopenharmony_ci * Return Codes: 24628c2ecf20Sopenharmony_ci * DFX_K_SUCCESS - Request succeeded 24638c2ecf20Sopenharmony_ci * DFX_K_FAILURE - Request failed 24648c2ecf20Sopenharmony_ci * 24658c2ecf20Sopenharmony_ci * Assumptions: 24668c2ecf20Sopenharmony_ci * All addresses being added (unicast and multicast) are in canonical 24678c2ecf20Sopenharmony_ci * order. 24688c2ecf20Sopenharmony_ci * 24698c2ecf20Sopenharmony_ci * Side Effects: 24708c2ecf20Sopenharmony_ci * On-board adapter CAM is updated. 24718c2ecf20Sopenharmony_ci */ 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_cistatic int dfx_ctl_update_cam(DFX_board_t *bp) 24748c2ecf20Sopenharmony_ci { 24758c2ecf20Sopenharmony_ci int i; /* used as index */ 24768c2ecf20Sopenharmony_ci PI_LAN_ADDR *p_addr; /* pointer to CAM entry */ 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci /* 24798c2ecf20Sopenharmony_ci * Fill in command request information 24808c2ecf20Sopenharmony_ci * 24818c2ecf20Sopenharmony_ci * Note: Even though both the unicast and multicast address 24828c2ecf20Sopenharmony_ci * table entries are stored as contiguous 6 byte entries, 24838c2ecf20Sopenharmony_ci * the firmware address filter set command expects each 24848c2ecf20Sopenharmony_ci * entry to be two longwords (8 bytes total). We must be 24858c2ecf20Sopenharmony_ci * careful to only copy the six bytes of each unicast and 24868c2ecf20Sopenharmony_ci * multicast table entry into each command entry. This 24878c2ecf20Sopenharmony_ci * is also why we must first clear the entire command 24888c2ecf20Sopenharmony_ci * request buffer. 24898c2ecf20Sopenharmony_ci */ 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci memset(bp->cmd_req_virt, 0, PI_CMD_REQ_K_SIZE_MAX); /* first clear buffer */ 24928c2ecf20Sopenharmony_ci bp->cmd_req_virt->cmd_type = PI_CMD_K_ADDR_FILTER_SET; 24938c2ecf20Sopenharmony_ci p_addr = &bp->cmd_req_virt->addr_filter_set.entry[0]; 24948c2ecf20Sopenharmony_ci 24958c2ecf20Sopenharmony_ci /* Now add unicast addresses to command request buffer, if any */ 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci for (i=0; i < (int)bp->uc_count; i++) 24988c2ecf20Sopenharmony_ci { 24998c2ecf20Sopenharmony_ci if (i < PI_CMD_ADDR_FILTER_K_SIZE) 25008c2ecf20Sopenharmony_ci { 25018c2ecf20Sopenharmony_ci memcpy(p_addr, &bp->uc_table[i*FDDI_K_ALEN], FDDI_K_ALEN); 25028c2ecf20Sopenharmony_ci p_addr++; /* point to next command entry */ 25038c2ecf20Sopenharmony_ci } 25048c2ecf20Sopenharmony_ci } 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_ci /* Now add multicast addresses to command request buffer, if any */ 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci for (i=0; i < (int)bp->mc_count; i++) 25098c2ecf20Sopenharmony_ci { 25108c2ecf20Sopenharmony_ci if ((i + bp->uc_count) < PI_CMD_ADDR_FILTER_K_SIZE) 25118c2ecf20Sopenharmony_ci { 25128c2ecf20Sopenharmony_ci memcpy(p_addr, &bp->mc_table[i*FDDI_K_ALEN], FDDI_K_ALEN); 25138c2ecf20Sopenharmony_ci p_addr++; /* point to next command entry */ 25148c2ecf20Sopenharmony_ci } 25158c2ecf20Sopenharmony_ci } 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ci /* Issue command to update adapter CAM, then return */ 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_ci if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) 25208c2ecf20Sopenharmony_ci return DFX_K_FAILURE; 25218c2ecf20Sopenharmony_ci return DFX_K_SUCCESS; 25228c2ecf20Sopenharmony_ci } 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci/* 25268c2ecf20Sopenharmony_ci * ========================== 25278c2ecf20Sopenharmony_ci * = dfx_ctl_update_filters = 25288c2ecf20Sopenharmony_ci * ========================== 25298c2ecf20Sopenharmony_ci * 25308c2ecf20Sopenharmony_ci * Overview: 25318c2ecf20Sopenharmony_ci * Procedure to update adapter filters with desired 25328c2ecf20Sopenharmony_ci * filter settings. 25338c2ecf20Sopenharmony_ci * 25348c2ecf20Sopenharmony_ci * Returns: 25358c2ecf20Sopenharmony_ci * Condition code 25368c2ecf20Sopenharmony_ci * 25378c2ecf20Sopenharmony_ci * Arguments: 25388c2ecf20Sopenharmony_ci * bp - pointer to board information 25398c2ecf20Sopenharmony_ci * 25408c2ecf20Sopenharmony_ci * Functional Description: 25418c2ecf20Sopenharmony_ci * Enables or disables filter using current filter settings. 25428c2ecf20Sopenharmony_ci * 25438c2ecf20Sopenharmony_ci * Return Codes: 25448c2ecf20Sopenharmony_ci * DFX_K_SUCCESS - Request succeeded. 25458c2ecf20Sopenharmony_ci * DFX_K_FAILURE - Request failed. 25468c2ecf20Sopenharmony_ci * 25478c2ecf20Sopenharmony_ci * Assumptions: 25488c2ecf20Sopenharmony_ci * We must always pass up packets destined to the broadcast 25498c2ecf20Sopenharmony_ci * address (FF-FF-FF-FF-FF-FF), so we'll always keep the 25508c2ecf20Sopenharmony_ci * broadcast filter enabled. 25518c2ecf20Sopenharmony_ci * 25528c2ecf20Sopenharmony_ci * Side Effects: 25538c2ecf20Sopenharmony_ci * On-board adapter filters are updated. 25548c2ecf20Sopenharmony_ci */ 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_cistatic int dfx_ctl_update_filters(DFX_board_t *bp) 25578c2ecf20Sopenharmony_ci { 25588c2ecf20Sopenharmony_ci int i = 0; /* used as index */ 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci /* Fill in command request information */ 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ci bp->cmd_req_virt->cmd_type = PI_CMD_K_FILTERS_SET; 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci /* Initialize Broadcast filter - * ALWAYS ENABLED * */ 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ci bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_BROADCAST; 25678c2ecf20Sopenharmony_ci bp->cmd_req_virt->filter_set.item[i++].value = PI_FSTATE_K_PASS; 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_ci /* Initialize LLC Individual/Group Promiscuous filter */ 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_IND_GROUP_PROM; 25728c2ecf20Sopenharmony_ci bp->cmd_req_virt->filter_set.item[i++].value = bp->ind_group_prom; 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci /* Initialize LLC Group Promiscuous filter */ 25758c2ecf20Sopenharmony_ci 25768c2ecf20Sopenharmony_ci bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_GROUP_PROM; 25778c2ecf20Sopenharmony_ci bp->cmd_req_virt->filter_set.item[i++].value = bp->group_prom; 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci /* Terminate the item code list */ 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci bp->cmd_req_virt->filter_set.item[i].item_code = PI_ITEM_K_EOL; 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci /* Issue command to update adapter filters, then return */ 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) 25868c2ecf20Sopenharmony_ci return DFX_K_FAILURE; 25878c2ecf20Sopenharmony_ci return DFX_K_SUCCESS; 25888c2ecf20Sopenharmony_ci } 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci/* 25928c2ecf20Sopenharmony_ci * ====================== 25938c2ecf20Sopenharmony_ci * = dfx_hw_dma_cmd_req = 25948c2ecf20Sopenharmony_ci * ====================== 25958c2ecf20Sopenharmony_ci * 25968c2ecf20Sopenharmony_ci * Overview: 25978c2ecf20Sopenharmony_ci * Sends PDQ DMA command to adapter firmware 25988c2ecf20Sopenharmony_ci * 25998c2ecf20Sopenharmony_ci * Returns: 26008c2ecf20Sopenharmony_ci * Condition code 26018c2ecf20Sopenharmony_ci * 26028c2ecf20Sopenharmony_ci * Arguments: 26038c2ecf20Sopenharmony_ci * bp - pointer to board information 26048c2ecf20Sopenharmony_ci * 26058c2ecf20Sopenharmony_ci * Functional Description: 26068c2ecf20Sopenharmony_ci * The command request and response buffers are posted to the adapter in the manner 26078c2ecf20Sopenharmony_ci * described in the PDQ Port Specification: 26088c2ecf20Sopenharmony_ci * 26098c2ecf20Sopenharmony_ci * 1. Command Response Buffer is posted to adapter. 26108c2ecf20Sopenharmony_ci * 2. Command Request Buffer is posted to adapter. 26118c2ecf20Sopenharmony_ci * 3. Command Request consumer index is polled until it indicates that request 26128c2ecf20Sopenharmony_ci * buffer has been DMA'd to adapter. 26138c2ecf20Sopenharmony_ci * 4. Command Response consumer index is polled until it indicates that response 26148c2ecf20Sopenharmony_ci * buffer has been DMA'd from adapter. 26158c2ecf20Sopenharmony_ci * 26168c2ecf20Sopenharmony_ci * This ordering ensures that a response buffer is already available for the firmware 26178c2ecf20Sopenharmony_ci * to use once it's done processing the request buffer. 26188c2ecf20Sopenharmony_ci * 26198c2ecf20Sopenharmony_ci * Return Codes: 26208c2ecf20Sopenharmony_ci * DFX_K_SUCCESS - DMA command succeeded 26218c2ecf20Sopenharmony_ci * DFX_K_OUTSTATE - Adapter is NOT in proper state 26228c2ecf20Sopenharmony_ci * DFX_K_HW_TIMEOUT - DMA command timed out 26238c2ecf20Sopenharmony_ci * 26248c2ecf20Sopenharmony_ci * Assumptions: 26258c2ecf20Sopenharmony_ci * Command request buffer has already been filled with desired DMA command. 26268c2ecf20Sopenharmony_ci * 26278c2ecf20Sopenharmony_ci * Side Effects: 26288c2ecf20Sopenharmony_ci * None 26298c2ecf20Sopenharmony_ci */ 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_cistatic int dfx_hw_dma_cmd_req(DFX_board_t *bp) 26328c2ecf20Sopenharmony_ci { 26338c2ecf20Sopenharmony_ci int status; /* adapter status */ 26348c2ecf20Sopenharmony_ci int timeout_cnt; /* used in for loops */ 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_ci /* Make sure the adapter is in a state that we can issue the DMA command in */ 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci status = dfx_hw_adap_state_rd(bp); 26398c2ecf20Sopenharmony_ci if ((status == PI_STATE_K_RESET) || 26408c2ecf20Sopenharmony_ci (status == PI_STATE_K_HALTED) || 26418c2ecf20Sopenharmony_ci (status == PI_STATE_K_DMA_UNAVAIL) || 26428c2ecf20Sopenharmony_ci (status == PI_STATE_K_UPGRADE)) 26438c2ecf20Sopenharmony_ci return DFX_K_OUTSTATE; 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci /* Put response buffer on the command response queue */ 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_ci bp->descr_block_virt->cmd_rsp[bp->cmd_rsp_reg.index.prod].long_0 = (u32) (PI_RCV_DESCR_M_SOP | 26488c2ecf20Sopenharmony_ci ((PI_CMD_RSP_K_SIZE_MAX / PI_ALIGN_K_CMD_RSP_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); 26498c2ecf20Sopenharmony_ci bp->descr_block_virt->cmd_rsp[bp->cmd_rsp_reg.index.prod].long_1 = bp->cmd_rsp_phys; 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci /* Bump (and wrap) the producer index and write out to register */ 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_ci bp->cmd_rsp_reg.index.prod += 1; 26548c2ecf20Sopenharmony_ci bp->cmd_rsp_reg.index.prod &= PI_CMD_RSP_K_NUM_ENTRIES-1; 26558c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_RSP_PROD, bp->cmd_rsp_reg.lword); 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_ci /* Put request buffer on the command request queue */ 26588c2ecf20Sopenharmony_ci 26598c2ecf20Sopenharmony_ci bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_0 = (u32) (PI_XMT_DESCR_M_SOP | 26608c2ecf20Sopenharmony_ci PI_XMT_DESCR_M_EOP | (PI_CMD_REQ_K_SIZE_MAX << PI_XMT_DESCR_V_SEG_LEN)); 26618c2ecf20Sopenharmony_ci bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_1 = bp->cmd_req_phys; 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_ci /* Bump (and wrap) the producer index and write out to register */ 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci bp->cmd_req_reg.index.prod += 1; 26668c2ecf20Sopenharmony_ci bp->cmd_req_reg.index.prod &= PI_CMD_REQ_K_NUM_ENTRIES-1; 26678c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_REQ_PROD, bp->cmd_req_reg.lword); 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_ci /* 26708c2ecf20Sopenharmony_ci * Here we wait for the command request consumer index to be equal 26718c2ecf20Sopenharmony_ci * to the producer, indicating that the adapter has DMAed the request. 26728c2ecf20Sopenharmony_ci */ 26738c2ecf20Sopenharmony_ci 26748c2ecf20Sopenharmony_ci for (timeout_cnt = 20000; timeout_cnt > 0; timeout_cnt--) 26758c2ecf20Sopenharmony_ci { 26768c2ecf20Sopenharmony_ci if (bp->cmd_req_reg.index.prod == (u8)(bp->cons_block_virt->cmd_req)) 26778c2ecf20Sopenharmony_ci break; 26788c2ecf20Sopenharmony_ci udelay(100); /* wait for 100 microseconds */ 26798c2ecf20Sopenharmony_ci } 26808c2ecf20Sopenharmony_ci if (timeout_cnt == 0) 26818c2ecf20Sopenharmony_ci return DFX_K_HW_TIMEOUT; 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci /* Bump (and wrap) the completion index and write out to register */ 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci bp->cmd_req_reg.index.comp += 1; 26868c2ecf20Sopenharmony_ci bp->cmd_req_reg.index.comp &= PI_CMD_REQ_K_NUM_ENTRIES-1; 26878c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_REQ_PROD, bp->cmd_req_reg.lword); 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_ci /* 26908c2ecf20Sopenharmony_ci * Here we wait for the command response consumer index to be equal 26918c2ecf20Sopenharmony_ci * to the producer, indicating that the adapter has DMAed the response. 26928c2ecf20Sopenharmony_ci */ 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci for (timeout_cnt = 20000; timeout_cnt > 0; timeout_cnt--) 26958c2ecf20Sopenharmony_ci { 26968c2ecf20Sopenharmony_ci if (bp->cmd_rsp_reg.index.prod == (u8)(bp->cons_block_virt->cmd_rsp)) 26978c2ecf20Sopenharmony_ci break; 26988c2ecf20Sopenharmony_ci udelay(100); /* wait for 100 microseconds */ 26998c2ecf20Sopenharmony_ci } 27008c2ecf20Sopenharmony_ci if (timeout_cnt == 0) 27018c2ecf20Sopenharmony_ci return DFX_K_HW_TIMEOUT; 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_ci /* Bump (and wrap) the completion index and write out to register */ 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ci bp->cmd_rsp_reg.index.comp += 1; 27068c2ecf20Sopenharmony_ci bp->cmd_rsp_reg.index.comp &= PI_CMD_RSP_K_NUM_ENTRIES-1; 27078c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_RSP_PROD, bp->cmd_rsp_reg.lword); 27088c2ecf20Sopenharmony_ci return DFX_K_SUCCESS; 27098c2ecf20Sopenharmony_ci } 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci 27128c2ecf20Sopenharmony_ci/* 27138c2ecf20Sopenharmony_ci * ======================== 27148c2ecf20Sopenharmony_ci * = dfx_hw_port_ctrl_req = 27158c2ecf20Sopenharmony_ci * ======================== 27168c2ecf20Sopenharmony_ci * 27178c2ecf20Sopenharmony_ci * Overview: 27188c2ecf20Sopenharmony_ci * Sends PDQ port control command to adapter firmware 27198c2ecf20Sopenharmony_ci * 27208c2ecf20Sopenharmony_ci * Returns: 27218c2ecf20Sopenharmony_ci * Host data register value in host_data if ptr is not NULL 27228c2ecf20Sopenharmony_ci * 27238c2ecf20Sopenharmony_ci * Arguments: 27248c2ecf20Sopenharmony_ci * bp - pointer to board information 27258c2ecf20Sopenharmony_ci * command - port control command 27268c2ecf20Sopenharmony_ci * data_a - port data A register value 27278c2ecf20Sopenharmony_ci * data_b - port data B register value 27288c2ecf20Sopenharmony_ci * host_data - ptr to host data register value 27298c2ecf20Sopenharmony_ci * 27308c2ecf20Sopenharmony_ci * Functional Description: 27318c2ecf20Sopenharmony_ci * Send generic port control command to adapter by writing 27328c2ecf20Sopenharmony_ci * to various PDQ port registers, then polling for completion. 27338c2ecf20Sopenharmony_ci * 27348c2ecf20Sopenharmony_ci * Return Codes: 27358c2ecf20Sopenharmony_ci * DFX_K_SUCCESS - port control command succeeded 27368c2ecf20Sopenharmony_ci * DFX_K_HW_TIMEOUT - port control command timed out 27378c2ecf20Sopenharmony_ci * 27388c2ecf20Sopenharmony_ci * Assumptions: 27398c2ecf20Sopenharmony_ci * None 27408c2ecf20Sopenharmony_ci * 27418c2ecf20Sopenharmony_ci * Side Effects: 27428c2ecf20Sopenharmony_ci * None 27438c2ecf20Sopenharmony_ci */ 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_cistatic int dfx_hw_port_ctrl_req( 27468c2ecf20Sopenharmony_ci DFX_board_t *bp, 27478c2ecf20Sopenharmony_ci PI_UINT32 command, 27488c2ecf20Sopenharmony_ci PI_UINT32 data_a, 27498c2ecf20Sopenharmony_ci PI_UINT32 data_b, 27508c2ecf20Sopenharmony_ci PI_UINT32 *host_data 27518c2ecf20Sopenharmony_ci ) 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci { 27548c2ecf20Sopenharmony_ci PI_UINT32 port_cmd; /* Port Control command register value */ 27558c2ecf20Sopenharmony_ci int timeout_cnt; /* used in for loops */ 27568c2ecf20Sopenharmony_ci 27578c2ecf20Sopenharmony_ci /* Set Command Error bit in command longword */ 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci port_cmd = (PI_UINT32) (command | PI_PCTRL_M_CMD_ERROR); 27608c2ecf20Sopenharmony_ci 27618c2ecf20Sopenharmony_ci /* Issue port command to the adapter */ 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_A, data_a); 27648c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_B, data_b); 27658c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_CTRL, port_cmd); 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci /* Now wait for command to complete */ 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci if (command == PI_PCTRL_M_BLAST_FLASH) 27708c2ecf20Sopenharmony_ci timeout_cnt = 600000; /* set command timeout count to 60 seconds */ 27718c2ecf20Sopenharmony_ci else 27728c2ecf20Sopenharmony_ci timeout_cnt = 20000; /* set command timeout count to 2 seconds */ 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci for (; timeout_cnt > 0; timeout_cnt--) 27758c2ecf20Sopenharmony_ci { 27768c2ecf20Sopenharmony_ci dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_CTRL, &port_cmd); 27778c2ecf20Sopenharmony_ci if (!(port_cmd & PI_PCTRL_M_CMD_ERROR)) 27788c2ecf20Sopenharmony_ci break; 27798c2ecf20Sopenharmony_ci udelay(100); /* wait for 100 microseconds */ 27808c2ecf20Sopenharmony_ci } 27818c2ecf20Sopenharmony_ci if (timeout_cnt == 0) 27828c2ecf20Sopenharmony_ci return DFX_K_HW_TIMEOUT; 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci /* 27858c2ecf20Sopenharmony_ci * If the address of host_data is non-zero, assume caller has supplied a 27868c2ecf20Sopenharmony_ci * non NULL pointer, and return the contents of the HOST_DATA register in 27878c2ecf20Sopenharmony_ci * it. 27888c2ecf20Sopenharmony_ci */ 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci if (host_data != NULL) 27918c2ecf20Sopenharmony_ci dfx_port_read_long(bp, PI_PDQ_K_REG_HOST_DATA, host_data); 27928c2ecf20Sopenharmony_ci return DFX_K_SUCCESS; 27938c2ecf20Sopenharmony_ci } 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_ci/* 27978c2ecf20Sopenharmony_ci * ===================== 27988c2ecf20Sopenharmony_ci * = dfx_hw_adap_reset = 27998c2ecf20Sopenharmony_ci * ===================== 28008c2ecf20Sopenharmony_ci * 28018c2ecf20Sopenharmony_ci * Overview: 28028c2ecf20Sopenharmony_ci * Resets adapter 28038c2ecf20Sopenharmony_ci * 28048c2ecf20Sopenharmony_ci * Returns: 28058c2ecf20Sopenharmony_ci * None 28068c2ecf20Sopenharmony_ci * 28078c2ecf20Sopenharmony_ci * Arguments: 28088c2ecf20Sopenharmony_ci * bp - pointer to board information 28098c2ecf20Sopenharmony_ci * type - type of reset to perform 28108c2ecf20Sopenharmony_ci * 28118c2ecf20Sopenharmony_ci * Functional Description: 28128c2ecf20Sopenharmony_ci * Issue soft reset to adapter by writing to PDQ Port Reset 28138c2ecf20Sopenharmony_ci * register. Use incoming reset type to tell adapter what 28148c2ecf20Sopenharmony_ci * kind of reset operation to perform. 28158c2ecf20Sopenharmony_ci * 28168c2ecf20Sopenharmony_ci * Return Codes: 28178c2ecf20Sopenharmony_ci * None 28188c2ecf20Sopenharmony_ci * 28198c2ecf20Sopenharmony_ci * Assumptions: 28208c2ecf20Sopenharmony_ci * This routine merely issues a soft reset to the adapter. 28218c2ecf20Sopenharmony_ci * It is expected that after this routine returns, the caller 28228c2ecf20Sopenharmony_ci * will appropriately poll the Port Status register for the 28238c2ecf20Sopenharmony_ci * adapter to enter the proper state. 28248c2ecf20Sopenharmony_ci * 28258c2ecf20Sopenharmony_ci * Side Effects: 28268c2ecf20Sopenharmony_ci * Internal adapter registers are cleared. 28278c2ecf20Sopenharmony_ci */ 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_cistatic void dfx_hw_adap_reset( 28308c2ecf20Sopenharmony_ci DFX_board_t *bp, 28318c2ecf20Sopenharmony_ci PI_UINT32 type 28328c2ecf20Sopenharmony_ci ) 28338c2ecf20Sopenharmony_ci 28348c2ecf20Sopenharmony_ci { 28358c2ecf20Sopenharmony_ci /* Set Reset type and assert reset */ 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_DATA_A, type); /* tell adapter type of reset */ 28388c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, PI_RESET_M_ASSERT_RESET); 28398c2ecf20Sopenharmony_ci 28408c2ecf20Sopenharmony_ci /* Wait for at least 1 Microsecond according to the spec. We wait 20 just to be safe */ 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_ci udelay(20); 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci /* Deassert reset */ 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, 0); 28478c2ecf20Sopenharmony_ci } 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci/* 28518c2ecf20Sopenharmony_ci * ======================== 28528c2ecf20Sopenharmony_ci * = dfx_hw_adap_state_rd = 28538c2ecf20Sopenharmony_ci * ======================== 28548c2ecf20Sopenharmony_ci * 28558c2ecf20Sopenharmony_ci * Overview: 28568c2ecf20Sopenharmony_ci * Returns current adapter state 28578c2ecf20Sopenharmony_ci * 28588c2ecf20Sopenharmony_ci * Returns: 28598c2ecf20Sopenharmony_ci * Adapter state per PDQ Port Specification 28608c2ecf20Sopenharmony_ci * 28618c2ecf20Sopenharmony_ci * Arguments: 28628c2ecf20Sopenharmony_ci * bp - pointer to board information 28638c2ecf20Sopenharmony_ci * 28648c2ecf20Sopenharmony_ci * Functional Description: 28658c2ecf20Sopenharmony_ci * Reads PDQ Port Status register and returns adapter state. 28668c2ecf20Sopenharmony_ci * 28678c2ecf20Sopenharmony_ci * Return Codes: 28688c2ecf20Sopenharmony_ci * None 28698c2ecf20Sopenharmony_ci * 28708c2ecf20Sopenharmony_ci * Assumptions: 28718c2ecf20Sopenharmony_ci * None 28728c2ecf20Sopenharmony_ci * 28738c2ecf20Sopenharmony_ci * Side Effects: 28748c2ecf20Sopenharmony_ci * None 28758c2ecf20Sopenharmony_ci */ 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_cistatic int dfx_hw_adap_state_rd(DFX_board_t *bp) 28788c2ecf20Sopenharmony_ci { 28798c2ecf20Sopenharmony_ci PI_UINT32 port_status; /* Port Status register value */ 28808c2ecf20Sopenharmony_ci 28818c2ecf20Sopenharmony_ci dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &port_status); 28828c2ecf20Sopenharmony_ci return (port_status & PI_PSTATUS_M_STATE) >> PI_PSTATUS_V_STATE; 28838c2ecf20Sopenharmony_ci } 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci/* 28878c2ecf20Sopenharmony_ci * ===================== 28888c2ecf20Sopenharmony_ci * = dfx_hw_dma_uninit = 28898c2ecf20Sopenharmony_ci * ===================== 28908c2ecf20Sopenharmony_ci * 28918c2ecf20Sopenharmony_ci * Overview: 28928c2ecf20Sopenharmony_ci * Brings adapter to DMA_UNAVAILABLE state 28938c2ecf20Sopenharmony_ci * 28948c2ecf20Sopenharmony_ci * Returns: 28958c2ecf20Sopenharmony_ci * Condition code 28968c2ecf20Sopenharmony_ci * 28978c2ecf20Sopenharmony_ci * Arguments: 28988c2ecf20Sopenharmony_ci * bp - pointer to board information 28998c2ecf20Sopenharmony_ci * type - type of reset to perform 29008c2ecf20Sopenharmony_ci * 29018c2ecf20Sopenharmony_ci * Functional Description: 29028c2ecf20Sopenharmony_ci * Bring adapter to DMA_UNAVAILABLE state by performing the following: 29038c2ecf20Sopenharmony_ci * 1. Set reset type bit in Port Data A Register then reset adapter. 29048c2ecf20Sopenharmony_ci * 2. Check that adapter is in DMA_UNAVAILABLE state. 29058c2ecf20Sopenharmony_ci * 29068c2ecf20Sopenharmony_ci * Return Codes: 29078c2ecf20Sopenharmony_ci * DFX_K_SUCCESS - adapter is in DMA_UNAVAILABLE state 29088c2ecf20Sopenharmony_ci * DFX_K_HW_TIMEOUT - adapter did not reset properly 29098c2ecf20Sopenharmony_ci * 29108c2ecf20Sopenharmony_ci * Assumptions: 29118c2ecf20Sopenharmony_ci * None 29128c2ecf20Sopenharmony_ci * 29138c2ecf20Sopenharmony_ci * Side Effects: 29148c2ecf20Sopenharmony_ci * Internal adapter registers are cleared. 29158c2ecf20Sopenharmony_ci */ 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_cistatic int dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type) 29188c2ecf20Sopenharmony_ci { 29198c2ecf20Sopenharmony_ci int timeout_cnt; /* used in for loops */ 29208c2ecf20Sopenharmony_ci 29218c2ecf20Sopenharmony_ci /* Set reset type bit and reset adapter */ 29228c2ecf20Sopenharmony_ci 29238c2ecf20Sopenharmony_ci dfx_hw_adap_reset(bp, type); 29248c2ecf20Sopenharmony_ci 29258c2ecf20Sopenharmony_ci /* Now wait for adapter to enter DMA_UNAVAILABLE state */ 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci for (timeout_cnt = 100000; timeout_cnt > 0; timeout_cnt--) 29288c2ecf20Sopenharmony_ci { 29298c2ecf20Sopenharmony_ci if (dfx_hw_adap_state_rd(bp) == PI_STATE_K_DMA_UNAVAIL) 29308c2ecf20Sopenharmony_ci break; 29318c2ecf20Sopenharmony_ci udelay(100); /* wait for 100 microseconds */ 29328c2ecf20Sopenharmony_ci } 29338c2ecf20Sopenharmony_ci if (timeout_cnt == 0) 29348c2ecf20Sopenharmony_ci return DFX_K_HW_TIMEOUT; 29358c2ecf20Sopenharmony_ci return DFX_K_SUCCESS; 29368c2ecf20Sopenharmony_ci } 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci/* 29398c2ecf20Sopenharmony_ci * Align an sk_buff to a boundary power of 2 29408c2ecf20Sopenharmony_ci * 29418c2ecf20Sopenharmony_ci */ 29428c2ecf20Sopenharmony_ci#ifdef DYNAMIC_BUFFERS 29438c2ecf20Sopenharmony_cistatic void my_skb_align(struct sk_buff *skb, int n) 29448c2ecf20Sopenharmony_ci{ 29458c2ecf20Sopenharmony_ci unsigned long x = (unsigned long)skb->data; 29468c2ecf20Sopenharmony_ci unsigned long v; 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci v = ALIGN(x, n); /* Where we want to be */ 29498c2ecf20Sopenharmony_ci 29508c2ecf20Sopenharmony_ci skb_reserve(skb, v - x); 29518c2ecf20Sopenharmony_ci} 29528c2ecf20Sopenharmony_ci#endif 29538c2ecf20Sopenharmony_ci 29548c2ecf20Sopenharmony_ci/* 29558c2ecf20Sopenharmony_ci * ================ 29568c2ecf20Sopenharmony_ci * = dfx_rcv_init = 29578c2ecf20Sopenharmony_ci * ================ 29588c2ecf20Sopenharmony_ci * 29598c2ecf20Sopenharmony_ci * Overview: 29608c2ecf20Sopenharmony_ci * Produces buffers to adapter LLC Host receive descriptor block 29618c2ecf20Sopenharmony_ci * 29628c2ecf20Sopenharmony_ci * Returns: 29638c2ecf20Sopenharmony_ci * None 29648c2ecf20Sopenharmony_ci * 29658c2ecf20Sopenharmony_ci * Arguments: 29668c2ecf20Sopenharmony_ci * bp - pointer to board information 29678c2ecf20Sopenharmony_ci * get_buffers - non-zero if buffers to be allocated 29688c2ecf20Sopenharmony_ci * 29698c2ecf20Sopenharmony_ci * Functional Description: 29708c2ecf20Sopenharmony_ci * This routine can be called during dfx_adap_init() or during an adapter 29718c2ecf20Sopenharmony_ci * reset. It initializes the descriptor block and produces all allocated 29728c2ecf20Sopenharmony_ci * LLC Host queue receive buffers. 29738c2ecf20Sopenharmony_ci * 29748c2ecf20Sopenharmony_ci * Return Codes: 29758c2ecf20Sopenharmony_ci * Return 0 on success or -ENOMEM if buffer allocation failed (when using 29768c2ecf20Sopenharmony_ci * dynamic buffer allocation). If the buffer allocation failed, the 29778c2ecf20Sopenharmony_ci * already allocated buffers will not be released and the caller should do 29788c2ecf20Sopenharmony_ci * this. 29798c2ecf20Sopenharmony_ci * 29808c2ecf20Sopenharmony_ci * Assumptions: 29818c2ecf20Sopenharmony_ci * The PDQ has been reset and the adapter and driver maintained Type 2 29828c2ecf20Sopenharmony_ci * register indices are cleared. 29838c2ecf20Sopenharmony_ci * 29848c2ecf20Sopenharmony_ci * Side Effects: 29858c2ecf20Sopenharmony_ci * Receive buffers are posted to the adapter LLC queue and the adapter 29868c2ecf20Sopenharmony_ci * is notified. 29878c2ecf20Sopenharmony_ci */ 29888c2ecf20Sopenharmony_ci 29898c2ecf20Sopenharmony_cistatic int dfx_rcv_init(DFX_board_t *bp, int get_buffers) 29908c2ecf20Sopenharmony_ci { 29918c2ecf20Sopenharmony_ci int i, j; /* used in for loop */ 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ci /* 29948c2ecf20Sopenharmony_ci * Since each receive buffer is a single fragment of same length, initialize 29958c2ecf20Sopenharmony_ci * first longword in each receive descriptor for entire LLC Host descriptor 29968c2ecf20Sopenharmony_ci * block. Also initialize second longword in each receive descriptor with 29978c2ecf20Sopenharmony_ci * physical address of receive buffer. We'll always allocate receive 29988c2ecf20Sopenharmony_ci * buffers in powers of 2 so that we can easily fill the 256 entry descriptor 29998c2ecf20Sopenharmony_ci * block and produce new receive buffers by simply updating the receive 30008c2ecf20Sopenharmony_ci * producer index. 30018c2ecf20Sopenharmony_ci * 30028c2ecf20Sopenharmony_ci * Assumptions: 30038c2ecf20Sopenharmony_ci * To support all shipping versions of PDQ, the receive buffer size 30048c2ecf20Sopenharmony_ci * must be mod 128 in length and the physical address must be 128 byte 30058c2ecf20Sopenharmony_ci * aligned. In other words, bits 0-6 of the length and address must 30068c2ecf20Sopenharmony_ci * be zero for the following descriptor field entries to be correct on 30078c2ecf20Sopenharmony_ci * all PDQ-based boards. We guaranteed both requirements during 30088c2ecf20Sopenharmony_ci * driver initialization when we allocated memory for the receive buffers. 30098c2ecf20Sopenharmony_ci */ 30108c2ecf20Sopenharmony_ci 30118c2ecf20Sopenharmony_ci if (get_buffers) { 30128c2ecf20Sopenharmony_ci#ifdef DYNAMIC_BUFFERS 30138c2ecf20Sopenharmony_ci for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++) 30148c2ecf20Sopenharmony_ci for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) 30158c2ecf20Sopenharmony_ci { 30168c2ecf20Sopenharmony_ci struct sk_buff *newskb; 30178c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 30188c2ecf20Sopenharmony_ci 30198c2ecf20Sopenharmony_ci newskb = __netdev_alloc_skb(bp->dev, NEW_SKB_SIZE, 30208c2ecf20Sopenharmony_ci GFP_NOIO); 30218c2ecf20Sopenharmony_ci if (!newskb) 30228c2ecf20Sopenharmony_ci return -ENOMEM; 30238c2ecf20Sopenharmony_ci /* 30248c2ecf20Sopenharmony_ci * align to 128 bytes for compatibility with 30258c2ecf20Sopenharmony_ci * the old EISA boards. 30268c2ecf20Sopenharmony_ci */ 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci my_skb_align(newskb, 128); 30298c2ecf20Sopenharmony_ci dma_addr = dma_map_single(bp->bus_dev, 30308c2ecf20Sopenharmony_ci newskb->data, 30318c2ecf20Sopenharmony_ci PI_RCV_DATA_K_SIZE_MAX, 30328c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 30338c2ecf20Sopenharmony_ci if (dma_mapping_error(bp->bus_dev, dma_addr)) { 30348c2ecf20Sopenharmony_ci dev_kfree_skb(newskb); 30358c2ecf20Sopenharmony_ci return -ENOMEM; 30368c2ecf20Sopenharmony_ci } 30378c2ecf20Sopenharmony_ci bp->descr_block_virt->rcv_data[i + j].long_0 = 30388c2ecf20Sopenharmony_ci (u32)(PI_RCV_DESCR_M_SOP | 30398c2ecf20Sopenharmony_ci ((PI_RCV_DATA_K_SIZE_MAX / 30408c2ecf20Sopenharmony_ci PI_ALIGN_K_RCV_DATA_BUFF) << 30418c2ecf20Sopenharmony_ci PI_RCV_DESCR_V_SEG_LEN)); 30428c2ecf20Sopenharmony_ci bp->descr_block_virt->rcv_data[i + j].long_1 = 30438c2ecf20Sopenharmony_ci (u32)dma_addr; 30448c2ecf20Sopenharmony_ci 30458c2ecf20Sopenharmony_ci /* 30468c2ecf20Sopenharmony_ci * p_rcv_buff_va is only used inside the 30478c2ecf20Sopenharmony_ci * kernel so we put the skb pointer here. 30488c2ecf20Sopenharmony_ci */ 30498c2ecf20Sopenharmony_ci bp->p_rcv_buff_va[i+j] = (char *) newskb; 30508c2ecf20Sopenharmony_ci } 30518c2ecf20Sopenharmony_ci#else 30528c2ecf20Sopenharmony_ci for (i=0; i < (int)(bp->rcv_bufs_to_post); i++) 30538c2ecf20Sopenharmony_ci for (j=0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) 30548c2ecf20Sopenharmony_ci { 30558c2ecf20Sopenharmony_ci bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP | 30568c2ecf20Sopenharmony_ci ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); 30578c2ecf20Sopenharmony_ci bp->descr_block_virt->rcv_data[i+j].long_1 = (u32) (bp->rcv_block_phys + (i * PI_RCV_DATA_K_SIZE_MAX)); 30588c2ecf20Sopenharmony_ci bp->p_rcv_buff_va[i+j] = (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX)); 30598c2ecf20Sopenharmony_ci } 30608c2ecf20Sopenharmony_ci#endif 30618c2ecf20Sopenharmony_ci } 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci /* Update receive producer and Type 2 register */ 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ci bp->rcv_xmt_reg.index.rcv_prod = bp->rcv_bufs_to_post; 30668c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); 30678c2ecf20Sopenharmony_ci return 0; 30688c2ecf20Sopenharmony_ci } 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci 30718c2ecf20Sopenharmony_ci/* 30728c2ecf20Sopenharmony_ci * ========================= 30738c2ecf20Sopenharmony_ci * = dfx_rcv_queue_process = 30748c2ecf20Sopenharmony_ci * ========================= 30758c2ecf20Sopenharmony_ci * 30768c2ecf20Sopenharmony_ci * Overview: 30778c2ecf20Sopenharmony_ci * Process received LLC frames. 30788c2ecf20Sopenharmony_ci * 30798c2ecf20Sopenharmony_ci * Returns: 30808c2ecf20Sopenharmony_ci * None 30818c2ecf20Sopenharmony_ci * 30828c2ecf20Sopenharmony_ci * Arguments: 30838c2ecf20Sopenharmony_ci * bp - pointer to board information 30848c2ecf20Sopenharmony_ci * 30858c2ecf20Sopenharmony_ci * Functional Description: 30868c2ecf20Sopenharmony_ci * Received LLC frames are processed until there are no more consumed frames. 30878c2ecf20Sopenharmony_ci * Once all frames are processed, the receive buffers are returned to the 30888c2ecf20Sopenharmony_ci * adapter. Note that this algorithm fixes the length of time that can be spent 30898c2ecf20Sopenharmony_ci * in this routine, because there are a fixed number of receive buffers to 30908c2ecf20Sopenharmony_ci * process and buffers are not produced until this routine exits and returns 30918c2ecf20Sopenharmony_ci * to the ISR. 30928c2ecf20Sopenharmony_ci * 30938c2ecf20Sopenharmony_ci * Return Codes: 30948c2ecf20Sopenharmony_ci * None 30958c2ecf20Sopenharmony_ci * 30968c2ecf20Sopenharmony_ci * Assumptions: 30978c2ecf20Sopenharmony_ci * None 30988c2ecf20Sopenharmony_ci * 30998c2ecf20Sopenharmony_ci * Side Effects: 31008c2ecf20Sopenharmony_ci * None 31018c2ecf20Sopenharmony_ci */ 31028c2ecf20Sopenharmony_ci 31038c2ecf20Sopenharmony_cistatic void dfx_rcv_queue_process( 31048c2ecf20Sopenharmony_ci DFX_board_t *bp 31058c2ecf20Sopenharmony_ci ) 31068c2ecf20Sopenharmony_ci 31078c2ecf20Sopenharmony_ci { 31088c2ecf20Sopenharmony_ci PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */ 31098c2ecf20Sopenharmony_ci char *p_buff; /* ptr to start of packet receive buffer (FMC descriptor) */ 31108c2ecf20Sopenharmony_ci u32 descr, pkt_len; /* FMC descriptor field and packet length */ 31118c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; /* pointer to a sk_buff to hold incoming packet data */ 31128c2ecf20Sopenharmony_ci 31138c2ecf20Sopenharmony_ci /* Service all consumed LLC receive frames */ 31148c2ecf20Sopenharmony_ci 31158c2ecf20Sopenharmony_ci p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data); 31168c2ecf20Sopenharmony_ci while (bp->rcv_xmt_reg.index.rcv_comp != p_type_2_cons->index.rcv_cons) 31178c2ecf20Sopenharmony_ci { 31188c2ecf20Sopenharmony_ci /* Process any errors */ 31198c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 31208c2ecf20Sopenharmony_ci int entry; 31218c2ecf20Sopenharmony_ci 31228c2ecf20Sopenharmony_ci entry = bp->rcv_xmt_reg.index.rcv_comp; 31238c2ecf20Sopenharmony_ci#ifdef DYNAMIC_BUFFERS 31248c2ecf20Sopenharmony_ci p_buff = (char *) (((struct sk_buff *)bp->p_rcv_buff_va[entry])->data); 31258c2ecf20Sopenharmony_ci#else 31268c2ecf20Sopenharmony_ci p_buff = bp->p_rcv_buff_va[entry]; 31278c2ecf20Sopenharmony_ci#endif 31288c2ecf20Sopenharmony_ci dma_addr = bp->descr_block_virt->rcv_data[entry].long_1; 31298c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(bp->bus_dev, 31308c2ecf20Sopenharmony_ci dma_addr + RCV_BUFF_K_DESCR, 31318c2ecf20Sopenharmony_ci sizeof(u32), 31328c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 31338c2ecf20Sopenharmony_ci memcpy(&descr, p_buff + RCV_BUFF_K_DESCR, sizeof(u32)); 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_ci if (descr & PI_FMC_DESCR_M_RCC_FLUSH) 31368c2ecf20Sopenharmony_ci { 31378c2ecf20Sopenharmony_ci if (descr & PI_FMC_DESCR_M_RCC_CRC) 31388c2ecf20Sopenharmony_ci bp->rcv_crc_errors++; 31398c2ecf20Sopenharmony_ci else 31408c2ecf20Sopenharmony_ci bp->rcv_frame_status_errors++; 31418c2ecf20Sopenharmony_ci } 31428c2ecf20Sopenharmony_ci else 31438c2ecf20Sopenharmony_ci { 31448c2ecf20Sopenharmony_ci int rx_in_place = 0; 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci /* The frame was received without errors - verify packet length */ 31478c2ecf20Sopenharmony_ci 31488c2ecf20Sopenharmony_ci pkt_len = (u32)((descr & PI_FMC_DESCR_M_LEN) >> PI_FMC_DESCR_V_LEN); 31498c2ecf20Sopenharmony_ci pkt_len -= 4; /* subtract 4 byte CRC */ 31508c2ecf20Sopenharmony_ci if (!IN_RANGE(pkt_len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN)) 31518c2ecf20Sopenharmony_ci bp->rcv_length_errors++; 31528c2ecf20Sopenharmony_ci else{ 31538c2ecf20Sopenharmony_ci#ifdef DYNAMIC_BUFFERS 31548c2ecf20Sopenharmony_ci struct sk_buff *newskb = NULL; 31558c2ecf20Sopenharmony_ci 31568c2ecf20Sopenharmony_ci if (pkt_len > SKBUFF_RX_COPYBREAK) { 31578c2ecf20Sopenharmony_ci dma_addr_t new_dma_addr; 31588c2ecf20Sopenharmony_ci 31598c2ecf20Sopenharmony_ci newskb = netdev_alloc_skb(bp->dev, 31608c2ecf20Sopenharmony_ci NEW_SKB_SIZE); 31618c2ecf20Sopenharmony_ci if (newskb){ 31628c2ecf20Sopenharmony_ci my_skb_align(newskb, 128); 31638c2ecf20Sopenharmony_ci new_dma_addr = dma_map_single( 31648c2ecf20Sopenharmony_ci bp->bus_dev, 31658c2ecf20Sopenharmony_ci newskb->data, 31668c2ecf20Sopenharmony_ci PI_RCV_DATA_K_SIZE_MAX, 31678c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 31688c2ecf20Sopenharmony_ci if (dma_mapping_error( 31698c2ecf20Sopenharmony_ci bp->bus_dev, 31708c2ecf20Sopenharmony_ci new_dma_addr)) { 31718c2ecf20Sopenharmony_ci dev_kfree_skb(newskb); 31728c2ecf20Sopenharmony_ci newskb = NULL; 31738c2ecf20Sopenharmony_ci } 31748c2ecf20Sopenharmony_ci } 31758c2ecf20Sopenharmony_ci if (newskb) { 31768c2ecf20Sopenharmony_ci rx_in_place = 1; 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_ci skb = (struct sk_buff *)bp->p_rcv_buff_va[entry]; 31798c2ecf20Sopenharmony_ci dma_unmap_single(bp->bus_dev, 31808c2ecf20Sopenharmony_ci dma_addr, 31818c2ecf20Sopenharmony_ci PI_RCV_DATA_K_SIZE_MAX, 31828c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 31838c2ecf20Sopenharmony_ci skb_reserve(skb, RCV_BUFF_K_PADDING); 31848c2ecf20Sopenharmony_ci bp->p_rcv_buff_va[entry] = (char *)newskb; 31858c2ecf20Sopenharmony_ci bp->descr_block_virt->rcv_data[entry].long_1 = (u32)new_dma_addr; 31868c2ecf20Sopenharmony_ci } 31878c2ecf20Sopenharmony_ci } 31888c2ecf20Sopenharmony_ci if (!newskb) 31898c2ecf20Sopenharmony_ci#endif 31908c2ecf20Sopenharmony_ci /* Alloc new buffer to pass up, 31918c2ecf20Sopenharmony_ci * add room for PRH. */ 31928c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(bp->dev, 31938c2ecf20Sopenharmony_ci pkt_len + 3); 31948c2ecf20Sopenharmony_ci if (skb == NULL) 31958c2ecf20Sopenharmony_ci { 31968c2ecf20Sopenharmony_ci printk("%s: Could not allocate receive buffer. Dropping packet.\n", bp->dev->name); 31978c2ecf20Sopenharmony_ci bp->rcv_discards++; 31988c2ecf20Sopenharmony_ci break; 31998c2ecf20Sopenharmony_ci } 32008c2ecf20Sopenharmony_ci else { 32018c2ecf20Sopenharmony_ci if (!rx_in_place) { 32028c2ecf20Sopenharmony_ci /* Receive buffer allocated, pass receive packet up */ 32038c2ecf20Sopenharmony_ci dma_sync_single_for_cpu( 32048c2ecf20Sopenharmony_ci bp->bus_dev, 32058c2ecf20Sopenharmony_ci dma_addr + 32068c2ecf20Sopenharmony_ci RCV_BUFF_K_PADDING, 32078c2ecf20Sopenharmony_ci pkt_len + 3, 32088c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 32098c2ecf20Sopenharmony_ci 32108c2ecf20Sopenharmony_ci skb_copy_to_linear_data(skb, 32118c2ecf20Sopenharmony_ci p_buff + RCV_BUFF_K_PADDING, 32128c2ecf20Sopenharmony_ci pkt_len + 3); 32138c2ecf20Sopenharmony_ci } 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci skb_reserve(skb,3); /* adjust data field so that it points to FC byte */ 32168c2ecf20Sopenharmony_ci skb_put(skb, pkt_len); /* pass up packet length, NOT including CRC */ 32178c2ecf20Sopenharmony_ci skb->protocol = fddi_type_trans(skb, bp->dev); 32188c2ecf20Sopenharmony_ci bp->rcv_total_bytes += skb->len; 32198c2ecf20Sopenharmony_ci netif_rx(skb); 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_ci /* Update the rcv counters */ 32228c2ecf20Sopenharmony_ci bp->rcv_total_frames++; 32238c2ecf20Sopenharmony_ci if (*(p_buff + RCV_BUFF_K_DA) & 0x01) 32248c2ecf20Sopenharmony_ci bp->rcv_multicast_frames++; 32258c2ecf20Sopenharmony_ci } 32268c2ecf20Sopenharmony_ci } 32278c2ecf20Sopenharmony_ci } 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ci /* 32308c2ecf20Sopenharmony_ci * Advance the producer (for recycling) and advance the completion 32318c2ecf20Sopenharmony_ci * (for servicing received frames). Note that it is okay to 32328c2ecf20Sopenharmony_ci * advance the producer without checking that it passes the 32338c2ecf20Sopenharmony_ci * completion index because they are both advanced at the same 32348c2ecf20Sopenharmony_ci * rate. 32358c2ecf20Sopenharmony_ci */ 32368c2ecf20Sopenharmony_ci 32378c2ecf20Sopenharmony_ci bp->rcv_xmt_reg.index.rcv_prod += 1; 32388c2ecf20Sopenharmony_ci bp->rcv_xmt_reg.index.rcv_comp += 1; 32398c2ecf20Sopenharmony_ci } 32408c2ecf20Sopenharmony_ci } 32418c2ecf20Sopenharmony_ci 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_ci/* 32448c2ecf20Sopenharmony_ci * ===================== 32458c2ecf20Sopenharmony_ci * = dfx_xmt_queue_pkt = 32468c2ecf20Sopenharmony_ci * ===================== 32478c2ecf20Sopenharmony_ci * 32488c2ecf20Sopenharmony_ci * Overview: 32498c2ecf20Sopenharmony_ci * Queues packets for transmission 32508c2ecf20Sopenharmony_ci * 32518c2ecf20Sopenharmony_ci * Returns: 32528c2ecf20Sopenharmony_ci * Condition code 32538c2ecf20Sopenharmony_ci * 32548c2ecf20Sopenharmony_ci * Arguments: 32558c2ecf20Sopenharmony_ci * skb - pointer to sk_buff to queue for transmission 32568c2ecf20Sopenharmony_ci * dev - pointer to device information 32578c2ecf20Sopenharmony_ci * 32588c2ecf20Sopenharmony_ci * Functional Description: 32598c2ecf20Sopenharmony_ci * Here we assume that an incoming skb transmit request 32608c2ecf20Sopenharmony_ci * is contained in a single physically contiguous buffer 32618c2ecf20Sopenharmony_ci * in which the virtual address of the start of packet 32628c2ecf20Sopenharmony_ci * (skb->data) can be converted to a physical address 32638c2ecf20Sopenharmony_ci * by using pci_map_single(). 32648c2ecf20Sopenharmony_ci * 32658c2ecf20Sopenharmony_ci * Since the adapter architecture requires a three byte 32668c2ecf20Sopenharmony_ci * packet request header to prepend the start of packet, 32678c2ecf20Sopenharmony_ci * we'll write the three byte field immediately prior to 32688c2ecf20Sopenharmony_ci * the FC byte. This assumption is valid because we've 32698c2ecf20Sopenharmony_ci * ensured that dev->hard_header_len includes three pad 32708c2ecf20Sopenharmony_ci * bytes. By posting a single fragment to the adapter, 32718c2ecf20Sopenharmony_ci * we'll reduce the number of descriptor fetches and 32728c2ecf20Sopenharmony_ci * bus traffic needed to send the request. 32738c2ecf20Sopenharmony_ci * 32748c2ecf20Sopenharmony_ci * Also, we can't free the skb until after it's been DMA'd 32758c2ecf20Sopenharmony_ci * out by the adapter, so we'll queue it in the driver and 32768c2ecf20Sopenharmony_ci * return it in dfx_xmt_done. 32778c2ecf20Sopenharmony_ci * 32788c2ecf20Sopenharmony_ci * Return Codes: 32798c2ecf20Sopenharmony_ci * 0 - driver queued packet, link is unavailable, or skbuff was bad 32808c2ecf20Sopenharmony_ci * 1 - caller should requeue the sk_buff for later transmission 32818c2ecf20Sopenharmony_ci * 32828c2ecf20Sopenharmony_ci * Assumptions: 32838c2ecf20Sopenharmony_ci * First and foremost, we assume the incoming skb pointer 32848c2ecf20Sopenharmony_ci * is NOT NULL and is pointing to a valid sk_buff structure. 32858c2ecf20Sopenharmony_ci * 32868c2ecf20Sopenharmony_ci * The outgoing packet is complete, starting with the 32878c2ecf20Sopenharmony_ci * frame control byte including the last byte of data, 32888c2ecf20Sopenharmony_ci * but NOT including the 4 byte CRC. We'll let the 32898c2ecf20Sopenharmony_ci * adapter hardware generate and append the CRC. 32908c2ecf20Sopenharmony_ci * 32918c2ecf20Sopenharmony_ci * The entire packet is stored in one physically 32928c2ecf20Sopenharmony_ci * contiguous buffer which is not cached and whose 32938c2ecf20Sopenharmony_ci * 32-bit physical address can be determined. 32948c2ecf20Sopenharmony_ci * 32958c2ecf20Sopenharmony_ci * It's vital that this routine is NOT reentered for the 32968c2ecf20Sopenharmony_ci * same board and that the OS is not in another section of 32978c2ecf20Sopenharmony_ci * code (eg. dfx_int_common) for the same board on a 32988c2ecf20Sopenharmony_ci * different thread. 32998c2ecf20Sopenharmony_ci * 33008c2ecf20Sopenharmony_ci * Side Effects: 33018c2ecf20Sopenharmony_ci * None 33028c2ecf20Sopenharmony_ci */ 33038c2ecf20Sopenharmony_ci 33048c2ecf20Sopenharmony_cistatic netdev_tx_t dfx_xmt_queue_pkt(struct sk_buff *skb, 33058c2ecf20Sopenharmony_ci struct net_device *dev) 33068c2ecf20Sopenharmony_ci { 33078c2ecf20Sopenharmony_ci DFX_board_t *bp = netdev_priv(dev); 33088c2ecf20Sopenharmony_ci u8 prod; /* local transmit producer index */ 33098c2ecf20Sopenharmony_ci PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */ 33108c2ecf20Sopenharmony_ci XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ 33118c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 33128c2ecf20Sopenharmony_ci unsigned long flags; 33138c2ecf20Sopenharmony_ci 33148c2ecf20Sopenharmony_ci netif_stop_queue(dev); 33158c2ecf20Sopenharmony_ci 33168c2ecf20Sopenharmony_ci /* 33178c2ecf20Sopenharmony_ci * Verify that incoming transmit request is OK 33188c2ecf20Sopenharmony_ci * 33198c2ecf20Sopenharmony_ci * Note: The packet size check is consistent with other 33208c2ecf20Sopenharmony_ci * Linux device drivers, although the correct packet 33218c2ecf20Sopenharmony_ci * size should be verified before calling the 33228c2ecf20Sopenharmony_ci * transmit routine. 33238c2ecf20Sopenharmony_ci */ 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_ci if (!IN_RANGE(skb->len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN)) 33268c2ecf20Sopenharmony_ci { 33278c2ecf20Sopenharmony_ci printk("%s: Invalid packet length - %u bytes\n", 33288c2ecf20Sopenharmony_ci dev->name, skb->len); 33298c2ecf20Sopenharmony_ci bp->xmt_length_errors++; /* bump error counter */ 33308c2ecf20Sopenharmony_ci netif_wake_queue(dev); 33318c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 33328c2ecf20Sopenharmony_ci return NETDEV_TX_OK; /* return "success" */ 33338c2ecf20Sopenharmony_ci } 33348c2ecf20Sopenharmony_ci /* 33358c2ecf20Sopenharmony_ci * See if adapter link is available, if not, free buffer 33368c2ecf20Sopenharmony_ci * 33378c2ecf20Sopenharmony_ci * Note: If the link isn't available, free buffer and return 0 33388c2ecf20Sopenharmony_ci * rather than tell the upper layer to requeue the packet. 33398c2ecf20Sopenharmony_ci * The methodology here is that by the time the link 33408c2ecf20Sopenharmony_ci * becomes available, the packet to be sent will be 33418c2ecf20Sopenharmony_ci * fairly stale. By simply dropping the packet, the 33428c2ecf20Sopenharmony_ci * higher layer protocols will eventually time out 33438c2ecf20Sopenharmony_ci * waiting for response packets which it won't receive. 33448c2ecf20Sopenharmony_ci */ 33458c2ecf20Sopenharmony_ci 33468c2ecf20Sopenharmony_ci if (bp->link_available == PI_K_FALSE) 33478c2ecf20Sopenharmony_ci { 33488c2ecf20Sopenharmony_ci if (dfx_hw_adap_state_rd(bp) == PI_STATE_K_LINK_AVAIL) /* is link really available? */ 33498c2ecf20Sopenharmony_ci bp->link_available = PI_K_TRUE; /* if so, set flag and continue */ 33508c2ecf20Sopenharmony_ci else 33518c2ecf20Sopenharmony_ci { 33528c2ecf20Sopenharmony_ci bp->xmt_discards++; /* bump error counter */ 33538c2ecf20Sopenharmony_ci dev_kfree_skb(skb); /* free sk_buff now */ 33548c2ecf20Sopenharmony_ci netif_wake_queue(dev); 33558c2ecf20Sopenharmony_ci return NETDEV_TX_OK; /* return "success" */ 33568c2ecf20Sopenharmony_ci } 33578c2ecf20Sopenharmony_ci } 33588c2ecf20Sopenharmony_ci 33598c2ecf20Sopenharmony_ci /* Write the three PRH bytes immediately before the FC byte */ 33608c2ecf20Sopenharmony_ci 33618c2ecf20Sopenharmony_ci skb_push(skb, 3); 33628c2ecf20Sopenharmony_ci skb->data[0] = DFX_PRH0_BYTE; /* these byte values are defined */ 33638c2ecf20Sopenharmony_ci skb->data[1] = DFX_PRH1_BYTE; /* in the Motorola FDDI MAC chip */ 33648c2ecf20Sopenharmony_ci skb->data[2] = DFX_PRH2_BYTE; /* specification */ 33658c2ecf20Sopenharmony_ci 33668c2ecf20Sopenharmony_ci dma_addr = dma_map_single(bp->bus_dev, skb->data, skb->len, 33678c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 33688c2ecf20Sopenharmony_ci if (dma_mapping_error(bp->bus_dev, dma_addr)) { 33698c2ecf20Sopenharmony_ci skb_pull(skb, 3); 33708c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 33718c2ecf20Sopenharmony_ci } 33728c2ecf20Sopenharmony_ci 33738c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 33748c2ecf20Sopenharmony_ci 33758c2ecf20Sopenharmony_ci /* Get the current producer and the next free xmt data descriptor */ 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_ci prod = bp->rcv_xmt_reg.index.xmt_prod; 33788c2ecf20Sopenharmony_ci p_xmt_descr = &(bp->descr_block_virt->xmt_data[prod]); 33798c2ecf20Sopenharmony_ci 33808c2ecf20Sopenharmony_ci /* 33818c2ecf20Sopenharmony_ci * Get pointer to auxiliary queue entry to contain information 33828c2ecf20Sopenharmony_ci * for this packet. 33838c2ecf20Sopenharmony_ci * 33848c2ecf20Sopenharmony_ci * Note: The current xmt producer index will become the 33858c2ecf20Sopenharmony_ci * current xmt completion index when we complete this 33868c2ecf20Sopenharmony_ci * packet later on. So, we'll get the pointer to the 33878c2ecf20Sopenharmony_ci * next auxiliary queue entry now before we bump the 33888c2ecf20Sopenharmony_ci * producer index. 33898c2ecf20Sopenharmony_ci */ 33908c2ecf20Sopenharmony_ci 33918c2ecf20Sopenharmony_ci p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[prod++]); /* also bump producer index */ 33928c2ecf20Sopenharmony_ci 33938c2ecf20Sopenharmony_ci /* 33948c2ecf20Sopenharmony_ci * Write the descriptor with buffer info and bump producer 33958c2ecf20Sopenharmony_ci * 33968c2ecf20Sopenharmony_ci * Note: Since we need to start DMA from the packet request 33978c2ecf20Sopenharmony_ci * header, we'll add 3 bytes to the DMA buffer length, 33988c2ecf20Sopenharmony_ci * and we'll determine the physical address of the 33998c2ecf20Sopenharmony_ci * buffer from the PRH, not skb->data. 34008c2ecf20Sopenharmony_ci * 34018c2ecf20Sopenharmony_ci * Assumptions: 34028c2ecf20Sopenharmony_ci * 1. Packet starts with the frame control (FC) byte 34038c2ecf20Sopenharmony_ci * at skb->data. 34048c2ecf20Sopenharmony_ci * 2. The 4-byte CRC is not appended to the buffer or 34058c2ecf20Sopenharmony_ci * included in the length. 34068c2ecf20Sopenharmony_ci * 3. Packet length (skb->len) is from FC to end of 34078c2ecf20Sopenharmony_ci * data, inclusive. 34088c2ecf20Sopenharmony_ci * 4. The packet length does not exceed the maximum 34098c2ecf20Sopenharmony_ci * FDDI LLC frame length of 4491 bytes. 34108c2ecf20Sopenharmony_ci * 5. The entire packet is contained in a physically 34118c2ecf20Sopenharmony_ci * contiguous, non-cached, locked memory space 34128c2ecf20Sopenharmony_ci * comprised of a single buffer pointed to by 34138c2ecf20Sopenharmony_ci * skb->data. 34148c2ecf20Sopenharmony_ci * 6. The physical address of the start of packet 34158c2ecf20Sopenharmony_ci * can be determined from the virtual address 34168c2ecf20Sopenharmony_ci * by using pci_map_single() and is only 32-bits 34178c2ecf20Sopenharmony_ci * wide. 34188c2ecf20Sopenharmony_ci */ 34198c2ecf20Sopenharmony_ci 34208c2ecf20Sopenharmony_ci p_xmt_descr->long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len) << PI_XMT_DESCR_V_SEG_LEN)); 34218c2ecf20Sopenharmony_ci p_xmt_descr->long_1 = (u32)dma_addr; 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_ci /* 34248c2ecf20Sopenharmony_ci * Verify that descriptor is actually available 34258c2ecf20Sopenharmony_ci * 34268c2ecf20Sopenharmony_ci * Note: If descriptor isn't available, return 1 which tells 34278c2ecf20Sopenharmony_ci * the upper layer to requeue the packet for later 34288c2ecf20Sopenharmony_ci * transmission. 34298c2ecf20Sopenharmony_ci * 34308c2ecf20Sopenharmony_ci * We need to ensure that the producer never reaches the 34318c2ecf20Sopenharmony_ci * completion, except to indicate that the queue is empty. 34328c2ecf20Sopenharmony_ci */ 34338c2ecf20Sopenharmony_ci 34348c2ecf20Sopenharmony_ci if (prod == bp->rcv_xmt_reg.index.xmt_comp) 34358c2ecf20Sopenharmony_ci { 34368c2ecf20Sopenharmony_ci skb_pull(skb,3); 34378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 34388c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; /* requeue packet for later */ 34398c2ecf20Sopenharmony_ci } 34408c2ecf20Sopenharmony_ci 34418c2ecf20Sopenharmony_ci /* 34428c2ecf20Sopenharmony_ci * Save info for this packet for xmt done indication routine 34438c2ecf20Sopenharmony_ci * 34448c2ecf20Sopenharmony_ci * Normally, we'd save the producer index in the p_xmt_drv_descr 34458c2ecf20Sopenharmony_ci * structure so that we'd have it handy when we complete this 34468c2ecf20Sopenharmony_ci * packet later (in dfx_xmt_done). However, since the current 34478c2ecf20Sopenharmony_ci * transmit architecture guarantees a single fragment for the 34488c2ecf20Sopenharmony_ci * entire packet, we can simply bump the completion index by 34498c2ecf20Sopenharmony_ci * one (1) for each completed packet. 34508c2ecf20Sopenharmony_ci * 34518c2ecf20Sopenharmony_ci * Note: If this assumption changes and we're presented with 34528c2ecf20Sopenharmony_ci * an inconsistent number of transmit fragments for packet 34538c2ecf20Sopenharmony_ci * data, we'll need to modify this code to save the current 34548c2ecf20Sopenharmony_ci * transmit producer index. 34558c2ecf20Sopenharmony_ci */ 34568c2ecf20Sopenharmony_ci 34578c2ecf20Sopenharmony_ci p_xmt_drv_descr->p_skb = skb; 34588c2ecf20Sopenharmony_ci 34598c2ecf20Sopenharmony_ci /* Update Type 2 register */ 34608c2ecf20Sopenharmony_ci 34618c2ecf20Sopenharmony_ci bp->rcv_xmt_reg.index.xmt_prod = prod; 34628c2ecf20Sopenharmony_ci dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); 34638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 34648c2ecf20Sopenharmony_ci netif_wake_queue(dev); 34658c2ecf20Sopenharmony_ci return NETDEV_TX_OK; /* packet queued to adapter */ 34668c2ecf20Sopenharmony_ci } 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_ci 34698c2ecf20Sopenharmony_ci/* 34708c2ecf20Sopenharmony_ci * ================ 34718c2ecf20Sopenharmony_ci * = dfx_xmt_done = 34728c2ecf20Sopenharmony_ci * ================ 34738c2ecf20Sopenharmony_ci * 34748c2ecf20Sopenharmony_ci * Overview: 34758c2ecf20Sopenharmony_ci * Processes all frames that have been transmitted. 34768c2ecf20Sopenharmony_ci * 34778c2ecf20Sopenharmony_ci * Returns: 34788c2ecf20Sopenharmony_ci * None 34798c2ecf20Sopenharmony_ci * 34808c2ecf20Sopenharmony_ci * Arguments: 34818c2ecf20Sopenharmony_ci * bp - pointer to board information 34828c2ecf20Sopenharmony_ci * 34838c2ecf20Sopenharmony_ci * Functional Description: 34848c2ecf20Sopenharmony_ci * For all consumed transmit descriptors that have not 34858c2ecf20Sopenharmony_ci * yet been completed, we'll free the skb we were holding 34868c2ecf20Sopenharmony_ci * onto using dev_kfree_skb and bump the appropriate 34878c2ecf20Sopenharmony_ci * counters. 34888c2ecf20Sopenharmony_ci * 34898c2ecf20Sopenharmony_ci * Return Codes: 34908c2ecf20Sopenharmony_ci * None 34918c2ecf20Sopenharmony_ci * 34928c2ecf20Sopenharmony_ci * Assumptions: 34938c2ecf20Sopenharmony_ci * The Type 2 register is not updated in this routine. It is 34948c2ecf20Sopenharmony_ci * assumed that it will be updated in the ISR when dfx_xmt_done 34958c2ecf20Sopenharmony_ci * returns. 34968c2ecf20Sopenharmony_ci * 34978c2ecf20Sopenharmony_ci * Side Effects: 34988c2ecf20Sopenharmony_ci * None 34998c2ecf20Sopenharmony_ci */ 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_cistatic int dfx_xmt_done(DFX_board_t *bp) 35028c2ecf20Sopenharmony_ci { 35038c2ecf20Sopenharmony_ci XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ 35048c2ecf20Sopenharmony_ci PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */ 35058c2ecf20Sopenharmony_ci u8 comp; /* local transmit completion index */ 35068c2ecf20Sopenharmony_ci int freed = 0; /* buffers freed */ 35078c2ecf20Sopenharmony_ci 35088c2ecf20Sopenharmony_ci /* Service all consumed transmit frames */ 35098c2ecf20Sopenharmony_ci 35108c2ecf20Sopenharmony_ci p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data); 35118c2ecf20Sopenharmony_ci while (bp->rcv_xmt_reg.index.xmt_comp != p_type_2_cons->index.xmt_cons) 35128c2ecf20Sopenharmony_ci { 35138c2ecf20Sopenharmony_ci /* Get pointer to the transmit driver descriptor block information */ 35148c2ecf20Sopenharmony_ci 35158c2ecf20Sopenharmony_ci p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[bp->rcv_xmt_reg.index.xmt_comp]); 35168c2ecf20Sopenharmony_ci 35178c2ecf20Sopenharmony_ci /* Increment transmit counters */ 35188c2ecf20Sopenharmony_ci 35198c2ecf20Sopenharmony_ci bp->xmt_total_frames++; 35208c2ecf20Sopenharmony_ci bp->xmt_total_bytes += p_xmt_drv_descr->p_skb->len; 35218c2ecf20Sopenharmony_ci 35228c2ecf20Sopenharmony_ci /* Return skb to operating system */ 35238c2ecf20Sopenharmony_ci comp = bp->rcv_xmt_reg.index.xmt_comp; 35248c2ecf20Sopenharmony_ci dma_unmap_single(bp->bus_dev, 35258c2ecf20Sopenharmony_ci bp->descr_block_virt->xmt_data[comp].long_1, 35268c2ecf20Sopenharmony_ci p_xmt_drv_descr->p_skb->len, 35278c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 35288c2ecf20Sopenharmony_ci dev_consume_skb_irq(p_xmt_drv_descr->p_skb); 35298c2ecf20Sopenharmony_ci 35308c2ecf20Sopenharmony_ci /* 35318c2ecf20Sopenharmony_ci * Move to start of next packet by updating completion index 35328c2ecf20Sopenharmony_ci * 35338c2ecf20Sopenharmony_ci * Here we assume that a transmit packet request is always 35348c2ecf20Sopenharmony_ci * serviced by posting one fragment. We can therefore 35358c2ecf20Sopenharmony_ci * simplify the completion code by incrementing the 35368c2ecf20Sopenharmony_ci * completion index by one. This code will need to be 35378c2ecf20Sopenharmony_ci * modified if this assumption changes. See comments 35388c2ecf20Sopenharmony_ci * in dfx_xmt_queue_pkt for more details. 35398c2ecf20Sopenharmony_ci */ 35408c2ecf20Sopenharmony_ci 35418c2ecf20Sopenharmony_ci bp->rcv_xmt_reg.index.xmt_comp += 1; 35428c2ecf20Sopenharmony_ci freed++; 35438c2ecf20Sopenharmony_ci } 35448c2ecf20Sopenharmony_ci return freed; 35458c2ecf20Sopenharmony_ci } 35468c2ecf20Sopenharmony_ci 35478c2ecf20Sopenharmony_ci 35488c2ecf20Sopenharmony_ci/* 35498c2ecf20Sopenharmony_ci * ================= 35508c2ecf20Sopenharmony_ci * = dfx_rcv_flush = 35518c2ecf20Sopenharmony_ci * ================= 35528c2ecf20Sopenharmony_ci * 35538c2ecf20Sopenharmony_ci * Overview: 35548c2ecf20Sopenharmony_ci * Remove all skb's in the receive ring. 35558c2ecf20Sopenharmony_ci * 35568c2ecf20Sopenharmony_ci * Returns: 35578c2ecf20Sopenharmony_ci * None 35588c2ecf20Sopenharmony_ci * 35598c2ecf20Sopenharmony_ci * Arguments: 35608c2ecf20Sopenharmony_ci * bp - pointer to board information 35618c2ecf20Sopenharmony_ci * 35628c2ecf20Sopenharmony_ci * Functional Description: 35638c2ecf20Sopenharmony_ci * Free's all the dynamically allocated skb's that are 35648c2ecf20Sopenharmony_ci * currently attached to the device receive ring. This 35658c2ecf20Sopenharmony_ci * function is typically only used when the device is 35668c2ecf20Sopenharmony_ci * initialized or reinitialized. 35678c2ecf20Sopenharmony_ci * 35688c2ecf20Sopenharmony_ci * Return Codes: 35698c2ecf20Sopenharmony_ci * None 35708c2ecf20Sopenharmony_ci * 35718c2ecf20Sopenharmony_ci * Side Effects: 35728c2ecf20Sopenharmony_ci * None 35738c2ecf20Sopenharmony_ci */ 35748c2ecf20Sopenharmony_ci#ifdef DYNAMIC_BUFFERS 35758c2ecf20Sopenharmony_cistatic void dfx_rcv_flush( DFX_board_t *bp ) 35768c2ecf20Sopenharmony_ci { 35778c2ecf20Sopenharmony_ci int i, j; 35788c2ecf20Sopenharmony_ci 35798c2ecf20Sopenharmony_ci for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++) 35808c2ecf20Sopenharmony_ci for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) 35818c2ecf20Sopenharmony_ci { 35828c2ecf20Sopenharmony_ci struct sk_buff *skb; 35838c2ecf20Sopenharmony_ci skb = (struct sk_buff *)bp->p_rcv_buff_va[i+j]; 35848c2ecf20Sopenharmony_ci if (skb) { 35858c2ecf20Sopenharmony_ci dma_unmap_single(bp->bus_dev, 35868c2ecf20Sopenharmony_ci bp->descr_block_virt->rcv_data[i+j].long_1, 35878c2ecf20Sopenharmony_ci PI_RCV_DATA_K_SIZE_MAX, 35888c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 35898c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 35908c2ecf20Sopenharmony_ci } 35918c2ecf20Sopenharmony_ci bp->p_rcv_buff_va[i+j] = NULL; 35928c2ecf20Sopenharmony_ci } 35938c2ecf20Sopenharmony_ci 35948c2ecf20Sopenharmony_ci } 35958c2ecf20Sopenharmony_ci#endif /* DYNAMIC_BUFFERS */ 35968c2ecf20Sopenharmony_ci 35978c2ecf20Sopenharmony_ci/* 35988c2ecf20Sopenharmony_ci * ================= 35998c2ecf20Sopenharmony_ci * = dfx_xmt_flush = 36008c2ecf20Sopenharmony_ci * ================= 36018c2ecf20Sopenharmony_ci * 36028c2ecf20Sopenharmony_ci * Overview: 36038c2ecf20Sopenharmony_ci * Processes all frames whether they've been transmitted 36048c2ecf20Sopenharmony_ci * or not. 36058c2ecf20Sopenharmony_ci * 36068c2ecf20Sopenharmony_ci * Returns: 36078c2ecf20Sopenharmony_ci * None 36088c2ecf20Sopenharmony_ci * 36098c2ecf20Sopenharmony_ci * Arguments: 36108c2ecf20Sopenharmony_ci * bp - pointer to board information 36118c2ecf20Sopenharmony_ci * 36128c2ecf20Sopenharmony_ci * Functional Description: 36138c2ecf20Sopenharmony_ci * For all produced transmit descriptors that have not 36148c2ecf20Sopenharmony_ci * yet been completed, we'll free the skb we were holding 36158c2ecf20Sopenharmony_ci * onto using dev_kfree_skb and bump the appropriate 36168c2ecf20Sopenharmony_ci * counters. Of course, it's possible that some of 36178c2ecf20Sopenharmony_ci * these transmit requests actually did go out, but we 36188c2ecf20Sopenharmony_ci * won't make that distinction here. Finally, we'll 36198c2ecf20Sopenharmony_ci * update the consumer index to match the producer. 36208c2ecf20Sopenharmony_ci * 36218c2ecf20Sopenharmony_ci * Return Codes: 36228c2ecf20Sopenharmony_ci * None 36238c2ecf20Sopenharmony_ci * 36248c2ecf20Sopenharmony_ci * Assumptions: 36258c2ecf20Sopenharmony_ci * This routine does NOT update the Type 2 register. It 36268c2ecf20Sopenharmony_ci * is assumed that this routine is being called during a 36278c2ecf20Sopenharmony_ci * transmit flush interrupt, or a shutdown or close routine. 36288c2ecf20Sopenharmony_ci * 36298c2ecf20Sopenharmony_ci * Side Effects: 36308c2ecf20Sopenharmony_ci * None 36318c2ecf20Sopenharmony_ci */ 36328c2ecf20Sopenharmony_ci 36338c2ecf20Sopenharmony_cistatic void dfx_xmt_flush( DFX_board_t *bp ) 36348c2ecf20Sopenharmony_ci { 36358c2ecf20Sopenharmony_ci u32 prod_cons; /* rcv/xmt consumer block longword */ 36368c2ecf20Sopenharmony_ci XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ 36378c2ecf20Sopenharmony_ci u8 comp; /* local transmit completion index */ 36388c2ecf20Sopenharmony_ci 36398c2ecf20Sopenharmony_ci /* Flush all outstanding transmit frames */ 36408c2ecf20Sopenharmony_ci 36418c2ecf20Sopenharmony_ci while (bp->rcv_xmt_reg.index.xmt_comp != bp->rcv_xmt_reg.index.xmt_prod) 36428c2ecf20Sopenharmony_ci { 36438c2ecf20Sopenharmony_ci /* Get pointer to the transmit driver descriptor block information */ 36448c2ecf20Sopenharmony_ci 36458c2ecf20Sopenharmony_ci p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[bp->rcv_xmt_reg.index.xmt_comp]); 36468c2ecf20Sopenharmony_ci 36478c2ecf20Sopenharmony_ci /* Return skb to operating system */ 36488c2ecf20Sopenharmony_ci comp = bp->rcv_xmt_reg.index.xmt_comp; 36498c2ecf20Sopenharmony_ci dma_unmap_single(bp->bus_dev, 36508c2ecf20Sopenharmony_ci bp->descr_block_virt->xmt_data[comp].long_1, 36518c2ecf20Sopenharmony_ci p_xmt_drv_descr->p_skb->len, 36528c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 36538c2ecf20Sopenharmony_ci dev_kfree_skb(p_xmt_drv_descr->p_skb); 36548c2ecf20Sopenharmony_ci 36558c2ecf20Sopenharmony_ci /* Increment transmit error counter */ 36568c2ecf20Sopenharmony_ci 36578c2ecf20Sopenharmony_ci bp->xmt_discards++; 36588c2ecf20Sopenharmony_ci 36598c2ecf20Sopenharmony_ci /* 36608c2ecf20Sopenharmony_ci * Move to start of next packet by updating completion index 36618c2ecf20Sopenharmony_ci * 36628c2ecf20Sopenharmony_ci * Here we assume that a transmit packet request is always 36638c2ecf20Sopenharmony_ci * serviced by posting one fragment. We can therefore 36648c2ecf20Sopenharmony_ci * simplify the completion code by incrementing the 36658c2ecf20Sopenharmony_ci * completion index by one. This code will need to be 36668c2ecf20Sopenharmony_ci * modified if this assumption changes. See comments 36678c2ecf20Sopenharmony_ci * in dfx_xmt_queue_pkt for more details. 36688c2ecf20Sopenharmony_ci */ 36698c2ecf20Sopenharmony_ci 36708c2ecf20Sopenharmony_ci bp->rcv_xmt_reg.index.xmt_comp += 1; 36718c2ecf20Sopenharmony_ci } 36728c2ecf20Sopenharmony_ci 36738c2ecf20Sopenharmony_ci /* Update the transmit consumer index in the consumer block */ 36748c2ecf20Sopenharmony_ci 36758c2ecf20Sopenharmony_ci prod_cons = (u32)(bp->cons_block_virt->xmt_rcv_data & ~PI_CONS_M_XMT_INDEX); 36768c2ecf20Sopenharmony_ci prod_cons |= (u32)(bp->rcv_xmt_reg.index.xmt_prod << PI_CONS_V_XMT_INDEX); 36778c2ecf20Sopenharmony_ci bp->cons_block_virt->xmt_rcv_data = prod_cons; 36788c2ecf20Sopenharmony_ci } 36798c2ecf20Sopenharmony_ci 36808c2ecf20Sopenharmony_ci/* 36818c2ecf20Sopenharmony_ci * ================== 36828c2ecf20Sopenharmony_ci * = dfx_unregister = 36838c2ecf20Sopenharmony_ci * ================== 36848c2ecf20Sopenharmony_ci * 36858c2ecf20Sopenharmony_ci * Overview: 36868c2ecf20Sopenharmony_ci * Shuts down an FDDI controller 36878c2ecf20Sopenharmony_ci * 36888c2ecf20Sopenharmony_ci * Returns: 36898c2ecf20Sopenharmony_ci * Condition code 36908c2ecf20Sopenharmony_ci * 36918c2ecf20Sopenharmony_ci * Arguments: 36928c2ecf20Sopenharmony_ci * bdev - pointer to device information 36938c2ecf20Sopenharmony_ci * 36948c2ecf20Sopenharmony_ci * Functional Description: 36958c2ecf20Sopenharmony_ci * 36968c2ecf20Sopenharmony_ci * Return Codes: 36978c2ecf20Sopenharmony_ci * None 36988c2ecf20Sopenharmony_ci * 36998c2ecf20Sopenharmony_ci * Assumptions: 37008c2ecf20Sopenharmony_ci * It compiles so it should work :-( (PCI cards do :-) 37018c2ecf20Sopenharmony_ci * 37028c2ecf20Sopenharmony_ci * Side Effects: 37038c2ecf20Sopenharmony_ci * Device structures for FDDI adapters (fddi0, fddi1, etc) are 37048c2ecf20Sopenharmony_ci * freed. 37058c2ecf20Sopenharmony_ci */ 37068c2ecf20Sopenharmony_cistatic void dfx_unregister(struct device *bdev) 37078c2ecf20Sopenharmony_ci{ 37088c2ecf20Sopenharmony_ci struct net_device *dev = dev_get_drvdata(bdev); 37098c2ecf20Sopenharmony_ci DFX_board_t *bp = netdev_priv(dev); 37108c2ecf20Sopenharmony_ci int dfx_bus_pci = dev_is_pci(bdev); 37118c2ecf20Sopenharmony_ci int dfx_bus_tc = DFX_BUS_TC(bdev); 37128c2ecf20Sopenharmony_ci int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; 37138c2ecf20Sopenharmony_ci resource_size_t bar_start[3] = {0}; /* pointers to ports */ 37148c2ecf20Sopenharmony_ci resource_size_t bar_len[3] = {0}; /* resource lengths */ 37158c2ecf20Sopenharmony_ci int alloc_size; /* total buffer size used */ 37168c2ecf20Sopenharmony_ci 37178c2ecf20Sopenharmony_ci unregister_netdev(dev); 37188c2ecf20Sopenharmony_ci 37198c2ecf20Sopenharmony_ci alloc_size = sizeof(PI_DESCR_BLOCK) + 37208c2ecf20Sopenharmony_ci PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX + 37218c2ecf20Sopenharmony_ci#ifndef DYNAMIC_BUFFERS 37228c2ecf20Sopenharmony_ci (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) + 37238c2ecf20Sopenharmony_ci#endif 37248c2ecf20Sopenharmony_ci sizeof(PI_CONSUMER_BLOCK) + 37258c2ecf20Sopenharmony_ci (PI_ALIGN_K_DESC_BLK - 1); 37268c2ecf20Sopenharmony_ci if (bp->kmalloced) 37278c2ecf20Sopenharmony_ci dma_free_coherent(bdev, alloc_size, 37288c2ecf20Sopenharmony_ci bp->kmalloced, bp->kmalloced_dma); 37298c2ecf20Sopenharmony_ci 37308c2ecf20Sopenharmony_ci dfx_bus_uninit(dev); 37318c2ecf20Sopenharmony_ci 37328c2ecf20Sopenharmony_ci dfx_get_bars(bdev, bar_start, bar_len); 37338c2ecf20Sopenharmony_ci if (bar_start[2] != 0) 37348c2ecf20Sopenharmony_ci release_region(bar_start[2], bar_len[2]); 37358c2ecf20Sopenharmony_ci if (bar_start[1] != 0) 37368c2ecf20Sopenharmony_ci release_region(bar_start[1], bar_len[1]); 37378c2ecf20Sopenharmony_ci if (dfx_use_mmio) { 37388c2ecf20Sopenharmony_ci iounmap(bp->base.mem); 37398c2ecf20Sopenharmony_ci release_mem_region(bar_start[0], bar_len[0]); 37408c2ecf20Sopenharmony_ci } else 37418c2ecf20Sopenharmony_ci release_region(bar_start[0], bar_len[0]); 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_ci if (dfx_bus_pci) 37448c2ecf20Sopenharmony_ci pci_disable_device(to_pci_dev(bdev)); 37458c2ecf20Sopenharmony_ci 37468c2ecf20Sopenharmony_ci free_netdev(dev); 37478c2ecf20Sopenharmony_ci} 37488c2ecf20Sopenharmony_ci 37498c2ecf20Sopenharmony_ci 37508c2ecf20Sopenharmony_cistatic int __maybe_unused dfx_dev_register(struct device *); 37518c2ecf20Sopenharmony_cistatic int __maybe_unused dfx_dev_unregister(struct device *); 37528c2ecf20Sopenharmony_ci 37538c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 37548c2ecf20Sopenharmony_cistatic int dfx_pci_register(struct pci_dev *, const struct pci_device_id *); 37558c2ecf20Sopenharmony_cistatic void dfx_pci_unregister(struct pci_dev *); 37568c2ecf20Sopenharmony_ci 37578c2ecf20Sopenharmony_cistatic const struct pci_device_id dfx_pci_table[] = { 37588c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI) }, 37598c2ecf20Sopenharmony_ci { } 37608c2ecf20Sopenharmony_ci}; 37618c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, dfx_pci_table); 37628c2ecf20Sopenharmony_ci 37638c2ecf20Sopenharmony_cistatic struct pci_driver dfx_pci_driver = { 37648c2ecf20Sopenharmony_ci .name = "defxx", 37658c2ecf20Sopenharmony_ci .id_table = dfx_pci_table, 37668c2ecf20Sopenharmony_ci .probe = dfx_pci_register, 37678c2ecf20Sopenharmony_ci .remove = dfx_pci_unregister, 37688c2ecf20Sopenharmony_ci}; 37698c2ecf20Sopenharmony_ci 37708c2ecf20Sopenharmony_cistatic int dfx_pci_register(struct pci_dev *pdev, 37718c2ecf20Sopenharmony_ci const struct pci_device_id *ent) 37728c2ecf20Sopenharmony_ci{ 37738c2ecf20Sopenharmony_ci return dfx_register(&pdev->dev); 37748c2ecf20Sopenharmony_ci} 37758c2ecf20Sopenharmony_ci 37768c2ecf20Sopenharmony_cistatic void dfx_pci_unregister(struct pci_dev *pdev) 37778c2ecf20Sopenharmony_ci{ 37788c2ecf20Sopenharmony_ci dfx_unregister(&pdev->dev); 37798c2ecf20Sopenharmony_ci} 37808c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 37818c2ecf20Sopenharmony_ci 37828c2ecf20Sopenharmony_ci#ifdef CONFIG_EISA 37838c2ecf20Sopenharmony_cistatic const struct eisa_device_id dfx_eisa_table[] = { 37848c2ecf20Sopenharmony_ci { "DEC3001", DEFEA_PROD_ID_1 }, 37858c2ecf20Sopenharmony_ci { "DEC3002", DEFEA_PROD_ID_2 }, 37868c2ecf20Sopenharmony_ci { "DEC3003", DEFEA_PROD_ID_3 }, 37878c2ecf20Sopenharmony_ci { "DEC3004", DEFEA_PROD_ID_4 }, 37888c2ecf20Sopenharmony_ci { } 37898c2ecf20Sopenharmony_ci}; 37908c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(eisa, dfx_eisa_table); 37918c2ecf20Sopenharmony_ci 37928c2ecf20Sopenharmony_cistatic struct eisa_driver dfx_eisa_driver = { 37938c2ecf20Sopenharmony_ci .id_table = dfx_eisa_table, 37948c2ecf20Sopenharmony_ci .driver = { 37958c2ecf20Sopenharmony_ci .name = "defxx", 37968c2ecf20Sopenharmony_ci .bus = &eisa_bus_type, 37978c2ecf20Sopenharmony_ci .probe = dfx_dev_register, 37988c2ecf20Sopenharmony_ci .remove = dfx_dev_unregister, 37998c2ecf20Sopenharmony_ci }, 38008c2ecf20Sopenharmony_ci}; 38018c2ecf20Sopenharmony_ci#endif /* CONFIG_EISA */ 38028c2ecf20Sopenharmony_ci 38038c2ecf20Sopenharmony_ci#ifdef CONFIG_TC 38048c2ecf20Sopenharmony_cistatic struct tc_device_id const dfx_tc_table[] = { 38058c2ecf20Sopenharmony_ci { "DEC ", "PMAF-FA " }, 38068c2ecf20Sopenharmony_ci { "DEC ", "PMAF-FD " }, 38078c2ecf20Sopenharmony_ci { "DEC ", "PMAF-FS " }, 38088c2ecf20Sopenharmony_ci { "DEC ", "PMAF-FU " }, 38098c2ecf20Sopenharmony_ci { } 38108c2ecf20Sopenharmony_ci}; 38118c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(tc, dfx_tc_table); 38128c2ecf20Sopenharmony_ci 38138c2ecf20Sopenharmony_cistatic struct tc_driver dfx_tc_driver = { 38148c2ecf20Sopenharmony_ci .id_table = dfx_tc_table, 38158c2ecf20Sopenharmony_ci .driver = { 38168c2ecf20Sopenharmony_ci .name = "defxx", 38178c2ecf20Sopenharmony_ci .bus = &tc_bus_type, 38188c2ecf20Sopenharmony_ci .probe = dfx_dev_register, 38198c2ecf20Sopenharmony_ci .remove = dfx_dev_unregister, 38208c2ecf20Sopenharmony_ci }, 38218c2ecf20Sopenharmony_ci}; 38228c2ecf20Sopenharmony_ci#endif /* CONFIG_TC */ 38238c2ecf20Sopenharmony_ci 38248c2ecf20Sopenharmony_cistatic int __maybe_unused dfx_dev_register(struct device *dev) 38258c2ecf20Sopenharmony_ci{ 38268c2ecf20Sopenharmony_ci int status; 38278c2ecf20Sopenharmony_ci 38288c2ecf20Sopenharmony_ci status = dfx_register(dev); 38298c2ecf20Sopenharmony_ci if (!status) 38308c2ecf20Sopenharmony_ci get_device(dev); 38318c2ecf20Sopenharmony_ci return status; 38328c2ecf20Sopenharmony_ci} 38338c2ecf20Sopenharmony_ci 38348c2ecf20Sopenharmony_cistatic int __maybe_unused dfx_dev_unregister(struct device *dev) 38358c2ecf20Sopenharmony_ci{ 38368c2ecf20Sopenharmony_ci put_device(dev); 38378c2ecf20Sopenharmony_ci dfx_unregister(dev); 38388c2ecf20Sopenharmony_ci return 0; 38398c2ecf20Sopenharmony_ci} 38408c2ecf20Sopenharmony_ci 38418c2ecf20Sopenharmony_ci 38428c2ecf20Sopenharmony_cistatic int dfx_init(void) 38438c2ecf20Sopenharmony_ci{ 38448c2ecf20Sopenharmony_ci int status; 38458c2ecf20Sopenharmony_ci 38468c2ecf20Sopenharmony_ci status = pci_register_driver(&dfx_pci_driver); 38478c2ecf20Sopenharmony_ci if (status) 38488c2ecf20Sopenharmony_ci goto err_pci_register; 38498c2ecf20Sopenharmony_ci 38508c2ecf20Sopenharmony_ci status = eisa_driver_register(&dfx_eisa_driver); 38518c2ecf20Sopenharmony_ci if (status) 38528c2ecf20Sopenharmony_ci goto err_eisa_register; 38538c2ecf20Sopenharmony_ci 38548c2ecf20Sopenharmony_ci status = tc_register_driver(&dfx_tc_driver); 38558c2ecf20Sopenharmony_ci if (status) 38568c2ecf20Sopenharmony_ci goto err_tc_register; 38578c2ecf20Sopenharmony_ci 38588c2ecf20Sopenharmony_ci return 0; 38598c2ecf20Sopenharmony_ci 38608c2ecf20Sopenharmony_cierr_tc_register: 38618c2ecf20Sopenharmony_ci eisa_driver_unregister(&dfx_eisa_driver); 38628c2ecf20Sopenharmony_cierr_eisa_register: 38638c2ecf20Sopenharmony_ci pci_unregister_driver(&dfx_pci_driver); 38648c2ecf20Sopenharmony_cierr_pci_register: 38658c2ecf20Sopenharmony_ci return status; 38668c2ecf20Sopenharmony_ci} 38678c2ecf20Sopenharmony_ci 38688c2ecf20Sopenharmony_cistatic void dfx_cleanup(void) 38698c2ecf20Sopenharmony_ci{ 38708c2ecf20Sopenharmony_ci tc_unregister_driver(&dfx_tc_driver); 38718c2ecf20Sopenharmony_ci eisa_driver_unregister(&dfx_eisa_driver); 38728c2ecf20Sopenharmony_ci pci_unregister_driver(&dfx_pci_driver); 38738c2ecf20Sopenharmony_ci} 38748c2ecf20Sopenharmony_ci 38758c2ecf20Sopenharmony_cimodule_init(dfx_init); 38768c2ecf20Sopenharmony_cimodule_exit(dfx_cleanup); 38778c2ecf20Sopenharmony_ciMODULE_AUTHOR("Lawrence V. Stefani"); 38788c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DEC FDDIcontroller TC/EISA/PCI (DEFTA/DEFEA/DEFPA) driver " 38798c2ecf20Sopenharmony_ci DRV_VERSION " " DRV_RELDATE); 38808c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3881