The VF device management in netvsc was using a pointer to the
rte_eth_devices. But the actual rte_eth_devices array is likely to
be place in the secondary process; which causes a crash.
The solution is to record the port of the VF (instead of a pointer)
and find the device in the per process array as needed.
Fixes:
dc7680e8597c ("net/netvsc: support integrated VF")
Cc: stable@dpdk.org
Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
hv->port_id = eth_dev->data->port_id;
hv->latency = HN_CHAN_LATENCY_NS;
hv->max_queues = 1;
hv->port_id = eth_dev->data->port_id;
hv->latency = HN_CHAN_LATENCY_NS;
hv->max_queues = 1;
+ hv->vf_port = HN_INVALID_PORT;
err = hn_parse_args(eth_dev);
if (err)
err = hn_parse_args(eth_dev);
if (err)
hv->max_queues = RTE_MIN(rxr_cnt, (unsigned int)max_chan);
/* If VF was reported but not added, do it now */
hv->max_queues = RTE_MIN(rxr_cnt, (unsigned int)max_chan);
/* If VF was reported but not added, do it now */
- if (hv->vf_present && !hv->vf_dev) {
+ if (hv->vf_present && !hn_vf_attached(hv)) {
PMD_INIT_LOG(DEBUG, "Adding VF device");
err = hn_vf_add(eth_dev, hv);
PMD_INIT_LOG(DEBUG, "Adding VF device");
err = hn_vf_add(eth_dev, hv);
return 0;
/* Transmit over VF if present and up */
return 0;
/* Transmit over VF if present and up */
- vf_dev = hv->vf_dev;
- rte_compiler_barrier();
+ vf_dev = hn_get_vf_dev(hv);
+
if (vf_dev && vf_dev->data->dev_started) {
void *sub_q = vf_dev->data->tx_queues[queue_id];
if (vf_dev && vf_dev->data->dev_started) {
void *sub_q = vf_dev->data->tx_queues[queue_id];
if (unlikely(hv->closed))
return 0;
if (unlikely(hv->closed))
return 0;
- vf_dev = hv->vf_dev;
- rte_compiler_barrier();
+ /* Transmit over VF if present and up */
+ vf_dev = hn_get_vf_dev(hv);
if (vf_dev && vf_dev->data->dev_started) {
/* Normally, with SR-IOV the ring buffer will be empty */
if (vf_dev && vf_dev->data->dev_started) {
/* Normally, with SR-IOV the ring buffer will be empty */
struct rte_mbuf_ext_shared_info shinfo;
} __rte_cache_aligned;
struct rte_mbuf_ext_shared_info shinfo;
} __rte_cache_aligned;
+#define HN_INVALID_PORT UINT16_MAX
+
struct hn_data {
struct rte_vmbus_device *vmbus;
struct hn_rx_queue *primary;
struct hn_data {
struct rte_vmbus_device *vmbus;
struct hn_rx_queue *primary;
- struct rte_eth_dev *vf_dev; /* Subordinate device */
rte_spinlock_t vf_lock;
uint16_t port_id;
rte_spinlock_t vf_lock;
uint16_t port_id;
uint32_t link_status;
uint32_t link_speed;
uint32_t link_status;
uint32_t link_speed;
struct rte_mempool *mp);
void hn_dev_rx_queue_release(void *arg);
struct rte_mempool *mp);
void hn_dev_rx_queue_release(void *arg);
+/* Check if VF is attached */
+static inline bool
+hn_vf_attached(const struct hn_data *hv)
+{
+ return hv->vf_port != HN_INVALID_PORT;
+}
+
+/* Get VF device for existing netvsc device */
+static inline struct rte_eth_dev *
+hn_get_vf_dev(const struct hn_data *hv)
+{
+ uint16_t vf_port = hv->vf_port;
+
+ /* make sure vf_port is loaded */
+ rte_smp_rmb();
+
+ if (vf_port == HN_INVALID_PORT)
+ return NULL;
+ else
+ return &rte_eth_devices[vf_port];
+}
+
void hn_vf_info_get(struct hn_data *hv,
struct rte_eth_dev_info *info);
int hn_vf_add(struct rte_eth_dev *dev, struct hn_data *hv);
void hn_vf_info_get(struct hn_data *hv,
struct rte_eth_dev_info *info);
int hn_vf_add(struct rte_eth_dev *dev, struct hn_data *hv);
/*
* Attach new PCI VF device and return the port_id
*/
/*
* Attach new PCI VF device and return the port_id
*/
-static int hn_vf_attach(struct hn_data *hv, uint16_t port_id,
- struct rte_eth_dev **vf_dev)
+static int hn_vf_attach(struct hn_data *hv, uint16_t port_id)
{
struct rte_eth_dev_owner owner = { .id = RTE_ETH_DEV_NO_OWNER };
int ret;
{
struct rte_eth_dev_owner owner = { .id = RTE_ETH_DEV_NO_OWNER };
int ret;
+ if (hn_vf_attached(hv)) {
+ PMD_DRV_LOG(ERR, "VF already attached");
+ return -EEXIST;
+ }
+
ret = rte_eth_dev_owner_get(port_id, &owner);
if (ret < 0) {
PMD_DRV_LOG(ERR, "Can not find owner for port %d", port_id);
ret = rte_eth_dev_owner_get(port_id, &owner);
if (ret < 0) {
PMD_DRV_LOG(ERR, "Can not find owner for port %d", port_id);
}
PMD_DRV_LOG(DEBUG, "Attach VF device %u", port_id);
}
PMD_DRV_LOG(DEBUG, "Attach VF device %u", port_id);
- *vf_dev = &rte_eth_devices[port_id];
}
rte_spinlock_lock(&hv->vf_lock);
}
rte_spinlock_lock(&hv->vf_lock);
- if (hv->vf_dev) {
- PMD_DRV_LOG(ERR, "VF already attached");
- err = -EBUSY;
- } else {
- err = hn_vf_attach(hv, port, &hv->vf_dev);
- }
+ err = hn_vf_attach(hv, port);
if (err == 0) {
dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
if (err == 0) {
dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
/* Remove new VF device */
static void hn_vf_remove(struct hn_data *hv)
{
/* Remove new VF device */
static void hn_vf_remove(struct hn_data *hv)
{
- struct rte_eth_dev *vf_dev;
rte_spinlock_lock(&hv->vf_lock);
rte_spinlock_lock(&hv->vf_lock);
- vf_dev = hv->vf_dev;
- if (!vf_dev) {
+
+ if (!hn_vf_attached(hv)) {
PMD_DRV_LOG(ERR, "VF path not active");
PMD_DRV_LOG(ERR, "VF path not active");
- rte_spinlock_unlock(&hv->vf_lock);
- return;
- }
+ } else {
+ /* Stop incoming packets from arriving on VF */
+ hn_nvs_set_datapath(hv, NVS_DATAPATH_SYNTHETIC);
- /* Stop incoming packets from arriving on VF */
- hn_nvs_set_datapath(hv, NVS_DATAPATH_SYNTHETIC);
- hv->vf_dev = NULL;
+ /* Stop transmission over VF */
+ hv->vf_port = HN_INVALID_PORT;
+ rte_smp_wmb();
- /* Give back ownership */
- rte_eth_dev_owner_unset(vf_dev->data->port_id, hv->owner.id);
+ /* Give back ownership */
+ rte_eth_dev_owner_unset(hv->vf_port, hv->owner.id);
+ }
rte_spinlock_unlock(&hv->vf_lock);
}
rte_spinlock_unlock(&hv->vf_lock);
}
struct rte_eth_dev *vf_dev;
rte_spinlock_lock(&hv->vf_lock);
struct rte_eth_dev *vf_dev;
rte_spinlock_lock(&hv->vf_lock);
+ vf_dev = hn_get_vf_dev(hv);
if (vf_dev)
hn_vf_info_merge(vf_dev, info);
rte_spinlock_unlock(&hv->vf_lock);
if (vf_dev)
hn_vf_info_merge(vf_dev, info);
rte_spinlock_unlock(&hv->vf_lock);
int ret = 0;
rte_spinlock_lock(&hv->vf_lock);
int ret = 0;
rte_spinlock_lock(&hv->vf_lock);
+ vf_dev = hn_get_vf_dev(hv);
if (vf_dev && vf_dev->dev_ops->link_update)
ret = (*vf_dev->dev_ops->link_update)(vf_dev, wait_to_complete);
rte_spinlock_unlock(&hv->vf_lock);
if (vf_dev && vf_dev->dev_ops->link_update)
ret = (*vf_dev->dev_ops->link_update)(vf_dev, wait_to_complete);
rte_spinlock_unlock(&hv->vf_lock);
}
static int _hn_vf_configure(struct rte_eth_dev *dev,
}
static int _hn_vf_configure(struct rte_eth_dev *dev,
- struct rte_eth_dev *vf_dev,
const struct rte_eth_conf *dev_conf)
{
struct rte_eth_conf vf_conf = *dev_conf;
const struct rte_eth_conf *dev_conf)
{
struct rte_eth_conf vf_conf = *dev_conf;
- uint16_t vf_port = vf_dev->data->port_id;
+ struct rte_eth_dev *vf_dev;
+ vf_dev = &rte_eth_devices[vf_port];
if (dev_conf->intr_conf.lsc &&
(vf_dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)) {
PMD_DRV_LOG(DEBUG, "enabling LSC for VF %u",
if (dev_conf->intr_conf.lsc &&
(vf_dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)) {
PMD_DRV_LOG(DEBUG, "enabling LSC for VF %u",
const struct rte_eth_conf *dev_conf)
{
struct hn_data *hv = dev->data->dev_private;
const struct rte_eth_conf *dev_conf)
{
struct hn_data *hv = dev->data->dev_private;
- struct rte_eth_dev *vf_dev;
int ret = 0;
rte_spinlock_lock(&hv->vf_lock);
int ret = 0;
rte_spinlock_lock(&hv->vf_lock);
- vf_dev = hv->vf_dev;
- if (vf_dev)
- ret = _hn_vf_configure(dev, vf_dev, dev_conf);
+ if (hv->vf_port != HN_INVALID_PORT)
+ ret = _hn_vf_configure(dev, hv->vf_port, dev_conf);
rte_spinlock_unlock(&hv->vf_lock);
return ret;
}
rte_spinlock_unlock(&hv->vf_lock);
return ret;
}
const uint32_t *ptypes = NULL;
rte_spinlock_lock(&hv->vf_lock);
const uint32_t *ptypes = NULL;
rte_spinlock_lock(&hv->vf_lock);
+ vf_dev = hn_get_vf_dev(hv);
if (vf_dev && vf_dev->dev_ops->dev_supported_ptypes_get)
ptypes = (*vf_dev->dev_ops->dev_supported_ptypes_get)(vf_dev);
rte_spinlock_unlock(&hv->vf_lock);
if (vf_dev && vf_dev->dev_ops->dev_supported_ptypes_get)
ptypes = (*vf_dev->dev_ops->dev_supported_ptypes_get)(vf_dev);
rte_spinlock_unlock(&hv->vf_lock);
int ret = 0;
rte_spinlock_lock(&hv->vf_lock);
int ret = 0;
rte_spinlock_lock(&hv->vf_lock);
+ vf_dev = hn_get_vf_dev(hv);
if (vf_dev)
ret = rte_eth_dev_start(vf_dev->data->port_id);
rte_spinlock_unlock(&hv->vf_lock);
if (vf_dev)
ret = rte_eth_dev_start(vf_dev->data->port_id);
rte_spinlock_unlock(&hv->vf_lock);
struct rte_eth_dev *vf_dev;
rte_spinlock_lock(&hv->vf_lock);
struct rte_eth_dev *vf_dev;
rte_spinlock_lock(&hv->vf_lock);
+ vf_dev = hn_get_vf_dev(hv);
if (vf_dev)
rte_eth_dev_stop(vf_dev->data->port_id);
rte_spinlock_unlock(&hv->vf_lock);
if (vf_dev)
rte_eth_dev_stop(vf_dev->data->port_id);
rte_spinlock_unlock(&hv->vf_lock);
struct hn_data *hv = (dev)->data->dev_private; \
struct rte_eth_dev *vf_dev; \
rte_spinlock_lock(&hv->vf_lock); \
struct hn_data *hv = (dev)->data->dev_private; \
struct rte_eth_dev *vf_dev; \
rte_spinlock_lock(&hv->vf_lock); \
+ vf_dev = hn_get_vf_dev(hv); \
if (vf_dev) \
func(vf_dev->data->port_id); \
rte_spinlock_unlock(&hv->vf_lock); \
if (vf_dev) \
func(vf_dev->data->port_id); \
rte_spinlock_unlock(&hv->vf_lock); \
int ret = 0;
rte_spinlock_lock(&hv->vf_lock);
int ret = 0;
rte_spinlock_lock(&hv->vf_lock);
+ vf_dev = hn_get_vf_dev(hv);
if (vf_dev)
ret = rte_eth_dev_set_mc_addr_list(vf_dev->data->port_id,
mc_addr_set, nb_mc_addr);
if (vf_dev)
ret = rte_eth_dev_set_mc_addr_list(vf_dev->data->port_id,
mc_addr_set, nb_mc_addr);
int ret = 0;
rte_spinlock_lock(&hv->vf_lock);
int ret = 0;
rte_spinlock_lock(&hv->vf_lock);
+ vf_dev = hn_get_vf_dev(hv);
if (vf_dev)
ret = rte_eth_tx_queue_setup(vf_dev->data->port_id,
queue_idx, nb_desc,
if (vf_dev)
ret = rte_eth_tx_queue_setup(vf_dev->data->port_id,
queue_idx, nb_desc,
struct rte_eth_dev *vf_dev;
rte_spinlock_lock(&hv->vf_lock);
struct rte_eth_dev *vf_dev;
rte_spinlock_lock(&hv->vf_lock);
+ vf_dev = hn_get_vf_dev(hv);
if (vf_dev && vf_dev->dev_ops->tx_queue_release) {
void *subq = vf_dev->data->tx_queues[queue_id];
if (vf_dev && vf_dev->dev_ops->tx_queue_release) {
void *subq = vf_dev->data->tx_queues[queue_id];
int ret = 0;
rte_spinlock_lock(&hv->vf_lock);
int ret = 0;
rte_spinlock_lock(&hv->vf_lock);
+ vf_dev = hn_get_vf_dev(hv);
if (vf_dev)
ret = rte_eth_rx_queue_setup(vf_dev->data->port_id,
queue_idx, nb_desc,
if (vf_dev)
ret = rte_eth_rx_queue_setup(vf_dev->data->port_id,
queue_idx, nb_desc,
struct rte_eth_dev *vf_dev;
rte_spinlock_lock(&hv->vf_lock);
struct rte_eth_dev *vf_dev;
rte_spinlock_lock(&hv->vf_lock);
+ vf_dev = hn_get_vf_dev(hv);
if (vf_dev && vf_dev->dev_ops->rx_queue_release) {
void *subq = vf_dev->data->rx_queues[queue_id];
if (vf_dev && vf_dev->dev_ops->rx_queue_release) {
void *subq = vf_dev->data->rx_queues[queue_id];
int ret = 0;
rte_spinlock_lock(&hv->vf_lock);
int ret = 0;
rte_spinlock_lock(&hv->vf_lock);
+ vf_dev = hn_get_vf_dev(hv);
if (vf_dev)
ret = rte_eth_stats_get(vf_dev->data->port_id, stats);
rte_spinlock_unlock(&hv->vf_lock);
if (vf_dev)
ret = rte_eth_stats_get(vf_dev->data->port_id, stats);
rte_spinlock_unlock(&hv->vf_lock);
char tmp[RTE_ETH_XSTATS_NAME_SIZE];
rte_spinlock_lock(&hv->vf_lock);
char tmp[RTE_ETH_XSTATS_NAME_SIZE];
rte_spinlock_lock(&hv->vf_lock);
+ vf_dev = hn_get_vf_dev(hv);
if (vf_dev && vf_dev->dev_ops->xstats_get_names)
count = vf_dev->dev_ops->xstats_get_names(vf_dev, names, n);
rte_spinlock_unlock(&hv->vf_lock);
if (vf_dev && vf_dev->dev_ops->xstats_get_names)
count = vf_dev->dev_ops->xstats_get_names(vf_dev, names, n);
rte_spinlock_unlock(&hv->vf_lock);
int count = 0;
rte_spinlock_lock(&hv->vf_lock);
int count = 0;
rte_spinlock_lock(&hv->vf_lock);
+ vf_dev = hn_get_vf_dev(hv);
if (vf_dev && vf_dev->dev_ops->xstats_get)
count = vf_dev->dev_ops->xstats_get(vf_dev, xstats, n);
rte_spinlock_unlock(&hv->vf_lock);
if (vf_dev && vf_dev->dev_ops->xstats_get)
count = vf_dev->dev_ops->xstats_get(vf_dev, xstats, n);
rte_spinlock_unlock(&hv->vf_lock);
struct rte_eth_dev *vf_dev;
rte_spinlock_lock(&hv->vf_lock);
struct rte_eth_dev *vf_dev;
rte_spinlock_lock(&hv->vf_lock);
+ vf_dev = hn_get_vf_dev(hv);
if (vf_dev && vf_dev->dev_ops->xstats_reset)
vf_dev->dev_ops->xstats_reset(vf_dev);
rte_spinlock_unlock(&hv->vf_lock);
if (vf_dev && vf_dev->dev_ops->xstats_reset)
vf_dev->dev_ops->xstats_reset(vf_dev);
rte_spinlock_unlock(&hv->vf_lock);