New upstream version 17.11.4
[deb_dpdk.git] / drivers / net / sfc / sfc_flow.c
index c3ea43a..90ef5bf 100644 (file)
@@ -107,7 +107,6 @@ sfc_flow_parse_init(const struct rte_flow_item *item,
        const uint8_t *spec;
        const uint8_t *mask;
        const uint8_t *last;
-       uint8_t match;
        uint8_t supp;
        unsigned int i;
 
@@ -168,12 +167,11 @@ sfc_flow_parse_init(const struct rte_flow_item *item,
                return -rte_errno;
        }
 
-       /* Check that mask and spec not asks for more match than supp_mask */
+       /* Check that mask does not ask for more match than supp_mask */
        for (i = 0; i < size; i++) {
-               match = spec[i] | mask[i];
                supp = ((const uint8_t *)supp_mask)[i];
 
-               if ((match | supp) != supp) {
+               if (~supp & mask[i]) {
                        rte_flow_error_set(error, ENOTSUP,
                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
                                           "Item's field is not supported");
@@ -332,7 +330,8 @@ sfc_flow_parse_vlan(const struct rte_flow_item *item,
         * the outer tag and the next matches the inner tag.
         */
        if (mask->tci == supp_mask.tci) {
-               vid = rte_bswap16(spec->tci);
+               /* Apply mask to keep VID only */
+               vid = rte_bswap16(spec->tci & mask->tci);
 
                if (!(efx_spec->efs_match_flags &
                      EFX_FILTER_MATCH_OUTER_VID)) {
@@ -803,7 +802,7 @@ sfc_flow_parse_attr(const struct rte_flow_attr *attr,
        }
 
        flow->spec.efs_flags |= EFX_FILTER_FLAG_RX;
-       flow->spec.efs_rss_context = EFX_FILTER_SPEC_RSS_CONTEXT_DEFAULT;
+       flow->spec.efs_rss_context = EFX_RSS_CONTEXT_DEFAULT;
 
        return 0;
 }
@@ -886,6 +885,170 @@ sfc_flow_parse_queue(struct sfc_adapter *sa,
        return 0;
 }
 
+#if EFSYS_OPT_RX_SCALE
+static int
+sfc_flow_parse_rss(struct sfc_adapter *sa,
+                  const struct rte_flow_action_rss *rss,
+                  struct rte_flow *flow)
+{
+       unsigned int rxq_sw_index;
+       struct sfc_rxq *rxq;
+       unsigned int rxq_hw_index_min;
+       unsigned int rxq_hw_index_max;
+       const struct rte_eth_rss_conf *rss_conf = rss->rss_conf;
+       uint64_t rss_hf;
+       uint8_t *rss_key = NULL;
+       struct sfc_flow_rss *sfc_rss_conf = &flow->rss_conf;
+       unsigned int i;
+
+       if (rss->num == 0)
+               return -EINVAL;
+
+       rxq_sw_index = sa->rxq_count - 1;
+       rxq = sa->rxq_info[rxq_sw_index].rxq;
+       rxq_hw_index_min = rxq->hw_index;
+       rxq_hw_index_max = 0;
+
+       for (i = 0; i < rss->num; ++i) {
+               rxq_sw_index = rss->queue[i];
+
+               if (rxq_sw_index >= sa->rxq_count)
+                       return -EINVAL;
+
+               rxq = sa->rxq_info[rxq_sw_index].rxq;
+
+               if (rxq->hw_index < rxq_hw_index_min)
+                       rxq_hw_index_min = rxq->hw_index;
+
+               if (rxq->hw_index > rxq_hw_index_max)
+                       rxq_hw_index_max = rxq->hw_index;
+       }
+
+       rss_hf = (rss_conf != NULL) ? rss_conf->rss_hf : SFC_RSS_OFFLOADS;
+       if ((rss_hf & ~SFC_RSS_OFFLOADS) != 0)
+               return -EINVAL;
+
+       if (rss_conf != NULL) {
+               if (rss_conf->rss_key_len != sizeof(sa->rss_key))
+                       return -EINVAL;
+
+               rss_key = rss_conf->rss_key;
+       } else {
+               rss_key = sa->rss_key;
+       }
+
+       flow->rss = B_TRUE;
+
+       sfc_rss_conf->rxq_hw_index_min = rxq_hw_index_min;
+       sfc_rss_conf->rxq_hw_index_max = rxq_hw_index_max;
+       sfc_rss_conf->rss_hash_types = sfc_rte_to_efx_hash_type(rss_hf);
+       rte_memcpy(sfc_rss_conf->rss_key, rss_key, sizeof(sa->rss_key));
+
+       for (i = 0; i < RTE_DIM(sfc_rss_conf->rss_tbl); ++i) {
+               unsigned int rxq_sw_index = rss->queue[i % rss->num];
+               struct sfc_rxq *rxq = sa->rxq_info[rxq_sw_index].rxq;
+
+               sfc_rss_conf->rss_tbl[i] = rxq->hw_index - rxq_hw_index_min;
+       }
+
+       return 0;
+}
+#endif /* EFSYS_OPT_RX_SCALE */
+
+static int
+sfc_flow_filter_insert(struct sfc_adapter *sa,
+                      struct rte_flow *flow)
+{
+       efx_filter_spec_t *spec = &flow->spec;
+
+#if EFSYS_OPT_RX_SCALE
+       struct sfc_flow_rss *rss = &flow->rss_conf;
+       int rc = 0;
+
+       if (flow->rss) {
+               unsigned int rss_spread = MIN(rss->rxq_hw_index_max -
+                                             rss->rxq_hw_index_min + 1,
+                                             EFX_MAXRSS);
+
+               rc = efx_rx_scale_context_alloc(sa->nic,
+                                               EFX_RX_SCALE_EXCLUSIVE,
+                                               rss_spread,
+                                               &spec->efs_rss_context);
+               if (rc != 0)
+                       goto fail_scale_context_alloc;
+
+               rc = efx_rx_scale_mode_set(sa->nic, spec->efs_rss_context,
+                                          EFX_RX_HASHALG_TOEPLITZ,
+                                          rss->rss_hash_types, B_TRUE);
+               if (rc != 0)
+                       goto fail_scale_mode_set;
+
+               rc = efx_rx_scale_key_set(sa->nic, spec->efs_rss_context,
+                                         rss->rss_key,
+                                         sizeof(sa->rss_key));
+               if (rc != 0)
+                       goto fail_scale_key_set;
+
+               spec->efs_dmaq_id = rss->rxq_hw_index_min;
+               spec->efs_flags |= EFX_FILTER_FLAG_RX_RSS;
+       }
+
+       rc = efx_filter_insert(sa->nic, spec);
+       if (rc != 0)
+               goto fail_filter_insert;
+
+       if (flow->rss) {
+               /*
+                * Scale table is set after filter insertion because
+                * the table entries are relative to the base RxQ ID
+                * and the latter is submitted to the HW by means of
+                * inserting a filter, so by the time of the request
+                * the HW knows all the information needed to verify
+                * the table entries, and the operation will succeed
+                */
+               rc = efx_rx_scale_tbl_set(sa->nic, spec->efs_rss_context,
+                                         rss->rss_tbl, RTE_DIM(rss->rss_tbl));
+               if (rc != 0)
+                       goto fail_scale_tbl_set;
+       }
+
+       return 0;
+
+fail_scale_tbl_set:
+       efx_filter_remove(sa->nic, spec);
+
+fail_filter_insert:
+fail_scale_key_set:
+fail_scale_mode_set:
+       if (flow->rss)
+               efx_rx_scale_context_free(sa->nic, spec->efs_rss_context);
+
+fail_scale_context_alloc:
+       return rc;
+#else /* !EFSYS_OPT_RX_SCALE */
+       return efx_filter_insert(sa->nic, spec);
+#endif /* EFSYS_OPT_RX_SCALE */
+}
+
+static int
+sfc_flow_filter_remove(struct sfc_adapter *sa,
+                      struct rte_flow *flow)
+{
+       efx_filter_spec_t *spec = &flow->spec;
+       int rc = 0;
+
+       rc = efx_filter_remove(sa->nic, spec);
+       if (rc != 0)
+               return rc;
+
+#if EFSYS_OPT_RX_SCALE
+       if (flow->rss)
+               rc = efx_rx_scale_context_free(sa->nic, spec->efs_rss_context);
+#endif /* EFSYS_OPT_RX_SCALE */
+
+       return rc;
+}
+
 static int
 sfc_flow_parse_actions(struct sfc_adapter *sa,
                       const struct rte_flow_action actions[],
@@ -919,6 +1082,20 @@ sfc_flow_parse_actions(struct sfc_adapter *sa,
                        is_specified = B_TRUE;
                        break;
 
+#if EFSYS_OPT_RX_SCALE
+               case RTE_FLOW_ACTION_TYPE_RSS:
+                       rc = sfc_flow_parse_rss(sa, actions->conf, flow);
+                       if (rc != 0) {
+                               rte_flow_error_set(error, rc,
+                                       RTE_FLOW_ERROR_TYPE_ACTION, actions,
+                                       "Bad RSS action");
+                               return -rte_errno;
+                       }
+
+                       is_specified = B_TRUE;
+                       break;
+#endif /* EFSYS_OPT_RX_SCALE */
+
                default:
                        rte_flow_error_set(error, ENOTSUP,
                                           RTE_FLOW_ERROR_TYPE_ACTION, actions,
@@ -948,8 +1125,6 @@ sfc_flow_parse(struct rte_eth_dev *dev,
        struct sfc_adapter *sa = dev->data->dev_private;
        int rc;
 
-       memset(&flow->spec, 0, sizeof(flow->spec));
-
        rc = sfc_flow_parse_attr(attr, flow, error);
        if (rc != 0)
                goto fail_bad_value;
@@ -982,6 +1157,8 @@ sfc_flow_validate(struct rte_eth_dev *dev,
 {
        struct rte_flow flow;
 
+       memset(&flow, 0, sizeof(flow));
+
        return sfc_flow_parse(dev, attr, pattern, actions, &flow, error);
 }
 
@@ -1013,7 +1190,7 @@ sfc_flow_create(struct rte_eth_dev *dev,
        sfc_adapter_lock(sa);
 
        if (sa->state == SFC_ADAPTER_STARTED) {
-               rc = efx_filter_insert(sa->nic, &flow->spec);
+               rc = sfc_flow_filter_insert(sa, flow);
                if (rc != 0) {
                        rte_flow_error_set(error, rc,
                                RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
@@ -1047,7 +1224,7 @@ sfc_flow_remove(struct sfc_adapter *sa,
        SFC_ASSERT(sfc_adapter_is_locked(sa));
 
        if (sa->state == SFC_ADAPTER_STARTED) {
-               rc = efx_filter_remove(sa->nic, &flow->spec);
+               rc = sfc_flow_filter_remove(sa, flow);
                if (rc != 0)
                        rte_flow_error_set(error, rc,
                                RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
@@ -1112,12 +1289,35 @@ sfc_flow_flush(struct rte_eth_dev *dev,
        return -ret;
 }
 
+static int
+sfc_flow_isolate(struct rte_eth_dev *dev, int enable,
+                struct rte_flow_error *error)
+{
+       struct sfc_adapter *sa = dev->data->dev_private;
+       struct sfc_port *port = &sa->port;
+       int ret = 0;
+
+       sfc_adapter_lock(sa);
+       if (sa->state != SFC_ADAPTER_INITIALIZED) {
+               rte_flow_error_set(error, EBUSY,
+                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                  NULL, "please close the port first");
+               ret = -rte_errno;
+       } else {
+               port->isolated = (enable) ? B_TRUE : B_FALSE;
+       }
+       sfc_adapter_unlock(sa);
+
+       return ret;
+}
+
 const struct rte_flow_ops sfc_flow_ops = {
        .validate = sfc_flow_validate,
        .create = sfc_flow_create,
        .destroy = sfc_flow_destroy,
        .flush = sfc_flow_flush,
        .query = NULL,
+       .isolate = sfc_flow_isolate,
 };
 
 void
@@ -1149,7 +1349,7 @@ sfc_flow_stop(struct sfc_adapter *sa)
        SFC_ASSERT(sfc_adapter_is_locked(sa));
 
        TAILQ_FOREACH(flow, &sa->filter.flow_list, entries)
-               efx_filter_remove(sa->nic, &flow->spec);
+               sfc_flow_filter_remove(sa, flow);
 }
 
 int
@@ -1163,7 +1363,7 @@ sfc_flow_start(struct sfc_adapter *sa)
        SFC_ASSERT(sfc_adapter_is_locked(sa));
 
        TAILQ_FOREACH(flow, &sa->filter.flow_list, entries) {
-               rc = efx_filter_insert(sa->nic, &flow->spec);
+               rc = sfc_flow_filter_insert(sa, flow);
                if (rc != 0)
                        goto fail_bad_flow;
        }