xref: /freebsd/sys/dev/ixgbe/ixgbe_hv_vf.c (revision f9bc005b8ef3b507a5ecbc2d7fe4411ef70eff38)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2001-2024 Intel Corporation
3  */
4 
5 #include "ixgbe_common.h"
6 #include "ixgbe_vf.h"
7 #include "ixgbe_hv_vf.h"
8 
9 /* Reading these PCI configuration bytes resets a VF on Hyper-V. */
10 #define IXGBE_HV_RESET_OFFSET	0x201
11 
12 /* Hyper-V emulates the VF queue limit in PCI configuration space. */
13 #define IXGBE_HV_QUEUE_COUNT_OFFSET	0x207
14 
15 /* E610 exposes VFLINKS in four emulated PCI configuration bytes. */
16 #define IXGBE_HV_LINK_STATUS_OFFSET	0x209
17 #define IXGBE_HV_LINK_STATUS_SIZE	4
18 
19 /**
20  * ixgbevf_hv_get_queues - Discover supported Hyper-V RSS queues at attach
21  * @hw: pointer to hardware structure
22  */
23 u32
24 ixgbevf_hv_get_queues(struct ixgbe_hw *hw)
25 {
26 	u32 grant, queues = 1;
27 
28 	switch (hw->mac.type) {
29 	case ixgbe_mac_X550_vf:
30 	case ixgbe_mac_X550EM_x_vf:
31 	case ixgbe_mac_X550EM_a_vf:
32 		/* 0x208 is a separate DCB flag on these PFs, not count bits. */
33 		grant = IXGBE_READ_PCIE_BYTE(hw, IXGBE_HV_QUEUE_COUNT_OFFSET);
34 		break;
35 	case ixgbe_mac_E610_vf:
36 		/* E610 reports the assigned count as a little-endian word. */
37 		grant = IXGBE_READ_PCIE_BYTE(hw, IXGBE_HV_QUEUE_COUNT_OFFSET);
38 		grant |= (u32)IXGBE_READ_PCIE_BYTE(hw,
39 		    IXGBE_HV_QUEUE_COUNT_OFFSET + 1) << NBBY;
40 		break;
41 	default:
42 		/* Older PFs do not provide VF-owned RSS on Hyper-V. */
43 		grant = 1;
44 		break;
45 	}
46 	/* Valid limits are 1, 2 and 4; use at most two symmetric RSS queues. */
47 	if (grant == 2 || grant == 4)
48 		queues = 2;
49 
50 	/* Shared stop must disable every queue that iflib can initialize. */
51 	hw->mac.max_tx_queues = queues;
52 	hw->mac.max_rx_queues = queues;
53 	return (queues);
54 }
55 
56 /**
57  * ixgbevf_hv_update_mc_addr_list_vf - Hyper-V variant - just a stub.
58  * @hw: unused
59  * @mc_addr_list: unused
60  * @mc_addr_count: unused
61  * @next: unused
62  * @clear: unused
63  */
64 static s32
65 ixgbevf_hv_update_mc_addr_list_vf(struct ixgbe_hw *hw, u8 *mc_addr_list,
66     u32 mc_addr_count, ixgbe_mc_addr_itr next, bool clear)
67 {
68 	UNREFERENCED_5PARAMETER(hw, mc_addr_list, mc_addr_count, next, clear);
69 
70 	return (IXGBE_ERR_FEATURE_NOT_SUPPORTED);
71 }
72 
73 /**
74  * ixgbevf_hv_update_xcast_mode - Leave receive-mode policy to Hyper-V
75  * @hw: unused
76  * @xcast_mode: unused
77  */
78 static s32
79 ixgbevf_hv_update_xcast_mode(struct ixgbe_hw *hw, int xcast_mode)
80 {
81 	UNREFERENCED_2PARAMETER(hw, xcast_mode);
82 
83 	return (IXGBE_SUCCESS);
84 }
85 
86 /**
87  * ixgbevf_hv_set_vfta_vf - Hyper-V variant - just a stub.
88  * @hw: unused
89  * @vlan: unused
90  * @vind: unused
91  * @vlan_on: unused
92  * @vlvf_bypass: unused
93  */
94 static s32
95 ixgbevf_hv_set_vfta_vf(struct ixgbe_hw *hw, u32 vlan, u32 vind,
96     bool vlan_on, bool vlvf_bypass)
97 {
98 	UNREFERENCED_5PARAMETER(hw, vlan, vind, vlan_on, vlvf_bypass);
99 
100 	return (IXGBE_ERR_FEATURE_NOT_SUPPORTED);
101 }
102 
103 static s32
104 ixgbevf_hv_set_uc_addr_vf(struct ixgbe_hw *hw, u32 index, u8 *addr)
105 {
106 	UNREFERENCED_3PARAMETER(hw, index, addr);
107 
108 	return (IXGBE_ERR_FEATURE_NOT_SUPPORTED);
109 }
110 
111 /**
112  * ixgbevf_hv_reset_hw_vf - Reset through the Hyper-V PCI side channel
113  * @hw: pointer to hardware structure
114  *
115  * Hyper-V returns the permanent VF address when the guest reads six bytes
116  * beginning at offset 0x201 in PCI configuration space.  The reads also
117  * perform the host-side VF reset handshake.
118  */
119 static s32
120 ixgbevf_hv_reset_hw_vf(struct ixgbe_hw *hw)
121 {
122 	int i;
123 
124 	hw->api_version = ixgbe_mbox_api_10;
125 	for (i = 0; i < IXGBE_ETH_LENGTH_OF_ADDRESS; i++)
126 		hw->mac.perm_addr[i] = IXGBE_READ_PCIE_BYTE(hw,
127 		    IXGBE_HV_RESET_OFFSET + i);
128 	if (ixgbe_validate_mac_addr(hw->mac.perm_addr) != IXGBE_SUCCESS)
129 		return (IXGBE_ERR_INVALID_MAC_ADDR);
130 
131 	return (IXGBE_SUCCESS);
132 }
133 
134 /**
135  * ixgbevf_hv_set_rar_vf - Hyper-V variant - just a stub.
136  * @hw: unused
137  * @index: unused
138  * @addr: unused
139  * @vmdq: unused
140  * @enable_addr: unused
141  */
142 static s32
143 ixgbevf_hv_set_rar_vf(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq,
144     u32 enable_addr)
145 {
146 	UNREFERENCED_5PARAMETER(hw, index, addr, vmdq, enable_addr);
147 
148 	return (IXGBE_ERR_FEATURE_NOT_SUPPORTED);
149 }
150 
151 static u32
152 ixgbevf_hv_read_links(struct ixgbe_hw *hw)
153 {
154 	u32 links_reg;
155 	int i;
156 
157 	if (hw->mac.type != ixgbe_mac_E610_vf)
158 		return (IXGBE_READ_REG(hw, IXGBE_VFLINKS));
159 
160 	links_reg = 0;
161 	for (i = 0; i < IXGBE_HV_LINK_STATUS_SIZE; i++)
162 		links_reg |= (u32)IXGBE_READ_PCIE_BYTE(hw,
163 		    IXGBE_HV_LINK_STATUS_OFFSET + i) << (i * NBBY);
164 	return (links_reg);
165 }
166 
167 /**
168  * ixgbevf_hv_check_mac_link_vf - Check link without mailbox communication
169  * @hw: pointer to hardware structure
170  * @speed: pointer to link speed
171  * @link_up: true is link is up, false otherwise
172  * @autoneg_wait_to_complete: unused
173  */
174 static s32
175 ixgbevf_hv_check_mac_link_vf(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
176     bool *link_up, bool autoneg_wait_to_complete)
177 {
178 	struct ixgbe_mbx_info *mbx = &hw->mbx;
179 	struct ixgbe_mac_info *mac = &hw->mac;
180 	u32 links_reg;
181 
182 	UNREFERENCED_1PARAMETER(autoneg_wait_to_complete);
183 
184 	/* If we were hit with a reset, drop the cached link state. */
185 	if (!mbx->ops[0].check_for_rst(hw, 0) || !mbx->timeout)
186 		mac->get_link_status = true;
187 	if (!mac->get_link_status)
188 		goto out;
189 
190 	links_reg = ixgbevf_hv_read_links(hw);
191 	if (hw->mac.type == ixgbe_mac_E610_vf) {
192 		*speed = IXGBE_LINK_SPEED_UNKNOWN;
193 		if (links_reg == UINT32_MAX)
194 			goto out;
195 		if (links_reg == 0) {
196 			/*
197 			 * Some hosts do not emulate the PCI link-status query.
198 			 * VFLINKS still reports carrier, but its speed is not the
199 			 * negotiated line rate.  Do not report its default 10 Gb/s.
200 			 */
201 			links_reg = IXGBE_READ_REG(hw, IXGBE_VFLINKS);
202 			if (links_reg != UINT32_MAX &&
203 			    (links_reg & IXGBE_LINKS_UP) != 0)
204 				mac->get_link_status = false;
205 			goto out;
206 		}
207 	}
208 	if (!(links_reg & IXGBE_LINKS_UP))
209 		goto out;
210 
211 	/* Link status can take up to 500 usec to settle on 82599. */
212 	if (mac->type == ixgbe_mac_82599_vf) {
213 		int i;
214 
215 		for (i = 0; i < 5; i++) {
216 			usec_delay(100);
217 			links_reg = ixgbevf_hv_read_links(hw);
218 			if (!(links_reg & IXGBE_LINKS_UP))
219 				goto out;
220 		}
221 	}
222 
223 	switch (links_reg & IXGBE_LINKS_SPEED_82599) {
224 	case IXGBE_LINKS_SPEED_10G_82599:
225 		*speed = IXGBE_LINK_SPEED_10GB_FULL;
226 		if (hw->mac.type >= ixgbe_mac_X550_vf &&
227 		    (links_reg & IXGBE_LINKS_SPEED_NON_STD) != 0)
228 			*speed = IXGBE_LINK_SPEED_2_5GB_FULL;
229 		break;
230 	case IXGBE_LINKS_SPEED_1G_82599:
231 		*speed = IXGBE_LINK_SPEED_1GB_FULL;
232 		break;
233 	case IXGBE_LINKS_SPEED_100_82599:
234 		*speed = IXGBE_LINK_SPEED_100_FULL;
235 		if ((hw->mac.type == ixgbe_mac_X550_vf ||
236 		    hw->mac.type == ixgbe_mac_E610_vf) &&
237 		    (links_reg & IXGBE_LINKS_SPEED_NON_STD) != 0)
238 			*speed = IXGBE_LINK_SPEED_5GB_FULL;
239 		break;
240 	case IXGBE_LINKS_SPEED_10_X550EM_A:
241 		*speed = IXGBE_LINK_SPEED_UNKNOWN;
242 		if (hw->mac.type >= ixgbe_mac_X550_vf)
243 			*speed = IXGBE_LINK_SPEED_10_FULL;
244 		break;
245 	default:
246 		*speed = IXGBE_LINK_SPEED_UNKNOWN;
247 	}
248 
249 	mac->get_link_status = false;
250 
251 out:
252 	*link_up = !mac->get_link_status;
253 	return (IXGBE_SUCCESS);
254 }
255 
256 /**
257  * ixgbevf_hv_get_link_state_vf - Hyper-V has no mailbox link policy
258  * @hw: unused
259  * @link_state: unused
260  */
261 static s32
262 ixgbevf_hv_get_link_state_vf(struct ixgbe_hw *hw, bool *link_state)
263 {
264 	UNREFERENCED_2PARAMETER(hw, link_state);
265 
266 	return (IXGBE_ERR_FEATURE_NOT_SUPPORTED);
267 }
268 
269 /**
270  * ixgbevf_hv_set_rlpml_vf - Set the maximum receive packet length
271  * @hw: pointer to hardware structure
272  * @max_size: maximum frame size
273  */
274 static s32
275 ixgbevf_hv_set_rlpml_vf(struct ixgbe_hw *hw, u16 max_size)
276 {
277 	u32 i, reg;
278 
279 	/* RLPML is not implemented by the 82599 VF. */
280 	if (hw->mac.type == ixgbe_mac_82599_vf)
281 		return (IXGBE_SUCCESS);
282 
283 	for (i = 0; i < hw->mac.max_rx_queues; i++) {
284 		reg = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i));
285 		reg &= ~IXGBE_RXDCTL_RLPMLMASK;
286 		reg |= ((max_size + 4) & IXGBE_RXDCTL_RLPMLMASK) |
287 		    IXGBE_RXDCTL_RLPML_EN;
288 		IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(i), reg);
289 	}
290 
291 	return (IXGBE_SUCCESS);
292 }
293 
294 /**
295  * ixgbevf_hv_negotiate_api_version_vf - Negotiate the Hyper-V API version
296  * @hw: pointer to hardware structure
297  * @api: requested API version
298  */
299 static int
300 ixgbevf_hv_negotiate_api_version_vf(struct ixgbe_hw *hw, int api)
301 {
302 	if (api != ixgbe_mbox_api_10)
303 		return (IXGBE_ERR_INVALID_ARGUMENT);
304 
305 	hw->api_version = api;
306 	return (IXGBE_SUCCESS);
307 }
308 
309 /**
310  * ixgbevf_hv_init_ops_vf - Initialize Hyper-V VF operations
311  * @hw: pointer to hardware structure
312  */
313 s32
314 ixgbevf_hv_init_ops_vf(struct ixgbe_hw *hw)
315 {
316 	s32 status;
317 
318 	status = ixgbe_init_ops_vf(hw);
319 	if (status != IXGBE_SUCCESS)
320 		return (status);
321 
322 	hw->mac.ops.reset_hw = ixgbevf_hv_reset_hw_vf;
323 	hw->mac.ops.check_link = ixgbevf_hv_check_mac_link_vf;
324 	hw->mac.ops.negotiate_api_version =
325 	    ixgbevf_hv_negotiate_api_version_vf;
326 	hw->mac.ops.set_rar = ixgbevf_hv_set_rar_vf;
327 	hw->mac.ops.update_mc_addr_list =
328 	    ixgbevf_hv_update_mc_addr_list_vf;
329 	hw->mac.ops.update_xcast_mode = ixgbevf_hv_update_xcast_mode;
330 	hw->mac.ops.get_link_state = ixgbevf_hv_get_link_state_vf;
331 	hw->mac.ops.set_uc_addr = ixgbevf_hv_set_uc_addr_vf;
332 	hw->mac.ops.set_vfta = ixgbevf_hv_set_vfta_vf;
333 	hw->mac.ops.set_rlpml = ixgbevf_hv_set_rlpml_vf;
334 
335 	return (IXGBE_SUCCESS);
336 }
337