1da5577f0SRobert Mustacchi /* 2da5577f0SRobert Mustacchi * This file and its contents are supplied under the terms of the 3da5577f0SRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0. 4da5577f0SRobert Mustacchi * You may only use this file in accordance with the terms of version 5da5577f0SRobert Mustacchi * 1.0 of the CDDL. 6da5577f0SRobert Mustacchi * 7da5577f0SRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this 8da5577f0SRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at 9da5577f0SRobert Mustacchi * http://www.illumos.org/license/CDDL. 10da5577f0SRobert Mustacchi */ 11da5577f0SRobert Mustacchi 12da5577f0SRobert Mustacchi /* 13da5577f0SRobert Mustacchi * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved. 148d5069bcSRyan Zezeski * Copyright 2019 Joyent, Inc. 1505768666SPaul Winder * Copyright 2017 Tegile Systems, Inc. All rights reserved. 16da5577f0SRobert Mustacchi */ 17da5577f0SRobert Mustacchi 18da5577f0SRobert Mustacchi /* 19da5577f0SRobert Mustacchi * i40e - Intel 10/40 Gb Ethernet driver 20da5577f0SRobert Mustacchi * 21da5577f0SRobert Mustacchi * The i40e driver is the main software device driver for the Intel 40 Gb family 22da5577f0SRobert Mustacchi * of devices. Note that these devices come in many flavors with both 40 GbE 23da5577f0SRobert Mustacchi * ports and 10 GbE ports. This device is the successor to the 82599 family of 24da5577f0SRobert Mustacchi * devices (ixgbe). 25da5577f0SRobert Mustacchi * 26da5577f0SRobert Mustacchi * Unlike previous generations of Intel 1 GbE and 10 GbE devices, the 40 GbE 27da5577f0SRobert Mustacchi * devices defined in the XL710 controller (previously known as Fortville) are a 28da5577f0SRobert Mustacchi * rather different beast and have a small switch embedded inside of them. In 29da5577f0SRobert Mustacchi * addition, the way that most of the programming is done has been overhauled. 30da5577f0SRobert Mustacchi * As opposed to just using PCIe memory mapped registers, it also has an 31da5577f0SRobert Mustacchi * administrative queue which is used to communicate with firmware running on 32da5577f0SRobert Mustacchi * the chip. 33da5577f0SRobert Mustacchi * 34da5577f0SRobert Mustacchi * Each physical function in the hardware shows up as a device that this driver 35da5577f0SRobert Mustacchi * will bind to. The hardware splits many resources evenly across all of the 36da5577f0SRobert Mustacchi * physical functions present on the device, while other resources are instead 37da5577f0SRobert Mustacchi * shared across the entire card and its up to the device driver to 38da5577f0SRobert Mustacchi * intelligently partition them. 39da5577f0SRobert Mustacchi * 40da5577f0SRobert Mustacchi * ------------ 41da5577f0SRobert Mustacchi * Organization 42da5577f0SRobert Mustacchi * ------------ 43da5577f0SRobert Mustacchi * 44da5577f0SRobert Mustacchi * This driver is made up of several files which have their own theory 45da5577f0SRobert Mustacchi * statements spread across them. We'll touch on the high level purpose of each 46da5577f0SRobert Mustacchi * file here, and then we'll get into more discussion on how the device is 47da5577f0SRobert Mustacchi * generally modelled with respect to the interfaces in illumos. 48da5577f0SRobert Mustacchi * 49da5577f0SRobert Mustacchi * i40e_gld.c: This file contains all of the bindings to MAC and the networking 50da5577f0SRobert Mustacchi * stack. 51da5577f0SRobert Mustacchi * 52da5577f0SRobert Mustacchi * i40e_intr.c: This file contains all of the interrupt service routines and 53da5577f0SRobert Mustacchi * contains logic to enable and disable interrupts on the hardware. 54da5577f0SRobert Mustacchi * It also contains the logic to map hardware resources such as the 55da5577f0SRobert Mustacchi * rings to and from interrupts and controls their ability to fire. 56da5577f0SRobert Mustacchi * 57da5577f0SRobert Mustacchi * There is a big theory statement on interrupts present there. 58da5577f0SRobert Mustacchi * 59da5577f0SRobert Mustacchi * i40e_main.c: The file that you're currently in. It interfaces with the 60da5577f0SRobert Mustacchi * traditional OS DDI interfaces and is in charge of configuring 61da5577f0SRobert Mustacchi * the device. 62da5577f0SRobert Mustacchi * 63da5577f0SRobert Mustacchi * i40e_osdep.[ch]: These files contain interfaces and definitions needed to 64da5577f0SRobert Mustacchi * work with Intel's common code for the device. 65da5577f0SRobert Mustacchi * 66da5577f0SRobert Mustacchi * i40e_stats.c: This file contains the general work and logic around our 67da5577f0SRobert Mustacchi * kstats. A theory statement on their organization and use of the 68da5577f0SRobert Mustacchi * hardware exists there. 69da5577f0SRobert Mustacchi * 70da5577f0SRobert Mustacchi * i40e_sw.h: This header file contains all of the primary structure definitions 71da5577f0SRobert Mustacchi * and constants that are used across the entire driver. 72da5577f0SRobert Mustacchi * 73da5577f0SRobert Mustacchi * i40e_transceiver.c: This file contains all of the logic for sending and 74da5577f0SRobert Mustacchi * receiving data. It contains all of the ring and DMA 75da5577f0SRobert Mustacchi * allocation logic, as well as, the actual interfaces to 76da5577f0SRobert Mustacchi * send and receive data. 77da5577f0SRobert Mustacchi * 78da5577f0SRobert Mustacchi * A big theory statement on ring management, descriptors, 79da5577f0SRobert Mustacchi * and how it ties into the OS is present there. 80da5577f0SRobert Mustacchi * 81da5577f0SRobert Mustacchi * -------------- 82da5577f0SRobert Mustacchi * General Design 83da5577f0SRobert Mustacchi * -------------- 84da5577f0SRobert Mustacchi * 85da5577f0SRobert Mustacchi * Before we go too far into the general way we've laid out data structures and 86da5577f0SRobert Mustacchi * the like, it's worth taking some time to explain how the hardware is 87da5577f0SRobert Mustacchi * organized. This organization informs a lot of how we do things at this time 88da5577f0SRobert Mustacchi * in the driver. 89da5577f0SRobert Mustacchi * 90da5577f0SRobert Mustacchi * Each physical device consists of a number of one or more ports, which are 91da5577f0SRobert Mustacchi * considered physical functions in the PCI sense and thus each get enumerated 92da5577f0SRobert Mustacchi * by the system, resulting in an instance being created and attached to. While 93da5577f0SRobert Mustacchi * there are many resources that are unique to each physical function eg. 94da5577f0SRobert Mustacchi * instance of the device, there are many that are shared across all of them. 95da5577f0SRobert Mustacchi * Several resources have an amount reserved for each Virtual Station Interface 96da5577f0SRobert Mustacchi * (VSI) and then a static pool of resources, available for all functions on the 97da5577f0SRobert Mustacchi * card. 98da5577f0SRobert Mustacchi * 99da5577f0SRobert Mustacchi * The most important resource in hardware are its transmit and receive queue 100da5577f0SRobert Mustacchi * pairs (i40e_trqpair_t). These should be thought of as rings in GLDv3 101da5577f0SRobert Mustacchi * parlance. There are a set number of these on each device; however, they are 102da5577f0SRobert Mustacchi * statically partitioned among all of the different physical functions. 103da5577f0SRobert Mustacchi * 104da5577f0SRobert Mustacchi * 'Fortville' (the code name for this device family) is basically a switch. To 105da5577f0SRobert Mustacchi * map MAC addresses and other things to queues, we end up having to create 106da5577f0SRobert Mustacchi * Virtual Station Interfaces (VSIs) and establish forwarding rules that direct 107da5577f0SRobert Mustacchi * traffic to a queue. A VSI owns a collection of queues and has a series of 108da5577f0SRobert Mustacchi * forwarding rules that point to it. One way to think of this is to treat it 109da5577f0SRobert Mustacchi * like MAC does a VNIC. When MAC refers to a group, a collection of rings and 110da5577f0SRobert Mustacchi * classification resources, that is a VSI in i40e. 111da5577f0SRobert Mustacchi * 112da5577f0SRobert Mustacchi * The sets of VSIs is shared across the entire device, though there may be some 113da5577f0SRobert Mustacchi * amount that are reserved to each PF. Because the GLDv3 does not let us change 114da5577f0SRobert Mustacchi * the number of groups dynamically, we instead statically divide this amount 115da5577f0SRobert Mustacchi * evenly between all the functions that exist. In addition, we have the same 116da5577f0SRobert Mustacchi * problem with the mac address forwarding rules. There are a static number that 117da5577f0SRobert Mustacchi * exist shared across all the functions. 118da5577f0SRobert Mustacchi * 119da5577f0SRobert Mustacchi * To handle both of these resources, what we end up doing is going through and 120da5577f0SRobert Mustacchi * determining which functions belong to the same device. Nominally one might do 121da5577f0SRobert Mustacchi * this by having a nexus driver; however, a prime requirement for a nexus 122da5577f0SRobert Mustacchi * driver is identifying the various children and activating them. While it is 123da5577f0SRobert Mustacchi * possible to get this information from NVRAM, we would end up duplicating a 124da5577f0SRobert Mustacchi * lot of the PCI enumeration logic. Really, at the end of the day, the device 125da5577f0SRobert Mustacchi * doesn't give us the traditional identification properties we want from a 126da5577f0SRobert Mustacchi * nexus driver. 127da5577f0SRobert Mustacchi * 128da5577f0SRobert Mustacchi * Instead, we rely on some properties that are guaranteed to be unique. While 129da5577f0SRobert Mustacchi * it might be tempting to leverage the PBA or serial number of the device from 130da5577f0SRobert Mustacchi * NVRAM, there is nothing that says that two devices can't be mis-programmed to 131da5577f0SRobert Mustacchi * have the same values in NVRAM. Instead, we uniquely identify a group of 132da5577f0SRobert Mustacchi * functions based on their parent in the /devices tree, their PCI bus and PCI 133da5577f0SRobert Mustacchi * function identifiers. Using either on their own may not be sufficient. 134da5577f0SRobert Mustacchi * 135da5577f0SRobert Mustacchi * For each unique PCI device that we encounter, we'll create a i40e_device_t. 136da5577f0SRobert Mustacchi * From there, because we don't have a good way to tell the GLDv3 about sharing 137da5577f0SRobert Mustacchi * resources between everything, we'll end up just dividing the resources 138da5577f0SRobert Mustacchi * evenly between all of the functions. Longer term, if we don't have to declare 139da5577f0SRobert Mustacchi * to the GLDv3 that these resources are shared, then we'll maintain a pool and 140b096a4f7SMarcel Telka * have each PF allocate from the pool in the device, thus if only two of four 141da5577f0SRobert Mustacchi * ports are being used, for example, then all of the resources can still be 142da5577f0SRobert Mustacchi * used. 143da5577f0SRobert Mustacchi * 144da5577f0SRobert Mustacchi * ------------------------------------------- 145da5577f0SRobert Mustacchi * Transmit and Receive Queue Pair Allocations 146da5577f0SRobert Mustacchi * ------------------------------------------- 147da5577f0SRobert Mustacchi * 148da5577f0SRobert Mustacchi * NVRAM ends up assigning each PF its own share of the transmit and receive LAN 149da5577f0SRobert Mustacchi * queue pairs, we have no way of modifying it, only observing it. From there, 150da5577f0SRobert Mustacchi * it's up to us to map these queues to VSIs and VFs. Since we don't support any 151da5577f0SRobert Mustacchi * VFs at this time, we only focus on assignments to VSIs. 152da5577f0SRobert Mustacchi * 153da5577f0SRobert Mustacchi * At the moment, we used a static mapping of transmit/receive queue pairs to a 154da5577f0SRobert Mustacchi * given VSI (eg. rings to a group). Though in the fullness of time, we want to 155da5577f0SRobert Mustacchi * make this something which is fully dynamic and take advantage of documented, 156da5577f0SRobert Mustacchi * but not yet available functionality for adding filters based on VXLAN and 157da5577f0SRobert Mustacchi * other encapsulation technologies. 158da5577f0SRobert Mustacchi * 159da5577f0SRobert Mustacchi * ------------------------------------- 160da5577f0SRobert Mustacchi * Broadcast, Multicast, and Promiscuous 161da5577f0SRobert Mustacchi * ------------------------------------- 162da5577f0SRobert Mustacchi * 163da5577f0SRobert Mustacchi * As part of the GLDv3, we need to make sure that we can handle receiving 164da5577f0SRobert Mustacchi * broadcast and multicast traffic. As well as enabling promiscuous mode when 165da5577f0SRobert Mustacchi * requested. GLDv3 requires that all broadcast and multicast traffic be 166da5577f0SRobert Mustacchi * retrieved by the default group, eg. the first one. This is the same thing as 167da5577f0SRobert Mustacchi * the default VSI. 168da5577f0SRobert Mustacchi * 169da5577f0SRobert Mustacchi * To receieve broadcast traffic, we enable it through the admin queue, rather 170da5577f0SRobert Mustacchi * than use one of our filters for it. For multicast traffic, we reserve a 171da5577f0SRobert Mustacchi * certain number of the hash filters and assign them to a given PF. When we 172b096a4f7SMarcel Telka * exceed those, we then switch to using promiscuous mode for multicast traffic. 173da5577f0SRobert Mustacchi * 174da5577f0SRobert Mustacchi * More specifically, once we exceed the number of filters (indicated because 175da5577f0SRobert Mustacchi * the i40e_t`i40e_resources.ifr_nmcastfilt == 176da5577f0SRobert Mustacchi * i40e_t`i40e_resources.ifr_nmcastfilt_used), we then instead need to toggle 177da5577f0SRobert Mustacchi * promiscuous mode. If promiscuous mode is toggled then we keep track of the 178da5577f0SRobert Mustacchi * number of MACs added to it by incrementing i40e_t`i40e_mcast_promisc_count. 179da5577f0SRobert Mustacchi * That will stay enabled until that count reaches zero indicating that we have 180da5577f0SRobert Mustacchi * only added multicast addresses that we have a corresponding entry for. 181da5577f0SRobert Mustacchi * 182da5577f0SRobert Mustacchi * Because MAC itself wants to toggle promiscuous mode, which includes both 183da5577f0SRobert Mustacchi * unicast and multicast traffic, we go through and keep track of that 184da5577f0SRobert Mustacchi * ourselves. That is maintained through the use of the i40e_t`i40e_promisc_on 185da5577f0SRobert Mustacchi * member. 186da5577f0SRobert Mustacchi * 187da5577f0SRobert Mustacchi * -------------- 188da5577f0SRobert Mustacchi * VSI Management 189da5577f0SRobert Mustacchi * -------------- 190da5577f0SRobert Mustacchi * 1918d5069bcSRyan Zezeski * The PFs share 384 VSIs. The firmware creates one VSI per PF by default. 1928d5069bcSRyan Zezeski * During chip start we retrieve the SEID of this VSI and assign it as the 1938d5069bcSRyan Zezeski * default VSI for our VEB (one VEB per PF). We then add additional VSIs to 1948d5069bcSRyan Zezeski * the VEB up to the determined number of rx groups: i40e_t`i40e_num_rx_groups. 1958d5069bcSRyan Zezeski * We currently cap this number to I40E_GROUP_MAX to a) make sure all PFs can 1968d5069bcSRyan Zezeski * allocate the same number of VSIs, and b) to keep the interrupt multiplexing 1978d5069bcSRyan Zezeski * under control. In the future, when we improve the interrupt allocation, we 1988d5069bcSRyan Zezeski * may want to revisit this cap to make better use of the available VSIs. The 1998d5069bcSRyan Zezeski * VSI allocation and configuration can be found in i40e_chip_start(). 200da5577f0SRobert Mustacchi * 201da5577f0SRobert Mustacchi * ---------------- 202da5577f0SRobert Mustacchi * Structure Layout 203da5577f0SRobert Mustacchi * ---------------- 204da5577f0SRobert Mustacchi * 205da5577f0SRobert Mustacchi * The following images relates the core data structures together. The primary 206da5577f0SRobert Mustacchi * structure in the system is the i40e_t. It itself contains multiple rings, 207da5577f0SRobert Mustacchi * i40e_trqpair_t's which contain the various transmit and receive data. The 208da5577f0SRobert Mustacchi * receive data is stored outside of the i40e_trqpair_t and instead in the 209da5577f0SRobert Mustacchi * i40e_rx_data_t. The i40e_t has a corresponding i40e_device_t which keeps 210da5577f0SRobert Mustacchi * track of per-physical device state. Finally, for every active descriptor, 211da5577f0SRobert Mustacchi * there is a corresponding control block, which is where the 212da5577f0SRobert Mustacchi * i40e_rx_control_block_t and the i40e_tx_control_block_t come from. 213da5577f0SRobert Mustacchi * 214da5577f0SRobert Mustacchi * +-----------------------+ +-----------------------+ 215da5577f0SRobert Mustacchi * | Global i40e_t list | | Global Device list | 216da5577f0SRobert Mustacchi * | | +--| | 217da5577f0SRobert Mustacchi * | i40e_glist | | | i40e_dlist | 218da5577f0SRobert Mustacchi * +-----------------------+ | +-----------------------+ 219da5577f0SRobert Mustacchi * | v 220da5577f0SRobert Mustacchi * | +------------------------+ +-----------------------+ 221da5577f0SRobert Mustacchi * | | Device-wide Structure |----->| Device-wide Structure |--> ... 222da5577f0SRobert Mustacchi * | | i40e_device_t | | i40e_device_t | 223da5577f0SRobert Mustacchi * | | | +-----------------------+ 224da5577f0SRobert Mustacchi * | | dev_info_t * ------+--> Parent in devices tree. 225da5577f0SRobert Mustacchi * | | uint_t ------+--> PCI bus number 226da5577f0SRobert Mustacchi * | | uint_t ------+--> PCI device number 227da5577f0SRobert Mustacchi * | | uint_t ------+--> Number of functions 228da5577f0SRobert Mustacchi * | | i40e_switch_rsrcs_t ---+--> Captured total switch resources 229da5577f0SRobert Mustacchi * | | list_t ------+-------------+ 230da5577f0SRobert Mustacchi * | +------------------------+ | 231da5577f0SRobert Mustacchi * | ^ | 232da5577f0SRobert Mustacchi * | +--------+ | 233da5577f0SRobert Mustacchi * | | v 234da5577f0SRobert Mustacchi * | +---------------------------+ | +-------------------+ 235da5577f0SRobert Mustacchi * +->| GLDv3 Device, per PF |-----|-->| GLDv3 Device (PF) |--> ... 236da5577f0SRobert Mustacchi * | i40e_t | | | i40e_t | 237da5577f0SRobert Mustacchi * | **Primary Structure** | | +-------------------+ 238da5577f0SRobert Mustacchi * | | | 239da5577f0SRobert Mustacchi * | i40e_device_t * --+-----+ 240da5577f0SRobert Mustacchi * | i40e_state_t --+---> Device State 241da5577f0SRobert Mustacchi * | i40e_hw_t --+---> Intel common code structure 242da5577f0SRobert Mustacchi * | mac_handle_t --+---> GLDv3 handle to MAC 243da5577f0SRobert Mustacchi * | ddi_periodic_t --+---> Link activity timer 2448d5069bcSRyan Zezeski * | i40e_vsi_t * --+---> Array of VSIs 245da5577f0SRobert Mustacchi * | i40e_func_rsrc_t --+---> Available hardware resources 246da5577f0SRobert Mustacchi * | i40e_switch_rsrc_t * --+---> Switch resource snapshot 247da5577f0SRobert Mustacchi * | i40e_sdu --+---> Current MTU 248da5577f0SRobert Mustacchi * | i40e_frame_max --+---> Current HW frame size 249da5577f0SRobert Mustacchi * | i40e_uaddr_t * --+---> Array of assigned unicast MACs 250da5577f0SRobert Mustacchi * | i40e_maddr_t * --+---> Array of assigned multicast MACs 251da5577f0SRobert Mustacchi * | i40e_mcast_promisccount --+---> Active multicast state 252da5577f0SRobert Mustacchi * | i40e_promisc_on --+---> Current promiscuous mode state 2538d5069bcSRyan Zezeski * | uint_t --+---> Number of transmit/receive pairs 2548d5069bcSRyan Zezeski * | i40e_rx_group_t * --+---> Array of Rx groups 255da5577f0SRobert Mustacchi * | kstat_t * --+---> PF kstats 256da5577f0SRobert Mustacchi * | i40e_pf_stats_t --+---> PF kstat backing data 257da5577f0SRobert Mustacchi * | i40e_trqpair_t * --+---------+ 258da5577f0SRobert Mustacchi * +---------------------------+ | 259da5577f0SRobert Mustacchi * | 260da5577f0SRobert Mustacchi * v 261da5577f0SRobert Mustacchi * +-------------------------------+ +-----------------------------+ 262da5577f0SRobert Mustacchi * | Transmit/Receive Queue Pair |-------| Transmit/Receive Queue Pair |->... 263da5577f0SRobert Mustacchi * | i40e_trqpair_t | | i40e_trqpair_t | 264da5577f0SRobert Mustacchi * + Ring Data Structure | +-----------------------------+ 265da5577f0SRobert Mustacchi * | | 266da5577f0SRobert Mustacchi * | mac_ring_handle_t +--> MAC RX ring handle 267da5577f0SRobert Mustacchi * | mac_ring_handle_t +--> MAC TX ring handle 268da5577f0SRobert Mustacchi * | i40e_rxq_stat_t --+--> RX Queue stats 269da5577f0SRobert Mustacchi * | i40e_txq_stat_t --+--> TX Queue stats 270da5577f0SRobert Mustacchi * | uint32_t (tx ring size) +--> TX Ring Size 271da5577f0SRobert Mustacchi * | uint32_t (tx free list size) +--> TX Free List Size 272da5577f0SRobert Mustacchi * | i40e_dma_buffer_t --------+--> TX Descriptor ring DMA 273da5577f0SRobert Mustacchi * | i40e_tx_desc_t * --------+--> TX descriptor ring 274da5577f0SRobert Mustacchi * | volatile unt32_t * +--> TX Write back head 275da5577f0SRobert Mustacchi * | uint32_t -------+--> TX ring head 276da5577f0SRobert Mustacchi * | uint32_t -------+--> TX ring tail 277da5577f0SRobert Mustacchi * | uint32_t -------+--> Num TX desc free 278da5577f0SRobert Mustacchi * | i40e_tx_control_block_t * --+--> TX control block array ---+ 279da5577f0SRobert Mustacchi * | i40e_tx_control_block_t ** --+--> TCB work list ----+ 280da5577f0SRobert Mustacchi * | i40e_tx_control_block_t ** --+--> TCB free list ---+ 281da5577f0SRobert Mustacchi * | uint32_t -------+--> Free TCB count | 282da5577f0SRobert Mustacchi * | i40e_rx_data_t * -------+--+ v 283da5577f0SRobert Mustacchi * +-------------------------------+ | +---------------------------+ 284da5577f0SRobert Mustacchi * | | Per-TX Frame Metadata | 285da5577f0SRobert Mustacchi * | | i40e_tx_control_block_t | 286da5577f0SRobert Mustacchi * +--------------------+ | | 287da5577f0SRobert Mustacchi * | mblk to transmit <--+--- mblk_t * | 288da5577f0SRobert Mustacchi * | type of transmit <--+--- i40e_tx_type_t | 289da5577f0SRobert Mustacchi * | TX DMA handle <--+--- ddi_dma_handle_t | 290da5577f0SRobert Mustacchi * v TX DMA buffer <--+--- i40e_dma_buffer_t | 291da5577f0SRobert Mustacchi * +------------------------------+ +---------------------------+ 292da5577f0SRobert Mustacchi * | Core Receive Data | 293da5577f0SRobert Mustacchi * | i40e_rx_data_t | 294da5577f0SRobert Mustacchi * | | 295da5577f0SRobert Mustacchi * | i40e_dma_buffer_t --+--> RX descriptor DMA Data 296da5577f0SRobert Mustacchi * | i40e_rx_desc_t --+--> RX descriptor ring 297da5577f0SRobert Mustacchi * | uint32_t --+--> Next free desc. 298da5577f0SRobert Mustacchi * | i40e_rx_control_block_t * --+--> RX Control Block Array ---+ 299da5577f0SRobert Mustacchi * | i40e_rx_control_block_t ** --+--> RCB work list ---+ 300da5577f0SRobert Mustacchi * | i40e_rx_control_block_t ** --+--> RCB free list ---+ 301da5577f0SRobert Mustacchi * +------------------------------+ | 302da5577f0SRobert Mustacchi * ^ | 303da5577f0SRobert Mustacchi * | +---------------------------+ | 304da5577f0SRobert Mustacchi * | | Per-RX Frame Metadata |<---------------+ 305da5577f0SRobert Mustacchi * | | i40e_rx_control_block_t | 306da5577f0SRobert Mustacchi * | | | 307da5577f0SRobert Mustacchi * | | mblk_t * ----+--> Received mblk_t data 308da5577f0SRobert Mustacchi * | | uint32_t ----+--> Reference count 309da5577f0SRobert Mustacchi * | | i40e_dma_buffer_t ----+--> Receive data DMA info 310da5577f0SRobert Mustacchi * | | frtn_t ----+--> mblk free function info 311da5577f0SRobert Mustacchi * +-----+-- i40e_rx_data_t * | 312da5577f0SRobert Mustacchi * +---------------------------+ 313da5577f0SRobert Mustacchi * 314da5577f0SRobert Mustacchi * ------------- 315da5577f0SRobert Mustacchi * Lock Ordering 316da5577f0SRobert Mustacchi * ------------- 317da5577f0SRobert Mustacchi * 318da5577f0SRobert Mustacchi * In order to ensure that we don't deadlock, the following represents the 319da5577f0SRobert Mustacchi * lock order being used. When grabbing locks, follow the following order. Lower 320da5577f0SRobert Mustacchi * numbers are more important. Thus, the i40e_glock which is number 0, must be 321da5577f0SRobert Mustacchi * taken before any other locks in the driver. On the other hand, the 322da5577f0SRobert Mustacchi * i40e_t`i40e_stat_lock, has the highest number because it's the least 323da5577f0SRobert Mustacchi * important lock. Note, that just because one lock is higher than another does 324da5577f0SRobert Mustacchi * not mean that all intermediary locks are required. 325da5577f0SRobert Mustacchi * 326da5577f0SRobert Mustacchi * 0) i40e_glock 327da5577f0SRobert Mustacchi * 1) i40e_t`i40e_general_lock 328da5577f0SRobert Mustacchi * 329da5577f0SRobert Mustacchi * 2) i40e_trqpair_t`itrq_rx_lock 330da5577f0SRobert Mustacchi * 3) i40e_trqpair_t`itrq_tx_lock 331da5577f0SRobert Mustacchi * 4) i40e_t`i40e_rx_pending_lock 332da5577f0SRobert Mustacchi * 5) i40e_trqpair_t`itrq_tcb_lock 333da5577f0SRobert Mustacchi * 334da5577f0SRobert Mustacchi * 6) i40e_t`i40e_stat_lock 335da5577f0SRobert Mustacchi * 336da5577f0SRobert Mustacchi * Rules and expectations: 337da5577f0SRobert Mustacchi * 338da5577f0SRobert Mustacchi * 1) A thread holding locks belong to one PF should not hold locks belonging to 339da5577f0SRobert Mustacchi * a second. If for some reason this becomes necessary, locks should be grabbed 340da5577f0SRobert Mustacchi * based on the list order in the i40e_device_t, which implies that the 341da5577f0SRobert Mustacchi * i40e_glock is held. 342da5577f0SRobert Mustacchi * 343da5577f0SRobert Mustacchi * 2) When grabbing locks between multiple transmit and receive queues, the 344da5577f0SRobert Mustacchi * locks for the lowest number transmit/receive queue should be grabbed first. 345da5577f0SRobert Mustacchi * 346da5577f0SRobert Mustacchi * 3) When grabbing both the transmit and receive lock for a given queue, always 347da5577f0SRobert Mustacchi * grab i40e_trqpair_t`itrq_rx_lock before the i40e_trqpair_t`itrq_tx_lock. 348da5577f0SRobert Mustacchi * 349da5577f0SRobert Mustacchi * 4) The following pairs of locks are not expected to be held at the same time: 350da5577f0SRobert Mustacchi * 351da5577f0SRobert Mustacchi * o i40e_t`i40e_rx_pending_lock and i40e_trqpair_t`itrq_tcb_lock 352da5577f0SRobert Mustacchi * 353da5577f0SRobert Mustacchi * ----------- 354da5577f0SRobert Mustacchi * Future Work 355da5577f0SRobert Mustacchi * ----------- 356da5577f0SRobert Mustacchi * 357da5577f0SRobert Mustacchi * At the moment the i40e_t driver is rather bare bones, allowing us to start 358da5577f0SRobert Mustacchi * getting data flowing and folks using it while we develop additional features. 359da5577f0SRobert Mustacchi * While bugs have been filed to cover this future work, the following gives an 360da5577f0SRobert Mustacchi * overview of expected work: 361da5577f0SRobert Mustacchi * 362da5577f0SRobert Mustacchi * o DMA binding and breaking up the locking in ring recycling. 363da5577f0SRobert Mustacchi * o Enhanced detection of device errors 364da5577f0SRobert Mustacchi * o Participation in IRM 365da5577f0SRobert Mustacchi * o FMA device reset 366da5577f0SRobert Mustacchi * o Stall detection, temperature error detection, etc. 367da5577f0SRobert Mustacchi * o More dynamic resource pools 368da5577f0SRobert Mustacchi */ 369da5577f0SRobert Mustacchi 370da5577f0SRobert Mustacchi #include "i40e_sw.h" 371da5577f0SRobert Mustacchi 3728d5069bcSRyan Zezeski static char i40e_ident[] = "Intel 10/40Gb Ethernet v1.0.3"; 373da5577f0SRobert Mustacchi 374da5577f0SRobert Mustacchi /* 375da5577f0SRobert Mustacchi * The i40e_glock primarily protects the lists below and the i40e_device_t 376da5577f0SRobert Mustacchi * structures. 377da5577f0SRobert Mustacchi */ 378da5577f0SRobert Mustacchi static kmutex_t i40e_glock; 379da5577f0SRobert Mustacchi static list_t i40e_glist; 380da5577f0SRobert Mustacchi static list_t i40e_dlist; 381da5577f0SRobert Mustacchi 382da5577f0SRobert Mustacchi /* 383da5577f0SRobert Mustacchi * Access attributes for register mapping. 384da5577f0SRobert Mustacchi */ 385da5577f0SRobert Mustacchi static ddi_device_acc_attr_t i40e_regs_acc_attr = { 386da5577f0SRobert Mustacchi DDI_DEVICE_ATTR_V1, 387da5577f0SRobert Mustacchi DDI_STRUCTURE_LE_ACC, 388da5577f0SRobert Mustacchi DDI_STRICTORDER_ACC, 389da5577f0SRobert Mustacchi DDI_FLAGERR_ACC 390da5577f0SRobert Mustacchi }; 391da5577f0SRobert Mustacchi 392da5577f0SRobert Mustacchi /* 393da5577f0SRobert Mustacchi * Logging function for this driver. 394da5577f0SRobert Mustacchi */ 395da5577f0SRobert Mustacchi static void 396da5577f0SRobert Mustacchi i40e_dev_err(i40e_t *i40e, int level, boolean_t console, const char *fmt, 397da5577f0SRobert Mustacchi va_list ap) 398da5577f0SRobert Mustacchi { 399da5577f0SRobert Mustacchi char buf[1024]; 400da5577f0SRobert Mustacchi 401da5577f0SRobert Mustacchi (void) vsnprintf(buf, sizeof (buf), fmt, ap); 402da5577f0SRobert Mustacchi 403da5577f0SRobert Mustacchi if (i40e == NULL) { 404da5577f0SRobert Mustacchi cmn_err(level, (console) ? "%s: %s" : "!%s: %s", 405da5577f0SRobert Mustacchi I40E_MODULE_NAME, buf); 406da5577f0SRobert Mustacchi } else { 407da5577f0SRobert Mustacchi dev_err(i40e->i40e_dip, level, (console) ? "%s" : "!%s", 408da5577f0SRobert Mustacchi buf); 409da5577f0SRobert Mustacchi } 410da5577f0SRobert Mustacchi } 411da5577f0SRobert Mustacchi 412da5577f0SRobert Mustacchi /* 413da5577f0SRobert Mustacchi * Because there's the stupid trailing-comma problem with the C preprocessor 414da5577f0SRobert Mustacchi * and variable arguments, I need to instantiate these. Pardon the redundant 415da5577f0SRobert Mustacchi * code. 416da5577f0SRobert Mustacchi */ 417da5577f0SRobert Mustacchi /*PRINTFLIKE2*/ 418da5577f0SRobert Mustacchi void 419da5577f0SRobert Mustacchi i40e_error(i40e_t *i40e, const char *fmt, ...) 420da5577f0SRobert Mustacchi { 421da5577f0SRobert Mustacchi va_list ap; 422da5577f0SRobert Mustacchi 423da5577f0SRobert Mustacchi va_start(ap, fmt); 424da5577f0SRobert Mustacchi i40e_dev_err(i40e, CE_WARN, B_FALSE, fmt, ap); 425da5577f0SRobert Mustacchi va_end(ap); 426da5577f0SRobert Mustacchi } 427da5577f0SRobert Mustacchi 428da5577f0SRobert Mustacchi /*PRINTFLIKE2*/ 429da5577f0SRobert Mustacchi void 430da5577f0SRobert Mustacchi i40e_log(i40e_t *i40e, const char *fmt, ...) 431da5577f0SRobert Mustacchi { 432da5577f0SRobert Mustacchi va_list ap; 433da5577f0SRobert Mustacchi 434da5577f0SRobert Mustacchi va_start(ap, fmt); 435da5577f0SRobert Mustacchi i40e_dev_err(i40e, CE_NOTE, B_FALSE, fmt, ap); 436da5577f0SRobert Mustacchi va_end(ap); 437da5577f0SRobert Mustacchi } 438da5577f0SRobert Mustacchi 439da5577f0SRobert Mustacchi /*PRINTFLIKE2*/ 440da5577f0SRobert Mustacchi void 441da5577f0SRobert Mustacchi i40e_notice(i40e_t *i40e, const char *fmt, ...) 442da5577f0SRobert Mustacchi { 443da5577f0SRobert Mustacchi va_list ap; 444da5577f0SRobert Mustacchi 445da5577f0SRobert Mustacchi va_start(ap, fmt); 446da5577f0SRobert Mustacchi i40e_dev_err(i40e, CE_NOTE, B_TRUE, fmt, ap); 447da5577f0SRobert Mustacchi va_end(ap); 448da5577f0SRobert Mustacchi } 449da5577f0SRobert Mustacchi 450a7f9b000SRobert Mustacchi /* 451a7f9b000SRobert Mustacchi * Various parts of the driver need to know if the controller is from the X722 452a7f9b000SRobert Mustacchi * family, which has a few additional capabilities and different programming 453a7f9b000SRobert Mustacchi * means. We don't consider virtual functions as part of this as they are quite 454a7f9b000SRobert Mustacchi * different and will require substantially more work. 455a7f9b000SRobert Mustacchi */ 456a7f9b000SRobert Mustacchi static boolean_t 457a7f9b000SRobert Mustacchi i40e_is_x722(i40e_t *i40e) 458a7f9b000SRobert Mustacchi { 459a7f9b000SRobert Mustacchi return (i40e->i40e_hw_space.mac.type == I40E_MAC_X722); 460a7f9b000SRobert Mustacchi } 461a7f9b000SRobert Mustacchi 462da5577f0SRobert Mustacchi static void 463da5577f0SRobert Mustacchi i40e_device_rele(i40e_t *i40e) 464da5577f0SRobert Mustacchi { 465da5577f0SRobert Mustacchi i40e_device_t *idp = i40e->i40e_device; 466da5577f0SRobert Mustacchi 467da5577f0SRobert Mustacchi if (idp == NULL) 468da5577f0SRobert Mustacchi return; 469da5577f0SRobert Mustacchi 470da5577f0SRobert Mustacchi mutex_enter(&i40e_glock); 471da5577f0SRobert Mustacchi VERIFY(idp->id_nreg > 0); 472da5577f0SRobert Mustacchi list_remove(&idp->id_i40e_list, i40e); 473da5577f0SRobert Mustacchi idp->id_nreg--; 474da5577f0SRobert Mustacchi if (idp->id_nreg == 0) { 475da5577f0SRobert Mustacchi list_remove(&i40e_dlist, idp); 476da5577f0SRobert Mustacchi list_destroy(&idp->id_i40e_list); 477da5577f0SRobert Mustacchi kmem_free(idp->id_rsrcs, sizeof (i40e_switch_rsrc_t) * 478da5577f0SRobert Mustacchi idp->id_rsrcs_alloc); 479da5577f0SRobert Mustacchi kmem_free(idp, sizeof (i40e_device_t)); 480da5577f0SRobert Mustacchi } 481da5577f0SRobert Mustacchi i40e->i40e_device = NULL; 482da5577f0SRobert Mustacchi mutex_exit(&i40e_glock); 483da5577f0SRobert Mustacchi } 484da5577f0SRobert Mustacchi 485da5577f0SRobert Mustacchi static i40e_device_t * 486da5577f0SRobert Mustacchi i40e_device_find(i40e_t *i40e, dev_info_t *parent, uint_t bus, uint_t device) 487da5577f0SRobert Mustacchi { 488da5577f0SRobert Mustacchi i40e_device_t *idp; 489da5577f0SRobert Mustacchi mutex_enter(&i40e_glock); 490da5577f0SRobert Mustacchi for (idp = list_head(&i40e_dlist); idp != NULL; 491da5577f0SRobert Mustacchi idp = list_next(&i40e_dlist, idp)) { 492da5577f0SRobert Mustacchi if (idp->id_parent == parent && idp->id_pci_bus == bus && 493da5577f0SRobert Mustacchi idp->id_pci_device == device) { 494da5577f0SRobert Mustacchi break; 495da5577f0SRobert Mustacchi } 496da5577f0SRobert Mustacchi } 497da5577f0SRobert Mustacchi 498da5577f0SRobert Mustacchi if (idp != NULL) { 499da5577f0SRobert Mustacchi VERIFY(idp->id_nreg < idp->id_nfuncs); 500da5577f0SRobert Mustacchi idp->id_nreg++; 501da5577f0SRobert Mustacchi } else { 502da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 503da5577f0SRobert Mustacchi ASSERT(hw->num_ports > 0); 504da5577f0SRobert Mustacchi ASSERT(hw->num_partitions > 0); 505da5577f0SRobert Mustacchi 506da5577f0SRobert Mustacchi /* 507da5577f0SRobert Mustacchi * The Intel common code doesn't exactly keep the number of PCI 508da5577f0SRobert Mustacchi * functions. But it calculates it during discovery of 509da5577f0SRobert Mustacchi * partitions and ports. So what we do is undo the calculation 510da5577f0SRobert Mustacchi * that it does originally, as functions are evenly spread 511da5577f0SRobert Mustacchi * across ports in the rare case of partitions. 512da5577f0SRobert Mustacchi */ 513da5577f0SRobert Mustacchi idp = kmem_alloc(sizeof (i40e_device_t), KM_SLEEP); 514da5577f0SRobert Mustacchi idp->id_parent = parent; 515da5577f0SRobert Mustacchi idp->id_pci_bus = bus; 516da5577f0SRobert Mustacchi idp->id_pci_device = device; 517da5577f0SRobert Mustacchi idp->id_nfuncs = hw->num_ports * hw->num_partitions; 518da5577f0SRobert Mustacchi idp->id_nreg = 1; 519da5577f0SRobert Mustacchi idp->id_rsrcs_alloc = i40e->i40e_switch_rsrc_alloc; 520da5577f0SRobert Mustacchi idp->id_rsrcs_act = i40e->i40e_switch_rsrc_actual; 521da5577f0SRobert Mustacchi idp->id_rsrcs = kmem_alloc(sizeof (i40e_switch_rsrc_t) * 522da5577f0SRobert Mustacchi idp->id_rsrcs_alloc, KM_SLEEP); 523da5577f0SRobert Mustacchi bcopy(i40e->i40e_switch_rsrcs, idp->id_rsrcs, 524da5577f0SRobert Mustacchi sizeof (i40e_switch_rsrc_t) * idp->id_rsrcs_alloc); 525da5577f0SRobert Mustacchi list_create(&idp->id_i40e_list, sizeof (i40e_t), 526da5577f0SRobert Mustacchi offsetof(i40e_t, i40e_dlink)); 527da5577f0SRobert Mustacchi 528da5577f0SRobert Mustacchi list_insert_tail(&i40e_dlist, idp); 529da5577f0SRobert Mustacchi } 530da5577f0SRobert Mustacchi 531da5577f0SRobert Mustacchi list_insert_tail(&idp->id_i40e_list, i40e); 532da5577f0SRobert Mustacchi mutex_exit(&i40e_glock); 533da5577f0SRobert Mustacchi 534da5577f0SRobert Mustacchi return (idp); 535da5577f0SRobert Mustacchi } 536da5577f0SRobert Mustacchi 537da5577f0SRobert Mustacchi static void 538da5577f0SRobert Mustacchi i40e_link_state_set(i40e_t *i40e, link_state_t state) 539da5577f0SRobert Mustacchi { 540da5577f0SRobert Mustacchi if (i40e->i40e_link_state == state) 541da5577f0SRobert Mustacchi return; 542da5577f0SRobert Mustacchi 543da5577f0SRobert Mustacchi i40e->i40e_link_state = state; 544da5577f0SRobert Mustacchi mac_link_update(i40e->i40e_mac_hdl, i40e->i40e_link_state); 545da5577f0SRobert Mustacchi } 546da5577f0SRobert Mustacchi 547da5577f0SRobert Mustacchi /* 548da5577f0SRobert Mustacchi * This is a basic link check routine. Mostly we're using this just to see 549da5577f0SRobert Mustacchi * if we can get any accurate information about the state of the link being 550da5577f0SRobert Mustacchi * up or down, as well as updating the link state, speed, etc. information. 551da5577f0SRobert Mustacchi */ 552da5577f0SRobert Mustacchi void 553da5577f0SRobert Mustacchi i40e_link_check(i40e_t *i40e) 554da5577f0SRobert Mustacchi { 555da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 556da5577f0SRobert Mustacchi boolean_t ls; 557da5577f0SRobert Mustacchi int ret; 558da5577f0SRobert Mustacchi 559da5577f0SRobert Mustacchi ASSERT(MUTEX_HELD(&i40e->i40e_general_lock)); 560da5577f0SRobert Mustacchi 561da5577f0SRobert Mustacchi hw->phy.get_link_info = B_TRUE; 562da5577f0SRobert Mustacchi if ((ret = i40e_get_link_status(hw, &ls)) != I40E_SUCCESS) { 563da5577f0SRobert Mustacchi i40e->i40e_s_link_status_errs++; 564da5577f0SRobert Mustacchi i40e->i40e_s_link_status_lasterr = ret; 565da5577f0SRobert Mustacchi return; 566da5577f0SRobert Mustacchi } 567da5577f0SRobert Mustacchi 568da5577f0SRobert Mustacchi /* 569da5577f0SRobert Mustacchi * Firmware abstracts all of the mac and phy information for us, so we 570da5577f0SRobert Mustacchi * can use i40e_get_link_status to determine the current state. 571da5577f0SRobert Mustacchi */ 572da5577f0SRobert Mustacchi if (ls == B_TRUE) { 573da5577f0SRobert Mustacchi enum i40e_aq_link_speed speed; 574da5577f0SRobert Mustacchi 575da5577f0SRobert Mustacchi speed = i40e_get_link_speed(hw); 576da5577f0SRobert Mustacchi 577da5577f0SRobert Mustacchi /* 578da5577f0SRobert Mustacchi * Translate from an i40e value to a value in Mbits/s. 579da5577f0SRobert Mustacchi */ 580da5577f0SRobert Mustacchi switch (speed) { 581da5577f0SRobert Mustacchi case I40E_LINK_SPEED_100MB: 582da5577f0SRobert Mustacchi i40e->i40e_link_speed = 100; 583da5577f0SRobert Mustacchi break; 584da5577f0SRobert Mustacchi case I40E_LINK_SPEED_1GB: 585da5577f0SRobert Mustacchi i40e->i40e_link_speed = 1000; 586da5577f0SRobert Mustacchi break; 587da5577f0SRobert Mustacchi case I40E_LINK_SPEED_10GB: 588da5577f0SRobert Mustacchi i40e->i40e_link_speed = 10000; 589da5577f0SRobert Mustacchi break; 590da5577f0SRobert Mustacchi case I40E_LINK_SPEED_20GB: 591da5577f0SRobert Mustacchi i40e->i40e_link_speed = 20000; 592da5577f0SRobert Mustacchi break; 593da5577f0SRobert Mustacchi case I40E_LINK_SPEED_40GB: 594da5577f0SRobert Mustacchi i40e->i40e_link_speed = 40000; 595da5577f0SRobert Mustacchi break; 596422542c1SRobert Mustacchi case I40E_LINK_SPEED_25GB: 597422542c1SRobert Mustacchi i40e->i40e_link_speed = 25000; 598422542c1SRobert Mustacchi break; 599da5577f0SRobert Mustacchi default: 600da5577f0SRobert Mustacchi i40e->i40e_link_speed = 0; 601da5577f0SRobert Mustacchi break; 602da5577f0SRobert Mustacchi } 603da5577f0SRobert Mustacchi 604da5577f0SRobert Mustacchi /* 605da5577f0SRobert Mustacchi * At this time, hardware does not support half-duplex 606da5577f0SRobert Mustacchi * operation, hence why we don't ask the hardware about our 607da5577f0SRobert Mustacchi * current speed. 608da5577f0SRobert Mustacchi */ 609da5577f0SRobert Mustacchi i40e->i40e_link_duplex = LINK_DUPLEX_FULL; 610da5577f0SRobert Mustacchi i40e_link_state_set(i40e, LINK_STATE_UP); 611da5577f0SRobert Mustacchi } else { 612da5577f0SRobert Mustacchi i40e->i40e_link_speed = 0; 613da5577f0SRobert Mustacchi i40e->i40e_link_duplex = 0; 614da5577f0SRobert Mustacchi i40e_link_state_set(i40e, LINK_STATE_DOWN); 615da5577f0SRobert Mustacchi } 616da5577f0SRobert Mustacchi } 617da5577f0SRobert Mustacchi 618da5577f0SRobert Mustacchi static void 619da5577f0SRobert Mustacchi i40e_rem_intrs(i40e_t *i40e) 620da5577f0SRobert Mustacchi { 621da5577f0SRobert Mustacchi int i, rc; 622da5577f0SRobert Mustacchi 623da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_intr_count; i++) { 624da5577f0SRobert Mustacchi rc = ddi_intr_free(i40e->i40e_intr_handles[i]); 625da5577f0SRobert Mustacchi if (rc != DDI_SUCCESS) { 626da5577f0SRobert Mustacchi i40e_log(i40e, "failed to free interrupt %d: %d", 627da5577f0SRobert Mustacchi i, rc); 628da5577f0SRobert Mustacchi } 629da5577f0SRobert Mustacchi } 630da5577f0SRobert Mustacchi 631da5577f0SRobert Mustacchi kmem_free(i40e->i40e_intr_handles, i40e->i40e_intr_size); 632da5577f0SRobert Mustacchi i40e->i40e_intr_handles = NULL; 633da5577f0SRobert Mustacchi } 634da5577f0SRobert Mustacchi 635da5577f0SRobert Mustacchi static void 636da5577f0SRobert Mustacchi i40e_rem_intr_handlers(i40e_t *i40e) 637da5577f0SRobert Mustacchi { 638da5577f0SRobert Mustacchi int i, rc; 639da5577f0SRobert Mustacchi 640da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_intr_count; i++) { 641da5577f0SRobert Mustacchi rc = ddi_intr_remove_handler(i40e->i40e_intr_handles[i]); 642da5577f0SRobert Mustacchi if (rc != DDI_SUCCESS) { 643da5577f0SRobert Mustacchi i40e_log(i40e, "failed to remove interrupt %d: %d", 644da5577f0SRobert Mustacchi i, rc); 645da5577f0SRobert Mustacchi } 646da5577f0SRobert Mustacchi } 647da5577f0SRobert Mustacchi } 648da5577f0SRobert Mustacchi 649da5577f0SRobert Mustacchi /* 650da5577f0SRobert Mustacchi * illumos Fault Management Architecture (FMA) support. 651da5577f0SRobert Mustacchi */ 652da5577f0SRobert Mustacchi 653da5577f0SRobert Mustacchi int 654da5577f0SRobert Mustacchi i40e_check_acc_handle(ddi_acc_handle_t handle) 655da5577f0SRobert Mustacchi { 656da5577f0SRobert Mustacchi ddi_fm_error_t de; 657da5577f0SRobert Mustacchi 658da5577f0SRobert Mustacchi ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION); 659da5577f0SRobert Mustacchi ddi_fm_acc_err_clear(handle, DDI_FME_VERSION); 660da5577f0SRobert Mustacchi return (de.fme_status); 661da5577f0SRobert Mustacchi } 662da5577f0SRobert Mustacchi 663da5577f0SRobert Mustacchi int 664da5577f0SRobert Mustacchi i40e_check_dma_handle(ddi_dma_handle_t handle) 665da5577f0SRobert Mustacchi { 666da5577f0SRobert Mustacchi ddi_fm_error_t de; 667da5577f0SRobert Mustacchi 668da5577f0SRobert Mustacchi ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION); 669da5577f0SRobert Mustacchi return (de.fme_status); 670da5577f0SRobert Mustacchi } 671da5577f0SRobert Mustacchi 672da5577f0SRobert Mustacchi /* 673da5577f0SRobert Mustacchi * Fault service error handling callback function. 674da5577f0SRobert Mustacchi */ 675da5577f0SRobert Mustacchi /* ARGSUSED */ 676da5577f0SRobert Mustacchi static int 677da5577f0SRobert Mustacchi i40e_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 678da5577f0SRobert Mustacchi { 679da5577f0SRobert Mustacchi pci_ereport_post(dip, err, NULL); 680da5577f0SRobert Mustacchi return (err->fme_status); 681da5577f0SRobert Mustacchi } 682da5577f0SRobert Mustacchi 683da5577f0SRobert Mustacchi static void 684da5577f0SRobert Mustacchi i40e_fm_init(i40e_t *i40e) 685da5577f0SRobert Mustacchi { 686da5577f0SRobert Mustacchi ddi_iblock_cookie_t iblk; 687da5577f0SRobert Mustacchi 688da5577f0SRobert Mustacchi i40e->i40e_fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY, 689da5577f0SRobert Mustacchi i40e->i40e_dip, DDI_PROP_DONTPASS, "fm_capable", 690da5577f0SRobert Mustacchi DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE | 691da5577f0SRobert Mustacchi DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE); 692da5577f0SRobert Mustacchi 693da5577f0SRobert Mustacchi if (i40e->i40e_fm_capabilities < 0) { 694da5577f0SRobert Mustacchi i40e->i40e_fm_capabilities = 0; 695da5577f0SRobert Mustacchi } else if (i40e->i40e_fm_capabilities > 0xf) { 696da5577f0SRobert Mustacchi i40e->i40e_fm_capabilities = DDI_FM_EREPORT_CAPABLE | 697da5577f0SRobert Mustacchi DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE | 698da5577f0SRobert Mustacchi DDI_FM_ERRCB_CAPABLE; 699da5577f0SRobert Mustacchi } 700da5577f0SRobert Mustacchi 701da5577f0SRobert Mustacchi /* 702da5577f0SRobert Mustacchi * Only register with IO Fault Services if we have some capability 703da5577f0SRobert Mustacchi */ 704da5577f0SRobert Mustacchi if (i40e->i40e_fm_capabilities & DDI_FM_ACCCHK_CAPABLE) { 705da5577f0SRobert Mustacchi i40e_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC; 706da5577f0SRobert Mustacchi } else { 707da5577f0SRobert Mustacchi i40e_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC; 708da5577f0SRobert Mustacchi } 709da5577f0SRobert Mustacchi 710da5577f0SRobert Mustacchi if (i40e->i40e_fm_capabilities) { 711da5577f0SRobert Mustacchi ddi_fm_init(i40e->i40e_dip, &i40e->i40e_fm_capabilities, &iblk); 712da5577f0SRobert Mustacchi 713da5577f0SRobert Mustacchi if (DDI_FM_EREPORT_CAP(i40e->i40e_fm_capabilities) || 714da5577f0SRobert Mustacchi DDI_FM_ERRCB_CAP(i40e->i40e_fm_capabilities)) { 715da5577f0SRobert Mustacchi pci_ereport_setup(i40e->i40e_dip); 716da5577f0SRobert Mustacchi } 717da5577f0SRobert Mustacchi 718da5577f0SRobert Mustacchi if (DDI_FM_ERRCB_CAP(i40e->i40e_fm_capabilities)) { 719da5577f0SRobert Mustacchi ddi_fm_handler_register(i40e->i40e_dip, 720da5577f0SRobert Mustacchi i40e_fm_error_cb, (void*)i40e); 721da5577f0SRobert Mustacchi } 722da5577f0SRobert Mustacchi } 723da5577f0SRobert Mustacchi 724da5577f0SRobert Mustacchi if (i40e->i40e_fm_capabilities & DDI_FM_DMACHK_CAPABLE) { 725da5577f0SRobert Mustacchi i40e_init_dma_attrs(i40e, B_TRUE); 726da5577f0SRobert Mustacchi } else { 727da5577f0SRobert Mustacchi i40e_init_dma_attrs(i40e, B_FALSE); 728da5577f0SRobert Mustacchi } 729da5577f0SRobert Mustacchi } 730da5577f0SRobert Mustacchi 731da5577f0SRobert Mustacchi static void 732da5577f0SRobert Mustacchi i40e_fm_fini(i40e_t *i40e) 733da5577f0SRobert Mustacchi { 734da5577f0SRobert Mustacchi if (i40e->i40e_fm_capabilities) { 735da5577f0SRobert Mustacchi 736da5577f0SRobert Mustacchi if (DDI_FM_EREPORT_CAP(i40e->i40e_fm_capabilities) || 737da5577f0SRobert Mustacchi DDI_FM_ERRCB_CAP(i40e->i40e_fm_capabilities)) 738da5577f0SRobert Mustacchi pci_ereport_teardown(i40e->i40e_dip); 739da5577f0SRobert Mustacchi 740da5577f0SRobert Mustacchi if (DDI_FM_ERRCB_CAP(i40e->i40e_fm_capabilities)) 741da5577f0SRobert Mustacchi ddi_fm_handler_unregister(i40e->i40e_dip); 742da5577f0SRobert Mustacchi 743da5577f0SRobert Mustacchi ddi_fm_fini(i40e->i40e_dip); 744da5577f0SRobert Mustacchi } 745da5577f0SRobert Mustacchi } 746da5577f0SRobert Mustacchi 747da5577f0SRobert Mustacchi void 748da5577f0SRobert Mustacchi i40e_fm_ereport(i40e_t *i40e, char *detail) 749da5577f0SRobert Mustacchi { 750da5577f0SRobert Mustacchi uint64_t ena; 751da5577f0SRobert Mustacchi char buf[FM_MAX_CLASS]; 752da5577f0SRobert Mustacchi 753da5577f0SRobert Mustacchi (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail); 754da5577f0SRobert Mustacchi ena = fm_ena_generate(0, FM_ENA_FMT1); 755da5577f0SRobert Mustacchi if (DDI_FM_EREPORT_CAP(i40e->i40e_fm_capabilities)) { 756da5577f0SRobert Mustacchi ddi_fm_ereport_post(i40e->i40e_dip, buf, ena, DDI_NOSLEEP, 757da5577f0SRobert Mustacchi FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL); 758da5577f0SRobert Mustacchi } 759da5577f0SRobert Mustacchi } 760da5577f0SRobert Mustacchi 761da5577f0SRobert Mustacchi /* 7628d5069bcSRyan Zezeski * Here we're trying to set the SEID of the default VSI. In general, 7638d5069bcSRyan Zezeski * when we come through and look at this shortly after attach, we 7648d5069bcSRyan Zezeski * expect there to only be a single element present, which is the 7658d5069bcSRyan Zezeski * default VSI. Importantly, each PF seems to not see any other 7668d5069bcSRyan Zezeski * devices, in part because of the simple switch mode that we're 7678d5069bcSRyan Zezeski * using. If for some reason, we see more artifacts, we'll need to 7688d5069bcSRyan Zezeski * revisit what we're doing here. 7698d5069bcSRyan Zezeski */ 7708d5069bcSRyan Zezeski static boolean_t 7718d5069bcSRyan Zezeski i40e_set_def_vsi_seid(i40e_t *i40e) 7728d5069bcSRyan Zezeski { 7738d5069bcSRyan Zezeski i40e_hw_t *hw = &i40e->i40e_hw_space; 7748d5069bcSRyan Zezeski struct i40e_aqc_get_switch_config_resp *sw_config; 7758d5069bcSRyan Zezeski uint8_t aq_buf[I40E_AQ_LARGE_BUF]; 7768d5069bcSRyan Zezeski uint16_t next = 0; 7778d5069bcSRyan Zezeski int rc; 7788d5069bcSRyan Zezeski 7798d5069bcSRyan Zezeski /* LINTED: E_BAD_PTR_CAST_ALIGN */ 7808d5069bcSRyan Zezeski sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 7818d5069bcSRyan Zezeski rc = i40e_aq_get_switch_config(hw, sw_config, sizeof (aq_buf), &next, 7828d5069bcSRyan Zezeski NULL); 7838d5069bcSRyan Zezeski if (rc != I40E_SUCCESS) { 7848d5069bcSRyan Zezeski i40e_error(i40e, "i40e_aq_get_switch_config() failed %d: %d", 7858d5069bcSRyan Zezeski rc, hw->aq.asq_last_status); 7868d5069bcSRyan Zezeski return (B_FALSE); 7878d5069bcSRyan Zezeski } 7888d5069bcSRyan Zezeski 7898d5069bcSRyan Zezeski if (LE_16(sw_config->header.num_reported) != 1) { 7908d5069bcSRyan Zezeski i40e_error(i40e, "encountered multiple (%d) switching units " 7918d5069bcSRyan Zezeski "during attach, not proceeding", 7928d5069bcSRyan Zezeski LE_16(sw_config->header.num_reported)); 7938d5069bcSRyan Zezeski return (B_FALSE); 7948d5069bcSRyan Zezeski } 7958d5069bcSRyan Zezeski 7968d5069bcSRyan Zezeski I40E_DEF_VSI_SEID(i40e) = sw_config->element[0].seid; 7978d5069bcSRyan Zezeski return (B_TRUE); 7988d5069bcSRyan Zezeski } 7998d5069bcSRyan Zezeski 8008d5069bcSRyan Zezeski /* 8018d5069bcSRyan Zezeski * Get the SEID of the uplink MAC. 802da5577f0SRobert Mustacchi */ 803da5577f0SRobert Mustacchi static int 8048d5069bcSRyan Zezeski i40e_get_mac_seid(i40e_t *i40e) 805da5577f0SRobert Mustacchi { 806da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 807da5577f0SRobert Mustacchi struct i40e_aqc_get_switch_config_resp *sw_config; 808da5577f0SRobert Mustacchi uint8_t aq_buf[I40E_AQ_LARGE_BUF]; 809da5577f0SRobert Mustacchi uint16_t next = 0; 810da5577f0SRobert Mustacchi int rc; 811da5577f0SRobert Mustacchi 812da5577f0SRobert Mustacchi /* LINTED: E_BAD_PTR_CAST_ALIGN */ 813da5577f0SRobert Mustacchi sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 814da5577f0SRobert Mustacchi rc = i40e_aq_get_switch_config(hw, sw_config, sizeof (aq_buf), &next, 815da5577f0SRobert Mustacchi NULL); 816da5577f0SRobert Mustacchi if (rc != I40E_SUCCESS) { 817da5577f0SRobert Mustacchi i40e_error(i40e, "i40e_aq_get_switch_config() failed %d: %d", 818da5577f0SRobert Mustacchi rc, hw->aq.asq_last_status); 819da5577f0SRobert Mustacchi return (-1); 820da5577f0SRobert Mustacchi } 821da5577f0SRobert Mustacchi 8228d5069bcSRyan Zezeski return (LE_16(sw_config->element[0].uplink_seid)); 823da5577f0SRobert Mustacchi } 824da5577f0SRobert Mustacchi 825da5577f0SRobert Mustacchi /* 826da5577f0SRobert Mustacchi * We need to fill the i40e_hw_t structure with the capabilities of this PF. We 827da5577f0SRobert Mustacchi * must also provide the memory for it; however, we don't need to keep it around 828da5577f0SRobert Mustacchi * to the call to the common code. It takes it and parses it into an internal 829da5577f0SRobert Mustacchi * structure. 830da5577f0SRobert Mustacchi */ 831da5577f0SRobert Mustacchi static boolean_t 832da5577f0SRobert Mustacchi i40e_get_hw_capabilities(i40e_t *i40e, i40e_hw_t *hw) 833da5577f0SRobert Mustacchi { 834da5577f0SRobert Mustacchi struct i40e_aqc_list_capabilities_element_resp *buf; 835da5577f0SRobert Mustacchi int rc; 836da5577f0SRobert Mustacchi size_t len; 837da5577f0SRobert Mustacchi uint16_t needed; 838da5577f0SRobert Mustacchi int nelems = I40E_HW_CAP_DEFAULT; 839da5577f0SRobert Mustacchi 840da5577f0SRobert Mustacchi len = nelems * sizeof (*buf); 841da5577f0SRobert Mustacchi 842da5577f0SRobert Mustacchi for (;;) { 843da5577f0SRobert Mustacchi ASSERT(len > 0); 844da5577f0SRobert Mustacchi buf = kmem_alloc(len, KM_SLEEP); 845da5577f0SRobert Mustacchi rc = i40e_aq_discover_capabilities(hw, buf, len, 846da5577f0SRobert Mustacchi &needed, i40e_aqc_opc_list_func_capabilities, NULL); 847da5577f0SRobert Mustacchi kmem_free(buf, len); 848da5577f0SRobert Mustacchi 849da5577f0SRobert Mustacchi if (hw->aq.asq_last_status == I40E_AQ_RC_ENOMEM && 850da5577f0SRobert Mustacchi nelems == I40E_HW_CAP_DEFAULT) { 851da5577f0SRobert Mustacchi if (nelems == needed) { 852da5577f0SRobert Mustacchi i40e_error(i40e, "Capability discovery failed " 853da5577f0SRobert Mustacchi "due to byzantine common code"); 854da5577f0SRobert Mustacchi return (B_FALSE); 855da5577f0SRobert Mustacchi } 856da5577f0SRobert Mustacchi len = needed; 857da5577f0SRobert Mustacchi continue; 858da5577f0SRobert Mustacchi } else if (rc != I40E_SUCCESS || 859da5577f0SRobert Mustacchi hw->aq.asq_last_status != I40E_AQ_RC_OK) { 860da5577f0SRobert Mustacchi i40e_error(i40e, "Capability discovery failed: %d", rc); 861da5577f0SRobert Mustacchi return (B_FALSE); 862da5577f0SRobert Mustacchi } 863da5577f0SRobert Mustacchi 864da5577f0SRobert Mustacchi break; 865da5577f0SRobert Mustacchi } 866da5577f0SRobert Mustacchi 867da5577f0SRobert Mustacchi return (B_TRUE); 868da5577f0SRobert Mustacchi } 869da5577f0SRobert Mustacchi 870da5577f0SRobert Mustacchi /* 871da5577f0SRobert Mustacchi * Obtain the switch's capabilities as seen by this PF and keep it around for 872da5577f0SRobert Mustacchi * our later use. 873da5577f0SRobert Mustacchi */ 874da5577f0SRobert Mustacchi static boolean_t 875da5577f0SRobert Mustacchi i40e_get_switch_resources(i40e_t *i40e) 876da5577f0SRobert Mustacchi { 877da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 878da5577f0SRobert Mustacchi uint8_t cnt = 2; 879da5577f0SRobert Mustacchi uint8_t act; 880da5577f0SRobert Mustacchi size_t size; 881da5577f0SRobert Mustacchi i40e_switch_rsrc_t *buf; 882da5577f0SRobert Mustacchi 883da5577f0SRobert Mustacchi for (;;) { 884da5577f0SRobert Mustacchi enum i40e_status_code ret; 885da5577f0SRobert Mustacchi size = cnt * sizeof (i40e_switch_rsrc_t); 886da5577f0SRobert Mustacchi ASSERT(size > 0); 887da5577f0SRobert Mustacchi if (size > UINT16_MAX) 888da5577f0SRobert Mustacchi return (B_FALSE); 889da5577f0SRobert Mustacchi buf = kmem_alloc(size, KM_SLEEP); 890da5577f0SRobert Mustacchi 891da5577f0SRobert Mustacchi ret = i40e_aq_get_switch_resource_alloc(hw, &act, buf, 892da5577f0SRobert Mustacchi cnt, NULL); 893da5577f0SRobert Mustacchi if (ret == I40E_ERR_ADMIN_QUEUE_ERROR && 894da5577f0SRobert Mustacchi hw->aq.asq_last_status == I40E_AQ_RC_EINVAL) { 895da5577f0SRobert Mustacchi kmem_free(buf, size); 896da5577f0SRobert Mustacchi cnt += I40E_SWITCH_CAP_DEFAULT; 897da5577f0SRobert Mustacchi continue; 898da5577f0SRobert Mustacchi } else if (ret != I40E_SUCCESS) { 899da5577f0SRobert Mustacchi kmem_free(buf, size); 900da5577f0SRobert Mustacchi i40e_error(i40e, 901da5577f0SRobert Mustacchi "failed to retrieve switch statistics: %d", ret); 902da5577f0SRobert Mustacchi return (B_FALSE); 903da5577f0SRobert Mustacchi } 904da5577f0SRobert Mustacchi 905da5577f0SRobert Mustacchi break; 906da5577f0SRobert Mustacchi } 907da5577f0SRobert Mustacchi 908da5577f0SRobert Mustacchi i40e->i40e_switch_rsrc_alloc = cnt; 909da5577f0SRobert Mustacchi i40e->i40e_switch_rsrc_actual = act; 910da5577f0SRobert Mustacchi i40e->i40e_switch_rsrcs = buf; 911da5577f0SRobert Mustacchi 912da5577f0SRobert Mustacchi return (B_TRUE); 913da5577f0SRobert Mustacchi } 914da5577f0SRobert Mustacchi 915da5577f0SRobert Mustacchi static void 916da5577f0SRobert Mustacchi i40e_cleanup_resources(i40e_t *i40e) 917da5577f0SRobert Mustacchi { 918da5577f0SRobert Mustacchi if (i40e->i40e_uaddrs != NULL) { 919da5577f0SRobert Mustacchi kmem_free(i40e->i40e_uaddrs, sizeof (i40e_uaddr_t) * 920da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nmacfilt); 921da5577f0SRobert Mustacchi i40e->i40e_uaddrs = NULL; 922da5577f0SRobert Mustacchi } 923da5577f0SRobert Mustacchi 924da5577f0SRobert Mustacchi if (i40e->i40e_maddrs != NULL) { 925da5577f0SRobert Mustacchi kmem_free(i40e->i40e_maddrs, sizeof (i40e_maddr_t) * 926da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nmcastfilt); 927da5577f0SRobert Mustacchi i40e->i40e_maddrs = NULL; 928da5577f0SRobert Mustacchi } 929da5577f0SRobert Mustacchi 930da5577f0SRobert Mustacchi if (i40e->i40e_switch_rsrcs != NULL) { 931da5577f0SRobert Mustacchi size_t sz = sizeof (i40e_switch_rsrc_t) * 932da5577f0SRobert Mustacchi i40e->i40e_switch_rsrc_alloc; 933da5577f0SRobert Mustacchi ASSERT(sz > 0); 934da5577f0SRobert Mustacchi kmem_free(i40e->i40e_switch_rsrcs, sz); 935da5577f0SRobert Mustacchi i40e->i40e_switch_rsrcs = NULL; 936da5577f0SRobert Mustacchi } 937da5577f0SRobert Mustacchi 938da5577f0SRobert Mustacchi if (i40e->i40e_device != NULL) 939da5577f0SRobert Mustacchi i40e_device_rele(i40e); 940da5577f0SRobert Mustacchi } 941da5577f0SRobert Mustacchi 942da5577f0SRobert Mustacchi static boolean_t 943da5577f0SRobert Mustacchi i40e_get_available_resources(i40e_t *i40e) 944da5577f0SRobert Mustacchi { 945da5577f0SRobert Mustacchi dev_info_t *parent; 946da5577f0SRobert Mustacchi uint16_t bus, device, func; 947da5577f0SRobert Mustacchi uint_t nregs; 948da5577f0SRobert Mustacchi int *regs, i; 949da5577f0SRobert Mustacchi i40e_device_t *idp; 950da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 951da5577f0SRobert Mustacchi 952da5577f0SRobert Mustacchi parent = ddi_get_parent(i40e->i40e_dip); 953da5577f0SRobert Mustacchi 954da5577f0SRobert Mustacchi if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, i40e->i40e_dip, 0, "reg", 955da5577f0SRobert Mustacchi ®s, &nregs) != DDI_PROP_SUCCESS) { 956da5577f0SRobert Mustacchi return (B_FALSE); 957da5577f0SRobert Mustacchi } 958da5577f0SRobert Mustacchi 959da5577f0SRobert Mustacchi if (nregs < 1) { 960da5577f0SRobert Mustacchi ddi_prop_free(regs); 961da5577f0SRobert Mustacchi return (B_FALSE); 962da5577f0SRobert Mustacchi } 963da5577f0SRobert Mustacchi 964da5577f0SRobert Mustacchi bus = PCI_REG_BUS_G(regs[0]); 965da5577f0SRobert Mustacchi device = PCI_REG_DEV_G(regs[0]); 966da5577f0SRobert Mustacchi func = PCI_REG_FUNC_G(regs[0]); 967da5577f0SRobert Mustacchi ddi_prop_free(regs); 968da5577f0SRobert Mustacchi 969da5577f0SRobert Mustacchi i40e->i40e_hw_space.bus.func = func; 970da5577f0SRobert Mustacchi i40e->i40e_hw_space.bus.device = device; 971da5577f0SRobert Mustacchi 972da5577f0SRobert Mustacchi if (i40e_get_switch_resources(i40e) == B_FALSE) { 973da5577f0SRobert Mustacchi return (B_FALSE); 974da5577f0SRobert Mustacchi } 975da5577f0SRobert Mustacchi 976da5577f0SRobert Mustacchi /* 977da5577f0SRobert Mustacchi * To calculate the total amount of a resource we have available, we 978da5577f0SRobert Mustacchi * need to add how many our i40e_t thinks it has guaranteed, if any, and 979da5577f0SRobert Mustacchi * then we need to go through and divide the number of available on the 980da5577f0SRobert Mustacchi * device, which was snapshotted before anyone should have allocated 981da5577f0SRobert Mustacchi * anything, and use that to derive how many are available from the 982da5577f0SRobert Mustacchi * pool. Longer term, we may want to turn this into something that's 983da5577f0SRobert Mustacchi * more of a pool-like resource that everything can share (though that 984da5577f0SRobert Mustacchi * may require some more assistance from MAC). 985da5577f0SRobert Mustacchi * 986da5577f0SRobert Mustacchi * Though for transmit and receive queue pairs, we just have to ask 987da5577f0SRobert Mustacchi * firmware instead. 988da5577f0SRobert Mustacchi */ 989da5577f0SRobert Mustacchi idp = i40e_device_find(i40e, parent, bus, device); 990da5577f0SRobert Mustacchi i40e->i40e_device = idp; 991da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nvsis = 0; 992da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nvsis_used = 0; 993da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nmacfilt = 0; 994da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nmacfilt_used = 0; 995da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nmcastfilt = 0; 996da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nmcastfilt_used = 0; 997da5577f0SRobert Mustacchi 998da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_switch_rsrc_actual; i++) { 999da5577f0SRobert Mustacchi i40e_switch_rsrc_t *srp = &i40e->i40e_switch_rsrcs[i]; 1000da5577f0SRobert Mustacchi 1001da5577f0SRobert Mustacchi switch (srp->resource_type) { 1002da5577f0SRobert Mustacchi case I40E_AQ_RESOURCE_TYPE_VSI: 1003da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nvsis += 1004da5577f0SRobert Mustacchi LE_16(srp->guaranteed); 1005da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nvsis_used = LE_16(srp->used); 1006da5577f0SRobert Mustacchi break; 1007da5577f0SRobert Mustacchi case I40E_AQ_RESOURCE_TYPE_MACADDR: 1008da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nmacfilt += 1009da5577f0SRobert Mustacchi LE_16(srp->guaranteed); 1010da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nmacfilt_used = 1011da5577f0SRobert Mustacchi LE_16(srp->used); 1012da5577f0SRobert Mustacchi break; 1013da5577f0SRobert Mustacchi case I40E_AQ_RESOURCE_TYPE_MULTICAST_HASH: 1014da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nmcastfilt += 1015da5577f0SRobert Mustacchi LE_16(srp->guaranteed); 1016da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nmcastfilt_used = 1017da5577f0SRobert Mustacchi LE_16(srp->used); 1018da5577f0SRobert Mustacchi break; 1019da5577f0SRobert Mustacchi default: 1020da5577f0SRobert Mustacchi break; 1021da5577f0SRobert Mustacchi } 1022da5577f0SRobert Mustacchi } 1023da5577f0SRobert Mustacchi 1024da5577f0SRobert Mustacchi for (i = 0; i < idp->id_rsrcs_act; i++) { 1025da5577f0SRobert Mustacchi i40e_switch_rsrc_t *srp = &i40e->i40e_switch_rsrcs[i]; 1026da5577f0SRobert Mustacchi switch (srp->resource_type) { 1027da5577f0SRobert Mustacchi case I40E_AQ_RESOURCE_TYPE_VSI: 1028da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nvsis += 1029da5577f0SRobert Mustacchi LE_16(srp->total_unalloced) / idp->id_nfuncs; 1030da5577f0SRobert Mustacchi break; 1031da5577f0SRobert Mustacchi case I40E_AQ_RESOURCE_TYPE_MACADDR: 1032da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nmacfilt += 1033da5577f0SRobert Mustacchi LE_16(srp->total_unalloced) / idp->id_nfuncs; 1034da5577f0SRobert Mustacchi break; 1035da5577f0SRobert Mustacchi case I40E_AQ_RESOURCE_TYPE_MULTICAST_HASH: 1036da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nmcastfilt += 1037da5577f0SRobert Mustacchi LE_16(srp->total_unalloced) / idp->id_nfuncs; 1038da5577f0SRobert Mustacchi default: 1039da5577f0SRobert Mustacchi break; 1040da5577f0SRobert Mustacchi } 1041da5577f0SRobert Mustacchi } 1042da5577f0SRobert Mustacchi 1043da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nrx_queue = hw->func_caps.num_rx_qp; 1044da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_ntx_queue = hw->func_caps.num_tx_qp; 1045da5577f0SRobert Mustacchi 1046da5577f0SRobert Mustacchi i40e->i40e_uaddrs = kmem_zalloc(sizeof (i40e_uaddr_t) * 1047da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nmacfilt, KM_SLEEP); 1048da5577f0SRobert Mustacchi i40e->i40e_maddrs = kmem_zalloc(sizeof (i40e_maddr_t) * 1049da5577f0SRobert Mustacchi i40e->i40e_resources.ifr_nmcastfilt, KM_SLEEP); 1050da5577f0SRobert Mustacchi 1051da5577f0SRobert Mustacchi /* 1052da5577f0SRobert Mustacchi * Initialize these as multicast addresses to indicate it's invalid for 1053da5577f0SRobert Mustacchi * sanity purposes. Think of it like 0xdeadbeef. 1054da5577f0SRobert Mustacchi */ 1055da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_resources.ifr_nmacfilt; i++) 1056da5577f0SRobert Mustacchi i40e->i40e_uaddrs[i].iua_mac[0] = 0x01; 1057da5577f0SRobert Mustacchi 1058da5577f0SRobert Mustacchi return (B_TRUE); 1059da5577f0SRobert Mustacchi } 1060da5577f0SRobert Mustacchi 1061da5577f0SRobert Mustacchi static boolean_t 1062da5577f0SRobert Mustacchi i40e_enable_interrupts(i40e_t *i40e) 1063da5577f0SRobert Mustacchi { 1064da5577f0SRobert Mustacchi int i, rc; 1065da5577f0SRobert Mustacchi 1066da5577f0SRobert Mustacchi if (i40e->i40e_intr_cap & DDI_INTR_FLAG_BLOCK) { 1067da5577f0SRobert Mustacchi rc = ddi_intr_block_enable(i40e->i40e_intr_handles, 1068da5577f0SRobert Mustacchi i40e->i40e_intr_count); 1069da5577f0SRobert Mustacchi if (rc != DDI_SUCCESS) { 1070da5577f0SRobert Mustacchi i40e_error(i40e, "Interrupt block-enable failed: %d", 1071da5577f0SRobert Mustacchi rc); 1072da5577f0SRobert Mustacchi return (B_FALSE); 1073da5577f0SRobert Mustacchi } 1074da5577f0SRobert Mustacchi } else { 1075da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_intr_count; i++) { 1076da5577f0SRobert Mustacchi rc = ddi_intr_enable(i40e->i40e_intr_handles[i]); 1077da5577f0SRobert Mustacchi if (rc != DDI_SUCCESS) { 1078da5577f0SRobert Mustacchi i40e_error(i40e, 1079da5577f0SRobert Mustacchi "Failed to enable interrupt %d: %d", i, rc); 1080da5577f0SRobert Mustacchi while (--i >= 0) { 1081da5577f0SRobert Mustacchi (void) ddi_intr_disable( 1082da5577f0SRobert Mustacchi i40e->i40e_intr_handles[i]); 1083da5577f0SRobert Mustacchi } 1084da5577f0SRobert Mustacchi return (B_FALSE); 1085da5577f0SRobert Mustacchi } 1086da5577f0SRobert Mustacchi } 1087da5577f0SRobert Mustacchi } 1088da5577f0SRobert Mustacchi 1089da5577f0SRobert Mustacchi return (B_TRUE); 1090da5577f0SRobert Mustacchi } 1091da5577f0SRobert Mustacchi 1092da5577f0SRobert Mustacchi static boolean_t 1093da5577f0SRobert Mustacchi i40e_disable_interrupts(i40e_t *i40e) 1094da5577f0SRobert Mustacchi { 1095da5577f0SRobert Mustacchi int i, rc; 1096da5577f0SRobert Mustacchi 1097da5577f0SRobert Mustacchi if (i40e->i40e_intr_cap & DDI_INTR_FLAG_BLOCK) { 1098da5577f0SRobert Mustacchi rc = ddi_intr_block_disable(i40e->i40e_intr_handles, 1099da5577f0SRobert Mustacchi i40e->i40e_intr_count); 1100da5577f0SRobert Mustacchi if (rc != DDI_SUCCESS) { 1101da5577f0SRobert Mustacchi i40e_error(i40e, 1102da5577f0SRobert Mustacchi "Interrupt block-disabled failed: %d", rc); 1103da5577f0SRobert Mustacchi return (B_FALSE); 1104da5577f0SRobert Mustacchi } 1105da5577f0SRobert Mustacchi } else { 1106da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_intr_count; i++) { 1107da5577f0SRobert Mustacchi rc = ddi_intr_disable(i40e->i40e_intr_handles[i]); 1108da5577f0SRobert Mustacchi if (rc != DDI_SUCCESS) { 1109da5577f0SRobert Mustacchi i40e_error(i40e, 1110da5577f0SRobert Mustacchi "Failed to disable interrupt %d: %d", 1111da5577f0SRobert Mustacchi i, rc); 1112da5577f0SRobert Mustacchi return (B_FALSE); 1113da5577f0SRobert Mustacchi } 1114da5577f0SRobert Mustacchi } 1115da5577f0SRobert Mustacchi } 1116da5577f0SRobert Mustacchi 1117da5577f0SRobert Mustacchi return (B_TRUE); 1118da5577f0SRobert Mustacchi } 1119da5577f0SRobert Mustacchi 1120da5577f0SRobert Mustacchi /* 1121da5577f0SRobert Mustacchi * Free receive & transmit rings. 1122da5577f0SRobert Mustacchi */ 1123da5577f0SRobert Mustacchi static void 1124da5577f0SRobert Mustacchi i40e_free_trqpairs(i40e_t *i40e) 1125da5577f0SRobert Mustacchi { 1126da5577f0SRobert Mustacchi i40e_trqpair_t *itrq; 1127da5577f0SRobert Mustacchi 11288d5069bcSRyan Zezeski if (i40e->i40e_rx_groups != NULL) { 11298d5069bcSRyan Zezeski kmem_free(i40e->i40e_rx_groups, 11308d5069bcSRyan Zezeski sizeof (i40e_rx_group_t) * i40e->i40e_num_rx_groups); 11318d5069bcSRyan Zezeski i40e->i40e_rx_groups = NULL; 11328d5069bcSRyan Zezeski } 11338d5069bcSRyan Zezeski 1134da5577f0SRobert Mustacchi if (i40e->i40e_trqpairs != NULL) { 11358d5069bcSRyan Zezeski for (uint_t i = 0; i < i40e->i40e_num_trqpairs; i++) { 1136da5577f0SRobert Mustacchi itrq = &i40e->i40e_trqpairs[i]; 1137da5577f0SRobert Mustacchi mutex_destroy(&itrq->itrq_rx_lock); 1138da5577f0SRobert Mustacchi mutex_destroy(&itrq->itrq_tx_lock); 1139da5577f0SRobert Mustacchi mutex_destroy(&itrq->itrq_tcb_lock); 1140da5577f0SRobert Mustacchi 1141da5577f0SRobert Mustacchi /* 1142da5577f0SRobert Mustacchi * Should have already been cleaned up by start/stop, 1143da5577f0SRobert Mustacchi * etc. 1144da5577f0SRobert Mustacchi */ 1145da5577f0SRobert Mustacchi ASSERT(itrq->itrq_txkstat == NULL); 1146da5577f0SRobert Mustacchi ASSERT(itrq->itrq_rxkstat == NULL); 1147da5577f0SRobert Mustacchi } 1148da5577f0SRobert Mustacchi 1149da5577f0SRobert Mustacchi kmem_free(i40e->i40e_trqpairs, 1150da5577f0SRobert Mustacchi sizeof (i40e_trqpair_t) * i40e->i40e_num_trqpairs); 1151da5577f0SRobert Mustacchi i40e->i40e_trqpairs = NULL; 1152da5577f0SRobert Mustacchi } 1153da5577f0SRobert Mustacchi 1154da5577f0SRobert Mustacchi cv_destroy(&i40e->i40e_rx_pending_cv); 1155da5577f0SRobert Mustacchi mutex_destroy(&i40e->i40e_rx_pending_lock); 1156da5577f0SRobert Mustacchi mutex_destroy(&i40e->i40e_general_lock); 1157da5577f0SRobert Mustacchi } 1158da5577f0SRobert Mustacchi 1159da5577f0SRobert Mustacchi /* 1160da5577f0SRobert Mustacchi * Allocate transmit and receive rings, as well as other data structures that we 1161da5577f0SRobert Mustacchi * need. 1162da5577f0SRobert Mustacchi */ 1163da5577f0SRobert Mustacchi static boolean_t 1164da5577f0SRobert Mustacchi i40e_alloc_trqpairs(i40e_t *i40e) 1165da5577f0SRobert Mustacchi { 1166da5577f0SRobert Mustacchi void *mutexpri = DDI_INTR_PRI(i40e->i40e_intr_pri); 1167da5577f0SRobert Mustacchi 1168da5577f0SRobert Mustacchi /* 1169da5577f0SRobert Mustacchi * Now that we have the priority for the interrupts, initialize 1170da5577f0SRobert Mustacchi * all relevant locks. 1171da5577f0SRobert Mustacchi */ 1172da5577f0SRobert Mustacchi mutex_init(&i40e->i40e_general_lock, NULL, MUTEX_DRIVER, mutexpri); 1173da5577f0SRobert Mustacchi mutex_init(&i40e->i40e_rx_pending_lock, NULL, MUTEX_DRIVER, mutexpri); 1174da5577f0SRobert Mustacchi cv_init(&i40e->i40e_rx_pending_cv, NULL, CV_DRIVER, NULL); 1175da5577f0SRobert Mustacchi 1176da5577f0SRobert Mustacchi i40e->i40e_trqpairs = kmem_zalloc(sizeof (i40e_trqpair_t) * 1177da5577f0SRobert Mustacchi i40e->i40e_num_trqpairs, KM_SLEEP); 11788d5069bcSRyan Zezeski for (uint_t i = 0; i < i40e->i40e_num_trqpairs; i++) { 1179da5577f0SRobert Mustacchi i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[i]; 1180da5577f0SRobert Mustacchi 1181da5577f0SRobert Mustacchi itrq->itrq_i40e = i40e; 1182da5577f0SRobert Mustacchi mutex_init(&itrq->itrq_rx_lock, NULL, MUTEX_DRIVER, mutexpri); 1183da5577f0SRobert Mustacchi mutex_init(&itrq->itrq_tx_lock, NULL, MUTEX_DRIVER, mutexpri); 1184da5577f0SRobert Mustacchi mutex_init(&itrq->itrq_tcb_lock, NULL, MUTEX_DRIVER, mutexpri); 1185da5577f0SRobert Mustacchi itrq->itrq_index = i; 1186da5577f0SRobert Mustacchi } 1187da5577f0SRobert Mustacchi 11888d5069bcSRyan Zezeski i40e->i40e_rx_groups = kmem_zalloc(sizeof (i40e_rx_group_t) * 11898d5069bcSRyan Zezeski i40e->i40e_num_rx_groups, KM_SLEEP); 11908d5069bcSRyan Zezeski 11918d5069bcSRyan Zezeski for (uint_t i = 0; i < i40e->i40e_num_rx_groups; i++) { 11928d5069bcSRyan Zezeski i40e_rx_group_t *rxg = &i40e->i40e_rx_groups[i]; 11938d5069bcSRyan Zezeski 11948d5069bcSRyan Zezeski rxg->irg_index = i; 11958d5069bcSRyan Zezeski rxg->irg_i40e = i40e; 11968d5069bcSRyan Zezeski } 11978d5069bcSRyan Zezeski 1198da5577f0SRobert Mustacchi return (B_TRUE); 1199da5577f0SRobert Mustacchi } 1200da5577f0SRobert Mustacchi 1201da5577f0SRobert Mustacchi 1202da5577f0SRobert Mustacchi 1203da5577f0SRobert Mustacchi /* 1204da5577f0SRobert Mustacchi * Unless a .conf file already overrode i40e_t structure values, they will 1205da5577f0SRobert Mustacchi * be 0, and need to be set in conjunction with the now-available HW report. 1206da5577f0SRobert Mustacchi */ 1207da5577f0SRobert Mustacchi /* ARGSUSED */ 1208da5577f0SRobert Mustacchi static void 1209da5577f0SRobert Mustacchi i40e_hw_to_instance(i40e_t *i40e, i40e_hw_t *hw) 1210da5577f0SRobert Mustacchi { 12118d5069bcSRyan Zezeski if (i40e->i40e_num_trqpairs_per_vsi == 0) { 12128d5069bcSRyan Zezeski if (i40e_is_x722(i40e)) { 12138d5069bcSRyan Zezeski i40e->i40e_num_trqpairs_per_vsi = 12148d5069bcSRyan Zezeski I40E_722_MAX_TC_QUEUES; 12158d5069bcSRyan Zezeski } else { 12168d5069bcSRyan Zezeski i40e->i40e_num_trqpairs_per_vsi = 12178d5069bcSRyan Zezeski I40E_710_MAX_TC_QUEUES; 12188d5069bcSRyan Zezeski } 1219da5577f0SRobert Mustacchi } 1220da5577f0SRobert Mustacchi 1221da5577f0SRobert Mustacchi if (i40e->i40e_num_rx_groups == 0) { 1222da5577f0SRobert Mustacchi i40e->i40e_num_rx_groups = I40E_GROUP_MAX; 1223da5577f0SRobert Mustacchi } 1224da5577f0SRobert Mustacchi } 1225da5577f0SRobert Mustacchi 1226da5577f0SRobert Mustacchi /* 1227da5577f0SRobert Mustacchi * Free any resources required by, or setup by, the Intel common code. 1228da5577f0SRobert Mustacchi */ 1229da5577f0SRobert Mustacchi static void 1230da5577f0SRobert Mustacchi i40e_common_code_fini(i40e_t *i40e) 1231da5577f0SRobert Mustacchi { 1232da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 1233da5577f0SRobert Mustacchi int rc; 1234da5577f0SRobert Mustacchi 1235da5577f0SRobert Mustacchi rc = i40e_shutdown_lan_hmc(hw); 1236da5577f0SRobert Mustacchi if (rc != I40E_SUCCESS) 1237da5577f0SRobert Mustacchi i40e_error(i40e, "failed to shutdown LAN hmc: %d", rc); 1238da5577f0SRobert Mustacchi 1239da5577f0SRobert Mustacchi rc = i40e_shutdown_adminq(hw); 1240da5577f0SRobert Mustacchi if (rc != I40E_SUCCESS) 1241da5577f0SRobert Mustacchi i40e_error(i40e, "failed to shutdown admin queue: %d", rc); 1242da5577f0SRobert Mustacchi } 1243da5577f0SRobert Mustacchi 1244da5577f0SRobert Mustacchi /* 1245da5577f0SRobert Mustacchi * Initialize and call Intel common-code routines, includes some setup 1246da5577f0SRobert Mustacchi * the common code expects from the driver. Also prints on failure, so 1247da5577f0SRobert Mustacchi * the caller doesn't have to. 1248da5577f0SRobert Mustacchi */ 1249da5577f0SRobert Mustacchi static boolean_t 1250da5577f0SRobert Mustacchi i40e_common_code_init(i40e_t *i40e, i40e_hw_t *hw) 1251da5577f0SRobert Mustacchi { 1252da5577f0SRobert Mustacchi int rc; 1253da5577f0SRobert Mustacchi 1254da5577f0SRobert Mustacchi i40e_clear_hw(hw); 1255da5577f0SRobert Mustacchi rc = i40e_pf_reset(hw); 1256da5577f0SRobert Mustacchi if (rc != 0) { 1257da5577f0SRobert Mustacchi i40e_error(i40e, "failed to reset hardware: %d", rc); 1258da5577f0SRobert Mustacchi i40e_fm_ereport(i40e, DDI_FM_DEVICE_NO_RESPONSE); 1259da5577f0SRobert Mustacchi return (B_FALSE); 1260da5577f0SRobert Mustacchi } 1261da5577f0SRobert Mustacchi 1262da5577f0SRobert Mustacchi rc = i40e_init_shared_code(hw); 1263da5577f0SRobert Mustacchi if (rc != 0) { 1264da5577f0SRobert Mustacchi i40e_error(i40e, "failed to initialize i40e core: %d", rc); 1265da5577f0SRobert Mustacchi return (B_FALSE); 1266da5577f0SRobert Mustacchi } 1267da5577f0SRobert Mustacchi 1268da5577f0SRobert Mustacchi hw->aq.num_arq_entries = I40E_DEF_ADMINQ_SIZE; 1269da5577f0SRobert Mustacchi hw->aq.num_asq_entries = I40E_DEF_ADMINQ_SIZE; 1270da5577f0SRobert Mustacchi hw->aq.arq_buf_size = I40E_ADMINQ_BUFSZ; 1271da5577f0SRobert Mustacchi hw->aq.asq_buf_size = I40E_ADMINQ_BUFSZ; 1272da5577f0SRobert Mustacchi 1273da5577f0SRobert Mustacchi rc = i40e_init_adminq(hw); 1274da5577f0SRobert Mustacchi if (rc != 0) { 1275da5577f0SRobert Mustacchi i40e_error(i40e, "failed to initialize firmware admin queue: " 1276da5577f0SRobert Mustacchi "%d, potential firmware version mismatch", rc); 1277da5577f0SRobert Mustacchi i40e_fm_ereport(i40e, DDI_FM_DEVICE_INVAL_STATE); 1278da5577f0SRobert Mustacchi return (B_FALSE); 1279da5577f0SRobert Mustacchi } 1280da5577f0SRobert Mustacchi 1281da5577f0SRobert Mustacchi if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && 1282da5577f0SRobert Mustacchi hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR) { 1283422542c1SRobert Mustacchi i40e_log(i40e, "The driver for the device detected a newer " 1284da5577f0SRobert Mustacchi "version of the NVM image (%d.%d) than expected (%d.%d).\n" 1285da5577f0SRobert Mustacchi "Please install the most recent version of the network " 1286da5577f0SRobert Mustacchi "driver.\n", hw->aq.api_maj_ver, hw->aq.api_min_ver, 1287da5577f0SRobert Mustacchi I40E_FW_API_VERSION_MAJOR, I40E_FW_API_VERSION_MINOR); 1288da5577f0SRobert Mustacchi } else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR || 1289da5577f0SRobert Mustacchi hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1)) { 1290422542c1SRobert Mustacchi i40e_log(i40e, "The driver for the device detected an older" 1291da5577f0SRobert Mustacchi " version of the NVM image (%d.%d) than expected (%d.%d)." 1292da5577f0SRobert Mustacchi "\nPlease update the NVM image.\n", 1293da5577f0SRobert Mustacchi hw->aq.api_maj_ver, hw->aq.api_min_ver, 1294da5577f0SRobert Mustacchi I40E_FW_API_VERSION_MAJOR, I40E_FW_API_VERSION_MINOR - 1); 1295da5577f0SRobert Mustacchi } 1296da5577f0SRobert Mustacchi 1297da5577f0SRobert Mustacchi i40e_clear_pxe_mode(hw); 1298da5577f0SRobert Mustacchi 1299da5577f0SRobert Mustacchi /* 1300da5577f0SRobert Mustacchi * We need to call this so that the common code can discover 1301da5577f0SRobert Mustacchi * capabilities of the hardware, which it uses throughout the rest. 1302da5577f0SRobert Mustacchi */ 1303da5577f0SRobert Mustacchi if (!i40e_get_hw_capabilities(i40e, hw)) { 1304da5577f0SRobert Mustacchi i40e_error(i40e, "failed to obtain hardware capabilities"); 1305da5577f0SRobert Mustacchi return (B_FALSE); 1306da5577f0SRobert Mustacchi } 1307da5577f0SRobert Mustacchi 1308da5577f0SRobert Mustacchi if (i40e_get_available_resources(i40e) == B_FALSE) { 1309da5577f0SRobert Mustacchi i40e_error(i40e, "failed to obtain hardware resources"); 1310da5577f0SRobert Mustacchi return (B_FALSE); 1311da5577f0SRobert Mustacchi } 1312da5577f0SRobert Mustacchi 1313da5577f0SRobert Mustacchi i40e_hw_to_instance(i40e, hw); 1314da5577f0SRobert Mustacchi 1315da5577f0SRobert Mustacchi rc = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, 1316da5577f0SRobert Mustacchi hw->func_caps.num_rx_qp, 0, 0); 1317da5577f0SRobert Mustacchi if (rc != 0) { 1318da5577f0SRobert Mustacchi i40e_error(i40e, "failed to initialize hardware memory cache: " 1319da5577f0SRobert Mustacchi "%d", rc); 1320da5577f0SRobert Mustacchi return (B_FALSE); 1321da5577f0SRobert Mustacchi } 1322da5577f0SRobert Mustacchi 1323da5577f0SRobert Mustacchi rc = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 1324da5577f0SRobert Mustacchi if (rc != 0) { 1325da5577f0SRobert Mustacchi i40e_error(i40e, "failed to configure hardware memory cache: " 1326da5577f0SRobert Mustacchi "%d", rc); 1327da5577f0SRobert Mustacchi return (B_FALSE); 1328da5577f0SRobert Mustacchi } 1329da5577f0SRobert Mustacchi 1330da5577f0SRobert Mustacchi (void) i40e_aq_stop_lldp(hw, TRUE, NULL); 1331da5577f0SRobert Mustacchi 1332da5577f0SRobert Mustacchi rc = i40e_get_mac_addr(hw, hw->mac.addr); 1333da5577f0SRobert Mustacchi if (rc != I40E_SUCCESS) { 1334da5577f0SRobert Mustacchi i40e_error(i40e, "failed to retrieve hardware mac address: %d", 1335da5577f0SRobert Mustacchi rc); 1336da5577f0SRobert Mustacchi return (B_FALSE); 1337da5577f0SRobert Mustacchi } 1338da5577f0SRobert Mustacchi 1339da5577f0SRobert Mustacchi rc = i40e_validate_mac_addr(hw->mac.addr); 1340da5577f0SRobert Mustacchi if (rc != 0) { 1341da5577f0SRobert Mustacchi i40e_error(i40e, "failed to validate internal mac address: " 1342da5577f0SRobert Mustacchi "%d", rc); 1343da5577f0SRobert Mustacchi return (B_FALSE); 1344da5577f0SRobert Mustacchi } 1345da5577f0SRobert Mustacchi bcopy(hw->mac.addr, hw->mac.perm_addr, ETHERADDRL); 1346da5577f0SRobert Mustacchi if ((rc = i40e_get_port_mac_addr(hw, hw->mac.port_addr)) != 1347da5577f0SRobert Mustacchi I40E_SUCCESS) { 1348da5577f0SRobert Mustacchi i40e_error(i40e, "failed to retrieve port mac address: %d", 1349da5577f0SRobert Mustacchi rc); 1350da5577f0SRobert Mustacchi return (B_FALSE); 1351da5577f0SRobert Mustacchi } 1352da5577f0SRobert Mustacchi 1353da5577f0SRobert Mustacchi /* 13548d5069bcSRyan Zezeski * We need to obtain the Default Virtual Station SEID (VSI) 13558d5069bcSRyan Zezeski * before we can perform other operations on the device. 1356da5577f0SRobert Mustacchi */ 13578d5069bcSRyan Zezeski if (!i40e_set_def_vsi_seid(i40e)) { 13588d5069bcSRyan Zezeski i40e_error(i40e, "failed to obtain Default VSI SEID"); 1359da5577f0SRobert Mustacchi return (B_FALSE); 1360da5577f0SRobert Mustacchi } 1361da5577f0SRobert Mustacchi 1362da5577f0SRobert Mustacchi return (B_TRUE); 1363da5577f0SRobert Mustacchi } 1364da5577f0SRobert Mustacchi 1365da5577f0SRobert Mustacchi static void 1366da5577f0SRobert Mustacchi i40e_unconfigure(dev_info_t *devinfo, i40e_t *i40e) 1367da5577f0SRobert Mustacchi { 1368da5577f0SRobert Mustacchi int rc; 1369da5577f0SRobert Mustacchi 1370da5577f0SRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_ENABLE_INTR) 1371da5577f0SRobert Mustacchi (void) i40e_disable_interrupts(i40e); 1372da5577f0SRobert Mustacchi 1373da5577f0SRobert Mustacchi if ((i40e->i40e_attach_progress & I40E_ATTACH_LINK_TIMER) && 1374da5577f0SRobert Mustacchi i40e->i40e_periodic_id != 0) { 1375da5577f0SRobert Mustacchi ddi_periodic_delete(i40e->i40e_periodic_id); 1376da5577f0SRobert Mustacchi i40e->i40e_periodic_id = 0; 1377da5577f0SRobert Mustacchi } 1378da5577f0SRobert Mustacchi 1379da5577f0SRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_MAC) { 1380da5577f0SRobert Mustacchi rc = mac_unregister(i40e->i40e_mac_hdl); 1381da5577f0SRobert Mustacchi if (rc != 0) { 1382da5577f0SRobert Mustacchi i40e_error(i40e, "failed to unregister from mac: %d", 1383da5577f0SRobert Mustacchi rc); 1384da5577f0SRobert Mustacchi } 1385da5577f0SRobert Mustacchi } 1386da5577f0SRobert Mustacchi 1387da5577f0SRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_STATS) { 1388da5577f0SRobert Mustacchi i40e_stats_fini(i40e); 1389da5577f0SRobert Mustacchi } 1390da5577f0SRobert Mustacchi 1391da5577f0SRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_ADD_INTR) 1392da5577f0SRobert Mustacchi i40e_rem_intr_handlers(i40e); 1393da5577f0SRobert Mustacchi 1394da5577f0SRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_ALLOC_RINGSLOCKS) 1395da5577f0SRobert Mustacchi i40e_free_trqpairs(i40e); 1396da5577f0SRobert Mustacchi 1397da5577f0SRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_ALLOC_INTR) 1398da5577f0SRobert Mustacchi i40e_rem_intrs(i40e); 1399da5577f0SRobert Mustacchi 1400da5577f0SRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_COMMON_CODE) 1401da5577f0SRobert Mustacchi i40e_common_code_fini(i40e); 1402da5577f0SRobert Mustacchi 1403da5577f0SRobert Mustacchi i40e_cleanup_resources(i40e); 1404da5577f0SRobert Mustacchi 1405da5577f0SRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_PROPS) 1406da5577f0SRobert Mustacchi (void) ddi_prop_remove_all(devinfo); 1407da5577f0SRobert Mustacchi 1408da5577f0SRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_REGS_MAP && 1409da5577f0SRobert Mustacchi i40e->i40e_osdep_space.ios_reg_handle != NULL) { 1410da5577f0SRobert Mustacchi ddi_regs_map_free(&i40e->i40e_osdep_space.ios_reg_handle); 1411da5577f0SRobert Mustacchi i40e->i40e_osdep_space.ios_reg_handle = NULL; 1412da5577f0SRobert Mustacchi } 1413da5577f0SRobert Mustacchi 1414da5577f0SRobert Mustacchi if ((i40e->i40e_attach_progress & I40E_ATTACH_PCI_CONFIG) && 1415da5577f0SRobert Mustacchi i40e->i40e_osdep_space.ios_cfg_handle != NULL) { 1416da5577f0SRobert Mustacchi pci_config_teardown(&i40e->i40e_osdep_space.ios_cfg_handle); 1417da5577f0SRobert Mustacchi i40e->i40e_osdep_space.ios_cfg_handle = NULL; 1418da5577f0SRobert Mustacchi } 1419da5577f0SRobert Mustacchi 1420da5577f0SRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_FM_INIT) 1421da5577f0SRobert Mustacchi i40e_fm_fini(i40e); 1422da5577f0SRobert Mustacchi 1423da5577f0SRobert Mustacchi kmem_free(i40e->i40e_aqbuf, I40E_ADMINQ_BUFSZ); 1424da5577f0SRobert Mustacchi kmem_free(i40e, sizeof (i40e_t)); 1425da5577f0SRobert Mustacchi 1426da5577f0SRobert Mustacchi ddi_set_driver_private(devinfo, NULL); 1427da5577f0SRobert Mustacchi } 1428da5577f0SRobert Mustacchi 1429da5577f0SRobert Mustacchi static boolean_t 1430da5577f0SRobert Mustacchi i40e_final_init(i40e_t *i40e) 1431da5577f0SRobert Mustacchi { 1432da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 1433da5577f0SRobert Mustacchi struct i40e_osdep *osdep = OS_DEP(hw); 1434da5577f0SRobert Mustacchi uint8_t pbanum[I40E_PBANUM_STRLEN]; 1435da5577f0SRobert Mustacchi enum i40e_status_code irc; 1436da5577f0SRobert Mustacchi char buf[I40E_DDI_PROP_LEN]; 1437da5577f0SRobert Mustacchi 1438da5577f0SRobert Mustacchi pbanum[0] = '\0'; 1439da5577f0SRobert Mustacchi irc = i40e_read_pba_string(hw, pbanum, sizeof (pbanum)); 1440da5577f0SRobert Mustacchi if (irc != I40E_SUCCESS) { 1441da5577f0SRobert Mustacchi i40e_log(i40e, "failed to read PBA string: %d", irc); 1442da5577f0SRobert Mustacchi } else { 1443da5577f0SRobert Mustacchi (void) ddi_prop_update_string(DDI_DEV_T_NONE, i40e->i40e_dip, 1444da5577f0SRobert Mustacchi "printed-board-assembly", (char *)pbanum); 1445da5577f0SRobert Mustacchi } 1446da5577f0SRobert Mustacchi 1447da5577f0SRobert Mustacchi #ifdef DEBUG 1448da5577f0SRobert Mustacchi ASSERT(snprintf(NULL, 0, "%d.%d", hw->aq.fw_maj_ver, 1449da5577f0SRobert Mustacchi hw->aq.fw_min_ver) < sizeof (buf)); 1450da5577f0SRobert Mustacchi ASSERT(snprintf(NULL, 0, "%x", hw->aq.fw_build) < sizeof (buf)); 1451da5577f0SRobert Mustacchi ASSERT(snprintf(NULL, 0, "%d.%d", hw->aq.api_maj_ver, 1452da5577f0SRobert Mustacchi hw->aq.api_min_ver) < sizeof (buf)); 1453da5577f0SRobert Mustacchi #endif 1454da5577f0SRobert Mustacchi 1455da5577f0SRobert Mustacchi (void) snprintf(buf, sizeof (buf), "%d.%d", hw->aq.fw_maj_ver, 1456da5577f0SRobert Mustacchi hw->aq.fw_min_ver); 1457da5577f0SRobert Mustacchi (void) ddi_prop_update_string(DDI_DEV_T_NONE, i40e->i40e_dip, 1458da5577f0SRobert Mustacchi "firmware-version", buf); 1459da5577f0SRobert Mustacchi (void) snprintf(buf, sizeof (buf), "%x", hw->aq.fw_build); 1460da5577f0SRobert Mustacchi (void) ddi_prop_update_string(DDI_DEV_T_NONE, i40e->i40e_dip, 1461da5577f0SRobert Mustacchi "firmware-build", buf); 1462da5577f0SRobert Mustacchi (void) snprintf(buf, sizeof (buf), "%d.%d", hw->aq.api_maj_ver, 1463da5577f0SRobert Mustacchi hw->aq.api_min_ver); 1464da5577f0SRobert Mustacchi (void) ddi_prop_update_string(DDI_DEV_T_NONE, i40e->i40e_dip, 1465da5577f0SRobert Mustacchi "api-version", buf); 1466da5577f0SRobert Mustacchi 1467da5577f0SRobert Mustacchi if (!i40e_set_hw_bus_info(hw)) 1468da5577f0SRobert Mustacchi return (B_FALSE); 1469da5577f0SRobert Mustacchi 1470da5577f0SRobert Mustacchi if (i40e_check_acc_handle(osdep->ios_reg_handle) != DDI_FM_OK) { 1471da5577f0SRobert Mustacchi ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST); 1472da5577f0SRobert Mustacchi return (B_FALSE); 1473da5577f0SRobert Mustacchi } 1474da5577f0SRobert Mustacchi 1475da5577f0SRobert Mustacchi return (B_TRUE); 1476da5577f0SRobert Mustacchi } 1477da5577f0SRobert Mustacchi 1478422542c1SRobert Mustacchi static void 1479da5577f0SRobert Mustacchi i40e_identify_hardware(i40e_t *i40e) 1480da5577f0SRobert Mustacchi { 1481da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 1482da5577f0SRobert Mustacchi struct i40e_osdep *osdep = &i40e->i40e_osdep_space; 1483da5577f0SRobert Mustacchi 1484da5577f0SRobert Mustacchi hw->vendor_id = pci_config_get16(osdep->ios_cfg_handle, PCI_CONF_VENID); 1485da5577f0SRobert Mustacchi hw->device_id = pci_config_get16(osdep->ios_cfg_handle, PCI_CONF_DEVID); 1486da5577f0SRobert Mustacchi hw->revision_id = pci_config_get8(osdep->ios_cfg_handle, 1487da5577f0SRobert Mustacchi PCI_CONF_REVID); 1488da5577f0SRobert Mustacchi hw->subsystem_device_id = 1489da5577f0SRobert Mustacchi pci_config_get16(osdep->ios_cfg_handle, PCI_CONF_SUBSYSID); 1490da5577f0SRobert Mustacchi hw->subsystem_vendor_id = 1491da5577f0SRobert Mustacchi pci_config_get16(osdep->ios_cfg_handle, PCI_CONF_SUBVENID); 1492da5577f0SRobert Mustacchi 1493da5577f0SRobert Mustacchi /* 1494da5577f0SRobert Mustacchi * Note that we set the hardware's bus information later on, in 1495da5577f0SRobert Mustacchi * i40e_get_available_resources(). The common code doesn't seem to 1496da5577f0SRobert Mustacchi * require that it be set in any ways, it seems to be mostly for 1497da5577f0SRobert Mustacchi * book-keeping. 1498da5577f0SRobert Mustacchi */ 1499da5577f0SRobert Mustacchi } 1500da5577f0SRobert Mustacchi 1501da5577f0SRobert Mustacchi static boolean_t 1502da5577f0SRobert Mustacchi i40e_regs_map(i40e_t *i40e) 1503da5577f0SRobert Mustacchi { 1504da5577f0SRobert Mustacchi dev_info_t *devinfo = i40e->i40e_dip; 1505da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 1506da5577f0SRobert Mustacchi struct i40e_osdep *osdep = &i40e->i40e_osdep_space; 1507da5577f0SRobert Mustacchi off_t memsize; 1508da5577f0SRobert Mustacchi int ret; 1509da5577f0SRobert Mustacchi 1510da5577f0SRobert Mustacchi if (ddi_dev_regsize(devinfo, I40E_ADAPTER_REGSET, &memsize) != 1511da5577f0SRobert Mustacchi DDI_SUCCESS) { 1512da5577f0SRobert Mustacchi i40e_error(i40e, "Used invalid register set to map PCIe regs"); 1513da5577f0SRobert Mustacchi return (B_FALSE); 1514da5577f0SRobert Mustacchi } 1515da5577f0SRobert Mustacchi 1516da5577f0SRobert Mustacchi if ((ret = ddi_regs_map_setup(devinfo, I40E_ADAPTER_REGSET, 1517da5577f0SRobert Mustacchi (caddr_t *)&hw->hw_addr, 0, memsize, &i40e_regs_acc_attr, 1518da5577f0SRobert Mustacchi &osdep->ios_reg_handle)) != DDI_SUCCESS) { 1519da5577f0SRobert Mustacchi i40e_error(i40e, "failed to map device registers: %d", ret); 1520da5577f0SRobert Mustacchi return (B_FALSE); 1521da5577f0SRobert Mustacchi } 1522da5577f0SRobert Mustacchi 1523da5577f0SRobert Mustacchi osdep->ios_reg_size = memsize; 1524da5577f0SRobert Mustacchi return (B_TRUE); 1525da5577f0SRobert Mustacchi } 1526da5577f0SRobert Mustacchi 1527da5577f0SRobert Mustacchi /* 1528da5577f0SRobert Mustacchi * Update parameters required when a new MTU has been configured. Calculate the 1529da5577f0SRobert Mustacchi * maximum frame size, as well as, size our DMA buffers which we size in 1530da5577f0SRobert Mustacchi * increments of 1K. 1531da5577f0SRobert Mustacchi */ 1532da5577f0SRobert Mustacchi void 1533da5577f0SRobert Mustacchi i40e_update_mtu(i40e_t *i40e) 1534da5577f0SRobert Mustacchi { 1535da5577f0SRobert Mustacchi uint32_t rx, tx; 1536da5577f0SRobert Mustacchi 1537da5577f0SRobert Mustacchi i40e->i40e_frame_max = i40e->i40e_sdu + 1538da5577f0SRobert Mustacchi sizeof (struct ether_vlan_header) + ETHERFCSL; 1539da5577f0SRobert Mustacchi 1540da5577f0SRobert Mustacchi rx = i40e->i40e_frame_max + I40E_BUF_IPHDR_ALIGNMENT; 1541da5577f0SRobert Mustacchi i40e->i40e_rx_buf_size = ((rx >> 10) + 1542da5577f0SRobert Mustacchi ((rx & (((uint32_t)1 << 10) -1)) > 0 ? 1 : 0)) << 10; 1543da5577f0SRobert Mustacchi 1544da5577f0SRobert Mustacchi tx = i40e->i40e_frame_max; 1545da5577f0SRobert Mustacchi i40e->i40e_tx_buf_size = ((tx >> 10) + 1546da5577f0SRobert Mustacchi ((tx & (((uint32_t)1 << 10) -1)) > 0 ? 1 : 0)) << 10; 1547da5577f0SRobert Mustacchi } 1548da5577f0SRobert Mustacchi 1549da5577f0SRobert Mustacchi static int 1550da5577f0SRobert Mustacchi i40e_get_prop(i40e_t *i40e, char *prop, int min, int max, int def) 1551da5577f0SRobert Mustacchi { 1552da5577f0SRobert Mustacchi int val; 1553da5577f0SRobert Mustacchi 1554da5577f0SRobert Mustacchi val = ddi_prop_get_int(DDI_DEV_T_ANY, i40e->i40e_dip, DDI_PROP_DONTPASS, 1555da5577f0SRobert Mustacchi prop, def); 1556da5577f0SRobert Mustacchi if (val > max) 1557da5577f0SRobert Mustacchi val = max; 1558da5577f0SRobert Mustacchi if (val < min) 1559da5577f0SRobert Mustacchi val = min; 1560da5577f0SRobert Mustacchi return (val); 1561da5577f0SRobert Mustacchi } 1562da5577f0SRobert Mustacchi 1563da5577f0SRobert Mustacchi static void 1564da5577f0SRobert Mustacchi i40e_init_properties(i40e_t *i40e) 1565da5577f0SRobert Mustacchi { 1566da5577f0SRobert Mustacchi i40e->i40e_sdu = i40e_get_prop(i40e, "default_mtu", 1567da5577f0SRobert Mustacchi I40E_MIN_MTU, I40E_MAX_MTU, I40E_DEF_MTU); 1568da5577f0SRobert Mustacchi 1569da5577f0SRobert Mustacchi i40e->i40e_intr_force = i40e_get_prop(i40e, "intr_force", 1570da5577f0SRobert Mustacchi I40E_INTR_NONE, I40E_INTR_LEGACY, I40E_INTR_NONE); 1571da5577f0SRobert Mustacchi 1572da5577f0SRobert Mustacchi i40e->i40e_mr_enable = i40e_get_prop(i40e, "mr_enable", 1573da5577f0SRobert Mustacchi B_FALSE, B_TRUE, B_TRUE); 1574da5577f0SRobert Mustacchi 1575da5577f0SRobert Mustacchi i40e->i40e_tx_ring_size = i40e_get_prop(i40e, "tx_ring_size", 1576da5577f0SRobert Mustacchi I40E_MIN_TX_RING_SIZE, I40E_MAX_TX_RING_SIZE, 1577da5577f0SRobert Mustacchi I40E_DEF_TX_RING_SIZE); 1578da5577f0SRobert Mustacchi if ((i40e->i40e_tx_ring_size % I40E_DESC_ALIGN) != 0) { 1579da5577f0SRobert Mustacchi i40e->i40e_tx_ring_size = P2ROUNDUP(i40e->i40e_tx_ring_size, 1580da5577f0SRobert Mustacchi I40E_DESC_ALIGN); 1581da5577f0SRobert Mustacchi } 1582da5577f0SRobert Mustacchi 1583da5577f0SRobert Mustacchi i40e->i40e_tx_block_thresh = i40e_get_prop(i40e, "tx_resched_threshold", 1584da5577f0SRobert Mustacchi I40E_MIN_TX_BLOCK_THRESH, 1585da5577f0SRobert Mustacchi i40e->i40e_tx_ring_size - I40E_TX_MAX_COOKIE, 1586da5577f0SRobert Mustacchi I40E_DEF_TX_BLOCK_THRESH); 1587da5577f0SRobert Mustacchi 1588da5577f0SRobert Mustacchi i40e->i40e_rx_ring_size = i40e_get_prop(i40e, "rx_ring_size", 1589da5577f0SRobert Mustacchi I40E_MIN_RX_RING_SIZE, I40E_MAX_RX_RING_SIZE, 1590da5577f0SRobert Mustacchi I40E_DEF_RX_RING_SIZE); 1591da5577f0SRobert Mustacchi if ((i40e->i40e_rx_ring_size % I40E_DESC_ALIGN) != 0) { 1592da5577f0SRobert Mustacchi i40e->i40e_rx_ring_size = P2ROUNDUP(i40e->i40e_rx_ring_size, 1593da5577f0SRobert Mustacchi I40E_DESC_ALIGN); 1594da5577f0SRobert Mustacchi } 1595da5577f0SRobert Mustacchi 1596da5577f0SRobert Mustacchi i40e->i40e_rx_limit_per_intr = i40e_get_prop(i40e, "rx_limit_per_intr", 1597da5577f0SRobert Mustacchi I40E_MIN_RX_LIMIT_PER_INTR, I40E_MAX_RX_LIMIT_PER_INTR, 1598da5577f0SRobert Mustacchi I40E_DEF_RX_LIMIT_PER_INTR); 1599da5577f0SRobert Mustacchi 1600da5577f0SRobert Mustacchi i40e->i40e_tx_hcksum_enable = i40e_get_prop(i40e, "tx_hcksum_enable", 1601da5577f0SRobert Mustacchi B_FALSE, B_TRUE, B_TRUE); 1602da5577f0SRobert Mustacchi 16038d5069bcSRyan Zezeski i40e->i40e_tx_lso_enable = i40e_get_prop(i40e, "tx_lso_enable", 16048d5069bcSRyan Zezeski B_FALSE, B_TRUE, B_TRUE); 16058d5069bcSRyan Zezeski 1606da5577f0SRobert Mustacchi i40e->i40e_rx_hcksum_enable = i40e_get_prop(i40e, "rx_hcksum_enable", 1607da5577f0SRobert Mustacchi B_FALSE, B_TRUE, B_TRUE); 1608da5577f0SRobert Mustacchi 1609da5577f0SRobert Mustacchi i40e->i40e_rx_dma_min = i40e_get_prop(i40e, "rx_dma_threshold", 1610da5577f0SRobert Mustacchi I40E_MIN_RX_DMA_THRESH, I40E_MAX_RX_DMA_THRESH, 1611da5577f0SRobert Mustacchi I40E_DEF_RX_DMA_THRESH); 1612da5577f0SRobert Mustacchi 1613da5577f0SRobert Mustacchi i40e->i40e_tx_dma_min = i40e_get_prop(i40e, "tx_dma_threshold", 1614da5577f0SRobert Mustacchi I40E_MIN_TX_DMA_THRESH, I40E_MAX_TX_DMA_THRESH, 1615da5577f0SRobert Mustacchi I40E_DEF_TX_DMA_THRESH); 1616da5577f0SRobert Mustacchi 1617da5577f0SRobert Mustacchi i40e->i40e_tx_itr = i40e_get_prop(i40e, "tx_intr_throttle", 1618da5577f0SRobert Mustacchi I40E_MIN_ITR, I40E_MAX_ITR, I40E_DEF_TX_ITR); 1619da5577f0SRobert Mustacchi 1620da5577f0SRobert Mustacchi i40e->i40e_rx_itr = i40e_get_prop(i40e, "rx_intr_throttle", 1621da5577f0SRobert Mustacchi I40E_MIN_ITR, I40E_MAX_ITR, I40E_DEF_RX_ITR); 1622da5577f0SRobert Mustacchi 1623da5577f0SRobert Mustacchi i40e->i40e_other_itr = i40e_get_prop(i40e, "other_intr_throttle", 1624da5577f0SRobert Mustacchi I40E_MIN_ITR, I40E_MAX_ITR, I40E_DEF_OTHER_ITR); 1625da5577f0SRobert Mustacchi 1626da5577f0SRobert Mustacchi if (!i40e->i40e_mr_enable) { 1627da5577f0SRobert Mustacchi i40e->i40e_num_trqpairs = I40E_TRQPAIR_NOMSIX; 1628da5577f0SRobert Mustacchi i40e->i40e_num_rx_groups = I40E_GROUP_NOMSIX; 1629da5577f0SRobert Mustacchi } 1630da5577f0SRobert Mustacchi 1631da5577f0SRobert Mustacchi i40e_update_mtu(i40e); 1632da5577f0SRobert Mustacchi } 1633da5577f0SRobert Mustacchi 1634da5577f0SRobert Mustacchi /* 1635da5577f0SRobert Mustacchi * There are a few constraints on interrupts that we're currently imposing, some 1636da5577f0SRobert Mustacchi * of which are restrictions from hardware. For a fuller treatment, see 1637da5577f0SRobert Mustacchi * i40e_intr.c. 1638da5577f0SRobert Mustacchi * 1639da5577f0SRobert Mustacchi * Currently, to use MSI-X we require two interrupts be available though in 1640da5577f0SRobert Mustacchi * theory we should participate in IRM and happily use more interrupts. 1641da5577f0SRobert Mustacchi * 1642da5577f0SRobert Mustacchi * Hardware only supports a single MSI being programmed and therefore if we 1643da5577f0SRobert Mustacchi * don't have MSI-X interrupts available at this time, then we ratchet down the 1644da5577f0SRobert Mustacchi * number of rings and groups available. Obviously, we only bother with a single 1645da5577f0SRobert Mustacchi * fixed interrupt. 1646da5577f0SRobert Mustacchi */ 1647da5577f0SRobert Mustacchi static boolean_t 1648da5577f0SRobert Mustacchi i40e_alloc_intr_handles(i40e_t *i40e, dev_info_t *devinfo, int intr_type) 1649da5577f0SRobert Mustacchi { 165005768666SPaul Winder i40e_hw_t *hw = &i40e->i40e_hw_space; 165105768666SPaul Winder ddi_acc_handle_t rh = i40e->i40e_osdep_space.ios_reg_handle; 1652da5577f0SRobert Mustacchi int request, count, actual, rc, min; 165305768666SPaul Winder uint32_t reg; 1654da5577f0SRobert Mustacchi 1655da5577f0SRobert Mustacchi switch (intr_type) { 1656da5577f0SRobert Mustacchi case DDI_INTR_TYPE_FIXED: 1657da5577f0SRobert Mustacchi case DDI_INTR_TYPE_MSI: 1658da5577f0SRobert Mustacchi request = 1; 1659da5577f0SRobert Mustacchi min = 1; 1660da5577f0SRobert Mustacchi break; 1661da5577f0SRobert Mustacchi case DDI_INTR_TYPE_MSIX: 1662da5577f0SRobert Mustacchi min = 2; 166305768666SPaul Winder if (!i40e->i40e_mr_enable) { 166405768666SPaul Winder request = 2; 166505768666SPaul Winder break; 166605768666SPaul Winder } 166705768666SPaul Winder reg = I40E_READ_REG(hw, I40E_GLPCI_CNF2); 166805768666SPaul Winder /* 166905768666SPaul Winder * Should this read fail, we will drop back to using 167005768666SPaul Winder * MSI or fixed interrupts. 167105768666SPaul Winder */ 167205768666SPaul Winder if (i40e_check_acc_handle(rh) != DDI_FM_OK) { 167305768666SPaul Winder ddi_fm_service_impact(i40e->i40e_dip, 167405768666SPaul Winder DDI_SERVICE_DEGRADED); 167505768666SPaul Winder return (B_FALSE); 167605768666SPaul Winder } 167705768666SPaul Winder request = (reg & I40E_GLPCI_CNF2_MSI_X_PF_N_MASK) >> 167805768666SPaul Winder I40E_GLPCI_CNF2_MSI_X_PF_N_SHIFT; 167905768666SPaul Winder request++; /* the register value is n - 1 */ 1680da5577f0SRobert Mustacchi break; 1681da5577f0SRobert Mustacchi default: 1682da5577f0SRobert Mustacchi panic("bad interrupt type passed to i40e_alloc_intr_handles: " 1683da5577f0SRobert Mustacchi "%d", intr_type); 1684da5577f0SRobert Mustacchi return (B_FALSE); 1685da5577f0SRobert Mustacchi } 1686da5577f0SRobert Mustacchi 1687da5577f0SRobert Mustacchi rc = ddi_intr_get_nintrs(devinfo, intr_type, &count); 1688da5577f0SRobert Mustacchi if (rc != DDI_SUCCESS || count < min) { 1689da5577f0SRobert Mustacchi i40e_log(i40e, "Get interrupt number failed, " 1690da5577f0SRobert Mustacchi "returned %d, count %d", rc, count); 1691da5577f0SRobert Mustacchi return (B_FALSE); 1692da5577f0SRobert Mustacchi } 1693da5577f0SRobert Mustacchi 1694da5577f0SRobert Mustacchi rc = ddi_intr_get_navail(devinfo, intr_type, &count); 1695da5577f0SRobert Mustacchi if (rc != DDI_SUCCESS || count < min) { 1696da5577f0SRobert Mustacchi i40e_log(i40e, "Get AVAILABLE interrupt number failed, " 1697da5577f0SRobert Mustacchi "returned %d, count %d", rc, count); 1698da5577f0SRobert Mustacchi return (B_FALSE); 1699da5577f0SRobert Mustacchi } 1700da5577f0SRobert Mustacchi 1701da5577f0SRobert Mustacchi actual = 0; 1702da5577f0SRobert Mustacchi i40e->i40e_intr_count = 0; 1703da5577f0SRobert Mustacchi i40e->i40e_intr_count_max = 0; 1704da5577f0SRobert Mustacchi i40e->i40e_intr_count_min = 0; 1705da5577f0SRobert Mustacchi 1706da5577f0SRobert Mustacchi i40e->i40e_intr_size = request * sizeof (ddi_intr_handle_t); 1707da5577f0SRobert Mustacchi ASSERT(i40e->i40e_intr_size != 0); 1708da5577f0SRobert Mustacchi i40e->i40e_intr_handles = kmem_alloc(i40e->i40e_intr_size, KM_SLEEP); 1709da5577f0SRobert Mustacchi 1710da5577f0SRobert Mustacchi rc = ddi_intr_alloc(devinfo, i40e->i40e_intr_handles, intr_type, 0, 1711da5577f0SRobert Mustacchi min(request, count), &actual, DDI_INTR_ALLOC_NORMAL); 1712da5577f0SRobert Mustacchi if (rc != DDI_SUCCESS) { 1713da5577f0SRobert Mustacchi i40e_log(i40e, "Interrupt allocation failed with %d.", rc); 1714da5577f0SRobert Mustacchi goto alloc_handle_fail; 1715da5577f0SRobert Mustacchi } 1716da5577f0SRobert Mustacchi 1717da5577f0SRobert Mustacchi i40e->i40e_intr_count = actual; 1718da5577f0SRobert Mustacchi i40e->i40e_intr_count_max = request; 1719da5577f0SRobert Mustacchi i40e->i40e_intr_count_min = min; 1720da5577f0SRobert Mustacchi 1721da5577f0SRobert Mustacchi if (actual < min) { 1722da5577f0SRobert Mustacchi i40e_log(i40e, "actual (%d) is less than minimum (%d).", 1723da5577f0SRobert Mustacchi actual, min); 1724da5577f0SRobert Mustacchi goto alloc_handle_fail; 1725da5577f0SRobert Mustacchi } 1726da5577f0SRobert Mustacchi 1727da5577f0SRobert Mustacchi /* 1728da5577f0SRobert Mustacchi * Record the priority and capabilities for our first vector. Once 1729da5577f0SRobert Mustacchi * we have it, that's our priority until detach time. Even if we 1730da5577f0SRobert Mustacchi * eventually participate in IRM, our priority shouldn't change. 1731da5577f0SRobert Mustacchi */ 1732da5577f0SRobert Mustacchi rc = ddi_intr_get_pri(i40e->i40e_intr_handles[0], &i40e->i40e_intr_pri); 1733da5577f0SRobert Mustacchi if (rc != DDI_SUCCESS) { 1734da5577f0SRobert Mustacchi i40e_log(i40e, 1735da5577f0SRobert Mustacchi "Getting interrupt priority failed with %d.", rc); 1736da5577f0SRobert Mustacchi goto alloc_handle_fail; 1737da5577f0SRobert Mustacchi } 1738da5577f0SRobert Mustacchi 1739da5577f0SRobert Mustacchi rc = ddi_intr_get_cap(i40e->i40e_intr_handles[0], &i40e->i40e_intr_cap); 1740da5577f0SRobert Mustacchi if (rc != DDI_SUCCESS) { 1741da5577f0SRobert Mustacchi i40e_log(i40e, 1742da5577f0SRobert Mustacchi "Getting interrupt capabilities failed with %d.", rc); 1743da5577f0SRobert Mustacchi goto alloc_handle_fail; 1744da5577f0SRobert Mustacchi } 1745da5577f0SRobert Mustacchi 1746da5577f0SRobert Mustacchi i40e->i40e_intr_type = intr_type; 1747da5577f0SRobert Mustacchi return (B_TRUE); 1748da5577f0SRobert Mustacchi 1749da5577f0SRobert Mustacchi alloc_handle_fail: 1750da5577f0SRobert Mustacchi 1751da5577f0SRobert Mustacchi i40e_rem_intrs(i40e); 1752da5577f0SRobert Mustacchi return (B_FALSE); 1753da5577f0SRobert Mustacchi } 1754da5577f0SRobert Mustacchi 1755da5577f0SRobert Mustacchi static boolean_t 1756da5577f0SRobert Mustacchi i40e_alloc_intrs(i40e_t *i40e, dev_info_t *devinfo) 1757da5577f0SRobert Mustacchi { 1758da5577f0SRobert Mustacchi int intr_types, rc; 1759a7f9b000SRobert Mustacchi uint_t max_trqpairs; 1760a7f9b000SRobert Mustacchi 1761a7f9b000SRobert Mustacchi if (i40e_is_x722(i40e)) { 1762a7f9b000SRobert Mustacchi max_trqpairs = I40E_722_MAX_TC_QUEUES; 1763a7f9b000SRobert Mustacchi } else { 1764a7f9b000SRobert Mustacchi max_trqpairs = I40E_710_MAX_TC_QUEUES; 1765a7f9b000SRobert Mustacchi } 1766da5577f0SRobert Mustacchi 1767da5577f0SRobert Mustacchi rc = ddi_intr_get_supported_types(devinfo, &intr_types); 1768da5577f0SRobert Mustacchi if (rc != DDI_SUCCESS) { 1769da5577f0SRobert Mustacchi i40e_error(i40e, "failed to get supported interrupt types: %d", 1770da5577f0SRobert Mustacchi rc); 1771da5577f0SRobert Mustacchi return (B_FALSE); 1772da5577f0SRobert Mustacchi } 1773da5577f0SRobert Mustacchi 1774da5577f0SRobert Mustacchi i40e->i40e_intr_type = 0; 17758d5069bcSRyan Zezeski i40e->i40e_num_rx_groups = I40E_GROUP_MAX; 1776da5577f0SRobert Mustacchi 17778d5069bcSRyan Zezeski /* 17788d5069bcSRyan Zezeski * We need to determine the number of queue pairs per traffic 17798d5069bcSRyan Zezeski * class. We only have one traffic class (TC0), so we'll base 17808d5069bcSRyan Zezeski * this off the number of interrupts provided. Furthermore, 17818d5069bcSRyan Zezeski * since we only use one traffic class, the number of queues 17828d5069bcSRyan Zezeski * per traffic class and per VSI are the same. 17838d5069bcSRyan Zezeski */ 1784da5577f0SRobert Mustacchi if ((intr_types & DDI_INTR_TYPE_MSIX) && 17858d5069bcSRyan Zezeski (i40e->i40e_intr_force <= I40E_INTR_MSIX) && 17868d5069bcSRyan Zezeski (i40e_alloc_intr_handles(i40e, devinfo, DDI_INTR_TYPE_MSIX))) { 17878d5069bcSRyan Zezeski uint32_t n; 17888d5069bcSRyan Zezeski 17898d5069bcSRyan Zezeski /* 17908d5069bcSRyan Zezeski * While we want the number of queue pairs to match 17918d5069bcSRyan Zezeski * the number of interrupts, we must keep stay in 17928d5069bcSRyan Zezeski * bounds of the maximum number of queues per traffic 17938d5069bcSRyan Zezeski * class. We subtract one from i40e_intr_count to 17948d5069bcSRyan Zezeski * account for interrupt zero; which is currently 17958d5069bcSRyan Zezeski * restricted to admin queue commands and other 17968d5069bcSRyan Zezeski * interrupt causes. 17978d5069bcSRyan Zezeski */ 17988d5069bcSRyan Zezeski n = MIN(i40e->i40e_intr_count - 1, max_trqpairs); 17998d5069bcSRyan Zezeski ASSERT3U(n, >, 0); 18008d5069bcSRyan Zezeski 18018d5069bcSRyan Zezeski /* 18028d5069bcSRyan Zezeski * Round up to the nearest power of two to ensure that 18038d5069bcSRyan Zezeski * the QBASE aligns with the TC size which must be 18048d5069bcSRyan Zezeski * programmed as a power of two. See the queue mapping 18058d5069bcSRyan Zezeski * description in section 7.4.9.5.5.1. 18068d5069bcSRyan Zezeski * 18078d5069bcSRyan Zezeski * If i40e_intr_count - 1 is not a power of two then 18088d5069bcSRyan Zezeski * some queue pairs on the same VSI will have to share 18098d5069bcSRyan Zezeski * an interrupt. 18108d5069bcSRyan Zezeski * 18118d5069bcSRyan Zezeski * We may want to revisit this logic in a future where 18128d5069bcSRyan Zezeski * we have more interrupts and more VSIs. Otherwise, 18138d5069bcSRyan Zezeski * each VSI will use as many interrupts as possible. 18148d5069bcSRyan Zezeski * Using more QPs per VSI means better RSS for each 18158d5069bcSRyan Zezeski * group, but at the same time may require more 18168d5069bcSRyan Zezeski * sharing of interrupts across VSIs. This may be a 18178d5069bcSRyan Zezeski * good candidate for a .conf tunable. 18188d5069bcSRyan Zezeski */ 18198d5069bcSRyan Zezeski n = 0x1 << ddi_fls(n); 18208d5069bcSRyan Zezeski i40e->i40e_num_trqpairs_per_vsi = n; 18218d5069bcSRyan Zezeski ASSERT3U(i40e->i40e_num_rx_groups, >, 0); 18228d5069bcSRyan Zezeski i40e->i40e_num_trqpairs = i40e->i40e_num_trqpairs_per_vsi * 18238d5069bcSRyan Zezeski i40e->i40e_num_rx_groups; 1824da5577f0SRobert Mustacchi return (B_TRUE); 1825da5577f0SRobert Mustacchi } 1826da5577f0SRobert Mustacchi 1827da5577f0SRobert Mustacchi /* 1828da5577f0SRobert Mustacchi * We only use multiple transmit/receive pairs when MSI-X interrupts are 1829da5577f0SRobert Mustacchi * available due to the fact that the device basically only supports a 1830da5577f0SRobert Mustacchi * single MSI interrupt. 1831da5577f0SRobert Mustacchi */ 1832da5577f0SRobert Mustacchi i40e->i40e_num_trqpairs = I40E_TRQPAIR_NOMSIX; 18338d5069bcSRyan Zezeski i40e->i40e_num_trqpairs_per_vsi = i40e->i40e_num_trqpairs; 1834da5577f0SRobert Mustacchi i40e->i40e_num_rx_groups = I40E_GROUP_NOMSIX; 1835da5577f0SRobert Mustacchi 1836da5577f0SRobert Mustacchi if ((intr_types & DDI_INTR_TYPE_MSI) && 1837da5577f0SRobert Mustacchi (i40e->i40e_intr_force <= I40E_INTR_MSI)) { 1838da5577f0SRobert Mustacchi if (i40e_alloc_intr_handles(i40e, devinfo, DDI_INTR_TYPE_MSI)) 1839da5577f0SRobert Mustacchi return (B_TRUE); 1840da5577f0SRobert Mustacchi } 1841da5577f0SRobert Mustacchi 1842da5577f0SRobert Mustacchi if (intr_types & DDI_INTR_TYPE_FIXED) { 1843da5577f0SRobert Mustacchi if (i40e_alloc_intr_handles(i40e, devinfo, DDI_INTR_TYPE_FIXED)) 1844da5577f0SRobert Mustacchi return (B_TRUE); 1845da5577f0SRobert Mustacchi } 1846da5577f0SRobert Mustacchi 1847da5577f0SRobert Mustacchi return (B_FALSE); 1848da5577f0SRobert Mustacchi } 1849da5577f0SRobert Mustacchi 1850da5577f0SRobert Mustacchi /* 1851da5577f0SRobert Mustacchi * Map different interrupts to MSI-X vectors. 1852da5577f0SRobert Mustacchi */ 1853da5577f0SRobert Mustacchi static boolean_t 1854da5577f0SRobert Mustacchi i40e_map_intrs_to_vectors(i40e_t *i40e) 1855da5577f0SRobert Mustacchi { 1856da5577f0SRobert Mustacchi if (i40e->i40e_intr_type != DDI_INTR_TYPE_MSIX) { 1857da5577f0SRobert Mustacchi return (B_TRUE); 1858da5577f0SRobert Mustacchi } 1859da5577f0SRobert Mustacchi 1860da5577f0SRobert Mustacchi /* 18618d5069bcSRyan Zezeski * Each queue pair is mapped to a single interrupt, so 18628d5069bcSRyan Zezeski * transmit and receive interrupts for a given queue share the 18638d5069bcSRyan Zezeski * same vector. Vector zero is reserved for the admin queue. 1864da5577f0SRobert Mustacchi */ 18658d5069bcSRyan Zezeski for (uint_t i = 0; i < i40e->i40e_num_trqpairs; i++) { 18668d5069bcSRyan Zezeski uint_t vector = i % (i40e->i40e_intr_count - 1); 1867da5577f0SRobert Mustacchi 18688d5069bcSRyan Zezeski i40e->i40e_trqpairs[i].itrq_rx_intrvec = vector + 1; 18698d5069bcSRyan Zezeski i40e->i40e_trqpairs[i].itrq_tx_intrvec = vector + 1; 187005768666SPaul Winder } 1871da5577f0SRobert Mustacchi 1872da5577f0SRobert Mustacchi return (B_TRUE); 1873da5577f0SRobert Mustacchi } 1874da5577f0SRobert Mustacchi 1875da5577f0SRobert Mustacchi static boolean_t 1876da5577f0SRobert Mustacchi i40e_add_intr_handlers(i40e_t *i40e) 1877da5577f0SRobert Mustacchi { 1878da5577f0SRobert Mustacchi int rc, vector; 1879da5577f0SRobert Mustacchi 1880da5577f0SRobert Mustacchi switch (i40e->i40e_intr_type) { 1881da5577f0SRobert Mustacchi case DDI_INTR_TYPE_MSIX: 1882da5577f0SRobert Mustacchi for (vector = 0; vector < i40e->i40e_intr_count; vector++) { 1883da5577f0SRobert Mustacchi rc = ddi_intr_add_handler( 1884da5577f0SRobert Mustacchi i40e->i40e_intr_handles[vector], 1885da5577f0SRobert Mustacchi (ddi_intr_handler_t *)i40e_intr_msix, i40e, 1886da5577f0SRobert Mustacchi (void *)(uintptr_t)vector); 1887da5577f0SRobert Mustacchi if (rc != DDI_SUCCESS) { 1888da5577f0SRobert Mustacchi i40e_log(i40e, "Add interrupt handler (MSI-X) " 1889da5577f0SRobert Mustacchi "failed: return %d, vector %d", rc, vector); 1890da5577f0SRobert Mustacchi for (vector--; vector >= 0; vector--) { 1891da5577f0SRobert Mustacchi (void) ddi_intr_remove_handler( 1892da5577f0SRobert Mustacchi i40e->i40e_intr_handles[vector]); 1893da5577f0SRobert Mustacchi } 1894da5577f0SRobert Mustacchi return (B_FALSE); 1895da5577f0SRobert Mustacchi } 1896da5577f0SRobert Mustacchi } 1897da5577f0SRobert Mustacchi break; 1898da5577f0SRobert Mustacchi case DDI_INTR_TYPE_MSI: 1899da5577f0SRobert Mustacchi rc = ddi_intr_add_handler(i40e->i40e_intr_handles[0], 1900da5577f0SRobert Mustacchi (ddi_intr_handler_t *)i40e_intr_msi, i40e, NULL); 1901da5577f0SRobert Mustacchi if (rc != DDI_SUCCESS) { 1902da5577f0SRobert Mustacchi i40e_log(i40e, "Add interrupt handler (MSI) failed: " 1903da5577f0SRobert Mustacchi "return %d", rc); 1904da5577f0SRobert Mustacchi return (B_FALSE); 1905da5577f0SRobert Mustacchi } 1906da5577f0SRobert Mustacchi break; 1907da5577f0SRobert Mustacchi case DDI_INTR_TYPE_FIXED: 1908da5577f0SRobert Mustacchi rc = ddi_intr_add_handler(i40e->i40e_intr_handles[0], 1909da5577f0SRobert Mustacchi (ddi_intr_handler_t *)i40e_intr_legacy, i40e, NULL); 1910da5577f0SRobert Mustacchi if (rc != DDI_SUCCESS) { 1911da5577f0SRobert Mustacchi i40e_log(i40e, "Add interrupt handler (legacy) failed:" 1912da5577f0SRobert Mustacchi " return %d", rc); 1913da5577f0SRobert Mustacchi return (B_FALSE); 1914da5577f0SRobert Mustacchi } 1915da5577f0SRobert Mustacchi break; 1916da5577f0SRobert Mustacchi default: 1917da5577f0SRobert Mustacchi /* Cast to pacify lint */ 1918da5577f0SRobert Mustacchi panic("i40e_intr_type %p contains an unknown type: %d", 1919da5577f0SRobert Mustacchi (void *)i40e, i40e->i40e_intr_type); 1920da5577f0SRobert Mustacchi } 1921da5577f0SRobert Mustacchi 1922da5577f0SRobert Mustacchi return (B_TRUE); 1923da5577f0SRobert Mustacchi } 1924da5577f0SRobert Mustacchi 1925da5577f0SRobert Mustacchi /* 1926da5577f0SRobert Mustacchi * Perform periodic checks. Longer term, we should be thinking about additional 1927da5577f0SRobert Mustacchi * things here: 1928da5577f0SRobert Mustacchi * 1929da5577f0SRobert Mustacchi * o Stall Detection 1930da5577f0SRobert Mustacchi * o Temperature sensor detection 1931da5577f0SRobert Mustacchi * o Device resetting 1932da5577f0SRobert Mustacchi * o Statistics updating to avoid wraparound 1933da5577f0SRobert Mustacchi */ 1934da5577f0SRobert Mustacchi static void 1935da5577f0SRobert Mustacchi i40e_timer(void *arg) 1936da5577f0SRobert Mustacchi { 1937da5577f0SRobert Mustacchi i40e_t *i40e = arg; 1938da5577f0SRobert Mustacchi 1939da5577f0SRobert Mustacchi mutex_enter(&i40e->i40e_general_lock); 1940da5577f0SRobert Mustacchi i40e_link_check(i40e); 1941da5577f0SRobert Mustacchi mutex_exit(&i40e->i40e_general_lock); 1942da5577f0SRobert Mustacchi } 1943da5577f0SRobert Mustacchi 1944da5577f0SRobert Mustacchi /* 1945da5577f0SRobert Mustacchi * Get the hardware state, and scribble away anything that needs scribbling. 1946da5577f0SRobert Mustacchi */ 1947da5577f0SRobert Mustacchi static void 1948da5577f0SRobert Mustacchi i40e_get_hw_state(i40e_t *i40e, i40e_hw_t *hw) 1949da5577f0SRobert Mustacchi { 1950da5577f0SRobert Mustacchi int rc; 1951da5577f0SRobert Mustacchi 1952da5577f0SRobert Mustacchi ASSERT(MUTEX_HELD(&i40e->i40e_general_lock)); 1953da5577f0SRobert Mustacchi 1954da5577f0SRobert Mustacchi (void) i40e_aq_get_link_info(hw, TRUE, NULL, NULL); 1955da5577f0SRobert Mustacchi i40e_link_check(i40e); 1956da5577f0SRobert Mustacchi 1957da5577f0SRobert Mustacchi /* 1958da5577f0SRobert Mustacchi * Try and determine our PHY. Note that we may have to retry to and 1959da5577f0SRobert Mustacchi * delay to detect fiber correctly. 1960da5577f0SRobert Mustacchi */ 1961da5577f0SRobert Mustacchi rc = i40e_aq_get_phy_capabilities(hw, B_FALSE, B_TRUE, &i40e->i40e_phy, 1962da5577f0SRobert Mustacchi NULL); 1963da5577f0SRobert Mustacchi if (rc == I40E_ERR_UNKNOWN_PHY) { 1964da5577f0SRobert Mustacchi i40e_msec_delay(200); 1965da5577f0SRobert Mustacchi rc = i40e_aq_get_phy_capabilities(hw, B_FALSE, B_TRUE, 1966da5577f0SRobert Mustacchi &i40e->i40e_phy, NULL); 1967da5577f0SRobert Mustacchi } 1968da5577f0SRobert Mustacchi 1969da5577f0SRobert Mustacchi if (rc != I40E_SUCCESS) { 1970da5577f0SRobert Mustacchi if (rc == I40E_ERR_UNKNOWN_PHY) { 1971da5577f0SRobert Mustacchi i40e_error(i40e, "encountered unknown PHY type, " 1972da5577f0SRobert Mustacchi "not attaching."); 1973da5577f0SRobert Mustacchi } else { 1974da5577f0SRobert Mustacchi i40e_error(i40e, "error getting physical capabilities: " 1975da5577f0SRobert Mustacchi "%d, %d", rc, hw->aq.asq_last_status); 1976da5577f0SRobert Mustacchi } 1977da5577f0SRobert Mustacchi } 1978da5577f0SRobert Mustacchi 1979da5577f0SRobert Mustacchi rc = i40e_update_link_info(hw); 1980da5577f0SRobert Mustacchi if (rc != I40E_SUCCESS) { 1981da5577f0SRobert Mustacchi i40e_error(i40e, "failed to update link information: %d", rc); 1982da5577f0SRobert Mustacchi } 1983da5577f0SRobert Mustacchi 1984da5577f0SRobert Mustacchi /* 1985da5577f0SRobert Mustacchi * In general, we don't want to mask off (as in stop from being a cause) 1986da5577f0SRobert Mustacchi * any of the interrupts that the phy might be able to generate. 1987da5577f0SRobert Mustacchi */ 1988da5577f0SRobert Mustacchi rc = i40e_aq_set_phy_int_mask(hw, 0, NULL); 1989da5577f0SRobert Mustacchi if (rc != I40E_SUCCESS) { 1990da5577f0SRobert Mustacchi i40e_error(i40e, "failed to update phy link mask: %d", rc); 1991da5577f0SRobert Mustacchi } 1992da5577f0SRobert Mustacchi } 1993da5577f0SRobert Mustacchi 1994da5577f0SRobert Mustacchi /* 1995da5577f0SRobert Mustacchi * Go through and re-initialize any existing filters that we may have set up for 1996da5577f0SRobert Mustacchi * this device. Note that we would only expect them to exist if hardware had 1997da5577f0SRobert Mustacchi * already been initialized and we had just reset it. While we're not 1998da5577f0SRobert Mustacchi * implementing this yet, we're keeping this around for when we add reset 1999da5577f0SRobert Mustacchi * capabilities, so this isn't forgotten. 2000da5577f0SRobert Mustacchi */ 2001da5577f0SRobert Mustacchi /* ARGSUSED */ 2002da5577f0SRobert Mustacchi static void 2003da5577f0SRobert Mustacchi i40e_init_macaddrs(i40e_t *i40e, i40e_hw_t *hw) 2004da5577f0SRobert Mustacchi { 2005da5577f0SRobert Mustacchi } 2006da5577f0SRobert Mustacchi 2007da5577f0SRobert Mustacchi /* 20088d5069bcSRyan Zezeski * Set the properties which have common values across all the VSIs. 20098d5069bcSRyan Zezeski * Consult the "Add VSI" command section (7.4.9.5.5.1) for a 20108d5069bcSRyan Zezeski * complete description of these properties. 20118d5069bcSRyan Zezeski */ 20128d5069bcSRyan Zezeski static void 20138d5069bcSRyan Zezeski i40e_set_shared_vsi_props(i40e_t *i40e, 20148d5069bcSRyan Zezeski struct i40e_aqc_vsi_properties_data *info, uint_t vsi_idx) 20158d5069bcSRyan Zezeski { 20168d5069bcSRyan Zezeski uint_t tc_queues; 20178d5069bcSRyan Zezeski uint16_t vsi_qp_base; 20188d5069bcSRyan Zezeski 20198d5069bcSRyan Zezeski /* 20208d5069bcSRyan Zezeski * It's important that we use bitwise-OR here; callers to this 20218d5069bcSRyan Zezeski * function might enable other sections before calling this 20228d5069bcSRyan Zezeski * function. 20238d5069bcSRyan Zezeski */ 20248d5069bcSRyan Zezeski info->valid_sections |= LE_16(I40E_AQ_VSI_PROP_QUEUE_MAP_VALID | 20258d5069bcSRyan Zezeski I40E_AQ_VSI_PROP_VLAN_VALID); 20268d5069bcSRyan Zezeski 20278d5069bcSRyan Zezeski /* 20288d5069bcSRyan Zezeski * Calculate the starting QP index for this VSI. This base is 20298d5069bcSRyan Zezeski * relative to the PF queue space; so a value of 0 for PF#1 20308d5069bcSRyan Zezeski * represents the absolute index PFLAN_QALLOC_FIRSTQ for PF#1. 20318d5069bcSRyan Zezeski */ 20328d5069bcSRyan Zezeski vsi_qp_base = vsi_idx * i40e->i40e_num_trqpairs_per_vsi; 20338d5069bcSRyan Zezeski info->mapping_flags = LE_16(I40E_AQ_VSI_QUE_MAP_CONTIG); 20348d5069bcSRyan Zezeski info->queue_mapping[0] = 20358d5069bcSRyan Zezeski LE_16((vsi_qp_base << I40E_AQ_VSI_QUEUE_SHIFT) & 20368d5069bcSRyan Zezeski I40E_AQ_VSI_QUEUE_MASK); 20378d5069bcSRyan Zezeski 20388d5069bcSRyan Zezeski /* 20398d5069bcSRyan Zezeski * tc_queues determines the size of the traffic class, where 20408d5069bcSRyan Zezeski * the size is 2^^tc_queues to a maximum of 64 for the X710 20418d5069bcSRyan Zezeski * and 128 for the X722. 20428d5069bcSRyan Zezeski * 20438d5069bcSRyan Zezeski * Some examples: 20448d5069bcSRyan Zezeski * i40e_num_trqpairs_per_vsi == 1 => tc_queues = 0, 2^^0 = 1. 20458d5069bcSRyan Zezeski * i40e_num_trqpairs_per_vsi == 7 => tc_queues = 3, 2^^3 = 8. 20468d5069bcSRyan Zezeski * i40e_num_trqpairs_per_vsi == 8 => tc_queues = 3, 2^^3 = 8. 20478d5069bcSRyan Zezeski * i40e_num_trqpairs_per_vsi == 9 => tc_queues = 4, 2^^4 = 16. 20488d5069bcSRyan Zezeski * i40e_num_trqpairs_per_vsi == 17 => tc_queues = 5, 2^^5 = 32. 20498d5069bcSRyan Zezeski * i40e_num_trqpairs_per_vsi == 64 => tc_queues = 6, 2^^6 = 64. 20508d5069bcSRyan Zezeski */ 20518d5069bcSRyan Zezeski tc_queues = ddi_fls(i40e->i40e_num_trqpairs_per_vsi - 1); 20528d5069bcSRyan Zezeski 20538d5069bcSRyan Zezeski /* 20548d5069bcSRyan Zezeski * The TC queue mapping is in relation to the VSI queue space. 20558d5069bcSRyan Zezeski * Since we are only using one traffic class (TC0) we always 20568d5069bcSRyan Zezeski * start at queue offset 0. 20578d5069bcSRyan Zezeski */ 20588d5069bcSRyan Zezeski info->tc_mapping[0] = 20598d5069bcSRyan Zezeski LE_16(((0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) & 20608d5069bcSRyan Zezeski I40E_AQ_VSI_TC_QUE_OFFSET_MASK) | 20618d5069bcSRyan Zezeski ((tc_queues << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT) & 20628d5069bcSRyan Zezeski I40E_AQ_VSI_TC_QUE_NUMBER_MASK)); 20638d5069bcSRyan Zezeski 20648d5069bcSRyan Zezeski /* 20658d5069bcSRyan Zezeski * I40E_AQ_VSI_PVLAN_MODE_ALL ("VLAN driver insertion mode") 20668d5069bcSRyan Zezeski * 20678d5069bcSRyan Zezeski * Allow tagged and untagged packets to be sent to this 20688d5069bcSRyan Zezeski * VSI from the host. 20698d5069bcSRyan Zezeski * 20708d5069bcSRyan Zezeski * I40E_AQ_VSI_PVLAN_EMOD_NOTHING ("VLAN and UP expose mode") 20718d5069bcSRyan Zezeski * 20728d5069bcSRyan Zezeski * Leave the tag on the frame and place no VLAN 20738d5069bcSRyan Zezeski * information in the descriptor. We want this mode 20748d5069bcSRyan Zezeski * because our MAC layer will take care of the VLAN tag, 20758d5069bcSRyan Zezeski * if there is one. 20768d5069bcSRyan Zezeski */ 20778d5069bcSRyan Zezeski info->port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL | 20788d5069bcSRyan Zezeski I40E_AQ_VSI_PVLAN_EMOD_NOTHING; 20798d5069bcSRyan Zezeski } 20808d5069bcSRyan Zezeski 20818d5069bcSRyan Zezeski /* 20828d5069bcSRyan Zezeski * Delete the VSI at this index, if one exists. We assume there is no 20838d5069bcSRyan Zezeski * action we can take if this command fails but to log the failure. 20848d5069bcSRyan Zezeski */ 20858d5069bcSRyan Zezeski static void 20868d5069bcSRyan Zezeski i40e_delete_vsi(i40e_t *i40e, uint_t idx) 20878d5069bcSRyan Zezeski { 20888d5069bcSRyan Zezeski i40e_hw_t *hw = &i40e->i40e_hw_space; 20898d5069bcSRyan Zezeski uint16_t seid = i40e->i40e_vsis[idx].iv_seid; 20908d5069bcSRyan Zezeski 20918d5069bcSRyan Zezeski if (seid != 0) { 20928d5069bcSRyan Zezeski int rc; 20938d5069bcSRyan Zezeski 20948d5069bcSRyan Zezeski rc = i40e_aq_delete_element(hw, seid, NULL); 20958d5069bcSRyan Zezeski 20968d5069bcSRyan Zezeski if (rc != I40E_SUCCESS) { 20978d5069bcSRyan Zezeski i40e_error(i40e, "Failed to delete VSI %d: %d", 20988d5069bcSRyan Zezeski rc, hw->aq.asq_last_status); 20998d5069bcSRyan Zezeski } 21008d5069bcSRyan Zezeski 21018d5069bcSRyan Zezeski i40e->i40e_vsis[idx].iv_seid = 0; 21028d5069bcSRyan Zezeski } 21038d5069bcSRyan Zezeski } 21048d5069bcSRyan Zezeski 21058d5069bcSRyan Zezeski /* 21068d5069bcSRyan Zezeski * Add a new VSI. 2107da5577f0SRobert Mustacchi */ 2108da5577f0SRobert Mustacchi static boolean_t 21098d5069bcSRyan Zezeski i40e_add_vsi(i40e_t *i40e, i40e_hw_t *hw, uint_t idx) 2110da5577f0SRobert Mustacchi { 21118d5069bcSRyan Zezeski struct i40e_vsi_context ctx; 21128d5069bcSRyan Zezeski i40e_rx_group_t *rxg; 21138d5069bcSRyan Zezeski int rc; 2114da5577f0SRobert Mustacchi 21158d5069bcSRyan Zezeski /* 21168d5069bcSRyan Zezeski * The default VSI is created by the controller. This function 21178d5069bcSRyan Zezeski * creates new, non-defualt VSIs only. 21188d5069bcSRyan Zezeski */ 21198d5069bcSRyan Zezeski ASSERT3U(idx, !=, 0); 21208d5069bcSRyan Zezeski 21218d5069bcSRyan Zezeski bzero(&ctx, sizeof (struct i40e_vsi_context)); 21228d5069bcSRyan Zezeski ctx.uplink_seid = i40e->i40e_veb_seid; 21238d5069bcSRyan Zezeski ctx.pf_num = hw->pf_id; 21248d5069bcSRyan Zezeski ctx.flags = I40E_AQ_VSI_TYPE_PF; 21258d5069bcSRyan Zezeski ctx.connection_type = I40E_AQ_VSI_CONN_TYPE_NORMAL; 21268d5069bcSRyan Zezeski i40e_set_shared_vsi_props(i40e, &ctx.info, idx); 21278d5069bcSRyan Zezeski 21288d5069bcSRyan Zezeski rc = i40e_aq_add_vsi(hw, &ctx, NULL); 21298d5069bcSRyan Zezeski if (rc != I40E_SUCCESS) { 21308d5069bcSRyan Zezeski i40e_error(i40e, "i40e_aq_add_vsi() failed %d: %d", rc, 21318d5069bcSRyan Zezeski hw->aq.asq_last_status); 21328d5069bcSRyan Zezeski return (B_FALSE); 21338d5069bcSRyan Zezeski } 21348d5069bcSRyan Zezeski 21358d5069bcSRyan Zezeski rxg = &i40e->i40e_rx_groups[idx]; 21368d5069bcSRyan Zezeski rxg->irg_vsi_seid = ctx.seid; 21378d5069bcSRyan Zezeski i40e->i40e_vsis[idx].iv_number = ctx.vsi_number; 21388d5069bcSRyan Zezeski i40e->i40e_vsis[idx].iv_seid = ctx.seid; 21398d5069bcSRyan Zezeski i40e->i40e_vsis[idx].iv_stats_id = LE_16(ctx.info.stat_counter_idx); 21408d5069bcSRyan Zezeski 21418d5069bcSRyan Zezeski if (i40e_stat_vsi_init(i40e, idx) == B_FALSE) 21428d5069bcSRyan Zezeski return (B_FALSE); 21438d5069bcSRyan Zezeski 21448d5069bcSRyan Zezeski return (B_TRUE); 21458d5069bcSRyan Zezeski } 21468d5069bcSRyan Zezeski 21478d5069bcSRyan Zezeski /* 21488d5069bcSRyan Zezeski * Configure the hardware for the Default Virtual Station Interface (VSI). 21498d5069bcSRyan Zezeski */ 21508d5069bcSRyan Zezeski static boolean_t 21518d5069bcSRyan Zezeski i40e_config_def_vsi(i40e_t *i40e, i40e_hw_t *hw) 21528d5069bcSRyan Zezeski { 21538d5069bcSRyan Zezeski struct i40e_vsi_context ctx; 21548d5069bcSRyan Zezeski i40e_rx_group_t *def_rxg; 21558d5069bcSRyan Zezeski int err; 21568d5069bcSRyan Zezeski struct i40e_aqc_remove_macvlan_element_data filt; 21578d5069bcSRyan Zezeski 21588d5069bcSRyan Zezeski bzero(&ctx, sizeof (struct i40e_vsi_context)); 21598d5069bcSRyan Zezeski ctx.seid = I40E_DEF_VSI_SEID(i40e); 21608d5069bcSRyan Zezeski ctx.pf_num = hw->pf_id; 21618d5069bcSRyan Zezeski err = i40e_aq_get_vsi_params(hw, &ctx, NULL); 2162da5577f0SRobert Mustacchi if (err != I40E_SUCCESS) { 2163da5577f0SRobert Mustacchi i40e_error(i40e, "get VSI params failed with %d", err); 2164da5577f0SRobert Mustacchi return (B_FALSE); 2165da5577f0SRobert Mustacchi } 2166da5577f0SRobert Mustacchi 21678d5069bcSRyan Zezeski ctx.info.valid_sections = 0; 21688d5069bcSRyan Zezeski i40e->i40e_vsis[0].iv_number = ctx.vsi_number; 21698d5069bcSRyan Zezeski i40e->i40e_vsis[0].iv_stats_id = LE_16(ctx.info.stat_counter_idx); 21708d5069bcSRyan Zezeski if (i40e_stat_vsi_init(i40e, 0) == B_FALSE) 2171da5577f0SRobert Mustacchi return (B_FALSE); 2172da5577f0SRobert Mustacchi 21738d5069bcSRyan Zezeski i40e_set_shared_vsi_props(i40e, &ctx.info, I40E_DEF_VSI_IDX); 21748d5069bcSRyan Zezeski 21758d5069bcSRyan Zezeski err = i40e_aq_update_vsi_params(hw, &ctx, NULL); 2176da5577f0SRobert Mustacchi if (err != I40E_SUCCESS) { 2177da5577f0SRobert Mustacchi i40e_error(i40e, "Update VSI params failed with %d", err); 2178da5577f0SRobert Mustacchi return (B_FALSE); 2179da5577f0SRobert Mustacchi } 2180da5577f0SRobert Mustacchi 21818d5069bcSRyan Zezeski def_rxg = &i40e->i40e_rx_groups[0]; 21828d5069bcSRyan Zezeski def_rxg->irg_vsi_seid = I40E_DEF_VSI_SEID(i40e); 21838d5069bcSRyan Zezeski 21848d5069bcSRyan Zezeski /* 2185*17117a01SRyan Zezeski * We have seen three different behaviors in regards to the 2186*17117a01SRyan Zezeski * Default VSI and its implicit L2 MAC+VLAN filter. 2187*17117a01SRyan Zezeski * 2188*17117a01SRyan Zezeski * 1. It has an implicit filter for the factory MAC address 2189*17117a01SRyan Zezeski * and this filter counts against 'ifr_nmacfilt_used'. 2190*17117a01SRyan Zezeski * 2191*17117a01SRyan Zezeski * 2. It has an implicit filter for the factory MAC address 2192*17117a01SRyan Zezeski * and this filter DOES NOT count against 'ifr_nmacfilt_used'. 2193*17117a01SRyan Zezeski * 2194*17117a01SRyan Zezeski * 3. It DOES NOT have an implicit filter. 2195*17117a01SRyan Zezeski * 2196*17117a01SRyan Zezeski * All three of these cases are accounted for below. If we 2197*17117a01SRyan Zezeski * fail to remove the L2 filter (ENOENT) then we assume there 2198*17117a01SRyan Zezeski * wasn't one. Otherwise, if we successfully remove the 2199*17117a01SRyan Zezeski * filter, we make sure to update the 'ifr_nmacfilt_used' 2200*17117a01SRyan Zezeski * count accordingly. 2201*17117a01SRyan Zezeski * 2202*17117a01SRyan Zezeski * We remove this filter to prevent duplicate delivery of 2203*17117a01SRyan Zezeski * packets destined for the primary MAC address as DLS will 2204*17117a01SRyan Zezeski * create the same filter on a non-default VSI for the primary 2205*17117a01SRyan Zezeski * MAC client. 2206*17117a01SRyan Zezeski * 2207*17117a01SRyan Zezeski * If you change the following code please test it across as 2208*17117a01SRyan Zezeski * many X700 series controllers and firmware revisions as you 2209*17117a01SRyan Zezeski * can. 22108d5069bcSRyan Zezeski */ 22118d5069bcSRyan Zezeski bzero(&filt, sizeof (filt)); 22128d5069bcSRyan Zezeski bcopy(hw->mac.port_addr, filt.mac_addr, ETHERADDRL); 22138d5069bcSRyan Zezeski filt.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH; 22148d5069bcSRyan Zezeski filt.vlan_tag = 0; 22158d5069bcSRyan Zezeski 22168d5069bcSRyan Zezeski ASSERT3U(i40e->i40e_resources.ifr_nmacfilt_used, <=, 1); 2217*17117a01SRyan Zezeski i40e_log(i40e, "Num L2 filters: %u", 2218*17117a01SRyan Zezeski i40e->i40e_resources.ifr_nmacfilt_used); 22198d5069bcSRyan Zezeski 22208d5069bcSRyan Zezeski err = i40e_aq_remove_macvlan(hw, I40E_DEF_VSI_SEID(i40e), &filt, 1, 22218d5069bcSRyan Zezeski NULL); 2222*17117a01SRyan Zezeski if (err == I40E_SUCCESS) { 2223*17117a01SRyan Zezeski i40e_log(i40e, 2224*17117a01SRyan Zezeski "Removed L2 filter from Default VSI with SEID %u", 2225*17117a01SRyan Zezeski I40E_DEF_VSI_SEID(i40e)); 2226*17117a01SRyan Zezeski } else if (hw->aq.asq_last_status == ENOENT) { 2227*17117a01SRyan Zezeski i40e_log(i40e, 2228*17117a01SRyan Zezeski "No L2 filter for Default VSI with SEID %u", 2229*17117a01SRyan Zezeski I40E_DEF_VSI_SEID(i40e)); 2230*17117a01SRyan Zezeski } else { 2231*17117a01SRyan Zezeski i40e_error(i40e, "Failed to remove L2 filter from" 2232*17117a01SRyan Zezeski " Default VSI with SEID %u: %d (%d)", 2233*17117a01SRyan Zezeski I40E_DEF_VSI_SEID(i40e), err, hw->aq.asq_last_status); 2234*17117a01SRyan Zezeski 22358d5069bcSRyan Zezeski return (B_FALSE); 22368d5069bcSRyan Zezeski } 22378d5069bcSRyan Zezeski 22388d5069bcSRyan Zezeski /* 22398d5069bcSRyan Zezeski * As mentioned above, the controller created an implicit L2 22408d5069bcSRyan Zezeski * filter for the primary MAC. We want to remove both the 22418d5069bcSRyan Zezeski * filter and decrement the filter count. However, not all 22428d5069bcSRyan Zezeski * controllers count this implicit filter against the total 22438d5069bcSRyan Zezeski * MAC filter count. So here we are making sure it is either 22448d5069bcSRyan Zezeski * one or zero. If it is one, then we know it is for the 22458d5069bcSRyan Zezeski * implicit filter and we should decrement since we just 22468d5069bcSRyan Zezeski * removed the filter above. If it is zero then we know the 22478d5069bcSRyan Zezeski * controller that does not count the implicit filter, and it 22488d5069bcSRyan Zezeski * was enough to just remove it; we leave the count alone. 22498d5069bcSRyan Zezeski * But if it is neither, then we have never seen a controller 22508d5069bcSRyan Zezeski * like this before and we should fail to attach. 22518d5069bcSRyan Zezeski * 22528d5069bcSRyan Zezeski * It is unfortunate that this code must exist but the 22538d5069bcSRyan Zezeski * behavior of this implicit L2 filter and its corresponding 22548d5069bcSRyan Zezeski * count were dicovered through empirical testing. The 22558d5069bcSRyan Zezeski * programming manuals hint at this filter but do not 22568d5069bcSRyan Zezeski * explicitly call out the exact behavior. 22578d5069bcSRyan Zezeski */ 22588d5069bcSRyan Zezeski if (i40e->i40e_resources.ifr_nmacfilt_used == 1) { 22598d5069bcSRyan Zezeski i40e->i40e_resources.ifr_nmacfilt_used--; 22608d5069bcSRyan Zezeski } else { 22618d5069bcSRyan Zezeski if (i40e->i40e_resources.ifr_nmacfilt_used != 0) { 2262*17117a01SRyan Zezeski i40e_error(i40e, "Unexpected L2 filter count: %u" 22638d5069bcSRyan Zezeski " (expected 0)", 22648d5069bcSRyan Zezeski i40e->i40e_resources.ifr_nmacfilt_used); 22658d5069bcSRyan Zezeski return (B_FALSE); 22668d5069bcSRyan Zezeski } 22678d5069bcSRyan Zezeski } 22688d5069bcSRyan Zezeski 22698d5069bcSRyan Zezeski return (B_TRUE); 22708d5069bcSRyan Zezeski } 22718d5069bcSRyan Zezeski 22728d5069bcSRyan Zezeski static boolean_t 22738d5069bcSRyan Zezeski i40e_config_rss_key_x722(i40e_t *i40e, i40e_hw_t *hw) 22748d5069bcSRyan Zezeski { 22758d5069bcSRyan Zezeski for (uint_t i = 0; i < i40e->i40e_num_rx_groups; i++) { 22768d5069bcSRyan Zezeski uint32_t seed[I40E_PFQF_HKEY_MAX_INDEX + 1]; 22778d5069bcSRyan Zezeski struct i40e_aqc_get_set_rss_key_data key; 22788d5069bcSRyan Zezeski const char *u8seed; 22798d5069bcSRyan Zezeski enum i40e_status_code status; 22808d5069bcSRyan Zezeski uint16_t vsi_number = i40e->i40e_vsis[i].iv_number; 22818d5069bcSRyan Zezeski 22828d5069bcSRyan Zezeski (void) random_get_pseudo_bytes((uint8_t *)seed, sizeof (seed)); 22838d5069bcSRyan Zezeski u8seed = (char *)seed; 22848d5069bcSRyan Zezeski 22858d5069bcSRyan Zezeski CTASSERT(sizeof (key) >= (sizeof (key.standard_rss_key) + 22868d5069bcSRyan Zezeski sizeof (key.extended_hash_key))); 22878d5069bcSRyan Zezeski 22888d5069bcSRyan Zezeski bcopy(u8seed, key.standard_rss_key, 22898d5069bcSRyan Zezeski sizeof (key.standard_rss_key)); 22908d5069bcSRyan Zezeski bcopy(&u8seed[sizeof (key.standard_rss_key)], 22918d5069bcSRyan Zezeski key.extended_hash_key, sizeof (key.extended_hash_key)); 22928d5069bcSRyan Zezeski 22938d5069bcSRyan Zezeski ASSERT3U(vsi_number, !=, 0); 22948d5069bcSRyan Zezeski status = i40e_aq_set_rss_key(hw, vsi_number, &key); 22958d5069bcSRyan Zezeski 22968d5069bcSRyan Zezeski if (status != I40E_SUCCESS) { 22978d5069bcSRyan Zezeski i40e_error(i40e, "failed to set RSS key for VSI %u: %d", 22988d5069bcSRyan Zezeski vsi_number, status); 22998d5069bcSRyan Zezeski return (B_FALSE); 23008d5069bcSRyan Zezeski } 23018d5069bcSRyan Zezeski } 2302da5577f0SRobert Mustacchi 2303da5577f0SRobert Mustacchi return (B_TRUE); 2304da5577f0SRobert Mustacchi } 2305da5577f0SRobert Mustacchi 2306da5577f0SRobert Mustacchi /* 2307a7f9b000SRobert Mustacchi * Configure the RSS key. For the X710 controller family, this is set on a 2308a7f9b000SRobert Mustacchi * per-PF basis via registers. For the X722, this is done on a per-VSI basis 2309a7f9b000SRobert Mustacchi * through the admin queue. 2310a7f9b000SRobert Mustacchi */ 2311a7f9b000SRobert Mustacchi static boolean_t 2312a7f9b000SRobert Mustacchi i40e_config_rss_key(i40e_t *i40e, i40e_hw_t *hw) 2313a7f9b000SRobert Mustacchi { 23148d5069bcSRyan Zezeski if (i40e_is_x722(i40e)) { 23158d5069bcSRyan Zezeski if (!i40e_config_rss_key_x722(i40e, hw)) 23168d5069bcSRyan Zezeski return (B_FALSE); 23178d5069bcSRyan Zezeski } else { 2318a7f9b000SRobert Mustacchi uint32_t seed[I40E_PFQF_HKEY_MAX_INDEX + 1]; 2319a7f9b000SRobert Mustacchi 2320a7f9b000SRobert Mustacchi (void) random_get_pseudo_bytes((uint8_t *)seed, sizeof (seed)); 23218d5069bcSRyan Zezeski for (uint_t i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++) 2322a7f9b000SRobert Mustacchi i40e_write_rx_ctl(hw, I40E_PFQF_HKEY(i), seed[i]); 2323a7f9b000SRobert Mustacchi } 2324a7f9b000SRobert Mustacchi 2325a7f9b000SRobert Mustacchi return (B_TRUE); 2326a7f9b000SRobert Mustacchi } 2327a7f9b000SRobert Mustacchi 2328a7f9b000SRobert Mustacchi /* 2329a7f9b000SRobert Mustacchi * Populate the LUT. The size of each entry in the LUT depends on the controller 2330a7f9b000SRobert Mustacchi * family, with the X722 using a known 7-bit width. On the X710 controller, this 2331a7f9b000SRobert Mustacchi * is programmed through its control registers where as on the X722 this is 2332a7f9b000SRobert Mustacchi * configured through the admin queue. Also of note, the X722 allows the LUT to 23338d5069bcSRyan Zezeski * be set on a per-PF or VSI basis. At this time we use the PF setting. If we 23348d5069bcSRyan Zezeski * decide to use the per-VSI LUT in the future, then we will need to modify the 23358d5069bcSRyan Zezeski * i40e_add_vsi() function to set the RSS LUT bits in the queueing section. 2336a7f9b000SRobert Mustacchi * 2337a7f9b000SRobert Mustacchi * We populate the LUT in a round robin fashion with the rx queue indices from 0 23388d5069bcSRyan Zezeski * to i40e_num_trqpairs_per_vsi - 1. 2339a7f9b000SRobert Mustacchi */ 2340a7f9b000SRobert Mustacchi static boolean_t 2341a7f9b000SRobert Mustacchi i40e_config_rss_hlut(i40e_t *i40e, i40e_hw_t *hw) 2342a7f9b000SRobert Mustacchi { 2343a7f9b000SRobert Mustacchi uint32_t *hlut; 2344a7f9b000SRobert Mustacchi uint8_t lut_mask; 2345a7f9b000SRobert Mustacchi uint_t i; 2346a7f9b000SRobert Mustacchi boolean_t ret = B_FALSE; 2347a7f9b000SRobert Mustacchi 2348a7f9b000SRobert Mustacchi /* 2349a7f9b000SRobert Mustacchi * We always configure the PF with a table size of 512 bytes in 2350a7f9b000SRobert Mustacchi * i40e_chip_start(). 2351a7f9b000SRobert Mustacchi */ 2352a7f9b000SRobert Mustacchi hlut = kmem_alloc(I40E_HLUT_TABLE_SIZE, KM_NOSLEEP); 2353a7f9b000SRobert Mustacchi if (hlut == NULL) { 2354a7f9b000SRobert Mustacchi i40e_error(i40e, "i40e_config_rss() buffer allocation failed"); 2355a7f9b000SRobert Mustacchi return (B_FALSE); 2356a7f9b000SRobert Mustacchi } 2357a7f9b000SRobert Mustacchi 2358a7f9b000SRobert Mustacchi /* 2359a7f9b000SRobert Mustacchi * The width of the X722 is apparently defined to be 7 bits, regardless 2360a7f9b000SRobert Mustacchi * of the capability. 2361a7f9b000SRobert Mustacchi */ 2362a7f9b000SRobert Mustacchi if (i40e_is_x722(i40e)) { 2363a7f9b000SRobert Mustacchi lut_mask = (1 << 7) - 1; 2364a7f9b000SRobert Mustacchi } else { 2365a7f9b000SRobert Mustacchi lut_mask = (1 << hw->func_caps.rss_table_entry_width) - 1; 2366a7f9b000SRobert Mustacchi } 2367a7f9b000SRobert Mustacchi 23688d5069bcSRyan Zezeski for (i = 0; i < I40E_HLUT_TABLE_SIZE; i++) { 23698d5069bcSRyan Zezeski ((uint8_t *)hlut)[i] = 23708d5069bcSRyan Zezeski (i % i40e->i40e_num_trqpairs_per_vsi) & lut_mask; 23718d5069bcSRyan Zezeski } 2372a7f9b000SRobert Mustacchi 2373a7f9b000SRobert Mustacchi if (i40e_is_x722(i40e)) { 2374a7f9b000SRobert Mustacchi enum i40e_status_code status; 23758d5069bcSRyan Zezeski 23768d5069bcSRyan Zezeski status = i40e_aq_set_rss_lut(hw, 0, B_TRUE, (uint8_t *)hlut, 23778d5069bcSRyan Zezeski I40E_HLUT_TABLE_SIZE); 23788d5069bcSRyan Zezeski 2379a7f9b000SRobert Mustacchi if (status != I40E_SUCCESS) { 23808d5069bcSRyan Zezeski i40e_error(i40e, "failed to set RSS LUT %d: %d", 23818d5069bcSRyan Zezeski status, hw->aq.asq_last_status); 2382a7f9b000SRobert Mustacchi goto out; 2383a7f9b000SRobert Mustacchi } 2384a7f9b000SRobert Mustacchi } else { 2385a7f9b000SRobert Mustacchi for (i = 0; i < I40E_HLUT_TABLE_SIZE >> 2; i++) { 2386a7f9b000SRobert Mustacchi I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i), hlut[i]); 2387a7f9b000SRobert Mustacchi } 2388a7f9b000SRobert Mustacchi } 2389a7f9b000SRobert Mustacchi ret = B_TRUE; 2390a7f9b000SRobert Mustacchi out: 2391a7f9b000SRobert Mustacchi kmem_free(hlut, I40E_HLUT_TABLE_SIZE); 2392a7f9b000SRobert Mustacchi return (ret); 2393a7f9b000SRobert Mustacchi } 2394a7f9b000SRobert Mustacchi 2395a7f9b000SRobert Mustacchi /* 239605768666SPaul Winder * Set up RSS. 239705768666SPaul Winder * 1. Seed the hash key. 239805768666SPaul Winder * 2. Enable PCTYPEs for the hash filter. 239905768666SPaul Winder * 3. Populate the LUT. 240005768666SPaul Winder */ 240105768666SPaul Winder static boolean_t 240205768666SPaul Winder i40e_config_rss(i40e_t *i40e, i40e_hw_t *hw) 240305768666SPaul Winder { 240405768666SPaul Winder uint64_t hena; 240505768666SPaul Winder 240605768666SPaul Winder /* 240705768666SPaul Winder * 1. Seed the hash key 240805768666SPaul Winder */ 2409a7f9b000SRobert Mustacchi if (!i40e_config_rss_key(i40e, hw)) 2410a7f9b000SRobert Mustacchi return (B_FALSE); 241105768666SPaul Winder 241205768666SPaul Winder /* 241305768666SPaul Winder * 2. Configure PCTYPES 241405768666SPaul Winder */ 241505768666SPaul Winder hena = (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | 241605768666SPaul Winder (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | 2417a7f9b000SRobert Mustacchi (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | 241805768666SPaul Winder (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | 241905768666SPaul Winder (1ULL << I40E_FILTER_PCTYPE_FRAG_IPV4) | 242005768666SPaul Winder (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | 242105768666SPaul Winder (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | 2422a7f9b000SRobert Mustacchi (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | 242305768666SPaul Winder (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | 242405768666SPaul Winder (1ULL << I40E_FILTER_PCTYPE_FRAG_IPV6) | 242505768666SPaul Winder (1ULL << I40E_FILTER_PCTYPE_L2_PAYLOAD); 242605768666SPaul Winder 2427a7f9b000SRobert Mustacchi /* 2428a7f9b000SRobert Mustacchi * Add additional types supported by the X722 controller. 2429a7f9b000SRobert Mustacchi */ 2430a7f9b000SRobert Mustacchi if (i40e_is_x722(i40e)) { 2431a7f9b000SRobert Mustacchi hena |= (1ULL << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) | 2432a7f9b000SRobert Mustacchi (1ULL << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) | 2433a7f9b000SRobert Mustacchi (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK) | 2434a7f9b000SRobert Mustacchi (1ULL << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) | 2435a7f9b000SRobert Mustacchi (1ULL << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP) | 2436a7f9b000SRobert Mustacchi (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK); 2437a7f9b000SRobert Mustacchi } 2438a7f9b000SRobert Mustacchi 243905768666SPaul Winder i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (uint32_t)hena); 244005768666SPaul Winder i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (uint32_t)(hena >> 32)); 244105768666SPaul Winder 244205768666SPaul Winder /* 244305768666SPaul Winder * 3. Populate LUT 244405768666SPaul Winder */ 2445a7f9b000SRobert Mustacchi return (i40e_config_rss_hlut(i40e, hw)); 244605768666SPaul Winder } 244705768666SPaul Winder 244805768666SPaul Winder /* 2449da5577f0SRobert Mustacchi * Wrapper to kick the chipset on. 2450da5577f0SRobert Mustacchi */ 2451da5577f0SRobert Mustacchi static boolean_t 2452da5577f0SRobert Mustacchi i40e_chip_start(i40e_t *i40e) 2453da5577f0SRobert Mustacchi { 2454da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 2455da5577f0SRobert Mustacchi struct i40e_filter_control_settings filter; 2456da5577f0SRobert Mustacchi int rc; 2457b4727ee2SRyan Zezeski uint8_t err; 2458da5577f0SRobert Mustacchi 2459da5577f0SRobert Mustacchi if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || 2460da5577f0SRobert Mustacchi (hw->aq.fw_maj_ver < 4)) { 2461da5577f0SRobert Mustacchi i40e_msec_delay(75); 2462da5577f0SRobert Mustacchi if (i40e_aq_set_link_restart_an(hw, TRUE, NULL) != 2463da5577f0SRobert Mustacchi I40E_SUCCESS) { 2464da5577f0SRobert Mustacchi i40e_error(i40e, "failed to restart link: admin queue " 2465da5577f0SRobert Mustacchi "error: %d", hw->aq.asq_last_status); 2466da5577f0SRobert Mustacchi return (B_FALSE); 2467da5577f0SRobert Mustacchi } 2468da5577f0SRobert Mustacchi } 2469da5577f0SRobert Mustacchi 2470da5577f0SRobert Mustacchi /* Determine hardware state */ 2471da5577f0SRobert Mustacchi i40e_get_hw_state(i40e, hw); 2472da5577f0SRobert Mustacchi 2473b4727ee2SRyan Zezeski /* For now, we always disable Ethernet Flow Control. */ 2474b4727ee2SRyan Zezeski hw->fc.requested_mode = I40E_FC_NONE; 2475b4727ee2SRyan Zezeski rc = i40e_set_fc(hw, &err, B_TRUE); 2476b4727ee2SRyan Zezeski if (rc != I40E_SUCCESS) { 2477b4727ee2SRyan Zezeski i40e_error(i40e, "Setting flow control failed, returned %d" 2478b4727ee2SRyan Zezeski " with error: 0x%x", rc, err); 2479b4727ee2SRyan Zezeski return (B_FALSE); 2480b4727ee2SRyan Zezeski } 2481b4727ee2SRyan Zezeski 2482da5577f0SRobert Mustacchi /* Initialize mac addresses. */ 2483da5577f0SRobert Mustacchi i40e_init_macaddrs(i40e, hw); 2484da5577f0SRobert Mustacchi 2485da5577f0SRobert Mustacchi /* 2486a7f9b000SRobert Mustacchi * Set up the filter control. If the hash lut size is changed from 2487a7f9b000SRobert Mustacchi * I40E_HASH_LUT_SIZE_512 then I40E_HLUT_TABLE_SIZE and 2488a7f9b000SRobert Mustacchi * i40e_config_rss_hlut() will need to be updated. 2489da5577f0SRobert Mustacchi */ 2490da5577f0SRobert Mustacchi bzero(&filter, sizeof (filter)); 2491da5577f0SRobert Mustacchi filter.enable_ethtype = TRUE; 2492da5577f0SRobert Mustacchi filter.enable_macvlan = TRUE; 249305768666SPaul Winder filter.hash_lut_size = I40E_HASH_LUT_SIZE_512; 2494da5577f0SRobert Mustacchi 2495da5577f0SRobert Mustacchi rc = i40e_set_filter_control(hw, &filter); 2496da5577f0SRobert Mustacchi if (rc != I40E_SUCCESS) { 2497da5577f0SRobert Mustacchi i40e_error(i40e, "i40e_set_filter_control() returned %d", rc); 2498da5577f0SRobert Mustacchi return (B_FALSE); 2499da5577f0SRobert Mustacchi } 2500da5577f0SRobert Mustacchi 2501da5577f0SRobert Mustacchi i40e_intr_chip_init(i40e); 2502da5577f0SRobert Mustacchi 25038d5069bcSRyan Zezeski rc = i40e_get_mac_seid(i40e); 25048d5069bcSRyan Zezeski if (rc == -1) { 25058d5069bcSRyan Zezeski i40e_error(i40e, "failed to obtain MAC Uplink SEID"); 2506da5577f0SRobert Mustacchi return (B_FALSE); 25078d5069bcSRyan Zezeski } 25088d5069bcSRyan Zezeski i40e->i40e_mac_seid = (uint16_t)rc; 25098d5069bcSRyan Zezeski 25108d5069bcSRyan Zezeski /* 25118d5069bcSRyan Zezeski * Create a VEB in order to support multiple VSIs. Each VSI 25128d5069bcSRyan Zezeski * functions as a MAC group. This call sets the PF's MAC as 25138d5069bcSRyan Zezeski * the uplink port and the PF's default VSI as the default 25148d5069bcSRyan Zezeski * downlink port. 25158d5069bcSRyan Zezeski */ 25168d5069bcSRyan Zezeski rc = i40e_aq_add_veb(hw, i40e->i40e_mac_seid, I40E_DEF_VSI_SEID(i40e), 25178d5069bcSRyan Zezeski 0x1, B_TRUE, &i40e->i40e_veb_seid, B_FALSE, NULL); 25188d5069bcSRyan Zezeski if (rc != I40E_SUCCESS) { 25198d5069bcSRyan Zezeski i40e_error(i40e, "i40e_aq_add_veb() failed %d: %d", rc, 25208d5069bcSRyan Zezeski hw->aq.asq_last_status); 25218d5069bcSRyan Zezeski return (B_FALSE); 25228d5069bcSRyan Zezeski } 25238d5069bcSRyan Zezeski 25248d5069bcSRyan Zezeski if (!i40e_config_def_vsi(i40e, hw)) 25258d5069bcSRyan Zezeski return (B_FALSE); 25268d5069bcSRyan Zezeski 25278d5069bcSRyan Zezeski for (uint_t i = 1; i < i40e->i40e_num_rx_groups; i++) { 25288d5069bcSRyan Zezeski if (!i40e_add_vsi(i40e, hw, i)) 25298d5069bcSRyan Zezeski return (B_FALSE); 25308d5069bcSRyan Zezeski } 2531da5577f0SRobert Mustacchi 253205768666SPaul Winder if (!i40e_config_rss(i40e, hw)) 253305768666SPaul Winder return (B_FALSE); 253405768666SPaul Winder 2535da5577f0SRobert Mustacchi i40e_flush(hw); 2536da5577f0SRobert Mustacchi 2537da5577f0SRobert Mustacchi return (B_TRUE); 2538da5577f0SRobert Mustacchi } 2539da5577f0SRobert Mustacchi 2540da5577f0SRobert Mustacchi /* 2541da5577f0SRobert Mustacchi * Take care of tearing down the rx ring. See 8.3.3.1.2 for more information. 2542da5577f0SRobert Mustacchi */ 2543da5577f0SRobert Mustacchi static void 2544da5577f0SRobert Mustacchi i40e_shutdown_rx_rings(i40e_t *i40e) 2545da5577f0SRobert Mustacchi { 2546da5577f0SRobert Mustacchi int i; 2547da5577f0SRobert Mustacchi uint32_t reg; 2548da5577f0SRobert Mustacchi 2549da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 2550da5577f0SRobert Mustacchi 2551da5577f0SRobert Mustacchi /* 2552da5577f0SRobert Mustacchi * Step 1. The interrupt linked list (see i40e_intr.c for more 2553da5577f0SRobert Mustacchi * information) should have already been cleared before calling this 2554da5577f0SRobert Mustacchi * function. 2555da5577f0SRobert Mustacchi */ 2556da5577f0SRobert Mustacchi #ifdef DEBUG 2557da5577f0SRobert Mustacchi if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) { 2558da5577f0SRobert Mustacchi for (i = 1; i < i40e->i40e_intr_count; i++) { 2559da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_PFINT_LNKLSTN(i - 1)); 2560da5577f0SRobert Mustacchi VERIFY3U(reg, ==, I40E_QUEUE_TYPE_EOL); 2561da5577f0SRobert Mustacchi } 2562da5577f0SRobert Mustacchi } else { 2563da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_PFINT_LNKLST0); 2564da5577f0SRobert Mustacchi VERIFY3U(reg, ==, I40E_QUEUE_TYPE_EOL); 2565da5577f0SRobert Mustacchi } 2566da5577f0SRobert Mustacchi 2567da5577f0SRobert Mustacchi #endif /* DEBUG */ 2568da5577f0SRobert Mustacchi 2569da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 2570da5577f0SRobert Mustacchi /* 2571da5577f0SRobert Mustacchi * Step 1. Request the queue by clearing QENA_REQ. It may not be 2572da5577f0SRobert Mustacchi * set due to unwinding from failures and a partially enabled 2573da5577f0SRobert Mustacchi * ring set. 2574da5577f0SRobert Mustacchi */ 2575da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QRX_ENA(i)); 2576da5577f0SRobert Mustacchi if (!(reg & I40E_QRX_ENA_QENA_REQ_MASK)) 2577da5577f0SRobert Mustacchi continue; 2578da5577f0SRobert Mustacchi VERIFY((reg & I40E_QRX_ENA_QENA_REQ_MASK) == 2579da5577f0SRobert Mustacchi I40E_QRX_ENA_QENA_REQ_MASK); 2580da5577f0SRobert Mustacchi reg &= ~I40E_QRX_ENA_QENA_REQ_MASK; 2581da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_QRX_ENA(i), reg); 2582da5577f0SRobert Mustacchi } 2583da5577f0SRobert Mustacchi 2584da5577f0SRobert Mustacchi /* 2585da5577f0SRobert Mustacchi * Step 2. Wait for the disable to take, by having QENA_STAT in the FPM 2586da5577f0SRobert Mustacchi * be cleared. Note that we could still receive data in the queue during 2587da5577f0SRobert Mustacchi * this time. We don't actually wait for this now and instead defer this 2588da5577f0SRobert Mustacchi * to i40e_shutdown_rings_wait(), after we've interleaved disabling the 2589da5577f0SRobert Mustacchi * TX queues as well. 2590da5577f0SRobert Mustacchi */ 2591da5577f0SRobert Mustacchi } 2592da5577f0SRobert Mustacchi 2593da5577f0SRobert Mustacchi static void 2594da5577f0SRobert Mustacchi i40e_shutdown_tx_rings(i40e_t *i40e) 2595da5577f0SRobert Mustacchi { 2596da5577f0SRobert Mustacchi int i; 2597da5577f0SRobert Mustacchi uint32_t reg; 2598da5577f0SRobert Mustacchi 2599da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 2600da5577f0SRobert Mustacchi 2601da5577f0SRobert Mustacchi /* 2602da5577f0SRobert Mustacchi * Step 1. The interrupt linked list should already have been cleared. 2603da5577f0SRobert Mustacchi */ 2604da5577f0SRobert Mustacchi #ifdef DEBUG 2605da5577f0SRobert Mustacchi if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) { 2606da5577f0SRobert Mustacchi for (i = 1; i < i40e->i40e_intr_count; i++) { 2607da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_PFINT_LNKLSTN(i - 1)); 2608da5577f0SRobert Mustacchi VERIFY3U(reg, ==, I40E_QUEUE_TYPE_EOL); 2609da5577f0SRobert Mustacchi } 2610da5577f0SRobert Mustacchi } else { 2611da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_PFINT_LNKLST0); 2612da5577f0SRobert Mustacchi VERIFY3U(reg, ==, I40E_QUEUE_TYPE_EOL); 2613da5577f0SRobert Mustacchi 2614da5577f0SRobert Mustacchi } 2615da5577f0SRobert Mustacchi #endif /* DEBUG */ 2616da5577f0SRobert Mustacchi 2617da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 2618da5577f0SRobert Mustacchi /* 2619da5577f0SRobert Mustacchi * Step 2. Set the SET_QDIS flag for every queue. 2620da5577f0SRobert Mustacchi */ 2621da5577f0SRobert Mustacchi i40e_pre_tx_queue_cfg(hw, i, B_FALSE); 2622da5577f0SRobert Mustacchi } 2623da5577f0SRobert Mustacchi 2624da5577f0SRobert Mustacchi /* 2625da5577f0SRobert Mustacchi * Step 3. Wait at least 400 usec (can be done once for all queues). 2626da5577f0SRobert Mustacchi */ 2627da5577f0SRobert Mustacchi drv_usecwait(500); 2628da5577f0SRobert Mustacchi 2629da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 2630da5577f0SRobert Mustacchi /* 2631da5577f0SRobert Mustacchi * Step 4. Clear the QENA_REQ flag which tells hardware to 2632da5577f0SRobert Mustacchi * quiesce. If QENA_REQ is not already set then that means that 2633da5577f0SRobert Mustacchi * we likely already tried to disable this queue. 2634da5577f0SRobert Mustacchi */ 2635da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QTX_ENA(i)); 2636da5577f0SRobert Mustacchi if (!(reg & I40E_QTX_ENA_QENA_REQ_MASK)) 2637da5577f0SRobert Mustacchi continue; 2638da5577f0SRobert Mustacchi reg &= ~I40E_QTX_ENA_QENA_REQ_MASK; 2639da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_QTX_ENA(i), reg); 2640da5577f0SRobert Mustacchi } 2641da5577f0SRobert Mustacchi 2642da5577f0SRobert Mustacchi /* 2643da5577f0SRobert Mustacchi * Step 5. Wait for all drains to finish. This will be done by the 2644da5577f0SRobert Mustacchi * hardware removing the QENA_STAT flag from the queue. Rather than 2645da5577f0SRobert Mustacchi * waiting here, we interleave it with all the others in 2646da5577f0SRobert Mustacchi * i40e_shutdown_rings_wait(). 2647da5577f0SRobert Mustacchi */ 2648da5577f0SRobert Mustacchi } 2649da5577f0SRobert Mustacchi 2650da5577f0SRobert Mustacchi /* 2651da5577f0SRobert Mustacchi * Wait for all the rings to be shut down. e.g. Steps 2 and 5 from the above 2652da5577f0SRobert Mustacchi * functions. 2653da5577f0SRobert Mustacchi */ 2654da5577f0SRobert Mustacchi static boolean_t 2655da5577f0SRobert Mustacchi i40e_shutdown_rings_wait(i40e_t *i40e) 2656da5577f0SRobert Mustacchi { 2657da5577f0SRobert Mustacchi int i, try; 2658da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 2659da5577f0SRobert Mustacchi 2660da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 2661da5577f0SRobert Mustacchi uint32_t reg; 2662da5577f0SRobert Mustacchi 2663da5577f0SRobert Mustacchi for (try = 0; try < I40E_RING_WAIT_NTRIES; try++) { 2664da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QRX_ENA(i)); 2665da5577f0SRobert Mustacchi if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) 2666da5577f0SRobert Mustacchi break; 2667da5577f0SRobert Mustacchi i40e_msec_delay(I40E_RING_WAIT_PAUSE); 2668da5577f0SRobert Mustacchi } 2669da5577f0SRobert Mustacchi 2670da5577f0SRobert Mustacchi if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) != 0) { 2671da5577f0SRobert Mustacchi i40e_error(i40e, "timed out disabling rx queue %d", 2672da5577f0SRobert Mustacchi i); 2673da5577f0SRobert Mustacchi return (B_FALSE); 2674da5577f0SRobert Mustacchi } 2675da5577f0SRobert Mustacchi 2676da5577f0SRobert Mustacchi for (try = 0; try < I40E_RING_WAIT_NTRIES; try++) { 2677da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QTX_ENA(i)); 2678da5577f0SRobert Mustacchi if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) 2679da5577f0SRobert Mustacchi break; 2680da5577f0SRobert Mustacchi i40e_msec_delay(I40E_RING_WAIT_PAUSE); 2681da5577f0SRobert Mustacchi } 2682da5577f0SRobert Mustacchi 2683da5577f0SRobert Mustacchi if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) != 0) { 2684da5577f0SRobert Mustacchi i40e_error(i40e, "timed out disabling tx queue %d", 2685da5577f0SRobert Mustacchi i); 2686da5577f0SRobert Mustacchi return (B_FALSE); 2687da5577f0SRobert Mustacchi } 2688da5577f0SRobert Mustacchi } 2689da5577f0SRobert Mustacchi 2690da5577f0SRobert Mustacchi return (B_TRUE); 2691da5577f0SRobert Mustacchi } 2692da5577f0SRobert Mustacchi 2693da5577f0SRobert Mustacchi static boolean_t 2694da5577f0SRobert Mustacchi i40e_shutdown_rings(i40e_t *i40e) 2695da5577f0SRobert Mustacchi { 2696da5577f0SRobert Mustacchi i40e_shutdown_rx_rings(i40e); 2697da5577f0SRobert Mustacchi i40e_shutdown_tx_rings(i40e); 2698da5577f0SRobert Mustacchi return (i40e_shutdown_rings_wait(i40e)); 2699da5577f0SRobert Mustacchi } 2700da5577f0SRobert Mustacchi 2701da5577f0SRobert Mustacchi static void 2702da5577f0SRobert Mustacchi i40e_setup_rx_descs(i40e_trqpair_t *itrq) 2703da5577f0SRobert Mustacchi { 2704da5577f0SRobert Mustacchi int i; 2705da5577f0SRobert Mustacchi i40e_rx_data_t *rxd = itrq->itrq_rxdata; 2706da5577f0SRobert Mustacchi 2707da5577f0SRobert Mustacchi for (i = 0; i < rxd->rxd_ring_size; i++) { 2708da5577f0SRobert Mustacchi i40e_rx_control_block_t *rcb; 2709da5577f0SRobert Mustacchi i40e_rx_desc_t *rdesc; 2710da5577f0SRobert Mustacchi 2711da5577f0SRobert Mustacchi rcb = rxd->rxd_work_list[i]; 2712da5577f0SRobert Mustacchi rdesc = &rxd->rxd_desc_ring[i]; 2713da5577f0SRobert Mustacchi 2714da5577f0SRobert Mustacchi rdesc->read.pkt_addr = 2715da5577f0SRobert Mustacchi CPU_TO_LE64((uintptr_t)rcb->rcb_dma.dmab_dma_address); 2716da5577f0SRobert Mustacchi rdesc->read.hdr_addr = 0; 2717da5577f0SRobert Mustacchi } 2718da5577f0SRobert Mustacchi } 2719da5577f0SRobert Mustacchi 2720da5577f0SRobert Mustacchi static boolean_t 2721da5577f0SRobert Mustacchi i40e_setup_rx_hmc(i40e_trqpair_t *itrq) 2722da5577f0SRobert Mustacchi { 2723da5577f0SRobert Mustacchi i40e_rx_data_t *rxd = itrq->itrq_rxdata; 2724da5577f0SRobert Mustacchi i40e_t *i40e = itrq->itrq_i40e; 2725da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 2726da5577f0SRobert Mustacchi 2727da5577f0SRobert Mustacchi struct i40e_hmc_obj_rxq rctx; 2728da5577f0SRobert Mustacchi int err; 2729da5577f0SRobert Mustacchi 2730da5577f0SRobert Mustacchi bzero(&rctx, sizeof (struct i40e_hmc_obj_rxq)); 2731da5577f0SRobert Mustacchi rctx.base = rxd->rxd_desc_area.dmab_dma_address / 2732da5577f0SRobert Mustacchi I40E_HMC_RX_CTX_UNIT; 2733da5577f0SRobert Mustacchi rctx.qlen = rxd->rxd_ring_size; 2734da5577f0SRobert Mustacchi VERIFY(i40e->i40e_rx_buf_size >= I40E_HMC_RX_DBUFF_MIN); 2735da5577f0SRobert Mustacchi VERIFY(i40e->i40e_rx_buf_size <= I40E_HMC_RX_DBUFF_MAX); 2736da5577f0SRobert Mustacchi rctx.dbuff = i40e->i40e_rx_buf_size >> I40E_RXQ_CTX_DBUFF_SHIFT; 2737da5577f0SRobert Mustacchi rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT; 2738da5577f0SRobert Mustacchi rctx.dtype = I40E_HMC_RX_DTYPE_NOSPLIT; 2739da5577f0SRobert Mustacchi rctx.dsize = I40E_HMC_RX_DSIZE_32BYTE; 2740da5577f0SRobert Mustacchi rctx.crcstrip = I40E_HMC_RX_CRCSTRIP_ENABLE; 2741da5577f0SRobert Mustacchi rctx.fc_ena = I40E_HMC_RX_FC_DISABLE; 2742da5577f0SRobert Mustacchi rctx.l2tsel = I40E_HMC_RX_L2TAGORDER; 2743da5577f0SRobert Mustacchi rctx.hsplit_0 = I40E_HMC_RX_HDRSPLIT_DISABLE; 2744da5577f0SRobert Mustacchi rctx.hsplit_1 = I40E_HMC_RX_HDRSPLIT_DISABLE; 2745da5577f0SRobert Mustacchi rctx.showiv = I40E_HMC_RX_INVLAN_DONTSTRIP; 2746da5577f0SRobert Mustacchi rctx.rxmax = i40e->i40e_frame_max; 2747da5577f0SRobert Mustacchi rctx.tphrdesc_ena = I40E_HMC_RX_TPH_DISABLE; 2748da5577f0SRobert Mustacchi rctx.tphwdesc_ena = I40E_HMC_RX_TPH_DISABLE; 2749da5577f0SRobert Mustacchi rctx.tphdata_ena = I40E_HMC_RX_TPH_DISABLE; 2750da5577f0SRobert Mustacchi rctx.tphhead_ena = I40E_HMC_RX_TPH_DISABLE; 2751da5577f0SRobert Mustacchi rctx.lrxqthresh = I40E_HMC_RX_LOWRXQ_NOINTR; 2752da5577f0SRobert Mustacchi 2753da5577f0SRobert Mustacchi /* 2754da5577f0SRobert Mustacchi * This must be set to 0x1, see Table 8-12 in section 8.3.3.2.2. 2755da5577f0SRobert Mustacchi */ 2756da5577f0SRobert Mustacchi rctx.prefena = I40E_HMC_RX_PREFENA; 2757da5577f0SRobert Mustacchi 2758da5577f0SRobert Mustacchi err = i40e_clear_lan_rx_queue_context(hw, itrq->itrq_index); 2759da5577f0SRobert Mustacchi if (err != I40E_SUCCESS) { 2760da5577f0SRobert Mustacchi i40e_error(i40e, "failed to clear rx queue %d context: %d", 2761da5577f0SRobert Mustacchi itrq->itrq_index, err); 2762da5577f0SRobert Mustacchi return (B_FALSE); 2763da5577f0SRobert Mustacchi } 2764da5577f0SRobert Mustacchi 2765da5577f0SRobert Mustacchi err = i40e_set_lan_rx_queue_context(hw, itrq->itrq_index, &rctx); 2766da5577f0SRobert Mustacchi if (err != I40E_SUCCESS) { 2767da5577f0SRobert Mustacchi i40e_error(i40e, "failed to set rx queue %d context: %d", 2768da5577f0SRobert Mustacchi itrq->itrq_index, err); 2769da5577f0SRobert Mustacchi return (B_FALSE); 2770da5577f0SRobert Mustacchi } 2771da5577f0SRobert Mustacchi 2772da5577f0SRobert Mustacchi return (B_TRUE); 2773da5577f0SRobert Mustacchi } 2774da5577f0SRobert Mustacchi 2775da5577f0SRobert Mustacchi /* 2776da5577f0SRobert Mustacchi * Take care of setting up the descriptor rings and actually programming the 2777da5577f0SRobert Mustacchi * device. See 8.3.3.1.1 for the full list of steps we need to do to enable the 2778da5577f0SRobert Mustacchi * rx rings. 2779da5577f0SRobert Mustacchi */ 2780da5577f0SRobert Mustacchi static boolean_t 2781da5577f0SRobert Mustacchi i40e_setup_rx_rings(i40e_t *i40e) 2782da5577f0SRobert Mustacchi { 2783da5577f0SRobert Mustacchi int i; 2784da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 2785da5577f0SRobert Mustacchi 2786da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 2787da5577f0SRobert Mustacchi i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[i]; 2788da5577f0SRobert Mustacchi i40e_rx_data_t *rxd = itrq->itrq_rxdata; 2789da5577f0SRobert Mustacchi uint32_t reg; 2790da5577f0SRobert Mustacchi 2791da5577f0SRobert Mustacchi /* 2792da5577f0SRobert Mustacchi * Step 1. Program all receive ring descriptors. 2793da5577f0SRobert Mustacchi */ 2794da5577f0SRobert Mustacchi i40e_setup_rx_descs(itrq); 2795da5577f0SRobert Mustacchi 2796da5577f0SRobert Mustacchi /* 2797da5577f0SRobert Mustacchi * Step 2. Program the queue's FPM/HMC context. 2798da5577f0SRobert Mustacchi */ 2799da5577f0SRobert Mustacchi if (i40e_setup_rx_hmc(itrq) == B_FALSE) 2800da5577f0SRobert Mustacchi return (B_FALSE); 2801da5577f0SRobert Mustacchi 2802da5577f0SRobert Mustacchi /* 2803da5577f0SRobert Mustacchi * Step 3. Clear the queue's tail pointer and set it to the end 2804da5577f0SRobert Mustacchi * of the space. 2805da5577f0SRobert Mustacchi */ 2806da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_QRX_TAIL(i), 0); 2807da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_QRX_TAIL(i), rxd->rxd_ring_size - 1); 2808da5577f0SRobert Mustacchi 2809da5577f0SRobert Mustacchi /* 2810da5577f0SRobert Mustacchi * Step 4. Enable the queue via the QENA_REQ. 2811da5577f0SRobert Mustacchi */ 2812da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QRX_ENA(i)); 2813da5577f0SRobert Mustacchi VERIFY0(reg & (I40E_QRX_ENA_QENA_REQ_MASK | 2814da5577f0SRobert Mustacchi I40E_QRX_ENA_QENA_STAT_MASK)); 2815da5577f0SRobert Mustacchi reg |= I40E_QRX_ENA_QENA_REQ_MASK; 2816da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_QRX_ENA(i), reg); 2817da5577f0SRobert Mustacchi } 2818da5577f0SRobert Mustacchi 2819da5577f0SRobert Mustacchi /* 2820da5577f0SRobert Mustacchi * Note, we wait for every queue to be enabled before we start checking. 2821da5577f0SRobert Mustacchi * This will hopefully cause most queues to be enabled at this point. 2822da5577f0SRobert Mustacchi */ 2823da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 2824da5577f0SRobert Mustacchi uint32_t j, reg; 2825da5577f0SRobert Mustacchi 2826da5577f0SRobert Mustacchi /* 2827da5577f0SRobert Mustacchi * Step 5. Verify that QENA_STAT has been set. It's promised 2828da5577f0SRobert Mustacchi * that this should occur within about 10 us, but like other 2829da5577f0SRobert Mustacchi * systems, we give the card a bit more time. 2830da5577f0SRobert Mustacchi */ 2831da5577f0SRobert Mustacchi for (j = 0; j < I40E_RING_WAIT_NTRIES; j++) { 2832da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QRX_ENA(i)); 2833da5577f0SRobert Mustacchi 2834da5577f0SRobert Mustacchi if (reg & I40E_QRX_ENA_QENA_STAT_MASK) 2835da5577f0SRobert Mustacchi break; 2836da5577f0SRobert Mustacchi i40e_msec_delay(I40E_RING_WAIT_PAUSE); 2837da5577f0SRobert Mustacchi } 2838da5577f0SRobert Mustacchi 2839da5577f0SRobert Mustacchi if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) { 2840da5577f0SRobert Mustacchi i40e_error(i40e, "failed to enable rx queue %d, timed " 2841da5577f0SRobert Mustacchi "out.", i); 2842da5577f0SRobert Mustacchi return (B_FALSE); 2843da5577f0SRobert Mustacchi } 2844da5577f0SRobert Mustacchi } 2845da5577f0SRobert Mustacchi 2846da5577f0SRobert Mustacchi return (B_TRUE); 2847da5577f0SRobert Mustacchi } 2848da5577f0SRobert Mustacchi 2849da5577f0SRobert Mustacchi static boolean_t 2850da5577f0SRobert Mustacchi i40e_setup_tx_hmc(i40e_trqpair_t *itrq) 2851da5577f0SRobert Mustacchi { 2852da5577f0SRobert Mustacchi i40e_t *i40e = itrq->itrq_i40e; 2853da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 2854da5577f0SRobert Mustacchi 2855da5577f0SRobert Mustacchi struct i40e_hmc_obj_txq tctx; 2856da5577f0SRobert Mustacchi struct i40e_vsi_context context; 2857da5577f0SRobert Mustacchi int err; 2858da5577f0SRobert Mustacchi 2859da5577f0SRobert Mustacchi bzero(&tctx, sizeof (struct i40e_hmc_obj_txq)); 2860da5577f0SRobert Mustacchi tctx.new_context = I40E_HMC_TX_NEW_CONTEXT; 2861da5577f0SRobert Mustacchi tctx.base = itrq->itrq_desc_area.dmab_dma_address / 2862da5577f0SRobert Mustacchi I40E_HMC_TX_CTX_UNIT; 2863da5577f0SRobert Mustacchi tctx.fc_ena = I40E_HMC_TX_FC_DISABLE; 2864da5577f0SRobert Mustacchi tctx.timesync_ena = I40E_HMC_TX_TS_DISABLE; 2865da5577f0SRobert Mustacchi tctx.fd_ena = I40E_HMC_TX_FD_DISABLE; 2866da5577f0SRobert Mustacchi tctx.alt_vlan_ena = I40E_HMC_TX_ALT_VLAN_DISABLE; 2867da5577f0SRobert Mustacchi tctx.head_wb_ena = I40E_HMC_TX_WB_ENABLE; 2868da5577f0SRobert Mustacchi tctx.qlen = itrq->itrq_tx_ring_size; 2869da5577f0SRobert Mustacchi tctx.tphrdesc_ena = I40E_HMC_TX_TPH_DISABLE; 2870da5577f0SRobert Mustacchi tctx.tphrpacket_ena = I40E_HMC_TX_TPH_DISABLE; 2871da5577f0SRobert Mustacchi tctx.tphwdesc_ena = I40E_HMC_TX_TPH_DISABLE; 2872da5577f0SRobert Mustacchi tctx.head_wb_addr = itrq->itrq_desc_area.dmab_dma_address + 2873da5577f0SRobert Mustacchi sizeof (i40e_tx_desc_t) * itrq->itrq_tx_ring_size; 2874da5577f0SRobert Mustacchi 2875da5577f0SRobert Mustacchi /* 2876da5577f0SRobert Mustacchi * This field isn't actually documented, like crc, but it suggests that 2877da5577f0SRobert Mustacchi * it should be zeroed. We leave both of these here because of that for 2878da5577f0SRobert Mustacchi * now. We should check with Intel on why these are here even. 2879da5577f0SRobert Mustacchi */ 2880da5577f0SRobert Mustacchi tctx.crc = 0; 2881da5577f0SRobert Mustacchi tctx.rdylist_act = 0; 2882da5577f0SRobert Mustacchi 2883da5577f0SRobert Mustacchi /* 2884da5577f0SRobert Mustacchi * We're supposed to assign the rdylist field with the value of the 2885da5577f0SRobert Mustacchi * traffic class index for the first device. We query the VSI parameters 2886da5577f0SRobert Mustacchi * again to get what the handle is. Note that every queue is always 2887da5577f0SRobert Mustacchi * assigned to traffic class zero, because we don't actually use them. 2888da5577f0SRobert Mustacchi */ 2889da5577f0SRobert Mustacchi bzero(&context, sizeof (struct i40e_vsi_context)); 28908d5069bcSRyan Zezeski context.seid = I40E_DEF_VSI_SEID(i40e); 2891da5577f0SRobert Mustacchi context.pf_num = hw->pf_id; 2892da5577f0SRobert Mustacchi err = i40e_aq_get_vsi_params(hw, &context, NULL); 2893da5577f0SRobert Mustacchi if (err != I40E_SUCCESS) { 2894da5577f0SRobert Mustacchi i40e_error(i40e, "get VSI params failed with %d", err); 2895da5577f0SRobert Mustacchi return (B_FALSE); 2896da5577f0SRobert Mustacchi } 2897da5577f0SRobert Mustacchi tctx.rdylist = LE_16(context.info.qs_handle[0]); 2898da5577f0SRobert Mustacchi 2899da5577f0SRobert Mustacchi err = i40e_clear_lan_tx_queue_context(hw, itrq->itrq_index); 2900da5577f0SRobert Mustacchi if (err != I40E_SUCCESS) { 2901da5577f0SRobert Mustacchi i40e_error(i40e, "failed to clear tx queue %d context: %d", 2902da5577f0SRobert Mustacchi itrq->itrq_index, err); 2903da5577f0SRobert Mustacchi return (B_FALSE); 2904da5577f0SRobert Mustacchi } 2905da5577f0SRobert Mustacchi 2906da5577f0SRobert Mustacchi err = i40e_set_lan_tx_queue_context(hw, itrq->itrq_index, &tctx); 2907da5577f0SRobert Mustacchi if (err != I40E_SUCCESS) { 2908da5577f0SRobert Mustacchi i40e_error(i40e, "failed to set tx queue %d context: %d", 2909da5577f0SRobert Mustacchi itrq->itrq_index, err); 2910da5577f0SRobert Mustacchi return (B_FALSE); 2911da5577f0SRobert Mustacchi } 2912da5577f0SRobert Mustacchi 2913da5577f0SRobert Mustacchi return (B_TRUE); 2914da5577f0SRobert Mustacchi } 2915da5577f0SRobert Mustacchi 2916da5577f0SRobert Mustacchi /* 2917da5577f0SRobert Mustacchi * Take care of setting up the descriptor rings and actually programming the 2918da5577f0SRobert Mustacchi * device. See 8.4.3.1.1 for what we need to do here. 2919da5577f0SRobert Mustacchi */ 2920da5577f0SRobert Mustacchi static boolean_t 2921da5577f0SRobert Mustacchi i40e_setup_tx_rings(i40e_t *i40e) 2922da5577f0SRobert Mustacchi { 2923da5577f0SRobert Mustacchi int i; 2924da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 2925da5577f0SRobert Mustacchi 2926da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 2927da5577f0SRobert Mustacchi i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[i]; 2928da5577f0SRobert Mustacchi uint32_t reg; 2929da5577f0SRobert Mustacchi 2930da5577f0SRobert Mustacchi /* 2931da5577f0SRobert Mustacchi * Step 1. Clear the queue disable flag and verify that the 2932da5577f0SRobert Mustacchi * index is set correctly. 2933da5577f0SRobert Mustacchi */ 2934da5577f0SRobert Mustacchi i40e_pre_tx_queue_cfg(hw, i, B_TRUE); 2935da5577f0SRobert Mustacchi 2936da5577f0SRobert Mustacchi /* 2937da5577f0SRobert Mustacchi * Step 2. Prepare the queue's FPM/HMC context. 2938da5577f0SRobert Mustacchi */ 2939da5577f0SRobert Mustacchi if (i40e_setup_tx_hmc(itrq) == B_FALSE) 2940da5577f0SRobert Mustacchi return (B_FALSE); 2941da5577f0SRobert Mustacchi 2942da5577f0SRobert Mustacchi /* 2943da5577f0SRobert Mustacchi * Step 3. Verify that it's clear that this PF owns this queue. 2944da5577f0SRobert Mustacchi */ 2945da5577f0SRobert Mustacchi reg = I40E_QTX_CTL_PF_QUEUE; 2946da5577f0SRobert Mustacchi reg |= (hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) & 2947da5577f0SRobert Mustacchi I40E_QTX_CTL_PF_INDX_MASK; 2948da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_QTX_CTL(itrq->itrq_index), reg); 2949da5577f0SRobert Mustacchi i40e_flush(hw); 2950da5577f0SRobert Mustacchi 2951da5577f0SRobert Mustacchi /* 2952da5577f0SRobert Mustacchi * Step 4. Set the QENA_REQ flag. 2953da5577f0SRobert Mustacchi */ 2954da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QTX_ENA(i)); 2955da5577f0SRobert Mustacchi VERIFY0(reg & (I40E_QTX_ENA_QENA_REQ_MASK | 2956da5577f0SRobert Mustacchi I40E_QTX_ENA_QENA_STAT_MASK)); 2957da5577f0SRobert Mustacchi reg |= I40E_QTX_ENA_QENA_REQ_MASK; 2958da5577f0SRobert Mustacchi I40E_WRITE_REG(hw, I40E_QTX_ENA(i), reg); 2959da5577f0SRobert Mustacchi } 2960da5577f0SRobert Mustacchi 2961da5577f0SRobert Mustacchi /* 2962da5577f0SRobert Mustacchi * Note, we wait for every queue to be enabled before we start checking. 2963da5577f0SRobert Mustacchi * This will hopefully cause most queues to be enabled at this point. 2964da5577f0SRobert Mustacchi */ 2965da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 2966da5577f0SRobert Mustacchi uint32_t j, reg; 2967da5577f0SRobert Mustacchi 2968da5577f0SRobert Mustacchi /* 2969da5577f0SRobert Mustacchi * Step 5. Verify that QENA_STAT has been set. It's promised 2970da5577f0SRobert Mustacchi * that this should occur within about 10 us, but like BSD, 2971da5577f0SRobert Mustacchi * we'll try for up to 100 ms for this queue. 2972da5577f0SRobert Mustacchi */ 2973da5577f0SRobert Mustacchi for (j = 0; j < I40E_RING_WAIT_NTRIES; j++) { 2974da5577f0SRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QTX_ENA(i)); 2975da5577f0SRobert Mustacchi 2976da5577f0SRobert Mustacchi if (reg & I40E_QTX_ENA_QENA_STAT_MASK) 2977da5577f0SRobert Mustacchi break; 2978da5577f0SRobert Mustacchi i40e_msec_delay(I40E_RING_WAIT_PAUSE); 2979da5577f0SRobert Mustacchi } 2980da5577f0SRobert Mustacchi 2981da5577f0SRobert Mustacchi if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) { 2982da5577f0SRobert Mustacchi i40e_error(i40e, "failed to enable tx queue %d, timed " 2983da5577f0SRobert Mustacchi "out", i); 2984da5577f0SRobert Mustacchi return (B_FALSE); 2985da5577f0SRobert Mustacchi } 2986da5577f0SRobert Mustacchi } 2987da5577f0SRobert Mustacchi 2988da5577f0SRobert Mustacchi return (B_TRUE); 2989da5577f0SRobert Mustacchi } 2990da5577f0SRobert Mustacchi 2991da5577f0SRobert Mustacchi void 2992da5577f0SRobert Mustacchi i40e_stop(i40e_t *i40e, boolean_t free_allocations) 2993da5577f0SRobert Mustacchi { 29948d5069bcSRyan Zezeski uint_t i; 29958d5069bcSRyan Zezeski i40e_hw_t *hw = &i40e->i40e_hw_space; 2996da5577f0SRobert Mustacchi 2997da5577f0SRobert Mustacchi ASSERT(MUTEX_HELD(&i40e->i40e_general_lock)); 2998da5577f0SRobert Mustacchi 2999da5577f0SRobert Mustacchi /* 3000da5577f0SRobert Mustacchi * Shutdown and drain the tx and rx pipeline. We do this using the 3001da5577f0SRobert Mustacchi * following steps. 3002da5577f0SRobert Mustacchi * 3003da5577f0SRobert Mustacchi * 1) Shutdown interrupts to all the queues (trying to keep the admin 3004da5577f0SRobert Mustacchi * queue alive). 3005da5577f0SRobert Mustacchi * 3006da5577f0SRobert Mustacchi * 2) Remove all of the interrupt tx and rx causes by setting the 3007da5577f0SRobert Mustacchi * interrupt linked lists to zero. 3008da5577f0SRobert Mustacchi * 3009da5577f0SRobert Mustacchi * 2) Shutdown the tx and rx rings. Because i40e_shutdown_rings() should 3010da5577f0SRobert Mustacchi * wait for all the queues to be disabled, once we reach that point 3011da5577f0SRobert Mustacchi * it should be safe to free associated data. 3012da5577f0SRobert Mustacchi * 3013da5577f0SRobert Mustacchi * 4) Wait 50ms after all that is done. This ensures that the rings are 3014da5577f0SRobert Mustacchi * ready for programming again and we don't have to think about this 3015da5577f0SRobert Mustacchi * in other parts of the driver. 3016da5577f0SRobert Mustacchi * 3017da5577f0SRobert Mustacchi * 5) Disable remaining chip interrupts, (admin queue, etc.) 3018da5577f0SRobert Mustacchi * 3019da5577f0SRobert Mustacchi * 6) Verify that FM is happy with all the register accesses we 3020da5577f0SRobert Mustacchi * performed. 3021da5577f0SRobert Mustacchi */ 3022da5577f0SRobert Mustacchi i40e_intr_io_disable_all(i40e); 3023da5577f0SRobert Mustacchi i40e_intr_io_clear_cause(i40e); 3024da5577f0SRobert Mustacchi 3025da5577f0SRobert Mustacchi if (i40e_shutdown_rings(i40e) == B_FALSE) { 3026da5577f0SRobert Mustacchi ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST); 3027da5577f0SRobert Mustacchi } 3028da5577f0SRobert Mustacchi 3029da5577f0SRobert Mustacchi delay(50 * drv_usectohz(1000)); 3030da5577f0SRobert Mustacchi 30318d5069bcSRyan Zezeski /* 30328d5069bcSRyan Zezeski * We don't delete the default VSI because it replaces the VEB 30338d5069bcSRyan Zezeski * after VEB deletion (see the "Delete Element" section). 30348d5069bcSRyan Zezeski * Furthermore, since the default VSI is provided by the 30358d5069bcSRyan Zezeski * firmware, we never attempt to delete it. 30368d5069bcSRyan Zezeski */ 30378d5069bcSRyan Zezeski for (i = 1; i < i40e->i40e_num_rx_groups; i++) { 30388d5069bcSRyan Zezeski i40e_delete_vsi(i40e, i); 30398d5069bcSRyan Zezeski } 30408d5069bcSRyan Zezeski 30418d5069bcSRyan Zezeski if (i40e->i40e_veb_seid != 0) { 30428d5069bcSRyan Zezeski int rc = i40e_aq_delete_element(hw, i40e->i40e_veb_seid, NULL); 30438d5069bcSRyan Zezeski 30448d5069bcSRyan Zezeski if (rc != I40E_SUCCESS) { 30458d5069bcSRyan Zezeski i40e_error(i40e, "Failed to delete VEB %d: %d", rc, 30468d5069bcSRyan Zezeski hw->aq.asq_last_status); 30478d5069bcSRyan Zezeski } 30488d5069bcSRyan Zezeski 30498d5069bcSRyan Zezeski i40e->i40e_veb_seid = 0; 30508d5069bcSRyan Zezeski } 30518d5069bcSRyan Zezeski 3052da5577f0SRobert Mustacchi i40e_intr_chip_fini(i40e); 3053da5577f0SRobert Mustacchi 3054da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 3055da5577f0SRobert Mustacchi mutex_enter(&i40e->i40e_trqpairs[i].itrq_rx_lock); 3056da5577f0SRobert Mustacchi mutex_enter(&i40e->i40e_trqpairs[i].itrq_tx_lock); 3057da5577f0SRobert Mustacchi } 3058da5577f0SRobert Mustacchi 3059da5577f0SRobert Mustacchi /* 3060da5577f0SRobert Mustacchi * We should consider refactoring this to be part of the ring start / 3061da5577f0SRobert Mustacchi * stop routines at some point. 3062da5577f0SRobert Mustacchi */ 3063da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 3064da5577f0SRobert Mustacchi i40e_stats_trqpair_fini(&i40e->i40e_trqpairs[i]); 3065da5577f0SRobert Mustacchi } 3066da5577f0SRobert Mustacchi 3067da5577f0SRobert Mustacchi if (i40e_check_acc_handle(i40e->i40e_osdep_space.ios_cfg_handle) != 3068da5577f0SRobert Mustacchi DDI_FM_OK) { 3069da5577f0SRobert Mustacchi ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST); 3070da5577f0SRobert Mustacchi } 3071da5577f0SRobert Mustacchi 3072da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 3073da5577f0SRobert Mustacchi i40e_tx_cleanup_ring(&i40e->i40e_trqpairs[i]); 3074da5577f0SRobert Mustacchi } 3075da5577f0SRobert Mustacchi 3076da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 3077da5577f0SRobert Mustacchi mutex_exit(&i40e->i40e_trqpairs[i].itrq_rx_lock); 3078da5577f0SRobert Mustacchi mutex_exit(&i40e->i40e_trqpairs[i].itrq_tx_lock); 3079da5577f0SRobert Mustacchi } 3080da5577f0SRobert Mustacchi 30818d5069bcSRyan Zezeski for (i = 0; i < i40e->i40e_num_rx_groups; i++) { 30828d5069bcSRyan Zezeski i40e_stat_vsi_fini(i40e, i); 30838d5069bcSRyan Zezeski } 3084da5577f0SRobert Mustacchi 3085da5577f0SRobert Mustacchi i40e->i40e_link_speed = 0; 3086da5577f0SRobert Mustacchi i40e->i40e_link_duplex = 0; 3087da5577f0SRobert Mustacchi i40e_link_state_set(i40e, LINK_STATE_UNKNOWN); 3088da5577f0SRobert Mustacchi 3089da5577f0SRobert Mustacchi if (free_allocations) { 3090da5577f0SRobert Mustacchi i40e_free_ring_mem(i40e, B_FALSE); 3091da5577f0SRobert Mustacchi } 3092da5577f0SRobert Mustacchi } 3093da5577f0SRobert Mustacchi 3094da5577f0SRobert Mustacchi boolean_t 3095da5577f0SRobert Mustacchi i40e_start(i40e_t *i40e, boolean_t alloc) 3096da5577f0SRobert Mustacchi { 3097da5577f0SRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 3098da5577f0SRobert Mustacchi boolean_t rc = B_TRUE; 3099da5577f0SRobert Mustacchi int i, err; 3100da5577f0SRobert Mustacchi 3101da5577f0SRobert Mustacchi ASSERT(MUTEX_HELD(&i40e->i40e_general_lock)); 3102da5577f0SRobert Mustacchi 3103da5577f0SRobert Mustacchi if (alloc) { 3104da5577f0SRobert Mustacchi if (i40e_alloc_ring_mem(i40e) == B_FALSE) { 3105da5577f0SRobert Mustacchi i40e_error(i40e, 3106da5577f0SRobert Mustacchi "Failed to allocate ring memory"); 3107da5577f0SRobert Mustacchi return (B_FALSE); 3108da5577f0SRobert Mustacchi } 3109da5577f0SRobert Mustacchi } 3110da5577f0SRobert Mustacchi 3111da5577f0SRobert Mustacchi /* 3112da5577f0SRobert Mustacchi * This should get refactored to be part of ring start and stop at 3113da5577f0SRobert Mustacchi * some point, along with most of the logic here. 3114da5577f0SRobert Mustacchi */ 3115da5577f0SRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 3116da5577f0SRobert Mustacchi if (i40e_stats_trqpair_init(&i40e->i40e_trqpairs[i]) == 3117da5577f0SRobert Mustacchi B_FALSE) { 3118da5577f0SRobert Mustacchi int j; 3119da5577f0SRobert Mustacchi 3120da5577f0SRobert Mustacchi for (j = 0; j < i; j++) { 3121da5577f0SRobert Mustacchi i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[j]; 3122da5577f0SRobert Mustacchi i40e_stats_trqpair_fini(itrq); 3123da5577f0SRobert Mustacchi } 3124da5577f0SRobert Mustacchi return (B_FALSE); 3125da5577f0SRobert Mustacchi } 3126da5577f0SRobert Mustacchi } 3127da5577f0SRobert Mustacchi 3128da5577f0SRobert Mustacchi if (!i40e_chip_start(i40e)) { 3129da5577f0SRobert Mustacchi i40e_fm_ereport(i40e, DDI_FM_DEVICE_INVAL_STATE); 3130da5577f0SRobert Mustacchi rc = B_FALSE; 3131da5577f0SRobert Mustacchi goto done; 3132da5577f0SRobert Mustacchi } 3133da5577f0SRobert Mustacchi 3134da5577f0SRobert Mustacchi if (i40e_setup_rx_rings(i40e) == B_FALSE) { 3135da5577f0SRobert Mustacchi rc = B_FALSE; 3136da5577f0SRobert Mustacchi goto done; 3137da5577f0SRobert Mustacchi } 3138da5577f0SRobert Mustacchi 3139da5577f0SRobert Mustacchi if (i40e_setup_tx_rings(i40e) == B_FALSE) { 3140da5577f0SRobert Mustacchi rc = B_FALSE; 3141da5577f0SRobert Mustacchi goto done; 3142da5577f0SRobert Mustacchi } 3143da5577f0SRobert Mustacchi 3144da5577f0SRobert Mustacchi /* 3145da5577f0SRobert Mustacchi * Enable broadcast traffic; however, do not enable multicast traffic. 3146da5577f0SRobert Mustacchi * That's handle exclusively through MAC's mc_multicst routines. 3147da5577f0SRobert Mustacchi */ 31488d5069bcSRyan Zezeski err = i40e_aq_set_vsi_broadcast(hw, I40E_DEF_VSI_SEID(i40e), B_TRUE, 31498d5069bcSRyan Zezeski NULL); 3150da5577f0SRobert Mustacchi if (err != I40E_SUCCESS) { 3151da5577f0SRobert Mustacchi i40e_error(i40e, "failed to set default VSI: %d", err); 3152da5577f0SRobert Mustacchi rc = B_FALSE; 3153da5577f0SRobert Mustacchi goto done; 3154da5577f0SRobert Mustacchi } 3155da5577f0SRobert Mustacchi 3156da5577f0SRobert Mustacchi err = i40e_aq_set_mac_config(hw, i40e->i40e_frame_max, B_TRUE, 0, NULL); 3157da5577f0SRobert Mustacchi if (err != I40E_SUCCESS) { 3158da5577f0SRobert Mustacchi i40e_error(i40e, "failed to set MAC config: %d", err); 3159da5577f0SRobert Mustacchi rc = B_FALSE; 3160da5577f0SRobert Mustacchi goto done; 3161da5577f0SRobert Mustacchi } 3162da5577f0SRobert Mustacchi 3163da5577f0SRobert Mustacchi /* 3164da5577f0SRobert Mustacchi * Finally, make sure that we're happy from an FM perspective. 3165da5577f0SRobert Mustacchi */ 3166da5577f0SRobert Mustacchi if (i40e_check_acc_handle(i40e->i40e_osdep_space.ios_reg_handle) != 3167da5577f0SRobert Mustacchi DDI_FM_OK) { 3168da5577f0SRobert Mustacchi rc = B_FALSE; 3169da5577f0SRobert Mustacchi goto done; 3170da5577f0SRobert Mustacchi } 3171da5577f0SRobert Mustacchi 3172da5577f0SRobert Mustacchi /* Clear state bits prior to final interrupt enabling. */ 3173da5577f0SRobert Mustacchi atomic_and_32(&i40e->i40e_state, 3174da5577f0SRobert Mustacchi ~(I40E_ERROR | I40E_STALL | I40E_OVERTEMP)); 3175da5577f0SRobert Mustacchi 3176da5577f0SRobert Mustacchi i40e_intr_io_enable_all(i40e); 3177da5577f0SRobert Mustacchi 3178da5577f0SRobert Mustacchi done: 3179da5577f0SRobert Mustacchi if (rc == B_FALSE) { 3180da5577f0SRobert Mustacchi i40e_stop(i40e, B_FALSE); 3181da5577f0SRobert Mustacchi if (alloc == B_TRUE) { 3182da5577f0SRobert Mustacchi i40e_free_ring_mem(i40e, B_TRUE); 3183da5577f0SRobert Mustacchi } 3184da5577f0SRobert Mustacchi ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST); 3185da5577f0SRobert Mustacchi } 3186da5577f0SRobert Mustacchi 3187da5577f0SRobert Mustacchi return (rc); 3188da5577f0SRobert Mustacchi } 3189da5577f0SRobert Mustacchi 3190da5577f0SRobert Mustacchi /* 3191da5577f0SRobert Mustacchi * We may have loaned up descriptors to the stack. As such, if we still have 3192da5577f0SRobert Mustacchi * them outstanding, then we will not continue with detach. 3193da5577f0SRobert Mustacchi */ 3194da5577f0SRobert Mustacchi static boolean_t 3195da5577f0SRobert Mustacchi i40e_drain_rx(i40e_t *i40e) 3196da5577f0SRobert Mustacchi { 3197da5577f0SRobert Mustacchi mutex_enter(&i40e->i40e_rx_pending_lock); 3198da5577f0SRobert Mustacchi while (i40e->i40e_rx_pending > 0) { 3199da5577f0SRobert Mustacchi if (cv_reltimedwait(&i40e->i40e_rx_pending_cv, 3200da5577f0SRobert Mustacchi &i40e->i40e_rx_pending_lock, 3201da5577f0SRobert Mustacchi drv_usectohz(I40E_DRAIN_RX_WAIT), TR_CLOCK_TICK) == -1) { 3202da5577f0SRobert Mustacchi mutex_exit(&i40e->i40e_rx_pending_lock); 3203da5577f0SRobert Mustacchi return (B_FALSE); 3204da5577f0SRobert Mustacchi } 3205da5577f0SRobert Mustacchi } 3206da5577f0SRobert Mustacchi mutex_exit(&i40e->i40e_rx_pending_lock); 3207da5577f0SRobert Mustacchi 3208da5577f0SRobert Mustacchi return (B_TRUE); 3209da5577f0SRobert Mustacchi } 3210da5577f0SRobert Mustacchi 3211da5577f0SRobert Mustacchi static int 3212da5577f0SRobert Mustacchi i40e_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 3213da5577f0SRobert Mustacchi { 3214da5577f0SRobert Mustacchi i40e_t *i40e; 3215da5577f0SRobert Mustacchi struct i40e_osdep *osdep; 3216da5577f0SRobert Mustacchi i40e_hw_t *hw; 3217da5577f0SRobert Mustacchi int instance; 3218da5577f0SRobert Mustacchi 3219da5577f0SRobert Mustacchi if (cmd != DDI_ATTACH) 3220da5577f0SRobert Mustacchi return (DDI_FAILURE); 3221da5577f0SRobert Mustacchi 3222da5577f0SRobert Mustacchi instance = ddi_get_instance(devinfo); 3223da5577f0SRobert Mustacchi i40e = kmem_zalloc(sizeof (i40e_t), KM_SLEEP); 3224da5577f0SRobert Mustacchi 3225da5577f0SRobert Mustacchi i40e->i40e_aqbuf = kmem_zalloc(I40E_ADMINQ_BUFSZ, KM_SLEEP); 3226da5577f0SRobert Mustacchi i40e->i40e_instance = instance; 3227da5577f0SRobert Mustacchi i40e->i40e_dip = devinfo; 3228da5577f0SRobert Mustacchi 3229da5577f0SRobert Mustacchi hw = &i40e->i40e_hw_space; 3230da5577f0SRobert Mustacchi osdep = &i40e->i40e_osdep_space; 3231da5577f0SRobert Mustacchi hw->back = osdep; 3232da5577f0SRobert Mustacchi osdep->ios_i40e = i40e; 3233da5577f0SRobert Mustacchi 3234da5577f0SRobert Mustacchi ddi_set_driver_private(devinfo, i40e); 3235da5577f0SRobert Mustacchi 3236da5577f0SRobert Mustacchi i40e_fm_init(i40e); 3237da5577f0SRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_FM_INIT; 3238da5577f0SRobert Mustacchi 3239da5577f0SRobert Mustacchi if (pci_config_setup(devinfo, &osdep->ios_cfg_handle) != DDI_SUCCESS) { 3240da5577f0SRobert Mustacchi i40e_error(i40e, "Failed to map PCI configurations."); 3241da5577f0SRobert Mustacchi goto attach_fail; 3242da5577f0SRobert Mustacchi } 3243da5577f0SRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_PCI_CONFIG; 3244da5577f0SRobert Mustacchi 3245422542c1SRobert Mustacchi i40e_identify_hardware(i40e); 3246da5577f0SRobert Mustacchi 3247da5577f0SRobert Mustacchi if (!i40e_regs_map(i40e)) { 3248da5577f0SRobert Mustacchi i40e_error(i40e, "Failed to map device registers."); 3249da5577f0SRobert Mustacchi goto attach_fail; 3250da5577f0SRobert Mustacchi } 3251da5577f0SRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_REGS_MAP; 3252da5577f0SRobert Mustacchi 3253da5577f0SRobert Mustacchi i40e_init_properties(i40e); 3254da5577f0SRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_PROPS; 3255da5577f0SRobert Mustacchi 3256da5577f0SRobert Mustacchi if (!i40e_common_code_init(i40e, hw)) 3257da5577f0SRobert Mustacchi goto attach_fail; 3258da5577f0SRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_COMMON_CODE; 3259da5577f0SRobert Mustacchi 3260da5577f0SRobert Mustacchi /* 3261da5577f0SRobert Mustacchi * When we participate in IRM, we should make sure that we register 3262da5577f0SRobert Mustacchi * ourselves with it before callbacks. 3263da5577f0SRobert Mustacchi */ 3264da5577f0SRobert Mustacchi if (!i40e_alloc_intrs(i40e, devinfo)) { 3265da5577f0SRobert Mustacchi i40e_error(i40e, "Failed to allocate interrupts."); 3266da5577f0SRobert Mustacchi goto attach_fail; 3267da5577f0SRobert Mustacchi } 3268da5577f0SRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_ALLOC_INTR; 3269da5577f0SRobert Mustacchi 3270da5577f0SRobert Mustacchi if (!i40e_alloc_trqpairs(i40e)) { 3271da5577f0SRobert Mustacchi i40e_error(i40e, 3272da5577f0SRobert Mustacchi "Failed to allocate receive & transmit rings."); 3273da5577f0SRobert Mustacchi goto attach_fail; 3274da5577f0SRobert Mustacchi } 3275da5577f0SRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_ALLOC_RINGSLOCKS; 3276da5577f0SRobert Mustacchi 3277da5577f0SRobert Mustacchi if (!i40e_map_intrs_to_vectors(i40e)) { 3278da5577f0SRobert Mustacchi i40e_error(i40e, "Failed to map interrupts to vectors."); 3279da5577f0SRobert Mustacchi goto attach_fail; 3280da5577f0SRobert Mustacchi } 3281da5577f0SRobert Mustacchi 3282da5577f0SRobert Mustacchi if (!i40e_add_intr_handlers(i40e)) { 3283da5577f0SRobert Mustacchi i40e_error(i40e, "Failed to add the interrupt handlers."); 3284da5577f0SRobert Mustacchi goto attach_fail; 3285da5577f0SRobert Mustacchi } 3286da5577f0SRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_ADD_INTR; 3287da5577f0SRobert Mustacchi 3288da5577f0SRobert Mustacchi if (!i40e_final_init(i40e)) { 3289da5577f0SRobert Mustacchi i40e_error(i40e, "Final initialization failed."); 3290da5577f0SRobert Mustacchi goto attach_fail; 3291da5577f0SRobert Mustacchi } 3292da5577f0SRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_INIT; 3293da5577f0SRobert Mustacchi 3294da5577f0SRobert Mustacchi if (i40e_check_acc_handle(i40e->i40e_osdep_space.ios_cfg_handle) != 3295da5577f0SRobert Mustacchi DDI_FM_OK) { 3296da5577f0SRobert Mustacchi ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST); 3297da5577f0SRobert Mustacchi goto attach_fail; 3298da5577f0SRobert Mustacchi } 3299da5577f0SRobert Mustacchi 3300da5577f0SRobert Mustacchi if (!i40e_stats_init(i40e)) { 3301da5577f0SRobert Mustacchi i40e_error(i40e, "Stats initialization failed."); 3302da5577f0SRobert Mustacchi goto attach_fail; 3303da5577f0SRobert Mustacchi } 3304da5577f0SRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_STATS; 3305da5577f0SRobert Mustacchi 3306da5577f0SRobert Mustacchi if (!i40e_register_mac(i40e)) { 3307da5577f0SRobert Mustacchi i40e_error(i40e, "Failed to register to MAC/GLDv3"); 3308da5577f0SRobert Mustacchi goto attach_fail; 3309da5577f0SRobert Mustacchi } 3310da5577f0SRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_MAC; 3311da5577f0SRobert Mustacchi 3312da5577f0SRobert Mustacchi i40e->i40e_periodic_id = ddi_periodic_add(i40e_timer, i40e, 3313da5577f0SRobert Mustacchi I40E_CYCLIC_PERIOD, DDI_IPL_0); 3314da5577f0SRobert Mustacchi if (i40e->i40e_periodic_id == 0) { 3315da5577f0SRobert Mustacchi i40e_error(i40e, "Failed to add the link-check timer"); 3316da5577f0SRobert Mustacchi goto attach_fail; 3317da5577f0SRobert Mustacchi } 3318da5577f0SRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_LINK_TIMER; 3319da5577f0SRobert Mustacchi 3320da5577f0SRobert Mustacchi if (!i40e_enable_interrupts(i40e)) { 3321da5577f0SRobert Mustacchi i40e_error(i40e, "Failed to enable DDI interrupts"); 3322da5577f0SRobert Mustacchi goto attach_fail; 3323da5577f0SRobert Mustacchi } 3324da5577f0SRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_ENABLE_INTR; 3325da5577f0SRobert Mustacchi 3326da5577f0SRobert Mustacchi atomic_or_32(&i40e->i40e_state, I40E_INITIALIZED); 3327da5577f0SRobert Mustacchi 3328da5577f0SRobert Mustacchi mutex_enter(&i40e_glock); 3329da5577f0SRobert Mustacchi list_insert_tail(&i40e_glist, i40e); 3330da5577f0SRobert Mustacchi mutex_exit(&i40e_glock); 3331da5577f0SRobert Mustacchi 3332da5577f0SRobert Mustacchi return (DDI_SUCCESS); 3333da5577f0SRobert Mustacchi 3334da5577f0SRobert Mustacchi attach_fail: 3335da5577f0SRobert Mustacchi i40e_unconfigure(devinfo, i40e); 3336da5577f0SRobert Mustacchi return (DDI_FAILURE); 3337da5577f0SRobert Mustacchi } 3338da5577f0SRobert Mustacchi 3339da5577f0SRobert Mustacchi static int 3340da5577f0SRobert Mustacchi i40e_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 3341da5577f0SRobert Mustacchi { 3342da5577f0SRobert Mustacchi i40e_t *i40e; 3343da5577f0SRobert Mustacchi 3344da5577f0SRobert Mustacchi if (cmd != DDI_DETACH) 3345da5577f0SRobert Mustacchi return (DDI_FAILURE); 3346da5577f0SRobert Mustacchi 3347da5577f0SRobert Mustacchi i40e = (i40e_t *)ddi_get_driver_private(devinfo); 3348da5577f0SRobert Mustacchi if (i40e == NULL) { 3349da5577f0SRobert Mustacchi i40e_log(NULL, "i40e_detach() called with no i40e pointer!"); 3350da5577f0SRobert Mustacchi return (DDI_FAILURE); 3351da5577f0SRobert Mustacchi } 3352da5577f0SRobert Mustacchi 3353da5577f0SRobert Mustacchi if (i40e_drain_rx(i40e) == B_FALSE) { 3354da5577f0SRobert Mustacchi i40e_log(i40e, "timed out draining DMA resources, %d buffers " 3355da5577f0SRobert Mustacchi "remain", i40e->i40e_rx_pending); 3356da5577f0SRobert Mustacchi return (DDI_FAILURE); 3357da5577f0SRobert Mustacchi } 3358da5577f0SRobert Mustacchi 3359da5577f0SRobert Mustacchi mutex_enter(&i40e_glock); 3360da5577f0SRobert Mustacchi list_remove(&i40e_glist, i40e); 3361da5577f0SRobert Mustacchi mutex_exit(&i40e_glock); 3362da5577f0SRobert Mustacchi 3363da5577f0SRobert Mustacchi i40e_unconfigure(devinfo, i40e); 3364da5577f0SRobert Mustacchi 3365da5577f0SRobert Mustacchi return (DDI_SUCCESS); 3366da5577f0SRobert Mustacchi } 3367da5577f0SRobert Mustacchi 3368da5577f0SRobert Mustacchi static struct cb_ops i40e_cb_ops = { 3369da5577f0SRobert Mustacchi nulldev, /* cb_open */ 3370da5577f0SRobert Mustacchi nulldev, /* cb_close */ 3371da5577f0SRobert Mustacchi nodev, /* cb_strategy */ 3372da5577f0SRobert Mustacchi nodev, /* cb_print */ 3373da5577f0SRobert Mustacchi nodev, /* cb_dump */ 3374da5577f0SRobert Mustacchi nodev, /* cb_read */ 3375da5577f0SRobert Mustacchi nodev, /* cb_write */ 3376da5577f0SRobert Mustacchi nodev, /* cb_ioctl */ 3377da5577f0SRobert Mustacchi nodev, /* cb_devmap */ 3378da5577f0SRobert Mustacchi nodev, /* cb_mmap */ 3379da5577f0SRobert Mustacchi nodev, /* cb_segmap */ 3380da5577f0SRobert Mustacchi nochpoll, /* cb_chpoll */ 3381da5577f0SRobert Mustacchi ddi_prop_op, /* cb_prop_op */ 3382da5577f0SRobert Mustacchi NULL, /* cb_stream */ 3383da5577f0SRobert Mustacchi D_MP | D_HOTPLUG, /* cb_flag */ 3384da5577f0SRobert Mustacchi CB_REV, /* cb_rev */ 3385da5577f0SRobert Mustacchi nodev, /* cb_aread */ 3386da5577f0SRobert Mustacchi nodev /* cb_awrite */ 3387da5577f0SRobert Mustacchi }; 3388da5577f0SRobert Mustacchi 3389da5577f0SRobert Mustacchi static struct dev_ops i40e_dev_ops = { 3390da5577f0SRobert Mustacchi DEVO_REV, /* devo_rev */ 3391da5577f0SRobert Mustacchi 0, /* devo_refcnt */ 3392da5577f0SRobert Mustacchi NULL, /* devo_getinfo */ 3393da5577f0SRobert Mustacchi nulldev, /* devo_identify */ 3394da5577f0SRobert Mustacchi nulldev, /* devo_probe */ 3395da5577f0SRobert Mustacchi i40e_attach, /* devo_attach */ 3396da5577f0SRobert Mustacchi i40e_detach, /* devo_detach */ 3397da5577f0SRobert Mustacchi nodev, /* devo_reset */ 3398da5577f0SRobert Mustacchi &i40e_cb_ops, /* devo_cb_ops */ 3399da5577f0SRobert Mustacchi NULL, /* devo_bus_ops */ 3400da5577f0SRobert Mustacchi ddi_power, /* devo_power */ 3401da5577f0SRobert Mustacchi ddi_quiesce_not_supported /* devo_quiesce */ 3402da5577f0SRobert Mustacchi }; 3403da5577f0SRobert Mustacchi 3404da5577f0SRobert Mustacchi static struct modldrv i40e_modldrv = { 3405da5577f0SRobert Mustacchi &mod_driverops, 3406da5577f0SRobert Mustacchi i40e_ident, 3407da5577f0SRobert Mustacchi &i40e_dev_ops 3408da5577f0SRobert Mustacchi }; 3409da5577f0SRobert Mustacchi 3410da5577f0SRobert Mustacchi static struct modlinkage i40e_modlinkage = { 3411da5577f0SRobert Mustacchi MODREV_1, 3412da5577f0SRobert Mustacchi &i40e_modldrv, 3413da5577f0SRobert Mustacchi NULL 3414da5577f0SRobert Mustacchi }; 3415da5577f0SRobert Mustacchi 3416da5577f0SRobert Mustacchi /* 3417da5577f0SRobert Mustacchi * Module Initialization Functions. 3418da5577f0SRobert Mustacchi */ 3419da5577f0SRobert Mustacchi int 3420da5577f0SRobert Mustacchi _init(void) 3421da5577f0SRobert Mustacchi { 3422da5577f0SRobert Mustacchi int status; 3423da5577f0SRobert Mustacchi 3424da5577f0SRobert Mustacchi list_create(&i40e_glist, sizeof (i40e_t), offsetof(i40e_t, i40e_glink)); 3425da5577f0SRobert Mustacchi list_create(&i40e_dlist, sizeof (i40e_device_t), 3426da5577f0SRobert Mustacchi offsetof(i40e_device_t, id_link)); 3427da5577f0SRobert Mustacchi mutex_init(&i40e_glock, NULL, MUTEX_DRIVER, NULL); 3428da5577f0SRobert Mustacchi mac_init_ops(&i40e_dev_ops, I40E_MODULE_NAME); 3429da5577f0SRobert Mustacchi 3430da5577f0SRobert Mustacchi status = mod_install(&i40e_modlinkage); 3431da5577f0SRobert Mustacchi if (status != DDI_SUCCESS) { 3432da5577f0SRobert Mustacchi mac_fini_ops(&i40e_dev_ops); 3433da5577f0SRobert Mustacchi mutex_destroy(&i40e_glock); 3434da5577f0SRobert Mustacchi list_destroy(&i40e_dlist); 3435da5577f0SRobert Mustacchi list_destroy(&i40e_glist); 3436da5577f0SRobert Mustacchi } 3437da5577f0SRobert Mustacchi 3438da5577f0SRobert Mustacchi return (status); 3439da5577f0SRobert Mustacchi } 3440da5577f0SRobert Mustacchi 3441da5577f0SRobert Mustacchi int 3442da5577f0SRobert Mustacchi _info(struct modinfo *modinfop) 3443da5577f0SRobert Mustacchi { 3444da5577f0SRobert Mustacchi return (mod_info(&i40e_modlinkage, modinfop)); 3445da5577f0SRobert Mustacchi } 3446da5577f0SRobert Mustacchi 3447da5577f0SRobert Mustacchi int 3448da5577f0SRobert Mustacchi _fini(void) 3449da5577f0SRobert Mustacchi { 3450da5577f0SRobert Mustacchi int status; 3451da5577f0SRobert Mustacchi 3452da5577f0SRobert Mustacchi status = mod_remove(&i40e_modlinkage); 3453da5577f0SRobert Mustacchi if (status == DDI_SUCCESS) { 3454da5577f0SRobert Mustacchi mac_fini_ops(&i40e_dev_ops); 3455da5577f0SRobert Mustacchi mutex_destroy(&i40e_glock); 3456da5577f0SRobert Mustacchi list_destroy(&i40e_dlist); 3457da5577f0SRobert Mustacchi list_destroy(&i40e_glist); 3458da5577f0SRobert Mustacchi } 3459da5577f0SRobert Mustacchi 3460da5577f0SRobert Mustacchi return (status); 3461da5577f0SRobert Mustacchi } 3462