diff options
Diffstat (limited to 'drivers/net')
190 files changed, 2330 insertions, 1019 deletions
diff --git a/drivers/net/amt.c b/drivers/net/amt.c index f2f3139e38a5..0f4ff41d0535 100644 --- a/drivers/net/amt.c +++ b/drivers/net/amt.c @@ -2979,7 +2979,7 @@ static int amt_socket_create(struct amt_dev *amt) tunnel_cfg.encap_rcv = amt_rcv; tunnel_cfg.encap_err_lookup = amt_err_lookup; tunnel_cfg.encap_destroy = NULL; - setup_udp_tunnel_sock(amt->net, sock, &tunnel_cfg); + setup_udp_tunnel_sock(amt->net, sock->sk, &tunnel_cfg); rcu_assign_pointer(amt->sock, sock); return 0; @@ -3032,7 +3032,7 @@ static int amt_dev_stop(struct net_device *dev) RCU_INIT_POINTER(amt->sock, NULL); synchronize_net(); if (sock) - udp_tunnel_sock_release(sock); + udp_tunnel_sock_release(sock->sk); cancel_work_sync(&amt->event_wq); for (i = 0; i < AMT_MAX_EVENTS; i++) { @@ -3301,9 +3301,9 @@ static size_t amt_get_size(const struct net_device *dev) nla_total_size(sizeof(__u16)) + /* IFLA_AMT_GATEWAY_PORT */ nla_total_size(sizeof(__u32)) + /* IFLA_AMT_LINK */ nla_total_size(sizeof(__u32)) + /* IFLA_MAX_TUNNELS */ - nla_total_size(sizeof(struct iphdr)) + /* IFLA_AMT_DISCOVERY_IP */ - nla_total_size(sizeof(struct iphdr)) + /* IFLA_AMT_REMOTE_IP */ - nla_total_size(sizeof(struct iphdr)); /* IFLA_AMT_LOCAL_IP */ + nla_total_size(sizeof(__be32)) + /* IFLA_AMT_DISCOVERY_IP */ + nla_total_size(sizeof(__be32)) + /* IFLA_AMT_REMOTE_IP */ + nla_total_size(sizeof(__be32)); /* IFLA_AMT_LOCAL_IP */ } static int amt_fill_info(struct sk_buff *skb, const struct net_device *dev) diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c index da5866ba0699..169ab90393cc 100644 --- a/drivers/net/bareudp.c +++ b/drivers/net/bareudp.c @@ -268,7 +268,7 @@ static int bareudp_socket_create(struct bareudp_dev *bareudp, __be16 port) tunnel_cfg.encap_rcv = bareudp_udp_encap_recv; tunnel_cfg.encap_err_lookup = bareudp_err_lookup; tunnel_cfg.encap_destroy = NULL; - setup_udp_tunnel_sock(bareudp->net, sock, &tunnel_cfg); + setup_udp_tunnel_sock(bareudp->net, sock->sk, &tunnel_cfg); rcu_assign_pointer(bareudp->sock, sock); return 0; @@ -290,7 +290,7 @@ static void bareudp_sock_release(struct bareudp_dev *bareudp) sock = bareudp->sock; rcu_assign_pointer(bareudp->sock, NULL); synchronize_net(); - udp_tunnel_sock_release(sock); + udp_tunnel_sock_release(sock->sk); } static int bareudp_stop(struct net_device *dev) diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 985ef66dc333..acbba08dbdfa 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -745,6 +745,21 @@ static void __set_agg_ports_ready(struct aggregator *aggregator, int val) } } +static int __agg_usable_ports(struct aggregator *agg) +{ + struct port *port; + int valid = 0; + + for (port = agg->lag_ports; port; + port = port->next_port_in_aggregator) { + if (port->actor_oper_port_state & LACP_STATE_COLLECTING && + port->actor_oper_port_state & LACP_STATE_DISTRIBUTING) + valid++; + } + + return valid; +} + static int __agg_active_ports(struct aggregator *agg) { struct port *port; @@ -1179,10 +1194,10 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr) switch (port->sm_mux_state) { case AD_MUX_DETACHED: port->actor_oper_port_state &= ~LACP_STATE_SYNCHRONIZATION; - ad_disable_collecting_distributing(port, - update_slave_arr); port->actor_oper_port_state &= ~LACP_STATE_COLLECTING; port->actor_oper_port_state &= ~LACP_STATE_DISTRIBUTING; + ad_disable_collecting_distributing(port, + update_slave_arr); port->ntt = true; break; case AD_MUX_WAITING: @@ -1322,6 +1337,7 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) fallthrough; case AD_RX_PORT_DISABLED: port->sm_vars &= ~AD_PORT_MATCHED; + port->partner_oper.port_state &= ~LACP_STATE_SYNCHRONIZATION; break; case AD_RX_LACP_DISABLED: port->sm_vars &= ~AD_PORT_SELECTED; @@ -2107,6 +2123,7 @@ static void ad_disable_distributing(struct port *port, bool *update_slave_arr) port->actor_port_number, aggregator->aggregator_identifier); __disable_distributing_port(port); + bond_3ad_set_carrier(port->slave->bond); /* Slave array needs an update */ *update_slave_arr = true; } @@ -2130,6 +2147,7 @@ static void ad_enable_collecting_distributing(struct port *port, port->actor_port_number, aggregator->aggregator_identifier); __enable_port(port); + bond_3ad_set_carrier(port->slave->bond); /* Slave array needs update */ *update_slave_arr = true; /* Should notify peers if possible */ @@ -2153,6 +2171,7 @@ static void ad_disable_collecting_distributing(struct port *port, port->actor_port_number, aggregator->aggregator_identifier); __disable_port(port); + bond_3ad_set_carrier(port->slave->bond); /* Slave array needs an update */ *update_slave_arr = true; } @@ -2832,7 +2851,9 @@ int bond_3ad_set_carrier(struct bonding *bond) active = __get_active_agg(&(SLAVE_AD_INFO(first_slave)->aggregator)); if (active) { /* are enough slaves available to consider link up? */ - if (__agg_active_ports(active) < bond->params.min_links) { + if ((bond->params.lacp_strict ? __agg_usable_ports(active) + : __agg_active_ports(active)) < + bond->params.min_links) { if (netif_carrier_ok(bond->dev)) { netif_carrier_off(bond->dev); goto out; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 8e75453ce0ef..cd9b0a6d6521 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -6446,6 +6446,7 @@ static int __init bond_check_params(struct bond_params *params) params->ad_user_port_key = ad_user_port_key; params->coupled_control = 1; params->broadcast_neighbor = 0; + params->lacp_strict = 0; if (packets_per_slave > 0) { params->reciprocal_packets_per_slave = reciprocal_value(packets_per_slave); diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 90365d3f7ebf..4a11572f663d 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -143,6 +143,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { [IFLA_BOND_NS_IP6_TARGET] = { .type = NLA_NESTED }, [IFLA_BOND_COUPLED_CONTROL] = { .type = NLA_U8 }, [IFLA_BOND_BROADCAST_NEIGH] = { .type = NLA_U8 }, + [IFLA_BOND_LACP_STRICT] = { .type = NLA_U8 }, }; static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = { @@ -599,6 +600,16 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], return err; } + if (data[IFLA_BOND_LACP_STRICT]) { + int fallback_mode = nla_get_u8(data[IFLA_BOND_LACP_STRICT]); + + bond_opt_initval(&newval, fallback_mode); + err = __bond_opt_set(bond, BOND_OPT_LACP_STRICT, &newval, + data[IFLA_BOND_LACP_STRICT], extack); + if (err) + return err; + } + return 0; } @@ -671,6 +682,7 @@ static size_t bond_get_size(const struct net_device *bond_dev) nla_total_size(sizeof(struct in6_addr)) * BOND_MAX_NS_TARGETS + nla_total_size(sizeof(u8)) + /* IFLA_BOND_COUPLED_CONTROL */ nla_total_size(sizeof(u8)) + /* IFLA_BOND_BROADCAST_NEIGH */ + nla_total_size(sizeof(u8)) + /* IFLA_BOND_LACP_STRICT */ 0; } @@ -838,6 +850,10 @@ static int bond_fill_info(struct sk_buff *skb, bond->params.broadcast_neighbor)) goto nla_put_failure; + if (nla_put_u8(skb, IFLA_BOND_LACP_STRICT, + bond->params.lacp_strict)) + goto nla_put_failure; + if (BOND_MODE(bond) == BOND_MODE_8023AD) { struct ad_info info; diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 7380cc4ee75a..94b7b0851f16 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -68,6 +68,8 @@ static int bond_option_lacp_active_set(struct bonding *bond, const struct bond_opt_value *newval); static int bond_option_lacp_rate_set(struct bonding *bond, const struct bond_opt_value *newval); +static int bond_option_lacp_strict_set(struct bonding *bond, + const struct bond_opt_value *newval); static int bond_option_ad_select_set(struct bonding *bond, const struct bond_opt_value *newval); static int bond_option_queue_id_set(struct bonding *bond, @@ -162,6 +164,12 @@ static const struct bond_opt_value bond_lacp_rate_tbl[] = { { NULL, -1, 0}, }; +static const struct bond_opt_value bond_lacp_strict_tbl[] = { + { "off", 0, BOND_VALFLAG_DEFAULT}, + { "on", 1, 0}, + { NULL, -1, 0 } +}; + static const struct bond_opt_value bond_ad_select_tbl[] = { { "stable", BOND_AD_STABLE, BOND_VALFLAG_DEFAULT}, { "bandwidth", BOND_AD_BANDWIDTH, 0}, @@ -363,6 +371,14 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { .values = bond_lacp_rate_tbl, .set = bond_option_lacp_rate_set }, + [BOND_OPT_LACP_STRICT] = { + .id = BOND_OPT_LACP_STRICT, + .name = "lacp_strict", + .desc = "Define the LACP fallback mode when no slaves have negotiated", + .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)), + .values = bond_lacp_strict_tbl, + .set = bond_option_lacp_strict_set + }, [BOND_OPT_MINLINKS] = { .id = BOND_OPT_MINLINKS, .name = "min_links", @@ -1684,6 +1700,17 @@ static int bond_option_lacp_rate_set(struct bonding *bond, return 0; } +static int bond_option_lacp_strict_set(struct bonding *bond, + const struct bond_opt_value *newval) +{ + netdev_dbg(bond->dev, "Setting LACP fallback to %s (%llu)\n", + newval->string, newval->value); + bond->params.lacp_strict = newval->value; + bond_3ad_set_carrier(bond); + + return 0; +} + static int bond_option_ad_select_set(struct bonding *bond, const struct bond_opt_value *newval) { diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c index d257440fa01f..f41d4a0d140f 100644 --- a/drivers/net/can/usb/esd_usb.c +++ b/drivers/net/can/usb/esd_usb.c @@ -1390,10 +1390,13 @@ static void esd_usb_disconnect(struct usb_interface *intf) netdev = dev->nets[i]->netdev; netdev_info(netdev, "unregister\n"); unregister_netdev(netdev); - free_candev(netdev); } } unlink_all_urbs(dev); + for (i = 0; i < dev->net_count; i++) { + if (dev->nets[i]) + free_candev(dev->nets[i]->netdev); + } kfree(dev); } } diff --git a/drivers/net/dsa/mxl862xx/mxl862xx-host.c b/drivers/net/dsa/mxl862xx/mxl862xx-host.c index d55f9dff6433..4acd216f7cc0 100644 --- a/drivers/net/dsa/mxl862xx/mxl862xx-host.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx-host.c @@ -12,6 +12,7 @@ #include <linux/crc16.h> #include <linux/iopoll.h> #include <linux/limits.h> +#include <linux/unaligned.h> #include <net/dsa.h> #include "mxl862xx.h" #include "mxl862xx-host.h" @@ -40,12 +41,13 @@ static void mxl862xx_crc_err_work_fn(struct work_struct *work) crc_err_work); struct dsa_port *dp; - dev_warn(&priv->mdiodev->dev, - "MDIO CRC error detected, shutting down all ports\n"); - rtnl_lock(); - dsa_switch_for_each_cpu_port(dp, priv->ds) - dev_close(dp->conduit); + if (!test_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags)) { + dev_warn(&priv->mdiodev->dev, + "MDIO CRC error detected, shutting down all ports\n"); + dsa_switch_for_each_cpu_port(dp, priv->ds) + dev_close(dp->conduit); + } rtnl_unlock(); clear_bit(MXL862XX_FLAG_CRC_ERR, &priv->flags); @@ -349,7 +351,7 @@ int mxl862xx_api_wrap(struct mxl862xx_priv *priv, u16 cmd, void *_data, * zero words individually. */ for (i = 0, zeros = 0; i < size / 2 && zeros < RST_DATA_THRESHOLD; i++) - if (!data[i]) + if (!get_unaligned_le16(&data[i])) zeros++; if (zeros < RST_DATA_THRESHOLD && (size & 1) && !*(u8 *)&data[i]) @@ -395,7 +397,7 @@ int mxl862xx_api_wrap(struct mxl862xx_priv *priv, u16 cmd, void *_data, */ val = *(u8 *)&data[i] | ((crc & 0xff) << 8); } else { - val = le16_to_cpu(data[i]); + val = get_unaligned_le16(&data[i]); } /* After RST_DATA, skip zero data words as the registers @@ -453,7 +455,7 @@ int mxl862xx_api_wrap(struct mxl862xx_priv *priv, u16 cmd, void *_data, *(uint8_t *)&data[i] = ret & 0xff; crc = (ret >> 8) & 0xff; } else { - data[i] = cpu_to_le16((u16)ret); + put_unaligned_le16((u16)ret, &data[i]); } } diff --git a/drivers/net/dsa/qca/qca8k-leds.c b/drivers/net/dsa/qca/qca8k-leds.c index 43ac68052baf..ef496e345a4e 100644 --- a/drivers/net/dsa/qca/qca8k-leds.c +++ b/drivers/net/dsa/qca/qca8k-leds.c @@ -429,7 +429,8 @@ qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int p init_data.fwnode = led; init_data.devname_mandatory = true; init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d", - priv->internal_mdio_bus->id, + priv->internal_mdio_bus ? + priv->internal_mdio_bus->id : priv->bus->id, port_num); if (!init_data.devicename) { fwnode_handle_put(led); diff --git a/drivers/net/dsa/realtek/rtl8366rb-leds.c b/drivers/net/dsa/realtek/rtl8366rb-leds.c index 509ffd3f8db5..ba50d311cb15 100644 --- a/drivers/net/dsa/realtek/rtl8366rb-leds.c +++ b/drivers/net/dsa/realtek/rtl8366rb-leds.c @@ -89,6 +89,7 @@ static int rtl8366rb_setup_led(struct realtek_priv *priv, struct dsa_port *dp, struct led_init_data init_data = { }; enum led_default_state state; struct rtl8366rb_led *led; + char name[64]; u32 led_group; int ret; @@ -129,10 +130,9 @@ static int rtl8366rb_setup_led(struct realtek_priv *priv, struct dsa_port *dp, init_data.fwnode = led_fwnode; init_data.devname_mandatory = true; - init_data.devicename = kasprintf(GFP_KERNEL, "Realtek-%d:0%d:%d", - dp->ds->index, dp->index, led_group); - if (!init_data.devicename) - return -ENOMEM; + snprintf(name, sizeof(name), "Realtek-%d:0%d:%d", + dp->ds->index, dp->index, led_group); + init_data.devicename = name; ret = devm_led_classdev_register_ext(priv->dev, &led->cdev, &init_data); if (ret) { diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index fefe46e2a5e6..350f958dcb2a 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -755,7 +755,7 @@ static int sja1105_per_out_enable(struct sja1105_private *priv, * 2 edges on PTP_CLK. So check for truncation which happens * at periods larger than around 68.7 seconds. */ - pin_duration = ns_to_sja1105_ticks(pin_duration / 2); + pin_duration = max_t(u64, ns_to_sja1105_ticks(pin_duration / 2), 1); if (pin_duration > U32_MAX) { rc = -ERANGE; goto out; diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c index 31cdb11cd78d..1e361a35ebd4 100644 --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c @@ -311,7 +311,7 @@ static void airoha_fe_pse_ports_init(struct airoha_eth *eth) PSE_QUEUE_RSV_PAGES); /* PPE1 */ for (q = 0; q < pse_port_num_queues[FE_PSE_PORT_PPE1]; q++) { - if (q < pse_port_num_queues[FE_PSE_PORT_PPE1]) + if (q < pse_port_num_queues[FE_PSE_PORT_PPE1] / 2) airoha_fe_set_pse_oq_rsv(eth, FE_PSE_PORT_PPE1, q, PSE_QUEUE_RSV_PAGES); else @@ -1256,7 +1256,7 @@ static void airoha_qdma_init_qos_stats(struct airoha_qdma *qdma) FIELD_PREP(CNTR_CHAN_MASK, i)); /* Tx-fwd transferred count */ airoha_qdma_wr(qdma, REG_CNTR_VAL((i << 1) + 1), 0); - airoha_qdma_wr(qdma, REG_CNTR_CFG(i << 1), + airoha_qdma_wr(qdma, REG_CNTR_CFG((i << 1) + 1), CNTR_EN_MASK | CNTR_ALL_QUEUE_EN_MASK | CNTR_ALL_DSCP_RING_EN_MASK | FIELD_PREP(CNTR_SRC_MASK, 1) | @@ -1933,7 +1933,7 @@ static u16 airoha_dev_select_queue(struct net_device *dev, struct sk_buff *skb, */ channel = netdev_uses_dsa(dev) ? skb_get_queue_mapping(skb) : port->id; channel = channel % AIROHA_NUM_QOS_CHANNELS; - queue = (skb->priority - 1) % AIROHA_NUM_QOS_QUEUES; /* QoS queue */ + queue = skb->priority % AIROHA_NUM_QOS_QUEUES; queue = channel * AIROHA_NUM_QOS_QUEUES + queue; return queue < dev->num_tx_queues ? queue : 0; diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c index 5c9dff6bccd1..a1f9939c21f2 100644 --- a/drivers/net/ethernet/airoha/airoha_ppe.c +++ b/drivers/net/ethernet/airoha/airoha_ppe.c @@ -1330,7 +1330,7 @@ static int airoha_ppe_flush_sram_entries(struct airoha_ppe *ppe) { u32 sram_num_entries = airoha_ppe_get_total_sram_num_entries(ppe); struct airoha_foe_entry *hwe = ppe->foe; - int i, err = 0; + int i; for (i = 0; i < sram_num_entries; i++) { int err; @@ -1338,10 +1338,10 @@ static int airoha_ppe_flush_sram_entries(struct airoha_ppe *ppe) memset(&hwe[i], 0, sizeof(*hwe)); err = airoha_ppe_foe_commit_sram_entry(ppe, i); if (err) - break; + return err; } - return err; + return 0; } static struct airoha_npu *airoha_ppe_npu_get(struct airoha_eth *eth) @@ -1578,7 +1578,8 @@ int airoha_ppe_init(struct airoha_eth *eth) return -ENOMEM; } - ppe->foe_check_time = devm_kzalloc(eth->dev, ppe_num_entries, + ppe->foe_check_time = devm_kzalloc(eth->dev, + ppe_num_entries * sizeof(*ppe->foe_check_time), GFP_KERNEL); if (!ppe->foe_check_time) return -ENOMEM; diff --git a/drivers/net/ethernet/airoha/airoha_ppe_debugfs.c b/drivers/net/ethernet/airoha/airoha_ppe_debugfs.c index 0112c41150bb..e46a98514486 100644 --- a/drivers/net/ethernet/airoha/airoha_ppe_debugfs.c +++ b/drivers/net/ethernet/airoha/airoha_ppe_debugfs.c @@ -121,8 +121,6 @@ static int airoha_ppe_debugfs_foe_show(struct seq_file *m, void *private, case PPE_PKT_TYPE_IPV4_DSLITE: src_port = &hwe->ipv4.new_tuple.src_port; dest_port = &hwe->ipv4.new_tuple.dest_port; - fallthrough; - case PPE_PKT_TYPE_IPV4_ROUTE: src_addr = &hwe->ipv4.new_tuple.src_ip; dest_addr = &hwe->ipv4.new_tuple.dest_ip; seq_puts(m, " new="); diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 92d149d4f091..5d05020a6d05 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -752,6 +752,18 @@ static void ena_destroy_all_tx_queues(struct ena_adapter *adapter) } } +static void ena_destroy_xdp_tx_queues(struct ena_adapter *adapter) +{ + u16 ena_qid; + int i; + + for (i = adapter->xdp_first_ring; + i < adapter->xdp_first_ring + adapter->xdp_num_queues; i++) { + ena_qid = ENA_IO_TXQ_IDX(i); + ena_com_destroy_io_queue(adapter->ena_dev, ena_qid); + } +} + static void ena_destroy_all_rx_queues(struct ena_adapter *adapter) { u16 ena_qid; @@ -2078,14 +2090,21 @@ static int create_queues_with_size_backoff(struct ena_adapter *adapter) rc = ena_setup_tx_resources_in_range(adapter, 0, adapter->num_io_queues); - if (rc) + if (rc) { + ena_destroy_xdp_tx_queues(adapter); + ena_free_all_io_tx_resources_in_range(adapter, + adapter->xdp_first_ring, + adapter->xdp_num_queues); goto err_setup_tx; + } rc = ena_create_io_tx_queues_in_range(adapter, 0, adapter->num_io_queues); - if (rc) + if (rc) { + ena_destroy_xdp_tx_queues(adapter); goto err_create_tx_queues; + } rc = ena_setup_all_rx_resources(adapter); if (rc) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 19e078479b0d..5b2640bd31c3 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -4748,6 +4748,7 @@ int bnx2x_alloc_mem_bp(struct bnx2x *bp) fp = kzalloc_objs(*fp, bp->fp_array_size); if (!fp) goto alloc_err; + bp->fp = fp; for (i = 0; i < bp->fp_array_size; i++) { fp[i].tpa_info = kzalloc_objs(struct bnx2x_agg_info, @@ -4756,8 +4757,6 @@ int bnx2x_alloc_mem_bp(struct bnx2x *bp) goto alloc_err; } - bp->fp = fp; - /* allocate sp objs */ bp->sp_objs = kzalloc_objs(struct bnx2x_sp_objs, bp->fp_array_size); if (!bp->sp_objs) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index c999f9733326..d44d3ac255aa 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -1011,6 +1011,7 @@ int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, mapping += bp->rx_dma_offset; rx_buf->data = page; rx_buf->data_ptr = page_address(page) + offset + bp->rx_offset; + rx_buf->offset = offset; } else { u8 *data = __bnxt_alloc_rx_frag(bp, &mapping, rxr, gfp); @@ -1019,6 +1020,7 @@ int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, rx_buf->data = data; rx_buf->data_ptr = data + bp->rx_offset; + rx_buf->offset = 0; } rx_buf->mapping = mapping; @@ -1040,6 +1042,7 @@ void bnxt_reuse_rx_data(struct bnxt_rx_ring_info *rxr, u16 cons, void *data) prod_rx_buf->data_ptr = cons_rx_buf->data_ptr; prod_rx_buf->mapping = cons_rx_buf->mapping; + prod_rx_buf->offset = cons_rx_buf->offset; prod_bd = &rxr->rx_desc_ring[RX_RING(bp, prod)][RX_IDX(prod)]; cons_bd = &rxr->rx_desc_ring[RX_RING(bp, cons)][RX_IDX(cons)]; @@ -1175,8 +1178,11 @@ static struct sk_buff *bnxt_rx_multi_page_skb(struct bnxt *bp, struct page *page = data; u16 prod = rxr->rx_prod; struct sk_buff *skb; + void *frag_start; int err; + frag_start = page_address(page) + rxr->rx_buf_ring[cons].offset; + err = bnxt_alloc_rx_data(bp, rxr, prod, GFP_ATOMIC); if (unlikely(err)) { bnxt_reuse_rx_data(rxr, cons, data); @@ -1185,13 +1191,13 @@ static struct sk_buff *bnxt_rx_multi_page_skb(struct bnxt *bp, dma_addr -= bp->rx_dma_offset; dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr, rxr->rx_page_size, bp->rx_dir); - skb = napi_build_skb(data_ptr - bp->rx_offset, rxr->rx_page_size); + skb = napi_build_skb(frag_start, rxr->rx_page_size); if (!skb) { page_pool_recycle_direct(rxr->page_pool, page); return NULL; } skb_mark_for_recycle(skb); - skb_reserve(skb, bp->rx_offset); + skb_reserve(skb, data_ptr - (u8 *)frag_start); __skb_put(skb, len); return skb; @@ -10524,7 +10530,7 @@ static void bnxt_accumulate_stats(struct bnxt_stats_mem *stats) stats->hw_masks, stats->len / 8, false); } -static void bnxt_accumulate_all_stats(struct bnxt *bp) +static void bnxt_accumulate_ring_stats(struct bnxt *bp) { struct bnxt_stats_mem *ring0_stats; bool ignore_zero = false; @@ -10547,6 +10553,10 @@ static void bnxt_accumulate_all_stats(struct bnxt *bp) ring0_stats->hw_masks, ring0_stats->len / 8, ignore_zero); } +} + +static void bnxt_accumulate_port_stats(struct bnxt *bp) +{ if (bp->flags & BNXT_FLAG_PORT_STATS) { struct bnxt_stats_mem *stats = &bp->port_stats; __le64 *hw_stats = stats->hw_stats; @@ -10569,6 +10579,41 @@ static void bnxt_accumulate_all_stats(struct bnxt *bp) } } +static void bnxt_accumulate_all_stats(struct bnxt *bp) +{ + bnxt_accumulate_ring_stats(bp); + bnxt_accumulate_port_stats(bp); +} + +/* Re-accumulate ring stats from DMA buffers if stale. + * uAPIs for reading sw_stats should call this first. + * + * We promise user space update frequency of bp->stats_coal_ticks but + * the update is a two step process - first device updates the DMA buffer, + * then we have to update from that buffer to driver stats in the service work. + * Worst case we would be 2x off from the desired frequency. + * Sync the stats sooner, if stale. The 20% threshold was chosen arbitrarily. + * + * Ideally we would split the user-configured time into two portions, + * i.e. also lower the DMA period by the 20%. But the DMA timer seems to have + * too coarse granularity to play such tricks. + */ +void bnxt_sync_ring_stats(struct bnxt *bp) +{ + unsigned long stale; + + if (!netif_running(bp->dev) || !bp->stats_coal_ticks) + return; + + spin_lock(&bp->stats_lock); + stale = usecs_to_jiffies(bp->stats_coal_ticks / 5); + if (time_after_eq(jiffies, bp->stats_updated_jiffies + stale)) { + bnxt_accumulate_ring_stats(bp); + bp->stats_updated_jiffies = jiffies; + } + spin_unlock(&bp->stats_lock); +} + static int bnxt_hwrm_port_qstats(struct bnxt *bp, u8 flags) { struct hwrm_port_qstats_input *req; @@ -13567,6 +13612,7 @@ bnxt_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) return; } + bnxt_sync_ring_stats(bp); bnxt_get_ring_stats(bp, stats); bnxt_add_prev_stats(bp, stats); @@ -14748,7 +14794,10 @@ static void bnxt_sp_task(struct work_struct *work) if (test_and_clear_bit(BNXT_PERIODIC_STATS_SP_EVENT, &bp->sp_event)) { bnxt_hwrm_port_qstats(bp, 0); bnxt_hwrm_port_qstats_ext(bp, 0); + spin_lock(&bp->stats_lock); bnxt_accumulate_all_stats(bp); + bp->stats_updated_jiffies = jiffies; + spin_unlock(&bp->stats_lock); } if (test_and_clear_bit(BNXT_LINK_CHNG_SP_EVENT, &bp->sp_event)) { @@ -15490,6 +15539,7 @@ static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev) INIT_DELAYED_WORK(&bp->fw_reset_task, bnxt_fw_reset_task); spin_lock_init(&bp->ntp_fltr_lock); + spin_lock_init(&bp->stats_lock); #if BITS_PER_LONG == 32 spin_lock_init(&bp->db_lock); #endif @@ -16058,6 +16108,7 @@ static void bnxt_get_queue_stats_rx(struct net_device *dev, int i, if (!bp->bnapi) return; + bnxt_sync_ring_stats(bp); cpr = &bp->bnapi[i]->cp_ring; sw = cpr->stats.sw_stats; @@ -16086,6 +16137,7 @@ static void bnxt_get_queue_stats_tx(struct net_device *dev, int i, if (!bp->tx_ring) return; + bnxt_sync_ring_stats(bp); bnapi = bp->tx_ring[bp->tx_ring_map[i]].bnapi; sw = bnapi->cp_ring.stats.sw_stats; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 61c847b36b9f..fa13cee55779 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -911,6 +911,7 @@ struct bnxt_sw_rx_bd { void *data; u8 *data_ptr; dma_addr_t mapping; + unsigned int offset; }; struct bnxt_sw_rx_agg_bd { @@ -2620,6 +2621,10 @@ struct bnxt { #define BNXT_MIN_STATS_COAL_TICKS 250000 #define BNXT_MAX_STATS_COAL_TICKS 1000000 + /* Protects stats_updated_jiffies and writes to sw_stats */ + spinlock_t stats_lock; + unsigned long stats_updated_jiffies; + struct work_struct sp_task; unsigned long sp_event; #define BNXT_RX_MASK_SP_EVENT 0 @@ -3028,6 +3033,7 @@ void bnxt_reenable_sriov(struct bnxt *bp); void bnxt_close_nic(struct bnxt *, bool, bool); void bnxt_get_ring_drv_stats(struct bnxt *bp, struct bnxt_total_ring_drv_stats *stats); +void bnxt_sync_ring_stats(struct bnxt *bp); bool bnxt_rfs_capable(struct bnxt *bp, bool new_rss_ctx); int bnxt_dbg_hwrm_rd_reg(struct bnxt *bp, u32 reg_off, u16 num_words, u32 *reg_buf); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 9b14134d62d2..b98761d55a2b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -606,6 +606,7 @@ static void bnxt_get_ethtool_stats(struct net_device *dev, goto skip_ring_stats; } + bnxt_sync_ring_stats(bp); tpa_stats = bnxt_get_num_tpa_ring_stats(bp); for (i = 0; i < bp->cp_nr_rings; i++) { struct bnxt_napi *bnapi = bp->bnapi[i]; diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 7c11cf916762..ad08c67269be 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -40,9 +40,8 @@ #include "bcmgenet.h" -/* Default highest priority queue for multi queue support */ -#define GENET_Q1_PRIORITY 0 -#define GENET_Q0_PRIORITY 1 +#define GENET_Q0_WEIGHT 1 +#define GENET_Q1_WEIGHT 4 #define GENET_Q0_RX_BD_CNT \ (TOTAL_DESC - priv->hw_params->rx_queues * priv->hw_params->rx_bds_per_q) @@ -2129,13 +2128,6 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) int i; index = skb_get_queue_mapping(skb); - /* Mapping strategy: - * queue_mapping = 0, unclassified, packet xmited through ring 0 - * queue_mapping = 1, goes to ring 1. (highest priority queue) - * queue_mapping = 2, goes to ring 2. - * queue_mapping = 3, goes to ring 3. - * queue_mapping = 4, goes to ring 4. - */ ring = &priv->tx_rings[index]; txq = netdev_get_tx_queue(dev, index); @@ -2881,8 +2873,9 @@ static int bcmgenet_rdma_disable(struct bcmgenet_priv *priv) /* Initialize Tx queues * - * Queues 1-4 are priority-based, each one has 32 descriptors, - * with queue 1 being the highest priority queue. + * Queues 1-4 are the priority queues, each one has 32 descriptors. + * The weighted round-robin arbiter gives them a larger share of TX + * bandwidth than the default queue 0. * * Queue 0 is the default Tx queue with * GENET_Q0_TX_BD_CNT = 256 - 4 * 32 = 128 descriptors. @@ -2900,8 +2893,8 @@ static void bcmgenet_init_tx_queues(struct net_device *dev) unsigned int start = 0, end = GENET_Q0_TX_BD_CNT; u32 i, ring_mask, dma_priority[3] = {0, 0, 0}; - /* Enable strict priority arbiter mode */ - bcmgenet_tdma_writel(priv, DMA_ARBITER_SP, DMA_ARB_CTRL); + /* Enable Weighted Round-Robin arbiter mode */ + bcmgenet_tdma_writel(priv, DMA_ARBITER_WRR, DMA_ARB_CTRL); /* Initialize Tx priority queues */ for (i = 0; i <= priv->hw_params->tx_queues; i++) { @@ -2909,7 +2902,7 @@ static void bcmgenet_init_tx_queues(struct net_device *dev) start = end; end += priv->hw_params->tx_bds_per_q; dma_priority[DMA_PRIO_REG_INDEX(i)] |= - (i ? GENET_Q1_PRIORITY : GENET_Q0_PRIORITY) + (i ? GENET_Q1_WEIGHT : GENET_Q0_WEIGHT) << DMA_PRIO_REG_SHIFT(i); } diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index a12aa21244e8..d394f1f43b68 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -2668,8 +2668,25 @@ static void macb_free_consistent(struct macb *bp) dma_free_coherent(dev, size, bp->queues[0].rx_ring, bp->queues[0].rx_ring_dma); for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { - kfree(queue->tx_skb); - queue->tx_skb = NULL; + if (queue->tx_skb) { + unsigned int dropped = 0, tail; + + for (tail = queue->tx_tail; tail != queue->tx_head; + tail++) { + if (macb_tx_skb(queue, tail)->skb) + dropped++; + macb_tx_unmap(bp, macb_tx_skb(queue, tail), 0); + } + + queue->stats.tx_dropped += dropped; + bp->dev->stats.tx_dropped += dropped; + + kfree(queue->tx_skb); + queue->tx_skb = NULL; + } + + queue->tx_head = 0; + queue->tx_tail = 0; queue->tx_ring = NULL; queue->rx_ring = NULL; } @@ -4522,6 +4539,13 @@ static int macb_setup_tc(struct net_device *dev, enum tc_setup_type type, } } +static void macb_tx_timeout(struct net_device *dev, unsigned int q) +{ + struct macb *bp = netdev_priv(dev); + + macb_tx_restart(&bp->queues[q]); +} + static const struct net_device_ops macb_netdev_ops = { .ndo_open = macb_open, .ndo_stop = macb_close, @@ -4540,6 +4564,7 @@ static const struct net_device_ops macb_netdev_ops = { .ndo_hwtstamp_set = macb_hwtstamp_set, .ndo_hwtstamp_get = macb_hwtstamp_get, .ndo_setup_tc = macb_setup_tc, + .ndo_tx_timeout = macb_tx_timeout, }; /* Configure peripheral capabilities according to device tree diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c index 75f22f74774c..06b4424e778e 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c @@ -1163,18 +1163,14 @@ int setup_cn23xx_octeon_pf_device(struct octeon_device *oct) if (octeon_map_pci_barx(oct, 1, MAX_BAR1_IOREMAP_SIZE)) { dev_err(&oct->pci_dev->dev, "%s CN23XX BAR1 map failed\n", __func__); - octeon_unmap_pci_barx(oct, 0); - return 1; + goto err_unmap_bar0; } if (cn23xx_get_pf_num(oct) != 0) - return 1; + goto err_unmap_bar1; - if (cn23xx_sriov_config(oct)) { - octeon_unmap_pci_barx(oct, 0); - octeon_unmap_pci_barx(oct, 1); - return 1; - } + if (cn23xx_sriov_config(oct)) + goto err_unmap_bar1; octeon_write_csr64(oct, CN23XX_SLI_MAC_CREDIT_CNT, 0x3F802080802080ULL); @@ -1205,6 +1201,12 @@ int setup_cn23xx_octeon_pf_device(struct octeon_device *oct) oct->coproc_clock_rate = 1000000ULL * cn23xx_coprocessor_clock(oct); return 0; + +err_unmap_bar1: + octeon_unmap_pci_barx(oct, 1); +err_unmap_bar0: + octeon_unmap_pci_barx(oct, 0); + return 1; } EXPORT_SYMBOL_GPL(setup_cn23xx_octeon_pf_device); diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index c1a3df225254..32dd9b25760e 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -3781,9 +3781,7 @@ setup_nic_dev_done: static int octeon_enable_sriov(struct octeon_device *oct) { unsigned int num_vfs_alloced = oct->sriov_info.num_vfs_alloced; - struct pci_dev *vfdev; int err; - u32 u; if (OCTEON_CN23XX_PF(oct) && num_vfs_alloced) { err = pci_enable_sriov(oct->pci_dev, @@ -3796,23 +3794,6 @@ static int octeon_enable_sriov(struct octeon_device *oct) return err; } oct->sriov_info.sriov_enabled = 1; - - /* init lookup table that maps DPI ring number to VF pci_dev - * struct pointer - */ - u = 0; - vfdev = pci_get_device(PCI_VENDOR_ID_CAVIUM, - OCTEON_CN23XX_VF_VID, NULL); - while (vfdev) { - if (vfdev->is_virtfn && - (vfdev->physfn == oct->pci_dev)) { - oct->sriov_info.dpiring_to_vfpcidev_lut[u] = - vfdev; - u += oct->sriov_info.rings_per_vf; - } - vfdev = pci_get_device(PCI_VENDOR_ID_CAVIUM, - OCTEON_CN23XX_VF_VID, vfdev); - } } return num_vfs_alloced; @@ -3820,8 +3801,6 @@ static int octeon_enable_sriov(struct octeon_device *oct) static int lio_pci_sriov_disable(struct octeon_device *oct) { - int u; - if (pci_vfs_assigned(oct->pci_dev)) { dev_err(&oct->pci_dev->dev, "VFs are still assigned to VMs.\n"); return -EPERM; @@ -3829,12 +3808,6 @@ static int lio_pci_sriov_disable(struct octeon_device *oct) pci_disable_sriov(oct->pci_dev); - u = 0; - while (u < MAX_POSSIBLE_VFS) { - oct->sriov_info.dpiring_to_vfpcidev_lut[u] = NULL; - u += oct->sriov_info.rings_per_vf; - } - oct->sriov_info.num_vfs_alloced = 0; dev_info(&oct->pci_dev->dev, "oct->pf_num:%d disabled VFs\n", oct->pf_num); diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.h b/drivers/net/ethernet/cavium/liquidio/octeon_device.h index 19344b21f8fb..858a0fff2cc0 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.h @@ -390,9 +390,6 @@ struct octeon_sriov_info { struct lio_trusted_vf trusted_vf; - /*lookup table that maps DPI ring number to VF pci_dev struct pointer*/ - struct pci_dev *dpiring_to_vfpcidev_lut[MAX_POSSIBLE_VFS]; - u64 vf_macaddr[MAX_POSSIBLE_VFS]; u16 vf_vlantci[MAX_POSSIBLE_VFS]; diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c index ad685f5d0a13..697fcdc41e3c 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c @@ -26,6 +26,31 @@ #include "octeon_mailbox.h" #include "cn23xx_pf_device.h" +static struct pci_dev *lio_vf_pci_dev_by_qno(struct octeon_device *oct, u32 q_no) +{ + struct pci_dev *vfdev = NULL; + int vfidx; + + if (!oct->sriov_info.rings_per_vf) + return NULL; + + if (q_no % oct->sriov_info.rings_per_vf) + return NULL; + + vfidx = q_no / oct->sriov_info.rings_per_vf; + if (vfidx >= oct->sriov_info.num_vfs_alloced) + return NULL; + + while ((vfdev = pci_get_device(PCI_VENDOR_ID_CAVIUM, + OCTEON_CN23XX_VF_VID, vfdev))) { + if (pci_physfn(vfdev) && pci_physfn(vfdev) == oct->pci_dev && + pci_iov_vf_id(vfdev) == vfidx) + return vfdev; + } + + return NULL; +} + /** * octeon_mbox_read: * @mbox: Pointer mailbox @@ -237,6 +262,7 @@ static int octeon_mbox_process_cmd(struct octeon_mbox *mbox, struct octeon_mbox_cmd *mbox_cmd) { struct octeon_device *oct = mbox->oct_dev; + struct pci_dev *vfdev; switch (mbox_cmd->msg.s.cmd) { case OCTEON_VF_ACTIVE: @@ -260,7 +286,12 @@ static int octeon_mbox_process_cmd(struct octeon_mbox *mbox, dev_info(&oct->pci_dev->dev, "got a request for FLR from VF that owns DPI ring %u\n", mbox->q_no); - pcie_flr(oct->sriov_info.dpiring_to_vfpcidev_lut[mbox->q_no]); + vfdev = lio_vf_pci_dev_by_qno(oct, mbox->q_no); + if (!vfdev) + break; + + pcie_flr(vfdev); + pci_dev_put(vfdev); break; case OCTEON_PF_CHANGED_VF_MACADDR: diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 171750fad44f..6871127427fa 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -6737,14 +6737,6 @@ void t4_sge_decode_idma_state(struct adapter *adapter, int state) return; } - if (is_t4(adapter->params.chip)) { - sge_idma_decode = (const char **)t4_decode; - sge_idma_decode_nstates = ARRAY_SIZE(t4_decode); - } else { - sge_idma_decode = (const char **)t5_decode; - sge_idma_decode_nstates = ARRAY_SIZE(t5_decode); - } - if (state < sge_idma_decode_nstates) CH_WARN(adapter, "idma state %s\n", sge_idma_decode[state]); else diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c index 52c1cb9cb7e0..fa4e4f479782 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c @@ -2177,7 +2177,7 @@ dpaa2_switch_prechangeupper_sanity_checks(struct net_device *netdev, if (err) { NL_SET_ERR_MSG_MOD(extack, "Cannot join a bridge while VLAN uppers are present"); - return 0; + return err; } netdev_for_each_lower_dev(upper_dev, other_dev, iter) { @@ -2198,6 +2198,7 @@ dpaa2_switch_prechangeupper_sanity_checks(struct net_device *netdev, static int dpaa2_switch_port_prechangeupper(struct net_device *netdev, struct netdev_notifier_changeupper_info *info) { + struct ethsw_port_priv *port_priv; struct netlink_ext_ack *extack; struct net_device *upper_dev; int err; @@ -2216,6 +2217,13 @@ static int dpaa2_switch_port_prechangeupper(struct net_device *netdev, if (!info->linking) dpaa2_switch_port_pre_bridge_leave(netdev); + } else if (is_vlan_dev(upper_dev)) { + port_priv = netdev_priv(netdev); + if (port_priv->fdb->bridge_dev) { + NL_SET_ERR_MSG_MOD(extack, + "Cannot accept VLAN uppers while bridged"); + return -EOPNOTSUPP; + } } return 0; diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index aa8a87124b10..8e3f345dd9aa 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -1783,6 +1783,7 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames, { struct enetc_tx_swbd xdp_redirect_arr[ENETC_MAX_SKB_FRAGS] = {0}; struct enetc_ndev_priv *priv = netdev_priv(ndev); + struct skb_shared_info *shinfo; struct enetc_bdr *tx_ring; int xdp_tx_bd_cnt, i, k; int xdp_tx_frm_cnt = 0; @@ -1798,6 +1799,12 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames, prefetchw(ENETC_TXBD(*tx_ring, tx_ring->next_to_use)); for (k = 0; k < num_frames; k++) { + if (xdp_frame_has_frags(frames[k])) { + shinfo = xdp_get_shared_info_from_frame(frames[k]); + if (unlikely((shinfo->nr_frags + 1) > ENETC_MAX_SKB_FRAGS)) + break; + } + xdp_tx_bd_cnt = enetc_xdp_frame_to_xdp_tx_swbd(tx_ring, xdp_redirect_arr, frames[k]); diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c index 56899f2254aa..71866d240b40 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c @@ -326,6 +326,9 @@ static void enetc4_default_rings_allocation(struct enetc_pf *pf) val = enetc4_psicfgr0_val_construct(false, num_tx_bdr, num_rx_bdr); enetc_port_wr(hw, ENETC4_PSICFGR0(0), val); + if (!pf->caps.num_vsi) + return; + num_rx_bdr = pf->caps.num_rx_bdr - num_rx_bdr; rx_rem = num_rx_bdr % pf->caps.num_vsi; num_rx_bdr = num_rx_bdr / pf->caps.num_vsi; diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c index 013273a2de32..299bab043175 100644 --- a/drivers/net/ethernet/freescale/fman/fman.c +++ b/drivers/net/ethernet/freescale/fman/fman.c @@ -1995,8 +1995,10 @@ static int fman_init(struct fman *fman) /* Init KeyGen */ fman->keygen = keygen_init(fman->kg_regs); - if (!fman->keygen) + if (!fman->keygen) { + free_init_resources(fman); return -EINVAL; + } err = enable(fman, cfg); if (err != 0) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 3271de5844f8..89215e1ddc2d 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -469,10 +469,13 @@ static void free_gfar_dev(struct gfar_private *priv) { int i, j; - for (i = 0; i < priv->num_grps; i++) + for (i = 0; i < MAXGROUPS; i++) for (j = 0; j < GFAR_NUM_IRQS; j++) { - kfree(priv->gfargrp[i].irqinfo[j]); - priv->gfargrp[i].irqinfo[j] = NULL; + if (priv->gfargrp[i].irqinfo[j]) { + irq_dispose_mapping(priv->gfargrp[i].irqinfo[j]->irq); + kfree(priv->gfargrp[i].irqinfo[j]); + priv->gfargrp[i].irqinfo[j] = NULL; + } } free_netdev(priv->ndev); @@ -616,7 +619,7 @@ static phy_interface_t gfar_get_interface(struct net_device *dev) static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) { const char *model; - int err = 0, i; + int err = 0, i, j; phy_interface_t interface; struct net_device *dev = NULL; struct gfar_private *priv = NULL; @@ -702,8 +705,11 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) priv->rx_list.count = 0; mutex_init(&priv->rx_queue_access); - for (i = 0; i < MAXGROUPS; i++) + for (i = 0; i < MAXGROUPS; i++) { priv->gfargrp[i].regs = NULL; + for (j = 0; j < GFAR_NUM_IRQS; j++) + priv->gfargrp[i].irqinfo[j] = NULL; + } /* Parse and initialize group specific information */ if (priv->mode == MQ_MG_MODE) { diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c index 7924dce719e2..02cba280d81a 100644 --- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c +++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c @@ -21,11 +21,13 @@ static void gve_rx_free_hdr_bufs(struct gve_priv *priv, struct gve_rx_ring *rx) { struct device *hdev = &priv->pdev->dev; - int buf_count = rx->dqo.bufq.mask + 1; if (rx->dqo.hdr_bufs.data) { - dma_free_coherent(hdev, priv->header_buf_size * buf_count, - rx->dqo.hdr_bufs.data, rx->dqo.hdr_bufs.addr); + size_t size = + (size_t)priv->header_buf_size * rx->dqo.num_buf_states; + + dma_free_coherent(hdev, size, rx->dqo.hdr_bufs.data, + rx->dqo.hdr_bufs.addr); rx->dqo.hdr_bufs.data = NULL; } } @@ -254,7 +256,7 @@ int gve_rx_alloc_ring_dqo(struct gve_priv *priv, /* Allocate header buffers for header-split */ if (cfg->enable_header_split) - if (gve_rx_alloc_hdr_bufs(priv, rx, buffer_queue_slots)) + if (gve_rx_alloc_hdr_bufs(priv, rx, rx->dqo.num_buf_states)) goto err; /* Allocate RX completion queue */ @@ -381,10 +383,13 @@ void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx) break; } - if (rx->dqo.hdr_bufs.data) + if (rx->dqo.hdr_bufs.data) { + u16 buf_id = le16_to_cpu(desc->buf_id); + desc->header_buf_addr = cpu_to_le64(rx->dqo.hdr_bufs.addr + - priv->header_buf_size * bufq->tail); + (size_t)priv->header_buf_size * buf_id); + } bufq->tail = (bufq->tail + 1) & bufq->mask; complq->num_free_slots--; @@ -826,10 +831,13 @@ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx, int unsplit = 0; if (hdr_len && !hbo) { - rx->ctx.skb_head = gve_rx_copy_data(priv->dev, napi, - rx->dqo.hdr_bufs.data + - desc_idx * priv->header_buf_size, - hdr_len); + size_t offset = + (size_t)buffer_id * priv->header_buf_size; + + rx->ctx.skb_head = + gve_rx_copy_data(priv->dev, napi, + rx->dqo.hdr_bufs.data + offset, + hdr_len); if (unlikely(!rx->ctx.skb_head)) goto error; rx->ctx.skb_tail = rx->ctx.skb_head; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 9cb7ce9fd311..442f15476af3 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -811,12 +811,11 @@ static int hns3_get_link_ksettings(struct net_device *netdev, } static int hns3_check_ksettings_param(const struct net_device *netdev, - const struct ethtool_link_ksettings *cmd) + const struct ethtool_link_ksettings *cmd, + u8 media_type) { struct hnae3_handle *handle = hns3_get_handle(netdev); const struct hnae3_ae_ops *ops = hns3_get_ops(handle); - u8 module_type = HNAE3_MODULE_TYPE_UNKNOWN; - u8 media_type = HNAE3_MEDIA_TYPE_UNKNOWN; u32 lane_num; u8 autoneg; u32 speed; @@ -836,9 +835,6 @@ static int hns3_check_ksettings_param(const struct net_device *netdev, return 0; } - if (ops->get_media_type) - ops->get_media_type(handle, &media_type, &module_type); - if (cmd->base.duplex == DUPLEX_HALF && media_type != HNAE3_MEDIA_TYPE_COPPER) { netdev_err(netdev, @@ -863,6 +859,8 @@ static int hns3_set_link_ksettings(struct net_device *netdev, struct hnae3_handle *handle = hns3_get_handle(netdev); struct hnae3_ae_dev *ae_dev = hns3_get_ae_dev(handle); const struct hnae3_ae_ops *ops = hns3_get_ops(handle); + u8 module_type = HNAE3_MODULE_TYPE_UNKNOWN; + u8 media_type = HNAE3_MEDIA_TYPE_UNKNOWN; int ret; /* Chip don't support this mode. */ @@ -878,22 +876,23 @@ static int hns3_set_link_ksettings(struct net_device *netdev, cmd->base.autoneg, cmd->base.speed, cmd->base.duplex, cmd->lanes); - /* Only support ksettings_set for netdev with phy attached for now */ - if (netdev->phydev) { - if (cmd->base.speed == SPEED_1000 && - cmd->base.autoneg == AUTONEG_DISABLE) - return -EINVAL; + if (!ops->get_media_type) + return -EOPNOTSUPP; + ops->get_media_type(handle, &media_type, &module_type); - return phy_ethtool_ksettings_set(netdev->phydev, cmd); - } else if (test_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, ae_dev->caps) && - ops->set_phy_link_ksettings) { - return ops->set_phy_link_ksettings(handle, cmd); + if (media_type == HNAE3_MEDIA_TYPE_COPPER) { + if (!ops->set_phy_link_ksettings) + return -EOPNOTSUPP; + ret = ops->set_phy_link_ksettings(handle, cmd); + if (ret != -ENODEV) + return ret; + /* PHY_INEXISTENT, use MAC-level configuration */ } if (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2) return -EOPNOTSUPP; - ret = hns3_check_ksettings_param(netdev, cmd); + ret = hns3_check_ksettings_param(netdev, cmd, media_type); if (ret) return ret; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index dd4045c773d4..2a6e4d17452c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -1577,6 +1577,11 @@ static int hclge_configure(struct hclge_dev *hdev) hdev->hw.mac.req_autoneg = AUTONEG_ENABLE; hdev->hw.mac.req_duplex = DUPLEX_FULL; + /* When lane_num is 0, the firmware will automatically + * select the appropriate lane_num based on the speed. + */ + hdev->hw.mac.req_lane_num = 0; + hclge_parse_link_mode(hdev, cfg.speed_ability); hdev->hw.mac.max_speed = hclge_get_max_speed(cfg.speed_ability); @@ -2652,8 +2657,11 @@ static int hclge_cfg_mac_speed_dup_h(struct hnae3_handle *handle, int speed, if (ret) return ret; - hdev->hw.mac.req_speed = (u32)speed; - hdev->hw.mac.req_duplex = duplex; + hdev->hw.mac.req_lane_num = lane_num; + if (speed != SPEED_UNKNOWN) + hdev->hw.mac.req_speed = (u32)speed; + if (duplex != DUPLEX_UNKNOWN) + hdev->hw.mac.req_duplex = duplex; return 0; } @@ -2684,6 +2692,7 @@ static int hclge_set_autoneg(struct hnae3_handle *handle, bool enable) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; + int ret; if (!hdev->hw.mac.support_autoneg) { if (enable) { @@ -2695,7 +2704,10 @@ static int hclge_set_autoneg(struct hnae3_handle *handle, bool enable) } } - return hclge_set_autoneg_en(hdev, enable); + ret = hclge_set_autoneg_en(hdev, enable); + if (!ret) + hdev->hw.mac.req_autoneg = enable; + return ret; } static int hclge_get_autoneg(struct hnae3_handle *handle) @@ -2957,20 +2969,6 @@ static int hclge_mac_init(struct hclge_dev *hdev) if (!test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) hdev->hw.mac.duplex = HCLGE_MAC_FULL; - if (hdev->hw.mac.support_autoneg) { - ret = hclge_set_autoneg_en(hdev, hdev->hw.mac.autoneg); - if (ret) - return ret; - } - - if (!hdev->hw.mac.autoneg) { - ret = hclge_cfg_mac_speed_dup_hw(hdev, hdev->hw.mac.req_speed, - hdev->hw.mac.req_duplex, - hdev->hw.mac.lane_num); - if (ret) - return ret; - } - mac->link = 0; if (mac->user_fec_mode & BIT(HNAE3_FEC_USER_DEF)) { @@ -3358,8 +3356,8 @@ static int hclge_get_phy_link_ksettings(struct hnae3_handle *handle, } static int -hclge_set_phy_link_ksettings(struct hnae3_handle *handle, - const struct ethtool_link_ksettings *cmd) +hclge_ethtool_ksettings_set(struct hnae3_handle *handle, + const struct ethtool_link_ksettings *cmd) { struct hclge_desc desc[HCLGE_PHY_LINK_SETTING_BD_NUM]; struct hclge_vport *vport = hclge_get_vport(handle); @@ -3400,10 +3398,34 @@ hclge_set_phy_link_ksettings(struct hnae3_handle *handle, return ret; } - hdev->hw.mac.req_autoneg = cmd->base.autoneg; - hdev->hw.mac.req_speed = cmd->base.speed; - hdev->hw.mac.req_duplex = cmd->base.duplex; linkmode_copy(hdev->hw.mac.advertising, cmd->link_modes.advertising); + return 0; +} + +static int +hclge_set_phy_link_ksettings(struct hnae3_handle *handle, + const struct ethtool_link_ksettings *cmd) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + int ret = -ENODEV; + + if (hnae3_dev_phy_imp_supported(hdev)) { + ret = hclge_ethtool_ksettings_set(handle, cmd); + } else if (handle->netdev->phydev) { + if (cmd->base.speed == SPEED_1000 && + cmd->base.autoneg == AUTONEG_DISABLE) + return -EINVAL; + ret = phy_ethtool_ksettings_set(handle->netdev->phydev, cmd); + } + if (ret) + return ret; + + hdev->hw.mac.req_autoneg = cmd->base.autoneg; + if (cmd->base.speed != SPEED_UNKNOWN) + hdev->hw.mac.req_speed = cmd->base.speed; + if (cmd->base.duplex != DUPLEX_UNKNOWN) + hdev->hw.mac.req_duplex = cmd->base.duplex; return 0; } @@ -11722,6 +11744,27 @@ static int hclge_set_wol(struct hnae3_handle *handle, return ret; } +static int hclge_set_autoneg_speed_dup(struct hclge_dev *hdev) +{ + int ret; + + if (hdev->hw.mac.support_autoneg) { + ret = hclge_set_autoneg_en(hdev, hdev->hw.mac.req_autoneg); + if (ret) + return ret; + } + + if (!hdev->hw.mac.req_autoneg) { + ret = hclge_cfg_mac_speed_dup_hw(hdev, hdev->hw.mac.req_speed, + hdev->hw.mac.req_duplex, + hdev->hw.mac.req_lane_num); + if (ret) + return ret; + } + + return 0; +} + static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) { struct pci_dev *pdev = ae_dev->pdev; @@ -11883,6 +11926,20 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) if (ret) goto err_ptp_uninit; + if (hdev->hw.mac.media_type != HNAE3_MEDIA_TYPE_COPPER) { + hdev->hw.mac.req_autoneg = hdev->hw.mac.autoneg; + if (hdev->hw.mac.autoneg == AUTONEG_DISABLE && + hdev->hw.mac.speed != SPEED_UNKNOWN) + hdev->hw.mac.req_speed = hdev->hw.mac.speed; + } + + ret = hclge_set_autoneg_speed_dup(hdev); + if (ret) { + dev_err(&pdev->dev, + "failed to set autoneg speed duplex, ret = %d\n", ret); + goto err_ptp_uninit; + } + INIT_KFIFO(hdev->mac_tnl_log); hclge_dcb_ops_set(hdev); @@ -12213,6 +12270,13 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev) return ret; } + ret = hclge_set_autoneg_speed_dup(hdev); + if (ret) { + dev_err(&pdev->dev, + "failed to set autoneg speed duplex, ret = %d\n", ret); + return ret; + } + ret = hclge_tp_port_init(hdev); if (ret) { dev_err(&pdev->dev, "failed to init tp port, ret = %d\n", diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 032b472d2368..4ca6458625a9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -287,6 +287,7 @@ struct hclge_mac { u8 support_autoneg; u8 speed_type; /* 0: sfp speed, 1: active speed */ u8 lane_num; + u8 req_lane_num; u32 speed; u32 req_speed; u32 max_speed; diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c index 4e503b3d0d2d..e1047915e101 100644 --- a/drivers/net/ethernet/ibm/emac/core.c +++ b/drivers/net/ethernet/ibm/emac/core.c @@ -3035,6 +3035,12 @@ static int emac_probe(struct platform_device *ofdev) if (err) goto err_gone; + dev->emacp = devm_platform_ioremap_resource(ofdev, 0); + if (IS_ERR(dev->emacp)) { + err = PTR_ERR(dev->emacp); + goto err_gone; + } + /* Setup error IRQ handler */ dev->emac_irq = platform_get_irq(ofdev, 0); err = devm_request_irq(&ofdev->dev, dev->emac_irq, emac_irq, 0, "EMAC", @@ -3047,13 +3053,6 @@ static int emac_probe(struct platform_device *ofdev) ndev->irq = dev->emac_irq; - dev->emacp = devm_platform_ioremap_resource(ofdev, 0); - if (IS_ERR(dev->emacp)) { - dev_err(&ofdev->dev, "can't map device registers"); - err = PTR_ERR(dev->emacp); - goto err_gone; - } - /* Wait for dependent devices */ err = emac_wait_deps(dev); if (err) diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index dea208db1be5..aa90e0ce8aca 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -1594,6 +1594,9 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) phy_reg &= ~I217_PLL_CLOCK_GATE_MASK; if (speed == SPEED_100 || speed == SPEED_10) phy_reg |= 0x3E8; + else if (hw->mac.type == e1000_pch_mtp || + hw->mac.type == e1000_pch_ptp) + phy_reg |= 0x1D5; else phy_reg |= 0xFA; e1e_wphy_locked(hw, I217_PLL_CLOCK_GATE_REG, phy_reg); diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 7ce0cc8ab8f4..7612ddd066fe 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -25,6 +25,7 @@ #include <linux/pm_runtime.h> #include <linux/prefetch.h> #include <linux/suspend.h> +#include <linux/dmi.h> #include "e1000.h" #define CREATE_TRACE_POINTS @@ -58,6 +59,17 @@ static const struct e1000_info *e1000_info_tbl[] = { [board_pch_ptp] = &e1000_pch_ptp_info, }; +static const struct dmi_system_id disable_k1_list[] = { + { + .ident = "Dell Pro 16 Plus PB16250", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Dell Pro 16 Plus PB16250"), + }, + }, + {} +}; + struct e1000_reg_info { u32 ofs; char *name; @@ -7670,7 +7682,8 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* init PTP hardware clock */ e1000e_ptp_init(adapter); - if (hw->mac.type >= e1000_pch_mtp) + /* disable K1 by default on known problematic systems */ + if (hw->mac.type >= e1000_pch_mtp && dmi_check_system(disable_k1_list)) adapter->flags2 |= FLAG2_DISABLE_K1; /* reset the hardware with the new settings */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_debug.h b/drivers/net/ethernet/intel/i40e/i40e_debug.h index e9871dfb32bd..01fd70db9086 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debug.h +++ b/drivers/net/ethernet/intel/i40e/i40e_debug.h @@ -42,7 +42,7 @@ struct device *i40e_hw_to_dev(struct i40e_hw *hw); #define i40e_debug(h, m, s, ...) \ do { \ if (((m) & (h)->debug_mask)) \ - dev_info(i40e_hw_to_dev(hw), s, ##__VA_ARGS__); \ + dev_info(i40e_hw_to_dev(h), s, ##__VA_ARGS__); \ } while (0) #endif /* _I40E_DEBUG_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index b617a6bff891..98960d3cbdd1 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -3882,7 +3882,6 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update) if (!pi || !aq_failures) return -EINVAL; - *aq_failures = 0; hw = pi->hw; pcaps = kzalloc_obj(*pcaps); diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 0704e92ab043..5f6f29142e30 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -4249,9 +4249,13 @@ ice_dpll_init_pins_info(struct ice_pf *pf, enum ice_dpll_pin_type pin_type) static void ice_dpll_deinit_info(struct ice_pf *pf) { kfree(pf->dplls.inputs); + pf->dplls.inputs = NULL; kfree(pf->dplls.outputs); + pf->dplls.outputs = NULL; kfree(pf->dplls.eec.input_prio); + pf->dplls.eec.input_prio = NULL; kfree(pf->dplls.pps.input_prio); + pf->dplls.pps.input_prio = NULL; } /** @@ -4343,12 +4347,16 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) alloc_size = sizeof(*de->input_prio) * d->num_inputs; de->input_prio = kzalloc(alloc_size, GFP_KERNEL); - if (!de->input_prio) - return -ENOMEM; + if (!de->input_prio) { + ret = -ENOMEM; + goto deinit_info; + } dp->input_prio = kzalloc(alloc_size, GFP_KERNEL); - if (!dp->input_prio) - return -ENOMEM; + if (!dp->input_prio) { + ret = -ENOMEM; + goto deinit_info; + } ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_INPUT); if (ret) @@ -4373,12 +4381,12 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) ret = ice_get_cgu_rclk_pin_info(&pf->hw, &d->base_rclk_idx, &pf->dplls.rclk.num_parents); if (ret) - return ret; + goto deinit_info; for (i = 0; i < pf->dplls.rclk.num_parents; i++) pf->dplls.rclk.parent_idx[i] = d->base_rclk_idx + i; ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_RCLK_INPUT); if (ret) - return ret; + goto deinit_info; de->mode = DPLL_MODE_AUTOMATIC; dp->mode = DPLL_MODE_AUTOMATIC; diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c index 2e4f0969035f..c30e27bbfe6e 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.c +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c @@ -117,8 +117,6 @@ static int ice_eswitch_setup_repr(struct ice_pf *pf, struct ice_repr *repr) if (!repr->dst) return -ENOMEM; - netif_keep_dst(uplink_vsi->netdev); - dst = repr->dst; dst->u.port_info.port_id = vsi->vsi_num; dst->u.port_info.lower_dev = uplink_vsi->netdev; @@ -312,6 +310,8 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf) if (ice_eswitch_br_offloads_init(pf)) goto err_br_offloads; + netif_keep_dst(uplink_vsi->netdev); + pf->eswitch.is_running = true; return 0; diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index f28416a707d7..cf6f3bd29f84 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -3508,7 +3508,7 @@ ice_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) struct ice_vsi *vsi = np->vsi; struct ice_hw *hw = &pf->hw; struct ice_port_info *pi; - u8 aq_failures; + u8 aq_failures = 0; bool link_up; u32 is_an; int err; @@ -3579,18 +3579,22 @@ ice_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) /* Set the FC mode and only restart AN if link is up */ err = ice_set_fc(pi, &aq_failures, link_up); - if (aq_failures & ICE_SET_FC_AQ_FAIL_GET) { + switch (aq_failures) { + case ICE_SET_FC_AQ_FAIL_GET: netdev_info(netdev, "Set fc failed on the get_phy_capabilities call with err %d aq_err %s\n", err, libie_aq_str(hw->adminq.sq_last_status)); err = -EAGAIN; - } else if (aq_failures & ICE_SET_FC_AQ_FAIL_SET) { + break; + case ICE_SET_FC_AQ_FAIL_SET: netdev_info(netdev, "Set fc failed on the set_phy_config call with err %d aq_err %s\n", err, libie_aq_str(hw->adminq.sq_last_status)); err = -EAGAIN; - } else if (aq_failures & ICE_SET_FC_AQ_FAIL_UPDATE) { + break; + case ICE_SET_FC_AQ_FAIL_UPDATE: netdev_info(netdev, "Set fc failed on the get_link_info call with err %d aq_err %s\n", err, libie_aq_str(hw->adminq.sq_last_status)); err = -EAGAIN; + break; } return err; diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index e2fbe111f849..e2fd2dab03e3 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -4789,16 +4789,14 @@ static void ice_init_wakeup(struct ice_pf *pf) device_set_wakeup_enable(ice_pf_to_dev(pf), false); } -static int ice_init_link(struct ice_pf *pf) +static void ice_init_link(struct ice_pf *pf) { struct device *dev = ice_pf_to_dev(pf); int err; err = ice_init_link_events(pf->hw.port_info); - if (err) { + if (err) dev_err(dev, "ice_init_link_events failed: %d\n", err); - return err; - } /* not a fatal error if this fails */ err = ice_init_nvm_phy_type(pf->hw.port_info); @@ -4838,8 +4836,6 @@ static int ice_init_link(struct ice_pf *pf) } else { set_bit(ICE_FLAG_NO_MEDIA, pf->flags); } - - return err; } static int ice_init_pf_sw(struct ice_pf *pf) @@ -4982,13 +4978,11 @@ static int ice_init(struct ice_pf *pf) ice_init_wakeup(pf); - err = ice_init_link(pf); - if (err) - goto err_init_link; + ice_init_link(pf); err = ice_send_version(pf); if (err) - goto err_init_link; + goto err_deinit_pf_sw; ice_verify_cacheline_size(pf); @@ -5007,7 +5001,7 @@ static int ice_init(struct ice_pf *pf) return 0; -err_init_link: +err_deinit_pf_sw: ice_deinit_pf_sw(pf); err_init_pf_sw: ice_dealloc_vsis(pf); diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c index b1f46707dcc0..27e4acb1620f 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c @@ -801,7 +801,7 @@ void ice_reset_all_vfs(struct ice_pf *pf) * setup only when VF creates its first FDIR rule. */ if (vf->ctrl_vsi_idx != ICE_NO_VSI) - ice_vf_ctrl_invalidate_vsi(vf); + ice_vf_ctrl_vsi_release(vf); ice_vf_pre_vsi_rebuild(vf); if (ice_vf_rebuild_vsi(vf)) { diff --git a/drivers/net/ethernet/intel/idpf/virtchnl2.h b/drivers/net/ethernet/intel/idpf/virtchnl2.h index 02ae447cc24a..39fea65c075c 100644 --- a/drivers/net/ethernet/intel/idpf/virtchnl2.h +++ b/drivers/net/ethernet/intel/idpf/virtchnl2.h @@ -1572,13 +1572,15 @@ VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_ptp_get_vport_tx_tstamp_latches); * struct virtchnl2_ptp_get_dev_clk_time - Associated with message * VIRTCHNL2_OP_PTP_GET_DEV_CLK_TIME. * @dev_time_ns: Device clock time value in nanoseconds + * @pad: Padding for future extensions * * PF/VF sends this message to receive the time from the main timer. */ struct virtchnl2_ptp_get_dev_clk_time { __le64 dev_time_ns; + u8 pad[8]; }; -VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_ptp_get_dev_clk_time); +VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_ptp_get_dev_clk_time); /** * struct virtchnl2_ptp_get_cross_time: Associated with message @@ -1586,26 +1588,30 @@ VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_ptp_get_dev_clk_time); * @sys_time_ns: System counter value expressed in nanoseconds, read * synchronously with device time * @dev_time_ns: Device clock time value expressed in nanoseconds + * @pad: Padding for future extensions * * PF/VF sends this message to receive the cross time. */ struct virtchnl2_ptp_get_cross_time { __le64 sys_time_ns; __le64 dev_time_ns; + u8 pad[8]; }; -VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_ptp_get_cross_time); +VIRTCHNL2_CHECK_STRUCT_LEN(24, virtchnl2_ptp_get_cross_time); /** * struct virtchnl2_ptp_set_dev_clk_time: Associated with message * VIRTCHNL2_OP_PTP_SET_DEV_CLK_TIME. * @dev_time_ns: Device time value expressed in nanoseconds to set + * @pad: Padding for future extensions * * PF/VF sends this message to set the time of the main timer. */ struct virtchnl2_ptp_set_dev_clk_time { __le64 dev_time_ns; + u8 pad[8]; }; -VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_ptp_set_dev_clk_time); +VIRTCHNL2_CHECK_STRUCT_LEN(16, virtchnl2_ptp_set_dev_clk_time); /** * struct virtchnl2_ptp_adj_dev_clk_fine: Associated with message diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 8ac16808023c..c470d2354ce8 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -2649,7 +2649,7 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget) } if (igc_fpe_is_pmac_enabled(adapter) && - igc_fpe_handle_mpacket(adapter, rx_desc, size, pktbuf)) { + igc_fpe_handle_mpacket(adapter, rx_desc, size, pktbuf + pkt_offset)) { /* Advance the ring next-to-clean */ igc_is_non_eop(rx_ring, rx_desc); cleaned_count++; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 2646ee6f295f..9ec250c26284 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -3958,7 +3958,8 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter, } /* initialize XPS */ - if (!test_and_set_bit(__IXGBE_TX_XPS_INIT_DONE, ring->state)) { + if (!ring_is_xdp(ring) && + !test_and_set_bit(__IXGBE_TX_XPS_INIT_DONE, ring->state)) { struct ixgbe_q_vector *q_vector = ring->q_vector; if (q_vector) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 61f2ef67defd..eb5bf3b6bbb5 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -2798,6 +2798,7 @@ struct ixgbe_hic_hdr2_rsp { }; union ixgbe_hic_hdr2 { + u32 buf[1]; struct ixgbe_hic_hdr2_req req; struct ixgbe_hic_hdr2_rsp rsp; }; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index 76d2fa3ef518..4a0ccbf448a2 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -1228,7 +1228,7 @@ static int ixgbe_update_flash_X550(struct ixgbe_hw *hw) buffer.req.buf_lenl = FW_SHADOW_RAM_DUMP_LEN; buffer.req.checksum = FW_DEFAULT_CHECKSUM; - status = ixgbe_host_interface_command(hw, &buffer, sizeof(buffer), + status = ixgbe_host_interface_command(hw, buffer.buf, sizeof(buffer), IXGBE_HI_COMMAND_TIMEOUT, false); return status; } diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 0c061fb0ed07..744d6585a949 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -5900,6 +5900,9 @@ static int mvneta_resume(struct device *device) rtnl_unlock(); mvneta_set_rx_mode(dev); + if (!pp->neta_armada3700) + on_each_cpu(mvneta_percpu_enable, pp, true); + return 0; } #endif diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c index fe8c4ffcd8f7..5dfdfbabfadd 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c @@ -3542,15 +3542,18 @@ static int npc_defrag_alloc_free_slots(struct rvu *rvu, alloc_cnt2 = 0; rc = __npc_subbank_alloc(rvu, sb, - NPC_MCAM_KEY_X2, sb->b0b, + f->key_type, sb->b0b, sb->b0t, NPC_MCAM_LOWER_PRIO, false, cnt, save, cnt, true, &alloc_cnt1); - if (alloc_cnt1 < cnt) { + /* X4 entries only occupy bank 0 (b0b..b0t); see npc_subbank_idx_2_mcam_idx(). + * X2 uses both halves of the subbank, so spill into bank 1 if needed. + */ + if (alloc_cnt1 < cnt && f->key_type == NPC_MCAM_KEY_X2) { rc = __npc_subbank_alloc(rvu, sb, - NPC_MCAM_KEY_X2, sb->b1b, + f->key_type, sb->b1b, sb->b1t, NPC_MCAM_LOWER_PRIO, false, cnt - alloc_cnt1, diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index dc42c81c0942..44fdd6ba7307 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -283,31 +283,30 @@ M(NPC_GET_FIELD_HASH_INFO, 0x6013, npc_get_field_hash_info, M(NPC_GET_FIELD_STATUS, 0x6014, npc_get_field_status, \ npc_get_field_status_req, \ npc_get_field_status_rsp) \ -M(NPC_CN20K_MCAM_GET_FREE_COUNT, 0x6015, npc_cn20k_get_fcnt, \ - msg_req, npc_cn20k_get_fcnt_rsp) \ -M(NPC_CN20K_GET_KEX_CFG, 0x6016, npc_cn20k_get_kex_cfg, \ +M(NPC_MCAM_DEFRAG, 0x6016, npc_defrag, \ + msg_req, \ + msg_rsp) \ +M(NPC_CN20K_GET_KEX_CFG, 0x6017, npc_cn20k_get_kex_cfg, \ msg_req, npc_cn20k_get_kex_cfg_rsp) \ -M(NPC_CN20K_MCAM_WRITE_ENTRY, 0x6017, npc_cn20k_mcam_write_entry, \ - npc_cn20k_mcam_write_entry_req, msg_rsp) \ -M(NPC_CN20K_MCAM_ALLOC_AND_WRITE_ENTRY, 0x6018, \ -npc_cn20k_mcam_alloc_and_write_entry, \ +M(NPC_CN20K_MCAM_GET_FREE_COUNT, 0x6018, npc_cn20k_get_fcnt, \ + msg_req, npc_cn20k_get_fcnt_rsp) \ +M(NPC_CN20K_MCAM_WRITE_ENTRY, 0x6019, npc_cn20k_mcam_write_entry, \ + npc_cn20k_mcam_write_entry_req, msg_rsp) \ +M(NPC_CN20K_MCAM_ALLOC_AND_WRITE_ENTRY, 0x601a, npc_cn20k_mcam_alloc_and_write_entry, \ npc_cn20k_mcam_alloc_and_write_entry_req, \ npc_mcam_alloc_and_write_entry_rsp) \ -M(NPC_CN20K_MCAM_READ_ENTRY, 0x6019, npc_cn20k_mcam_read_entry, \ +M(NPC_CN20K_MCAM_READ_ENTRY, 0x601b, npc_cn20k_mcam_read_entry, \ npc_mcam_read_entry_req, \ npc_cn20k_mcam_read_entry_rsp) \ -M(NPC_CN20K_MCAM_READ_BASE_RULE, 0x601a, npc_cn20k_read_base_steer_rule, \ - msg_req, npc_cn20k_mcam_read_base_rule_rsp) \ -M(NPC_MCAM_DEFRAG, 0x601b, npc_defrag, \ - msg_req, \ - msg_rsp) \ -M(NPC_MCAM_GET_NUM_KWS, 0x601c, npc_get_num_kws, \ +M(NPC_CN20K_MCAM_READ_BASE_RULE, 0x601c, npc_cn20k_read_base_steer_rule, \ + msg_req, npc_cn20k_mcam_read_base_rule_rsp) \ +M(NPC_MCAM_GET_NUM_KWS, 0x601d, npc_get_num_kws, \ npc_get_num_kws_req, \ npc_get_num_kws_rsp) \ -M(NPC_MCAM_GET_DFT_RL_IDXS, 0x601d, npc_get_dft_rl_idxs, \ +M(NPC_MCAM_GET_DFT_RL_IDXS, 0x601e, npc_get_dft_rl_idxs, \ msg_req, \ npc_get_dft_rl_idxs_rsp)\ -M(NPC_MCAM_GET_NPC_PFL_INFO, 0x601e, npc_get_pfl_info, \ +M(NPC_MCAM_GET_NPC_PFL_INFO, 0x601f, npc_get_pfl_info, \ msg_req, \ npc_get_pfl_info_rsp) \ /* NIX mbox IDs (range 0x8000 - 0xFFFF) */ \ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mcs.c b/drivers/net/ethernet/marvell/octeontx2/af/mcs.c index c1775bd01c2b..a07e0b3d8d00 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mcs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/mcs.c @@ -120,13 +120,13 @@ void mcs_get_rx_secy_stats(struct mcs *mcs, struct mcs_secy_stats *stats, int id reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYUNTAGGEDX(id); stats->pkt_untaged_cnt = mcs_reg_read(mcs, reg); - reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYCTLX(id); - stats->pkt_ctl_cnt = mcs_reg_read(mcs, reg); - if (mcs->hw->mcs_blks > 1) { reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYNOTAGX(id); stats->pkt_notag_cnt = mcs_reg_read(mcs, reg); + return; } + reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYCTLX(id); + stats->pkt_ctl_cnt = mcs_reg_read(mcs, reg); } void mcs_get_flowid_stats(struct mcs *mcs, struct mcs_flowid_stats *stats, diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c index d2163da28d18..fa4ea1258d29 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c @@ -178,6 +178,15 @@ int rvu_mbox_handler_lmtst_tbl_setup(struct rvu *rvu, * pcifunc (will be the one who is calling this mailbox). */ if (req->base_pcifunc) { + /* A VF is untrusted and must not redirect its LMTLINE to + * another PF's region, so confine VF callers to their own PF. + */ + if (is_vf(req->hdr.pcifunc) && + (!is_pf_func_valid(rvu, req->base_pcifunc) || + rvu_get_pf(rvu->pdev, req->hdr.pcifunc) != + rvu_get_pf(rvu->pdev, req->base_pcifunc))) + return -EPERM; + /* Calculating the LMT table index equivalent to primary * pcifunc. */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c index fa461489acdd..3456313d3b3c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c @@ -482,10 +482,11 @@ static int rvu_dbg_mcs_rx_secy_stats_display(struct seq_file *filp, void *unused seq_printf(filp, "secy%d: Tagged ctrl pkts: %lld\n", secy_id, stats.pkt_tagged_ctl_cnt); seq_printf(filp, "secy%d: Untaged pkts: %lld\n", secy_id, stats.pkt_untaged_cnt); - seq_printf(filp, "secy%d: Ctrl pkts: %lld\n", secy_id, stats.pkt_ctl_cnt); if (mcs->hw->mcs_blks > 1) seq_printf(filp, "secy%d: pkts notag: %lld\n", secy_id, stats.pkt_notag_cnt); + else + seq_printf(filp, "secy%d: Ctrl pkts: %lld\n", secy_id, stats.pkt_ctl_cnt); } mutex_unlock(&mcs->stats_lock); return 0; @@ -2809,6 +2810,14 @@ static void rvu_dbg_npa_init(struct rvu *rvu) &rvu_dbg_npa_ndc_hits_miss_fops); } +/* Per-lmac CGX debugfs files need both RVU and CGX handle; inode->i_private + * points here so seq_file ops avoid pci_get_device(PCI_DEVID_OCTEONTX2_RVU_AF). + */ +struct rvu_cgx_lmac_dbgfs_ctx { + struct rvu *rvu; + void *cgxd; +}; + #define PRINT_CGX_CUML_NIXRX_STATUS(idx, name) \ ({ \ u64 cnt; \ @@ -2831,18 +2840,14 @@ static void rvu_dbg_npa_init(struct rvu *rvu) static int cgx_print_stats(struct seq_file *s, int lmac_id) { + struct rvu_cgx_lmac_dbgfs_ctx *dctx = s->private; struct cgx_link_user_info linfo; + struct rvu *rvu = dctx->rvu; struct mac_ops *mac_ops; - void *cgxd = s->private; + void *cgxd = dctx->cgxd; u64 ucast, mcast, bcast; int stat = 0, err = 0; u64 tx_stat, rx_stat; - struct rvu *rvu; - - rvu = pci_get_drvdata(pci_get_device(PCI_VENDOR_ID_CAVIUM, - PCI_DEVID_OCTEONTX2_RVU_AF, NULL)); - if (!rvu) - return -ENODEV; mac_ops = get_mac_ops(cgxd); /* There can be no CGX devices at all */ @@ -2949,20 +2954,16 @@ RVU_DEBUG_SEQ_FOPS(cgx_stat, cgx_stat_display, NULL); static int cgx_print_dmac_flt(struct seq_file *s, int lmac_id) { + struct rvu_cgx_lmac_dbgfs_ctx *dctx = s->private; + struct rvu *rvu = dctx->rvu; struct pci_dev *pdev = NULL; - void *cgxd = s->private; + void *cgxd = dctx->cgxd; char *bcast, *mcast; u16 index, domain; u8 dmac[ETH_ALEN]; - struct rvu *rvu; u64 cfg, mac; int pf; - rvu = pci_get_drvdata(pci_get_device(PCI_VENDOR_ID_CAVIUM, - PCI_DEVID_OCTEONTX2_RVU_AF, NULL)); - if (!rvu) - return -ENODEV; - pf = cgxlmac_to_pf(rvu, cgx_get_cgxid(cgxd), lmac_id); domain = 2; @@ -3009,17 +3010,13 @@ RVU_DEBUG_SEQ_FOPS(cgx_dmac_flt, cgx_dmac_flt_display, NULL); static int cgx_print_fwdata(struct seq_file *s, int lmac_id) { + struct rvu_cgx_lmac_dbgfs_ctx *dctx = s->private; struct cgx_lmac_fwdata_s *fwdata; - void *cgxd = s->private; + struct rvu *rvu = dctx->rvu; + void *cgxd = dctx->cgxd; struct phy_s *phy; - struct rvu *rvu; int cgx_id, i; - rvu = pci_get_drvdata(pci_get_device(PCI_VENDOR_ID_CAVIUM, - PCI_DEVID_OCTEONTX2_RVU_AF, NULL)); - if (!rvu) - return -ENODEV; - if (!rvu->fwdata) return -EAGAIN; @@ -3100,6 +3097,7 @@ RVU_DEBUG_SEQ_FOPS(cgx_fwdata, cgx_fwdata_display, NULL); static void rvu_dbg_cgx_init(struct rvu *rvu) { + struct rvu_cgx_lmac_dbgfs_ctx *ctx; struct mac_ops *mac_ops; unsigned long lmac_bmap; int i, lmac_id; @@ -3126,6 +3124,13 @@ static void rvu_dbg_cgx_init(struct rvu *rvu) rvu->rvu_dbg.cgx = debugfs_create_dir(dname, rvu->rvu_dbg.cgx_root); + ctx = devm_kzalloc(rvu->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + continue; + + ctx->rvu = rvu; + ctx->cgxd = cgx; + for_each_set_bit(lmac_id, &lmac_bmap, rvu->hw->lmac_per_cgx) { /* lmac debugfs dir */ sprintf(dname, "lmac%d", lmac_id); @@ -3133,13 +3138,13 @@ static void rvu_dbg_cgx_init(struct rvu *rvu) debugfs_create_dir(dname, rvu->rvu_dbg.cgx); debugfs_create_file_aux_num("stats", 0600, rvu->rvu_dbg.lmac, - cgx, lmac_id, &rvu_dbg_cgx_stat_fops); + ctx, lmac_id, &rvu_dbg_cgx_stat_fops); debugfs_create_file_aux_num("mac_filter", 0600, - rvu->rvu_dbg.lmac, cgx, lmac_id, + rvu->rvu_dbg.lmac, ctx, lmac_id, &rvu_dbg_cgx_dmac_flt_fops); - debugfs_create_file("fwdata", 0600, - rvu->rvu_dbg.lmac, cgx, - &rvu_dbg_cgx_fwdata_fops); + debugfs_create_file_aux_num("fwdata", 0600, + rvu->rvu_dbg.lmac, ctx, + lmac_id, &rvu_dbg_cgx_fwdata_fops); } } } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c index 6494a9ee2f0d..3b47ecb44d51 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c @@ -1510,7 +1510,9 @@ static int rvu_af_dl_nix_maxlf_validate(struct devlink *devlink, u32 id, struct rvu_devlink *rvu_dl = devlink_priv(devlink); struct rvu *rvu = rvu_dl->rvu; u16 max_nix0_lf, max_nix1_lf; - struct npc_mcam *mcam; + struct rvu_block *block; + int blkaddr = 0; + int free_lfs; u64 cfg; cfg = rvu_read64(rvu, BLKADDR_NIX0, NIX_AF_CONST2); @@ -1518,14 +1520,23 @@ static int rvu_af_dl_nix_maxlf_validate(struct devlink *devlink, u32 id, cfg = rvu_read64(rvu, BLKADDR_NIX1, NIX_AF_CONST2); max_nix1_lf = cfg & 0xFFF; - /* Do not allow user to modify maximum NIX LFs while mcam entries - * have already been assigned. + /* Do not allow user to modify maximum NIX LFs while NIX LFs + * have already been assigned. Note that modifying NIX LFs count + * can be done only before any LF attach requests from PFs and VFs + * and not later or concurrently. */ - mcam = &rvu->hw->mcam; - if (mcam->bmap_fcnt < mcam->bmap_entries) { - NL_SET_ERR_MSG_MOD(extack, - "mcam entries have already been assigned, can't resize"); - return -EPERM; + blkaddr = rvu_get_next_nix_blkaddr(rvu, blkaddr); + while (blkaddr) { + block = &rvu->hw->block[blkaddr]; + + free_lfs = rvu_rsrc_free_count(&block->lf); + if (free_lfs != block->lf.max) { + NL_SET_ERR_MSG_MOD(extack, + "NIX LFs already assigned, can't resize"); + return -EPERM; + } + + blkaddr = rvu_get_next_nix_blkaddr(rvu, blkaddr); } if (max_nix0_lf && val.vu16 > max_nix0_lf) { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index f977734ae712..219fc44ab68d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -527,19 +527,24 @@ static int nix_setup_bpids(struct rvu *rvu, struct nix_hw *hw, int blkaddr) bp->fn_map = devm_kcalloc(rvu->dev, bp->bpids.max, sizeof(u16), GFP_KERNEL); if (!bp->fn_map) - return -ENOMEM; + goto free_bpids; bp->intf_map = devm_kcalloc(rvu->dev, bp->bpids.max, sizeof(u8), GFP_KERNEL); if (!bp->intf_map) - return -ENOMEM; + goto free_bpids; bp->ref_cnt = devm_kcalloc(rvu->dev, bp->bpids.max, sizeof(u8), GFP_KERNEL); if (!bp->ref_cnt) - return -ENOMEM; + goto free_bpids; return 0; + +free_bpids: + rvu_free_bitmap(&bp->bpids); + bp->bpids.bmap = NULL; + return -ENOMEM; } void rvu_nix_flr_free_bpids(struct rvu *rvu, u16 pcifunc) @@ -4548,7 +4553,7 @@ int rvu_mbox_handler_nix_set_rx_mode(struct rvu *rvu, struct nix_rx_mode *req, rvu_npc_install_allmulti_entry(rvu, pcifunc, nixlf, pfvf->rx_chan_base); } else { - if (!nix_rx_multicast) + if (!nix_rx_multicast && !is_vf(pcifunc)) rvu_npc_enable_allmulti_entry(rvu, pcifunc, nixlf, false); } @@ -4558,7 +4563,7 @@ int rvu_mbox_handler_nix_set_rx_mode(struct rvu *rvu, struct nix_rx_mode *req, pfvf->rx_chan_base, pfvf->rx_chan_cnt); else - if (!nix_rx_multicast) + if (!nix_rx_multicast && !is_vf(pcifunc)) rvu_npc_enable_promisc_entry(rvu, pcifunc, nixlf, false); return 0; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c index d301a3f0f87a..4994385a822b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -2181,7 +2181,7 @@ int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr) /* Alloc memory for MCAM entry to counter mapping and for tracking * counter's reference count. */ - mcam->entry2cntr_map = kcalloc(mcam->bmap_entries, sizeof(u16), + mcam->entry2cntr_map = kcalloc(mcam->total_entries, sizeof(u16), GFP_KERNEL); if (!mcam->entry2cntr_map) goto free_cntr_map; @@ -2197,10 +2197,11 @@ int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr) if (!mcam->entry2target_pffunc) goto free_cntr_refcnt; - for (index = 0; index < mcam->bmap_entries; index++) { + for (index = 0; index < mcam->bmap_entries; index++) mcam->entry2pfvf_map[index] = NPC_MCAM_INVALID_MAP; + + for (index = 0; index < mcam->total_entries; index++) mcam->entry2cntr_map[index] = NPC_MCAM_INVALID_MAP; - } for (cntr = 0; cntr < mcam->counters.max; cntr++) mcam->cntr2pfvf_map[cntr] = NPC_MCAM_INVALID_MAP; @@ -3531,7 +3532,7 @@ static int __npc_mcam_free_counter(struct rvu *rvu, struct msg_rsp *rsp) { struct npc_mcam *mcam = &rvu->hw->mcam; - u16 index, entry = 0; + u16 index; int blkaddr, err; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); @@ -3547,20 +3548,16 @@ static int __npc_mcam_free_counter(struct rvu *rvu, mcam->cntr2pfvf_map[req->cntr] = NPC_MCAM_INVALID_MAP; rvu_free_rsrc(&mcam->counters, req->cntr); - /* Disable all MCAM entry's stats which are using this counter */ - while (entry < mcam->bmap_entries) { + /* Disable all MCAM entry's stats which are using this counter. + * Scan the full MCAM index range: AF-reserved rules (e.g. CPT pass-2) + */ + for (index = 0; index < mcam->total_entries; index++) { if (!mcam->cntr_refcnt[req->cntr]) break; - - index = find_next_bit(mcam->bmap, mcam->bmap_entries, entry); - if (index >= mcam->bmap_entries) - break; - entry = index + 1; if (mcam->entry2cntr_map[index] != req->cntr) continue; - - npc_unmap_mcam_entry_and_cntr(rvu, mcam, blkaddr, - index, req->cntr); + npc_unmap_mcam_entry_and_cntr(rvu, mcam, blkaddr, index, + req->cntr); } return 0; @@ -3631,7 +3628,7 @@ int rvu_mbox_handler_npc_mcam_unmap_counter(struct rvu *rvu, struct npc_mcam_unmap_counter_req *req, struct msg_rsp *rsp) { struct npc_mcam *mcam = &rvu->hw->mcam; - u16 index, entry = 0; + u16 index; int blkaddr, rc; /* Counter is not supported for CN20K */ @@ -3658,20 +3655,13 @@ int rvu_mbox_handler_npc_mcam_unmap_counter(struct rvu *rvu, } /* Disable all MCAM entry's stats which are using this counter */ - while (entry < mcam->bmap_entries) { + for (index = 0; index < mcam->total_entries; index++) { if (!mcam->cntr_refcnt[req->cntr]) break; - - index = find_next_bit(mcam->bmap, mcam->bmap_entries, entry); - if (index >= mcam->bmap_entries) - break; - entry = index + 1; - if (mcam->entry2cntr_map[index] != req->cntr) continue; - - npc_unmap_mcam_entry_and_cntr(rvu, mcam, blkaddr, - index, req->cntr); + npc_unmap_mcam_entry_and_cntr(rvu, mcam, blkaddr, index, + req->cntr); } exit: mutex_unlock(&mcam->lock); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c index 34f1e066707b..3d4d3ab5183b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c @@ -2215,7 +2215,7 @@ int npc_install_mcam_drop_rule(struct rvu *rvu, int mcam_idx, u16 *counter_idx, return err; } - dev_err(rvu->dev, + dev_dbg(rvu->dev, "%s: Installed single drop on non hit rule at %d, cntr=%d\n", __func__, mcam_idx, req.cntr); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c index 2cc1bdfd9b2e..9524d38f1582 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c @@ -182,6 +182,7 @@ static void cn10k_mcs_free_rsrc(struct otx2_nic *pfvf, enum mcs_direction dir, clear_req->id = hw_rsrc_id; clear_req->type = type; clear_req->dir = dir; + clear_req->all = all; req = otx2_mbox_alloc_msg_mcs_free_resources(mbox); if (!req) @@ -1776,11 +1777,16 @@ fail: void cn10k_mcs_free(struct otx2_nic *pfvf) { + struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; + if (!test_bit(CN10K_HW_MACSEC, &pfvf->hw.cap_flag)) return; - cn10k_mcs_free_rsrc(pfvf, MCS_TX, MCS_RSRC_TYPE_SECY, 0, true); - cn10k_mcs_free_rsrc(pfvf, MCS_RX, MCS_RSRC_TYPE_SECY, 0, true); + if (!list_empty(&cfg->txsc_list)) { + cn10k_mcs_free_rsrc(pfvf, MCS_TX, MCS_RSRC_TYPE_SECY, 0, true); + cn10k_mcs_free_rsrc(pfvf, MCS_RX, MCS_RSRC_TYPE_SECY, 0, true); + } + kfree(pfvf->macsec_cfg); pfvf->macsec_cfg = NULL; } diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c index f9fbf0c17648..617a0db97e80 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c @@ -1119,9 +1119,16 @@ int otx2_register_mbox_intr(struct otx2_nic *pf, bool probe_af) { struct otx2_hw *hw = &pf->hw; struct msg_req *req; + u64 mbox_int_mask; char *irq_name; int err; + mbox_int_mask = !is_cn20k(pf->pdev) ? BIT_ULL(0) : + BIT_ULL(0) | BIT_ULL(1); + + /* Clear stale mailbox interrupt state before installing the handler. */ + otx2_write64(pf, RVU_PF_INT, mbox_int_mask); + /* Register mailbox interrupt handler */ if (!is_cn20k(pf->pdev)) { irq_name = &hw->irq_name[RVU_PF_INT_VEC_AFPF_MBOX * NAME_SIZE]; @@ -1147,17 +1154,8 @@ int otx2_register_mbox_intr(struct otx2_nic *pf, bool probe_af) return err; } - /* Enable mailbox interrupt for msgs coming from AF. - * First clear to avoid spurious interrupts, if any. - */ - if (!is_cn20k(pf->pdev)) { - otx2_write64(pf, RVU_PF_INT, BIT_ULL(0)); - otx2_write64(pf, RVU_PF_INT_ENA_W1S, BIT_ULL(0)); - } else { - otx2_write64(pf, RVU_PF_INT, BIT_ULL(0) | BIT_ULL(1)); - otx2_write64(pf, RVU_PF_INT_ENA_W1S, BIT_ULL(0) | - BIT_ULL(1)); - } + /* Enable mailbox interrupt for msgs coming from AF. */ + otx2_write64(pf, RVU_PF_INT_ENA_W1S, mbox_int_mask); if (!probe_af) return 0; @@ -1571,14 +1569,15 @@ static void otx2_free_sq_res(struct otx2_nic *pf) otx2_sq_free_sqbs(pf); for (qidx = 0; qidx < otx2_get_total_tx_queues(pf); qidx++) { sq = &qset->sq[qidx]; - /* Skip freeing Qos queues if they are not initialized */ - if (!sq->sqe) - continue; - qmem_free(pf->dev, sq->sqe); - qmem_free(pf->dev, sq->sqe_ring); - qmem_free(pf->dev, sq->cpt_resp); - qmem_free(pf->dev, sq->tso_hdrs); - kfree(sq->sg); + /* sq->sqe is not initialized for unused QoS queues */ + if (sq->sqe) { + qmem_free(pf->dev, sq->sqe); + qmem_free(pf->dev, sq->sqe_ring); + qmem_free(pf->dev, sq->cpt_resp); + qmem_free(pf->dev, sq->tso_hdrs); + qmem_free(pf->dev, sq->timestamps); + kfree(sq->sg); + } kfree(sq->sqb_ptrs); } } @@ -1713,13 +1712,12 @@ int otx2_init_hw_resources(struct otx2_nic *pf) return err; err_free_nix_queues: - otx2_free_sq_res(pf); otx2_free_cq_res(pf); otx2_ctx_disable(mbox, NIX_AQ_CTYPE_RQ, false); err_free_txsch: otx2_txschq_stop(pf); err_free_sq_ptrs: - otx2_sq_free_sqbs(pf); + otx2_free_sq_res(pf); err_free_rq_ptrs: otx2_free_aura_ptr(pf, AURA_NIX_RQ); otx2_ctx_disable(mbox, NPA_AQ_CTYPE_POOL, true); @@ -2520,10 +2518,42 @@ EXPORT_SYMBOL(otx2_config_hwtstamp_set); static int otx2_do_set_vf_mac(struct otx2_nic *pf, int vf, const u8 *mac) { + struct npc_get_field_status_req *freq; + struct npc_get_field_status_rsp *frsp; struct npc_install_flow_req *req; int err; mutex_lock(&pf->mbox.lock); + + /* Skip installing the DMAC filter if the hardware parser profile + * does not support DMAC extraction. + */ + freq = otx2_mbox_alloc_msg_npc_get_field_status(&pf->mbox); + if (!freq) { + err = -ENOMEM; + goto out; + } + + freq->field = NPC_DMAC; + err = otx2_sync_mbox_msg(&pf->mbox); + if (err) + goto out; + + frsp = (struct npc_get_field_status_rsp *)otx2_mbox_get_rsp + (&pf->mbox.mbox, 0, &freq->hdr); + if (IS_ERR(frsp)) { + err = PTR_ERR(frsp); + goto out; + } + + if (!frsp->enable) { + netdev_warn(pf->netdev, + "VF %d MAC filter not installed: DMAC extraction not supported by parser profile\n", + vf); + err = -EOPNOTSUPP; + goto out; + } + req = otx2_mbox_alloc_msg_npc_install_flow(&pf->mbox); if (!req) { err = -ENOMEM; @@ -2562,13 +2592,12 @@ static int otx2_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) if (!is_valid_ether_addr(mac)) return -EINVAL; - config = &pf->vf_configs[vf]; - ether_addr_copy(config->mac, mac); - ret = otx2_do_set_vf_mac(pf, vf, mac); - if (ret == 0) - dev_info(&pdev->dev, - "Load/Reload VF driver\n"); + if (ret == 0) { + config = &pf->vf_configs[vf]; + ether_addr_copy(config->mac, mac); + dev_info(&pdev->dev, "Load/Reload VF driver\n"); + } return ret; } diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c index f4fdbfba8667..b022f52c6845 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c @@ -251,9 +251,17 @@ static int otx2vf_register_mbox_intr(struct otx2_nic *vf, bool probe_pf) { struct otx2_hw *hw = &vf->hw; struct msg_req *req; + u64 mbox_int_mask; char *irq_name; int err; + mbox_int_mask = !is_cn20k(vf->pdev) ? BIT_ULL(0) : + BIT_ULL(0) | BIT_ULL(1) | + BIT_ULL(2) | BIT_ULL(3); + + /* Clear stale mailbox interrupt state before installing the handler. */ + otx2_write64(vf, RVU_VF_INT, mbox_int_mask); + /* Register mailbox interrupt handler */ irq_name = &hw->irq_name[RVU_VF_INT_VEC_MBOX * NAME_SIZE]; snprintf(irq_name, NAME_SIZE, "RVUVF%d AFVF Mbox", ((vf->pcifunc & @@ -274,18 +282,8 @@ static int otx2vf_register_mbox_intr(struct otx2_nic *vf, bool probe_pf) return err; } - /* Enable mailbox interrupt for msgs coming from PF. - * First clear to avoid spurious interrupts, if any. - */ - if (!is_cn20k(vf->pdev)) { - otx2_write64(vf, RVU_VF_INT, BIT_ULL(0)); - otx2_write64(vf, RVU_VF_INT_ENA_W1S, BIT_ULL(0)); - } else { - otx2_write64(vf, RVU_VF_INT, BIT_ULL(0) | BIT_ULL(1) | - BIT_ULL(2) | BIT_ULL(3)); - otx2_write64(vf, RVU_VF_INT_ENA_W1S, BIT_ULL(0) | - BIT_ULL(1) | BIT_ULL(2) | BIT_ULL(3)); - } + /* Enable mailbox interrupt for msgs coming from PF. */ + otx2_write64(vf, RVU_VF_INT_ENA_W1S, mbox_int_mask); if (!probe_pf) return 0; diff --git a/drivers/net/ethernet/marvell/prestera/prestera_main.c b/drivers/net/ethernet/marvell/prestera/prestera_main.c index 41e19e9ad28d..a82e7a802985 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_main.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_main.c @@ -373,7 +373,7 @@ static int prestera_port_sfp_bind(struct prestera_port *port) struct device_node *ports, *node; struct fwnode_handle *fwnode; struct phylink *phy_link; - int err; + int err = 0; if (!sw->np) return 0; diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 7d771168b990..5d291e50a47b 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -4960,6 +4960,11 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) mac_ops = &rt5350_phylink_ops; + if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_2P5GPHY) && + id == MTK_GMAC2_ID) + __set_bit(PHY_INTERFACE_MODE_INTERNAL, + mac->phylink_config.supported_interfaces); + phylink = phylink_create(&mac->phylink_config, of_fwnode_handle(mac->of_node), phy_mode, mac_ops); @@ -4970,11 +4975,6 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) mac->phylink = phylink; - if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_2P5GPHY) && - id == MTK_GMAC2_ID) - __set_bit(PHY_INTERFACE_MODE_INTERNAL, - mac->phylink_config.supported_interfaces); - SET_NETDEV_DEV(eth->netdev[id], eth->dev); eth->netdev[id]->watchdog_timeo = 5 * HZ; eth->netdev[id]->netdev_ops = &mtk_netdev_ops; diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c index 18279e2a7022..8451dc3fd00a 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c @@ -918,7 +918,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) mib = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*mib), &ppe->mib_phys, GFP_KERNEL); if (!mib) - return NULL; + goto err_free_l2_flows; ppe->mib_table = mib; @@ -926,7 +926,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) GFP_KERNEL); if (!acct) - return NULL; + goto err_free_l2_flows; ppe->acct_table = acct; } diff --git a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c index 781c691473e1..519c364e87d1 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c +++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c @@ -310,9 +310,9 @@ wed_amsdu_show(struct seq_file *s, void *data) WED_AMSDU_ENG_MAX_QGPP_CNT), DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(1), WED_AMSDU_ENG_CUR_ENTRY), - DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(2), + DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(1), WED_AMSDU_ENG_MAX_BUF_MERGED), - DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(2), + DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(1), WED_AMSDU_ENG_MAX_MSDU_MERGED), DUMP_STR("WED AMDSU ENG2 INFO"), @@ -414,7 +414,7 @@ wed_amsdu_show(struct seq_file *s, void *data) WED_AMSDU_ENG_CUR_ENTRY), DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(7), WED_AMSDU_ENG_MAX_BUF_MERGED), - DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(4), + DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(7), WED_AMSDU_ENG_MAX_MSDU_MERGED), DUMP_STR("WED AMDSU ENG8 INFO"), diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c index fa6b21603416..0d38183c6ba7 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c +++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c @@ -367,8 +367,12 @@ mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo) /* wo firmware reset */ wo_w32(MTK_WO_MCU_CFG_LS_WF_MCCR_CLR_ADDR, 0xc00); - val = wo_r32(MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR) | - MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK; + val = wo_r32(MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR); + + if (!mtk_wed_is_v3_or_greater(wo->hw) && wo->hw->index) + val |= MTK_WO_MCU_CFG_LS_WF_WM_WA_WA_CPU_RSTB_MASK; + else + val |= MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK; wo_w32(MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val); out: release_firmware(fw); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index d39fe9c4a87c..19e50f0d55af 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -41,7 +41,7 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o mlx5_core-$(CONFIG_PCI_HYPERV_INTERFACE) += en/hv_vhca_stats.o mlx5_core-$(CONFIG_MLX5_ESWITCH) += lag/mp.o lag/port_sel.o lib/geneve.o lib/port_tun.o \ en_rep.o en/rep/bond.o en/mod_hdr.o \ - en/mapping.o lag/mpesw.o + en/mapping.o lag/mpesw.o lag/shared_fdb.o mlx5_core-$(CONFIG_MLX5_CLS_ACT) += en_tc.o en/rep/tc.o en/rep/neigh.o \ lib/fs_chains.o en/tc_tun.o \ esw/indir_table.o en/tc_tun_encap.o \ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 2270e2e550dd..d507289096c2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -987,6 +987,18 @@ struct mlx5e_priv { struct ethtool_fec_hist_range *fec_ranges; }; +static inline u16 mlx5e_stats_nch_read(const struct mlx5e_priv *priv) +{ + /* Pairs with smp_store_release in mlx5e_stats_nch_write(). */ + return smp_load_acquire(&priv->stats_nch); +} + +static inline void mlx5e_stats_nch_write(struct mlx5e_priv *priv, u16 n) +{ + /* Pairs with smp_load_acquire in mlx5e_stats_nch_read(). */ + smp_store_release(&priv->stats_nch, n); +} + struct mlx5e_dev { struct net_device *netdev; struct devlink_port dl_port; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c index 195863b2c013..631f802105d5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c @@ -33,9 +33,10 @@ mlx5e_hv_vhca_fill_ring_stats(struct mlx5e_priv *priv, int ch, static void mlx5e_hv_vhca_fill_stats(struct mlx5e_priv *priv, void *data, int buf_len) { + u16 nch = mlx5e_stats_nch_read(priv); int ch, i = 0; - for (ch = 0; ch < priv->stats_nch; ch++) { + for (ch = 0; ch < nch; ch++) { void *buf = data + i; if (WARN_ON_ONCE(buf + @@ -50,8 +51,15 @@ static void mlx5e_hv_vhca_fill_stats(struct mlx5e_priv *priv, void *data, static int mlx5e_hv_vhca_stats_buf_size(struct mlx5e_priv *priv) { + u16 nch = mlx5e_stats_nch_read(priv); + + return sizeof(struct mlx5e_hv_vhca_per_ring_stats) * nch; +} + +static int mlx5e_hv_vhca_stats_buf_max_size(struct mlx5e_priv *priv) +{ return (sizeof(struct mlx5e_hv_vhca_per_ring_stats) * - priv->stats_nch); + max(priv->max_nch, priv->stats_nch)); } static void mlx5e_hv_vhca_stats_work(struct work_struct *work) @@ -67,7 +75,7 @@ static void mlx5e_hv_vhca_stats_work(struct work_struct *work) sagent = container_of(dwork, struct mlx5e_hv_vhca_stats_agent, work); priv = container_of(sagent, struct mlx5e_priv, stats_agent); buf_len = mlx5e_hv_vhca_stats_buf_size(priv); - agent = sagent->agent; + agent = READ_ONCE(sagent->agent); buf = sagent->buf; memset(buf, 0, buf_len); @@ -100,7 +108,7 @@ static void mlx5e_hv_vhca_stats_control(struct mlx5_hv_vhca_agent *agent, sagent = &priv->stats_agent; block->version = MLX5_HV_VHCA_STATS_VERSION; - block->rings = priv->stats_nch; + block->rings = mlx5e_stats_nch_read(priv); if (!block->command) { cancel_delayed_work_sync(&priv->stats_agent.work); @@ -122,18 +130,21 @@ static void mlx5e_hv_vhca_stats_cleanup(struct mlx5_hv_vhca_agent *agent) void mlx5e_hv_vhca_stats_create(struct mlx5e_priv *priv) { - int buf_len = mlx5e_hv_vhca_stats_buf_size(priv); + int buf_len = mlx5e_hv_vhca_stats_buf_max_size(priv); struct mlx5_hv_vhca_agent *agent; priv->stats_agent.buf = kvzalloc(buf_len, GFP_KERNEL); if (!priv->stats_agent.buf) return; + INIT_DELAYED_WORK(&priv->stats_agent.work, mlx5e_hv_vhca_stats_work); + agent = mlx5_hv_vhca_agent_create(priv->mdev->hv_vhca, MLX5_HV_VHCA_AGENT_STATS, mlx5e_hv_vhca_stats_control, NULL, mlx5e_hv_vhca_stats_cleanup, - priv); + priv, + &priv->stats_agent.agent); if (IS_ERR_OR_NULL(agent)) { if (IS_ERR(agent)) @@ -142,18 +153,20 @@ void mlx5e_hv_vhca_stats_create(struct mlx5e_priv *priv) agent); kvfree(priv->stats_agent.buf); - return; + priv->stats_agent.buf = NULL; } - - priv->stats_agent.agent = agent; - INIT_DELAYED_WORK(&priv->stats_agent.work, mlx5e_hv_vhca_stats_work); } void mlx5e_hv_vhca_stats_destroy(struct mlx5e_priv *priv) { - if (IS_ERR_OR_NULL(priv->stats_agent.agent)) + struct mlx5_hv_vhca_agent *agent; + + agent = READ_ONCE(priv->stats_agent.agent); + if (IS_ERR_OR_NULL(agent)) return; - mlx5_hv_vhca_agent_destroy(priv->stats_agent.agent); + mlx5_hv_vhca_agent_destroy(agent); + WRITE_ONCE(priv->stats_agent.agent, NULL); kvfree(priv->stats_agent.buf); + priv->stats_agent.buf = NULL; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c index 71b3a059c964..daff53ba7d09 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c @@ -714,34 +714,43 @@ static int mlx5e_macsec_add_rxsc(struct macsec_context *ctx) } sc_xarray_element->rx_sc = rx_sc; - err = xa_alloc(&macsec->sc_xarray, &sc_xarray_element->fs_id, sc_xarray_element, - XA_LIMIT(1, MLX5_MACEC_RX_FS_ID_MAX), GFP_KERNEL); - if (err) { - if (err == -EBUSY) - netdev_err(ctx->netdev, - "MACsec offload: unable to create entry for RX SC (%d Rx SCs already allocated)\n", - MLX5_MACEC_RX_FS_ID_MAX); - goto destroy_sc_xarray_elemenet; - } rx_sc->md_dst = metadata_dst_alloc(0, METADATA_MACSEC, GFP_KERNEL); if (!rx_sc->md_dst) { err = -ENOMEM; - goto erase_xa_alloc; + goto destroy_sc_xarray_elemenet; } rx_sc->sci = ctx_rx_sc->sci; rx_sc->active = ctx_rx_sc->active; - list_add_rcu(&rx_sc->rx_sc_list_element, rx_sc_list); - rx_sc->sc_xarray_element = sc_xarray_element; rx_sc->md_dst->u.macsec_info.sci = rx_sc->sci; + + /* + * Publish the fully-initialised SC last: xa_alloc() makes + * sc_xarray_element->rx_sc (and rx_sc->md_dst) reachable from the RX + * datapath via xa_load(). Doing it only after md_dst is allocated and + * initialised pairs with the rcu_read_lock()/xa_load() in + * mlx5e_macsec_offload_handle_rx_skb(), so a reader can never observe + * a non-NULL md_dst with uninitialised contents. + */ + err = xa_alloc(&macsec->sc_xarray, &sc_xarray_element->fs_id, sc_xarray_element, + XA_LIMIT(1, MLX5_MACEC_RX_FS_ID_MAX), GFP_KERNEL); + if (err) { + if (err == -EBUSY) + netdev_err(ctx->netdev, + "MACsec offload: unable to create entry for RX SC (%d Rx SCs already allocated)\n", + MLX5_MACEC_RX_FS_ID_MAX); + goto destroy_md_dst; + } + + list_add_rcu(&rx_sc->rx_sc_list_element, rx_sc_list); mutex_unlock(&macsec->lock); return 0; -erase_xa_alloc: - xa_erase(&macsec->sc_xarray, sc_xarray_element->fs_id); +destroy_md_dst: + dst_release(&rx_sc->md_dst->dst); destroy_sc_xarray_elemenet: kfree(sc_xarray_element); destroy_rx_sc: @@ -829,7 +838,7 @@ static void macsec_del_rxsc_ctx(struct mlx5e_macsec *macsec, struct mlx5e_macsec */ list_del_rcu(&rx_sc->rx_sc_list_element); xa_erase(&macsec->sc_xarray, rx_sc->sc_xarray_element->fs_id); - metadata_dst_free(rx_sc->md_dst); + dst_release(&rx_sc->md_dst->dst); kfree(rx_sc->sc_xarray_element); kfree_rcu_mightsleep(rx_sc); } @@ -1695,10 +1704,10 @@ void mlx5e_macsec_offload_handle_rx_skb(struct net_device *netdev, rcu_read_lock(); sc_xarray_element = xa_load(&macsec->sc_xarray, fs_id); - rx_sc = sc_xarray_element->rx_sc; - if (rx_sc) { - dst_hold(&rx_sc->md_dst->dst); - skb_dst_set(skb, &rx_sc->md_dst->dst); + rx_sc = sc_xarray_element ? sc_xarray_element->rx_sc : NULL; + if (rx_sc && rx_sc->md_dst) { + if (dst_hold_safe(&rx_sc->md_dst->dst)) + skb_dst_set(skb, &rx_sc->md_dst->dst); } rcu_read_unlock(); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 8f2b3abe0092..94e5352a246c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -2773,7 +2773,7 @@ static int mlx5e_channel_stats_alloc(struct mlx5e_priv *priv, int ix, int cpu) GFP_KERNEL, cpu_to_node(cpu)); if (!priv->channel_stats[ix]) return -ENOMEM; - priv->stats_nch++; + mlx5e_stats_nch_write(priv, priv->stats_nch + 1); return 0; } @@ -4043,9 +4043,10 @@ static int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type, void mlx5e_fold_sw_stats64(struct mlx5e_priv *priv, struct rtnl_link_stats64 *s) { + u16 nch = mlx5e_stats_nch_read(priv); int i; - for (i = 0; i < priv->stats_nch; i++) { + for (i = 0; i < nch; i++) { struct mlx5e_channel_stats *channel_stats = priv->channel_stats[i]; struct mlx5e_rq_stats *xskrq_stats = &channel_stats->xskrq; struct mlx5e_rq_stats *rq_stats = &channel_stats->rq; @@ -5489,7 +5490,7 @@ static void mlx5e_get_queue_stats_rx(struct net_device *dev, int i, struct mlx5e_rq_stats *xskrq_stats; struct mlx5e_rq_stats *rq_stats; - if (mlx5e_is_uplink_rep(priv) || !priv->stats_nch) + if (mlx5e_is_uplink_rep(priv) || !mlx5e_stats_nch_read(priv)) return; channel_stats = priv->channel_stats[i]; @@ -5508,7 +5509,7 @@ static void mlx5e_get_queue_stats_tx(struct net_device *dev, int i, struct mlx5e_priv *priv = netdev_priv(dev); struct mlx5e_sq_stats *sq_stats; - if (!priv->stats_nch) + if (!mlx5e_stats_nch_read(priv)) return; /* no special case needed for ptp htb etc since txq2sq_stats is kept up @@ -5525,6 +5526,7 @@ static void mlx5e_get_base_stats(struct net_device *dev, struct netdev_queue_stats_tx *tx) { struct mlx5e_priv *priv = netdev_priv(dev); + u16 nch = mlx5e_stats_nch_read(priv); struct mlx5e_ptp *ptp_channel; int i, tc; @@ -5533,7 +5535,7 @@ static void mlx5e_get_base_stats(struct net_device *dev, rx->bytes = 0; rx->alloc_fail = 0; - for (i = priv->channels.params.num_channels; i < priv->stats_nch; i++) { + for (i = priv->channels.params.num_channels; i < nch; i++) { struct netdev_queue_stats_rx rx_i = {0}; mlx5e_get_queue_stats_rx(dev, i, &rx_i); @@ -5558,7 +5560,7 @@ static void mlx5e_get_base_stats(struct net_device *dev, tx->packets = 0; tx->bytes = 0; - for (i = 0; i < priv->stats_nch; i++) { + for (i = 0; i < nch; i++) { struct mlx5e_channel_stats *channel_stats = priv->channel_stats[i]; /* handle two cases: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c index 1a3ecf073913..8632b73179cb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c @@ -516,6 +516,7 @@ static void mlx5e_stats_update_stats_rq_page_pool(struct mlx5e_channel *c) static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(sw) { struct mlx5e_sw_stats *s = &priv->stats.sw; + u16 nch = mlx5e_stats_nch_read(priv); int i; memset(s, 0, sizeof(*s)); @@ -523,7 +524,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(sw) for (i = 0; i < priv->channels.num; i++) /* for active channels only */ mlx5e_stats_update_stats_rq_page_pool(priv->channels.c[i]); - for (i = 0; i < priv->stats_nch; i++) { + for (i = 0; i < nch; i++) { struct mlx5e_channel_stats *channel_stats = priv->channel_stats[i]; @@ -2615,7 +2616,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(ptp) { return; } static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(channels) { - int max_nch = priv->stats_nch; + int max_nch = mlx5e_stats_nch_read(priv); return (NUM_RQ_STATS * max_nch) + (NUM_CH_STATS * max_nch) + @@ -2628,8 +2629,8 @@ static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(channels) static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(channels) { + int max_nch = mlx5e_stats_nch_read(priv); bool is_xsk = priv->xsk.ever_used; - int max_nch = priv->stats_nch; int i, j, tc; for (i = 0; i < max_nch; i++) @@ -2661,8 +2662,8 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(channels) static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(channels) { + int max_nch = mlx5e_stats_nch_read(priv); bool is_xsk = priv->xsk.ever_used; - int max_nch = priv->stats_nch; int i, j, tc; for (i = 0; i < max_nch; i++) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index a9001d1c902f..8b5a421a22a3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -5526,6 +5526,9 @@ void mlx5e_tc_clean_fdb_peer_flows(struct mlx5_eswitch *esw) mlx5_devcom_for_each_peer_entry(devcom, peer_esw, pos) { i = mlx5_lag_get_dev_seq(peer_esw->dev); + if (i < 0) + continue; + list_for_each_entry_safe(flow, tmp, &esw->offloads.peer_flows[i], peer[i]) mlx5e_tc_del_fdb_peers_flow(flow); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index e9cf7c592ce9..f248c66caa84 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -316,6 +316,7 @@ struct mlx5_esw_offload { DECLARE_HASHTABLE(termtbl_tbl, 8); struct mutex termtbl_mutex; /* protects termtbl hash */ struct xarray vhca_map; + struct mutex reps_lock; /* protects representor load/unload/register */ const struct mlx5_eswitch_rep_ops *rep_ops[NUM_REP_TYPES]; u8 inline_mode; atomic64_t num_flows; @@ -898,6 +899,8 @@ int mlx5_eswitch_offloads_single_fdb_add_one(struct mlx5_eswitch *master_esw, void mlx5_eswitch_offloads_single_fdb_del_one(struct mlx5_eswitch *master_esw, struct mlx5_eswitch *slave_esw); int mlx5_eswitch_reload_ib_reps(struct mlx5_eswitch *esw); +bool mlx5_eswitch_is_peer(struct mlx5_eswitch *esw, + struct mlx5_eswitch *peer_esw); bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev, bool from_fdb); void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev); @@ -913,13 +916,6 @@ static inline int mlx5_eswitch_num_vfs(struct mlx5_eswitch *esw) return 0; } -static inline int mlx5_eswitch_get_npeers(struct mlx5_eswitch *esw) -{ - if (mlx5_esw_allowed(esw)) - return esw->num_peers; - return 0; -} - static inline struct mlx5_flow_table * mlx5_eswitch_get_slow_fdb(struct mlx5_eswitch *esw) { @@ -949,6 +945,8 @@ mlx5_esw_lag_demux_fg_create(struct mlx5_eswitch *esw, struct mlx5_flow_handle * mlx5_esw_lag_demux_rule_create(struct mlx5_eswitch *esw, u16 vport_num, struct mlx5_flow_table *lag_ft); +void mlx5_esw_reps_block(struct mlx5_eswitch *esw); +void mlx5_esw_reps_unblock(struct mlx5_eswitch *esw); #else /* CONFIG_MLX5_ESWITCH */ /* eswitch API stubs */ static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; } @@ -993,8 +991,6 @@ static inline void mlx5_eswitch_offloads_single_fdb_del_one(struct mlx5_eswitch *master_esw, struct mlx5_eswitch *slave_esw) {} -static inline int mlx5_eswitch_get_npeers(struct mlx5_eswitch *esw) { return 0; } - static inline int mlx5_eswitch_reload_ib_reps(struct mlx5_eswitch *esw) { @@ -1026,6 +1022,9 @@ mlx5_esw_host_functions_enabled(const struct mlx5_core_dev *dev) return true; } +static inline void mlx5_esw_reps_block(struct mlx5_eswitch *esw) {} +static inline void mlx5_esw_reps_unblock(struct mlx5_eswitch *esw) {} + static inline bool mlx5_esw_vport_vhca_id(struct mlx5_eswitch *esw, u16 vportn, u16 *vhca_id) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index a078d06f4567..fbd59225b863 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2410,6 +2410,16 @@ out_free: return err; } +void mlx5_esw_reps_block(struct mlx5_eswitch *esw) +{ + mutex_lock(&esw->offloads.reps_lock); +} + +void mlx5_esw_reps_unblock(struct mlx5_eswitch *esw) +{ + mutex_unlock(&esw->offloads.reps_lock); +} + static void esw_mode_change(struct mlx5_eswitch *esw, u16 mode) { mlx5_devcom_comp_lock(esw->dev->priv.hca_devcom_comp); @@ -2642,6 +2652,7 @@ static void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw) mlx5_esw_for_each_rep(esw, i, rep) mlx5_esw_offloads_rep_cleanup(esw, rep); xa_destroy(&esw->offloads.vport_reps); + mutex_destroy(&esw->offloads.reps_lock); } static int esw_offloads_init_reps(struct mlx5_eswitch *esw) @@ -2651,6 +2662,7 @@ static int esw_offloads_init_reps(struct mlx5_eswitch *esw) int err; xa_init(&esw->offloads.vport_reps); + mutex_init(&esw->offloads.reps_lock); mlx5_esw_for_each_vport(esw, i, vport) { err = mlx5_esw_offloads_rep_add(esw, vport); @@ -3225,6 +3237,18 @@ static int mlx5_esw_offloads_set_ns_peer(struct mlx5_eswitch *esw, return 0; } +bool mlx5_eswitch_is_peer(struct mlx5_eswitch *esw, + struct mlx5_eswitch *peer_esw) +{ + u16 peer_esw_i; + + if (!mlx5_esw_allowed(esw) || !mlx5_esw_allowed(peer_esw)) + return false; + + peer_esw_i = MLX5_CAP_GEN(peer_esw->dev, vhca_id); + return !!xa_load(&esw->paired, peer_esw_i); +} + static int mlx5_esw_offloads_devcom_event(int event, void *my_data, void *event_data) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c index 0a6003fe60e9..674bed721e63 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c @@ -135,10 +135,11 @@ void mlx5i_cleanup(struct mlx5e_priv *priv) static void mlx5i_grp_sw_update_stats(struct mlx5e_priv *priv) { + u16 nch = mlx5e_stats_nch_read(priv); struct rtnl_link_stats64 s = {}; int i, j; - for (i = 0; i < priv->stats_nch; i++) { + for (i = 0; i < nch; i++) { struct mlx5e_channel_stats *channel_stats; struct mlx5e_rq_stats *rq_stats; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c index f8e70ac5a85b..3decb49e9f19 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c @@ -242,7 +242,7 @@ static void mlx5_ldev_free(struct kref *ref) unregister_netdevice_notifier_net(net, &ldev->nb); } - mlx5_ldev_for_each(i, 0, ldev) { + mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) { pf = mlx5_lag_pf(ldev, i); if (pf->port_change_nb.nb.notifier_call) { struct mlx5_nb *nb = &pf->port_change_nb; @@ -370,6 +370,22 @@ int mlx5_lag_get_dev_index_by_seq(struct mlx5_lag *ldev, int seq) return -ENOENT; } +/* Return the appropriate iterator filter for a device in LAG: + * - SD shared FDB active: iterate only the device's SD group + * - SD group exists but shared FDB not active: iterate all devices + * - No SD: iterate ports only + */ +static u32 mlx5_lag_get_filter(struct mlx5_lag *ldev, struct mlx5_core_dev *dev) +{ + struct lag_func *pf = mlx5_lag_pf_by_dev(ldev, dev); + + if (pf && pf->sd_fdb_active) + return pf->group_id; + if (pf && pf->group_id) + return MLX5_LAG_FILTER_ALL; + return MLX5_LAG_FILTER_PORTS; +} + /* Reverse of mlx5_lag_get_dev_index_by_seq: given a device, return its * sequence number in the LAG. Master is always 0, others numbered * sequentially starting from 1. @@ -379,11 +395,13 @@ int mlx5_lag_get_dev_seq(struct mlx5_core_dev *dev) struct mlx5_lag *ldev = mlx5_lag_dev(dev); int master_idx, i, num = 1; struct lag_func *pf; + u32 filter; if (!ldev) return -ENOENT; - master_idx = mlx5_lag_get_master_idx(ldev); + filter = mlx5_lag_get_filter(ldev, dev); + master_idx = mlx5_lag_get_dev_index_by_seq_filter(ldev, 0, filter); if (master_idx < 0) return -ENOENT; @@ -391,7 +409,7 @@ int mlx5_lag_get_dev_seq(struct mlx5_core_dev *dev) if (pf && pf->dev == dev) return 0; - mlx5_ldev_for_each(i, 0, ldev) { + mlx5_lag_for_each(i, 0, ldev, filter) { if (i == master_idx) continue; pf = mlx5_lag_pf(ldev, i); @@ -403,6 +421,69 @@ int mlx5_lag_get_dev_seq(struct mlx5_core_dev *dev) } EXPORT_SYMBOL(mlx5_lag_get_dev_seq); +/* seq 0 = master, then all remaining devices */ +static int mlx5_lag_get_dev_index_by_seq_all(struct mlx5_lag *ldev, int seq) +{ + int master_idx, i, num = 0; + + master_idx = mlx5_lag_get_master_idx(ldev); + + if (master_idx >= 0) { + if (seq == 0) + return master_idx; + num++; + } + + mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) { + if (i == master_idx) + continue; + if (num == seq) + return i; + num++; + } + return -ENOENT; +} + +/* From group POV, port-marked entry is the lag master */ +static int mlx5_lag_get_dev_index_by_seq_group(struct mlx5_lag *ldev, int seq, + u32 group_id) +{ + int i, num = 0; + + mlx5_lag_for_each(i, 0, ldev, group_id) { + if (xa_get_mark(&ldev->pfs, i, MLX5_LAG_XA_MARK_PORT)) { + if (seq == 0) + return i; + num++; + break; + } + } + + mlx5_lag_for_each(i, 0, ldev, group_id) { + if (xa_get_mark(&ldev->pfs, i, MLX5_LAG_XA_MARK_PORT)) + continue; + if (num == seq) + return i; + num++; + } + return -ENOENT; +} + +int mlx5_lag_get_dev_index_by_seq_filter(struct mlx5_lag *ldev, int seq, + u32 filter) +{ + if (!ldev) + return -ENOENT; + + if (!filter || filter == MLX5_LAG_FILTER_PORTS) + return mlx5_lag_get_dev_index_by_seq(ldev, seq); + + if (filter == MLX5_LAG_FILTER_ALL) + return mlx5_lag_get_dev_index_by_seq_all(ldev, seq); + + return mlx5_lag_get_dev_index_by_seq_group(ldev, seq, filter); +} + /* Devcom events for LAG master marking */ #define LAG_DEVCOM_PAIR (0) #define LAG_DEVCOM_UNPAIR (1) @@ -512,6 +593,14 @@ static bool __mlx5_lag_is_sriov(struct mlx5_lag *ldev) return ldev->mode == MLX5_LAG_MODE_SRIOV; } +static bool __mlx5_lag_is_sd_active(struct mlx5_lag *ldev, + struct mlx5_core_dev *dev) +{ + struct lag_func *pf = mlx5_lag_pf_by_dev(ldev, dev); + + return pf && pf->sd_fdb_active; +} + /* Create a mapping between steering slots and active ports. * As we have ldev->buckets slots per port first assume the native * mapping should be used. @@ -817,43 +906,6 @@ char *mlx5_get_str_port_sel_mode(enum mlx5_lag_mode mode, unsigned long flags) } } -static int mlx5_lag_create_single_fdb(struct mlx5_lag *ldev) -{ - int master_idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1); - struct mlx5_eswitch *master_esw; - struct mlx5_core_dev *dev0; - int i, j; - int err; - - if (master_idx < 0) - return -EINVAL; - - dev0 = mlx5_lag_pf(ldev, master_idx)->dev; - master_esw = dev0->priv.eswitch; - mlx5_ldev_for_each(i, 0, ldev) { - struct mlx5_eswitch *slave_esw; - - if (i == master_idx) - continue; - - slave_esw = mlx5_lag_pf(ldev, i)->dev->priv.eswitch; - - err = mlx5_eswitch_offloads_single_fdb_add_one(master_esw, - slave_esw, ldev->ports); - if (err) - goto err; - } - return 0; -err: - mlx5_ldev_for_each_reverse(j, i, 0, ldev) { - if (j == master_idx) - continue; - mlx5_eswitch_offloads_single_fdb_del_one(master_esw, - mlx5_lag_pf(ldev, j)->dev->priv.eswitch); - } - return err; -} - static int mlx5_create_lag(struct mlx5_lag *ldev, struct lag_tracker *tracker, enum mlx5_lag_mode mode, @@ -964,27 +1016,19 @@ int mlx5_deactivate_lag(struct mlx5_lag *ldev) u32 in[MLX5_ST_SZ_DW(destroy_lag_in)] = {}; bool roce_lag = __mlx5_lag_is_roce(ldev); unsigned long flags = ldev->mode_flags; - struct mlx5_eswitch *master_esw; struct mlx5_core_dev *dev0; int err; - int i; if (master_idx < 0) return -EINVAL; dev0 = mlx5_lag_pf(ldev, master_idx)->dev; - master_esw = dev0->priv.eswitch; ldev->mode = MLX5_LAG_MODE_NONE; ldev->mode_flags = 0; mlx5_lag_mp_reset(ldev); if (test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &flags)) { - mlx5_ldev_for_each(i, 0, ldev) { - if (i == master_idx) - continue; - mlx5_eswitch_offloads_single_fdb_del_one(master_esw, - mlx5_lag_pf(ldev, i)->dev->priv.eswitch); - } + mlx5_lag_destroy_single_fdb(ldev); clear_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &flags); } @@ -1063,34 +1107,159 @@ bool mlx5_lag_check_prereq(struct mlx5_lag *ldev) return true; } -void mlx5_lag_add_devices(struct mlx5_lag *ldev) +static void mlx5_lag_assert_locked_transition(struct mlx5_lag *ldev, u32 filter) { + struct mlx5_devcom_comp_dev *devcom = NULL; struct lag_func *pf; int i; - mlx5_ldev_for_each(i, 0, ldev) { + lockdep_assert_held(&ldev->lock); + + i = mlx5_get_next_lag_func(ldev, 0, filter); + if (i < MLX5_MAX_PORTS) { + pf = mlx5_lag_pf(ldev, i); + if (filter == MLX5_LAG_FILTER_PORTS || + filter == MLX5_LAG_FILTER_ALL) + devcom = pf->dev->priv.hca_devcom_comp; + else + devcom = mlx5_sd_get_devcom(pf->dev); + } + mlx5_devcom_comp_assert_locked(devcom); +} + +static void mlx5_lag_drop_lock_for_reps(struct mlx5_lag *ldev, u32 filter) +{ + mlx5_lag_assert_locked_transition(ldev, filter); + + /* Keep PF membership stable while ldev->lock is dropped. Device add + * and remove paths observe mode_changes_in_progress and retry. + */ + ldev->mode_changes_in_progress++; + mutex_unlock(&ldev->lock); +} + +static void mlx5_lag_retake_lock_after_reps(struct mlx5_lag *ldev) +{ + mutex_lock(&ldev->lock); + ldev->mode_changes_in_progress--; +} + +void mlx5_lag_rescan_dev_locked(struct mlx5_lag *ldev, + struct mlx5_core_dev *dev, + bool enable) +{ + if (dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV) + return; + + if (enable) + dev->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; + else + dev->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; + + /* Auxiliary bus probe/remove can register or unregister representor + * callbacks and take reps_lock. Drop ldev->lock so the only ordering + * remains reps_lock -> ldev->lock from representor callbacks. + */ + mlx5_lag_drop_lock_for_reps(ldev, mlx5_lag_get_filter(ldev, dev)); + mlx5_rescan_drivers_locked(dev); + mlx5_lag_retake_lock_after_reps(ldev); +} + +static void mlx5_lag_rescan_devices_locked_filter(struct mlx5_lag *ldev, + bool enable, u32 filter) +{ + struct mlx5_core_dev *devs[MLX5_MAX_PORTS]; + struct lag_func *pf; + int num_devs = 0; + int i; + + mlx5_lag_assert_locked_transition(ldev, filter); + + mlx5_lag_for_each(i, 0, ldev, filter) { pf = mlx5_lag_pf(ldev, i); if (pf->dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV) continue; - pf->dev->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; - mlx5_rescan_drivers_locked(pf->dev); + if (enable) + pf->dev->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; + else + pf->dev->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; + devs[num_devs++] = pf->dev; } + + mlx5_lag_drop_lock_for_reps(ldev, filter); + for (i = 0; i < num_devs; i++) + mlx5_rescan_drivers_locked(devs[i]); + mlx5_lag_retake_lock_after_reps(ldev); +} + +void mlx5_lag_add_devices_filter(struct mlx5_lag *ldev, u32 filter) +{ + mlx5_lag_rescan_devices_locked_filter(ldev, true, filter); +} + +void mlx5_lag_add_devices(struct mlx5_lag *ldev) +{ + mlx5_lag_add_devices_filter(ldev, MLX5_LAG_FILTER_PORTS); +} + +void mlx5_lag_remove_devices_filter(struct mlx5_lag *ldev, u32 filter) +{ + mlx5_lag_rescan_devices_locked_filter(ldev, false, filter); } void mlx5_lag_remove_devices(struct mlx5_lag *ldev) { + mlx5_lag_remove_devices_filter(ldev, MLX5_LAG_FILTER_PORTS); +} + +static int mlx5_lag_reload_ib_reps_unlocked(struct mlx5_lag *ldev, u32 flags, + u32 filter, bool cont_on_fail) +{ struct lag_func *pf; + int ret; int i; - mlx5_ldev_for_each(i, 0, ldev) { + mlx5_lag_for_each(i, 0, ldev, filter) { pf = mlx5_lag_pf(ldev, i); - if (pf->dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV) - continue; - - pf->dev->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; - mlx5_rescan_drivers_locked(pf->dev); + if (!(pf->dev->priv.flags & flags)) { + struct mlx5_eswitch *esw; + + esw = pf->dev->priv.eswitch; + mlx5_esw_reps_block(esw); + ret = mlx5_eswitch_reload_ib_reps(esw); + mlx5_esw_reps_unblock(esw); + if (ret && !cont_on_fail) + return ret; + } } + + return 0; +} + +static int mlx5_lag_reload_ib_reps(struct mlx5_lag *ldev, u32 flags, + u32 filter, bool cont_on_fail) +{ + int ret; + + /* The HCA devcom component lock serializes LAG mode transitions while + * ldev->lock is dropped here. Dropping ldev->lock is required because + * the reload takes the per-E-Switch reps_lock, and representor + * load/unload callbacks can re-enter LAG netdev add/remove and take + * ldev->lock. Keep the ordering reps_lock -> ldev->lock. + */ + mlx5_lag_drop_lock_for_reps(ldev, filter); + ret = mlx5_lag_reload_ib_reps_unlocked(ldev, flags, filter, + cont_on_fail); + mlx5_lag_retake_lock_after_reps(ldev); + + return ret; +} + +int mlx5_lag_reload_ib_reps_from_locked(struct mlx5_lag *ldev, u32 flags, + u32 filter, bool cont_on_fail) +{ + return mlx5_lag_reload_ib_reps(ldev, flags, filter, cont_on_fail); } void mlx5_disable_lag(struct mlx5_lag *ldev) @@ -1105,16 +1274,16 @@ void mlx5_disable_lag(struct mlx5_lag *ldev) if (idx < 0) return; + if (shared_fdb) { + mlx5_lag_shared_fdb_destroy(ldev, 0); + return; + } + dev0 = mlx5_lag_pf(ldev, idx)->dev; roce_lag = __mlx5_lag_is_roce(ldev); - if (shared_fdb) { - mlx5_lag_remove_devices(ldev); - } else if (roce_lag) { - if (!(dev0->priv.flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV)) { - dev0->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; - mlx5_rescan_drivers_locked(dev0); - } + if (roce_lag) { + mlx5_lag_rescan_dev_locked(ldev, dev0, false); mlx5_ldev_for_each(i, 0, ldev) { if (i == idx) continue; @@ -1126,49 +1295,8 @@ void mlx5_disable_lag(struct mlx5_lag *ldev) if (err) return; - if (shared_fdb || roce_lag) + if (roce_lag) mlx5_lag_add_devices(ldev); - - if (shared_fdb) - mlx5_ldev_for_each(i, 0, ldev) - if (!(mlx5_lag_pf(ldev, i)->dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV)) - mlx5_eswitch_reload_ib_reps(mlx5_lag_pf(ldev, i)->dev->priv.eswitch); -} - -bool mlx5_lag_shared_fdb_supported(struct mlx5_lag *ldev) -{ - struct mlx5_core_dev *dev; - bool ret = false; - int idx; - int i; - - idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1); - if (idx < 0) - return false; - - mlx5_ldev_for_each(i, 0, ldev) { - if (i == idx) - continue; - dev = mlx5_lag_pf(ldev, i)->dev; - if (is_mdev_switchdev_mode(dev) && - mlx5_eswitch_vport_match_metadata_enabled(dev->priv.eswitch) && - MLX5_CAP_GEN(dev, lag_native_fdb_selection) && - MLX5_CAP_ESW(dev, root_ft_on_other_esw) && - mlx5_eswitch_get_npeers(dev->priv.eswitch) == - MLX5_CAP_GEN(dev, num_lag_ports) - 1) - continue; - return false; - } - - dev = mlx5_lag_pf(ldev, idx)->dev; - if (is_mdev_switchdev_mode(dev) && - mlx5_eswitch_vport_match_metadata_enabled(dev->priv.eswitch) && - mlx5_esw_offloads_devcom_is_ready(dev->priv.eswitch) && - MLX5_CAP_ESW(dev, esw_shared_ingress_acl) && - mlx5_eswitch_get_npeers(dev->priv.eswitch) == MLX5_CAP_GEN(dev, num_lag_ports) - 1) - ret = true; - - return ret; } static bool mlx5_lag_is_roce_lag(struct mlx5_lag *ldev) @@ -1383,58 +1511,38 @@ static void mlx5_do_bond(struct mlx5_lag *ldev) roce_lag = mlx5_lag_is_roce_lag(ldev); - if (shared_fdb || roce_lag) - mlx5_lag_remove_devices(ldev); - - err = mlx5_activate_lag(ldev, &tracker, - roce_lag ? MLX5_LAG_MODE_ROCE : - MLX5_LAG_MODE_SRIOV, - shared_fdb); - if (err) { - if (shared_fdb || roce_lag) - mlx5_lag_add_devices(ldev); - if (shared_fdb) { - mlx5_ldev_for_each(i, 0, ldev) - mlx5_eswitch_reload_ib_reps(mlx5_lag_pf(ldev, i)->dev->priv.eswitch); - } - - return; - } - - if (roce_lag) { - struct mlx5_core_dev *dev; - - dev0->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; - mlx5_rescan_drivers_locked(dev0); - mlx5_ldev_for_each(i, 0, ldev) { - if (i == idx) - continue; - dev = mlx5_lag_pf(ldev, i)->dev; - if (mlx5_get_roce_state(dev)) - mlx5_nic_vport_enable_roce(dev); - } - } else if (shared_fdb) { - int i; - - dev0->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; - mlx5_rescan_drivers_locked(dev0); - - mlx5_ldev_for_each(i, 0, ldev) { - err = mlx5_eswitch_reload_ib_reps(mlx5_lag_pf(ldev, i)->dev->priv.eswitch); - if (err) - break; - } + if (shared_fdb) { + err = mlx5_lag_shared_fdb_create(ldev, &tracker, + MLX5_LAG_MODE_SRIOV, + 0); + if (err) + return; + } else { + if (roce_lag) + mlx5_lag_remove_devices(ldev); + err = mlx5_activate_lag(ldev, &tracker, + roce_lag ? MLX5_LAG_MODE_ROCE : + MLX5_LAG_MODE_SRIOV, + false); if (err) { - dev0->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; - mlx5_rescan_drivers_locked(dev0); - mlx5_deactivate_lag(ldev); - mlx5_lag_add_devices(ldev); - mlx5_ldev_for_each(i, 0, ldev) - mlx5_eswitch_reload_ib_reps(mlx5_lag_pf(ldev, i)->dev->priv.eswitch); - mlx5_core_err(dev0, "Failed to enable lag\n"); + if (roce_lag) + mlx5_lag_add_devices(ldev); return; } + + if (roce_lag) { + struct mlx5_core_dev *dev; + + mlx5_lag_rescan_dev_locked(ldev, dev0, true); + mlx5_ldev_for_each(i, 0, ldev) { + if (i == idx) + continue; + dev = mlx5_lag_pf(ldev, i)->dev; + if (mlx5_get_roce_state(dev)) + mlx5_nic_vport_enable_roce(dev); + } + } } if (tracker.tx_type == NETDEV_LAG_TX_TYPE_ACTIVEBACKUP) { ndev = mlx5_lag_active_backup_get_netdev(dev0); @@ -1446,7 +1554,8 @@ static void mlx5_do_bond(struct mlx5_lag *ldev) ndev); dev_put(ndev); } - mlx5_lag_set_vports_agg_speed(ldev); + if (!shared_fdb) + mlx5_lag_set_vports_agg_speed(ldev); } else if (mlx5_lag_should_modify_lag(ldev, do_bond)) { mlx5_modify_lag(ldev, &tracker); mlx5_lag_set_vports_agg_speed(ldev); @@ -1467,7 +1576,7 @@ struct mlx5_devcom_comp_dev *mlx5_lag_get_devcom_comp(struct mlx5_lag *ldev) int i; mutex_lock(&ldev->lock); - i = mlx5_get_next_ldev_func(ldev, 0); + i = mlx5_get_next_lag_func(ldev, 0, MLX5_LAG_FILTER_PORTS); if (i < MLX5_MAX_PORTS) { pf = mlx5_lag_pf(ldev, i); devcom = pf->dev->priv.hca_devcom_comp; @@ -1950,8 +2059,9 @@ static void mlx5_ldev_remove_netdev(struct mlx5_lag *ldev, spin_unlock_irqrestore(&lag_lock, flags); } -static int mlx5_ldev_add_mdev(struct mlx5_lag *ldev, - struct mlx5_core_dev *dev) +int mlx5_ldev_add_mdev(struct mlx5_lag *ldev, + struct mlx5_core_dev *dev, + u32 group_id) { struct lag_func *pf; u32 idx; @@ -1970,8 +2080,14 @@ static int mlx5_ldev_add_mdev(struct mlx5_lag *ldev, pf->idx = idx; pf->dev = dev; + pf->group_id = group_id; dev->priv.lag = ldev; + if (group_id) + return 0; + + xa_set_mark(&ldev->pfs, idx, MLX5_LAG_XA_MARK_PORT); + MLX5_NB_INIT(&pf->port_change_nb, mlx5_lag_mpesw_port_change_event, PORT_CHANGE); mlx5_eq_notifier_register(dev, &pf->port_change_nb); @@ -1979,13 +2095,13 @@ static int mlx5_ldev_add_mdev(struct mlx5_lag *ldev, return 0; } -static void mlx5_ldev_remove_mdev(struct mlx5_lag *ldev, - struct mlx5_core_dev *dev) +void mlx5_ldev_remove_mdev(struct mlx5_lag *ldev, + struct mlx5_core_dev *dev) { struct lag_func *pf; int i; - mlx5_ldev_for_each(i, 0, ldev) { + mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) { pf = mlx5_lag_pf(ldev, i); if (pf->dev == dev) break; @@ -2020,7 +2136,7 @@ static int __mlx5_lag_dev_add_mdev(struct mlx5_core_dev *dev) mlx5_core_err(dev, "Failed to alloc lag dev\n"); return 0; } - err = mlx5_ldev_add_mdev(ldev, dev); + err = mlx5_ldev_add_mdev(ldev, dev, 0); if (err) { mlx5_core_err(dev, "Failed to add mdev to lag dev\n"); mlx5_ldev_put(ldev); @@ -2035,7 +2151,7 @@ static int __mlx5_lag_dev_add_mdev(struct mlx5_core_dev *dev) return -EAGAIN; } mlx5_ldev_get(ldev); - err = mlx5_ldev_add_mdev(ldev, dev); + err = mlx5_ldev_add_mdev(ldev, dev, 0); if (err) { mlx5_ldev_put(ldev); mutex_unlock(&ldev->lock); @@ -2172,27 +2288,47 @@ void mlx5_lag_add_netdev(struct mlx5_core_dev *dev, mlx5_queue_bond_work(ldev, 0); } -int mlx5_get_pre_ldev_func(struct mlx5_lag *ldev, int start_idx, int end_idx) +int mlx5_get_pre_lag_func(struct mlx5_lag *ldev, int start_idx, int end_idx, + u32 filter) { struct lag_func *pf; int i; for (i = start_idx; i >= end_idx; i--) { pf = xa_load(&ldev->pfs, i); - if (pf && pf->dev) + if (!pf || !pf->dev) + continue; + if (filter == MLX5_LAG_FILTER_PORTS) { + if (xa_get_mark(&ldev->pfs, i, MLX5_LAG_XA_MARK_PORT)) + return i; + } else if (filter == MLX5_LAG_FILTER_ALL || + filter == pf->group_id) { return i; + } } return -1; } -int mlx5_get_next_ldev_func(struct mlx5_lag *ldev, int start_idx) +int mlx5_get_next_lag_func(struct mlx5_lag *ldev, int start_idx, u32 filter) { struct lag_func *pf; unsigned long idx; - xa_for_each_start(&ldev->pfs, idx, pf, start_idx) - if (pf->dev) + if (filter == MLX5_LAG_FILTER_PORTS) { + xa_for_each_marked_start(&ldev->pfs, idx, pf, + MLX5_LAG_XA_MARK_PORT, start_idx) + if (pf->dev) + return idx; + return MLX5_MAX_PORTS; + } + + xa_for_each_start(&ldev->pfs, idx, pf, start_idx) { + if (!pf->dev) + continue; + if (filter == MLX5_LAG_FILTER_ALL || + filter == pf->group_id) return idx; + } return MLX5_MAX_PORTS; } @@ -2219,7 +2355,8 @@ bool mlx5_lag_is_active(struct mlx5_core_dev *dev) spin_lock_irqsave(&lag_lock, flags); ldev = mlx5_lag_dev(dev); - res = ldev && __mlx5_lag_is_active(ldev); + res = ldev && (__mlx5_lag_is_active(ldev) || + __mlx5_lag_is_sd_active(ldev, dev)); spin_unlock_irqrestore(&lag_lock, flags); return res; @@ -2252,10 +2389,17 @@ bool mlx5_lag_is_master(struct mlx5_core_dev *dev) spin_lock_irqsave(&lag_lock, flags); ldev = mlx5_lag_dev(dev); - idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1); - if (ldev && __mlx5_lag_is_active(ldev) && idx >= 0) { - pf = mlx5_lag_pf(ldev, idx); - res = pf && dev == pf->dev; + if (ldev) { + u32 filter; + + filter = mlx5_lag_get_filter(ldev, dev); + idx = mlx5_lag_get_dev_index_by_seq_filter(ldev, MLX5_LAG_P1, + filter); + if ((__mlx5_lag_is_active(ldev) || + __mlx5_lag_is_sd_active(ldev, dev)) && idx >= 0) { + pf = mlx5_lag_pf(ldev, idx); + res = pf && dev == pf->dev; + } } spin_unlock_irqrestore(&lag_lock, flags); @@ -2282,11 +2426,16 @@ bool mlx5_lag_is_shared_fdb(struct mlx5_core_dev *dev) { struct mlx5_lag *ldev; unsigned long flags; - bool res; + bool res = false; spin_lock_irqsave(&lag_lock, flags); ldev = mlx5_lag_dev(dev); - res = ldev && test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &ldev->mode_flags); + if (ldev) { + res = test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, + &ldev->mode_flags); + if (__mlx5_lag_is_sd(ldev, dev) && !__mlx5_lag_is_active(ldev)) + res = __mlx5_lag_is_sd_active(ldev, dev); + } spin_unlock_irqrestore(&lag_lock, flags); return res; @@ -2387,7 +2536,7 @@ struct mlx5_core_dev *mlx5_lag_get_next_peer_mdev(struct mlx5_core_dev *dev, int if (*i == MLX5_MAX_PORTS) goto unlock; - mlx5_ldev_for_each(idx, *i, ldev) { + mlx5_lag_for_each(idx, *i, ldev, mlx5_lag_get_filter(ldev, dev)) { pf = mlx5_lag_pf(ldev, idx); if (pf->dev != dev) break; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h index 6c911374f409..82b82bdb16dd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h @@ -15,6 +15,13 @@ * Note: XA_MARK_0 is reserved by XA_FLAGS_ALLOC for free-slot tracking. */ #define MLX5_LAG_XA_MARK_MASTER XA_MARK_1 +/* XArray mark for port-level entries (excludes SD secondaries) */ +#define MLX5_LAG_XA_MARK_PORT XA_MARK_2 + +/* Like xa_for_each_marked but starting from a given index */ +#define xa_for_each_marked_start(xa, index, entry, filter, start) \ + for (index = start, entry = xa_find(xa, &index, ULONG_MAX, filter); \ + entry; entry = xa_find_after(xa, &index, ULONG_MAX, filter)) #include "mlx5_core.h" #include "mp.h" @@ -50,6 +57,8 @@ struct lag_func { bool has_drop; unsigned int idx; /* xarray index assigned by LAG */ struct mlx5_nb port_change_nb; + u32 group_id; /* SD group ID, 0 = not SD */ + bool sd_fdb_active; /* set on all SD group members */ }; /* Used for collection of netdev event info. */ @@ -125,6 +134,28 @@ mlx5_lag_pf_by_dev_idx(struct mlx5_lag *ldev, int dev_idx) return NULL; } +/* Find lag_func by mlx5_core_dev pointer */ +static inline struct lag_func * +mlx5_lag_pf_by_dev(struct mlx5_lag *ldev, struct mlx5_core_dev *dev) +{ + struct lag_func *pf; + unsigned long idx; + + xa_for_each(&ldev->pfs, idx, pf) { + if (pf->dev == dev) + return pf; + } + return NULL; +} + +static inline bool +__mlx5_lag_is_sd(struct mlx5_lag *ldev, struct mlx5_core_dev *dev) +{ + struct lag_func *pf = mlx5_lag_pf_by_dev(ldev, dev); + + return pf && pf->group_id != 0; +} + static inline bool __mlx5_lag_is_active(struct mlx5_lag *ldev) { @@ -137,7 +168,39 @@ mlx5_lag_is_ready(struct mlx5_lag *ldev) return test_bit(MLX5_LAG_FLAG_NDEVS_READY, &ldev->state_flags); } +#ifdef CONFIG_MLX5_ESWITCH +int mlx5_lag_shared_fdb_create(struct mlx5_lag *ldev, + struct lag_tracker *tracker, + enum mlx5_lag_mode mode, + u32 group_id); +void mlx5_lag_shared_fdb_destroy(struct mlx5_lag *ldev, u32 group_id); +int mlx5_lag_create_single_fdb(struct mlx5_lag *ldev); +void mlx5_lag_destroy_single_fdb(struct mlx5_lag *ldev); bool mlx5_lag_shared_fdb_supported(struct mlx5_lag *ldev); +bool mlx5_lag_shared_fdb_supported_filter(struct mlx5_lag *ldev, u32 filter); +#else +static inline int mlx5_lag_shared_fdb_create(struct mlx5_lag *ldev, + struct lag_tracker *tracker, + enum mlx5_lag_mode mode, + u32 group_id) +{ + return -EOPNOTSUPP; +} + +static inline void mlx5_lag_shared_fdb_destroy(struct mlx5_lag *ldev, + u32 group_id) {} + +static inline int mlx5_lag_create_single_fdb(struct mlx5_lag *ldev) +{ + return -EOPNOTSUPP; +} + +static inline void mlx5_lag_destroy_single_fdb(struct mlx5_lag *ldev) {} +static inline bool mlx5_lag_shared_fdb_supported(struct mlx5_lag *ldev) +{ + return false; +} +#endif bool mlx5_lag_check_prereq(struct mlx5_lag *ldev); int mlx5_lag_demux_init(struct mlx5_core_dev *dev, struct mlx5_flow_table_attr *ft_attr); @@ -162,8 +225,13 @@ void mlx5_ldev_add_debugfs(struct mlx5_core_dev *dev); void mlx5_ldev_remove_debugfs(struct dentry *dbg); void mlx5_disable_lag(struct mlx5_lag *ldev); void mlx5_lag_remove_devices(struct mlx5_lag *ldev); +void mlx5_lag_remove_devices_filter(struct mlx5_lag *ldev, u32 filter); int mlx5_deactivate_lag(struct mlx5_lag *ldev); void mlx5_lag_add_devices(struct mlx5_lag *ldev); +void mlx5_lag_rescan_dev_locked(struct mlx5_lag *ldev, + struct mlx5_core_dev *dev, + bool enable); +void mlx5_lag_add_devices_filter(struct mlx5_lag *ldev, u32 filter); struct mlx5_devcom_comp_dev *mlx5_lag_get_devcom_comp(struct mlx5_lag *ldev); #ifdef CONFIG_MLX5_ESWITCH @@ -185,18 +253,40 @@ static inline bool mlx5_lag_is_supported(struct mlx5_core_dev *dev) return true; } -#define mlx5_ldev_for_each(i, start_index, ldev) \ - for (int tmp = start_index; tmp = mlx5_get_next_ldev_func(ldev, tmp), \ +/* Iterator filter constants for mlx5_lag_for_each() */ +#define MLX5_LAG_FILTER_PORTS 0 /* iterate ports only (XA_MARK_PORT) */ +#define MLX5_LAG_FILTER_ALL U32_MAX /* iterate ALL devices */ +/* any other value = iterate devices with that specific group_id */ + +#define mlx5_lag_for_each(i, start_index, ldev, filter) \ + for (int tmp = start_index; \ + tmp = mlx5_get_next_lag_func(ldev, tmp, filter), \ i = tmp, tmp < MLX5_MAX_PORTS; tmp++) -#define mlx5_ldev_for_each_reverse(i, start_index, end_index, ldev) \ +#define mlx5_lag_for_each_reverse(i, start_index, end_index, ldev, filter) \ for (int tmp = start_index, tmp1 = end_index; \ - tmp = mlx5_get_pre_ldev_func(ldev, tmp, tmp1), \ + tmp = mlx5_get_pre_lag_func(ldev, tmp, tmp1, filter), \ i = tmp, tmp >= tmp1; tmp--) -int mlx5_get_pre_ldev_func(struct mlx5_lag *ldev, int start_idx, int end_idx); -int mlx5_get_next_ldev_func(struct mlx5_lag *ldev, int start_idx); +/* Convenience wrappers - keeps existing behavior */ +#define mlx5_ldev_for_each(i, start_index, ldev) \ + mlx5_lag_for_each(i, start_index, ldev, MLX5_LAG_FILTER_PORTS) + +#define mlx5_ldev_for_each_reverse(i, start_index, end_index, ldev) \ + mlx5_lag_for_each_reverse(i, start_index, end_index, ldev, \ + MLX5_LAG_FILTER_PORTS) + +int mlx5_get_pre_lag_func(struct mlx5_lag *ldev, int start_idx, int end_idx, + u32 filter); +int mlx5_get_next_lag_func(struct mlx5_lag *ldev, int start_idx, u32 filter); int mlx5_lag_get_dev_index_by_seq(struct mlx5_lag *ldev, int seq); +int mlx5_lag_get_dev_index_by_seq_filter(struct mlx5_lag *ldev, int seq, + u32 filter); int mlx5_lag_num_devs(struct mlx5_lag *ldev); int mlx5_lag_num_netdevs(struct mlx5_lag *ldev); +int mlx5_lag_reload_ib_reps_from_locked(struct mlx5_lag *ldev, u32 flags, + u32 filter, bool cont_on_fail); +int mlx5_ldev_add_mdev(struct mlx5_lag *ldev, struct mlx5_core_dev *dev, + u32 group_id); +void mlx5_ldev_remove_mdev(struct mlx5_lag *ldev, struct mlx5_core_dev *dev); #endif /* __MLX5_LAG_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c index 5eea12a6887a..97334b563c24 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c @@ -70,7 +70,6 @@ static int mlx5_lag_enable_mpesw(struct mlx5_lag *ldev) int idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1); struct mlx5_core_dev *dev0; int err; - int i; if (ldev->mode == MLX5_LAG_MODE_MPESW) return 0; @@ -86,50 +85,29 @@ static int mlx5_lag_enable_mpesw(struct mlx5_lag *ldev) !MLX5_CAP_PORT_SELECTION(dev0, port_select_flow_table) || !MLX5_CAP_GEN(dev0, create_lag_when_not_master_up) || !mlx5_lag_check_prereq(ldev) || - !mlx5_lag_shared_fdb_supported(ldev)) + !mlx5_lag_shared_fdb_supported_filter(ldev, MLX5_LAG_FILTER_ALL)) return -EOPNOTSUPP; err = mlx5_mpesw_metadata_set(ldev); if (err) return err; - mlx5_lag_remove_devices(ldev); - - err = mlx5_activate_lag(ldev, NULL, MLX5_LAG_MODE_MPESW, true); + err = mlx5_lag_shared_fdb_create(ldev, NULL, MLX5_LAG_MODE_MPESW, + MLX5_LAG_FILTER_ALL); if (err) { mlx5_core_warn(dev0, "Failed to create LAG in MPESW mode (%d)\n", err); - goto err_add_devices; - } - - dev0->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; - mlx5_rescan_drivers_locked(dev0); - mlx5_ldev_for_each(i, 0, ldev) { - err = mlx5_eswitch_reload_ib_reps(mlx5_lag_pf(ldev, i)->dev->priv.eswitch); - if (err) - goto err_rescan_drivers; + mlx5_mpesw_metadata_cleanup(ldev); + return err; } - mlx5_lag_set_vports_agg_speed(ldev); - return 0; - -err_rescan_drivers: - dev0->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; - mlx5_rescan_drivers_locked(dev0); - mlx5_deactivate_lag(ldev); -err_add_devices: - mlx5_lag_add_devices(ldev); - mlx5_ldev_for_each(i, 0, ldev) - mlx5_eswitch_reload_ib_reps(mlx5_lag_pf(ldev, i)->dev->priv.eswitch); - mlx5_mpesw_metadata_cleanup(ldev); - return err; } void mlx5_lag_disable_mpesw(struct mlx5_lag *ldev) { if (ldev->mode == MLX5_LAG_MODE_MPESW) { mlx5_mpesw_metadata_cleanup(ldev); - mlx5_disable_lag(ldev); + mlx5_lag_shared_fdb_destroy(ldev, MLX5_LAG_FILTER_ALL); } } @@ -140,8 +118,10 @@ static void mlx5_mpesw_work(struct work_struct *work) struct mlx5_lag *ldev = mpesww->lag; devcom = mlx5_lag_get_devcom_comp(ldev); - if (!devcom) - return; + if (!devcom) { + mpesww->result = -ENODEV; + goto complete; + } mlx5_devcom_comp_lock(devcom); mutex_lock(&ldev->lock); @@ -157,6 +137,7 @@ static void mlx5_mpesw_work(struct work_struct *work) unlock: mutex_unlock(&ldev->lock); mlx5_devcom_comp_unlock(devcom); +complete: complete(&mpesww->comp); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c new file mode 100644 index 000000000000..b72e8659a968 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ + +#include <linux/netdevice.h> +#include <linux/mlx5/driver.h> +#include <linux/mlx5/eswitch.h> +#include "mlx5_core.h" +#include "lag.h" +#include "eswitch.h" + +bool mlx5_lag_shared_fdb_supported_filter(struct mlx5_lag *ldev, u32 filter) +{ + int idx = mlx5_lag_get_dev_index_by_seq_filter(ldev, MLX5_LAG_P1, + filter); + struct mlx5_core_dev *dev0, *dev; + bool ret = false; + int i; + + if (idx < 0) + return false; + + dev0 = mlx5_lag_pf(ldev, idx)->dev; + mlx5_lag_for_each(i, 0, ldev, filter) { + if (i == idx) + continue; + dev = mlx5_lag_pf(ldev, i)->dev; + if (is_mdev_switchdev_mode(dev) && + mlx5_eswitch_vport_match_metadata_enabled(dev->priv.eswitch) && + MLX5_CAP_GEN(dev, lag_native_fdb_selection) && + MLX5_CAP_ESW(dev, root_ft_on_other_esw) && + mlx5_eswitch_is_peer(dev0->priv.eswitch, dev->priv.eswitch)) + continue; + return false; + } + + if (is_mdev_switchdev_mode(dev0) && + mlx5_eswitch_vport_match_metadata_enabled(dev0->priv.eswitch) && + mlx5_esw_offloads_devcom_is_ready(dev0->priv.eswitch) && + MLX5_CAP_ESW(dev0, esw_shared_ingress_acl)) + ret = true; + + return ret; +} + +bool mlx5_lag_shared_fdb_supported(struct mlx5_lag *ldev) +{ + return mlx5_lag_shared_fdb_supported_filter(ldev, + MLX5_LAG_FILTER_PORTS); +} + +static int mlx5_lag_create_single_fdb_filter(struct mlx5_lag *ldev, u32 filter) +{ + int master_idx = mlx5_lag_get_dev_index_by_seq_filter(ldev, MLX5_LAG_P1, + filter); + struct mlx5_eswitch *master_esw; + struct mlx5_core_dev *dev0; + int i, j; + int err; + + if (master_idx < 0) + return -EINVAL; + + dev0 = mlx5_lag_pf(ldev, master_idx)->dev; + master_esw = dev0->priv.eswitch; + mlx5_lag_for_each(i, 0, ldev, filter) { + struct mlx5_eswitch *slave_esw; + + if (i == master_idx) + continue; + + slave_esw = mlx5_lag_pf(ldev, i)->dev->priv.eswitch; + + err = mlx5_eswitch_offloads_single_fdb_add_one(master_esw, + slave_esw, + ldev->ports); + if (err) + goto err; + } + return 0; +err: + mlx5_lag_for_each_reverse(j, i - 1, 0, ldev, filter) { + struct mlx5_eswitch *slave_esw; + + if (j == master_idx) + continue; + slave_esw = mlx5_lag_pf(ldev, j)->dev->priv.eswitch; + mlx5_eswitch_offloads_single_fdb_del_one(master_esw, slave_esw); + } + return err; +} + +static void mlx5_lag_destroy_single_fdb_filter(struct mlx5_lag *ldev, + u32 filter) +{ + int master_idx = mlx5_lag_get_dev_index_by_seq_filter(ldev, MLX5_LAG_P1, + filter); + struct mlx5_eswitch *master_esw; + struct mlx5_eswitch *peer_esw; + int i; + + if (master_idx < 0) + return; + + master_esw = mlx5_lag_pf(ldev, master_idx)->dev->priv.eswitch; + mlx5_lag_for_each(i, 0, ldev, filter) { + if (i == master_idx) + continue; + + peer_esw = mlx5_lag_pf(ldev, i)->dev->priv.eswitch; + mlx5_eswitch_offloads_single_fdb_del_one(master_esw, peer_esw); + } +} + +int mlx5_lag_create_single_fdb(struct mlx5_lag *ldev) +{ + return mlx5_lag_create_single_fdb_filter(ldev, MLX5_LAG_FILTER_ALL); +} + +void mlx5_lag_destroy_single_fdb(struct mlx5_lag *ldev) +{ + mlx5_lag_destroy_single_fdb_filter(ldev, MLX5_LAG_FILTER_ALL); +} + +/** + * mlx5_lag_shared_fdb_create - Create shared FDB LAG + * @ldev: LAG device + * @tracker: LAG tracker (NULL for SD) + * @mode: LAG mode (unused for SD) + * @group_id: SD group ID; 0 (MLX5_LAG_FILTER_PORTS) for ports LAG; + * MLX5_LAG_FILTER_ALL for all-device (mpesw) LAG + * + * When group_id is 0 (MLX5_LAG_FILTER_PORTS) or MLX5_LAG_FILTER_ALL, + * activates a FW LAG with shared FDB. + * When group_id is a specific SD group ID, creates a software-only shared + * FDB scoped to that group (no FW LAG commands). + * + * Return: 0 on success, negative error code on failure. + */ +int mlx5_lag_shared_fdb_create(struct mlx5_lag *ldev, + struct lag_tracker *tracker, + enum mlx5_lag_mode mode, + u32 group_id) +{ + u32 filter = group_id ? group_id : MLX5_LAG_FILTER_PORTS; + int idx = mlx5_lag_get_dev_index_by_seq_filter(ldev, MLX5_LAG_P1, + filter); + struct mlx5_core_dev *dev0; + struct lag_func *pf; + int err; + int i; + + if (idx < 0) + return -EINVAL; + + dev0 = mlx5_lag_pf(ldev, idx)->dev; + + mlx5_lag_remove_devices_filter(ldev, filter); + + if (filter == MLX5_LAG_FILTER_PORTS || filter == MLX5_LAG_FILTER_ALL) { + err = mlx5_activate_lag(ldev, tracker, mode, true); + if (err) { + mlx5_core_warn(dev0, + "Failed to create LAG in shared FDB mode (%d)\n", + err); + goto err_add_devices; + } + } else { + err = mlx5_lag_create_single_fdb_filter(ldev, group_id); + if (err) { + mlx5_core_warn(dev0, + "Failed to create SD shared FDB (%d)\n", + err); + goto err_add_devices; + } + mlx5_lag_for_each(i, 0, ldev, filter) { + pf = mlx5_lag_pf(ldev, i); + pf->sd_fdb_active = true; + } + BLOCKING_INIT_NOTIFIER_HEAD(&dev0->priv.lag_nh); + } + + mlx5_lag_rescan_dev_locked(ldev, dev0, true); + err = mlx5_lag_reload_ib_reps_from_locked(ldev, 0, filter, false); + if (err) { + mlx5_core_err(dev0, "Failed to enable lag\n"); + goto err_rescan_drivers; + } + + if (filter == MLX5_LAG_FILTER_PORTS || filter == MLX5_LAG_FILTER_ALL) + mlx5_lag_set_vports_agg_speed(ldev); + return 0; + +err_rescan_drivers: + mlx5_lag_rescan_dev_locked(ldev, dev0, false); + if (filter == MLX5_LAG_FILTER_PORTS || filter == MLX5_LAG_FILTER_ALL) { + mlx5_deactivate_lag(ldev); + } else { + mlx5_lag_for_each(i, 0, ldev, filter) { + pf = mlx5_lag_pf(ldev, i); + pf->sd_fdb_active = false; + } + mlx5_lag_destroy_single_fdb_filter(ldev, group_id); + } +err_add_devices: + mlx5_lag_add_devices_filter(ldev, filter); + mlx5_lag_reload_ib_reps_from_locked(ldev, 0, filter, true); + return err; +} + +void mlx5_lag_shared_fdb_destroy(struct mlx5_lag *ldev, u32 group_id) +{ + u32 filter = group_id ? group_id : MLX5_LAG_FILTER_PORTS; + struct lag_func *pf; + int err; + int i; + + mlx5_lag_remove_devices_filter(ldev, filter); + + if (filter == MLX5_LAG_FILTER_PORTS || filter == MLX5_LAG_FILTER_ALL) { + err = mlx5_deactivate_lag(ldev); + if (err) + return; + } else { + mlx5_lag_for_each(i, 0, ldev, filter) { + pf = mlx5_lag_pf(ldev, i); + pf->sd_fdb_active = false; + } + mlx5_lag_destroy_single_fdb_filter(ldev, group_id); + } + + mlx5_lag_add_devices_filter(ldev, filter); + mlx5_lag_reload_ib_reps_from_locked(ldev, + MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV, + filter, true); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c index 4b5ac2db55ce..d40c53193ea8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c @@ -3,6 +3,7 @@ #include <linux/mlx5/vport.h> #include <linux/list.h> +#include <linux/lockdep.h> #include "lib/devcom.h" #include "lib/mlx5.h" #include "mlx5_core.h" @@ -438,3 +439,10 @@ int mlx5_devcom_comp_trylock(struct mlx5_devcom_comp_dev *devcom) return 0; return down_write_trylock(&devcom->comp->sem); } + +void mlx5_devcom_comp_assert_locked(struct mlx5_devcom_comp_dev *devcom) +{ + if (!devcom) + return; + lockdep_assert_held_write(&devcom->comp->sem); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h index 91e5ae529d5c..316052a85ca5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h @@ -75,5 +75,6 @@ void *mlx5_devcom_get_next_peer_data_rcu(struct mlx5_devcom_comp_dev *devcom, void mlx5_devcom_comp_lock(struct mlx5_devcom_comp_dev *devcom); void mlx5_devcom_comp_unlock(struct mlx5_devcom_comp_dev *devcom); int mlx5_devcom_comp_trylock(struct mlx5_devcom_comp_dev *devcom); +void mlx5_devcom_comp_assert_locked(struct mlx5_devcom_comp_dev *devcom); #endif /* __LIB_MLX5_DEVCOM_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.c index d6dc7bce855e..305752dab7bd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.c @@ -190,7 +190,7 @@ mlx5_hv_vhca_control_agent_create(struct mlx5_hv_vhca *hv_vhca) return mlx5_hv_vhca_agent_create(hv_vhca, MLX5_HV_VHCA_AGENT_CONTROL, NULL, mlx5_hv_vhca_control_agent_invalidate, - NULL, NULL); + NULL, NULL, NULL); } static void mlx5_hv_vhca_control_agent_destroy(struct mlx5_hv_vhca_agent *agent) @@ -256,7 +256,8 @@ mlx5_hv_vhca_agent_create(struct mlx5_hv_vhca *hv_vhca, void (*invalidate)(struct mlx5_hv_vhca_agent*, u64 block_mask), void (*cleaup)(struct mlx5_hv_vhca_agent *agent), - void *priv) + void *priv, + struct mlx5_hv_vhca_agent **ctx_update) { struct mlx5_hv_vhca_agent *agent; @@ -284,6 +285,9 @@ mlx5_hv_vhca_agent_create(struct mlx5_hv_vhca *hv_vhca, agent->invalidate = invalidate; agent->cleanup = cleaup; + if (ctx_update) + WRITE_ONCE(*ctx_update, agent); + mutex_lock(&hv_vhca->agents_lock); hv_vhca->agents[type] = agent; mutex_unlock(&hv_vhca->agents_lock); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.h index f240ffe5116c..8b3974cf0ee4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.h @@ -43,7 +43,8 @@ mlx5_hv_vhca_agent_create(struct mlx5_hv_vhca *hv_vhca, void (*invalidate)(struct mlx5_hv_vhca_agent*, u64 block_mask), void (*cleanup)(struct mlx5_hv_vhca_agent *agent), - void *context); + void *context, + struct mlx5_hv_vhca_agent **ctx_update); void mlx5_hv_vhca_agent_destroy(struct mlx5_hv_vhca_agent *agent); int mlx5_hv_vhca_agent_write(struct mlx5_hv_vhca_agent *agent, @@ -84,7 +85,8 @@ mlx5_hv_vhca_agent_create(struct mlx5_hv_vhca *hv_vhca, void (*invalidate)(struct mlx5_hv_vhca_agent*, u64 block_mask), void (*cleanup)(struct mlx5_hv_vhca_agent *agent), - void *context) + void *context, + struct mlx5_hv_vhca_agent **ctx_update) { return NULL; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c index 4571c56ec3c9..97f6097d4c70 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c @@ -176,7 +176,8 @@ void mlx5_tun_entropy_refcount_dec(struct mlx5_tun_entropy *tun_entropy, int reformat_type) { mutex_lock(&tun_entropy->lock); - if (reformat_type == MLX5_REFORMAT_TYPE_L2_TO_VXLAN) + if (reformat_type == MLX5_REFORMAT_TYPE_L2_TO_VXLAN || + reformat_type == MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL) tun_entropy->num_enabling_entries--; else if (reformat_type == MLX5_REFORMAT_TYPE_L2_TO_NVGRE && --tun_entropy->num_disabling_entries == 0) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/sd.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/sd.c index 6e199161b008..bbd77ae11e84 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/sd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/sd.c @@ -57,6 +57,16 @@ static struct mlx5_core_dev *mlx5_sd_get_primary(struct mlx5_core_dev *dev) return sd->primary ? dev : sd->primary_dev; } +struct mlx5_devcom_comp_dev *mlx5_sd_get_devcom(struct mlx5_core_dev *dev) +{ + struct mlx5_sd *sd = mlx5_get_sd(dev); + + if (!sd) + return NULL; + + return sd->devcom; +} + struct mlx5_core_dev * mlx5_sd_primary_get_peer(struct mlx5_core_dev *primary, int idx) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/sd.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/sd.h index 9bfd5b9756b5..2ab259095d7e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/sd.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/sd.h @@ -21,6 +21,16 @@ void mlx5_sd_put_adev(struct auxiliary_device *actual_adev, int mlx5_sd_init(struct mlx5_core_dev *dev); void mlx5_sd_cleanup(struct mlx5_core_dev *dev); +#ifdef CONFIG_MLX5_CORE_EN +struct mlx5_devcom_comp_dev *mlx5_sd_get_devcom(struct mlx5_core_dev *dev); +#else +static inline struct mlx5_devcom_comp_dev * +mlx5_sd_get_devcom(struct mlx5_core_dev *dev) +{ + return NULL; +} +#endif + #define mlx5_sd_for_each_dev_from_to(i, primary, ix_from, to, pos) \ for (i = ix_from; \ (pos = mlx5_sd_primary_get_peer(primary, i)) && pos != (to); i++) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/st.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/st.c index 997be91f0a13..7cedc348790d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/st.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/st.c @@ -175,6 +175,7 @@ int mlx5_st_dealloc_index(struct mlx5_core_dev *dev, u16 st_index) if (refcount_dec_and_test(&idx_data->usecount)) { xa_erase(&st->idx_xa, st_index); + kfree(idx_data); /* We leave PCI config space as was before, no mkey will refer to it */ } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 74827e8ca125..37af619e5e04 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -527,7 +527,6 @@ static int handle_hca_cap(struct mlx5_core_dev *dev, void *set_ctx) { struct mlx5_profile *prof = &dev->profile; void *set_hca_cap; - int max_uc_list; int err; err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL); @@ -610,10 +609,13 @@ static int handle_hca_cap(struct mlx5_core_dev *dev, void *set_ctx) MLX5_SET(cmd_hca_cap, set_hca_cap, roce, mlx5_is_roce_on(dev)); - max_uc_list = max_uc_list_get_devlink_param(dev); - if (max_uc_list > 0) - MLX5_SET(cmd_hca_cap, set_hca_cap, log_max_current_uc_list, - ilog2(max_uc_list)); + if (MLX5_CAP_GEN_MAX(dev, log_max_current_uc_list)) { + int max_uc_list = max_uc_list_get_devlink_param(dev); + + if (max_uc_list > 0) + MLX5_SET(cmd_hca_cap, set_hca_cap, + log_max_current_uc_list, ilog2(max_uc_list)); + } /* enable absolute native port num */ if (MLX5_CAP_GEN_MAX(dev, abs_native_port_num)) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c index 6dcd9c2a78aa..e60435eaebc5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c @@ -205,6 +205,7 @@ static int hws_bwc_matcher_move(struct mlx5hws_bwc_matcher *bwc_matcher) ret = mlx5hws_matcher_resize_set_target(old_matcher, new_matcher); if (ret) { mlx5hws_err(ctx, "Rehash error: failed setting resize target\n"); + mlx5hws_matcher_destroy(new_matcher); return ret; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 3a65420fa1ad..fed708c17332 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4360,7 +4360,7 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, lag_id = lag->lag_id; err = mlxsw_sp_port_lag_index_get(mlxsw_sp, lag_id, &port_index); if (err) - return err; + goto err_lag_uppers_bridge_join; err = mlxsw_sp_lag_uppers_bridge_join(mlxsw_sp_port, lag_dev, extack); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 7bd87d0547d8..3d6fdbab05e0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -1018,6 +1018,7 @@ static int mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp, err_tree_replace: for (i--; i >= 0; i--) { + vr = &mlxsw_sp->router->vrs[i]; if (!mlxsw_sp_vr_lpm_tree_should_replace(vr, proto, new_id)) continue; mlxsw_sp_vr_lpm_tree_replace(mlxsw_sp, diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c index 0c6812fcf185..283d25fae79e 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c @@ -526,15 +526,10 @@ int fbnic_fw_xmit_ownership_msg(struct fbnic_dev *fbd, bool take_ownership) goto free_message; } - err = fbnic_mbx_map_tlv_msg(fbd, msg); - if (err) - goto free_message; - /* Initialize heartbeat, set last response to 1 second in the past * so that we will trigger a timeout if the firmware doesn't respond */ fbd->last_heartbeat_response = req_time - HZ; - fbd->last_heartbeat_request = req_time; /* Set prev_firmware_time to 0 to avoid triggering firmware crash @@ -542,6 +537,10 @@ int fbnic_fw_xmit_ownership_msg(struct fbnic_dev *fbd, bool take_ownership) */ fbd->prev_firmware_time = 0; + err = fbnic_mbx_map_tlv_msg(fbd, msg); + if (err) + goto free_message; + /* Set heartbeat detection based on if we are taking ownership */ fbd->fw_heartbeat_enabled = take_ownership; diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c index 4dea2bb58d2f..44c046b25312 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c @@ -262,8 +262,11 @@ static int fbnic_set_mac(struct net_device *netdev, void *p) eth_hw_addr_set(netdev, addr->sa_data); - if (netif_running(netdev)) + if (netif_running(netdev)) { + netif_addr_lock_bh(netdev); __fbnic_set_rx_mode(fbn->fbd, &netdev->uc, &netdev->mc); + netif_addr_unlock_bh(netdev); + } return 0; } @@ -308,8 +311,10 @@ void fbnic_clear_rx_mode(struct fbnic_dev *fbd) /* Write updates to hardware */ fbnic_write_macda(fbd); + netif_addr_lock_bh(netdev); __dev_uc_unsync(netdev, NULL); __dev_mc_unsync(netdev, NULL); + netif_addr_unlock_bh(netdev); } static int fbnic_hwtstamp_get(struct net_device *netdev, diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c index 7e85b480203c..8b9bc9e8ea56 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c @@ -135,7 +135,9 @@ void fbnic_up(struct fbnic_net *fbn) fbnic_rss_reinit_hw(fbn->fbd, fbn); + netif_addr_lock_bh(fbn->netdev); __fbnic_set_rx_mode(fbn->fbd, &fbn->netdev->uc, &fbn->netdev->mc); + netif_addr_unlock_bh(fbn->netdev); /* Enable Tx/Rx processing */ fbnic_napi_enable(fbn); @@ -180,7 +182,9 @@ static int fbnic_fw_config_after_crash(struct fbnic_dev *fbd) } fbnic_rpc_reset_valid_entries(fbd); + netif_addr_lock_bh(fbd->netdev); __fbnic_set_rx_mode(fbd, &fbd->netdev->uc, &fbd->netdev->mc); + netif_addr_unlock_bh(fbd->netdev); return 0; } diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c b/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c index fe95b6f69646..bc0f38b6a2b2 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c @@ -244,7 +244,9 @@ void fbnic_bmc_rpc_check(struct fbnic_dev *fbd) if (fbd->fw_cap.need_bmc_tcam_reinit) { fbnic_bmc_rpc_init(fbd); + netif_addr_lock_bh(fbd->netdev); __fbnic_set_rx_mode(fbd, &fbd->netdev->uc, &fbd->netdev->mc); + netif_addr_unlock_bh(fbd->netdev); fbd->fw_cap.need_bmc_tcam_reinit = false; } diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c index 9cd85a0d0c3a..401f8b8ae1ca 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c @@ -194,16 +194,18 @@ static bool fbnic_tx_tstamp(struct sk_buff *skb) static bool fbnic_tx_lso(struct fbnic_ring *ring, struct sk_buff *skb, - struct skb_shared_info *shinfo, __le64 *meta, - unsigned int *l2len, unsigned int *i3len) + __le64 *meta, unsigned int *l2len, unsigned int *i3len) { unsigned int l3_type, l4_type, l4len, hdrlen; + struct skb_shared_info *shinfo; unsigned char *l4hdr; __be16 payload_len; if (unlikely(skb_cow_head(skb, 0))) return true; + shinfo = skb_shinfo(skb); + if (shinfo->gso_type & SKB_GSO_PARTIAL) { l3_type = FBNIC_TWD_L3_TYPE_OTHER; } else if (!skb->encapsulation) { @@ -258,7 +260,6 @@ fbnic_tx_lso(struct fbnic_ring *ring, struct sk_buff *skb, static bool fbnic_tx_offloads(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta) { - struct skb_shared_info *shinfo = skb_shinfo(skb); unsigned int l2len, i3len; if (fbnic_tx_tstamp(skb)) @@ -273,8 +274,8 @@ fbnic_tx_offloads(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta) *meta |= cpu_to_le64(FIELD_PREP(FBNIC_TWD_CSUM_OFFSET_MASK, skb->csum_offset / 2)); - if (shinfo->gso_size) { - if (fbnic_tx_lso(ring, skb, shinfo, meta, &l2len, &i3len)) + if (skb_is_gso(skb)) { + if (fbnic_tx_lso(ring, skb, meta, &l2len, &i3len)) return true; } else { *meta |= cpu_to_le64(FBNIC_TWD_FLAG_REQ_CSO); diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c index ffac22883e49..95257c2bc451 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.c +++ b/drivers/net/ethernet/microchip/lan743x_main.c @@ -3542,8 +3542,8 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter, adapter->max_tx_channels = PCI11X1X_MAX_TX_CHANNELS; adapter->used_tx_channels = PCI11X1X_USED_TX_CHANNELS; adapter->max_vector_count = PCI11X1X_MAX_VECTOR_COUNT; - pci11x1x_strap_get_status(adapter); spin_lock_init(&adapter->eth_syslock_spinlock); + pci11x1x_strap_get_status(adapter); mutex_init(&adapter->sgmii_rw_lock); pci11x1x_set_rfe_rd_fifo_threshold(adapter); sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL); diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c b/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c index 72e3b189bac5..eb28df80b281 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c @@ -601,7 +601,6 @@ static void lan966x_vcap_admin_free(struct vcap_admin *admin) kfree(admin->cache.keystream); kfree(admin->cache.maskstream); kfree(admin->cache.actionstream); - mutex_destroy(&admin->lock); kfree(admin); } @@ -615,7 +614,7 @@ lan966x_vcap_admin_alloc(struct lan966x *lan966x, struct vcap_control *ctrl, if (!admin) return ERR_PTR(-ENOMEM); - mutex_init(&admin->lock); + admin->vctrl = ctrl; INIT_LIST_HEAD(&admin->list); INIT_LIST_HEAD(&admin->rules); INIT_LIST_HEAD(&admin->enabled); @@ -721,6 +720,7 @@ int lan966x_vcap_init(struct lan966x *lan966x) ctrl->ops = &lan966x_vcap_ops; INIT_LIST_HEAD(&ctrl->list); + mutex_init(&ctrl->lock); for (int i = 0; i < ARRAY_SIZE(lan966x_vcap_inst_cfg); ++i) { cfg = &lan966x_vcap_inst_cfg[i]; @@ -780,5 +780,6 @@ void lan966x_vcap_deinit(struct lan966x *lan966x) lan966x_vcap_admin_free(admin); } + mutex_destroy(&ctrl->lock); kfree(ctrl); } diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c b/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c index 644458108dd2..dac4dd833127 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c @@ -765,11 +765,13 @@ int sparx5_register_notifier_blocks(struct sparx5 *s5) sparx5_owq = alloc_ordered_workqueue("sparx5_order", 0); if (!sparx5_owq) { err = -ENOMEM; - goto err_switchdev_blocking_nb; + goto err_alloc_workqueue; } return 0; +err_alloc_workqueue: + unregister_switchdev_blocking_notifier(&s5->switchdev_blocking_nb); err_switchdev_blocking_nb: unregister_switchdev_notifier(&s5->switchdev_nb); err_switchdev_nb: diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c index 95b93e46a41d..cf332de6bf73 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c @@ -1930,7 +1930,6 @@ static void sparx5_vcap_admin_free(struct vcap_admin *admin) { if (!admin) return; - mutex_destroy(&admin->lock); kfree(admin->cache.keystream); kfree(admin->cache.maskstream); kfree(admin->cache.actionstream); @@ -1950,7 +1949,7 @@ sparx5_vcap_admin_alloc(struct sparx5 *sparx5, struct vcap_control *ctrl, INIT_LIST_HEAD(&admin->list); INIT_LIST_HEAD(&admin->rules); INIT_LIST_HEAD(&admin->enabled); - mutex_init(&admin->lock); + admin->vctrl = ctrl; admin->vtype = cfg->vtype; admin->vinst = cfg->vinst; admin->ingress = cfg->ingress; @@ -2059,6 +2058,7 @@ int sparx5_vcap_init(struct sparx5 *sparx5) ctrl->ops = &sparx5_vcap_ops; INIT_LIST_HEAD(&ctrl->list); + mutex_init(&ctrl->lock); for (idx = 0; idx < ARRAY_SIZE(sparx5_vcap_inst_cfg); ++idx) { cfg = &consts->vcaps_cfg[idx]; admin = sparx5_vcap_admin_alloc(sparx5, ctrl, cfg); @@ -2097,5 +2097,6 @@ void sparx5_vcap_deinit(struct sparx5 *sparx5) list_del(&admin->list); sparx5_vcap_admin_free(admin); } + mutex_destroy(&ctrl->lock); kfree(ctrl); } diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c index 0fdb5e363bad..ff86cde11a32 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c @@ -934,6 +934,16 @@ static bool vcap_rule_exists(struct vcap_control *vctrl, u32 id) return false; } +void vcap_lock(struct vcap_admin *admin) +{ + mutex_lock(&admin->vctrl->lock); +} + +void vcap_unlock(struct vcap_admin *admin) +{ + mutex_unlock(&admin->vctrl->lock); +} + /* Find a rule with a provided rule id return a locked vcap */ static struct vcap_rule_internal * vcap_get_locked_rule(struct vcap_control *vctrl, u32 id) @@ -943,11 +953,11 @@ vcap_get_locked_rule(struct vcap_control *vctrl, u32 id) /* Look for the rule id in all vcaps */ list_for_each_entry(admin, &vctrl->list, list) { - mutex_lock(&admin->lock); + vcap_lock(admin); list_for_each_entry(ri, &admin->rules, list) if (ri->data.id == id) return ri; - mutex_unlock(&admin->lock); + vcap_unlock(admin); } return NULL; } @@ -961,14 +971,14 @@ int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie) /* Look for the rule id in all vcaps */ list_for_each_entry(admin, &vctrl->list, list) { - mutex_lock(&admin->lock); + vcap_lock(admin); list_for_each_entry(ri, &admin->rules, list) { if (ri->data.cookie == cookie) { id = ri->data.id; break; } } - mutex_unlock(&admin->lock); + vcap_unlock(admin); if (id) return id; } @@ -985,11 +995,11 @@ int vcap_admin_rule_count(struct vcap_admin *admin, int cid) int count = 0; list_for_each_entry(elem, &admin->rules, list) { - mutex_lock(&admin->lock); + vcap_lock(admin); if (elem->data.vcap_chain_id >= min_cid && elem->data.vcap_chain_id < max_cid) ++count; - mutex_unlock(&admin->lock); + vcap_unlock(admin); } return count; } @@ -2266,7 +2276,7 @@ int vcap_add_rule(struct vcap_rule *rule) if (ret) return ret; /* Insert the new rule in the list of vcap rules */ - mutex_lock(&ri->admin->lock); + vcap_lock(ri->admin); vcap_rule_set_state(ri); ret = vcap_insert_rule(ri, &move); @@ -2302,7 +2312,7 @@ int vcap_add_rule(struct vcap_rule *rule) goto out; } out: - mutex_unlock(&ri->admin->lock); + vcap_unlock(ri->admin); return ret; } EXPORT_SYMBOL_GPL(vcap_add_rule); @@ -2330,7 +2340,7 @@ struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl, if (vctrl->vcaps[admin->vtype].rows == 0) return ERR_PTR(-EINVAL); - mutex_lock(&admin->lock); + vcap_lock(admin); /* Check if a rule with this id already exists */ if (vcap_rule_exists(vctrl, id)) { err = -EINVAL; @@ -2369,13 +2379,13 @@ struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl, goto out_free; } - mutex_unlock(&admin->lock); + vcap_unlock(admin); return (struct vcap_rule *)ri; out_free: kfree(ri); out_unlock: - mutex_unlock(&admin->lock); + vcap_unlock(admin); return ERR_PTR(err); } @@ -2446,7 +2456,7 @@ struct vcap_rule *vcap_get_rule(struct vcap_control *vctrl, u32 id) return ERR_PTR(-ENOENT); rule = vcap_decode_rule(elem); - mutex_unlock(&elem->admin->lock); + vcap_unlock(elem->admin); return rule; } EXPORT_SYMBOL_GPL(vcap_get_rule); @@ -2483,7 +2493,7 @@ int vcap_mod_rule(struct vcap_rule *rule) err = vcap_write_counter(ri, &ctr); out: - mutex_unlock(&ri->admin->lock); + vcap_unlock(ri->admin); return err; } EXPORT_SYMBOL_GPL(vcap_mod_rule); @@ -2570,7 +2580,7 @@ int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id) admin->last_used_addr = elem->addr; } - mutex_unlock(&admin->lock); + vcap_unlock(admin); return err; } EXPORT_SYMBOL_GPL(vcap_del_rule); @@ -2585,7 +2595,7 @@ int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin) if (ret) return ret; - mutex_lock(&admin->lock); + vcap_lock(admin); list_for_each_entry_safe(ri, next_ri, &admin->rules, list) { vctrl->ops->init(ri->ndev, admin, ri->addr, ri->size); list_del(&ri->list); @@ -2598,7 +2608,7 @@ int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin) list_del(&eport->list); kfree(eport); } - mutex_unlock(&admin->lock); + vcap_unlock(admin); return 0; } @@ -3016,7 +3026,7 @@ static int vcap_enable_rules(struct vcap_control *vctrl, continue; /* Found the admin, now find the offloadable rules */ - mutex_lock(&admin->lock); + vcap_lock(admin); list_for_each_entry(ri, &admin->rules, list) { /* Is the rule in the lookup defined by the chain */ if (!(ri->data.vcap_chain_id >= chain && @@ -3034,7 +3044,7 @@ static int vcap_enable_rules(struct vcap_control *vctrl, if (err) break; } - mutex_unlock(&admin->lock); + vcap_unlock(admin); if (err) break; } @@ -3074,7 +3084,7 @@ static int vcap_disable_rules(struct vcap_control *vctrl, continue; /* Found the admin, now find the rules on the chain */ - mutex_lock(&admin->lock); + vcap_lock(admin); list_for_each_entry(ri, &admin->rules, list) { if (ri->data.vcap_chain_id != chain) continue; @@ -3089,7 +3099,7 @@ static int vcap_disable_rules(struct vcap_control *vctrl, if (err) break; } - mutex_unlock(&admin->lock); + vcap_unlock(admin); if (err) break; } @@ -3133,9 +3143,9 @@ static int vcap_enable(struct vcap_control *vctrl, struct net_device *ndev, eport->cookie = cookie; eport->src_cid = src_cid; eport->dst_cid = dst_cid; - mutex_lock(&admin->lock); + vcap_lock(admin); list_add_tail(&eport->list, &admin->enabled); - mutex_unlock(&admin->lock); + vcap_unlock(admin); if (vcap_path_exist(vctrl, ndev, src_cid)) { /* Enable chained lookups */ @@ -3185,9 +3195,9 @@ static int vcap_disable(struct vcap_control *vctrl, struct net_device *ndev, dst_cid = vcap_get_next_chain(vctrl, ndev, dst_cid); } - mutex_lock(&found->lock); + vcap_lock(found); list_del(&eport->list); - mutex_unlock(&found->lock); + vcap_unlock(found); kfree(eport); return 0; } @@ -3270,9 +3280,9 @@ int vcap_rule_set_counter(struct vcap_rule *rule, struct vcap_counter *ctr) return -EINVAL; } - mutex_lock(&ri->admin->lock); + vcap_lock(ri->admin); err = vcap_write_counter(ri, ctr); - mutex_unlock(&ri->admin->lock); + vcap_unlock(ri->admin); return err; } @@ -3291,9 +3301,9 @@ int vcap_rule_get_counter(struct vcap_rule *rule, struct vcap_counter *ctr) return -EINVAL; } - mutex_lock(&ri->admin->lock); + vcap_lock(ri->admin); err = vcap_read_counter(ri, ctr); - mutex_unlock(&ri->admin->lock); + vcap_unlock(ri->admin); return err; } @@ -3395,7 +3405,7 @@ int vcap_get_rule_count_by_cookie(struct vcap_control *vctrl, /* Iterate all rules in each VCAP instance */ list_for_each_entry(admin, &vctrl->list, list) { - mutex_lock(&admin->lock); + vcap_lock(admin); list_for_each_entry(ri, &admin->rules, list) { if (ri->data.cookie != cookie) continue; @@ -3412,12 +3422,12 @@ int vcap_get_rule_count_by_cookie(struct vcap_control *vctrl, if (err) goto unlock; } - mutex_unlock(&admin->lock); + vcap_unlock(admin); } return err; unlock: - mutex_unlock(&admin->lock); + vcap_unlock(admin); return err; } EXPORT_SYMBOL_GPL(vcap_get_rule_count_by_cookie); diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.h b/drivers/net/ethernet/microchip/vcap/vcap_api.h index 6069ad95c27e..05b4b02e59ef 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api.h +++ b/drivers/net/ethernet/microchip/vcap/vcap_api.h @@ -164,7 +164,7 @@ struct vcap_admin { struct list_head list; /* for insertion in vcap_control */ struct list_head rules; /* list of rules */ struct list_head enabled; /* list of enabled ports */ - struct mutex lock; /* control access to rules */ + struct vcap_control *vctrl; /* the control instance owning this vcap */ enum vcap_type vtype; /* type of vcap */ int vinst; /* instance number within the same type */ int first_cid; /* first chain id in this vcap */ @@ -275,6 +275,7 @@ struct vcap_control { const struct vcap_info *vcaps; /* client supplied vcap models */ const struct vcap_statistics *stats; /* client supplied vcap stats */ struct list_head list; /* list of vcap instances */ + struct mutex lock; /* serialize access to all vcap instances */ }; #endif /* __VCAP_API__ */ diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c b/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c index 59bfbda29bb3..e0c65c7ab23e 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c @@ -410,9 +410,9 @@ static int vcap_debugfs_show(struct seq_file *m, void *unused) }; int ret; - mutex_lock(&info->admin->lock); + vcap_lock(info->admin); ret = vcap_show_admin(info->vctrl, info->admin, &out); - mutex_unlock(&info->admin->lock); + vcap_unlock(info->admin); return ret; } DEFINE_SHOW_ATTRIBUTE(vcap_debugfs); @@ -427,9 +427,9 @@ static int vcap_raw_debugfs_show(struct seq_file *m, void *unused) }; int ret; - mutex_lock(&info->admin->lock); + vcap_lock(info->admin); ret = vcap_show_admin_raw(info->vctrl, info->admin, &out); - mutex_unlock(&info->admin->lock); + vcap_unlock(info->admin); return ret; } DEFINE_SHOW_ATTRIBUTE(vcap_raw_debugfs); diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs_kunit.c b/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs_kunit.c index 9c9d38042125..ac2a3b8c4f32 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs_kunit.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs_kunit.c @@ -243,10 +243,11 @@ static void vcap_test_api_init(struct vcap_admin *admin) { /* Initialize the shared objects */ INIT_LIST_HEAD(&test_vctrl.list); + mutex_init(&test_vctrl.lock); INIT_LIST_HEAD(&admin->list); INIT_LIST_HEAD(&admin->rules); INIT_LIST_HEAD(&admin->enabled); - mutex_init(&admin->lock); + admin->vctrl = &test_vctrl; list_add_tail(&admin->list, &test_vctrl.list); memset(test_updateaddr, 0, sizeof(test_updateaddr)); test_updateaddridx = 0; diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c index ce26ccbdccdf..83de384d3e3b 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c @@ -233,10 +233,11 @@ static void vcap_test_api_init(struct vcap_admin *admin) { /* Initialize the shared objects */ INIT_LIST_HEAD(&test_vctrl.list); + mutex_init(&test_vctrl.lock); INIT_LIST_HEAD(&admin->list); INIT_LIST_HEAD(&admin->rules); INIT_LIST_HEAD(&admin->enabled); - mutex_init(&admin->lock); + admin->vctrl = &test_vctrl; list_add_tail(&admin->list, &test_vctrl.list); memset(test_updateaddr, 0, sizeof(test_updateaddr)); test_updateaddridx = 0; diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_private.h b/drivers/net/ethernet/microchip/vcap/vcap_api_private.h index 844bdf6b5f45..b4057fbe3d18 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_private.h +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_private.h @@ -50,6 +50,9 @@ struct vcap_stream_iter { /* Check that the control has a valid set of callbacks */ int vcap_api_check(struct vcap_control *ctrl); +/* Serialize access to the vcap instances of a control */ +void vcap_lock(struct vcap_admin *admin); +void vcap_unlock(struct vcap_admin *admin); /* Erase the VCAP cache area used or encoding and decoding */ void vcap_erase_cache(struct vcap_rule_internal *ri); diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c index d8e816882f02..ac71ca8450bf 100644 --- a/drivers/net/ethernet/microsoft/mana/gdma_main.c +++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c @@ -1192,6 +1192,8 @@ int mana_gd_create_mana_wq_cq(struct gdma_dev *gd, if (!queue) return -ENOMEM; + queue->id = INVALID_QUEUE_ID; + gmi = &queue->mem_info; err = mana_gd_alloc_memory(gc, spec->queue_size, gmi); if (err) { diff --git a/drivers/net/ethernet/microsoft/mana/mana_bpf.c b/drivers/net/ethernet/microsoft/mana/mana_bpf.c index 7697c9b52ed3..d59dec89a807 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_bpf.c +++ b/drivers/net/ethernet/microsoft/mana/mana_bpf.c @@ -237,7 +237,8 @@ static int mana_xdp_set(struct net_device *ndev, struct bpf_prog *prog, bpf_prog_put(old_prog); if (prog) - ndev->max_mtu = MANA_XDP_MTU_MAX; + ndev->max_mtu = min_t(unsigned int, MANA_XDP_MTU_MAX, + gc->adapter_mtu - ETH_HLEN); else ndev->max_mtu = gc->adapter_mtu - ETH_HLEN; diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c index c9b1df1ed109..352398ae0376 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_en.c +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c @@ -1215,12 +1215,24 @@ static int mana_query_device_cfg(struct mana_context *ac, u32 proto_major_ver, *max_num_vports = resp.max_num_vports; if (resp.hdr.response.msg_version >= GDMA_MESSAGE_V2) { - if (resp.adapter_mtu < ETH_MIN_MTU + ETH_HLEN) { + if (resp.adapter_mtu == 0) { + /* + * Some older PF firmware versions report an + * adapter_mtu of 0. MANA hardware always supports the + * standard Ethernet MTU, so fall back to ETH_FRAME_LEN. + * Jumbo frames will not be available in this case. + */ + dev_info(dev, + "PF reported adapter_mtu of 0, falling back to %u (jumbo frames disabled)\n", + ETH_FRAME_LEN); + gc->adapter_mtu = ETH_FRAME_LEN; + } else if (resp.adapter_mtu < ETH_MIN_MTU + ETH_HLEN) { dev_err(dev, "Adapter MTU too small: %u\n", resp.adapter_mtu); return -EPROTO; + } else { + gc->adapter_mtu = resp.adapter_mtu; } - gc->adapter_mtu = resp.adapter_mtu; } else { gc->adapter_mtu = ETH_FRAME_LEN; } @@ -2044,12 +2056,16 @@ drop: } static void *mana_get_rxfrag(struct mana_rxq *rxq, struct device *dev, - dma_addr_t *da, bool *from_pool) + dma_addr_t *da, bool *from_pool, + struct page **pp_page, u32 *dma_sync_offset) { struct page *page; u32 offset; void *va; + *from_pool = false; + *pp_page = NULL; + *dma_sync_offset = 0; /* Don't use fragments for jumbo frames or XDP where it's 1 fragment * per page. @@ -2087,31 +2103,47 @@ static void *mana_get_rxfrag(struct mana_rxq *rxq, struct device *dev, va = page_to_virt(page) + offset; *da = page_pool_get_dma_addr(page) + offset + rxq->headroom; *from_pool = true; + *pp_page = page; + *dma_sync_offset = offset + rxq->headroom; return va; } /* Allocate frag for rx buffer, and save the old buf */ static void mana_refill_rx_oob(struct device *dev, struct mana_rxq *rxq, - struct mana_recv_buf_oob *rxoob, void **old_buf, - bool *old_fp) + struct mana_recv_buf_oob *rxoob, u32 pktlen, + void **old_buf, bool *old_fp) { + struct page *pp_page; + u32 dma_sync_offset; bool from_pool; dma_addr_t da; void *va; - va = mana_get_rxfrag(rxq, dev, &da, &from_pool); + va = mana_get_rxfrag(rxq, dev, &da, &from_pool, &pp_page, + &dma_sync_offset); if (!va) return; - if (!rxoob->from_pool || rxq->frag_count == 1) + if (!rxoob->from_pool || rxq->frag_count == 1) { dma_unmap_single(dev, rxoob->sgl[0].address, rxq->datasize, DMA_FROM_DEVICE); + } else { + /* The page pool maps the whole page and only syncs for device + * automatically (PP_FLAG_DMA_SYNC_DEV). Sync the received bytes + * for the CPU before they are read: this is required if DMA + * is incoherent or bounce buffers are used. + */ + page_pool_dma_sync_for_cpu(rxq->page_pool, rxoob->pp_page, + rxoob->dma_sync_offset, pktlen); + } *old_buf = rxoob->buf_va; *old_fp = rxoob->from_pool; rxoob->buf_va = va; rxoob->sgl[0].address = da; rxoob->from_pool = from_pool; + rxoob->pp_page = pp_page; + rxoob->dma_sync_offset = dma_sync_offset; } static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq, @@ -2170,12 +2202,26 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq, rxbuf_oob = &rxq->rx_oobs[curr]; WARN_ON_ONCE(rxbuf_oob->wqe_inf.wqe_size_in_bu != 1); - mana_refill_rx_oob(dev, rxq, rxbuf_oob, &old_buf, &old_fp); + if (unlikely(pktlen > rxq->datasize)) { + /* Increase it even if mana_rx_skb() isn't called. */ + rxq->rx_cq.work_done++; - /* Unsuccessful refill will have old_buf == NULL. - * In this case, mana_rx_skb() will drop the packet. - */ - mana_rx_skb(old_buf, old_fp, oob, rxq, i); + ++ndev->stats.rx_dropped; + netdev_warn_once(ndev, + "Dropped oversized RX packet: len=%u, datasize=%u\n", + pktlen, rxq->datasize); + + /* Reuse the RX buffer since rxbuf_oob is unchanged. */ + } else { + + mana_refill_rx_oob(dev, rxq, rxbuf_oob, pktlen, + &old_buf, &old_fp); + + /* Unsuccessful refill will have old_buf == NULL. + * In this case, mana_rx_skb() will drop the packet. + */ + mana_rx_skb(old_buf, old_fp, oob, rxq, i); + } mana_move_wq_tail(rxq->gdma_rq, rxbuf_oob->wqe_inf.wqe_size_in_bu); @@ -2334,7 +2380,8 @@ static void mana_destroy_txq(struct mana_port_context *apc) netif_napi_del_locked(napi); apc->tx_qp[i].txq.napi_initialized = false; } - mana_destroy_wq_obj(apc, GDMA_SQ, apc->tx_qp[i].tx_object); + if (apc->tx_qp[i].tx_object != INVALID_MANA_HANDLE) + mana_destroy_wq_obj(apc, GDMA_SQ, apc->tx_qp[i].tx_object); mana_deinit_cq(apc, &apc->tx_qp[i].tx_cq); @@ -2566,6 +2613,8 @@ static int mana_fill_rx_oob(struct mana_recv_buf_oob *rx_oob, u32 mem_key, struct mana_rxq *rxq, struct device *dev) { struct mana_port_context *mpc = netdev_priv(rxq->ndev); + struct page *pp_page = NULL; + u32 dma_sync_offset = 0; bool from_pool = false; dma_addr_t da; void *va; @@ -2573,13 +2622,16 @@ static int mana_fill_rx_oob(struct mana_recv_buf_oob *rx_oob, u32 mem_key, if (mpc->rxbufs_pre) va = mana_get_rxbuf_pre(rxq, &da); else - va = mana_get_rxfrag(rxq, dev, &da, &from_pool); + va = mana_get_rxfrag(rxq, dev, &da, &from_pool, &pp_page, + &dma_sync_offset); if (!va) return -ENOMEM; rx_oob->buf_va = va; rx_oob->from_pool = from_pool; + rx_oob->pp_page = pp_page; + rx_oob->dma_sync_offset = dma_sync_offset; rx_oob->sgl[0].address = da; rx_oob->sgl[0].size = rxq->datasize; diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx.c b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx.c index de5e29230b3c..c46408698263 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx.c +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx.c @@ -166,18 +166,23 @@ static void mucse_mbx_inc_pf_ack(struct mucse_hw *hw) * * Return: 0 on success, negative errno on failure **/ -static int mucse_read_mbx_pf(struct mucse_hw *hw, u32 *msg, u16 size) +static int mucse_read_mbx_pf(struct mucse_hw *hw, __le32 *msg, u16 size) { - const int size_in_words = size / sizeof(u32); + const int size_in_words = size / sizeof(__le32); struct mucse_mbx_info *mbx = &hw->mbx; + int off = MUCSE_MBX_FWPF_SHM; int err; err = mucse_obtain_mbx_lock_pf(hw); if (err) return err; + /* memcpy_fromio() is unsuitable: the mailbox uses 32-bit MMIO + * registers, not byte-addressable RAM. readl() guarantees + * the required 32-bit access width. + */ for (int i = 0; i < size_in_words; i++) - msg[i] = mbx_data_rd32(mbx, MUCSE_MBX_FWPF_SHM + 4 * i); + msg[i] = cpu_to_le32(mbx_data_rd32(mbx, off + 4 * i)); /* Hw needs write data_reg at last */ mbx_data_wr32(mbx, MUCSE_MBX_FWPF_SHM, 0); /* flush reqs as we have read this request data */ @@ -236,7 +241,7 @@ static int mucse_poll_for_msg(struct mucse_hw *hw) * Return: 0 if it successfully received a message notification and * copied it into the receive buffer, negative errno on failure **/ -int mucse_poll_and_read_mbx(struct mucse_hw *hw, u32 *msg, u16 size) +int mucse_poll_and_read_mbx(struct mucse_hw *hw, __le32 *msg, u16 size) { int err; @@ -290,9 +295,9 @@ static void mucse_mbx_inc_pf_req(struct mucse_hw *hw) * Return: 0 if it successfully copied message into the buffer, * negative errno on failure **/ -static int mucse_write_mbx_pf(struct mucse_hw *hw, u32 *msg, u16 size) +static int mucse_write_mbx_pf(struct mucse_hw *hw, const __le32 *msg, u16 size) { - const int size_in_words = size / sizeof(u32); + const int size_in_words = size / sizeof(__le32); struct mucse_mbx_info *mbx = &hw->mbx; int err; @@ -300,8 +305,12 @@ static int mucse_write_mbx_pf(struct mucse_hw *hw, u32 *msg, u16 size) if (err) return err; + /* memcpy_toio() would decompose into arbitrary-width accesses; + * the mailbox requires 32-bit MMIO writes via writel(). + */ for (int i = 0; i < size_in_words; i++) - mbx_data_wr32(mbx, MUCSE_MBX_FWPF_SHM + i * 4, msg[i]); + mbx_data_wr32(mbx, MUCSE_MBX_FWPF_SHM + i * 4, + le32_to_cpu(msg[i])); /* flush acks as we are overwriting the message buffer */ hw->mbx.fw_ack = mucse_mbx_get_fwack(mbx); @@ -360,7 +369,8 @@ static int mucse_poll_for_ack(struct mucse_hw *hw) * Return: 0 if it successfully copied message into the buffer and * received an ack to that message within delay * timeout_cnt period **/ -int mucse_write_and_wait_ack_mbx(struct mucse_hw *hw, u32 *msg, u16 size) +int mucse_write_and_wait_ack_mbx(struct mucse_hw *hw, const __le32 *msg, + u16 size) { int err; diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx.h b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx.h index e6fcc8d1d3ca..75b88b18b04d 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx.h +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx.h @@ -14,7 +14,8 @@ #define MUCSE_MBX_REQ BIT(0) /* Request a req to mailbox */ #define MUCSE_MBX_PFU BIT(3) /* PF owns the mailbox buffer */ -int mucse_write_and_wait_ack_mbx(struct mucse_hw *hw, u32 *msg, u16 size); +int mucse_write_and_wait_ack_mbx(struct mucse_hw *hw, + const __le32 *msg, u16 size); void mucse_init_mbx_params_pf(struct mucse_hw *hw); -int mucse_poll_and_read_mbx(struct mucse_hw *hw, u32 *msg, u16 size); +int mucse_poll_and_read_mbx(struct mucse_hw *hw, __le32 *msg, u16 size); #endif /* _RNPGBE_MBX_H */ diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c index 8c8bd5e8e1db..5ba74997beac 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c @@ -20,32 +20,32 @@ * Return: 0 on success, negative errno on failure **/ static int mucse_fw_send_cmd_wait_resp(struct mucse_hw *hw, - struct mbx_fw_cmd_req *req, - struct mbx_fw_cmd_reply *reply) + union mbx_fw_cmd_req_u *req, + union mbx_fw_cmd_reply_u *reply) { - int len = le16_to_cpu(req->datalen); + int len = le16_to_cpu(req->r.datalen); int retry_cnt = 3; int err; mutex_lock(&hw->mbx.lock); - err = mucse_write_and_wait_ack_mbx(hw, (u32 *)req, len); + err = mucse_write_and_wait_ack_mbx(hw, req->dwords, len); if (err) goto out; do { - err = mucse_poll_and_read_mbx(hw, (u32 *)reply, - sizeof(*reply)); + err = mucse_poll_and_read_mbx(hw, reply->dwords, + sizeof(reply->r)); if (err) goto out; /* mucse_write_and_wait_ack_mbx return 0 means fw has * received request, wait for the expect opcode * reply with 'retry_cnt' times. */ - } while (--retry_cnt >= 0 && reply->opcode != req->opcode); + } while (--retry_cnt >= 0 && reply->r.opcode != req->r.opcode); out: mutex_unlock(&hw->mbx.lock); if (!err && retry_cnt < 0) return -ETIMEDOUT; - if (!err && reply->error_code) + if (!err && reply->r.error_code) return -EIO; return err; @@ -61,17 +61,19 @@ out: **/ static int mucse_mbx_get_info(struct mucse_hw *hw) { - struct mbx_fw_cmd_req req = { - .datalen = cpu_to_le16(MUCSE_MBX_REQ_HDR_LEN), - .opcode = cpu_to_le16(GET_HW_INFO), + union mbx_fw_cmd_req_u req = { + .r = { + .datalen = cpu_to_le16(MUCSE_MBX_REQ_HDR_LEN), + .opcode = cpu_to_le16(GET_HW_INFO), + }, }; - struct mbx_fw_cmd_reply reply = {}; + union mbx_fw_cmd_reply_u reply = {}; int err; err = mucse_fw_send_cmd_wait_resp(hw, &req, &reply); if (!err) hw->pfvfnum = FIELD_GET(GENMASK_U16(7, 0), - le16_to_cpu(reply.hw_info.pfnum)); + le16_to_cpu(reply.r.hw_info.pfnum)); return err; } @@ -111,21 +113,23 @@ int mucse_mbx_sync_fw(struct mucse_hw *hw) **/ int mucse_mbx_powerup(struct mucse_hw *hw, bool is_powerup) { - struct mbx_fw_cmd_req req = { - .datalen = cpu_to_le16(sizeof(req.powerup) + - MUCSE_MBX_REQ_HDR_LEN), - .opcode = cpu_to_le16(POWER_UP), - .powerup = { - /* fw needs this to reply correct cmd */ - .version = cpu_to_le32(GENMASK_U32(31, 0)), - .status = cpu_to_le32(is_powerup ? 1 : 0), + union mbx_fw_cmd_req_u req = { + .r = { + .datalen = cpu_to_le16(sizeof(req.r.powerup) + + MUCSE_MBX_REQ_HDR_LEN), + .opcode = cpu_to_le16(POWER_UP), + .powerup = { + /* fw needs this to reply correct cmd */ + .version = cpu_to_le32(GENMASK_U32(31, 0)), + .status = cpu_to_le32(is_powerup ? 1 : 0), + }, }, }; int len, err; - len = le16_to_cpu(req.datalen); + len = le16_to_cpu(req.r.datalen); mutex_lock(&hw->mbx.lock); - err = mucse_write_and_wait_ack_mbx(hw, (u32 *)&req, len); + err = mucse_write_and_wait_ack_mbx(hw, req.dwords, len); mutex_unlock(&hw->mbx.lock); return err; @@ -142,11 +146,13 @@ int mucse_mbx_powerup(struct mucse_hw *hw, bool is_powerup) **/ int mucse_mbx_reset_hw(struct mucse_hw *hw) { - struct mbx_fw_cmd_req req = { - .datalen = cpu_to_le16(MUCSE_MBX_REQ_HDR_LEN), - .opcode = cpu_to_le16(RESET_HW), + union mbx_fw_cmd_req_u req = { + .r = { + .datalen = cpu_to_le16(MUCSE_MBX_REQ_HDR_LEN), + .opcode = cpu_to_le16(RESET_HW), + }, }; - struct mbx_fw_cmd_reply reply = {}; + union mbx_fw_cmd_reply_u reply = {}; return mucse_fw_send_cmd_wait_resp(hw, &req, &reply); } @@ -166,24 +172,26 @@ int mucse_mbx_get_macaddr(struct mucse_hw *hw, int pfvfnum, u8 *mac_addr, int port) { - struct mbx_fw_cmd_req req = { - .datalen = cpu_to_le16(sizeof(req.get_mac_addr) + - MUCSE_MBX_REQ_HDR_LEN), - .opcode = cpu_to_le16(GET_MAC_ADDRESS), - .get_mac_addr = { - .port_mask = cpu_to_le32(BIT(port)), - .pfvf_num = cpu_to_le32(pfvfnum), + union mbx_fw_cmd_req_u req = { + .r = { + .datalen = cpu_to_le16(sizeof(req.r.get_mac_addr) + + MUCSE_MBX_REQ_HDR_LEN), + .opcode = cpu_to_le16(GET_MAC_ADDRESS), + .get_mac_addr = { + .port_mask = cpu_to_le32(BIT(port)), + .pfvf_num = cpu_to_le32(pfvfnum), + }, }, }; - struct mbx_fw_cmd_reply reply = {}; + union mbx_fw_cmd_reply_u reply = {}; int err; err = mucse_fw_send_cmd_wait_resp(hw, &req, &reply); if (err) return err; - if (le32_to_cpu(reply.mac_addr.ports) & BIT(port)) - memcpy(mac_addr, reply.mac_addr.addrs[port].mac, ETH_ALEN); + if (le32_to_cpu(reply.r.mac_addr.ports) & BIT(port)) + memcpy(mac_addr, reply.r.mac_addr.addrs[port].mac, ETH_ALEN); else return -ENODATA; diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.h b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.h index fb24fc12b613..fe996aeffc4d 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.h +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.h @@ -80,6 +80,20 @@ struct mbx_fw_cmd_reply { }; } __packed; +/* Union wrappers to expose struct as __le32 dword array for mailbox + * transport, eliminating the need for pointer casts. The __packed + * structs have no padding, so dwords[] overlays the fields exactly. + */ +union mbx_fw_cmd_req_u { + struct mbx_fw_cmd_req r; + __le32 dwords[sizeof(struct mbx_fw_cmd_req) / sizeof(__le32)]; +}; + +union mbx_fw_cmd_reply_u { + struct mbx_fw_cmd_reply r; + __le32 dwords[sizeof(struct mbx_fw_cmd_reply) / sizeof(__le32)]; +}; + int mucse_mbx_sync_fw(struct mucse_hw *hw); int mucse_mbx_powerup(struct mucse_hw *hw, bool is_powerup); int mucse_mbx_reset_hw(struct mucse_hw *hw); diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index 91a906a7918a..cfe1f6e3cd12 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -752,6 +752,17 @@ static int oa_tc6_process_rx_chunk_footer(struct oa_tc6 *tc6, u32 footer) static void oa_tc6_submit_rx_skb(struct oa_tc6 *tc6) { + /* MAC-PHY delivers each frame with its Ethernet FCS attached. + * Strip it before handing over to the stack, unless the user + * has asked to keep it via NETIF_F_RXFCS. Keeping the FCS + * in the frame is harmless for IP traffic, but is parsed as + * a (malformed) suffix TLV by PTP, which makes ptp4l reject + * every message with "bad message" error. + */ + if (!(tc6->netdev->features & NETIF_F_RXFCS) && + tc6->rx_skb->len > ETH_FCS_LEN) + skb_trim(tc6->rx_skb, tc6->rx_skb->len - ETH_FCS_LEN); + tc6->rx_skb->protocol = eth_type_trans(tc6->rx_skb, tc6->netdev); tc6->netdev->stats.rx_packets++; tc6->netdev->stats.rx_bytes += tc6->rx_skb->len; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c index 78a802eb159f..6069fa460913 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c @@ -116,8 +116,15 @@ static void ionic_get_link_ext_stats(struct net_device *netdev, { struct ionic_lif *lif = netdev_priv(netdev); - if (lif->ionic->pdev->is_physfn) - stats->link_down_events = lif->link_down_count; + if (lif->ionic->pdev->is_virtfn) + return; + + if (!lif->ionic->idev.port_info) { + netdev_err_once(netdev, "port_info not initialized\n"); + return; + } + + stats->link_down_events = lif->link_down_count; } static int ionic_get_link_ksettings(struct net_device *netdev, diff --git a/drivers/net/ethernet/qlogic/qede/qede_fp.c b/drivers/net/ethernet/qlogic/qede/qede_fp.c index e338bfc8b7b2..c11e0d8f98aa 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_fp.c +++ b/drivers/net/ethernet/qlogic/qede/qede_fp.c @@ -765,6 +765,9 @@ qede_tpa_rx_build_skb(struct qede_dev *edev, struct sk_buff *skb; skb = qede_build_skb(rxq, bd, len, pad); + if (unlikely(!skb)) + return NULL; + bd->page_offset += rxq->rx_buf_seg_size; if (bd->page_offset == PAGE_SIZE) { @@ -812,6 +815,8 @@ qede_rx_build_skb(struct qede_dev *edev, } skb = qede_build_skb(rxq, bd, len, pad); + if (unlikely(!skb)) + return NULL; if (unlikely(qede_realloc_rx_buffer(rxq, bd))) { /* Incr page ref count to reuse on allocation failure so @@ -961,7 +966,7 @@ static inline void qede_tpa_cont(struct qede_dev *edev, { int i; - for (i = 0; cqe->len_list[i] && i < ARRAY_SIZE(cqe->len_list); i++) + for (i = 0; i < ARRAY_SIZE(cqe->len_list) && cqe->len_list[i]; i++) qede_fill_frag_skb(edev, rxq, cqe->tpa_agg_index, le16_to_cpu(cqe->len_list[i])); @@ -986,7 +991,7 @@ static int qede_tpa_end(struct qede_dev *edev, dma_unmap_page(rxq->dev, tpa_info->buffer.mapping, PAGE_SIZE, rxq->data_direction); - for (i = 0; cqe->len_list[i] && i < ARRAY_SIZE(cqe->len_list); i++) + for (i = 0; i < ARRAY_SIZE(cqe->len_list) && cqe->len_list[i]; i++) qede_fill_frag_skb(edev, rxq, cqe->tpa_agg_index, le16_to_cpu(cqe->len_list[i])); if (unlikely(i > 1)) diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c index 9f3479500f85..d055a2628d8c 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c @@ -126,7 +126,10 @@ rmnet_map_ingress_handler(struct sk_buff *skb, consume_skb(skb); } else { - __rmnet_map_ingress_handler(skb, port); + if (rmnet_map_validate_packet_len(skb, port)) + __rmnet_map_ingress_handler(skb, port); + else + kfree_skb(skb); } } diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h index b70284095568..60ca8b780c88 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h @@ -59,5 +59,6 @@ void rmnet_map_tx_aggregate_init(struct rmnet_port *port); void rmnet_map_tx_aggregate_exit(struct rmnet_port *port); void rmnet_map_update_ul_agg_config(struct rmnet_port *port, u32 size, u32 count, u32 time); +u32 rmnet_map_validate_packet_len(struct sk_buff *skb, struct rmnet_port *port); #endif /* _RMNET_MAP_H_ */ diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c index 8b4640c5d61e..305ae15ae8f3 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c @@ -333,54 +333,62 @@ done: return map_header; } -/* Deaggregates a single packet - * A whole new buffer is allocated for each portion of an aggregated frame. - * Caller should keep calling deaggregate() on the source skb until 0 is - * returned, indicating that there are no more packets to deaggregate. Caller - * is responsible for freeing the original skb. - */ -struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb, - struct rmnet_port *port) +u32 rmnet_map_validate_packet_len(struct sk_buff *skb, struct rmnet_port *port) { struct rmnet_map_v5_csum_header *next_hdr = NULL; struct rmnet_map_header *maph; void *data = skb->data; - struct sk_buff *skbn; - u8 nexthdr_type; u32 packet_len; - if (skb->len == 0) - return NULL; + if (skb->len < sizeof(*maph)) + return 0; maph = (struct rmnet_map_header *)skb->data; + + /* Some hardware can send us empty frames. Catch them */ + if (!maph->pkt_len) + return 0; + packet_len = ntohs(maph->pkt_len) + sizeof(*maph); if (port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV4) { packet_len += sizeof(struct rmnet_map_dl_csum_trailer); - } else if (port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV5) { - if (!(maph->flags & MAP_CMD_FLAG)) { - packet_len += sizeof(*next_hdr); - if (maph->flags & MAP_NEXT_HEADER_FLAG) - next_hdr = data + sizeof(*maph); - else - /* Mapv5 data pkt without csum hdr is invalid */ - return NULL; - } + } else if ((port->data_format & RMNET_FLAGS_INGRESS_MAP_CKSUMV5) && + !(maph->flags & MAP_CMD_FLAG)) { + /* Mapv5 data pkt without csum hdr is invalid */ + if (!(maph->flags & MAP_NEXT_HEADER_FLAG)) + return 0; + + packet_len += sizeof(*next_hdr); + next_hdr = data + sizeof(*maph); } - if (((int)skb->len - (int)packet_len) < 0) - return NULL; + if (skb->len < packet_len) + return 0; - /* Some hardware can send us empty frames. Catch them */ - if (!maph->pkt_len) - return NULL; + if (next_hdr && + u8_get_bits(next_hdr->header_info, MAPV5_HDRINFO_HDR_TYPE_FMASK) != + RMNET_MAP_HEADER_TYPE_CSUM_OFFLOAD) + return 0; - if (next_hdr) { - nexthdr_type = u8_get_bits(next_hdr->header_info, - MAPV5_HDRINFO_HDR_TYPE_FMASK); - if (nexthdr_type != RMNET_MAP_HEADER_TYPE_CSUM_OFFLOAD) - return NULL; - } + return packet_len; +} + +/* Deaggregates a single packet + * A whole new buffer is allocated for each portion of an aggregated frame. + * Caller should keep calling deaggregate() on the source skb until 0 is + * returned, indicating that there are no more packets to deaggregate. Caller + * is responsible for freeing the original skb. + */ +struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb, + struct rmnet_port *port) +{ + struct sk_buff *skbn; + u32 packet_len; + + packet_len = rmnet_map_validate_packet_len(skb, port); + if (!packet_len) + return NULL; skbn = alloc_skb(packet_len + RMNET_MAP_DEAGGR_SPACING, GFP_ATOMIC); if (!skbn) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c index 223754cc5c79..322bdf167a4a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c @@ -18,10 +18,12 @@ #include "stmmac_platform.h" /* ctrl register bits */ -#define CTRL_PHY_INTF_RGMII BIT(3) -#define CTRL_PHY_INTF_MII BIT(4) -#define CTRL_WAKE_IRQ_EN BIT(9) -#define CTRL_PHY_IRQ_EN BIT(12) +#define CTRL_PHY_INTF_MODE GENMASK(4, 3) +#define CTRL_PHY_INTF_RMII FIELD_PREP(CTRL_PHY_INTF_MODE, 0) +#define CTRL_PHY_INTF_RGMII FIELD_PREP(CTRL_PHY_INTF_MODE, 1) +#define CTRL_PHY_INTF_MII FIELD_PREP(CTRL_PHY_INTF_MODE, 3) +#define CTRL_LPI_IRQ_EN BIT(9) +#define CTRL_WAKE_IRQ_EN BIT(12) /* dline register bits */ #define RGMII_RX_DLINE_EN BIT(0) @@ -118,7 +120,7 @@ static void spacemit_get_interfaces(struct stmmac_priv *priv, void *bsp_priv, static int spacemit_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel) { - unsigned int mask = CTRL_PHY_INTF_MII | CTRL_PHY_INTF_RGMII; + unsigned int mask = CTRL_PHY_INTF_MODE; struct spacmit_dwmac *dwmac = bsp_priv; unsigned int val = 0; @@ -128,6 +130,7 @@ static int spacemit_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel) break; case PHY_INTF_SEL_RMII: + val = CTRL_PHY_INTF_RMII; break; case PHY_INTF_SEL_RGMII: diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c index 8e69d917d827..26974ee71352 100644 --- a/drivers/net/ethernet/sun/sungem.c +++ b/drivers/net/ethernet/sun/sungem.c @@ -2986,10 +2986,10 @@ static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->max_mtu = GEM_MAX_MTU; /* Register with kernel */ - if (register_netdev(dev)) { + err = register_netdev(dev); + if (err) { pr_err("Cannot register net device, aborting\n"); - err = -ENOMEM; - goto err_out_free_consistent; + goto err_out_clear_drvdata; } /* Undo the get_cell with appropriate locking (we could use @@ -3003,8 +3003,13 @@ static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->dev_addr); return 0; +err_out_clear_drvdata: + pci_set_drvdata(pdev, NULL); + netif_napi_del(&gp->napi); + err_out_free_consistent: - gem_remove_one(pdev); + dma_free_coherent(&pdev->dev, sizeof(struct gem_init_block), + gp->init_block, gp->gblock_dvma); err_out_iounmap: gem_put_cell(gp); iounmap(gp->regs); diff --git a/drivers/net/ethernet/sunplus/spl2sw_phy.c b/drivers/net/ethernet/sunplus/spl2sw_phy.c index 6f899e48f51d..a4889c52e00e 100644 --- a/drivers/net/ethernet/sunplus/spl2sw_phy.c +++ b/drivers/net/ethernet/sunplus/spl2sw_phy.c @@ -79,12 +79,14 @@ int spl2sw_phy_connect(struct spl2sw_common *comm) void spl2sw_phy_remove(struct spl2sw_common *comm) { struct net_device *ndev; + struct spl2sw_mac *mac; int i; for (i = 0; i < MAX_NETDEV_NUM; i++) if (comm->ndev[i]) { ndev = comm->ndev[i]; - if (ndev) - phy_disconnect(ndev->phydev); + mac = netdev_priv(ndev); + phy_disconnect(ndev->phydev); + of_node_put(mac->phy_node); } } diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c index a28a608f9bf4..4a7d1a6f470b 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_common.c +++ b/drivers/net/ethernet/ti/icssg/icssg_common.c @@ -93,8 +93,8 @@ void prueth_ndev_del_tx_napi(struct prueth_emac *emac, int num) } EXPORT_SYMBOL_GPL(prueth_ndev_del_tx_napi); -static int emac_xsk_xmit_zc(struct prueth_emac *emac, - unsigned int q_idx) +static void emac_xsk_xmit_zc(struct prueth_emac *emac, + unsigned int q_idx) { struct prueth_tx_chn *tx_chn = &emac->tx_chns[q_idx]; struct xsk_buff_pool *pool = tx_chn->xsk_pool; @@ -105,6 +105,7 @@ static int emac_xsk_xmit_zc(struct prueth_emac *emac, struct xdp_desc xdp_desc; int num_tx = 0, pkt_len; int descs_avail, ret; + u32 dst_tag_id; u32 *epib; int i; @@ -114,7 +115,7 @@ static int emac_xsk_xmit_zc(struct prueth_emac *emac, * necessary */ if (descs_avail <= MAX_SKB_FRAGS) - return 0; + return; descs_avail -= MAX_SKB_FRAGS; @@ -137,9 +138,17 @@ static int emac_xsk_xmit_zc(struct prueth_emac *emac, epib[0] = 0; epib[1] = 0; cppi5_hdesc_set_pktlen(host_desc, pkt_len); - cppi5_desc_set_tags_ids(&host_desc->hdr, 0, - (emac->port_id | (q_idx << 8))); + dst_tag_id = emac->port_id | (q_idx << 8); + + if (emac->prueth->is_hsr_offload_mode && + (ndev->features & NETIF_F_HW_HSR_DUP)) + dst_tag_id = PRUETH_UNDIRECTED_PKT_DST_TAG; + + if (emac->prueth->is_hsr_offload_mode && + (ndev->features & NETIF_F_HW_HSR_TAG_INS)) + epib[1] |= PRUETH_UNDIRECTED_PKT_TAG_INS; + cppi5_desc_set_tags_ids(&host_desc->hdr, 0, dst_tag_id); k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &dma_buf); cppi5_hdesc_attach_buf(host_desc, dma_buf, pkt_len, dma_buf, pkt_len); @@ -161,8 +170,8 @@ static int emac_xsk_xmit_zc(struct prueth_emac *emac, num_tx++; } - xsk_tx_release(tx_chn->xsk_pool); - return num_tx; + if (num_tx) + xsk_tx_release(tx_chn->xsk_pool); } void prueth_xmit_free(struct prueth_tx_chn *tx_chn, @@ -270,9 +279,6 @@ int emac_tx_complete_packets(struct prueth_emac *emac, int chn, num_tx++; } - if (!num_tx) - return 0; - netif_txq = netdev_get_tx_queue(ndev, chn); netdev_tx_completed_queue(netif_txq, num_tx, total_bytes); @@ -288,16 +294,18 @@ int emac_tx_complete_packets(struct prueth_emac *emac, int chn, __netif_tx_unlock(netif_txq); } - if (tx_chn->xsk_pool) { - if (xsk_frames_done) + if (budget && tx_chn->xsk_pool) { + if (xsk_frames_done) { xsk_tx_completed(tx_chn->xsk_pool, xsk_frames_done); + txq_trans_cond_update(netif_txq); + } if (xsk_uses_need_wakeup(tx_chn->xsk_pool)) xsk_set_tx_need_wakeup(tx_chn->xsk_pool); - netif_txq = netdev_get_tx_queue(ndev, chn); - txq_trans_cond_update(netif_txq); + __netif_tx_lock(netif_txq, smp_processor_id()); emac_xsk_xmit_zc(emac, chn); + __netif_tx_unlock(netif_txq); } return num_tx; @@ -696,6 +704,7 @@ u32 emac_xmit_xdp_frame(struct prueth_emac *emac, dma_addr_t desc_dma, buf_dma; struct prueth_swdata *swdata; struct page *page; + u32 dst_tag_id; u32 *epib; int ret; @@ -737,9 +746,25 @@ u32 emac_xmit_xdp_frame(struct prueth_emac *emac, /* set dst tag to indicate internal qid at the firmware which is at * bit8..bit15. bit0..bit7 indicates port num for directed - * packets in case of switch mode operation + * packets in case of switch mode operation and port num 0 + * for undirected packets in case of HSR offload mode. + * + * XDP_TX frames arrive on a slave port with the HSR tag already + * stripped by the PRU firmware. Like skb TX via hsr0, they must + * be sent as undirected so the PRU duplicates them to both ports + * and re-inserts the HSR sequence tag. */ - cppi5_desc_set_tags_ids(&first_desc->hdr, 0, (emac->port_id | (q_idx << 8))); + dst_tag_id = emac->port_id | (q_idx << 8); + + if (emac->prueth->is_hsr_offload_mode && + (ndev->features & NETIF_F_HW_HSR_DUP)) + dst_tag_id = PRUETH_UNDIRECTED_PKT_DST_TAG; + + if (emac->prueth->is_hsr_offload_mode && + (ndev->features & NETIF_F_HW_HSR_TAG_INS)) + epib[1] |= PRUETH_UNDIRECTED_PKT_TAG_INS; + + cppi5_desc_set_tags_ids(&first_desc->hdr, 0, dst_tag_id); k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma); cppi5_hdesc_attach_buf(first_desc, buf_dma, xdpf->len, buf_dma, xdpf->len); swdata = cppi5_hdesc_get_swdata(first_desc); @@ -927,6 +952,7 @@ static int emac_rx_packet_zc(struct prueth_emac *emac, u32 flow_id, struct cppi5_host_desc_t *desc_rx; struct prueth_swdata *swdata; dma_addr_t desc_dma, buf_dma; + int avail_desc, alloc_budget; struct xdp_buff *xdp; int xdp_status = 0; int count = 0; @@ -993,16 +1019,13 @@ static int emac_rx_packet_zc(struct prueth_emac *emac, u32 flow_id, if (xdp_status & ICSSG_XDP_REDIR) xdp_do_flush(); - /* Allocate xsk buffers from the pool for the "count" number of - * packets processed in order to be able to receive more packets. - */ - ret = prueth_rx_alloc_zc(emac, count); + avail_desc = k3_cppi_desc_pool_avail(rx_chn->desc_pool); + alloc_budget = min_t(int, budget, avail_desc); + + ret = prueth_rx_alloc_zc(emac, alloc_budget); if (xsk_uses_need_wakeup(rx_chn->xsk_pool)) { - /* If the user space doesn't provide enough buffers then it must - * explicitly wake up the kernel when new buffers are available - */ - if (ret < count) + if (ret < alloc_budget) xsk_set_rx_need_wakeup(rx_chn->xsk_pool); else xsk_clear_rx_need_wakeup(rx_chn->xsk_pool); @@ -1628,28 +1651,35 @@ void icssg_ndo_get_stats64(struct net_device *ndev, stats->rx_over_errors = emac_get_stat_by_name(emac, "rx_over_errors"); stats->multicast = emac_get_stat_by_name(emac, "rx_multicast_frames"); - stats->rx_errors = ndev->stats.rx_errors + - emac_get_stat_by_name(emac, "FW_RX_ERROR") + - emac_get_stat_by_name(emac, "FW_RX_EOF_SHORT_FRMERR") + - emac_get_stat_by_name(emac, "FW_RX_B0_DROP_EARLY_EOF") + - emac_get_stat_by_name(emac, "FW_RX_EXP_FRAG_Q_DROP") + - emac_get_stat_by_name(emac, "FW_RX_FIFO_OVERRUN"); - stats->rx_dropped = ndev->stats.rx_dropped + - emac_get_stat_by_name(emac, "FW_DROPPED_PKT") + - emac_get_stat_by_name(emac, "FW_INF_PORT_DISABLED") + - emac_get_stat_by_name(emac, "FW_INF_SAV") + - emac_get_stat_by_name(emac, "FW_INF_SA_DL") + - emac_get_stat_by_name(emac, "FW_INF_PORT_BLOCKED") + - emac_get_stat_by_name(emac, "FW_INF_DROP_TAGGED") + - emac_get_stat_by_name(emac, "FW_INF_DROP_PRIOTAGGED") + - emac_get_stat_by_name(emac, "FW_INF_DROP_NOTAG") + - emac_get_stat_by_name(emac, "FW_INF_DROP_NOTMEMBER"); + stats->rx_errors = ndev->stats.rx_errors; + stats->rx_dropped = ndev->stats.rx_dropped; stats->tx_errors = ndev->stats.tx_errors; - stats->tx_dropped = ndev->stats.tx_dropped + - emac_get_stat_by_name(emac, "FW_RTU_PKT_DROP") + - emac_get_stat_by_name(emac, "FW_TX_DROPPED_PACKET") + - emac_get_stat_by_name(emac, "FW_TX_TS_DROPPED_PACKET") + - emac_get_stat_by_name(emac, "FW_TX_JUMBO_FRM_CUTOFF"); + stats->tx_dropped = ndev->stats.tx_dropped; + + if (!emac->prueth->pa_stats) + return; + + stats->rx_errors += + emac_get_stat_by_name(emac, "FW_RX_ERROR") + + emac_get_stat_by_name(emac, "FW_RX_EOF_SHORT_FRMERR") + + emac_get_stat_by_name(emac, "FW_RX_B0_DROP_EARLY_EOF") + + emac_get_stat_by_name(emac, "FW_RX_EXP_FRAG_Q_DROP") + + emac_get_stat_by_name(emac, "FW_RX_FIFO_OVERRUN"); + stats->rx_dropped += + emac_get_stat_by_name(emac, "FW_DROPPED_PKT") + + emac_get_stat_by_name(emac, "FW_INF_PORT_DISABLED") + + emac_get_stat_by_name(emac, "FW_INF_SAV") + + emac_get_stat_by_name(emac, "FW_INF_SA_DL") + + emac_get_stat_by_name(emac, "FW_INF_PORT_BLOCKED") + + emac_get_stat_by_name(emac, "FW_INF_DROP_TAGGED") + + emac_get_stat_by_name(emac, "FW_INF_DROP_PRIOTAGGED") + + emac_get_stat_by_name(emac, "FW_INF_DROP_NOTAG") + + emac_get_stat_by_name(emac, "FW_INF_DROP_NOTMEMBER"); + stats->tx_dropped += + emac_get_stat_by_name(emac, "FW_RTU_PKT_DROP") + + emac_get_stat_by_name(emac, "FW_TX_DROPPED_PACKET") + + emac_get_stat_by_name(emac, "FW_TX_TS_DROPPED_PACKET") + + emac_get_stat_by_name(emac, "FW_TX_JUMBO_FRM_CUTOFF"); } EXPORT_SYMBOL_GPL(icssg_ndo_get_stats64); diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index 746623fa59b4..5c2cd5756f8a 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -1802,6 +1802,7 @@ static bool wx_set_vmdq_queues(struct wx *wx) rss_i = 4; } } else { + vmdq_m = WX_VMDQ_1Q_MASK; /* double check we are limited to maximum pools */ vmdq_i = min_t(u16, 8, vmdq_i); diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index 0da5565ee4ff..1b3dc2a808f9 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -486,6 +486,7 @@ enum WX_MSCA_CMD_value { #define WX_VMDQ_4Q_MASK 0x7C #define WX_VMDQ_2Q_MASK 0x7E +#define WX_VMDQ_1Q_MASK 0x7F /****************** Manageablility Host Interface defines ********************/ #define WX_HI_MAX_BLOCK_BYTE_LENGTH 256 /* Num of bytes in range */ diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 715180c3a1b3..c55bdb805a64 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -603,7 +603,7 @@ static int geneve_post_decap_hint(const struct sock *sk, struct sk_buff *skb, ipv6h = (void *)skb->data + gro_hint->nested_nh_offset; iph = (struct iphdr *)ipv6h; total_len = skb->len - gro_hint->nested_nh_offset; - if (total_len > GRO_LEGACY_MAX_SIZE) + if (total_len >= GRO_LEGACY_MAX_SIZE) return -E2BIG; /* @@ -948,13 +948,27 @@ static int geneve_gro_complete(struct sock *sk, struct sk_buff *skb, struct genevehdr *gh; struct packet_offload *ptype; __be16 type; - int gh_len; + unsigned int gh_len; int err = -ENOSYS; gh = (struct genevehdr *)(skb->data + nhoff); gh_len = geneve_hlen(gh); type = gh->proto_type; - geneve_opt_gro_hint_off(gh, &type, &gh_len); + geneve_sk_gro_hint_off(sk, gh, &type, &gh_len); + + /* Bail out if we are about to dispatch past the inner network header + * gro_receive() validated. An inner VLAN tag only pushes + * inner_network_offset out, so use a lower bound. + */ + if (skb->encapsulation) { + unsigned int inner_nh = nhoff + gh_len; + + if (type == htons(ETH_P_TEB)) + inner_nh += ETH_HLEN; + + if (unlikely(inner_nh > NAPI_GRO_CB(skb)->inner_network_offset)) + return -EINVAL; + } /* since skb->encapsulation is set, eth_gro_complete() sets the inner mac header */ if (likely(type == htons(ETH_P_TEB))) @@ -1006,7 +1020,7 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port, tunnel_cfg.encap_rcv = geneve_udp_encap_recv; tunnel_cfg.encap_err_lookup = geneve_udp_encap_err_lookup; tunnel_cfg.encap_destroy = NULL; - setup_udp_tunnel_sock(net, sock, &tunnel_cfg); + setup_udp_tunnel_sock(net, sock->sk, &tunnel_cfg); list_add(&gs->list, &gn->sock_list); return gs; } @@ -1018,7 +1032,7 @@ static void __geneve_sock_release(struct geneve_sock *gs) list_del(&gs->list); udp_tunnel_notify_del_rx_port(gs->sock, UDP_TUNNEL_TYPE_GENEVE); - udp_tunnel_sock_release(gs->sock); + udp_tunnel_sock_release(gs->sock->sk); kfree_rcu(gs, rcu); } diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 5150f2e4f66b..a60ef32b35b8 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -885,8 +885,8 @@ static void gtp_encap_disable_sock(struct sock *sk) static void gtp_encap_disable(struct gtp_dev *gtp) { if (gtp->sk_created) { - udp_tunnel_sock_release(gtp->sk0->sk_socket); - udp_tunnel_sock_release(gtp->sk1u->sk_socket); + udp_tunnel_sock_release(gtp->sk0); + udp_tunnel_sock_release(gtp->sk1u); gtp->sk_created = false; gtp->sk0 = NULL; gtp->sk1u = NULL; @@ -1434,7 +1434,7 @@ static struct sock *gtp_create_sock(int type, struct gtp_dev *gtp, tuncfg.encap_rcv = gtp_encap_recv; tuncfg.encap_destroy = NULL; - setup_udp_tunnel_sock(net, sock, &tuncfg); + setup_udp_tunnel_sock(net, sock->sk, &tuncfg); return sock->sk; } @@ -1451,7 +1451,7 @@ static int gtp_create_sockets(struct gtp_dev *gtp, const struct nlattr *nla, sk1u = gtp_create_sock(UDP_ENCAP_GTP1U, gtp, nla, family); if (IS_ERR(sk1u)) { - udp_tunnel_sock_release(sk0->sk_socket); + udp_tunnel_sock_release(sk0); return PTR_ERR(sk1u); } @@ -1689,7 +1689,7 @@ static struct sock *gtp_encap_enable_socket(int fd, int type, tuncfg.encap_rcv = gtp_encap_recv; tuncfg.encap_destroy = gtp_encap_destroy; - setup_udp_tunnel_sock(sock_net(sock->sk), sock, &tuncfg); + setup_udp_tunnel_sock(sock_net(sock->sk), sk, &tuncfg); out_rel_sock: release_sock(sock->sk); diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c index ed4178155a5d..01af4f9cf7f2 100644 --- a/drivers/net/ieee802154/ca8210.c +++ b/drivers/net/ieee802154/ca8210.c @@ -595,7 +595,7 @@ static int ca8210_test_int_driver_write( fifo_buffer = kmemdup(buf, len, GFP_KERNEL); if (!fifo_buffer) return -ENOMEM; - kfifo_in(&test->up_fifo, &fifo_buffer, 4); + kfifo_in(&test->up_fifo, &fifo_buffer, sizeof(fifo_buffer)); wake_up_interruptible(&priv->test.readq); return 0; @@ -919,9 +919,10 @@ static int ca8210_spi_transfer( if (status < 0) { dev_crit( &spi->dev, - "status %d from spi_sync in write\n", + "status %d from spi_async in write\n", status ); + kfree(cas_ctl); } return status; @@ -2525,6 +2526,7 @@ static ssize_t ca8210_test_int_user_read( struct ca8210_priv *priv = filp->private_data; unsigned char *fifo_buffer; unsigned long bytes_not_copied; + unsigned int copied; if (filp->f_flags & O_NONBLOCK) { /* Non-blocking mode */ @@ -2538,7 +2540,8 @@ static ssize_t ca8210_test_int_user_read( ); } - if (kfifo_out(&priv->test.up_fifo, &fifo_buffer, 4) != 4) { + copied = kfifo_out(&priv->test.up_fifo, &fifo_buffer, sizeof(fifo_buffer)); + if (copied != sizeof(fifo_buffer)) { dev_err( &priv->spi->dev, "test_interface: Wrong number of elements popped from upstream fifo\n" diff --git a/drivers/net/ipa/ipa_smp2p.c b/drivers/net/ipa/ipa_smp2p.c index 2f0ccdd937cc..331c00ad02c0 100644 --- a/drivers/net/ipa/ipa_smp2p.c +++ b/drivers/net/ipa/ipa_smp2p.c @@ -232,19 +232,27 @@ ipa_smp2p_init(struct ipa *ipa, struct platform_device *pdev, bool modem_init) &valid_bit); if (IS_ERR(valid_state)) return PTR_ERR(valid_state); - if (valid_bit >= 32) /* BITS_PER_U32 */ - return -EINVAL; + if (valid_bit >= 32) { /* BITS_PER_U32 */ + ret = -EINVAL; + goto err_valid_state_put; + } enabled_state = qcom_smem_state_get(dev, "ipa-clock-enabled", &enabled_bit); - if (IS_ERR(enabled_state)) - return PTR_ERR(enabled_state); - if (enabled_bit >= 32) /* BITS_PER_U32 */ - return -EINVAL; + if (IS_ERR(enabled_state)) { + ret = PTR_ERR(enabled_state); + goto err_valid_state_put; + } + if (enabled_bit >= 32) { /* BITS_PER_U32 */ + ret = -EINVAL; + goto err_enabled_state_put; + } smp2p = kzalloc_obj(*smp2p); - if (!smp2p) - return -ENOMEM; + if (!smp2p) { + ret = -ENOMEM; + goto err_enabled_state_put; + } smp2p->ipa = ipa; @@ -289,6 +297,10 @@ err_null_smp2p: ipa->smp2p = NULL; mutex_destroy(&smp2p->mutex); kfree(smp2p); +err_enabled_state_put: + qcom_smem_state_put(enabled_state); +err_valid_state_put: + qcom_smem_state_put(valid_state); return ret; } @@ -305,6 +317,8 @@ void ipa_smp2p_exit(struct ipa *ipa) ipa_smp2p_power_release(ipa); ipa->smp2p = NULL; mutex_destroy(&smp2p->mutex); + qcom_smem_state_put(smp2p->enabled_state); + qcom_smem_state_put(smp2p->valid_state); kfree(smp2p); } diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index fb009120a924..ee0e2eb7dbc6 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -646,7 +646,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb, } unprotected_len = skb->len; - eth = eth_hdr(skb); + eth = skb_eth_hdr(skb); sci_present = macsec_send_sci(secy); hh = skb_push(skb, macsec_extra_len(sci_present)); memmove(hh, eth, 2 * ETH_ALEN); @@ -3615,19 +3615,22 @@ static int macsec_dev_open(struct net_device *dev) ops = macsec_get_ops(netdev_priv(dev), &ctx); if (!ops) { err = -EOPNOTSUPP; - goto clear_allmulti; + goto clear_promisc; } ctx.secy = &macsec->secy; err = macsec_offload(ops->mdo_dev_open, &ctx); if (err) - goto clear_allmulti; + goto clear_promisc; } if (netif_carrier_ok(real_dev)) netif_carrier_on(dev); return 0; +clear_promisc: + if (dev->flags & IFF_PROMISC) + dev_set_promiscuity(real_dev, -1); clear_allmulti: if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(real_dev, -1); diff --git a/drivers/net/mdio/Kconfig b/drivers/net/mdio/Kconfig index c71132f33f84..733fa0b1cd3a 100644 --- a/drivers/net/mdio/Kconfig +++ b/drivers/net/mdio/Kconfig @@ -122,7 +122,8 @@ config MDIO_MVUSB config MDIO_MSCC_MIIM tristate "Microsemi MIIM interface support" - depends on HAS_IOMEM && REGMAP_MMIO + depends on HAS_IOMEM + select REGMAP_MMIO help This driver supports the MIIM (MDIO) interface found in the network switches of the Microsemi SoCs; it is recommended to switch on diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 57dd6821a8aa..bfab0a47678c 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -184,8 +184,10 @@ struct netconsole_target { bool extended; bool release; struct netpoll np; - /* protected by target_list_lock */ - char buf[MAX_PRINT_CHUNK]; + /* protected by target_list_lock; +1 gives scnprintf() room for its + * NUL terminator so a full MAX_PRINT_CHUNK payload is not truncated + */ + char buf[MAX_PRINT_CHUNK + 1]; struct work_struct resume_wq; }; @@ -1692,7 +1694,7 @@ static void send_msg_no_fragmentation(struct netconsole_target *nt, if (release_len) { release = init_utsname()->release; - scnprintf(nt->buf, MAX_PRINT_CHUNK, "%s,%.*s", release, + scnprintf(nt->buf, sizeof(nt->buf), "%s,%.*s", release, msg_len, msg); msg_len += release_len; } else { @@ -1701,12 +1703,12 @@ static void send_msg_no_fragmentation(struct netconsole_target *nt, if (userdata) msg_len += scnprintf(&nt->buf[msg_len], - MAX_PRINT_CHUNK - msg_len, "%s", + sizeof(nt->buf) - msg_len, "%s", userdata); if (sysdata) msg_len += scnprintf(&nt->buf[msg_len], - MAX_PRINT_CHUNK - msg_len, "%s", + sizeof(nt->buf) - msg_len, "%s", sysdata); send_udp(nt, nt->buf, msg_len); diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c index 8811aa9eedeb..7f69e8890b5b 100644 --- a/drivers/net/ovpn/udp.c +++ b/drivers/net/ovpn/udp.c @@ -399,7 +399,7 @@ int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock, struct socket *sock, if (!old_data) { /* socket is currently unused - we can take it */ rcu_read_unlock(); - setup_udp_tunnel_sock(sock_net(ovpn_sock->sk), sock, &cfg); + setup_udp_tunnel_sock(sock_net(ovpn_sock->sk), sock->sk, &cfg); return 0; } diff --git a/drivers/net/pfcp.c b/drivers/net/pfcp.c index 28e6bc4a1f14..5559bac41a9e 100644 --- a/drivers/net/pfcp.c +++ b/drivers/net/pfcp.c @@ -104,7 +104,7 @@ drop: static void pfcp_del_sock(struct pfcp_dev *pfcp) { - udp_tunnel_sock_release(pfcp->sock); + udp_tunnel_sock_release(pfcp->sock->sk); pfcp->sock = NULL; } @@ -148,6 +148,7 @@ static void pfcp_link_setup(struct net_device *dev) dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; dev->priv_flags |= IFF_NO_QUEUE; + dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; netif_keep_dst(dev); } @@ -172,7 +173,7 @@ static struct socket *pfcp_create_sock(struct pfcp_dev *pfcp) tuncfg.encap_rcv = pfcp_encap_recv; tuncfg.encap_type = 1; - setup_udp_tunnel_sock(net, sock, &tuncfg); + setup_udp_tunnel_sock(net, sock->sk, &tuncfg); return sock; } diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c index 79c867ef64da..01bbddeb4a30 100644 --- a/drivers/net/phy/realtek/realtek_main.c +++ b/drivers/net/phy/realtek/realtek_main.c @@ -1632,7 +1632,8 @@ static int rtl822x_config_aneg(struct phy_device *phydev) ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL_MDIO_AN_10GBT_CTRL, MDIO_AN_10GBT_CTRL_ADV2_5G | - MDIO_AN_10GBT_CTRL_ADV5G, adv); + MDIO_AN_10GBT_CTRL_ADV5G | + MDIO_AN_10GBT_CTRL_ADV10G, adv); if (ret < 0) return ret; } diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index b94b9c433a21..c47536b456e3 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -852,6 +852,7 @@ static int sfp_i2c_mdiobus_create(struct sfp *sfp) static void sfp_i2c_mdiobus_destroy(struct sfp *sfp) { mdiobus_unregister(sfp->i2c_mii); + mdiobus_free(sfp->i2c_mii); sfp->i2c_mii = NULL; } diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c index 69dbdbde9d71..a5e6d7b26b9f 100644 --- a/drivers/net/pse-pd/pse_core.c +++ b/drivers/net/pse-pd/pse_core.c @@ -1367,7 +1367,7 @@ static void __pse_control_release(struct kref *kref) if (psec->pcdev->pi[psec->id].admin_state_enabled) regulator_disable(psec->ps); - devm_regulator_put(psec->ps); + regulator_put(psec->ps); module_put(psec->pcdev->owner); @@ -1436,8 +1436,8 @@ pse_control_get_internal(struct pse_controller_dev *pcdev, unsigned int index, goto free_psec; pcdev->pi[index].admin_state_enabled = ret; - psec->ps = devm_regulator_get_exclusive(pcdev->dev, - rdev_get_name(pcdev->pi[index].rdev)); + psec->ps = regulator_get_exclusive(pcdev->dev, + rdev_get_name(pcdev->pi[index].rdev)); if (IS_ERR(psec->ps)) { ret = PTR_ERR(psec->ps); goto put_module; diff --git a/drivers/net/thunderbolt/main.c b/drivers/net/thunderbolt/main.c index 7aae5d915a1e..ac016890646c 100644 --- a/drivers/net/thunderbolt/main.c +++ b/drivers/net/thunderbolt/main.c @@ -787,8 +787,12 @@ static bool tbnet_check_frame(struct tbnet *net, const struct tbnet_frame *tf, return true; } - /* Start of packet, validate the frame header */ - if (frame_count == 0 || frame_count > TBNET_RING_SIZE / 4) { + /* Start of packet, validate the frame header. tbnet_poll() puts the + * first frame in the skb linear area and every further frame in a page + * fragment, so a packet may not span more than MAX_SKB_FRAGS + 1 frames + * without overflowing skb_shinfo()->frags[]. + */ + if (frame_count == 0 || frame_count > MAX_SKB_FRAGS + 1) { net->stats.rx_length_errors++; return false; } diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c index 0bfa37c14059..09afd137b64e 100644 --- a/drivers/net/usb/gl620a.c +++ b/drivers/net/usb/gl620a.c @@ -104,6 +104,9 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) return 0; } + if (!skb_pull(skb, size + 4)) + return 0; + // allocate the skb for the individual packet gl_skb = alloc_skb(size, GFP_ATOMIC); if (gl_skb) { @@ -116,9 +119,6 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) // advance to the next packet packet = (struct gl_packet *)&packet->packet_data[size]; count--; - - // shift the data pointer to the next gl_packet - skb_pull(skb, size + 4); } // skip the packet length field 4 bytes diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index bcf293ea1bd3..cb782d81d84f 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -1452,6 +1452,15 @@ static inline u32 lan78xx_hash(char addr[ETH_ALEN]) return (ether_crc(ETH_ALEN, addr) >> 23) & 0x1ff; } +static int lan78xx_write_mchash_table(struct lan78xx_net *dev) +{ + struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); + + return lan78xx_dataport_write(dev, DP_SEL_RSEL_VLAN_DA_, + DP_SEL_VHF_VLAN_LEN, + DP_SEL_VHF_HASH_LEN, pdata->mchash_table); +} + static void lan78xx_deferred_multicast_write(struct work_struct *param) { struct lan78xx_priv *pdata = @@ -1462,9 +1471,7 @@ static void lan78xx_deferred_multicast_write(struct work_struct *param) netif_dbg(dev, drv, dev->net, "deferred multicast write 0x%08x\n", pdata->rfe_ctl); - ret = lan78xx_dataport_write(dev, DP_SEL_RSEL_VLAN_DA_, - DP_SEL_VHF_VLAN_LEN, - DP_SEL_VHF_HASH_LEN, pdata->mchash_table); + ret = lan78xx_write_mchash_table(dev); if (ret < 0) goto multicast_write_done; @@ -1492,6 +1499,17 @@ multicast_write_done: return; } +static void lan78xx_update_vlan_filter(struct lan78xx_priv *pdata, + struct net_device *netdev, + netdev_features_t features) +{ + if ((features & NETIF_F_HW_VLAN_CTAG_FILTER) && + !(netdev->flags & IFF_PROMISC)) + pdata->rfe_ctl |= RFE_CTL_VLAN_FILTER_; + else + pdata->rfe_ctl &= ~RFE_CTL_VLAN_FILTER_; +} + static void lan78xx_set_multicast(struct net_device *netdev) { struct lan78xx_net *dev = netdev_priv(netdev); @@ -1526,6 +1544,8 @@ static void lan78xx_set_multicast(struct net_device *netdev) } } + lan78xx_update_vlan_filter(pdata, dev->net, dev->net->features); + if (netdev_mc_count(dev->net)) { struct netdev_hw_addr *ha; int i; @@ -1557,6 +1577,7 @@ static void lan78xx_set_multicast(struct net_device *netdev) } static void lan78xx_rx_urb_submit_all(struct lan78xx_net *dev); +static int lan78xx_write_vlan_table(struct lan78xx_net *dev); static int lan78xx_mac_reset(struct lan78xx_net *dev) { @@ -2514,6 +2535,17 @@ static void lan78xx_mac_link_up(struct phylink_config *config, if (ret < 0) goto link_up_fail; + /* The RFE clears the VLAN/DA hash filter (VHF) on a link down/up + * cycle, so reprogram both tables from their shadow copies. + */ + ret = lan78xx_write_vlan_table(dev); + if (ret < 0) + goto link_up_fail; + + ret = lan78xx_write_mchash_table(dev); + if (ret < 0) + goto link_up_fail; + netif_start_queue(net); return; @@ -3055,24 +3087,27 @@ static int lan78xx_set_features(struct net_device *netdev, else pdata->rfe_ctl &= ~RFE_CTL_VLAN_STRIP_; - if (features & NETIF_F_HW_VLAN_CTAG_FILTER) - pdata->rfe_ctl |= RFE_CTL_VLAN_FILTER_; - else - pdata->rfe_ctl &= ~RFE_CTL_VLAN_FILTER_; + lan78xx_update_vlan_filter(pdata, netdev, features); spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); return lan78xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); } +static int lan78xx_write_vlan_table(struct lan78xx_net *dev) +{ + struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); + + return lan78xx_dataport_write(dev, DP_SEL_RSEL_VLAN_DA_, 0, + DP_SEL_VHF_VLAN_LEN, pdata->vlan_table); +} + static void lan78xx_deferred_vlan_write(struct work_struct *param) { struct lan78xx_priv *pdata = container_of(param, struct lan78xx_priv, set_vlan); - struct lan78xx_net *dev = pdata->dev; - lan78xx_dataport_write(dev, DP_SEL_RSEL_VLAN_DA_, 0, - DP_SEL_VHF_VLAN_LEN, pdata->vlan_table); + lan78xx_write_vlan_table(pdata->dev); } static int lan78xx_vlan_rx_add_vid(struct net_device *netdev, diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c index 5d4a1fd2b524..19f6e1222d93 100644 --- a/drivers/net/usb/net1080.c +++ b/drivers/net/usb/net1080.c @@ -381,7 +381,7 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb) skb_trim(skb, skb->len - sizeof *trailer); if ((packet_len & 0x01) == 0) { - if (skb->data [packet_len] != PAD_BYTE) { + if (packet_len >= skb->len || skb->data[packet_len] != PAD_BYTE) { dev->net->stats.rx_frame_errors++; netdev_dbg(dev->net, "bad pad\n"); return 0; diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 0cfb19b760dd..1c5142149175 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -1137,6 +1137,8 @@ static int veth_enable_xdp_range(struct net_device *dev, int start, int end, err_reg_mem: xdp_rxq_info_unreg(&priv->rq[i].xdp_rxq); err_rxq_reg: + if (!napi_already_on) + netif_napi_del(&priv->rq[i].xdp_napi); for (i--; i >= start; i--) { struct veth_rq *rq = &priv->rq[i]; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index f4adcfee7a80..3e2a5876c6c8 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1999,15 +1999,18 @@ static struct sk_buff *receive_big(struct net_device *dev, struct virtnet_rq_stats *stats) { struct page *page = buf; + unsigned long max_len; struct sk_buff *skb; + max_len = (vi->big_packets_num_skbfrags + 1) * PAGE_SIZE - + sizeof(struct padded_vnet_hdr) + vi->hdr_len; + /* Make sure that len does not exceed the size allocated in * add_recvbuf_big. */ - if (unlikely(len > (vi->big_packets_num_skbfrags + 1) * PAGE_SIZE)) { + if (unlikely(len > max_len)) { pr_debug("%s: rx error: len %u exceeds allocated size %lu\n", - dev->name, len, - (vi->big_packets_num_skbfrags + 1) * PAGE_SIZE); + dev->name, len, max_len); goto err; } @@ -3008,6 +3011,9 @@ static int virtnet_poll(struct napi_struct *napi, int budget) unsigned int xdp_xmit = 0; bool napi_complete; + if (budget) + virtqueue_disable_cb(rq->vq); + virtnet_poll_cleantx(rq, budget); received = virtnet_receive(rq, budget, &xdp_xmit); @@ -6222,6 +6228,19 @@ static void virtnet_free_irq_moder(struct virtnet_info *vi) rtnl_unlock(); } +static netdev_features_t virtnet_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) +{ + /* Inner csum offload is only available for GSO packets. */ + if (skb->encapsulation && + (!skb_is_gso(skb) || netif_needs_gso(skb, features))) + return features & ~NETIF_F_CSUM_MASK; + + /* Passthru. */ + return features; +} + static const struct net_device_ops virtnet_netdev = { .ndo_open = virtnet_open, .ndo_stop = virtnet_close, @@ -6235,7 +6254,7 @@ static const struct net_device_ops virtnet_netdev = { .ndo_bpf = virtnet_xdp, .ndo_xdp_xmit = virtnet_xdp_xmit, .ndo_xsk_wakeup = virtnet_xsk_wakeup, - .ndo_features_check = passthru_features_check, + .ndo_features_check = virtnet_features_check, .ndo_get_phys_port_name = virtnet_get_phys_port_name, .ndo_set_features = virtnet_set_features, .ndo_tx_timeout = virtnet_tx_timeout, diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index b5b1253ac08b..dae82a4d6027 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -657,14 +657,18 @@ static struct vxlanhdr *vxlan_gro_prepare_receive(struct sock *sk, struct sk_buff *skb, struct gro_remcsum *grc) { - struct sk_buff *p; struct vxlanhdr *vh, *vh2; unsigned int hlen, off_vx; - struct vxlan_sock *vs = rcu_dereference_sk_user_data(sk); + struct vxlan_sock *vs; + struct sk_buff *p; __be32 flags; skb_gro_remcsum_init(grc); + vs = rcu_dereference_sk_user_data(sk); + if (!vs) + return NULL; + off_vx = skb_gro_offset(skb); hlen = off_vx + sizeof(*vh); vh = skb_gro_header(skb, hlen, off_vx); @@ -1519,13 +1523,13 @@ static void vxlan_sock_release(struct vxlan_dev *vxlan) vxlan_vs_del_dev(vxlan); if (__vxlan_sock_release_prep(sock4)) { - udp_tunnel_sock_release(sock4->sock); + udp_tunnel_sock_release(sock4->sock->sk); kfree(sock4); } #if IS_ENABLED(CONFIG_IPV6) if (__vxlan_sock_release_prep(sock6)) { - udp_tunnel_sock_release(sock6->sock); + udp_tunnel_sock_release(sock6->sock->sk); kfree(sock6); } #endif @@ -3620,7 +3624,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, bool ipv6, tunnel_cfg.gro_complete = vxlan_gro_complete; } - setup_udp_tunnel_sock(net, sock, &tunnel_cfg); + setup_udp_tunnel_sock(net, sock->sk, &tunnel_cfg); return vs; } diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index 720c5dc889ea..7f4645ff90aa 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c @@ -1487,11 +1487,11 @@ static int ixp4xx_hss_probe(struct platform_device *pdev) "unable to get CLK internal GPIO\n"); ndev = alloc_hdlcdev(port); - port->netdev = alloc_hdlcdev(port); - if (!port->netdev) { + if (!ndev) { err = -ENOMEM; goto err_plat; } + port->netdev = ndev; SET_NETDEV_DEV(ndev, &pdev->dev); hdlc = dev_to_hdlc(ndev); diff --git a/drivers/net/wireguard/socket.c b/drivers/net/wireguard/socket.c index c362c78d908e..0028ef17dc71 100644 --- a/drivers/net/wireguard/socket.c +++ b/drivers/net/wireguard/socket.c @@ -335,7 +335,7 @@ static void sock_free(struct sock *sock) if (unlikely(!sock)) return; sk_clear_memalloc(sock); - udp_tunnel_sock_release(sock->sk_socket); + udp_tunnel_sock_release(sock); } static void set_sock_opts(struct socket *sock) @@ -389,14 +389,14 @@ retry: goto out; } set_sock_opts(new4); - setup_udp_tunnel_sock(net, new4, &cfg); + setup_udp_tunnel_sock(net, new4->sk, &cfg); #if IS_ENABLED(CONFIG_IPV6) if (ipv6_mod_enabled()) { port6.local_udp_port = inet_sk(new4->sk)->inet_sport; ret = udp_sock_create(net, &port6, &new6); if (ret < 0) { - udp_tunnel_sock_release(new4); + udp_tunnel_sock_release(new4->sk); if (ret == -EADDRINUSE && !port && retries++ < 100) goto retry; pr_err("%s: Could not create IPv6 socket\n", @@ -404,7 +404,7 @@ retry: goto out; } set_sock_opts(new6); - setup_udp_tunnel_sock(net, new6, &cfg); + setup_udp_tunnel_sock(net, new6->sk, &cfg); } #endif diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index f994233df2bb..a6c9ff112c68 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include <linux/msi.h> @@ -282,8 +282,10 @@ static void ath11k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl, break; } + spin_lock_bh(&ab->base_lock); if (!(test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags))) queue_work(ab->workqueue_aux, &ab->reset_work); + spin_unlock_bh(&ab->base_lock); break; default: diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 7114eca8810d..35bb9e7a63a2 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -1210,6 +1210,14 @@ static void ath11k_pci_shutdown(struct pci_dev *pdev) struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); + + spin_lock_bh(&ab->base_lock); + set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); + spin_unlock_bh(&ab->base_lock); + + cancel_work_sync(&ab->reset_work); + cancel_work_sync(&ab->dump_work); + ath11k_pci_power_down(ab, false); } diff --git a/drivers/net/wireless/ath/ath12k/ahb.c b/drivers/net/wireless/ath/ath12k/ahb.c index 2dcf0a52e4c1..30733a244454 100644 --- a/drivers/net/wireless/ath/ath12k/ahb.c +++ b/drivers/net/wireless/ath/ath12k/ahb.c @@ -583,31 +583,36 @@ static int ath12k_ahb_config_ext_irq(struct ath12k_base *ab) netif_napi_add(irq_grp->napi_ndev, &irq_grp->napi, ath12k_ahb_ext_grp_napi_poll); - for (j = 0; j < ATH12K_EXT_IRQ_NUM_MAX; j++) { - /* For TX ring, ensure that the ring mask and the - * tcl_to_wbm_rbm_map point to the same ring number. - */ + for (j = 0; j < DP_TCL_NUM_RING_MAX; j++) { if (ring_mask->tx[i] & - BIT(ab->hal.tcl_to_wbm_rbm_map[j].wbm_ring_num)) { + BIT(ab->hal.tcl_to_wbm_rbm_map[j].wbm_ring_num) && + num_irq < ATH12K_EXT_IRQ_NUM_MAX) { irq_grp->irqs[num_irq++] = wbm2host_tx_completions_ring1 - j; } + } - if (ring_mask->rx[i] & BIT(j)) { + for (j = 0; j < ATH12K_EXT_IRQ_NUM_MAX; j++) { + if (ring_mask->rx[i] & BIT(j) && + num_irq < ATH12K_EXT_IRQ_NUM_MAX) { irq_grp->irqs[num_irq++] = reo2host_destination_ring1 - j; } - if (ring_mask->rx_err[i] & BIT(j)) + if (ring_mask->rx_err[i] & BIT(j) && + num_irq < ATH12K_EXT_IRQ_NUM_MAX) irq_grp->irqs[num_irq++] = reo2host_exception; - if (ring_mask->rx_wbm_rel[i] & BIT(j)) + if (ring_mask->rx_wbm_rel[i] & BIT(j) && + num_irq < ATH12K_EXT_IRQ_NUM_MAX) irq_grp->irqs[num_irq++] = wbm2host_rx_release; - if (ring_mask->reo_status[i] & BIT(j)) + if (ring_mask->reo_status[i] & BIT(j) && + num_irq < ATH12K_EXT_IRQ_NUM_MAX) irq_grp->irqs[num_irq++] = reo2host_status; - if (ring_mask->rx_mon_dest[i] & BIT(j)) + if (ring_mask->rx_mon_dest[i] & BIT(j) && + num_irq < ATH12K_EXT_IRQ_NUM_MAX) irq_grp->irqs[num_irq++] = rxdma2host_monitor_destination_mac1; } diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index 90802ed1aa59..af5f11fc1d84 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -943,11 +943,11 @@ void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif) dp_link_vif = ath12k_dp_vif_to_dp_link_vif(&ahvif->dp_vif, link_id); - dp_link_vif->tcl_metadata |= u32_encode_bits(1, HTT_TCL_META_DATA_TYPE) | - u32_encode_bits(arvif->vdev_id, - HTT_TCL_META_DATA_VDEV_ID) | - u32_encode_bits(ar->pdev->pdev_id, - HTT_TCL_META_DATA_PDEV_ID); + dp_link_vif->tcl_metadata = u32_encode_bits(1, HTT_TCL_META_DATA_TYPE) | + u32_encode_bits(arvif->vdev_id, + HTT_TCL_META_DATA_VDEV_ID) | + u32_encode_bits(ar->pdev->pdev_id, + HTT_TCL_META_DATA_PDEV_ID); /* set HTT extension valid bit to 0 by default */ dp_link_vif->tcl_metadata &= ~HTT_TCL_META_DATA_VALID_HTT; diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 737287a9aa46..44c5cff75f16 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -115,13 +115,14 @@ ath12k_dp_mon_fill_rx_rate(struct ath12k_pdev_dp *dp_pdev, bool is_cck; pkt_type = ppdu_info->preamble_type; - rate_mcs = ppdu_info->rate; + rate_mcs = ppdu_info->mcs; nss = ppdu_info->nss; sgi = ppdu_info->gi; switch (pkt_type) { case RX_MSDU_START_PKT_TYPE_11A: case RX_MSDU_START_PKT_TYPE_11B: + rate_mcs = ppdu_info->rate; is_cck = (pkt_type == RX_MSDU_START_PKT_TYPE_11B); if (rx_status->band < NUM_NL80211_BANDS) { struct ath12k *ar = ath12k_pdev_dp_to_ar(dp_pdev); @@ -471,13 +472,10 @@ void ath12k_dp_mon_update_radiotap(struct ath12k_pdev_dp *dp_pdev, rxs->encoding = RX_ENC_HE; ptr = skb_push(mon_skb, sizeof(struct ieee80211_radiotap_he)); ath12k_dp_mon_rx_update_radiotap_he(ppduinfo, ptr); - rxs->rate_idx = ppduinfo->rate; } else if (ppduinfo->vht_flags) { rxs->encoding = RX_ENC_VHT; - rxs->rate_idx = ppduinfo->rate; } else if (ppduinfo->ht_flags) { rxs->encoding = RX_ENC_HT; - rxs->rate_idx = ppduinfo->rate; } else { struct ath12k *ar; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 2cff9485c95a..7190aafd3ae6 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -8054,16 +8054,16 @@ int ath12k_mac_op_change_sta_links(struct ieee80211_hw *hw, continue; arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); - arsta = ath12k_mac_alloc_assign_link_sta(ah, ahsta, ahvif, link_id); + if (!arvif || !arvif->is_created) + continue; - if (!arvif || !arsta) { + arsta = ath12k_mac_alloc_assign_link_sta(ah, ahsta, ahvif, link_id); + if (!arsta) { ath12k_hw_warn(ah, "Failed to alloc/assign link sta"); continue; } ar = arvif->ar; - if (!ar) - continue; ret = ath12k_mac_station_add(ar, arvif, arsta); if (ret) { @@ -8399,6 +8399,10 @@ ath12k_create_vht_cap(struct ath12k *ar, u32 rate_cap_tx_chainmask, vht_cap.vht_supported = 1; vht_cap.cap = ar->pdev->cap.vht_cap; + if (ar->pdev->cap.nss_ratio_enabled) + vht_cap.vht_mcs.tx_highest |= + cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); + ath12k_set_vht_txbf_cap(ar, &vht_cap.cap); /* 80P80 is not supported */ @@ -10293,7 +10297,7 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif) if (ret) { ath12k_warn(ab, "failed to create WMI vdev %d: %d\n", arvif->vdev_id, ret); - return ret; + goto err; } ar->num_created_vdevs++; @@ -10440,13 +10444,13 @@ err_peer_del: if (ret) { ath12k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n", arvif->vdev_id, arvif->bssid); - goto err; + goto err_dp_peer_del; } ret = ath12k_wait_for_peer_delete_done(ar, arvif->vdev_id, arvif->bssid); if (ret) - goto err_vdev_del; + goto err_dp_peer_del; ar->num_peers--; } @@ -10463,8 +10467,6 @@ err_vdev_del: ath12k_wmi_vdev_delete(ar, arvif->vdev_id); ar->num_created_vdevs--; - arvif->is_created = false; - arvif->ar = NULL; ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); ab->free_vdev_map |= 1LL << arvif->vdev_id; ab->free_vdev_stats_id_map &= ~(1LL << arvif->vdev_stats_id); @@ -10473,6 +10475,7 @@ err_vdev_del: spin_unlock_bh(&ar->data_lock); err: + arvif->is_created = false; arvif->ar = NULL; return ret; } diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 375277ca2b89..d9a22d6afbb0 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -1639,7 +1639,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev, ret = ab_pci->device_family_ops->arch_init(ab); if (ret) { ath12k_err(ab, "PCI arch_init failed %d\n", ret); - goto err_pci_msi_free; + goto err_free_irq; } ret = ath12k_core_init(ab); diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c index 945680b3ebdf..a5e290edaa89 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c @@ -1028,8 +1028,10 @@ mic_fail: skb_pull(msdu, hal_rx_desc_sz); if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(dp, msdu, - rx_info))) + rx_info))) { + dev_kfree_skb_any(msdu); return -EINVAL; + } ath12k_dp_rx_h_ppdu(dp_pdev, rx_info); ath12k_dp_rx_h_undecap(dp_pdev, msdu, HAL_ENCRYPT_TYPE_TKIP_MIC, true, diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 0ac9212e42f7..957646b2df4d 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2746,6 +2746,11 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) continue; } + if (ts.qid >= ATH9K_NUM_TX_QUEUES) { + ath_dbg(common, XMIT, "invalid qid %d\n", ts.qid); + continue; + } + txq = &sc->tx.txq[ts.qid]; ath_txq_lock(sc, txq); diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 813553edcb78..c0b477345832 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -2599,6 +2599,9 @@ static int wcn36xx_smd_trigger_ba_rsp(void *buf, int len, struct add_ba_info *ba if (rsp->candidate_cnt < 1) return rsp->status ? rsp->status : -EINVAL; + if (len < sizeof(*rsp) + sizeof(*candidate)) + return -EINVAL; + candidate = (struct wcn36xx_hal_trigger_ba_rsp_candidate *)(buf + sizeof(*rsp)); for (i = 0; i < STACFG_MAX_TC; i++) { @@ -2805,6 +2808,12 @@ static int wcn36xx_smd_print_reg_info_ind(struct wcn36xx *wcn, return -EIO; } + if (rsp->count > (len - sizeof(*rsp)) / sizeof(rsp->regs[0])) { + wcn36xx_warn("Truncated print reg info indication: count %u, len %zu\n", + rsp->count, len); + return -EIO; + } + wcn36xx_dbg(WCN36XX_DBG_HAL, "reginfo indication, scenario: 0x%x reason: 0x%x\n", rsp->scenario, rsp->reason); @@ -3293,6 +3302,10 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev, case WCN36XX_HAL_EXIT_IMPS_RSP: case WCN36XX_HAL_UPDATE_CHANNEL_LIST_RSP: case WCN36XX_HAL_ADD_BCN_FILTER_RSP: + if (len > WCN36XX_HAL_BUF_SIZE) { + wcn36xx_warn("HAL response too large: %d\n", len); + break; + } memcpy(wcn->hal_buf, buf, len); wcn->hal_rsp_len = len; complete(&wcn->hal_rsp_compl); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c index ce09d44fa73c..873754be5174 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c @@ -293,6 +293,12 @@ brcmf_notify_auth_frame_rx(struct brcmf_if *ifp, return -EINVAL; } + if (mgmt_frame_len < offsetof(struct ieee80211_mgmt, u)) { + bphy_err(drvr, "Event %s (%d) frame too small. Ignore\n", + brcmf_fweh_event_name(e->event_code), e->event_code); + return -EINVAL; + } + wdev = &ifp->vif->wdev; WARN_ON(!wdev); diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index fb20fe31cd36..42be6fa22f9c 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -174,7 +174,7 @@ static void lbtf_free_adapter(struct lbtf_private *priv) { lbtf_deb_enter(LBTF_DEB_MAIN); lbtf_free_cmd_buffer(priv); - timer_delete(&priv->command_timer); + timer_delete_sync(&priv->command_timer); lbtf_deb_leave(LBTF_DEB_MAIN); } diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index c9a651bdf882..ca04aaae1e2f 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -4333,7 +4333,7 @@ mwifiex_cfg80211_authenticate(struct wiphy *wiphy, return -EOPNOTSUPP; } - if (!priv->auth_flag) { + if (!(priv->auth_flag & HOST_MLME_AUTH_PENDING)) { ret = mwifiex_remain_on_chan_cfg(priv, HostCmd_ACT_GEN_SET, req->bss->channel, AUTH_TX_DEFAULT_WAIT_TIME); diff --git a/drivers/net/wireless/marvell/mwifiex/join.c b/drivers/net/wireless/marvell/mwifiex/join.c index 5a1a0287c1d5..b48f7febaf03 100644 --- a/drivers/net/wireless/marvell/mwifiex/join.c +++ b/drivers/net/wireless/marvell/mwifiex/join.c @@ -736,7 +736,6 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, /* Send a Media Connected event, according to the Spec */ priv->media_connected = true; - priv->adapter->ps_state = PS_STATE_AWAKE; priv->adapter->pps_uapsd_mode = false; priv->adapter->tx_lock_flag = false; diff --git a/drivers/net/wireless/mediatek/mt76/channel.c b/drivers/net/wireless/mediatek/mt76/channel.c index 05eee64706ea..6edcb3b8f279 100644 --- a/drivers/net/wireless/mediatek/mt76/channel.c +++ b/drivers/net/wireless/mediatek/mt76/channel.c @@ -307,7 +307,7 @@ void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif, rcu_assign_pointer(mvif->offchannel_link, NULL); dev->drv->vif_link_remove(phy, vif, &vif->bss_conf, mlink); - kfree(mlink); + kfree_rcu(mlink, rcu_head); } void mt76_roc_complete(struct mt76_phy *phy) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index b78b4cd206e0..13c4e8abe281 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -449,6 +449,8 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL); + if (!wiphy->max_remain_on_channel_duration) + wiphy->max_remain_on_channel_duration = 5000; if (!wiphy->available_antennas_tx) wiphy->available_antennas_tx = phy->antenna_mask; if (!wiphy->available_antennas_rx) @@ -1321,7 +1323,7 @@ mt76_check_ccmp_pn(struct sk_buff *skb) * All further fragments will be validated by mac80211 only. */ if (ieee80211_is_frag(hdr) && - !ieee80211_is_first_frag(hdr->frame_control)) + !ieee80211_is_first_frag(hdr->seq_ctrl)) return; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 42e11ba1206e..e437e088b2e9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -195,7 +195,6 @@ mt7615_check_offload_capability(struct mt7615_dev *dev) ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); wiphy->flags &= ~WIPHY_FLAG_4ADDR_STATION; - wiphy->max_remain_on_channel_duration = 5000; wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index cec2c4208255..334c19ab2b22 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -912,16 +912,16 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len) } if (!mtk_wed_device_active(&mdev->mmio.wed) && wcid) { - u32 tx_retries = 0, tx_failed = 0; + u32 tx_retries = 0, tx_failed = 0, count; if (v3 && (info & MT_TX_FREE_MPDU_HEADER_V3)) { - tx_retries = - FIELD_GET(MT_TX_FREE_COUNT_V3, info) - 1; + count = FIELD_GET(MT_TX_FREE_COUNT_V3, info); + tx_retries = count ? count - 1 : 0; tx_failed = tx_retries + !!FIELD_GET(MT_TX_FREE_STAT_V3, info); } else if (!v3 && (info & MT_TX_FREE_MPDU_HEADER)) { - tx_retries = - FIELD_GET(MT_TX_FREE_COUNT, info) - 1; + count = FIELD_GET(MT_TX_FREE_COUNT, info); + tx_retries = count ? count - 1 : 0; tx_failed = tx_retries + !!FIELD_GET(MT_TX_FREE_STAT, info); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 03b4960db73f..668bfa195380 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -530,8 +530,9 @@ static void mt7921_mac_tx_free(struct mt792x_dev *dev, void *data, int len) stat = FIELD_GET(MT_TX_FREE_STATUS, info); if (wcid) { - wcid->stats.tx_retries += - FIELD_GET(MT_TX_FREE_COUNT, info) - 1; + u32 count = FIELD_GET(MT_TX_FREE_COUNT, info); + + wcid->stats.tx_retries += count ? count - 1 : 0; wcid->stats.tx_failed += !!stat; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index 7a790ddf43bb..49a37185f056 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -343,11 +343,14 @@ static int mt7921_pci_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, mdev); + dev = container_of(mdev, struct mt792x_dev, mt76); + regs = pcim_iomap_region(pdev, 0, pci_name(pdev)); - if (IS_ERR(regs)) - return PTR_ERR(regs); + if (IS_ERR(regs)) { + ret = PTR_ERR(regs); + goto err_free_dev; + } - dev = container_of(mdev, struct mt792x_dev, mt76); dev->fw_features = features; dev->hif_ops = &mt7921_pcie_ops; dev->irq_map = &irq_map; @@ -359,8 +362,10 @@ static int mt7921_pci_probe(struct pci_dev *pdev, /* MT7902 needs a mutable copy because wm2_complete_mask differs */ map = devm_kmemdup(&pdev->dev, &irq_map, sizeof(irq_map), GFP_KERNEL); - if (!map) - return -ENOMEM; + if (!map) { + ret = -ENOMEM; + goto err_free_dev; + } map->rx.wm2_complete_mask = 0; dev->irq_map = map; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c index c47bd812b66b..50034d7c04f0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c @@ -841,7 +841,6 @@ static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb, { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_link_sta *link_sta; - struct mt792x_link_sta *mlink; struct mt792x_sta *msta; bool is_8023; u16 fc, tid; @@ -880,14 +879,14 @@ static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb, msta = (struct mt792x_sta *)sta->drv_priv; - if (sta->mlo && msta->deflink_id != IEEE80211_LINK_UNSPECIFIED) - mlink = rcu_dereference(msta->link[msta->deflink_id]); - else - mlink = &msta->deflink; - - if (!test_and_set_bit(tid, &mlink->wcid.ampdu_state)) { + /* Packets belonging to the same TID can be transmitted over multiple + * links. Keep the TX BA session state in the primary link so all links + * share the same AMPDU bookkeeping. + */ + if (!test_and_set_bit(tid, &msta->deflink.wcid.ampdu_state)) { if (ieee80211_start_tx_ba_session(sta, tid, 0)) - clear_bit(tid, &mlink->wcid.ampdu_state); + clear_bit(tid, &msta->deflink.wcid.ampdu_state); + } } @@ -1141,8 +1140,9 @@ mt7925_mac_tx_free(struct mt792x_dev *dev, void *data, int len) if (info & MT_TXFREE_INFO_HEADER) { if (wcid) { - wcid->stats.tx_retries += - FIELD_GET(MT_TXFREE_INFO_COUNT, info) - 1; + u32 count = FIELD_GET(MT_TXFREE_INFO_COUNT, info); + + wcid->stats.tx_retries += count ? count - 1 : 0; wcid->stats.tx_failed += !!FIELD_GET(MT_TXFREE_INFO_STAT, info); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 9dc5ee51eb9f..8765121b916a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -2182,9 +2182,9 @@ free: rcu_assign_pointer(mvif->link_conf[link_id], NULL); rcu_assign_pointer(mvif->sta.link[link_id], NULL); - if (mconf != &mvif->bss_conf) + if (mconfs[link_id] != &mvif->bss_conf) devm_kfree(dev->mt76.dev, mconfs[link_id]); - if (mlink != &mvif->sta.deflink) + if (mlinks[link_id] != &mvif->sta.deflink) devm_kfree(dev->mt76.dev, mlinks[link_id]); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c index c4161754c01d..48837723024d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c @@ -415,10 +415,12 @@ static int mt7925_pci_probe(struct pci_dev *pdev, ret = mt7925_register_device(dev); if (ret) - goto err_free_irq; + goto err_free_dma; return 0; +err_free_dma: + mt792x_dma_cleanup(dev); err_free_irq: devm_free_irq(&pdev->dev, pdev->irq, dev); err_free_dev: diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7925/testmode.c index 3d40aacfc011..22a8f1ddc321 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/testmode.c @@ -105,6 +105,11 @@ mt7925_tm_query(struct mt792x_dev *dev, struct mt7925_tm_cmd *req, if (ret) goto out; + if (skb->len < MT7925_EVT_RSP_LEN + 8) { + ret = -EINVAL; + goto out; + } + memcpy((char *)evt_resp, (char *)skb->data + 8, MT7925_EVT_RSP_LEN); out: diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index 152cfcca2f90..dc63400c1b99 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -105,7 +105,8 @@ void mt792x_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, wcid = &mvif->sta.deflink.wcid; } - if (vif && control->sta && ieee80211_vif_is_mld(vif)) { + if (vif && control->sta && ieee80211_vif_is_mld(vif) && + !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_link_sta *link_sta; struct ieee80211_bss_conf *conf; @@ -657,7 +658,6 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw) BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_DEVICE); - wiphy->max_remain_on_channel_duration = 5000; wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN; wiphy->max_scan_ssids = 4; wiphy->max_sched_scan_plan_interval = diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 8f5d297dafce..3d9353811a02 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -683,7 +683,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) ret = mt7996_init_tx_queues(&dev->phy, MT_TXQ_ID(0), MT7996_NPU_TX_RING_SIZE, MT_TXQ_RING_BASE(0) + hif1_ofs, - NULL); + wed); else ret = mt7996_init_tx_queues(&dev->phy, MT_TXQ_ID(dev->mphy.band_idx), diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index e2a83da3a09c..2a0511b2e4d2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -757,6 +757,7 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi, bool multicast = is_multicast_ether_addr(hdr->addr1); u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; __le16 fc = hdr->frame_control, sc = hdr->seq_ctrl; + struct ieee80211_vif *vif = info->control.vif; u16 seqno = le16_to_cpu(sc); bool hw_bigtk = false; u8 fc_type, fc_stype; @@ -819,7 +820,7 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi, txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT); } - if (multicast && ieee80211_vif_is_mld(info->control.vif)) { + if (multicast && vif && ieee80211_vif_is_mld(vif)) { val = MT_TXD3_SN_VALID | FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno)); txwi[3] |= cpu_to_le32(val); @@ -839,12 +840,12 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi, txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU); } - if (ieee80211_vif_is_mld(info->control.vif) && + if (vif && ieee80211_vif_is_mld(vif) && (multicast || unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))) txwi[5] |= cpu_to_le32(MT_TXD5_FL); if (ieee80211_is_nullfunc(fc) && ieee80211_has_a4(fc) && - ieee80211_vif_is_mld(info->control.vif)) { + vif && ieee80211_vif_is_mld(vif)) { txwi[5] |= cpu_to_le32(MT_TXD5_FL); txwi[6] |= cpu_to_le32(MT_TXD6_DIS_MAT); } @@ -856,7 +857,8 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi, void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, - enum mt76_txq_id qid, u32 changed) + enum mt76_txq_id qid, u32 changed, + unsigned int link_id) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -866,7 +868,6 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; struct mt76_vif_link *mlink = NULL; struct mt7996_vif *mvif; - unsigned int link_id; u16 tx_count = 15; u32 val; bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | @@ -874,17 +875,11 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, bool beacon = !!(changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) && (!inband_disc); - if (wcid != &dev->mt76.global_wcid) - link_id = wcid->link_id; - else - link_id = u32_get_bits(info->control.flags, - IEEE80211_TX_CTRL_MLO_LINK); - mvif = vif ? (struct mt7996_vif *)vif->drv_priv : NULL; if (mvif) { if (wcid->offchannel) mlink = rcu_dereference(mvif->mt76.offchannel_link); - if (!mlink) + if (!mlink && link_id != IEEE80211_LINK_UNSPECIFIED) mlink = rcu_dereference(mvif->mt76.link[link_id]); } @@ -1067,11 +1062,11 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, link_conf = rcu_dereference(vif->link_conf[wcid->link_id]); if (!link_conf) - return -EINVAL; + goto error_release_token; link_sta = rcu_dereference(sta->link[wcid->link_id]); if (!link_sta) - return -EINVAL; + goto error_release_token; dma_sync_single_for_cpu(mdev->dma_dev, tx_info->buf[1].addr, tx_info->buf[1].len, DMA_TO_DEVICE); @@ -1096,7 +1091,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, /* Transmit non qos data by 802.11 header and need to fill txd by host*/ if (!is_8023 || pid >= MT_PACKET_ID_FIRST) mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, - pid, qid, 0); + pid, qid, 0, link_id); /* MT7996 and MT7992 require driver to provide the MAC TXP for AddBA * req @@ -1176,6 +1171,10 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, tx_info->nbuf = MT_CT_DMA_BUF_NUM; return 0; + +error_release_token: + mt76_token_release(mdev, id, NULL); + return -EINVAL; } u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id) @@ -1360,13 +1359,13 @@ next: cur_info++; continue; } else if (info & MT_TXFREE_INFO_HEADER) { - u32 tx_retries = 0, tx_failed = 0; + u32 tx_retries = 0, tx_failed = 0, count; if (!wcid) continue; - tx_retries = - FIELD_GET(MT_TXFREE_INFO_COUNT, info) - 1; + count = FIELD_GET(MT_TXFREE_INFO_COUNT, info); + tx_retries = count ? count - 1 : 0; tx_failed = tx_retries + !!FIELD_GET(MT_TXFREE_INFO_STAT, info); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index a8a6552d49f6..26b8c91db0a8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -1959,7 +1959,11 @@ static void mt7996_sta_rate_ctrl_update(void *data, struct ieee80211_sta *sta) { struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; struct mt7996_sta_link *msta_link; - u32 *changed = data; + struct mt7996_vif *mvif = data; + u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED; + + if (msta->vif != mvif) + return; msta_link = rcu_dereference(msta->link[msta->deflink_id]); if (msta_link) @@ -1972,7 +1976,6 @@ mt7996_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct mt7996_dev *dev = mt7996_hw_dev(hw); struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED; mvif->deflink.bitrate_mask = *mask; @@ -1985,7 +1988,7 @@ mt7996_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, * then multiple MCS setting (MCS 4,5,6) is not supported. */ ieee80211_iterate_stations_atomic(hw, mt7996_sta_rate_ctrl_update, - &changed); + mvif); ieee80211_queue_work(hw, &dev->rc_work); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 16420375112d..2748bfeb4797 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -3098,7 +3098,7 @@ mt7996_mcu_beacon_cont(struct mt7996_dev *dev, buf = (u8 *)bcn + sizeof(*bcn); mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, 0, 0, - BSS_CHANGED_BEACON); + BSS_CHANGED_BEACON, link_conf->link_id); memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); } @@ -3244,7 +3244,8 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev, buf = (u8 *)tlv + sizeof(*discov); - mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, 0, 0, changed); + mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, 0, 0, + changed, link_conf->link_id); memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index bdcf72457954..5f39a583bd37 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -855,7 +855,8 @@ void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band); void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, - enum mt76_txq_id qid, u32 changed); + enum mt76_txq_id qid, u32 changed, + unsigned int link_id); void mt7996_mac_update_beacons(struct mt7996_phy *phy); void mt7996_mac_set_coverage_class(struct mt7996_phy *phy); void mt7996_mac_work(struct work_struct *work); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c index 12523ddba630..b7d9193e042f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c @@ -141,7 +141,7 @@ static int mt7996_pci_probe(struct pci_dev *pdev, dev->hif2 = hif2; mt76_npu_init(mdev, pci_resource_start(pdev, 0), - pdev->bus && pci_domain_nr(pdev->bus) ? 3 : 2); + pci_domain_nr(pdev->bus) ? 3 : 2); ret = mt7996_mmio_wed_init(dev, pdev, false, &irq); if (ret < 0) diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 22f9690634c9..f96d9c471853 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -933,7 +933,7 @@ mt76_token_release(struct mt76_dev *dev, int token, bool *wake) #endif } - if (dev->token_count < dev->token_size - MT76_TOKEN_FREE_THR && + if (wake && dev->token_count < dev->token_size - MT76_TOKEN_FREE_THR && dev->phy.q_tx[0]->blocked) *wake = true; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c index 82fb230a73bb..4d94b7062f44 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c @@ -1388,7 +1388,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) GFP_KERNEL); if (!rt2x00dev->drv_data) { retval = -ENOMEM; - goto exit; + return retval; } } @@ -1422,7 +1422,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) alloc_ordered_workqueue("%s", 0, wiphy_name(rt2x00dev->hw->wiphy)); if (!rt2x00dev->workqueue) { retval = -ENOMEM; - goto exit; + goto exit_free_drv_data; } INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); @@ -1495,6 +1495,14 @@ exit: rt2x00lib_remove_dev(rt2x00dev); return retval; + +exit_free_drv_data: + clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); + + kfree(rt2x00dev->drv_data); + rt2x00dev->drv_data = NULL; + + return retval; } EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev); diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index bba370ad510c..c2bf44e880cf 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1077,6 +1077,11 @@ static u32 rtw_pci_rx_napi(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci, * discard the frame if none available */ new_len = pkt_stat.pkt_len + pkt_offset; + if (unlikely(new_len > RTK_PCI_RX_BUF_SIZE)) { + rtw_dbg(rtwdev, RTW_DBG_RX, + "oversized RX packet: %u\n", new_len); + goto next_rp; + } new = dev_alloc_skb(new_len); if (WARN_ONCE(!new, "rx routine starvation\n")) goto next_rp; @@ -1711,9 +1716,9 @@ static void rtw_pci_napi_deinit(struct rtw_dev *rtwdev) static pci_ers_result_t rtw_pci_io_err_detected(struct pci_dev *pdev, pci_channel_state_t state) { - struct net_device *netdev = pci_get_drvdata(pdev); + struct ieee80211_hw *hw = pci_get_drvdata(pdev); - netif_device_detach(netdev); + ieee80211_stop_queues(hw); return PCI_ERS_RESULT_NEED_RESET; } @@ -1730,12 +1735,12 @@ static pci_ers_result_t rtw_pci_io_slot_reset(struct pci_dev *pdev) static void rtw_pci_io_resume(struct pci_dev *pdev) { - struct net_device *netdev = pci_get_drvdata(pdev); + struct ieee80211_hw *hw = pci_get_drvdata(pdev); /* ack any pending wake events, disable PME */ pci_enable_wake(pdev, PCI_D0, 0); - netif_device_attach(netdev); + ieee80211_wake_queues(hw); } const struct pci_error_handlers rtw_pci_err_handler = { diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index fd29dbbb120d..05adf20a65be 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -6492,6 +6492,9 @@ static inline void rtw89_assoc_link_clr(struct rtw89_sta_link *rtwsta_link) static inline struct rtw89_sta_link * rtw89_assoc_link_rcu_dereference(struct rtw89_dev *rtwdev, u8 macid) { + if (unlikely(macid >= RTW89_MAX_MAC_ID_NUM)) + return NULL; + return rcu_dereference(rtwdev->assoc_link_on_macid[macid]); } diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 17704f054727..089c9071b58f 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -8318,7 +8318,7 @@ static int rtw89_update_6ghz_rnr_chan_ax(struct rtw89_dev *rtwdev, struct sk_buff *skb; bool found; int ret = 0; - u8 i; + u32 i; if (!req->n_6ghz_params) return 0; diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 43c61b3dc969..64554eb35a72 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -4624,9 +4624,9 @@ EXPORT_SYMBOL(rtw89_pm_ops); static pci_ers_result_t rtw89_pci_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { - struct net_device *netdev = pci_get_drvdata(pdev); + struct ieee80211_hw *hw = pci_get_drvdata(pdev); - netif_device_detach(netdev); + ieee80211_stop_queues(hw); return PCI_ERS_RESULT_NEED_RESET; } @@ -4643,12 +4643,12 @@ static pci_ers_result_t rtw89_pci_io_slot_reset(struct pci_dev *pdev) static void rtw89_pci_io_resume(struct pci_dev *pdev) { - struct net_device *netdev = pci_get_drvdata(pdev); + struct ieee80211_hw *hw = pci_get_drvdata(pdev); /* ack any pending wake events, disable PME */ pci_enable_wake(pdev, PCI_D0, 0); - netif_device_attach(netdev); + ieee80211_wake_queues(hw); } const struct pci_error_handlers rtw89_pci_err_handler = { diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 1c340a4a0930..be583ae331c0 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -32,6 +32,15 @@ #define WL1271_BOOT_RETRIES 3 #define WL1271_WAKEUP_TIMEOUT 500 +static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + WL1271_CIPHER_SUITE_GEM, + WLAN_CIPHER_SUITE_AES_CMAC, +}; + static char *fwlog_param; static int fwlog_mem_blocks = -1; static int bug_on_recovery = -1; @@ -2367,6 +2376,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) static int wl12xx_init_fw(struct wl1271 *wl) { + struct wlcore_platdev_data *pdev_data = dev_get_platdata(&wl->pdev->dev); int retries = WL1271_BOOT_RETRIES; bool booted = false; struct wiphy *wiphy = wl->hw->wiphy; @@ -2421,8 +2431,9 @@ power_off: /* WLAN_CIPHER_SUITE_AES_CMAC must be last in cipher_suites; support only with firmware 8.9.1 and newer */ - if (wl->chip.fw_ver[FW_VER_MAJOR] < 1) - wl->hw->wiphy->n_cipher_suites--; + if (wl->chip.fw_ver[FW_VER_MAJOR] < 1 || + (!strncmp(pdev_data->family->name, "wl12", 4))) + wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites) - 1; /* * Now we know if 11a is supported (info from the NVS), so disable @@ -6198,14 +6209,6 @@ static void wl1271_unregister_hw(struct wl1271 *wl) static int wl1271_init_ieee80211(struct wl1271 *wl) { int i; - static const u32 cipher_suites[] = { - WLAN_CIPHER_SUITE_WEP40, - WLAN_CIPHER_SUITE_WEP104, - WLAN_CIPHER_SUITE_TKIP, - WLAN_CIPHER_SUITE_CCMP, - WL1271_CIPHER_SUITE_GEM, - WLAN_CIPHER_SUITE_AES_CMAC, - }; /* The tx descriptor buffer */ wl->hw->extra_tx_headroom = sizeof(struct wl1271_tx_hw_descr); diff --git a/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c b/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c index bff46f7ca59f..0bbd41263cc2 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c +++ b/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c @@ -553,19 +553,21 @@ static int mux_dl_process_dg(struct iosm_mux *ipc_mux, struct mux_adbh *adbh, u32 packet_offset, i, rc, dg_len; for (i = 0; i < nr_of_dg; i++, dg++) { - if (le32_to_cpu(dg->datagram_index) - < sizeof(struct mux_adbh)) + u32 dg_index = le32_to_cpu(dg->datagram_index); + + dg_len = le16_to_cpu(dg->datagram_length); + + if (dg_index < sizeof(struct mux_adbh)) goto dg_error; - /* Is the packet inside of the ADB */ - if (le32_to_cpu(dg->datagram_index) >= - le32_to_cpu(adbh->block_length)) { + /* Is the packet inside of the ADB and the received skb ? */ + if (dg_index >= le32_to_cpu(adbh->block_length) || + dg_index >= skb->len || + dg_len > skb->len - dg_index || + dl_head_pad_len >= dg_len) { goto dg_error; } else { - packet_offset = - le32_to_cpu(dg->datagram_index) + - dl_head_pad_len; - dg_len = le16_to_cpu(dg->datagram_length); + packet_offset = dg_index + dl_head_pad_len; /* Pass the packet to the netif layer. */ rc = ipc_mux_net_receive(ipc_mux, if_id, ipc_mux->wwan, packet_offset, @@ -589,12 +591,16 @@ static void mux_dl_adb_decode(struct iosm_mux *ipc_mux, struct mux_adbh *adbh; struct mux_adth *adth; int nr_of_dg, if_id; - u32 adth_index; + u32 adth_index, prev_index = 0; u8 *block; block = skb->data; adbh = (struct mux_adbh *)block; + /* The block header itself must fit in the received skb. */ + if (skb->len < sizeof(struct mux_adbh)) + goto adb_decode_err; + /* Process the aggregated datagram tables. */ adth_index = le32_to_cpu(adbh->first_table_index); @@ -606,6 +612,16 @@ static void mux_dl_adb_decode(struct iosm_mux *ipc_mux, /* Loop through mixed session tables. */ while (adth_index) { + /* The table header must lie within the received skb, and the + * chain must move forward so a modem cannot make the loop + * cycle between two tables. + */ + if (adth_index <= prev_index || + adth_index < sizeof(struct mux_adbh) || + adth_index > skb->len - sizeof(struct mux_adth)) + goto adb_decode_err; + prev_index = adth_index; + /* Get the reference to the table header. */ adth = (struct mux_adth *)(block + adth_index); @@ -629,6 +645,10 @@ static void mux_dl_adb_decode(struct iosm_mux *ipc_mux, if (le16_to_cpu(adth->table_length) < sizeof(struct mux_adth)) goto adb_decode_err; + /* The whole datagram table must fit in the received skb. */ + if (le16_to_cpu(adth->table_length) > skb->len - adth_index) + goto adb_decode_err; + /* Calculate the number of datagrams. */ nr_of_dg = (le16_to_cpu(adth->table_length) - sizeof(struct mux_adth)) / diff --git a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c index e10cb4f9104e..2917cee9b802 100644 --- a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c +++ b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c @@ -1063,6 +1063,9 @@ err_free_tx_ring: while (i--) t7xx_cldma_ring_free(md_ctrl, &md_ctrl->tx_ring[i], DMA_TO_DEVICE); + dma_pool_destroy(md_ctrl->gpd_dmapool); + md_ctrl->gpd_dmapool = NULL; + return ret; } diff --git a/drivers/net/wwan/t7xx/t7xx_port_wwan.c b/drivers/net/wwan/t7xx/t7xx_port_wwan.c index 7fc569565ff9..d2529df7592a 100644 --- a/drivers/net/wwan/t7xx/t7xx_port_wwan.c +++ b/drivers/net/wwan/t7xx/t7xx_port_wwan.c @@ -106,6 +106,8 @@ static int t7xx_port_ctrl_tx(struct t7xx_port *port, struct sk_buff *skb) while (cur) { cloned = skb_clone(cur, GFP_KERNEL); + if (!cloned) + return cnt ? cnt : -ENOMEM; cloned->len = skb_headlen(cur); ret = t7xx_port_send_skb(port, cloned, 0, 0); if (ret) { |
