diff options
Diffstat (limited to 'drivers/net/ethernet/netronome')
28 files changed, 634 insertions, 177 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/flower/action.c b/drivers/net/ethernet/netronome/nfp/flower/action.c index 0147de405365..7453cc5ba832 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/action.c +++ b/drivers/net/ethernet/netronome/nfp/flower/action.c @@ -149,7 +149,7 @@ nfp_fl_pre_lag(struct nfp_app *app, const struct flow_action_entry *act, } /* Pre_lag action must be first on action list. - * If other actions already exist they need pushed forward. + * If other actions already exist they need to be pushed forward. */ if (act_len) memmove(nfp_flow->action_data + act_size, @@ -674,9 +674,9 @@ nfp_fl_set_ip6_hop_limit_flow_label(u32 off, __be32 exact, __be32 mask, fl_hl_mask->hop_limit; break; case round_down(offsetof(struct ipv6hdr, flow_lbl), 4): - if (mask & ~IPV6_FLOW_LABEL_MASK || - exact & ~IPV6_FLOW_LABEL_MASK) { - NL_SET_ERR_MSG_MOD(extack, "unsupported offload: invalid pedit IPv6 flow label action"); + if (mask & ~IPV6_FLOWINFO_MASK || + exact & ~IPV6_FLOWINFO_MASK) { + NL_SET_ERR_MSG_MOD(extack, "unsupported offload: invalid pedit IPv6 flow info action"); return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h index 68e8a2fb1a29..2df2af1da716 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/cmsg.h +++ b/drivers/net/ethernet/netronome/nfp/flower/cmsg.h @@ -96,8 +96,6 @@ #define NFP_FL_PUSH_VLAN_PRIO GENMASK(15, 13) #define NFP_FL_PUSH_VLAN_VID GENMASK(11, 0) -#define IPV6_FLOW_LABEL_MASK cpu_to_be32(0x000fffff) - /* LAG ports */ #define NFP_FL_LAG_OUT 0xC0DE0000 diff --git a/drivers/net/ethernet/netronome/nfp/flower/conntrack.c b/drivers/net/ethernet/netronome/nfp/flower/conntrack.c index 7c31a46195b2..b3b2a23b8d89 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/conntrack.c +++ b/drivers/net/ethernet/netronome/nfp/flower/conntrack.c @@ -182,7 +182,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1, u8 ip_proto = 0; /* Temporary buffer for mangling keys, 64 is enough to cover max * struct size of key in various fields that may be mangled. - * Supported fileds to mangle: + * Supported fields to mangle: * mac_src/mac_dst(struct flow_match_eth_addrs, 12B) * nw_tos/nw_ttl(struct flow_match_ip, 2B) * nw_src/nw_dst(struct flow_match_ipv4/6_addrs, 32B) @@ -194,7 +194,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1, entry1->netdev != entry2->netdev) return -EINVAL; - /* check the overlapped fields one by one, the unmasked part + /* Check the overlapped fields one by one, the unmasked part * should not conflict with each other. */ if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL)) { @@ -563,7 +563,7 @@ static int nfp_fl_merge_actions_offload(struct flow_rule **rules, if (flow_rule_match_key(rules[j], FLOW_DISSECTOR_KEY_BASIC)) { struct flow_match_basic match; - /* ip_proto is the only field that needed in later compile_action, + /* ip_proto is the only field that is needed in later compile_action, * needed to set the correct checksum flags. It doesn't really matter * which input rule's ip_proto field we take as the earlier merge checks * would have made sure that they don't conflict. We do not know which @@ -1013,7 +1013,7 @@ static int nfp_ct_do_nft_merge(struct nfp_fl_ct_zone_entry *zt, nft_m_entry->tc_m_parent = tc_m_entry; nft_m_entry->nft_parent = nft_entry; nft_m_entry->tc_flower_cookie = 0; - /* Copy the netdev from one the pre_ct entry. When the tc_m_entry was created + /* Copy the netdev from the pre_ct entry. When the tc_m_entry was created * it only combined them if the netdevs were the same, so can use any of them. */ nft_m_entry->netdev = pre_ct_entry->netdev; @@ -1143,7 +1143,7 @@ nfp_fl_ct_zone_entry *get_nfp_zone_entry(struct nfp_flower_priv *priv, zt->priv = priv; zt->nft = NULL; - /* init the various hash tables and lists*/ + /* init the various hash tables and lists */ INIT_LIST_HEAD(&zt->pre_ct_list); INIT_LIST_HEAD(&zt->post_ct_list); INIT_LIST_HEAD(&zt->nft_flows_list); @@ -1346,7 +1346,7 @@ static void nfp_free_nft_merge_children(void *entry, bool is_nft_flow) */ if (is_nft_flow) { - /* Need to iterate through list of nft_flow entries*/ + /* Need to iterate through list of nft_flow entries */ struct nfp_fl_ct_flow_entry *ct_entry = entry; list_for_each_entry_safe(m_entry, tmp, &ct_entry->children, @@ -1354,7 +1354,7 @@ static void nfp_free_nft_merge_children(void *entry, bool is_nft_flow) cleanup_nft_merge_entry(m_entry); } } else { - /* Need to iterate through list of tc_merged_flow entries*/ + /* Need to iterate through list of tc_merged_flow entries */ struct nfp_fl_ct_tc_merge *ct_entry = entry; list_for_each_entry_safe(m_entry, tmp, &ct_entry->children, diff --git a/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c b/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c index ede90e086b28..e92860e20a24 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c +++ b/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c @@ -234,7 +234,7 @@ nfp_fl_lag_config_group(struct nfp_fl_lag *lag, struct nfp_fl_lag_group *group, } /* To signal the end of a batch, both the switch and last flags are set - * and the the reserved SYNC group ID is used. + * and the reserved SYNC group ID is used. */ if (*batch == NFP_FL_LAG_BATCH_FINISHED) { flags |= NFP_FL_LAG_SWITCH | NFP_FL_LAG_LAST; @@ -576,7 +576,7 @@ nfp_fl_lag_changeupper_event(struct nfp_fl_lag *lag, group->dirty = true; group->slave_cnt = slave_count; - /* Group may have been on queue for removal but is now offloable. */ + /* Group may have been on queue for removal but is now offloadable. */ group->to_remove = false; mutex_unlock(&lag->lock); diff --git a/drivers/net/ethernet/netronome/nfp/flower/metadata.c b/drivers/net/ethernet/netronome/nfp/flower/metadata.c index 74e1b279c13b..0f06ef6e24bf 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/metadata.c +++ b/drivers/net/ethernet/netronome/nfp/flower/metadata.c @@ -339,7 +339,7 @@ int nfp_compile_flow_metadata(struct nfp_app *app, u32 cookie, goto err_free_ctx_entry; } - /* Do net allocate a mask-id for pre_tun_rules. These flows are used to + /* Do not allocate a mask-id for pre_tun_rules. These flows are used to * configure the pre_tun table and are never actually send to the * firmware as an add-flow message. This causes the mask-id allocation * on the firmware to get out of sync if allocated here. diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c index 9d65459bdba5..83c97154c0c7 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/offload.c +++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c @@ -359,7 +359,7 @@ nfp_flower_calculate_key_layers(struct nfp_app *app, flow_rule_match_enc_opts(rule, &enc_op); if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS)) { - /* check if GRE, which has no enc_ports */ + /* Check if GRE, which has no enc_ports */ if (!netif_is_gretap(netdev) && !netif_is_ip6gretap(netdev)) { NL_SET_ERR_MSG_MOD(extack, "unsupported offload: an exact match on L4 destination port is required for non-GRE tunnels"); return -EOPNOTSUPP; @@ -1016,7 +1016,7 @@ int nfp_flower_merge_offloaded_flows(struct nfp_app *app, nfp_flower_is_merge_flow(sub_flow2)) return -EINVAL; - /* check if the two flows are already merged */ + /* Check if the two flows are already merged */ parent_ctx = (u64)(be32_to_cpu(sub_flow1->meta.host_ctx_id)) << 32; parent_ctx |= (u64)(be32_to_cpu(sub_flow2->meta.host_ctx_id)); if (rhashtable_lookup_fast(&priv->merge_table, diff --git a/drivers/net/ethernet/netronome/nfp/flower/qos_conf.c b/drivers/net/ethernet/netronome/nfp/flower/qos_conf.c index 3206ba83b1aa..4e5df9f2c372 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/qos_conf.c +++ b/drivers/net/ethernet/netronome/nfp/flower/qos_conf.c @@ -534,7 +534,7 @@ int nfp_flower_setup_qos_offload(struct nfp_app *app, struct net_device *netdev, } } -/* offload tc action, currently only for tc police */ +/* Offload tc action, currently only for tc police */ static const struct rhashtable_params stats_meter_table_params = { .key_offset = offsetof(struct nfp_meter_entry, meter_id), @@ -690,7 +690,7 @@ nfp_act_install_actions(struct nfp_app *app, struct flow_offload_action *fl_act, pps_support = !!(fl_priv->flower_ext_feats & NFP_FL_FEATS_QOS_PPS); for (i = 0 ; i < action_num; i++) { - /*set qos associate data for this interface */ + /* Set qos associate data for this interface */ action = paction + i; if (action->id != FLOW_ACTION_POLICE) { NL_SET_ERR_MSG_MOD(extack, @@ -736,7 +736,7 @@ nfp_act_remove_actions(struct nfp_app *app, struct flow_offload_action *fl_act, u32 meter_id; bool pps; - /*delete qos associate data for this interface */ + /* Delete qos associate data for this interface */ if (fl_act->id != FLOW_ACTION_POLICE) { NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload requires police action"); diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c index 97dcf8db7ed2..52f67157bd0f 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c +++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c @@ -1072,7 +1072,7 @@ nfp_tunnel_del_shared_mac(struct nfp_app *app, struct net_device *netdev, return 0; entry->ref_count--; - /* If del is part of a mod then mac_list is still in use elsewheree. */ + /* If del is part of a mod then mac_list is still in use elsewhere. */ if (nfp_netdev_is_nfp_repr(netdev) && !mod) { repr = netdev_priv(netdev); repr_priv = repr->app_priv; diff --git a/drivers/net/ethernet/netronome/nfp/nfd3/dp.c b/drivers/net/ethernet/netronome/nfp/nfd3/dp.c index 7db56abaa582..448c1c1afaee 100644 --- a/drivers/net/ethernet/netronome/nfp/nfd3/dp.c +++ b/drivers/net/ethernet/netronome/nfp/nfd3/dp.c @@ -3,6 +3,7 @@ #include <linux/bpf_trace.h> #include <linux/netdevice.h> +#include <linux/bitfield.h> #include "../nfp_app.h" #include "../nfp_net.h" @@ -81,12 +82,11 @@ nfp_nfd3_tx_tso(struct nfp_net_r_vector *r_vec, struct nfp_nfd3_tx_buf *txbuf, if (!skb->encapsulation) { l3_offset = skb_network_offset(skb); l4_offset = skb_transport_offset(skb); - hdrlen = skb_transport_offset(skb) + tcp_hdrlen(skb); + hdrlen = skb_tcp_all_headers(skb); } else { l3_offset = skb_inner_network_offset(skb); l4_offset = skb_inner_transport_offset(skb); - hdrlen = skb_inner_transport_header(skb) - skb->data + - inner_tcp_hdrlen(skb); + hdrlen = skb_inner_tcp_all_headers(skb); } txbuf->pkt_cnt = skb_shinfo(skb)->gso_segs; @@ -167,30 +167,35 @@ nfp_nfd3_tx_csum(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec, u64_stats_update_end(&r_vec->tx_sync); } -static int nfp_nfd3_prep_tx_meta(struct sk_buff *skb, u64 tls_handle) +static int nfp_nfd3_prep_tx_meta(struct nfp_net_dp *dp, struct sk_buff *skb, u64 tls_handle) { struct metadata_dst *md_dst = skb_metadata_dst(skb); unsigned char *data; + bool vlan_insert; u32 meta_id = 0; int md_bytes; - if (likely(!md_dst && !tls_handle)) - return 0; - if (unlikely(md_dst && md_dst->type != METADATA_HW_PORT_MUX)) { - if (!tls_handle) - return 0; - md_dst = NULL; + if (unlikely(md_dst || tls_handle)) { + if (unlikely(md_dst && md_dst->type != METADATA_HW_PORT_MUX)) + md_dst = NULL; } - md_bytes = 4 + !!md_dst * 4 + !!tls_handle * 8; + vlan_insert = skb_vlan_tag_present(skb) && (dp->ctrl & NFP_NET_CFG_CTRL_TXVLAN_V2); + + if (!(md_dst || tls_handle || vlan_insert)) + return 0; + + md_bytes = sizeof(meta_id) + + !!md_dst * NFP_NET_META_PORTID_SIZE + + !!tls_handle * NFP_NET_META_CONN_HANDLE_SIZE + + vlan_insert * NFP_NET_META_VLAN_SIZE; if (unlikely(skb_cow_head(skb, md_bytes))) return -ENOMEM; - meta_id = 0; data = skb_push(skb, md_bytes) + md_bytes; if (md_dst) { - data -= 4; + data -= NFP_NET_META_PORTID_SIZE; put_unaligned_be32(md_dst->u.port_info.port_id, data); meta_id = NFP_NET_META_PORTID; } @@ -198,13 +203,23 @@ static int nfp_nfd3_prep_tx_meta(struct sk_buff *skb, u64 tls_handle) /* conn handle is opaque, we just use u64 to be able to quickly * compare it to zero */ - data -= 8; + data -= NFP_NET_META_CONN_HANDLE_SIZE; memcpy(data, &tls_handle, sizeof(tls_handle)); meta_id <<= NFP_NET_META_FIELD_SIZE; meta_id |= NFP_NET_META_CONN_HANDLE; } + if (vlan_insert) { + data -= NFP_NET_META_VLAN_SIZE; + /* data type of skb->vlan_proto is __be16 + * so it fills metadata without calling put_unaligned_be16 + */ + memcpy(data, &skb->vlan_proto, sizeof(skb->vlan_proto)); + put_unaligned_be16(skb_vlan_tag_get(skb), data + sizeof(skb->vlan_proto)); + meta_id <<= NFP_NET_META_FIELD_SIZE; + meta_id |= NFP_NET_META_VLAN; + } - data -= 4; + data -= sizeof(meta_id); put_unaligned_be32(meta_id, data); return md_bytes; @@ -258,7 +273,7 @@ netdev_tx_t nfp_nfd3_tx(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; } - md_bytes = nfp_nfd3_prep_tx_meta(skb, tls_handle); + md_bytes = nfp_nfd3_prep_tx_meta(dp, skb, tls_handle); if (unlikely(md_bytes < 0)) goto err_flush; @@ -282,7 +297,7 @@ netdev_tx_t nfp_nfd3_tx(struct sk_buff *skb, struct net_device *netdev) txd = &tx_ring->txds[wr_idx]; txd->offset_eop = (nr_frags ? 0 : NFD3_DESC_TX_EOP) | md_bytes; txd->dma_len = cpu_to_le16(skb_headlen(skb)); - nfp_desc_set_dma_addr(txd, dma_addr); + nfp_desc_set_dma_addr_40b(txd, dma_addr); txd->data_len = cpu_to_le16(skb->len); txd->flags = 0; @@ -320,7 +335,7 @@ netdev_tx_t nfp_nfd3_tx(struct sk_buff *skb, struct net_device *netdev) txd = &tx_ring->txds[wr_idx]; txd->dma_len = cpu_to_le16(fsize); - nfp_desc_set_dma_addr(txd, dma_addr); + nfp_desc_set_dma_addr_40b(txd, dma_addr); txd->offset_eop = md_bytes | ((f == nr_frags - 1) ? NFD3_DESC_TX_EOP : 0); txd->vals8[1] = second_half; @@ -562,8 +577,12 @@ nfp_nfd3_rx_give_one(const struct nfp_net_dp *dp, /* Fill freelist descriptor */ rx_ring->rxds[wr_idx].fld.reserved = 0; rx_ring->rxds[wr_idx].fld.meta_len_dd = 0; - nfp_desc_set_dma_addr(&rx_ring->rxds[wr_idx].fld, - dma_addr + dp->rx_dma_off); + /* DMA address is expanded to 48-bit width in freelist for NFP3800, + * so the *_48b macro is used accordingly, it's also OK to fill + * a 40-bit address since the top 8 bits are get set to 0. + */ + nfp_desc_set_dma_addr_48b(&rx_ring->rxds[wr_idx].fld, + dma_addr + dp->rx_dma_off); rx_ring->wr_p++; if (!(rx_ring->wr_p % NFP_NET_FL_BATCH)) { @@ -700,7 +719,7 @@ bool nfp_nfd3_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta, void *data, void *pkt, unsigned int pkt_len, int meta_len) { - u32 meta_info; + u32 meta_info, vlan_info; meta_info = get_unaligned_be32(data); data += 4; @@ -718,6 +737,17 @@ nfp_nfd3_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta, meta->mark = get_unaligned_be32(data); data += 4; break; + case NFP_NET_META_VLAN: + vlan_info = get_unaligned_be32(data); + if (FIELD_GET(NFP_NET_META_VLAN_STRIP, vlan_info)) { + meta->vlan.stripped = true; + meta->vlan.tpid = FIELD_GET(NFP_NET_META_VLAN_TPID_MASK, + vlan_info); + meta->vlan.tci = FIELD_GET(NFP_NET_META_VLAN_TCI_MASK, + vlan_info); + } + data += 4; + break; case NFP_NET_META_PORTID: meta->portid = get_unaligned_be32(data); data += 4; @@ -817,7 +847,7 @@ nfp_nfd3_tx_xdp_buf(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring, txd = &tx_ring->txds[wr_idx]; txd->offset_eop = NFD3_DESC_TX_EOP; txd->dma_len = cpu_to_le16(pkt_len); - nfp_desc_set_dma_addr(txd, rxbuf->dma_addr + dma_off); + nfp_desc_set_dma_addr_40b(txd, rxbuf->dma_addr + dma_off); txd->data_len = cpu_to_le16(pkt_len); txd->flags = 0; @@ -1046,9 +1076,11 @@ static int nfp_nfd3_rx(struct nfp_net_rx_ring *rx_ring, int budget) } #endif - if (rxd->rxd.flags & PCIE_DESC_RX_VLAN) - __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), - le16_to_cpu(rxd->rxd.vlan)); + if (unlikely(!nfp_net_vlan_strip(skb, rxd, &meta))) { + nfp_nfd3_rx_drop(dp, r_vec, rx_ring, NULL, skb); + continue; + } + if (meta_len_xdp) skb_metadata_set(skb, meta_len_xdp); @@ -1193,7 +1225,7 @@ nfp_nfd3_ctrl_tx_one(struct nfp_net *nn, struct nfp_net_r_vector *r_vec, txd = &tx_ring->txds[wr_idx]; txd->offset_eop = meta_len | NFD3_DESC_TX_EOP; txd->dma_len = cpu_to_le16(skb_headlen(skb)); - nfp_desc_set_dma_addr(txd, dma_addr); + nfp_desc_set_dma_addr_40b(txd, dma_addr); txd->data_len = cpu_to_le16(skb->len); txd->flags = 0; diff --git a/drivers/net/ethernet/netronome/nfp/nfd3/rings.c b/drivers/net/ethernet/netronome/nfp/nfd3/rings.c index 47604d5e25eb..a03190c9313c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfd3/rings.c +++ b/drivers/net/ethernet/netronome/nfp/nfd3/rings.c @@ -247,10 +247,13 @@ nfp_nfd3_print_tx_descs(struct seq_file *file, NFP_NET_CFG_CTRL_L2BC | NFP_NET_CFG_CTRL_L2MC | \ NFP_NET_CFG_CTRL_RXCSUM | NFP_NET_CFG_CTRL_TXCSUM | \ NFP_NET_CFG_CTRL_RXVLAN | NFP_NET_CFG_CTRL_TXVLAN | \ + NFP_NET_CFG_CTRL_RXVLAN_V2 | NFP_NET_CFG_CTRL_RXQINQ | \ + NFP_NET_CFG_CTRL_TXVLAN_V2 | \ NFP_NET_CFG_CTRL_GATHER | NFP_NET_CFG_CTRL_LSO | \ NFP_NET_CFG_CTRL_CTAG_FILTER | NFP_NET_CFG_CTRL_CMSG_DATA | \ NFP_NET_CFG_CTRL_RINGCFG | NFP_NET_CFG_CTRL_RSS | \ NFP_NET_CFG_CTRL_IRQMOD | NFP_NET_CFG_CTRL_TXRWB | \ + NFP_NET_CFG_CTRL_VEPA | \ NFP_NET_CFG_CTRL_VXLAN | NFP_NET_CFG_CTRL_NVGRE | \ NFP_NET_CFG_CTRL_BPF | NFP_NET_CFG_CTRL_LSO2 | \ NFP_NET_CFG_CTRL_RSS2 | NFP_NET_CFG_CTRL_CSUM_COMPLETE | \ @@ -260,6 +263,7 @@ const struct nfp_dp_ops nfp_nfd3_ops = { .version = NFP_NFD_VER_NFD3, .tx_min_desc_per_pkt = 1, .cap_mask = NFP_NFD3_CFG_CTRL_SUPPORTED, + .dma_mask = DMA_BIT_MASK(40), .poll = nfp_nfd3_poll, .xsk_poll = nfp_nfd3_xsk_poll, .ctrl_poll = nfp_nfd3_ctrl_poll, diff --git a/drivers/net/ethernet/netronome/nfp/nfd3/xsk.c b/drivers/net/ethernet/netronome/nfp/nfd3/xsk.c index c16c4b42ecfd..65e243168765 100644 --- a/drivers/net/ethernet/netronome/nfp/nfd3/xsk.c +++ b/drivers/net/ethernet/netronome/nfp/nfd3/xsk.c @@ -40,7 +40,7 @@ nfp_nfd3_xsk_tx_xdp(const struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec, txd = &tx_ring->txds[wr_idx]; txd->offset_eop = NFD3_DESC_TX_EOP; txd->dma_len = cpu_to_le16(pkt_len); - nfp_desc_set_dma_addr(txd, xrxbuf->dma_addr + pkt_off); + nfp_desc_set_dma_addr_40b(txd, xrxbuf->dma_addr + pkt_off); txd->data_len = cpu_to_le16(pkt_len); txd->flags = 0; @@ -94,9 +94,12 @@ static void nfp_nfd3_xsk_rx_skb(struct nfp_net_rx_ring *rx_ring, nfp_nfd3_rx_csum(dp, r_vec, rxd, meta, skb); - if (rxd->rxd.flags & PCIE_DESC_RX_VLAN) - __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), - le16_to_cpu(rxd->rxd.vlan)); + if (unlikely(!nfp_net_vlan_strip(skb, rxd, meta))) { + dev_kfree_skb_any(skb); + nfp_net_xsk_rx_drop(r_vec, xrxbuf); + return; + } + if (meta_xdp) skb_metadata_set(skb, xrxbuf->xdp->data - xrxbuf->xdp->data_meta); @@ -361,10 +364,8 @@ static void nfp_nfd3_xsk_tx(struct nfp_net_tx_ring *tx_ring) /* Build TX descriptor. */ txd = &tx_ring->txds[wr_idx]; - nfp_desc_set_dma_addr(txd, - xsk_buff_raw_get_dma(xsk_pool, - desc[i].addr - )); + nfp_desc_set_dma_addr_40b(txd, + xsk_buff_raw_get_dma(xsk_pool, desc[i].addr)); txd->offset_eop = NFD3_DESC_TX_EOP; txd->dma_len = cpu_to_le16(desc[i].len); txd->data_len = cpu_to_le16(desc[i].len); diff --git a/drivers/net/ethernet/netronome/nfp/nfdk/dp.c b/drivers/net/ethernet/netronome/nfp/nfdk/dp.c index 805071d64a20..2b427d8ccb2f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfdk/dp.c +++ b/drivers/net/ethernet/netronome/nfp/nfdk/dp.c @@ -46,28 +46,16 @@ nfp_nfdk_tx_tso(struct nfp_net_r_vector *r_vec, struct nfp_nfdk_tx_buf *txbuf, if (!skb->encapsulation) { l3_offset = skb_network_offset(skb); l4_offset = skb_transport_offset(skb); - hdrlen = skb_transport_offset(skb) + tcp_hdrlen(skb); + hdrlen = skb_tcp_all_headers(skb); } else { l3_offset = skb_inner_network_offset(skb); l4_offset = skb_inner_transport_offset(skb); - hdrlen = skb_inner_transport_header(skb) - skb->data + - inner_tcp_hdrlen(skb); + hdrlen = skb_inner_tcp_all_headers(skb); } segs = skb_shinfo(skb)->gso_segs; mss = skb_shinfo(skb)->gso_size & NFDK_DESC_TX_MSS_MASK; - /* Note: TSO of the packet with metadata prepended to skb is not - * supported yet, in which case l3/l4_offset and lso_hdrlen need - * be correctly handled here. - * Concern: - * The driver doesn't have md_bytes easily available at this point. - * The PCI.IN PD ME won't have md_bytes bytes to add to lso_hdrlen, - * so it needs the full length there. The app MEs might prefer - * l3_offset and l4_offset relative to the start of packet data, - * but could probably cope with it being relative to the CTM buf - * data offset. - */ txd.l3_offset = l3_offset; txd.l4_offset = l4_offset; txd.lso_meta_res = 0; @@ -182,55 +170,52 @@ close_block: return 0; } -static int nfp_nfdk_prep_port_id(struct sk_buff *skb) +static int +nfp_nfdk_prep_tx_meta(struct nfp_net_dp *dp, struct nfp_app *app, + struct sk_buff *skb) { struct metadata_dst *md_dst = skb_metadata_dst(skb); unsigned char *data; + bool vlan_insert; + u32 meta_id = 0; + int md_bytes; - if (likely(!md_dst)) - return 0; - if (unlikely(md_dst->type != METADATA_HW_PORT_MUX)) - return 0; - - /* Note: Unsupported case when TSO a skb with metedata prepended. - * See the comments in `nfp_nfdk_tx_tso` for details. - */ - if (unlikely(md_dst && skb_is_gso(skb))) - return -EOPNOTSUPP; - - if (unlikely(skb_cow_head(skb, sizeof(md_dst->u.port_info.port_id)))) - return -ENOMEM; - - data = skb_push(skb, sizeof(md_dst->u.port_info.port_id)); - put_unaligned_be32(md_dst->u.port_info.port_id, data); - - return sizeof(md_dst->u.port_info.port_id); -} + if (unlikely(md_dst && md_dst->type != METADATA_HW_PORT_MUX)) + md_dst = NULL; -static int -nfp_nfdk_prep_tx_meta(struct nfp_app *app, struct sk_buff *skb, - struct nfp_net_r_vector *r_vec) -{ - unsigned char *data; - int res, md_bytes; - u32 meta_id = 0; + vlan_insert = skb_vlan_tag_present(skb) && (dp->ctrl & NFP_NET_CFG_CTRL_TXVLAN_V2); - res = nfp_nfdk_prep_port_id(skb); - if (unlikely(res <= 0)) - return res; + if (!(md_dst || vlan_insert)) + return 0; - md_bytes = res; - meta_id = NFP_NET_META_PORTID; + md_bytes = sizeof(meta_id) + + !!md_dst * NFP_NET_META_PORTID_SIZE + + vlan_insert * NFP_NET_META_VLAN_SIZE; - if (unlikely(skb_cow_head(skb, sizeof(meta_id)))) + if (unlikely(skb_cow_head(skb, md_bytes))) return -ENOMEM; - md_bytes += sizeof(meta_id); + data = skb_push(skb, md_bytes) + md_bytes; + if (md_dst) { + data -= NFP_NET_META_PORTID_SIZE; + put_unaligned_be32(md_dst->u.port_info.port_id, data); + meta_id = NFP_NET_META_PORTID; + } + if (vlan_insert) { + data -= NFP_NET_META_VLAN_SIZE; + /* data type of skb->vlan_proto is __be16 + * so it fills metadata without calling put_unaligned_be16 + */ + memcpy(data, &skb->vlan_proto, sizeof(skb->vlan_proto)); + put_unaligned_be16(skb_vlan_tag_get(skb), data + sizeof(skb->vlan_proto)); + meta_id <<= NFP_NET_META_FIELD_SIZE; + meta_id |= NFP_NET_META_VLAN; + } meta_id = FIELD_PREP(NFDK_META_LEN, md_bytes) | FIELD_PREP(NFDK_META_FIELDS, meta_id); - data = skb_push(skb, sizeof(meta_id)); + data -= sizeof(meta_id); put_unaligned_be32(meta_id, data); return NFDK_DESC_TX_CHAIN_META; @@ -278,7 +263,7 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_BUSY; } - metadata = nfp_nfdk_prep_tx_meta(nn->app, skb, r_vec); + metadata = nfp_nfdk_prep_tx_meta(dp, nn->app, skb); if (unlikely((int)metadata < 0)) goto err_flush; @@ -327,7 +312,7 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev) FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type); txd->dma_len_type = cpu_to_le16(dlen_type); - nfp_nfdk_tx_desc_set_dma_addr(txd, dma_addr); + nfp_desc_set_dma_addr_48b(txd, dma_addr); /* starts at bit 0 */ BUILD_BUG_ON(!(NFDK_DESC_TX_DMA_LEN_HEAD & 1)); @@ -352,7 +337,7 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev) dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN, dma_len); txd->dma_len_type = cpu_to_le16(dlen_type); - nfp_nfdk_tx_desc_set_dma_addr(txd, dma_addr); + nfp_desc_set_dma_addr_48b(txd, dma_addr); dma_len -= dlen_type; dma_addr += dlen_type + 1; @@ -608,8 +593,8 @@ nfp_nfdk_rx_give_one(const struct nfp_net_dp *dp, /* Fill freelist descriptor */ rx_ring->rxds[wr_idx].fld.reserved = 0; rx_ring->rxds[wr_idx].fld.meta_len_dd = 0; - nfp_desc_set_dma_addr(&rx_ring->rxds[wr_idx].fld, - dma_addr + dp->rx_dma_off); + nfp_desc_set_dma_addr_48b(&rx_ring->rxds[wr_idx].fld, + dma_addr + dp->rx_dma_off); rx_ring->wr_p++; if (!(rx_ring->wr_p % NFP_NET_FL_BATCH)) { @@ -730,7 +715,7 @@ static bool nfp_nfdk_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta, void *data, void *pkt, unsigned int pkt_len, int meta_len) { - u32 meta_info; + u32 meta_info, vlan_info; meta_info = get_unaligned_be32(data); data += 4; @@ -748,6 +733,17 @@ nfp_nfdk_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta, meta->mark = get_unaligned_be32(data); data += 4; break; + case NFP_NET_META_VLAN: + vlan_info = get_unaligned_be32(data); + if (FIELD_GET(NFP_NET_META_VLAN_STRIP, vlan_info)) { + meta->vlan.stripped = true; + meta->vlan.tpid = FIELD_GET(NFP_NET_META_VLAN_TPID_MASK, + vlan_info); + meta->vlan.tci = FIELD_GET(NFP_NET_META_VLAN_TCI_MASK, + vlan_info); + } + data += 4; + break; case NFP_NET_META_PORTID: meta->portid = get_unaligned_be32(data); data += 4; @@ -944,7 +940,7 @@ nfp_nfdk_tx_xdp_buf(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring, FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type); txd->dma_len_type = cpu_to_le16(dlen_type); - nfp_nfdk_tx_desc_set_dma_addr(txd, dma_addr); + nfp_desc_set_dma_addr_48b(txd, dma_addr); tmp_dlen = dlen_type & NFDK_DESC_TX_DMA_LEN_HEAD; dma_len -= tmp_dlen; @@ -955,7 +951,7 @@ nfp_nfdk_tx_xdp_buf(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring, dma_len -= 1; dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN, dma_len); txd->dma_len_type = cpu_to_le16(dlen_type); - nfp_nfdk_tx_desc_set_dma_addr(txd, dma_addr); + nfp_desc_set_dma_addr_48b(txd, dma_addr); dlen_type &= NFDK_DESC_TX_DMA_LEN; dma_len -= dlen_type; @@ -1185,9 +1181,11 @@ static int nfp_nfdk_rx(struct nfp_net_rx_ring *rx_ring, int budget) nfp_nfdk_rx_csum(dp, r_vec, rxd, &meta, skb); - if (rxd->rxd.flags & PCIE_DESC_RX_VLAN) - __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), - le16_to_cpu(rxd->rxd.vlan)); + if (unlikely(!nfp_net_vlan_strip(skb, rxd, &meta))) { + nfp_nfdk_rx_drop(dp, r_vec, rx_ring, NULL, skb); + continue; + } + if (meta_len_xdp) skb_metadata_set(skb, meta_len_xdp); @@ -1349,7 +1347,7 @@ nfp_nfdk_ctrl_tx_one(struct nfp_net *nn, struct nfp_net_r_vector *r_vec, FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type); txd->dma_len_type = cpu_to_le16(dlen_type); - nfp_nfdk_tx_desc_set_dma_addr(txd, dma_addr); + nfp_desc_set_dma_addr_48b(txd, dma_addr); tmp_dlen = dlen_type & NFDK_DESC_TX_DMA_LEN_HEAD; dma_len -= tmp_dlen; @@ -1360,7 +1358,7 @@ nfp_nfdk_ctrl_tx_one(struct nfp_net *nn, struct nfp_net_r_vector *r_vec, dma_len -= 1; dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN, dma_len); txd->dma_len_type = cpu_to_le16(dlen_type); - nfp_nfdk_tx_desc_set_dma_addr(txd, dma_addr); + nfp_desc_set_dma_addr_48b(txd, dma_addr); dlen_type &= NFDK_DESC_TX_DMA_LEN; dma_len -= dlen_type; diff --git a/drivers/net/ethernet/netronome/nfp/nfdk/rings.c b/drivers/net/ethernet/netronome/nfp/nfdk/rings.c index 301f11108826..fdb8144a63e0 100644 --- a/drivers/net/ethernet/netronome/nfp/nfdk/rings.c +++ b/drivers/net/ethernet/netronome/nfp/nfdk/rings.c @@ -168,10 +168,12 @@ nfp_nfdk_print_tx_descs(struct seq_file *file, NFP_NET_CFG_CTRL_L2BC | NFP_NET_CFG_CTRL_L2MC | \ NFP_NET_CFG_CTRL_RXCSUM | NFP_NET_CFG_CTRL_TXCSUM | \ NFP_NET_CFG_CTRL_RXVLAN | \ + NFP_NET_CFG_CTRL_RXVLAN_V2 | NFP_NET_CFG_CTRL_RXQINQ | \ + NFP_NET_CFG_CTRL_TXVLAN_V2 | \ NFP_NET_CFG_CTRL_GATHER | NFP_NET_CFG_CTRL_LSO | \ NFP_NET_CFG_CTRL_CTAG_FILTER | NFP_NET_CFG_CTRL_CMSG_DATA | \ NFP_NET_CFG_CTRL_RINGCFG | NFP_NET_CFG_CTRL_IRQMOD | \ - NFP_NET_CFG_CTRL_TXRWB | \ + NFP_NET_CFG_CTRL_TXRWB | NFP_NET_CFG_CTRL_VEPA | \ NFP_NET_CFG_CTRL_VXLAN | NFP_NET_CFG_CTRL_NVGRE | \ NFP_NET_CFG_CTRL_BPF | NFP_NET_CFG_CTRL_LSO2 | \ NFP_NET_CFG_CTRL_RSS2 | NFP_NET_CFG_CTRL_CSUM_COMPLETE | \ @@ -181,6 +183,7 @@ const struct nfp_dp_ops nfp_nfdk_ops = { .version = NFP_NFD_VER_NFDK, .tx_min_desc_per_pkt = NFDK_TX_DESC_PER_SIMPLE_PKT, .cap_mask = NFP_NFDK_CFG_CTRL_SUPPORTED, + .dma_mask = DMA_BIT_MASK(48), .poll = nfp_nfdk_poll, .ctrl_poll = nfp_nfdk_ctrl_poll, .xmit = nfp_nfdk_tx, diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c index 09f250e74dfa..bb3f46c74f77 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c @@ -230,7 +230,7 @@ struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id) struct nfp_app *app; if (id >= ARRAY_SIZE(apps) || !apps[id]) { - nfp_err(pf->cpp, "unknown FW app ID 0x%02hhx, driver too old or support for FW not built in\n", id); + nfp_err(pf->cpp, "unknown FW app ID 0x%02x, driver too old or support for FW not built in\n", id); return ERR_PTR(-EINVAL); } diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index 4f88d17536c3..873429f7a6da 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -392,7 +392,7 @@ nfp_net_fw_find(struct pci_dev *pdev, struct nfp_pf *pf) /* First try to find a firmware image specific for this device */ interface = nfp_cpp_interface(pf->cpp); nfp_cpp_serial(pf->cpp, &serial); - sprintf(fw_name, "netronome/serial-%pMF-%02hhx-%02hhx.nffw", + sprintf(fw_name, "netronome/serial-%pMF-%02x-%02x.nffw", serial, interface >> 8, interface & 0xff); fw = nfp_net_fw_request(pdev, pf, fw_name); if (fw) @@ -410,7 +410,9 @@ nfp_net_fw_find(struct pci_dev *pdev, struct nfp_pf *pf) return NULL; } - fw_model = nfp_hwinfo_lookup(pf->hwinfo, "assembly.partno"); + fw_model = nfp_hwinfo_lookup(pf->hwinfo, "nffw.partno"); + if (!fw_model) + fw_model = nfp_hwinfo_lookup(pf->hwinfo, "assembly.partno"); if (!fw_model) { dev_err(&pdev->dev, "Error: can't read part number\n"); return NULL; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 3dd3a92d2e7f..a101ff30a1ae 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -115,7 +115,7 @@ struct nfp_nfdk_tx_buf; #define D_IDX(ring, idx) ((idx) & ((ring)->cnt - 1)) /* Convenience macro for writing dma address into RX/TX descriptors */ -#define nfp_desc_set_dma_addr(desc, dma_addr) \ +#define nfp_desc_set_dma_addr_40b(desc, dma_addr) \ do { \ __typeof__(desc) __d = (desc); \ dma_addr_t __addr = (dma_addr); \ @@ -124,13 +124,13 @@ struct nfp_nfdk_tx_buf; __d->dma_addr_hi = upper_32_bits(__addr) & 0xff; \ } while (0) -#define nfp_nfdk_tx_desc_set_dma_addr(desc, dma_addr) \ - do { \ - __typeof__(desc) __d = (desc); \ - dma_addr_t __addr = (dma_addr); \ - \ - __d->dma_addr_hi = cpu_to_le16(upper_32_bits(__addr) & 0xff); \ - __d->dma_addr_lo = cpu_to_le32(lower_32_bits(__addr)); \ +#define nfp_desc_set_dma_addr_48b(desc, dma_addr) \ + do { \ + __typeof__(desc) __d = (desc); \ + dma_addr_t __addr = (dma_addr); \ + \ + __d->dma_addr_hi = cpu_to_le16(upper_32_bits(__addr)); \ + __d->dma_addr_lo = cpu_to_le32(lower_32_bits(__addr)); \ } while (0) /** @@ -225,8 +225,8 @@ struct nfp_net_tx_ring { struct nfp_net_rx_desc { union { struct { - u8 dma_addr_hi; /* High bits of the buf address */ - __le16 reserved; /* Must be zero */ + __le16 dma_addr_hi; /* High bits of the buf address */ + u8 reserved; /* Must be zero */ u8 meta_len_dd; /* Must be zero */ __le32 dma_addr_lo; /* Low bits of the buffer address */ @@ -248,6 +248,8 @@ struct nfp_net_rx_desc { }; #define NFP_NET_META_FIELD_MASK GENMASK(NFP_NET_META_FIELD_SIZE - 1, 0) +#define NFP_NET_VLAN_CTAG 0 +#define NFP_NET_VLAN_STAG 1 struct nfp_meta_parsed { u8 hash_type; @@ -256,6 +258,11 @@ struct nfp_meta_parsed { u32 mark; u32 portid; __wsum csum; + struct { + bool stripped; + u8 tpid; + u16 tci; + } vlan; }; struct nfp_net_rx_hash { diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 4e56a99087fa..cf4d6f1129fa 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -31,6 +31,7 @@ #include <linux/ethtool.h> #include <linux/log2.h> #include <linux/if_vlan.h> +#include <linux/if_bridge.h> #include <linux/random.h> #include <linux/vmalloc.h> #include <linux/ktime.h> @@ -597,7 +598,7 @@ nfp_net_tls_tx(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec, if (!skb->sk || !tls_is_sk_tx_device_offloaded(skb->sk)) return skb; - datalen = skb->len - (skb_transport_offset(skb) + tcp_hdrlen(skb)); + datalen = skb->len - skb_tcp_all_headers(skb); seq = ntohl(tcp_hdr(skb)->seq); ntls = tls_driver_ctx(skb->sk, TLS_OFFLOAD_CTX_DIR_TX); resync_pending = tls_offload_tx_resync_pending(skb->sk); @@ -665,7 +666,7 @@ void nfp_net_tls_tx_undo(struct sk_buff *skb, u64 tls_handle) if (WARN_ON_ONCE(!skb->sk || !tls_is_sk_tx_device_offloaded(skb->sk))) return; - datalen = skb->len - (skb_transport_offset(skb) + tcp_hdrlen(skb)); + datalen = skb->len - skb_tcp_all_headers(skb); seq = ntohl(tcp_hdr(skb)->seq); ntls = tls_driver_ctx(skb->sk, TLS_OFFLOAD_CTX_DIR_TX); @@ -1694,16 +1695,18 @@ static int nfp_net_set_features(struct net_device *netdev, if (changed & NETIF_F_HW_VLAN_CTAG_RX) { if (features & NETIF_F_HW_VLAN_CTAG_RX) - new_ctrl |= NFP_NET_CFG_CTRL_RXVLAN; + new_ctrl |= nn->cap & NFP_NET_CFG_CTRL_RXVLAN_V2 ?: + NFP_NET_CFG_CTRL_RXVLAN; else - new_ctrl &= ~NFP_NET_CFG_CTRL_RXVLAN; + new_ctrl &= ~NFP_NET_CFG_CTRL_RXVLAN_ANY; } if (changed & NETIF_F_HW_VLAN_CTAG_TX) { if (features & NETIF_F_HW_VLAN_CTAG_TX) - new_ctrl |= NFP_NET_CFG_CTRL_TXVLAN; + new_ctrl |= nn->cap & NFP_NET_CFG_CTRL_TXVLAN_V2 ?: + NFP_NET_CFG_CTRL_TXVLAN; else - new_ctrl &= ~NFP_NET_CFG_CTRL_TXVLAN; + new_ctrl &= ~NFP_NET_CFG_CTRL_TXVLAN_ANY; } if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) { @@ -1713,6 +1716,13 @@ static int nfp_net_set_features(struct net_device *netdev, new_ctrl &= ~NFP_NET_CFG_CTRL_CTAG_FILTER; } + if (changed & NETIF_F_HW_VLAN_STAG_RX) { + if (features & NETIF_F_HW_VLAN_STAG_RX) + new_ctrl |= NFP_NET_CFG_CTRL_RXQINQ; + else + new_ctrl &= ~NFP_NET_CFG_CTRL_RXQINQ; + } + if (changed & NETIF_F_SG) { if (features & NETIF_F_SG) new_ctrl |= NFP_NET_CFG_CTRL_GATHER; @@ -1742,6 +1752,27 @@ static int nfp_net_set_features(struct net_device *netdev, } static netdev_features_t +nfp_net_fix_features(struct net_device *netdev, + netdev_features_t features) +{ + if ((features & NETIF_F_HW_VLAN_CTAG_RX) && + (features & NETIF_F_HW_VLAN_STAG_RX)) { + if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { + features &= ~NETIF_F_HW_VLAN_CTAG_RX; + netdev->wanted_features &= ~NETIF_F_HW_VLAN_CTAG_RX; + netdev_warn(netdev, + "S-tag and C-tag stripping can't be enabled at the same time. Enabling S-tag stripping and disabling C-tag stripping\n"); + } else if (netdev->features & NETIF_F_HW_VLAN_STAG_RX) { + features &= ~NETIF_F_HW_VLAN_STAG_RX; + netdev->wanted_features &= ~NETIF_F_HW_VLAN_STAG_RX; + netdev_warn(netdev, + "S-tag and C-tag stripping can't be enabled at the same time. Enabling C-tag stripping and disabling S-tag stripping\n"); + } + } + return features; +} + +static netdev_features_t nfp_net_features_check(struct sk_buff *skb, struct net_device *dev, netdev_features_t features) { @@ -1757,8 +1788,7 @@ nfp_net_features_check(struct sk_buff *skb, struct net_device *dev, if (skb_is_gso(skb)) { u32 hdrlen; - hdrlen = skb_inner_transport_header(skb) - skb->data + - inner_tcp_hdrlen(skb); + hdrlen = skb_inner_tcp_all_headers(skb); /* Assume worst case scenario of having longest possible * metadata prepend - 8B @@ -1892,6 +1922,69 @@ static int nfp_net_set_mac_address(struct net_device *netdev, void *addr) return 0; } +static int nfp_net_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, + struct net_device *dev, u32 filter_mask, + int nlflags) +{ + struct nfp_net *nn = netdev_priv(dev); + u16 mode; + + if (!(nn->cap & NFP_NET_CFG_CTRL_VEPA)) + return -EOPNOTSUPP; + + mode = (nn->dp.ctrl & NFP_NET_CFG_CTRL_VEPA) ? + BRIDGE_MODE_VEPA : BRIDGE_MODE_VEB; + + return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode, 0, 0, + nlflags, filter_mask, NULL); +} + +static int nfp_net_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh, + u16 flags, struct netlink_ext_ack *extack) +{ + struct nfp_net *nn = netdev_priv(dev); + struct nlattr *attr, *br_spec; + int rem, err; + u32 new_ctrl; + u16 mode; + + if (!(nn->cap & NFP_NET_CFG_CTRL_VEPA)) + return -EOPNOTSUPP; + + br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); + if (!br_spec) + return -EINVAL; + + nla_for_each_nested(attr, br_spec, rem) { + if (nla_type(attr) != IFLA_BRIDGE_MODE) + continue; + + if (nla_len(attr) < sizeof(mode)) + return -EINVAL; + + new_ctrl = nn->dp.ctrl; + mode = nla_get_u16(attr); + if (mode == BRIDGE_MODE_VEPA) + new_ctrl |= NFP_NET_CFG_CTRL_VEPA; + else if (mode == BRIDGE_MODE_VEB) + new_ctrl &= ~NFP_NET_CFG_CTRL_VEPA; + else + return -EOPNOTSUPP; + + if (new_ctrl == nn->dp.ctrl) + return 0; + + nn_writel(nn, NFP_NET_CFG_CTRL, new_ctrl); + err = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_GEN); + if (!err) + nn->dp.ctrl = new_ctrl; + + return err; + } + + return -EINVAL; +} + const struct net_device_ops nfp_nfd3_netdev_ops = { .ndo_init = nfp_app_ndo_init, .ndo_uninit = nfp_app_ndo_uninit, @@ -1914,11 +2007,14 @@ const struct net_device_ops nfp_nfd3_netdev_ops = { .ndo_change_mtu = nfp_net_change_mtu, .ndo_set_mac_address = nfp_net_set_mac_address, .ndo_set_features = nfp_net_set_features, + .ndo_fix_features = nfp_net_fix_features, .ndo_features_check = nfp_net_features_check, .ndo_get_phys_port_name = nfp_net_get_phys_port_name, .ndo_bpf = nfp_net_xdp, .ndo_xsk_wakeup = nfp_net_xsk_wakeup, .ndo_get_devlink_port = nfp_devlink_get_devlink_port, + .ndo_bridge_getlink = nfp_net_bridge_getlink, + .ndo_bridge_setlink = nfp_net_bridge_setlink, }; const struct net_device_ops nfp_nfdk_netdev_ops = { @@ -1932,6 +2028,7 @@ const struct net_device_ops nfp_nfdk_netdev_ops = { .ndo_vlan_rx_kill_vid = nfp_net_vlan_rx_kill_vid, .ndo_set_vf_mac = nfp_app_set_vf_mac, .ndo_set_vf_vlan = nfp_app_set_vf_vlan, + .ndo_set_vf_rate = nfp_app_set_vf_rate, .ndo_set_vf_spoofchk = nfp_app_set_vf_spoofchk, .ndo_set_vf_trust = nfp_app_set_vf_trust, .ndo_get_vf_config = nfp_app_get_vf_config, @@ -1942,10 +2039,13 @@ const struct net_device_ops nfp_nfdk_netdev_ops = { .ndo_change_mtu = nfp_net_change_mtu, .ndo_set_mac_address = nfp_net_set_mac_address, .ndo_set_features = nfp_net_set_features, + .ndo_fix_features = nfp_net_fix_features, .ndo_features_check = nfp_net_features_check, .ndo_get_phys_port_name = nfp_net_get_phys_port_name, .ndo_bpf = nfp_net_xdp, .ndo_get_devlink_port = nfp_devlink_get_devlink_port, + .ndo_bridge_getlink = nfp_net_bridge_getlink, + .ndo_bridge_setlink = nfp_net_bridge_setlink, }; static int nfp_udp_tunnel_sync(struct net_device *netdev, unsigned int table) @@ -1993,7 +2093,7 @@ void nfp_net_info(struct nfp_net *nn) nn->fw_ver.extend, nn->fw_ver.class, nn->fw_ver.major, nn->fw_ver.minor, nn->max_mtu); - nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", nn->cap, nn->cap & NFP_NET_CFG_CTRL_PROMISC ? "PROMISC " : "", nn->cap & NFP_NET_CFG_CTRL_L2BC ? "L2BCFILT " : "", @@ -2002,6 +2102,9 @@ void nfp_net_info(struct nfp_net *nn) nn->cap & NFP_NET_CFG_CTRL_TXCSUM ? "TXCSUM " : "", nn->cap & NFP_NET_CFG_CTRL_RXVLAN ? "RXVLAN " : "", nn->cap & NFP_NET_CFG_CTRL_TXVLAN ? "TXVLAN " : "", + nn->cap & NFP_NET_CFG_CTRL_RXQINQ ? "RXQINQ " : "", + nn->cap & NFP_NET_CFG_CTRL_RXVLAN_V2 ? "RXVLANv2 " : "", + nn->cap & NFP_NET_CFG_CTRL_TXVLAN_V2 ? "TXVLANv2 " : "", nn->cap & NFP_NET_CFG_CTRL_SCATTER ? "SCATTER " : "", nn->cap & NFP_NET_CFG_CTRL_GATHER ? "GATHER " : "", nn->cap & NFP_NET_CFG_CTRL_LSO ? "TSO1 " : "", @@ -2012,6 +2115,7 @@ void nfp_net_info(struct nfp_net *nn) nn->cap & NFP_NET_CFG_CTRL_MSIXAUTO ? "AUTOMASK " : "", nn->cap & NFP_NET_CFG_CTRL_IRQMOD ? "IRQMOD " : "", nn->cap & NFP_NET_CFG_CTRL_TXRWB ? "TXRWB " : "", + nn->cap & NFP_NET_CFG_CTRL_VEPA ? "VEPA " : "", nn->cap & NFP_NET_CFG_CTRL_VXLAN ? "VXLAN " : "", nn->cap & NFP_NET_CFG_CTRL_NVGRE ? "NVGRE " : "", nn->cap & NFP_NET_CFG_CTRL_CSUM_COMPLETE ? @@ -2040,6 +2144,7 @@ nfp_net_alloc(struct pci_dev *pdev, const struct nfp_dev_info *dev_info, void __iomem *ctrl_bar, bool needs_netdev, unsigned int max_tx_rings, unsigned int max_rx_rings) { + u64 dma_mask = dma_get_mask(&pdev->dev); struct nfp_net *nn; int err; @@ -2085,6 +2190,14 @@ nfp_net_alloc(struct pci_dev *pdev, const struct nfp_dev_info *dev_info, goto err_free_nn; } + if ((dma_mask & nn->dp.ops->dma_mask) != dma_mask) { + dev_err(&pdev->dev, + "DMA mask of loaded firmware: %llx, required DMA mask: %llx\n", + nn->dp.ops->dma_mask, dma_mask); + err = -EINVAL; + goto err_free_nn; + } + nn->max_tx_rings = max_tx_rings; nn->max_rx_rings = max_rx_rings; @@ -2279,31 +2392,39 @@ static void nfp_net_netdev_init(struct nfp_net *nn) netdev->vlan_features = netdev->hw_features; - if (nn->cap & NFP_NET_CFG_CTRL_RXVLAN) { + if (nn->cap & NFP_NET_CFG_CTRL_RXVLAN_ANY) { netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX; - nn->dp.ctrl |= NFP_NET_CFG_CTRL_RXVLAN; + nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_RXVLAN_V2 ?: + NFP_NET_CFG_CTRL_RXVLAN; } - if (nn->cap & NFP_NET_CFG_CTRL_TXVLAN) { + if (nn->cap & NFP_NET_CFG_CTRL_TXVLAN_ANY) { if (nn->cap & NFP_NET_CFG_CTRL_LSO2) { nn_warn(nn, "Device advertises both TSO2 and TXVLAN. Refusing to enable TXVLAN.\n"); } else { netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX; - nn->dp.ctrl |= NFP_NET_CFG_CTRL_TXVLAN; + nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_TXVLAN_V2 ?: + NFP_NET_CFG_CTRL_TXVLAN; } } if (nn->cap & NFP_NET_CFG_CTRL_CTAG_FILTER) { netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; nn->dp.ctrl |= NFP_NET_CFG_CTRL_CTAG_FILTER; } + if (nn->cap & NFP_NET_CFG_CTRL_RXQINQ) { + netdev->hw_features |= NETIF_F_HW_VLAN_STAG_RX; + nn->dp.ctrl |= NFP_NET_CFG_CTRL_RXQINQ; + } netdev->features = netdev->hw_features; if (nfp_app_has_tc(nn->app) && nn->port) netdev->hw_features |= NETIF_F_HW_TC; - /* Advertise but disable TSO by default. */ - netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_LSO_ANY; + /* C-Tag strip and S-Tag strip can't be supported simultaneously, + * so enable C-Tag strip and disable S-Tag strip by default. + */ + netdev->features &= ~NETIF_F_HW_VLAN_STAG_RX; + nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_RXQINQ; /* Finalise the netdev setup */ switch (nn->dp.ops->version) { diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h index 8892a94f00c3..ac05ec34d69e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h @@ -31,10 +31,16 @@ #define NFP_NET_LSO_MAX_HDR_SZ 255 #define NFP_NET_LSO_MAX_SEGS 64 +/* working with metadata vlan api (NFD version >= 2.0) */ +#define NFP_NET_META_VLAN_STRIP BIT(31) +#define NFP_NET_META_VLAN_TPID_MASK GENMASK(19, 16) +#define NFP_NET_META_VLAN_TCI_MASK GENMASK(15, 0) + /* Prepend field types */ #define NFP_NET_META_FIELD_SIZE 4 #define NFP_NET_META_HASH 1 /* next field carries hash type */ #define NFP_NET_META_MARK 2 +#define NFP_NET_META_VLAN 4 /* ctag or stag type */ #define NFP_NET_META_PORTID 5 #define NFP_NET_META_CSUM 6 /* checksum complete type */ #define NFP_NET_META_CONN_HANDLE 7 @@ -42,6 +48,10 @@ #define NFP_META_PORT_ID_CTRL ~0U +/* Prepend field sizes */ +#define NFP_NET_META_VLAN_SIZE 4 +#define NFP_NET_META_PORTID_SIZE 4 +#define NFP_NET_META_CONN_HANDLE_SIZE 8 /* Hash type pre-pended when a RSS hash was computed */ #define NFP_NET_RSS_NONE 0 #define NFP_NET_RSS_IPV4 1 @@ -89,11 +99,15 @@ #define NFP_NET_CFG_CTRL_LSO (0x1 << 10) /* LSO/TSO (version 1) */ #define NFP_NET_CFG_CTRL_CTAG_FILTER (0x1 << 11) /* VLAN CTAG filtering */ #define NFP_NET_CFG_CTRL_CMSG_DATA (0x1 << 12) /* RX cmsgs on data Qs */ +#define NFP_NET_CFG_CTRL_RXQINQ (0x1 << 13) /* Enable S-tag strip */ +#define NFP_NET_CFG_CTRL_RXVLAN_V2 (0x1 << 15) /* Enable C-tag strip */ #define NFP_NET_CFG_CTRL_RINGCFG (0x1 << 16) /* Ring runtime changes */ #define NFP_NET_CFG_CTRL_RSS (0x1 << 17) /* RSS (version 1) */ #define NFP_NET_CFG_CTRL_IRQMOD (0x1 << 18) /* Interrupt moderation */ #define NFP_NET_CFG_CTRL_MSIXAUTO (0x1 << 20) /* MSI-X auto-masking */ #define NFP_NET_CFG_CTRL_TXRWB (0x1 << 21) /* Write-back of TX ring*/ +#define NFP_NET_CFG_CTRL_VEPA (0x1 << 22) /* Enable VEPA mode */ +#define NFP_NET_CFG_CTRL_TXVLAN_V2 (0x1 << 23) /* Enable VLAN C-tag insert*/ #define NFP_NET_CFG_CTRL_VXLAN (0x1 << 24) /* VXLAN tunnel support */ #define NFP_NET_CFG_CTRL_NVGRE (0x1 << 25) /* NVGRE tunnel support */ #define NFP_NET_CFG_CTRL_BPF (0x1 << 27) /* BPF offload capable */ @@ -110,6 +124,10 @@ NFP_NET_CFG_CTRL_CSUM_COMPLETE) #define NFP_NET_CFG_CTRL_CHAIN_META (NFP_NET_CFG_CTRL_RSS2 | \ NFP_NET_CFG_CTRL_CSUM_COMPLETE) +#define NFP_NET_CFG_CTRL_RXVLAN_ANY (NFP_NET_CFG_CTRL_RXVLAN | \ + NFP_NET_CFG_CTRL_RXVLAN_V2) +#define NFP_NET_CFG_CTRL_TXVLAN_ANY (NFP_NET_CFG_CTRL_TXVLAN | \ + NFP_NET_CFG_CTRL_TXVLAN_V2) #define NFP_NET_CFG_UPDATE 0x0004 #define NFP_NET_CFG_UPDATE_GEN (0x1 << 0) /* General update */ diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_dp.c b/drivers/net/ethernet/netronome/nfp/nfp_net_dp.c index 34dd94811df3..550df83b798c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_dp.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_dp.c @@ -440,3 +440,27 @@ bool nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb) return ret; } + +bool nfp_net_vlan_strip(struct sk_buff *skb, const struct nfp_net_rx_desc *rxd, + const struct nfp_meta_parsed *meta) +{ + u16 tpid = 0, tci = 0; + + if (rxd->rxd.flags & PCIE_DESC_RX_VLAN) { + tpid = ETH_P_8021Q; + tci = le16_to_cpu(rxd->rxd.vlan); + } else if (meta->vlan.stripped) { + if (meta->vlan.tpid == NFP_NET_VLAN_CTAG) + tpid = ETH_P_8021Q; + else if (meta->vlan.tpid == NFP_NET_VLAN_STAG) + tpid = ETH_P_8021AD; + else + return false; + + tci = meta->vlan.tci; + } + if (tpid) + __vlan_hwaccel_put_tag(skb, htons(tpid), tci); + + return true; +} diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_dp.h b/drivers/net/ethernet/netronome/nfp/nfp_net_dp.h index c934cc2d3208..831c83ce0d3d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_dp.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_dp.h @@ -106,6 +106,8 @@ int nfp_net_tx_rings_prepare(struct nfp_net *nn, struct nfp_net_dp *dp); void nfp_net_rx_rings_free(struct nfp_net_dp *dp); void nfp_net_tx_rings_free(struct nfp_net_dp *dp); void nfp_net_rx_ring_reset(struct nfp_net_rx_ring *rx_ring); +bool nfp_net_vlan_strip(struct sk_buff *skb, const struct nfp_net_rx_desc *rxd, + const struct nfp_meta_parsed *meta); enum nfp_nfd_version { NFP_NFD_VER_NFD3, @@ -117,6 +119,7 @@ enum nfp_nfd_version { * @version: Indicate dp type * @tx_min_desc_per_pkt: Minimal TX descs needed for each packet * @cap_mask: Mask of supported features + * @dma_mask: DMA addressing capability * @poll: Napi poll for normal rx/tx * @xsk_poll: Napi poll when xsk is enabled * @ctrl_poll: Tasklet poll for ctrl rx/tx @@ -134,6 +137,7 @@ struct nfp_dp_ops { enum nfp_nfd_version version; unsigned int tx_min_desc_per_pkt; u32 cap_mask; + u64 dma_mask; int (*poll)(struct napi_struct *napi, int budget); int (*xsk_poll)(struct napi_struct *napi, int budget); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index df0afd271a21..c922dfab8080 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -29,6 +29,7 @@ #include "nfp_net_dp.h" #include "nfp_net.h" #include "nfp_port.h" +#include "nfpcore/nfp_cpp.h" struct nfp_et_stat { char name[ETH_GSTRING_LEN]; @@ -442,6 +443,160 @@ static int nfp_net_set_ringparam(struct net_device *netdev, return nfp_net_set_ring_size(nn, rxd_cnt, txd_cnt); } +static int nfp_test_link(struct net_device *netdev) +{ + if (!netif_carrier_ok(netdev) || !(netdev->flags & IFF_UP)) + return 1; + + return 0; +} + +static int nfp_test_nsp(struct net_device *netdev) +{ + struct nfp_app *app = nfp_app_from_netdev(netdev); + struct nfp_nsp_identify *nspi; + struct nfp_nsp *nsp; + int err; + + nsp = nfp_nsp_open(app->cpp); + if (IS_ERR(nsp)) { + err = PTR_ERR(nsp); + netdev_info(netdev, "NSP Test: failed to access the NSP: %d\n", err); + goto exit; + } + + if (nfp_nsp_get_abi_ver_minor(nsp) < 15) { + err = -EOPNOTSUPP; + goto exit_close_nsp; + } + + nspi = kzalloc(sizeof(*nspi), GFP_KERNEL); + if (!nspi) { + err = -ENOMEM; + goto exit_close_nsp; + } + + err = nfp_nsp_read_identify(nsp, nspi, sizeof(*nspi)); + if (err < 0) + netdev_info(netdev, "NSP Test: reading bsp version failed %d\n", err); + + kfree(nspi); +exit_close_nsp: + nfp_nsp_close(nsp); +exit: + return err; +} + +static int nfp_test_fw(struct net_device *netdev) +{ + struct nfp_net *nn = netdev_priv(netdev); + int err; + + err = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_GEN); + if (err) + netdev_info(netdev, "FW Test: update failed %d\n", err); + + return err; +} + +static int nfp_test_reg(struct net_device *netdev) +{ + struct nfp_app *app = nfp_app_from_netdev(netdev); + struct nfp_cpp *cpp = app->cpp; + u32 model = nfp_cpp_model(cpp); + u32 value; + int err; + + err = nfp_cpp_model_autodetect(cpp, &value); + if (err < 0) { + netdev_info(netdev, "REG Test: NFP model detection failed %d\n", err); + return err; + } + + return (value == model) ? 0 : 1; +} + +static bool link_test_supported(struct net_device *netdev) +{ + return true; +} + +static bool nsp_test_supported(struct net_device *netdev) +{ + if (nfp_app_from_netdev(netdev)) + return true; + + return false; +} + +static bool fw_test_supported(struct net_device *netdev) +{ + if (nfp_netdev_is_nfp_net(netdev)) + return true; + + return false; +} + +static bool reg_test_supported(struct net_device *netdev) +{ + if (nfp_app_from_netdev(netdev)) + return true; + + return false; +} + +static struct nfp_self_test_item { + char name[ETH_GSTRING_LEN]; + bool (*is_supported)(struct net_device *dev); + int (*func)(struct net_device *dev); +} nfp_self_test[] = { + {"Link Test", link_test_supported, nfp_test_link}, + {"NSP Test", nsp_test_supported, nfp_test_nsp}, + {"Firmware Test", fw_test_supported, nfp_test_fw}, + {"Register Test", reg_test_supported, nfp_test_reg} +}; + +#define NFP_TEST_TOTAL_NUM ARRAY_SIZE(nfp_self_test) + +static void nfp_get_self_test_strings(struct net_device *netdev, u8 *data) +{ + int i; + + for (i = 0; i < NFP_TEST_TOTAL_NUM; i++) + if (nfp_self_test[i].is_supported(netdev)) + ethtool_sprintf(&data, nfp_self_test[i].name); +} + +static int nfp_get_self_test_count(struct net_device *netdev) +{ + int i, count = 0; + + for (i = 0; i < NFP_TEST_TOTAL_NUM; i++) + if (nfp_self_test[i].is_supported(netdev)) + count++; + + return count; +} + +static void nfp_net_self_test(struct net_device *netdev, struct ethtool_test *eth_test, + u64 *data) +{ + int i, ret, count = 0; + + netdev_info(netdev, "Start self test\n"); + + for (i = 0; i < NFP_TEST_TOTAL_NUM; i++) { + if (nfp_self_test[i].is_supported(netdev)) { + ret = nfp_self_test[i].func(netdev); + if (ret) + eth_test->flags |= ETH_TEST_FL_FAILED; + data[count++] = ret; + } + } + + netdev_info(netdev, "Test end\n"); +} + static unsigned int nfp_vnic_get_sw_stats_count(struct net_device *netdev) { struct nfp_net *nn = netdev_priv(netdev); @@ -705,6 +860,9 @@ static void nfp_net_get_strings(struct net_device *netdev, data = nfp_mac_get_stats_strings(netdev, data); data = nfp_app_port_get_stats_strings(nn->port, data); break; + case ETH_SS_TEST: + nfp_get_self_test_strings(netdev, data); + break; } } @@ -739,6 +897,8 @@ static int nfp_net_get_sset_count(struct net_device *netdev, int sset) cnt += nfp_mac_get_stats_count(netdev); cnt += nfp_app_port_get_stats_count(nn->port); return cnt; + case ETH_SS_TEST: + return nfp_get_self_test_count(netdev); default: return -EOPNOTSUPP; } @@ -757,6 +917,9 @@ static void nfp_port_get_strings(struct net_device *netdev, data = nfp_mac_get_stats_strings(netdev, data); data = nfp_app_port_get_stats_strings(port, data); break; + case ETH_SS_TEST: + nfp_get_self_test_strings(netdev, data); + break; } } @@ -786,6 +949,8 @@ static int nfp_port_get_sset_count(struct net_device *netdev, int sset) count = nfp_mac_get_stats_count(netdev); count += nfp_app_port_get_stats_count(port); return count; + case ETH_SS_TEST: + return nfp_get_self_test_count(netdev); default: return -EOPNOTSUPP; } @@ -1460,6 +1625,55 @@ static int nfp_net_set_channels(struct net_device *netdev, return nfp_net_set_num_rings(nn, total_rx, total_tx); } +static void nfp_port_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct nfp_eth_table_port *eth_port; + struct nfp_port *port; + + port = nfp_port_from_netdev(netdev); + eth_port = nfp_port_get_eth_port(port); + if (!eth_port) + return; + + /* Currently pause frame support is fixed */ + pause->autoneg = AUTONEG_DISABLE; + pause->rx_pause = 1; + pause->tx_pause = 1; +} + +static int nfp_net_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) +{ + struct nfp_eth_table_port *eth_port; + struct nfp_port *port; + int err; + + port = nfp_port_from_netdev(netdev); + eth_port = __nfp_port_get_eth_port(port); + if (!eth_port) + return -EOPNOTSUPP; + + switch (state) { + case ETHTOOL_ID_ACTIVE: + /* Control LED to blink */ + err = nfp_eth_set_idmode(port->app->cpp, eth_port->index, 1); + break; + + case ETHTOOL_ID_INACTIVE: + /* Control LED to normal mode */ + err = nfp_eth_set_idmode(port->app->cpp, eth_port->index, 0); + break; + + case ETHTOOL_ID_ON: + case ETHTOOL_ID_OFF: + default: + return -EOPNOTSUPP; + } + + return err; +} + static const struct ethtool_ops nfp_net_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_MAX_FRAMES | @@ -1468,6 +1682,7 @@ static const struct ethtool_ops nfp_net_ethtool_ops = { .get_link = ethtool_op_get_link, .get_ringparam = nfp_net_get_ringparam, .set_ringparam = nfp_net_set_ringparam, + .self_test = nfp_net_self_test, .get_strings = nfp_net_get_strings, .get_ethtool_stats = nfp_net_get_stats, .get_sset_count = nfp_net_get_sset_count, @@ -1492,6 +1707,8 @@ static const struct ethtool_ops nfp_net_ethtool_ops = { .set_link_ksettings = nfp_net_set_link_ksettings, .get_fecparam = nfp_port_get_fecparam, .set_fecparam = nfp_port_set_fecparam, + .get_pauseparam = nfp_port_get_pauseparam, + .set_phys_id = nfp_net_set_phys_id, }; const struct ethtool_ops nfp_port_ethtool_ops = { @@ -1499,6 +1716,7 @@ const struct ethtool_ops nfp_port_ethtool_ops = { .get_link = ethtool_op_get_link, .get_strings = nfp_port_get_strings, .get_ethtool_stats = nfp_port_get_stats, + .self_test = nfp_net_self_test, .get_sset_count = nfp_port_get_sset_count, .set_dump = nfp_app_set_dump, .get_dump_flag = nfp_app_get_dump_flag, @@ -1509,6 +1727,8 @@ const struct ethtool_ops nfp_port_ethtool_ops = { .set_link_ksettings = nfp_net_set_link_ksettings, .get_fecparam = nfp_port_get_fecparam, .set_fecparam = nfp_port_set_fecparam, + .get_pauseparam = nfp_port_get_pauseparam, + .set_phys_id = nfp_net_set_phys_id, }; void nfp_net_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c index 75b5018f2e1b..8b77582bdfa0 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c @@ -365,9 +365,9 @@ int nfp_repr_init(struct nfp_app *app, struct net_device *netdev, netdev->vlan_features = netdev->hw_features; - if (repr_cap & NFP_NET_CFG_CTRL_RXVLAN) + if (repr_cap & NFP_NET_CFG_CTRL_RXVLAN_ANY) netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX; - if (repr_cap & NFP_NET_CFG_CTRL_TXVLAN) { + if (repr_cap & NFP_NET_CFG_CTRL_TXVLAN_ANY) { if (repr_cap & NFP_NET_CFG_CTRL_LSO2) netdev_warn(netdev, "Device advertises both TSO2 and TXVLAN. Refusing to enable TXVLAN.\n"); else @@ -375,11 +375,15 @@ int nfp_repr_init(struct nfp_app *app, struct net_device *netdev, } if (repr_cap & NFP_NET_CFG_CTRL_CTAG_FILTER) netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; + if (repr_cap & NFP_NET_CFG_CTRL_RXQINQ) + netdev->hw_features |= NETIF_F_HW_VLAN_STAG_RX; netdev->features = netdev->hw_features; - /* Advertise but disable TSO by default. */ - netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + /* C-Tag strip and S-Tag strip can't be supported simultaneously, + * so enable C-Tag strip and disable S-Tag strip by default. + */ + netdev->features &= ~NETIF_F_HW_VLAN_STAG_RX; netif_set_tso_max_segs(netdev, NFP_NET_LSO_MAX_SEGS); netdev->priv_flags |= IFF_NO_QUEUE | IFF_DISABLE_NETPOLL; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_xsk.c b/drivers/net/ethernet/netronome/nfp/nfp_net_xsk.c index 86829446c637..aea507aed49d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_xsk.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_xsk.c @@ -70,8 +70,12 @@ void nfp_net_xsk_rx_ring_fill_freelist(struct nfp_net_rx_ring *rx_ring) nfp_net_xsk_rx_bufs_stash(rx_ring, wr_idx, xdp); - nfp_desc_set_dma_addr(&rx_ring->rxds[wr_idx].fld, - rx_ring->xsk_rxbufs[wr_idx].dma_addr); + /* DMA address is expanded to 48-bit width in freelist for NFP3800, + * so the *_48b macro is used accordingly, it's also OK to fill + * a 40-bit address since the top 8 bits are get set to 0. + */ + nfp_desc_set_dma_addr_48b(&rx_ring->rxds[wr_idx].fld, + rx_ring->xsk_rxbufs[wr_idx].dma_addr); rx_ring->wr_p++; wr_ptr_add++; diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/crc32.h b/drivers/net/ethernet/netronome/nfp/nfpcore/crc32.h index afab6f0fc564..6ad43c7cefe6 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/crc32.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/crc32.h @@ -4,7 +4,6 @@ #ifndef NFP_CRC32_H #define NFP_CRC32_H -#include <linux/kernel.h> #include <linux/crc32.h> /** diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h index ddb34bfb9bef..3d379e937184 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h @@ -13,36 +13,22 @@ #include <linux/ctype.h> #include <linux/types.h> #include <linux/sizes.h> -#include <linux/stringify.h> #ifndef NFP_SUBSYS #define NFP_SUBSYS "nfp" #endif -#define string_format(x) __FILE__ ":" __stringify(__LINE__) ": " x - -#define __nfp_err(cpp, fmt, args...) \ - dev_err(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args) -#define __nfp_warn(cpp, fmt, args...) \ - dev_warn(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args) -#define __nfp_info(cpp, fmt, args...) \ - dev_info(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args) -#define __nfp_dbg(cpp, fmt, args...) \ - dev_dbg(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args) -#define __nfp_printk(level, cpp, fmt, args...) \ - dev_printk(level, nfp_cpp_device(cpp)->parent, \ - NFP_SUBSYS ": " fmt, ## args) - #define nfp_err(cpp, fmt, args...) \ - __nfp_err(cpp, string_format(fmt), ## args) + dev_err(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args) #define nfp_warn(cpp, fmt, args...) \ - __nfp_warn(cpp, string_format(fmt), ## args) + dev_warn(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args) #define nfp_info(cpp, fmt, args...) \ - __nfp_info(cpp, string_format(fmt), ## args) + dev_info(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args) #define nfp_dbg(cpp, fmt, args...) \ - __nfp_dbg(cpp, string_format(fmt), ## args) + dev_dbg(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args) #define nfp_printk(level, cpp, fmt, args...) \ - __nfp_printk(level, cpp, string_format(fmt), ## args) + dev_printk(level, nfp_cpp_device(cpp)->parent, \ + NFP_SUBSYS ": " fmt, ## args) #define PCI_64BIT_BAR_COUNT 3 diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_dev.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_dev.c index 28384d6d1c6f..0725b51c2a95 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_dev.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_dev.c @@ -9,7 +9,7 @@ const struct nfp_dev_info nfp_dev_info[NFP_DEV_CNT] = { [NFP_DEV_NFP3800] = { - .dma_mask = DMA_BIT_MASK(40), + .dma_mask = DMA_BIT_MASK(48), .qc_idx_mask = GENMASK(8, 0), .qc_addr_offset = 0x400000, .min_qc_size = 512, @@ -21,7 +21,7 @@ const struct nfp_dev_info nfp_dev_info[NFP_DEV_CNT] = { .qc_area_sz = 0x100000, }, [NFP_DEV_NFP3800_VF] = { - .dma_mask = DMA_BIT_MASK(40), + .dma_mask = DMA_BIT_MASK(48), .qc_idx_mask = GENMASK(8, 0), .qc_addr_offset = 0, .min_qc_size = 512, diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h index f5360bae6f75..77d66855be42 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h @@ -196,6 +196,8 @@ int nfp_eth_set_configured(struct nfp_cpp *cpp, unsigned int idx, int nfp_eth_set_fec(struct nfp_cpp *cpp, unsigned int idx, enum nfp_eth_fec mode); +int nfp_eth_set_idmode(struct nfp_cpp *cpp, unsigned int idx, bool state); + static inline bool nfp_eth_can_support_fec(struct nfp_eth_table_port *eth_port) { return !!eth_port->fec_modes_supported; diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c index 311a5be25acb..edd300033735 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c @@ -49,6 +49,7 @@ #define NSP_ETH_CTRL_SET_LANES BIT_ULL(5) #define NSP_ETH_CTRL_SET_ANEG BIT_ULL(6) #define NSP_ETH_CTRL_SET_FEC BIT_ULL(7) +#define NSP_ETH_CTRL_SET_IDMODE BIT_ULL(8) enum nfp_eth_raw { NSP_ETH_RAW_PORT = 0, @@ -492,6 +493,35 @@ nfp_eth_set_bit_config(struct nfp_nsp *nsp, unsigned int raw_idx, return 0; } +int nfp_eth_set_idmode(struct nfp_cpp *cpp, unsigned int idx, bool state) +{ + union eth_table_entry *entries; + struct nfp_nsp *nsp; + u64 reg; + + nsp = nfp_eth_config_start(cpp, idx); + if (IS_ERR(nsp)) + return PTR_ERR(nsp); + + /* Set this features were added in ABI 0.32 */ + if (nfp_nsp_get_abi_ver_minor(nsp) < 32) { + nfp_err(nfp_nsp_cpp(nsp), + "set id mode operation not supported, please update flash\n"); + return -EOPNOTSUPP; + } + + entries = nfp_nsp_config_entries(nsp); + + reg = le64_to_cpu(entries[idx].control); + reg &= ~NSP_ETH_CTRL_SET_IDMODE; + reg |= FIELD_PREP(NSP_ETH_CTRL_SET_IDMODE, state); + entries[idx].control = cpu_to_le64(reg); + + nfp_nsp_config_set_modified(nsp, true); + + return nfp_eth_config_commit_end(nsp); +} + #define NFP_ETH_SET_BIT_CONFIG(nsp, raw_idx, mask, val, ctrl_bit) \ ({ \ __BF_FIELD_CHECK(mask, 0ULL, val, "NFP_ETH_SET_BIT_CONFIG: "); \ |