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