#include <rte_eal.h>
#include <rte_alarm.h>
#include <rte_ether.h>
-#include <rte_ethdev_driver.h>
-#include <rte_ethdev_pci.h>
+#include <ethdev_driver.h>
+#include <ethdev_pci.h>
#include <rte_malloc.h>
#include <rte_dev.h>
static int i40evf_dev_configure(struct rte_eth_dev *dev);
static int i40evf_dev_start(struct rte_eth_dev *dev);
-static void i40evf_dev_stop(struct rte_eth_dev *dev);
+static int i40evf_dev_stop(struct rte_eth_dev *dev);
static int i40evf_dev_info_get(struct rte_eth_dev *dev,
struct rte_eth_dev_info *dev_info);
static int i40evf_dev_link_update(struct rte_eth_dev *dev,
static int i40evf_vlan_filter_set(struct rte_eth_dev *dev,
uint16_t vlan_id, int on);
static int i40evf_vlan_offload_set(struct rte_eth_dev *dev, int mask);
-static void i40evf_dev_close(struct rte_eth_dev *dev);
-static int i40evf_dev_reset(struct rte_eth_dev *dev);
+static int i40evf_dev_close(struct rte_eth_dev *dev);
+static int i40evf_dev_reset(struct rte_eth_dev *dev);
+static int i40evf_check_vf_reset_done(struct rte_eth_dev *dev);
static int i40evf_dev_promiscuous_enable(struct rte_eth_dev *dev);
static int i40evf_dev_promiscuous_disable(struct rte_eth_dev *dev);
static int i40evf_dev_allmulticast_enable(struct rte_eth_dev *dev);
uint16_t tx_queue_id);
static int i40evf_dev_tx_queue_stop(struct rte_eth_dev *dev,
uint16_t tx_queue_id);
+static int i40evf_add_del_eth_addr(struct rte_eth_dev *dev,
+ struct rte_ether_addr *addr,
+ bool add, uint8_t type);
static int i40evf_add_mac_addr(struct rte_eth_dev *dev,
struct rte_ether_addr *addr,
uint32_t index,
.rx_queue_release = i40e_dev_rx_queue_release,
.rx_queue_intr_enable = i40evf_dev_rx_queue_intr_enable,
.rx_queue_intr_disable = i40evf_dev_rx_queue_intr_disable,
- .rx_descriptor_done = i40e_dev_rx_descriptor_done,
- .rx_descriptor_status = i40e_dev_rx_descriptor_status,
- .tx_descriptor_status = i40e_dev_tx_descriptor_status,
.tx_queue_setup = i40e_dev_tx_queue_setup,
.tx_queue_release = i40e_dev_tx_queue_release,
- .rx_queue_count = i40e_dev_rx_queue_count,
.rxq_info_get = i40e_rxq_info_get,
.txq_info_get = i40e_txq_info_get,
.mac_addr_add = i40evf_add_mac_addr,
.mtu_set = i40evf_dev_mtu_set,
.mac_addr_set = i40evf_set_default_mac_addr,
.tx_done_cleanup = i40e_tx_done_cleanup,
+ .get_monitor_addr = i40e_get_monitor_addr
};
/*
case VIRTCHNL_EVENT_RESET_IMPENDING:
vf->vf_reset = true;
vf->pend_msg |= PFMSG_RESET_IMPENDING;
- PMD_DRV_LOG(INFO, "vf is reseting");
+ PMD_DRV_LOG(INFO, "VF is resetting");
break;
case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
vf->dev_closed = true;
#define ASQ_DELAY_MS 10
static int
-i40evf_execute_vf_cmd(struct rte_eth_dev *dev, struct vf_cmd_info *args)
+_i40evf_execute_vf_cmd(struct rte_eth_dev *dev, struct vf_cmd_info *args)
{
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
return err | vf->cmd_retval;
}
+static int
+i40evf_execute_vf_cmd(struct rte_eth_dev *dev, struct vf_cmd_info *args)
+{
+ struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+ int err;
+
+ while (!rte_spinlock_trylock(&vf->cmd_send_lock))
+ rte_delay_us_sleep(50);
+ err = _i40evf_execute_vf_cmd(dev, args);
+ rte_spinlock_unlock(&vf->cmd_send_lock);
+ return err;
+}
+
/*
* Check API version with sync wait until version read or fail from admin queue
*/
VIRTCHNL_VF_OFFLOAD_RSS_AQ |
VIRTCHNL_VF_OFFLOAD_RSS_REG |
VIRTCHNL_VF_OFFLOAD_VLAN |
- VIRTCHNL_VF_OFFLOAD_RX_POLLING;
+ VIRTCHNL_VF_OFFLOAD_RX_POLLING |
+ VIRTCHNL_VF_CAP_ADV_LINK_SPEED;
args.in_args = (uint8_t *)∩︀
args.in_args_size = sizeof(caps);
} else {
err = i40evf_execute_vf_cmd(dev, &args);
- if (err)
+ if (err) {
PMD_DRV_LOG(ERR, "fail to execute command "
"CONFIG_PROMISCUOUS_MODE");
- return err;
+
+ if (err == I40E_NOT_SUPPORTED)
+ return -ENOTSUP;
+
+ return -EAGAIN;
+ }
+
+ vf->promisc_unicast_enabled = enable_unicast;
+ vf->promisc_multicast_enabled = enable_multicast;
+ return 0;
}
static int
for (i = 0; i < dev->data->nb_tx_queues; i++) {
if (i40evf_dev_tx_queue_stop(dev, i) != 0) {
PMD_DRV_LOG(ERR, "Fail to stop queue %u", i);
- return -1;
}
}
for (i = 0; i < dev->data->nb_rx_queues; i++) {
if (i40evf_dev_rx_queue_stop(dev, i) != 0) {
PMD_DRV_LOG(ERR, "Fail to stop queue %u", i);
- return -1;
}
}
}
static int
-i40evf_add_mac_addr(struct rte_eth_dev *dev,
- struct rte_ether_addr *addr,
- __rte_unused uint32_t index,
- __rte_unused uint32_t pool)
+i40evf_add_del_eth_addr(struct rte_eth_dev *dev,
+ struct rte_ether_addr *addr,
+ bool add, uint8_t type)
{
struct virtchnl_ether_addr_list *list;
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
int err;
struct vf_cmd_info args;
- if (rte_is_zero_ether_addr(addr)) {
- PMD_DRV_LOG(ERR, "Invalid mac:%x:%x:%x:%x:%x:%x",
- addr->addr_bytes[0], addr->addr_bytes[1],
- addr->addr_bytes[2], addr->addr_bytes[3],
- addr->addr_bytes[4], addr->addr_bytes[5]);
- return I40E_ERR_INVALID_MAC_ADDR;
- }
-
list = (struct virtchnl_ether_addr_list *)cmd_buffer;
list->vsi_id = vf->vsi_res->vsi_id;
list->num_elements = 1;
+ list->list[0].type = type;
rte_memcpy(list->list[0].addr, addr->addr_bytes,
sizeof(addr->addr_bytes));
- args.ops = VIRTCHNL_OP_ADD_ETH_ADDR;
+ args.ops = add ? VIRTCHNL_OP_ADD_ETH_ADDR : VIRTCHNL_OP_DEL_ETH_ADDR;
args.in_args = cmd_buffer;
args.in_args_size = sizeof(cmd_buffer);
args.out_buffer = vf->aq_resp;
args.out_size = I40E_AQ_BUF_SZ;
err = i40evf_execute_vf_cmd(dev, &args);
if (err)
- PMD_DRV_LOG(ERR, "fail to execute command "
- "OP_ADD_ETHER_ADDRESS");
- else
- vf->vsi.mac_num++;
-
+ PMD_DRV_LOG(ERR, "fail to execute command %s",
+ add ? "OP_ADD_ETH_ADDR" : "OP_DEL_ETH_ADDR");
return err;
}
-static void
-i40evf_del_mac_addr_by_addr(struct rte_eth_dev *dev,
- struct rte_ether_addr *addr)
+static int
+i40evf_add_mac_addr(struct rte_eth_dev *dev,
+ struct rte_ether_addr *addr,
+ __rte_unused uint32_t index,
+ __rte_unused uint32_t pool)
{
- struct virtchnl_ether_addr_list *list;
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
- uint8_t cmd_buffer[sizeof(struct virtchnl_ether_addr_list) + \
- sizeof(struct virtchnl_ether_addr)];
int err;
- struct vf_cmd_info args;
- if (i40e_validate_mac_addr(addr->addr_bytes) != I40E_SUCCESS) {
- PMD_DRV_LOG(ERR, "Invalid mac:%x-%x-%x-%x-%x-%x",
- addr->addr_bytes[0], addr->addr_bytes[1],
- addr->addr_bytes[2], addr->addr_bytes[3],
- addr->addr_bytes[4], addr->addr_bytes[5]);
- return;
+ if (rte_is_zero_ether_addr(addr)) {
+ PMD_DRV_LOG(ERR, "Invalid mac:" RTE_ETHER_ADDR_PRT_FMT,
+ RTE_ETHER_ADDR_BYTES(addr));
+ return I40E_ERR_INVALID_MAC_ADDR;
}
- list = (struct virtchnl_ether_addr_list *)cmd_buffer;
- list->vsi_id = vf->vsi_res->vsi_id;
- list->num_elements = 1;
- rte_memcpy(list->list[0].addr, addr->addr_bytes,
- sizeof(addr->addr_bytes));
+ err = i40evf_add_del_eth_addr(dev, addr, TRUE, VIRTCHNL_ETHER_ADDR_EXTRA);
- args.ops = VIRTCHNL_OP_DEL_ETH_ADDR;
- args.in_args = cmd_buffer;
- args.in_args_size = sizeof(cmd_buffer);
- args.out_buffer = vf->aq_resp;
- args.out_size = I40E_AQ_BUF_SZ;
- err = i40evf_execute_vf_cmd(dev, &args);
if (err)
- PMD_DRV_LOG(ERR, "fail to execute command "
- "OP_DEL_ETHER_ADDRESS");
+ PMD_DRV_LOG(ERR, "fail to add MAC address");
else
- vf->vsi.mac_num--;
- return;
+ vf->vsi.mac_num++;
+
+ return err;
}
static void
i40evf_del_mac_addr(struct rte_eth_dev *dev, uint32_t index)
{
+ struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
struct rte_eth_dev_data *data = dev->data;
struct rte_ether_addr *addr;
+ int err;
addr = &data->mac_addrs[index];
- i40evf_del_mac_addr_by_addr(dev, addr);
+ err = i40evf_add_del_eth_addr(dev, addr, FALSE, VIRTCHNL_ETHER_ADDR_EXTRA);
+
+ if (err)
+ PMD_DRV_LOG(ERR, "fail to delete MAC address");
+ else
+ vf->vsi.mac_num--;
+
+ return;
}
static int
args.out_buffer = vf->aq_resp;
args.out_size = I40E_AQ_BUF_SZ;
err = i40evf_execute_vf_cmd(dev, &args);
- if (err)
+ if (err) {
PMD_DRV_LOG(ERR, "fail to execute command OP_ADD_VLAN");
+ return err;
+ }
+ /**
+ * In linux kernel driver on receiving ADD_VLAN it enables
+ * VLAN_STRIP by default. So reconfigure the vlan_offload
+ * as it was done by the app earlier.
+ */
+ err = i40evf_vlan_offload_set(dev, ETH_VLAN_STRIP_MASK);
+ if (err)
+ PMD_DRV_LOG(ERR, "fail to set vlan_strip");
return err;
}
args.out_size = I40E_AQ_BUF_SZ;
rte_eal_alarm_cancel(i40evf_dev_alarm_handler, dev);
+
err = i40evf_execute_vf_cmd(dev, &args);
- if (err)
+
+ rte_eal_alarm_set(I40EVF_ALARM_INTERVAL, i40evf_dev_alarm_handler, dev);
+
+ if (err != I40E_SUCCESS) {
PMD_DRV_LOG(ERR, "fail to execute command OP_REQUEST_QUEUES");
+ return err;
+ }
+
+ /* The PF will issue a reset to the VF when change the number of
+ * queues. The PF will set I40E_VFGEN_RSTAT to COMPLETE first, then
+ * wait 10ms and set it to ACTIVE. In this duration, vf may not catch
+ * the moment that COMPLETE is set. So, for vf, we'll try to wait a
+ * long time.
+ */
+ rte_delay_ms(100);
+
+ err = i40evf_check_vf_reset_done(dev);
+ if (err)
+ PMD_DRV_LOG(ERR, "VF is still resetting");
- rte_eal_alarm_set(I40EVF_ALARM_INTERVAL,
- i40evf_dev_alarm_handler, dev);
return err;
}
if (i >= MAX_RESET_WAIT_CNT)
return -1;
- vf->vf_reset = false;
vf->pend_msg &= ~PFMSG_RESET_IMPENDING;
return 0;
* it to ACTIVE. In this duration, vf may not catch the moment that
* COMPLETE is set. So, for vf, we'll try to wait a long time.
*/
- rte_delay_ms(200);
+ rte_delay_ms(500);
ret = i40evf_check_vf_reset_done(dev);
if (ret) {
vf->adapter = I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
vf->dev_data = dev->data;
+ rte_spinlock_init(&vf->cmd_send_lock);
err = i40e_set_mac_type(hw);
if (err) {
PMD_INIT_LOG(ERR, "set_mac_type failed: %d", err);
switch (pf_msg->event) {
case VIRTCHNL_EVENT_RESET_IMPENDING:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event");
- _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_RESET,
- NULL);
+ vf->vf_reset = true;
+ rte_eth_dev_callback_process(dev,
+ RTE_ETH_EVENT_INTR_RESET, NULL);
break;
case VIRTCHNL_EVENT_LINK_CHANGE:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event");
- vf->link_up = pf_msg->event_data.link_event.link_status;
- vf->link_speed = pf_msg->event_data.link_event.link_speed;
+
+ if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_CAP_ADV_LINK_SPEED) {
+ vf->link_up =
+ pf_msg->event_data.link_event_adv.link_status;
+
+ switch (pf_msg->event_data.link_event_adv.link_speed) {
+ case ETH_SPEED_NUM_100M:
+ vf->link_speed = VIRTCHNL_LINK_SPEED_100MB;
+ break;
+ case ETH_SPEED_NUM_1G:
+ vf->link_speed = VIRTCHNL_LINK_SPEED_1GB;
+ break;
+ case ETH_SPEED_NUM_2_5G:
+ vf->link_speed = VIRTCHNL_LINK_SPEED_2_5GB;
+ break;
+ case ETH_SPEED_NUM_5G:
+ vf->link_speed = VIRTCHNL_LINK_SPEED_5GB;
+ break;
+ case ETH_SPEED_NUM_10G:
+ vf->link_speed = VIRTCHNL_LINK_SPEED_10GB;
+ break;
+ case ETH_SPEED_NUM_20G:
+ vf->link_speed = VIRTCHNL_LINK_SPEED_20GB;
+ break;
+ case ETH_SPEED_NUM_25G:
+ vf->link_speed = VIRTCHNL_LINK_SPEED_25GB;
+ break;
+ case ETH_SPEED_NUM_40G:
+ vf->link_speed = VIRTCHNL_LINK_SPEED_40GB;
+ break;
+ default:
+ vf->link_speed = VIRTCHNL_LINK_SPEED_UNKNOWN;
+ break;
+ }
+ } else {
+ vf->link_up =
+ pf_msg->event_data.link_event.link_status;
+ vf->link_speed =
+ pf_msg->event_data.link_event.link_speed;
+ }
+
+ i40evf_dev_link_update(dev, 0);
+ rte_eth_dev_callback_process(dev,
+ RTE_ETH_EVENT_INTR_LSC, NULL);
break;
case VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event");
info.msg_len);
else {
/* read message and it's expected one */
- if (msg_opc == vf->pend_cmd) {
+ if ((volatile uint32_t)msg_opc ==
+ vf->pend_cmd) {
vf->cmd_retval = msg_ret;
/* prevent compiler reordering */
rte_compiler_barrier();
/* assign ops func pointer */
eth_dev->dev_ops = &i40evf_eth_dev_ops;
+ eth_dev->rx_queue_count = i40e_dev_rx_queue_count;
+ eth_dev->rx_descriptor_done = i40e_dev_rx_descriptor_done;
+ eth_dev->rx_descriptor_status = i40e_dev_rx_descriptor_status;
+ eth_dev->tx_descriptor_status = i40e_dev_tx_descriptor_status;
eth_dev->rx_pkt_burst = &i40e_recv_pkts;
eth_dev->tx_pkt_burst = &i40e_xmit_pkts;
}
i40e_set_default_ptype_table(eth_dev);
rte_eth_copy_pci_info(eth_dev, pci_dev);
+ eth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
hw->vendor_id = pci_dev->id.vendor_id;
hw->device_id = pci_dev->id.device_id;
hw->bus.device = pci_dev->addr.devid;
hw->bus.func = pci_dev->addr.function;
hw->hw_addr = (void *)pci_dev->mem_resource[0].addr;
- hw->adapter_stopped = 0;
+ hw->adapter_stopped = 1;
hw->adapter_closed = 0;
- /* Pass the information to the rte_eth_dev_close() that it should also
- * release the private port resources.
- */
- eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
-
if(i40evf_init_vf(eth_dev) != 0) {
PMD_INIT_LOG(ERR, "Init vf failed");
return -1;
return 0;
}
+static int
+i40evf_check_driver_handler(__rte_unused const char *key,
+ const char *value, __rte_unused void *opaque)
+{
+ if (strcmp(value, "i40evf"))
+ return -1;
+
+ return 0;
+}
+
+static int
+i40evf_driver_selected(struct rte_devargs *devargs)
+{
+ struct rte_kvargs *kvlist;
+ int ret = 0;
+
+ if (devargs == NULL)
+ return 0;
+
+ kvlist = rte_kvargs_parse(devargs->args, NULL);
+ if (kvlist == NULL)
+ return 0;
+
+ if (!rte_kvargs_count(kvlist, RTE_DEVARGS_KEY_DRIVER))
+ goto exit;
+
+ /* i40evf driver selected when there's a key-value pair:
+ * driver=i40evf
+ */
+ if (rte_kvargs_process(kvlist, RTE_DEVARGS_KEY_DRIVER,
+ i40evf_check_driver_handler, NULL) < 0)
+ goto exit;
+
+ ret = 1;
+
+exit:
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
static int eth_i40evf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
struct rte_pci_device *pci_dev)
{
+ if (!i40evf_driver_selected(pci_dev->device.devargs))
+ return 1;
+
return rte_eth_dev_pci_generic_probe(pci_dev,
sizeof(struct i40e_adapter), i40evf_dev_init);
}
*/
static struct rte_pci_driver rte_i40evf_pmd = {
.id_table = pci_id_i40evf_map,
- .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+ .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
.probe = eth_i40evf_pci_probe,
.remove = eth_i40evf_pci_remove,
};
RTE_PMD_REGISTER_PCI(net_i40e_vf, rte_i40evf_pmd);
RTE_PMD_REGISTER_PCI_TABLE(net_i40e_vf, pci_id_i40evf_map);
RTE_PMD_REGISTER_KMOD_DEP(net_i40e_vf, "* igb_uio | vfio-pci");
+RTE_PMD_REGISTER_PARAM_STRING(net_i40e_vf, "driver=i40evf");
static int
i40evf_dev_configure(struct rte_eth_dev *dev)
ad->tx_simple_allowed = true;
ad->tx_vec_allowed = true;
+ dev->data->dev_conf.intr_conf.lsc =
+ !!(dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC);
+
if (num_queue_pairs > vf->vsi_res->num_queue_pairs) {
- int ret = 0;
+ struct i40e_hw *hw;
+ int ret;
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+ PMD_DRV_LOG(ERR,
+ "For secondary processes, change queue pairs is not supported!");
+ return -ENOTSUP;
+ }
+
+ hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ if (!hw->adapter_stopped) {
+ PMD_DRV_LOG(ERR, "Device must be stopped first!");
+ return -EBUSY;
+ }
PMD_DRV_LOG(INFO, "change queue pairs from %u to %u",
vf->vsi_res->num_queue_pairs, num_queue_pairs);
* Check if the jumbo frame and maximum packet length are set correctly
*/
if (dev_data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_JUMBO_FRAME) {
- if (rxq->max_pkt_len <= RTE_ETHER_MAX_LEN ||
+ if (rxq->max_pkt_len <= I40E_ETH_MAX_LEN ||
rxq->max_pkt_len > I40E_FRAME_SIZE_MAX) {
PMD_DRV_LOG(ERR, "maximum packet length must be "
"larger than %u and smaller than %u, as jumbo "
- "frame is enabled", (uint32_t)RTE_ETHER_MAX_LEN,
+ "frame is enabled", (uint32_t)I40E_ETH_MAX_LEN,
(uint32_t)I40E_FRAME_SIZE_MAX);
return I40E_ERR_CONFIG;
}
} else {
if (rxq->max_pkt_len < RTE_ETHER_MIN_LEN ||
- rxq->max_pkt_len > RTE_ETHER_MAX_LEN) {
+ rxq->max_pkt_len > I40E_ETH_MAX_LEN) {
PMD_DRV_LOG(ERR, "maximum packet length must be "
"larger than %u and smaller than %u, as jumbo "
"frame is disabled",
(uint32_t)RTE_ETHER_MIN_LEN,
- (uint32_t)RTE_ETHER_MAX_LEN);
+ (uint32_t)I40E_ETH_MAX_LEN);
return I40E_ERR_CONFIG;
}
}
continue;
rte_memcpy(list->list[j].addr, addr->addr_bytes,
sizeof(addr->addr_bytes));
- PMD_DRV_LOG(DEBUG, "add/rm mac:%x:%x:%x:%x:%x:%x",
- addr->addr_bytes[0], addr->addr_bytes[1],
- addr->addr_bytes[2], addr->addr_bytes[3],
- addr->addr_bytes[4], addr->addr_bytes[5]);
+ list->list[j].type = (j == 0 ?
+ VIRTCHNL_ETHER_ADDR_PRIMARY :
+ VIRTCHNL_ETHER_ADDR_EXTRA);
+ PMD_DRV_LOG(DEBUG, "add/rm mac:" RTE_ETHER_ADDR_PRT_FMT,
+ RTE_ETHER_ADDR_BYTES(addr));
j++;
}
list->vsi_id = vf->vsi_res->vsi_id;
return -1;
}
-static void
+static int
i40evf_dev_stop(struct rte_eth_dev *dev)
{
struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
rte_intr_disable(intr_handle);
if (hw->adapter_stopped == 1)
- return;
+ return 0;
i40evf_stop_queues(dev);
i40evf_disable_queues_intr(dev);
i40e_dev_clear_queues(dev);
i40evf_add_del_mc_addr_list(dev, vf->mc_addrs, vf->mc_addrs_num,
FALSE);
hw->adapter_stopped = 1;
+ dev->data->dev_started = 0;
+ return 0;
}
static int
new_link.link_speed = ETH_SPEED_NUM_40G;
break;
default:
- new_link.link_speed = ETH_SPEED_NUM_NONE;
+ if (vf->link_up)
+ new_link.link_speed = ETH_SPEED_NUM_UNKNOWN;
+ else
+ new_link.link_speed = ETH_SPEED_NUM_NONE;
break;
}
/* full duplex only */
new_link.link_duplex = ETH_LINK_FULL_DUPLEX;
- new_link.link_status = vf->link_up &&
- new_link.link_speed != ETH_SPEED_NUM_NONE
- ? ETH_LINK_UP
- : ETH_LINK_DOWN;
+ new_link.link_status = vf->link_up ? ETH_LINK_UP : ETH_LINK_DOWN;
new_link.link_autoneg =
!(dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED);
i40evf_dev_promiscuous_enable(struct rte_eth_dev *dev)
{
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
- int ret;
-
- ret = i40evf_config_promisc(dev, 1, vf->promisc_multicast_enabled);
- if (ret == 0)
- vf->promisc_unicast_enabled = TRUE;
- else if (ret == I40E_NOT_SUPPORTED)
- ret = -ENOTSUP;
- else
- ret = -EAGAIN;
- return ret;
+ return i40evf_config_promisc(dev, true, vf->promisc_multicast_enabled);
}
static int
i40evf_dev_promiscuous_disable(struct rte_eth_dev *dev)
{
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
- int ret;
-
- ret = i40evf_config_promisc(dev, 0, vf->promisc_multicast_enabled);
- if (ret == 0)
- vf->promisc_unicast_enabled = FALSE;
- else if (ret == I40E_NOT_SUPPORTED)
- ret = -ENOTSUP;
- else
- ret = -EAGAIN;
- return ret;
+ return i40evf_config_promisc(dev, false, vf->promisc_multicast_enabled);
}
static int
i40evf_dev_allmulticast_enable(struct rte_eth_dev *dev)
{
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
- int ret;
- ret = i40evf_config_promisc(dev, vf->promisc_unicast_enabled, 1);
- if (ret == 0)
- vf->promisc_multicast_enabled = TRUE;
- else if (ret == I40E_NOT_SUPPORTED)
- ret = -ENOTSUP;
- else
- ret = -EAGAIN;
-
- return ret;
+ return i40evf_config_promisc(dev, vf->promisc_unicast_enabled, true);
}
static int
i40evf_dev_allmulticast_disable(struct rte_eth_dev *dev)
{
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
- int ret;
-
- ret = i40evf_config_promisc(dev, vf->promisc_unicast_enabled, 0);
- if (ret == 0)
- vf->promisc_multicast_enabled = FALSE;
- else if (ret == I40E_NOT_SUPPORTED)
- ret = -ENOTSUP;
- else
- ret = -EAGAIN;
- return ret;
+ return i40evf_config_promisc(dev, vf->promisc_unicast_enabled, false);
}
static int
stats->imissed = pstats->rx_discards;
stats->oerrors = pstats->tx_errors + pstats->tx_discards;
stats->ibytes = pstats->rx_bytes;
+ stats->ibytes -= stats->ipackets * RTE_ETHER_CRC_LEN;
stats->obytes = pstats->tx_bytes;
} else {
PMD_DRV_LOG(ERR, "Get statistics failed");
return ret;
}
-static void
+static int
i40evf_dev_close(struct rte_eth_dev *dev)
{
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ int ret;
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return 0;
+
+ ret = i40evf_dev_stop(dev);
- i40evf_dev_stop(dev);
i40e_dev_free_queues(dev);
/*
* disable promiscuous mode before reset vf
* it is a workaround solution when work with kernel driver
* and it is not the normal way
*/
- i40evf_dev_promiscuous_disable(dev);
- i40evf_dev_allmulticast_disable(dev);
+ if (vf->promisc_unicast_enabled || vf->promisc_multicast_enabled)
+ i40evf_config_promisc(dev, false, false);
+
rte_eal_alarm_cancel(i40evf_dev_alarm_handler, dev);
i40evf_reset_vf(dev);
i40e_shutdown_adminq(hw);
i40evf_disable_irq0(hw);
- dev->dev_ops = NULL;
- dev->rx_pkt_burst = NULL;
- dev->tx_pkt_burst = NULL;
+ /*
+ * If the VF is reset via VFLR, the device will be knocked out of bus
+ * master mode, and the driver will fail to recover from the reset. Fix
+ * this by enabling bus mastering after every reset. In a non-VFLR case,
+ * the bus master bit will not be disabled, and this call will have no
+ * effect.
+ */
+ if (vf->vf_reset && !rte_pci_set_bus_master(pci_dev, true))
+ vf->vf_reset = false;
rte_free(vf->vf_res);
vf->vf_res = NULL;
vf->aq_resp = NULL;
hw->adapter_closed = 1;
+ return ret;
}
/*
}
for (i = 0; i < rss_lut_size; i++)
- lut_info[i] = i % vf->num_queue_pairs;
+ lut_info[i] = i % num;
ret = i40evf_set_rss_lut(&vf->vsi, lut_info,
rss_lut_size);
return -EBUSY;
}
- if (frame_size > RTE_ETHER_MAX_LEN)
+ if (frame_size > I40E_ETH_MAX_LEN)
dev_data->dev_conf.rxmode.offloads |=
DEV_RX_OFFLOAD_JUMBO_FRAME;
else
struct rte_ether_addr *mac_addr)
{
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_ether_addr *old_addr;
+ int ret;
+
+ old_addr = (struct rte_ether_addr *)hw->mac.addr;
if (!rte_is_valid_assigned_ether_addr(mac_addr)) {
PMD_DRV_LOG(ERR, "Tried to set invalid MAC address.");
return -EINVAL;
}
- i40evf_del_mac_addr_by_addr(dev, (struct rte_ether_addr *)hw->mac.addr);
+ if (rte_is_same_ether_addr(old_addr, mac_addr))
+ return 0;
- if (i40evf_add_mac_addr(dev, mac_addr, 0, 0) != 0)
+ i40evf_add_del_eth_addr(dev, old_addr, FALSE, VIRTCHNL_ETHER_ADDR_PRIMARY);
+
+ ret = i40evf_add_del_eth_addr(dev, mac_addr, TRUE, VIRTCHNL_ETHER_ADDR_PRIMARY);
+ if (ret)
return -EIO;
rte_ether_addr_copy(mac_addr, (struct rte_ether_addr *)hw->mac.addr);
for (i = 0; i < mc_addrs_num; i++) {
if (!I40E_IS_MULTICAST(mc_addrs[i].addr_bytes)) {
- PMD_DRV_LOG(ERR, "Invalid mac:%x:%x:%x:%x:%x:%x",
- mc_addrs[i].addr_bytes[0],
- mc_addrs[i].addr_bytes[1],
- mc_addrs[i].addr_bytes[2],
- mc_addrs[i].addr_bytes[3],
- mc_addrs[i].addr_bytes[4],
- mc_addrs[i].addr_bytes[5]);
+ PMD_DRV_LOG(ERR, "Invalid mac:" RTE_ETHER_ADDR_PRT_FMT,
+ RTE_ETHER_ADDR_BYTES(&mc_addrs[i]));
return -EINVAL;
}
memcpy(list->list[i].addr, mc_addrs[i].addr_bytes,
sizeof(list->list[i].addr));
+ list->list[i].type = VIRTCHNL_ETHER_ADDR_EXTRA;
}
args.ops = add ? VIRTCHNL_OP_ADD_ETH_ADDR : VIRTCHNL_OP_DEL_ETH_ADDR;