Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ixl/ixl_pf_iov.c
Show First 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | |||||
static void ixl_vf_add_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size); | static void ixl_vf_add_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size); | ||||
static void ixl_vf_del_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size); | static void ixl_vf_del_mac_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size); | ||||
static enum i40e_status_code ixl_vf_enable_vlan_strip(struct ixl_pf *pf, struct ixl_vf *vf); | static enum i40e_status_code ixl_vf_enable_vlan_strip(struct ixl_pf *pf, struct ixl_vf *vf); | ||||
static void ixl_vf_add_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size); | static void ixl_vf_add_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size); | ||||
static void ixl_vf_del_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size); | static void ixl_vf_del_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size); | ||||
static void ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size); | static void ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size); | ||||
static void ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size); | static void ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, uint16_t msg_size); | ||||
static int ixl_vf_reserve_queues(struct ixl_pf *pf, struct ixl_vf *vf, int num_queues); | static int ixl_vf_reserve_queues(struct ixl_pf *pf, struct ixl_vf *vf, int num_queues); | ||||
static int ixl_config_pf_vsi_loopback(struct ixl_pf *pf, bool enable); | |||||
static int ixl_adminq_err_to_errno(enum i40e_admin_queue_err err); | static int ixl_adminq_err_to_errno(enum i40e_admin_queue_err err); | ||||
/* | |||||
* TODO: Move pieces of this into iflib and call the rest in a handler? | |||||
* | |||||
* e.g. ixl_if_iov_set_schema | |||||
* | |||||
* It's odd to do pci_iov_detach() there while doing pci_iov_attach() | |||||
* in the driver. | |||||
*/ | |||||
void | void | ||||
ixl_initialize_sriov(struct ixl_pf *pf) | ixl_initialize_sriov(struct ixl_pf *pf) | ||||
{ | { | ||||
return; | |||||
#if 0 | |||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
nvlist_t *pf_schema, *vf_schema; | nvlist_t *pf_schema, *vf_schema; | ||||
int iov_error; | int iov_error; | ||||
pf_schema = pci_iov_schema_alloc_node(); | pf_schema = pci_iov_schema_alloc_node(); | ||||
vf_schema = pci_iov_schema_alloc_node(); | vf_schema = pci_iov_schema_alloc_node(); | ||||
pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL); | pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL); | ||||
pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof", | pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof", | ||||
IOV_SCHEMA_HASDEFAULT, TRUE); | IOV_SCHEMA_HASDEFAULT, TRUE); | ||||
pci_iov_schema_add_bool(vf_schema, "allow-set-mac", | pci_iov_schema_add_bool(vf_schema, "allow-set-mac", | ||||
IOV_SCHEMA_HASDEFAULT, FALSE); | IOV_SCHEMA_HASDEFAULT, FALSE); | ||||
pci_iov_schema_add_bool(vf_schema, "allow-promisc", | pci_iov_schema_add_bool(vf_schema, "allow-promisc", | ||||
IOV_SCHEMA_HASDEFAULT, FALSE); | IOV_SCHEMA_HASDEFAULT, FALSE); | ||||
pci_iov_schema_add_uint16(vf_schema, "num-queues", | pci_iov_schema_add_uint16(vf_schema, "num-queues", | ||||
IOV_SCHEMA_HASDEFAULT, | IOV_SCHEMA_HASDEFAULT, | ||||
max(1, hw->func_caps.num_msix_vectors_vf - 1) % IXLV_MAX_QUEUES); | max(1, min(hw->func_caps.num_msix_vectors_vf - 1, IXLV_MAX_QUEUES))); | ||||
iov_error = pci_iov_attach(dev, pf_schema, vf_schema); | iov_error = pci_iov_attach(dev, pf_schema, vf_schema); | ||||
if (iov_error != 0) { | if (iov_error != 0) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"Failed to initialize SR-IOV (error=%d)\n", | "Failed to initialize SR-IOV (error=%d)\n", | ||||
iov_error); | iov_error); | ||||
} else | } else | ||||
device_printf(dev, "SR-IOV ready\n"); | device_printf(dev, "SR-IOV ready\n"); | ||||
pf->vc_debug_lvl = 1; | |||||
#endif | |||||
} | } | ||||
/* | /* | ||||
* Allocate the VSI for a VF. | * Allocate the VSI for a VF. | ||||
*/ | */ | ||||
static int | static int | ||||
ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf) | ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf) | ||||
Show All 13 Lines | ixl_vf_alloc_vsi(struct ixl_pf *pf, struct ixl_vf *vf) | ||||
vsi_ctx.uplink_seid = pf->veb_seid; | vsi_ctx.uplink_seid = pf->veb_seid; | ||||
vsi_ctx.connection_type = IXL_VSI_DATA_PORT; | vsi_ctx.connection_type = IXL_VSI_DATA_PORT; | ||||
vsi_ctx.vf_num = hw->func_caps.vf_base_id + vf->vf_num; | vsi_ctx.vf_num = hw->func_caps.vf_base_id + vf->vf_num; | ||||
vsi_ctx.flags = I40E_AQ_VSI_TYPE_VF; | vsi_ctx.flags = I40E_AQ_VSI_TYPE_VF; | ||||
bzero(&vsi_ctx.info, sizeof(vsi_ctx.info)); | bzero(&vsi_ctx.info, sizeof(vsi_ctx.info)); | ||||
vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID); | vsi_ctx.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID); | ||||
vsi_ctx.info.switch_id = htole16(0); | if (pf->enable_vf_loopback) | ||||
vsi_ctx.info.switch_id = | |||||
htole16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB); | |||||
vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_SECURITY_VALID); | vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_SECURITY_VALID); | ||||
vsi_ctx.info.sec_flags = 0; | vsi_ctx.info.sec_flags = 0; | ||||
if (vf->vf_flags & VF_FLAG_MAC_ANTI_SPOOF) | if (vf->vf_flags & VF_FLAG_MAC_ANTI_SPOOF) | ||||
vsi_ctx.info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK; | vsi_ctx.info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK; | ||||
vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_VLAN_VALID); | vsi_ctx.info.valid_sections |= htole16(I40E_AQ_VSI_PROP_VLAN_VALID); | ||||
vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL | | vsi_ctx.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL | | ||||
Show All 13 Lines | vsi_ctx.info.tc_mapping[0] = htole16( | ||||
(0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) | | (0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) | | ||||
((fls(vf->qtag.num_allocated) - 1) << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)); | ((fls(vf->qtag.num_allocated) - 1) << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)); | ||||
code = i40e_aq_add_vsi(hw, &vsi_ctx, NULL); | code = i40e_aq_add_vsi(hw, &vsi_ctx, NULL); | ||||
if (code != I40E_SUCCESS) | if (code != I40E_SUCCESS) | ||||
return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); | return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); | ||||
vf->vsi.seid = vsi_ctx.seid; | vf->vsi.seid = vsi_ctx.seid; | ||||
vf->vsi.vsi_num = vsi_ctx.vsi_number; | vf->vsi.vsi_num = vsi_ctx.vsi_number; | ||||
// TODO: How to deal with num tx queues / num rx queues split? | |||||
// I don't think just assigning this variable is going to work | |||||
vf->vsi.num_rx_queues = vf->qtag.num_active; | vf->vsi.num_rx_queues = vf->qtag.num_active; | ||||
vf->vsi.num_tx_queues = vf->qtag.num_active; | vf->vsi.num_tx_queues = vf->qtag.num_active; | ||||
code = i40e_aq_get_vsi_params(hw, &vsi_ctx, NULL); | code = i40e_aq_get_vsi_params(hw, &vsi_ctx, NULL); | ||||
if (code != I40E_SUCCESS) | if (code != I40E_SUCCESS) | ||||
return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); | return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); | ||||
code = i40e_aq_config_vsi_bw_limit(hw, vf->vsi.seid, 0, 0, NULL); | code = i40e_aq_config_vsi_bw_limit(hw, vf->vsi.seid, 0, 0, NULL); | ||||
Show All 14 Lines | ixl_vf_setup_vsi(struct ixl_pf *pf, struct ixl_vf *vf) | ||||
int error; | int error; | ||||
hw = &pf->hw; | hw = &pf->hw; | ||||
error = ixl_vf_alloc_vsi(pf, vf); | error = ixl_vf_alloc_vsi(pf, vf); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
/* Let VF receive broadcast Ethernet frames */ | |||||
error = i40e_aq_set_vsi_broadcast(hw, vf->vsi.seid, TRUE, NULL); | |||||
if (error) | |||||
device_printf(pf->dev, "Error configuring VF VSI for broadcast promiscuous\n"); | |||||
/* Re-add VF's MAC/VLAN filters to its VSI */ | |||||
ixl_reconfigure_filters(&vf->vsi); | |||||
/* Reset stats? */ | |||||
vf->vsi.hw_filters_add = 0; | vf->vsi.hw_filters_add = 0; | ||||
vf->vsi.hw_filters_del = 0; | vf->vsi.hw_filters_del = 0; | ||||
// ixl_add_filter(&vf->vsi, ixl_bcast_addr, IXL_VLAN_ANY); | |||||
ixl_reconfigure_filters(&vf->vsi); | |||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
ixl_vf_map_vsi_queue(struct i40e_hw *hw, struct ixl_vf *vf, int qnum, | ixl_vf_map_vsi_queue(struct i40e_hw *hw, struct ixl_vf *vf, int qnum, | ||||
uint32_t val) | uint32_t val) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf) | ixl_reset_vf(struct ixl_pf *pf, struct ixl_vf *vf) | ||||
{ | { | ||||
struct i40e_hw *hw; | struct i40e_hw *hw; | ||||
uint32_t vfrtrig; | uint32_t vfrtrig; | ||||
hw = &pf->hw; | hw = &pf->hw; | ||||
ixl_dbg(pf, IXL_DBG_IOV, "Resetting VF-%d\n", vf->vf_num); | |||||
vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num)); | vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num)); | ||||
vfrtrig |= I40E_VPGEN_VFRTRIG_VFSWR_MASK; | vfrtrig |= I40E_VPGEN_VFRTRIG_VFSWR_MASK; | ||||
wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig); | wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig); | ||||
ixl_flush(hw); | ixl_flush(hw); | ||||
ixl_reinit_vf(pf, vf); | ixl_reinit_vf(pf, vf); | ||||
ixl_dbg(pf, IXL_DBG_IOV, "Resetting VF-%d done.\n", vf->vf_num); | |||||
} | } | ||||
static void | static void | ||||
ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf) | ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf) | ||||
{ | { | ||||
struct i40e_hw *hw; | struct i40e_hw *hw; | ||||
uint32_t vfrstat, vfrtrig; | uint32_t vfrstat, vfrtrig; | ||||
int i, error; | int i, error; | ||||
Show All 19 Lines | ixl_reinit_vf(struct ixl_pf *pf, struct ixl_vf *vf) | ||||
wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), VIRTCHNL_VFR_COMPLETED); | wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), VIRTCHNL_VFR_COMPLETED); | ||||
vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num)); | vfrtrig = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num)); | ||||
vfrtrig &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK; | vfrtrig &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK; | ||||
wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig); | wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_num), vfrtrig); | ||||
if (vf->vsi.seid != 0) | if (vf->vsi.seid != 0) | ||||
ixl_disable_rings(&vf->vsi); | ixl_disable_rings(pf, &vf->vsi, &vf->qtag); | ||||
ixl_vf_release_resources(pf, vf); | ixl_vf_release_resources(pf, vf); | ||||
ixl_vf_setup_vsi(pf, vf); | ixl_vf_setup_vsi(pf, vf); | ||||
ixl_vf_map_queues(pf, vf); | ixl_vf_map_queues(pf, vf); | ||||
wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), VIRTCHNL_VFR_VFACTIVE); | wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_num), VIRTCHNL_VFR_VFACTIVE); | ||||
ixl_flush(hw); | ixl_flush(hw); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 219 Lines • ▼ Show 20 Lines | ixl_vf_config_rx_queue(struct ixl_pf *pf, struct ixl_vf *vf, | ||||
rxq.crcstrip = 1; | rxq.crcstrip = 1; | ||||
rxq.l2tsel = 1; | rxq.l2tsel = 1; | ||||
rxq.rxmax = info->max_pkt_size; | rxq.rxmax = info->max_pkt_size; | ||||
rxq.tphrdesc_ena = 1; | rxq.tphrdesc_ena = 1; | ||||
rxq.tphwdesc_ena = 1; | rxq.tphwdesc_ena = 1; | ||||
rxq.tphdata_ena = 1; | rxq.tphdata_ena = 1; | ||||
rxq.tphhead_ena = 1; | rxq.tphhead_ena = 1; | ||||
rxq.lrxqthresh = 2; | rxq.lrxqthresh = 1; | ||||
rxq.prefena = 1; | rxq.prefena = 1; | ||||
status = i40e_set_lan_rx_queue_context(hw, global_queue_num, &rxq); | status = i40e_set_lan_rx_queue_context(hw, global_queue_num, &rxq); | ||||
if (status != I40E_SUCCESS) | if (status != I40E_SUCCESS) | ||||
return (EINVAL); | return (EINVAL); | ||||
ixl_pf_qmgr_mark_queue_configured(&vf->qtag, info->queue_id, false); | ixl_pf_qmgr_mark_queue_configured(&vf->qtag, info->queue_id, false); | ||||
▲ Show 20 Lines • Show All 337 Lines • ▼ Show 20 Lines | if ((1 << i) & select->tx_queues) { | ||||
vf->vf_num, i); | vf->vf_num, i); | ||||
break; | break; | ||||
} | } | ||||
/* Skip this queue if it hasn't been configured */ | /* Skip this queue if it hasn't been configured */ | ||||
if (!ixl_pf_qmgr_is_queue_configured(&vf->qtag, i, true)) | if (!ixl_pf_qmgr_is_queue_configured(&vf->qtag, i, true)) | ||||
continue; | continue; | ||||
/* Warn if this queue is already marked as disabled */ | /* Warn if this queue is already marked as disabled */ | ||||
if (!ixl_pf_qmgr_is_queue_enabled(&vf->qtag, i, true)) { | if (!ixl_pf_qmgr_is_queue_enabled(&vf->qtag, i, true)) { | ||||
device_printf(pf->dev, "VF %d: TX ring %d is already disabled!\n", | ixl_dbg(pf, IXL_DBG_IOV, "VF %d: TX ring %d is already disabled!\n", | ||||
vf->vf_num, i); | vf->vf_num, i); | ||||
continue; | continue; | ||||
} | } | ||||
error = ixl_disable_tx_ring(pf, &vf->qtag, i); | error = ixl_disable_tx_ring(pf, &vf->qtag, i); | ||||
if (error) | if (error) | ||||
break; | break; | ||||
else | else | ||||
ixl_pf_qmgr_mark_queue_disabled(&vf->qtag, i, true); | ixl_pf_qmgr_mark_queue_disabled(&vf->qtag, i, true); | ||||
Show All 9 Lines | if ((1 << i) & select->rx_queues) { | ||||
vf->vf_num, i); | vf->vf_num, i); | ||||
break; | break; | ||||
} | } | ||||
/* Skip this queue if it hasn't been configured */ | /* Skip this queue if it hasn't been configured */ | ||||
if (!ixl_pf_qmgr_is_queue_configured(&vf->qtag, i, false)) | if (!ixl_pf_qmgr_is_queue_configured(&vf->qtag, i, false)) | ||||
continue; | continue; | ||||
/* Warn if this queue is already marked as disabled */ | /* Warn if this queue is already marked as disabled */ | ||||
if (!ixl_pf_qmgr_is_queue_enabled(&vf->qtag, i, false)) { | if (!ixl_pf_qmgr_is_queue_enabled(&vf->qtag, i, false)) { | ||||
device_printf(pf->dev, "VF %d: RX ring %d is already disabled!\n", | ixl_dbg(pf, IXL_DBG_IOV, "VF %d: RX ring %d is already disabled!\n", | ||||
vf->vf_num, i); | vf->vf_num, i); | ||||
continue; | continue; | ||||
} | } | ||||
error = ixl_disable_rx_ring(pf, &vf->qtag, i); | error = ixl_disable_rx_ring(pf, &vf->qtag, i); | ||||
if (error) | if (error) | ||||
break; | break; | ||||
else | else | ||||
ixl_pf_qmgr_mark_queue_disabled(&vf->qtag, i, false); | ixl_pf_qmgr_mark_queue_disabled(&vf->qtag, i, false); | ||||
▲ Show 20 Lines • Show All 246 Lines • ▼ Show 20 Lines | ixl_vf_del_vlan_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, | ||||
ixl_send_vf_ack(pf, vf, VIRTCHNL_OP_DEL_VLAN); | ixl_send_vf_ack(pf, vf, VIRTCHNL_OP_DEL_VLAN); | ||||
} | } | ||||
static void | static void | ||||
ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf, | ixl_vf_config_promisc_msg(struct ixl_pf *pf, struct ixl_vf *vf, | ||||
void *msg, uint16_t msg_size) | void *msg, uint16_t msg_size) | ||||
{ | { | ||||
struct virtchnl_promisc_info *info; | struct virtchnl_promisc_info *info; | ||||
struct i40e_hw *hw = &pf->hw; | |||||
enum i40e_status_code code; | enum i40e_status_code code; | ||||
if (msg_size != sizeof(*info)) { | if (msg_size != sizeof(*info)) { | ||||
i40e_send_vf_nack(pf, vf, | i40e_send_vf_nack(pf, vf, | ||||
VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); | VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); | ||||
return; | return; | ||||
} | } | ||||
if (!(vf->vf_flags & VF_FLAG_PROMISC_CAP)) { | if (!(vf->vf_flags & VF_FLAG_PROMISC_CAP)) { | ||||
/* | |||||
* Do the same thing as the Linux PF driver -- lie to the VF | |||||
*/ | |||||
i40e_send_vf_nack(pf, vf, | i40e_send_vf_nack(pf, vf, | ||||
VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); | VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_SUCCESS); | ||||
return; | return; | ||||
} | } | ||||
info = msg; | info = msg; | ||||
if (info->vsi_id != vf->vsi.vsi_num) { | if (info->vsi_id != vf->vsi.vsi_num) { | ||||
i40e_send_vf_nack(pf, vf, | i40e_send_vf_nack(pf, vf, | ||||
VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); | VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); | ||||
return; | return; | ||||
} | } | ||||
code = i40e_aq_set_vsi_unicast_promiscuous(&pf->hw, info->vsi_id, | code = i40e_aq_set_vsi_unicast_promiscuous(hw, vf->vsi.seid, | ||||
info->flags & FLAG_VF_UNICAST_PROMISC, NULL, TRUE); | info->flags & FLAG_VF_UNICAST_PROMISC, NULL, TRUE); | ||||
if (code != I40E_SUCCESS) { | if (code != I40E_SUCCESS) { | ||||
device_printf(pf->dev, "i40e_aq_set_vsi_unicast_promiscuous (seid %d) failed: status %s," | |||||
" error %s\n", vf->vsi.seid, i40e_stat_str(hw, code), | |||||
i40e_aq_str(hw, hw->aq.asq_last_status)); | |||||
i40e_send_vf_nack(pf, vf, | i40e_send_vf_nack(pf, vf, | ||||
VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code); | VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); | ||||
return; | return; | ||||
} | } | ||||
code = i40e_aq_set_vsi_multicast_promiscuous(&pf->hw, info->vsi_id, | code = i40e_aq_set_vsi_multicast_promiscuous(hw, vf->vsi.seid, | ||||
info->flags & FLAG_VF_MULTICAST_PROMISC, NULL); | info->flags & FLAG_VF_MULTICAST_PROMISC, NULL); | ||||
if (code != I40E_SUCCESS) { | if (code != I40E_SUCCESS) { | ||||
device_printf(pf->dev, "i40e_aq_set_vsi_multicast_promiscuous (seid %d) failed: status %s," | |||||
" error %s\n", vf->vsi.seid, i40e_stat_str(hw, code), | |||||
i40e_aq_str(hw, hw->aq.asq_last_status)); | |||||
i40e_send_vf_nack(pf, vf, | i40e_send_vf_nack(pf, vf, | ||||
VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, code); | VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, I40E_ERR_PARAM); | ||||
return; | return; | ||||
} | } | ||||
ixl_send_vf_ack(pf, vf, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE); | ixl_send_vf_ack(pf, vf, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE); | ||||
} | } | ||||
static void | static void | ||||
ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, | ixl_vf_get_stats_msg(struct ixl_pf *pf, struct ixl_vf *vf, void *msg, | ||||
▲ Show 20 Lines • Show All 285 Lines • ▼ Show 20 Lines | ixl_handle_vf_msg(struct ixl_pf *pf, struct i40e_arq_event_info *event) | ||||
default: | default: | ||||
i40e_send_vf_nack(pf, vf, opcode, I40E_ERR_NOT_IMPLEMENTED); | i40e_send_vf_nack(pf, vf, opcode, I40E_ERR_NOT_IMPLEMENTED); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* Handle any VFs that have reset themselves via a Function Level Reset(FLR). */ | /* Handle any VFs that have reset themselves via a Function Level Reset(FLR). */ | ||||
void | void | ||||
ixl_handle_vflr(void *arg, int pending) | ixl_handle_vflr(struct ixl_pf *pf) | ||||
{ | { | ||||
struct ixl_pf *pf; | |||||
struct ixl_vf *vf; | struct ixl_vf *vf; | ||||
struct i40e_hw *hw; | struct i40e_hw *hw; | ||||
uint16_t global_vf_num; | uint16_t global_vf_num; | ||||
uint32_t vflrstat_index, vflrstat_mask, vflrstat, icr0; | uint32_t vflrstat_index, vflrstat_mask, vflrstat, icr0; | ||||
int i; | int i; | ||||
pf = arg; | |||||
hw = &pf->hw; | hw = &pf->hw; | ||||
/* TODO: May need to lock this */ | ixl_dbg(pf, IXL_DBG_IOV, "%s: begin\n", __func__); | ||||
/* Re-enable VFLR interrupt cause so driver doesn't miss a | |||||
* reset interrupt for another VF */ | |||||
icr0 = rd32(hw, I40E_PFINT_ICR0_ENA); | |||||
icr0 |= I40E_PFINT_ICR0_ENA_VFLR_MASK; | |||||
wr32(hw, I40E_PFINT_ICR0_ENA, icr0); | |||||
ixl_flush(hw); | |||||
for (i = 0; i < pf->num_vfs; i++) { | for (i = 0; i < pf->num_vfs; i++) { | ||||
global_vf_num = hw->func_caps.vf_base_id + i; | global_vf_num = hw->func_caps.vf_base_id + i; | ||||
vf = &pf->vfs[i]; | vf = &pf->vfs[i]; | ||||
if (!(vf->vf_flags & VF_FLAG_ENABLED)) | if (!(vf->vf_flags & VF_FLAG_ENABLED)) | ||||
continue; | continue; | ||||
vflrstat_index = IXL_GLGEN_VFLRSTAT_INDEX(global_vf_num); | vflrstat_index = IXL_GLGEN_VFLRSTAT_INDEX(global_vf_num); | ||||
vflrstat_mask = IXL_GLGEN_VFLRSTAT_MASK(global_vf_num); | vflrstat_mask = IXL_GLGEN_VFLRSTAT_MASK(global_vf_num); | ||||
vflrstat = rd32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index)); | vflrstat = rd32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index)); | ||||
if (vflrstat & vflrstat_mask) { | if (vflrstat & vflrstat_mask) { | ||||
wr32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index), | wr32(hw, I40E_GLGEN_VFLRSTAT(vflrstat_index), | ||||
vflrstat_mask); | vflrstat_mask); | ||||
ixl_dbg(pf, IXL_DBG_IOV, "Reinitializing VF-%d\n", i); | |||||
ixl_reinit_vf(pf, vf); | ixl_reinit_vf(pf, vf); | ||||
ixl_dbg(pf, IXL_DBG_IOV, "Reinitializing VF-%d done\n", i); | |||||
} | } | ||||
} | } | ||||
atomic_clear_32(&pf->state, IXL_PF_STATE_VF_RESET_REQ); | |||||
icr0 = rd32(hw, I40E_PFINT_ICR0_ENA); | |||||
icr0 |= I40E_PFINT_ICR0_ENA_VFLR_MASK; | |||||
wr32(hw, I40E_PFINT_ICR0_ENA, icr0); | |||||
ixl_flush(hw); | |||||
// IXL_PF_UNLOCK() | |||||
} | } | ||||
static int | static int | ||||
ixl_adminq_err_to_errno(enum i40e_admin_queue_err err) | ixl_adminq_err_to_errno(enum i40e_admin_queue_err err) | ||||
{ | { | ||||
switch (err) { | switch (err) { | ||||
case I40E_AQ_RC_EPERM: | case I40E_AQ_RC_EPERM: | ||||
Show All 40 Lines | case I40E_AQ_RC_EMODE: | ||||
return (EPERM); | return (EPERM); | ||||
case I40E_AQ_RC_EFBIG: | case I40E_AQ_RC_EFBIG: | ||||
return (EFBIG); | return (EFBIG); | ||||
default: | default: | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
} | } | ||||
static int | |||||
ixl_config_pf_vsi_loopback(struct ixl_pf *pf, bool enable) | |||||
{ | |||||
struct i40e_hw *hw = &pf->hw; | |||||
device_t dev = pf->dev; | |||||
struct ixl_vsi *vsi = &pf->vsi; | |||||
struct i40e_vsi_context ctxt; | |||||
int error; | |||||
memset(&ctxt, 0, sizeof(ctxt)); | |||||
ctxt.seid = vsi->seid; | |||||
if (pf->veb_seid != 0) | |||||
ctxt.uplink_seid = pf->veb_seid; | |||||
ctxt.pf_num = hw->pf_id; | |||||
ctxt.connection_type = IXL_VSI_DATA_PORT; | |||||
ctxt.info.valid_sections = htole16(I40E_AQ_VSI_PROP_SWITCH_VALID); | |||||
ctxt.info.switch_id = (enable) ? | |||||
htole16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB) : 0; | |||||
/* error is set to 0 on success */ | |||||
error = i40e_aq_update_vsi_params(hw, &ctxt, NULL); | |||||
if (error) { | |||||
device_printf(dev, "i40e_aq_update_vsi_params() failed, error %d," | |||||
" aq_error %d\n", error, hw->aq.asq_last_status); | |||||
} | |||||
return (error); | |||||
} | |||||
int | int | ||||
ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params) | ixl_if_iov_init(if_ctx_t ctx, uint16_t num_vfs, const nvlist_t *params) | ||||
{ | { | ||||
struct ixl_pf *pf; | struct ixl_pf *pf = iflib_get_softc(ctx); | ||||
device_t dev = iflib_get_dev(ctx); | |||||
struct i40e_hw *hw; | struct i40e_hw *hw; | ||||
struct ixl_vsi *pf_vsi; | struct ixl_vsi *pf_vsi; | ||||
enum i40e_status_code ret; | enum i40e_status_code ret; | ||||
int i, error; | int i, error; | ||||
pf = device_get_softc(dev); | |||||
hw = &pf->hw; | hw = &pf->hw; | ||||
pf_vsi = &pf->vsi; | pf_vsi = &pf->vsi; | ||||
//IXL_PF_LOCK(pf); | |||||
pf->vfs = malloc(sizeof(struct ixl_vf) * num_vfs, M_IXL, M_NOWAIT | | pf->vfs = malloc(sizeof(struct ixl_vf) * num_vfs, M_IXL, M_NOWAIT | | ||||
M_ZERO); | M_ZERO); | ||||
if (pf->vfs == NULL) { | if (pf->vfs == NULL) { | ||||
error = ENOMEM; | error = ENOMEM; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
for (i = 0; i < num_vfs; i++) | for (i = 0; i < num_vfs; i++) | ||||
sysctl_ctx_init(&pf->vfs[i].ctx); | sysctl_ctx_init(&pf->vfs[i].ctx); | ||||
/* | |||||
* Add the VEB and ... | |||||
* - do nothing: VEPA mode | |||||
* - enable loopback mode on connected VSIs: VEB mode | |||||
*/ | |||||
ret = i40e_aq_add_veb(hw, pf_vsi->uplink_seid, pf_vsi->seid, | ret = i40e_aq_add_veb(hw, pf_vsi->uplink_seid, pf_vsi->seid, | ||||
1, FALSE, &pf->veb_seid, FALSE, NULL); | 1, FALSE, &pf->veb_seid, FALSE, NULL); | ||||
if (ret != I40E_SUCCESS) { | if (ret != I40E_SUCCESS) { | ||||
error = ixl_adminq_err_to_errno(hw->aq.asq_last_status); | error = hw->aq.asq_last_status; | ||||
device_printf(dev, "add_veb failed; code=%d error=%d", ret, | device_printf(dev, "i40e_aq_add_veb failed; status %s error %s", | ||||
error); | i40e_stat_str(hw, ret), i40e_aq_str(hw, error)); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
if (pf->enable_vf_loopback) | |||||
ixl_config_pf_vsi_loopback(pf, true); | |||||
pf->num_vfs = num_vfs; | pf->num_vfs = num_vfs; | ||||
//IXL_PF_UNLOCK(pf); | |||||
return (0); | return (0); | ||||
fail: | fail: | ||||
free(pf->vfs, M_IXL); | free(pf->vfs, M_IXL); | ||||
pf->vfs = NULL; | pf->vfs = NULL; | ||||
//IXL_PF_UNLOCK(pf); | |||||
return (error); | return (error); | ||||
} | } | ||||
void | void | ||||
ixl_iov_uninit(device_t dev) | ixl_if_iov_uninit(if_ctx_t ctx) | ||||
{ | { | ||||
struct ixl_pf *pf; | struct ixl_pf *pf = iflib_get_softc(ctx); | ||||
struct i40e_hw *hw; | struct i40e_hw *hw; | ||||
struct ixl_vsi *vsi; | struct ixl_vsi *vsi; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct ixl_vf *vfs; | struct ixl_vf *vfs; | ||||
int i, num_vfs; | int i, num_vfs; | ||||
pf = device_get_softc(dev); | |||||
hw = &pf->hw; | hw = &pf->hw; | ||||
vsi = &pf->vsi; | vsi = &pf->vsi; | ||||
ifp = vsi->ifp; | ifp = vsi->ifp; | ||||
//IXL_PF_LOCK(pf); | |||||
for (i = 0; i < pf->num_vfs; i++) { | for (i = 0; i < pf->num_vfs; i++) { | ||||
if (pf->vfs[i].vsi.seid != 0) | if (pf->vfs[i].vsi.seid != 0) | ||||
i40e_aq_delete_element(hw, pf->vfs[i].vsi.seid, NULL); | i40e_aq_delete_element(hw, pf->vfs[i].vsi.seid, NULL); | ||||
ixl_pf_qmgr_release(&pf->qmgr, &pf->vfs[i].qtag); | ixl_pf_qmgr_release(&pf->qmgr, &pf->vfs[i].qtag); | ||||
ixl_free_mac_filters(&pf->vfs[i].vsi); | ixl_free_mac_filters(&pf->vfs[i].vsi); | ||||
DDPRINTF(dev, "VF %d: %d released\n", | ixl_dbg(pf, IXL_DBG_IOV, "VF %d: %d released\n", | ||||
i, pf->vfs[i].qtag.num_allocated); | i, pf->vfs[i].qtag.num_allocated); | ||||
DDPRINTF(dev, "Unallocated total: %d\n", ixl_pf_qmgr_get_num_free(&pf->qmgr)); | ixl_dbg(pf, IXL_DBG_IOV, "Unallocated total: %d\n", ixl_pf_qmgr_get_num_free(&pf->qmgr)); | ||||
} | } | ||||
if (pf->veb_seid != 0) { | if (pf->veb_seid != 0) { | ||||
i40e_aq_delete_element(hw, pf->veb_seid, NULL); | i40e_aq_delete_element(hw, pf->veb_seid, NULL); | ||||
pf->veb_seid = 0; | pf->veb_seid = 0; | ||||
} | } | ||||
/* Reset PF VSI loopback mode */ | |||||
if (pf->enable_vf_loopback) | |||||
ixl_config_pf_vsi_loopback(pf, false); | |||||
vfs = pf->vfs; | vfs = pf->vfs; | ||||
num_vfs = pf->num_vfs; | num_vfs = pf->num_vfs; | ||||
pf->vfs = NULL; | pf->vfs = NULL; | ||||
pf->num_vfs = 0; | pf->num_vfs = 0; | ||||
//IXL_PF_UNLOCK(pf); | |||||
/* Do this after the unlock as sysctl_ctx_free might sleep. */ | /* sysctl_ctx_free might sleep, but this func is called w/ an sx lock */ | ||||
for (i = 0; i < num_vfs; i++) | for (i = 0; i < num_vfs; i++) | ||||
sysctl_ctx_free(&vfs[i].ctx); | sysctl_ctx_free(&vfs[i].ctx); | ||||
free(vfs, M_IXL); | free(vfs, M_IXL); | ||||
} | } | ||||
static int | static int | ||||
ixl_vf_reserve_queues(struct ixl_pf *pf, struct ixl_vf *vf, int num_queues) | ixl_vf_reserve_queues(struct ixl_pf *pf, struct ixl_vf *vf, int num_queues) | ||||
{ | { | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
int error; | int error; | ||||
/* Validate, and clamp value if invalid */ | /* Validate, and clamp value if invalid */ | ||||
if (num_queues < 1 || num_queues > 16) | if (num_queues < 1 || num_queues > 16) | ||||
device_printf(dev, "Invalid num-queues (%d) for VF %d\n", | device_printf(dev, "Invalid num-queues (%d) for VF %d\n", | ||||
num_queues, vf->vf_num); | num_queues, vf->vf_num); | ||||
if (num_queues < 1) { | if (num_queues < 1) { | ||||
device_printf(dev, "Setting VF %d num-queues to 1\n", vf->vf_num); | device_printf(dev, "Setting VF %d num-queues to 1\n", vf->vf_num); | ||||
num_queues = 1; | num_queues = 1; | ||||
} else if (num_queues > 16) { | } else if (num_queues > IXLV_MAX_QUEUES) { | ||||
device_printf(dev, "Setting VF %d num-queues to 16\n", vf->vf_num); | device_printf(dev, "Setting VF %d num-queues to %d\n", vf->vf_num, IXLV_MAX_QUEUES); | ||||
num_queues = 16; | num_queues = IXLV_MAX_QUEUES; | ||||
} | } | ||||
error = ixl_pf_qmgr_alloc_scattered(&pf->qmgr, num_queues, &vf->qtag); | error = ixl_pf_qmgr_alloc_scattered(&pf->qmgr, num_queues, &vf->qtag); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "Error allocating %d queues for VF %d's VSI\n", | device_printf(dev, "Error allocating %d queues for VF %d's VSI\n", | ||||
num_queues, vf->vf_num); | num_queues, vf->vf_num); | ||||
return (ENOSPC); | return (ENOSPC); | ||||
} | } | ||||
DDPRINTF(dev, "VF %d: %d allocated, %d active", | ixl_dbg(pf, IXL_DBG_IOV, "VF %d: %d allocated, %d active\n", | ||||
vf->vf_num, vf->qtag.num_allocated, vf->qtag.num_active); | vf->vf_num, vf->qtag.num_allocated, vf->qtag.num_active); | ||||
DDPRINTF(dev, "Unallocated total: %d", ixl_pf_qmgr_get_num_free(&pf->qmgr)); | ixl_dbg(pf, IXL_DBG_IOV, "Unallocated total: %d\n", ixl_pf_qmgr_get_num_free(&pf->qmgr)); | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
ixl_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params) | ixl_if_iov_vf_add(if_ctx_t ctx, uint16_t vfnum, const nvlist_t *params) | ||||
{ | { | ||||
struct ixl_pf *pf = iflib_get_softc(ctx); | |||||
device_t dev = pf->dev; | |||||
char sysctl_name[QUEUE_NAME_LEN]; | char sysctl_name[QUEUE_NAME_LEN]; | ||||
struct ixl_pf *pf; | |||||
struct ixl_vf *vf; | struct ixl_vf *vf; | ||||
const void *mac; | const void *mac; | ||||
size_t size; | size_t size; | ||||
int error; | int error; | ||||
int vf_num_queues; | int vf_num_queues; | ||||
pf = device_get_softc(dev); | |||||
vf = &pf->vfs[vfnum]; | vf = &pf->vfs[vfnum]; | ||||
//IXL_PF_LOCK(pf); | |||||
vf->vf_num = vfnum; | vf->vf_num = vfnum; | ||||
vf->vsi.back = pf; | vf->vsi.back = pf; | ||||
vf->vf_flags = VF_FLAG_ENABLED; | vf->vf_flags = VF_FLAG_ENABLED; | ||||
SLIST_INIT(&vf->vsi.ftl); | SLIST_INIT(&vf->vsi.ftl); | ||||
/* Reserve queue allocation from PF */ | /* Reserve queue allocation from PF */ | ||||
vf_num_queues = nvlist_get_number(params, "num-queues"); | vf_num_queues = nvlist_get_number(params, "num-queues"); | ||||
error = ixl_vf_reserve_queues(pf, vf, vf_num_queues); | error = ixl_vf_reserve_queues(pf, vf, vf_num_queues); | ||||
if (error != 0) | if (error != 0) | ||||
Show All 19 Lines | ixl_if_iov_vf_add(if_ctx_t ctx, uint16_t vfnum, const nvlist_t *params) | ||||
if (nvlist_get_bool(params, "mac-anti-spoof")) | if (nvlist_get_bool(params, "mac-anti-spoof")) | ||||
vf->vf_flags |= VF_FLAG_MAC_ANTI_SPOOF; | vf->vf_flags |= VF_FLAG_MAC_ANTI_SPOOF; | ||||
if (nvlist_get_bool(params, "allow-promisc")) | if (nvlist_get_bool(params, "allow-promisc")) | ||||
vf->vf_flags |= VF_FLAG_PROMISC_CAP; | vf->vf_flags |= VF_FLAG_PROMISC_CAP; | ||||
vf->vf_flags |= VF_FLAG_VLAN_CAP; | vf->vf_flags |= VF_FLAG_VLAN_CAP; | ||||
/* VF needs to be reset before it can be used */ | |||||
ixl_reset_vf(pf, vf); | ixl_reset_vf(pf, vf); | ||||
out: | out: | ||||
//IXL_PF_UNLOCK(pf); | |||||
if (error == 0) { | if (error == 0) { | ||||
snprintf(sysctl_name, sizeof(sysctl_name), "vf%d", vfnum); | snprintf(sysctl_name, sizeof(sysctl_name), "vf%d", vfnum); | ||||
ixl_add_vsi_sysctls(pf, &vf->vsi, &vf->ctx, sysctl_name); | ixl_add_vsi_sysctls(dev, &vf->vsi, &vf->ctx, sysctl_name); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||