19d26e4fcSRobert Mustacchi /* 29d26e4fcSRobert Mustacchi * This file and its contents are supplied under the terms of the 39d26e4fcSRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0. 49d26e4fcSRobert Mustacchi * You may only use this file in accordance with the terms of version 59d26e4fcSRobert Mustacchi * 1.0 of the CDDL. 69d26e4fcSRobert Mustacchi * 79d26e4fcSRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this 89d26e4fcSRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at 99d26e4fcSRobert Mustacchi * http://www.illumos.org/license/CDDL. 109d26e4fcSRobert Mustacchi */ 119d26e4fcSRobert Mustacchi 129d26e4fcSRobert Mustacchi /* 139d26e4fcSRobert Mustacchi * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved. 149d26e4fcSRobert Mustacchi * Copyright 2016 Joyent, Inc. 15396505afSPaul Winder * Copyright 2017 Tegile Systems, Inc. All rights reserved. 169d26e4fcSRobert Mustacchi */ 179d26e4fcSRobert Mustacchi 189d26e4fcSRobert Mustacchi /* 199d26e4fcSRobert Mustacchi * i40e - Intel 10/40 Gb Ethernet driver 209d26e4fcSRobert Mustacchi * 219d26e4fcSRobert Mustacchi * The i40e driver is the main software device driver for the Intel 40 Gb family 229d26e4fcSRobert Mustacchi * of devices. Note that these devices come in many flavors with both 40 GbE 239d26e4fcSRobert Mustacchi * ports and 10 GbE ports. This device is the successor to the 82599 family of 249d26e4fcSRobert Mustacchi * devices (ixgbe). 259d26e4fcSRobert Mustacchi * 269d26e4fcSRobert Mustacchi * Unlike previous generations of Intel 1 GbE and 10 GbE devices, the 40 GbE 279d26e4fcSRobert Mustacchi * devices defined in the XL710 controller (previously known as Fortville) are a 289d26e4fcSRobert Mustacchi * rather different beast and have a small switch embedded inside of them. In 299d26e4fcSRobert Mustacchi * addition, the way that most of the programming is done has been overhauled. 309d26e4fcSRobert Mustacchi * As opposed to just using PCIe memory mapped registers, it also has an 319d26e4fcSRobert Mustacchi * administrative queue which is used to communicate with firmware running on 329d26e4fcSRobert Mustacchi * the chip. 339d26e4fcSRobert Mustacchi * 349d26e4fcSRobert Mustacchi * Each physical function in the hardware shows up as a device that this driver 359d26e4fcSRobert Mustacchi * will bind to. The hardware splits many resources evenly across all of the 369d26e4fcSRobert Mustacchi * physical functions present on the device, while other resources are instead 379d26e4fcSRobert Mustacchi * shared across the entire card and its up to the device driver to 389d26e4fcSRobert Mustacchi * intelligently partition them. 399d26e4fcSRobert Mustacchi * 409d26e4fcSRobert Mustacchi * ------------ 419d26e4fcSRobert Mustacchi * Organization 429d26e4fcSRobert Mustacchi * ------------ 439d26e4fcSRobert Mustacchi * 449d26e4fcSRobert Mustacchi * This driver is made up of several files which have their own theory 459d26e4fcSRobert Mustacchi * statements spread across them. We'll touch on the high level purpose of each 469d26e4fcSRobert Mustacchi * file here, and then we'll get into more discussion on how the device is 479d26e4fcSRobert Mustacchi * generally modelled with respect to the interfaces in illumos. 489d26e4fcSRobert Mustacchi * 499d26e4fcSRobert Mustacchi * i40e_gld.c: This file contains all of the bindings to MAC and the networking 509d26e4fcSRobert Mustacchi * stack. 519d26e4fcSRobert Mustacchi * 529d26e4fcSRobert Mustacchi * i40e_intr.c: This file contains all of the interrupt service routines and 539d26e4fcSRobert Mustacchi * contains logic to enable and disable interrupts on the hardware. 549d26e4fcSRobert Mustacchi * It also contains the logic to map hardware resources such as the 559d26e4fcSRobert Mustacchi * rings to and from interrupts and controls their ability to fire. 569d26e4fcSRobert Mustacchi * 579d26e4fcSRobert Mustacchi * There is a big theory statement on interrupts present there. 589d26e4fcSRobert Mustacchi * 599d26e4fcSRobert Mustacchi * i40e_main.c: The file that you're currently in. It interfaces with the 609d26e4fcSRobert Mustacchi * traditional OS DDI interfaces and is in charge of configuring 619d26e4fcSRobert Mustacchi * the device. 629d26e4fcSRobert Mustacchi * 639d26e4fcSRobert Mustacchi * i40e_osdep.[ch]: These files contain interfaces and definitions needed to 649d26e4fcSRobert Mustacchi * work with Intel's common code for the device. 659d26e4fcSRobert Mustacchi * 669d26e4fcSRobert Mustacchi * i40e_stats.c: This file contains the general work and logic around our 679d26e4fcSRobert Mustacchi * kstats. A theory statement on their organization and use of the 689d26e4fcSRobert Mustacchi * hardware exists there. 699d26e4fcSRobert Mustacchi * 709d26e4fcSRobert Mustacchi * i40e_sw.h: This header file contains all of the primary structure definitions 719d26e4fcSRobert Mustacchi * and constants that are used across the entire driver. 729d26e4fcSRobert Mustacchi * 739d26e4fcSRobert Mustacchi * i40e_transceiver.c: This file contains all of the logic for sending and 749d26e4fcSRobert Mustacchi * receiving data. It contains all of the ring and DMA 759d26e4fcSRobert Mustacchi * allocation logic, as well as, the actual interfaces to 769d26e4fcSRobert Mustacchi * send and receive data. 779d26e4fcSRobert Mustacchi * 789d26e4fcSRobert Mustacchi * A big theory statement on ring management, descriptors, 799d26e4fcSRobert Mustacchi * and how it ties into the OS is present there. 809d26e4fcSRobert Mustacchi * 819d26e4fcSRobert Mustacchi * -------------- 829d26e4fcSRobert Mustacchi * General Design 839d26e4fcSRobert Mustacchi * -------------- 849d26e4fcSRobert Mustacchi * 859d26e4fcSRobert Mustacchi * Before we go too far into the general way we've laid out data structures and 869d26e4fcSRobert Mustacchi * the like, it's worth taking some time to explain how the hardware is 879d26e4fcSRobert Mustacchi * organized. This organization informs a lot of how we do things at this time 889d26e4fcSRobert Mustacchi * in the driver. 899d26e4fcSRobert Mustacchi * 909d26e4fcSRobert Mustacchi * Each physical device consists of a number of one or more ports, which are 919d26e4fcSRobert Mustacchi * considered physical functions in the PCI sense and thus each get enumerated 929d26e4fcSRobert Mustacchi * by the system, resulting in an instance being created and attached to. While 939d26e4fcSRobert Mustacchi * there are many resources that are unique to each physical function eg. 949d26e4fcSRobert Mustacchi * instance of the device, there are many that are shared across all of them. 959d26e4fcSRobert Mustacchi * Several resources have an amount reserved for each Virtual Station Interface 969d26e4fcSRobert Mustacchi * (VSI) and then a static pool of resources, available for all functions on the 979d26e4fcSRobert Mustacchi * card. 989d26e4fcSRobert Mustacchi * 999d26e4fcSRobert Mustacchi * The most important resource in hardware are its transmit and receive queue 1009d26e4fcSRobert Mustacchi * pairs (i40e_trqpair_t). These should be thought of as rings in GLDv3 1019d26e4fcSRobert Mustacchi * parlance. There are a set number of these on each device; however, they are 1029d26e4fcSRobert Mustacchi * statically partitioned among all of the different physical functions. 1039d26e4fcSRobert Mustacchi * 1049d26e4fcSRobert Mustacchi * 'Fortville' (the code name for this device family) is basically a switch. To 1059d26e4fcSRobert Mustacchi * map MAC addresses and other things to queues, we end up having to create 1069d26e4fcSRobert Mustacchi * Virtual Station Interfaces (VSIs) and establish forwarding rules that direct 1079d26e4fcSRobert Mustacchi * traffic to a queue. A VSI owns a collection of queues and has a series of 1089d26e4fcSRobert Mustacchi * forwarding rules that point to it. One way to think of this is to treat it 1099d26e4fcSRobert Mustacchi * like MAC does a VNIC. When MAC refers to a group, a collection of rings and 1109d26e4fcSRobert Mustacchi * classification resources, that is a VSI in i40e. 1119d26e4fcSRobert Mustacchi * 1129d26e4fcSRobert Mustacchi * The sets of VSIs is shared across the entire device, though there may be some 1139d26e4fcSRobert Mustacchi * amount that are reserved to each PF. Because the GLDv3 does not let us change 1149d26e4fcSRobert Mustacchi * the number of groups dynamically, we instead statically divide this amount 1159d26e4fcSRobert Mustacchi * evenly between all the functions that exist. In addition, we have the same 1169d26e4fcSRobert Mustacchi * problem with the mac address forwarding rules. There are a static number that 1179d26e4fcSRobert Mustacchi * exist shared across all the functions. 1189d26e4fcSRobert Mustacchi * 1199d26e4fcSRobert Mustacchi * To handle both of these resources, what we end up doing is going through and 1209d26e4fcSRobert Mustacchi * determining which functions belong to the same device. Nominally one might do 1219d26e4fcSRobert Mustacchi * this by having a nexus driver; however, a prime requirement for a nexus 1229d26e4fcSRobert Mustacchi * driver is identifying the various children and activating them. While it is 1239d26e4fcSRobert Mustacchi * possible to get this information from NVRAM, we would end up duplicating a 1249d26e4fcSRobert Mustacchi * lot of the PCI enumeration logic. Really, at the end of the day, the device 1259d26e4fcSRobert Mustacchi * doesn't give us the traditional identification properties we want from a 1269d26e4fcSRobert Mustacchi * nexus driver. 1279d26e4fcSRobert Mustacchi * 1289d26e4fcSRobert Mustacchi * Instead, we rely on some properties that are guaranteed to be unique. While 1299d26e4fcSRobert Mustacchi * it might be tempting to leverage the PBA or serial number of the device from 1309d26e4fcSRobert Mustacchi * NVRAM, there is nothing that says that two devices can't be mis-programmed to 1319d26e4fcSRobert Mustacchi * have the same values in NVRAM. Instead, we uniquely identify a group of 1329d26e4fcSRobert Mustacchi * functions based on their parent in the /devices tree, their PCI bus and PCI 1339d26e4fcSRobert Mustacchi * function identifiers. Using either on their own may not be sufficient. 1349d26e4fcSRobert Mustacchi * 1359d26e4fcSRobert Mustacchi * For each unique PCI device that we encounter, we'll create a i40e_device_t. 1369d26e4fcSRobert Mustacchi * From there, because we don't have a good way to tell the GLDv3 about sharing 1379d26e4fcSRobert Mustacchi * resources between everything, we'll end up just dividing the resources 1389d26e4fcSRobert Mustacchi * evenly between all of the functions. Longer term, if we don't have to declare 1399d26e4fcSRobert Mustacchi * to the GLDv3 that these resources are shared, then we'll maintain a pool and 1409d26e4fcSRobert Mustacchi * hae each PF allocate from the pool in the device, thus if only two of four 1419d26e4fcSRobert Mustacchi * ports are being used, for example, then all of the resources can still be 1429d26e4fcSRobert Mustacchi * used. 1439d26e4fcSRobert Mustacchi * 1449d26e4fcSRobert Mustacchi * ------------------------------------------- 1459d26e4fcSRobert Mustacchi * Transmit and Receive Queue Pair Allocations 1469d26e4fcSRobert Mustacchi * ------------------------------------------- 1479d26e4fcSRobert Mustacchi * 1489d26e4fcSRobert Mustacchi * NVRAM ends up assigning each PF its own share of the transmit and receive LAN 1499d26e4fcSRobert Mustacchi * queue pairs, we have no way of modifying it, only observing it. From there, 1509d26e4fcSRobert Mustacchi * it's up to us to map these queues to VSIs and VFs. Since we don't support any 1519d26e4fcSRobert Mustacchi * VFs at this time, we only focus on assignments to VSIs. 1529d26e4fcSRobert Mustacchi * 1539d26e4fcSRobert Mustacchi * At the moment, we used a static mapping of transmit/receive queue pairs to a 1549d26e4fcSRobert Mustacchi * given VSI (eg. rings to a group). Though in the fullness of time, we want to 1559d26e4fcSRobert Mustacchi * make this something which is fully dynamic and take advantage of documented, 1569d26e4fcSRobert Mustacchi * but not yet available functionality for adding filters based on VXLAN and 1579d26e4fcSRobert Mustacchi * other encapsulation technologies. 1589d26e4fcSRobert Mustacchi * 1599d26e4fcSRobert Mustacchi * ------------------------------------- 1609d26e4fcSRobert Mustacchi * Broadcast, Multicast, and Promiscuous 1619d26e4fcSRobert Mustacchi * ------------------------------------- 1629d26e4fcSRobert Mustacchi * 1639d26e4fcSRobert Mustacchi * As part of the GLDv3, we need to make sure that we can handle receiving 1649d26e4fcSRobert Mustacchi * broadcast and multicast traffic. As well as enabling promiscuous mode when 1659d26e4fcSRobert Mustacchi * requested. GLDv3 requires that all broadcast and multicast traffic be 1669d26e4fcSRobert Mustacchi * retrieved by the default group, eg. the first one. This is the same thing as 1679d26e4fcSRobert Mustacchi * the default VSI. 1689d26e4fcSRobert Mustacchi * 1699d26e4fcSRobert Mustacchi * To receieve broadcast traffic, we enable it through the admin queue, rather 1709d26e4fcSRobert Mustacchi * than use one of our filters for it. For multicast traffic, we reserve a 1719d26e4fcSRobert Mustacchi * certain number of the hash filters and assign them to a given PF. When we 1729d26e4fcSRobert Mustacchi * exceed those, we then switch to using promicuous mode for multicast traffic. 1739d26e4fcSRobert Mustacchi * 1749d26e4fcSRobert Mustacchi * More specifically, once we exceed the number of filters (indicated because 1759d26e4fcSRobert Mustacchi * the i40e_t`i40e_resources.ifr_nmcastfilt == 1769d26e4fcSRobert Mustacchi * i40e_t`i40e_resources.ifr_nmcastfilt_used), we then instead need to toggle 1779d26e4fcSRobert Mustacchi * promiscuous mode. If promiscuous mode is toggled then we keep track of the 1789d26e4fcSRobert Mustacchi * number of MACs added to it by incrementing i40e_t`i40e_mcast_promisc_count. 1799d26e4fcSRobert Mustacchi * That will stay enabled until that count reaches zero indicating that we have 1809d26e4fcSRobert Mustacchi * only added multicast addresses that we have a corresponding entry for. 1819d26e4fcSRobert Mustacchi * 1829d26e4fcSRobert Mustacchi * Because MAC itself wants to toggle promiscuous mode, which includes both 1839d26e4fcSRobert Mustacchi * unicast and multicast traffic, we go through and keep track of that 1849d26e4fcSRobert Mustacchi * ourselves. That is maintained through the use of the i40e_t`i40e_promisc_on 1859d26e4fcSRobert Mustacchi * member. 1869d26e4fcSRobert Mustacchi * 1879d26e4fcSRobert Mustacchi * -------------- 1889d26e4fcSRobert Mustacchi * VSI Management 1899d26e4fcSRobert Mustacchi * -------------- 1909d26e4fcSRobert Mustacchi * 1919d26e4fcSRobert Mustacchi * At this time, we currently only support a single MAC group, and thus a single 1929d26e4fcSRobert Mustacchi * VSI. This VSI is considered the default VSI and should be the only one that 1939d26e4fcSRobert Mustacchi * exists after a reset. Currently it is stored as the member 1949d26e4fcSRobert Mustacchi * i40e_t`i40e_vsi_id. While this works for the moment and for an initial 1959d26e4fcSRobert Mustacchi * driver, it's not sufficient for the longer-term path of the driver. Instead, 1969d26e4fcSRobert Mustacchi * we'll want to actually have a unique i40e_vsi_t structure which is used 1979d26e4fcSRobert Mustacchi * everywhere. Note that this means that every place that uses the 1989d26e4fcSRobert Mustacchi * i40e_t`i40e_vsi_id will need to be refactored. 1999d26e4fcSRobert Mustacchi * 2009d26e4fcSRobert Mustacchi * ---------------- 2019d26e4fcSRobert Mustacchi * Structure Layout 2029d26e4fcSRobert Mustacchi * ---------------- 2039d26e4fcSRobert Mustacchi * 2049d26e4fcSRobert Mustacchi * The following images relates the core data structures together. The primary 2059d26e4fcSRobert Mustacchi * structure in the system is the i40e_t. It itself contains multiple rings, 2069d26e4fcSRobert Mustacchi * i40e_trqpair_t's which contain the various transmit and receive data. The 2079d26e4fcSRobert Mustacchi * receive data is stored outside of the i40e_trqpair_t and instead in the 2089d26e4fcSRobert Mustacchi * i40e_rx_data_t. The i40e_t has a corresponding i40e_device_t which keeps 2099d26e4fcSRobert Mustacchi * track of per-physical device state. Finally, for every active descriptor, 2109d26e4fcSRobert Mustacchi * there is a corresponding control block, which is where the 2119d26e4fcSRobert Mustacchi * i40e_rx_control_block_t and the i40e_tx_control_block_t come from. 2129d26e4fcSRobert Mustacchi * 2139d26e4fcSRobert Mustacchi * +-----------------------+ +-----------------------+ 2149d26e4fcSRobert Mustacchi * | Global i40e_t list | | Global Device list | 2159d26e4fcSRobert Mustacchi * | | +--| | 2169d26e4fcSRobert Mustacchi * | i40e_glist | | | i40e_dlist | 2179d26e4fcSRobert Mustacchi * +-----------------------+ | +-----------------------+ 2189d26e4fcSRobert Mustacchi * | v 2199d26e4fcSRobert Mustacchi * | +------------------------+ +-----------------------+ 2209d26e4fcSRobert Mustacchi * | | Device-wide Structure |----->| Device-wide Structure |--> ... 2219d26e4fcSRobert Mustacchi * | | i40e_device_t | | i40e_device_t | 2229d26e4fcSRobert Mustacchi * | | | +-----------------------+ 2239d26e4fcSRobert Mustacchi * | | dev_info_t * ------+--> Parent in devices tree. 2249d26e4fcSRobert Mustacchi * | | uint_t ------+--> PCI bus number 2259d26e4fcSRobert Mustacchi * | | uint_t ------+--> PCI device number 2269d26e4fcSRobert Mustacchi * | | uint_t ------+--> Number of functions 2279d26e4fcSRobert Mustacchi * | | i40e_switch_rsrcs_t ---+--> Captured total switch resources 2289d26e4fcSRobert Mustacchi * | | list_t ------+-------------+ 2299d26e4fcSRobert Mustacchi * | +------------------------+ | 2309d26e4fcSRobert Mustacchi * | ^ | 2319d26e4fcSRobert Mustacchi * | +--------+ | 2329d26e4fcSRobert Mustacchi * | | v 2339d26e4fcSRobert Mustacchi * | +---------------------------+ | +-------------------+ 2349d26e4fcSRobert Mustacchi * +->| GLDv3 Device, per PF |-----|-->| GLDv3 Device (PF) |--> ... 2359d26e4fcSRobert Mustacchi * | i40e_t | | | i40e_t | 2369d26e4fcSRobert Mustacchi * | **Primary Structure** | | +-------------------+ 2379d26e4fcSRobert Mustacchi * | | | 2389d26e4fcSRobert Mustacchi * | i40e_device_t * --+-----+ 2399d26e4fcSRobert Mustacchi * | i40e_state_t --+---> Device State 2409d26e4fcSRobert Mustacchi * | i40e_hw_t --+---> Intel common code structure 2419d26e4fcSRobert Mustacchi * | mac_handle_t --+---> GLDv3 handle to MAC 2429d26e4fcSRobert Mustacchi * | ddi_periodic_t --+---> Link activity timer 2439d26e4fcSRobert Mustacchi * | int (vsi_id) --+---> VSI ID, main identifier 2449d26e4fcSRobert Mustacchi * | i40e_func_rsrc_t --+---> Available hardware resources 2459d26e4fcSRobert Mustacchi * | i40e_switch_rsrc_t * --+---> Switch resource snapshot 2469d26e4fcSRobert Mustacchi * | i40e_sdu --+---> Current MTU 2479d26e4fcSRobert Mustacchi * | i40e_frame_max --+---> Current HW frame size 2489d26e4fcSRobert Mustacchi * | i40e_uaddr_t * --+---> Array of assigned unicast MACs 2499d26e4fcSRobert Mustacchi * | i40e_maddr_t * --+---> Array of assigned multicast MACs 2509d26e4fcSRobert Mustacchi * | i40e_mcast_promisccount --+---> Active multicast state 2519d26e4fcSRobert Mustacchi * | i40e_promisc_on --+---> Current promiscuous mode state 2529d26e4fcSRobert Mustacchi * | int --+---> Number of transmit/receive pairs 2539d26e4fcSRobert Mustacchi * | kstat_t * --+---> PF kstats 2549d26e4fcSRobert Mustacchi * | kstat_t * --+---> VSI kstats 2559d26e4fcSRobert Mustacchi * | i40e_pf_stats_t --+---> PF kstat backing data 2569d26e4fcSRobert Mustacchi * | i40e_vsi_stats_t --+---> VSI kstat backing data 2579d26e4fcSRobert Mustacchi * | i40e_trqpair_t * --+---------+ 2589d26e4fcSRobert Mustacchi * +---------------------------+ | 2599d26e4fcSRobert Mustacchi * | 2609d26e4fcSRobert Mustacchi * v 2619d26e4fcSRobert Mustacchi * +-------------------------------+ +-----------------------------+ 2629d26e4fcSRobert Mustacchi * | Transmit/Receive Queue Pair |-------| Transmit/Receive Queue Pair |->... 2639d26e4fcSRobert Mustacchi * | i40e_trqpair_t | | i40e_trqpair_t | 2649d26e4fcSRobert Mustacchi * + Ring Data Structure | +-----------------------------+ 2659d26e4fcSRobert Mustacchi * | | 2669d26e4fcSRobert Mustacchi * | mac_ring_handle_t +--> MAC RX ring handle 2679d26e4fcSRobert Mustacchi * | mac_ring_handle_t +--> MAC TX ring handle 2689d26e4fcSRobert Mustacchi * | i40e_rxq_stat_t --+--> RX Queue stats 2699d26e4fcSRobert Mustacchi * | i40e_txq_stat_t --+--> TX Queue stats 2709d26e4fcSRobert Mustacchi * | uint32_t (tx ring size) +--> TX Ring Size 2719d26e4fcSRobert Mustacchi * | uint32_t (tx free list size) +--> TX Free List Size 2729d26e4fcSRobert Mustacchi * | i40e_dma_buffer_t --------+--> TX Descriptor ring DMA 2739d26e4fcSRobert Mustacchi * | i40e_tx_desc_t * --------+--> TX descriptor ring 2749d26e4fcSRobert Mustacchi * | volatile unt32_t * +--> TX Write back head 2759d26e4fcSRobert Mustacchi * | uint32_t -------+--> TX ring head 2769d26e4fcSRobert Mustacchi * | uint32_t -------+--> TX ring tail 2779d26e4fcSRobert Mustacchi * | uint32_t -------+--> Num TX desc free 2789d26e4fcSRobert Mustacchi * | i40e_tx_control_block_t * --+--> TX control block array ---+ 2799d26e4fcSRobert Mustacchi * | i40e_tx_control_block_t ** --+--> TCB work list ----+ 2809d26e4fcSRobert Mustacchi * | i40e_tx_control_block_t ** --+--> TCB free list ---+ 2819d26e4fcSRobert Mustacchi * | uint32_t -------+--> Free TCB count | 2829d26e4fcSRobert Mustacchi * | i40e_rx_data_t * -------+--+ v 2839d26e4fcSRobert Mustacchi * +-------------------------------+ | +---------------------------+ 2849d26e4fcSRobert Mustacchi * | | Per-TX Frame Metadata | 2859d26e4fcSRobert Mustacchi * | | i40e_tx_control_block_t | 2869d26e4fcSRobert Mustacchi * +--------------------+ | | 2879d26e4fcSRobert Mustacchi * | mblk to transmit <--+--- mblk_t * | 2889d26e4fcSRobert Mustacchi * | type of transmit <--+--- i40e_tx_type_t | 2899d26e4fcSRobert Mustacchi * | TX DMA handle <--+--- ddi_dma_handle_t | 2909d26e4fcSRobert Mustacchi * v TX DMA buffer <--+--- i40e_dma_buffer_t | 2919d26e4fcSRobert Mustacchi * +------------------------------+ +---------------------------+ 2929d26e4fcSRobert Mustacchi * | Core Receive Data | 2939d26e4fcSRobert Mustacchi * | i40e_rx_data_t | 2949d26e4fcSRobert Mustacchi * | | 2959d26e4fcSRobert Mustacchi * | i40e_dma_buffer_t --+--> RX descriptor DMA Data 2969d26e4fcSRobert Mustacchi * | i40e_rx_desc_t --+--> RX descriptor ring 2979d26e4fcSRobert Mustacchi * | uint32_t --+--> Next free desc. 2989d26e4fcSRobert Mustacchi * | i40e_rx_control_block_t * --+--> RX Control Block Array ---+ 2999d26e4fcSRobert Mustacchi * | i40e_rx_control_block_t ** --+--> RCB work list ---+ 3009d26e4fcSRobert Mustacchi * | i40e_rx_control_block_t ** --+--> RCB free list ---+ 3019d26e4fcSRobert Mustacchi * +------------------------------+ | 3029d26e4fcSRobert Mustacchi * ^ | 3039d26e4fcSRobert Mustacchi * | +---------------------------+ | 3049d26e4fcSRobert Mustacchi * | | Per-RX Frame Metadata |<---------------+ 3059d26e4fcSRobert Mustacchi * | | i40e_rx_control_block_t | 3069d26e4fcSRobert Mustacchi * | | | 3079d26e4fcSRobert Mustacchi * | | mblk_t * ----+--> Received mblk_t data 3089d26e4fcSRobert Mustacchi * | | uint32_t ----+--> Reference count 3099d26e4fcSRobert Mustacchi * | | i40e_dma_buffer_t ----+--> Receive data DMA info 3109d26e4fcSRobert Mustacchi * | | frtn_t ----+--> mblk free function info 3119d26e4fcSRobert Mustacchi * +-----+-- i40e_rx_data_t * | 3129d26e4fcSRobert Mustacchi * +---------------------------+ 3139d26e4fcSRobert Mustacchi * 3149d26e4fcSRobert Mustacchi * ------------- 3159d26e4fcSRobert Mustacchi * Lock Ordering 3169d26e4fcSRobert Mustacchi * ------------- 3179d26e4fcSRobert Mustacchi * 3189d26e4fcSRobert Mustacchi * In order to ensure that we don't deadlock, the following represents the 3199d26e4fcSRobert Mustacchi * lock order being used. When grabbing locks, follow the following order. Lower 3209d26e4fcSRobert Mustacchi * numbers are more important. Thus, the i40e_glock which is number 0, must be 3219d26e4fcSRobert Mustacchi * taken before any other locks in the driver. On the other hand, the 3229d26e4fcSRobert Mustacchi * i40e_t`i40e_stat_lock, has the highest number because it's the least 3239d26e4fcSRobert Mustacchi * important lock. Note, that just because one lock is higher than another does 3249d26e4fcSRobert Mustacchi * not mean that all intermediary locks are required. 3259d26e4fcSRobert Mustacchi * 3269d26e4fcSRobert Mustacchi * 0) i40e_glock 3279d26e4fcSRobert Mustacchi * 1) i40e_t`i40e_general_lock 3289d26e4fcSRobert Mustacchi * 3299d26e4fcSRobert Mustacchi * 2) i40e_trqpair_t`itrq_rx_lock 3309d26e4fcSRobert Mustacchi * 3) i40e_trqpair_t`itrq_tx_lock 3319d26e4fcSRobert Mustacchi * 4) i40e_t`i40e_rx_pending_lock 3329d26e4fcSRobert Mustacchi * 5) i40e_trqpair_t`itrq_tcb_lock 3339d26e4fcSRobert Mustacchi * 3349d26e4fcSRobert Mustacchi * 6) i40e_t`i40e_stat_lock 3359d26e4fcSRobert Mustacchi * 3369d26e4fcSRobert Mustacchi * Rules and expectations: 3379d26e4fcSRobert Mustacchi * 3389d26e4fcSRobert Mustacchi * 1) A thread holding locks belong to one PF should not hold locks belonging to 3399d26e4fcSRobert Mustacchi * a second. If for some reason this becomes necessary, locks should be grabbed 3409d26e4fcSRobert Mustacchi * based on the list order in the i40e_device_t, which implies that the 3419d26e4fcSRobert Mustacchi * i40e_glock is held. 3429d26e4fcSRobert Mustacchi * 3439d26e4fcSRobert Mustacchi * 2) When grabbing locks between multiple transmit and receive queues, the 3449d26e4fcSRobert Mustacchi * locks for the lowest number transmit/receive queue should be grabbed first. 3459d26e4fcSRobert Mustacchi * 3469d26e4fcSRobert Mustacchi * 3) When grabbing both the transmit and receive lock for a given queue, always 3479d26e4fcSRobert Mustacchi * grab i40e_trqpair_t`itrq_rx_lock before the i40e_trqpair_t`itrq_tx_lock. 3489d26e4fcSRobert Mustacchi * 3499d26e4fcSRobert Mustacchi * 4) The following pairs of locks are not expected to be held at the same time: 3509d26e4fcSRobert Mustacchi * 3519d26e4fcSRobert Mustacchi * o i40e_t`i40e_rx_pending_lock and i40e_trqpair_t`itrq_tcb_lock 3529d26e4fcSRobert Mustacchi * 3539d26e4fcSRobert Mustacchi * ----------- 3549d26e4fcSRobert Mustacchi * Future Work 3559d26e4fcSRobert Mustacchi * ----------- 3569d26e4fcSRobert Mustacchi * 3579d26e4fcSRobert Mustacchi * At the moment the i40e_t driver is rather bare bones, allowing us to start 3589d26e4fcSRobert Mustacchi * getting data flowing and folks using it while we develop additional features. 3599d26e4fcSRobert Mustacchi * While bugs have been filed to cover this future work, the following gives an 3609d26e4fcSRobert Mustacchi * overview of expected work: 3619d26e4fcSRobert Mustacchi * 3629d26e4fcSRobert Mustacchi * o TSO support 3639d26e4fcSRobert Mustacchi * o Multiple group support 3649d26e4fcSRobert Mustacchi * o DMA binding and breaking up the locking in ring recycling. 3659d26e4fcSRobert Mustacchi * o Enhanced detection of device errors 3669d26e4fcSRobert Mustacchi * o Participation in IRM 3679d26e4fcSRobert Mustacchi * o FMA device reset 3689d26e4fcSRobert Mustacchi * o Stall detection, temperature error detection, etc. 3699d26e4fcSRobert Mustacchi * o More dynamic resource pools 3709d26e4fcSRobert Mustacchi */ 3719d26e4fcSRobert Mustacchi 3729d26e4fcSRobert Mustacchi #include "i40e_sw.h" 3739d26e4fcSRobert Mustacchi 374396505afSPaul Winder static char i40e_ident[] = "Intel 10/40Gb Ethernet v1.0.1"; 3759d26e4fcSRobert Mustacchi 3769d26e4fcSRobert Mustacchi /* 3779d26e4fcSRobert Mustacchi * The i40e_glock primarily protects the lists below and the i40e_device_t 3789d26e4fcSRobert Mustacchi * structures. 3799d26e4fcSRobert Mustacchi */ 3809d26e4fcSRobert Mustacchi static kmutex_t i40e_glock; 3819d26e4fcSRobert Mustacchi static list_t i40e_glist; 3829d26e4fcSRobert Mustacchi static list_t i40e_dlist; 3839d26e4fcSRobert Mustacchi 3849d26e4fcSRobert Mustacchi /* 3859d26e4fcSRobert Mustacchi * Access attributes for register mapping. 3869d26e4fcSRobert Mustacchi */ 3879d26e4fcSRobert Mustacchi static ddi_device_acc_attr_t i40e_regs_acc_attr = { 3889d26e4fcSRobert Mustacchi DDI_DEVICE_ATTR_V1, 3899d26e4fcSRobert Mustacchi DDI_STRUCTURE_LE_ACC, 3909d26e4fcSRobert Mustacchi DDI_STRICTORDER_ACC, 3919d26e4fcSRobert Mustacchi DDI_FLAGERR_ACC 3929d26e4fcSRobert Mustacchi }; 3939d26e4fcSRobert Mustacchi 3949d26e4fcSRobert Mustacchi /* 3959d26e4fcSRobert Mustacchi * Logging function for this driver. 3969d26e4fcSRobert Mustacchi */ 3979d26e4fcSRobert Mustacchi static void 3989d26e4fcSRobert Mustacchi i40e_dev_err(i40e_t *i40e, int level, boolean_t console, const char *fmt, 3999d26e4fcSRobert Mustacchi va_list ap) 4009d26e4fcSRobert Mustacchi { 4019d26e4fcSRobert Mustacchi char buf[1024]; 4029d26e4fcSRobert Mustacchi 4039d26e4fcSRobert Mustacchi (void) vsnprintf(buf, sizeof (buf), fmt, ap); 4049d26e4fcSRobert Mustacchi 4059d26e4fcSRobert Mustacchi if (i40e == NULL) { 4069d26e4fcSRobert Mustacchi cmn_err(level, (console) ? "%s: %s" : "!%s: %s", 4079d26e4fcSRobert Mustacchi I40E_MODULE_NAME, buf); 4089d26e4fcSRobert Mustacchi } else { 4099d26e4fcSRobert Mustacchi dev_err(i40e->i40e_dip, level, (console) ? "%s" : "!%s", 4109d26e4fcSRobert Mustacchi buf); 4119d26e4fcSRobert Mustacchi } 4129d26e4fcSRobert Mustacchi } 4139d26e4fcSRobert Mustacchi 4149d26e4fcSRobert Mustacchi /* 4159d26e4fcSRobert Mustacchi * Because there's the stupid trailing-comma problem with the C preprocessor 4169d26e4fcSRobert Mustacchi * and variable arguments, I need to instantiate these. Pardon the redundant 4179d26e4fcSRobert Mustacchi * code. 4189d26e4fcSRobert Mustacchi */ 4199d26e4fcSRobert Mustacchi /*PRINTFLIKE2*/ 4209d26e4fcSRobert Mustacchi void 4219d26e4fcSRobert Mustacchi i40e_error(i40e_t *i40e, const char *fmt, ...) 4229d26e4fcSRobert Mustacchi { 4239d26e4fcSRobert Mustacchi va_list ap; 4249d26e4fcSRobert Mustacchi 4259d26e4fcSRobert Mustacchi va_start(ap, fmt); 4269d26e4fcSRobert Mustacchi i40e_dev_err(i40e, CE_WARN, B_FALSE, fmt, ap); 4279d26e4fcSRobert Mustacchi va_end(ap); 4289d26e4fcSRobert Mustacchi } 4299d26e4fcSRobert Mustacchi 4309d26e4fcSRobert Mustacchi /*PRINTFLIKE2*/ 4319d26e4fcSRobert Mustacchi void 4329d26e4fcSRobert Mustacchi i40e_log(i40e_t *i40e, const char *fmt, ...) 4339d26e4fcSRobert Mustacchi { 4349d26e4fcSRobert Mustacchi va_list ap; 4359d26e4fcSRobert Mustacchi 4369d26e4fcSRobert Mustacchi va_start(ap, fmt); 4379d26e4fcSRobert Mustacchi i40e_dev_err(i40e, CE_NOTE, B_FALSE, fmt, ap); 4389d26e4fcSRobert Mustacchi va_end(ap); 4399d26e4fcSRobert Mustacchi } 4409d26e4fcSRobert Mustacchi 4419d26e4fcSRobert Mustacchi /*PRINTFLIKE2*/ 4429d26e4fcSRobert Mustacchi void 4439d26e4fcSRobert Mustacchi i40e_notice(i40e_t *i40e, const char *fmt, ...) 4449d26e4fcSRobert Mustacchi { 4459d26e4fcSRobert Mustacchi va_list ap; 4469d26e4fcSRobert Mustacchi 4479d26e4fcSRobert Mustacchi va_start(ap, fmt); 4489d26e4fcSRobert Mustacchi i40e_dev_err(i40e, CE_NOTE, B_TRUE, fmt, ap); 4499d26e4fcSRobert Mustacchi va_end(ap); 4509d26e4fcSRobert Mustacchi } 4519d26e4fcSRobert Mustacchi 4529d26e4fcSRobert Mustacchi static void 4539d26e4fcSRobert Mustacchi i40e_device_rele(i40e_t *i40e) 4549d26e4fcSRobert Mustacchi { 4559d26e4fcSRobert Mustacchi i40e_device_t *idp = i40e->i40e_device; 4569d26e4fcSRobert Mustacchi 4579d26e4fcSRobert Mustacchi if (idp == NULL) 4589d26e4fcSRobert Mustacchi return; 4599d26e4fcSRobert Mustacchi 4609d26e4fcSRobert Mustacchi mutex_enter(&i40e_glock); 4619d26e4fcSRobert Mustacchi VERIFY(idp->id_nreg > 0); 4629d26e4fcSRobert Mustacchi list_remove(&idp->id_i40e_list, i40e); 4639d26e4fcSRobert Mustacchi idp->id_nreg--; 4649d26e4fcSRobert Mustacchi if (idp->id_nreg == 0) { 4659d26e4fcSRobert Mustacchi list_remove(&i40e_dlist, idp); 4669d26e4fcSRobert Mustacchi list_destroy(&idp->id_i40e_list); 4679d26e4fcSRobert Mustacchi kmem_free(idp->id_rsrcs, sizeof (i40e_switch_rsrc_t) * 4689d26e4fcSRobert Mustacchi idp->id_rsrcs_alloc); 4699d26e4fcSRobert Mustacchi kmem_free(idp, sizeof (i40e_device_t)); 4709d26e4fcSRobert Mustacchi } 4719d26e4fcSRobert Mustacchi i40e->i40e_device = NULL; 4729d26e4fcSRobert Mustacchi mutex_exit(&i40e_glock); 4739d26e4fcSRobert Mustacchi } 4749d26e4fcSRobert Mustacchi 4759d26e4fcSRobert Mustacchi static i40e_device_t * 4769d26e4fcSRobert Mustacchi i40e_device_find(i40e_t *i40e, dev_info_t *parent, uint_t bus, uint_t device) 4779d26e4fcSRobert Mustacchi { 4789d26e4fcSRobert Mustacchi i40e_device_t *idp; 4799d26e4fcSRobert Mustacchi mutex_enter(&i40e_glock); 4809d26e4fcSRobert Mustacchi for (idp = list_head(&i40e_dlist); idp != NULL; 4819d26e4fcSRobert Mustacchi idp = list_next(&i40e_dlist, idp)) { 4829d26e4fcSRobert Mustacchi if (idp->id_parent == parent && idp->id_pci_bus == bus && 4839d26e4fcSRobert Mustacchi idp->id_pci_device == device) { 4849d26e4fcSRobert Mustacchi break; 4859d26e4fcSRobert Mustacchi } 4869d26e4fcSRobert Mustacchi } 4879d26e4fcSRobert Mustacchi 4889d26e4fcSRobert Mustacchi if (idp != NULL) { 4899d26e4fcSRobert Mustacchi VERIFY(idp->id_nreg < idp->id_nfuncs); 4909d26e4fcSRobert Mustacchi idp->id_nreg++; 4919d26e4fcSRobert Mustacchi } else { 4929d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 4939d26e4fcSRobert Mustacchi ASSERT(hw->num_ports > 0); 4949d26e4fcSRobert Mustacchi ASSERT(hw->num_partitions > 0); 4959d26e4fcSRobert Mustacchi 4969d26e4fcSRobert Mustacchi /* 4979d26e4fcSRobert Mustacchi * The Intel common code doesn't exactly keep the number of PCI 4989d26e4fcSRobert Mustacchi * functions. But it calculates it during discovery of 4999d26e4fcSRobert Mustacchi * partitions and ports. So what we do is undo the calculation 5009d26e4fcSRobert Mustacchi * that it does originally, as functions are evenly spread 5019d26e4fcSRobert Mustacchi * across ports in the rare case of partitions. 5029d26e4fcSRobert Mustacchi */ 5039d26e4fcSRobert Mustacchi idp = kmem_alloc(sizeof (i40e_device_t), KM_SLEEP); 5049d26e4fcSRobert Mustacchi idp->id_parent = parent; 5059d26e4fcSRobert Mustacchi idp->id_pci_bus = bus; 5069d26e4fcSRobert Mustacchi idp->id_pci_device = device; 5079d26e4fcSRobert Mustacchi idp->id_nfuncs = hw->num_ports * hw->num_partitions; 5089d26e4fcSRobert Mustacchi idp->id_nreg = 1; 5099d26e4fcSRobert Mustacchi idp->id_rsrcs_alloc = i40e->i40e_switch_rsrc_alloc; 5109d26e4fcSRobert Mustacchi idp->id_rsrcs_act = i40e->i40e_switch_rsrc_actual; 5119d26e4fcSRobert Mustacchi idp->id_rsrcs = kmem_alloc(sizeof (i40e_switch_rsrc_t) * 5129d26e4fcSRobert Mustacchi idp->id_rsrcs_alloc, KM_SLEEP); 5139d26e4fcSRobert Mustacchi bcopy(i40e->i40e_switch_rsrcs, idp->id_rsrcs, 5149d26e4fcSRobert Mustacchi sizeof (i40e_switch_rsrc_t) * idp->id_rsrcs_alloc); 5159d26e4fcSRobert Mustacchi list_create(&idp->id_i40e_list, sizeof (i40e_t), 5169d26e4fcSRobert Mustacchi offsetof(i40e_t, i40e_dlink)); 5179d26e4fcSRobert Mustacchi 5189d26e4fcSRobert Mustacchi list_insert_tail(&i40e_dlist, idp); 5199d26e4fcSRobert Mustacchi } 5209d26e4fcSRobert Mustacchi 5219d26e4fcSRobert Mustacchi list_insert_tail(&idp->id_i40e_list, i40e); 5229d26e4fcSRobert Mustacchi mutex_exit(&i40e_glock); 5239d26e4fcSRobert Mustacchi 5249d26e4fcSRobert Mustacchi return (idp); 5259d26e4fcSRobert Mustacchi } 5269d26e4fcSRobert Mustacchi 5279d26e4fcSRobert Mustacchi static void 5289d26e4fcSRobert Mustacchi i40e_link_state_set(i40e_t *i40e, link_state_t state) 5299d26e4fcSRobert Mustacchi { 5309d26e4fcSRobert Mustacchi if (i40e->i40e_link_state == state) 5319d26e4fcSRobert Mustacchi return; 5329d26e4fcSRobert Mustacchi 5339d26e4fcSRobert Mustacchi i40e->i40e_link_state = state; 5349d26e4fcSRobert Mustacchi mac_link_update(i40e->i40e_mac_hdl, i40e->i40e_link_state); 5359d26e4fcSRobert Mustacchi } 5369d26e4fcSRobert Mustacchi 5379d26e4fcSRobert Mustacchi /* 5389d26e4fcSRobert Mustacchi * This is a basic link check routine. Mostly we're using this just to see 5399d26e4fcSRobert Mustacchi * if we can get any accurate information about the state of the link being 5409d26e4fcSRobert Mustacchi * up or down, as well as updating the link state, speed, etc. information. 5419d26e4fcSRobert Mustacchi */ 5429d26e4fcSRobert Mustacchi void 5439d26e4fcSRobert Mustacchi i40e_link_check(i40e_t *i40e) 5449d26e4fcSRobert Mustacchi { 5459d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 5469d26e4fcSRobert Mustacchi boolean_t ls; 5479d26e4fcSRobert Mustacchi int ret; 5489d26e4fcSRobert Mustacchi 5499d26e4fcSRobert Mustacchi ASSERT(MUTEX_HELD(&i40e->i40e_general_lock)); 5509d26e4fcSRobert Mustacchi 5519d26e4fcSRobert Mustacchi hw->phy.get_link_info = B_TRUE; 5529d26e4fcSRobert Mustacchi if ((ret = i40e_get_link_status(hw, &ls)) != I40E_SUCCESS) { 5539d26e4fcSRobert Mustacchi i40e->i40e_s_link_status_errs++; 5549d26e4fcSRobert Mustacchi i40e->i40e_s_link_status_lasterr = ret; 5559d26e4fcSRobert Mustacchi return; 5569d26e4fcSRobert Mustacchi } 5579d26e4fcSRobert Mustacchi 5589d26e4fcSRobert Mustacchi /* 5599d26e4fcSRobert Mustacchi * Firmware abstracts all of the mac and phy information for us, so we 5609d26e4fcSRobert Mustacchi * can use i40e_get_link_status to determine the current state. 5619d26e4fcSRobert Mustacchi */ 5629d26e4fcSRobert Mustacchi if (ls == B_TRUE) { 5639d26e4fcSRobert Mustacchi enum i40e_aq_link_speed speed; 5649d26e4fcSRobert Mustacchi 5659d26e4fcSRobert Mustacchi speed = i40e_get_link_speed(hw); 5669d26e4fcSRobert Mustacchi 5679d26e4fcSRobert Mustacchi /* 5689d26e4fcSRobert Mustacchi * Translate from an i40e value to a value in Mbits/s. 5699d26e4fcSRobert Mustacchi */ 5709d26e4fcSRobert Mustacchi switch (speed) { 5719d26e4fcSRobert Mustacchi case I40E_LINK_SPEED_100MB: 5729d26e4fcSRobert Mustacchi i40e->i40e_link_speed = 100; 5739d26e4fcSRobert Mustacchi break; 5749d26e4fcSRobert Mustacchi case I40E_LINK_SPEED_1GB: 5759d26e4fcSRobert Mustacchi i40e->i40e_link_speed = 1000; 5769d26e4fcSRobert Mustacchi break; 5779d26e4fcSRobert Mustacchi case I40E_LINK_SPEED_10GB: 5789d26e4fcSRobert Mustacchi i40e->i40e_link_speed = 10000; 5799d26e4fcSRobert Mustacchi break; 5809d26e4fcSRobert Mustacchi case I40E_LINK_SPEED_20GB: 5819d26e4fcSRobert Mustacchi i40e->i40e_link_speed = 20000; 5829d26e4fcSRobert Mustacchi break; 5839d26e4fcSRobert Mustacchi case I40E_LINK_SPEED_40GB: 5849d26e4fcSRobert Mustacchi i40e->i40e_link_speed = 40000; 5859d26e4fcSRobert Mustacchi break; 586*3d75a287SRobert Mustacchi case I40E_LINK_SPEED_25GB: 587*3d75a287SRobert Mustacchi i40e->i40e_link_speed = 25000; 588*3d75a287SRobert Mustacchi break; 5899d26e4fcSRobert Mustacchi default: 5909d26e4fcSRobert Mustacchi i40e->i40e_link_speed = 0; 5919d26e4fcSRobert Mustacchi break; 5929d26e4fcSRobert Mustacchi } 5939d26e4fcSRobert Mustacchi 5949d26e4fcSRobert Mustacchi /* 5959d26e4fcSRobert Mustacchi * At this time, hardware does not support half-duplex 5969d26e4fcSRobert Mustacchi * operation, hence why we don't ask the hardware about our 5979d26e4fcSRobert Mustacchi * current speed. 5989d26e4fcSRobert Mustacchi */ 5999d26e4fcSRobert Mustacchi i40e->i40e_link_duplex = LINK_DUPLEX_FULL; 6009d26e4fcSRobert Mustacchi i40e_link_state_set(i40e, LINK_STATE_UP); 6019d26e4fcSRobert Mustacchi } else { 6029d26e4fcSRobert Mustacchi i40e->i40e_link_speed = 0; 6039d26e4fcSRobert Mustacchi i40e->i40e_link_duplex = 0; 6049d26e4fcSRobert Mustacchi i40e_link_state_set(i40e, LINK_STATE_DOWN); 6059d26e4fcSRobert Mustacchi } 6069d26e4fcSRobert Mustacchi } 6079d26e4fcSRobert Mustacchi 6089d26e4fcSRobert Mustacchi static void 6099d26e4fcSRobert Mustacchi i40e_rem_intrs(i40e_t *i40e) 6109d26e4fcSRobert Mustacchi { 6119d26e4fcSRobert Mustacchi int i, rc; 6129d26e4fcSRobert Mustacchi 6139d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_intr_count; i++) { 6149d26e4fcSRobert Mustacchi rc = ddi_intr_free(i40e->i40e_intr_handles[i]); 6159d26e4fcSRobert Mustacchi if (rc != DDI_SUCCESS) { 6169d26e4fcSRobert Mustacchi i40e_log(i40e, "failed to free interrupt %d: %d", 6179d26e4fcSRobert Mustacchi i, rc); 6189d26e4fcSRobert Mustacchi } 6199d26e4fcSRobert Mustacchi } 6209d26e4fcSRobert Mustacchi 6219d26e4fcSRobert Mustacchi kmem_free(i40e->i40e_intr_handles, i40e->i40e_intr_size); 6229d26e4fcSRobert Mustacchi i40e->i40e_intr_handles = NULL; 6239d26e4fcSRobert Mustacchi } 6249d26e4fcSRobert Mustacchi 6259d26e4fcSRobert Mustacchi static void 6269d26e4fcSRobert Mustacchi i40e_rem_intr_handlers(i40e_t *i40e) 6279d26e4fcSRobert Mustacchi { 6289d26e4fcSRobert Mustacchi int i, rc; 6299d26e4fcSRobert Mustacchi 6309d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_intr_count; i++) { 6319d26e4fcSRobert Mustacchi rc = ddi_intr_remove_handler(i40e->i40e_intr_handles[i]); 6329d26e4fcSRobert Mustacchi if (rc != DDI_SUCCESS) { 6339d26e4fcSRobert Mustacchi i40e_log(i40e, "failed to remove interrupt %d: %d", 6349d26e4fcSRobert Mustacchi i, rc); 6359d26e4fcSRobert Mustacchi } 6369d26e4fcSRobert Mustacchi } 6379d26e4fcSRobert Mustacchi } 6389d26e4fcSRobert Mustacchi 6399d26e4fcSRobert Mustacchi /* 6409d26e4fcSRobert Mustacchi * illumos Fault Management Architecture (FMA) support. 6419d26e4fcSRobert Mustacchi */ 6429d26e4fcSRobert Mustacchi 6439d26e4fcSRobert Mustacchi int 6449d26e4fcSRobert Mustacchi i40e_check_acc_handle(ddi_acc_handle_t handle) 6459d26e4fcSRobert Mustacchi { 6469d26e4fcSRobert Mustacchi ddi_fm_error_t de; 6479d26e4fcSRobert Mustacchi 6489d26e4fcSRobert Mustacchi ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION); 6499d26e4fcSRobert Mustacchi ddi_fm_acc_err_clear(handle, DDI_FME_VERSION); 6509d26e4fcSRobert Mustacchi return (de.fme_status); 6519d26e4fcSRobert Mustacchi } 6529d26e4fcSRobert Mustacchi 6539d26e4fcSRobert Mustacchi int 6549d26e4fcSRobert Mustacchi i40e_check_dma_handle(ddi_dma_handle_t handle) 6559d26e4fcSRobert Mustacchi { 6569d26e4fcSRobert Mustacchi ddi_fm_error_t de; 6579d26e4fcSRobert Mustacchi 6589d26e4fcSRobert Mustacchi ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION); 6599d26e4fcSRobert Mustacchi return (de.fme_status); 6609d26e4fcSRobert Mustacchi } 6619d26e4fcSRobert Mustacchi 6629d26e4fcSRobert Mustacchi /* 6639d26e4fcSRobert Mustacchi * Fault service error handling callback function. 6649d26e4fcSRobert Mustacchi */ 6659d26e4fcSRobert Mustacchi /* ARGSUSED */ 6669d26e4fcSRobert Mustacchi static int 6679d26e4fcSRobert Mustacchi i40e_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 6689d26e4fcSRobert Mustacchi { 6699d26e4fcSRobert Mustacchi pci_ereport_post(dip, err, NULL); 6709d26e4fcSRobert Mustacchi return (err->fme_status); 6719d26e4fcSRobert Mustacchi } 6729d26e4fcSRobert Mustacchi 6739d26e4fcSRobert Mustacchi static void 6749d26e4fcSRobert Mustacchi i40e_fm_init(i40e_t *i40e) 6759d26e4fcSRobert Mustacchi { 6769d26e4fcSRobert Mustacchi ddi_iblock_cookie_t iblk; 6779d26e4fcSRobert Mustacchi 6789d26e4fcSRobert Mustacchi i40e->i40e_fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY, 6799d26e4fcSRobert Mustacchi i40e->i40e_dip, DDI_PROP_DONTPASS, "fm_capable", 6809d26e4fcSRobert Mustacchi DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE | 6819d26e4fcSRobert Mustacchi DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE); 6829d26e4fcSRobert Mustacchi 6839d26e4fcSRobert Mustacchi if (i40e->i40e_fm_capabilities < 0) { 6849d26e4fcSRobert Mustacchi i40e->i40e_fm_capabilities = 0; 6859d26e4fcSRobert Mustacchi } else if (i40e->i40e_fm_capabilities > 0xf) { 6869d26e4fcSRobert Mustacchi i40e->i40e_fm_capabilities = DDI_FM_EREPORT_CAPABLE | 6879d26e4fcSRobert Mustacchi DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE | 6889d26e4fcSRobert Mustacchi DDI_FM_ERRCB_CAPABLE; 6899d26e4fcSRobert Mustacchi } 6909d26e4fcSRobert Mustacchi 6919d26e4fcSRobert Mustacchi /* 6929d26e4fcSRobert Mustacchi * Only register with IO Fault Services if we have some capability 6939d26e4fcSRobert Mustacchi */ 6949d26e4fcSRobert Mustacchi if (i40e->i40e_fm_capabilities & DDI_FM_ACCCHK_CAPABLE) { 6959d26e4fcSRobert Mustacchi i40e_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC; 6969d26e4fcSRobert Mustacchi } else { 6979d26e4fcSRobert Mustacchi i40e_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC; 6989d26e4fcSRobert Mustacchi } 6999d26e4fcSRobert Mustacchi 7009d26e4fcSRobert Mustacchi if (i40e->i40e_fm_capabilities) { 7019d26e4fcSRobert Mustacchi ddi_fm_init(i40e->i40e_dip, &i40e->i40e_fm_capabilities, &iblk); 7029d26e4fcSRobert Mustacchi 7039d26e4fcSRobert Mustacchi if (DDI_FM_EREPORT_CAP(i40e->i40e_fm_capabilities) || 7049d26e4fcSRobert Mustacchi DDI_FM_ERRCB_CAP(i40e->i40e_fm_capabilities)) { 7059d26e4fcSRobert Mustacchi pci_ereport_setup(i40e->i40e_dip); 7069d26e4fcSRobert Mustacchi } 7079d26e4fcSRobert Mustacchi 7089d26e4fcSRobert Mustacchi if (DDI_FM_ERRCB_CAP(i40e->i40e_fm_capabilities)) { 7099d26e4fcSRobert Mustacchi ddi_fm_handler_register(i40e->i40e_dip, 7109d26e4fcSRobert Mustacchi i40e_fm_error_cb, (void*)i40e); 7119d26e4fcSRobert Mustacchi } 7129d26e4fcSRobert Mustacchi } 7139d26e4fcSRobert Mustacchi 7149d26e4fcSRobert Mustacchi if (i40e->i40e_fm_capabilities & DDI_FM_DMACHK_CAPABLE) { 7159d26e4fcSRobert Mustacchi i40e_init_dma_attrs(i40e, B_TRUE); 7169d26e4fcSRobert Mustacchi } else { 7179d26e4fcSRobert Mustacchi i40e_init_dma_attrs(i40e, B_FALSE); 7189d26e4fcSRobert Mustacchi } 7199d26e4fcSRobert Mustacchi } 7209d26e4fcSRobert Mustacchi 7219d26e4fcSRobert Mustacchi static void 7229d26e4fcSRobert Mustacchi i40e_fm_fini(i40e_t *i40e) 7239d26e4fcSRobert Mustacchi { 7249d26e4fcSRobert Mustacchi if (i40e->i40e_fm_capabilities) { 7259d26e4fcSRobert Mustacchi 7269d26e4fcSRobert Mustacchi if (DDI_FM_EREPORT_CAP(i40e->i40e_fm_capabilities) || 7279d26e4fcSRobert Mustacchi DDI_FM_ERRCB_CAP(i40e->i40e_fm_capabilities)) 7289d26e4fcSRobert Mustacchi pci_ereport_teardown(i40e->i40e_dip); 7299d26e4fcSRobert Mustacchi 7309d26e4fcSRobert Mustacchi if (DDI_FM_ERRCB_CAP(i40e->i40e_fm_capabilities)) 7319d26e4fcSRobert Mustacchi ddi_fm_handler_unregister(i40e->i40e_dip); 7329d26e4fcSRobert Mustacchi 7339d26e4fcSRobert Mustacchi ddi_fm_fini(i40e->i40e_dip); 7349d26e4fcSRobert Mustacchi } 7359d26e4fcSRobert Mustacchi } 7369d26e4fcSRobert Mustacchi 7379d26e4fcSRobert Mustacchi void 7389d26e4fcSRobert Mustacchi i40e_fm_ereport(i40e_t *i40e, char *detail) 7399d26e4fcSRobert Mustacchi { 7409d26e4fcSRobert Mustacchi uint64_t ena; 7419d26e4fcSRobert Mustacchi char buf[FM_MAX_CLASS]; 7429d26e4fcSRobert Mustacchi 7439d26e4fcSRobert Mustacchi (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail); 7449d26e4fcSRobert Mustacchi ena = fm_ena_generate(0, FM_ENA_FMT1); 7459d26e4fcSRobert Mustacchi if (DDI_FM_EREPORT_CAP(i40e->i40e_fm_capabilities)) { 7469d26e4fcSRobert Mustacchi ddi_fm_ereport_post(i40e->i40e_dip, buf, ena, DDI_NOSLEEP, 7479d26e4fcSRobert Mustacchi FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL); 7489d26e4fcSRobert Mustacchi } 7499d26e4fcSRobert Mustacchi } 7509d26e4fcSRobert Mustacchi 7519d26e4fcSRobert Mustacchi /* 7529d26e4fcSRobert Mustacchi * Here we're trying to get the ID of the default VSI. In general, when we come 7539d26e4fcSRobert Mustacchi * through and look at this shortly after attach, we expect there to only be a 7549d26e4fcSRobert Mustacchi * single element present, which is the default VSI. Importantly, each PF seems 7559d26e4fcSRobert Mustacchi * to not see any other devices, in part because of the simple switch mode that 7569d26e4fcSRobert Mustacchi * we're using. If for some reason, we see more artifact, we'll need to revisit 7579d26e4fcSRobert Mustacchi * what we're doing here. 7589d26e4fcSRobert Mustacchi */ 7599d26e4fcSRobert Mustacchi static int 7609d26e4fcSRobert Mustacchi i40e_get_vsi_id(i40e_t *i40e) 7619d26e4fcSRobert Mustacchi { 7629d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 7639d26e4fcSRobert Mustacchi struct i40e_aqc_get_switch_config_resp *sw_config; 7649d26e4fcSRobert Mustacchi uint8_t aq_buf[I40E_AQ_LARGE_BUF]; 7659d26e4fcSRobert Mustacchi uint16_t next = 0; 7669d26e4fcSRobert Mustacchi int rc; 7679d26e4fcSRobert Mustacchi 7689d26e4fcSRobert Mustacchi /* LINTED: E_BAD_PTR_CAST_ALIGN */ 7699d26e4fcSRobert Mustacchi sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf; 7709d26e4fcSRobert Mustacchi rc = i40e_aq_get_switch_config(hw, sw_config, sizeof (aq_buf), &next, 7719d26e4fcSRobert Mustacchi NULL); 7729d26e4fcSRobert Mustacchi if (rc != I40E_SUCCESS) { 7739d26e4fcSRobert Mustacchi i40e_error(i40e, "i40e_aq_get_switch_config() failed %d: %d", 7749d26e4fcSRobert Mustacchi rc, hw->aq.asq_last_status); 7759d26e4fcSRobert Mustacchi return (-1); 7769d26e4fcSRobert Mustacchi } 7779d26e4fcSRobert Mustacchi 7789d26e4fcSRobert Mustacchi if (LE_16(sw_config->header.num_reported) != 1) { 7799d26e4fcSRobert Mustacchi i40e_error(i40e, "encountered multiple (%d) switching units " 7809d26e4fcSRobert Mustacchi "during attach, not proceeding", 7819d26e4fcSRobert Mustacchi LE_16(sw_config->header.num_reported)); 7829d26e4fcSRobert Mustacchi return (-1); 7839d26e4fcSRobert Mustacchi } 7849d26e4fcSRobert Mustacchi 7859d26e4fcSRobert Mustacchi return (sw_config->element[0].seid); 7869d26e4fcSRobert Mustacchi } 7879d26e4fcSRobert Mustacchi 7889d26e4fcSRobert Mustacchi /* 7899d26e4fcSRobert Mustacchi * We need to fill the i40e_hw_t structure with the capabilities of this PF. We 7909d26e4fcSRobert Mustacchi * must also provide the memory for it; however, we don't need to keep it around 7919d26e4fcSRobert Mustacchi * to the call to the common code. It takes it and parses it into an internal 7929d26e4fcSRobert Mustacchi * structure. 7939d26e4fcSRobert Mustacchi */ 7949d26e4fcSRobert Mustacchi static boolean_t 7959d26e4fcSRobert Mustacchi i40e_get_hw_capabilities(i40e_t *i40e, i40e_hw_t *hw) 7969d26e4fcSRobert Mustacchi { 7979d26e4fcSRobert Mustacchi struct i40e_aqc_list_capabilities_element_resp *buf; 7989d26e4fcSRobert Mustacchi int rc; 7999d26e4fcSRobert Mustacchi size_t len; 8009d26e4fcSRobert Mustacchi uint16_t needed; 8019d26e4fcSRobert Mustacchi int nelems = I40E_HW_CAP_DEFAULT; 8029d26e4fcSRobert Mustacchi 8039d26e4fcSRobert Mustacchi len = nelems * sizeof (*buf); 8049d26e4fcSRobert Mustacchi 8059d26e4fcSRobert Mustacchi for (;;) { 8069d26e4fcSRobert Mustacchi ASSERT(len > 0); 8079d26e4fcSRobert Mustacchi buf = kmem_alloc(len, KM_SLEEP); 8089d26e4fcSRobert Mustacchi rc = i40e_aq_discover_capabilities(hw, buf, len, 8099d26e4fcSRobert Mustacchi &needed, i40e_aqc_opc_list_func_capabilities, NULL); 8109d26e4fcSRobert Mustacchi kmem_free(buf, len); 8119d26e4fcSRobert Mustacchi 8129d26e4fcSRobert Mustacchi if (hw->aq.asq_last_status == I40E_AQ_RC_ENOMEM && 8139d26e4fcSRobert Mustacchi nelems == I40E_HW_CAP_DEFAULT) { 8149d26e4fcSRobert Mustacchi if (nelems == needed) { 8159d26e4fcSRobert Mustacchi i40e_error(i40e, "Capability discovery failed " 8169d26e4fcSRobert Mustacchi "due to byzantine common code"); 8179d26e4fcSRobert Mustacchi return (B_FALSE); 8189d26e4fcSRobert Mustacchi } 8199d26e4fcSRobert Mustacchi len = needed; 8209d26e4fcSRobert Mustacchi continue; 8219d26e4fcSRobert Mustacchi } else if (rc != I40E_SUCCESS || 8229d26e4fcSRobert Mustacchi hw->aq.asq_last_status != I40E_AQ_RC_OK) { 8239d26e4fcSRobert Mustacchi i40e_error(i40e, "Capability discovery failed: %d", rc); 8249d26e4fcSRobert Mustacchi return (B_FALSE); 8259d26e4fcSRobert Mustacchi } 8269d26e4fcSRobert Mustacchi 8279d26e4fcSRobert Mustacchi break; 8289d26e4fcSRobert Mustacchi } 8299d26e4fcSRobert Mustacchi 8309d26e4fcSRobert Mustacchi return (B_TRUE); 8319d26e4fcSRobert Mustacchi } 8329d26e4fcSRobert Mustacchi 8339d26e4fcSRobert Mustacchi /* 8349d26e4fcSRobert Mustacchi * Obtain the switch's capabilities as seen by this PF and keep it around for 8359d26e4fcSRobert Mustacchi * our later use. 8369d26e4fcSRobert Mustacchi */ 8379d26e4fcSRobert Mustacchi static boolean_t 8389d26e4fcSRobert Mustacchi i40e_get_switch_resources(i40e_t *i40e) 8399d26e4fcSRobert Mustacchi { 8409d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 8419d26e4fcSRobert Mustacchi uint8_t cnt = 2; 8429d26e4fcSRobert Mustacchi uint8_t act; 8439d26e4fcSRobert Mustacchi size_t size; 8449d26e4fcSRobert Mustacchi i40e_switch_rsrc_t *buf; 8459d26e4fcSRobert Mustacchi 8469d26e4fcSRobert Mustacchi for (;;) { 8479d26e4fcSRobert Mustacchi enum i40e_status_code ret; 8489d26e4fcSRobert Mustacchi size = cnt * sizeof (i40e_switch_rsrc_t); 8499d26e4fcSRobert Mustacchi ASSERT(size > 0); 8509d26e4fcSRobert Mustacchi if (size > UINT16_MAX) 8519d26e4fcSRobert Mustacchi return (B_FALSE); 8529d26e4fcSRobert Mustacchi buf = kmem_alloc(size, KM_SLEEP); 8539d26e4fcSRobert Mustacchi 8549d26e4fcSRobert Mustacchi ret = i40e_aq_get_switch_resource_alloc(hw, &act, buf, 8559d26e4fcSRobert Mustacchi cnt, NULL); 8569d26e4fcSRobert Mustacchi if (ret == I40E_ERR_ADMIN_QUEUE_ERROR && 8579d26e4fcSRobert Mustacchi hw->aq.asq_last_status == I40E_AQ_RC_EINVAL) { 8589d26e4fcSRobert Mustacchi kmem_free(buf, size); 8599d26e4fcSRobert Mustacchi cnt += I40E_SWITCH_CAP_DEFAULT; 8609d26e4fcSRobert Mustacchi continue; 8619d26e4fcSRobert Mustacchi } else if (ret != I40E_SUCCESS) { 8629d26e4fcSRobert Mustacchi kmem_free(buf, size); 8639d26e4fcSRobert Mustacchi i40e_error(i40e, 8649d26e4fcSRobert Mustacchi "failed to retrieve switch statistics: %d", ret); 8659d26e4fcSRobert Mustacchi return (B_FALSE); 8669d26e4fcSRobert Mustacchi } 8679d26e4fcSRobert Mustacchi 8689d26e4fcSRobert Mustacchi break; 8699d26e4fcSRobert Mustacchi } 8709d26e4fcSRobert Mustacchi 8719d26e4fcSRobert Mustacchi i40e->i40e_switch_rsrc_alloc = cnt; 8729d26e4fcSRobert Mustacchi i40e->i40e_switch_rsrc_actual = act; 8739d26e4fcSRobert Mustacchi i40e->i40e_switch_rsrcs = buf; 8749d26e4fcSRobert Mustacchi 8759d26e4fcSRobert Mustacchi return (B_TRUE); 8769d26e4fcSRobert Mustacchi } 8779d26e4fcSRobert Mustacchi 8789d26e4fcSRobert Mustacchi static void 8799d26e4fcSRobert Mustacchi i40e_cleanup_resources(i40e_t *i40e) 8809d26e4fcSRobert Mustacchi { 8819d26e4fcSRobert Mustacchi if (i40e->i40e_uaddrs != NULL) { 8829d26e4fcSRobert Mustacchi kmem_free(i40e->i40e_uaddrs, sizeof (i40e_uaddr_t) * 8839d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nmacfilt); 8849d26e4fcSRobert Mustacchi i40e->i40e_uaddrs = NULL; 8859d26e4fcSRobert Mustacchi } 8869d26e4fcSRobert Mustacchi 8879d26e4fcSRobert Mustacchi if (i40e->i40e_maddrs != NULL) { 8889d26e4fcSRobert Mustacchi kmem_free(i40e->i40e_maddrs, sizeof (i40e_maddr_t) * 8899d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nmcastfilt); 8909d26e4fcSRobert Mustacchi i40e->i40e_maddrs = NULL; 8919d26e4fcSRobert Mustacchi } 8929d26e4fcSRobert Mustacchi 8939d26e4fcSRobert Mustacchi if (i40e->i40e_switch_rsrcs != NULL) { 8949d26e4fcSRobert Mustacchi size_t sz = sizeof (i40e_switch_rsrc_t) * 8959d26e4fcSRobert Mustacchi i40e->i40e_switch_rsrc_alloc; 8969d26e4fcSRobert Mustacchi ASSERT(sz > 0); 8979d26e4fcSRobert Mustacchi kmem_free(i40e->i40e_switch_rsrcs, sz); 8989d26e4fcSRobert Mustacchi i40e->i40e_switch_rsrcs = NULL; 8999d26e4fcSRobert Mustacchi } 9009d26e4fcSRobert Mustacchi 9019d26e4fcSRobert Mustacchi if (i40e->i40e_device != NULL) 9029d26e4fcSRobert Mustacchi i40e_device_rele(i40e); 9039d26e4fcSRobert Mustacchi } 9049d26e4fcSRobert Mustacchi 9059d26e4fcSRobert Mustacchi static boolean_t 9069d26e4fcSRobert Mustacchi i40e_get_available_resources(i40e_t *i40e) 9079d26e4fcSRobert Mustacchi { 9089d26e4fcSRobert Mustacchi dev_info_t *parent; 9099d26e4fcSRobert Mustacchi uint16_t bus, device, func; 9109d26e4fcSRobert Mustacchi uint_t nregs; 9119d26e4fcSRobert Mustacchi int *regs, i; 9129d26e4fcSRobert Mustacchi i40e_device_t *idp; 9139d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 9149d26e4fcSRobert Mustacchi 9159d26e4fcSRobert Mustacchi parent = ddi_get_parent(i40e->i40e_dip); 9169d26e4fcSRobert Mustacchi 9179d26e4fcSRobert Mustacchi if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, i40e->i40e_dip, 0, "reg", 9189d26e4fcSRobert Mustacchi ®s, &nregs) != DDI_PROP_SUCCESS) { 9199d26e4fcSRobert Mustacchi return (B_FALSE); 9209d26e4fcSRobert Mustacchi } 9219d26e4fcSRobert Mustacchi 9229d26e4fcSRobert Mustacchi if (nregs < 1) { 9239d26e4fcSRobert Mustacchi ddi_prop_free(regs); 9249d26e4fcSRobert Mustacchi return (B_FALSE); 9259d26e4fcSRobert Mustacchi } 9269d26e4fcSRobert Mustacchi 9279d26e4fcSRobert Mustacchi bus = PCI_REG_BUS_G(regs[0]); 9289d26e4fcSRobert Mustacchi device = PCI_REG_DEV_G(regs[0]); 9299d26e4fcSRobert Mustacchi func = PCI_REG_FUNC_G(regs[0]); 9309d26e4fcSRobert Mustacchi ddi_prop_free(regs); 9319d26e4fcSRobert Mustacchi 9329d26e4fcSRobert Mustacchi i40e->i40e_hw_space.bus.func = func; 9339d26e4fcSRobert Mustacchi i40e->i40e_hw_space.bus.device = device; 9349d26e4fcSRobert Mustacchi 9359d26e4fcSRobert Mustacchi if (i40e_get_switch_resources(i40e) == B_FALSE) { 9369d26e4fcSRobert Mustacchi return (B_FALSE); 9379d26e4fcSRobert Mustacchi } 9389d26e4fcSRobert Mustacchi 9399d26e4fcSRobert Mustacchi /* 9409d26e4fcSRobert Mustacchi * To calculate the total amount of a resource we have available, we 9419d26e4fcSRobert Mustacchi * need to add how many our i40e_t thinks it has guaranteed, if any, and 9429d26e4fcSRobert Mustacchi * then we need to go through and divide the number of available on the 9439d26e4fcSRobert Mustacchi * device, which was snapshotted before anyone should have allocated 9449d26e4fcSRobert Mustacchi * anything, and use that to derive how many are available from the 9459d26e4fcSRobert Mustacchi * pool. Longer term, we may want to turn this into something that's 9469d26e4fcSRobert Mustacchi * more of a pool-like resource that everything can share (though that 9479d26e4fcSRobert Mustacchi * may require some more assistance from MAC). 9489d26e4fcSRobert Mustacchi * 9499d26e4fcSRobert Mustacchi * Though for transmit and receive queue pairs, we just have to ask 9509d26e4fcSRobert Mustacchi * firmware instead. 9519d26e4fcSRobert Mustacchi */ 9529d26e4fcSRobert Mustacchi idp = i40e_device_find(i40e, parent, bus, device); 9539d26e4fcSRobert Mustacchi i40e->i40e_device = idp; 9549d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nvsis = 0; 9559d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nvsis_used = 0; 9569d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nmacfilt = 0; 9579d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nmacfilt_used = 0; 9589d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nmcastfilt = 0; 9599d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nmcastfilt_used = 0; 9609d26e4fcSRobert Mustacchi 9619d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_switch_rsrc_actual; i++) { 9629d26e4fcSRobert Mustacchi i40e_switch_rsrc_t *srp = &i40e->i40e_switch_rsrcs[i]; 9639d26e4fcSRobert Mustacchi 9649d26e4fcSRobert Mustacchi switch (srp->resource_type) { 9659d26e4fcSRobert Mustacchi case I40E_AQ_RESOURCE_TYPE_VSI: 9669d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nvsis += 9679d26e4fcSRobert Mustacchi LE_16(srp->guaranteed); 9689d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nvsis_used = LE_16(srp->used); 9699d26e4fcSRobert Mustacchi break; 9709d26e4fcSRobert Mustacchi case I40E_AQ_RESOURCE_TYPE_MACADDR: 9719d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nmacfilt += 9729d26e4fcSRobert Mustacchi LE_16(srp->guaranteed); 9739d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nmacfilt_used = 9749d26e4fcSRobert Mustacchi LE_16(srp->used); 9759d26e4fcSRobert Mustacchi break; 9769d26e4fcSRobert Mustacchi case I40E_AQ_RESOURCE_TYPE_MULTICAST_HASH: 9779d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nmcastfilt += 9789d26e4fcSRobert Mustacchi LE_16(srp->guaranteed); 9799d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nmcastfilt_used = 9809d26e4fcSRobert Mustacchi LE_16(srp->used); 9819d26e4fcSRobert Mustacchi break; 9829d26e4fcSRobert Mustacchi default: 9839d26e4fcSRobert Mustacchi break; 9849d26e4fcSRobert Mustacchi } 9859d26e4fcSRobert Mustacchi } 9869d26e4fcSRobert Mustacchi 9879d26e4fcSRobert Mustacchi for (i = 0; i < idp->id_rsrcs_act; i++) { 9889d26e4fcSRobert Mustacchi i40e_switch_rsrc_t *srp = &i40e->i40e_switch_rsrcs[i]; 9899d26e4fcSRobert Mustacchi switch (srp->resource_type) { 9909d26e4fcSRobert Mustacchi case I40E_AQ_RESOURCE_TYPE_VSI: 9919d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nvsis += 9929d26e4fcSRobert Mustacchi LE_16(srp->total_unalloced) / idp->id_nfuncs; 9939d26e4fcSRobert Mustacchi break; 9949d26e4fcSRobert Mustacchi case I40E_AQ_RESOURCE_TYPE_MACADDR: 9959d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nmacfilt += 9969d26e4fcSRobert Mustacchi LE_16(srp->total_unalloced) / idp->id_nfuncs; 9979d26e4fcSRobert Mustacchi break; 9989d26e4fcSRobert Mustacchi case I40E_AQ_RESOURCE_TYPE_MULTICAST_HASH: 9999d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nmcastfilt += 10009d26e4fcSRobert Mustacchi LE_16(srp->total_unalloced) / idp->id_nfuncs; 10019d26e4fcSRobert Mustacchi default: 10029d26e4fcSRobert Mustacchi break; 10039d26e4fcSRobert Mustacchi } 10049d26e4fcSRobert Mustacchi } 10059d26e4fcSRobert Mustacchi 10069d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nrx_queue = hw->func_caps.num_rx_qp; 10079d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_ntx_queue = hw->func_caps.num_tx_qp; 10089d26e4fcSRobert Mustacchi 10099d26e4fcSRobert Mustacchi i40e->i40e_uaddrs = kmem_zalloc(sizeof (i40e_uaddr_t) * 10109d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nmacfilt, KM_SLEEP); 10119d26e4fcSRobert Mustacchi i40e->i40e_maddrs = kmem_zalloc(sizeof (i40e_maddr_t) * 10129d26e4fcSRobert Mustacchi i40e->i40e_resources.ifr_nmcastfilt, KM_SLEEP); 10139d26e4fcSRobert Mustacchi 10149d26e4fcSRobert Mustacchi /* 10159d26e4fcSRobert Mustacchi * Initialize these as multicast addresses to indicate it's invalid for 10169d26e4fcSRobert Mustacchi * sanity purposes. Think of it like 0xdeadbeef. 10179d26e4fcSRobert Mustacchi */ 10189d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_resources.ifr_nmacfilt; i++) 10199d26e4fcSRobert Mustacchi i40e->i40e_uaddrs[i].iua_mac[0] = 0x01; 10209d26e4fcSRobert Mustacchi 10219d26e4fcSRobert Mustacchi return (B_TRUE); 10229d26e4fcSRobert Mustacchi } 10239d26e4fcSRobert Mustacchi 10249d26e4fcSRobert Mustacchi static boolean_t 10259d26e4fcSRobert Mustacchi i40e_enable_interrupts(i40e_t *i40e) 10269d26e4fcSRobert Mustacchi { 10279d26e4fcSRobert Mustacchi int i, rc; 10289d26e4fcSRobert Mustacchi 10299d26e4fcSRobert Mustacchi if (i40e->i40e_intr_cap & DDI_INTR_FLAG_BLOCK) { 10309d26e4fcSRobert Mustacchi rc = ddi_intr_block_enable(i40e->i40e_intr_handles, 10319d26e4fcSRobert Mustacchi i40e->i40e_intr_count); 10329d26e4fcSRobert Mustacchi if (rc != DDI_SUCCESS) { 10339d26e4fcSRobert Mustacchi i40e_error(i40e, "Interrupt block-enable failed: %d", 10349d26e4fcSRobert Mustacchi rc); 10359d26e4fcSRobert Mustacchi return (B_FALSE); 10369d26e4fcSRobert Mustacchi } 10379d26e4fcSRobert Mustacchi } else { 10389d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_intr_count; i++) { 10399d26e4fcSRobert Mustacchi rc = ddi_intr_enable(i40e->i40e_intr_handles[i]); 10409d26e4fcSRobert Mustacchi if (rc != DDI_SUCCESS) { 10419d26e4fcSRobert Mustacchi i40e_error(i40e, 10429d26e4fcSRobert Mustacchi "Failed to enable interrupt %d: %d", i, rc); 10439d26e4fcSRobert Mustacchi while (--i >= 0) { 10449d26e4fcSRobert Mustacchi (void) ddi_intr_disable( 10459d26e4fcSRobert Mustacchi i40e->i40e_intr_handles[i]); 10469d26e4fcSRobert Mustacchi } 10479d26e4fcSRobert Mustacchi return (B_FALSE); 10489d26e4fcSRobert Mustacchi } 10499d26e4fcSRobert Mustacchi } 10509d26e4fcSRobert Mustacchi } 10519d26e4fcSRobert Mustacchi 10529d26e4fcSRobert Mustacchi return (B_TRUE); 10539d26e4fcSRobert Mustacchi } 10549d26e4fcSRobert Mustacchi 10559d26e4fcSRobert Mustacchi static boolean_t 10569d26e4fcSRobert Mustacchi i40e_disable_interrupts(i40e_t *i40e) 10579d26e4fcSRobert Mustacchi { 10589d26e4fcSRobert Mustacchi int i, rc; 10599d26e4fcSRobert Mustacchi 10609d26e4fcSRobert Mustacchi if (i40e->i40e_intr_cap & DDI_INTR_FLAG_BLOCK) { 10619d26e4fcSRobert Mustacchi rc = ddi_intr_block_disable(i40e->i40e_intr_handles, 10629d26e4fcSRobert Mustacchi i40e->i40e_intr_count); 10639d26e4fcSRobert Mustacchi if (rc != DDI_SUCCESS) { 10649d26e4fcSRobert Mustacchi i40e_error(i40e, 10659d26e4fcSRobert Mustacchi "Interrupt block-disabled failed: %d", rc); 10669d26e4fcSRobert Mustacchi return (B_FALSE); 10679d26e4fcSRobert Mustacchi } 10689d26e4fcSRobert Mustacchi } else { 10699d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_intr_count; i++) { 10709d26e4fcSRobert Mustacchi rc = ddi_intr_disable(i40e->i40e_intr_handles[i]); 10719d26e4fcSRobert Mustacchi if (rc != DDI_SUCCESS) { 10729d26e4fcSRobert Mustacchi i40e_error(i40e, 10739d26e4fcSRobert Mustacchi "Failed to disable interrupt %d: %d", 10749d26e4fcSRobert Mustacchi i, rc); 10759d26e4fcSRobert Mustacchi return (B_FALSE); 10769d26e4fcSRobert Mustacchi } 10779d26e4fcSRobert Mustacchi } 10789d26e4fcSRobert Mustacchi } 10799d26e4fcSRobert Mustacchi 10809d26e4fcSRobert Mustacchi return (B_TRUE); 10819d26e4fcSRobert Mustacchi } 10829d26e4fcSRobert Mustacchi 10839d26e4fcSRobert Mustacchi /* 10849d26e4fcSRobert Mustacchi * Free receive & transmit rings. 10859d26e4fcSRobert Mustacchi */ 10869d26e4fcSRobert Mustacchi static void 10879d26e4fcSRobert Mustacchi i40e_free_trqpairs(i40e_t *i40e) 10889d26e4fcSRobert Mustacchi { 10899d26e4fcSRobert Mustacchi int i; 10909d26e4fcSRobert Mustacchi i40e_trqpair_t *itrq; 10919d26e4fcSRobert Mustacchi 10929d26e4fcSRobert Mustacchi if (i40e->i40e_trqpairs != NULL) { 10939d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 10949d26e4fcSRobert Mustacchi itrq = &i40e->i40e_trqpairs[i]; 10959d26e4fcSRobert Mustacchi mutex_destroy(&itrq->itrq_rx_lock); 10969d26e4fcSRobert Mustacchi mutex_destroy(&itrq->itrq_tx_lock); 10979d26e4fcSRobert Mustacchi mutex_destroy(&itrq->itrq_tcb_lock); 10989d26e4fcSRobert Mustacchi 10999d26e4fcSRobert Mustacchi /* 11009d26e4fcSRobert Mustacchi * Should have already been cleaned up by start/stop, 11019d26e4fcSRobert Mustacchi * etc. 11029d26e4fcSRobert Mustacchi */ 11039d26e4fcSRobert Mustacchi ASSERT(itrq->itrq_txkstat == NULL); 11049d26e4fcSRobert Mustacchi ASSERT(itrq->itrq_rxkstat == NULL); 11059d26e4fcSRobert Mustacchi } 11069d26e4fcSRobert Mustacchi 11079d26e4fcSRobert Mustacchi kmem_free(i40e->i40e_trqpairs, 11089d26e4fcSRobert Mustacchi sizeof (i40e_trqpair_t) * i40e->i40e_num_trqpairs); 11099d26e4fcSRobert Mustacchi i40e->i40e_trqpairs = NULL; 11109d26e4fcSRobert Mustacchi } 11119d26e4fcSRobert Mustacchi 11129d26e4fcSRobert Mustacchi cv_destroy(&i40e->i40e_rx_pending_cv); 11139d26e4fcSRobert Mustacchi mutex_destroy(&i40e->i40e_rx_pending_lock); 11149d26e4fcSRobert Mustacchi mutex_destroy(&i40e->i40e_general_lock); 11159d26e4fcSRobert Mustacchi } 11169d26e4fcSRobert Mustacchi 11179d26e4fcSRobert Mustacchi /* 11189d26e4fcSRobert Mustacchi * Allocate transmit and receive rings, as well as other data structures that we 11199d26e4fcSRobert Mustacchi * need. 11209d26e4fcSRobert Mustacchi */ 11219d26e4fcSRobert Mustacchi static boolean_t 11229d26e4fcSRobert Mustacchi i40e_alloc_trqpairs(i40e_t *i40e) 11239d26e4fcSRobert Mustacchi { 11249d26e4fcSRobert Mustacchi int i; 11259d26e4fcSRobert Mustacchi void *mutexpri = DDI_INTR_PRI(i40e->i40e_intr_pri); 11269d26e4fcSRobert Mustacchi 11279d26e4fcSRobert Mustacchi /* 11289d26e4fcSRobert Mustacchi * Now that we have the priority for the interrupts, initialize 11299d26e4fcSRobert Mustacchi * all relevant locks. 11309d26e4fcSRobert Mustacchi */ 11319d26e4fcSRobert Mustacchi mutex_init(&i40e->i40e_general_lock, NULL, MUTEX_DRIVER, mutexpri); 11329d26e4fcSRobert Mustacchi mutex_init(&i40e->i40e_rx_pending_lock, NULL, MUTEX_DRIVER, mutexpri); 11339d26e4fcSRobert Mustacchi cv_init(&i40e->i40e_rx_pending_cv, NULL, CV_DRIVER, NULL); 11349d26e4fcSRobert Mustacchi 11359d26e4fcSRobert Mustacchi i40e->i40e_trqpairs = kmem_zalloc(sizeof (i40e_trqpair_t) * 11369d26e4fcSRobert Mustacchi i40e->i40e_num_trqpairs, KM_SLEEP); 11379d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 11389d26e4fcSRobert Mustacchi i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[i]; 11399d26e4fcSRobert Mustacchi 11409d26e4fcSRobert Mustacchi itrq->itrq_i40e = i40e; 11419d26e4fcSRobert Mustacchi mutex_init(&itrq->itrq_rx_lock, NULL, MUTEX_DRIVER, mutexpri); 11429d26e4fcSRobert Mustacchi mutex_init(&itrq->itrq_tx_lock, NULL, MUTEX_DRIVER, mutexpri); 11439d26e4fcSRobert Mustacchi mutex_init(&itrq->itrq_tcb_lock, NULL, MUTEX_DRIVER, mutexpri); 11449d26e4fcSRobert Mustacchi itrq->itrq_index = i; 11459d26e4fcSRobert Mustacchi } 11469d26e4fcSRobert Mustacchi 11479d26e4fcSRobert Mustacchi return (B_TRUE); 11489d26e4fcSRobert Mustacchi } 11499d26e4fcSRobert Mustacchi 11509d26e4fcSRobert Mustacchi 11519d26e4fcSRobert Mustacchi 11529d26e4fcSRobert Mustacchi /* 11539d26e4fcSRobert Mustacchi * Unless a .conf file already overrode i40e_t structure values, they will 11549d26e4fcSRobert Mustacchi * be 0, and need to be set in conjunction with the now-available HW report. 11559d26e4fcSRobert Mustacchi * 11569d26e4fcSRobert Mustacchi * However, at the moment, we cap all of these resources as we only support a 11579d26e4fcSRobert Mustacchi * single receive ring and a single group. 11589d26e4fcSRobert Mustacchi */ 11599d26e4fcSRobert Mustacchi /* ARGSUSED */ 11609d26e4fcSRobert Mustacchi static void 11619d26e4fcSRobert Mustacchi i40e_hw_to_instance(i40e_t *i40e, i40e_hw_t *hw) 11629d26e4fcSRobert Mustacchi { 11639d26e4fcSRobert Mustacchi if (i40e->i40e_num_trqpairs == 0) { 11649d26e4fcSRobert Mustacchi i40e->i40e_num_trqpairs = I40E_TRQPAIR_MAX; 11659d26e4fcSRobert Mustacchi } 11669d26e4fcSRobert Mustacchi 11679d26e4fcSRobert Mustacchi if (i40e->i40e_num_rx_groups == 0) { 11689d26e4fcSRobert Mustacchi i40e->i40e_num_rx_groups = I40E_GROUP_MAX; 11699d26e4fcSRobert Mustacchi } 11709d26e4fcSRobert Mustacchi } 11719d26e4fcSRobert Mustacchi 11729d26e4fcSRobert Mustacchi /* 11739d26e4fcSRobert Mustacchi * Free any resources required by, or setup by, the Intel common code. 11749d26e4fcSRobert Mustacchi */ 11759d26e4fcSRobert Mustacchi static void 11769d26e4fcSRobert Mustacchi i40e_common_code_fini(i40e_t *i40e) 11779d26e4fcSRobert Mustacchi { 11789d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 11799d26e4fcSRobert Mustacchi int rc; 11809d26e4fcSRobert Mustacchi 11819d26e4fcSRobert Mustacchi rc = i40e_shutdown_lan_hmc(hw); 11829d26e4fcSRobert Mustacchi if (rc != I40E_SUCCESS) 11839d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to shutdown LAN hmc: %d", rc); 11849d26e4fcSRobert Mustacchi 11859d26e4fcSRobert Mustacchi rc = i40e_shutdown_adminq(hw); 11869d26e4fcSRobert Mustacchi if (rc != I40E_SUCCESS) 11879d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to shutdown admin queue: %d", rc); 11889d26e4fcSRobert Mustacchi } 11899d26e4fcSRobert Mustacchi 11909d26e4fcSRobert Mustacchi /* 11919d26e4fcSRobert Mustacchi * Initialize and call Intel common-code routines, includes some setup 11929d26e4fcSRobert Mustacchi * the common code expects from the driver. Also prints on failure, so 11939d26e4fcSRobert Mustacchi * the caller doesn't have to. 11949d26e4fcSRobert Mustacchi */ 11959d26e4fcSRobert Mustacchi static boolean_t 11969d26e4fcSRobert Mustacchi i40e_common_code_init(i40e_t *i40e, i40e_hw_t *hw) 11979d26e4fcSRobert Mustacchi { 11989d26e4fcSRobert Mustacchi int rc; 11999d26e4fcSRobert Mustacchi 12009d26e4fcSRobert Mustacchi i40e_clear_hw(hw); 12019d26e4fcSRobert Mustacchi rc = i40e_pf_reset(hw); 12029d26e4fcSRobert Mustacchi if (rc != 0) { 12039d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to reset hardware: %d", rc); 12049d26e4fcSRobert Mustacchi i40e_fm_ereport(i40e, DDI_FM_DEVICE_NO_RESPONSE); 12059d26e4fcSRobert Mustacchi return (B_FALSE); 12069d26e4fcSRobert Mustacchi } 12079d26e4fcSRobert Mustacchi 12089d26e4fcSRobert Mustacchi rc = i40e_init_shared_code(hw); 12099d26e4fcSRobert Mustacchi if (rc != 0) { 12109d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to initialize i40e core: %d", rc); 12119d26e4fcSRobert Mustacchi return (B_FALSE); 12129d26e4fcSRobert Mustacchi } 12139d26e4fcSRobert Mustacchi 12149d26e4fcSRobert Mustacchi hw->aq.num_arq_entries = I40E_DEF_ADMINQ_SIZE; 12159d26e4fcSRobert Mustacchi hw->aq.num_asq_entries = I40E_DEF_ADMINQ_SIZE; 12169d26e4fcSRobert Mustacchi hw->aq.arq_buf_size = I40E_ADMINQ_BUFSZ; 12179d26e4fcSRobert Mustacchi hw->aq.asq_buf_size = I40E_ADMINQ_BUFSZ; 12189d26e4fcSRobert Mustacchi 12199d26e4fcSRobert Mustacchi rc = i40e_init_adminq(hw); 12209d26e4fcSRobert Mustacchi if (rc != 0) { 12219d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to initialize firmware admin queue: " 12229d26e4fcSRobert Mustacchi "%d, potential firmware version mismatch", rc); 12239d26e4fcSRobert Mustacchi i40e_fm_ereport(i40e, DDI_FM_DEVICE_INVAL_STATE); 12249d26e4fcSRobert Mustacchi return (B_FALSE); 12259d26e4fcSRobert Mustacchi } 12269d26e4fcSRobert Mustacchi 12279d26e4fcSRobert Mustacchi if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && 12289d26e4fcSRobert Mustacchi hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR) { 1229*3d75a287SRobert Mustacchi i40e_log(i40e, "The driver for the device detected a newer " 12309d26e4fcSRobert Mustacchi "version of the NVM image (%d.%d) than expected (%d.%d).\n" 12319d26e4fcSRobert Mustacchi "Please install the most recent version of the network " 12329d26e4fcSRobert Mustacchi "driver.\n", hw->aq.api_maj_ver, hw->aq.api_min_ver, 12339d26e4fcSRobert Mustacchi I40E_FW_API_VERSION_MAJOR, I40E_FW_API_VERSION_MINOR); 12349d26e4fcSRobert Mustacchi } else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR || 12359d26e4fcSRobert Mustacchi hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1)) { 1236*3d75a287SRobert Mustacchi i40e_log(i40e, "The driver for the device detected an older" 12379d26e4fcSRobert Mustacchi " version of the NVM image (%d.%d) than expected (%d.%d)." 12389d26e4fcSRobert Mustacchi "\nPlease update the NVM image.\n", 12399d26e4fcSRobert Mustacchi hw->aq.api_maj_ver, hw->aq.api_min_ver, 12409d26e4fcSRobert Mustacchi I40E_FW_API_VERSION_MAJOR, I40E_FW_API_VERSION_MINOR - 1); 12419d26e4fcSRobert Mustacchi } 12429d26e4fcSRobert Mustacchi 12439d26e4fcSRobert Mustacchi i40e_clear_pxe_mode(hw); 12449d26e4fcSRobert Mustacchi 12459d26e4fcSRobert Mustacchi /* 12469d26e4fcSRobert Mustacchi * We need to call this so that the common code can discover 12479d26e4fcSRobert Mustacchi * capabilities of the hardware, which it uses throughout the rest. 12489d26e4fcSRobert Mustacchi */ 12499d26e4fcSRobert Mustacchi if (!i40e_get_hw_capabilities(i40e, hw)) { 12509d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to obtain hardware capabilities"); 12519d26e4fcSRobert Mustacchi return (B_FALSE); 12529d26e4fcSRobert Mustacchi } 12539d26e4fcSRobert Mustacchi 12549d26e4fcSRobert Mustacchi if (i40e_get_available_resources(i40e) == B_FALSE) { 12559d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to obtain hardware resources"); 12569d26e4fcSRobert Mustacchi return (B_FALSE); 12579d26e4fcSRobert Mustacchi } 12589d26e4fcSRobert Mustacchi 12599d26e4fcSRobert Mustacchi i40e_hw_to_instance(i40e, hw); 12609d26e4fcSRobert Mustacchi 12619d26e4fcSRobert Mustacchi rc = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, 12629d26e4fcSRobert Mustacchi hw->func_caps.num_rx_qp, 0, 0); 12639d26e4fcSRobert Mustacchi if (rc != 0) { 12649d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to initialize hardware memory cache: " 12659d26e4fcSRobert Mustacchi "%d", rc); 12669d26e4fcSRobert Mustacchi return (B_FALSE); 12679d26e4fcSRobert Mustacchi } 12689d26e4fcSRobert Mustacchi 12699d26e4fcSRobert Mustacchi rc = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 12709d26e4fcSRobert Mustacchi if (rc != 0) { 12719d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to configure hardware memory cache: " 12729d26e4fcSRobert Mustacchi "%d", rc); 12739d26e4fcSRobert Mustacchi return (B_FALSE); 12749d26e4fcSRobert Mustacchi } 12759d26e4fcSRobert Mustacchi 12769d26e4fcSRobert Mustacchi (void) i40e_aq_stop_lldp(hw, TRUE, NULL); 12779d26e4fcSRobert Mustacchi 12789d26e4fcSRobert Mustacchi rc = i40e_get_mac_addr(hw, hw->mac.addr); 12799d26e4fcSRobert Mustacchi if (rc != I40E_SUCCESS) { 12809d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to retrieve hardware mac address: %d", 12819d26e4fcSRobert Mustacchi rc); 12829d26e4fcSRobert Mustacchi return (B_FALSE); 12839d26e4fcSRobert Mustacchi } 12849d26e4fcSRobert Mustacchi 12859d26e4fcSRobert Mustacchi rc = i40e_validate_mac_addr(hw->mac.addr); 12869d26e4fcSRobert Mustacchi if (rc != 0) { 12879d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to validate internal mac address: " 12889d26e4fcSRobert Mustacchi "%d", rc); 12899d26e4fcSRobert Mustacchi return (B_FALSE); 12909d26e4fcSRobert Mustacchi } 12919d26e4fcSRobert Mustacchi bcopy(hw->mac.addr, hw->mac.perm_addr, ETHERADDRL); 12929d26e4fcSRobert Mustacchi if ((rc = i40e_get_port_mac_addr(hw, hw->mac.port_addr)) != 12939d26e4fcSRobert Mustacchi I40E_SUCCESS) { 12949d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to retrieve port mac address: %d", 12959d26e4fcSRobert Mustacchi rc); 12969d26e4fcSRobert Mustacchi return (B_FALSE); 12979d26e4fcSRobert Mustacchi } 12989d26e4fcSRobert Mustacchi 12999d26e4fcSRobert Mustacchi /* 13009d26e4fcSRobert Mustacchi * We need to obtain the Virtual Station ID (VSI) before we can 13019d26e4fcSRobert Mustacchi * perform other operations on the device. 13029d26e4fcSRobert Mustacchi */ 13039d26e4fcSRobert Mustacchi i40e->i40e_vsi_id = i40e_get_vsi_id(i40e); 13049d26e4fcSRobert Mustacchi if (i40e->i40e_vsi_id == -1) { 13059d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to obtain VSI ID"); 13069d26e4fcSRobert Mustacchi return (B_FALSE); 13079d26e4fcSRobert Mustacchi } 13089d26e4fcSRobert Mustacchi 13099d26e4fcSRobert Mustacchi return (B_TRUE); 13109d26e4fcSRobert Mustacchi } 13119d26e4fcSRobert Mustacchi 13129d26e4fcSRobert Mustacchi static void 13139d26e4fcSRobert Mustacchi i40e_unconfigure(dev_info_t *devinfo, i40e_t *i40e) 13149d26e4fcSRobert Mustacchi { 13159d26e4fcSRobert Mustacchi int rc; 13169d26e4fcSRobert Mustacchi 13179d26e4fcSRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_ENABLE_INTR) 13189d26e4fcSRobert Mustacchi (void) i40e_disable_interrupts(i40e); 13199d26e4fcSRobert Mustacchi 13209d26e4fcSRobert Mustacchi if ((i40e->i40e_attach_progress & I40E_ATTACH_LINK_TIMER) && 13219d26e4fcSRobert Mustacchi i40e->i40e_periodic_id != 0) { 13229d26e4fcSRobert Mustacchi ddi_periodic_delete(i40e->i40e_periodic_id); 13239d26e4fcSRobert Mustacchi i40e->i40e_periodic_id = 0; 13249d26e4fcSRobert Mustacchi } 13259d26e4fcSRobert Mustacchi 13269d26e4fcSRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_MAC) { 13279d26e4fcSRobert Mustacchi rc = mac_unregister(i40e->i40e_mac_hdl); 13289d26e4fcSRobert Mustacchi if (rc != 0) { 13299d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to unregister from mac: %d", 13309d26e4fcSRobert Mustacchi rc); 13319d26e4fcSRobert Mustacchi } 13329d26e4fcSRobert Mustacchi } 13339d26e4fcSRobert Mustacchi 13349d26e4fcSRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_STATS) { 13359d26e4fcSRobert Mustacchi i40e_stats_fini(i40e); 13369d26e4fcSRobert Mustacchi } 13379d26e4fcSRobert Mustacchi 13389d26e4fcSRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_ADD_INTR) 13399d26e4fcSRobert Mustacchi i40e_rem_intr_handlers(i40e); 13409d26e4fcSRobert Mustacchi 13419d26e4fcSRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_ALLOC_RINGSLOCKS) 13429d26e4fcSRobert Mustacchi i40e_free_trqpairs(i40e); 13439d26e4fcSRobert Mustacchi 13449d26e4fcSRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_ALLOC_INTR) 13459d26e4fcSRobert Mustacchi i40e_rem_intrs(i40e); 13469d26e4fcSRobert Mustacchi 13479d26e4fcSRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_COMMON_CODE) 13489d26e4fcSRobert Mustacchi i40e_common_code_fini(i40e); 13499d26e4fcSRobert Mustacchi 13509d26e4fcSRobert Mustacchi i40e_cleanup_resources(i40e); 13519d26e4fcSRobert Mustacchi 13529d26e4fcSRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_PROPS) 13539d26e4fcSRobert Mustacchi (void) ddi_prop_remove_all(devinfo); 13549d26e4fcSRobert Mustacchi 13559d26e4fcSRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_REGS_MAP && 13569d26e4fcSRobert Mustacchi i40e->i40e_osdep_space.ios_reg_handle != NULL) { 13579d26e4fcSRobert Mustacchi ddi_regs_map_free(&i40e->i40e_osdep_space.ios_reg_handle); 13589d26e4fcSRobert Mustacchi i40e->i40e_osdep_space.ios_reg_handle = NULL; 13599d26e4fcSRobert Mustacchi } 13609d26e4fcSRobert Mustacchi 13619d26e4fcSRobert Mustacchi if ((i40e->i40e_attach_progress & I40E_ATTACH_PCI_CONFIG) && 13629d26e4fcSRobert Mustacchi i40e->i40e_osdep_space.ios_cfg_handle != NULL) { 13639d26e4fcSRobert Mustacchi pci_config_teardown(&i40e->i40e_osdep_space.ios_cfg_handle); 13649d26e4fcSRobert Mustacchi i40e->i40e_osdep_space.ios_cfg_handle = NULL; 13659d26e4fcSRobert Mustacchi } 13669d26e4fcSRobert Mustacchi 13679d26e4fcSRobert Mustacchi if (i40e->i40e_attach_progress & I40E_ATTACH_FM_INIT) 13689d26e4fcSRobert Mustacchi i40e_fm_fini(i40e); 13699d26e4fcSRobert Mustacchi 13709d26e4fcSRobert Mustacchi kmem_free(i40e->i40e_aqbuf, I40E_ADMINQ_BUFSZ); 13719d26e4fcSRobert Mustacchi kmem_free(i40e, sizeof (i40e_t)); 13729d26e4fcSRobert Mustacchi 13739d26e4fcSRobert Mustacchi ddi_set_driver_private(devinfo, NULL); 13749d26e4fcSRobert Mustacchi } 13759d26e4fcSRobert Mustacchi 13769d26e4fcSRobert Mustacchi static boolean_t 13779d26e4fcSRobert Mustacchi i40e_final_init(i40e_t *i40e) 13789d26e4fcSRobert Mustacchi { 13799d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 13809d26e4fcSRobert Mustacchi struct i40e_osdep *osdep = OS_DEP(hw); 13819d26e4fcSRobert Mustacchi uint8_t pbanum[I40E_PBANUM_STRLEN]; 13829d26e4fcSRobert Mustacchi enum i40e_status_code irc; 13839d26e4fcSRobert Mustacchi char buf[I40E_DDI_PROP_LEN]; 13849d26e4fcSRobert Mustacchi 13859d26e4fcSRobert Mustacchi pbanum[0] = '\0'; 13869d26e4fcSRobert Mustacchi irc = i40e_read_pba_string(hw, pbanum, sizeof (pbanum)); 13879d26e4fcSRobert Mustacchi if (irc != I40E_SUCCESS) { 13889d26e4fcSRobert Mustacchi i40e_log(i40e, "failed to read PBA string: %d", irc); 13899d26e4fcSRobert Mustacchi } else { 13909d26e4fcSRobert Mustacchi (void) ddi_prop_update_string(DDI_DEV_T_NONE, i40e->i40e_dip, 13919d26e4fcSRobert Mustacchi "printed-board-assembly", (char *)pbanum); 13929d26e4fcSRobert Mustacchi } 13939d26e4fcSRobert Mustacchi 13949d26e4fcSRobert Mustacchi #ifdef DEBUG 13959d26e4fcSRobert Mustacchi ASSERT(snprintf(NULL, 0, "%d.%d", hw->aq.fw_maj_ver, 13969d26e4fcSRobert Mustacchi hw->aq.fw_min_ver) < sizeof (buf)); 13979d26e4fcSRobert Mustacchi ASSERT(snprintf(NULL, 0, "%x", hw->aq.fw_build) < sizeof (buf)); 13989d26e4fcSRobert Mustacchi ASSERT(snprintf(NULL, 0, "%d.%d", hw->aq.api_maj_ver, 13999d26e4fcSRobert Mustacchi hw->aq.api_min_ver) < sizeof (buf)); 14009d26e4fcSRobert Mustacchi #endif 14019d26e4fcSRobert Mustacchi 14029d26e4fcSRobert Mustacchi (void) snprintf(buf, sizeof (buf), "%d.%d", hw->aq.fw_maj_ver, 14039d26e4fcSRobert Mustacchi hw->aq.fw_min_ver); 14049d26e4fcSRobert Mustacchi (void) ddi_prop_update_string(DDI_DEV_T_NONE, i40e->i40e_dip, 14059d26e4fcSRobert Mustacchi "firmware-version", buf); 14069d26e4fcSRobert Mustacchi (void) snprintf(buf, sizeof (buf), "%x", hw->aq.fw_build); 14079d26e4fcSRobert Mustacchi (void) ddi_prop_update_string(DDI_DEV_T_NONE, i40e->i40e_dip, 14089d26e4fcSRobert Mustacchi "firmware-build", buf); 14099d26e4fcSRobert Mustacchi (void) snprintf(buf, sizeof (buf), "%d.%d", hw->aq.api_maj_ver, 14109d26e4fcSRobert Mustacchi hw->aq.api_min_ver); 14119d26e4fcSRobert Mustacchi (void) ddi_prop_update_string(DDI_DEV_T_NONE, i40e->i40e_dip, 14129d26e4fcSRobert Mustacchi "api-version", buf); 14139d26e4fcSRobert Mustacchi 14149d26e4fcSRobert Mustacchi if (!i40e_set_hw_bus_info(hw)) 14159d26e4fcSRobert Mustacchi return (B_FALSE); 14169d26e4fcSRobert Mustacchi 14179d26e4fcSRobert Mustacchi if (i40e_check_acc_handle(osdep->ios_reg_handle) != DDI_FM_OK) { 14189d26e4fcSRobert Mustacchi ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST); 14199d26e4fcSRobert Mustacchi return (B_FALSE); 14209d26e4fcSRobert Mustacchi } 14219d26e4fcSRobert Mustacchi 14229d26e4fcSRobert Mustacchi return (B_TRUE); 14239d26e4fcSRobert Mustacchi } 14249d26e4fcSRobert Mustacchi 1425*3d75a287SRobert Mustacchi static void 14269d26e4fcSRobert Mustacchi i40e_identify_hardware(i40e_t *i40e) 14279d26e4fcSRobert Mustacchi { 14289d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 14299d26e4fcSRobert Mustacchi struct i40e_osdep *osdep = &i40e->i40e_osdep_space; 14309d26e4fcSRobert Mustacchi 14319d26e4fcSRobert Mustacchi hw->vendor_id = pci_config_get16(osdep->ios_cfg_handle, PCI_CONF_VENID); 14329d26e4fcSRobert Mustacchi hw->device_id = pci_config_get16(osdep->ios_cfg_handle, PCI_CONF_DEVID); 14339d26e4fcSRobert Mustacchi hw->revision_id = pci_config_get8(osdep->ios_cfg_handle, 14349d26e4fcSRobert Mustacchi PCI_CONF_REVID); 14359d26e4fcSRobert Mustacchi hw->subsystem_device_id = 14369d26e4fcSRobert Mustacchi pci_config_get16(osdep->ios_cfg_handle, PCI_CONF_SUBSYSID); 14379d26e4fcSRobert Mustacchi hw->subsystem_vendor_id = 14389d26e4fcSRobert Mustacchi pci_config_get16(osdep->ios_cfg_handle, PCI_CONF_SUBVENID); 14399d26e4fcSRobert Mustacchi 14409d26e4fcSRobert Mustacchi /* 14419d26e4fcSRobert Mustacchi * Note that we set the hardware's bus information later on, in 14429d26e4fcSRobert Mustacchi * i40e_get_available_resources(). The common code doesn't seem to 14439d26e4fcSRobert Mustacchi * require that it be set in any ways, it seems to be mostly for 14449d26e4fcSRobert Mustacchi * book-keeping. 14459d26e4fcSRobert Mustacchi */ 14469d26e4fcSRobert Mustacchi } 14479d26e4fcSRobert Mustacchi 14489d26e4fcSRobert Mustacchi static boolean_t 14499d26e4fcSRobert Mustacchi i40e_regs_map(i40e_t *i40e) 14509d26e4fcSRobert Mustacchi { 14519d26e4fcSRobert Mustacchi dev_info_t *devinfo = i40e->i40e_dip; 14529d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 14539d26e4fcSRobert Mustacchi struct i40e_osdep *osdep = &i40e->i40e_osdep_space; 14549d26e4fcSRobert Mustacchi off_t memsize; 14559d26e4fcSRobert Mustacchi int ret; 14569d26e4fcSRobert Mustacchi 14579d26e4fcSRobert Mustacchi if (ddi_dev_regsize(devinfo, I40E_ADAPTER_REGSET, &memsize) != 14589d26e4fcSRobert Mustacchi DDI_SUCCESS) { 14599d26e4fcSRobert Mustacchi i40e_error(i40e, "Used invalid register set to map PCIe regs"); 14609d26e4fcSRobert Mustacchi return (B_FALSE); 14619d26e4fcSRobert Mustacchi } 14629d26e4fcSRobert Mustacchi 14639d26e4fcSRobert Mustacchi if ((ret = ddi_regs_map_setup(devinfo, I40E_ADAPTER_REGSET, 14649d26e4fcSRobert Mustacchi (caddr_t *)&hw->hw_addr, 0, memsize, &i40e_regs_acc_attr, 14659d26e4fcSRobert Mustacchi &osdep->ios_reg_handle)) != DDI_SUCCESS) { 14669d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to map device registers: %d", ret); 14679d26e4fcSRobert Mustacchi return (B_FALSE); 14689d26e4fcSRobert Mustacchi } 14699d26e4fcSRobert Mustacchi 14709d26e4fcSRobert Mustacchi osdep->ios_reg_size = memsize; 14719d26e4fcSRobert Mustacchi return (B_TRUE); 14729d26e4fcSRobert Mustacchi } 14739d26e4fcSRobert Mustacchi 14749d26e4fcSRobert Mustacchi /* 14759d26e4fcSRobert Mustacchi * Update parameters required when a new MTU has been configured. Calculate the 14769d26e4fcSRobert Mustacchi * maximum frame size, as well as, size our DMA buffers which we size in 14779d26e4fcSRobert Mustacchi * increments of 1K. 14789d26e4fcSRobert Mustacchi */ 14799d26e4fcSRobert Mustacchi void 14809d26e4fcSRobert Mustacchi i40e_update_mtu(i40e_t *i40e) 14819d26e4fcSRobert Mustacchi { 14829d26e4fcSRobert Mustacchi uint32_t rx, tx; 14839d26e4fcSRobert Mustacchi 14849d26e4fcSRobert Mustacchi i40e->i40e_frame_max = i40e->i40e_sdu + 14859d26e4fcSRobert Mustacchi sizeof (struct ether_vlan_header) + ETHERFCSL; 14869d26e4fcSRobert Mustacchi 14879d26e4fcSRobert Mustacchi rx = i40e->i40e_frame_max + I40E_BUF_IPHDR_ALIGNMENT; 14889d26e4fcSRobert Mustacchi i40e->i40e_rx_buf_size = ((rx >> 10) + 14899d26e4fcSRobert Mustacchi ((rx & (((uint32_t)1 << 10) -1)) > 0 ? 1 : 0)) << 10; 14909d26e4fcSRobert Mustacchi 14919d26e4fcSRobert Mustacchi tx = i40e->i40e_frame_max; 14929d26e4fcSRobert Mustacchi i40e->i40e_tx_buf_size = ((tx >> 10) + 14939d26e4fcSRobert Mustacchi ((tx & (((uint32_t)1 << 10) -1)) > 0 ? 1 : 0)) << 10; 14949d26e4fcSRobert Mustacchi } 14959d26e4fcSRobert Mustacchi 14969d26e4fcSRobert Mustacchi static int 14979d26e4fcSRobert Mustacchi i40e_get_prop(i40e_t *i40e, char *prop, int min, int max, int def) 14989d26e4fcSRobert Mustacchi { 14999d26e4fcSRobert Mustacchi int val; 15009d26e4fcSRobert Mustacchi 15019d26e4fcSRobert Mustacchi val = ddi_prop_get_int(DDI_DEV_T_ANY, i40e->i40e_dip, DDI_PROP_DONTPASS, 15029d26e4fcSRobert Mustacchi prop, def); 15039d26e4fcSRobert Mustacchi if (val > max) 15049d26e4fcSRobert Mustacchi val = max; 15059d26e4fcSRobert Mustacchi if (val < min) 15069d26e4fcSRobert Mustacchi val = min; 15079d26e4fcSRobert Mustacchi return (val); 15089d26e4fcSRobert Mustacchi } 15099d26e4fcSRobert Mustacchi 15109d26e4fcSRobert Mustacchi static void 15119d26e4fcSRobert Mustacchi i40e_init_properties(i40e_t *i40e) 15129d26e4fcSRobert Mustacchi { 15139d26e4fcSRobert Mustacchi i40e->i40e_sdu = i40e_get_prop(i40e, "default_mtu", 15149d26e4fcSRobert Mustacchi I40E_MIN_MTU, I40E_MAX_MTU, I40E_DEF_MTU); 15159d26e4fcSRobert Mustacchi 15169d26e4fcSRobert Mustacchi i40e->i40e_intr_force = i40e_get_prop(i40e, "intr_force", 15179d26e4fcSRobert Mustacchi I40E_INTR_NONE, I40E_INTR_LEGACY, I40E_INTR_NONE); 15189d26e4fcSRobert Mustacchi 15199d26e4fcSRobert Mustacchi i40e->i40e_mr_enable = i40e_get_prop(i40e, "mr_enable", 15209d26e4fcSRobert Mustacchi B_FALSE, B_TRUE, B_TRUE); 15219d26e4fcSRobert Mustacchi 15229d26e4fcSRobert Mustacchi i40e->i40e_tx_ring_size = i40e_get_prop(i40e, "tx_ring_size", 15239d26e4fcSRobert Mustacchi I40E_MIN_TX_RING_SIZE, I40E_MAX_TX_RING_SIZE, 15249d26e4fcSRobert Mustacchi I40E_DEF_TX_RING_SIZE); 15259d26e4fcSRobert Mustacchi if ((i40e->i40e_tx_ring_size % I40E_DESC_ALIGN) != 0) { 15269d26e4fcSRobert Mustacchi i40e->i40e_tx_ring_size = P2ROUNDUP(i40e->i40e_tx_ring_size, 15279d26e4fcSRobert Mustacchi I40E_DESC_ALIGN); 15289d26e4fcSRobert Mustacchi } 15299d26e4fcSRobert Mustacchi 15309d26e4fcSRobert Mustacchi i40e->i40e_tx_block_thresh = i40e_get_prop(i40e, "tx_resched_threshold", 15319d26e4fcSRobert Mustacchi I40E_MIN_TX_BLOCK_THRESH, 15329d26e4fcSRobert Mustacchi i40e->i40e_tx_ring_size - I40E_TX_MAX_COOKIE, 15339d26e4fcSRobert Mustacchi I40E_DEF_TX_BLOCK_THRESH); 15349d26e4fcSRobert Mustacchi 15359d26e4fcSRobert Mustacchi i40e->i40e_rx_ring_size = i40e_get_prop(i40e, "rx_ring_size", 15369d26e4fcSRobert Mustacchi I40E_MIN_RX_RING_SIZE, I40E_MAX_RX_RING_SIZE, 15379d26e4fcSRobert Mustacchi I40E_DEF_RX_RING_SIZE); 15389d26e4fcSRobert Mustacchi if ((i40e->i40e_rx_ring_size % I40E_DESC_ALIGN) != 0) { 15399d26e4fcSRobert Mustacchi i40e->i40e_rx_ring_size = P2ROUNDUP(i40e->i40e_rx_ring_size, 15409d26e4fcSRobert Mustacchi I40E_DESC_ALIGN); 15419d26e4fcSRobert Mustacchi } 15429d26e4fcSRobert Mustacchi 15439d26e4fcSRobert Mustacchi i40e->i40e_rx_limit_per_intr = i40e_get_prop(i40e, "rx_limit_per_intr", 15449d26e4fcSRobert Mustacchi I40E_MIN_RX_LIMIT_PER_INTR, I40E_MAX_RX_LIMIT_PER_INTR, 15459d26e4fcSRobert Mustacchi I40E_DEF_RX_LIMIT_PER_INTR); 15469d26e4fcSRobert Mustacchi 15479d26e4fcSRobert Mustacchi i40e->i40e_tx_hcksum_enable = i40e_get_prop(i40e, "tx_hcksum_enable", 15489d26e4fcSRobert Mustacchi B_FALSE, B_TRUE, B_TRUE); 15499d26e4fcSRobert Mustacchi 15509d26e4fcSRobert Mustacchi i40e->i40e_rx_hcksum_enable = i40e_get_prop(i40e, "rx_hcksum_enable", 15519d26e4fcSRobert Mustacchi B_FALSE, B_TRUE, B_TRUE); 15529d26e4fcSRobert Mustacchi 15539d26e4fcSRobert Mustacchi i40e->i40e_rx_dma_min = i40e_get_prop(i40e, "rx_dma_threshold", 15549d26e4fcSRobert Mustacchi I40E_MIN_RX_DMA_THRESH, I40E_MAX_RX_DMA_THRESH, 15559d26e4fcSRobert Mustacchi I40E_DEF_RX_DMA_THRESH); 15569d26e4fcSRobert Mustacchi 15579d26e4fcSRobert Mustacchi i40e->i40e_tx_dma_min = i40e_get_prop(i40e, "tx_dma_threshold", 15589d26e4fcSRobert Mustacchi I40E_MIN_TX_DMA_THRESH, I40E_MAX_TX_DMA_THRESH, 15599d26e4fcSRobert Mustacchi I40E_DEF_TX_DMA_THRESH); 15609d26e4fcSRobert Mustacchi 15619d26e4fcSRobert Mustacchi i40e->i40e_tx_itr = i40e_get_prop(i40e, "tx_intr_throttle", 15629d26e4fcSRobert Mustacchi I40E_MIN_ITR, I40E_MAX_ITR, I40E_DEF_TX_ITR); 15639d26e4fcSRobert Mustacchi 15649d26e4fcSRobert Mustacchi i40e->i40e_rx_itr = i40e_get_prop(i40e, "rx_intr_throttle", 15659d26e4fcSRobert Mustacchi I40E_MIN_ITR, I40E_MAX_ITR, I40E_DEF_RX_ITR); 15669d26e4fcSRobert Mustacchi 15679d26e4fcSRobert Mustacchi i40e->i40e_other_itr = i40e_get_prop(i40e, "other_intr_throttle", 15689d26e4fcSRobert Mustacchi I40E_MIN_ITR, I40E_MAX_ITR, I40E_DEF_OTHER_ITR); 15699d26e4fcSRobert Mustacchi 15709d26e4fcSRobert Mustacchi if (!i40e->i40e_mr_enable) { 15719d26e4fcSRobert Mustacchi i40e->i40e_num_trqpairs = I40E_TRQPAIR_NOMSIX; 15729d26e4fcSRobert Mustacchi i40e->i40e_num_rx_groups = I40E_GROUP_NOMSIX; 15739d26e4fcSRobert Mustacchi } 15749d26e4fcSRobert Mustacchi 15759d26e4fcSRobert Mustacchi i40e_update_mtu(i40e); 15769d26e4fcSRobert Mustacchi } 15779d26e4fcSRobert Mustacchi 15789d26e4fcSRobert Mustacchi /* 15799d26e4fcSRobert Mustacchi * There are a few constraints on interrupts that we're currently imposing, some 15809d26e4fcSRobert Mustacchi * of which are restrictions from hardware. For a fuller treatment, see 15819d26e4fcSRobert Mustacchi * i40e_intr.c. 15829d26e4fcSRobert Mustacchi * 15839d26e4fcSRobert Mustacchi * Currently, to use MSI-X we require two interrupts be available though in 15849d26e4fcSRobert Mustacchi * theory we should participate in IRM and happily use more interrupts. 15859d26e4fcSRobert Mustacchi * 15869d26e4fcSRobert Mustacchi * Hardware only supports a single MSI being programmed and therefore if we 15879d26e4fcSRobert Mustacchi * don't have MSI-X interrupts available at this time, then we ratchet down the 15889d26e4fcSRobert Mustacchi * number of rings and groups available. Obviously, we only bother with a single 15899d26e4fcSRobert Mustacchi * fixed interrupt. 15909d26e4fcSRobert Mustacchi */ 15919d26e4fcSRobert Mustacchi static boolean_t 15929d26e4fcSRobert Mustacchi i40e_alloc_intr_handles(i40e_t *i40e, dev_info_t *devinfo, int intr_type) 15939d26e4fcSRobert Mustacchi { 1594396505afSPaul Winder i40e_hw_t *hw = &i40e->i40e_hw_space; 1595396505afSPaul Winder ddi_acc_handle_t rh = i40e->i40e_osdep_space.ios_reg_handle; 15969d26e4fcSRobert Mustacchi int request, count, actual, rc, min; 1597396505afSPaul Winder uint32_t reg; 15989d26e4fcSRobert Mustacchi 15999d26e4fcSRobert Mustacchi switch (intr_type) { 16009d26e4fcSRobert Mustacchi case DDI_INTR_TYPE_FIXED: 16019d26e4fcSRobert Mustacchi case DDI_INTR_TYPE_MSI: 16029d26e4fcSRobert Mustacchi request = 1; 16039d26e4fcSRobert Mustacchi min = 1; 16049d26e4fcSRobert Mustacchi break; 16059d26e4fcSRobert Mustacchi case DDI_INTR_TYPE_MSIX: 1606396505afSPaul Winder min = 2; 1607396505afSPaul Winder if (!i40e->i40e_mr_enable) { 1608396505afSPaul Winder request = 2; 1609396505afSPaul Winder break; 1610396505afSPaul Winder } 1611396505afSPaul Winder reg = I40E_READ_REG(hw, I40E_GLPCI_CNF2); 16129d26e4fcSRobert Mustacchi /* 1613396505afSPaul Winder * Should this read fail, we will drop back to using 1614396505afSPaul Winder * MSI or fixed interrupts. 16159d26e4fcSRobert Mustacchi */ 1616396505afSPaul Winder if (i40e_check_acc_handle(rh) != DDI_FM_OK) { 1617396505afSPaul Winder ddi_fm_service_impact(i40e->i40e_dip, 1618396505afSPaul Winder DDI_SERVICE_DEGRADED); 1619396505afSPaul Winder return (B_FALSE); 1620396505afSPaul Winder } 1621396505afSPaul Winder request = (reg & I40E_GLPCI_CNF2_MSI_X_PF_N_MASK) >> 1622396505afSPaul Winder I40E_GLPCI_CNF2_MSI_X_PF_N_SHIFT; 1623396505afSPaul Winder request++; /* the register value is n - 1 */ 16249d26e4fcSRobert Mustacchi break; 16259d26e4fcSRobert Mustacchi default: 16269d26e4fcSRobert Mustacchi panic("bad interrupt type passed to i40e_alloc_intr_handles: " 16279d26e4fcSRobert Mustacchi "%d", intr_type); 16289d26e4fcSRobert Mustacchi return (B_FALSE); 16299d26e4fcSRobert Mustacchi } 16309d26e4fcSRobert Mustacchi 16319d26e4fcSRobert Mustacchi rc = ddi_intr_get_nintrs(devinfo, intr_type, &count); 16329d26e4fcSRobert Mustacchi if (rc != DDI_SUCCESS || count < min) { 16339d26e4fcSRobert Mustacchi i40e_log(i40e, "Get interrupt number failed, " 16349d26e4fcSRobert Mustacchi "returned %d, count %d", rc, count); 16359d26e4fcSRobert Mustacchi return (B_FALSE); 16369d26e4fcSRobert Mustacchi } 16379d26e4fcSRobert Mustacchi 16389d26e4fcSRobert Mustacchi rc = ddi_intr_get_navail(devinfo, intr_type, &count); 16399d26e4fcSRobert Mustacchi if (rc != DDI_SUCCESS || count < min) { 16409d26e4fcSRobert Mustacchi i40e_log(i40e, "Get AVAILABLE interrupt number failed, " 16419d26e4fcSRobert Mustacchi "returned %d, count %d", rc, count); 16429d26e4fcSRobert Mustacchi return (B_FALSE); 16439d26e4fcSRobert Mustacchi } 16449d26e4fcSRobert Mustacchi 16459d26e4fcSRobert Mustacchi actual = 0; 16469d26e4fcSRobert Mustacchi i40e->i40e_intr_count = 0; 16479d26e4fcSRobert Mustacchi i40e->i40e_intr_count_max = 0; 16489d26e4fcSRobert Mustacchi i40e->i40e_intr_count_min = 0; 16499d26e4fcSRobert Mustacchi 16509d26e4fcSRobert Mustacchi i40e->i40e_intr_size = request * sizeof (ddi_intr_handle_t); 16519d26e4fcSRobert Mustacchi ASSERT(i40e->i40e_intr_size != 0); 16529d26e4fcSRobert Mustacchi i40e->i40e_intr_handles = kmem_alloc(i40e->i40e_intr_size, KM_SLEEP); 16539d26e4fcSRobert Mustacchi 16549d26e4fcSRobert Mustacchi rc = ddi_intr_alloc(devinfo, i40e->i40e_intr_handles, intr_type, 0, 16559d26e4fcSRobert Mustacchi min(request, count), &actual, DDI_INTR_ALLOC_NORMAL); 16569d26e4fcSRobert Mustacchi if (rc != DDI_SUCCESS) { 16579d26e4fcSRobert Mustacchi i40e_log(i40e, "Interrupt allocation failed with %d.", rc); 16589d26e4fcSRobert Mustacchi goto alloc_handle_fail; 16599d26e4fcSRobert Mustacchi } 16609d26e4fcSRobert Mustacchi 16619d26e4fcSRobert Mustacchi i40e->i40e_intr_count = actual; 16629d26e4fcSRobert Mustacchi i40e->i40e_intr_count_max = request; 16639d26e4fcSRobert Mustacchi i40e->i40e_intr_count_min = min; 16649d26e4fcSRobert Mustacchi 16659d26e4fcSRobert Mustacchi if (actual < min) { 16669d26e4fcSRobert Mustacchi i40e_log(i40e, "actual (%d) is less than minimum (%d).", 16679d26e4fcSRobert Mustacchi actual, min); 16689d26e4fcSRobert Mustacchi goto alloc_handle_fail; 16699d26e4fcSRobert Mustacchi } 16709d26e4fcSRobert Mustacchi 16719d26e4fcSRobert Mustacchi /* 16729d26e4fcSRobert Mustacchi * Record the priority and capabilities for our first vector. Once 16739d26e4fcSRobert Mustacchi * we have it, that's our priority until detach time. Even if we 16749d26e4fcSRobert Mustacchi * eventually participate in IRM, our priority shouldn't change. 16759d26e4fcSRobert Mustacchi */ 16769d26e4fcSRobert Mustacchi rc = ddi_intr_get_pri(i40e->i40e_intr_handles[0], &i40e->i40e_intr_pri); 16779d26e4fcSRobert Mustacchi if (rc != DDI_SUCCESS) { 16789d26e4fcSRobert Mustacchi i40e_log(i40e, 16799d26e4fcSRobert Mustacchi "Getting interrupt priority failed with %d.", rc); 16809d26e4fcSRobert Mustacchi goto alloc_handle_fail; 16819d26e4fcSRobert Mustacchi } 16829d26e4fcSRobert Mustacchi 16839d26e4fcSRobert Mustacchi rc = ddi_intr_get_cap(i40e->i40e_intr_handles[0], &i40e->i40e_intr_cap); 16849d26e4fcSRobert Mustacchi if (rc != DDI_SUCCESS) { 16859d26e4fcSRobert Mustacchi i40e_log(i40e, 16869d26e4fcSRobert Mustacchi "Getting interrupt capabilities failed with %d.", rc); 16879d26e4fcSRobert Mustacchi goto alloc_handle_fail; 16889d26e4fcSRobert Mustacchi } 16899d26e4fcSRobert Mustacchi 16909d26e4fcSRobert Mustacchi i40e->i40e_intr_type = intr_type; 16919d26e4fcSRobert Mustacchi return (B_TRUE); 16929d26e4fcSRobert Mustacchi 16939d26e4fcSRobert Mustacchi alloc_handle_fail: 16949d26e4fcSRobert Mustacchi 16959d26e4fcSRobert Mustacchi i40e_rem_intrs(i40e); 16969d26e4fcSRobert Mustacchi return (B_FALSE); 16979d26e4fcSRobert Mustacchi } 16989d26e4fcSRobert Mustacchi 16999d26e4fcSRobert Mustacchi static boolean_t 17009d26e4fcSRobert Mustacchi i40e_alloc_intrs(i40e_t *i40e, dev_info_t *devinfo) 17019d26e4fcSRobert Mustacchi { 17029d26e4fcSRobert Mustacchi int intr_types, rc; 17039d26e4fcSRobert Mustacchi 17049d26e4fcSRobert Mustacchi rc = ddi_intr_get_supported_types(devinfo, &intr_types); 17059d26e4fcSRobert Mustacchi if (rc != DDI_SUCCESS) { 17069d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to get supported interrupt types: %d", 17079d26e4fcSRobert Mustacchi rc); 17089d26e4fcSRobert Mustacchi return (B_FALSE); 17099d26e4fcSRobert Mustacchi } 17109d26e4fcSRobert Mustacchi 17119d26e4fcSRobert Mustacchi i40e->i40e_intr_type = 0; 17129d26e4fcSRobert Mustacchi 17139d26e4fcSRobert Mustacchi if ((intr_types & DDI_INTR_TYPE_MSIX) && 17149d26e4fcSRobert Mustacchi i40e->i40e_intr_force <= I40E_INTR_MSIX) { 1715396505afSPaul Winder if (i40e_alloc_intr_handles(i40e, devinfo, 1716396505afSPaul Winder DDI_INTR_TYPE_MSIX)) { 1717396505afSPaul Winder i40e->i40e_num_trqpairs = 1718396505afSPaul Winder MIN(i40e->i40e_intr_count - 1, 1719396505afSPaul Winder I40E_AQ_VSI_TC_QUE_SIZE_MAX); 17209d26e4fcSRobert Mustacchi return (B_TRUE); 1721396505afSPaul Winder } 17229d26e4fcSRobert Mustacchi } 17239d26e4fcSRobert Mustacchi 17249d26e4fcSRobert Mustacchi /* 17259d26e4fcSRobert Mustacchi * We only use multiple transmit/receive pairs when MSI-X interrupts are 17269d26e4fcSRobert Mustacchi * available due to the fact that the device basically only supports a 17279d26e4fcSRobert Mustacchi * single MSI interrupt. 17289d26e4fcSRobert Mustacchi */ 17299d26e4fcSRobert Mustacchi i40e->i40e_num_trqpairs = I40E_TRQPAIR_NOMSIX; 17309d26e4fcSRobert Mustacchi i40e->i40e_num_rx_groups = I40E_GROUP_NOMSIX; 17319d26e4fcSRobert Mustacchi 17329d26e4fcSRobert Mustacchi if ((intr_types & DDI_INTR_TYPE_MSI) && 17339d26e4fcSRobert Mustacchi (i40e->i40e_intr_force <= I40E_INTR_MSI)) { 17349d26e4fcSRobert Mustacchi if (i40e_alloc_intr_handles(i40e, devinfo, DDI_INTR_TYPE_MSI)) 17359d26e4fcSRobert Mustacchi return (B_TRUE); 17369d26e4fcSRobert Mustacchi } 17379d26e4fcSRobert Mustacchi 17389d26e4fcSRobert Mustacchi if (intr_types & DDI_INTR_TYPE_FIXED) { 17399d26e4fcSRobert Mustacchi if (i40e_alloc_intr_handles(i40e, devinfo, DDI_INTR_TYPE_FIXED)) 17409d26e4fcSRobert Mustacchi return (B_TRUE); 17419d26e4fcSRobert Mustacchi } 17429d26e4fcSRobert Mustacchi 17439d26e4fcSRobert Mustacchi return (B_FALSE); 17449d26e4fcSRobert Mustacchi } 17459d26e4fcSRobert Mustacchi 17469d26e4fcSRobert Mustacchi /* 17479d26e4fcSRobert Mustacchi * Map different interrupts to MSI-X vectors. 17489d26e4fcSRobert Mustacchi */ 17499d26e4fcSRobert Mustacchi static boolean_t 17509d26e4fcSRobert Mustacchi i40e_map_intrs_to_vectors(i40e_t *i40e) 17519d26e4fcSRobert Mustacchi { 1752396505afSPaul Winder int i; 1753396505afSPaul Winder 17549d26e4fcSRobert Mustacchi if (i40e->i40e_intr_type != DDI_INTR_TYPE_MSIX) { 17559d26e4fcSRobert Mustacchi return (B_TRUE); 17569d26e4fcSRobert Mustacchi } 17579d26e4fcSRobert Mustacchi 17589d26e4fcSRobert Mustacchi /* 1759396505afSPaul Winder * Each queue pair is mapped to a single interrupt, so transmit 1760396505afSPaul Winder * and receive interrupts for a given queue share the same vector. 1761396505afSPaul Winder * The number of queue pairs is one less than the number of interrupt 1762396505afSPaul Winder * vectors and is assigned the vector one higher than its index. 1763396505afSPaul Winder * Vector zero is reserved for the admin queue. 17649d26e4fcSRobert Mustacchi */ 1765396505afSPaul Winder ASSERT(i40e->i40e_intr_count == i40e->i40e_num_trqpairs + 1); 17669d26e4fcSRobert Mustacchi 1767396505afSPaul Winder for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 1768396505afSPaul Winder i40e->i40e_trqpairs[i].itrq_rx_intrvec = i + 1; 1769396505afSPaul Winder i40e->i40e_trqpairs[i].itrq_tx_intrvec = i + 1; 1770396505afSPaul Winder } 17719d26e4fcSRobert Mustacchi 17729d26e4fcSRobert Mustacchi return (B_TRUE); 17739d26e4fcSRobert Mustacchi } 17749d26e4fcSRobert Mustacchi 17759d26e4fcSRobert Mustacchi static boolean_t 17769d26e4fcSRobert Mustacchi i40e_add_intr_handlers(i40e_t *i40e) 17779d26e4fcSRobert Mustacchi { 17789d26e4fcSRobert Mustacchi int rc, vector; 17799d26e4fcSRobert Mustacchi 17809d26e4fcSRobert Mustacchi switch (i40e->i40e_intr_type) { 17819d26e4fcSRobert Mustacchi case DDI_INTR_TYPE_MSIX: 17829d26e4fcSRobert Mustacchi for (vector = 0; vector < i40e->i40e_intr_count; vector++) { 17839d26e4fcSRobert Mustacchi rc = ddi_intr_add_handler( 17849d26e4fcSRobert Mustacchi i40e->i40e_intr_handles[vector], 17859d26e4fcSRobert Mustacchi (ddi_intr_handler_t *)i40e_intr_msix, i40e, 17869d26e4fcSRobert Mustacchi (void *)(uintptr_t)vector); 17879d26e4fcSRobert Mustacchi if (rc != DDI_SUCCESS) { 17889d26e4fcSRobert Mustacchi i40e_log(i40e, "Add interrupt handler (MSI-X) " 17899d26e4fcSRobert Mustacchi "failed: return %d, vector %d", rc, vector); 17909d26e4fcSRobert Mustacchi for (vector--; vector >= 0; vector--) { 17919d26e4fcSRobert Mustacchi (void) ddi_intr_remove_handler( 17929d26e4fcSRobert Mustacchi i40e->i40e_intr_handles[vector]); 17939d26e4fcSRobert Mustacchi } 17949d26e4fcSRobert Mustacchi return (B_FALSE); 17959d26e4fcSRobert Mustacchi } 17969d26e4fcSRobert Mustacchi } 17979d26e4fcSRobert Mustacchi break; 17989d26e4fcSRobert Mustacchi case DDI_INTR_TYPE_MSI: 17999d26e4fcSRobert Mustacchi rc = ddi_intr_add_handler(i40e->i40e_intr_handles[0], 18009d26e4fcSRobert Mustacchi (ddi_intr_handler_t *)i40e_intr_msi, i40e, NULL); 18019d26e4fcSRobert Mustacchi if (rc != DDI_SUCCESS) { 18029d26e4fcSRobert Mustacchi i40e_log(i40e, "Add interrupt handler (MSI) failed: " 18039d26e4fcSRobert Mustacchi "return %d", rc); 18049d26e4fcSRobert Mustacchi return (B_FALSE); 18059d26e4fcSRobert Mustacchi } 18069d26e4fcSRobert Mustacchi break; 18079d26e4fcSRobert Mustacchi case DDI_INTR_TYPE_FIXED: 18089d26e4fcSRobert Mustacchi rc = ddi_intr_add_handler(i40e->i40e_intr_handles[0], 18099d26e4fcSRobert Mustacchi (ddi_intr_handler_t *)i40e_intr_legacy, i40e, NULL); 18109d26e4fcSRobert Mustacchi if (rc != DDI_SUCCESS) { 18119d26e4fcSRobert Mustacchi i40e_log(i40e, "Add interrupt handler (legacy) failed:" 18129d26e4fcSRobert Mustacchi " return %d", rc); 18139d26e4fcSRobert Mustacchi return (B_FALSE); 18149d26e4fcSRobert Mustacchi } 18159d26e4fcSRobert Mustacchi break; 18169d26e4fcSRobert Mustacchi default: 18179d26e4fcSRobert Mustacchi /* Cast to pacify lint */ 18189d26e4fcSRobert Mustacchi panic("i40e_intr_type %p contains an unknown type: %d", 18199d26e4fcSRobert Mustacchi (void *)i40e, i40e->i40e_intr_type); 18209d26e4fcSRobert Mustacchi } 18219d26e4fcSRobert Mustacchi 18229d26e4fcSRobert Mustacchi return (B_TRUE); 18239d26e4fcSRobert Mustacchi } 18249d26e4fcSRobert Mustacchi 18259d26e4fcSRobert Mustacchi /* 18269d26e4fcSRobert Mustacchi * Perform periodic checks. Longer term, we should be thinking about additional 18279d26e4fcSRobert Mustacchi * things here: 18289d26e4fcSRobert Mustacchi * 18299d26e4fcSRobert Mustacchi * o Stall Detection 18309d26e4fcSRobert Mustacchi * o Temperature sensor detection 18319d26e4fcSRobert Mustacchi * o Device resetting 18329d26e4fcSRobert Mustacchi * o Statistics updating to avoid wraparound 18339d26e4fcSRobert Mustacchi */ 18349d26e4fcSRobert Mustacchi static void 18359d26e4fcSRobert Mustacchi i40e_timer(void *arg) 18369d26e4fcSRobert Mustacchi { 18379d26e4fcSRobert Mustacchi i40e_t *i40e = arg; 18389d26e4fcSRobert Mustacchi 18399d26e4fcSRobert Mustacchi mutex_enter(&i40e->i40e_general_lock); 18409d26e4fcSRobert Mustacchi i40e_link_check(i40e); 18419d26e4fcSRobert Mustacchi mutex_exit(&i40e->i40e_general_lock); 18429d26e4fcSRobert Mustacchi } 18439d26e4fcSRobert Mustacchi 18449d26e4fcSRobert Mustacchi /* 18459d26e4fcSRobert Mustacchi * Get the hardware state, and scribble away anything that needs scribbling. 18469d26e4fcSRobert Mustacchi */ 18479d26e4fcSRobert Mustacchi static void 18489d26e4fcSRobert Mustacchi i40e_get_hw_state(i40e_t *i40e, i40e_hw_t *hw) 18499d26e4fcSRobert Mustacchi { 18509d26e4fcSRobert Mustacchi int rc; 18519d26e4fcSRobert Mustacchi 18529d26e4fcSRobert Mustacchi ASSERT(MUTEX_HELD(&i40e->i40e_general_lock)); 18539d26e4fcSRobert Mustacchi 18549d26e4fcSRobert Mustacchi (void) i40e_aq_get_link_info(hw, TRUE, NULL, NULL); 18559d26e4fcSRobert Mustacchi i40e_link_check(i40e); 18569d26e4fcSRobert Mustacchi 18579d26e4fcSRobert Mustacchi /* 18589d26e4fcSRobert Mustacchi * Try and determine our PHY. Note that we may have to retry to and 18599d26e4fcSRobert Mustacchi * delay to detect fiber correctly. 18609d26e4fcSRobert Mustacchi */ 18619d26e4fcSRobert Mustacchi rc = i40e_aq_get_phy_capabilities(hw, B_FALSE, B_TRUE, &i40e->i40e_phy, 18629d26e4fcSRobert Mustacchi NULL); 18639d26e4fcSRobert Mustacchi if (rc == I40E_ERR_UNKNOWN_PHY) { 18649d26e4fcSRobert Mustacchi i40e_msec_delay(200); 18659d26e4fcSRobert Mustacchi rc = i40e_aq_get_phy_capabilities(hw, B_FALSE, B_TRUE, 18669d26e4fcSRobert Mustacchi &i40e->i40e_phy, NULL); 18679d26e4fcSRobert Mustacchi } 18689d26e4fcSRobert Mustacchi 18699d26e4fcSRobert Mustacchi if (rc != I40E_SUCCESS) { 18709d26e4fcSRobert Mustacchi if (rc == I40E_ERR_UNKNOWN_PHY) { 18719d26e4fcSRobert Mustacchi i40e_error(i40e, "encountered unknown PHY type, " 18729d26e4fcSRobert Mustacchi "not attaching."); 18739d26e4fcSRobert Mustacchi } else { 18749d26e4fcSRobert Mustacchi i40e_error(i40e, "error getting physical capabilities: " 18759d26e4fcSRobert Mustacchi "%d, %d", rc, hw->aq.asq_last_status); 18769d26e4fcSRobert Mustacchi } 18779d26e4fcSRobert Mustacchi } 18789d26e4fcSRobert Mustacchi 18799d26e4fcSRobert Mustacchi rc = i40e_update_link_info(hw); 18809d26e4fcSRobert Mustacchi if (rc != I40E_SUCCESS) { 18819d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to update link information: %d", rc); 18829d26e4fcSRobert Mustacchi } 18839d26e4fcSRobert Mustacchi 18849d26e4fcSRobert Mustacchi /* 18859d26e4fcSRobert Mustacchi * In general, we don't want to mask off (as in stop from being a cause) 18869d26e4fcSRobert Mustacchi * any of the interrupts that the phy might be able to generate. 18879d26e4fcSRobert Mustacchi */ 18889d26e4fcSRobert Mustacchi rc = i40e_aq_set_phy_int_mask(hw, 0, NULL); 18899d26e4fcSRobert Mustacchi if (rc != I40E_SUCCESS) { 18909d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to update phy link mask: %d", rc); 18919d26e4fcSRobert Mustacchi } 18929d26e4fcSRobert Mustacchi } 18939d26e4fcSRobert Mustacchi 18949d26e4fcSRobert Mustacchi /* 18959d26e4fcSRobert Mustacchi * Go through and re-initialize any existing filters that we may have set up for 18969d26e4fcSRobert Mustacchi * this device. Note that we would only expect them to exist if hardware had 18979d26e4fcSRobert Mustacchi * already been initialized and we had just reset it. While we're not 18989d26e4fcSRobert Mustacchi * implementing this yet, we're keeping this around for when we add reset 18999d26e4fcSRobert Mustacchi * capabilities, so this isn't forgotten. 19009d26e4fcSRobert Mustacchi */ 19019d26e4fcSRobert Mustacchi /* ARGSUSED */ 19029d26e4fcSRobert Mustacchi static void 19039d26e4fcSRobert Mustacchi i40e_init_macaddrs(i40e_t *i40e, i40e_hw_t *hw) 19049d26e4fcSRobert Mustacchi { 19059d26e4fcSRobert Mustacchi } 19069d26e4fcSRobert Mustacchi 19079d26e4fcSRobert Mustacchi /* 19089d26e4fcSRobert Mustacchi * Configure the hardware for the Virtual Station Interface (VSI). Currently 19099d26e4fcSRobert Mustacchi * we only support one, but in the future we could instantiate more than one 19109d26e4fcSRobert Mustacchi * per attach-point. 19119d26e4fcSRobert Mustacchi */ 19129d26e4fcSRobert Mustacchi static boolean_t 19139d26e4fcSRobert Mustacchi i40e_config_vsi(i40e_t *i40e, i40e_hw_t *hw) 19149d26e4fcSRobert Mustacchi { 19159d26e4fcSRobert Mustacchi struct i40e_vsi_context context; 1916396505afSPaul Winder int err, tc_queues; 19179d26e4fcSRobert Mustacchi 19189d26e4fcSRobert Mustacchi bzero(&context, sizeof (struct i40e_vsi_context)); 19199d26e4fcSRobert Mustacchi context.seid = i40e->i40e_vsi_id; 19209d26e4fcSRobert Mustacchi context.pf_num = hw->pf_id; 19219d26e4fcSRobert Mustacchi err = i40e_aq_get_vsi_params(hw, &context, NULL); 19229d26e4fcSRobert Mustacchi if (err != I40E_SUCCESS) { 19239d26e4fcSRobert Mustacchi i40e_error(i40e, "get VSI params failed with %d", err); 19249d26e4fcSRobert Mustacchi return (B_FALSE); 19259d26e4fcSRobert Mustacchi } 19269d26e4fcSRobert Mustacchi 1927396505afSPaul Winder i40e->i40e_vsi_num = context.vsi_number; 1928396505afSPaul Winder 19299d26e4fcSRobert Mustacchi /* 19309d26e4fcSRobert Mustacchi * Set the queue and traffic class bits. Keep it simple for now. 19319d26e4fcSRobert Mustacchi */ 19329d26e4fcSRobert Mustacchi context.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID; 19339d26e4fcSRobert Mustacchi context.info.mapping_flags = I40E_AQ_VSI_QUE_MAP_CONTIG; 19349d26e4fcSRobert Mustacchi context.info.queue_mapping[0] = I40E_ASSIGN_ALL_QUEUES; 1935396505afSPaul Winder 1936396505afSPaul Winder /* 1937396505afSPaul Winder * tc_queues determines the size of the traffic class, where the 1938396505afSPaul Winder * size is 2^^tc_queues to a maximum of 64. 1939396505afSPaul Winder * Some examples: 1940396505afSPaul Winder * i40e_num_trqpairs == 1 => tc_queues = 0, 2^^0 = 1. 1941396505afSPaul Winder * i40e_num_trqpairs == 7 => tc_queues = 3, 2^^3 = 8. 1942396505afSPaul Winder * i40e_num_trqpairs == 8 => tc_queues = 3, 2^^3 = 8. 1943396505afSPaul Winder * i40e_num_trqpairs == 9 => tc_queues = 4, 2^^4 = 16. 1944396505afSPaul Winder * i40e_num_trqpairs == 17 => tc_queues = 5, 2^^5 = 32. 1945396505afSPaul Winder * i40e_num_trqpairs == 64 => tc_queues = 6, 2^^6 = 64. 1946396505afSPaul Winder */ 1947396505afSPaul Winder tc_queues = ddi_fls(i40e->i40e_num_trqpairs - 1); 1948396505afSPaul Winder 1949396505afSPaul Winder context.info.tc_mapping[0] = ((0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) & 1950396505afSPaul Winder I40E_AQ_VSI_TC_QUE_OFFSET_MASK) | 1951396505afSPaul Winder ((tc_queues << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT) & 1952396505afSPaul Winder I40E_AQ_VSI_TC_QUE_NUMBER_MASK); 19539d26e4fcSRobert Mustacchi 19549d26e4fcSRobert Mustacchi context.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID; 19559d26e4fcSRobert Mustacchi context.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL | 19569d26e4fcSRobert Mustacchi I40E_AQ_VSI_PVLAN_EMOD_NOTHING; 19579d26e4fcSRobert Mustacchi 19589d26e4fcSRobert Mustacchi context.flags = LE16_TO_CPU(I40E_AQ_VSI_TYPE_PF); 19599d26e4fcSRobert Mustacchi 19609d26e4fcSRobert Mustacchi i40e->i40e_vsi_stat_id = LE16_TO_CPU(context.info.stat_counter_idx); 19619d26e4fcSRobert Mustacchi if (i40e_stat_vsi_init(i40e) == B_FALSE) 19629d26e4fcSRobert Mustacchi return (B_FALSE); 19639d26e4fcSRobert Mustacchi 19649d26e4fcSRobert Mustacchi err = i40e_aq_update_vsi_params(hw, &context, NULL); 19659d26e4fcSRobert Mustacchi if (err != I40E_SUCCESS) { 19669d26e4fcSRobert Mustacchi i40e_error(i40e, "Update VSI params failed with %d", err); 19679d26e4fcSRobert Mustacchi return (B_FALSE); 19689d26e4fcSRobert Mustacchi } 19699d26e4fcSRobert Mustacchi 19709d26e4fcSRobert Mustacchi 19719d26e4fcSRobert Mustacchi return (B_TRUE); 19729d26e4fcSRobert Mustacchi } 19739d26e4fcSRobert Mustacchi 1974396505afSPaul Winder /* 1975396505afSPaul Winder * Set up RSS. 1976396505afSPaul Winder * 1. Seed the hash key. 1977396505afSPaul Winder * 2. Enable PCTYPEs for the hash filter. 1978396505afSPaul Winder * 3. Populate the LUT. 1979396505afSPaul Winder * 1980396505afSPaul Winder * Note: When/if X722 support is added the hash key is seeded via a call 1981396505afSPaul Winder * to i40e_aq_set_rss_key(), and the LUT is populated using 1982396505afSPaul Winder * i40e_aq_set_rss_lut(). 1983396505afSPaul Winder */ 1984396505afSPaul Winder static boolean_t 1985396505afSPaul Winder i40e_config_rss(i40e_t *i40e, i40e_hw_t *hw) 1986396505afSPaul Winder { 1987396505afSPaul Winder int i; 1988396505afSPaul Winder uint8_t lut_mask; 1989396505afSPaul Winder uint32_t *hlut; 1990396505afSPaul Winder uint64_t hena; 1991396505afSPaul Winder boolean_t rv = B_TRUE; 1992396505afSPaul Winder uint32_t seed[I40E_PFQF_HKEY_MAX_INDEX + 1]; 1993396505afSPaul Winder 1994396505afSPaul Winder /* 1995396505afSPaul Winder * 1. Seed the hash key 1996396505afSPaul Winder */ 1997396505afSPaul Winder (void) random_get_pseudo_bytes((uint8_t *)seed, sizeof (seed)); 1998396505afSPaul Winder 1999396505afSPaul Winder for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++) 2000396505afSPaul Winder i40e_write_rx_ctl(hw, I40E_PFQF_HKEY(i), seed[i]); 2001396505afSPaul Winder 2002396505afSPaul Winder /* 2003396505afSPaul Winder * 2. Configure PCTYPES 2004396505afSPaul Winder */ 2005396505afSPaul Winder hena = (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | 2006396505afSPaul Winder (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | 2007396505afSPaul Winder (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | 2008396505afSPaul Winder (1ULL << I40E_FILTER_PCTYPE_FRAG_IPV4) | 2009396505afSPaul Winder (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | 2010396505afSPaul Winder (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | 2011396505afSPaul Winder (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | 2012396505afSPaul Winder (1ULL << I40E_FILTER_PCTYPE_FRAG_IPV6) | 2013396505afSPaul Winder (1ULL << I40E_FILTER_PCTYPE_L2_PAYLOAD); 2014396505afSPaul Winder 2015396505afSPaul Winder i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (uint32_t)hena); 2016396505afSPaul Winder i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (uint32_t)(hena >> 32)); 2017396505afSPaul Winder 2018396505afSPaul Winder /* 2019396505afSPaul Winder * 3. Populate LUT 2020396505afSPaul Winder * 2021396505afSPaul Winder * Each entry in the LUT is 8 bits and is used to index 2022396505afSPaul Winder * the rx queue. Populate the LUT in a round robin fashion 2023396505afSPaul Winder * with rx queue indices from 0 to i40e_num_trqpairs - 1. 2024396505afSPaul Winder */ 2025396505afSPaul Winder hlut = kmem_alloc(hw->func_caps.rss_table_size, KM_NOSLEEP); 2026396505afSPaul Winder if (hlut == NULL) { 2027396505afSPaul Winder i40e_error(i40e, "i40e_config_rss() buffer allocation failed"); 2028396505afSPaul Winder return (B_FALSE); 2029396505afSPaul Winder } 2030396505afSPaul Winder 2031396505afSPaul Winder lut_mask = (1 << hw->func_caps.rss_table_entry_width) - 1; 2032396505afSPaul Winder 2033396505afSPaul Winder for (i = 0; i < hw->func_caps.rss_table_size; i++) 2034396505afSPaul Winder ((uint8_t *)hlut)[i] = (i % i40e->i40e_num_trqpairs) & lut_mask; 2035396505afSPaul Winder 2036396505afSPaul Winder for (i = 0; i < hw->func_caps.rss_table_size >> 2; i++) 2037396505afSPaul Winder I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i), hlut[i]); 2038396505afSPaul Winder 2039396505afSPaul Winder kmem_free(hlut, hw->func_caps.rss_table_size); 2040396505afSPaul Winder 2041396505afSPaul Winder return (rv); 2042396505afSPaul Winder } 2043396505afSPaul Winder 20449d26e4fcSRobert Mustacchi /* 20459d26e4fcSRobert Mustacchi * Wrapper to kick the chipset on. 20469d26e4fcSRobert Mustacchi */ 20479d26e4fcSRobert Mustacchi static boolean_t 20489d26e4fcSRobert Mustacchi i40e_chip_start(i40e_t *i40e) 20499d26e4fcSRobert Mustacchi { 20509d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 20519d26e4fcSRobert Mustacchi struct i40e_filter_control_settings filter; 20529d26e4fcSRobert Mustacchi int rc; 20539d26e4fcSRobert Mustacchi 20549d26e4fcSRobert Mustacchi if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) || 20559d26e4fcSRobert Mustacchi (hw->aq.fw_maj_ver < 4)) { 20569d26e4fcSRobert Mustacchi i40e_msec_delay(75); 20579d26e4fcSRobert Mustacchi if (i40e_aq_set_link_restart_an(hw, TRUE, NULL) != 20589d26e4fcSRobert Mustacchi I40E_SUCCESS) { 20599d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to restart link: admin queue " 20609d26e4fcSRobert Mustacchi "error: %d", hw->aq.asq_last_status); 20619d26e4fcSRobert Mustacchi return (B_FALSE); 20629d26e4fcSRobert Mustacchi } 20639d26e4fcSRobert Mustacchi } 20649d26e4fcSRobert Mustacchi 20659d26e4fcSRobert Mustacchi /* Determine hardware state */ 20669d26e4fcSRobert Mustacchi i40e_get_hw_state(i40e, hw); 20679d26e4fcSRobert Mustacchi 20689d26e4fcSRobert Mustacchi /* Initialize mac addresses. */ 20699d26e4fcSRobert Mustacchi i40e_init_macaddrs(i40e, hw); 20709d26e4fcSRobert Mustacchi 20719d26e4fcSRobert Mustacchi /* 20729d26e4fcSRobert Mustacchi * Set up the filter control. 20739d26e4fcSRobert Mustacchi */ 20749d26e4fcSRobert Mustacchi bzero(&filter, sizeof (filter)); 20759d26e4fcSRobert Mustacchi filter.enable_ethtype = TRUE; 20769d26e4fcSRobert Mustacchi filter.enable_macvlan = TRUE; 2077396505afSPaul Winder filter.hash_lut_size = I40E_HASH_LUT_SIZE_512; 20789d26e4fcSRobert Mustacchi 20799d26e4fcSRobert Mustacchi rc = i40e_set_filter_control(hw, &filter); 20809d26e4fcSRobert Mustacchi if (rc != I40E_SUCCESS) { 20819d26e4fcSRobert Mustacchi i40e_error(i40e, "i40e_set_filter_control() returned %d", rc); 20829d26e4fcSRobert Mustacchi return (B_FALSE); 20839d26e4fcSRobert Mustacchi } 20849d26e4fcSRobert Mustacchi 20859d26e4fcSRobert Mustacchi i40e_intr_chip_init(i40e); 20869d26e4fcSRobert Mustacchi 20879d26e4fcSRobert Mustacchi if (!i40e_config_vsi(i40e, hw)) 20889d26e4fcSRobert Mustacchi return (B_FALSE); 20899d26e4fcSRobert Mustacchi 2090396505afSPaul Winder if (!i40e_config_rss(i40e, hw)) 2091396505afSPaul Winder return (B_FALSE); 2092396505afSPaul Winder 20939d26e4fcSRobert Mustacchi i40e_flush(hw); 20949d26e4fcSRobert Mustacchi 20959d26e4fcSRobert Mustacchi return (B_TRUE); 20969d26e4fcSRobert Mustacchi } 20979d26e4fcSRobert Mustacchi 20989d26e4fcSRobert Mustacchi /* 20999d26e4fcSRobert Mustacchi * Take care of tearing down the rx ring. See 8.3.3.1.2 for more information. 21009d26e4fcSRobert Mustacchi */ 21019d26e4fcSRobert Mustacchi static void 21029d26e4fcSRobert Mustacchi i40e_shutdown_rx_rings(i40e_t *i40e) 21039d26e4fcSRobert Mustacchi { 21049d26e4fcSRobert Mustacchi int i; 21059d26e4fcSRobert Mustacchi uint32_t reg; 21069d26e4fcSRobert Mustacchi 21079d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 21089d26e4fcSRobert Mustacchi 21099d26e4fcSRobert Mustacchi /* 21109d26e4fcSRobert Mustacchi * Step 1. The interrupt linked list (see i40e_intr.c for more 21119d26e4fcSRobert Mustacchi * information) should have already been cleared before calling this 21129d26e4fcSRobert Mustacchi * function. 21139d26e4fcSRobert Mustacchi */ 21149d26e4fcSRobert Mustacchi #ifdef DEBUG 21159d26e4fcSRobert Mustacchi if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) { 21169d26e4fcSRobert Mustacchi for (i = 1; i < i40e->i40e_intr_count; i++) { 21179d26e4fcSRobert Mustacchi reg = I40E_READ_REG(hw, I40E_PFINT_LNKLSTN(i - 1)); 21189d26e4fcSRobert Mustacchi VERIFY3U(reg, ==, I40E_QUEUE_TYPE_EOL); 21199d26e4fcSRobert Mustacchi } 21209d26e4fcSRobert Mustacchi } else { 21219d26e4fcSRobert Mustacchi reg = I40E_READ_REG(hw, I40E_PFINT_LNKLST0); 21229d26e4fcSRobert Mustacchi VERIFY3U(reg, ==, I40E_QUEUE_TYPE_EOL); 21239d26e4fcSRobert Mustacchi } 21249d26e4fcSRobert Mustacchi 21259d26e4fcSRobert Mustacchi #endif /* DEBUG */ 21269d26e4fcSRobert Mustacchi 21279d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 21289d26e4fcSRobert Mustacchi /* 21299d26e4fcSRobert Mustacchi * Step 1. Request the queue by clearing QENA_REQ. It may not be 21309d26e4fcSRobert Mustacchi * set due to unwinding from failures and a partially enabled 21319d26e4fcSRobert Mustacchi * ring set. 21329d26e4fcSRobert Mustacchi */ 21339d26e4fcSRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QRX_ENA(i)); 21349d26e4fcSRobert Mustacchi if (!(reg & I40E_QRX_ENA_QENA_REQ_MASK)) 21359d26e4fcSRobert Mustacchi continue; 21369d26e4fcSRobert Mustacchi VERIFY((reg & I40E_QRX_ENA_QENA_REQ_MASK) == 21379d26e4fcSRobert Mustacchi I40E_QRX_ENA_QENA_REQ_MASK); 21389d26e4fcSRobert Mustacchi reg &= ~I40E_QRX_ENA_QENA_REQ_MASK; 21399d26e4fcSRobert Mustacchi I40E_WRITE_REG(hw, I40E_QRX_ENA(i), reg); 21409d26e4fcSRobert Mustacchi } 21419d26e4fcSRobert Mustacchi 21429d26e4fcSRobert Mustacchi /* 21439d26e4fcSRobert Mustacchi * Step 2. Wait for the disable to take, by having QENA_STAT in the FPM 21449d26e4fcSRobert Mustacchi * be cleared. Note that we could still receive data in the queue during 21459d26e4fcSRobert Mustacchi * this time. We don't actually wait for this now and instead defer this 21469d26e4fcSRobert Mustacchi * to i40e_shutdown_rings_wait(), after we've interleaved disabling the 21479d26e4fcSRobert Mustacchi * TX queues as well. 21489d26e4fcSRobert Mustacchi */ 21499d26e4fcSRobert Mustacchi } 21509d26e4fcSRobert Mustacchi 21519d26e4fcSRobert Mustacchi static void 21529d26e4fcSRobert Mustacchi i40e_shutdown_tx_rings(i40e_t *i40e) 21539d26e4fcSRobert Mustacchi { 21549d26e4fcSRobert Mustacchi int i; 21559d26e4fcSRobert Mustacchi uint32_t reg; 21569d26e4fcSRobert Mustacchi 21579d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 21589d26e4fcSRobert Mustacchi 21599d26e4fcSRobert Mustacchi /* 21609d26e4fcSRobert Mustacchi * Step 1. The interrupt linked list should already have been cleared. 21619d26e4fcSRobert Mustacchi */ 21629d26e4fcSRobert Mustacchi #ifdef DEBUG 21639d26e4fcSRobert Mustacchi if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) { 21649d26e4fcSRobert Mustacchi for (i = 1; i < i40e->i40e_intr_count; i++) { 21659d26e4fcSRobert Mustacchi reg = I40E_READ_REG(hw, I40E_PFINT_LNKLSTN(i - 1)); 21669d26e4fcSRobert Mustacchi VERIFY3U(reg, ==, I40E_QUEUE_TYPE_EOL); 21679d26e4fcSRobert Mustacchi } 21689d26e4fcSRobert Mustacchi } else { 21699d26e4fcSRobert Mustacchi reg = I40E_READ_REG(hw, I40E_PFINT_LNKLST0); 21709d26e4fcSRobert Mustacchi VERIFY3U(reg, ==, I40E_QUEUE_TYPE_EOL); 21719d26e4fcSRobert Mustacchi 21729d26e4fcSRobert Mustacchi } 21739d26e4fcSRobert Mustacchi #endif /* DEBUG */ 21749d26e4fcSRobert Mustacchi 21759d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 21769d26e4fcSRobert Mustacchi /* 21779d26e4fcSRobert Mustacchi * Step 2. Set the SET_QDIS flag for every queue. 21789d26e4fcSRobert Mustacchi */ 21799d26e4fcSRobert Mustacchi i40e_pre_tx_queue_cfg(hw, i, B_FALSE); 21809d26e4fcSRobert Mustacchi } 21819d26e4fcSRobert Mustacchi 21829d26e4fcSRobert Mustacchi /* 21839d26e4fcSRobert Mustacchi * Step 3. Wait at least 400 usec (can be done once for all queues). 21849d26e4fcSRobert Mustacchi */ 21859d26e4fcSRobert Mustacchi drv_usecwait(500); 21869d26e4fcSRobert Mustacchi 21879d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 21889d26e4fcSRobert Mustacchi /* 21899d26e4fcSRobert Mustacchi * Step 4. Clear the QENA_REQ flag which tells hardware to 21909d26e4fcSRobert Mustacchi * quiesce. If QENA_REQ is not already set then that means that 21919d26e4fcSRobert Mustacchi * we likely already tried to disable this queue. 21929d26e4fcSRobert Mustacchi */ 21939d26e4fcSRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QTX_ENA(i)); 21949d26e4fcSRobert Mustacchi if (!(reg & I40E_QTX_ENA_QENA_REQ_MASK)) 21959d26e4fcSRobert Mustacchi continue; 21969d26e4fcSRobert Mustacchi reg &= ~I40E_QTX_ENA_QENA_REQ_MASK; 21979d26e4fcSRobert Mustacchi I40E_WRITE_REG(hw, I40E_QTX_ENA(i), reg); 21989d26e4fcSRobert Mustacchi } 21999d26e4fcSRobert Mustacchi 22009d26e4fcSRobert Mustacchi /* 22019d26e4fcSRobert Mustacchi * Step 5. Wait for all drains to finish. This will be done by the 22029d26e4fcSRobert Mustacchi * hardware removing the QENA_STAT flag from the queue. Rather than 22039d26e4fcSRobert Mustacchi * waiting here, we interleave it with all the others in 22049d26e4fcSRobert Mustacchi * i40e_shutdown_rings_wait(). 22059d26e4fcSRobert Mustacchi */ 22069d26e4fcSRobert Mustacchi } 22079d26e4fcSRobert Mustacchi 22089d26e4fcSRobert Mustacchi /* 22099d26e4fcSRobert Mustacchi * Wait for all the rings to be shut down. e.g. Steps 2 and 5 from the above 22109d26e4fcSRobert Mustacchi * functions. 22119d26e4fcSRobert Mustacchi */ 22129d26e4fcSRobert Mustacchi static boolean_t 22139d26e4fcSRobert Mustacchi i40e_shutdown_rings_wait(i40e_t *i40e) 22149d26e4fcSRobert Mustacchi { 22159d26e4fcSRobert Mustacchi int i, try; 22169d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 22179d26e4fcSRobert Mustacchi 22189d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 22199d26e4fcSRobert Mustacchi uint32_t reg; 22209d26e4fcSRobert Mustacchi 22219d26e4fcSRobert Mustacchi for (try = 0; try < I40E_RING_WAIT_NTRIES; try++) { 22229d26e4fcSRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QRX_ENA(i)); 22239d26e4fcSRobert Mustacchi if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) 22249d26e4fcSRobert Mustacchi break; 22259d26e4fcSRobert Mustacchi i40e_msec_delay(I40E_RING_WAIT_PAUSE); 22269d26e4fcSRobert Mustacchi } 22279d26e4fcSRobert Mustacchi 22289d26e4fcSRobert Mustacchi if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) != 0) { 22299d26e4fcSRobert Mustacchi i40e_error(i40e, "timed out disabling rx queue %d", 22309d26e4fcSRobert Mustacchi i); 22319d26e4fcSRobert Mustacchi return (B_FALSE); 22329d26e4fcSRobert Mustacchi } 22339d26e4fcSRobert Mustacchi 22349d26e4fcSRobert Mustacchi for (try = 0; try < I40E_RING_WAIT_NTRIES; try++) { 22359d26e4fcSRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QTX_ENA(i)); 22369d26e4fcSRobert Mustacchi if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) 22379d26e4fcSRobert Mustacchi break; 22389d26e4fcSRobert Mustacchi i40e_msec_delay(I40E_RING_WAIT_PAUSE); 22399d26e4fcSRobert Mustacchi } 22409d26e4fcSRobert Mustacchi 22419d26e4fcSRobert Mustacchi if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) != 0) { 22429d26e4fcSRobert Mustacchi i40e_error(i40e, "timed out disabling tx queue %d", 22439d26e4fcSRobert Mustacchi i); 22449d26e4fcSRobert Mustacchi return (B_FALSE); 22459d26e4fcSRobert Mustacchi } 22469d26e4fcSRobert Mustacchi } 22479d26e4fcSRobert Mustacchi 22489d26e4fcSRobert Mustacchi return (B_TRUE); 22499d26e4fcSRobert Mustacchi } 22509d26e4fcSRobert Mustacchi 22519d26e4fcSRobert Mustacchi static boolean_t 22529d26e4fcSRobert Mustacchi i40e_shutdown_rings(i40e_t *i40e) 22539d26e4fcSRobert Mustacchi { 22549d26e4fcSRobert Mustacchi i40e_shutdown_rx_rings(i40e); 22559d26e4fcSRobert Mustacchi i40e_shutdown_tx_rings(i40e); 22569d26e4fcSRobert Mustacchi return (i40e_shutdown_rings_wait(i40e)); 22579d26e4fcSRobert Mustacchi } 22589d26e4fcSRobert Mustacchi 22599d26e4fcSRobert Mustacchi static void 22609d26e4fcSRobert Mustacchi i40e_setup_rx_descs(i40e_trqpair_t *itrq) 22619d26e4fcSRobert Mustacchi { 22629d26e4fcSRobert Mustacchi int i; 22639d26e4fcSRobert Mustacchi i40e_rx_data_t *rxd = itrq->itrq_rxdata; 22649d26e4fcSRobert Mustacchi 22659d26e4fcSRobert Mustacchi for (i = 0; i < rxd->rxd_ring_size; i++) { 22669d26e4fcSRobert Mustacchi i40e_rx_control_block_t *rcb; 22679d26e4fcSRobert Mustacchi i40e_rx_desc_t *rdesc; 22689d26e4fcSRobert Mustacchi 22699d26e4fcSRobert Mustacchi rcb = rxd->rxd_work_list[i]; 22709d26e4fcSRobert Mustacchi rdesc = &rxd->rxd_desc_ring[i]; 22719d26e4fcSRobert Mustacchi 22729d26e4fcSRobert Mustacchi rdesc->read.pkt_addr = 22739d26e4fcSRobert Mustacchi CPU_TO_LE64((uintptr_t)rcb->rcb_dma.dmab_dma_address); 22749d26e4fcSRobert Mustacchi rdesc->read.hdr_addr = 0; 22759d26e4fcSRobert Mustacchi } 22769d26e4fcSRobert Mustacchi } 22779d26e4fcSRobert Mustacchi 22789d26e4fcSRobert Mustacchi static boolean_t 22799d26e4fcSRobert Mustacchi i40e_setup_rx_hmc(i40e_trqpair_t *itrq) 22809d26e4fcSRobert Mustacchi { 22819d26e4fcSRobert Mustacchi i40e_rx_data_t *rxd = itrq->itrq_rxdata; 22829d26e4fcSRobert Mustacchi i40e_t *i40e = itrq->itrq_i40e; 22839d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 22849d26e4fcSRobert Mustacchi 22859d26e4fcSRobert Mustacchi struct i40e_hmc_obj_rxq rctx; 22869d26e4fcSRobert Mustacchi int err; 22879d26e4fcSRobert Mustacchi 22889d26e4fcSRobert Mustacchi bzero(&rctx, sizeof (struct i40e_hmc_obj_rxq)); 22899d26e4fcSRobert Mustacchi rctx.base = rxd->rxd_desc_area.dmab_dma_address / 22909d26e4fcSRobert Mustacchi I40E_HMC_RX_CTX_UNIT; 22919d26e4fcSRobert Mustacchi rctx.qlen = rxd->rxd_ring_size; 22929d26e4fcSRobert Mustacchi VERIFY(i40e->i40e_rx_buf_size >= I40E_HMC_RX_DBUFF_MIN); 22939d26e4fcSRobert Mustacchi VERIFY(i40e->i40e_rx_buf_size <= I40E_HMC_RX_DBUFF_MAX); 22949d26e4fcSRobert Mustacchi rctx.dbuff = i40e->i40e_rx_buf_size >> I40E_RXQ_CTX_DBUFF_SHIFT; 22959d26e4fcSRobert Mustacchi rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT; 22969d26e4fcSRobert Mustacchi rctx.dtype = I40E_HMC_RX_DTYPE_NOSPLIT; 22979d26e4fcSRobert Mustacchi rctx.dsize = I40E_HMC_RX_DSIZE_32BYTE; 22989d26e4fcSRobert Mustacchi rctx.crcstrip = I40E_HMC_RX_CRCSTRIP_ENABLE; 22999d26e4fcSRobert Mustacchi rctx.fc_ena = I40E_HMC_RX_FC_DISABLE; 23009d26e4fcSRobert Mustacchi rctx.l2tsel = I40E_HMC_RX_L2TAGORDER; 23019d26e4fcSRobert Mustacchi rctx.hsplit_0 = I40E_HMC_RX_HDRSPLIT_DISABLE; 23029d26e4fcSRobert Mustacchi rctx.hsplit_1 = I40E_HMC_RX_HDRSPLIT_DISABLE; 23039d26e4fcSRobert Mustacchi rctx.showiv = I40E_HMC_RX_INVLAN_DONTSTRIP; 23049d26e4fcSRobert Mustacchi rctx.rxmax = i40e->i40e_frame_max; 23059d26e4fcSRobert Mustacchi rctx.tphrdesc_ena = I40E_HMC_RX_TPH_DISABLE; 23069d26e4fcSRobert Mustacchi rctx.tphwdesc_ena = I40E_HMC_RX_TPH_DISABLE; 23079d26e4fcSRobert Mustacchi rctx.tphdata_ena = I40E_HMC_RX_TPH_DISABLE; 23089d26e4fcSRobert Mustacchi rctx.tphhead_ena = I40E_HMC_RX_TPH_DISABLE; 23099d26e4fcSRobert Mustacchi rctx.lrxqthresh = I40E_HMC_RX_LOWRXQ_NOINTR; 23109d26e4fcSRobert Mustacchi 23119d26e4fcSRobert Mustacchi /* 23129d26e4fcSRobert Mustacchi * This must be set to 0x1, see Table 8-12 in section 8.3.3.2.2. 23139d26e4fcSRobert Mustacchi */ 23149d26e4fcSRobert Mustacchi rctx.prefena = I40E_HMC_RX_PREFENA; 23159d26e4fcSRobert Mustacchi 23169d26e4fcSRobert Mustacchi err = i40e_clear_lan_rx_queue_context(hw, itrq->itrq_index); 23179d26e4fcSRobert Mustacchi if (err != I40E_SUCCESS) { 23189d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to clear rx queue %d context: %d", 23199d26e4fcSRobert Mustacchi itrq->itrq_index, err); 23209d26e4fcSRobert Mustacchi return (B_FALSE); 23219d26e4fcSRobert Mustacchi } 23229d26e4fcSRobert Mustacchi 23239d26e4fcSRobert Mustacchi err = i40e_set_lan_rx_queue_context(hw, itrq->itrq_index, &rctx); 23249d26e4fcSRobert Mustacchi if (err != I40E_SUCCESS) { 23259d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to set rx queue %d context: %d", 23269d26e4fcSRobert Mustacchi itrq->itrq_index, err); 23279d26e4fcSRobert Mustacchi return (B_FALSE); 23289d26e4fcSRobert Mustacchi } 23299d26e4fcSRobert Mustacchi 23309d26e4fcSRobert Mustacchi return (B_TRUE); 23319d26e4fcSRobert Mustacchi } 23329d26e4fcSRobert Mustacchi 23339d26e4fcSRobert Mustacchi /* 23349d26e4fcSRobert Mustacchi * Take care of setting up the descriptor rings and actually programming the 23359d26e4fcSRobert Mustacchi * device. See 8.3.3.1.1 for the full list of steps we need to do to enable the 23369d26e4fcSRobert Mustacchi * rx rings. 23379d26e4fcSRobert Mustacchi */ 23389d26e4fcSRobert Mustacchi static boolean_t 23399d26e4fcSRobert Mustacchi i40e_setup_rx_rings(i40e_t *i40e) 23409d26e4fcSRobert Mustacchi { 23419d26e4fcSRobert Mustacchi int i; 23429d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 23439d26e4fcSRobert Mustacchi 23449d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 23459d26e4fcSRobert Mustacchi i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[i]; 23469d26e4fcSRobert Mustacchi i40e_rx_data_t *rxd = itrq->itrq_rxdata; 23479d26e4fcSRobert Mustacchi uint32_t reg; 23489d26e4fcSRobert Mustacchi 23499d26e4fcSRobert Mustacchi /* 23509d26e4fcSRobert Mustacchi * Step 1. Program all receive ring descriptors. 23519d26e4fcSRobert Mustacchi */ 23529d26e4fcSRobert Mustacchi i40e_setup_rx_descs(itrq); 23539d26e4fcSRobert Mustacchi 23549d26e4fcSRobert Mustacchi /* 23559d26e4fcSRobert Mustacchi * Step 2. Program the queue's FPM/HMC context. 23569d26e4fcSRobert Mustacchi */ 23579d26e4fcSRobert Mustacchi if (i40e_setup_rx_hmc(itrq) == B_FALSE) 23589d26e4fcSRobert Mustacchi return (B_FALSE); 23599d26e4fcSRobert Mustacchi 23609d26e4fcSRobert Mustacchi /* 23619d26e4fcSRobert Mustacchi * Step 3. Clear the queue's tail pointer and set it to the end 23629d26e4fcSRobert Mustacchi * of the space. 23639d26e4fcSRobert Mustacchi */ 23649d26e4fcSRobert Mustacchi I40E_WRITE_REG(hw, I40E_QRX_TAIL(i), 0); 23659d26e4fcSRobert Mustacchi I40E_WRITE_REG(hw, I40E_QRX_TAIL(i), rxd->rxd_ring_size - 1); 23669d26e4fcSRobert Mustacchi 23679d26e4fcSRobert Mustacchi /* 23689d26e4fcSRobert Mustacchi * Step 4. Enable the queue via the QENA_REQ. 23699d26e4fcSRobert Mustacchi */ 23709d26e4fcSRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QRX_ENA(i)); 23719d26e4fcSRobert Mustacchi VERIFY0(reg & (I40E_QRX_ENA_QENA_REQ_MASK | 23729d26e4fcSRobert Mustacchi I40E_QRX_ENA_QENA_STAT_MASK)); 23739d26e4fcSRobert Mustacchi reg |= I40E_QRX_ENA_QENA_REQ_MASK; 23749d26e4fcSRobert Mustacchi I40E_WRITE_REG(hw, I40E_QRX_ENA(i), reg); 23759d26e4fcSRobert Mustacchi } 23769d26e4fcSRobert Mustacchi 23779d26e4fcSRobert Mustacchi /* 23789d26e4fcSRobert Mustacchi * Note, we wait for every queue to be enabled before we start checking. 23799d26e4fcSRobert Mustacchi * This will hopefully cause most queues to be enabled at this point. 23809d26e4fcSRobert Mustacchi */ 23819d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 23829d26e4fcSRobert Mustacchi uint32_t j, reg; 23839d26e4fcSRobert Mustacchi 23849d26e4fcSRobert Mustacchi /* 23859d26e4fcSRobert Mustacchi * Step 5. Verify that QENA_STAT has been set. It's promised 23869d26e4fcSRobert Mustacchi * that this should occur within about 10 us, but like other 23879d26e4fcSRobert Mustacchi * systems, we give the card a bit more time. 23889d26e4fcSRobert Mustacchi */ 23899d26e4fcSRobert Mustacchi for (j = 0; j < I40E_RING_WAIT_NTRIES; j++) { 23909d26e4fcSRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QRX_ENA(i)); 23919d26e4fcSRobert Mustacchi 23929d26e4fcSRobert Mustacchi if (reg & I40E_QRX_ENA_QENA_STAT_MASK) 23939d26e4fcSRobert Mustacchi break; 23949d26e4fcSRobert Mustacchi i40e_msec_delay(I40E_RING_WAIT_PAUSE); 23959d26e4fcSRobert Mustacchi } 23969d26e4fcSRobert Mustacchi 23979d26e4fcSRobert Mustacchi if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) { 23989d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to enable rx queue %d, timed " 23999d26e4fcSRobert Mustacchi "out.", i); 24009d26e4fcSRobert Mustacchi return (B_FALSE); 24019d26e4fcSRobert Mustacchi } 24029d26e4fcSRobert Mustacchi } 24039d26e4fcSRobert Mustacchi 24049d26e4fcSRobert Mustacchi return (B_TRUE); 24059d26e4fcSRobert Mustacchi } 24069d26e4fcSRobert Mustacchi 24079d26e4fcSRobert Mustacchi static boolean_t 24089d26e4fcSRobert Mustacchi i40e_setup_tx_hmc(i40e_trqpair_t *itrq) 24099d26e4fcSRobert Mustacchi { 24109d26e4fcSRobert Mustacchi i40e_t *i40e = itrq->itrq_i40e; 24119d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 24129d26e4fcSRobert Mustacchi 24139d26e4fcSRobert Mustacchi struct i40e_hmc_obj_txq tctx; 24149d26e4fcSRobert Mustacchi struct i40e_vsi_context context; 24159d26e4fcSRobert Mustacchi int err; 24169d26e4fcSRobert Mustacchi 24179d26e4fcSRobert Mustacchi bzero(&tctx, sizeof (struct i40e_hmc_obj_txq)); 24189d26e4fcSRobert Mustacchi tctx.new_context = I40E_HMC_TX_NEW_CONTEXT; 24199d26e4fcSRobert Mustacchi tctx.base = itrq->itrq_desc_area.dmab_dma_address / 24209d26e4fcSRobert Mustacchi I40E_HMC_TX_CTX_UNIT; 24219d26e4fcSRobert Mustacchi tctx.fc_ena = I40E_HMC_TX_FC_DISABLE; 24229d26e4fcSRobert Mustacchi tctx.timesync_ena = I40E_HMC_TX_TS_DISABLE; 24239d26e4fcSRobert Mustacchi tctx.fd_ena = I40E_HMC_TX_FD_DISABLE; 24249d26e4fcSRobert Mustacchi tctx.alt_vlan_ena = I40E_HMC_TX_ALT_VLAN_DISABLE; 24259d26e4fcSRobert Mustacchi tctx.head_wb_ena = I40E_HMC_TX_WB_ENABLE; 24269d26e4fcSRobert Mustacchi tctx.qlen = itrq->itrq_tx_ring_size; 24279d26e4fcSRobert Mustacchi tctx.tphrdesc_ena = I40E_HMC_TX_TPH_DISABLE; 24289d26e4fcSRobert Mustacchi tctx.tphrpacket_ena = I40E_HMC_TX_TPH_DISABLE; 24299d26e4fcSRobert Mustacchi tctx.tphwdesc_ena = I40E_HMC_TX_TPH_DISABLE; 24309d26e4fcSRobert Mustacchi tctx.head_wb_addr = itrq->itrq_desc_area.dmab_dma_address + 24319d26e4fcSRobert Mustacchi sizeof (i40e_tx_desc_t) * itrq->itrq_tx_ring_size; 24329d26e4fcSRobert Mustacchi 24339d26e4fcSRobert Mustacchi /* 24349d26e4fcSRobert Mustacchi * This field isn't actually documented, like crc, but it suggests that 24359d26e4fcSRobert Mustacchi * it should be zeroed. We leave both of these here because of that for 24369d26e4fcSRobert Mustacchi * now. We should check with Intel on why these are here even. 24379d26e4fcSRobert Mustacchi */ 24389d26e4fcSRobert Mustacchi tctx.crc = 0; 24399d26e4fcSRobert Mustacchi tctx.rdylist_act = 0; 24409d26e4fcSRobert Mustacchi 24419d26e4fcSRobert Mustacchi /* 24429d26e4fcSRobert Mustacchi * We're supposed to assign the rdylist field with the value of the 24439d26e4fcSRobert Mustacchi * traffic class index for the first device. We query the VSI parameters 24449d26e4fcSRobert Mustacchi * again to get what the handle is. Note that every queue is always 24459d26e4fcSRobert Mustacchi * assigned to traffic class zero, because we don't actually use them. 24469d26e4fcSRobert Mustacchi */ 24479d26e4fcSRobert Mustacchi bzero(&context, sizeof (struct i40e_vsi_context)); 24489d26e4fcSRobert Mustacchi context.seid = i40e->i40e_vsi_id; 24499d26e4fcSRobert Mustacchi context.pf_num = hw->pf_id; 24509d26e4fcSRobert Mustacchi err = i40e_aq_get_vsi_params(hw, &context, NULL); 24519d26e4fcSRobert Mustacchi if (err != I40E_SUCCESS) { 24529d26e4fcSRobert Mustacchi i40e_error(i40e, "get VSI params failed with %d", err); 24539d26e4fcSRobert Mustacchi return (B_FALSE); 24549d26e4fcSRobert Mustacchi } 24559d26e4fcSRobert Mustacchi tctx.rdylist = LE_16(context.info.qs_handle[0]); 24569d26e4fcSRobert Mustacchi 24579d26e4fcSRobert Mustacchi err = i40e_clear_lan_tx_queue_context(hw, itrq->itrq_index); 24589d26e4fcSRobert Mustacchi if (err != I40E_SUCCESS) { 24599d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to clear tx queue %d context: %d", 24609d26e4fcSRobert Mustacchi itrq->itrq_index, err); 24619d26e4fcSRobert Mustacchi return (B_FALSE); 24629d26e4fcSRobert Mustacchi } 24639d26e4fcSRobert Mustacchi 24649d26e4fcSRobert Mustacchi err = i40e_set_lan_tx_queue_context(hw, itrq->itrq_index, &tctx); 24659d26e4fcSRobert Mustacchi if (err != I40E_SUCCESS) { 24669d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to set tx queue %d context: %d", 24679d26e4fcSRobert Mustacchi itrq->itrq_index, err); 24689d26e4fcSRobert Mustacchi return (B_FALSE); 24699d26e4fcSRobert Mustacchi } 24709d26e4fcSRobert Mustacchi 24719d26e4fcSRobert Mustacchi return (B_TRUE); 24729d26e4fcSRobert Mustacchi } 24739d26e4fcSRobert Mustacchi 24749d26e4fcSRobert Mustacchi /* 24759d26e4fcSRobert Mustacchi * Take care of setting up the descriptor rings and actually programming the 24769d26e4fcSRobert Mustacchi * device. See 8.4.3.1.1 for what we need to do here. 24779d26e4fcSRobert Mustacchi */ 24789d26e4fcSRobert Mustacchi static boolean_t 24799d26e4fcSRobert Mustacchi i40e_setup_tx_rings(i40e_t *i40e) 24809d26e4fcSRobert Mustacchi { 24819d26e4fcSRobert Mustacchi int i; 24829d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 24839d26e4fcSRobert Mustacchi 24849d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 24859d26e4fcSRobert Mustacchi i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[i]; 24869d26e4fcSRobert Mustacchi uint32_t reg; 24879d26e4fcSRobert Mustacchi 24889d26e4fcSRobert Mustacchi /* 24899d26e4fcSRobert Mustacchi * Step 1. Clear the queue disable flag and verify that the 24909d26e4fcSRobert Mustacchi * index is set correctly. 24919d26e4fcSRobert Mustacchi */ 24929d26e4fcSRobert Mustacchi i40e_pre_tx_queue_cfg(hw, i, B_TRUE); 24939d26e4fcSRobert Mustacchi 24949d26e4fcSRobert Mustacchi /* 24959d26e4fcSRobert Mustacchi * Step 2. Prepare the queue's FPM/HMC context. 24969d26e4fcSRobert Mustacchi */ 24979d26e4fcSRobert Mustacchi if (i40e_setup_tx_hmc(itrq) == B_FALSE) 24989d26e4fcSRobert Mustacchi return (B_FALSE); 24999d26e4fcSRobert Mustacchi 25009d26e4fcSRobert Mustacchi /* 25019d26e4fcSRobert Mustacchi * Step 3. Verify that it's clear that this PF owns this queue. 25029d26e4fcSRobert Mustacchi */ 25039d26e4fcSRobert Mustacchi reg = I40E_QTX_CTL_PF_QUEUE; 25049d26e4fcSRobert Mustacchi reg |= (hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) & 25059d26e4fcSRobert Mustacchi I40E_QTX_CTL_PF_INDX_MASK; 25069d26e4fcSRobert Mustacchi I40E_WRITE_REG(hw, I40E_QTX_CTL(itrq->itrq_index), reg); 25079d26e4fcSRobert Mustacchi i40e_flush(hw); 25089d26e4fcSRobert Mustacchi 25099d26e4fcSRobert Mustacchi /* 25109d26e4fcSRobert Mustacchi * Step 4. Set the QENA_REQ flag. 25119d26e4fcSRobert Mustacchi */ 25129d26e4fcSRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QTX_ENA(i)); 25139d26e4fcSRobert Mustacchi VERIFY0(reg & (I40E_QTX_ENA_QENA_REQ_MASK | 25149d26e4fcSRobert Mustacchi I40E_QTX_ENA_QENA_STAT_MASK)); 25159d26e4fcSRobert Mustacchi reg |= I40E_QTX_ENA_QENA_REQ_MASK; 25169d26e4fcSRobert Mustacchi I40E_WRITE_REG(hw, I40E_QTX_ENA(i), reg); 25179d26e4fcSRobert Mustacchi } 25189d26e4fcSRobert Mustacchi 25199d26e4fcSRobert Mustacchi /* 25209d26e4fcSRobert Mustacchi * Note, we wait for every queue to be enabled before we start checking. 25219d26e4fcSRobert Mustacchi * This will hopefully cause most queues to be enabled at this point. 25229d26e4fcSRobert Mustacchi */ 25239d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 25249d26e4fcSRobert Mustacchi uint32_t j, reg; 25259d26e4fcSRobert Mustacchi 25269d26e4fcSRobert Mustacchi /* 25279d26e4fcSRobert Mustacchi * Step 5. Verify that QENA_STAT has been set. It's promised 25289d26e4fcSRobert Mustacchi * that this should occur within about 10 us, but like BSD, 25299d26e4fcSRobert Mustacchi * we'll try for up to 100 ms for this queue. 25309d26e4fcSRobert Mustacchi */ 25319d26e4fcSRobert Mustacchi for (j = 0; j < I40E_RING_WAIT_NTRIES; j++) { 25329d26e4fcSRobert Mustacchi reg = I40E_READ_REG(hw, I40E_QTX_ENA(i)); 25339d26e4fcSRobert Mustacchi 25349d26e4fcSRobert Mustacchi if (reg & I40E_QTX_ENA_QENA_STAT_MASK) 25359d26e4fcSRobert Mustacchi break; 25369d26e4fcSRobert Mustacchi i40e_msec_delay(I40E_RING_WAIT_PAUSE); 25379d26e4fcSRobert Mustacchi } 25389d26e4fcSRobert Mustacchi 25399d26e4fcSRobert Mustacchi if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) { 25409d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to enable tx queue %d, timed " 25419d26e4fcSRobert Mustacchi "out", i); 25429d26e4fcSRobert Mustacchi return (B_FALSE); 25439d26e4fcSRobert Mustacchi } 25449d26e4fcSRobert Mustacchi } 25459d26e4fcSRobert Mustacchi 25469d26e4fcSRobert Mustacchi return (B_TRUE); 25479d26e4fcSRobert Mustacchi } 25489d26e4fcSRobert Mustacchi 25499d26e4fcSRobert Mustacchi void 25509d26e4fcSRobert Mustacchi i40e_stop(i40e_t *i40e, boolean_t free_allocations) 25519d26e4fcSRobert Mustacchi { 25529d26e4fcSRobert Mustacchi int i; 25539d26e4fcSRobert Mustacchi 25549d26e4fcSRobert Mustacchi ASSERT(MUTEX_HELD(&i40e->i40e_general_lock)); 25559d26e4fcSRobert Mustacchi 25569d26e4fcSRobert Mustacchi /* 25579d26e4fcSRobert Mustacchi * Shutdown and drain the tx and rx pipeline. We do this using the 25589d26e4fcSRobert Mustacchi * following steps. 25599d26e4fcSRobert Mustacchi * 25609d26e4fcSRobert Mustacchi * 1) Shutdown interrupts to all the queues (trying to keep the admin 25619d26e4fcSRobert Mustacchi * queue alive). 25629d26e4fcSRobert Mustacchi * 25639d26e4fcSRobert Mustacchi * 2) Remove all of the interrupt tx and rx causes by setting the 25649d26e4fcSRobert Mustacchi * interrupt linked lists to zero. 25659d26e4fcSRobert Mustacchi * 25669d26e4fcSRobert Mustacchi * 2) Shutdown the tx and rx rings. Because i40e_shutdown_rings() should 25679d26e4fcSRobert Mustacchi * wait for all the queues to be disabled, once we reach that point 25689d26e4fcSRobert Mustacchi * it should be safe to free associated data. 25699d26e4fcSRobert Mustacchi * 25709d26e4fcSRobert Mustacchi * 4) Wait 50ms after all that is done. This ensures that the rings are 25719d26e4fcSRobert Mustacchi * ready for programming again and we don't have to think about this 25729d26e4fcSRobert Mustacchi * in other parts of the driver. 25739d26e4fcSRobert Mustacchi * 25749d26e4fcSRobert Mustacchi * 5) Disable remaining chip interrupts, (admin queue, etc.) 25759d26e4fcSRobert Mustacchi * 25769d26e4fcSRobert Mustacchi * 6) Verify that FM is happy with all the register accesses we 25779d26e4fcSRobert Mustacchi * performed. 25789d26e4fcSRobert Mustacchi */ 25799d26e4fcSRobert Mustacchi i40e_intr_io_disable_all(i40e); 25809d26e4fcSRobert Mustacchi i40e_intr_io_clear_cause(i40e); 25819d26e4fcSRobert Mustacchi 25829d26e4fcSRobert Mustacchi if (i40e_shutdown_rings(i40e) == B_FALSE) { 25839d26e4fcSRobert Mustacchi ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST); 25849d26e4fcSRobert Mustacchi } 25859d26e4fcSRobert Mustacchi 25869d26e4fcSRobert Mustacchi delay(50 * drv_usectohz(1000)); 25879d26e4fcSRobert Mustacchi 25889d26e4fcSRobert Mustacchi i40e_intr_chip_fini(i40e); 25899d26e4fcSRobert Mustacchi 25909d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 25919d26e4fcSRobert Mustacchi mutex_enter(&i40e->i40e_trqpairs[i].itrq_rx_lock); 25929d26e4fcSRobert Mustacchi mutex_enter(&i40e->i40e_trqpairs[i].itrq_tx_lock); 25939d26e4fcSRobert Mustacchi } 25949d26e4fcSRobert Mustacchi 25959d26e4fcSRobert Mustacchi /* 25969d26e4fcSRobert Mustacchi * We should consider refactoring this to be part of the ring start / 25979d26e4fcSRobert Mustacchi * stop routines at some point. 25989d26e4fcSRobert Mustacchi */ 25999d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 26009d26e4fcSRobert Mustacchi i40e_stats_trqpair_fini(&i40e->i40e_trqpairs[i]); 26019d26e4fcSRobert Mustacchi } 26029d26e4fcSRobert Mustacchi 26039d26e4fcSRobert Mustacchi if (i40e_check_acc_handle(i40e->i40e_osdep_space.ios_cfg_handle) != 26049d26e4fcSRobert Mustacchi DDI_FM_OK) { 26059d26e4fcSRobert Mustacchi ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST); 26069d26e4fcSRobert Mustacchi } 26079d26e4fcSRobert Mustacchi 26089d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 26099d26e4fcSRobert Mustacchi i40e_tx_cleanup_ring(&i40e->i40e_trqpairs[i]); 26109d26e4fcSRobert Mustacchi } 26119d26e4fcSRobert Mustacchi 26129d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 26139d26e4fcSRobert Mustacchi mutex_exit(&i40e->i40e_trqpairs[i].itrq_rx_lock); 26149d26e4fcSRobert Mustacchi mutex_exit(&i40e->i40e_trqpairs[i].itrq_tx_lock); 26159d26e4fcSRobert Mustacchi } 26169d26e4fcSRobert Mustacchi 26179d26e4fcSRobert Mustacchi i40e_stat_vsi_fini(i40e); 26189d26e4fcSRobert Mustacchi 26199d26e4fcSRobert Mustacchi i40e->i40e_link_speed = 0; 26209d26e4fcSRobert Mustacchi i40e->i40e_link_duplex = 0; 26219d26e4fcSRobert Mustacchi i40e_link_state_set(i40e, LINK_STATE_UNKNOWN); 26229d26e4fcSRobert Mustacchi 26239d26e4fcSRobert Mustacchi if (free_allocations) { 26249d26e4fcSRobert Mustacchi i40e_free_ring_mem(i40e, B_FALSE); 26259d26e4fcSRobert Mustacchi } 26269d26e4fcSRobert Mustacchi } 26279d26e4fcSRobert Mustacchi 26289d26e4fcSRobert Mustacchi boolean_t 26299d26e4fcSRobert Mustacchi i40e_start(i40e_t *i40e, boolean_t alloc) 26309d26e4fcSRobert Mustacchi { 26319d26e4fcSRobert Mustacchi i40e_hw_t *hw = &i40e->i40e_hw_space; 26329d26e4fcSRobert Mustacchi boolean_t rc = B_TRUE; 26339d26e4fcSRobert Mustacchi int i, err; 26349d26e4fcSRobert Mustacchi 26359d26e4fcSRobert Mustacchi ASSERT(MUTEX_HELD(&i40e->i40e_general_lock)); 26369d26e4fcSRobert Mustacchi 26379d26e4fcSRobert Mustacchi if (alloc) { 26389d26e4fcSRobert Mustacchi if (i40e_alloc_ring_mem(i40e) == B_FALSE) { 26399d26e4fcSRobert Mustacchi i40e_error(i40e, 26409d26e4fcSRobert Mustacchi "Failed to allocate ring memory"); 26419d26e4fcSRobert Mustacchi return (B_FALSE); 26429d26e4fcSRobert Mustacchi } 26439d26e4fcSRobert Mustacchi } 26449d26e4fcSRobert Mustacchi 26459d26e4fcSRobert Mustacchi /* 26469d26e4fcSRobert Mustacchi * This should get refactored to be part of ring start and stop at 26479d26e4fcSRobert Mustacchi * some point, along with most of the logic here. 26489d26e4fcSRobert Mustacchi */ 26499d26e4fcSRobert Mustacchi for (i = 0; i < i40e->i40e_num_trqpairs; i++) { 26509d26e4fcSRobert Mustacchi if (i40e_stats_trqpair_init(&i40e->i40e_trqpairs[i]) == 26519d26e4fcSRobert Mustacchi B_FALSE) { 26529d26e4fcSRobert Mustacchi int j; 26539d26e4fcSRobert Mustacchi 26549d26e4fcSRobert Mustacchi for (j = 0; j < i; j++) { 26559d26e4fcSRobert Mustacchi i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[j]; 26569d26e4fcSRobert Mustacchi i40e_stats_trqpair_fini(itrq); 26579d26e4fcSRobert Mustacchi } 26589d26e4fcSRobert Mustacchi return (B_FALSE); 26599d26e4fcSRobert Mustacchi } 26609d26e4fcSRobert Mustacchi } 26619d26e4fcSRobert Mustacchi 26629d26e4fcSRobert Mustacchi if (!i40e_chip_start(i40e)) { 26639d26e4fcSRobert Mustacchi i40e_fm_ereport(i40e, DDI_FM_DEVICE_INVAL_STATE); 26649d26e4fcSRobert Mustacchi rc = B_FALSE; 26659d26e4fcSRobert Mustacchi goto done; 26669d26e4fcSRobert Mustacchi } 26679d26e4fcSRobert Mustacchi 26689d26e4fcSRobert Mustacchi if (i40e_setup_rx_rings(i40e) == B_FALSE) { 26699d26e4fcSRobert Mustacchi rc = B_FALSE; 26709d26e4fcSRobert Mustacchi goto done; 26719d26e4fcSRobert Mustacchi } 26729d26e4fcSRobert Mustacchi 26739d26e4fcSRobert Mustacchi if (i40e_setup_tx_rings(i40e) == B_FALSE) { 26749d26e4fcSRobert Mustacchi rc = B_FALSE; 26759d26e4fcSRobert Mustacchi goto done; 26769d26e4fcSRobert Mustacchi } 26779d26e4fcSRobert Mustacchi 26789d26e4fcSRobert Mustacchi /* 26799d26e4fcSRobert Mustacchi * Enable broadcast traffic; however, do not enable multicast traffic. 26809d26e4fcSRobert Mustacchi * That's handle exclusively through MAC's mc_multicst routines. 26819d26e4fcSRobert Mustacchi */ 26829d26e4fcSRobert Mustacchi err = i40e_aq_set_vsi_broadcast(hw, i40e->i40e_vsi_id, B_TRUE, NULL); 26839d26e4fcSRobert Mustacchi if (err != I40E_SUCCESS) { 26849d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to set default VSI: %d", err); 26859d26e4fcSRobert Mustacchi rc = B_FALSE; 26869d26e4fcSRobert Mustacchi goto done; 26879d26e4fcSRobert Mustacchi } 26889d26e4fcSRobert Mustacchi 26899d26e4fcSRobert Mustacchi err = i40e_aq_set_mac_config(hw, i40e->i40e_frame_max, B_TRUE, 0, NULL); 26909d26e4fcSRobert Mustacchi if (err != I40E_SUCCESS) { 26919d26e4fcSRobert Mustacchi i40e_error(i40e, "failed to set MAC config: %d", err); 26929d26e4fcSRobert Mustacchi rc = B_FALSE; 26939d26e4fcSRobert Mustacchi goto done; 26949d26e4fcSRobert Mustacchi } 26959d26e4fcSRobert Mustacchi 26969d26e4fcSRobert Mustacchi /* 26979d26e4fcSRobert Mustacchi * Finally, make sure that we're happy from an FM perspective. 26989d26e4fcSRobert Mustacchi */ 26999d26e4fcSRobert Mustacchi if (i40e_check_acc_handle(i40e->i40e_osdep_space.ios_reg_handle) != 27009d26e4fcSRobert Mustacchi DDI_FM_OK) { 27019d26e4fcSRobert Mustacchi rc = B_FALSE; 27029d26e4fcSRobert Mustacchi goto done; 27039d26e4fcSRobert Mustacchi } 27049d26e4fcSRobert Mustacchi 27059d26e4fcSRobert Mustacchi /* Clear state bits prior to final interrupt enabling. */ 27069d26e4fcSRobert Mustacchi atomic_and_32(&i40e->i40e_state, 27079d26e4fcSRobert Mustacchi ~(I40E_ERROR | I40E_STALL | I40E_OVERTEMP)); 27089d26e4fcSRobert Mustacchi 27099d26e4fcSRobert Mustacchi i40e_intr_io_enable_all(i40e); 27109d26e4fcSRobert Mustacchi 27119d26e4fcSRobert Mustacchi done: 27129d26e4fcSRobert Mustacchi if (rc == B_FALSE) { 27139d26e4fcSRobert Mustacchi i40e_stop(i40e, B_FALSE); 27149d26e4fcSRobert Mustacchi if (alloc == B_TRUE) { 27159d26e4fcSRobert Mustacchi i40e_free_ring_mem(i40e, B_TRUE); 27169d26e4fcSRobert Mustacchi } 27179d26e4fcSRobert Mustacchi ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST); 27189d26e4fcSRobert Mustacchi } 27199d26e4fcSRobert Mustacchi 27209d26e4fcSRobert Mustacchi return (rc); 27219d26e4fcSRobert Mustacchi } 27229d26e4fcSRobert Mustacchi 27239d26e4fcSRobert Mustacchi /* 27249d26e4fcSRobert Mustacchi * We may have loaned up descriptors to the stack. As such, if we still have 27259d26e4fcSRobert Mustacchi * them outstanding, then we will not continue with detach. 27269d26e4fcSRobert Mustacchi */ 27279d26e4fcSRobert Mustacchi static boolean_t 27289d26e4fcSRobert Mustacchi i40e_drain_rx(i40e_t *i40e) 27299d26e4fcSRobert Mustacchi { 27309d26e4fcSRobert Mustacchi mutex_enter(&i40e->i40e_rx_pending_lock); 27319d26e4fcSRobert Mustacchi while (i40e->i40e_rx_pending > 0) { 27329d26e4fcSRobert Mustacchi if (cv_reltimedwait(&i40e->i40e_rx_pending_cv, 27339d26e4fcSRobert Mustacchi &i40e->i40e_rx_pending_lock, 27349d26e4fcSRobert Mustacchi drv_usectohz(I40E_DRAIN_RX_WAIT), TR_CLOCK_TICK) == -1) { 27359d26e4fcSRobert Mustacchi mutex_exit(&i40e->i40e_rx_pending_lock); 27369d26e4fcSRobert Mustacchi return (B_FALSE); 27379d26e4fcSRobert Mustacchi } 27389d26e4fcSRobert Mustacchi } 27399d26e4fcSRobert Mustacchi mutex_exit(&i40e->i40e_rx_pending_lock); 27409d26e4fcSRobert Mustacchi 27419d26e4fcSRobert Mustacchi return (B_TRUE); 27429d26e4fcSRobert Mustacchi } 27439d26e4fcSRobert Mustacchi 27449d26e4fcSRobert Mustacchi static int 27459d26e4fcSRobert Mustacchi i40e_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 27469d26e4fcSRobert Mustacchi { 27479d26e4fcSRobert Mustacchi i40e_t *i40e; 27489d26e4fcSRobert Mustacchi struct i40e_osdep *osdep; 27499d26e4fcSRobert Mustacchi i40e_hw_t *hw; 27509d26e4fcSRobert Mustacchi int instance; 27519d26e4fcSRobert Mustacchi 27529d26e4fcSRobert Mustacchi if (cmd != DDI_ATTACH) 27539d26e4fcSRobert Mustacchi return (DDI_FAILURE); 27549d26e4fcSRobert Mustacchi 27559d26e4fcSRobert Mustacchi instance = ddi_get_instance(devinfo); 27569d26e4fcSRobert Mustacchi i40e = kmem_zalloc(sizeof (i40e_t), KM_SLEEP); 27579d26e4fcSRobert Mustacchi 27589d26e4fcSRobert Mustacchi i40e->i40e_aqbuf = kmem_zalloc(I40E_ADMINQ_BUFSZ, KM_SLEEP); 27599d26e4fcSRobert Mustacchi i40e->i40e_instance = instance; 27609d26e4fcSRobert Mustacchi i40e->i40e_dip = devinfo; 27619d26e4fcSRobert Mustacchi 27629d26e4fcSRobert Mustacchi hw = &i40e->i40e_hw_space; 27639d26e4fcSRobert Mustacchi osdep = &i40e->i40e_osdep_space; 27649d26e4fcSRobert Mustacchi hw->back = osdep; 27659d26e4fcSRobert Mustacchi osdep->ios_i40e = i40e; 27669d26e4fcSRobert Mustacchi 27679d26e4fcSRobert Mustacchi ddi_set_driver_private(devinfo, i40e); 27689d26e4fcSRobert Mustacchi 27699d26e4fcSRobert Mustacchi i40e_fm_init(i40e); 27709d26e4fcSRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_FM_INIT; 27719d26e4fcSRobert Mustacchi 27729d26e4fcSRobert Mustacchi if (pci_config_setup(devinfo, &osdep->ios_cfg_handle) != DDI_SUCCESS) { 27739d26e4fcSRobert Mustacchi i40e_error(i40e, "Failed to map PCI configurations."); 27749d26e4fcSRobert Mustacchi goto attach_fail; 27759d26e4fcSRobert Mustacchi } 27769d26e4fcSRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_PCI_CONFIG; 27779d26e4fcSRobert Mustacchi 2778*3d75a287SRobert Mustacchi i40e_identify_hardware(i40e); 27799d26e4fcSRobert Mustacchi 27809d26e4fcSRobert Mustacchi if (!i40e_regs_map(i40e)) { 27819d26e4fcSRobert Mustacchi i40e_error(i40e, "Failed to map device registers."); 27829d26e4fcSRobert Mustacchi goto attach_fail; 27839d26e4fcSRobert Mustacchi } 27849d26e4fcSRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_REGS_MAP; 27859d26e4fcSRobert Mustacchi 27869d26e4fcSRobert Mustacchi i40e_init_properties(i40e); 27879d26e4fcSRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_PROPS; 27889d26e4fcSRobert Mustacchi 27899d26e4fcSRobert Mustacchi if (!i40e_common_code_init(i40e, hw)) 27909d26e4fcSRobert Mustacchi goto attach_fail; 27919d26e4fcSRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_COMMON_CODE; 27929d26e4fcSRobert Mustacchi 27939d26e4fcSRobert Mustacchi /* 27949d26e4fcSRobert Mustacchi * When we participate in IRM, we should make sure that we register 27959d26e4fcSRobert Mustacchi * ourselves with it before callbacks. 27969d26e4fcSRobert Mustacchi */ 27979d26e4fcSRobert Mustacchi if (!i40e_alloc_intrs(i40e, devinfo)) { 27989d26e4fcSRobert Mustacchi i40e_error(i40e, "Failed to allocate interrupts."); 27999d26e4fcSRobert Mustacchi goto attach_fail; 28009d26e4fcSRobert Mustacchi } 28019d26e4fcSRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_ALLOC_INTR; 28029d26e4fcSRobert Mustacchi 28039d26e4fcSRobert Mustacchi if (!i40e_alloc_trqpairs(i40e)) { 28049d26e4fcSRobert Mustacchi i40e_error(i40e, 28059d26e4fcSRobert Mustacchi "Failed to allocate receive & transmit rings."); 28069d26e4fcSRobert Mustacchi goto attach_fail; 28079d26e4fcSRobert Mustacchi } 28089d26e4fcSRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_ALLOC_RINGSLOCKS; 28099d26e4fcSRobert Mustacchi 28109d26e4fcSRobert Mustacchi if (!i40e_map_intrs_to_vectors(i40e)) { 28119d26e4fcSRobert Mustacchi i40e_error(i40e, "Failed to map interrupts to vectors."); 28129d26e4fcSRobert Mustacchi goto attach_fail; 28139d26e4fcSRobert Mustacchi } 28149d26e4fcSRobert Mustacchi 28159d26e4fcSRobert Mustacchi if (!i40e_add_intr_handlers(i40e)) { 28169d26e4fcSRobert Mustacchi i40e_error(i40e, "Failed to add the interrupt handlers."); 28179d26e4fcSRobert Mustacchi goto attach_fail; 28189d26e4fcSRobert Mustacchi } 28199d26e4fcSRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_ADD_INTR; 28209d26e4fcSRobert Mustacchi 28219d26e4fcSRobert Mustacchi if (!i40e_final_init(i40e)) { 28229d26e4fcSRobert Mustacchi i40e_error(i40e, "Final initialization failed."); 28239d26e4fcSRobert Mustacchi goto attach_fail; 28249d26e4fcSRobert Mustacchi } 28259d26e4fcSRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_INIT; 28269d26e4fcSRobert Mustacchi 28279d26e4fcSRobert Mustacchi if (i40e_check_acc_handle(i40e->i40e_osdep_space.ios_cfg_handle) != 28289d26e4fcSRobert Mustacchi DDI_FM_OK) { 28299d26e4fcSRobert Mustacchi ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST); 28309d26e4fcSRobert Mustacchi goto attach_fail; 28319d26e4fcSRobert Mustacchi } 28329d26e4fcSRobert Mustacchi 28339d26e4fcSRobert Mustacchi if (!i40e_stats_init(i40e)) { 28349d26e4fcSRobert Mustacchi i40e_error(i40e, "Stats initialization failed."); 28359d26e4fcSRobert Mustacchi goto attach_fail; 28369d26e4fcSRobert Mustacchi } 28379d26e4fcSRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_STATS; 28389d26e4fcSRobert Mustacchi 28399d26e4fcSRobert Mustacchi if (!i40e_register_mac(i40e)) { 28409d26e4fcSRobert Mustacchi i40e_error(i40e, "Failed to register to MAC/GLDv3"); 28419d26e4fcSRobert Mustacchi goto attach_fail; 28429d26e4fcSRobert Mustacchi } 28439d26e4fcSRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_MAC; 28449d26e4fcSRobert Mustacchi 28459d26e4fcSRobert Mustacchi i40e->i40e_periodic_id = ddi_periodic_add(i40e_timer, i40e, 28469d26e4fcSRobert Mustacchi I40E_CYCLIC_PERIOD, DDI_IPL_0); 28479d26e4fcSRobert Mustacchi if (i40e->i40e_periodic_id == 0) { 28489d26e4fcSRobert Mustacchi i40e_error(i40e, "Failed to add the link-check timer"); 28499d26e4fcSRobert Mustacchi goto attach_fail; 28509d26e4fcSRobert Mustacchi } 28519d26e4fcSRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_LINK_TIMER; 28529d26e4fcSRobert Mustacchi 28539d26e4fcSRobert Mustacchi if (!i40e_enable_interrupts(i40e)) { 28549d26e4fcSRobert Mustacchi i40e_error(i40e, "Failed to enable DDI interrupts"); 28559d26e4fcSRobert Mustacchi goto attach_fail; 28569d26e4fcSRobert Mustacchi } 28579d26e4fcSRobert Mustacchi i40e->i40e_attach_progress |= I40E_ATTACH_ENABLE_INTR; 28589d26e4fcSRobert Mustacchi 28599d26e4fcSRobert Mustacchi atomic_or_32(&i40e->i40e_state, I40E_INITIALIZED); 28609d26e4fcSRobert Mustacchi 28619d26e4fcSRobert Mustacchi mutex_enter(&i40e_glock); 28629d26e4fcSRobert Mustacchi list_insert_tail(&i40e_glist, i40e); 28639d26e4fcSRobert Mustacchi mutex_exit(&i40e_glock); 28649d26e4fcSRobert Mustacchi 28659d26e4fcSRobert Mustacchi return (DDI_SUCCESS); 28669d26e4fcSRobert Mustacchi 28679d26e4fcSRobert Mustacchi attach_fail: 28689d26e4fcSRobert Mustacchi i40e_unconfigure(devinfo, i40e); 28699d26e4fcSRobert Mustacchi return (DDI_FAILURE); 28709d26e4fcSRobert Mustacchi } 28719d26e4fcSRobert Mustacchi 28729d26e4fcSRobert Mustacchi static int 28739d26e4fcSRobert Mustacchi i40e_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 28749d26e4fcSRobert Mustacchi { 28759d26e4fcSRobert Mustacchi i40e_t *i40e; 28769d26e4fcSRobert Mustacchi 28779d26e4fcSRobert Mustacchi if (cmd != DDI_DETACH) 28789d26e4fcSRobert Mustacchi return (DDI_FAILURE); 28799d26e4fcSRobert Mustacchi 28809d26e4fcSRobert Mustacchi i40e = (i40e_t *)ddi_get_driver_private(devinfo); 28819d26e4fcSRobert Mustacchi if (i40e == NULL) { 28829d26e4fcSRobert Mustacchi i40e_log(NULL, "i40e_detach() called with no i40e pointer!"); 28839d26e4fcSRobert Mustacchi return (DDI_FAILURE); 28849d26e4fcSRobert Mustacchi } 28859d26e4fcSRobert Mustacchi 28869d26e4fcSRobert Mustacchi if (i40e_drain_rx(i40e) == B_FALSE) { 28879d26e4fcSRobert Mustacchi i40e_log(i40e, "timed out draining DMA resources, %d buffers " 28889d26e4fcSRobert Mustacchi "remain", i40e->i40e_rx_pending); 28899d26e4fcSRobert Mustacchi return (DDI_FAILURE); 28909d26e4fcSRobert Mustacchi } 28919d26e4fcSRobert Mustacchi 28929d26e4fcSRobert Mustacchi mutex_enter(&i40e_glock); 28939d26e4fcSRobert Mustacchi list_remove(&i40e_glist, i40e); 28949d26e4fcSRobert Mustacchi mutex_exit(&i40e_glock); 28959d26e4fcSRobert Mustacchi 28969d26e4fcSRobert Mustacchi i40e_unconfigure(devinfo, i40e); 28979d26e4fcSRobert Mustacchi 28989d26e4fcSRobert Mustacchi return (DDI_SUCCESS); 28999d26e4fcSRobert Mustacchi } 29009d26e4fcSRobert Mustacchi 29019d26e4fcSRobert Mustacchi static struct cb_ops i40e_cb_ops = { 29029d26e4fcSRobert Mustacchi nulldev, /* cb_open */ 29039d26e4fcSRobert Mustacchi nulldev, /* cb_close */ 29049d26e4fcSRobert Mustacchi nodev, /* cb_strategy */ 29059d26e4fcSRobert Mustacchi nodev, /* cb_print */ 29069d26e4fcSRobert Mustacchi nodev, /* cb_dump */ 29079d26e4fcSRobert Mustacchi nodev, /* cb_read */ 29089d26e4fcSRobert Mustacchi nodev, /* cb_write */ 29099d26e4fcSRobert Mustacchi nodev, /* cb_ioctl */ 29109d26e4fcSRobert Mustacchi nodev, /* cb_devmap */ 29119d26e4fcSRobert Mustacchi nodev, /* cb_mmap */ 29129d26e4fcSRobert Mustacchi nodev, /* cb_segmap */ 29139d26e4fcSRobert Mustacchi nochpoll, /* cb_chpoll */ 29149d26e4fcSRobert Mustacchi ddi_prop_op, /* cb_prop_op */ 29159d26e4fcSRobert Mustacchi NULL, /* cb_stream */ 29169d26e4fcSRobert Mustacchi D_MP | D_HOTPLUG, /* cb_flag */ 29179d26e4fcSRobert Mustacchi CB_REV, /* cb_rev */ 29189d26e4fcSRobert Mustacchi nodev, /* cb_aread */ 29199d26e4fcSRobert Mustacchi nodev /* cb_awrite */ 29209d26e4fcSRobert Mustacchi }; 29219d26e4fcSRobert Mustacchi 29229d26e4fcSRobert Mustacchi static struct dev_ops i40e_dev_ops = { 29239d26e4fcSRobert Mustacchi DEVO_REV, /* devo_rev */ 29249d26e4fcSRobert Mustacchi 0, /* devo_refcnt */ 29259d26e4fcSRobert Mustacchi NULL, /* devo_getinfo */ 29269d26e4fcSRobert Mustacchi nulldev, /* devo_identify */ 29279d26e4fcSRobert Mustacchi nulldev, /* devo_probe */ 29289d26e4fcSRobert Mustacchi i40e_attach, /* devo_attach */ 29299d26e4fcSRobert Mustacchi i40e_detach, /* devo_detach */ 29309d26e4fcSRobert Mustacchi nodev, /* devo_reset */ 29319d26e4fcSRobert Mustacchi &i40e_cb_ops, /* devo_cb_ops */ 29329d26e4fcSRobert Mustacchi NULL, /* devo_bus_ops */ 29339d26e4fcSRobert Mustacchi ddi_power, /* devo_power */ 29349d26e4fcSRobert Mustacchi ddi_quiesce_not_supported /* devo_quiesce */ 29359d26e4fcSRobert Mustacchi }; 29369d26e4fcSRobert Mustacchi 29379d26e4fcSRobert Mustacchi static struct modldrv i40e_modldrv = { 29389d26e4fcSRobert Mustacchi &mod_driverops, 29399d26e4fcSRobert Mustacchi i40e_ident, 29409d26e4fcSRobert Mustacchi &i40e_dev_ops 29419d26e4fcSRobert Mustacchi }; 29429d26e4fcSRobert Mustacchi 29439d26e4fcSRobert Mustacchi static struct modlinkage i40e_modlinkage = { 29449d26e4fcSRobert Mustacchi MODREV_1, 29459d26e4fcSRobert Mustacchi &i40e_modldrv, 29469d26e4fcSRobert Mustacchi NULL 29479d26e4fcSRobert Mustacchi }; 29489d26e4fcSRobert Mustacchi 29499d26e4fcSRobert Mustacchi /* 29509d26e4fcSRobert Mustacchi * Module Initialization Functions. 29519d26e4fcSRobert Mustacchi */ 29529d26e4fcSRobert Mustacchi int 29539d26e4fcSRobert Mustacchi _init(void) 29549d26e4fcSRobert Mustacchi { 29559d26e4fcSRobert Mustacchi int status; 29569d26e4fcSRobert Mustacchi 29579d26e4fcSRobert Mustacchi list_create(&i40e_glist, sizeof (i40e_t), offsetof(i40e_t, i40e_glink)); 29589d26e4fcSRobert Mustacchi list_create(&i40e_dlist, sizeof (i40e_device_t), 29599d26e4fcSRobert Mustacchi offsetof(i40e_device_t, id_link)); 29609d26e4fcSRobert Mustacchi mutex_init(&i40e_glock, NULL, MUTEX_DRIVER, NULL); 29619d26e4fcSRobert Mustacchi mac_init_ops(&i40e_dev_ops, I40E_MODULE_NAME); 29629d26e4fcSRobert Mustacchi 29639d26e4fcSRobert Mustacchi status = mod_install(&i40e_modlinkage); 29649d26e4fcSRobert Mustacchi if (status != DDI_SUCCESS) { 29659d26e4fcSRobert Mustacchi mac_fini_ops(&i40e_dev_ops); 29669d26e4fcSRobert Mustacchi mutex_destroy(&i40e_glock); 29679d26e4fcSRobert Mustacchi list_destroy(&i40e_dlist); 29689d26e4fcSRobert Mustacchi list_destroy(&i40e_glist); 29699d26e4fcSRobert Mustacchi } 29709d26e4fcSRobert Mustacchi 29719d26e4fcSRobert Mustacchi return (status); 29729d26e4fcSRobert Mustacchi } 29739d26e4fcSRobert Mustacchi 29749d26e4fcSRobert Mustacchi int 29759d26e4fcSRobert Mustacchi _info(struct modinfo *modinfop) 29769d26e4fcSRobert Mustacchi { 29779d26e4fcSRobert Mustacchi return (mod_info(&i40e_modlinkage, modinfop)); 29789d26e4fcSRobert Mustacchi } 29799d26e4fcSRobert Mustacchi 29809d26e4fcSRobert Mustacchi int 29819d26e4fcSRobert Mustacchi _fini(void) 29829d26e4fcSRobert Mustacchi { 29839d26e4fcSRobert Mustacchi int status; 29849d26e4fcSRobert Mustacchi 29859d26e4fcSRobert Mustacchi status = mod_remove(&i40e_modlinkage); 29869d26e4fcSRobert Mustacchi if (status == DDI_SUCCESS) { 29879d26e4fcSRobert Mustacchi mac_fini_ops(&i40e_dev_ops); 29889d26e4fcSRobert Mustacchi mutex_destroy(&i40e_glock); 29899d26e4fcSRobert Mustacchi list_destroy(&i40e_dlist); 29909d26e4fcSRobert Mustacchi list_destroy(&i40e_glist); 29919d26e4fcSRobert Mustacchi } 29929d26e4fcSRobert Mustacchi 29939d26e4fcSRobert Mustacchi return (status); 29949d26e4fcSRobert Mustacchi } 2995