xref: /illumos-gate/usr/src/uts/common/io/i40e/i40e_main.c (revision 9d26e4fc)
1*9d26e4fcSRobert Mustacchi /*
2*9d26e4fcSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*9d26e4fcSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*9d26e4fcSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*9d26e4fcSRobert Mustacchi  * 1.0 of the CDDL.
6*9d26e4fcSRobert Mustacchi  *
7*9d26e4fcSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*9d26e4fcSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*9d26e4fcSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*9d26e4fcSRobert Mustacchi  */
11*9d26e4fcSRobert Mustacchi 
12*9d26e4fcSRobert Mustacchi /*
13*9d26e4fcSRobert Mustacchi  * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved.
14*9d26e4fcSRobert Mustacchi  * Copyright 2016 Joyent, Inc.
15*9d26e4fcSRobert Mustacchi  */
16*9d26e4fcSRobert Mustacchi 
17*9d26e4fcSRobert Mustacchi /*
18*9d26e4fcSRobert Mustacchi  * i40e - Intel 10/40 Gb Ethernet driver
19*9d26e4fcSRobert Mustacchi  *
20*9d26e4fcSRobert Mustacchi  * The i40e driver is the main software device driver for the Intel 40 Gb family
21*9d26e4fcSRobert Mustacchi  * of devices. Note that these devices come in many flavors with both 40 GbE
22*9d26e4fcSRobert Mustacchi  * ports and 10 GbE ports. This device is the successor to the 82599 family of
23*9d26e4fcSRobert Mustacchi  * devices (ixgbe).
24*9d26e4fcSRobert Mustacchi  *
25*9d26e4fcSRobert Mustacchi  * Unlike previous generations of Intel 1 GbE and 10 GbE devices, the 40 GbE
26*9d26e4fcSRobert Mustacchi  * devices defined in the XL710 controller (previously known as Fortville) are a
27*9d26e4fcSRobert Mustacchi  * rather different beast and have a small switch embedded inside of them. In
28*9d26e4fcSRobert Mustacchi  * addition, the way that most of the programming is done has been overhauled.
29*9d26e4fcSRobert Mustacchi  * As opposed to just using PCIe memory mapped registers, it also has an
30*9d26e4fcSRobert Mustacchi  * administrative queue which is used to communicate with firmware running on
31*9d26e4fcSRobert Mustacchi  * the chip.
32*9d26e4fcSRobert Mustacchi  *
33*9d26e4fcSRobert Mustacchi  * Each physical function in the hardware shows up as a device that this driver
34*9d26e4fcSRobert Mustacchi  * will bind to. The hardware splits many resources evenly across all of the
35*9d26e4fcSRobert Mustacchi  * physical functions present on the device, while other resources are instead
36*9d26e4fcSRobert Mustacchi  * shared across the entire card and its up to the device driver to
37*9d26e4fcSRobert Mustacchi  * intelligently partition them.
38*9d26e4fcSRobert Mustacchi  *
39*9d26e4fcSRobert Mustacchi  * ------------
40*9d26e4fcSRobert Mustacchi  * Organization
41*9d26e4fcSRobert Mustacchi  * ------------
42*9d26e4fcSRobert Mustacchi  *
43*9d26e4fcSRobert Mustacchi  * This driver is made up of several files which have their own theory
44*9d26e4fcSRobert Mustacchi  * statements spread across them. We'll touch on the high level purpose of each
45*9d26e4fcSRobert Mustacchi  * file here, and then we'll get into more discussion on how the device is
46*9d26e4fcSRobert Mustacchi  * generally modelled with respect to the interfaces in illumos.
47*9d26e4fcSRobert Mustacchi  *
48*9d26e4fcSRobert Mustacchi  * i40e_gld.c: This file contains all of the bindings to MAC and the networking
49*9d26e4fcSRobert Mustacchi  *             stack.
50*9d26e4fcSRobert Mustacchi  *
51*9d26e4fcSRobert Mustacchi  * i40e_intr.c: This file contains all of the interrupt service routines and
52*9d26e4fcSRobert Mustacchi  *              contains logic to enable and disable interrupts on the hardware.
53*9d26e4fcSRobert Mustacchi  *              It also contains the logic to map hardware resources such as the
54*9d26e4fcSRobert Mustacchi  *              rings to and from interrupts and controls their ability to fire.
55*9d26e4fcSRobert Mustacchi  *
56*9d26e4fcSRobert Mustacchi  *              There is a big theory statement on interrupts present there.
57*9d26e4fcSRobert Mustacchi  *
58*9d26e4fcSRobert Mustacchi  * i40e_main.c: The file that you're currently in. It interfaces with the
59*9d26e4fcSRobert Mustacchi  *              traditional OS DDI interfaces and is in charge of configuring
60*9d26e4fcSRobert Mustacchi  *              the device.
61*9d26e4fcSRobert Mustacchi  *
62*9d26e4fcSRobert Mustacchi  * i40e_osdep.[ch]: These files contain interfaces and definitions needed to
63*9d26e4fcSRobert Mustacchi  *                  work with Intel's common code for the device.
64*9d26e4fcSRobert Mustacchi  *
65*9d26e4fcSRobert Mustacchi  * i40e_stats.c: This file contains the general work and logic around our
66*9d26e4fcSRobert Mustacchi  *               kstats. A theory statement on their organization and use of the
67*9d26e4fcSRobert Mustacchi  *               hardware exists there.
68*9d26e4fcSRobert Mustacchi  *
69*9d26e4fcSRobert Mustacchi  * i40e_sw.h: This header file contains all of the primary structure definitions
70*9d26e4fcSRobert Mustacchi  *            and constants that are used across the entire driver.
71*9d26e4fcSRobert Mustacchi  *
72*9d26e4fcSRobert Mustacchi  * i40e_transceiver.c: This file contains all of the logic for sending and
73*9d26e4fcSRobert Mustacchi  *                     receiving data. It contains all of the ring and DMA
74*9d26e4fcSRobert Mustacchi  *                     allocation logic, as well as, the actual interfaces to
75*9d26e4fcSRobert Mustacchi  *                     send and receive data.
76*9d26e4fcSRobert Mustacchi  *
77*9d26e4fcSRobert Mustacchi  *                     A big theory statement on ring management, descriptors,
78*9d26e4fcSRobert Mustacchi  *                     and how it ties into the OS is present there.
79*9d26e4fcSRobert Mustacchi  *
80*9d26e4fcSRobert Mustacchi  * --------------
81*9d26e4fcSRobert Mustacchi  * General Design
82*9d26e4fcSRobert Mustacchi  * --------------
83*9d26e4fcSRobert Mustacchi  *
84*9d26e4fcSRobert Mustacchi  * Before we go too far into the general way we've laid out data structures and
85*9d26e4fcSRobert Mustacchi  * the like, it's worth taking some time to explain how the hardware is
86*9d26e4fcSRobert Mustacchi  * organized. This organization informs a lot of how we do things at this time
87*9d26e4fcSRobert Mustacchi  * in the driver.
88*9d26e4fcSRobert Mustacchi  *
89*9d26e4fcSRobert Mustacchi  * Each physical device consists of a number of one or more ports, which are
90*9d26e4fcSRobert Mustacchi  * considered physical functions in the PCI sense and thus each get enumerated
91*9d26e4fcSRobert Mustacchi  * by the system, resulting in an instance being created and attached to. While
92*9d26e4fcSRobert Mustacchi  * there are many resources that are unique to each physical function eg.
93*9d26e4fcSRobert Mustacchi  * instance of the device, there are many that are shared across all of them.
94*9d26e4fcSRobert Mustacchi  * Several resources have an amount reserved for each Virtual Station Interface
95*9d26e4fcSRobert Mustacchi  * (VSI) and then a static pool of resources, available for all functions on the
96*9d26e4fcSRobert Mustacchi  * card.
97*9d26e4fcSRobert Mustacchi  *
98*9d26e4fcSRobert Mustacchi  * The most important resource in hardware are its transmit and receive queue
99*9d26e4fcSRobert Mustacchi  * pairs (i40e_trqpair_t). These should be thought of as rings in GLDv3
100*9d26e4fcSRobert Mustacchi  * parlance. There are a set number of these on each device; however, they are
101*9d26e4fcSRobert Mustacchi  * statically partitioned among all of the different physical functions.
102*9d26e4fcSRobert Mustacchi  *
103*9d26e4fcSRobert Mustacchi  * 'Fortville' (the code name for this device family) is basically a switch. To
104*9d26e4fcSRobert Mustacchi  * map MAC addresses and other things to queues, we end up having to create
105*9d26e4fcSRobert Mustacchi  * Virtual Station Interfaces (VSIs) and establish forwarding rules that direct
106*9d26e4fcSRobert Mustacchi  * traffic to a queue. A VSI owns a collection of queues and has a series of
107*9d26e4fcSRobert Mustacchi  * forwarding rules that point to it. One way to think of this is to treat it
108*9d26e4fcSRobert Mustacchi  * like MAC does a VNIC. When MAC refers to a group, a collection of rings and
109*9d26e4fcSRobert Mustacchi  * classification resources, that is a VSI in i40e.
110*9d26e4fcSRobert Mustacchi  *
111*9d26e4fcSRobert Mustacchi  * The sets of VSIs is shared across the entire device, though there may be some
112*9d26e4fcSRobert Mustacchi  * amount that are reserved to each PF. Because the GLDv3 does not let us change
113*9d26e4fcSRobert Mustacchi  * the number of groups dynamically, we instead statically divide this amount
114*9d26e4fcSRobert Mustacchi  * evenly between all the functions that exist. In addition, we have the same
115*9d26e4fcSRobert Mustacchi  * problem with the mac address forwarding rules. There are a static number that
116*9d26e4fcSRobert Mustacchi  * exist shared across all the functions.
117*9d26e4fcSRobert Mustacchi  *
118*9d26e4fcSRobert Mustacchi  * To handle both of these resources, what we end up doing is going through and
119*9d26e4fcSRobert Mustacchi  * determining which functions belong to the same device. Nominally one might do
120*9d26e4fcSRobert Mustacchi  * this by having a nexus driver; however, a prime requirement for a nexus
121*9d26e4fcSRobert Mustacchi  * driver is identifying the various children and activating them. While it is
122*9d26e4fcSRobert Mustacchi  * possible to get this information from NVRAM, we would end up duplicating a
123*9d26e4fcSRobert Mustacchi  * lot of the PCI enumeration logic. Really, at the end of the day, the device
124*9d26e4fcSRobert Mustacchi  * doesn't give us the traditional identification properties we want from a
125*9d26e4fcSRobert Mustacchi  * nexus driver.
126*9d26e4fcSRobert Mustacchi  *
127*9d26e4fcSRobert Mustacchi  * Instead, we rely on some properties that are guaranteed to be unique. While
128*9d26e4fcSRobert Mustacchi  * it might be tempting to leverage the PBA or serial number of the device from
129*9d26e4fcSRobert Mustacchi  * NVRAM, there is nothing that says that two devices can't be mis-programmed to
130*9d26e4fcSRobert Mustacchi  * have the same values in NVRAM. Instead, we uniquely identify a group of
131*9d26e4fcSRobert Mustacchi  * functions based on their parent in the /devices tree, their PCI bus and PCI
132*9d26e4fcSRobert Mustacchi  * function identifiers. Using either on their own may not be sufficient.
133*9d26e4fcSRobert Mustacchi  *
134*9d26e4fcSRobert Mustacchi  * For each unique PCI device that we encounter, we'll create a i40e_device_t.
135*9d26e4fcSRobert Mustacchi  * From there, because we don't have a good way to tell the GLDv3 about sharing
136*9d26e4fcSRobert Mustacchi  * resources between everything, we'll end up just dividing the resources
137*9d26e4fcSRobert Mustacchi  * evenly between all of the functions. Longer term, if we don't have to declare
138*9d26e4fcSRobert Mustacchi  * to the GLDv3 that these resources are shared, then we'll maintain a pool and
139*9d26e4fcSRobert Mustacchi  * hae each PF allocate from the pool in the device, thus if only two of four
140*9d26e4fcSRobert Mustacchi  * ports are being used, for example, then all of the resources can still be
141*9d26e4fcSRobert Mustacchi  * used.
142*9d26e4fcSRobert Mustacchi  *
143*9d26e4fcSRobert Mustacchi  * -------------------------------------------
144*9d26e4fcSRobert Mustacchi  * Transmit and Receive Queue Pair Allocations
145*9d26e4fcSRobert Mustacchi  * -------------------------------------------
146*9d26e4fcSRobert Mustacchi  *
147*9d26e4fcSRobert Mustacchi  * NVRAM ends up assigning each PF its own share of the transmit and receive LAN
148*9d26e4fcSRobert Mustacchi  * queue pairs, we have no way of modifying it, only observing it. From there,
149*9d26e4fcSRobert Mustacchi  * it's up to us to map these queues to VSIs and VFs. Since we don't support any
150*9d26e4fcSRobert Mustacchi  * VFs at this time, we only focus on assignments to VSIs.
151*9d26e4fcSRobert Mustacchi  *
152*9d26e4fcSRobert Mustacchi  * At the moment, we used a static mapping of transmit/receive queue pairs to a
153*9d26e4fcSRobert Mustacchi  * given VSI (eg. rings to a group). Though in the fullness of time, we want to
154*9d26e4fcSRobert Mustacchi  * make this something which is fully dynamic and take advantage of documented,
155*9d26e4fcSRobert Mustacchi  * but not yet available functionality for adding filters based on VXLAN and
156*9d26e4fcSRobert Mustacchi  * other encapsulation technologies.
157*9d26e4fcSRobert Mustacchi  *
158*9d26e4fcSRobert Mustacchi  * -------------------------------------
159*9d26e4fcSRobert Mustacchi  * Broadcast, Multicast, and Promiscuous
160*9d26e4fcSRobert Mustacchi  * -------------------------------------
161*9d26e4fcSRobert Mustacchi  *
162*9d26e4fcSRobert Mustacchi  * As part of the GLDv3, we need to make sure that we can handle receiving
163*9d26e4fcSRobert Mustacchi  * broadcast and multicast traffic. As well as enabling promiscuous mode when
164*9d26e4fcSRobert Mustacchi  * requested. GLDv3 requires that all broadcast and multicast traffic be
165*9d26e4fcSRobert Mustacchi  * retrieved by the default group, eg. the first one. This is the same thing as
166*9d26e4fcSRobert Mustacchi  * the default VSI.
167*9d26e4fcSRobert Mustacchi  *
168*9d26e4fcSRobert Mustacchi  * To receieve broadcast traffic, we enable it through the admin queue, rather
169*9d26e4fcSRobert Mustacchi  * than use one of our filters for it. For multicast traffic, we reserve a
170*9d26e4fcSRobert Mustacchi  * certain number of the hash filters and assign them to a given PF. When we
171*9d26e4fcSRobert Mustacchi  * exceed those, we then switch to using promicuous mode for multicast traffic.
172*9d26e4fcSRobert Mustacchi  *
173*9d26e4fcSRobert Mustacchi  * More specifically, once we exceed the number of filters (indicated because
174*9d26e4fcSRobert Mustacchi  * the i40e_t`i40e_resources.ifr_nmcastfilt ==
175*9d26e4fcSRobert Mustacchi  * i40e_t`i40e_resources.ifr_nmcastfilt_used), we then instead need to toggle
176*9d26e4fcSRobert Mustacchi  * promiscuous mode. If promiscuous mode is toggled then we keep track of the
177*9d26e4fcSRobert Mustacchi  * number of MACs added to it by incrementing i40e_t`i40e_mcast_promisc_count.
178*9d26e4fcSRobert Mustacchi  * That will stay enabled until that count reaches zero indicating that we have
179*9d26e4fcSRobert Mustacchi  * only added multicast addresses that we have a corresponding entry for.
180*9d26e4fcSRobert Mustacchi  *
181*9d26e4fcSRobert Mustacchi  * Because MAC itself wants to toggle promiscuous mode, which includes both
182*9d26e4fcSRobert Mustacchi  * unicast and multicast traffic, we go through and keep track of that
183*9d26e4fcSRobert Mustacchi  * ourselves. That is maintained through the use of the i40e_t`i40e_promisc_on
184*9d26e4fcSRobert Mustacchi  * member.
185*9d26e4fcSRobert Mustacchi  *
186*9d26e4fcSRobert Mustacchi  * --------------
187*9d26e4fcSRobert Mustacchi  * VSI Management
188*9d26e4fcSRobert Mustacchi  * --------------
189*9d26e4fcSRobert Mustacchi  *
190*9d26e4fcSRobert Mustacchi  * At this time, we currently only support a single MAC group, and thus a single
191*9d26e4fcSRobert Mustacchi  * VSI. This VSI is considered the default VSI and should be the only one that
192*9d26e4fcSRobert Mustacchi  * exists after a reset. Currently it is stored as the member
193*9d26e4fcSRobert Mustacchi  * i40e_t`i40e_vsi_id. While this works for the moment and for an initial
194*9d26e4fcSRobert Mustacchi  * driver, it's not sufficient for the longer-term path of the driver. Instead,
195*9d26e4fcSRobert Mustacchi  * we'll want to actually have a unique i40e_vsi_t structure which is used
196*9d26e4fcSRobert Mustacchi  * everywhere. Note that this means that every place that uses the
197*9d26e4fcSRobert Mustacchi  * i40e_t`i40e_vsi_id will need to be refactored.
198*9d26e4fcSRobert Mustacchi  *
199*9d26e4fcSRobert Mustacchi  * ----------------
200*9d26e4fcSRobert Mustacchi  * Structure Layout
201*9d26e4fcSRobert Mustacchi  * ----------------
202*9d26e4fcSRobert Mustacchi  *
203*9d26e4fcSRobert Mustacchi  * The following images relates the core data structures together. The primary
204*9d26e4fcSRobert Mustacchi  * structure in the system is the i40e_t. It itself contains multiple rings,
205*9d26e4fcSRobert Mustacchi  * i40e_trqpair_t's which contain the various transmit and receive data. The
206*9d26e4fcSRobert Mustacchi  * receive data is stored outside of the i40e_trqpair_t and instead in the
207*9d26e4fcSRobert Mustacchi  * i40e_rx_data_t. The i40e_t has a corresponding i40e_device_t which keeps
208*9d26e4fcSRobert Mustacchi  * track of per-physical device state. Finally, for every active descriptor,
209*9d26e4fcSRobert Mustacchi  * there is a corresponding control block, which is where the
210*9d26e4fcSRobert Mustacchi  * i40e_rx_control_block_t and the i40e_tx_control_block_t come from.
211*9d26e4fcSRobert Mustacchi  *
212*9d26e4fcSRobert Mustacchi  *   +-----------------------+       +-----------------------+
213*9d26e4fcSRobert Mustacchi  *   | Global i40e_t list    |       | Global Device list    |
214*9d26e4fcSRobert Mustacchi  *   |                       |    +--|                       |
215*9d26e4fcSRobert Mustacchi  *   | i40e_glist            |    |  | i40e_dlist            |
216*9d26e4fcSRobert Mustacchi  *   +-----------------------+    |  +-----------------------+
217*9d26e4fcSRobert Mustacchi  *       |                        v
218*9d26e4fcSRobert Mustacchi  *       |      +------------------------+      +-----------------------+
219*9d26e4fcSRobert Mustacchi  *       |      | Device-wide Structure  |----->| Device-wide Structure |--> ...
220*9d26e4fcSRobert Mustacchi  *       |      | i40e_device_t          |      | i40e_device_t         |
221*9d26e4fcSRobert Mustacchi  *       |      |                        |      +-----------------------+
222*9d26e4fcSRobert Mustacchi  *       |      | dev_info_t *     ------+--> Parent in devices tree.
223*9d26e4fcSRobert Mustacchi  *       |      | uint_t           ------+--> PCI bus number
224*9d26e4fcSRobert Mustacchi  *       |      | uint_t           ------+--> PCI device number
225*9d26e4fcSRobert Mustacchi  *       |      | uint_t           ------+--> Number of functions
226*9d26e4fcSRobert Mustacchi  *       |      | i40e_switch_rsrcs_t ---+--> Captured total switch resources
227*9d26e4fcSRobert Mustacchi  *       |      | list_t           ------+-------------+
228*9d26e4fcSRobert Mustacchi  *       |      +------------------------+             |
229*9d26e4fcSRobert Mustacchi  *       |                           ^                 |
230*9d26e4fcSRobert Mustacchi  *       |                           +--------+        |
231*9d26e4fcSRobert Mustacchi  *       |                                    |        v
232*9d26e4fcSRobert Mustacchi  *       |  +---------------------------+     |   +-------------------+
233*9d26e4fcSRobert Mustacchi  *       +->| GLDv3 Device, per PF      |-----|-->| GLDv3 Device (PF) |--> ...
234*9d26e4fcSRobert Mustacchi  *          | i40e_t                    |     |   | i40e_t            |
235*9d26e4fcSRobert Mustacchi  *          | **Primary Structure**     |     |   +-------------------+
236*9d26e4fcSRobert Mustacchi  *          |                           |     |
237*9d26e4fcSRobert Mustacchi  *          | i40e_device_t *         --+-----+
238*9d26e4fcSRobert Mustacchi  *          | i40e_state_t            --+---> Device State
239*9d26e4fcSRobert Mustacchi  *          | i40e_hw_t               --+---> Intel common code structure
240*9d26e4fcSRobert Mustacchi  *          | mac_handle_t            --+---> GLDv3 handle to MAC
241*9d26e4fcSRobert Mustacchi  *          | ddi_periodic_t          --+---> Link activity timer
242*9d26e4fcSRobert Mustacchi  *          | int (vsi_id)            --+---> VSI ID, main identifier
243*9d26e4fcSRobert Mustacchi  *          | i40e_func_rsrc_t        --+---> Available hardware resources
244*9d26e4fcSRobert Mustacchi  *          | i40e_switch_rsrc_t *    --+---> Switch resource snapshot
245*9d26e4fcSRobert Mustacchi  *          | i40e_sdu                --+---> Current MTU
246*9d26e4fcSRobert Mustacchi  *          | i40e_frame_max          --+---> Current HW frame size
247*9d26e4fcSRobert Mustacchi  *          | i40e_uaddr_t *          --+---> Array of assigned unicast MACs
248*9d26e4fcSRobert Mustacchi  *          | i40e_maddr_t *          --+---> Array of assigned multicast MACs
249*9d26e4fcSRobert Mustacchi  *          | i40e_mcast_promisccount --+---> Active multicast state
250*9d26e4fcSRobert Mustacchi  *          | i40e_promisc_on         --+---> Current promiscuous mode state
251*9d26e4fcSRobert Mustacchi  *          | int                     --+---> Number of transmit/receive pairs
252*9d26e4fcSRobert Mustacchi  *          | kstat_t *               --+---> PF kstats
253*9d26e4fcSRobert Mustacchi  *          | kstat_t *               --+---> VSI kstats
254*9d26e4fcSRobert Mustacchi  *          | i40e_pf_stats_t         --+---> PF kstat backing data
255*9d26e4fcSRobert Mustacchi  *          | i40e_vsi_stats_t        --+---> VSI kstat backing data
256*9d26e4fcSRobert Mustacchi  *          | i40e_trqpair_t *        --+---------+
257*9d26e4fcSRobert Mustacchi  *          +---------------------------+         |
258*9d26e4fcSRobert Mustacchi  *                                                |
259*9d26e4fcSRobert Mustacchi  *                                                v
260*9d26e4fcSRobert Mustacchi  *  +-------------------------------+       +-----------------------------+
261*9d26e4fcSRobert Mustacchi  *  | Transmit/Receive Queue Pair   |-------| Transmit/Receive Queue Pair |->...
262*9d26e4fcSRobert Mustacchi  *  | i40e_trqpair_t                |       | i40e_trqpair_t              |
263*9d26e4fcSRobert Mustacchi  *  + Ring Data Structure           |       +-----------------------------+
264*9d26e4fcSRobert Mustacchi  *  |                               |
265*9d26e4fcSRobert Mustacchi  *  | mac_ring_handle_t             +--> MAC RX ring handle
266*9d26e4fcSRobert Mustacchi  *  | mac_ring_handle_t             +--> MAC TX ring handle
267*9d26e4fcSRobert Mustacchi  *  | i40e_rxq_stat_t             --+--> RX Queue stats
268*9d26e4fcSRobert Mustacchi  *  | i40e_txq_stat_t             --+--> TX Queue stats
269*9d26e4fcSRobert Mustacchi  *  | uint32_t (tx ring size)       +--> TX Ring Size
270*9d26e4fcSRobert Mustacchi  *  | uint32_t (tx free list size)  +--> TX Free List Size
271*9d26e4fcSRobert Mustacchi  *  | i40e_dma_buffer_t     --------+--> TX Descriptor ring DMA
272*9d26e4fcSRobert Mustacchi  *  | i40e_tx_desc_t *      --------+--> TX descriptor ring
273*9d26e4fcSRobert Mustacchi  *  | volatile unt32_t *            +--> TX Write back head
274*9d26e4fcSRobert Mustacchi  *  | uint32_t               -------+--> TX ring head
275*9d26e4fcSRobert Mustacchi  *  | uint32_t               -------+--> TX ring tail
276*9d26e4fcSRobert Mustacchi  *  | uint32_t               -------+--> Num TX desc free
277*9d26e4fcSRobert Mustacchi  *  | i40e_tx_control_block_t *   --+--> TX control block array  ---+
278*9d26e4fcSRobert Mustacchi  *  | i40e_tx_control_block_t **  --+--> TCB work list          ----+
279*9d26e4fcSRobert Mustacchi  *  | i40e_tx_control_block_t **  --+--> TCB free list           ---+
280*9d26e4fcSRobert Mustacchi  *  | uint32_t               -------+--> Free TCB count             |
281*9d26e4fcSRobert Mustacchi  *  | i40e_rx_data_t *       -------+--+                            v
282*9d26e4fcSRobert Mustacchi  *  +-------------------------------+  |          +---------------------------+
283*9d26e4fcSRobert Mustacchi  *                                     |          | Per-TX Frame Metadata     |
284*9d26e4fcSRobert Mustacchi  *                                     |          | i40e_tx_control_block_t   |
285*9d26e4fcSRobert Mustacchi  *                +--------------------+          |                           |
286*9d26e4fcSRobert Mustacchi  *                |           mblk to transmit <--+---      mblk_t *          |
287*9d26e4fcSRobert Mustacchi  *                |           type of transmit <--+---      i40e_tx_type_t    |
288*9d26e4fcSRobert Mustacchi  *                |              TX DMA handle <--+---      ddi_dma_handle_t  |
289*9d26e4fcSRobert Mustacchi  *                v              TX DMA buffer <--+---      i40e_dma_buffer_t |
290*9d26e4fcSRobert Mustacchi  *    +------------------------------+            +---------------------------+
291*9d26e4fcSRobert Mustacchi  *    | Core Receive Data            |
292*9d26e4fcSRobert Mustacchi  *    | i40e_rx_data_t               |
293*9d26e4fcSRobert Mustacchi  *    |                              |
294*9d26e4fcSRobert Mustacchi  *    | i40e_dma_buffer_t          --+--> RX descriptor DMA Data
295*9d26e4fcSRobert Mustacchi  *    | i40e_rx_desc_t             --+--> RX descriptor ring
296*9d26e4fcSRobert Mustacchi  *    | uint32_t                   --+--> Next free desc.
297*9d26e4fcSRobert Mustacchi  *    | i40e_rx_control_block_t *  --+--> RX Control Block Array  ---+
298*9d26e4fcSRobert Mustacchi  *    | i40e_rx_control_block_t ** --+--> RCB work list           ---+
299*9d26e4fcSRobert Mustacchi  *    | i40e_rx_control_block_t ** --+--> RCB free list           ---+
300*9d26e4fcSRobert Mustacchi  *    +------------------------------+                               |
301*9d26e4fcSRobert Mustacchi  *                ^                                                  |
302*9d26e4fcSRobert Mustacchi  *                |     +---------------------------+                |
303*9d26e4fcSRobert Mustacchi  *                |     | Per-RX Frame Metadata     |<---------------+
304*9d26e4fcSRobert Mustacchi  *                |     | i40e_rx_control_block_t   |
305*9d26e4fcSRobert Mustacchi  *                |     |                           |
306*9d26e4fcSRobert Mustacchi  *                |     | mblk_t *              ----+--> Received mblk_t data
307*9d26e4fcSRobert Mustacchi  *                |     | uint32_t              ----+--> Reference count
308*9d26e4fcSRobert Mustacchi  *                |     | i40e_dma_buffer_t     ----+--> Receive data DMA info
309*9d26e4fcSRobert Mustacchi  *                |     | frtn_t                ----+--> mblk free function info
310*9d26e4fcSRobert Mustacchi  *                +-----+-- i40e_rx_data_t *        |
311*9d26e4fcSRobert Mustacchi  *                      +---------------------------+
312*9d26e4fcSRobert Mustacchi  *
313*9d26e4fcSRobert Mustacchi  * -------------
314*9d26e4fcSRobert Mustacchi  * Lock Ordering
315*9d26e4fcSRobert Mustacchi  * -------------
316*9d26e4fcSRobert Mustacchi  *
317*9d26e4fcSRobert Mustacchi  * In order to ensure that we don't deadlock, the following represents the
318*9d26e4fcSRobert Mustacchi  * lock order being used. When grabbing locks, follow the following order. Lower
319*9d26e4fcSRobert Mustacchi  * numbers are more important. Thus, the i40e_glock which is number 0, must be
320*9d26e4fcSRobert Mustacchi  * taken before any other locks in the driver. On the other hand, the
321*9d26e4fcSRobert Mustacchi  * i40e_t`i40e_stat_lock, has the highest number because it's the least
322*9d26e4fcSRobert Mustacchi  * important lock. Note, that just because one lock is higher than another does
323*9d26e4fcSRobert Mustacchi  * not mean that all intermediary locks are required.
324*9d26e4fcSRobert Mustacchi  *
325*9d26e4fcSRobert Mustacchi  * 0) i40e_glock
326*9d26e4fcSRobert Mustacchi  * 1) i40e_t`i40e_general_lock
327*9d26e4fcSRobert Mustacchi  *
328*9d26e4fcSRobert Mustacchi  * 2) i40e_trqpair_t`itrq_rx_lock
329*9d26e4fcSRobert Mustacchi  * 3) i40e_trqpair_t`itrq_tx_lock
330*9d26e4fcSRobert Mustacchi  * 4) i40e_t`i40e_rx_pending_lock
331*9d26e4fcSRobert Mustacchi  * 5) i40e_trqpair_t`itrq_tcb_lock
332*9d26e4fcSRobert Mustacchi  *
333*9d26e4fcSRobert Mustacchi  * 6) i40e_t`i40e_stat_lock
334*9d26e4fcSRobert Mustacchi  *
335*9d26e4fcSRobert Mustacchi  * Rules and expectations:
336*9d26e4fcSRobert Mustacchi  *
337*9d26e4fcSRobert Mustacchi  * 1) A thread holding locks belong to one PF should not hold locks belonging to
338*9d26e4fcSRobert Mustacchi  * a second. If for some reason this becomes necessary, locks should be grabbed
339*9d26e4fcSRobert Mustacchi  * based on the list order in the i40e_device_t, which implies that the
340*9d26e4fcSRobert Mustacchi  * i40e_glock is held.
341*9d26e4fcSRobert Mustacchi  *
342*9d26e4fcSRobert Mustacchi  * 2) When grabbing locks between multiple transmit and receive queues, the
343*9d26e4fcSRobert Mustacchi  * locks for the lowest number transmit/receive queue should be grabbed first.
344*9d26e4fcSRobert Mustacchi  *
345*9d26e4fcSRobert Mustacchi  * 3) When grabbing both the transmit and receive lock for a given queue, always
346*9d26e4fcSRobert Mustacchi  * grab i40e_trqpair_t`itrq_rx_lock before the i40e_trqpair_t`itrq_tx_lock.
347*9d26e4fcSRobert Mustacchi  *
348*9d26e4fcSRobert Mustacchi  * 4) The following pairs of locks are not expected to be held at the same time:
349*9d26e4fcSRobert Mustacchi  *
350*9d26e4fcSRobert Mustacchi  * o i40e_t`i40e_rx_pending_lock and i40e_trqpair_t`itrq_tcb_lock
351*9d26e4fcSRobert Mustacchi  *
352*9d26e4fcSRobert Mustacchi  * -----------
353*9d26e4fcSRobert Mustacchi  * Future Work
354*9d26e4fcSRobert Mustacchi  * -----------
355*9d26e4fcSRobert Mustacchi  *
356*9d26e4fcSRobert Mustacchi  * At the moment the i40e_t driver is rather bare bones, allowing us to start
357*9d26e4fcSRobert Mustacchi  * getting data flowing and folks using it while we develop additional features.
358*9d26e4fcSRobert Mustacchi  * While bugs have been filed to cover this future work, the following gives an
359*9d26e4fcSRobert Mustacchi  * overview of expected work:
360*9d26e4fcSRobert Mustacchi  *
361*9d26e4fcSRobert Mustacchi  *  o TSO support
362*9d26e4fcSRobert Mustacchi  *  o RSS / multiple ring support
363*9d26e4fcSRobert Mustacchi  *  o Multiple group support
364*9d26e4fcSRobert Mustacchi  *  o DMA binding and breaking up the locking in ring recycling.
365*9d26e4fcSRobert Mustacchi  *  o Enhanced detection of device errors
366*9d26e4fcSRobert Mustacchi  *  o Participation in IRM
367*9d26e4fcSRobert Mustacchi  *  o FMA device reset
368*9d26e4fcSRobert Mustacchi  *  o Stall detection, temperature error detection, etc.
369*9d26e4fcSRobert Mustacchi  *  o More dynamic resource pools
370*9d26e4fcSRobert Mustacchi  */
371*9d26e4fcSRobert Mustacchi 
372*9d26e4fcSRobert Mustacchi #include "i40e_sw.h"
373*9d26e4fcSRobert Mustacchi 
374*9d26e4fcSRobert Mustacchi static char i40e_ident[] = "Intel 10/40Gb Ethernet v1.0.0";
375*9d26e4fcSRobert Mustacchi 
376*9d26e4fcSRobert Mustacchi /*
377*9d26e4fcSRobert Mustacchi  * The i40e_glock primarily protects the lists below and the i40e_device_t
378*9d26e4fcSRobert Mustacchi  * structures.
379*9d26e4fcSRobert Mustacchi  */
380*9d26e4fcSRobert Mustacchi static kmutex_t i40e_glock;
381*9d26e4fcSRobert Mustacchi static list_t i40e_glist;
382*9d26e4fcSRobert Mustacchi static list_t i40e_dlist;
383*9d26e4fcSRobert Mustacchi 
384*9d26e4fcSRobert Mustacchi /*
385*9d26e4fcSRobert Mustacchi  * Access attributes for register mapping.
386*9d26e4fcSRobert Mustacchi  */
387*9d26e4fcSRobert Mustacchi static ddi_device_acc_attr_t i40e_regs_acc_attr = {
388*9d26e4fcSRobert Mustacchi 	DDI_DEVICE_ATTR_V1,
389*9d26e4fcSRobert Mustacchi 	DDI_STRUCTURE_LE_ACC,
390*9d26e4fcSRobert Mustacchi 	DDI_STRICTORDER_ACC,
391*9d26e4fcSRobert Mustacchi 	DDI_FLAGERR_ACC
392*9d26e4fcSRobert Mustacchi };
393*9d26e4fcSRobert Mustacchi 
394*9d26e4fcSRobert Mustacchi /*
395*9d26e4fcSRobert Mustacchi  * Logging function for this driver.
396*9d26e4fcSRobert Mustacchi  */
397*9d26e4fcSRobert Mustacchi static void
398*9d26e4fcSRobert Mustacchi i40e_dev_err(i40e_t *i40e, int level, boolean_t console, const char *fmt,
399*9d26e4fcSRobert Mustacchi     va_list ap)
400*9d26e4fcSRobert Mustacchi {
401*9d26e4fcSRobert Mustacchi 	char buf[1024];
402*9d26e4fcSRobert Mustacchi 
403*9d26e4fcSRobert Mustacchi 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
404*9d26e4fcSRobert Mustacchi 
405*9d26e4fcSRobert Mustacchi 	if (i40e == NULL) {
406*9d26e4fcSRobert Mustacchi 		cmn_err(level, (console) ? "%s: %s" : "!%s: %s",
407*9d26e4fcSRobert Mustacchi 		    I40E_MODULE_NAME, buf);
408*9d26e4fcSRobert Mustacchi 	} else {
409*9d26e4fcSRobert Mustacchi 		dev_err(i40e->i40e_dip, level, (console) ? "%s" : "!%s",
410*9d26e4fcSRobert Mustacchi 		    buf);
411*9d26e4fcSRobert Mustacchi 	}
412*9d26e4fcSRobert Mustacchi }
413*9d26e4fcSRobert Mustacchi 
414*9d26e4fcSRobert Mustacchi /*
415*9d26e4fcSRobert Mustacchi  * Because there's the stupid trailing-comma problem with the C preprocessor
416*9d26e4fcSRobert Mustacchi  * and variable arguments, I need to instantiate these.	 Pardon the redundant
417*9d26e4fcSRobert Mustacchi  * code.
418*9d26e4fcSRobert Mustacchi  */
419*9d26e4fcSRobert Mustacchi /*PRINTFLIKE2*/
420*9d26e4fcSRobert Mustacchi void
421*9d26e4fcSRobert Mustacchi i40e_error(i40e_t *i40e, const char *fmt, ...)
422*9d26e4fcSRobert Mustacchi {
423*9d26e4fcSRobert Mustacchi 	va_list ap;
424*9d26e4fcSRobert Mustacchi 
425*9d26e4fcSRobert Mustacchi 	va_start(ap, fmt);
426*9d26e4fcSRobert Mustacchi 	i40e_dev_err(i40e, CE_WARN, B_FALSE, fmt, ap);
427*9d26e4fcSRobert Mustacchi 	va_end(ap);
428*9d26e4fcSRobert Mustacchi }
429*9d26e4fcSRobert Mustacchi 
430*9d26e4fcSRobert Mustacchi /*PRINTFLIKE2*/
431*9d26e4fcSRobert Mustacchi void
432*9d26e4fcSRobert Mustacchi i40e_log(i40e_t *i40e, const char *fmt, ...)
433*9d26e4fcSRobert Mustacchi {
434*9d26e4fcSRobert Mustacchi 	va_list ap;
435*9d26e4fcSRobert Mustacchi 
436*9d26e4fcSRobert Mustacchi 	va_start(ap, fmt);
437*9d26e4fcSRobert Mustacchi 	i40e_dev_err(i40e, CE_NOTE, B_FALSE, fmt, ap);
438*9d26e4fcSRobert Mustacchi 	va_end(ap);
439*9d26e4fcSRobert Mustacchi }
440*9d26e4fcSRobert Mustacchi 
441*9d26e4fcSRobert Mustacchi /*PRINTFLIKE2*/
442*9d26e4fcSRobert Mustacchi void
443*9d26e4fcSRobert Mustacchi i40e_notice(i40e_t *i40e, const char *fmt, ...)
444*9d26e4fcSRobert Mustacchi {
445*9d26e4fcSRobert Mustacchi 	va_list ap;
446*9d26e4fcSRobert Mustacchi 
447*9d26e4fcSRobert Mustacchi 	va_start(ap, fmt);
448*9d26e4fcSRobert Mustacchi 	i40e_dev_err(i40e, CE_NOTE, B_TRUE, fmt, ap);
449*9d26e4fcSRobert Mustacchi 	va_end(ap);
450*9d26e4fcSRobert Mustacchi }
451*9d26e4fcSRobert Mustacchi 
452*9d26e4fcSRobert Mustacchi static void
453*9d26e4fcSRobert Mustacchi i40e_device_rele(i40e_t *i40e)
454*9d26e4fcSRobert Mustacchi {
455*9d26e4fcSRobert Mustacchi 	i40e_device_t *idp = i40e->i40e_device;
456*9d26e4fcSRobert Mustacchi 
457*9d26e4fcSRobert Mustacchi 	if (idp == NULL)
458*9d26e4fcSRobert Mustacchi 		return;
459*9d26e4fcSRobert Mustacchi 
460*9d26e4fcSRobert Mustacchi 	mutex_enter(&i40e_glock);
461*9d26e4fcSRobert Mustacchi 	VERIFY(idp->id_nreg > 0);
462*9d26e4fcSRobert Mustacchi 	list_remove(&idp->id_i40e_list, i40e);
463*9d26e4fcSRobert Mustacchi 	idp->id_nreg--;
464*9d26e4fcSRobert Mustacchi 	if (idp->id_nreg == 0) {
465*9d26e4fcSRobert Mustacchi 		list_remove(&i40e_dlist, idp);
466*9d26e4fcSRobert Mustacchi 		list_destroy(&idp->id_i40e_list);
467*9d26e4fcSRobert Mustacchi 		kmem_free(idp->id_rsrcs, sizeof (i40e_switch_rsrc_t) *
468*9d26e4fcSRobert Mustacchi 		    idp->id_rsrcs_alloc);
469*9d26e4fcSRobert Mustacchi 		kmem_free(idp, sizeof (i40e_device_t));
470*9d26e4fcSRobert Mustacchi 	}
471*9d26e4fcSRobert Mustacchi 	i40e->i40e_device = NULL;
472*9d26e4fcSRobert Mustacchi 	mutex_exit(&i40e_glock);
473*9d26e4fcSRobert Mustacchi }
474*9d26e4fcSRobert Mustacchi 
475*9d26e4fcSRobert Mustacchi static i40e_device_t *
476*9d26e4fcSRobert Mustacchi i40e_device_find(i40e_t *i40e, dev_info_t *parent, uint_t bus, uint_t device)
477*9d26e4fcSRobert Mustacchi {
478*9d26e4fcSRobert Mustacchi 	i40e_device_t *idp;
479*9d26e4fcSRobert Mustacchi 	mutex_enter(&i40e_glock);
480*9d26e4fcSRobert Mustacchi 	for (idp = list_head(&i40e_dlist); idp != NULL;
481*9d26e4fcSRobert Mustacchi 	    idp = list_next(&i40e_dlist, idp)) {
482*9d26e4fcSRobert Mustacchi 		if (idp->id_parent == parent && idp->id_pci_bus == bus &&
483*9d26e4fcSRobert Mustacchi 		    idp->id_pci_device == device) {
484*9d26e4fcSRobert Mustacchi 			break;
485*9d26e4fcSRobert Mustacchi 		}
486*9d26e4fcSRobert Mustacchi 	}
487*9d26e4fcSRobert Mustacchi 
488*9d26e4fcSRobert Mustacchi 	if (idp != NULL) {
489*9d26e4fcSRobert Mustacchi 		VERIFY(idp->id_nreg < idp->id_nfuncs);
490*9d26e4fcSRobert Mustacchi 		idp->id_nreg++;
491*9d26e4fcSRobert Mustacchi 	} else {
492*9d26e4fcSRobert Mustacchi 		i40e_hw_t *hw = &i40e->i40e_hw_space;
493*9d26e4fcSRobert Mustacchi 		ASSERT(hw->num_ports > 0);
494*9d26e4fcSRobert Mustacchi 		ASSERT(hw->num_partitions > 0);
495*9d26e4fcSRobert Mustacchi 
496*9d26e4fcSRobert Mustacchi 		/*
497*9d26e4fcSRobert Mustacchi 		 * The Intel common code doesn't exactly keep the number of PCI
498*9d26e4fcSRobert Mustacchi 		 * functions. But it calculates it during discovery of
499*9d26e4fcSRobert Mustacchi 		 * partitions and ports. So what we do is undo the calculation
500*9d26e4fcSRobert Mustacchi 		 * that it does originally, as functions are evenly spread
501*9d26e4fcSRobert Mustacchi 		 * across ports in the rare case of partitions.
502*9d26e4fcSRobert Mustacchi 		 */
503*9d26e4fcSRobert Mustacchi 		idp = kmem_alloc(sizeof (i40e_device_t), KM_SLEEP);
504*9d26e4fcSRobert Mustacchi 		idp->id_parent = parent;
505*9d26e4fcSRobert Mustacchi 		idp->id_pci_bus = bus;
506*9d26e4fcSRobert Mustacchi 		idp->id_pci_device = device;
507*9d26e4fcSRobert Mustacchi 		idp->id_nfuncs = hw->num_ports * hw->num_partitions;
508*9d26e4fcSRobert Mustacchi 		idp->id_nreg = 1;
509*9d26e4fcSRobert Mustacchi 		idp->id_rsrcs_alloc = i40e->i40e_switch_rsrc_alloc;
510*9d26e4fcSRobert Mustacchi 		idp->id_rsrcs_act = i40e->i40e_switch_rsrc_actual;
511*9d26e4fcSRobert Mustacchi 		idp->id_rsrcs = kmem_alloc(sizeof (i40e_switch_rsrc_t) *
512*9d26e4fcSRobert Mustacchi 		    idp->id_rsrcs_alloc, KM_SLEEP);
513*9d26e4fcSRobert Mustacchi 		bcopy(i40e->i40e_switch_rsrcs, idp->id_rsrcs,
514*9d26e4fcSRobert Mustacchi 		    sizeof (i40e_switch_rsrc_t) * idp->id_rsrcs_alloc);
515*9d26e4fcSRobert Mustacchi 		list_create(&idp->id_i40e_list, sizeof (i40e_t),
516*9d26e4fcSRobert Mustacchi 		    offsetof(i40e_t, i40e_dlink));
517*9d26e4fcSRobert Mustacchi 
518*9d26e4fcSRobert Mustacchi 		list_insert_tail(&i40e_dlist, idp);
519*9d26e4fcSRobert Mustacchi 	}
520*9d26e4fcSRobert Mustacchi 
521*9d26e4fcSRobert Mustacchi 	list_insert_tail(&idp->id_i40e_list, i40e);
522*9d26e4fcSRobert Mustacchi 	mutex_exit(&i40e_glock);
523*9d26e4fcSRobert Mustacchi 
524*9d26e4fcSRobert Mustacchi 	return (idp);
525*9d26e4fcSRobert Mustacchi }
526*9d26e4fcSRobert Mustacchi 
527*9d26e4fcSRobert Mustacchi static void
528*9d26e4fcSRobert Mustacchi i40e_link_state_set(i40e_t *i40e, link_state_t state)
529*9d26e4fcSRobert Mustacchi {
530*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_link_state == state)
531*9d26e4fcSRobert Mustacchi 		return;
532*9d26e4fcSRobert Mustacchi 
533*9d26e4fcSRobert Mustacchi 	i40e->i40e_link_state = state;
534*9d26e4fcSRobert Mustacchi 	mac_link_update(i40e->i40e_mac_hdl, i40e->i40e_link_state);
535*9d26e4fcSRobert Mustacchi }
536*9d26e4fcSRobert Mustacchi 
537*9d26e4fcSRobert Mustacchi /*
538*9d26e4fcSRobert Mustacchi  * This is a basic link check routine. Mostly we're using this just to see
539*9d26e4fcSRobert Mustacchi  * if we can get any accurate information about the state of the link being
540*9d26e4fcSRobert Mustacchi  * up or down, as well as updating the link state, speed, etc. information.
541*9d26e4fcSRobert Mustacchi  */
542*9d26e4fcSRobert Mustacchi void
543*9d26e4fcSRobert Mustacchi i40e_link_check(i40e_t *i40e)
544*9d26e4fcSRobert Mustacchi {
545*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
546*9d26e4fcSRobert Mustacchi 	boolean_t ls;
547*9d26e4fcSRobert Mustacchi 	int ret;
548*9d26e4fcSRobert Mustacchi 
549*9d26e4fcSRobert Mustacchi 	ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
550*9d26e4fcSRobert Mustacchi 
551*9d26e4fcSRobert Mustacchi 	hw->phy.get_link_info = B_TRUE;
552*9d26e4fcSRobert Mustacchi 	if ((ret = i40e_get_link_status(hw, &ls)) != I40E_SUCCESS) {
553*9d26e4fcSRobert Mustacchi 		i40e->i40e_s_link_status_errs++;
554*9d26e4fcSRobert Mustacchi 		i40e->i40e_s_link_status_lasterr = ret;
555*9d26e4fcSRobert Mustacchi 		return;
556*9d26e4fcSRobert Mustacchi 	}
557*9d26e4fcSRobert Mustacchi 
558*9d26e4fcSRobert Mustacchi 	/*
559*9d26e4fcSRobert Mustacchi 	 * Firmware abstracts all of the mac and phy information for us, so we
560*9d26e4fcSRobert Mustacchi 	 * can use i40e_get_link_status to determine the current state.
561*9d26e4fcSRobert Mustacchi 	 */
562*9d26e4fcSRobert Mustacchi 	if (ls == B_TRUE) {
563*9d26e4fcSRobert Mustacchi 		enum i40e_aq_link_speed speed;
564*9d26e4fcSRobert Mustacchi 
565*9d26e4fcSRobert Mustacchi 		speed = i40e_get_link_speed(hw);
566*9d26e4fcSRobert Mustacchi 
567*9d26e4fcSRobert Mustacchi 		/*
568*9d26e4fcSRobert Mustacchi 		 * Translate from an i40e value to a value in Mbits/s.
569*9d26e4fcSRobert Mustacchi 		 */
570*9d26e4fcSRobert Mustacchi 		switch (speed) {
571*9d26e4fcSRobert Mustacchi 		case I40E_LINK_SPEED_100MB:
572*9d26e4fcSRobert Mustacchi 			i40e->i40e_link_speed = 100;
573*9d26e4fcSRobert Mustacchi 			break;
574*9d26e4fcSRobert Mustacchi 		case I40E_LINK_SPEED_1GB:
575*9d26e4fcSRobert Mustacchi 			i40e->i40e_link_speed = 1000;
576*9d26e4fcSRobert Mustacchi 			break;
577*9d26e4fcSRobert Mustacchi 		case I40E_LINK_SPEED_10GB:
578*9d26e4fcSRobert Mustacchi 			i40e->i40e_link_speed = 10000;
579*9d26e4fcSRobert Mustacchi 			break;
580*9d26e4fcSRobert Mustacchi 		case I40E_LINK_SPEED_20GB:
581*9d26e4fcSRobert Mustacchi 			i40e->i40e_link_speed = 20000;
582*9d26e4fcSRobert Mustacchi 			break;
583*9d26e4fcSRobert Mustacchi 		case I40E_LINK_SPEED_40GB:
584*9d26e4fcSRobert Mustacchi 			i40e->i40e_link_speed = 40000;
585*9d26e4fcSRobert Mustacchi 			break;
586*9d26e4fcSRobert Mustacchi 		default:
587*9d26e4fcSRobert Mustacchi 			i40e->i40e_link_speed = 0;
588*9d26e4fcSRobert Mustacchi 			break;
589*9d26e4fcSRobert Mustacchi 		}
590*9d26e4fcSRobert Mustacchi 
591*9d26e4fcSRobert Mustacchi 		/*
592*9d26e4fcSRobert Mustacchi 		 * At this time, hardware does not support half-duplex
593*9d26e4fcSRobert Mustacchi 		 * operation, hence why we don't ask the hardware about our
594*9d26e4fcSRobert Mustacchi 		 * current speed.
595*9d26e4fcSRobert Mustacchi 		 */
596*9d26e4fcSRobert Mustacchi 		i40e->i40e_link_duplex = LINK_DUPLEX_FULL;
597*9d26e4fcSRobert Mustacchi 		i40e_link_state_set(i40e, LINK_STATE_UP);
598*9d26e4fcSRobert Mustacchi 	} else {
599*9d26e4fcSRobert Mustacchi 		i40e->i40e_link_speed = 0;
600*9d26e4fcSRobert Mustacchi 		i40e->i40e_link_duplex = 0;
601*9d26e4fcSRobert Mustacchi 		i40e_link_state_set(i40e, LINK_STATE_DOWN);
602*9d26e4fcSRobert Mustacchi 	}
603*9d26e4fcSRobert Mustacchi }
604*9d26e4fcSRobert Mustacchi 
605*9d26e4fcSRobert Mustacchi static void
606*9d26e4fcSRobert Mustacchi i40e_rem_intrs(i40e_t *i40e)
607*9d26e4fcSRobert Mustacchi {
608*9d26e4fcSRobert Mustacchi 	int i, rc;
609*9d26e4fcSRobert Mustacchi 
610*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_intr_count; i++) {
611*9d26e4fcSRobert Mustacchi 		rc = ddi_intr_free(i40e->i40e_intr_handles[i]);
612*9d26e4fcSRobert Mustacchi 		if (rc != DDI_SUCCESS) {
613*9d26e4fcSRobert Mustacchi 			i40e_log(i40e, "failed to free interrupt %d: %d",
614*9d26e4fcSRobert Mustacchi 			    i, rc);
615*9d26e4fcSRobert Mustacchi 		}
616*9d26e4fcSRobert Mustacchi 	}
617*9d26e4fcSRobert Mustacchi 
618*9d26e4fcSRobert Mustacchi 	kmem_free(i40e->i40e_intr_handles, i40e->i40e_intr_size);
619*9d26e4fcSRobert Mustacchi 	i40e->i40e_intr_handles = NULL;
620*9d26e4fcSRobert Mustacchi }
621*9d26e4fcSRobert Mustacchi 
622*9d26e4fcSRobert Mustacchi static void
623*9d26e4fcSRobert Mustacchi i40e_rem_intr_handlers(i40e_t *i40e)
624*9d26e4fcSRobert Mustacchi {
625*9d26e4fcSRobert Mustacchi 	int i, rc;
626*9d26e4fcSRobert Mustacchi 
627*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_intr_count; i++) {
628*9d26e4fcSRobert Mustacchi 		rc = ddi_intr_remove_handler(i40e->i40e_intr_handles[i]);
629*9d26e4fcSRobert Mustacchi 		if (rc != DDI_SUCCESS) {
630*9d26e4fcSRobert Mustacchi 			i40e_log(i40e, "failed to remove interrupt %d: %d",
631*9d26e4fcSRobert Mustacchi 			    i, rc);
632*9d26e4fcSRobert Mustacchi 		}
633*9d26e4fcSRobert Mustacchi 	}
634*9d26e4fcSRobert Mustacchi }
635*9d26e4fcSRobert Mustacchi 
636*9d26e4fcSRobert Mustacchi /*
637*9d26e4fcSRobert Mustacchi  * illumos Fault Management Architecture (FMA) support.
638*9d26e4fcSRobert Mustacchi  */
639*9d26e4fcSRobert Mustacchi 
640*9d26e4fcSRobert Mustacchi int
641*9d26e4fcSRobert Mustacchi i40e_check_acc_handle(ddi_acc_handle_t handle)
642*9d26e4fcSRobert Mustacchi {
643*9d26e4fcSRobert Mustacchi 	ddi_fm_error_t de;
644*9d26e4fcSRobert Mustacchi 
645*9d26e4fcSRobert Mustacchi 	ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
646*9d26e4fcSRobert Mustacchi 	ddi_fm_acc_err_clear(handle, DDI_FME_VERSION);
647*9d26e4fcSRobert Mustacchi 	return (de.fme_status);
648*9d26e4fcSRobert Mustacchi }
649*9d26e4fcSRobert Mustacchi 
650*9d26e4fcSRobert Mustacchi int
651*9d26e4fcSRobert Mustacchi i40e_check_dma_handle(ddi_dma_handle_t handle)
652*9d26e4fcSRobert Mustacchi {
653*9d26e4fcSRobert Mustacchi 	ddi_fm_error_t de;
654*9d26e4fcSRobert Mustacchi 
655*9d26e4fcSRobert Mustacchi 	ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
656*9d26e4fcSRobert Mustacchi 	return (de.fme_status);
657*9d26e4fcSRobert Mustacchi }
658*9d26e4fcSRobert Mustacchi 
659*9d26e4fcSRobert Mustacchi /*
660*9d26e4fcSRobert Mustacchi  * Fault service error handling callback function.
661*9d26e4fcSRobert Mustacchi  */
662*9d26e4fcSRobert Mustacchi /* ARGSUSED */
663*9d26e4fcSRobert Mustacchi static int
664*9d26e4fcSRobert Mustacchi i40e_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
665*9d26e4fcSRobert Mustacchi {
666*9d26e4fcSRobert Mustacchi 	pci_ereport_post(dip, err, NULL);
667*9d26e4fcSRobert Mustacchi 	return (err->fme_status);
668*9d26e4fcSRobert Mustacchi }
669*9d26e4fcSRobert Mustacchi 
670*9d26e4fcSRobert Mustacchi static void
671*9d26e4fcSRobert Mustacchi i40e_fm_init(i40e_t *i40e)
672*9d26e4fcSRobert Mustacchi {
673*9d26e4fcSRobert Mustacchi 	ddi_iblock_cookie_t iblk;
674*9d26e4fcSRobert Mustacchi 
675*9d26e4fcSRobert Mustacchi 	i40e->i40e_fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY,
676*9d26e4fcSRobert Mustacchi 	    i40e->i40e_dip, DDI_PROP_DONTPASS, "fm_capable",
677*9d26e4fcSRobert Mustacchi 	    DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
678*9d26e4fcSRobert Mustacchi 	    DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
679*9d26e4fcSRobert Mustacchi 
680*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_fm_capabilities < 0) {
681*9d26e4fcSRobert Mustacchi 		i40e->i40e_fm_capabilities = 0;
682*9d26e4fcSRobert Mustacchi 	} else if (i40e->i40e_fm_capabilities > 0xf) {
683*9d26e4fcSRobert Mustacchi 		i40e->i40e_fm_capabilities = DDI_FM_EREPORT_CAPABLE |
684*9d26e4fcSRobert Mustacchi 		    DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE |
685*9d26e4fcSRobert Mustacchi 		    DDI_FM_ERRCB_CAPABLE;
686*9d26e4fcSRobert Mustacchi 	}
687*9d26e4fcSRobert Mustacchi 
688*9d26e4fcSRobert Mustacchi 	/*
689*9d26e4fcSRobert Mustacchi 	 * Only register with IO Fault Services if we have some capability
690*9d26e4fcSRobert Mustacchi 	 */
691*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_fm_capabilities & DDI_FM_ACCCHK_CAPABLE) {
692*9d26e4fcSRobert Mustacchi 		i40e_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC;
693*9d26e4fcSRobert Mustacchi 	} else {
694*9d26e4fcSRobert Mustacchi 		i40e_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC;
695*9d26e4fcSRobert Mustacchi 	}
696*9d26e4fcSRobert Mustacchi 
697*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_fm_capabilities) {
698*9d26e4fcSRobert Mustacchi 		ddi_fm_init(i40e->i40e_dip, &i40e->i40e_fm_capabilities, &iblk);
699*9d26e4fcSRobert Mustacchi 
700*9d26e4fcSRobert Mustacchi 		if (DDI_FM_EREPORT_CAP(i40e->i40e_fm_capabilities) ||
701*9d26e4fcSRobert Mustacchi 		    DDI_FM_ERRCB_CAP(i40e->i40e_fm_capabilities)) {
702*9d26e4fcSRobert Mustacchi 			pci_ereport_setup(i40e->i40e_dip);
703*9d26e4fcSRobert Mustacchi 		}
704*9d26e4fcSRobert Mustacchi 
705*9d26e4fcSRobert Mustacchi 		if (DDI_FM_ERRCB_CAP(i40e->i40e_fm_capabilities)) {
706*9d26e4fcSRobert Mustacchi 			ddi_fm_handler_register(i40e->i40e_dip,
707*9d26e4fcSRobert Mustacchi 			    i40e_fm_error_cb, (void*)i40e);
708*9d26e4fcSRobert Mustacchi 		}
709*9d26e4fcSRobert Mustacchi 	}
710*9d26e4fcSRobert Mustacchi 
711*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_fm_capabilities & DDI_FM_DMACHK_CAPABLE) {
712*9d26e4fcSRobert Mustacchi 		i40e_init_dma_attrs(i40e, B_TRUE);
713*9d26e4fcSRobert Mustacchi 	} else {
714*9d26e4fcSRobert Mustacchi 		i40e_init_dma_attrs(i40e, B_FALSE);
715*9d26e4fcSRobert Mustacchi 	}
716*9d26e4fcSRobert Mustacchi }
717*9d26e4fcSRobert Mustacchi 
718*9d26e4fcSRobert Mustacchi static void
719*9d26e4fcSRobert Mustacchi i40e_fm_fini(i40e_t *i40e)
720*9d26e4fcSRobert Mustacchi {
721*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_fm_capabilities) {
722*9d26e4fcSRobert Mustacchi 
723*9d26e4fcSRobert Mustacchi 		if (DDI_FM_EREPORT_CAP(i40e->i40e_fm_capabilities) ||
724*9d26e4fcSRobert Mustacchi 		    DDI_FM_ERRCB_CAP(i40e->i40e_fm_capabilities))
725*9d26e4fcSRobert Mustacchi 			pci_ereport_teardown(i40e->i40e_dip);
726*9d26e4fcSRobert Mustacchi 
727*9d26e4fcSRobert Mustacchi 		if (DDI_FM_ERRCB_CAP(i40e->i40e_fm_capabilities))
728*9d26e4fcSRobert Mustacchi 			ddi_fm_handler_unregister(i40e->i40e_dip);
729*9d26e4fcSRobert Mustacchi 
730*9d26e4fcSRobert Mustacchi 		ddi_fm_fini(i40e->i40e_dip);
731*9d26e4fcSRobert Mustacchi 	}
732*9d26e4fcSRobert Mustacchi }
733*9d26e4fcSRobert Mustacchi 
734*9d26e4fcSRobert Mustacchi void
735*9d26e4fcSRobert Mustacchi i40e_fm_ereport(i40e_t *i40e, char *detail)
736*9d26e4fcSRobert Mustacchi {
737*9d26e4fcSRobert Mustacchi 	uint64_t ena;
738*9d26e4fcSRobert Mustacchi 	char buf[FM_MAX_CLASS];
739*9d26e4fcSRobert Mustacchi 
740*9d26e4fcSRobert Mustacchi 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
741*9d26e4fcSRobert Mustacchi 	ena = fm_ena_generate(0, FM_ENA_FMT1);
742*9d26e4fcSRobert Mustacchi 	if (DDI_FM_EREPORT_CAP(i40e->i40e_fm_capabilities)) {
743*9d26e4fcSRobert Mustacchi 		ddi_fm_ereport_post(i40e->i40e_dip, buf, ena, DDI_NOSLEEP,
744*9d26e4fcSRobert Mustacchi 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
745*9d26e4fcSRobert Mustacchi 	}
746*9d26e4fcSRobert Mustacchi }
747*9d26e4fcSRobert Mustacchi 
748*9d26e4fcSRobert Mustacchi /*
749*9d26e4fcSRobert Mustacchi  * Here we're trying to get the ID of the default VSI. In general, when we come
750*9d26e4fcSRobert Mustacchi  * through and look at this shortly after attach, we expect there to only be a
751*9d26e4fcSRobert Mustacchi  * single element present, which is the default VSI. Importantly, each PF seems
752*9d26e4fcSRobert Mustacchi  * to not see any other devices, in part because of the simple switch mode that
753*9d26e4fcSRobert Mustacchi  * we're using. If for some reason, we see more artifact, we'll need to revisit
754*9d26e4fcSRobert Mustacchi  * what we're doing here.
755*9d26e4fcSRobert Mustacchi  */
756*9d26e4fcSRobert Mustacchi static int
757*9d26e4fcSRobert Mustacchi i40e_get_vsi_id(i40e_t *i40e)
758*9d26e4fcSRobert Mustacchi {
759*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
760*9d26e4fcSRobert Mustacchi 	struct i40e_aqc_get_switch_config_resp *sw_config;
761*9d26e4fcSRobert Mustacchi 	uint8_t aq_buf[I40E_AQ_LARGE_BUF];
762*9d26e4fcSRobert Mustacchi 	uint16_t next = 0;
763*9d26e4fcSRobert Mustacchi 	int rc;
764*9d26e4fcSRobert Mustacchi 
765*9d26e4fcSRobert Mustacchi 	/* LINTED: E_BAD_PTR_CAST_ALIGN */
766*9d26e4fcSRobert Mustacchi 	sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
767*9d26e4fcSRobert Mustacchi 	rc = i40e_aq_get_switch_config(hw, sw_config, sizeof (aq_buf), &next,
768*9d26e4fcSRobert Mustacchi 	    NULL);
769*9d26e4fcSRobert Mustacchi 	if (rc != I40E_SUCCESS) {
770*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "i40e_aq_get_switch_config() failed %d: %d",
771*9d26e4fcSRobert Mustacchi 		    rc, hw->aq.asq_last_status);
772*9d26e4fcSRobert Mustacchi 		return (-1);
773*9d26e4fcSRobert Mustacchi 	}
774*9d26e4fcSRobert Mustacchi 
775*9d26e4fcSRobert Mustacchi 	if (LE_16(sw_config->header.num_reported) != 1) {
776*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "encountered multiple (%d) switching units "
777*9d26e4fcSRobert Mustacchi 		    "during attach, not proceeding",
778*9d26e4fcSRobert Mustacchi 		    LE_16(sw_config->header.num_reported));
779*9d26e4fcSRobert Mustacchi 		return (-1);
780*9d26e4fcSRobert Mustacchi 	}
781*9d26e4fcSRobert Mustacchi 
782*9d26e4fcSRobert Mustacchi 	return (sw_config->element[0].seid);
783*9d26e4fcSRobert Mustacchi }
784*9d26e4fcSRobert Mustacchi 
785*9d26e4fcSRobert Mustacchi /*
786*9d26e4fcSRobert Mustacchi  * We need to fill the i40e_hw_t structure with the capabilities of this PF. We
787*9d26e4fcSRobert Mustacchi  * must also provide the memory for it; however, we don't need to keep it around
788*9d26e4fcSRobert Mustacchi  * to the call to the common code. It takes it and parses it into an internal
789*9d26e4fcSRobert Mustacchi  * structure.
790*9d26e4fcSRobert Mustacchi  */
791*9d26e4fcSRobert Mustacchi static boolean_t
792*9d26e4fcSRobert Mustacchi i40e_get_hw_capabilities(i40e_t *i40e, i40e_hw_t *hw)
793*9d26e4fcSRobert Mustacchi {
794*9d26e4fcSRobert Mustacchi 	struct i40e_aqc_list_capabilities_element_resp *buf;
795*9d26e4fcSRobert Mustacchi 	int rc;
796*9d26e4fcSRobert Mustacchi 	size_t len;
797*9d26e4fcSRobert Mustacchi 	uint16_t needed;
798*9d26e4fcSRobert Mustacchi 	int nelems = I40E_HW_CAP_DEFAULT;
799*9d26e4fcSRobert Mustacchi 
800*9d26e4fcSRobert Mustacchi 	len = nelems * sizeof (*buf);
801*9d26e4fcSRobert Mustacchi 
802*9d26e4fcSRobert Mustacchi 	for (;;) {
803*9d26e4fcSRobert Mustacchi 		ASSERT(len > 0);
804*9d26e4fcSRobert Mustacchi 		buf = kmem_alloc(len, KM_SLEEP);
805*9d26e4fcSRobert Mustacchi 		rc = i40e_aq_discover_capabilities(hw, buf, len,
806*9d26e4fcSRobert Mustacchi 		    &needed, i40e_aqc_opc_list_func_capabilities, NULL);
807*9d26e4fcSRobert Mustacchi 		kmem_free(buf, len);
808*9d26e4fcSRobert Mustacchi 
809*9d26e4fcSRobert Mustacchi 		if (hw->aq.asq_last_status == I40E_AQ_RC_ENOMEM &&
810*9d26e4fcSRobert Mustacchi 		    nelems == I40E_HW_CAP_DEFAULT) {
811*9d26e4fcSRobert Mustacchi 			if (nelems == needed) {
812*9d26e4fcSRobert Mustacchi 				i40e_error(i40e, "Capability discovery failed "
813*9d26e4fcSRobert Mustacchi 				    "due to byzantine common code");
814*9d26e4fcSRobert Mustacchi 				return (B_FALSE);
815*9d26e4fcSRobert Mustacchi 			}
816*9d26e4fcSRobert Mustacchi 			len = needed;
817*9d26e4fcSRobert Mustacchi 			continue;
818*9d26e4fcSRobert Mustacchi 		} else if (rc != I40E_SUCCESS ||
819*9d26e4fcSRobert Mustacchi 		    hw->aq.asq_last_status != I40E_AQ_RC_OK) {
820*9d26e4fcSRobert Mustacchi 			i40e_error(i40e, "Capability discovery failed: %d", rc);
821*9d26e4fcSRobert Mustacchi 			return (B_FALSE);
822*9d26e4fcSRobert Mustacchi 		}
823*9d26e4fcSRobert Mustacchi 
824*9d26e4fcSRobert Mustacchi 		break;
825*9d26e4fcSRobert Mustacchi 	}
826*9d26e4fcSRobert Mustacchi 
827*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
828*9d26e4fcSRobert Mustacchi }
829*9d26e4fcSRobert Mustacchi 
830*9d26e4fcSRobert Mustacchi /*
831*9d26e4fcSRobert Mustacchi  * Obtain the switch's capabilities as seen by this PF and keep it around for
832*9d26e4fcSRobert Mustacchi  * our later use.
833*9d26e4fcSRobert Mustacchi  */
834*9d26e4fcSRobert Mustacchi static boolean_t
835*9d26e4fcSRobert Mustacchi i40e_get_switch_resources(i40e_t *i40e)
836*9d26e4fcSRobert Mustacchi {
837*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
838*9d26e4fcSRobert Mustacchi 	uint8_t cnt = 2;
839*9d26e4fcSRobert Mustacchi 	uint8_t act;
840*9d26e4fcSRobert Mustacchi 	size_t size;
841*9d26e4fcSRobert Mustacchi 	i40e_switch_rsrc_t *buf;
842*9d26e4fcSRobert Mustacchi 
843*9d26e4fcSRobert Mustacchi 	for (;;) {
844*9d26e4fcSRobert Mustacchi 		enum i40e_status_code ret;
845*9d26e4fcSRobert Mustacchi 		size = cnt * sizeof (i40e_switch_rsrc_t);
846*9d26e4fcSRobert Mustacchi 		ASSERT(size > 0);
847*9d26e4fcSRobert Mustacchi 		if (size > UINT16_MAX)
848*9d26e4fcSRobert Mustacchi 			return (B_FALSE);
849*9d26e4fcSRobert Mustacchi 		buf = kmem_alloc(size, KM_SLEEP);
850*9d26e4fcSRobert Mustacchi 
851*9d26e4fcSRobert Mustacchi 		ret = i40e_aq_get_switch_resource_alloc(hw, &act, buf,
852*9d26e4fcSRobert Mustacchi 		    cnt, NULL);
853*9d26e4fcSRobert Mustacchi 		if (ret == I40E_ERR_ADMIN_QUEUE_ERROR &&
854*9d26e4fcSRobert Mustacchi 		    hw->aq.asq_last_status == I40E_AQ_RC_EINVAL) {
855*9d26e4fcSRobert Mustacchi 			kmem_free(buf, size);
856*9d26e4fcSRobert Mustacchi 			cnt += I40E_SWITCH_CAP_DEFAULT;
857*9d26e4fcSRobert Mustacchi 			continue;
858*9d26e4fcSRobert Mustacchi 		} else if (ret != I40E_SUCCESS) {
859*9d26e4fcSRobert Mustacchi 			kmem_free(buf, size);
860*9d26e4fcSRobert Mustacchi 			i40e_error(i40e,
861*9d26e4fcSRobert Mustacchi 			    "failed to retrieve switch statistics: %d", ret);
862*9d26e4fcSRobert Mustacchi 			return (B_FALSE);
863*9d26e4fcSRobert Mustacchi 		}
864*9d26e4fcSRobert Mustacchi 
865*9d26e4fcSRobert Mustacchi 		break;
866*9d26e4fcSRobert Mustacchi 	}
867*9d26e4fcSRobert Mustacchi 
868*9d26e4fcSRobert Mustacchi 	i40e->i40e_switch_rsrc_alloc = cnt;
869*9d26e4fcSRobert Mustacchi 	i40e->i40e_switch_rsrc_actual = act;
870*9d26e4fcSRobert Mustacchi 	i40e->i40e_switch_rsrcs = buf;
871*9d26e4fcSRobert Mustacchi 
872*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
873*9d26e4fcSRobert Mustacchi }
874*9d26e4fcSRobert Mustacchi 
875*9d26e4fcSRobert Mustacchi static void
876*9d26e4fcSRobert Mustacchi i40e_cleanup_resources(i40e_t *i40e)
877*9d26e4fcSRobert Mustacchi {
878*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_uaddrs != NULL) {
879*9d26e4fcSRobert Mustacchi 		kmem_free(i40e->i40e_uaddrs, sizeof (i40e_uaddr_t) *
880*9d26e4fcSRobert Mustacchi 		    i40e->i40e_resources.ifr_nmacfilt);
881*9d26e4fcSRobert Mustacchi 		i40e->i40e_uaddrs = NULL;
882*9d26e4fcSRobert Mustacchi 	}
883*9d26e4fcSRobert Mustacchi 
884*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_maddrs != NULL) {
885*9d26e4fcSRobert Mustacchi 		kmem_free(i40e->i40e_maddrs, sizeof (i40e_maddr_t) *
886*9d26e4fcSRobert Mustacchi 		    i40e->i40e_resources.ifr_nmcastfilt);
887*9d26e4fcSRobert Mustacchi 		i40e->i40e_maddrs = NULL;
888*9d26e4fcSRobert Mustacchi 	}
889*9d26e4fcSRobert Mustacchi 
890*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_switch_rsrcs != NULL) {
891*9d26e4fcSRobert Mustacchi 		size_t sz = sizeof (i40e_switch_rsrc_t) *
892*9d26e4fcSRobert Mustacchi 		    i40e->i40e_switch_rsrc_alloc;
893*9d26e4fcSRobert Mustacchi 		ASSERT(sz > 0);
894*9d26e4fcSRobert Mustacchi 		kmem_free(i40e->i40e_switch_rsrcs, sz);
895*9d26e4fcSRobert Mustacchi 		i40e->i40e_switch_rsrcs = NULL;
896*9d26e4fcSRobert Mustacchi 	}
897*9d26e4fcSRobert Mustacchi 
898*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_device != NULL)
899*9d26e4fcSRobert Mustacchi 		i40e_device_rele(i40e);
900*9d26e4fcSRobert Mustacchi }
901*9d26e4fcSRobert Mustacchi 
902*9d26e4fcSRobert Mustacchi static boolean_t
903*9d26e4fcSRobert Mustacchi i40e_get_available_resources(i40e_t *i40e)
904*9d26e4fcSRobert Mustacchi {
905*9d26e4fcSRobert Mustacchi 	dev_info_t *parent;
906*9d26e4fcSRobert Mustacchi 	uint16_t bus, device, func;
907*9d26e4fcSRobert Mustacchi 	uint_t nregs;
908*9d26e4fcSRobert Mustacchi 	int *regs, i;
909*9d26e4fcSRobert Mustacchi 	i40e_device_t *idp;
910*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
911*9d26e4fcSRobert Mustacchi 
912*9d26e4fcSRobert Mustacchi 	parent = ddi_get_parent(i40e->i40e_dip);
913*9d26e4fcSRobert Mustacchi 
914*9d26e4fcSRobert Mustacchi 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, i40e->i40e_dip, 0, "reg",
915*9d26e4fcSRobert Mustacchi 	    &regs, &nregs) != DDI_PROP_SUCCESS) {
916*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
917*9d26e4fcSRobert Mustacchi 	}
918*9d26e4fcSRobert Mustacchi 
919*9d26e4fcSRobert Mustacchi 	if (nregs < 1) {
920*9d26e4fcSRobert Mustacchi 		ddi_prop_free(regs);
921*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
922*9d26e4fcSRobert Mustacchi 	}
923*9d26e4fcSRobert Mustacchi 
924*9d26e4fcSRobert Mustacchi 	bus = PCI_REG_BUS_G(regs[0]);
925*9d26e4fcSRobert Mustacchi 	device = PCI_REG_DEV_G(regs[0]);
926*9d26e4fcSRobert Mustacchi 	func = PCI_REG_FUNC_G(regs[0]);
927*9d26e4fcSRobert Mustacchi 	ddi_prop_free(regs);
928*9d26e4fcSRobert Mustacchi 
929*9d26e4fcSRobert Mustacchi 	i40e->i40e_hw_space.bus.func = func;
930*9d26e4fcSRobert Mustacchi 	i40e->i40e_hw_space.bus.device = device;
931*9d26e4fcSRobert Mustacchi 
932*9d26e4fcSRobert Mustacchi 	if (i40e_get_switch_resources(i40e) == B_FALSE) {
933*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
934*9d26e4fcSRobert Mustacchi 	}
935*9d26e4fcSRobert Mustacchi 
936*9d26e4fcSRobert Mustacchi 	/*
937*9d26e4fcSRobert Mustacchi 	 * To calculate the total amount of a resource we have available, we
938*9d26e4fcSRobert Mustacchi 	 * need to add how many our i40e_t thinks it has guaranteed, if any, and
939*9d26e4fcSRobert Mustacchi 	 * then we need to go through and divide the number of available on the
940*9d26e4fcSRobert Mustacchi 	 * device, which was snapshotted before anyone should have allocated
941*9d26e4fcSRobert Mustacchi 	 * anything, and use that to derive how many are available from the
942*9d26e4fcSRobert Mustacchi 	 * pool. Longer term, we may want to turn this into something that's
943*9d26e4fcSRobert Mustacchi 	 * more of a pool-like resource that everything can share (though that
944*9d26e4fcSRobert Mustacchi 	 * may require some more assistance from MAC).
945*9d26e4fcSRobert Mustacchi 	 *
946*9d26e4fcSRobert Mustacchi 	 * Though for transmit and receive queue pairs, we just have to ask
947*9d26e4fcSRobert Mustacchi 	 * firmware instead.
948*9d26e4fcSRobert Mustacchi 	 */
949*9d26e4fcSRobert Mustacchi 	idp = i40e_device_find(i40e, parent, bus, device);
950*9d26e4fcSRobert Mustacchi 	i40e->i40e_device = idp;
951*9d26e4fcSRobert Mustacchi 	i40e->i40e_resources.ifr_nvsis = 0;
952*9d26e4fcSRobert Mustacchi 	i40e->i40e_resources.ifr_nvsis_used = 0;
953*9d26e4fcSRobert Mustacchi 	i40e->i40e_resources.ifr_nmacfilt = 0;
954*9d26e4fcSRobert Mustacchi 	i40e->i40e_resources.ifr_nmacfilt_used = 0;
955*9d26e4fcSRobert Mustacchi 	i40e->i40e_resources.ifr_nmcastfilt = 0;
956*9d26e4fcSRobert Mustacchi 	i40e->i40e_resources.ifr_nmcastfilt_used = 0;
957*9d26e4fcSRobert Mustacchi 
958*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_switch_rsrc_actual; i++) {
959*9d26e4fcSRobert Mustacchi 		i40e_switch_rsrc_t *srp = &i40e->i40e_switch_rsrcs[i];
960*9d26e4fcSRobert Mustacchi 
961*9d26e4fcSRobert Mustacchi 		switch (srp->resource_type) {
962*9d26e4fcSRobert Mustacchi 		case I40E_AQ_RESOURCE_TYPE_VSI:
963*9d26e4fcSRobert Mustacchi 			i40e->i40e_resources.ifr_nvsis +=
964*9d26e4fcSRobert Mustacchi 			    LE_16(srp->guaranteed);
965*9d26e4fcSRobert Mustacchi 			i40e->i40e_resources.ifr_nvsis_used = LE_16(srp->used);
966*9d26e4fcSRobert Mustacchi 			break;
967*9d26e4fcSRobert Mustacchi 		case I40E_AQ_RESOURCE_TYPE_MACADDR:
968*9d26e4fcSRobert Mustacchi 			i40e->i40e_resources.ifr_nmacfilt +=
969*9d26e4fcSRobert Mustacchi 			    LE_16(srp->guaranteed);
970*9d26e4fcSRobert Mustacchi 			i40e->i40e_resources.ifr_nmacfilt_used =
971*9d26e4fcSRobert Mustacchi 			    LE_16(srp->used);
972*9d26e4fcSRobert Mustacchi 			break;
973*9d26e4fcSRobert Mustacchi 		case I40E_AQ_RESOURCE_TYPE_MULTICAST_HASH:
974*9d26e4fcSRobert Mustacchi 			i40e->i40e_resources.ifr_nmcastfilt +=
975*9d26e4fcSRobert Mustacchi 			    LE_16(srp->guaranteed);
976*9d26e4fcSRobert Mustacchi 			i40e->i40e_resources.ifr_nmcastfilt_used =
977*9d26e4fcSRobert Mustacchi 			    LE_16(srp->used);
978*9d26e4fcSRobert Mustacchi 			break;
979*9d26e4fcSRobert Mustacchi 		default:
980*9d26e4fcSRobert Mustacchi 			break;
981*9d26e4fcSRobert Mustacchi 		}
982*9d26e4fcSRobert Mustacchi 	}
983*9d26e4fcSRobert Mustacchi 
984*9d26e4fcSRobert Mustacchi 	for (i = 0; i < idp->id_rsrcs_act; i++) {
985*9d26e4fcSRobert Mustacchi 		i40e_switch_rsrc_t *srp = &i40e->i40e_switch_rsrcs[i];
986*9d26e4fcSRobert Mustacchi 		switch (srp->resource_type) {
987*9d26e4fcSRobert Mustacchi 		case I40E_AQ_RESOURCE_TYPE_VSI:
988*9d26e4fcSRobert Mustacchi 			i40e->i40e_resources.ifr_nvsis +=
989*9d26e4fcSRobert Mustacchi 			    LE_16(srp->total_unalloced) / idp->id_nfuncs;
990*9d26e4fcSRobert Mustacchi 			break;
991*9d26e4fcSRobert Mustacchi 		case I40E_AQ_RESOURCE_TYPE_MACADDR:
992*9d26e4fcSRobert Mustacchi 			i40e->i40e_resources.ifr_nmacfilt +=
993*9d26e4fcSRobert Mustacchi 			    LE_16(srp->total_unalloced) / idp->id_nfuncs;
994*9d26e4fcSRobert Mustacchi 			break;
995*9d26e4fcSRobert Mustacchi 		case I40E_AQ_RESOURCE_TYPE_MULTICAST_HASH:
996*9d26e4fcSRobert Mustacchi 			i40e->i40e_resources.ifr_nmcastfilt +=
997*9d26e4fcSRobert Mustacchi 			    LE_16(srp->total_unalloced) / idp->id_nfuncs;
998*9d26e4fcSRobert Mustacchi 		default:
999*9d26e4fcSRobert Mustacchi 			break;
1000*9d26e4fcSRobert Mustacchi 		}
1001*9d26e4fcSRobert Mustacchi 	}
1002*9d26e4fcSRobert Mustacchi 
1003*9d26e4fcSRobert Mustacchi 	i40e->i40e_resources.ifr_nrx_queue = hw->func_caps.num_rx_qp;
1004*9d26e4fcSRobert Mustacchi 	i40e->i40e_resources.ifr_ntx_queue = hw->func_caps.num_tx_qp;
1005*9d26e4fcSRobert Mustacchi 
1006*9d26e4fcSRobert Mustacchi 	i40e->i40e_uaddrs = kmem_zalloc(sizeof (i40e_uaddr_t) *
1007*9d26e4fcSRobert Mustacchi 	    i40e->i40e_resources.ifr_nmacfilt, KM_SLEEP);
1008*9d26e4fcSRobert Mustacchi 	i40e->i40e_maddrs = kmem_zalloc(sizeof (i40e_maddr_t) *
1009*9d26e4fcSRobert Mustacchi 	    i40e->i40e_resources.ifr_nmcastfilt, KM_SLEEP);
1010*9d26e4fcSRobert Mustacchi 
1011*9d26e4fcSRobert Mustacchi 	/*
1012*9d26e4fcSRobert Mustacchi 	 * Initialize these as multicast addresses to indicate it's invalid for
1013*9d26e4fcSRobert Mustacchi 	 * sanity purposes. Think of it like 0xdeadbeef.
1014*9d26e4fcSRobert Mustacchi 	 */
1015*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_resources.ifr_nmacfilt; i++)
1016*9d26e4fcSRobert Mustacchi 		i40e->i40e_uaddrs[i].iua_mac[0] = 0x01;
1017*9d26e4fcSRobert Mustacchi 
1018*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
1019*9d26e4fcSRobert Mustacchi }
1020*9d26e4fcSRobert Mustacchi 
1021*9d26e4fcSRobert Mustacchi static boolean_t
1022*9d26e4fcSRobert Mustacchi i40e_enable_interrupts(i40e_t *i40e)
1023*9d26e4fcSRobert Mustacchi {
1024*9d26e4fcSRobert Mustacchi 	int i, rc;
1025*9d26e4fcSRobert Mustacchi 
1026*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_intr_cap & DDI_INTR_FLAG_BLOCK) {
1027*9d26e4fcSRobert Mustacchi 		rc = ddi_intr_block_enable(i40e->i40e_intr_handles,
1028*9d26e4fcSRobert Mustacchi 		    i40e->i40e_intr_count);
1029*9d26e4fcSRobert Mustacchi 		if (rc != DDI_SUCCESS) {
1030*9d26e4fcSRobert Mustacchi 			i40e_error(i40e, "Interrupt block-enable failed: %d",
1031*9d26e4fcSRobert Mustacchi 			    rc);
1032*9d26e4fcSRobert Mustacchi 			return (B_FALSE);
1033*9d26e4fcSRobert Mustacchi 		}
1034*9d26e4fcSRobert Mustacchi 	} else {
1035*9d26e4fcSRobert Mustacchi 		for (i = 0; i < i40e->i40e_intr_count; i++) {
1036*9d26e4fcSRobert Mustacchi 			rc = ddi_intr_enable(i40e->i40e_intr_handles[i]);
1037*9d26e4fcSRobert Mustacchi 			if (rc != DDI_SUCCESS) {
1038*9d26e4fcSRobert Mustacchi 				i40e_error(i40e,
1039*9d26e4fcSRobert Mustacchi 				    "Failed to enable interrupt %d: %d", i, rc);
1040*9d26e4fcSRobert Mustacchi 				while (--i >= 0) {
1041*9d26e4fcSRobert Mustacchi 					(void) ddi_intr_disable(
1042*9d26e4fcSRobert Mustacchi 					    i40e->i40e_intr_handles[i]);
1043*9d26e4fcSRobert Mustacchi 				}
1044*9d26e4fcSRobert Mustacchi 				return (B_FALSE);
1045*9d26e4fcSRobert Mustacchi 			}
1046*9d26e4fcSRobert Mustacchi 		}
1047*9d26e4fcSRobert Mustacchi 	}
1048*9d26e4fcSRobert Mustacchi 
1049*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
1050*9d26e4fcSRobert Mustacchi }
1051*9d26e4fcSRobert Mustacchi 
1052*9d26e4fcSRobert Mustacchi static boolean_t
1053*9d26e4fcSRobert Mustacchi i40e_disable_interrupts(i40e_t *i40e)
1054*9d26e4fcSRobert Mustacchi {
1055*9d26e4fcSRobert Mustacchi 	int i, rc;
1056*9d26e4fcSRobert Mustacchi 
1057*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_intr_cap & DDI_INTR_FLAG_BLOCK) {
1058*9d26e4fcSRobert Mustacchi 		rc = ddi_intr_block_disable(i40e->i40e_intr_handles,
1059*9d26e4fcSRobert Mustacchi 		    i40e->i40e_intr_count);
1060*9d26e4fcSRobert Mustacchi 		if (rc != DDI_SUCCESS) {
1061*9d26e4fcSRobert Mustacchi 			i40e_error(i40e,
1062*9d26e4fcSRobert Mustacchi 			    "Interrupt block-disabled failed: %d", rc);
1063*9d26e4fcSRobert Mustacchi 			return (B_FALSE);
1064*9d26e4fcSRobert Mustacchi 		}
1065*9d26e4fcSRobert Mustacchi 	} else {
1066*9d26e4fcSRobert Mustacchi 		for (i = 0; i < i40e->i40e_intr_count; i++) {
1067*9d26e4fcSRobert Mustacchi 			rc = ddi_intr_disable(i40e->i40e_intr_handles[i]);
1068*9d26e4fcSRobert Mustacchi 			if (rc != DDI_SUCCESS) {
1069*9d26e4fcSRobert Mustacchi 				i40e_error(i40e,
1070*9d26e4fcSRobert Mustacchi 				    "Failed to disable interrupt %d: %d",
1071*9d26e4fcSRobert Mustacchi 				    i, rc);
1072*9d26e4fcSRobert Mustacchi 				return (B_FALSE);
1073*9d26e4fcSRobert Mustacchi 			}
1074*9d26e4fcSRobert Mustacchi 		}
1075*9d26e4fcSRobert Mustacchi 	}
1076*9d26e4fcSRobert Mustacchi 
1077*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
1078*9d26e4fcSRobert Mustacchi }
1079*9d26e4fcSRobert Mustacchi 
1080*9d26e4fcSRobert Mustacchi /*
1081*9d26e4fcSRobert Mustacchi  * Free receive & transmit rings.
1082*9d26e4fcSRobert Mustacchi  */
1083*9d26e4fcSRobert Mustacchi static void
1084*9d26e4fcSRobert Mustacchi i40e_free_trqpairs(i40e_t *i40e)
1085*9d26e4fcSRobert Mustacchi {
1086*9d26e4fcSRobert Mustacchi 	int i;
1087*9d26e4fcSRobert Mustacchi 	i40e_trqpair_t *itrq;
1088*9d26e4fcSRobert Mustacchi 
1089*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_trqpairs != NULL) {
1090*9d26e4fcSRobert Mustacchi 		for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
1091*9d26e4fcSRobert Mustacchi 			itrq = &i40e->i40e_trqpairs[i];
1092*9d26e4fcSRobert Mustacchi 			mutex_destroy(&itrq->itrq_rx_lock);
1093*9d26e4fcSRobert Mustacchi 			mutex_destroy(&itrq->itrq_tx_lock);
1094*9d26e4fcSRobert Mustacchi 			mutex_destroy(&itrq->itrq_tcb_lock);
1095*9d26e4fcSRobert Mustacchi 
1096*9d26e4fcSRobert Mustacchi 			/*
1097*9d26e4fcSRobert Mustacchi 			 * Should have already been cleaned up by start/stop,
1098*9d26e4fcSRobert Mustacchi 			 * etc.
1099*9d26e4fcSRobert Mustacchi 			 */
1100*9d26e4fcSRobert Mustacchi 			ASSERT(itrq->itrq_txkstat == NULL);
1101*9d26e4fcSRobert Mustacchi 			ASSERT(itrq->itrq_rxkstat == NULL);
1102*9d26e4fcSRobert Mustacchi 		}
1103*9d26e4fcSRobert Mustacchi 
1104*9d26e4fcSRobert Mustacchi 		kmem_free(i40e->i40e_trqpairs,
1105*9d26e4fcSRobert Mustacchi 		    sizeof (i40e_trqpair_t) * i40e->i40e_num_trqpairs);
1106*9d26e4fcSRobert Mustacchi 		i40e->i40e_trqpairs = NULL;
1107*9d26e4fcSRobert Mustacchi 	}
1108*9d26e4fcSRobert Mustacchi 
1109*9d26e4fcSRobert Mustacchi 	cv_destroy(&i40e->i40e_rx_pending_cv);
1110*9d26e4fcSRobert Mustacchi 	mutex_destroy(&i40e->i40e_rx_pending_lock);
1111*9d26e4fcSRobert Mustacchi 	mutex_destroy(&i40e->i40e_general_lock);
1112*9d26e4fcSRobert Mustacchi }
1113*9d26e4fcSRobert Mustacchi 
1114*9d26e4fcSRobert Mustacchi /*
1115*9d26e4fcSRobert Mustacchi  * Allocate transmit and receive rings, as well as other data structures that we
1116*9d26e4fcSRobert Mustacchi  * need.
1117*9d26e4fcSRobert Mustacchi  */
1118*9d26e4fcSRobert Mustacchi static boolean_t
1119*9d26e4fcSRobert Mustacchi i40e_alloc_trqpairs(i40e_t *i40e)
1120*9d26e4fcSRobert Mustacchi {
1121*9d26e4fcSRobert Mustacchi 	int i;
1122*9d26e4fcSRobert Mustacchi 	void *mutexpri = DDI_INTR_PRI(i40e->i40e_intr_pri);
1123*9d26e4fcSRobert Mustacchi 
1124*9d26e4fcSRobert Mustacchi 	/*
1125*9d26e4fcSRobert Mustacchi 	 * Now that we have the priority for the interrupts, initialize
1126*9d26e4fcSRobert Mustacchi 	 * all relevant locks.
1127*9d26e4fcSRobert Mustacchi 	 */
1128*9d26e4fcSRobert Mustacchi 	mutex_init(&i40e->i40e_general_lock, NULL, MUTEX_DRIVER, mutexpri);
1129*9d26e4fcSRobert Mustacchi 	mutex_init(&i40e->i40e_rx_pending_lock, NULL, MUTEX_DRIVER, mutexpri);
1130*9d26e4fcSRobert Mustacchi 	cv_init(&i40e->i40e_rx_pending_cv, NULL, CV_DRIVER, NULL);
1131*9d26e4fcSRobert Mustacchi 
1132*9d26e4fcSRobert Mustacchi 	i40e->i40e_trqpairs = kmem_zalloc(sizeof (i40e_trqpair_t) *
1133*9d26e4fcSRobert Mustacchi 	    i40e->i40e_num_trqpairs, KM_SLEEP);
1134*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
1135*9d26e4fcSRobert Mustacchi 		i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[i];
1136*9d26e4fcSRobert Mustacchi 
1137*9d26e4fcSRobert Mustacchi 		itrq->itrq_i40e = i40e;
1138*9d26e4fcSRobert Mustacchi 		mutex_init(&itrq->itrq_rx_lock, NULL, MUTEX_DRIVER, mutexpri);
1139*9d26e4fcSRobert Mustacchi 		mutex_init(&itrq->itrq_tx_lock, NULL, MUTEX_DRIVER, mutexpri);
1140*9d26e4fcSRobert Mustacchi 		mutex_init(&itrq->itrq_tcb_lock, NULL, MUTEX_DRIVER, mutexpri);
1141*9d26e4fcSRobert Mustacchi 		itrq->itrq_index = i;
1142*9d26e4fcSRobert Mustacchi 	}
1143*9d26e4fcSRobert Mustacchi 
1144*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
1145*9d26e4fcSRobert Mustacchi }
1146*9d26e4fcSRobert Mustacchi 
1147*9d26e4fcSRobert Mustacchi 
1148*9d26e4fcSRobert Mustacchi 
1149*9d26e4fcSRobert Mustacchi /*
1150*9d26e4fcSRobert Mustacchi  * Unless a .conf file already overrode i40e_t structure values, they will
1151*9d26e4fcSRobert Mustacchi  * be 0, and need to be set in conjunction with the now-available HW report.
1152*9d26e4fcSRobert Mustacchi  *
1153*9d26e4fcSRobert Mustacchi  * However, at the moment, we cap all of these resources as we only support a
1154*9d26e4fcSRobert Mustacchi  * single receive ring and a single group.
1155*9d26e4fcSRobert Mustacchi  */
1156*9d26e4fcSRobert Mustacchi /* ARGSUSED */
1157*9d26e4fcSRobert Mustacchi static void
1158*9d26e4fcSRobert Mustacchi i40e_hw_to_instance(i40e_t *i40e, i40e_hw_t *hw)
1159*9d26e4fcSRobert Mustacchi {
1160*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_num_trqpairs == 0) {
1161*9d26e4fcSRobert Mustacchi 		i40e->i40e_num_trqpairs = I40E_TRQPAIR_MAX;
1162*9d26e4fcSRobert Mustacchi 	}
1163*9d26e4fcSRobert Mustacchi 
1164*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_num_rx_groups == 0) {
1165*9d26e4fcSRobert Mustacchi 		i40e->i40e_num_rx_groups = I40E_GROUP_MAX;
1166*9d26e4fcSRobert Mustacchi 	}
1167*9d26e4fcSRobert Mustacchi }
1168*9d26e4fcSRobert Mustacchi 
1169*9d26e4fcSRobert Mustacchi /*
1170*9d26e4fcSRobert Mustacchi  * Free any resources required by, or setup by, the Intel common code.
1171*9d26e4fcSRobert Mustacchi  */
1172*9d26e4fcSRobert Mustacchi static void
1173*9d26e4fcSRobert Mustacchi i40e_common_code_fini(i40e_t *i40e)
1174*9d26e4fcSRobert Mustacchi {
1175*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
1176*9d26e4fcSRobert Mustacchi 	int rc;
1177*9d26e4fcSRobert Mustacchi 
1178*9d26e4fcSRobert Mustacchi 	rc = i40e_shutdown_lan_hmc(hw);
1179*9d26e4fcSRobert Mustacchi 	if (rc != I40E_SUCCESS)
1180*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to shutdown LAN hmc: %d", rc);
1181*9d26e4fcSRobert Mustacchi 
1182*9d26e4fcSRobert Mustacchi 	rc = i40e_shutdown_adminq(hw);
1183*9d26e4fcSRobert Mustacchi 	if (rc != I40E_SUCCESS)
1184*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to shutdown admin queue: %d", rc);
1185*9d26e4fcSRobert Mustacchi }
1186*9d26e4fcSRobert Mustacchi 
1187*9d26e4fcSRobert Mustacchi /*
1188*9d26e4fcSRobert Mustacchi  * Initialize and call Intel common-code routines, includes some setup
1189*9d26e4fcSRobert Mustacchi  * the common code expects from the driver.  Also prints on failure, so
1190*9d26e4fcSRobert Mustacchi  * the caller doesn't have to.
1191*9d26e4fcSRobert Mustacchi  */
1192*9d26e4fcSRobert Mustacchi static boolean_t
1193*9d26e4fcSRobert Mustacchi i40e_common_code_init(i40e_t *i40e, i40e_hw_t *hw)
1194*9d26e4fcSRobert Mustacchi {
1195*9d26e4fcSRobert Mustacchi 	int rc;
1196*9d26e4fcSRobert Mustacchi 
1197*9d26e4fcSRobert Mustacchi 	i40e_clear_hw(hw);
1198*9d26e4fcSRobert Mustacchi 	rc = i40e_pf_reset(hw);
1199*9d26e4fcSRobert Mustacchi 	if (rc != 0) {
1200*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to reset hardware: %d", rc);
1201*9d26e4fcSRobert Mustacchi 		i40e_fm_ereport(i40e, DDI_FM_DEVICE_NO_RESPONSE);
1202*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1203*9d26e4fcSRobert Mustacchi 	}
1204*9d26e4fcSRobert Mustacchi 
1205*9d26e4fcSRobert Mustacchi 	rc = i40e_init_shared_code(hw);
1206*9d26e4fcSRobert Mustacchi 	if (rc != 0) {
1207*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to initialize i40e core: %d", rc);
1208*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1209*9d26e4fcSRobert Mustacchi 	}
1210*9d26e4fcSRobert Mustacchi 
1211*9d26e4fcSRobert Mustacchi 	hw->aq.num_arq_entries = I40E_DEF_ADMINQ_SIZE;
1212*9d26e4fcSRobert Mustacchi 	hw->aq.num_asq_entries =  I40E_DEF_ADMINQ_SIZE;
1213*9d26e4fcSRobert Mustacchi 	hw->aq.arq_buf_size = I40E_ADMINQ_BUFSZ;
1214*9d26e4fcSRobert Mustacchi 	hw->aq.asq_buf_size = I40E_ADMINQ_BUFSZ;
1215*9d26e4fcSRobert Mustacchi 
1216*9d26e4fcSRobert Mustacchi 	rc = i40e_init_adminq(hw);
1217*9d26e4fcSRobert Mustacchi 	if (rc != 0) {
1218*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to initialize firmware admin queue: "
1219*9d26e4fcSRobert Mustacchi 		    "%d, potential firmware version mismatch", rc);
1220*9d26e4fcSRobert Mustacchi 		i40e_fm_ereport(i40e, DDI_FM_DEVICE_INVAL_STATE);
1221*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1222*9d26e4fcSRobert Mustacchi 	}
1223*9d26e4fcSRobert Mustacchi 
1224*9d26e4fcSRobert Mustacchi 	if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
1225*9d26e4fcSRobert Mustacchi 	    hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR) {
1226*9d26e4fcSRobert Mustacchi 		i40e_notice(i40e, "The driver for the device detected a newer "
1227*9d26e4fcSRobert Mustacchi 		    "version of the NVM image (%d.%d) than expected (%d.%d).\n"
1228*9d26e4fcSRobert Mustacchi 		    "Please install the most recent version of the network "
1229*9d26e4fcSRobert Mustacchi 		    "driver.\n", hw->aq.api_maj_ver, hw->aq.api_min_ver,
1230*9d26e4fcSRobert Mustacchi 		    I40E_FW_API_VERSION_MAJOR, I40E_FW_API_VERSION_MINOR);
1231*9d26e4fcSRobert Mustacchi 	} else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR ||
1232*9d26e4fcSRobert Mustacchi 	    hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1)) {
1233*9d26e4fcSRobert Mustacchi 		i40e_notice(i40e, "The driver for the device detected an older"
1234*9d26e4fcSRobert Mustacchi 		    " version of the NVM image (%d.%d) than expected (%d.%d)."
1235*9d26e4fcSRobert Mustacchi 		    "\nPlease update the NVM image.\n",
1236*9d26e4fcSRobert Mustacchi 		    hw->aq.api_maj_ver, hw->aq.api_min_ver,
1237*9d26e4fcSRobert Mustacchi 		    I40E_FW_API_VERSION_MAJOR, I40E_FW_API_VERSION_MINOR - 1);
1238*9d26e4fcSRobert Mustacchi 	}
1239*9d26e4fcSRobert Mustacchi 
1240*9d26e4fcSRobert Mustacchi 	i40e_clear_pxe_mode(hw);
1241*9d26e4fcSRobert Mustacchi 
1242*9d26e4fcSRobert Mustacchi 	/*
1243*9d26e4fcSRobert Mustacchi 	 * We need to call this so that the common code can discover
1244*9d26e4fcSRobert Mustacchi 	 * capabilities of the hardware, which it uses throughout the rest.
1245*9d26e4fcSRobert Mustacchi 	 */
1246*9d26e4fcSRobert Mustacchi 	if (!i40e_get_hw_capabilities(i40e, hw)) {
1247*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to obtain hardware capabilities");
1248*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1249*9d26e4fcSRobert Mustacchi 	}
1250*9d26e4fcSRobert Mustacchi 
1251*9d26e4fcSRobert Mustacchi 	if (i40e_get_available_resources(i40e) == B_FALSE) {
1252*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to obtain hardware resources");
1253*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1254*9d26e4fcSRobert Mustacchi 	}
1255*9d26e4fcSRobert Mustacchi 
1256*9d26e4fcSRobert Mustacchi 	i40e_hw_to_instance(i40e, hw);
1257*9d26e4fcSRobert Mustacchi 
1258*9d26e4fcSRobert Mustacchi 	rc = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
1259*9d26e4fcSRobert Mustacchi 	    hw->func_caps.num_rx_qp, 0, 0);
1260*9d26e4fcSRobert Mustacchi 	if (rc != 0) {
1261*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to initialize hardware memory cache: "
1262*9d26e4fcSRobert Mustacchi 		    "%d", rc);
1263*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1264*9d26e4fcSRobert Mustacchi 	}
1265*9d26e4fcSRobert Mustacchi 
1266*9d26e4fcSRobert Mustacchi 	rc = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
1267*9d26e4fcSRobert Mustacchi 	if (rc != 0) {
1268*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to configure hardware memory cache: "
1269*9d26e4fcSRobert Mustacchi 		    "%d", rc);
1270*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1271*9d26e4fcSRobert Mustacchi 	}
1272*9d26e4fcSRobert Mustacchi 
1273*9d26e4fcSRobert Mustacchi 	(void) i40e_aq_stop_lldp(hw, TRUE, NULL);
1274*9d26e4fcSRobert Mustacchi 
1275*9d26e4fcSRobert Mustacchi 	rc = i40e_get_mac_addr(hw, hw->mac.addr);
1276*9d26e4fcSRobert Mustacchi 	if (rc != I40E_SUCCESS) {
1277*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to retrieve hardware mac address: %d",
1278*9d26e4fcSRobert Mustacchi 		    rc);
1279*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1280*9d26e4fcSRobert Mustacchi 	}
1281*9d26e4fcSRobert Mustacchi 
1282*9d26e4fcSRobert Mustacchi 	rc = i40e_validate_mac_addr(hw->mac.addr);
1283*9d26e4fcSRobert Mustacchi 	if (rc != 0) {
1284*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to validate internal mac address: "
1285*9d26e4fcSRobert Mustacchi 		    "%d", rc);
1286*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1287*9d26e4fcSRobert Mustacchi 	}
1288*9d26e4fcSRobert Mustacchi 	bcopy(hw->mac.addr, hw->mac.perm_addr, ETHERADDRL);
1289*9d26e4fcSRobert Mustacchi 	if ((rc = i40e_get_port_mac_addr(hw, hw->mac.port_addr)) !=
1290*9d26e4fcSRobert Mustacchi 	    I40E_SUCCESS) {
1291*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to retrieve port mac address: %d",
1292*9d26e4fcSRobert Mustacchi 		    rc);
1293*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1294*9d26e4fcSRobert Mustacchi 	}
1295*9d26e4fcSRobert Mustacchi 
1296*9d26e4fcSRobert Mustacchi 	/*
1297*9d26e4fcSRobert Mustacchi 	 * We need to obtain the Virtual Station ID (VSI) before we can
1298*9d26e4fcSRobert Mustacchi 	 * perform other operations on the device.
1299*9d26e4fcSRobert Mustacchi 	 */
1300*9d26e4fcSRobert Mustacchi 	i40e->i40e_vsi_id = i40e_get_vsi_id(i40e);
1301*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_vsi_id == -1) {
1302*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to obtain VSI ID");
1303*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1304*9d26e4fcSRobert Mustacchi 	}
1305*9d26e4fcSRobert Mustacchi 
1306*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
1307*9d26e4fcSRobert Mustacchi }
1308*9d26e4fcSRobert Mustacchi 
1309*9d26e4fcSRobert Mustacchi static void
1310*9d26e4fcSRobert Mustacchi i40e_unconfigure(dev_info_t *devinfo, i40e_t *i40e)
1311*9d26e4fcSRobert Mustacchi {
1312*9d26e4fcSRobert Mustacchi 	int rc;
1313*9d26e4fcSRobert Mustacchi 
1314*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_attach_progress & I40E_ATTACH_ENABLE_INTR)
1315*9d26e4fcSRobert Mustacchi 		(void) i40e_disable_interrupts(i40e);
1316*9d26e4fcSRobert Mustacchi 
1317*9d26e4fcSRobert Mustacchi 	if ((i40e->i40e_attach_progress & I40E_ATTACH_LINK_TIMER) &&
1318*9d26e4fcSRobert Mustacchi 	    i40e->i40e_periodic_id != 0) {
1319*9d26e4fcSRobert Mustacchi 		ddi_periodic_delete(i40e->i40e_periodic_id);
1320*9d26e4fcSRobert Mustacchi 		i40e->i40e_periodic_id = 0;
1321*9d26e4fcSRobert Mustacchi 	}
1322*9d26e4fcSRobert Mustacchi 
1323*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_attach_progress & I40E_ATTACH_MAC) {
1324*9d26e4fcSRobert Mustacchi 		rc = mac_unregister(i40e->i40e_mac_hdl);
1325*9d26e4fcSRobert Mustacchi 		if (rc != 0) {
1326*9d26e4fcSRobert Mustacchi 			i40e_error(i40e, "failed to unregister from mac: %d",
1327*9d26e4fcSRobert Mustacchi 			    rc);
1328*9d26e4fcSRobert Mustacchi 		}
1329*9d26e4fcSRobert Mustacchi 	}
1330*9d26e4fcSRobert Mustacchi 
1331*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_attach_progress & I40E_ATTACH_STATS) {
1332*9d26e4fcSRobert Mustacchi 		i40e_stats_fini(i40e);
1333*9d26e4fcSRobert Mustacchi 	}
1334*9d26e4fcSRobert Mustacchi 
1335*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_attach_progress & I40E_ATTACH_ADD_INTR)
1336*9d26e4fcSRobert Mustacchi 		i40e_rem_intr_handlers(i40e);
1337*9d26e4fcSRobert Mustacchi 
1338*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_attach_progress & I40E_ATTACH_ALLOC_RINGSLOCKS)
1339*9d26e4fcSRobert Mustacchi 		i40e_free_trqpairs(i40e);
1340*9d26e4fcSRobert Mustacchi 
1341*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_attach_progress & I40E_ATTACH_ALLOC_INTR)
1342*9d26e4fcSRobert Mustacchi 		i40e_rem_intrs(i40e);
1343*9d26e4fcSRobert Mustacchi 
1344*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_attach_progress & I40E_ATTACH_COMMON_CODE)
1345*9d26e4fcSRobert Mustacchi 		i40e_common_code_fini(i40e);
1346*9d26e4fcSRobert Mustacchi 
1347*9d26e4fcSRobert Mustacchi 	i40e_cleanup_resources(i40e);
1348*9d26e4fcSRobert Mustacchi 
1349*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_attach_progress & I40E_ATTACH_PROPS)
1350*9d26e4fcSRobert Mustacchi 		(void) ddi_prop_remove_all(devinfo);
1351*9d26e4fcSRobert Mustacchi 
1352*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_attach_progress & I40E_ATTACH_REGS_MAP &&
1353*9d26e4fcSRobert Mustacchi 	    i40e->i40e_osdep_space.ios_reg_handle != NULL) {
1354*9d26e4fcSRobert Mustacchi 		ddi_regs_map_free(&i40e->i40e_osdep_space.ios_reg_handle);
1355*9d26e4fcSRobert Mustacchi 		i40e->i40e_osdep_space.ios_reg_handle = NULL;
1356*9d26e4fcSRobert Mustacchi 	}
1357*9d26e4fcSRobert Mustacchi 
1358*9d26e4fcSRobert Mustacchi 	if ((i40e->i40e_attach_progress & I40E_ATTACH_PCI_CONFIG) &&
1359*9d26e4fcSRobert Mustacchi 	    i40e->i40e_osdep_space.ios_cfg_handle != NULL) {
1360*9d26e4fcSRobert Mustacchi 		pci_config_teardown(&i40e->i40e_osdep_space.ios_cfg_handle);
1361*9d26e4fcSRobert Mustacchi 		i40e->i40e_osdep_space.ios_cfg_handle = NULL;
1362*9d26e4fcSRobert Mustacchi 	}
1363*9d26e4fcSRobert Mustacchi 
1364*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_attach_progress & I40E_ATTACH_FM_INIT)
1365*9d26e4fcSRobert Mustacchi 		i40e_fm_fini(i40e);
1366*9d26e4fcSRobert Mustacchi 
1367*9d26e4fcSRobert Mustacchi 	kmem_free(i40e->i40e_aqbuf, I40E_ADMINQ_BUFSZ);
1368*9d26e4fcSRobert Mustacchi 	kmem_free(i40e, sizeof (i40e_t));
1369*9d26e4fcSRobert Mustacchi 
1370*9d26e4fcSRobert Mustacchi 	ddi_set_driver_private(devinfo, NULL);
1371*9d26e4fcSRobert Mustacchi }
1372*9d26e4fcSRobert Mustacchi 
1373*9d26e4fcSRobert Mustacchi static boolean_t
1374*9d26e4fcSRobert Mustacchi i40e_final_init(i40e_t *i40e)
1375*9d26e4fcSRobert Mustacchi {
1376*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
1377*9d26e4fcSRobert Mustacchi 	struct i40e_osdep *osdep = OS_DEP(hw);
1378*9d26e4fcSRobert Mustacchi 	uint8_t pbanum[I40E_PBANUM_STRLEN];
1379*9d26e4fcSRobert Mustacchi 	enum i40e_status_code irc;
1380*9d26e4fcSRobert Mustacchi 	char buf[I40E_DDI_PROP_LEN];
1381*9d26e4fcSRobert Mustacchi 
1382*9d26e4fcSRobert Mustacchi 	pbanum[0] = '\0';
1383*9d26e4fcSRobert Mustacchi 	irc = i40e_read_pba_string(hw, pbanum, sizeof (pbanum));
1384*9d26e4fcSRobert Mustacchi 	if (irc != I40E_SUCCESS) {
1385*9d26e4fcSRobert Mustacchi 		i40e_log(i40e, "failed to read PBA string: %d", irc);
1386*9d26e4fcSRobert Mustacchi 	} else {
1387*9d26e4fcSRobert Mustacchi 		(void) ddi_prop_update_string(DDI_DEV_T_NONE, i40e->i40e_dip,
1388*9d26e4fcSRobert Mustacchi 		    "printed-board-assembly", (char *)pbanum);
1389*9d26e4fcSRobert Mustacchi 	}
1390*9d26e4fcSRobert Mustacchi 
1391*9d26e4fcSRobert Mustacchi #ifdef	DEBUG
1392*9d26e4fcSRobert Mustacchi 	ASSERT(snprintf(NULL, 0, "%d.%d", hw->aq.fw_maj_ver,
1393*9d26e4fcSRobert Mustacchi 	    hw->aq.fw_min_ver) < sizeof (buf));
1394*9d26e4fcSRobert Mustacchi 	ASSERT(snprintf(NULL, 0, "%x", hw->aq.fw_build) < sizeof (buf));
1395*9d26e4fcSRobert Mustacchi 	ASSERT(snprintf(NULL, 0, "%d.%d", hw->aq.api_maj_ver,
1396*9d26e4fcSRobert Mustacchi 	    hw->aq.api_min_ver) < sizeof (buf));
1397*9d26e4fcSRobert Mustacchi #endif
1398*9d26e4fcSRobert Mustacchi 
1399*9d26e4fcSRobert Mustacchi 	(void) snprintf(buf, sizeof (buf), "%d.%d", hw->aq.fw_maj_ver,
1400*9d26e4fcSRobert Mustacchi 	    hw->aq.fw_min_ver);
1401*9d26e4fcSRobert Mustacchi 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, i40e->i40e_dip,
1402*9d26e4fcSRobert Mustacchi 	    "firmware-version", buf);
1403*9d26e4fcSRobert Mustacchi 	(void) snprintf(buf, sizeof (buf), "%x", hw->aq.fw_build);
1404*9d26e4fcSRobert Mustacchi 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, i40e->i40e_dip,
1405*9d26e4fcSRobert Mustacchi 	    "firmware-build", buf);
1406*9d26e4fcSRobert Mustacchi 	(void) snprintf(buf, sizeof (buf), "%d.%d", hw->aq.api_maj_ver,
1407*9d26e4fcSRobert Mustacchi 	    hw->aq.api_min_ver);
1408*9d26e4fcSRobert Mustacchi 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, i40e->i40e_dip,
1409*9d26e4fcSRobert Mustacchi 	    "api-version", buf);
1410*9d26e4fcSRobert Mustacchi 
1411*9d26e4fcSRobert Mustacchi 	if (!i40e_set_hw_bus_info(hw))
1412*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1413*9d26e4fcSRobert Mustacchi 
1414*9d26e4fcSRobert Mustacchi 	if (i40e_check_acc_handle(osdep->ios_reg_handle) != DDI_FM_OK) {
1415*9d26e4fcSRobert Mustacchi 		ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST);
1416*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1417*9d26e4fcSRobert Mustacchi 	}
1418*9d26e4fcSRobert Mustacchi 
1419*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
1420*9d26e4fcSRobert Mustacchi }
1421*9d26e4fcSRobert Mustacchi 
1422*9d26e4fcSRobert Mustacchi static boolean_t
1423*9d26e4fcSRobert Mustacchi i40e_identify_hardware(i40e_t *i40e)
1424*9d26e4fcSRobert Mustacchi {
1425*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
1426*9d26e4fcSRobert Mustacchi 	struct i40e_osdep *osdep = &i40e->i40e_osdep_space;
1427*9d26e4fcSRobert Mustacchi 
1428*9d26e4fcSRobert Mustacchi 	hw->vendor_id = pci_config_get16(osdep->ios_cfg_handle, PCI_CONF_VENID);
1429*9d26e4fcSRobert Mustacchi 	hw->device_id = pci_config_get16(osdep->ios_cfg_handle, PCI_CONF_DEVID);
1430*9d26e4fcSRobert Mustacchi 	hw->revision_id = pci_config_get8(osdep->ios_cfg_handle,
1431*9d26e4fcSRobert Mustacchi 	    PCI_CONF_REVID);
1432*9d26e4fcSRobert Mustacchi 	hw->subsystem_device_id =
1433*9d26e4fcSRobert Mustacchi 	    pci_config_get16(osdep->ios_cfg_handle, PCI_CONF_SUBSYSID);
1434*9d26e4fcSRobert Mustacchi 	hw->subsystem_vendor_id =
1435*9d26e4fcSRobert Mustacchi 	    pci_config_get16(osdep->ios_cfg_handle, PCI_CONF_SUBVENID);
1436*9d26e4fcSRobert Mustacchi 
1437*9d26e4fcSRobert Mustacchi 	/*
1438*9d26e4fcSRobert Mustacchi 	 * Note that we set the hardware's bus information later on, in
1439*9d26e4fcSRobert Mustacchi 	 * i40e_get_available_resources(). The common code doesn't seem to
1440*9d26e4fcSRobert Mustacchi 	 * require that it be set in any ways, it seems to be mostly for
1441*9d26e4fcSRobert Mustacchi 	 * book-keeping.
1442*9d26e4fcSRobert Mustacchi 	 */
1443*9d26e4fcSRobert Mustacchi 
1444*9d26e4fcSRobert Mustacchi 	/* Call common code to set the MAC type for this adapter. */
1445*9d26e4fcSRobert Mustacchi 	if (i40e_set_mac_type(hw) != I40E_SUCCESS)
1446*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1447*9d26e4fcSRobert Mustacchi 
1448*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
1449*9d26e4fcSRobert Mustacchi }
1450*9d26e4fcSRobert Mustacchi 
1451*9d26e4fcSRobert Mustacchi static boolean_t
1452*9d26e4fcSRobert Mustacchi i40e_regs_map(i40e_t *i40e)
1453*9d26e4fcSRobert Mustacchi {
1454*9d26e4fcSRobert Mustacchi 	dev_info_t *devinfo = i40e->i40e_dip;
1455*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
1456*9d26e4fcSRobert Mustacchi 	struct i40e_osdep *osdep = &i40e->i40e_osdep_space;
1457*9d26e4fcSRobert Mustacchi 	off_t memsize;
1458*9d26e4fcSRobert Mustacchi 	int ret;
1459*9d26e4fcSRobert Mustacchi 
1460*9d26e4fcSRobert Mustacchi 	if (ddi_dev_regsize(devinfo, I40E_ADAPTER_REGSET, &memsize) !=
1461*9d26e4fcSRobert Mustacchi 	    DDI_SUCCESS) {
1462*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "Used invalid register set to map PCIe regs");
1463*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1464*9d26e4fcSRobert Mustacchi 	}
1465*9d26e4fcSRobert Mustacchi 
1466*9d26e4fcSRobert Mustacchi 	if ((ret = ddi_regs_map_setup(devinfo, I40E_ADAPTER_REGSET,
1467*9d26e4fcSRobert Mustacchi 	    (caddr_t *)&hw->hw_addr, 0, memsize, &i40e_regs_acc_attr,
1468*9d26e4fcSRobert Mustacchi 	    &osdep->ios_reg_handle)) != DDI_SUCCESS) {
1469*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to map device registers: %d", ret);
1470*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1471*9d26e4fcSRobert Mustacchi 	}
1472*9d26e4fcSRobert Mustacchi 
1473*9d26e4fcSRobert Mustacchi 	osdep->ios_reg_size = memsize;
1474*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
1475*9d26e4fcSRobert Mustacchi }
1476*9d26e4fcSRobert Mustacchi 
1477*9d26e4fcSRobert Mustacchi /*
1478*9d26e4fcSRobert Mustacchi  * Update parameters required when a new MTU has been configured.  Calculate the
1479*9d26e4fcSRobert Mustacchi  * maximum frame size, as well as, size our DMA buffers which we size in
1480*9d26e4fcSRobert Mustacchi  * increments of 1K.
1481*9d26e4fcSRobert Mustacchi  */
1482*9d26e4fcSRobert Mustacchi void
1483*9d26e4fcSRobert Mustacchi i40e_update_mtu(i40e_t *i40e)
1484*9d26e4fcSRobert Mustacchi {
1485*9d26e4fcSRobert Mustacchi 	uint32_t rx, tx;
1486*9d26e4fcSRobert Mustacchi 
1487*9d26e4fcSRobert Mustacchi 	i40e->i40e_frame_max = i40e->i40e_sdu +
1488*9d26e4fcSRobert Mustacchi 	    sizeof (struct ether_vlan_header) + ETHERFCSL;
1489*9d26e4fcSRobert Mustacchi 
1490*9d26e4fcSRobert Mustacchi 	rx = i40e->i40e_frame_max + I40E_BUF_IPHDR_ALIGNMENT;
1491*9d26e4fcSRobert Mustacchi 	i40e->i40e_rx_buf_size = ((rx >> 10) +
1492*9d26e4fcSRobert Mustacchi 	    ((rx & (((uint32_t)1 << 10) -1)) > 0 ? 1 : 0)) << 10;
1493*9d26e4fcSRobert Mustacchi 
1494*9d26e4fcSRobert Mustacchi 	tx = i40e->i40e_frame_max;
1495*9d26e4fcSRobert Mustacchi 	i40e->i40e_tx_buf_size = ((tx >> 10) +
1496*9d26e4fcSRobert Mustacchi 	    ((tx & (((uint32_t)1 << 10) -1)) > 0 ? 1 : 0)) << 10;
1497*9d26e4fcSRobert Mustacchi }
1498*9d26e4fcSRobert Mustacchi 
1499*9d26e4fcSRobert Mustacchi static int
1500*9d26e4fcSRobert Mustacchi i40e_get_prop(i40e_t *i40e, char *prop, int min, int max, int def)
1501*9d26e4fcSRobert Mustacchi {
1502*9d26e4fcSRobert Mustacchi 	int val;
1503*9d26e4fcSRobert Mustacchi 
1504*9d26e4fcSRobert Mustacchi 	val = ddi_prop_get_int(DDI_DEV_T_ANY, i40e->i40e_dip, DDI_PROP_DONTPASS,
1505*9d26e4fcSRobert Mustacchi 	    prop, def);
1506*9d26e4fcSRobert Mustacchi 	if (val > max)
1507*9d26e4fcSRobert Mustacchi 		val = max;
1508*9d26e4fcSRobert Mustacchi 	if (val < min)
1509*9d26e4fcSRobert Mustacchi 		val = min;
1510*9d26e4fcSRobert Mustacchi 	return (val);
1511*9d26e4fcSRobert Mustacchi }
1512*9d26e4fcSRobert Mustacchi 
1513*9d26e4fcSRobert Mustacchi static void
1514*9d26e4fcSRobert Mustacchi i40e_init_properties(i40e_t *i40e)
1515*9d26e4fcSRobert Mustacchi {
1516*9d26e4fcSRobert Mustacchi 	i40e->i40e_sdu = i40e_get_prop(i40e, "default_mtu",
1517*9d26e4fcSRobert Mustacchi 	    I40E_MIN_MTU, I40E_MAX_MTU, I40E_DEF_MTU);
1518*9d26e4fcSRobert Mustacchi 
1519*9d26e4fcSRobert Mustacchi 	i40e->i40e_intr_force = i40e_get_prop(i40e, "intr_force",
1520*9d26e4fcSRobert Mustacchi 	    I40E_INTR_NONE, I40E_INTR_LEGACY, I40E_INTR_NONE);
1521*9d26e4fcSRobert Mustacchi 
1522*9d26e4fcSRobert Mustacchi 	i40e->i40e_mr_enable = i40e_get_prop(i40e, "mr_enable",
1523*9d26e4fcSRobert Mustacchi 	    B_FALSE, B_TRUE, B_TRUE);
1524*9d26e4fcSRobert Mustacchi 
1525*9d26e4fcSRobert Mustacchi 	i40e->i40e_tx_ring_size = i40e_get_prop(i40e, "tx_ring_size",
1526*9d26e4fcSRobert Mustacchi 	    I40E_MIN_TX_RING_SIZE, I40E_MAX_TX_RING_SIZE,
1527*9d26e4fcSRobert Mustacchi 	    I40E_DEF_TX_RING_SIZE);
1528*9d26e4fcSRobert Mustacchi 	if ((i40e->i40e_tx_ring_size % I40E_DESC_ALIGN) != 0) {
1529*9d26e4fcSRobert Mustacchi 		i40e->i40e_tx_ring_size = P2ROUNDUP(i40e->i40e_tx_ring_size,
1530*9d26e4fcSRobert Mustacchi 		    I40E_DESC_ALIGN);
1531*9d26e4fcSRobert Mustacchi 	}
1532*9d26e4fcSRobert Mustacchi 
1533*9d26e4fcSRobert Mustacchi 	i40e->i40e_tx_block_thresh = i40e_get_prop(i40e, "tx_resched_threshold",
1534*9d26e4fcSRobert Mustacchi 	    I40E_MIN_TX_BLOCK_THRESH,
1535*9d26e4fcSRobert Mustacchi 	    i40e->i40e_tx_ring_size - I40E_TX_MAX_COOKIE,
1536*9d26e4fcSRobert Mustacchi 	    I40E_DEF_TX_BLOCK_THRESH);
1537*9d26e4fcSRobert Mustacchi 
1538*9d26e4fcSRobert Mustacchi 	i40e->i40e_rx_ring_size = i40e_get_prop(i40e, "rx_ring_size",
1539*9d26e4fcSRobert Mustacchi 	    I40E_MIN_RX_RING_SIZE, I40E_MAX_RX_RING_SIZE,
1540*9d26e4fcSRobert Mustacchi 	    I40E_DEF_RX_RING_SIZE);
1541*9d26e4fcSRobert Mustacchi 	if ((i40e->i40e_rx_ring_size % I40E_DESC_ALIGN) != 0) {
1542*9d26e4fcSRobert Mustacchi 		i40e->i40e_rx_ring_size = P2ROUNDUP(i40e->i40e_rx_ring_size,
1543*9d26e4fcSRobert Mustacchi 		    I40E_DESC_ALIGN);
1544*9d26e4fcSRobert Mustacchi 	}
1545*9d26e4fcSRobert Mustacchi 
1546*9d26e4fcSRobert Mustacchi 	i40e->i40e_rx_limit_per_intr = i40e_get_prop(i40e, "rx_limit_per_intr",
1547*9d26e4fcSRobert Mustacchi 	    I40E_MIN_RX_LIMIT_PER_INTR,	I40E_MAX_RX_LIMIT_PER_INTR,
1548*9d26e4fcSRobert Mustacchi 	    I40E_DEF_RX_LIMIT_PER_INTR);
1549*9d26e4fcSRobert Mustacchi 
1550*9d26e4fcSRobert Mustacchi 	i40e->i40e_tx_hcksum_enable = i40e_get_prop(i40e, "tx_hcksum_enable",
1551*9d26e4fcSRobert Mustacchi 	    B_FALSE, B_TRUE, B_TRUE);
1552*9d26e4fcSRobert Mustacchi 
1553*9d26e4fcSRobert Mustacchi 	i40e->i40e_rx_hcksum_enable = i40e_get_prop(i40e, "rx_hcksum_enable",
1554*9d26e4fcSRobert Mustacchi 	    B_FALSE, B_TRUE, B_TRUE);
1555*9d26e4fcSRobert Mustacchi 
1556*9d26e4fcSRobert Mustacchi 	i40e->i40e_rx_dma_min = i40e_get_prop(i40e, "rx_dma_threshold",
1557*9d26e4fcSRobert Mustacchi 	    I40E_MIN_RX_DMA_THRESH, I40E_MAX_RX_DMA_THRESH,
1558*9d26e4fcSRobert Mustacchi 	    I40E_DEF_RX_DMA_THRESH);
1559*9d26e4fcSRobert Mustacchi 
1560*9d26e4fcSRobert Mustacchi 	i40e->i40e_tx_dma_min = i40e_get_prop(i40e, "tx_dma_threshold",
1561*9d26e4fcSRobert Mustacchi 	    I40E_MIN_TX_DMA_THRESH, I40E_MAX_TX_DMA_THRESH,
1562*9d26e4fcSRobert Mustacchi 	    I40E_DEF_TX_DMA_THRESH);
1563*9d26e4fcSRobert Mustacchi 
1564*9d26e4fcSRobert Mustacchi 	i40e->i40e_tx_itr = i40e_get_prop(i40e, "tx_intr_throttle",
1565*9d26e4fcSRobert Mustacchi 	    I40E_MIN_ITR, I40E_MAX_ITR, I40E_DEF_TX_ITR);
1566*9d26e4fcSRobert Mustacchi 
1567*9d26e4fcSRobert Mustacchi 	i40e->i40e_rx_itr = i40e_get_prop(i40e, "rx_intr_throttle",
1568*9d26e4fcSRobert Mustacchi 	    I40E_MIN_ITR, I40E_MAX_ITR, I40E_DEF_RX_ITR);
1569*9d26e4fcSRobert Mustacchi 
1570*9d26e4fcSRobert Mustacchi 	i40e->i40e_other_itr = i40e_get_prop(i40e, "other_intr_throttle",
1571*9d26e4fcSRobert Mustacchi 	    I40E_MIN_ITR, I40E_MAX_ITR, I40E_DEF_OTHER_ITR);
1572*9d26e4fcSRobert Mustacchi 
1573*9d26e4fcSRobert Mustacchi 	if (!i40e->i40e_mr_enable) {
1574*9d26e4fcSRobert Mustacchi 		i40e->i40e_num_trqpairs = I40E_TRQPAIR_NOMSIX;
1575*9d26e4fcSRobert Mustacchi 		i40e->i40e_num_rx_groups = I40E_GROUP_NOMSIX;
1576*9d26e4fcSRobert Mustacchi 	}
1577*9d26e4fcSRobert Mustacchi 
1578*9d26e4fcSRobert Mustacchi 	i40e_update_mtu(i40e);
1579*9d26e4fcSRobert Mustacchi }
1580*9d26e4fcSRobert Mustacchi 
1581*9d26e4fcSRobert Mustacchi /*
1582*9d26e4fcSRobert Mustacchi  * There are a few constraints on interrupts that we're currently imposing, some
1583*9d26e4fcSRobert Mustacchi  * of which are restrictions from hardware. For a fuller treatment, see
1584*9d26e4fcSRobert Mustacchi  * i40e_intr.c.
1585*9d26e4fcSRobert Mustacchi  *
1586*9d26e4fcSRobert Mustacchi  * Currently, to use MSI-X we require two interrupts be available though in
1587*9d26e4fcSRobert Mustacchi  * theory we should participate in IRM and happily use more interrupts.
1588*9d26e4fcSRobert Mustacchi  *
1589*9d26e4fcSRobert Mustacchi  * Hardware only supports a single MSI being programmed and therefore if we
1590*9d26e4fcSRobert Mustacchi  * don't have MSI-X interrupts available at this time, then we ratchet down the
1591*9d26e4fcSRobert Mustacchi  * number of rings and groups available. Obviously, we only bother with a single
1592*9d26e4fcSRobert Mustacchi  * fixed interrupt.
1593*9d26e4fcSRobert Mustacchi  */
1594*9d26e4fcSRobert Mustacchi static boolean_t
1595*9d26e4fcSRobert Mustacchi i40e_alloc_intr_handles(i40e_t *i40e, dev_info_t *devinfo, int intr_type)
1596*9d26e4fcSRobert Mustacchi {
1597*9d26e4fcSRobert Mustacchi 	int request, count, actual, rc, min;
1598*9d26e4fcSRobert Mustacchi 
1599*9d26e4fcSRobert Mustacchi 	switch (intr_type) {
1600*9d26e4fcSRobert Mustacchi 	case DDI_INTR_TYPE_FIXED:
1601*9d26e4fcSRobert Mustacchi 	case DDI_INTR_TYPE_MSI:
1602*9d26e4fcSRobert Mustacchi 		request = 1;
1603*9d26e4fcSRobert Mustacchi 		min = 1;
1604*9d26e4fcSRobert Mustacchi 		break;
1605*9d26e4fcSRobert Mustacchi 	case DDI_INTR_TYPE_MSIX:
1606*9d26e4fcSRobert Mustacchi 		/*
1607*9d26e4fcSRobert Mustacchi 		 * At the moment, we always request two MSI-X while we still
1608*9d26e4fcSRobert Mustacchi 		 * only support a single interrupt. The upper bound on what's
1609*9d26e4fcSRobert Mustacchi 		 * supported by a given device is defined by MSI_X_PF_N in
1610*9d26e4fcSRobert Mustacchi 		 * GLPCI_CNF2. When we evolve, we should read it to determine
1611*9d26e4fcSRobert Mustacchi 		 * what the real max is.
1612*9d26e4fcSRobert Mustacchi 		 */
1613*9d26e4fcSRobert Mustacchi 		ASSERT(i40e->i40e_num_trqpairs == 1);
1614*9d26e4fcSRobert Mustacchi 		request = 2;
1615*9d26e4fcSRobert Mustacchi 		min = 2;
1616*9d26e4fcSRobert Mustacchi 		break;
1617*9d26e4fcSRobert Mustacchi 	default:
1618*9d26e4fcSRobert Mustacchi 		panic("bad interrupt type passed to i40e_alloc_intr_handles: "
1619*9d26e4fcSRobert Mustacchi 		    "%d", intr_type);
1620*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1621*9d26e4fcSRobert Mustacchi 	}
1622*9d26e4fcSRobert Mustacchi 
1623*9d26e4fcSRobert Mustacchi 	rc = ddi_intr_get_nintrs(devinfo, intr_type, &count);
1624*9d26e4fcSRobert Mustacchi 	if (rc != DDI_SUCCESS || count < min) {
1625*9d26e4fcSRobert Mustacchi 		i40e_log(i40e, "Get interrupt number failed, "
1626*9d26e4fcSRobert Mustacchi 		    "returned %d, count %d", rc, count);
1627*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1628*9d26e4fcSRobert Mustacchi 	}
1629*9d26e4fcSRobert Mustacchi 
1630*9d26e4fcSRobert Mustacchi 	rc = ddi_intr_get_navail(devinfo, intr_type, &count);
1631*9d26e4fcSRobert Mustacchi 	if (rc != DDI_SUCCESS || count < min) {
1632*9d26e4fcSRobert Mustacchi 		i40e_log(i40e, "Get AVAILABLE interrupt number failed, "
1633*9d26e4fcSRobert Mustacchi 		    "returned %d, count %d", rc, count);
1634*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1635*9d26e4fcSRobert Mustacchi 	}
1636*9d26e4fcSRobert Mustacchi 
1637*9d26e4fcSRobert Mustacchi 	actual = 0;
1638*9d26e4fcSRobert Mustacchi 	i40e->i40e_intr_count = 0;
1639*9d26e4fcSRobert Mustacchi 	i40e->i40e_intr_count_max = 0;
1640*9d26e4fcSRobert Mustacchi 	i40e->i40e_intr_count_min = 0;
1641*9d26e4fcSRobert Mustacchi 
1642*9d26e4fcSRobert Mustacchi 	i40e->i40e_intr_size = request * sizeof (ddi_intr_handle_t);
1643*9d26e4fcSRobert Mustacchi 	ASSERT(i40e->i40e_intr_size != 0);
1644*9d26e4fcSRobert Mustacchi 	i40e->i40e_intr_handles = kmem_alloc(i40e->i40e_intr_size, KM_SLEEP);
1645*9d26e4fcSRobert Mustacchi 
1646*9d26e4fcSRobert Mustacchi 	rc = ddi_intr_alloc(devinfo, i40e->i40e_intr_handles, intr_type, 0,
1647*9d26e4fcSRobert Mustacchi 	    min(request, count), &actual, DDI_INTR_ALLOC_NORMAL);
1648*9d26e4fcSRobert Mustacchi 	if (rc != DDI_SUCCESS) {
1649*9d26e4fcSRobert Mustacchi 		i40e_log(i40e, "Interrupt allocation failed with %d.", rc);
1650*9d26e4fcSRobert Mustacchi 		goto alloc_handle_fail;
1651*9d26e4fcSRobert Mustacchi 	}
1652*9d26e4fcSRobert Mustacchi 
1653*9d26e4fcSRobert Mustacchi 	i40e->i40e_intr_count = actual;
1654*9d26e4fcSRobert Mustacchi 	i40e->i40e_intr_count_max = request;
1655*9d26e4fcSRobert Mustacchi 	i40e->i40e_intr_count_min = min;
1656*9d26e4fcSRobert Mustacchi 
1657*9d26e4fcSRobert Mustacchi 	if (actual < min) {
1658*9d26e4fcSRobert Mustacchi 		i40e_log(i40e, "actual (%d) is less than minimum (%d).",
1659*9d26e4fcSRobert Mustacchi 		    actual, min);
1660*9d26e4fcSRobert Mustacchi 		goto alloc_handle_fail;
1661*9d26e4fcSRobert Mustacchi 	}
1662*9d26e4fcSRobert Mustacchi 
1663*9d26e4fcSRobert Mustacchi 	/*
1664*9d26e4fcSRobert Mustacchi 	 * Record the priority and capabilities for our first vector.  Once
1665*9d26e4fcSRobert Mustacchi 	 * we have it, that's our priority until detach time.  Even if we
1666*9d26e4fcSRobert Mustacchi 	 * eventually participate in IRM, our priority shouldn't change.
1667*9d26e4fcSRobert Mustacchi 	 */
1668*9d26e4fcSRobert Mustacchi 	rc = ddi_intr_get_pri(i40e->i40e_intr_handles[0], &i40e->i40e_intr_pri);
1669*9d26e4fcSRobert Mustacchi 	if (rc != DDI_SUCCESS) {
1670*9d26e4fcSRobert Mustacchi 		i40e_log(i40e,
1671*9d26e4fcSRobert Mustacchi 		    "Getting interrupt priority failed with %d.", rc);
1672*9d26e4fcSRobert Mustacchi 		goto alloc_handle_fail;
1673*9d26e4fcSRobert Mustacchi 	}
1674*9d26e4fcSRobert Mustacchi 
1675*9d26e4fcSRobert Mustacchi 	rc = ddi_intr_get_cap(i40e->i40e_intr_handles[0], &i40e->i40e_intr_cap);
1676*9d26e4fcSRobert Mustacchi 	if (rc != DDI_SUCCESS) {
1677*9d26e4fcSRobert Mustacchi 		i40e_log(i40e,
1678*9d26e4fcSRobert Mustacchi 		    "Getting interrupt capabilities failed with %d.", rc);
1679*9d26e4fcSRobert Mustacchi 		goto alloc_handle_fail;
1680*9d26e4fcSRobert Mustacchi 	}
1681*9d26e4fcSRobert Mustacchi 
1682*9d26e4fcSRobert Mustacchi 	i40e->i40e_intr_type = intr_type;
1683*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
1684*9d26e4fcSRobert Mustacchi 
1685*9d26e4fcSRobert Mustacchi alloc_handle_fail:
1686*9d26e4fcSRobert Mustacchi 
1687*9d26e4fcSRobert Mustacchi 	i40e_rem_intrs(i40e);
1688*9d26e4fcSRobert Mustacchi 	return (B_FALSE);
1689*9d26e4fcSRobert Mustacchi }
1690*9d26e4fcSRobert Mustacchi 
1691*9d26e4fcSRobert Mustacchi static boolean_t
1692*9d26e4fcSRobert Mustacchi i40e_alloc_intrs(i40e_t *i40e, dev_info_t *devinfo)
1693*9d26e4fcSRobert Mustacchi {
1694*9d26e4fcSRobert Mustacchi 	int intr_types, rc;
1695*9d26e4fcSRobert Mustacchi 
1696*9d26e4fcSRobert Mustacchi 	rc = ddi_intr_get_supported_types(devinfo, &intr_types);
1697*9d26e4fcSRobert Mustacchi 	if (rc != DDI_SUCCESS) {
1698*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to get supported interrupt types: %d",
1699*9d26e4fcSRobert Mustacchi 		    rc);
1700*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1701*9d26e4fcSRobert Mustacchi 	}
1702*9d26e4fcSRobert Mustacchi 
1703*9d26e4fcSRobert Mustacchi 	i40e->i40e_intr_type = 0;
1704*9d26e4fcSRobert Mustacchi 
1705*9d26e4fcSRobert Mustacchi 	if ((intr_types & DDI_INTR_TYPE_MSIX) &&
1706*9d26e4fcSRobert Mustacchi 	    i40e->i40e_intr_force <= I40E_INTR_MSIX) {
1707*9d26e4fcSRobert Mustacchi 		if (i40e_alloc_intr_handles(i40e, devinfo, DDI_INTR_TYPE_MSIX))
1708*9d26e4fcSRobert Mustacchi 			return (B_TRUE);
1709*9d26e4fcSRobert Mustacchi 	}
1710*9d26e4fcSRobert Mustacchi 
1711*9d26e4fcSRobert Mustacchi 	/*
1712*9d26e4fcSRobert Mustacchi 	 * We only use multiple transmit/receive pairs when MSI-X interrupts are
1713*9d26e4fcSRobert Mustacchi 	 * available due to the fact that the device basically only supports a
1714*9d26e4fcSRobert Mustacchi 	 * single MSI interrupt.
1715*9d26e4fcSRobert Mustacchi 	 */
1716*9d26e4fcSRobert Mustacchi 	i40e->i40e_num_trqpairs = I40E_TRQPAIR_NOMSIX;
1717*9d26e4fcSRobert Mustacchi 	i40e->i40e_num_rx_groups = I40E_GROUP_NOMSIX;
1718*9d26e4fcSRobert Mustacchi 
1719*9d26e4fcSRobert Mustacchi 	if ((intr_types & DDI_INTR_TYPE_MSI) &&
1720*9d26e4fcSRobert Mustacchi 	    (i40e->i40e_intr_force <= I40E_INTR_MSI)) {
1721*9d26e4fcSRobert Mustacchi 		if (i40e_alloc_intr_handles(i40e, devinfo, DDI_INTR_TYPE_MSI))
1722*9d26e4fcSRobert Mustacchi 			return (B_TRUE);
1723*9d26e4fcSRobert Mustacchi 	}
1724*9d26e4fcSRobert Mustacchi 
1725*9d26e4fcSRobert Mustacchi 	if (intr_types & DDI_INTR_TYPE_FIXED) {
1726*9d26e4fcSRobert Mustacchi 		if (i40e_alloc_intr_handles(i40e, devinfo, DDI_INTR_TYPE_FIXED))
1727*9d26e4fcSRobert Mustacchi 			return (B_TRUE);
1728*9d26e4fcSRobert Mustacchi 	}
1729*9d26e4fcSRobert Mustacchi 
1730*9d26e4fcSRobert Mustacchi 	return (B_FALSE);
1731*9d26e4fcSRobert Mustacchi }
1732*9d26e4fcSRobert Mustacchi 
1733*9d26e4fcSRobert Mustacchi /*
1734*9d26e4fcSRobert Mustacchi  * Map different interrupts to MSI-X vectors.
1735*9d26e4fcSRobert Mustacchi  */
1736*9d26e4fcSRobert Mustacchi static boolean_t
1737*9d26e4fcSRobert Mustacchi i40e_map_intrs_to_vectors(i40e_t *i40e)
1738*9d26e4fcSRobert Mustacchi {
1739*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_intr_type != DDI_INTR_TYPE_MSIX) {
1740*9d26e4fcSRobert Mustacchi 		return (B_TRUE);
1741*9d26e4fcSRobert Mustacchi 	}
1742*9d26e4fcSRobert Mustacchi 
1743*9d26e4fcSRobert Mustacchi 	/*
1744*9d26e4fcSRobert Mustacchi 	 * At the moment, we only have one queue and one interrupt thus both are
1745*9d26e4fcSRobert Mustacchi 	 * on that one interrupt. However, longer term we need to go back to
1746*9d26e4fcSRobert Mustacchi 	 * using the ixgbe style map of queues to vectors or walk the linked
1747*9d26e4fcSRobert Mustacchi 	 * list from the device to know what to go handle. Therefore for the
1748*9d26e4fcSRobert Mustacchi 	 * moment, since we need to map our single set of rings to the one
1749*9d26e4fcSRobert Mustacchi 	 * I/O interrupt that exists for MSI-X.
1750*9d26e4fcSRobert Mustacchi 	 */
1751*9d26e4fcSRobert Mustacchi 	ASSERT(i40e->i40e_intr_count == 2);
1752*9d26e4fcSRobert Mustacchi 	ASSERT(i40e->i40e_num_trqpairs == 1);
1753*9d26e4fcSRobert Mustacchi 
1754*9d26e4fcSRobert Mustacchi 	i40e->i40e_trqpairs[0].itrq_rx_intrvec = 1;
1755*9d26e4fcSRobert Mustacchi 	i40e->i40e_trqpairs[0].itrq_tx_intrvec = 1;
1756*9d26e4fcSRobert Mustacchi 
1757*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
1758*9d26e4fcSRobert Mustacchi }
1759*9d26e4fcSRobert Mustacchi 
1760*9d26e4fcSRobert Mustacchi static boolean_t
1761*9d26e4fcSRobert Mustacchi i40e_add_intr_handlers(i40e_t *i40e)
1762*9d26e4fcSRobert Mustacchi {
1763*9d26e4fcSRobert Mustacchi 	int rc, vector;
1764*9d26e4fcSRobert Mustacchi 
1765*9d26e4fcSRobert Mustacchi 	switch (i40e->i40e_intr_type) {
1766*9d26e4fcSRobert Mustacchi 	case DDI_INTR_TYPE_MSIX:
1767*9d26e4fcSRobert Mustacchi 		for (vector = 0; vector < i40e->i40e_intr_count; vector++) {
1768*9d26e4fcSRobert Mustacchi 			rc = ddi_intr_add_handler(
1769*9d26e4fcSRobert Mustacchi 			    i40e->i40e_intr_handles[vector],
1770*9d26e4fcSRobert Mustacchi 			    (ddi_intr_handler_t *)i40e_intr_msix, i40e,
1771*9d26e4fcSRobert Mustacchi 			    (void *)(uintptr_t)vector);
1772*9d26e4fcSRobert Mustacchi 			if (rc != DDI_SUCCESS) {
1773*9d26e4fcSRobert Mustacchi 				i40e_log(i40e, "Add interrupt handler (MSI-X) "
1774*9d26e4fcSRobert Mustacchi 				    "failed: return %d, vector %d", rc, vector);
1775*9d26e4fcSRobert Mustacchi 				for (vector--; vector >= 0; vector--) {
1776*9d26e4fcSRobert Mustacchi 					(void) ddi_intr_remove_handler(
1777*9d26e4fcSRobert Mustacchi 					    i40e->i40e_intr_handles[vector]);
1778*9d26e4fcSRobert Mustacchi 				}
1779*9d26e4fcSRobert Mustacchi 				return (B_FALSE);
1780*9d26e4fcSRobert Mustacchi 			}
1781*9d26e4fcSRobert Mustacchi 		}
1782*9d26e4fcSRobert Mustacchi 		break;
1783*9d26e4fcSRobert Mustacchi 	case DDI_INTR_TYPE_MSI:
1784*9d26e4fcSRobert Mustacchi 		rc = ddi_intr_add_handler(i40e->i40e_intr_handles[0],
1785*9d26e4fcSRobert Mustacchi 		    (ddi_intr_handler_t *)i40e_intr_msi, i40e, NULL);
1786*9d26e4fcSRobert Mustacchi 		if (rc != DDI_SUCCESS) {
1787*9d26e4fcSRobert Mustacchi 			i40e_log(i40e, "Add interrupt handler (MSI) failed: "
1788*9d26e4fcSRobert Mustacchi 			    "return %d", rc);
1789*9d26e4fcSRobert Mustacchi 			return (B_FALSE);
1790*9d26e4fcSRobert Mustacchi 		}
1791*9d26e4fcSRobert Mustacchi 		break;
1792*9d26e4fcSRobert Mustacchi 	case DDI_INTR_TYPE_FIXED:
1793*9d26e4fcSRobert Mustacchi 		rc = ddi_intr_add_handler(i40e->i40e_intr_handles[0],
1794*9d26e4fcSRobert Mustacchi 		    (ddi_intr_handler_t *)i40e_intr_legacy, i40e, NULL);
1795*9d26e4fcSRobert Mustacchi 		if (rc != DDI_SUCCESS) {
1796*9d26e4fcSRobert Mustacchi 			i40e_log(i40e, "Add interrupt handler (legacy) failed:"
1797*9d26e4fcSRobert Mustacchi 			    " return %d", rc);
1798*9d26e4fcSRobert Mustacchi 			return (B_FALSE);
1799*9d26e4fcSRobert Mustacchi 		}
1800*9d26e4fcSRobert Mustacchi 		break;
1801*9d26e4fcSRobert Mustacchi 	default:
1802*9d26e4fcSRobert Mustacchi 		/* Cast to pacify lint */
1803*9d26e4fcSRobert Mustacchi 		panic("i40e_intr_type %p contains an unknown type: %d",
1804*9d26e4fcSRobert Mustacchi 		    (void *)i40e, i40e->i40e_intr_type);
1805*9d26e4fcSRobert Mustacchi 	}
1806*9d26e4fcSRobert Mustacchi 
1807*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
1808*9d26e4fcSRobert Mustacchi }
1809*9d26e4fcSRobert Mustacchi 
1810*9d26e4fcSRobert Mustacchi /*
1811*9d26e4fcSRobert Mustacchi  * Perform periodic checks. Longer term, we should be thinking about additional
1812*9d26e4fcSRobert Mustacchi  * things here:
1813*9d26e4fcSRobert Mustacchi  *
1814*9d26e4fcSRobert Mustacchi  * o Stall Detection
1815*9d26e4fcSRobert Mustacchi  * o Temperature sensor detection
1816*9d26e4fcSRobert Mustacchi  * o Device resetting
1817*9d26e4fcSRobert Mustacchi  * o Statistics updating to avoid wraparound
1818*9d26e4fcSRobert Mustacchi  */
1819*9d26e4fcSRobert Mustacchi static void
1820*9d26e4fcSRobert Mustacchi i40e_timer(void *arg)
1821*9d26e4fcSRobert Mustacchi {
1822*9d26e4fcSRobert Mustacchi 	i40e_t *i40e = arg;
1823*9d26e4fcSRobert Mustacchi 
1824*9d26e4fcSRobert Mustacchi 	mutex_enter(&i40e->i40e_general_lock);
1825*9d26e4fcSRobert Mustacchi 	i40e_link_check(i40e);
1826*9d26e4fcSRobert Mustacchi 	mutex_exit(&i40e->i40e_general_lock);
1827*9d26e4fcSRobert Mustacchi }
1828*9d26e4fcSRobert Mustacchi 
1829*9d26e4fcSRobert Mustacchi /*
1830*9d26e4fcSRobert Mustacchi  * Get the hardware state, and scribble away anything that needs scribbling.
1831*9d26e4fcSRobert Mustacchi  */
1832*9d26e4fcSRobert Mustacchi static void
1833*9d26e4fcSRobert Mustacchi i40e_get_hw_state(i40e_t *i40e, i40e_hw_t *hw)
1834*9d26e4fcSRobert Mustacchi {
1835*9d26e4fcSRobert Mustacchi 	int rc;
1836*9d26e4fcSRobert Mustacchi 
1837*9d26e4fcSRobert Mustacchi 	ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
1838*9d26e4fcSRobert Mustacchi 
1839*9d26e4fcSRobert Mustacchi 	(void) i40e_aq_get_link_info(hw, TRUE, NULL, NULL);
1840*9d26e4fcSRobert Mustacchi 	i40e_link_check(i40e);
1841*9d26e4fcSRobert Mustacchi 
1842*9d26e4fcSRobert Mustacchi 	/*
1843*9d26e4fcSRobert Mustacchi 	 * Try and determine our PHY. Note that we may have to retry to and
1844*9d26e4fcSRobert Mustacchi 	 * delay to detect fiber correctly.
1845*9d26e4fcSRobert Mustacchi 	 */
1846*9d26e4fcSRobert Mustacchi 	rc = i40e_aq_get_phy_capabilities(hw, B_FALSE, B_TRUE, &i40e->i40e_phy,
1847*9d26e4fcSRobert Mustacchi 	    NULL);
1848*9d26e4fcSRobert Mustacchi 	if (rc == I40E_ERR_UNKNOWN_PHY) {
1849*9d26e4fcSRobert Mustacchi 		i40e_msec_delay(200);
1850*9d26e4fcSRobert Mustacchi 		rc = i40e_aq_get_phy_capabilities(hw, B_FALSE, B_TRUE,
1851*9d26e4fcSRobert Mustacchi 		    &i40e->i40e_phy, NULL);
1852*9d26e4fcSRobert Mustacchi 	}
1853*9d26e4fcSRobert Mustacchi 
1854*9d26e4fcSRobert Mustacchi 	if (rc != I40E_SUCCESS) {
1855*9d26e4fcSRobert Mustacchi 		if (rc == I40E_ERR_UNKNOWN_PHY) {
1856*9d26e4fcSRobert Mustacchi 			i40e_error(i40e, "encountered unknown PHY type, "
1857*9d26e4fcSRobert Mustacchi 			    "not attaching.");
1858*9d26e4fcSRobert Mustacchi 		} else {
1859*9d26e4fcSRobert Mustacchi 			i40e_error(i40e, "error getting physical capabilities: "
1860*9d26e4fcSRobert Mustacchi 			    "%d, %d", rc, hw->aq.asq_last_status);
1861*9d26e4fcSRobert Mustacchi 		}
1862*9d26e4fcSRobert Mustacchi 	}
1863*9d26e4fcSRobert Mustacchi 
1864*9d26e4fcSRobert Mustacchi 	rc = i40e_update_link_info(hw);
1865*9d26e4fcSRobert Mustacchi 	if (rc != I40E_SUCCESS) {
1866*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to update link information: %d", rc);
1867*9d26e4fcSRobert Mustacchi 	}
1868*9d26e4fcSRobert Mustacchi 
1869*9d26e4fcSRobert Mustacchi 	/*
1870*9d26e4fcSRobert Mustacchi 	 * In general, we don't want to mask off (as in stop from being a cause)
1871*9d26e4fcSRobert Mustacchi 	 * any of the interrupts that the phy might be able to generate.
1872*9d26e4fcSRobert Mustacchi 	 */
1873*9d26e4fcSRobert Mustacchi 	rc = i40e_aq_set_phy_int_mask(hw, 0, NULL);
1874*9d26e4fcSRobert Mustacchi 	if (rc != I40E_SUCCESS) {
1875*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to update phy link mask: %d", rc);
1876*9d26e4fcSRobert Mustacchi 	}
1877*9d26e4fcSRobert Mustacchi }
1878*9d26e4fcSRobert Mustacchi 
1879*9d26e4fcSRobert Mustacchi /*
1880*9d26e4fcSRobert Mustacchi  * Go through and re-initialize any existing filters that we may have set up for
1881*9d26e4fcSRobert Mustacchi  * this device. Note that we would only expect them to exist if hardware had
1882*9d26e4fcSRobert Mustacchi  * already been initialized and we had just reset it. While we're not
1883*9d26e4fcSRobert Mustacchi  * implementing this yet, we're keeping this around for when we add reset
1884*9d26e4fcSRobert Mustacchi  * capabilities, so this isn't forgotten.
1885*9d26e4fcSRobert Mustacchi  */
1886*9d26e4fcSRobert Mustacchi /* ARGSUSED */
1887*9d26e4fcSRobert Mustacchi static void
1888*9d26e4fcSRobert Mustacchi i40e_init_macaddrs(i40e_t *i40e, i40e_hw_t *hw)
1889*9d26e4fcSRobert Mustacchi {
1890*9d26e4fcSRobert Mustacchi }
1891*9d26e4fcSRobert Mustacchi 
1892*9d26e4fcSRobert Mustacchi /*
1893*9d26e4fcSRobert Mustacchi  * Configure the hardware for the Virtual Station Interface (VSI).  Currently
1894*9d26e4fcSRobert Mustacchi  * we only support one, but in the future we could instantiate more than one
1895*9d26e4fcSRobert Mustacchi  * per attach-point.
1896*9d26e4fcSRobert Mustacchi  */
1897*9d26e4fcSRobert Mustacchi static boolean_t
1898*9d26e4fcSRobert Mustacchi i40e_config_vsi(i40e_t *i40e, i40e_hw_t *hw)
1899*9d26e4fcSRobert Mustacchi {
1900*9d26e4fcSRobert Mustacchi 	struct i40e_vsi_context	context;
1901*9d26e4fcSRobert Mustacchi 	int err;
1902*9d26e4fcSRobert Mustacchi 
1903*9d26e4fcSRobert Mustacchi 	bzero(&context, sizeof (struct i40e_vsi_context));
1904*9d26e4fcSRobert Mustacchi 	context.seid = i40e->i40e_vsi_id;
1905*9d26e4fcSRobert Mustacchi 	context.pf_num = hw->pf_id;
1906*9d26e4fcSRobert Mustacchi 	err = i40e_aq_get_vsi_params(hw, &context, NULL);
1907*9d26e4fcSRobert Mustacchi 	if (err != I40E_SUCCESS) {
1908*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "get VSI params failed with %d", err);
1909*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1910*9d26e4fcSRobert Mustacchi 	}
1911*9d26e4fcSRobert Mustacchi 
1912*9d26e4fcSRobert Mustacchi 	/*
1913*9d26e4fcSRobert Mustacchi 	 * Set the queue and traffic class bits.  Keep it simple for now.
1914*9d26e4fcSRobert Mustacchi 	 */
1915*9d26e4fcSRobert Mustacchi 	context.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
1916*9d26e4fcSRobert Mustacchi 	context.info.mapping_flags = I40E_AQ_VSI_QUE_MAP_CONTIG;
1917*9d26e4fcSRobert Mustacchi 	context.info.queue_mapping[0] = I40E_ASSIGN_ALL_QUEUES;
1918*9d26e4fcSRobert Mustacchi 	context.info.tc_mapping[0] = I40E_TRAFFIC_CLASS_NO_QUEUES;
1919*9d26e4fcSRobert Mustacchi 
1920*9d26e4fcSRobert Mustacchi 	context.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID;
1921*9d26e4fcSRobert Mustacchi 	context.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
1922*9d26e4fcSRobert Mustacchi 	    I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
1923*9d26e4fcSRobert Mustacchi 
1924*9d26e4fcSRobert Mustacchi 	context.flags = LE16_TO_CPU(I40E_AQ_VSI_TYPE_PF);
1925*9d26e4fcSRobert Mustacchi 
1926*9d26e4fcSRobert Mustacchi 	i40e->i40e_vsi_stat_id = LE16_TO_CPU(context.info.stat_counter_idx);
1927*9d26e4fcSRobert Mustacchi 	if (i40e_stat_vsi_init(i40e) == B_FALSE)
1928*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1929*9d26e4fcSRobert Mustacchi 
1930*9d26e4fcSRobert Mustacchi 	err = i40e_aq_update_vsi_params(hw, &context, NULL);
1931*9d26e4fcSRobert Mustacchi 	if (err != I40E_SUCCESS) {
1932*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "Update VSI params failed with %d", err);
1933*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1934*9d26e4fcSRobert Mustacchi 	}
1935*9d26e4fcSRobert Mustacchi 
1936*9d26e4fcSRobert Mustacchi 
1937*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
1938*9d26e4fcSRobert Mustacchi }
1939*9d26e4fcSRobert Mustacchi 
1940*9d26e4fcSRobert Mustacchi /*
1941*9d26e4fcSRobert Mustacchi  * Wrapper to kick the chipset on.
1942*9d26e4fcSRobert Mustacchi  */
1943*9d26e4fcSRobert Mustacchi static boolean_t
1944*9d26e4fcSRobert Mustacchi i40e_chip_start(i40e_t *i40e)
1945*9d26e4fcSRobert Mustacchi {
1946*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
1947*9d26e4fcSRobert Mustacchi 	struct i40e_filter_control_settings filter;
1948*9d26e4fcSRobert Mustacchi 	int rc;
1949*9d26e4fcSRobert Mustacchi 
1950*9d26e4fcSRobert Mustacchi 	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
1951*9d26e4fcSRobert Mustacchi 	    (hw->aq.fw_maj_ver < 4)) {
1952*9d26e4fcSRobert Mustacchi 		i40e_msec_delay(75);
1953*9d26e4fcSRobert Mustacchi 		if (i40e_aq_set_link_restart_an(hw, TRUE, NULL) !=
1954*9d26e4fcSRobert Mustacchi 		    I40E_SUCCESS) {
1955*9d26e4fcSRobert Mustacchi 			i40e_error(i40e, "failed to restart link: admin queue "
1956*9d26e4fcSRobert Mustacchi 			    "error: %d", hw->aq.asq_last_status);
1957*9d26e4fcSRobert Mustacchi 			return (B_FALSE);
1958*9d26e4fcSRobert Mustacchi 		}
1959*9d26e4fcSRobert Mustacchi 	}
1960*9d26e4fcSRobert Mustacchi 
1961*9d26e4fcSRobert Mustacchi 	/* Determine hardware state */
1962*9d26e4fcSRobert Mustacchi 	i40e_get_hw_state(i40e, hw);
1963*9d26e4fcSRobert Mustacchi 
1964*9d26e4fcSRobert Mustacchi 	/* Initialize mac addresses. */
1965*9d26e4fcSRobert Mustacchi 	i40e_init_macaddrs(i40e, hw);
1966*9d26e4fcSRobert Mustacchi 
1967*9d26e4fcSRobert Mustacchi 	/*
1968*9d26e4fcSRobert Mustacchi 	 * Set up the filter control.
1969*9d26e4fcSRobert Mustacchi 	 */
1970*9d26e4fcSRobert Mustacchi 	bzero(&filter, sizeof (filter));
1971*9d26e4fcSRobert Mustacchi 	filter.enable_ethtype = TRUE;
1972*9d26e4fcSRobert Mustacchi 	filter.enable_macvlan = TRUE;
1973*9d26e4fcSRobert Mustacchi 
1974*9d26e4fcSRobert Mustacchi 	rc = i40e_set_filter_control(hw, &filter);
1975*9d26e4fcSRobert Mustacchi 	if (rc != I40E_SUCCESS) {
1976*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "i40e_set_filter_control() returned %d", rc);
1977*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1978*9d26e4fcSRobert Mustacchi 	}
1979*9d26e4fcSRobert Mustacchi 
1980*9d26e4fcSRobert Mustacchi 	i40e_intr_chip_init(i40e);
1981*9d26e4fcSRobert Mustacchi 
1982*9d26e4fcSRobert Mustacchi 	if (!i40e_config_vsi(i40e, hw))
1983*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
1984*9d26e4fcSRobert Mustacchi 
1985*9d26e4fcSRobert Mustacchi 	i40e_flush(hw);
1986*9d26e4fcSRobert Mustacchi 
1987*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
1988*9d26e4fcSRobert Mustacchi }
1989*9d26e4fcSRobert Mustacchi 
1990*9d26e4fcSRobert Mustacchi /*
1991*9d26e4fcSRobert Mustacchi  * Take care of tearing down the rx ring. See 8.3.3.1.2 for more information.
1992*9d26e4fcSRobert Mustacchi  */
1993*9d26e4fcSRobert Mustacchi static void
1994*9d26e4fcSRobert Mustacchi i40e_shutdown_rx_rings(i40e_t *i40e)
1995*9d26e4fcSRobert Mustacchi {
1996*9d26e4fcSRobert Mustacchi 	int i;
1997*9d26e4fcSRobert Mustacchi 	uint32_t reg;
1998*9d26e4fcSRobert Mustacchi 
1999*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
2000*9d26e4fcSRobert Mustacchi 
2001*9d26e4fcSRobert Mustacchi 	/*
2002*9d26e4fcSRobert Mustacchi 	 * Step 1. The interrupt linked list (see i40e_intr.c for more
2003*9d26e4fcSRobert Mustacchi 	 * information) should have already been cleared before calling this
2004*9d26e4fcSRobert Mustacchi 	 * function.
2005*9d26e4fcSRobert Mustacchi 	 */
2006*9d26e4fcSRobert Mustacchi #ifdef	DEBUG
2007*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) {
2008*9d26e4fcSRobert Mustacchi 		for (i = 1; i < i40e->i40e_intr_count; i++) {
2009*9d26e4fcSRobert Mustacchi 			reg = I40E_READ_REG(hw, I40E_PFINT_LNKLSTN(i - 1));
2010*9d26e4fcSRobert Mustacchi 			VERIFY3U(reg, ==, I40E_QUEUE_TYPE_EOL);
2011*9d26e4fcSRobert Mustacchi 		}
2012*9d26e4fcSRobert Mustacchi 	} else {
2013*9d26e4fcSRobert Mustacchi 		reg = I40E_READ_REG(hw, I40E_PFINT_LNKLST0);
2014*9d26e4fcSRobert Mustacchi 		VERIFY3U(reg, ==, I40E_QUEUE_TYPE_EOL);
2015*9d26e4fcSRobert Mustacchi 	}
2016*9d26e4fcSRobert Mustacchi 
2017*9d26e4fcSRobert Mustacchi #endif	/* DEBUG */
2018*9d26e4fcSRobert Mustacchi 
2019*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
2020*9d26e4fcSRobert Mustacchi 		/*
2021*9d26e4fcSRobert Mustacchi 		 * Step 1. Request the queue by clearing QENA_REQ. It may not be
2022*9d26e4fcSRobert Mustacchi 		 * set due to unwinding from failures and a partially enabled
2023*9d26e4fcSRobert Mustacchi 		 * ring set.
2024*9d26e4fcSRobert Mustacchi 		 */
2025*9d26e4fcSRobert Mustacchi 		reg = I40E_READ_REG(hw, I40E_QRX_ENA(i));
2026*9d26e4fcSRobert Mustacchi 		if (!(reg & I40E_QRX_ENA_QENA_REQ_MASK))
2027*9d26e4fcSRobert Mustacchi 			continue;
2028*9d26e4fcSRobert Mustacchi 		VERIFY((reg & I40E_QRX_ENA_QENA_REQ_MASK) ==
2029*9d26e4fcSRobert Mustacchi 		    I40E_QRX_ENA_QENA_REQ_MASK);
2030*9d26e4fcSRobert Mustacchi 		reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
2031*9d26e4fcSRobert Mustacchi 		I40E_WRITE_REG(hw, I40E_QRX_ENA(i), reg);
2032*9d26e4fcSRobert Mustacchi 	}
2033*9d26e4fcSRobert Mustacchi 
2034*9d26e4fcSRobert Mustacchi 	/*
2035*9d26e4fcSRobert Mustacchi 	 * Step 2. Wait for the disable to take, by having QENA_STAT in the FPM
2036*9d26e4fcSRobert Mustacchi 	 * be cleared. Note that we could still receive data in the queue during
2037*9d26e4fcSRobert Mustacchi 	 * this time. We don't actually wait for this now and instead defer this
2038*9d26e4fcSRobert Mustacchi 	 * to i40e_shutdown_rings_wait(), after we've interleaved disabling the
2039*9d26e4fcSRobert Mustacchi 	 * TX queues as well.
2040*9d26e4fcSRobert Mustacchi 	 */
2041*9d26e4fcSRobert Mustacchi }
2042*9d26e4fcSRobert Mustacchi 
2043*9d26e4fcSRobert Mustacchi static void
2044*9d26e4fcSRobert Mustacchi i40e_shutdown_tx_rings(i40e_t *i40e)
2045*9d26e4fcSRobert Mustacchi {
2046*9d26e4fcSRobert Mustacchi 	int i;
2047*9d26e4fcSRobert Mustacchi 	uint32_t reg;
2048*9d26e4fcSRobert Mustacchi 
2049*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
2050*9d26e4fcSRobert Mustacchi 
2051*9d26e4fcSRobert Mustacchi 	/*
2052*9d26e4fcSRobert Mustacchi 	 * Step 1. The interrupt linked list should already have been cleared.
2053*9d26e4fcSRobert Mustacchi 	 */
2054*9d26e4fcSRobert Mustacchi #ifdef DEBUG
2055*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) {
2056*9d26e4fcSRobert Mustacchi 		for (i = 1; i < i40e->i40e_intr_count; i++) {
2057*9d26e4fcSRobert Mustacchi 			reg = I40E_READ_REG(hw, I40E_PFINT_LNKLSTN(i - 1));
2058*9d26e4fcSRobert Mustacchi 			VERIFY3U(reg, ==, I40E_QUEUE_TYPE_EOL);
2059*9d26e4fcSRobert Mustacchi 		}
2060*9d26e4fcSRobert Mustacchi 	} else {
2061*9d26e4fcSRobert Mustacchi 		reg = I40E_READ_REG(hw, I40E_PFINT_LNKLST0);
2062*9d26e4fcSRobert Mustacchi 		VERIFY3U(reg, ==, I40E_QUEUE_TYPE_EOL);
2063*9d26e4fcSRobert Mustacchi 
2064*9d26e4fcSRobert Mustacchi 	}
2065*9d26e4fcSRobert Mustacchi #endif	/* DEBUG */
2066*9d26e4fcSRobert Mustacchi 
2067*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
2068*9d26e4fcSRobert Mustacchi 		/*
2069*9d26e4fcSRobert Mustacchi 		 * Step 2. Set the SET_QDIS flag for every queue.
2070*9d26e4fcSRobert Mustacchi 		 */
2071*9d26e4fcSRobert Mustacchi 		i40e_pre_tx_queue_cfg(hw, i, B_FALSE);
2072*9d26e4fcSRobert Mustacchi 	}
2073*9d26e4fcSRobert Mustacchi 
2074*9d26e4fcSRobert Mustacchi 	/*
2075*9d26e4fcSRobert Mustacchi 	 * Step 3. Wait at least 400 usec (can be done once for all queues).
2076*9d26e4fcSRobert Mustacchi 	 */
2077*9d26e4fcSRobert Mustacchi 	drv_usecwait(500);
2078*9d26e4fcSRobert Mustacchi 
2079*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
2080*9d26e4fcSRobert Mustacchi 		/*
2081*9d26e4fcSRobert Mustacchi 		 * Step 4. Clear the QENA_REQ flag which tells hardware to
2082*9d26e4fcSRobert Mustacchi 		 * quiesce. If QENA_REQ is not already set then that means that
2083*9d26e4fcSRobert Mustacchi 		 * we likely already tried to disable this queue.
2084*9d26e4fcSRobert Mustacchi 		 */
2085*9d26e4fcSRobert Mustacchi 		reg = I40E_READ_REG(hw, I40E_QTX_ENA(i));
2086*9d26e4fcSRobert Mustacchi 		if (!(reg & I40E_QTX_ENA_QENA_REQ_MASK))
2087*9d26e4fcSRobert Mustacchi 			continue;
2088*9d26e4fcSRobert Mustacchi 		reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
2089*9d26e4fcSRobert Mustacchi 		I40E_WRITE_REG(hw, I40E_QTX_ENA(i), reg);
2090*9d26e4fcSRobert Mustacchi 	}
2091*9d26e4fcSRobert Mustacchi 
2092*9d26e4fcSRobert Mustacchi 	/*
2093*9d26e4fcSRobert Mustacchi 	 * Step 5. Wait for all drains to finish. This will be done by the
2094*9d26e4fcSRobert Mustacchi 	 * hardware removing the QENA_STAT flag from the queue. Rather than
2095*9d26e4fcSRobert Mustacchi 	 * waiting here, we interleave it with all the others in
2096*9d26e4fcSRobert Mustacchi 	 * i40e_shutdown_rings_wait().
2097*9d26e4fcSRobert Mustacchi 	 */
2098*9d26e4fcSRobert Mustacchi }
2099*9d26e4fcSRobert Mustacchi 
2100*9d26e4fcSRobert Mustacchi /*
2101*9d26e4fcSRobert Mustacchi  * Wait for all the rings to be shut down. e.g. Steps 2 and 5 from the above
2102*9d26e4fcSRobert Mustacchi  * functions.
2103*9d26e4fcSRobert Mustacchi  */
2104*9d26e4fcSRobert Mustacchi static boolean_t
2105*9d26e4fcSRobert Mustacchi i40e_shutdown_rings_wait(i40e_t *i40e)
2106*9d26e4fcSRobert Mustacchi {
2107*9d26e4fcSRobert Mustacchi 	int i, try;
2108*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
2109*9d26e4fcSRobert Mustacchi 
2110*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
2111*9d26e4fcSRobert Mustacchi 		uint32_t reg;
2112*9d26e4fcSRobert Mustacchi 
2113*9d26e4fcSRobert Mustacchi 		for (try = 0; try < I40E_RING_WAIT_NTRIES; try++) {
2114*9d26e4fcSRobert Mustacchi 			reg = I40E_READ_REG(hw, I40E_QRX_ENA(i));
2115*9d26e4fcSRobert Mustacchi 			if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0)
2116*9d26e4fcSRobert Mustacchi 				break;
2117*9d26e4fcSRobert Mustacchi 			i40e_msec_delay(I40E_RING_WAIT_PAUSE);
2118*9d26e4fcSRobert Mustacchi 		}
2119*9d26e4fcSRobert Mustacchi 
2120*9d26e4fcSRobert Mustacchi 		if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) != 0) {
2121*9d26e4fcSRobert Mustacchi 			i40e_error(i40e, "timed out disabling rx queue %d",
2122*9d26e4fcSRobert Mustacchi 			    i);
2123*9d26e4fcSRobert Mustacchi 			return (B_FALSE);
2124*9d26e4fcSRobert Mustacchi 		}
2125*9d26e4fcSRobert Mustacchi 
2126*9d26e4fcSRobert Mustacchi 		for (try = 0; try < I40E_RING_WAIT_NTRIES; try++) {
2127*9d26e4fcSRobert Mustacchi 			reg = I40E_READ_REG(hw, I40E_QTX_ENA(i));
2128*9d26e4fcSRobert Mustacchi 			if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0)
2129*9d26e4fcSRobert Mustacchi 				break;
2130*9d26e4fcSRobert Mustacchi 			i40e_msec_delay(I40E_RING_WAIT_PAUSE);
2131*9d26e4fcSRobert Mustacchi 		}
2132*9d26e4fcSRobert Mustacchi 
2133*9d26e4fcSRobert Mustacchi 		if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) != 0) {
2134*9d26e4fcSRobert Mustacchi 			i40e_error(i40e, "timed out disabling tx queue %d",
2135*9d26e4fcSRobert Mustacchi 			    i);
2136*9d26e4fcSRobert Mustacchi 			return (B_FALSE);
2137*9d26e4fcSRobert Mustacchi 		}
2138*9d26e4fcSRobert Mustacchi 	}
2139*9d26e4fcSRobert Mustacchi 
2140*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
2141*9d26e4fcSRobert Mustacchi }
2142*9d26e4fcSRobert Mustacchi 
2143*9d26e4fcSRobert Mustacchi static boolean_t
2144*9d26e4fcSRobert Mustacchi i40e_shutdown_rings(i40e_t *i40e)
2145*9d26e4fcSRobert Mustacchi {
2146*9d26e4fcSRobert Mustacchi 	i40e_shutdown_rx_rings(i40e);
2147*9d26e4fcSRobert Mustacchi 	i40e_shutdown_tx_rings(i40e);
2148*9d26e4fcSRobert Mustacchi 	return (i40e_shutdown_rings_wait(i40e));
2149*9d26e4fcSRobert Mustacchi }
2150*9d26e4fcSRobert Mustacchi 
2151*9d26e4fcSRobert Mustacchi static void
2152*9d26e4fcSRobert Mustacchi i40e_setup_rx_descs(i40e_trqpair_t *itrq)
2153*9d26e4fcSRobert Mustacchi {
2154*9d26e4fcSRobert Mustacchi 	int i;
2155*9d26e4fcSRobert Mustacchi 	i40e_rx_data_t *rxd = itrq->itrq_rxdata;
2156*9d26e4fcSRobert Mustacchi 
2157*9d26e4fcSRobert Mustacchi 	for (i = 0; i < rxd->rxd_ring_size; i++) {
2158*9d26e4fcSRobert Mustacchi 		i40e_rx_control_block_t *rcb;
2159*9d26e4fcSRobert Mustacchi 		i40e_rx_desc_t *rdesc;
2160*9d26e4fcSRobert Mustacchi 
2161*9d26e4fcSRobert Mustacchi 		rcb = rxd->rxd_work_list[i];
2162*9d26e4fcSRobert Mustacchi 		rdesc = &rxd->rxd_desc_ring[i];
2163*9d26e4fcSRobert Mustacchi 
2164*9d26e4fcSRobert Mustacchi 		rdesc->read.pkt_addr =
2165*9d26e4fcSRobert Mustacchi 		    CPU_TO_LE64((uintptr_t)rcb->rcb_dma.dmab_dma_address);
2166*9d26e4fcSRobert Mustacchi 		rdesc->read.hdr_addr = 0;
2167*9d26e4fcSRobert Mustacchi 	}
2168*9d26e4fcSRobert Mustacchi }
2169*9d26e4fcSRobert Mustacchi 
2170*9d26e4fcSRobert Mustacchi static boolean_t
2171*9d26e4fcSRobert Mustacchi i40e_setup_rx_hmc(i40e_trqpair_t *itrq)
2172*9d26e4fcSRobert Mustacchi {
2173*9d26e4fcSRobert Mustacchi 	i40e_rx_data_t *rxd = itrq->itrq_rxdata;
2174*9d26e4fcSRobert Mustacchi 	i40e_t *i40e = itrq->itrq_i40e;
2175*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
2176*9d26e4fcSRobert Mustacchi 
2177*9d26e4fcSRobert Mustacchi 	struct i40e_hmc_obj_rxq rctx;
2178*9d26e4fcSRobert Mustacchi 	int err;
2179*9d26e4fcSRobert Mustacchi 
2180*9d26e4fcSRobert Mustacchi 	bzero(&rctx, sizeof (struct i40e_hmc_obj_rxq));
2181*9d26e4fcSRobert Mustacchi 	rctx.base = rxd->rxd_desc_area.dmab_dma_address /
2182*9d26e4fcSRobert Mustacchi 	    I40E_HMC_RX_CTX_UNIT;
2183*9d26e4fcSRobert Mustacchi 	rctx.qlen = rxd->rxd_ring_size;
2184*9d26e4fcSRobert Mustacchi 	VERIFY(i40e->i40e_rx_buf_size >= I40E_HMC_RX_DBUFF_MIN);
2185*9d26e4fcSRobert Mustacchi 	VERIFY(i40e->i40e_rx_buf_size <= I40E_HMC_RX_DBUFF_MAX);
2186*9d26e4fcSRobert Mustacchi 	rctx.dbuff = i40e->i40e_rx_buf_size >> I40E_RXQ_CTX_DBUFF_SHIFT;
2187*9d26e4fcSRobert Mustacchi 	rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT;
2188*9d26e4fcSRobert Mustacchi 	rctx.dtype = I40E_HMC_RX_DTYPE_NOSPLIT;
2189*9d26e4fcSRobert Mustacchi 	rctx.dsize = I40E_HMC_RX_DSIZE_32BYTE;
2190*9d26e4fcSRobert Mustacchi 	rctx.crcstrip = I40E_HMC_RX_CRCSTRIP_ENABLE;
2191*9d26e4fcSRobert Mustacchi 	rctx.fc_ena = I40E_HMC_RX_FC_DISABLE;
2192*9d26e4fcSRobert Mustacchi 	rctx.l2tsel = I40E_HMC_RX_L2TAGORDER;
2193*9d26e4fcSRobert Mustacchi 	rctx.hsplit_0 = I40E_HMC_RX_HDRSPLIT_DISABLE;
2194*9d26e4fcSRobert Mustacchi 	rctx.hsplit_1 = I40E_HMC_RX_HDRSPLIT_DISABLE;
2195*9d26e4fcSRobert Mustacchi 	rctx.showiv = I40E_HMC_RX_INVLAN_DONTSTRIP;
2196*9d26e4fcSRobert Mustacchi 	rctx.rxmax = i40e->i40e_frame_max;
2197*9d26e4fcSRobert Mustacchi 	rctx.tphrdesc_ena = I40E_HMC_RX_TPH_DISABLE;
2198*9d26e4fcSRobert Mustacchi 	rctx.tphwdesc_ena = I40E_HMC_RX_TPH_DISABLE;
2199*9d26e4fcSRobert Mustacchi 	rctx.tphdata_ena = I40E_HMC_RX_TPH_DISABLE;
2200*9d26e4fcSRobert Mustacchi 	rctx.tphhead_ena = I40E_HMC_RX_TPH_DISABLE;
2201*9d26e4fcSRobert Mustacchi 	rctx.lrxqthresh = I40E_HMC_RX_LOWRXQ_NOINTR;
2202*9d26e4fcSRobert Mustacchi 
2203*9d26e4fcSRobert Mustacchi 	/*
2204*9d26e4fcSRobert Mustacchi 	 * This must be set to 0x1, see Table 8-12 in section 8.3.3.2.2.
2205*9d26e4fcSRobert Mustacchi 	 */
2206*9d26e4fcSRobert Mustacchi 	rctx.prefena = I40E_HMC_RX_PREFENA;
2207*9d26e4fcSRobert Mustacchi 
2208*9d26e4fcSRobert Mustacchi 	err = i40e_clear_lan_rx_queue_context(hw, itrq->itrq_index);
2209*9d26e4fcSRobert Mustacchi 	if (err != I40E_SUCCESS) {
2210*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to clear rx queue %d context: %d",
2211*9d26e4fcSRobert Mustacchi 		    itrq->itrq_index, err);
2212*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
2213*9d26e4fcSRobert Mustacchi 	}
2214*9d26e4fcSRobert Mustacchi 
2215*9d26e4fcSRobert Mustacchi 	err = i40e_set_lan_rx_queue_context(hw, itrq->itrq_index, &rctx);
2216*9d26e4fcSRobert Mustacchi 	if (err != I40E_SUCCESS) {
2217*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to set rx queue %d context: %d",
2218*9d26e4fcSRobert Mustacchi 		    itrq->itrq_index, err);
2219*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
2220*9d26e4fcSRobert Mustacchi 	}
2221*9d26e4fcSRobert Mustacchi 
2222*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
2223*9d26e4fcSRobert Mustacchi }
2224*9d26e4fcSRobert Mustacchi 
2225*9d26e4fcSRobert Mustacchi /*
2226*9d26e4fcSRobert Mustacchi  * Take care of setting up the descriptor rings and actually programming the
2227*9d26e4fcSRobert Mustacchi  * device. See 8.3.3.1.1 for the full list of steps we need to do to enable the
2228*9d26e4fcSRobert Mustacchi  * rx rings.
2229*9d26e4fcSRobert Mustacchi  */
2230*9d26e4fcSRobert Mustacchi static boolean_t
2231*9d26e4fcSRobert Mustacchi i40e_setup_rx_rings(i40e_t *i40e)
2232*9d26e4fcSRobert Mustacchi {
2233*9d26e4fcSRobert Mustacchi 	int i;
2234*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
2235*9d26e4fcSRobert Mustacchi 
2236*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
2237*9d26e4fcSRobert Mustacchi 		i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[i];
2238*9d26e4fcSRobert Mustacchi 		i40e_rx_data_t *rxd = itrq->itrq_rxdata;
2239*9d26e4fcSRobert Mustacchi 		uint32_t reg;
2240*9d26e4fcSRobert Mustacchi 
2241*9d26e4fcSRobert Mustacchi 		/*
2242*9d26e4fcSRobert Mustacchi 		 * Step 1. Program all receive ring descriptors.
2243*9d26e4fcSRobert Mustacchi 		 */
2244*9d26e4fcSRobert Mustacchi 		i40e_setup_rx_descs(itrq);
2245*9d26e4fcSRobert Mustacchi 
2246*9d26e4fcSRobert Mustacchi 		/*
2247*9d26e4fcSRobert Mustacchi 		 * Step 2. Program the queue's FPM/HMC context.
2248*9d26e4fcSRobert Mustacchi 		 */
2249*9d26e4fcSRobert Mustacchi 		if (i40e_setup_rx_hmc(itrq) == B_FALSE)
2250*9d26e4fcSRobert Mustacchi 			return (B_FALSE);
2251*9d26e4fcSRobert Mustacchi 
2252*9d26e4fcSRobert Mustacchi 		/*
2253*9d26e4fcSRobert Mustacchi 		 * Step 3. Clear the queue's tail pointer and set it to the end
2254*9d26e4fcSRobert Mustacchi 		 * of the space.
2255*9d26e4fcSRobert Mustacchi 		 */
2256*9d26e4fcSRobert Mustacchi 		I40E_WRITE_REG(hw, I40E_QRX_TAIL(i), 0);
2257*9d26e4fcSRobert Mustacchi 		I40E_WRITE_REG(hw, I40E_QRX_TAIL(i), rxd->rxd_ring_size - 1);
2258*9d26e4fcSRobert Mustacchi 
2259*9d26e4fcSRobert Mustacchi 		/*
2260*9d26e4fcSRobert Mustacchi 		 * Step 4. Enable the queue via the QENA_REQ.
2261*9d26e4fcSRobert Mustacchi 		 */
2262*9d26e4fcSRobert Mustacchi 		reg = I40E_READ_REG(hw, I40E_QRX_ENA(i));
2263*9d26e4fcSRobert Mustacchi 		VERIFY0(reg & (I40E_QRX_ENA_QENA_REQ_MASK |
2264*9d26e4fcSRobert Mustacchi 		    I40E_QRX_ENA_QENA_STAT_MASK));
2265*9d26e4fcSRobert Mustacchi 		reg |= I40E_QRX_ENA_QENA_REQ_MASK;
2266*9d26e4fcSRobert Mustacchi 		I40E_WRITE_REG(hw, I40E_QRX_ENA(i), reg);
2267*9d26e4fcSRobert Mustacchi 	}
2268*9d26e4fcSRobert Mustacchi 
2269*9d26e4fcSRobert Mustacchi 	/*
2270*9d26e4fcSRobert Mustacchi 	 * Note, we wait for every queue to be enabled before we start checking.
2271*9d26e4fcSRobert Mustacchi 	 * This will hopefully cause most queues to be enabled at this point.
2272*9d26e4fcSRobert Mustacchi 	 */
2273*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
2274*9d26e4fcSRobert Mustacchi 		uint32_t j, reg;
2275*9d26e4fcSRobert Mustacchi 
2276*9d26e4fcSRobert Mustacchi 		/*
2277*9d26e4fcSRobert Mustacchi 		 * Step 5. Verify that QENA_STAT has been set. It's promised
2278*9d26e4fcSRobert Mustacchi 		 * that this should occur within about 10 us, but like other
2279*9d26e4fcSRobert Mustacchi 		 * systems, we give the card a bit more time.
2280*9d26e4fcSRobert Mustacchi 		 */
2281*9d26e4fcSRobert Mustacchi 		for (j = 0; j < I40E_RING_WAIT_NTRIES; j++) {
2282*9d26e4fcSRobert Mustacchi 			reg = I40E_READ_REG(hw, I40E_QRX_ENA(i));
2283*9d26e4fcSRobert Mustacchi 
2284*9d26e4fcSRobert Mustacchi 			if (reg & I40E_QRX_ENA_QENA_STAT_MASK)
2285*9d26e4fcSRobert Mustacchi 				break;
2286*9d26e4fcSRobert Mustacchi 			i40e_msec_delay(I40E_RING_WAIT_PAUSE);
2287*9d26e4fcSRobert Mustacchi 		}
2288*9d26e4fcSRobert Mustacchi 
2289*9d26e4fcSRobert Mustacchi 		if ((reg & I40E_QRX_ENA_QENA_STAT_MASK) == 0) {
2290*9d26e4fcSRobert Mustacchi 			i40e_error(i40e, "failed to enable rx queue %d, timed "
2291*9d26e4fcSRobert Mustacchi 			    "out.", i);
2292*9d26e4fcSRobert Mustacchi 			return (B_FALSE);
2293*9d26e4fcSRobert Mustacchi 		}
2294*9d26e4fcSRobert Mustacchi 	}
2295*9d26e4fcSRobert Mustacchi 
2296*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
2297*9d26e4fcSRobert Mustacchi }
2298*9d26e4fcSRobert Mustacchi 
2299*9d26e4fcSRobert Mustacchi static boolean_t
2300*9d26e4fcSRobert Mustacchi i40e_setup_tx_hmc(i40e_trqpair_t *itrq)
2301*9d26e4fcSRobert Mustacchi {
2302*9d26e4fcSRobert Mustacchi 	i40e_t *i40e = itrq->itrq_i40e;
2303*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
2304*9d26e4fcSRobert Mustacchi 
2305*9d26e4fcSRobert Mustacchi 	struct i40e_hmc_obj_txq tctx;
2306*9d26e4fcSRobert Mustacchi 	struct i40e_vsi_context	context;
2307*9d26e4fcSRobert Mustacchi 	int err;
2308*9d26e4fcSRobert Mustacchi 
2309*9d26e4fcSRobert Mustacchi 	bzero(&tctx, sizeof (struct i40e_hmc_obj_txq));
2310*9d26e4fcSRobert Mustacchi 	tctx.new_context = I40E_HMC_TX_NEW_CONTEXT;
2311*9d26e4fcSRobert Mustacchi 	tctx.base = itrq->itrq_desc_area.dmab_dma_address /
2312*9d26e4fcSRobert Mustacchi 	    I40E_HMC_TX_CTX_UNIT;
2313*9d26e4fcSRobert Mustacchi 	tctx.fc_ena = I40E_HMC_TX_FC_DISABLE;
2314*9d26e4fcSRobert Mustacchi 	tctx.timesync_ena = I40E_HMC_TX_TS_DISABLE;
2315*9d26e4fcSRobert Mustacchi 	tctx.fd_ena = I40E_HMC_TX_FD_DISABLE;
2316*9d26e4fcSRobert Mustacchi 	tctx.alt_vlan_ena = I40E_HMC_TX_ALT_VLAN_DISABLE;
2317*9d26e4fcSRobert Mustacchi 	tctx.head_wb_ena = I40E_HMC_TX_WB_ENABLE;
2318*9d26e4fcSRobert Mustacchi 	tctx.qlen = itrq->itrq_tx_ring_size;
2319*9d26e4fcSRobert Mustacchi 	tctx.tphrdesc_ena = I40E_HMC_TX_TPH_DISABLE;
2320*9d26e4fcSRobert Mustacchi 	tctx.tphrpacket_ena = I40E_HMC_TX_TPH_DISABLE;
2321*9d26e4fcSRobert Mustacchi 	tctx.tphwdesc_ena = I40E_HMC_TX_TPH_DISABLE;
2322*9d26e4fcSRobert Mustacchi 	tctx.head_wb_addr = itrq->itrq_desc_area.dmab_dma_address +
2323*9d26e4fcSRobert Mustacchi 	    sizeof (i40e_tx_desc_t) * itrq->itrq_tx_ring_size;
2324*9d26e4fcSRobert Mustacchi 
2325*9d26e4fcSRobert Mustacchi 	/*
2326*9d26e4fcSRobert Mustacchi 	 * This field isn't actually documented, like crc, but it suggests that
2327*9d26e4fcSRobert Mustacchi 	 * it should be zeroed. We leave both of these here because of that for
2328*9d26e4fcSRobert Mustacchi 	 * now. We should check with Intel on why these are here even.
2329*9d26e4fcSRobert Mustacchi 	 */
2330*9d26e4fcSRobert Mustacchi 	tctx.crc = 0;
2331*9d26e4fcSRobert Mustacchi 	tctx.rdylist_act = 0;
2332*9d26e4fcSRobert Mustacchi 
2333*9d26e4fcSRobert Mustacchi 	/*
2334*9d26e4fcSRobert Mustacchi 	 * We're supposed to assign the rdylist field with the value of the
2335*9d26e4fcSRobert Mustacchi 	 * traffic class index for the first device. We query the VSI parameters
2336*9d26e4fcSRobert Mustacchi 	 * again to get what the handle is. Note that every queue is always
2337*9d26e4fcSRobert Mustacchi 	 * assigned to traffic class zero, because we don't actually use them.
2338*9d26e4fcSRobert Mustacchi 	 */
2339*9d26e4fcSRobert Mustacchi 	bzero(&context, sizeof (struct i40e_vsi_context));
2340*9d26e4fcSRobert Mustacchi 	context.seid = i40e->i40e_vsi_id;
2341*9d26e4fcSRobert Mustacchi 	context.pf_num = hw->pf_id;
2342*9d26e4fcSRobert Mustacchi 	err = i40e_aq_get_vsi_params(hw, &context, NULL);
2343*9d26e4fcSRobert Mustacchi 	if (err != I40E_SUCCESS) {
2344*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "get VSI params failed with %d", err);
2345*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
2346*9d26e4fcSRobert Mustacchi 	}
2347*9d26e4fcSRobert Mustacchi 	tctx.rdylist = LE_16(context.info.qs_handle[0]);
2348*9d26e4fcSRobert Mustacchi 
2349*9d26e4fcSRobert Mustacchi 	err = i40e_clear_lan_tx_queue_context(hw, itrq->itrq_index);
2350*9d26e4fcSRobert Mustacchi 	if (err != I40E_SUCCESS) {
2351*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to clear tx queue %d context: %d",
2352*9d26e4fcSRobert Mustacchi 		    itrq->itrq_index, err);
2353*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
2354*9d26e4fcSRobert Mustacchi 	}
2355*9d26e4fcSRobert Mustacchi 
2356*9d26e4fcSRobert Mustacchi 	err = i40e_set_lan_tx_queue_context(hw, itrq->itrq_index, &tctx);
2357*9d26e4fcSRobert Mustacchi 	if (err != I40E_SUCCESS) {
2358*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to set tx queue %d context: %d",
2359*9d26e4fcSRobert Mustacchi 		    itrq->itrq_index, err);
2360*9d26e4fcSRobert Mustacchi 		return (B_FALSE);
2361*9d26e4fcSRobert Mustacchi 	}
2362*9d26e4fcSRobert Mustacchi 
2363*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
2364*9d26e4fcSRobert Mustacchi }
2365*9d26e4fcSRobert Mustacchi 
2366*9d26e4fcSRobert Mustacchi /*
2367*9d26e4fcSRobert Mustacchi  * Take care of setting up the descriptor rings and actually programming the
2368*9d26e4fcSRobert Mustacchi  * device. See 8.4.3.1.1 for what we need to do here.
2369*9d26e4fcSRobert Mustacchi  */
2370*9d26e4fcSRobert Mustacchi static boolean_t
2371*9d26e4fcSRobert Mustacchi i40e_setup_tx_rings(i40e_t *i40e)
2372*9d26e4fcSRobert Mustacchi {
2373*9d26e4fcSRobert Mustacchi 	int i;
2374*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
2375*9d26e4fcSRobert Mustacchi 
2376*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
2377*9d26e4fcSRobert Mustacchi 		i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[i];
2378*9d26e4fcSRobert Mustacchi 		uint32_t reg;
2379*9d26e4fcSRobert Mustacchi 
2380*9d26e4fcSRobert Mustacchi 		/*
2381*9d26e4fcSRobert Mustacchi 		 * Step 1. Clear the queue disable flag and verify that the
2382*9d26e4fcSRobert Mustacchi 		 * index is set correctly.
2383*9d26e4fcSRobert Mustacchi 		 */
2384*9d26e4fcSRobert Mustacchi 		i40e_pre_tx_queue_cfg(hw, i, B_TRUE);
2385*9d26e4fcSRobert Mustacchi 
2386*9d26e4fcSRobert Mustacchi 		/*
2387*9d26e4fcSRobert Mustacchi 		 * Step 2. Prepare the queue's FPM/HMC context.
2388*9d26e4fcSRobert Mustacchi 		 */
2389*9d26e4fcSRobert Mustacchi 		if (i40e_setup_tx_hmc(itrq) == B_FALSE)
2390*9d26e4fcSRobert Mustacchi 			return (B_FALSE);
2391*9d26e4fcSRobert Mustacchi 
2392*9d26e4fcSRobert Mustacchi 		/*
2393*9d26e4fcSRobert Mustacchi 		 * Step 3. Verify that it's clear that this PF owns this queue.
2394*9d26e4fcSRobert Mustacchi 		 */
2395*9d26e4fcSRobert Mustacchi 		reg = I40E_QTX_CTL_PF_QUEUE;
2396*9d26e4fcSRobert Mustacchi 		reg |= (hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
2397*9d26e4fcSRobert Mustacchi 		    I40E_QTX_CTL_PF_INDX_MASK;
2398*9d26e4fcSRobert Mustacchi 		I40E_WRITE_REG(hw, I40E_QTX_CTL(itrq->itrq_index), reg);
2399*9d26e4fcSRobert Mustacchi 		i40e_flush(hw);
2400*9d26e4fcSRobert Mustacchi 
2401*9d26e4fcSRobert Mustacchi 		/*
2402*9d26e4fcSRobert Mustacchi 		 * Step 4. Set the QENA_REQ flag.
2403*9d26e4fcSRobert Mustacchi 		 */
2404*9d26e4fcSRobert Mustacchi 		reg = I40E_READ_REG(hw, I40E_QTX_ENA(i));
2405*9d26e4fcSRobert Mustacchi 		VERIFY0(reg & (I40E_QTX_ENA_QENA_REQ_MASK |
2406*9d26e4fcSRobert Mustacchi 		    I40E_QTX_ENA_QENA_STAT_MASK));
2407*9d26e4fcSRobert Mustacchi 		reg |= I40E_QTX_ENA_QENA_REQ_MASK;
2408*9d26e4fcSRobert Mustacchi 		I40E_WRITE_REG(hw, I40E_QTX_ENA(i), reg);
2409*9d26e4fcSRobert Mustacchi 	}
2410*9d26e4fcSRobert Mustacchi 
2411*9d26e4fcSRobert Mustacchi 	/*
2412*9d26e4fcSRobert Mustacchi 	 * Note, we wait for every queue to be enabled before we start checking.
2413*9d26e4fcSRobert Mustacchi 	 * This will hopefully cause most queues to be enabled at this point.
2414*9d26e4fcSRobert Mustacchi 	 */
2415*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
2416*9d26e4fcSRobert Mustacchi 		uint32_t j, reg;
2417*9d26e4fcSRobert Mustacchi 
2418*9d26e4fcSRobert Mustacchi 		/*
2419*9d26e4fcSRobert Mustacchi 		 * Step 5. Verify that QENA_STAT has been set. It's promised
2420*9d26e4fcSRobert Mustacchi 		 * that this should occur within about 10 us, but like BSD,
2421*9d26e4fcSRobert Mustacchi 		 * we'll try for up to 100 ms for this queue.
2422*9d26e4fcSRobert Mustacchi 		 */
2423*9d26e4fcSRobert Mustacchi 		for (j = 0; j < I40E_RING_WAIT_NTRIES; j++) {
2424*9d26e4fcSRobert Mustacchi 			reg = I40E_READ_REG(hw, I40E_QTX_ENA(i));
2425*9d26e4fcSRobert Mustacchi 
2426*9d26e4fcSRobert Mustacchi 			if (reg & I40E_QTX_ENA_QENA_STAT_MASK)
2427*9d26e4fcSRobert Mustacchi 				break;
2428*9d26e4fcSRobert Mustacchi 			i40e_msec_delay(I40E_RING_WAIT_PAUSE);
2429*9d26e4fcSRobert Mustacchi 		}
2430*9d26e4fcSRobert Mustacchi 
2431*9d26e4fcSRobert Mustacchi 		if ((reg & I40E_QTX_ENA_QENA_STAT_MASK) == 0) {
2432*9d26e4fcSRobert Mustacchi 			i40e_error(i40e, "failed to enable tx queue %d, timed "
2433*9d26e4fcSRobert Mustacchi 			    "out", i);
2434*9d26e4fcSRobert Mustacchi 			return (B_FALSE);
2435*9d26e4fcSRobert Mustacchi 		}
2436*9d26e4fcSRobert Mustacchi 	}
2437*9d26e4fcSRobert Mustacchi 
2438*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
2439*9d26e4fcSRobert Mustacchi }
2440*9d26e4fcSRobert Mustacchi 
2441*9d26e4fcSRobert Mustacchi void
2442*9d26e4fcSRobert Mustacchi i40e_stop(i40e_t *i40e, boolean_t free_allocations)
2443*9d26e4fcSRobert Mustacchi {
2444*9d26e4fcSRobert Mustacchi 	int i;
2445*9d26e4fcSRobert Mustacchi 
2446*9d26e4fcSRobert Mustacchi 	ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
2447*9d26e4fcSRobert Mustacchi 
2448*9d26e4fcSRobert Mustacchi 	/*
2449*9d26e4fcSRobert Mustacchi 	 * Shutdown and drain the tx and rx pipeline. We do this using the
2450*9d26e4fcSRobert Mustacchi 	 * following steps.
2451*9d26e4fcSRobert Mustacchi 	 *
2452*9d26e4fcSRobert Mustacchi 	 * 1) Shutdown interrupts to all the queues (trying to keep the admin
2453*9d26e4fcSRobert Mustacchi 	 *    queue alive).
2454*9d26e4fcSRobert Mustacchi 	 *
2455*9d26e4fcSRobert Mustacchi 	 * 2) Remove all of the interrupt tx and rx causes by setting the
2456*9d26e4fcSRobert Mustacchi 	 *    interrupt linked lists to zero.
2457*9d26e4fcSRobert Mustacchi 	 *
2458*9d26e4fcSRobert Mustacchi 	 * 2) Shutdown the tx and rx rings. Because i40e_shutdown_rings() should
2459*9d26e4fcSRobert Mustacchi 	 *    wait for all the queues to be disabled, once we reach that point
2460*9d26e4fcSRobert Mustacchi 	 *    it should be safe to free associated data.
2461*9d26e4fcSRobert Mustacchi 	 *
2462*9d26e4fcSRobert Mustacchi 	 * 4) Wait 50ms after all that is done. This ensures that the rings are
2463*9d26e4fcSRobert Mustacchi 	 *    ready for programming again and we don't have to think about this
2464*9d26e4fcSRobert Mustacchi 	 *    in other parts of the driver.
2465*9d26e4fcSRobert Mustacchi 	 *
2466*9d26e4fcSRobert Mustacchi 	 * 5) Disable remaining chip interrupts, (admin queue, etc.)
2467*9d26e4fcSRobert Mustacchi 	 *
2468*9d26e4fcSRobert Mustacchi 	 * 6) Verify that FM is happy with all the register accesses we
2469*9d26e4fcSRobert Mustacchi 	 *    performed.
2470*9d26e4fcSRobert Mustacchi 	 */
2471*9d26e4fcSRobert Mustacchi 	i40e_intr_io_disable_all(i40e);
2472*9d26e4fcSRobert Mustacchi 	i40e_intr_io_clear_cause(i40e);
2473*9d26e4fcSRobert Mustacchi 
2474*9d26e4fcSRobert Mustacchi 	if (i40e_shutdown_rings(i40e) == B_FALSE) {
2475*9d26e4fcSRobert Mustacchi 		ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST);
2476*9d26e4fcSRobert Mustacchi 	}
2477*9d26e4fcSRobert Mustacchi 
2478*9d26e4fcSRobert Mustacchi 	delay(50 * drv_usectohz(1000));
2479*9d26e4fcSRobert Mustacchi 
2480*9d26e4fcSRobert Mustacchi 	i40e_intr_chip_fini(i40e);
2481*9d26e4fcSRobert Mustacchi 
2482*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
2483*9d26e4fcSRobert Mustacchi 		mutex_enter(&i40e->i40e_trqpairs[i].itrq_rx_lock);
2484*9d26e4fcSRobert Mustacchi 		mutex_enter(&i40e->i40e_trqpairs[i].itrq_tx_lock);
2485*9d26e4fcSRobert Mustacchi 	}
2486*9d26e4fcSRobert Mustacchi 
2487*9d26e4fcSRobert Mustacchi 	/*
2488*9d26e4fcSRobert Mustacchi 	 * We should consider refactoring this to be part of the ring start /
2489*9d26e4fcSRobert Mustacchi 	 * stop routines at some point.
2490*9d26e4fcSRobert Mustacchi 	 */
2491*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
2492*9d26e4fcSRobert Mustacchi 		i40e_stats_trqpair_fini(&i40e->i40e_trqpairs[i]);
2493*9d26e4fcSRobert Mustacchi 	}
2494*9d26e4fcSRobert Mustacchi 
2495*9d26e4fcSRobert Mustacchi 	if (i40e_check_acc_handle(i40e->i40e_osdep_space.ios_cfg_handle) !=
2496*9d26e4fcSRobert Mustacchi 	    DDI_FM_OK) {
2497*9d26e4fcSRobert Mustacchi 		ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST);
2498*9d26e4fcSRobert Mustacchi 	}
2499*9d26e4fcSRobert Mustacchi 
2500*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
2501*9d26e4fcSRobert Mustacchi 		i40e_tx_cleanup_ring(&i40e->i40e_trqpairs[i]);
2502*9d26e4fcSRobert Mustacchi 	}
2503*9d26e4fcSRobert Mustacchi 
2504*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
2505*9d26e4fcSRobert Mustacchi 		mutex_exit(&i40e->i40e_trqpairs[i].itrq_rx_lock);
2506*9d26e4fcSRobert Mustacchi 		mutex_exit(&i40e->i40e_trqpairs[i].itrq_tx_lock);
2507*9d26e4fcSRobert Mustacchi 	}
2508*9d26e4fcSRobert Mustacchi 
2509*9d26e4fcSRobert Mustacchi 	i40e_stat_vsi_fini(i40e);
2510*9d26e4fcSRobert Mustacchi 
2511*9d26e4fcSRobert Mustacchi 	i40e->i40e_link_speed = 0;
2512*9d26e4fcSRobert Mustacchi 	i40e->i40e_link_duplex = 0;
2513*9d26e4fcSRobert Mustacchi 	i40e_link_state_set(i40e, LINK_STATE_UNKNOWN);
2514*9d26e4fcSRobert Mustacchi 
2515*9d26e4fcSRobert Mustacchi 	if (free_allocations) {
2516*9d26e4fcSRobert Mustacchi 		i40e_free_ring_mem(i40e, B_FALSE);
2517*9d26e4fcSRobert Mustacchi 	}
2518*9d26e4fcSRobert Mustacchi }
2519*9d26e4fcSRobert Mustacchi 
2520*9d26e4fcSRobert Mustacchi boolean_t
2521*9d26e4fcSRobert Mustacchi i40e_start(i40e_t *i40e, boolean_t alloc)
2522*9d26e4fcSRobert Mustacchi {
2523*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
2524*9d26e4fcSRobert Mustacchi 	boolean_t rc = B_TRUE;
2525*9d26e4fcSRobert Mustacchi 	int i, err;
2526*9d26e4fcSRobert Mustacchi 
2527*9d26e4fcSRobert Mustacchi 	ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
2528*9d26e4fcSRobert Mustacchi 
2529*9d26e4fcSRobert Mustacchi 	if (alloc) {
2530*9d26e4fcSRobert Mustacchi 		if (i40e_alloc_ring_mem(i40e) == B_FALSE) {
2531*9d26e4fcSRobert Mustacchi 			i40e_error(i40e,
2532*9d26e4fcSRobert Mustacchi 			    "Failed to allocate ring memory");
2533*9d26e4fcSRobert Mustacchi 			return (B_FALSE);
2534*9d26e4fcSRobert Mustacchi 		}
2535*9d26e4fcSRobert Mustacchi 	}
2536*9d26e4fcSRobert Mustacchi 
2537*9d26e4fcSRobert Mustacchi 	/*
2538*9d26e4fcSRobert Mustacchi 	 * This should get refactored to be part of ring start and stop at
2539*9d26e4fcSRobert Mustacchi 	 * some point, along with most of the logic here.
2540*9d26e4fcSRobert Mustacchi 	 */
2541*9d26e4fcSRobert Mustacchi 	for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
2542*9d26e4fcSRobert Mustacchi 		if (i40e_stats_trqpair_init(&i40e->i40e_trqpairs[i]) ==
2543*9d26e4fcSRobert Mustacchi 		    B_FALSE) {
2544*9d26e4fcSRobert Mustacchi 			int j;
2545*9d26e4fcSRobert Mustacchi 
2546*9d26e4fcSRobert Mustacchi 			for (j = 0; j < i; j++) {
2547*9d26e4fcSRobert Mustacchi 				i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[j];
2548*9d26e4fcSRobert Mustacchi 				i40e_stats_trqpair_fini(itrq);
2549*9d26e4fcSRobert Mustacchi 			}
2550*9d26e4fcSRobert Mustacchi 			return (B_FALSE);
2551*9d26e4fcSRobert Mustacchi 		}
2552*9d26e4fcSRobert Mustacchi 	}
2553*9d26e4fcSRobert Mustacchi 
2554*9d26e4fcSRobert Mustacchi 	if (!i40e_chip_start(i40e)) {
2555*9d26e4fcSRobert Mustacchi 		i40e_fm_ereport(i40e, DDI_FM_DEVICE_INVAL_STATE);
2556*9d26e4fcSRobert Mustacchi 		rc = B_FALSE;
2557*9d26e4fcSRobert Mustacchi 		goto done;
2558*9d26e4fcSRobert Mustacchi 	}
2559*9d26e4fcSRobert Mustacchi 
2560*9d26e4fcSRobert Mustacchi 	if (i40e_setup_rx_rings(i40e) == B_FALSE) {
2561*9d26e4fcSRobert Mustacchi 		rc = B_FALSE;
2562*9d26e4fcSRobert Mustacchi 		goto done;
2563*9d26e4fcSRobert Mustacchi 	}
2564*9d26e4fcSRobert Mustacchi 
2565*9d26e4fcSRobert Mustacchi 	if (i40e_setup_tx_rings(i40e) == B_FALSE) {
2566*9d26e4fcSRobert Mustacchi 		rc = B_FALSE;
2567*9d26e4fcSRobert Mustacchi 		goto done;
2568*9d26e4fcSRobert Mustacchi 	}
2569*9d26e4fcSRobert Mustacchi 
2570*9d26e4fcSRobert Mustacchi 	/*
2571*9d26e4fcSRobert Mustacchi 	 * Enable broadcast traffic; however, do not enable multicast traffic.
2572*9d26e4fcSRobert Mustacchi 	 * That's handle exclusively through MAC's mc_multicst routines.
2573*9d26e4fcSRobert Mustacchi 	 */
2574*9d26e4fcSRobert Mustacchi 	err = i40e_aq_set_vsi_broadcast(hw, i40e->i40e_vsi_id, B_TRUE, NULL);
2575*9d26e4fcSRobert Mustacchi 	if (err != I40E_SUCCESS) {
2576*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to set default VSI: %d", err);
2577*9d26e4fcSRobert Mustacchi 		rc = B_FALSE;
2578*9d26e4fcSRobert Mustacchi 		goto done;
2579*9d26e4fcSRobert Mustacchi 	}
2580*9d26e4fcSRobert Mustacchi 
2581*9d26e4fcSRobert Mustacchi 	err = i40e_aq_set_mac_config(hw, i40e->i40e_frame_max, B_TRUE, 0, NULL);
2582*9d26e4fcSRobert Mustacchi 	if (err != I40E_SUCCESS) {
2583*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to set MAC config: %d", err);
2584*9d26e4fcSRobert Mustacchi 		rc = B_FALSE;
2585*9d26e4fcSRobert Mustacchi 		goto done;
2586*9d26e4fcSRobert Mustacchi 	}
2587*9d26e4fcSRobert Mustacchi 
2588*9d26e4fcSRobert Mustacchi 	/*
2589*9d26e4fcSRobert Mustacchi 	 * Finally, make sure that we're happy from an FM perspective.
2590*9d26e4fcSRobert Mustacchi 	 */
2591*9d26e4fcSRobert Mustacchi 	if (i40e_check_acc_handle(i40e->i40e_osdep_space.ios_reg_handle) !=
2592*9d26e4fcSRobert Mustacchi 	    DDI_FM_OK) {
2593*9d26e4fcSRobert Mustacchi 		rc = B_FALSE;
2594*9d26e4fcSRobert Mustacchi 		goto done;
2595*9d26e4fcSRobert Mustacchi 	}
2596*9d26e4fcSRobert Mustacchi 
2597*9d26e4fcSRobert Mustacchi 	/* Clear state bits prior to final interrupt enabling. */
2598*9d26e4fcSRobert Mustacchi 	atomic_and_32(&i40e->i40e_state,
2599*9d26e4fcSRobert Mustacchi 	    ~(I40E_ERROR | I40E_STALL | I40E_OVERTEMP));
2600*9d26e4fcSRobert Mustacchi 
2601*9d26e4fcSRobert Mustacchi 	i40e_intr_io_enable_all(i40e);
2602*9d26e4fcSRobert Mustacchi 
2603*9d26e4fcSRobert Mustacchi done:
2604*9d26e4fcSRobert Mustacchi 	if (rc == B_FALSE) {
2605*9d26e4fcSRobert Mustacchi 		i40e_stop(i40e, B_FALSE);
2606*9d26e4fcSRobert Mustacchi 		if (alloc == B_TRUE) {
2607*9d26e4fcSRobert Mustacchi 			i40e_free_ring_mem(i40e, B_TRUE);
2608*9d26e4fcSRobert Mustacchi 		}
2609*9d26e4fcSRobert Mustacchi 		ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST);
2610*9d26e4fcSRobert Mustacchi 	}
2611*9d26e4fcSRobert Mustacchi 
2612*9d26e4fcSRobert Mustacchi 	return (rc);
2613*9d26e4fcSRobert Mustacchi }
2614*9d26e4fcSRobert Mustacchi 
2615*9d26e4fcSRobert Mustacchi /*
2616*9d26e4fcSRobert Mustacchi  * We may have loaned up descriptors to the stack. As such, if we still have
2617*9d26e4fcSRobert Mustacchi  * them outstanding, then we will not continue with detach.
2618*9d26e4fcSRobert Mustacchi  */
2619*9d26e4fcSRobert Mustacchi static boolean_t
2620*9d26e4fcSRobert Mustacchi i40e_drain_rx(i40e_t *i40e)
2621*9d26e4fcSRobert Mustacchi {
2622*9d26e4fcSRobert Mustacchi 	mutex_enter(&i40e->i40e_rx_pending_lock);
2623*9d26e4fcSRobert Mustacchi 	while (i40e->i40e_rx_pending > 0) {
2624*9d26e4fcSRobert Mustacchi 		if (cv_reltimedwait(&i40e->i40e_rx_pending_cv,
2625*9d26e4fcSRobert Mustacchi 		    &i40e->i40e_rx_pending_lock,
2626*9d26e4fcSRobert Mustacchi 		    drv_usectohz(I40E_DRAIN_RX_WAIT), TR_CLOCK_TICK) == -1) {
2627*9d26e4fcSRobert Mustacchi 			mutex_exit(&i40e->i40e_rx_pending_lock);
2628*9d26e4fcSRobert Mustacchi 			return (B_FALSE);
2629*9d26e4fcSRobert Mustacchi 		}
2630*9d26e4fcSRobert Mustacchi 	}
2631*9d26e4fcSRobert Mustacchi 	mutex_exit(&i40e->i40e_rx_pending_lock);
2632*9d26e4fcSRobert Mustacchi 
2633*9d26e4fcSRobert Mustacchi 	return (B_TRUE);
2634*9d26e4fcSRobert Mustacchi }
2635*9d26e4fcSRobert Mustacchi 
2636*9d26e4fcSRobert Mustacchi static int
2637*9d26e4fcSRobert Mustacchi i40e_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
2638*9d26e4fcSRobert Mustacchi {
2639*9d26e4fcSRobert Mustacchi 	i40e_t *i40e;
2640*9d26e4fcSRobert Mustacchi 	struct i40e_osdep *osdep;
2641*9d26e4fcSRobert Mustacchi 	i40e_hw_t *hw;
2642*9d26e4fcSRobert Mustacchi 	int instance;
2643*9d26e4fcSRobert Mustacchi 
2644*9d26e4fcSRobert Mustacchi 	if (cmd != DDI_ATTACH)
2645*9d26e4fcSRobert Mustacchi 		return (DDI_FAILURE);
2646*9d26e4fcSRobert Mustacchi 
2647*9d26e4fcSRobert Mustacchi 	instance = ddi_get_instance(devinfo);
2648*9d26e4fcSRobert Mustacchi 	i40e = kmem_zalloc(sizeof (i40e_t), KM_SLEEP);
2649*9d26e4fcSRobert Mustacchi 
2650*9d26e4fcSRobert Mustacchi 	i40e->i40e_aqbuf = kmem_zalloc(I40E_ADMINQ_BUFSZ, KM_SLEEP);
2651*9d26e4fcSRobert Mustacchi 	i40e->i40e_instance = instance;
2652*9d26e4fcSRobert Mustacchi 	i40e->i40e_dip = devinfo;
2653*9d26e4fcSRobert Mustacchi 
2654*9d26e4fcSRobert Mustacchi 	hw = &i40e->i40e_hw_space;
2655*9d26e4fcSRobert Mustacchi 	osdep = &i40e->i40e_osdep_space;
2656*9d26e4fcSRobert Mustacchi 	hw->back = osdep;
2657*9d26e4fcSRobert Mustacchi 	osdep->ios_i40e = i40e;
2658*9d26e4fcSRobert Mustacchi 
2659*9d26e4fcSRobert Mustacchi 	ddi_set_driver_private(devinfo, i40e);
2660*9d26e4fcSRobert Mustacchi 
2661*9d26e4fcSRobert Mustacchi 	i40e_fm_init(i40e);
2662*9d26e4fcSRobert Mustacchi 	i40e->i40e_attach_progress |= I40E_ATTACH_FM_INIT;
2663*9d26e4fcSRobert Mustacchi 
2664*9d26e4fcSRobert Mustacchi 	if (pci_config_setup(devinfo, &osdep->ios_cfg_handle) != DDI_SUCCESS) {
2665*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "Failed to map PCI configurations.");
2666*9d26e4fcSRobert Mustacchi 		goto attach_fail;
2667*9d26e4fcSRobert Mustacchi 	}
2668*9d26e4fcSRobert Mustacchi 	i40e->i40e_attach_progress |= I40E_ATTACH_PCI_CONFIG;
2669*9d26e4fcSRobert Mustacchi 
2670*9d26e4fcSRobert Mustacchi 	if (!i40e_identify_hardware(i40e)) {
2671*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "Failed to identify hardware");
2672*9d26e4fcSRobert Mustacchi 		goto attach_fail;
2673*9d26e4fcSRobert Mustacchi 	}
2674*9d26e4fcSRobert Mustacchi 
2675*9d26e4fcSRobert Mustacchi 	if (!i40e_regs_map(i40e)) {
2676*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "Failed to map device registers.");
2677*9d26e4fcSRobert Mustacchi 		goto attach_fail;
2678*9d26e4fcSRobert Mustacchi 	}
2679*9d26e4fcSRobert Mustacchi 	i40e->i40e_attach_progress |= I40E_ATTACH_REGS_MAP;
2680*9d26e4fcSRobert Mustacchi 
2681*9d26e4fcSRobert Mustacchi 	i40e_init_properties(i40e);
2682*9d26e4fcSRobert Mustacchi 	i40e->i40e_attach_progress |= I40E_ATTACH_PROPS;
2683*9d26e4fcSRobert Mustacchi 
2684*9d26e4fcSRobert Mustacchi 	if (!i40e_common_code_init(i40e, hw))
2685*9d26e4fcSRobert Mustacchi 		goto attach_fail;
2686*9d26e4fcSRobert Mustacchi 	i40e->i40e_attach_progress |= I40E_ATTACH_COMMON_CODE;
2687*9d26e4fcSRobert Mustacchi 
2688*9d26e4fcSRobert Mustacchi 	/*
2689*9d26e4fcSRobert Mustacchi 	 * When we participate in IRM, we should make sure that we register
2690*9d26e4fcSRobert Mustacchi 	 * ourselves with it before callbacks.
2691*9d26e4fcSRobert Mustacchi 	 */
2692*9d26e4fcSRobert Mustacchi 	if (!i40e_alloc_intrs(i40e, devinfo)) {
2693*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "Failed to allocate interrupts.");
2694*9d26e4fcSRobert Mustacchi 		goto attach_fail;
2695*9d26e4fcSRobert Mustacchi 	}
2696*9d26e4fcSRobert Mustacchi 	i40e->i40e_attach_progress |= I40E_ATTACH_ALLOC_INTR;
2697*9d26e4fcSRobert Mustacchi 
2698*9d26e4fcSRobert Mustacchi 	if (!i40e_alloc_trqpairs(i40e)) {
2699*9d26e4fcSRobert Mustacchi 		i40e_error(i40e,
2700*9d26e4fcSRobert Mustacchi 		    "Failed to allocate receive & transmit rings.");
2701*9d26e4fcSRobert Mustacchi 		goto attach_fail;
2702*9d26e4fcSRobert Mustacchi 	}
2703*9d26e4fcSRobert Mustacchi 	i40e->i40e_attach_progress |= I40E_ATTACH_ALLOC_RINGSLOCKS;
2704*9d26e4fcSRobert Mustacchi 
2705*9d26e4fcSRobert Mustacchi 	if (!i40e_map_intrs_to_vectors(i40e)) {
2706*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "Failed to map interrupts to vectors.");
2707*9d26e4fcSRobert Mustacchi 		goto attach_fail;
2708*9d26e4fcSRobert Mustacchi 	}
2709*9d26e4fcSRobert Mustacchi 
2710*9d26e4fcSRobert Mustacchi 	if (!i40e_add_intr_handlers(i40e)) {
2711*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "Failed to add the interrupt handlers.");
2712*9d26e4fcSRobert Mustacchi 		goto attach_fail;
2713*9d26e4fcSRobert Mustacchi 	}
2714*9d26e4fcSRobert Mustacchi 	i40e->i40e_attach_progress |= I40E_ATTACH_ADD_INTR;
2715*9d26e4fcSRobert Mustacchi 
2716*9d26e4fcSRobert Mustacchi 	if (!i40e_final_init(i40e)) {
2717*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "Final initialization failed.");
2718*9d26e4fcSRobert Mustacchi 		goto attach_fail;
2719*9d26e4fcSRobert Mustacchi 	}
2720*9d26e4fcSRobert Mustacchi 	i40e->i40e_attach_progress |= I40E_ATTACH_INIT;
2721*9d26e4fcSRobert Mustacchi 
2722*9d26e4fcSRobert Mustacchi 	if (i40e_check_acc_handle(i40e->i40e_osdep_space.ios_cfg_handle) !=
2723*9d26e4fcSRobert Mustacchi 	    DDI_FM_OK) {
2724*9d26e4fcSRobert Mustacchi 		ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST);
2725*9d26e4fcSRobert Mustacchi 		goto attach_fail;
2726*9d26e4fcSRobert Mustacchi 	}
2727*9d26e4fcSRobert Mustacchi 
2728*9d26e4fcSRobert Mustacchi 	if (!i40e_stats_init(i40e)) {
2729*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "Stats initialization failed.");
2730*9d26e4fcSRobert Mustacchi 		goto attach_fail;
2731*9d26e4fcSRobert Mustacchi 	}
2732*9d26e4fcSRobert Mustacchi 	i40e->i40e_attach_progress |= I40E_ATTACH_STATS;
2733*9d26e4fcSRobert Mustacchi 
2734*9d26e4fcSRobert Mustacchi 	if (!i40e_register_mac(i40e)) {
2735*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "Failed to register to MAC/GLDv3");
2736*9d26e4fcSRobert Mustacchi 		goto attach_fail;
2737*9d26e4fcSRobert Mustacchi 	}
2738*9d26e4fcSRobert Mustacchi 	i40e->i40e_attach_progress |= I40E_ATTACH_MAC;
2739*9d26e4fcSRobert Mustacchi 
2740*9d26e4fcSRobert Mustacchi 	i40e->i40e_periodic_id = ddi_periodic_add(i40e_timer, i40e,
2741*9d26e4fcSRobert Mustacchi 	    I40E_CYCLIC_PERIOD, DDI_IPL_0);
2742*9d26e4fcSRobert Mustacchi 	if (i40e->i40e_periodic_id == 0) {
2743*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "Failed to add the link-check timer");
2744*9d26e4fcSRobert Mustacchi 		goto attach_fail;
2745*9d26e4fcSRobert Mustacchi 	}
2746*9d26e4fcSRobert Mustacchi 	i40e->i40e_attach_progress |= I40E_ATTACH_LINK_TIMER;
2747*9d26e4fcSRobert Mustacchi 
2748*9d26e4fcSRobert Mustacchi 	if (!i40e_enable_interrupts(i40e)) {
2749*9d26e4fcSRobert Mustacchi 		i40e_error(i40e, "Failed to enable DDI interrupts");
2750*9d26e4fcSRobert Mustacchi 		goto attach_fail;
2751*9d26e4fcSRobert Mustacchi 	}
2752*9d26e4fcSRobert Mustacchi 	i40e->i40e_attach_progress |= I40E_ATTACH_ENABLE_INTR;
2753*9d26e4fcSRobert Mustacchi 
2754*9d26e4fcSRobert Mustacchi 	atomic_or_32(&i40e->i40e_state, I40E_INITIALIZED);
2755*9d26e4fcSRobert Mustacchi 
2756*9d26e4fcSRobert Mustacchi 	mutex_enter(&i40e_glock);
2757*9d26e4fcSRobert Mustacchi 	list_insert_tail(&i40e_glist, i40e);
2758*9d26e4fcSRobert Mustacchi 	mutex_exit(&i40e_glock);
2759*9d26e4fcSRobert Mustacchi 
2760*9d26e4fcSRobert Mustacchi 	return (DDI_SUCCESS);
2761*9d26e4fcSRobert Mustacchi 
2762*9d26e4fcSRobert Mustacchi attach_fail:
2763*9d26e4fcSRobert Mustacchi 	i40e_unconfigure(devinfo, i40e);
2764*9d26e4fcSRobert Mustacchi 	return (DDI_FAILURE);
2765*9d26e4fcSRobert Mustacchi }
2766*9d26e4fcSRobert Mustacchi 
2767*9d26e4fcSRobert Mustacchi static int
2768*9d26e4fcSRobert Mustacchi i40e_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
2769*9d26e4fcSRobert Mustacchi {
2770*9d26e4fcSRobert Mustacchi 	i40e_t *i40e;
2771*9d26e4fcSRobert Mustacchi 
2772*9d26e4fcSRobert Mustacchi 	if (cmd != DDI_DETACH)
2773*9d26e4fcSRobert Mustacchi 		return (DDI_FAILURE);
2774*9d26e4fcSRobert Mustacchi 
2775*9d26e4fcSRobert Mustacchi 	i40e = (i40e_t *)ddi_get_driver_private(devinfo);
2776*9d26e4fcSRobert Mustacchi 	if (i40e == NULL) {
2777*9d26e4fcSRobert Mustacchi 		i40e_log(NULL, "i40e_detach() called with no i40e pointer!");
2778*9d26e4fcSRobert Mustacchi 		return (DDI_FAILURE);
2779*9d26e4fcSRobert Mustacchi 	}
2780*9d26e4fcSRobert Mustacchi 
2781*9d26e4fcSRobert Mustacchi 	if (i40e_drain_rx(i40e) == B_FALSE) {
2782*9d26e4fcSRobert Mustacchi 		i40e_log(i40e, "timed out draining DMA resources, %d buffers "
2783*9d26e4fcSRobert Mustacchi 		    "remain", i40e->i40e_rx_pending);
2784*9d26e4fcSRobert Mustacchi 		return (DDI_FAILURE);
2785*9d26e4fcSRobert Mustacchi 	}
2786*9d26e4fcSRobert Mustacchi 
2787*9d26e4fcSRobert Mustacchi 	mutex_enter(&i40e_glock);
2788*9d26e4fcSRobert Mustacchi 	list_remove(&i40e_glist, i40e);
2789*9d26e4fcSRobert Mustacchi 	mutex_exit(&i40e_glock);
2790*9d26e4fcSRobert Mustacchi 
2791*9d26e4fcSRobert Mustacchi 	i40e_unconfigure(devinfo, i40e);
2792*9d26e4fcSRobert Mustacchi 
2793*9d26e4fcSRobert Mustacchi 	return (DDI_SUCCESS);
2794*9d26e4fcSRobert Mustacchi }
2795*9d26e4fcSRobert Mustacchi 
2796*9d26e4fcSRobert Mustacchi static struct cb_ops i40e_cb_ops = {
2797*9d26e4fcSRobert Mustacchi 	nulldev,		/* cb_open */
2798*9d26e4fcSRobert Mustacchi 	nulldev,		/* cb_close */
2799*9d26e4fcSRobert Mustacchi 	nodev,			/* cb_strategy */
2800*9d26e4fcSRobert Mustacchi 	nodev,			/* cb_print */
2801*9d26e4fcSRobert Mustacchi 	nodev,			/* cb_dump */
2802*9d26e4fcSRobert Mustacchi 	nodev,			/* cb_read */
2803*9d26e4fcSRobert Mustacchi 	nodev,			/* cb_write */
2804*9d26e4fcSRobert Mustacchi 	nodev,			/* cb_ioctl */
2805*9d26e4fcSRobert Mustacchi 	nodev,			/* cb_devmap */
2806*9d26e4fcSRobert Mustacchi 	nodev,			/* cb_mmap */
2807*9d26e4fcSRobert Mustacchi 	nodev,			/* cb_segmap */
2808*9d26e4fcSRobert Mustacchi 	nochpoll,		/* cb_chpoll */
2809*9d26e4fcSRobert Mustacchi 	ddi_prop_op,		/* cb_prop_op */
2810*9d26e4fcSRobert Mustacchi 	NULL,			/* cb_stream */
2811*9d26e4fcSRobert Mustacchi 	D_MP | D_HOTPLUG,	/* cb_flag */
2812*9d26e4fcSRobert Mustacchi 	CB_REV,			/* cb_rev */
2813*9d26e4fcSRobert Mustacchi 	nodev,			/* cb_aread */
2814*9d26e4fcSRobert Mustacchi 	nodev			/* cb_awrite */
2815*9d26e4fcSRobert Mustacchi };
2816*9d26e4fcSRobert Mustacchi 
2817*9d26e4fcSRobert Mustacchi static struct dev_ops i40e_dev_ops = {
2818*9d26e4fcSRobert Mustacchi 	DEVO_REV,		/* devo_rev */
2819*9d26e4fcSRobert Mustacchi 	0,			/* devo_refcnt */
2820*9d26e4fcSRobert Mustacchi 	NULL,			/* devo_getinfo */
2821*9d26e4fcSRobert Mustacchi 	nulldev,		/* devo_identify */
2822*9d26e4fcSRobert Mustacchi 	nulldev,		/* devo_probe */
2823*9d26e4fcSRobert Mustacchi 	i40e_attach,		/* devo_attach */
2824*9d26e4fcSRobert Mustacchi 	i40e_detach,		/* devo_detach */
2825*9d26e4fcSRobert Mustacchi 	nodev,			/* devo_reset */
2826*9d26e4fcSRobert Mustacchi 	&i40e_cb_ops,		/* devo_cb_ops */
2827*9d26e4fcSRobert Mustacchi 	NULL,			/* devo_bus_ops */
2828*9d26e4fcSRobert Mustacchi 	ddi_power,		/* devo_power */
2829*9d26e4fcSRobert Mustacchi 	ddi_quiesce_not_supported /* devo_quiesce */
2830*9d26e4fcSRobert Mustacchi };
2831*9d26e4fcSRobert Mustacchi 
2832*9d26e4fcSRobert Mustacchi static struct modldrv i40e_modldrv = {
2833*9d26e4fcSRobert Mustacchi 	&mod_driverops,
2834*9d26e4fcSRobert Mustacchi 	i40e_ident,
2835*9d26e4fcSRobert Mustacchi 	&i40e_dev_ops
2836*9d26e4fcSRobert Mustacchi };
2837*9d26e4fcSRobert Mustacchi 
2838*9d26e4fcSRobert Mustacchi static struct modlinkage i40e_modlinkage = {
2839*9d26e4fcSRobert Mustacchi 	MODREV_1,
2840*9d26e4fcSRobert Mustacchi 	&i40e_modldrv,
2841*9d26e4fcSRobert Mustacchi 	NULL
2842*9d26e4fcSRobert Mustacchi };
2843*9d26e4fcSRobert Mustacchi 
2844*9d26e4fcSRobert Mustacchi /*
2845*9d26e4fcSRobert Mustacchi  * Module Initialization Functions.
2846*9d26e4fcSRobert Mustacchi  */
2847*9d26e4fcSRobert Mustacchi int
2848*9d26e4fcSRobert Mustacchi _init(void)
2849*9d26e4fcSRobert Mustacchi {
2850*9d26e4fcSRobert Mustacchi 	int status;
2851*9d26e4fcSRobert Mustacchi 
2852*9d26e4fcSRobert Mustacchi 	list_create(&i40e_glist, sizeof (i40e_t), offsetof(i40e_t, i40e_glink));
2853*9d26e4fcSRobert Mustacchi 	list_create(&i40e_dlist, sizeof (i40e_device_t),
2854*9d26e4fcSRobert Mustacchi 	    offsetof(i40e_device_t, id_link));
2855*9d26e4fcSRobert Mustacchi 	mutex_init(&i40e_glock, NULL, MUTEX_DRIVER, NULL);
2856*9d26e4fcSRobert Mustacchi 	mac_init_ops(&i40e_dev_ops, I40E_MODULE_NAME);
2857*9d26e4fcSRobert Mustacchi 
2858*9d26e4fcSRobert Mustacchi 	status = mod_install(&i40e_modlinkage);
2859*9d26e4fcSRobert Mustacchi 	if (status != DDI_SUCCESS) {
2860*9d26e4fcSRobert Mustacchi 		mac_fini_ops(&i40e_dev_ops);
2861*9d26e4fcSRobert Mustacchi 		mutex_destroy(&i40e_glock);
2862*9d26e4fcSRobert Mustacchi 		list_destroy(&i40e_dlist);
2863*9d26e4fcSRobert Mustacchi 		list_destroy(&i40e_glist);
2864*9d26e4fcSRobert Mustacchi 	}
2865*9d26e4fcSRobert Mustacchi 
2866*9d26e4fcSRobert Mustacchi 	return (status);
2867*9d26e4fcSRobert Mustacchi }
2868*9d26e4fcSRobert Mustacchi 
2869*9d26e4fcSRobert Mustacchi int
2870*9d26e4fcSRobert Mustacchi _info(struct modinfo *modinfop)
2871*9d26e4fcSRobert Mustacchi {
2872*9d26e4fcSRobert Mustacchi 	return (mod_info(&i40e_modlinkage, modinfop));
2873*9d26e4fcSRobert Mustacchi }
2874*9d26e4fcSRobert Mustacchi 
2875*9d26e4fcSRobert Mustacchi int
2876*9d26e4fcSRobert Mustacchi _fini(void)
2877*9d26e4fcSRobert Mustacchi {
2878*9d26e4fcSRobert Mustacchi 	int status;
2879*9d26e4fcSRobert Mustacchi 
2880*9d26e4fcSRobert Mustacchi 	status = mod_remove(&i40e_modlinkage);
2881*9d26e4fcSRobert Mustacchi 	if (status == DDI_SUCCESS) {
2882*9d26e4fcSRobert Mustacchi 		mac_fini_ops(&i40e_dev_ops);
2883*9d26e4fcSRobert Mustacchi 		mutex_destroy(&i40e_glock);
2884*9d26e4fcSRobert Mustacchi 		list_destroy(&i40e_dlist);
2885*9d26e4fcSRobert Mustacchi 		list_destroy(&i40e_glist);
2886*9d26e4fcSRobert Mustacchi 	}
2887*9d26e4fcSRobert Mustacchi 
2888*9d26e4fcSRobert Mustacchi 	return (status);
2889*9d26e4fcSRobert Mustacchi }
2890