xref: /freebsd/sys/dev/ixl/ixl_pf_iov.c (revision 71625ec9ad2a9bc8c09784fbd23b759830e0ee5f)
14294f337SSean Bruno /******************************************************************************
24294f337SSean Bruno 
3f4cc2d17SEric Joyner   Copyright (c) 2013-2018, Intel Corporation
44294f337SSean Bruno   All rights reserved.
54294f337SSean Bruno 
64294f337SSean Bruno   Redistribution and use in source and binary forms, with or without
74294f337SSean Bruno   modification, are permitted provided that the following conditions are met:
84294f337SSean Bruno 
94294f337SSean Bruno    1. Redistributions of source code must retain the above copyright notice,
104294f337SSean Bruno       this list of conditions and the following disclaimer.
114294f337SSean Bruno 
124294f337SSean Bruno    2. Redistributions in binary form must reproduce the above copyright
134294f337SSean Bruno       notice, this list of conditions and the following disclaimer in the
144294f337SSean Bruno       documentation and/or other materials provided with the distribution.
154294f337SSean Bruno 
164294f337SSean Bruno    3. Neither the name of the Intel Corporation nor the names of its
174294f337SSean Bruno       contributors may be used to endorse or promote products derived from
184294f337SSean Bruno       this software without specific prior written permission.
194294f337SSean Bruno 
204294f337SSean Bruno   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
214294f337SSean Bruno   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224294f337SSean Bruno   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234294f337SSean Bruno   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
244294f337SSean Bruno   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
254294f337SSean Bruno   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
264294f337SSean Bruno   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
274294f337SSean Bruno   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
284294f337SSean Bruno   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
294294f337SSean Bruno   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
304294f337SSean Bruno   POSSIBILITY OF SUCH DAMAGE.
314294f337SSean Bruno 
324294f337SSean Bruno ******************************************************************************/
334294f337SSean Bruno 
344294f337SSean Bruno #include "ixl_pf_iov.h"
354294f337SSean Bruno 
364294f337SSean Bruno /* Private functions */
374294f337SSean Bruno static void	ixl_vf_map_vsi_queue(struct i40e_hw *hw, struct ixl_vf *vf, int qnum, uint32_t val);
384294f337SSean Bruno static void	ixl_vf_disable_queue_intr(struct i40e_hw *hw, uint32_t vfint_reg);
394294f337SSean Bruno static void	ixl_vf_unregister_intr(struct i40e_hw *hw, uint32_t vpint_reg);
404294f337SSean Bruno 
414294f337SSean Bruno static int	ixl_vc_opcode_level(uint16_t opcode);
424294f337SSean Bruno 
434294f337SSean Bruno static int	ixl_vf_mac_valid(struct ixl_vf *vf, const uint8_t *addr);
444294f337SSean Bruno 
454294f337SSean Bruno static int	ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf);
464294f337SSean Bruno static int	ixl_vf_setup_vsi(struct ixl_pf *pf, struct ixl_vf *vf);
474294f337SSean Bruno static void	ixl_vf_map_queues(struct ixl_pf *pf, struct ixl_vf *vf);
484294f337SSean Bruno static void	ixl_vf_vsi_release(struct ixl_pf *pf, struct ixl_vsi *vsi);
494294f337SSean Bruno static void	ixl_vf_release_resources(struct ixl_pf *pf, struct ixl_vf *vf);
504294f337SSean Bruno static int	ixl_flush_pcie(struct ixl_pf *pf, struct ixl_vf *vf);
514294f337SSean Bruno static void	ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf);
524294f337SSean Bruno static void	ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf);
534294f337SSean Bruno static void	ixl_send_vf_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op, enum i40e_status_code status, void *msg, uint16_t len);
544294f337SSean Bruno static void	ixl_send_vf_ack(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op);
554294f337SSean Bruno static void	ixl_send_vf_nack_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op, enum i40e_status_code status, const char *file, int line);
564294f337SSean Bruno static void	ixl_vf_version_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size);
574294f337SSean Bruno static void	ixl_vf_reset_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size);
584294f337SSean Bruno static void	ixl_vf_get_resources_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size);
59ceebc2f3SEric Joyner static int	ixl_vf_config_tx_queue(struct ixl_pf *pf, struct ixl_vf *vf, struct virtchnl_txq_info *info);
60ceebc2f3SEric Joyner static int	ixl_vf_config_rx_queue(struct ixl_pf *pf, struct ixl_vf *vf, struct virtchnl_rxq_info *info);
614294f337SSean Bruno static void	ixl_vf_config_vsi_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size);
62ceebc2f3SEric Joyner static void	ixl_vf_set_qctl(struct ixl_pf *pf, const struct virtchnl_vector_map *vector, enum i40e_queue_type cur_type, uint16_t cur_queue,
634294f337SSean Bruno     enum i40e_queue_type *last_type, uint16_t *last_queue);
64ceebc2f3SEric Joyner static void	ixl_vf_config_vector(struct ixl_pf *pf, struct ixl_vf *vf, const struct virtchnl_vector_map *vector);
654294f337SSean Bruno static void	ixl_vf_config_irq_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size);
664294f337SSean Bruno static void	ixl_vf_enable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size);
674294f337SSean Bruno static void	ixl_vf_disable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size);
684294f337SSean Bruno static void	ixl_vf_add_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size);
694294f337SSean Bruno static void	ixl_vf_del_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size);
704294f337SSean Bruno static enum i40e_status_code	ixl_vf_enable_vlan_strip(struct ixl_pf *pf, struct ixl_vf *vf);
714294f337SSean Bruno static void	ixl_vf_add_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size);
724294f337SSean Bruno static void	ixl_vf_del_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size);
734294f337SSean Bruno static void	ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size);
744294f337SSean Bruno static void	ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size);
754294f337SSean Bruno static int	ixl_vf_reserve_queues(struct ixl_pf *pf, struct ixl_vf *vf, int num_queues);
7677c1fcecSEric Joyner static int	ixl_config_pf_vsi_loopback(struct ixl_pf *pf, bool enable);
774294f337SSean Bruno 
784294f337SSean Bruno static int	ixl_adminq_err_to_errno(enum i40e_admin_queue_err err);
794294f337SSean Bruno 
8077c1fcecSEric Joyner /*
8177c1fcecSEric Joyner  * TODO: Move pieces of this into iflib and call the rest in a handler?
8277c1fcecSEric Joyner  *
8377c1fcecSEric Joyner  * e.g. ixl_if_iov_set_schema
8477c1fcecSEric Joyner  *
8577c1fcecSEric Joyner  * It's odd to do pci_iov_detach() there while doing pci_iov_attach()
8677c1fcecSEric Joyner  * in the driver.
8777c1fcecSEric Joyner  */
884294f337SSean Bruno void
ixl_initialize_sriov(struct ixl_pf * pf)894294f337SSean Bruno ixl_initialize_sriov(struct ixl_pf *pf)
904294f337SSean Bruno {
914294f337SSean Bruno 	device_t dev = pf->dev;
924294f337SSean Bruno 	struct i40e_hw *hw = &pf->hw;
934294f337SSean Bruno 	nvlist_t	*pf_schema, *vf_schema;
944294f337SSean Bruno 	int		iov_error;
954294f337SSean Bruno 
964294f337SSean Bruno 	pf_schema = pci_iov_schema_alloc_node();
974294f337SSean Bruno 	vf_schema = pci_iov_schema_alloc_node();
984294f337SSean Bruno 	pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
994294f337SSean Bruno 	pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof",
1004294f337SSean Bruno 	    IOV_SCHEMA_HASDEFAULT, TRUE);
1014294f337SSean Bruno 	pci_iov_schema_add_bool(vf_schema, "allow-set-mac",
1024294f337SSean Bruno 	    IOV_SCHEMA_HASDEFAULT, FALSE);
1034294f337SSean Bruno 	pci_iov_schema_add_bool(vf_schema, "allow-promisc",
1044294f337SSean Bruno 	    IOV_SCHEMA_HASDEFAULT, FALSE);
1054294f337SSean Bruno 	pci_iov_schema_add_uint16(vf_schema, "num-queues",
1064294f337SSean Bruno 	    IOV_SCHEMA_HASDEFAULT,
1073f74c027SEric Joyner 	    max(1, min(hw->func_caps.num_msix_vectors_vf - 1, IAVF_MAX_QUEUES)));
1084294f337SSean Bruno 
1094294f337SSean Bruno 	iov_error = pci_iov_attach(dev, pf_schema, vf_schema);
1104294f337SSean Bruno 	if (iov_error != 0) {
1114294f337SSean Bruno 		device_printf(dev,
1124294f337SSean Bruno 		    "Failed to initialize SR-IOV (error=%d)\n",
1134294f337SSean Bruno 		    iov_error);
1144294f337SSean Bruno 	} else
1154294f337SSean Bruno 		device_printf(dev, "SR-IOV ready\n");
1164294f337SSean Bruno 
117b4a7ce06SEric Joyner 	pf->vc_debug_lvl = 1;
118b4a7ce06SEric Joyner }
1191031d839SEric Joyner 
1204294f337SSean Bruno /*
1214294f337SSean Bruno  * Allocate the VSI for a VF.
1224294f337SSean Bruno  */
1234294f337SSean Bruno static int
ixl_vf_alloc_vsi(struct ixl_pf * pf,struct ixl_vf * vf)1244294f337SSean Bruno ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
1254294f337SSean Bruno {
1264294f337SSean Bruno 	device_t dev;
1274294f337SSean Bruno 	struct i40e_hw *hw;
1284294f337SSean Bruno 	struct i40e_vsi_context vsi_ctx;
1294294f337SSean Bruno 	int i;
1304294f337SSean Bruno 	enum i40e_status_code code;
1314294f337SSean Bruno 
1324294f337SSean Bruno 	hw = &pf->hw;
1334294f337SSean Bruno 	dev = pf->dev;
1344294f337SSean Bruno 
1354294f337SSean Bruno 	vsi_ctx.pf_num = hw->pf_id;
1364294f337SSean Bruno 	vsi_ctx.uplink_seid = pf->veb_seid;
1374294f337SSean Bruno 	vsi_ctx.connection_type = IXL_VSI_DATA_PORT;
1384294f337SSean Bruno 	vsi_ctx.vf_num = hw->func_caps.vf_base_id + vf->vf_num;
1394294f337SSean Bruno 	vsi_ctx.flags = I40E_AQ_VSI_TYPE_VF;
1404294f337SSean Bruno 
1414294f337SSean Bruno 	bzero(&vsi_ctx.info, sizeof(vsi_ctx.info));
1424294f337SSean Bruno 
1434294f337SSean Bruno 	vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID);
14477c1fcecSEric Joyner 	if (pf->enable_vf_loopback)
14577c1fcecSEric Joyner 		vsi_ctx.info.switch_id =
14677c1fcecSEric Joyner 		   htole16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
1474294f337SSean Bruno 
1484294f337SSean Bruno 	vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_SECURITY_VALID);
1494294f337SSean Bruno 	vsi_ctx.info.sec_flags = 0;
1504294f337SSean Bruno 	if (vf->vf_flags & VF_FLAG_MAC_ANTI_SPOOF)
1514294f337SSean Bruno 		vsi_ctx.info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK;
1524294f337SSean Bruno 
1534294f337SSean Bruno 	vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_VLAN_VALID);
1544294f337SSean Bruno 	vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
1554294f337SSean Bruno 	    I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
1564294f337SSean Bruno 
1574294f337SSean Bruno 	vsi_ctx.info.valid_sections |=
1584294f337SSean Bruno 	    htole16(I40E_AQ_VSI_PROP_QUEUE_MAP_VALID);
1594294f337SSean Bruno 	vsi_ctx.info.mapping_flags = htole16(I40E_AQ_VSI_QUE_MAP_NONCONTIG);
1604294f337SSean Bruno 
16177c1fcecSEric Joyner 	/* XXX: Only scattered allocation is supported for VFs right now */
1624294f337SSean Bruno 	for (i = 0; i < vf->qtag.num_active; i++)
1634294f337SSean Bruno 		vsi_ctx.info.queue_mapping[i] = vf->qtag.qidx[i];
1644294f337SSean Bruno 	for (; i < nitems(vsi_ctx.info.queue_mapping); i++)
1654294f337SSean Bruno 		vsi_ctx.info.queue_mapping[i] = htole16(I40E_AQ_VSI_QUEUE_MASK);
1664294f337SSean Bruno 
1674294f337SSean Bruno 	vsi_ctx.info.tc_mapping[0] = htole16(
1684294f337SSean Bruno 	    (0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) |
1691031d839SEric Joyner 	    ((fls(vf->qtag.num_allocated) - 1) << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT));
1704294f337SSean Bruno 
1714294f337SSean Bruno 	code = i40e_aq_add_vsi(hw, &vsi_ctx, NULL);
1724294f337SSean Bruno 	if (code != I40E_SUCCESS)
1734294f337SSean Bruno 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
1744294f337SSean Bruno 	vf->vsi.seid = vsi_ctx.seid;
1754294f337SSean Bruno 	vf->vsi.vsi_num = vsi_ctx.vsi_number;
1761031d839SEric Joyner 	vf->vsi.num_rx_queues = vf->qtag.num_active;
1771031d839SEric Joyner 	vf->vsi.num_tx_queues = vf->qtag.num_active;
1784294f337SSean Bruno 
1794294f337SSean Bruno 	code = i40e_aq_get_vsi_params(hw, &vsi_ctx, NULL);
1804294f337SSean Bruno 	if (code != I40E_SUCCESS)
1814294f337SSean Bruno 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
1824294f337SSean Bruno 
1834294f337SSean Bruno 	code = i40e_aq_config_vsi_bw_limit(hw, vf->vsi.seid, 0, 0, NULL);
1844294f337SSean Bruno 	if (code != I40E_SUCCESS) {
1854294f337SSean Bruno 		device_printf(dev, "Failed to disable BW limit: %d\n",
1864294f337SSean Bruno 		    ixl_adminq_err_to_errno(hw->aq.asq_last_status));
1874294f337SSean Bruno 		return (ixl_adminq_err_to_errno(hw->aq.asq_last_status));
1884294f337SSean Bruno 	}
1894294f337SSean Bruno 
1904294f337SSean Bruno 	memcpy(&vf->vsi.info, &vsi_ctx.info, sizeof(vf->vsi.info));
1914294f337SSean Bruno 	return (0);
1924294f337SSean Bruno }
1934294f337SSean Bruno 
1944294f337SSean Bruno static int
ixl_vf_setup_vsi(struct ixl_pf * pf,struct ixl_vf * vf)1954294f337SSean Bruno ixl_vf_setup_vsi(struct ixl_pf *pf, struct ixl_vf *vf)
1964294f337SSean Bruno {
1974294f337SSean Bruno 	struct i40e_hw *hw;
1984294f337SSean Bruno 	int error;
1994294f337SSean Bruno 
2004294f337SSean Bruno 	hw = &pf->hw;
201b4a7ce06SEric Joyner 	vf->vsi.flags |= IXL_FLAGS_IS_VF;
2024294f337SSean Bruno 
2034294f337SSean Bruno 	error = ixl_vf_alloc_vsi(pf, vf);
2044294f337SSean Bruno 	if (error != 0)
2054294f337SSean Bruno 		return (error);
2064294f337SSean Bruno 
207b4a7ce06SEric Joyner 	vf->vsi.dev = pf->dev;
208b4a7ce06SEric Joyner 
209b4a7ce06SEric Joyner 	ixl_init_filters(&vf->vsi);
21077c1fcecSEric Joyner 	/* Let VF receive broadcast Ethernet frames */
21177c1fcecSEric Joyner 	error = i40e_aq_set_vsi_broadcast(hw, vf->vsi.seid, TRUE, NULL);
21277c1fcecSEric Joyner 	if (error)
21377c1fcecSEric Joyner 		device_printf(pf->dev, "Error configuring VF VSI for broadcast promiscuous\n");
21477c1fcecSEric Joyner 	/* Re-add VF's MAC/VLAN filters to its VSI */
21577c1fcecSEric Joyner 	ixl_reconfigure_filters(&vf->vsi);
2164294f337SSean Bruno 
2174294f337SSean Bruno 	return (0);
2184294f337SSean Bruno }
2194294f337SSean Bruno 
2204294f337SSean Bruno static void
ixl_vf_map_vsi_queue(struct i40e_hw * hw,struct ixl_vf * vf,int qnum,uint32_t val)2214294f337SSean Bruno ixl_vf_map_vsi_queue(struct i40e_hw *hw, struct ixl_vf *vf, int qnum,
2224294f337SSean Bruno     uint32_t val)
2234294f337SSean Bruno {
2244294f337SSean Bruno 	uint32_t qtable;
2254294f337SSean Bruno 	int index, shift;
2264294f337SSean Bruno 
2274294f337SSean Bruno 	/*
2284294f337SSean Bruno 	 * Two queues are mapped in a single register, so we have to do some
2294294f337SSean Bruno 	 * gymnastics to convert the queue number into a register index and
2304294f337SSean Bruno 	 * shift.
2314294f337SSean Bruno 	 */
2324294f337SSean Bruno 	index = qnum / 2;
2334294f337SSean Bruno 	shift = (qnum % 2) * I40E_VSILAN_QTABLE_QINDEX_1_SHIFT;
2344294f337SSean Bruno 
2354294f337SSean Bruno 	qtable = i40e_read_rx_ctl(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num));
2364294f337SSean Bruno 	qtable &= ~(I40E_VSILAN_QTABLE_QINDEX_0_MASK << shift);
2374294f337SSean Bruno 	qtable |= val << shift;
2384294f337SSean Bruno 	i40e_write_rx_ctl(hw, I40E_VSILAN_QTABLE(index, vf->vsi.vsi_num), qtable);
2394294f337SSean Bruno }
2404294f337SSean Bruno 
2414294f337SSean Bruno static void
ixl_vf_map_queues(struct ixl_pf * pf,struct ixl_vf * vf)2424294f337SSean Bruno ixl_vf_map_queues(struct ixl_pf *pf, struct ixl_vf *vf)
2434294f337SSean Bruno {
2444294f337SSean Bruno 	struct i40e_hw *hw;
2454294f337SSean Bruno 	uint32_t qtable;
2464294f337SSean Bruno 	int i;
2474294f337SSean Bruno 
2484294f337SSean Bruno 	hw = &pf->hw;
2494294f337SSean Bruno 
2504294f337SSean Bruno 	/*
2514294f337SSean Bruno 	 * Contiguous mappings aren't actually supported by the hardware,
2524294f337SSean Bruno 	 * so we have to use non-contiguous mappings.
2534294f337SSean Bruno 	 */
2544294f337SSean Bruno 	i40e_write_rx_ctl(hw, I40E_VSILAN_QBASE(vf->vsi.vsi_num),
2554294f337SSean Bruno 	     I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK);
2564294f337SSean Bruno 
2574294f337SSean Bruno 	/* Enable LAN traffic on this VF */
2584294f337SSean Bruno 	wr32(hw, I40E_VPLAN_MAPENA(vf->vf_num),
2594294f337SSean Bruno 	    I40E_VPLAN_MAPENA_TXRX_ENA_MASK);
2604294f337SSean Bruno 
2614294f337SSean Bruno 	/* Program index of each VF queue into PF queue space
2624294f337SSean Bruno 	 * (This is only needed if QTABLE is enabled) */
2631031d839SEric Joyner 	for (i = 0; i < vf->vsi.num_tx_queues; i++) {
2644294f337SSean Bruno 		qtable = ixl_pf_qidx_from_vsi_qidx(&vf->qtag, i) <<
2654294f337SSean Bruno 		    I40E_VPLAN_QTABLE_QINDEX_SHIFT;
2664294f337SSean Bruno 
2674294f337SSean Bruno 		wr32(hw, I40E_VPLAN_QTABLE(i, vf->vf_num), qtable);
2684294f337SSean Bruno 	}
2694294f337SSean Bruno 	for (; i < IXL_MAX_VSI_QUEUES; i++)
2704294f337SSean Bruno 		wr32(hw, I40E_VPLAN_QTABLE(i, vf->vf_num),
2714294f337SSean Bruno 		    I40E_VPLAN_QTABLE_QINDEX_MASK);
2724294f337SSean Bruno 
2734294f337SSean Bruno 	/* Map queues allocated to VF to its VSI;
2744294f337SSean Bruno 	 * This mapping matches the VF-wide mapping since the VF
2754294f337SSean Bruno 	 * is only given a single VSI */
2761031d839SEric Joyner 	for (i = 0; i < vf->vsi.num_tx_queues; i++)
2774294f337SSean Bruno 		ixl_vf_map_vsi_queue(hw, vf, i,
2784294f337SSean Bruno 		    ixl_pf_qidx_from_vsi_qidx(&vf->qtag, i));
2794294f337SSean Bruno 
2804294f337SSean Bruno 	/* Set rest of VSI queues as unused. */
2814294f337SSean Bruno 	for (; i < IXL_MAX_VSI_QUEUES; i++)
2824294f337SSean Bruno 		ixl_vf_map_vsi_queue(hw, vf, i,
2834294f337SSean Bruno 		    I40E_VSILAN_QTABLE_QINDEX_0_MASK);
2844294f337SSean Bruno 
2854294f337SSean Bruno 	ixl_flush(hw);
2864294f337SSean Bruno }
2874294f337SSean Bruno 
2884294f337SSean Bruno static void
ixl_vf_vsi_release(struct ixl_pf * pf,struct ixl_vsi * vsi)2894294f337SSean Bruno ixl_vf_vsi_release(struct ixl_pf *pf, struct ixl_vsi *vsi)
2904294f337SSean Bruno {
2914294f337SSean Bruno 	struct i40e_hw *hw;
2924294f337SSean Bruno 
2934294f337SSean Bruno 	hw = &pf->hw;
2944294f337SSean Bruno 
2954294f337SSean Bruno 	if (vsi->seid == 0)
2964294f337SSean Bruno 		return;
2974294f337SSean Bruno 
2984294f337SSean Bruno 	i40e_aq_delete_element(hw, vsi->seid, NULL);
2994294f337SSean Bruno }
3004294f337SSean Bruno 
3014294f337SSean Bruno static void
ixl_vf_disable_queue_intr(struct i40e_hw * hw,uint32_t vfint_reg)3024294f337SSean Bruno ixl_vf_disable_queue_intr(struct i40e_hw *hw, uint32_t vfint_reg)
3034294f337SSean Bruno {
3044294f337SSean Bruno 
3054294f337SSean Bruno 	wr32(hw, vfint_reg, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK);
3064294f337SSean Bruno 	ixl_flush(hw);
3074294f337SSean Bruno }
3084294f337SSean Bruno 
3094294f337SSean Bruno static void
ixl_vf_unregister_intr(struct i40e_hw * hw,uint32_t vpint_reg)3104294f337SSean Bruno ixl_vf_unregister_intr(struct i40e_hw *hw, uint32_t vpint_reg)
3114294f337SSean Bruno {
3124294f337SSean Bruno 
3134294f337SSean Bruno 	wr32(hw, vpint_reg, I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK |
3144294f337SSean Bruno 	    I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK);
3154294f337SSean Bruno 	ixl_flush(hw);
3164294f337SSean Bruno }
3174294f337SSean Bruno 
3184294f337SSean Bruno static void
ixl_vf_release_resources(struct ixl_pf * pf,struct ixl_vf * vf)3194294f337SSean Bruno ixl_vf_release_resources(struct ixl_pf *pf, struct ixl_vf *vf)
3204294f337SSean Bruno {
3214294f337SSean Bruno 	struct i40e_hw *hw;
3224294f337SSean Bruno 	uint32_t vfint_reg, vpint_reg;
3234294f337SSean Bruno 	int i;
3244294f337SSean Bruno 
3254294f337SSean Bruno 	hw = &pf->hw;
3264294f337SSean Bruno 
3274294f337SSean Bruno 	ixl_vf_vsi_release(pf, &vf->vsi);
3284294f337SSean Bruno 
3294294f337SSean Bruno 	/* Index 0 has a special register. */
3304294f337SSean Bruno 	ixl_vf_disable_queue_intr(hw, I40E_VFINT_DYN_CTL0(vf->vf_num));
3314294f337SSean Bruno 
3324294f337SSean Bruno 	for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) {
3334294f337SSean Bruno 		vfint_reg = IXL_VFINT_DYN_CTLN_REG(hw, i , vf->vf_num);
3344294f337SSean Bruno 		ixl_vf_disable_queue_intr(hw, vfint_reg);
3354294f337SSean Bruno 	}
3364294f337SSean Bruno 
3374294f337SSean Bruno 	/* Index 0 has a special register. */
3384294f337SSean Bruno 	ixl_vf_unregister_intr(hw, I40E_VPINT_LNKLST0(vf->vf_num));
3394294f337SSean Bruno 
3404294f337SSean Bruno 	for (i = 1; i < hw->func_caps.num_msix_vectors_vf; i++) {
3414294f337SSean Bruno 		vpint_reg = IXL_VPINT_LNKLSTN_REG(hw, i, vf->vf_num);
3424294f337SSean Bruno 		ixl_vf_unregister_intr(hw, vpint_reg);
3434294f337SSean Bruno 	}
3444294f337SSean Bruno 
3451031d839SEric Joyner 	vf->vsi.num_tx_queues = 0;
3461031d839SEric Joyner 	vf->vsi.num_rx_queues = 0;
3474294f337SSean Bruno }
3484294f337SSean Bruno 
3494294f337SSean Bruno static int
ixl_flush_pcie(struct ixl_pf * pf,struct ixl_vf * vf)3504294f337SSean Bruno ixl_flush_pcie(struct ixl_pf *pf, struct ixl_vf *vf)
3514294f337SSean Bruno {
3524294f337SSean Bruno 	struct i40e_hw *hw;
3534294f337SSean Bruno 	int i;
3544294f337SSean Bruno 	uint16_t global_vf_num;
3554294f337SSean Bruno 	uint32_t ciad;
3564294f337SSean Bruno 
3574294f337SSean Bruno 	hw = &pf->hw;
3584294f337SSean Bruno 	global_vf_num = hw->func_caps.vf_base_id + vf->vf_num;
3594294f337SSean Bruno 
3604294f337SSean Bruno 	wr32(hw, I40E_PF_PCI_CIAA, IXL_PF_PCI_CIAA_VF_DEVICE_STATUS |
3614294f337SSean Bruno 	     (global_vf_num << I40E_PF_PCI_CIAA_VF_NUM_SHIFT));
3624294f337SSean Bruno 	for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) {
3634294f337SSean Bruno 		ciad = rd32(hw, I40E_PF_PCI_CIAD);
3644294f337SSean Bruno 		if ((ciad & IXL_PF_PCI_CIAD_VF_TRANS_PENDING_MASK) == 0)
3654294f337SSean Bruno 			return (0);
3664294f337SSean Bruno 		DELAY(1);
3674294f337SSean Bruno 	}
3684294f337SSean Bruno 
3694294f337SSean Bruno 	return (ETIMEDOUT);
3704294f337SSean Bruno }
3714294f337SSean Bruno 
3724294f337SSean Bruno static void
ixl_reset_vf(struct ixl_pf * pf,struct ixl_vf * vf)3734294f337SSean Bruno ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf)
3744294f337SSean Bruno {
3754294f337SSean Bruno 	struct i40e_hw *hw;
3764294f337SSean Bruno 	uint32_t vfrtrig;
3774294f337SSean Bruno 
3784294f337SSean Bruno 	hw = &pf->hw;
3794294f337SSean Bruno 
38077c1fcecSEric Joyner 	ixl_dbg_iov(pf, "Resetting VF-%d\n", vf->vf_num);
38177c1fcecSEric Joyner 
3824294f337SSean Bruno 	vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num));
3834294f337SSean Bruno 	vfrtrig |= I40E_VPGEN_VFRTRIG_VFSWR_MASK;
3844294f337SSean Bruno 	wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig);
3854294f337SSean Bruno 	ixl_flush(hw);
3864294f337SSean Bruno 
3874294f337SSean Bruno 	ixl_reinit_vf(pf, vf);
38877c1fcecSEric Joyner 
38977c1fcecSEric Joyner 	ixl_dbg_iov(pf, "Resetting VF-%d done.\n", vf->vf_num);
3904294f337SSean Bruno }
3914294f337SSean Bruno 
3924294f337SSean Bruno static void
ixl_reinit_vf(struct ixl_pf * pf,struct ixl_vf * vf)3934294f337SSean Bruno ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf)
3944294f337SSean Bruno {
3954294f337SSean Bruno 	struct i40e_hw *hw;
3964294f337SSean Bruno 	uint32_t vfrstat, vfrtrig;
3974294f337SSean Bruno 	int i, error;
3984294f337SSean Bruno 
3994294f337SSean Bruno 	hw = &pf->hw;
4004294f337SSean Bruno 
4014294f337SSean Bruno 	error = ixl_flush_pcie(pf, vf);
4024294f337SSean Bruno 	if (error != 0)
4034294f337SSean Bruno 		device_printf(pf->dev,
4044294f337SSean Bruno 		    "Timed out waiting for PCIe activity to stop on VF-%d\n",
4054294f337SSean Bruno 		    vf->vf_num);
4064294f337SSean Bruno 
4074294f337SSean Bruno 	for (i = 0; i < IXL_VF_RESET_TIMEOUT; i++) {
4084294f337SSean Bruno 		DELAY(10);
4094294f337SSean Bruno 
4104294f337SSean Bruno 		vfrstat = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_num));
4114294f337SSean Bruno 		if (vfrstat & I40E_VPGEN_VFRSTAT_VFRD_MASK)
4124294f337SSean Bruno 			break;
4134294f337SSean Bruno 	}
4144294f337SSean Bruno 
4154294f337SSean Bruno 	if (i == IXL_VF_RESET_TIMEOUT)
4164294f337SSean Bruno 		device_printf(pf->dev, "VF %d failed to reset\n", vf->vf_num);
4174294f337SSean Bruno 
418ceebc2f3SEric Joyner 	wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), VIRTCHNL_VFR_COMPLETED);
4194294f337SSean Bruno 
4204294f337SSean Bruno 	vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num));
4214294f337SSean Bruno 	vfrtrig &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK;
4224294f337SSean Bruno 	wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig);
4234294f337SSean Bruno 
4244294f337SSean Bruno 	if (vf->vsi.seid != 0)
42577c1fcecSEric Joyner 		ixl_disable_rings(pf, &vf->vsi, &vf->qtag);
42677c1fcecSEric Joyner 	ixl_pf_qmgr_clear_queue_flags(&vf->qtag);
4274294f337SSean Bruno 
4284294f337SSean Bruno 	ixl_vf_release_resources(pf, vf);
4294294f337SSean Bruno 	ixl_vf_setup_vsi(pf, vf);
4304294f337SSean Bruno 	ixl_vf_map_queues(pf, vf);
4314294f337SSean Bruno 
432ceebc2f3SEric Joyner 	wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), VIRTCHNL_VFR_VFACTIVE);
4334294f337SSean Bruno 	ixl_flush(hw);
4344294f337SSean Bruno }
4354294f337SSean Bruno 
4364294f337SSean Bruno static int
ixl_vc_opcode_level(uint16_t opcode)4374294f337SSean Bruno ixl_vc_opcode_level(uint16_t opcode)
4384294f337SSean Bruno {
4394294f337SSean Bruno 	switch (opcode) {
440ceebc2f3SEric Joyner 	case VIRTCHNL_OP_GET_STATS:
4414294f337SSean Bruno 		return (10);
4424294f337SSean Bruno 	default:
4434294f337SSean Bruno 		return (5);
4444294f337SSean Bruno 	}
4454294f337SSean Bruno }
4464294f337SSean Bruno 
4474294f337SSean Bruno static void
ixl_send_vf_msg(struct ixl_pf * pf,struct ixl_vf * vf,uint16_t op,enum i40e_status_code status,void * msg,uint16_t len)4484294f337SSean Bruno ixl_send_vf_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op,
4494294f337SSean Bruno     enum i40e_status_code status, void *msg, uint16_t len)
4504294f337SSean Bruno {
4514294f337SSean Bruno 	struct i40e_hw *hw;
4524294f337SSean Bruno 	int global_vf_id;
4534294f337SSean Bruno 
4544294f337SSean Bruno 	hw = &pf->hw;
4554294f337SSean Bruno 	global_vf_id = hw->func_caps.vf_base_id + vf->vf_num;
4564294f337SSean Bruno 
4574294f337SSean Bruno 	I40E_VC_DEBUG(pf, ixl_vc_opcode_level(op),
4584294f337SSean Bruno 	    "Sending msg (op=%s[%d], status=%d) to VF-%d\n",
4594294f337SSean Bruno 	    ixl_vc_opcode_str(op), op, status, vf->vf_num);
4604294f337SSean Bruno 
4614294f337SSean Bruno 	i40e_aq_send_msg_to_vf(hw, global_vf_id, op, status, msg, len, NULL);
4624294f337SSean Bruno }
4634294f337SSean Bruno 
4644294f337SSean Bruno static void
ixl_send_vf_ack(struct ixl_pf * pf,struct ixl_vf * vf,uint16_t op)4654294f337SSean Bruno ixl_send_vf_ack(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op)
4664294f337SSean Bruno {
4674294f337SSean Bruno 
4684294f337SSean Bruno 	ixl_send_vf_msg(pf, vf, op, I40E_SUCCESS, NULL, 0);
4694294f337SSean Bruno }
4704294f337SSean Bruno 
4714294f337SSean Bruno static void
ixl_send_vf_nack_msg(struct ixl_pf * pf,struct ixl_vf * vf,uint16_t op,enum i40e_status_code status,const char * file,int line)4724294f337SSean Bruno ixl_send_vf_nack_msg(struct ixl_pf *pf, struct ixl_vf *vf, uint16_t op,
4734294f337SSean Bruno     enum i40e_status_code status, const char *file, int line)
4744294f337SSean Bruno {
4754294f337SSean Bruno 
4764294f337SSean Bruno 	I40E_VC_DEBUG(pf, 1,
4774294f337SSean Bruno 	    "Sending NACK (op=%s[%d], err=%s[%d]) to VF-%d from %s:%d\n",
4784294f337SSean Bruno 	    ixl_vc_opcode_str(op), op, i40e_stat_str(&pf->hw, status),
4794294f337SSean Bruno 	    status, vf->vf_num, file, line);
4804294f337SSean Bruno 	ixl_send_vf_msg(pf, vf, op, status, NULL, 0);
4814294f337SSean Bruno }
4824294f337SSean Bruno 
4834294f337SSean Bruno static void
ixl_vf_version_msg(struct ixl_pf * pf,struct ixl_vf * vf,void * msg,uint16_t msg_size)4844294f337SSean Bruno ixl_vf_version_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
4854294f337SSean Bruno     uint16_t msg_size)
4864294f337SSean Bruno {
487b4a7ce06SEric Joyner 	struct virtchnl_version_info *recv_vf_version;
488b4a7ce06SEric Joyner 	device_t dev = pf->dev;
4894294f337SSean Bruno 
490b4a7ce06SEric Joyner 	recv_vf_version = (struct virtchnl_version_info *)msg;
491b4a7ce06SEric Joyner 
492b4a7ce06SEric Joyner 	/* VFs running the 1.0 API expect to get 1.0 back */
493b4a7ce06SEric Joyner 	if (VF_IS_V10(recv_vf_version)) {
494b4a7ce06SEric Joyner 		vf->version.major = 1;
495b4a7ce06SEric Joyner 		vf->version.minor = VIRTCHNL_VERSION_MINOR_NO_VF_CAPS;
496b4a7ce06SEric Joyner 	} else {
497b4a7ce06SEric Joyner 		vf->version.major = VIRTCHNL_VERSION_MAJOR;
498b4a7ce06SEric Joyner 		vf->version.minor = VIRTCHNL_VERSION_MINOR;
499b4a7ce06SEric Joyner 
500b4a7ce06SEric Joyner 		if ((recv_vf_version->major != VIRTCHNL_VERSION_MAJOR) ||
501b4a7ce06SEric Joyner 		    (recv_vf_version->minor != VIRTCHNL_VERSION_MINOR))
502b4a7ce06SEric Joyner 		    device_printf(dev,
503b4a7ce06SEric Joyner 		        "%s: VF-%d requested version (%d.%d) differs from PF version (%d.%d)\n",
504b4a7ce06SEric Joyner 			__func__, vf->vf_num,
505b4a7ce06SEric Joyner 			recv_vf_version->major, recv_vf_version->minor,
506b4a7ce06SEric Joyner 			VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
5074294f337SSean Bruno 	}
5084294f337SSean Bruno 
509b4a7ce06SEric Joyner 	ixl_send_vf_msg(pf, vf, VIRTCHNL_OP_VERSION, I40E_SUCCESS,
510b4a7ce06SEric Joyner 	    &vf->version, sizeof(vf->version));
5114294f337SSean Bruno }
5124294f337SSean Bruno 
5134294f337SSean Bruno static void
ixl_vf_reset_msg(struct ixl_pf * pf,struct ixl_vf * vf,void * msg,uint16_t msg_size)5144294f337SSean Bruno ixl_vf_reset_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
5154294f337SSean Bruno     uint16_t msg_size)
5164294f337SSean Bruno {
5174294f337SSean Bruno 	ixl_reset_vf(pf, vf);
5184294f337SSean Bruno 
5194294f337SSean Bruno 	/* No response to a reset message. */
5204294f337SSean Bruno }
5214294f337SSean Bruno 
5224294f337SSean Bruno static void
ixl_vf_get_resources_msg(struct ixl_pf * pf,struct ixl_vf * vf,void * msg,uint16_t msg_size)5234294f337SSean Bruno ixl_vf_get_resources_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
5244294f337SSean Bruno     uint16_t msg_size)
5254294f337SSean Bruno {
526ceebc2f3SEric Joyner 	struct virtchnl_vf_resource reply;
5274294f337SSean Bruno 
5284294f337SSean Bruno 	bzero(&reply, sizeof(reply));
5294294f337SSean Bruno 
530b4a7ce06SEric Joyner 	if (vf->version.minor == VIRTCHNL_VERSION_MINOR_NO_VF_CAPS)
531ceebc2f3SEric Joyner 		reply.vf_cap_flags = VIRTCHNL_VF_OFFLOAD_L2 |
532ceebc2f3SEric Joyner 					 VIRTCHNL_VF_OFFLOAD_RSS_REG |
533ceebc2f3SEric Joyner 					 VIRTCHNL_VF_OFFLOAD_VLAN;
5344294f337SSean Bruno 	else
5354294f337SSean Bruno 		/* Force VF RSS setup by PF in 1.1+ VFs */
536ceebc2f3SEric Joyner 		reply.vf_cap_flags = *(u32 *)msg & (
537ceebc2f3SEric Joyner 					 VIRTCHNL_VF_OFFLOAD_L2 |
538ceebc2f3SEric Joyner 					 VIRTCHNL_VF_OFFLOAD_RSS_PF |
539ceebc2f3SEric Joyner 					 VIRTCHNL_VF_OFFLOAD_VLAN);
5404294f337SSean Bruno 
5414294f337SSean Bruno 	reply.num_vsis = 1;
5421031d839SEric Joyner 	reply.num_queue_pairs = vf->vsi.num_tx_queues;
5434294f337SSean Bruno 	reply.max_vectors = pf->hw.func_caps.num_msix_vectors_vf;
5444294f337SSean Bruno 	reply.rss_key_size = 52;
5454294f337SSean Bruno 	reply.rss_lut_size = 64;
5464294f337SSean Bruno 	reply.vsi_res[0].vsi_id = vf->vsi.vsi_num;
547ceebc2f3SEric Joyner 	reply.vsi_res[0].vsi_type = VIRTCHNL_VSI_SRIOV;
5481031d839SEric Joyner 	reply.vsi_res[0].num_queue_pairs = vf->vsi.num_tx_queues;
5494294f337SSean Bruno 	memcpy(reply.vsi_res[0].default_mac_addr, vf->mac, ETHER_ADDR_LEN);
5504294f337SSean Bruno 
551ceebc2f3SEric Joyner 	ixl_send_vf_msg(pf, vf, VIRTCHNL_OP_GET_VF_RESOURCES,
5524294f337SSean Bruno 	    I40E_SUCCESS, &reply, sizeof(reply));
5534294f337SSean Bruno }
5544294f337SSean Bruno 
5554294f337SSean Bruno static int
ixl_vf_config_tx_queue(struct ixl_pf * pf,struct ixl_vf * vf,struct virtchnl_txq_info * info)5564294f337SSean Bruno ixl_vf_config_tx_queue(struct ixl_pf *pf, struct ixl_vf *vf,
557ceebc2f3SEric Joyner     struct virtchnl_txq_info *info)
5584294f337SSean Bruno {
5594294f337SSean Bruno 	struct i40e_hw *hw;
5604294f337SSean Bruno 	struct i40e_hmc_obj_txq txq;
5614294f337SSean Bruno 	uint16_t global_queue_num, global_vf_num;
5624294f337SSean Bruno 	enum i40e_status_code status;
5634294f337SSean Bruno 	uint32_t qtx_ctl;
5644294f337SSean Bruno 
5654294f337SSean Bruno 	hw = &pf->hw;
5664294f337SSean Bruno 	global_queue_num = ixl_pf_qidx_from_vsi_qidx(&vf->qtag, info->queue_id);
5674294f337SSean Bruno 	global_vf_num = hw->func_caps.vf_base_id + vf->vf_num;
5684294f337SSean Bruno 	bzero(&txq, sizeof(txq));
5694294f337SSean Bruno 
5704294f337SSean Bruno 	DDPRINTF(pf->dev, "VF %d: PF TX queue %d / VF TX queue %d (Global VF %d)\n",
5714294f337SSean Bruno 	    vf->vf_num, global_queue_num, info->queue_id, global_vf_num);
5724294f337SSean Bruno 
5734294f337SSean Bruno 	status = i40e_clear_lan_tx_queue_context(hw, global_queue_num);
5744294f337SSean Bruno 	if (status != I40E_SUCCESS)
5754294f337SSean Bruno 		return (EINVAL);
5764294f337SSean Bruno 
5774294f337SSean Bruno 	txq.base = info->dma_ring_addr / IXL_TX_CTX_BASE_UNITS;
5784294f337SSean Bruno 
5794294f337SSean Bruno 	txq.head_wb_ena = info->headwb_enabled;
5804294f337SSean Bruno 	txq.head_wb_addr = info->dma_headwb_addr;
5814294f337SSean Bruno 	txq.qlen = info->ring_len;
5824294f337SSean Bruno 	txq.rdylist = le16_to_cpu(vf->vsi.info.qs_handle[0]);
5834294f337SSean Bruno 	txq.rdylist_act = 0;
5844294f337SSean Bruno 
5854294f337SSean Bruno 	status = i40e_set_lan_tx_queue_context(hw, global_queue_num, &txq);
5864294f337SSean Bruno 	if (status != I40E_SUCCESS)
5874294f337SSean Bruno 		return (EINVAL);
5884294f337SSean Bruno 
5894294f337SSean Bruno 	qtx_ctl = I40E_QTX_CTL_VF_QUEUE |
5904294f337SSean Bruno 	    (hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) |
5914294f337SSean Bruno 	    (global_vf_num << I40E_QTX_CTL_VFVM_INDX_SHIFT);
5924294f337SSean Bruno 	wr32(hw, I40E_QTX_CTL(global_queue_num), qtx_ctl);
5934294f337SSean Bruno 	ixl_flush(hw);
5944294f337SSean Bruno 
5954294f337SSean Bruno 	ixl_pf_qmgr_mark_queue_configured(&vf->qtag, info->queue_id, true);
5964294f337SSean Bruno 
5974294f337SSean Bruno 	return (0);
5984294f337SSean Bruno }
5994294f337SSean Bruno 
6004294f337SSean Bruno static int
ixl_vf_config_rx_queue(struct ixl_pf * pf,struct ixl_vf * vf,struct virtchnl_rxq_info * info)6014294f337SSean Bruno ixl_vf_config_rx_queue(struct ixl_pf *pf, struct ixl_vf *vf,
602ceebc2f3SEric Joyner     struct virtchnl_rxq_info *info)
6034294f337SSean Bruno {
6044294f337SSean Bruno 	struct i40e_hw *hw;
6054294f337SSean Bruno 	struct i40e_hmc_obj_rxq rxq;
6064294f337SSean Bruno 	uint16_t global_queue_num;
6074294f337SSean Bruno 	enum i40e_status_code status;
6084294f337SSean Bruno 
6094294f337SSean Bruno 	hw = &pf->hw;
6104294f337SSean Bruno 	global_queue_num = ixl_pf_qidx_from_vsi_qidx(&vf->qtag, info->queue_id);
6114294f337SSean Bruno 	bzero(&rxq, sizeof(rxq));
6124294f337SSean Bruno 
6134294f337SSean Bruno 	DDPRINTF(pf->dev, "VF %d: PF RX queue %d / VF RX queue %d\n",
6144294f337SSean Bruno 	    vf->vf_num, global_queue_num, info->queue_id);
6154294f337SSean Bruno 
6164294f337SSean Bruno 	if (info->databuffer_size > IXL_VF_MAX_BUFFER)
6174294f337SSean Bruno 		return (EINVAL);
6184294f337SSean Bruno 
6194294f337SSean Bruno 	if (info->max_pkt_size > IXL_VF_MAX_FRAME ||
6204294f337SSean Bruno 	    info->max_pkt_size < ETHER_MIN_LEN)
6214294f337SSean Bruno 		return (EINVAL);
6224294f337SSean Bruno 
6234294f337SSean Bruno 	if (info->splithdr_enabled) {
6244294f337SSean Bruno 		if (info->hdr_size > IXL_VF_MAX_HDR_BUFFER)
6254294f337SSean Bruno 			return (EINVAL);
6264294f337SSean Bruno 
6274294f337SSean Bruno 		rxq.hsplit_0 = info->rx_split_pos &
6284294f337SSean Bruno 		    (I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_L2 |
6294294f337SSean Bruno 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_IP |
6304294f337SSean Bruno 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_TCP_UDP |
6314294f337SSean Bruno 		     I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_SCTP);
6324294f337SSean Bruno 		rxq.hbuff = info->hdr_size >> I40E_RXQ_CTX_HBUFF_SHIFT;
6334294f337SSean Bruno 
6344294f337SSean Bruno 		rxq.dtype = 2;
6354294f337SSean Bruno 	}
6364294f337SSean Bruno 
6374294f337SSean Bruno 	status = i40e_clear_lan_rx_queue_context(hw, global_queue_num);
6384294f337SSean Bruno 	if (status != I40E_SUCCESS)
6394294f337SSean Bruno 		return (EINVAL);
6404294f337SSean Bruno 
6414294f337SSean Bruno 	rxq.base = info->dma_ring_addr / IXL_RX_CTX_BASE_UNITS;
6424294f337SSean Bruno 	rxq.qlen = info->ring_len;
6434294f337SSean Bruno 
6444294f337SSean Bruno 	rxq.dbuff = info->databuffer_size >> I40E_RXQ_CTX_DBUFF_SHIFT;
6454294f337SSean Bruno 
6464294f337SSean Bruno 	rxq.dsize = 1;
6474294f337SSean Bruno 	rxq.crcstrip = 1;
6484294f337SSean Bruno 	rxq.l2tsel = 1;
6494294f337SSean Bruno 
6504294f337SSean Bruno 	rxq.rxmax = info->max_pkt_size;
6514294f337SSean Bruno 	rxq.tphrdesc_ena = 1;
6524294f337SSean Bruno 	rxq.tphwdesc_ena = 1;
6534294f337SSean Bruno 	rxq.tphdata_ena = 1;
6544294f337SSean Bruno 	rxq.tphhead_ena = 1;
65577c1fcecSEric Joyner 	rxq.lrxqthresh = 1;
6564294f337SSean Bruno 	rxq.prefena = 1;
6574294f337SSean Bruno 
6584294f337SSean Bruno 	status = i40e_set_lan_rx_queue_context(hw, global_queue_num, &rxq);
6594294f337SSean Bruno 	if (status != I40E_SUCCESS)
6604294f337SSean Bruno 		return (EINVAL);
6614294f337SSean Bruno 
6624294f337SSean Bruno 	ixl_pf_qmgr_mark_queue_configured(&vf->qtag, info->queue_id, false);
6634294f337SSean Bruno 
6644294f337SSean Bruno 	return (0);
6654294f337SSean Bruno }
6664294f337SSean Bruno 
6674294f337SSean Bruno static void
ixl_vf_config_vsi_msg(struct ixl_pf * pf,struct ixl_vf * vf,void * msg,uint16_t msg_size)6684294f337SSean Bruno ixl_vf_config_vsi_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
6694294f337SSean Bruno     uint16_t msg_size)
6704294f337SSean Bruno {
671ceebc2f3SEric Joyner 	struct virtchnl_vsi_queue_config_info *info;
672ceebc2f3SEric Joyner 	struct virtchnl_queue_pair_info *pair;
6734294f337SSean Bruno 	int i;
6744294f337SSean Bruno 
6754294f337SSean Bruno 	info = msg;
6761031d839SEric Joyner 	if (info->num_queue_pairs == 0 || info->num_queue_pairs > vf->vsi.num_tx_queues) {
6774294f337SSean Bruno 		device_printf(pf->dev, "VF %d: invalid # of qpairs (msg has %d, VSI has %d)\n",
6781031d839SEric Joyner 		    vf->vf_num, info->num_queue_pairs, vf->vsi.num_tx_queues);
679ceebc2f3SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES,
6804294f337SSean Bruno 		    I40E_ERR_PARAM);
6814294f337SSean Bruno 		return;
6824294f337SSean Bruno 	}
6834294f337SSean Bruno 
6844294f337SSean Bruno 	if (info->vsi_id != vf->vsi.vsi_num) {
6854294f337SSean Bruno 		device_printf(pf->dev, "VF %d: VSI id in recvd message (%d) does not match expected id (%d)\n",
6864294f337SSean Bruno 		    vf->vf_num, info->vsi_id, vf->vsi.vsi_num);
687ceebc2f3SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES,
6884294f337SSean Bruno 		    I40E_ERR_PARAM);
6894294f337SSean Bruno 		return;
6904294f337SSean Bruno 	}
6914294f337SSean Bruno 
6924294f337SSean Bruno 	for (i = 0; i < info->num_queue_pairs; i++) {
6934294f337SSean Bruno 		pair = &info->qpair[i];
6944294f337SSean Bruno 
6954294f337SSean Bruno 		if (pair->txq.vsi_id != vf->vsi.vsi_num ||
6964294f337SSean Bruno 		    pair->rxq.vsi_id != vf->vsi.vsi_num ||
6974294f337SSean Bruno 		    pair->txq.queue_id != pair->rxq.queue_id ||
6981031d839SEric Joyner 		    pair->txq.queue_id >= vf->vsi.num_tx_queues) {
6994294f337SSean Bruno 
7004294f337SSean Bruno 			i40e_send_vf_nack(pf, vf,
701ceebc2f3SEric Joyner 			    VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
7024294f337SSean Bruno 			return;
7034294f337SSean Bruno 		}
7044294f337SSean Bruno 
7054294f337SSean Bruno 		if (ixl_vf_config_tx_queue(pf, vf, &pair->txq) != 0) {
7064294f337SSean Bruno 			i40e_send_vf_nack(pf, vf,
707ceebc2f3SEric Joyner 			    VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
7084294f337SSean Bruno 			return;
7094294f337SSean Bruno 		}
7104294f337SSean Bruno 
7114294f337SSean Bruno 		if (ixl_vf_config_rx_queue(pf, vf, &pair->rxq) != 0) {
7124294f337SSean Bruno 			i40e_send_vf_nack(pf, vf,
713ceebc2f3SEric Joyner 			    VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM);
7144294f337SSean Bruno 			return;
7154294f337SSean Bruno 		}
7164294f337SSean Bruno 	}
7174294f337SSean Bruno 
718ceebc2f3SEric Joyner 	ixl_send_vf_ack(pf, vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES);
7194294f337SSean Bruno }
7204294f337SSean Bruno 
7214294f337SSean Bruno static void
ixl_vf_set_qctl(struct ixl_pf * pf,const struct virtchnl_vector_map * vector,enum i40e_queue_type cur_type,uint16_t cur_queue,enum i40e_queue_type * last_type,uint16_t * last_queue)7224294f337SSean Bruno ixl_vf_set_qctl(struct ixl_pf *pf,
723ceebc2f3SEric Joyner     const struct virtchnl_vector_map *vector,
7244294f337SSean Bruno     enum i40e_queue_type cur_type, uint16_t cur_queue,
7254294f337SSean Bruno     enum i40e_queue_type *last_type, uint16_t *last_queue)
7264294f337SSean Bruno {
7274294f337SSean Bruno 	uint32_t offset, qctl;
7284294f337SSean Bruno 	uint16_t itr_indx;
7294294f337SSean Bruno 
7304294f337SSean Bruno 	if (cur_type == I40E_QUEUE_TYPE_RX) {
7314294f337SSean Bruno 		offset = I40E_QINT_RQCTL(cur_queue);
7324294f337SSean Bruno 		itr_indx = vector->rxitr_idx;
7334294f337SSean Bruno 	} else {
7344294f337SSean Bruno 		offset = I40E_QINT_TQCTL(cur_queue);
7354294f337SSean Bruno 		itr_indx = vector->txitr_idx;
7364294f337SSean Bruno 	}
7374294f337SSean Bruno 
7384294f337SSean Bruno 	qctl = htole32((vector->vector_id << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
7394294f337SSean Bruno 	    (*last_type << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
7404294f337SSean Bruno 	    (*last_queue << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
7414294f337SSean Bruno 	    I40E_QINT_RQCTL_CAUSE_ENA_MASK |
7424294f337SSean Bruno 	    (itr_indx << I40E_QINT_RQCTL_ITR_INDX_SHIFT));
7434294f337SSean Bruno 
7444294f337SSean Bruno 	wr32(&pf->hw, offset, qctl);
7454294f337SSean Bruno 
7464294f337SSean Bruno 	*last_type = cur_type;
7474294f337SSean Bruno 	*last_queue = cur_queue;
7484294f337SSean Bruno }
7494294f337SSean Bruno 
7504294f337SSean Bruno static void
ixl_vf_config_vector(struct ixl_pf * pf,struct ixl_vf * vf,const struct virtchnl_vector_map * vector)7514294f337SSean Bruno ixl_vf_config_vector(struct ixl_pf *pf, struct ixl_vf *vf,
752ceebc2f3SEric Joyner     const struct virtchnl_vector_map *vector)
7534294f337SSean Bruno {
7544294f337SSean Bruno 	struct i40e_hw *hw;
7554294f337SSean Bruno 	u_int qindex;
7564294f337SSean Bruno 	enum i40e_queue_type type, last_type;
7574294f337SSean Bruno 	uint32_t lnklst_reg;
7584294f337SSean Bruno 	uint16_t rxq_map, txq_map, cur_queue, last_queue;
7594294f337SSean Bruno 
7604294f337SSean Bruno 	hw = &pf->hw;
7614294f337SSean Bruno 
7624294f337SSean Bruno 	rxq_map = vector->rxq_map;
7634294f337SSean Bruno 	txq_map = vector->txq_map;
7644294f337SSean Bruno 
7654294f337SSean Bruno 	last_queue = IXL_END_OF_INTR_LNKLST;
7664294f337SSean Bruno 	last_type = I40E_QUEUE_TYPE_RX;
7674294f337SSean Bruno 
7684294f337SSean Bruno 	/*
7694294f337SSean Bruno 	 * The datasheet says to optimize performance, RX queues and TX queues
7704294f337SSean Bruno 	 * should be interleaved in the interrupt linked list, so we process
7714294f337SSean Bruno 	 * both at once here.
7724294f337SSean Bruno 	 */
7734294f337SSean Bruno 	while ((rxq_map != 0) || (txq_map != 0)) {
7744294f337SSean Bruno 		if (txq_map != 0) {
7754294f337SSean Bruno 			qindex = ffs(txq_map) - 1;
7764294f337SSean Bruno 			type = I40E_QUEUE_TYPE_TX;
7774294f337SSean Bruno 			cur_queue = ixl_pf_qidx_from_vsi_qidx(&vf->qtag, qindex);
7784294f337SSean Bruno 			ixl_vf_set_qctl(pf, vector, type, cur_queue,
7794294f337SSean Bruno 			    &last_type, &last_queue);
7804294f337SSean Bruno 			txq_map &= ~(1 << qindex);
7814294f337SSean Bruno 		}
7824294f337SSean Bruno 
7834294f337SSean Bruno 		if (rxq_map != 0) {
7844294f337SSean Bruno 			qindex = ffs(rxq_map) - 1;
7854294f337SSean Bruno 			type = I40E_QUEUE_TYPE_RX;
7864294f337SSean Bruno 			cur_queue = ixl_pf_qidx_from_vsi_qidx(&vf->qtag, qindex);
7874294f337SSean Bruno 			ixl_vf_set_qctl(pf, vector, type, cur_queue,
7884294f337SSean Bruno 			    &last_type, &last_queue);
7894294f337SSean Bruno 			rxq_map &= ~(1 << qindex);
7904294f337SSean Bruno 		}
7914294f337SSean Bruno 	}
7924294f337SSean Bruno 
7934294f337SSean Bruno 	if (vector->vector_id == 0)
7944294f337SSean Bruno 		lnklst_reg = I40E_VPINT_LNKLST0(vf->vf_num);
7954294f337SSean Bruno 	else
7964294f337SSean Bruno 		lnklst_reg = IXL_VPINT_LNKLSTN_REG(hw, vector->vector_id,
7974294f337SSean Bruno 		    vf->vf_num);
7984294f337SSean Bruno 	wr32(hw, lnklst_reg,
7994294f337SSean Bruno 	    (last_queue << I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
8004294f337SSean Bruno 	    (last_type << I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT));
8014294f337SSean Bruno 
8024294f337SSean Bruno 	ixl_flush(hw);
8034294f337SSean Bruno }
8044294f337SSean Bruno 
8054294f337SSean Bruno static void
ixl_vf_config_irq_msg(struct ixl_pf * pf,struct ixl_vf * vf,void * msg,uint16_t msg_size)8064294f337SSean Bruno ixl_vf_config_irq_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
8074294f337SSean Bruno     uint16_t msg_size)
8084294f337SSean Bruno {
809ceebc2f3SEric Joyner 	struct virtchnl_irq_map_info *map;
810ceebc2f3SEric Joyner 	struct virtchnl_vector_map *vector;
8114294f337SSean Bruno 	struct i40e_hw *hw;
8124294f337SSean Bruno 	int i, largest_txq, largest_rxq;
8134294f337SSean Bruno 
8144294f337SSean Bruno 	hw = &pf->hw;
8154294f337SSean Bruno 	map = msg;
8164294f337SSean Bruno 
8174294f337SSean Bruno 	for (i = 0; i < map->num_vectors; i++) {
8184294f337SSean Bruno 		vector = &map->vecmap[i];
8194294f337SSean Bruno 
8204294f337SSean Bruno 		if ((vector->vector_id >= hw->func_caps.num_msix_vectors_vf) ||
8214294f337SSean Bruno 		    vector->vsi_id != vf->vsi.vsi_num) {
8224294f337SSean Bruno 			i40e_send_vf_nack(pf, vf,
823ceebc2f3SEric Joyner 			    VIRTCHNL_OP_CONFIG_IRQ_MAP, I40E_ERR_PARAM);
8244294f337SSean Bruno 			return;
8254294f337SSean Bruno 		}
8264294f337SSean Bruno 
8274294f337SSean Bruno 		if (vector->rxq_map != 0) {
8284294f337SSean Bruno 			largest_rxq = fls(vector->rxq_map) - 1;
8291031d839SEric Joyner 			if (largest_rxq >= vf->vsi.num_rx_queues) {
8304294f337SSean Bruno 				i40e_send_vf_nack(pf, vf,
831ceebc2f3SEric Joyner 				    VIRTCHNL_OP_CONFIG_IRQ_MAP,
8324294f337SSean Bruno 				    I40E_ERR_PARAM);
8334294f337SSean Bruno 				return;
8344294f337SSean Bruno 			}
8354294f337SSean Bruno 		}
8364294f337SSean Bruno 
8374294f337SSean Bruno 		if (vector->txq_map != 0) {
8384294f337SSean Bruno 			largest_txq = fls(vector->txq_map) - 1;
8391031d839SEric Joyner 			if (largest_txq >= vf->vsi.num_tx_queues) {
8404294f337SSean Bruno 				i40e_send_vf_nack(pf, vf,
841ceebc2f3SEric Joyner 				    VIRTCHNL_OP_CONFIG_IRQ_MAP,
8424294f337SSean Bruno 				    I40E_ERR_PARAM);
8434294f337SSean Bruno 				return;
8444294f337SSean Bruno 			}
8454294f337SSean Bruno 		}
8464294f337SSean Bruno 
8474294f337SSean Bruno 		if (vector->rxitr_idx > IXL_MAX_ITR_IDX ||
8484294f337SSean Bruno 		    vector->txitr_idx > IXL_MAX_ITR_IDX) {
8494294f337SSean Bruno 			i40e_send_vf_nack(pf, vf,
850ceebc2f3SEric Joyner 			    VIRTCHNL_OP_CONFIG_IRQ_MAP,
8514294f337SSean Bruno 			    I40E_ERR_PARAM);
8524294f337SSean Bruno 			return;
8534294f337SSean Bruno 		}
8544294f337SSean Bruno 
8554294f337SSean Bruno 		ixl_vf_config_vector(pf, vf, vector);
8564294f337SSean Bruno 	}
8574294f337SSean Bruno 
858ceebc2f3SEric Joyner 	ixl_send_vf_ack(pf, vf, VIRTCHNL_OP_CONFIG_IRQ_MAP);
8594294f337SSean Bruno }
8604294f337SSean Bruno 
8614294f337SSean Bruno static void
ixl_vf_enable_queues_msg(struct ixl_pf * pf,struct ixl_vf * vf,void * msg,uint16_t msg_size)8624294f337SSean Bruno ixl_vf_enable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
8634294f337SSean Bruno     uint16_t msg_size)
8644294f337SSean Bruno {
865ceebc2f3SEric Joyner 	struct virtchnl_queue_select *select;
8664294f337SSean Bruno 	int error = 0;
8674294f337SSean Bruno 
8684294f337SSean Bruno 	select = msg;
869b4a7ce06SEric Joyner 
8704294f337SSean Bruno 	if (select->vsi_id != vf->vsi.vsi_num ||
8714294f337SSean Bruno 	    select->rx_queues == 0 || select->tx_queues == 0) {
872ceebc2f3SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_ENABLE_QUEUES,
8734294f337SSean Bruno 		    I40E_ERR_PARAM);
8744294f337SSean Bruno 		return;
8754294f337SSean Bruno 	}
8764294f337SSean Bruno 
8774294f337SSean Bruno 	/* Enable TX rings selected by the VF */
8784294f337SSean Bruno 	for (int i = 0; i < 32; i++) {
8794294f337SSean Bruno 		if ((1 << i) & select->tx_queues) {
8804294f337SSean Bruno 			/* Warn if queue is out of VF allocation range */
8811031d839SEric Joyner 			if (i >= vf->vsi.num_tx_queues) {
8824294f337SSean Bruno 				device_printf(pf->dev, "VF %d: TX ring %d is outside of VF VSI allocation!\n",
8834294f337SSean Bruno 				    vf->vf_num, i);
8844294f337SSean Bruno 				break;
8854294f337SSean Bruno 			}
8864294f337SSean Bruno 			/* Skip this queue if it hasn't been configured */
8874294f337SSean Bruno 			if (!ixl_pf_qmgr_is_queue_configured(&vf->qtag, i, true))
8884294f337SSean Bruno 				continue;
8894294f337SSean Bruno 			/* Warn if this queue is already marked as enabled */
8904294f337SSean Bruno 			if (ixl_pf_qmgr_is_queue_enabled(&vf->qtag, i, true))
89177c1fcecSEric Joyner 				ixl_dbg_iov(pf, "VF %d: TX ring %d is already enabled!\n",
8924294f337SSean Bruno 				    vf->vf_num, i);
8934294f337SSean Bruno 
8944294f337SSean Bruno 			error = ixl_enable_tx_ring(pf, &vf->qtag, i);
8954294f337SSean Bruno 			if (error)
8964294f337SSean Bruno 				break;
8974294f337SSean Bruno 			else
8984294f337SSean Bruno 				ixl_pf_qmgr_mark_queue_enabled(&vf->qtag, i, true);
8994294f337SSean Bruno 		}
9004294f337SSean Bruno 	}
9014294f337SSean Bruno 
9024294f337SSean Bruno 	/* Enable RX rings selected by the VF */
9034294f337SSean Bruno 	for (int i = 0; i < 32; i++) {
9044294f337SSean Bruno 		if ((1 << i) & select->rx_queues) {
9054294f337SSean Bruno 			/* Warn if queue is out of VF allocation range */
9061031d839SEric Joyner 			if (i >= vf->vsi.num_rx_queues) {
9074294f337SSean Bruno 				device_printf(pf->dev, "VF %d: RX ring %d is outside of VF VSI allocation!\n",
9084294f337SSean Bruno 				    vf->vf_num, i);
9094294f337SSean Bruno 				break;
9104294f337SSean Bruno 			}
9114294f337SSean Bruno 			/* Skip this queue if it hasn't been configured */
9124294f337SSean Bruno 			if (!ixl_pf_qmgr_is_queue_configured(&vf->qtag, i, false))
9134294f337SSean Bruno 				continue;
9144294f337SSean Bruno 			/* Warn if this queue is already marked as enabled */
9154294f337SSean Bruno 			if (ixl_pf_qmgr_is_queue_enabled(&vf->qtag, i, false))
91677c1fcecSEric Joyner 				ixl_dbg_iov(pf, "VF %d: RX ring %d is already enabled!\n",
9174294f337SSean Bruno 				    vf->vf_num, i);
9184294f337SSean Bruno 			error = ixl_enable_rx_ring(pf, &vf->qtag, i);
9194294f337SSean Bruno 			if (error)
9204294f337SSean Bruno 				break;
9214294f337SSean Bruno 			else
9224294f337SSean Bruno 				ixl_pf_qmgr_mark_queue_enabled(&vf->qtag, i, false);
9234294f337SSean Bruno 		}
9244294f337SSean Bruno 	}
9254294f337SSean Bruno 
9264294f337SSean Bruno 	if (error) {
927ceebc2f3SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_ENABLE_QUEUES,
9284294f337SSean Bruno 		    I40E_ERR_TIMEOUT);
9294294f337SSean Bruno 		return;
9304294f337SSean Bruno 	}
9314294f337SSean Bruno 
932ceebc2f3SEric Joyner 	ixl_send_vf_ack(pf, vf, VIRTCHNL_OP_ENABLE_QUEUES);
9334294f337SSean Bruno }
9344294f337SSean Bruno 
9354294f337SSean Bruno static void
ixl_vf_disable_queues_msg(struct ixl_pf * pf,struct ixl_vf * vf,void * msg,uint16_t msg_size)9364294f337SSean Bruno ixl_vf_disable_queues_msg(struct ixl_pf *pf, struct ixl_vf *vf,
9374294f337SSean Bruno     void *msg, uint16_t msg_size)
9384294f337SSean Bruno {
939ceebc2f3SEric Joyner 	struct virtchnl_queue_select *select;
9404294f337SSean Bruno 	int error = 0;
9414294f337SSean Bruno 
9424294f337SSean Bruno 	select = msg;
943b4a7ce06SEric Joyner 
9444294f337SSean Bruno 	if (select->vsi_id != vf->vsi.vsi_num ||
9454294f337SSean Bruno 	    select->rx_queues == 0 || select->tx_queues == 0) {
946ceebc2f3SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_DISABLE_QUEUES,
9474294f337SSean Bruno 		    I40E_ERR_PARAM);
9484294f337SSean Bruno 		return;
9494294f337SSean Bruno 	}
9504294f337SSean Bruno 
9514294f337SSean Bruno 	/* Disable TX rings selected by the VF */
9524294f337SSean Bruno 	for (int i = 0; i < 32; i++) {
9534294f337SSean Bruno 		if ((1 << i) & select->tx_queues) {
9544294f337SSean Bruno 			/* Warn if queue is out of VF allocation range */
9551031d839SEric Joyner 			if (i >= vf->vsi.num_tx_queues) {
9564294f337SSean Bruno 				device_printf(pf->dev, "VF %d: TX ring %d is outside of VF VSI allocation!\n",
9574294f337SSean Bruno 				    vf->vf_num, i);
9584294f337SSean Bruno 				break;
9594294f337SSean Bruno 			}
9604294f337SSean Bruno 			/* Skip this queue if it hasn't been configured */
9614294f337SSean Bruno 			if (!ixl_pf_qmgr_is_queue_configured(&vf->qtag, i, true))
9624294f337SSean Bruno 				continue;
9634294f337SSean Bruno 			/* Warn if this queue is already marked as disabled */
9644294f337SSean Bruno 			if (!ixl_pf_qmgr_is_queue_enabled(&vf->qtag, i, true)) {
96577c1fcecSEric Joyner 				ixl_dbg_iov(pf, "VF %d: TX ring %d is already disabled!\n",
9664294f337SSean Bruno 				    vf->vf_num, i);
9674294f337SSean Bruno 				continue;
9684294f337SSean Bruno 			}
9694294f337SSean Bruno 			error = ixl_disable_tx_ring(pf, &vf->qtag, i);
9704294f337SSean Bruno 			if (error)
9714294f337SSean Bruno 				break;
9724294f337SSean Bruno 			else
9734294f337SSean Bruno 				ixl_pf_qmgr_mark_queue_disabled(&vf->qtag, i, true);
9744294f337SSean Bruno 		}
9754294f337SSean Bruno 	}
9764294f337SSean Bruno 
9774294f337SSean Bruno 	/* Enable RX rings selected by the VF */
9784294f337SSean Bruno 	for (int i = 0; i < 32; i++) {
9794294f337SSean Bruno 		if ((1 << i) & select->rx_queues) {
9804294f337SSean Bruno 			/* Warn if queue is out of VF allocation range */
9811031d839SEric Joyner 			if (i >= vf->vsi.num_rx_queues) {
9824294f337SSean Bruno 				device_printf(pf->dev, "VF %d: RX ring %d is outside of VF VSI allocation!\n",
9834294f337SSean Bruno 				    vf->vf_num, i);
9844294f337SSean Bruno 				break;
9854294f337SSean Bruno 			}
9864294f337SSean Bruno 			/* Skip this queue if it hasn't been configured */
9874294f337SSean Bruno 			if (!ixl_pf_qmgr_is_queue_configured(&vf->qtag, i, false))
9884294f337SSean Bruno 				continue;
9894294f337SSean Bruno 			/* Warn if this queue is already marked as disabled */
9904294f337SSean Bruno 			if (!ixl_pf_qmgr_is_queue_enabled(&vf->qtag, i, false)) {
99177c1fcecSEric Joyner 				ixl_dbg_iov(pf, "VF %d: RX ring %d is already disabled!\n",
9924294f337SSean Bruno 				    vf->vf_num, i);
9934294f337SSean Bruno 				continue;
9944294f337SSean Bruno 			}
9954294f337SSean Bruno 			error = ixl_disable_rx_ring(pf, &vf->qtag, i);
9964294f337SSean Bruno 			if (error)
9974294f337SSean Bruno 				break;
9984294f337SSean Bruno 			else
9994294f337SSean Bruno 				ixl_pf_qmgr_mark_queue_disabled(&vf->qtag, i, false);
10004294f337SSean Bruno 		}
10014294f337SSean Bruno 	}
10024294f337SSean Bruno 
10034294f337SSean Bruno 	if (error) {
1004ceebc2f3SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_DISABLE_QUEUES,
10054294f337SSean Bruno 		    I40E_ERR_TIMEOUT);
10064294f337SSean Bruno 		return;
10074294f337SSean Bruno 	}
10084294f337SSean Bruno 
1009ceebc2f3SEric Joyner 	ixl_send_vf_ack(pf, vf, VIRTCHNL_OP_DISABLE_QUEUES);
10104294f337SSean Bruno }
10114294f337SSean Bruno 
10124294f337SSean Bruno static int
ixl_vf_mac_valid(struct ixl_vf * vf,const uint8_t * addr)10134294f337SSean Bruno ixl_vf_mac_valid(struct ixl_vf *vf, const uint8_t *addr)
10144294f337SSean Bruno {
10154294f337SSean Bruno 
1016b4a7ce06SEric Joyner 	if (ETHER_IS_ZERO(addr) || ETHER_IS_BROADCAST(addr))
10174294f337SSean Bruno 		return (EINVAL);
10184294f337SSean Bruno 
10194294f337SSean Bruno 	/*
10204294f337SSean Bruno 	 * If the VF is not allowed to change its MAC address, don't let it
10214294f337SSean Bruno 	 * set a MAC filter for an address that is not a multicast address and
10224294f337SSean Bruno 	 * is not its assigned MAC.
10234294f337SSean Bruno 	 */
10244294f337SSean Bruno 	if (!(vf->vf_flags & VF_FLAG_SET_MAC_CAP) &&
1025*7d4dceecSKrzysztof Galazka 	    !(ETHER_IS_MULTICAST(addr) || !ixl_ether_is_equal(addr, vf->mac)))
10264294f337SSean Bruno 		return (EPERM);
10274294f337SSean Bruno 
10284294f337SSean Bruno 	return (0);
10294294f337SSean Bruno }
10304294f337SSean Bruno 
10314294f337SSean Bruno static void
ixl_vf_add_mac_msg(struct ixl_pf * pf,struct ixl_vf * vf,void * msg,uint16_t msg_size)10324294f337SSean Bruno ixl_vf_add_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
10334294f337SSean Bruno     uint16_t msg_size)
10344294f337SSean Bruno {
1035ceebc2f3SEric Joyner 	struct virtchnl_ether_addr_list *addr_list;
1036ceebc2f3SEric Joyner 	struct virtchnl_ether_addr *addr;
10374294f337SSean Bruno 	struct ixl_vsi *vsi;
10384294f337SSean Bruno 	int i;
10394294f337SSean Bruno 
10404294f337SSean Bruno 	vsi = &vf->vsi;
10414294f337SSean Bruno 	addr_list = msg;
10424294f337SSean Bruno 
1043b4a7ce06SEric Joyner 	if (addr_list->vsi_id != vsi->vsi_num) {
1044ceebc2f3SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_ADD_ETH_ADDR,
10454294f337SSean Bruno 		    I40E_ERR_PARAM);
10464294f337SSean Bruno 		return;
10474294f337SSean Bruno 	}
10484294f337SSean Bruno 
10494294f337SSean Bruno 	for (i = 0; i < addr_list->num_elements; i++) {
10504294f337SSean Bruno 		if (ixl_vf_mac_valid(vf, addr_list->list[i].addr) != 0) {
10514294f337SSean Bruno 			i40e_send_vf_nack(pf, vf,
1052ceebc2f3SEric Joyner 			    VIRTCHNL_OP_ADD_ETH_ADDR, I40E_ERR_PARAM);
10534294f337SSean Bruno 			return;
10544294f337SSean Bruno 		}
10554294f337SSean Bruno 	}
10564294f337SSean Bruno 
10574294f337SSean Bruno 	for (i = 0; i < addr_list->num_elements; i++) {
10584294f337SSean Bruno 		addr = &addr_list->list[i];
10594294f337SSean Bruno 		ixl_add_filter(vsi, addr->addr, IXL_VLAN_ANY);
10604294f337SSean Bruno 	}
10614294f337SSean Bruno 
1062ceebc2f3SEric Joyner 	ixl_send_vf_ack(pf, vf, VIRTCHNL_OP_ADD_ETH_ADDR);
10634294f337SSean Bruno }
10644294f337SSean Bruno 
10654294f337SSean Bruno static void
ixl_vf_del_mac_msg(struct ixl_pf * pf,struct ixl_vf * vf,void * msg,uint16_t msg_size)10664294f337SSean Bruno ixl_vf_del_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
10674294f337SSean Bruno     uint16_t msg_size)
10684294f337SSean Bruno {
1069ceebc2f3SEric Joyner 	struct virtchnl_ether_addr_list *addr_list;
1070ceebc2f3SEric Joyner 	struct virtchnl_ether_addr *addr;
1071b4a7ce06SEric Joyner 	struct ixl_vsi *vsi;
10724294f337SSean Bruno 	int i;
10734294f337SSean Bruno 
1074b4a7ce06SEric Joyner 	vsi = &vf->vsi;
10754294f337SSean Bruno 	addr_list = msg;
10764294f337SSean Bruno 
1077b4a7ce06SEric Joyner 	if (addr_list->vsi_id != vsi->vsi_num) {
1078b4a7ce06SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_DEL_ETH_ADDR,
10794294f337SSean Bruno 		    I40E_ERR_PARAM);
10804294f337SSean Bruno 		return;
10814294f337SSean Bruno 	}
10824294f337SSean Bruno 
10834294f337SSean Bruno 	for (i = 0; i < addr_list->num_elements; i++) {
10844294f337SSean Bruno 		addr = &addr_list->list[i];
1085b4a7ce06SEric Joyner 		if (ETHER_IS_ZERO(addr->addr) || ETHER_IS_BROADCAST(addr->addr)) {
10864294f337SSean Bruno 			i40e_send_vf_nack(pf, vf,
1087b4a7ce06SEric Joyner 			    VIRTCHNL_OP_DEL_ETH_ADDR, I40E_ERR_PARAM);
10884294f337SSean Bruno 			return;
10894294f337SSean Bruno 		}
10904294f337SSean Bruno 	}
10914294f337SSean Bruno 
10924294f337SSean Bruno 	for (i = 0; i < addr_list->num_elements; i++) {
10934294f337SSean Bruno 		addr = &addr_list->list[i];
10944294f337SSean Bruno 		ixl_del_filter(&vf->vsi, addr->addr, IXL_VLAN_ANY);
10954294f337SSean Bruno 	}
10964294f337SSean Bruno 
1097ceebc2f3SEric Joyner 	ixl_send_vf_ack(pf, vf, VIRTCHNL_OP_DEL_ETH_ADDR);
10984294f337SSean Bruno }
10994294f337SSean Bruno 
11004294f337SSean Bruno static enum i40e_status_code
ixl_vf_enable_vlan_strip(struct ixl_pf * pf,struct ixl_vf * vf)11014294f337SSean Bruno ixl_vf_enable_vlan_strip(struct ixl_pf *pf, struct ixl_vf *vf)
11024294f337SSean Bruno {
11034294f337SSean Bruno 	struct i40e_vsi_context vsi_ctx;
11044294f337SSean Bruno 
11054294f337SSean Bruno 	vsi_ctx.seid = vf->vsi.seid;
11064294f337SSean Bruno 
11074294f337SSean Bruno 	bzero(&vsi_ctx.info, sizeof(vsi_ctx.info));
11084294f337SSean Bruno 	vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_VLAN_VALID);
11094294f337SSean Bruno 	vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
11104294f337SSean Bruno 	    I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
11114294f337SSean Bruno 	return (i40e_aq_update_vsi_params(&pf->hw, &vsi_ctx, NULL));
11124294f337SSean Bruno }
11134294f337SSean Bruno 
11144294f337SSean Bruno static void
ixl_vf_add_vlan_msg(struct ixl_pf * pf,struct ixl_vf * vf,void * msg,uint16_t msg_size)11154294f337SSean Bruno ixl_vf_add_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
11164294f337SSean Bruno     uint16_t msg_size)
11174294f337SSean Bruno {
1118ceebc2f3SEric Joyner 	struct virtchnl_vlan_filter_list *filter_list;
11194294f337SSean Bruno 	enum i40e_status_code code;
11204294f337SSean Bruno 	int i;
11214294f337SSean Bruno 
11224294f337SSean Bruno 	filter_list = msg;
1123b4a7ce06SEric Joyner 
1124b4a7ce06SEric Joyner 	if (filter_list->vsi_id != vf->vsi.vsi_num) {
1125ceebc2f3SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_ADD_VLAN,
11264294f337SSean Bruno 		    I40E_ERR_PARAM);
11274294f337SSean Bruno 		return;
11284294f337SSean Bruno 	}
11294294f337SSean Bruno 
11304294f337SSean Bruno 	if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) {
1131ceebc2f3SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_ADD_VLAN,
11324294f337SSean Bruno 		    I40E_ERR_PARAM);
11334294f337SSean Bruno 		return;
11344294f337SSean Bruno 	}
11354294f337SSean Bruno 
11364294f337SSean Bruno 	for (i = 0; i < filter_list->num_elements; i++) {
11374294f337SSean Bruno 		if (filter_list->vlan_id[i] > EVL_VLID_MASK) {
1138ceebc2f3SEric Joyner 			i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_ADD_VLAN,
11394294f337SSean Bruno 			    I40E_ERR_PARAM);
11404294f337SSean Bruno 			return;
11414294f337SSean Bruno 		}
11424294f337SSean Bruno 	}
11434294f337SSean Bruno 
11444294f337SSean Bruno 	code = ixl_vf_enable_vlan_strip(pf, vf);
11454294f337SSean Bruno 	if (code != I40E_SUCCESS) {
1146ceebc2f3SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_ADD_VLAN,
11474294f337SSean Bruno 		    I40E_ERR_PARAM);
11484294f337SSean Bruno 	}
11494294f337SSean Bruno 
11504294f337SSean Bruno 	for (i = 0; i < filter_list->num_elements; i++)
11514294f337SSean Bruno 		ixl_add_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]);
11524294f337SSean Bruno 
1153ceebc2f3SEric Joyner 	ixl_send_vf_ack(pf, vf, VIRTCHNL_OP_ADD_VLAN);
11544294f337SSean Bruno }
11554294f337SSean Bruno 
11564294f337SSean Bruno static void
ixl_vf_del_vlan_msg(struct ixl_pf * pf,struct ixl_vf * vf,void * msg,uint16_t msg_size)11574294f337SSean Bruno ixl_vf_del_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
11584294f337SSean Bruno     uint16_t msg_size)
11594294f337SSean Bruno {
1160ceebc2f3SEric Joyner 	struct virtchnl_vlan_filter_list *filter_list;
11614294f337SSean Bruno 	int i;
11624294f337SSean Bruno 
11634294f337SSean Bruno 	filter_list = msg;
1164b4a7ce06SEric Joyner 
1165b4a7ce06SEric Joyner 	if (filter_list->vsi_id != vf->vsi.vsi_num) {
1166ceebc2f3SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_DEL_VLAN,
11674294f337SSean Bruno 		    I40E_ERR_PARAM);
11684294f337SSean Bruno 		return;
11694294f337SSean Bruno 	}
11704294f337SSean Bruno 
11714294f337SSean Bruno 	for (i = 0; i < filter_list->num_elements; i++) {
11724294f337SSean Bruno 		if (filter_list->vlan_id[i] > EVL_VLID_MASK) {
1173ceebc2f3SEric Joyner 			i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_ADD_VLAN,
11744294f337SSean Bruno 			    I40E_ERR_PARAM);
11754294f337SSean Bruno 			return;
11764294f337SSean Bruno 		}
11774294f337SSean Bruno 	}
11784294f337SSean Bruno 
11794294f337SSean Bruno 	if (!(vf->vf_flags & VF_FLAG_VLAN_CAP)) {
1180ceebc2f3SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_ADD_VLAN,
11814294f337SSean Bruno 		    I40E_ERR_PARAM);
11824294f337SSean Bruno 		return;
11834294f337SSean Bruno 	}
11844294f337SSean Bruno 
11854294f337SSean Bruno 	for (i = 0; i < filter_list->num_elements; i++)
11864294f337SSean Bruno 		ixl_del_filter(&vf->vsi, vf->mac, filter_list->vlan_id[i]);
11874294f337SSean Bruno 
1188ceebc2f3SEric Joyner 	ixl_send_vf_ack(pf, vf, VIRTCHNL_OP_DEL_VLAN);
11894294f337SSean Bruno }
11904294f337SSean Bruno 
11914294f337SSean Bruno static void
ixl_vf_config_promisc_msg(struct ixl_pf * pf,struct ixl_vf * vf,void * msg,uint16_t msg_size)11924294f337SSean Bruno ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf,
11934294f337SSean Bruno     void *msg, uint16_t msg_size)
11944294f337SSean Bruno {
1195ceebc2f3SEric Joyner 	struct virtchnl_promisc_info *info;
119677c1fcecSEric Joyner 	struct i40e_hw *hw = &pf->hw;
11974294f337SSean Bruno 	enum i40e_status_code code;
11984294f337SSean Bruno 
11994294f337SSean Bruno 	if (!(vf->vf_flags & VF_FLAG_PROMISC_CAP)) {
120077c1fcecSEric Joyner 		/*
120177c1fcecSEric Joyner 		 * Do the same thing as the Linux PF driver -- lie to the VF
120277c1fcecSEric Joyner 		 */
120377c1fcecSEric Joyner 		ixl_send_vf_ack(pf, vf,
120477c1fcecSEric Joyner 		    VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE);
12054294f337SSean Bruno 		return;
12064294f337SSean Bruno 	}
12074294f337SSean Bruno 
12084294f337SSean Bruno 	info = msg;
12094294f337SSean Bruno 	if (info->vsi_id != vf->vsi.vsi_num) {
12104294f337SSean Bruno 		i40e_send_vf_nack(pf, vf,
1211ceebc2f3SEric Joyner 		    VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
12124294f337SSean Bruno 		return;
12134294f337SSean Bruno 	}
12144294f337SSean Bruno 
121577c1fcecSEric Joyner 	code = i40e_aq_set_vsi_unicast_promiscuous(hw, vf->vsi.seid,
1216ceebc2f3SEric Joyner 	    info->flags & FLAG_VF_UNICAST_PROMISC, NULL, TRUE);
12174294f337SSean Bruno 	if (code != I40E_SUCCESS) {
121877c1fcecSEric Joyner 		device_printf(pf->dev, "i40e_aq_set_vsi_unicast_promiscuous (seid %d) failed: status %s,"
121977c1fcecSEric Joyner 		    " error %s\n", vf->vsi.seid, i40e_stat_str(hw, code),
122077c1fcecSEric Joyner 		    i40e_aq_str(hw, hw->aq.asq_last_status));
12214294f337SSean Bruno 		i40e_send_vf_nack(pf, vf,
122277c1fcecSEric Joyner 		    VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
12234294f337SSean Bruno 		return;
12244294f337SSean Bruno 	}
12254294f337SSean Bruno 
122677c1fcecSEric Joyner 	code = i40e_aq_set_vsi_multicast_promiscuous(hw, vf->vsi.seid,
1227ceebc2f3SEric Joyner 	    info->flags & FLAG_VF_MULTICAST_PROMISC, NULL);
12284294f337SSean Bruno 	if (code != I40E_SUCCESS) {
122977c1fcecSEric Joyner 		device_printf(pf->dev, "i40e_aq_set_vsi_multicast_promiscuous (seid %d) failed: status %s,"
123077c1fcecSEric Joyner 		    " error %s\n", vf->vsi.seid, i40e_stat_str(hw, code),
123177c1fcecSEric Joyner 		    i40e_aq_str(hw, hw->aq.asq_last_status));
12324294f337SSean Bruno 		i40e_send_vf_nack(pf, vf,
123377c1fcecSEric Joyner 		    VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM);
12344294f337SSean Bruno 		return;
12354294f337SSean Bruno 	}
12364294f337SSean Bruno 
1237ceebc2f3SEric Joyner 	ixl_send_vf_ack(pf, vf, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE);
12384294f337SSean Bruno }
12394294f337SSean Bruno 
12404294f337SSean Bruno static void
ixl_vf_get_stats_msg(struct ixl_pf * pf,struct ixl_vf * vf,void * msg,uint16_t msg_size)12414294f337SSean Bruno ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
12424294f337SSean Bruno     uint16_t msg_size)
12434294f337SSean Bruno {
1244ceebc2f3SEric Joyner 	struct virtchnl_queue_select *queue;
12454294f337SSean Bruno 
12464294f337SSean Bruno 	queue = msg;
12474294f337SSean Bruno 	if (queue->vsi_id != vf->vsi.vsi_num) {
1248ceebc2f3SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_GET_STATS,
12494294f337SSean Bruno 		    I40E_ERR_PARAM);
12504294f337SSean Bruno 		return;
12514294f337SSean Bruno 	}
12524294f337SSean Bruno 
12534294f337SSean Bruno 	ixl_update_eth_stats(&vf->vsi);
12544294f337SSean Bruno 
1255ceebc2f3SEric Joyner 	ixl_send_vf_msg(pf, vf, VIRTCHNL_OP_GET_STATS,
12564294f337SSean Bruno 	    I40E_SUCCESS, &vf->vsi.eth_stats, sizeof(vf->vsi.eth_stats));
12574294f337SSean Bruno }
12584294f337SSean Bruno 
12594294f337SSean Bruno static void
ixl_vf_config_rss_key_msg(struct ixl_pf * pf,struct ixl_vf * vf,void * msg,uint16_t msg_size)12604294f337SSean Bruno ixl_vf_config_rss_key_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
12614294f337SSean Bruno     uint16_t msg_size)
12624294f337SSean Bruno {
12634294f337SSean Bruno 	struct i40e_hw *hw;
1264ceebc2f3SEric Joyner 	struct virtchnl_rss_key *key;
12654294f337SSean Bruno 	struct i40e_aqc_get_set_rss_key_data key_data;
12664294f337SSean Bruno 	enum i40e_status_code status;
12674294f337SSean Bruno 
12684294f337SSean Bruno 	hw = &pf->hw;
12694294f337SSean Bruno 
12704294f337SSean Bruno 	key = msg;
12714294f337SSean Bruno 
12724294f337SSean Bruno 	if (key->key_len > 52) {
12734294f337SSean Bruno 		device_printf(pf->dev, "VF %d: Key size in msg (%d) is greater than max key size (%d)\n",
12744294f337SSean Bruno 		    vf->vf_num, key->key_len, 52);
1275ceebc2f3SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_CONFIG_RSS_KEY,
12764294f337SSean Bruno 		    I40E_ERR_PARAM);
12774294f337SSean Bruno 		return;
12784294f337SSean Bruno 	}
12794294f337SSean Bruno 
12804294f337SSean Bruno 	if (key->vsi_id != vf->vsi.vsi_num) {
12814294f337SSean Bruno 		device_printf(pf->dev, "VF %d: VSI id in recvd message (%d) does not match expected id (%d)\n",
12824294f337SSean Bruno 		    vf->vf_num, key->vsi_id, vf->vsi.vsi_num);
1283ceebc2f3SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_CONFIG_RSS_KEY,
12844294f337SSean Bruno 		    I40E_ERR_PARAM);
12854294f337SSean Bruno 		return;
12864294f337SSean Bruno 	}
12874294f337SSean Bruno 
12884294f337SSean Bruno 	/* Fill out hash using MAC-dependent method */
12894294f337SSean Bruno 	if (hw->mac.type == I40E_MAC_X722) {
12904294f337SSean Bruno 		bzero(&key_data, sizeof(key_data));
12914294f337SSean Bruno 		if (key->key_len <= 40)
12924294f337SSean Bruno 			bcopy(key->key, key_data.standard_rss_key, key->key_len);
12934294f337SSean Bruno 		else {
12944294f337SSean Bruno 			bcopy(key->key, key_data.standard_rss_key, 40);
12954294f337SSean Bruno 			bcopy(&key->key[40], key_data.extended_hash_key, key->key_len - 40);
12964294f337SSean Bruno 		}
12974294f337SSean Bruno 		status = i40e_aq_set_rss_key(hw, vf->vsi.vsi_num, &key_data);
12984294f337SSean Bruno 		if (status) {
12994294f337SSean Bruno 			device_printf(pf->dev, "i40e_aq_set_rss_key status %s, error %s\n",
13004294f337SSean Bruno 			    i40e_stat_str(hw, status), i40e_aq_str(hw, hw->aq.asq_last_status));
1301ceebc2f3SEric Joyner 			i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_CONFIG_RSS_KEY,
13024294f337SSean Bruno 			    I40E_ERR_ADMIN_QUEUE_ERROR);
13034294f337SSean Bruno 			return;
13044294f337SSean Bruno 		}
13054294f337SSean Bruno 	} else {
13064294f337SSean Bruno 		for (int i = 0; i < (key->key_len / 4); i++)
1307ceebc2f3SEric Joyner 			i40e_write_rx_ctl(hw, I40E_VFQF_HKEY1(i, vf->vf_num), ((u32 *)key->key)[i]);
13084294f337SSean Bruno 	}
13094294f337SSean Bruno 
13104294f337SSean Bruno 	DDPRINTF(pf->dev, "VF %d: Programmed key starting with 0x%x ok!",
13114294f337SSean Bruno 	    vf->vf_num, key->key[0]);
13124294f337SSean Bruno 
1313ceebc2f3SEric Joyner 	ixl_send_vf_ack(pf, vf, VIRTCHNL_OP_CONFIG_RSS_KEY);
13144294f337SSean Bruno }
13154294f337SSean Bruno 
13164294f337SSean Bruno static void
ixl_vf_config_rss_lut_msg(struct ixl_pf * pf,struct ixl_vf * vf,void * msg,uint16_t msg_size)13174294f337SSean Bruno ixl_vf_config_rss_lut_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
13184294f337SSean Bruno     uint16_t msg_size)
13194294f337SSean Bruno {
13204294f337SSean Bruno 	struct i40e_hw *hw;
1321ceebc2f3SEric Joyner 	struct virtchnl_rss_lut *lut;
13224294f337SSean Bruno 	enum i40e_status_code status;
13234294f337SSean Bruno 
13244294f337SSean Bruno 	hw = &pf->hw;
13254294f337SSean Bruno 
13264294f337SSean Bruno 	lut = msg;
13274294f337SSean Bruno 
13284294f337SSean Bruno 	if (lut->lut_entries > 64) {
13294294f337SSean Bruno 		device_printf(pf->dev, "VF %d: # of LUT entries in msg (%d) is greater than max (%d)\n",
13304294f337SSean Bruno 		    vf->vf_num, lut->lut_entries, 64);
1331ceebc2f3SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_CONFIG_RSS_LUT,
13324294f337SSean Bruno 		    I40E_ERR_PARAM);
13334294f337SSean Bruno 		return;
13344294f337SSean Bruno 	}
13354294f337SSean Bruno 
13364294f337SSean Bruno 	if (lut->vsi_id != vf->vsi.vsi_num) {
13374294f337SSean Bruno 		device_printf(pf->dev, "VF %d: VSI id in recvd message (%d) does not match expected id (%d)\n",
13384294f337SSean Bruno 		    vf->vf_num, lut->vsi_id, vf->vsi.vsi_num);
1339ceebc2f3SEric Joyner 		i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_CONFIG_RSS_LUT,
13404294f337SSean Bruno 		    I40E_ERR_PARAM);
13414294f337SSean Bruno 		return;
13424294f337SSean Bruno 	}
13434294f337SSean Bruno 
13444294f337SSean Bruno 	/* Fill out LUT using MAC-dependent method */
13454294f337SSean Bruno 	if (hw->mac.type == I40E_MAC_X722) {
13464294f337SSean Bruno 		status = i40e_aq_set_rss_lut(hw, vf->vsi.vsi_num, false, lut->lut, lut->lut_entries);
13474294f337SSean Bruno 		if (status) {
13484294f337SSean Bruno 			device_printf(pf->dev, "i40e_aq_set_rss_lut status %s, error %s\n",
13494294f337SSean Bruno 			    i40e_stat_str(hw, status), i40e_aq_str(hw, hw->aq.asq_last_status));
1350ceebc2f3SEric Joyner 			i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_CONFIG_RSS_LUT,
13514294f337SSean Bruno 			    I40E_ERR_ADMIN_QUEUE_ERROR);
13524294f337SSean Bruno 			return;
13534294f337SSean Bruno 		}
13544294f337SSean Bruno 	} else {
13554294f337SSean Bruno 		for (int i = 0; i < (lut->lut_entries / 4); i++)
1356ceebc2f3SEric Joyner 			i40e_write_rx_ctl(hw, I40E_VFQF_HLUT1(i, vf->vf_num), ((u32 *)lut->lut)[i]);
13574294f337SSean Bruno 	}
13584294f337SSean Bruno 
13594294f337SSean Bruno 	DDPRINTF(pf->dev, "VF %d: Programmed LUT starting with 0x%x and length %d ok!",
13604294f337SSean Bruno 	    vf->vf_num, lut->lut[0], lut->lut_entries);
13614294f337SSean Bruno 
1362ceebc2f3SEric Joyner 	ixl_send_vf_ack(pf, vf, VIRTCHNL_OP_CONFIG_RSS_LUT);
13634294f337SSean Bruno }
13644294f337SSean Bruno 
13654294f337SSean Bruno static void
ixl_vf_set_rss_hena_msg(struct ixl_pf * pf,struct ixl_vf * vf,void * msg,uint16_t msg_size)13664294f337SSean Bruno ixl_vf_set_rss_hena_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg,
13674294f337SSean Bruno     uint16_t msg_size)
13684294f337SSean Bruno {
13694294f337SSean Bruno 	struct i40e_hw *hw;
1370ceebc2f3SEric Joyner 	struct virtchnl_rss_hena *hena;
13714294f337SSean Bruno 
13724294f337SSean Bruno 	hw = &pf->hw;
13734294f337SSean Bruno 	hena = msg;
13744294f337SSean Bruno 
13754294f337SSean Bruno 	/* Set HENA */
1376ceebc2f3SEric Joyner 	i40e_write_rx_ctl(hw, I40E_VFQF_HENA1(0, vf->vf_num), (u32)hena->hena);
1377ceebc2f3SEric Joyner 	i40e_write_rx_ctl(hw, I40E_VFQF_HENA1(1, vf->vf_num), (u32)(hena->hena >> 32));
13784294f337SSean Bruno 
13794294f337SSean Bruno 	DDPRINTF(pf->dev, "VF %d: Programmed HENA with 0x%016lx",
13804294f337SSean Bruno 	    vf->vf_num, hena->hena);
13814294f337SSean Bruno 
1382ceebc2f3SEric Joyner 	ixl_send_vf_ack(pf, vf, VIRTCHNL_OP_SET_RSS_HENA);
1383ceebc2f3SEric Joyner }
1384ceebc2f3SEric Joyner 
1385ceebc2f3SEric Joyner static void
ixl_notify_vf_link_state(struct ixl_pf * pf,struct ixl_vf * vf)1386ceebc2f3SEric Joyner ixl_notify_vf_link_state(struct ixl_pf *pf, struct ixl_vf *vf)
1387ceebc2f3SEric Joyner {
1388ceebc2f3SEric Joyner 	struct virtchnl_pf_event event;
1389ceebc2f3SEric Joyner 	struct i40e_hw *hw;
1390ceebc2f3SEric Joyner 
1391ceebc2f3SEric Joyner 	hw = &pf->hw;
1392ceebc2f3SEric Joyner 	event.event = VIRTCHNL_EVENT_LINK_CHANGE;
1393ceebc2f3SEric Joyner 	event.severity = PF_EVENT_SEVERITY_INFO;
1394ceebc2f3SEric Joyner 	event.event_data.link_event.link_status = pf->vsi.link_active;
1395ceebc2f3SEric Joyner 	event.event_data.link_event.link_speed =
1396b4a7ce06SEric Joyner 	    i40e_virtchnl_link_speed(hw->phy.link_info.link_speed);
1397ceebc2f3SEric Joyner 
1398ceebc2f3SEric Joyner 	ixl_send_vf_msg(pf, vf, VIRTCHNL_OP_EVENT, I40E_SUCCESS, &event,
1399ceebc2f3SEric Joyner 			sizeof(event));
1400ceebc2f3SEric Joyner }
1401ceebc2f3SEric Joyner 
1402ceebc2f3SEric Joyner void
ixl_broadcast_link_state(struct ixl_pf * pf)1403ceebc2f3SEric Joyner ixl_broadcast_link_state(struct ixl_pf *pf)
1404ceebc2f3SEric Joyner {
1405ceebc2f3SEric Joyner 	int i;
1406ceebc2f3SEric Joyner 
1407ceebc2f3SEric Joyner 	for (i = 0; i < pf->num_vfs; i++)
1408ceebc2f3SEric Joyner 		ixl_notify_vf_link_state(pf, &pf->vfs[i]);
14094294f337SSean Bruno }
14104294f337SSean Bruno 
14114294f337SSean Bruno void
ixl_handle_vf_msg(struct ixl_pf * pf,struct i40e_arq_event_info * event)14124294f337SSean Bruno ixl_handle_vf_msg(struct ixl_pf *pf, struct i40e_arq_event_info *event)
14134294f337SSean Bruno {
1414b4a7ce06SEric Joyner 	device_t dev = pf->dev;
14154294f337SSean Bruno 	struct ixl_vf *vf;
14164294f337SSean Bruno 	uint16_t vf_num, msg_size;
14174294f337SSean Bruno 	uint32_t opcode;
1418b4a7ce06SEric Joyner 	void *msg;
1419b4a7ce06SEric Joyner 	int err;
14204294f337SSean Bruno 
14214294f337SSean Bruno 	vf_num = le16toh(event->desc.retval) - pf->hw.func_caps.vf_base_id;
14224294f337SSean Bruno 	opcode = le32toh(event->desc.cookie_high);
14234294f337SSean Bruno 
14244294f337SSean Bruno 	if (vf_num >= pf->num_vfs) {
14254294f337SSean Bruno 		device_printf(pf->dev, "Got msg from illegal VF: %d\n", vf_num);
14264294f337SSean Bruno 		return;
14274294f337SSean Bruno 	}
14284294f337SSean Bruno 
14294294f337SSean Bruno 	vf = &pf->vfs[vf_num];
14304294f337SSean Bruno 	msg = event->msg_buf;
14314294f337SSean Bruno 	msg_size = event->msg_len;
14324294f337SSean Bruno 
14334294f337SSean Bruno 	I40E_VC_DEBUG(pf, ixl_vc_opcode_level(opcode),
14344294f337SSean Bruno 	    "Got msg %s(%d) from%sVF-%d of size %d\n",
14354294f337SSean Bruno 	    ixl_vc_opcode_str(opcode), opcode,
14364294f337SSean Bruno 	    (vf->vf_flags & VF_FLAG_ENABLED) ? " " : " disabled ",
14374294f337SSean Bruno 	    vf_num, msg_size);
14384294f337SSean Bruno 
1439b4a7ce06SEric Joyner 	/* Perform basic checks on the msg */
1440b4a7ce06SEric Joyner 	err = virtchnl_vc_validate_vf_msg(&vf->version, opcode, msg, msg_size);
1441b4a7ce06SEric Joyner 	if (err) {
1442b4a7ce06SEric Joyner 		device_printf(dev, "%s: Received invalid msg from VF-%d: opcode %d, len %d, error %d\n",
1443b4a7ce06SEric Joyner 		    __func__, vf->vf_num, opcode, msg_size, err);
1444b4a7ce06SEric Joyner 		i40e_send_vf_nack(pf, vf, opcode, I40E_ERR_PARAM);
1445b4a7ce06SEric Joyner 		return;
1446b4a7ce06SEric Joyner 	}
1447b4a7ce06SEric Joyner 
14484294f337SSean Bruno 	/* This must be a stray msg from a previously destroyed VF. */
14494294f337SSean Bruno 	if (!(vf->vf_flags & VF_FLAG_ENABLED))
14504294f337SSean Bruno 		return;
14514294f337SSean Bruno 
14524294f337SSean Bruno 	switch (opcode) {
1453ceebc2f3SEric Joyner 	case VIRTCHNL_OP_VERSION:
14544294f337SSean Bruno 		ixl_vf_version_msg(pf, vf, msg, msg_size);
14554294f337SSean Bruno 		break;
1456ceebc2f3SEric Joyner 	case VIRTCHNL_OP_RESET_VF:
14574294f337SSean Bruno 		ixl_vf_reset_msg(pf, vf, msg, msg_size);
14584294f337SSean Bruno 		break;
1459ceebc2f3SEric Joyner 	case VIRTCHNL_OP_GET_VF_RESOURCES:
14604294f337SSean Bruno 		ixl_vf_get_resources_msg(pf, vf, msg, msg_size);
1461ceebc2f3SEric Joyner 		/* Notify VF of link state after it obtains queues, as this is
1462ceebc2f3SEric Joyner 		 * the last thing it will do as part of initialization
1463ceebc2f3SEric Joyner 		 */
1464ceebc2f3SEric Joyner 		ixl_notify_vf_link_state(pf, vf);
14654294f337SSean Bruno 		break;
1466ceebc2f3SEric Joyner 	case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
14674294f337SSean Bruno 		ixl_vf_config_vsi_msg(pf, vf, msg, msg_size);
14684294f337SSean Bruno 		break;
1469ceebc2f3SEric Joyner 	case VIRTCHNL_OP_CONFIG_IRQ_MAP:
14704294f337SSean Bruno 		ixl_vf_config_irq_msg(pf, vf, msg, msg_size);
14714294f337SSean Bruno 		break;
1472ceebc2f3SEric Joyner 	case VIRTCHNL_OP_ENABLE_QUEUES:
14734294f337SSean Bruno 		ixl_vf_enable_queues_msg(pf, vf, msg, msg_size);
1474ceebc2f3SEric Joyner 		/* Notify VF of link state after it obtains queues, as this is
1475ceebc2f3SEric Joyner 		 * the last thing it will do as part of initialization
1476ceebc2f3SEric Joyner 		 */
1477ceebc2f3SEric Joyner 		ixl_notify_vf_link_state(pf, vf);
14784294f337SSean Bruno 		break;
1479ceebc2f3SEric Joyner 	case VIRTCHNL_OP_DISABLE_QUEUES:
14804294f337SSean Bruno 		ixl_vf_disable_queues_msg(pf, vf, msg, msg_size);
14814294f337SSean Bruno 		break;
1482ceebc2f3SEric Joyner 	case VIRTCHNL_OP_ADD_ETH_ADDR:
14834294f337SSean Bruno 		ixl_vf_add_mac_msg(pf, vf, msg, msg_size);
14844294f337SSean Bruno 		break;
1485ceebc2f3SEric Joyner 	case VIRTCHNL_OP_DEL_ETH_ADDR:
14864294f337SSean Bruno 		ixl_vf_del_mac_msg(pf, vf, msg, msg_size);
14874294f337SSean Bruno 		break;
1488ceebc2f3SEric Joyner 	case VIRTCHNL_OP_ADD_VLAN:
14894294f337SSean Bruno 		ixl_vf_add_vlan_msg(pf, vf, msg, msg_size);
14904294f337SSean Bruno 		break;
1491ceebc2f3SEric Joyner 	case VIRTCHNL_OP_DEL_VLAN:
14924294f337SSean Bruno 		ixl_vf_del_vlan_msg(pf, vf, msg, msg_size);
14934294f337SSean Bruno 		break;
1494ceebc2f3SEric Joyner 	case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
14954294f337SSean Bruno 		ixl_vf_config_promisc_msg(pf, vf, msg, msg_size);
14964294f337SSean Bruno 		break;
1497ceebc2f3SEric Joyner 	case VIRTCHNL_OP_GET_STATS:
14984294f337SSean Bruno 		ixl_vf_get_stats_msg(pf, vf, msg, msg_size);
14994294f337SSean Bruno 		break;
1500ceebc2f3SEric Joyner 	case VIRTCHNL_OP_CONFIG_RSS_KEY:
15014294f337SSean Bruno 		ixl_vf_config_rss_key_msg(pf, vf, msg, msg_size);
15024294f337SSean Bruno 		break;
1503ceebc2f3SEric Joyner 	case VIRTCHNL_OP_CONFIG_RSS_LUT:
15044294f337SSean Bruno 		ixl_vf_config_rss_lut_msg(pf, vf, msg, msg_size);
15054294f337SSean Bruno 		break;
1506ceebc2f3SEric Joyner 	case VIRTCHNL_OP_SET_RSS_HENA:
15074294f337SSean Bruno 		ixl_vf_set_rss_hena_msg(pf, vf, msg, msg_size);
15084294f337SSean Bruno 		break;
15094294f337SSean Bruno 
15104294f337SSean Bruno 	/* These two opcodes have been superseded by CONFIG_VSI_QUEUES. */
1511ceebc2f3SEric Joyner 	case VIRTCHNL_OP_CONFIG_TX_QUEUE:
1512ceebc2f3SEric Joyner 	case VIRTCHNL_OP_CONFIG_RX_QUEUE:
15134294f337SSean Bruno 	default:
15144294f337SSean Bruno 		i40e_send_vf_nack(pf, vf, opcode, I40E_ERR_NOT_IMPLEMENTED);
15154294f337SSean Bruno 		break;
15164294f337SSean Bruno 	}
15174294f337SSean Bruno }
15184294f337SSean Bruno 
15194294f337SSean Bruno /* Handle any VFs that have reset themselves via a Function Level Reset(FLR). */
15204294f337SSean Bruno void
ixl_handle_vflr(struct ixl_pf * pf)152177c1fcecSEric Joyner ixl_handle_vflr(struct ixl_pf *pf)
15224294f337SSean Bruno {
15234294f337SSean Bruno 	struct ixl_vf *vf;
15244294f337SSean Bruno 	struct i40e_hw *hw;
15254294f337SSean Bruno 	uint16_t global_vf_num;
15264294f337SSean Bruno 	uint32_t vflrstat_index, vflrstat_mask, vflrstat, icr0;
15274294f337SSean Bruno 	int i;
15284294f337SSean Bruno 
15294294f337SSean Bruno 	hw = &pf->hw;
15304294f337SSean Bruno 
153177c1fcecSEric Joyner 	ixl_dbg_iov(pf, "%s: begin\n", __func__);
153277c1fcecSEric Joyner 
153377c1fcecSEric Joyner 	/* Re-enable VFLR interrupt cause so driver doesn't miss a
153477c1fcecSEric Joyner 	 * reset interrupt for another VF */
153577c1fcecSEric Joyner 	icr0 = rd32(hw, I40E_PFINT_ICR0_ENA);
153677c1fcecSEric Joyner 	icr0 |= I40E_PFINT_ICR0_ENA_VFLR_MASK;
153777c1fcecSEric Joyner 	wr32(hw, I40E_PFINT_ICR0_ENA, icr0);
153877c1fcecSEric Joyner 	ixl_flush(hw);
153977c1fcecSEric Joyner 
15404294f337SSean Bruno 	for (i = 0; i < pf->num_vfs; i++) {
15414294f337SSean Bruno 		global_vf_num = hw->func_caps.vf_base_id + i;
15424294f337SSean Bruno 
15434294f337SSean Bruno 		vf = &pf->vfs[i];
15444294f337SSean Bruno 		if (!(vf->vf_flags & VF_FLAG_ENABLED))
15454294f337SSean Bruno 			continue;
15464294f337SSean Bruno 
15474294f337SSean Bruno 		vflrstat_index = IXL_GLGEN_VFLRSTAT_INDEX(global_vf_num);
15484294f337SSean Bruno 		vflrstat_mask = IXL_GLGEN_VFLRSTAT_MASK(global_vf_num);
15494294f337SSean Bruno 		vflrstat = rd32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index));
15504294f337SSean Bruno 		if (vflrstat & vflrstat_mask) {
15514294f337SSean Bruno 			wr32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index),
15524294f337SSean Bruno 			    vflrstat_mask);
15534294f337SSean Bruno 
155477c1fcecSEric Joyner 			ixl_dbg_iov(pf, "Reinitializing VF-%d\n", i);
15554294f337SSean Bruno 			ixl_reinit_vf(pf, vf);
155677c1fcecSEric Joyner 			ixl_dbg_iov(pf, "Reinitializing VF-%d done\n", i);
15574294f337SSean Bruno 		}
15584294f337SSean Bruno 	}
15594294f337SSean Bruno 
15604294f337SSean Bruno }
15614294f337SSean Bruno 
15624294f337SSean Bruno static int
ixl_adminq_err_to_errno(enum i40e_admin_queue_err err)15634294f337SSean Bruno ixl_adminq_err_to_errno(enum i40e_admin_queue_err err)
15644294f337SSean Bruno {
15654294f337SSean Bruno 
15664294f337SSean Bruno 	switch (err) {
15674294f337SSean Bruno 	case I40E_AQ_RC_EPERM:
15684294f337SSean Bruno 		return (EPERM);
15694294f337SSean Bruno 	case I40E_AQ_RC_ENOENT:
15704294f337SSean Bruno 		return (ENOENT);
15714294f337SSean Bruno 	case I40E_AQ_RC_ESRCH:
15724294f337SSean Bruno 		return (ESRCH);
15734294f337SSean Bruno 	case I40E_AQ_RC_EINTR:
15744294f337SSean Bruno 		return (EINTR);
15754294f337SSean Bruno 	case I40E_AQ_RC_EIO:
15764294f337SSean Bruno 		return (EIO);
15774294f337SSean Bruno 	case I40E_AQ_RC_ENXIO:
15784294f337SSean Bruno 		return (ENXIO);
15794294f337SSean Bruno 	case I40E_AQ_RC_E2BIG:
15804294f337SSean Bruno 		return (E2BIG);
15814294f337SSean Bruno 	case I40E_AQ_RC_EAGAIN:
15824294f337SSean Bruno 		return (EAGAIN);
15834294f337SSean Bruno 	case I40E_AQ_RC_ENOMEM:
15844294f337SSean Bruno 		return (ENOMEM);
15854294f337SSean Bruno 	case I40E_AQ_RC_EACCES:
15864294f337SSean Bruno 		return (EACCES);
15874294f337SSean Bruno 	case I40E_AQ_RC_EFAULT:
15884294f337SSean Bruno 		return (EFAULT);
15894294f337SSean Bruno 	case I40E_AQ_RC_EBUSY:
15904294f337SSean Bruno 		return (EBUSY);
15914294f337SSean Bruno 	case I40E_AQ_RC_EEXIST:
15924294f337SSean Bruno 		return (EEXIST);
15934294f337SSean Bruno 	case I40E_AQ_RC_EINVAL:
15944294f337SSean Bruno 		return (EINVAL);
15954294f337SSean Bruno 	case I40E_AQ_RC_ENOTTY:
15964294f337SSean Bruno 		return (ENOTTY);
15974294f337SSean Bruno 	case I40E_AQ_RC_ENOSPC:
15984294f337SSean Bruno 		return (ENOSPC);
15994294f337SSean Bruno 	case I40E_AQ_RC_ENOSYS:
16004294f337SSean Bruno 		return (ENOSYS);
16014294f337SSean Bruno 	case I40E_AQ_RC_ERANGE:
16024294f337SSean Bruno 		return (ERANGE);
16034294f337SSean Bruno 	case I40E_AQ_RC_EFLUSHED:
16044294f337SSean Bruno 		return (EINVAL);	/* No exact equivalent in errno.h */
16054294f337SSean Bruno 	case I40E_AQ_RC_BAD_ADDR:
16064294f337SSean Bruno 		return (EFAULT);
16074294f337SSean Bruno 	case I40E_AQ_RC_EMODE:
16084294f337SSean Bruno 		return (EPERM);
16094294f337SSean Bruno 	case I40E_AQ_RC_EFBIG:
16104294f337SSean Bruno 		return (EFBIG);
16114294f337SSean Bruno 	default:
16124294f337SSean Bruno 		return (EINVAL);
16134294f337SSean Bruno 	}
16144294f337SSean Bruno }
16154294f337SSean Bruno 
161677c1fcecSEric Joyner static int
ixl_config_pf_vsi_loopback(struct ixl_pf * pf,bool enable)161777c1fcecSEric Joyner ixl_config_pf_vsi_loopback(struct ixl_pf *pf, bool enable)
16184294f337SSean Bruno {
161977c1fcecSEric Joyner 	struct i40e_hw *hw = &pf->hw;
162077c1fcecSEric Joyner 	device_t dev = pf->dev;
162177c1fcecSEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
162277c1fcecSEric Joyner 	struct i40e_vsi_context	ctxt;
162377c1fcecSEric Joyner 	int error;
162477c1fcecSEric Joyner 
162577c1fcecSEric Joyner 	memset(&ctxt, 0, sizeof(ctxt));
162677c1fcecSEric Joyner 
162777c1fcecSEric Joyner 	ctxt.seid = vsi->seid;
162877c1fcecSEric Joyner 	if (pf->veb_seid != 0)
162977c1fcecSEric Joyner 		ctxt.uplink_seid = pf->veb_seid;
163077c1fcecSEric Joyner 	ctxt.pf_num = hw->pf_id;
163177c1fcecSEric Joyner 	ctxt.connection_type = IXL_VSI_DATA_PORT;
163277c1fcecSEric Joyner 
163377c1fcecSEric Joyner 	ctxt.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID);
163477c1fcecSEric Joyner 	ctxt.info.switch_id = (enable) ?
163577c1fcecSEric Joyner 	    htole16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB) : 0;
163677c1fcecSEric Joyner 
163777c1fcecSEric Joyner 	/* error is set to 0 on success */
163877c1fcecSEric Joyner 	error = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
163977c1fcecSEric Joyner 	if (error) {
164077c1fcecSEric Joyner 		device_printf(dev, "i40e_aq_update_vsi_params() failed, error %d,"
164177c1fcecSEric Joyner 		    " aq_error %d\n", error, hw->aq.asq_last_status);
164277c1fcecSEric Joyner 	}
164377c1fcecSEric Joyner 
164477c1fcecSEric Joyner 	return (error);
164577c1fcecSEric Joyner }
164677c1fcecSEric Joyner 
164777c1fcecSEric Joyner int
ixl_if_iov_init(if_ctx_t ctx,uint16_t num_vfs,const nvlist_t * params)164877c1fcecSEric Joyner ixl_if_iov_init(if_ctx_t ctx, uint16_t num_vfs, const nvlist_t *params)
164977c1fcecSEric Joyner {
165077c1fcecSEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
165177c1fcecSEric Joyner 	device_t dev = iflib_get_dev(ctx);
16524294f337SSean Bruno 	struct i40e_hw *hw;
16534294f337SSean Bruno 	struct ixl_vsi *pf_vsi;
16544294f337SSean Bruno 	enum i40e_status_code ret;
1655b4a7ce06SEric Joyner 	int error;
16564294f337SSean Bruno 
16574294f337SSean Bruno 	hw = &pf->hw;
16584294f337SSean Bruno 	pf_vsi = &pf->vsi;
16594294f337SSean Bruno 
1660ac2fffa4SPedro F. Giffuni 	pf->vfs = malloc(sizeof(struct ixl_vf) * num_vfs, M_IXL, M_NOWAIT |
1661ac2fffa4SPedro F. Giffuni 	    M_ZERO);
16624294f337SSean Bruno 	if (pf->vfs == NULL) {
16634294f337SSean Bruno 		error = ENOMEM;
16644294f337SSean Bruno 		goto fail;
16654294f337SSean Bruno 	}
16664294f337SSean Bruno 
166777c1fcecSEric Joyner 	/*
166877c1fcecSEric Joyner 	 * Add the VEB and ...
166977c1fcecSEric Joyner 	 * - do nothing: VEPA mode
167077c1fcecSEric Joyner 	 * - enable loopback mode on connected VSIs: VEB mode
167177c1fcecSEric Joyner 	 */
16724294f337SSean Bruno 	ret = i40e_aq_add_veb(hw, pf_vsi->uplink_seid, pf_vsi->seid,
16734294f337SSean Bruno 	    1, FALSE, &pf->veb_seid, FALSE, NULL);
16744294f337SSean Bruno 	if (ret != I40E_SUCCESS) {
167577c1fcecSEric Joyner 		error = hw->aq.asq_last_status;
167677c1fcecSEric Joyner 		device_printf(dev, "i40e_aq_add_veb failed; status %s error %s",
167777c1fcecSEric Joyner 		    i40e_stat_str(hw, ret), i40e_aq_str(hw, error));
16784294f337SSean Bruno 		goto fail;
16794294f337SSean Bruno 	}
168077c1fcecSEric Joyner 	if (pf->enable_vf_loopback)
168177c1fcecSEric Joyner 		ixl_config_pf_vsi_loopback(pf, true);
168277c1fcecSEric Joyner 
168377c1fcecSEric Joyner 	/*
168477c1fcecSEric Joyner 	 * Adding a VEB brings back the default MAC filter(s). Remove them,
168577c1fcecSEric Joyner 	 * and let the driver add the proper filters back.
168677c1fcecSEric Joyner 	 */
168777c1fcecSEric Joyner 	ixl_del_default_hw_filters(pf_vsi);
168877c1fcecSEric Joyner 	ixl_reconfigure_filters(pf_vsi);
16894294f337SSean Bruno 
16904294f337SSean Bruno 	pf->num_vfs = num_vfs;
16914294f337SSean Bruno 	return (0);
16924294f337SSean Bruno 
16934294f337SSean Bruno fail:
16944294f337SSean Bruno 	free(pf->vfs, M_IXL);
16954294f337SSean Bruno 	pf->vfs = NULL;
16964294f337SSean Bruno 	return (error);
16974294f337SSean Bruno }
16984294f337SSean Bruno 
16994294f337SSean Bruno void
ixl_if_iov_uninit(if_ctx_t ctx)170077c1fcecSEric Joyner ixl_if_iov_uninit(if_ctx_t ctx)
17014294f337SSean Bruno {
170277c1fcecSEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
17034294f337SSean Bruno 	struct i40e_hw *hw;
17044294f337SSean Bruno 	struct ixl_vf *vfs;
17054294f337SSean Bruno 	int i, num_vfs;
17064294f337SSean Bruno 
17074294f337SSean Bruno 	hw = &pf->hw;
17084294f337SSean Bruno 
17094294f337SSean Bruno 	for (i = 0; i < pf->num_vfs; i++) {
17104294f337SSean Bruno 		if (pf->vfs[i].vsi.seid != 0)
17114294f337SSean Bruno 			i40e_aq_delete_element(hw, pf->vfs[i].vsi.seid, NULL);
17124294f337SSean Bruno 		ixl_pf_qmgr_release(&pf->qmgr, &pf->vfs[i].qtag);
1713*7d4dceecSKrzysztof Galazka 		ixl_free_filters(&pf->vfs[i].vsi.ftl);
171477c1fcecSEric Joyner 		ixl_dbg_iov(pf, "VF %d: %d released\n",
17154294f337SSean Bruno 		    i, pf->vfs[i].qtag.num_allocated);
171677c1fcecSEric Joyner 		ixl_dbg_iov(pf, "Unallocated total: %d\n", ixl_pf_qmgr_get_num_free(&pf->qmgr));
17174294f337SSean Bruno 	}
17184294f337SSean Bruno 
17194294f337SSean Bruno 	if (pf->veb_seid != 0) {
17204294f337SSean Bruno 		i40e_aq_delete_element(hw, pf->veb_seid, NULL);
17214294f337SSean Bruno 		pf->veb_seid = 0;
17224294f337SSean Bruno 	}
172377c1fcecSEric Joyner 	/* Reset PF VSI loopback mode */
172477c1fcecSEric Joyner 	if (pf->enable_vf_loopback)
172577c1fcecSEric Joyner 		ixl_config_pf_vsi_loopback(pf, false);
17264294f337SSean Bruno 
17274294f337SSean Bruno 	vfs = pf->vfs;
17284294f337SSean Bruno 	num_vfs = pf->num_vfs;
17294294f337SSean Bruno 
17304294f337SSean Bruno 	pf->vfs = NULL;
17314294f337SSean Bruno 	pf->num_vfs = 0;
17324294f337SSean Bruno 
173377c1fcecSEric Joyner 	/* sysctl_ctx_free might sleep, but this func is called w/ an sx lock */
17344294f337SSean Bruno 	for (i = 0; i < num_vfs; i++)
1735b4a7ce06SEric Joyner 		sysctl_ctx_free(&vfs[i].vsi.sysctl_ctx);
17364294f337SSean Bruno 	free(vfs, M_IXL);
17374294f337SSean Bruno }
17384294f337SSean Bruno 
17394294f337SSean Bruno static int
ixl_vf_reserve_queues(struct ixl_pf * pf,struct ixl_vf * vf,int num_queues)17404294f337SSean Bruno ixl_vf_reserve_queues(struct ixl_pf *pf, struct ixl_vf *vf, int num_queues)
17414294f337SSean Bruno {
17424294f337SSean Bruno 	device_t dev = pf->dev;
17434294f337SSean Bruno 	int error;
17444294f337SSean Bruno 
17454294f337SSean Bruno 	/* Validate, and clamp value if invalid */
17464294f337SSean Bruno 	if (num_queues < 1 || num_queues > 16)
17474294f337SSean Bruno 		device_printf(dev, "Invalid num-queues (%d) for VF %d\n",
17484294f337SSean Bruno 		    num_queues, vf->vf_num);
17494294f337SSean Bruno 	if (num_queues < 1) {
17504294f337SSean Bruno 		device_printf(dev, "Setting VF %d num-queues to 1\n", vf->vf_num);
17514294f337SSean Bruno 		num_queues = 1;
17523f74c027SEric Joyner 	} else if (num_queues > IAVF_MAX_QUEUES) {
17533f74c027SEric Joyner 		device_printf(dev, "Setting VF %d num-queues to %d\n", vf->vf_num, IAVF_MAX_QUEUES);
17543f74c027SEric Joyner 		num_queues = IAVF_MAX_QUEUES;
17554294f337SSean Bruno 	}
17564294f337SSean Bruno 	error = ixl_pf_qmgr_alloc_scattered(&pf->qmgr, num_queues, &vf->qtag);
17574294f337SSean Bruno 	if (error) {
17584294f337SSean Bruno 		device_printf(dev, "Error allocating %d queues for VF %d's VSI\n",
17594294f337SSean Bruno 		    num_queues, vf->vf_num);
17604294f337SSean Bruno 		return (ENOSPC);
17614294f337SSean Bruno 	}
17624294f337SSean Bruno 
176377c1fcecSEric Joyner 	ixl_dbg_iov(pf, "VF %d: %d allocated, %d active\n",
17644294f337SSean Bruno 	    vf->vf_num, vf->qtag.num_allocated, vf->qtag.num_active);
176577c1fcecSEric Joyner 	ixl_dbg_iov(pf, "Unallocated total: %d\n", ixl_pf_qmgr_get_num_free(&pf->qmgr));
17664294f337SSean Bruno 
17674294f337SSean Bruno 	return (0);
17684294f337SSean Bruno }
17694294f337SSean Bruno 
17704294f337SSean Bruno int
ixl_if_iov_vf_add(if_ctx_t ctx,uint16_t vfnum,const nvlist_t * params)177177c1fcecSEric Joyner ixl_if_iov_vf_add(if_ctx_t ctx, uint16_t vfnum, const nvlist_t *params)
17724294f337SSean Bruno {
177377c1fcecSEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
1774b4a7ce06SEric Joyner 	char sysctl_name[IXL_QUEUE_NAME_LEN];
17754294f337SSean Bruno 	struct ixl_vf *vf;
17764294f337SSean Bruno 	const void *mac;
17774294f337SSean Bruno 	size_t size;
17784294f337SSean Bruno 	int error;
17794294f337SSean Bruno 	int vf_num_queues;
17804294f337SSean Bruno 
17814294f337SSean Bruno 	vf = &pf->vfs[vfnum];
17824294f337SSean Bruno 	vf->vf_num = vfnum;
17834294f337SSean Bruno 	vf->vsi.back = pf;
17844294f337SSean Bruno 	vf->vf_flags = VF_FLAG_ENABLED;
17854294f337SSean Bruno 
17864294f337SSean Bruno 	/* Reserve queue allocation from PF */
17874294f337SSean Bruno 	vf_num_queues = nvlist_get_number(params, "num-queues");
17884294f337SSean Bruno 	error = ixl_vf_reserve_queues(pf, vf, vf_num_queues);
17894294f337SSean Bruno 	if (error != 0)
17904294f337SSean Bruno 		goto out;
17914294f337SSean Bruno 
17924294f337SSean Bruno 	error = ixl_vf_setup_vsi(pf, vf);
17934294f337SSean Bruno 	if (error != 0)
17944294f337SSean Bruno 		goto out;
17954294f337SSean Bruno 
17964294f337SSean Bruno 	if (nvlist_exists_binary(params, "mac-addr")) {
17974294f337SSean Bruno 		mac = nvlist_get_binary(params, "mac-addr", &size);
17984294f337SSean Bruno 		bcopy(mac, vf->mac, ETHER_ADDR_LEN);
17994294f337SSean Bruno 
18004294f337SSean Bruno 		if (nvlist_get_bool(params, "allow-set-mac"))
18014294f337SSean Bruno 			vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
18024294f337SSean Bruno 	} else
18034294f337SSean Bruno 		/*
18044294f337SSean Bruno 		 * If the administrator has not specified a MAC address then
18054294f337SSean Bruno 		 * we must allow the VF to choose one.
18064294f337SSean Bruno 		 */
18074294f337SSean Bruno 		vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
18084294f337SSean Bruno 
18094294f337SSean Bruno 	if (nvlist_get_bool(params, "mac-anti-spoof"))
18104294f337SSean Bruno 		vf->vf_flags |= VF_FLAG_MAC_ANTI_SPOOF;
18114294f337SSean Bruno 
18124294f337SSean Bruno 	if (nvlist_get_bool(params, "allow-promisc"))
18134294f337SSean Bruno 		vf->vf_flags |= VF_FLAG_PROMISC_CAP;
18144294f337SSean Bruno 
18154294f337SSean Bruno 	vf->vf_flags |= VF_FLAG_VLAN_CAP;
18164294f337SSean Bruno 
181777c1fcecSEric Joyner 	/* VF needs to be reset before it can be used */
18184294f337SSean Bruno 	ixl_reset_vf(pf, vf);
18194294f337SSean Bruno out:
18204294f337SSean Bruno 	if (error == 0) {
18214294f337SSean Bruno 		snprintf(sysctl_name, sizeof(sysctl_name), "vf%d", vfnum);
1822b4a7ce06SEric Joyner 		ixl_vsi_add_sysctls(&vf->vsi, sysctl_name, false);
18234294f337SSean Bruno 	}
18244294f337SSean Bruno 
18254294f337SSean Bruno 	return (error);
18264294f337SSean Bruno }
18274294f337SSean Bruno 
1828