From: Haiyue Wang Date: Mon, 18 Jan 2021 11:38:29 +0000 (+0800) Subject: net/ice: refactor DCF VLAN handling X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=c7e1a1a3bfebd5a09f3693c9f353fe703e7ae8da;p=dpdk.git net/ice: refactor DCF VLAN handling Since DCF always configure the outer VLAN offloads for the target AVF, so rename the related variables to align with this design. Also, the DCF needs to trace the AVF reset status to re-apply the VLAN offload setting, refactor the reset event handling to support this. Change the VF representor API 'ethdev' parameter to 'vf_rep_eth_dev' to avoid introducing confusion with VF representor eth_dev ops name. Signed-off-by: Haiyue Wang Acked-by: Qi Zhang --- diff --git a/drivers/net/ice/ice_dcf_ethdev.c b/drivers/net/ice/ice_dcf_ethdev.c index d46734a57b..ea1f2951ba 100644 --- a/drivers/net/ice/ice_dcf_ethdev.c +++ b/drivers/net/ice/ice_dcf_ethdev.c @@ -601,6 +601,9 @@ ice_dcf_dev_stop(struct rte_eth_dev *dev) return 0; } + /* Stop the VF representors for this device */ + ice_dcf_vf_repr_stop_all(dcf_ad); + ice_dcf_stop_queues(dev); rte_intr_efd_disable(intr_handle); @@ -849,6 +852,30 @@ ice_dcf_stats_reset(struct rte_eth_dev *dev) return 0; } +static void +ice_dcf_free_repr_info(struct ice_dcf_adapter *dcf_adapter) +{ + if (dcf_adapter->repr_infos) { + rte_free(dcf_adapter->repr_infos); + dcf_adapter->repr_infos = NULL; + } +} + +static int +ice_dcf_init_repr_info(struct ice_dcf_adapter *dcf_adapter) +{ + dcf_adapter->repr_infos = + rte_calloc("ice_dcf_rep_info", + dcf_adapter->real_hw.num_vfs, + sizeof(dcf_adapter->repr_infos[0]), 0); + if (!dcf_adapter->repr_infos) { + PMD_DRV_LOG(ERR, "Failed to alloc memory for VF representors\n"); + return -ENOMEM; + } + + return 0; +} + static int ice_dcf_dev_close(struct rte_eth_dev *dev) { @@ -857,6 +884,7 @@ ice_dcf_dev_close(struct rte_eth_dev *dev) if (rte_eal_process_type() != RTE_PROC_PRIMARY) return 0; + ice_dcf_free_repr_info(adapter); ice_dcf_uninit_parent_adapter(dev); ice_dcf_uninit_hw(dev, &adapter->real_hw); @@ -1000,21 +1028,26 @@ eth_ice_dcf_pci_probe(__rte_unused struct rte_pci_driver *pci_drv, return -ENODEV; dcf_adapter = dcf_ethdev->data->dev_private; + ret = ice_dcf_init_repr_info(dcf_adapter); + if (ret) + return ret; if (eth_da.nb_representor_ports > dcf_adapter->real_hw.num_vfs || eth_da.nb_representor_ports >= RTE_MAX_ETHPORTS) { PMD_DRV_LOG(ERR, "the number of port representors is too large: %u", eth_da.nb_representor_ports); + ice_dcf_free_repr_info(dcf_adapter); return -EINVAL; } dcf_vsi_id = dcf_adapter->real_hw.vsi_id | VIRTCHNL_DCF_VF_VSI_VALID; - repr_param.adapter = dcf_adapter; + repr_param.dcf_eth_dev = dcf_ethdev; repr_param.switch_domain_id = 0; for (i = 0; i < eth_da.nb_representor_ports; i++) { uint16_t vf_id = eth_da.representor_ports[i]; + struct rte_eth_dev *vf_rep_eth_dev; if (vf_id >= dcf_adapter->real_hw.num_vfs) { PMD_DRV_LOG(ERR, "VF ID %u is out of range (0 ~ %u)", @@ -1041,6 +1074,18 @@ eth_ice_dcf_pci_probe(__rte_unused struct rte_pci_driver *pci_drv, repr_name); break; } + + vf_rep_eth_dev = rte_eth_dev_allocated(repr_name); + if (!vf_rep_eth_dev) { + PMD_DRV_LOG(ERR, + "Failed to find the ethdev for DCF VF representor: %s", + repr_name); + ret = -ENODEV; + break; + } + + dcf_adapter->repr_infos[vf_id].vf_rep_eth_dev = vf_rep_eth_dev; + dcf_adapter->num_reprs++; } return ret; diff --git a/drivers/net/ice/ice_dcf_ethdev.h b/drivers/net/ice/ice_dcf_ethdev.h index 7695815e14..e7c9d7fe41 100644 --- a/drivers/net/ice/ice_dcf_ethdev.h +++ b/drivers/net/ice/ice_dcf_ethdev.h @@ -17,30 +17,39 @@ struct ice_dcf_queue { uint64_t dummy; }; +struct ice_dcf_repr_info { + struct rte_eth_dev *vf_rep_eth_dev; +}; + struct ice_dcf_adapter { struct ice_adapter parent; /* Must be first */ struct ice_dcf_hw real_hw; + + int num_reprs; + struct ice_dcf_repr_info *repr_infos; }; struct ice_dcf_vf_repr_param { - struct ice_dcf_adapter *adapter; + struct rte_eth_dev *dcf_eth_dev; uint16_t switch_domain_id; uint16_t vf_id; }; struct ice_dcf_vlan { + bool port_vlan_ena; + bool stripping_ena; + uint16_t tpid; uint16_t vid; }; struct ice_dcf_vf_repr { - struct ice_dcf_adapter *dcf_adapter; + struct rte_eth_dev *dcf_eth_dev; struct rte_ether_addr mac_addr; uint16_t switch_domain_id; uint16_t vf_id; - bool port_vlan_ena; - struct ice_dcf_vlan port_vlan_info; + struct ice_dcf_vlan outer_vlan_info; /* DCF always handle outer VLAN */ }; void ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw, @@ -48,7 +57,9 @@ void ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw, int ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev); void ice_dcf_uninit_parent_adapter(struct rte_eth_dev *eth_dev); -int ice_dcf_vf_repr_init(struct rte_eth_dev *ethdev, void *init_param); -int ice_dcf_vf_repr_uninit(struct rte_eth_dev *ethdev); +int ice_dcf_vf_repr_init(struct rte_eth_dev *vf_rep_eth_dev, void *init_param); +int ice_dcf_vf_repr_uninit(struct rte_eth_dev *vf_rep_eth_dev); +int ice_dcf_vf_repr_init_vlan(struct rte_eth_dev *vf_rep_eth_dev); +void ice_dcf_vf_repr_stop_all(struct ice_dcf_adapter *dcf_adapter); #endif /* _ICE_DCF_ETHDEV_H_ */ diff --git a/drivers/net/ice/ice_dcf_parent.c b/drivers/net/ice/ice_dcf_parent.c index 7d565028f6..476fd49067 100644 --- a/drivers/net/ice/ice_dcf_parent.c +++ b/drivers/net/ice/ice_dcf_parent.c @@ -14,6 +14,13 @@ #define ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL 100000 /* us */ static rte_spinlock_t vsi_update_lock = RTE_SPINLOCK_INITIALIZER; +struct ice_dcf_reset_event_param { + struct ice_dcf_hw *dcf_hw; + + bool vfr; /* VF reset event */ + uint16_t vf_id; /* The reset VF ID */ +}; + static __rte_always_inline void ice_dcf_update_vsi_ctx(struct ice_hw *hw, uint16_t vsi_handle, uint16_t vsi_map) @@ -110,31 +117,67 @@ ice_dcf_update_pf_vsi_map(struct ice_hw *hw, uint16_t pf_vsi_idx, static void* ice_dcf_vsi_update_service_handler(void *param) { - struct ice_dcf_hw *hw = param; + struct ice_dcf_reset_event_param *reset_param = param; + struct ice_dcf_hw *hw = reset_param->dcf_hw; + struct ice_dcf_adapter *adapter; usleep(ICE_DCF_VSI_UPDATE_SERVICE_INTERVAL); rte_spinlock_lock(&vsi_update_lock); - if (!ice_dcf_handle_vsi_update_event(hw)) { - struct ice_dcf_adapter *dcf_ad = - container_of(hw, struct ice_dcf_adapter, real_hw); + adapter = container_of(hw, struct ice_dcf_adapter, real_hw); - ice_dcf_update_vf_vsi_map(&dcf_ad->parent.hw, + if (!ice_dcf_handle_vsi_update_event(hw)) + ice_dcf_update_vf_vsi_map(&adapter->parent.hw, hw->num_vfs, hw->vf_vsi_map); + + if (reset_param->vfr && adapter->repr_infos) { + struct rte_eth_dev *vf_rep_eth_dev = + adapter->repr_infos[reset_param->vf_id].vf_rep_eth_dev; + if (vf_rep_eth_dev && vf_rep_eth_dev->data->dev_started) { + PMD_DRV_LOG(DEBUG, "VF%u representor is resetting", + reset_param->vf_id); + ice_dcf_vf_repr_init_vlan(vf_rep_eth_dev); + } } rte_spinlock_unlock(&vsi_update_lock); + free(param); + return NULL; } +static void +start_vsi_reset_thread(struct ice_dcf_hw *dcf_hw, bool vfr, uint16_t vf_id) +{ + struct ice_dcf_reset_event_param *param; + pthread_t thread; + int ret; + + param = malloc(sizeof(*param)); + if (!param) { + PMD_DRV_LOG(ERR, "Failed to allocate the memory for reset handling"); + return; + } + + param->dcf_hw = dcf_hw; + param->vfr = vfr; + param->vf_id = vf_id; + + ret = pthread_create(&thread, NULL, + ice_dcf_vsi_update_service_handler, param); + if (ret) { + PMD_DRV_LOG(ERR, "Failed to start the thread for reset handling"); + free(param); + } +} + void ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw, uint8_t *msg, uint16_t msglen) { struct virtchnl_pf_event *pf_msg = (struct virtchnl_pf_event *)msg; - pthread_t thread; if (msglen < sizeof(struct virtchnl_pf_event)) { PMD_DRV_LOG(DEBUG, "Invalid event message length : %u", msglen); @@ -144,8 +187,7 @@ ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw, switch (pf_msg->event) { case VIRTCHNL_EVENT_RESET_IMPENDING: PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event"); - pthread_create(&thread, NULL, - ice_dcf_vsi_update_service_handler, dcf_hw); + start_vsi_reset_thread(dcf_hw, false, 0); break; case VIRTCHNL_EVENT_LINK_CHANGE: PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event"); @@ -157,8 +199,8 @@ ice_dcf_handle_pf_event_msg(struct ice_dcf_hw *dcf_hw, PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_DCF_VSI_MAP_UPDATE event : VF%u with VSI num %u", pf_msg->event_data.vf_vsi_map.vf_id, pf_msg->event_data.vf_vsi_map.vsi_id); - pthread_create(&thread, NULL, - ice_dcf_vsi_update_service_handler, dcf_hw); + start_vsi_reset_thread(dcf_hw, true, + pf_msg->event_data.vf_vsi_map.vf_id); break; default: PMD_DRV_LOG(ERR, "Unknown event received %u", pf_msg->event); diff --git a/drivers/net/ice/ice_dcf_vf_representor.c b/drivers/net/ice/ice_dcf_vf_representor.c index 09ca4df5a6..970461f3e9 100644 --- a/drivers/net/ice/ice_dcf_vf_representor.c +++ b/drivers/net/ice/ice_dcf_vf_representor.c @@ -27,8 +27,10 @@ ice_dcf_vf_repr_tx_burst(__rte_unused void *txq, } static int -ice_dcf_vf_repr_dev_configure(__rte_unused struct rte_eth_dev *dev) +ice_dcf_vf_repr_dev_configure(struct rte_eth_dev *dev) { + ice_dcf_vf_repr_init_vlan(dev); + return 0; } @@ -106,13 +108,21 @@ ice_dcf_vf_repr_link_update(__rte_unused struct rte_eth_dev *ethdev, return 0; } +static __rte_always_inline struct ice_dcf_hw * +ice_dcf_vf_repr_hw(struct ice_dcf_vf_repr *repr) +{ + struct ice_dcf_adapter *dcf_adapter = + repr->dcf_eth_dev->data->dev_private; + + return &dcf_adapter->real_hw; +} + static int ice_dcf_vf_repr_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) { struct ice_dcf_vf_repr *repr = dev->data->dev_private; - struct ice_dcf_hw *dcf_hw = - &repr->dcf_adapter->real_hw; + struct ice_dcf_hw *dcf_hw = ice_dcf_vf_repr_hw(repr); dev_info->device = dev->device; dev_info->max_mac_addrs = 1; @@ -190,25 +200,82 @@ ice_dcf_vf_repr_dev_info_get(struct rte_eth_dev *dev, return 0; } +static __rte_always_inline bool +ice_dcf_vlan_offload_ena(struct ice_dcf_vf_repr *repr) +{ + return !!(ice_dcf_vf_repr_hw(repr)->vf_res->vf_cap_flags & + VIRTCHNL_VF_OFFLOAD_VLAN_V2); +} + static int ice_dcf_vlan_offload_config(struct ice_dcf_vf_repr *repr, struct virtchnl_dcf_vlan_offload *vlan_offload) { struct dcf_virtchnl_cmd args; + int err; memset(&args, 0, sizeof(args)); args.v_op = VIRTCHNL_OP_DCF_VLAN_OFFLOAD; args.req_msg = (uint8_t *)vlan_offload; args.req_msglen = sizeof(*vlan_offload); - return ice_dcf_execute_virtchnl_cmd(&repr->dcf_adapter->real_hw, &args); + err = ice_dcf_execute_virtchnl_cmd(ice_dcf_vf_repr_hw(repr), &args); + if (err) + PMD_DRV_LOG(ERR, + "Failed to execute command of VIRTCHNL_OP_DCF_VLAN_OFFLOAD"); + + return err; } -static __rte_always_inline bool -ice_dcf_vlan_offload_ena(struct ice_dcf_vf_repr *repr) +static int +ice_dcf_vf_repr_vlan_offload_set(struct rte_eth_dev *dev, int mask) { - return !!(repr->dcf_adapter->real_hw.vf_res->vf_cap_flags & - VIRTCHNL_VF_OFFLOAD_VLAN_V2); + struct ice_dcf_vf_repr *repr = dev->data->dev_private; + struct rte_eth_conf *dev_conf = &dev->data->dev_conf; + struct virtchnl_dcf_vlan_offload vlan_offload; + int err; + + if (!ice_dcf_vlan_offload_ena(repr)) + return -ENOTSUP; + + /* Vlan stripping setting */ + if (mask & ETH_VLAN_STRIP_MASK) { + bool enable = !!(dev_conf->rxmode.offloads & + DEV_RX_OFFLOAD_VLAN_STRIP); + + if (enable && repr->outer_vlan_info.port_vlan_ena) { + PMD_DRV_LOG(ERR, + "Disable the port VLAN firstly\n"); + return -EINVAL; + } + + memset(&vlan_offload, 0, sizeof(vlan_offload)); + + if (enable) + vlan_offload.vlan_flags = + VIRTCHNL_DCF_VLAN_STRIP_INTO_RX_DESC << + VIRTCHNL_DCF_VLAN_STRIP_MODE_S; + else if (repr->outer_vlan_info.stripping_ena && !enable) + vlan_offload.vlan_flags = + VIRTCHNL_DCF_VLAN_STRIP_DISABLE << + VIRTCHNL_DCF_VLAN_STRIP_MODE_S; + + if (vlan_offload.vlan_flags) { + vlan_offload.vf_id = repr->vf_id; + vlan_offload.tpid = repr->outer_vlan_info.tpid; + vlan_offload.vlan_flags |= + VIRTCHNL_DCF_VLAN_TYPE_OUTER << + VIRTCHNL_DCF_VLAN_TYPE_S; + + err = ice_dcf_vlan_offload_config(repr, &vlan_offload); + if (err) + return -EIO; + + repr->outer_vlan_info.stripping_ena = enable; + } + } + + return 0; } static int @@ -222,26 +289,39 @@ ice_dcf_vf_repr_vlan_pvid_set(struct rte_eth_dev *dev, if (!ice_dcf_vlan_offload_ena(repr)) return -ENOTSUP; - if (on && (pvid == 0 || pvid > RTE_ETHER_MAX_VLAN_ID)) + if (repr->outer_vlan_info.stripping_ena) { + PMD_DRV_LOG(ERR, + "Disable the VLAN stripping firstly\n"); + return -EINVAL; + } + + if (pvid > RTE_ETHER_MAX_VLAN_ID) return -EINVAL; memset(&vlan_offload, 0, sizeof(vlan_offload)); + if (on) + vlan_offload.vlan_flags = + (VIRTCHNL_DCF_VLAN_INSERT_PORT_BASED << + VIRTCHNL_DCF_VLAN_INSERT_MODE_S); + else + vlan_offload.vlan_flags = + (VIRTCHNL_DCF_VLAN_INSERT_DISABLE << + VIRTCHNL_DCF_VLAN_INSERT_MODE_S); + vlan_offload.vf_id = repr->vf_id; - vlan_offload.tpid = repr->port_vlan_info.tpid; - vlan_offload.vlan_flags = (VIRTCHNL_DCF_VLAN_TYPE_OUTER << - VIRTCHNL_DCF_VLAN_TYPE_S) | - (VIRTCHNL_DCF_VLAN_INSERT_PORT_BASED << - VIRTCHNL_DCF_VLAN_INSERT_MODE_S); - vlan_offload.vlan_id = on ? pvid : 0; + vlan_offload.tpid = repr->outer_vlan_info.tpid; + vlan_offload.vlan_flags |= (VIRTCHNL_DCF_VLAN_TYPE_OUTER << + VIRTCHNL_DCF_VLAN_TYPE_S); + vlan_offload.vlan_id = pvid; err = ice_dcf_vlan_offload_config(repr, &vlan_offload); if (!err) { if (on) { - repr->port_vlan_ena = true; - repr->port_vlan_info.vid = pvid; + repr->outer_vlan_info.port_vlan_ena = true; + repr->outer_vlan_info.vid = pvid; } else { - repr->port_vlan_ena = false; + repr->outer_vlan_info.port_vlan_ena = false; } } @@ -272,13 +352,32 @@ ice_dcf_vf_repr_vlan_tpid_set(struct rte_eth_dev *dev, return -EINVAL; } - repr->port_vlan_info.tpid = tpid; + repr->outer_vlan_info.tpid = tpid; - if (repr->port_vlan_ena) + if (repr->outer_vlan_info.port_vlan_ena) { err = ice_dcf_vf_repr_vlan_pvid_set(dev, - repr->port_vlan_info.vid, + repr->outer_vlan_info.vid, true); - return err; + if (err) { + PMD_DRV_LOG(ERR, + "Failed to reset port VLAN : %d\n", + err); + return err; + } + } + + if (repr->outer_vlan_info.stripping_ena) { + err = ice_dcf_vf_repr_vlan_offload_set(dev, + ETH_VLAN_STRIP_MASK); + if (err) { + PMD_DRV_LOG(ERR, + "Failed to reset VLAN stripping : %d\n", + err); + return err; + } + } + + return 0; } static const struct eth_dev_ops ice_dcf_vf_repr_dev_ops = { @@ -294,31 +393,33 @@ static const struct eth_dev_ops ice_dcf_vf_repr_dev_ops = { .allmulticast_enable = ice_dcf_vf_repr_allmulticast_enable, .allmulticast_disable = ice_dcf_vf_repr_allmulticast_disable, .link_update = ice_dcf_vf_repr_link_update, + .vlan_offload_set = ice_dcf_vf_repr_vlan_offload_set, .vlan_pvid_set = ice_dcf_vf_repr_vlan_pvid_set, .vlan_tpid_set = ice_dcf_vf_repr_vlan_tpid_set, }; int -ice_dcf_vf_repr_init(struct rte_eth_dev *ethdev, void *init_param) +ice_dcf_vf_repr_init(struct rte_eth_dev *vf_rep_eth_dev, void *init_param) { - struct ice_dcf_vf_repr *repr = ethdev->data->dev_private; + struct ice_dcf_vf_repr *repr = vf_rep_eth_dev->data->dev_private; struct ice_dcf_vf_repr_param *param = init_param; - repr->dcf_adapter = param->adapter; + repr->dcf_eth_dev = param->dcf_eth_dev; repr->switch_domain_id = param->switch_domain_id; repr->vf_id = param->vf_id; - repr->port_vlan_ena = false; - repr->port_vlan_info.tpid = RTE_ETHER_TYPE_VLAN; + repr->outer_vlan_info.port_vlan_ena = false; + repr->outer_vlan_info.stripping_ena = false; + repr->outer_vlan_info.tpid = RTE_ETHER_TYPE_VLAN; - ethdev->dev_ops = &ice_dcf_vf_repr_dev_ops; + vf_rep_eth_dev->dev_ops = &ice_dcf_vf_repr_dev_ops; - ethdev->rx_pkt_burst = ice_dcf_vf_repr_rx_burst; - ethdev->tx_pkt_burst = ice_dcf_vf_repr_tx_burst; + vf_rep_eth_dev->rx_pkt_burst = ice_dcf_vf_repr_rx_burst; + vf_rep_eth_dev->tx_pkt_burst = ice_dcf_vf_repr_tx_burst; - ethdev->data->dev_flags |= RTE_ETH_DEV_REPRESENTOR; - ethdev->data->representor_id = repr->vf_id; + vf_rep_eth_dev->data->dev_flags |= RTE_ETH_DEV_REPRESENTOR; + vf_rep_eth_dev->data->representor_id = repr->vf_id; - ethdev->data->mac_addrs = &repr->mac_addr; + vf_rep_eth_dev->data->mac_addrs = &repr->mac_addr; rte_eth_random_addr(repr->mac_addr.addr_bytes); @@ -326,9 +427,56 @@ ice_dcf_vf_repr_init(struct rte_eth_dev *ethdev, void *init_param) } int -ice_dcf_vf_repr_uninit(struct rte_eth_dev *ethdev) +ice_dcf_vf_repr_uninit(struct rte_eth_dev *vf_rep_eth_dev) { - ethdev->data->mac_addrs = NULL; + vf_rep_eth_dev->data->mac_addrs = NULL; return 0; } + +int +ice_dcf_vf_repr_init_vlan(struct rte_eth_dev *vf_rep_eth_dev) +{ + struct ice_dcf_vf_repr *repr = vf_rep_eth_dev->data->dev_private; + int err; + + err = ice_dcf_vf_repr_vlan_offload_set(vf_rep_eth_dev, + ETH_VLAN_STRIP_MASK); + if (err) { + PMD_DRV_LOG(ERR, "Failed to set VLAN offload"); + return err; + } + + if (repr->outer_vlan_info.port_vlan_ena) { + err = ice_dcf_vf_repr_vlan_pvid_set(vf_rep_eth_dev, + repr->outer_vlan_info.vid, + true); + if (err) { + PMD_DRV_LOG(ERR, "Failed to enable port VLAN"); + return err; + } + } + + return 0; +} + +void +ice_dcf_vf_repr_stop_all(struct ice_dcf_adapter *dcf_adapter) +{ + uint16_t vf_id; + int ret; + + if (!dcf_adapter->repr_infos) + return; + + for (vf_id = 0; vf_id < dcf_adapter->real_hw.num_vfs; vf_id++) { + struct rte_eth_dev *vf_rep_eth_dev = + dcf_adapter->repr_infos[vf_id].vf_rep_eth_dev; + if (!vf_rep_eth_dev || vf_rep_eth_dev->data->dev_started == 0) + continue; + + ret = ice_dcf_vf_repr_dev_stop(vf_rep_eth_dev); + if (!ret) + vf_rep_eth_dev->data->dev_started = 0; + } +}