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