X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fenic%2Fenic_vf_representor.c;h=c2c03c02816692db5235b87a8a30cb540390e447;hb=c450ea96a48549eecf41c3f9f4e8a25da635439f;hp=cb41bb14061db089516c2b8f6a2ceb64ea07a422;hpb=edd0854815503c1c2b60cc80841b462873fa3866;p=dpdk.git diff --git a/drivers/net/enic/enic_vf_representor.c b/drivers/net/enic/enic_vf_representor.c index cb41bb1406..c2c03c0281 100644 --- a/drivers/net/enic/enic_vf_representor.c +++ b/drivers/net/enic/enic_vf_representor.c @@ -124,6 +124,33 @@ static int enic_vf_dev_configure(struct rte_eth_dev *eth_dev __rte_unused) return 0; } +static int +setup_rep_vf_fwd(struct enic_vf_representor *vf) +{ + int ret; + + ENICPMD_FUNC_TRACE(); + /* Representor -> VF rule + * Egress packets from this representor are on the representor's WQ. + * So, loop back that WQ to VF. + */ + ret = enic_fm_add_rep2vf_flow(vf); + if (ret) { + ENICPMD_LOG(ERR, "Cannot create representor->VF flow"); + return ret; + } + /* VF -> representor rule + * Packets from VF loop back to the representor, unless they match + * user-added flows. + */ + ret = enic_fm_add_vf2rep_flow(vf); + if (ret) { + ENICPMD_LOG(ERR, "Cannot create VF->representor flow"); + return ret; + } + return 0; +} + static int enic_vf_dev_start(struct rte_eth_dev *eth_dev) { struct enic_vf_representor *vf; @@ -138,6 +165,16 @@ static int enic_vf_dev_start(struct rte_eth_dev *eth_dev) vf = eth_dev->data->dev_private; pf = vf->pf; + /* Get representor flowman for flow API and representor path */ + ret = enic_fm_init(&vf->enic); + if (ret) + return ret; + /* Set up implicit flow rules to forward between representor and VF */ + ret = setup_rep_vf_fwd(vf); + if (ret) { + ENICPMD_LOG(ERR, "Cannot set up representor-VF flows"); + return ret; + } /* Remove all packet filters so no ingress packets go to VF. * When PF enables switchdev, it will ensure packet filters * are removed. So, this is not technically needed. @@ -205,7 +242,7 @@ static int enic_vf_dev_start(struct rte_eth_dev *eth_dev) return 0; } -static void enic_vf_dev_stop(struct rte_eth_dev *eth_dev) +static int enic_vf_dev_stop(struct rte_eth_dev *eth_dev) { struct enic_vf_representor *vf; struct vnic_rq *rq; @@ -213,7 +250,7 @@ static void enic_vf_dev_stop(struct rte_eth_dev *eth_dev) ENICPMD_FUNC_TRACE(); if (rte_eal_process_type() != RTE_PROC_PRIMARY) - return; + return 0; /* Undo dev_start. Disable/clean WQ */ vf = eth_dev->data->dev_private; pf = vf->pf; @@ -232,17 +269,142 @@ static void enic_vf_dev_stop(struct rte_eth_dev *eth_dev) vnic_cq_clean(&pf->cq[enic_cq_rq(vf->pf, vf->pf_rq_sop_idx)]); eth_dev->data->tx_queue_state[0] = RTE_ETH_QUEUE_STATE_STOPPED; eth_dev->data->rx_queue_state[0] = RTE_ETH_QUEUE_STATE_STOPPED; + /* Clean up representor flowman */ + enic_fm_destroy(&vf->enic); + + return 0; } /* * "close" is no-op for now and solely exists so that rte_eth_dev_close() * can finish its own cleanup without errors. */ -static void enic_vf_dev_close(struct rte_eth_dev *eth_dev __rte_unused) +static int enic_vf_dev_close(struct rte_eth_dev *eth_dev __rte_unused) { ENICPMD_FUNC_TRACE(); if (rte_eal_process_type() != RTE_PROC_PRIMARY) - return; + return 0; + return 0; +} + +static int +adjust_flow_attr(const struct rte_flow_attr *attrs, + struct rte_flow_attr *vf_attrs, + struct rte_flow_error *error) +{ + if (!attrs) { + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR, + NULL, "no attribute specified"); + } + /* + * Swap ingress and egress as the firmware view of direction + * is the opposite of the representor. + */ + *vf_attrs = *attrs; + if (attrs->ingress && !attrs->egress) { + vf_attrs->ingress = 0; + vf_attrs->egress = 1; + return 0; + } + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, NULL, + "representor only supports ingress"); +} + +static int +enic_vf_flow_validate(struct rte_eth_dev *dev, + const struct rte_flow_attr *attrs, + const struct rte_flow_item pattern[], + const struct rte_flow_action actions[], + struct rte_flow_error *error) +{ + struct rte_flow_attr vf_attrs; + int ret; + + ret = adjust_flow_attr(attrs, &vf_attrs, error); + if (ret) + return ret; + attrs = &vf_attrs; + return enic_fm_flow_ops.validate(dev, attrs, pattern, actions, error); +} + +static struct rte_flow * +enic_vf_flow_create(struct rte_eth_dev *dev, + const struct rte_flow_attr *attrs, + const struct rte_flow_item pattern[], + const struct rte_flow_action actions[], + struct rte_flow_error *error) +{ + struct rte_flow_attr vf_attrs; + + if (adjust_flow_attr(attrs, &vf_attrs, error)) + return NULL; + attrs = &vf_attrs; + return enic_fm_flow_ops.create(dev, attrs, pattern, actions, error); +} + +static int +enic_vf_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow, + struct rte_flow_error *error) +{ + return enic_fm_flow_ops.destroy(dev, flow, error); +} + +static int +enic_vf_flow_query(struct rte_eth_dev *dev, + struct rte_flow *flow, + const struct rte_flow_action *actions, + void *data, + struct rte_flow_error *error) +{ + return enic_fm_flow_ops.query(dev, flow, actions, data, error); +} + +static int +enic_vf_flow_flush(struct rte_eth_dev *dev, + struct rte_flow_error *error) +{ + return enic_fm_flow_ops.flush(dev, error); +} + +static const struct rte_flow_ops enic_vf_flow_ops = { + .validate = enic_vf_flow_validate, + .create = enic_vf_flow_create, + .destroy = enic_vf_flow_destroy, + .flush = enic_vf_flow_flush, + .query = enic_vf_flow_query, +}; + +static int +enic_vf_filter_ctrl(struct rte_eth_dev *eth_dev, + enum rte_filter_type filter_type, + enum rte_filter_op filter_op, + void *arg) +{ + struct enic_vf_representor *vf; + int ret = 0; + + ENICPMD_FUNC_TRACE(); + vf = eth_dev->data->dev_private; + switch (filter_type) { + case RTE_ETH_FILTER_GENERIC: + if (filter_op != RTE_ETH_FILTER_GET) + return -EINVAL; + if (vf->enic.flow_filter_mode == FILTER_FLOWMAN) { + *(const void **)arg = &enic_vf_flow_ops; + } else { + ENICPMD_LOG(WARNING, "VF representors require flowman support for rte_flow API"); + ret = -EINVAL; + } + break; + default: + ENICPMD_LOG(WARNING, "Filter type (%d) not supported", + filter_type); + ret = -EINVAL; + break; + } + return ret; } static int enic_vf_link_update(struct rte_eth_dev *eth_dev, @@ -404,6 +566,7 @@ static const struct eth_dev_ops enic_vf_representor_dev_ops = { .dev_start = enic_vf_dev_start, .dev_stop = enic_vf_dev_stop, .dev_close = enic_vf_dev_close, + .filter_ctrl = enic_vf_filter_ctrl, .link_update = enic_vf_link_update, .promiscuous_enable = enic_vf_promiscuous_enable, .promiscuous_disable = enic_vf_promiscuous_disable, @@ -509,8 +672,8 @@ int enic_vf_representor_init(struct rte_eth_dev *eth_dev, void *init_params) eth_dev->device->driver = pf->rte_dev->device->driver; eth_dev->dev_ops = &enic_vf_representor_dev_ops; - eth_dev->data->dev_flags |= RTE_ETH_DEV_REPRESENTOR - | RTE_ETH_DEV_CLOSE_REMOVE; + eth_dev->data->dev_flags |= RTE_ETH_DEV_REPRESENTOR | + RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS; eth_dev->data->representor_id = vf->vf_id; eth_dev->data->mac_addrs = rte_zmalloc("enic_mac_addr_vf", sizeof(struct rte_ether_addr) *