summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-07-30 19:18:49 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2026-07-30 19:18:49 +0300
commit2812e64e1575e05500a35c405aaa6e99b7d7930b (patch)
tree788f0312e43983920569c9e46ea4a239ea72b9b0 /drivers
parent110b5cdd5b72bcef01b8d4dfe45d922bdd16de0e (diff)
parent451c9075d6c53f2438d110addbeeeea6fac18567 (diff)
downloadlinux-2812e64e1575e05500a35c405aaa6e99b7d7930b.tar.xz
Merge tag 'net-7.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Pull networking fixes from Paolo Abeni: "This is again larger than usual: the backlog accumulated in the past weeks is not done yet. I'm not aware of any known pending regression. Including fixes from netfilter, Bluetooth, WiFi and CAN. Current release - regressions: - bluetooth: remove unnecessary hci_conn_get in create_conn_sync - can: isotp: fix timer drain order, wakeup handling and tx_gen ordering - eth: - tun/vhost: revert avoid ptr_ring tail-drop when a qdisc is present Previous releases - regressions: - core: do not send ICMP/NDISC Redirects when peer allocation fails - ipv6: take nexthop lock for f6i_list walks in replace check and notify - wifi: fix an ath12k MLO regression impacting WCN7850/QCC2072. - netfilter: nf_tables: make nft_object rhltable per table - af_unix: fix listen() succeeding on sockets in the wrong state - openvswitch: fix potential UAF on meter attach failure - bluetooth: - fix advertising data UAFs - avoid deadlocks in iso_sock_timeout - smc: fix socket use-after-free during link group termination - dpll: use pin owner's dpll ref for pin-level attribute reporting - eth: - veth: convert frag_list skbs before running XDP - ice: wait for reset completion in ice_resume() - igc: remove napi_synchronize() in igc_down() - vxlan: use pskb_network_may_pull() for transmit path header pulls Previous releases - always broken: - xsk: fix AF_XDP multi-buffer Tx descriptor reclaim - psp: fix NULL genl_sock deref race with concurrent netns teardown - netfilter: widen NAT rewrite delta to s32 in sip_help_tcp() - can: peak_usb: fix double free of transfer buffer on URB submit error - dibs: fix use-after-free of dmb_node in loopback attach/detach/unregister - sctp: prevent peer transport count overflow - dsa: mt7530: error out on failed reads in MT7531 PHY polling - eth: - idpf: bound interrupt-vector register fill to the allocated array" * tag 'net-7.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (156 commits) qede: sync udp_tunnel ports outside qede_lock in the recovery path net: openvswitch: fix potential UAF on meter attach failure octeontx2-pf: Set correct sequence for carrier off and tx queue stop net: libwx: fix FDIR ATR queue mismatch for software VLAN packets net: dsa: realtek: use devm_mutex_init for l2_lock net: dsa: realtek: use devm_mutex_init for vlan_lock net: dsa: realtek: use devm_mutex_init for regmap lock net: dsa: realtek: rtl8365mb: use devm_mutex_init for mib_lock ptp: netc: fix potential interrupt storm caused by incorrect unbind order net: mana: Return error code from mana_create_rxq() net: openvswitch: fix skb leak on flow key update failure during ct net: openvswitch: fix skb leak on flow key update failure during recirculation net: stmmac: Fix E2E delay mechanism net: dsa: mt7530: error out on failed reads in MT7531 PHY polling net: dsa: mt7530: error out on failed reads in ATC/VTCR command polling net: dsa: mt7530: check bus->read() errors in the MDIO regmap backend Revert "tun/tap: add ptr_ring consume helper with netdev queue wakeup" Revert "vhost-net: wake queue of tun/tap after ptr_ring consume" Revert "ptr_ring: move free-space check into separate helper" Revert "tun/tap & vhost-net: avoid ptr_ring tail-drop when a qdisc is present" ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bluetooth/btintel.c3
-rw-r--r--drivers/bluetooth/btmtk.c86
-rw-r--r--drivers/bluetooth/btusb.c30
-rw-r--r--drivers/dibs/dibs_loopback.c47
-rw-r--r--drivers/dpll/dpll_core.c27
-rw-r--r--drivers/dpll/dpll_core.h1
-rw-r--r--drivers/dpll/dpll_netlink.c60
-rw-r--r--drivers/net/can/c_can/c_can_main.c8
-rw-r--r--drivers/net/can/ctucanfd/ctucanfd_base.c14
-rw-r--r--drivers/net/can/ctucanfd/ctucanfd_pci.c3
-rw-r--r--drivers/net/can/rcar/rcar_canfd.c32
-rw-r--r--drivers/net/can/softing/softing_fw.c46
-rw-r--r--drivers/net/can/usb/ems_usb.c43
-rw-r--r--drivers/net/can/usb/etas_es58x/es58x_core.c1
-rw-r--r--drivers/net/can/usb/gs_usb.c4
-rw-r--r--drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c1
-rw-r--r--drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c13
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_core.c1
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_fd.c40
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_pro.c20
-rw-r--r--drivers/net/dsa/mt7530-mdio.c11
-rw-r--r--drivers/net/dsa/mt7530.c86
-rw-r--r--drivers/net/dsa/realtek/rtl8365mb_main.c16
-rw-r--r--drivers/net/dsa/realtek/rtl83xx.c14
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dpll.c19
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool.c10
-rw-r--r--drivers/net/ethernet/intel/ice/ice_main.c10
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vf_lib.c27
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vf_lib_private.h1
-rw-r--r--drivers/net/ethernet/intel/ice/virt/queues.c21
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_dev.c2
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_lib.c2
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_txrx.c5
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_txrx.h2
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_vf_dev.c2
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_virtchnl.c5
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_virtchnl.h2
-rw-r--r--drivers/net/ethernet/intel/igbvf/netdev.c2
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c3
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/cgx.c12
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/cgx.h1
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu.h2
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c79
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c22
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c29
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c2
-rw-r--r--drivers/net/ethernet/mediatek/mtk_eth_soc.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_main.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_stats.c19
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_en.c8
-rw-r--r--drivers/net/ethernet/nvidia/forcedeth.c4
-rw-r--r--drivers/net/ethernet/qlogic/qede/qede_main.c44
-rw-r--r--drivers/net/ethernet/realtek/rtase/rtase_main.c3
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c14
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c3
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_lib.c2
-rw-r--r--drivers/net/phy/phylink.c29
-rw-r--r--drivers/net/tun.c109
-rw-r--r--drivers/net/veth.c4
-rw-r--r--drivers/net/vxlan/vxlan_core.c21
-rw-r--r--drivers/net/vxlan/vxlan_mdb.c4
-rw-r--r--drivers/net/wireless/ath/ath12k/core.c2
-rw-r--r--drivers/net/wireless/ath/ath12k/core.h3
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_htt.c49
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_htt.h12
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_peer.c75
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_peer.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/hw.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.c165
-rw-r--r--drivers/net/wireless/ath/ath12k/peer.c31
-rw-r--r--drivers/net/wireless/ath/ath12k/peer.h1
-rw-r--r--drivers/net/wireless/ath/ath12k/wifi7/hw.c12
-rw-r--r--drivers/net/wireless/intel/iwlegacy/common.c7
-rw-r--r--drivers/net/wireless/intel/iwlegacy/debug.c2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c2
-rw-r--r--drivers/ptp/ptp_netc.c15
-rw-r--r--drivers/s390/net/qeth_core_main.c3
-rw-r--r--drivers/vhost/net.c21
80 files changed, 1028 insertions, 519 deletions
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 5e9cac090bd8..bf567b7c5f00 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -3771,6 +3771,9 @@ static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
{
struct intel_tlv *tlv = (void *)&skb->data[5];
+ if (skb->len < 5 + sizeof(*tlv) + sizeof(tlv->val[0]))
+ goto recv_frame;
+
/* The first event is always an event type TLV */
if (tlv->type != INTEL_TLV_TYPE_ID)
goto recv_frame;
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 02a96342e964..66b346761043 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -804,56 +804,44 @@ static int btmtk_usb_uhw_reg_write(struct hci_dev *hdev, u32 reg, u32 val)
static int btmtk_usb_uhw_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
{
struct btmtk_data *data = hci_get_priv(hdev);
- int pipe, err;
- void *buf;
-
- buf = kzalloc(4, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+ u8 buf[sizeof(u32)];
+ int err;
- pipe = usb_rcvctrlpipe(data->udev, 0);
- err = usb_control_msg(data->udev, pipe, 0x01,
- 0xDE,
- reg >> 16, reg & 0xffff,
- buf, 4, USB_CTRL_GET_TIMEOUT);
- if (err < 0) {
+ *val = 0;
+ err = usb_control_msg_recv(data->udev, 0, 0x01,
+ 0xDE,
+ reg >> 16, reg & 0xffff,
+ buf, sizeof(buf), USB_CTRL_GET_TIMEOUT,
+ GFP_KERNEL);
+ if (err) {
bt_dev_err(hdev, "Failed to read uhw reg(%d)", err);
- goto err_free_buf;
+ return err;
}
*val = get_unaligned_le32(buf);
bt_dev_dbg(hdev, "reg=%x, value=0x%08x", reg, *val);
-err_free_buf:
- kfree(buf);
-
- return err;
+ return 0;
}
static int btmtk_usb_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
{
struct btmtk_data *data = hci_get_priv(hdev);
- int pipe, err, size = sizeof(u32);
- void *buf;
-
- buf = kzalloc(size, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+ u8 buf[sizeof(u32)];
+ int err;
- pipe = usb_rcvctrlpipe(data->udev, 0);
- err = usb_control_msg(data->udev, pipe, 0x63,
- USB_TYPE_VENDOR | USB_DIR_IN,
- reg >> 16, reg & 0xffff,
- buf, size, USB_CTRL_GET_TIMEOUT);
+ *val = 0;
+ err = usb_control_msg_recv(data->udev, 0, 0x63,
+ USB_TYPE_VENDOR | USB_DIR_IN,
+ reg >> 16, reg & 0xffff,
+ buf, sizeof(buf), USB_CTRL_GET_TIMEOUT,
+ GFP_KERNEL);
if (err < 0)
- goto err_free_buf;
+ return err;
*val = get_unaligned_le32(buf);
-err_free_buf:
- kfree(buf);
-
- return err;
+ return 0;
}
static int btmtk_usb_id_get(struct hci_dev *hdev, u32 reg, u32 *id)
@@ -877,7 +865,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (dev_id == 0x7922) {
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
- if (err < 0)
+ if (err)
return err;
val |= 0x00002020;
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, val);
@@ -887,7 +875,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
- if (err < 0)
+ if (err)
return err;
val |= BIT(0);
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, val);
@@ -896,14 +884,14 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
msleep(100);
} else if (dev_id == 0x7925 || dev_id == 0x6639) {
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
- if (err < 0)
+ if (err)
return err;
val |= (1 << 5);
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_RESET_REG_CONNV3, val);
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
- if (err < 0)
+ if (err)
return err;
val &= 0xFFFF00FF;
val |= (1 << 13);
@@ -914,7 +902,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
- if (err < 0)
+ if (err)
return err;
val |= (1 << 0);
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_RESET_REG_CONNV3, val);
@@ -924,13 +912,13 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT, &val);
- if (err < 0)
+ if (err)
return err;
err = btmtk_usb_uhw_reg_write(hdev, MTK_UDMA_INT_STA_BT1, 0x000000FF);
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT1, &val);
- if (err < 0)
+ if (err)
return err;
msleep(100);
} else {
@@ -940,7 +928,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_WDT_STATUS, &val);
- if (err < 0)
+ if (err)
return err;
/* Reset the bluetooth chip via USB interface. */
err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, 1);
@@ -950,13 +938,13 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT, &val);
- if (err < 0)
+ if (err)
return err;
err = btmtk_usb_uhw_reg_write(hdev, MTK_UDMA_INT_STA_BT1, 0x000000FF);
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT1, &val);
- if (err < 0)
+ if (err)
return err;
/* MT7921 need to delay 20ms between toggle reset bit */
msleep(20);
@@ -964,7 +952,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
if (err < 0)
return err;
err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
- if (err < 0)
+ if (err)
return err;
}
@@ -980,7 +968,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
}
err = btmtk_usb_id_get(hdev, 0x70010200, &val);
- if (err < 0 || (!val && dev_id != 0x6639))
+ if (err || (!val && dev_id != 0x6639))
bt_dev_err(hdev, "Can't get device id, subsys reset fail.");
return err;
@@ -1324,24 +1312,24 @@ int btmtk_usb_setup(struct hci_dev *hdev)
calltime = ktime_get();
err = btmtk_usb_id_get(hdev, 0x80000008, &dev_id);
- if (err < 0) {
+ if (err) {
bt_dev_err(hdev, "Failed to get device id (%d)", err);
return err;
}
if (!dev_id || dev_id != 0x7663) {
err = btmtk_usb_id_get(hdev, 0x70010200, &dev_id);
- if (err < 0) {
+ if (err) {
bt_dev_err(hdev, "Failed to get device id (%d)", err);
return err;
}
err = btmtk_usb_id_get(hdev, 0x80021004, &fw_version);
- if (err < 0) {
+ if (err) {
bt_dev_err(hdev, "Failed to get fw version (%d)", err);
return err;
}
err = btmtk_usb_id_get(hdev, 0x70010020, &fw_flavor);
- if (err < 0) {
+ if (err) {
bt_dev_err(hdev, "Failed to get fw flavor (%d)", err);
return err;
}
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 8f7ed469cac6..184e95c1625e 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -3424,28 +3424,16 @@ static const char *qca_get_fw_subdirectory(const struct qca_version *ver)
static int btusb_qca_send_vendor_req(struct usb_device *udev, u8 request,
void *data, u16 size)
{
- int pipe, err;
- u8 *buf;
-
- buf = kmalloc(size, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+ int err;
/* Found some of USB hosts have IOT issues with ours so that we should
* not wait until HCI layer is ready.
*/
- pipe = usb_rcvctrlpipe(udev, 0);
- err = usb_control_msg(udev, pipe, request, USB_TYPE_VENDOR | USB_DIR_IN,
- 0, 0, buf, size, USB_CTRL_GET_TIMEOUT);
- if (err < 0) {
+ err = usb_control_msg_recv(udev, 0, request, USB_TYPE_VENDOR | USB_DIR_IN,
+ 0, 0, data, size, USB_CTRL_GET_TIMEOUT,
+ GFP_KERNEL);
+ if (err)
dev_err(&udev->dev, "Failed to access otp area (%d)", err);
- goto done;
- }
-
- memcpy(data, buf, size);
-
-done:
- kfree(buf);
return err;
}
@@ -3652,7 +3640,7 @@ static bool btusb_qca_need_patch(struct usb_device *udev)
struct qca_version ver;
if (btusb_qca_send_vendor_req(udev, QCA_GET_TARGET_VERSION, &ver,
- sizeof(ver)) < 0)
+ sizeof(ver)))
return false;
/* only low ROM versions need patches */
return !(le32_to_cpu(ver.rom_version) & ~0xffffU);
@@ -3670,7 +3658,7 @@ static int btusb_setup_qca(struct hci_dev *hdev)
err = btusb_qca_send_vendor_req(udev, QCA_GET_TARGET_VERSION, &ver,
sizeof(ver));
- if (err < 0)
+ if (err)
return err;
ver_rom = le32_to_cpu(ver.rom_version);
@@ -3693,7 +3681,7 @@ static int btusb_setup_qca(struct hci_dev *hdev)
err = btusb_qca_send_vendor_req(udev, QCA_CHECK_STATUS, &status,
sizeof(status));
- if (err < 0)
+ if (err)
return err;
if (!(status & QCA_PATCH_UPDATED)) {
@@ -3704,7 +3692,7 @@ static int btusb_setup_qca(struct hci_dev *hdev)
err = btusb_qca_send_vendor_req(udev, QCA_GET_TARGET_VERSION, &ver,
sizeof(ver));
- if (err < 0)
+ if (err)
return err;
btdata->qca_dump.fw_version = le32_to_cpu(ver.patch_version);
diff --git a/drivers/dibs/dibs_loopback.c b/drivers/dibs/dibs_loopback.c
index 0f2e09311152..fd5caf1e19a8 100644
--- a/drivers/dibs/dibs_loopback.c
+++ b/drivers/dibs/dibs_loopback.c
@@ -118,14 +118,9 @@ err_bit:
return rc;
}
-static void __dibs_lo_unregister_dmb(struct dibs_lo_dev *ldev,
- struct dibs_lo_dmb_node *dmb_node)
+static void dibs_lo_free_dmb(struct dibs_lo_dev *ldev,
+ struct dibs_lo_dmb_node *dmb_node)
{
- /* remove dmb from hash table */
- write_lock_bh(&ldev->dmb_ht_lock);
- hash_del(&dmb_node->list);
- write_unlock_bh(&ldev->dmb_ht_lock);
-
clear_bit(dmb_node->sba_idx, ldev->sba_idx_mask);
folio_put(virt_to_folio(dmb_node->cpu_addr));
kfree(dmb_node);
@@ -139,27 +134,33 @@ static int dibs_lo_unregister_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
struct dibs_lo_dev *ldev;
unsigned long flags;
+ bool last;
ldev = dibs->drv_priv;
/* find dmb from hash table */
- read_lock_bh(&ldev->dmb_ht_lock);
+ write_lock_bh(&ldev->dmb_ht_lock);
hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
if (tmp_node->token == dmb->dmb_tok) {
dmb_node = tmp_node;
break;
}
}
- read_unlock_bh(&ldev->dmb_ht_lock);
- if (!dmb_node)
+ if (!dmb_node) {
+ write_unlock_bh(&ldev->dmb_ht_lock);
return -EINVAL;
+ }
+ last = refcount_dec_and_test(&dmb_node->refcnt);
+ if (last)
+ hash_del(&dmb_node->list);
+ write_unlock_bh(&ldev->dmb_ht_lock);
- if (refcount_dec_and_test(&dmb_node->refcnt)) {
+ if (last) {
spin_lock_irqsave(&dibs->lock, flags);
dibs->dmb_clientid_arr[dmb_node->sba_idx] = NO_DIBS_CLIENT;
spin_unlock_irqrestore(&dibs->lock, flags);
- __dibs_lo_unregister_dmb(ldev, dmb_node);
+ dibs_lo_free_dmb(ldev, dmb_node);
}
return 0;
}
@@ -188,14 +189,9 @@ static int dibs_lo_attach_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
read_unlock_bh(&ldev->dmb_ht_lock);
return -EINVAL;
}
+ refcount_inc(&dmb_node->refcnt);
read_unlock_bh(&ldev->dmb_ht_lock);
- if (!refcount_inc_not_zero(&dmb_node->refcnt))
- /* the dmb is being unregistered, but has
- * not been removed from the hash table.
- */
- return -EINVAL;
-
/* provide dmb information */
dmb->idx = dmb_node->sba_idx;
dmb->dmb_tok = dmb_node->token;
@@ -209,11 +205,12 @@ static int dibs_lo_detach_dmb(struct dibs_dev *dibs, u64 token)
{
struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
struct dibs_lo_dev *ldev;
+ bool last;
ldev = dibs->drv_priv;
/* find dmb_node according to dmb->dmb_tok */
- read_lock_bh(&ldev->dmb_ht_lock);
+ write_lock_bh(&ldev->dmb_ht_lock);
hash_for_each_possible(ldev->dmb_ht, tmp_node, list, token) {
if (tmp_node->token == token) {
dmb_node = tmp_node;
@@ -221,13 +218,17 @@ static int dibs_lo_detach_dmb(struct dibs_dev *dibs, u64 token)
}
}
if (!dmb_node) {
- read_unlock_bh(&ldev->dmb_ht_lock);
+ write_unlock_bh(&ldev->dmb_ht_lock);
return -EINVAL;
}
- read_unlock_bh(&ldev->dmb_ht_lock);
+ last = refcount_dec_and_test(&dmb_node->refcnt);
+ if (last)
+ hash_del(&dmb_node->list);
+ write_unlock_bh(&ldev->dmb_ht_lock);
+
+ if (last)
+ dibs_lo_free_dmb(ldev, dmb_node);
- if (refcount_dec_and_test(&dmb_node->refcnt))
- __dibs_lo_unregister_dmb(ldev, dmb_node);
return 0;
}
diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c
index 2e8690cb3c16..43d51d942ead 100644
--- a/drivers/dpll/dpll_core.c
+++ b/drivers/dpll/dpll_core.c
@@ -1142,6 +1142,33 @@ void *dpll_pin_on_pin_priv(struct dpll_pin *parent,
return reg->priv;
}
+/**
+ * dpll_pin_own_dpll_ref_first - find the first owner dpll ref of a pin
+ * @pin: pointer to a dpll pin
+ *
+ * Search pin's dpll_refs for a ref whose dpll matches the pin's
+ * (module, clock_id) tuple, i.e. the dpll registered by the driver
+ * that created the pin. This ensures pin-level attributes are
+ * reported and modified using the owner's ops even when the pin is
+ * also registered with dplls from other drivers.
+ *
+ * Return: pointer to the owner's dpll_pin_ref, or NULL if no
+ * owner ref is found.
+ */
+struct dpll_pin_ref *dpll_pin_own_dpll_ref_first(struct dpll_pin *pin)
+{
+ struct dpll_pin_ref *ref;
+ unsigned long i;
+
+ xa_for_each(&pin->dpll_refs, i, ref) {
+ if (ref->dpll->module == pin->module &&
+ ref->dpll->clock_id == pin->clock_id)
+ return ref;
+ }
+
+ return NULL;
+}
+
const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref)
{
struct dpll_pin_registration *reg;
diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h
index e24577113431..da8a369556ed 100644
--- a/drivers/dpll/dpll_core.h
+++ b/drivers/dpll/dpll_core.h
@@ -93,6 +93,7 @@ void *dpll_pin_on_pin_priv(struct dpll_pin *parent, struct dpll_pin *pin);
const struct dpll_device_ops *dpll_device_ops(struct dpll_device *dpll);
struct dpll_device *dpll_device_get_by_id(int id);
+struct dpll_pin_ref *dpll_pin_own_dpll_ref_first(struct dpll_pin *pin);
const struct dpll_pin_ops *dpll_pin_ops(struct dpll_pin_ref *ref);
struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs);
extern struct xarray dpll_device_xa;
diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c
index 5703667593a7..afb31c004038 100644
--- a/drivers/dpll/dpll_netlink.c
+++ b/drivers/dpll/dpll_netlink.c
@@ -699,7 +699,9 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
struct dpll_pin_ref *ref;
int ret;
- ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
+ ref = dpll_pin_own_dpll_ref_first(pin);
+ if (!ref)
+ ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
ASSERT_NOT_NULL(ref);
ret = dpll_msg_add_pin_handle(msg, pin);
@@ -1090,12 +1092,19 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
- if (!ops->frequency_set || !ops->frequency_get) {
- NL_SET_ERR_MSG(extack, "frequency set not supported by the device");
+ if ((!ops->frequency_set || !ops->frequency_get) &&
+ ref->dpll->module == pin->module &&
+ ref->dpll->clock_id == pin->clock_id) {
+ NL_SET_ERR_MSG(extack,
+ "frequency set not supported by the device");
return -EOPNOTSUPP;
}
}
- ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
+ ref = dpll_pin_own_dpll_ref_first(pin);
+ if (!ref) {
+ NL_SET_ERR_MSG(extack, "pin owner dpll not found");
+ return -ENODEV;
+ }
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
ret = ops->frequency_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
@@ -1109,6 +1118,8 @@ dpll_pin_freq_set(struct dpll_pin *pin, struct nlattr *a,
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
+ if (!ops->frequency_set)
+ continue;
dpll = ref->dpll;
ret = ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
dpll, dpll_priv(dpll), freq, extack);
@@ -1128,6 +1139,8 @@ rollback:
if (ref == failed)
break;
ops = dpll_pin_ops(ref);
+ if (!ops->frequency_set)
+ continue;
dpll = ref->dpll;
if (ops->frequency_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
dpll, dpll_priv(dpll), old_freq, extack))
@@ -1151,13 +1164,19 @@ dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
- if (!ops->esync_set || !ops->esync_get) {
+ if ((!ops->esync_set || !ops->esync_get) &&
+ ref->dpll->module == pin->module &&
+ ref->dpll->clock_id == pin->clock_id) {
NL_SET_ERR_MSG(extack,
"embedded sync feature is not supported by this device");
return -EOPNOTSUPP;
}
}
- ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
+ ref = dpll_pin_own_dpll_ref_first(pin);
+ if (!ref) {
+ NL_SET_ERR_MSG(extack, "pin owner dpll not found");
+ return -ENODEV;
+ }
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
ret = ops->esync_get(pin, dpll_pin_on_dpll_priv(dpll, pin), dpll,
@@ -1181,6 +1200,8 @@ dpll_pin_esync_set(struct dpll_pin *pin, struct nlattr *a,
void *pin_dpll_priv;
ops = dpll_pin_ops(ref);
+ if (!ops->esync_set)
+ continue;
dpll = ref->dpll;
pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
ret = ops->esync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll),
@@ -1204,6 +1225,8 @@ rollback:
if (ref == failed)
break;
ops = dpll_pin_ops(ref);
+ if (!ops->esync_set)
+ continue;
dpll = ref->dpll;
pin_dpll_priv = dpll_pin_on_dpll_priv(dpll, pin);
if (ops->esync_set(pin, pin_dpll_priv, dpll, dpll_priv(dpll),
@@ -1238,8 +1261,11 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
NL_SET_ERR_MSG(extack, "reference sync pin not available");
return -EINVAL;
}
- ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
- ASSERT_NOT_NULL(ref);
+ ref = dpll_pin_own_dpll_ref_first(pin);
+ if (!ref) {
+ NL_SET_ERR_MSG(extack, "pin owner dpll not found");
+ return -ENODEV;
+ }
ops = dpll_pin_ops(ref);
if (!ops->ref_sync_set || !ops->ref_sync_get) {
NL_SET_ERR_MSG(extack, "reference sync not supported by this pin");
@@ -1258,6 +1284,8 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin,
return 0;
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
+ if (!ops->ref_sync_set)
+ continue;
dpll = ref->dpll;
ret = ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
ref_sync_pin,
@@ -1280,6 +1308,8 @@ rollback:
if (ref == failed)
break;
ops = dpll_pin_ops(ref);
+ if (!ops->ref_sync_set)
+ continue;
dpll = ref->dpll;
if (ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
ref_sync_pin,
@@ -1471,12 +1501,18 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
- if (!ops->phase_adjust_set || !ops->phase_adjust_get) {
+ if ((!ops->phase_adjust_set || !ops->phase_adjust_get) &&
+ ref->dpll->module == pin->module &&
+ ref->dpll->clock_id == pin->clock_id) {
NL_SET_ERR_MSG(extack, "phase adjust not supported");
return -EOPNOTSUPP;
}
}
- ref = dpll_xa_ref_dpll_first(&pin->dpll_refs);
+ ref = dpll_pin_own_dpll_ref_first(pin);
+ if (!ref) {
+ NL_SET_ERR_MSG(extack, "pin owner dpll not found");
+ return -ENODEV;
+ }
ops = dpll_pin_ops(ref);
dpll = ref->dpll;
ret = ops->phase_adjust_get(pin, dpll_pin_on_dpll_priv(dpll, pin),
@@ -1491,6 +1527,8 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
xa_for_each(&pin->dpll_refs, i, ref) {
ops = dpll_pin_ops(ref);
+ if (!ops->phase_adjust_set)
+ continue;
dpll = ref->dpll;
ret = ops->phase_adjust_set(pin,
dpll_pin_on_dpll_priv(dpll, pin),
@@ -1513,6 +1551,8 @@ rollback:
if (ref == failed)
break;
ops = dpll_pin_ops(ref);
+ if (!ops->phase_adjust_set)
+ continue;
dpll = ref->dpll;
if (ops->phase_adjust_set(pin, dpll_pin_on_dpll_priv(dpll, pin),
dpll, dpll_priv(dpll), old_phase_adj,
diff --git a/drivers/net/can/c_can/c_can_main.c b/drivers/net/can/c_can/c_can_main.c
index 3702cac7fbf0..b3b321d9ce68 100644
--- a/drivers/net/can/c_can/c_can_main.c
+++ b/drivers/net/can/c_can/c_can_main.c
@@ -597,20 +597,20 @@ static int c_can_chip_config(struct net_device *dev)
return err;
/* enable automatic retransmission */
- priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_ENABLE_AR);
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_ENABLE_AR | CONTROL_INIT);
if ((priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) &&
(priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)) {
/* loopback + silent mode : useful for hot self-test */
- priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST | CONTROL_INIT);
priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK | TEST_SILENT);
} else if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
/* loopback mode : useful for self-test function */
- priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST | CONTROL_INIT);
priv->write_reg(priv, C_CAN_TEST_REG, TEST_LBACK);
} else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
/* silent mode : bus-monitoring mode */
- priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST);
+ priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_TEST | CONTROL_INIT);
priv->write_reg(priv, C_CAN_TEST_REG, TEST_SILENT);
}
diff --git a/drivers/net/can/ctucanfd/ctucanfd_base.c b/drivers/net/can/ctucanfd/ctucanfd_base.c
index 0ea1ff28dfce..07d4aa43c700 100644
--- a/drivers/net/can/ctucanfd/ctucanfd_base.c
+++ b/drivers/net/can/ctucanfd/ctucanfd_base.c
@@ -340,8 +340,8 @@ static void ctucan_set_mode(struct ctucan_priv *priv, const struct can_ctrlmode
(mode_reg & ~REG_MODE_FDE);
mode_reg = (mode->flags & CAN_CTRLMODE_PRESUME_ACK) ?
- (mode_reg | REG_MODE_ACF) :
- (mode_reg & ~REG_MODE_ACF);
+ (mode_reg | REG_MODE_STM) :
+ (mode_reg & ~REG_MODE_STM);
mode_reg = (mode->flags & CAN_CTRLMODE_FD_NON_ISO) ?
(mode_reg | REG_MODE_NISOFD) :
@@ -869,7 +869,7 @@ static void ctucan_err_interrupt(struct net_device *ndev, u32 isr)
break;
case CAN_STATE_ERROR_ACTIVE:
if (skb) {
- cf->can_id |= CAN_ERR_CNT;
+ cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT;
cf->data[1] = CAN_ERR_CRTL_ACTIVE;
cf->data[6] = bec.txerr;
cf->data[7] = bec.rxerr;
@@ -1136,8 +1136,12 @@ static irqreturn_t ctucan_interrupt(int irq, void *dev_id)
/* Error interrupts */
if (FIELD_GET(REG_INT_STAT_EWLI, isr) ||
FIELD_GET(REG_INT_STAT_FCSI, isr) ||
- FIELD_GET(REG_INT_STAT_ALI, isr)) {
- icr = isr & (REG_INT_STAT_EWLI | REG_INT_STAT_FCSI | REG_INT_STAT_ALI);
+ FIELD_GET(REG_INT_STAT_ALI, isr) ||
+ FIELD_GET(REG_INT_STAT_BEI, isr)) {
+ icr = isr & (REG_INT_STAT_EWLI |
+ REG_INT_STAT_FCSI |
+ REG_INT_STAT_ALI |
+ REG_INT_STAT_BEI);
ctucan_netdev_dbg(ndev, "some ERR interrupt: clearing 0x%08x\n", icr);
ctucan_write32(priv, CTUCANFD_INT_STAT, icr);
diff --git a/drivers/net/can/ctucanfd/ctucanfd_pci.c b/drivers/net/can/ctucanfd/ctucanfd_pci.c
index 625788fa8976..4b6db28f7b67 100644
--- a/drivers/net/can/ctucanfd/ctucanfd_pci.c
+++ b/drivers/net/can/ctucanfd/ctucanfd_pci.c
@@ -194,7 +194,7 @@ err_free_board:
pci_set_drvdata(pdev, NULL);
kfree(bdata);
err_pci_iounmap_bar0:
- pci_iounmap(pdev, cra_addr);
+ pci_iounmap(pdev, bar0_base);
err_pci_iounmap_bar1:
pci_iounmap(pdev, addr);
err_release_regions:
@@ -266,6 +266,7 @@ static const struct pci_device_id ctucan_pci_tbl[] = {
CTUCAN_WITH_CTUCAN_ID)},
{},
};
+MODULE_DEVICE_TABLE(pci, ctucan_pci_tbl);
static struct pci_driver ctucan_pci_driver = {
.name = KBUILD_MODNAME,
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index eaf8cac78038..fcc37b73ed43 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -2003,20 +2003,12 @@ static int rcar_canfd_global_init(struct rcar_canfd_global *gpriv)
u32 ch, sts;
int err;
- err = reset_control_reset(gpriv->rstc1);
- if (err)
- return err;
-
- err = reset_control_reset(gpriv->rstc2);
- if (err)
- goto fail_reset1;
-
/* Enable peripheral clock for register access */
err = clk_prepare_enable(gpriv->clkp);
if (err) {
dev_err(dev, "failed to enable peripheral clock: %pe\n",
ERR_PTR(err));
- goto fail_reset2;
+ return err;
}
/* Enable RAM clock */
@@ -2027,10 +2019,18 @@ static int rcar_canfd_global_init(struct rcar_canfd_global *gpriv)
goto fail_clk;
}
+ err = reset_control_reset(gpriv->rstc1);
+ if (err)
+ goto fail_ram_clk;
+
+ err = reset_control_reset(gpriv->rstc2);
+ if (err)
+ goto fail_reset1;
+
err = rcar_canfd_reset_controller(gpriv);
if (err) {
dev_err(dev, "reset controller failed: %pe\n", ERR_PTR(err));
- goto fail_ram_clk;
+ goto fail_reset2;
}
/* Controller in Global reset & Channel reset mode */
@@ -2068,14 +2068,14 @@ static int rcar_canfd_global_init(struct rcar_canfd_global *gpriv)
fail_mode:
rcar_canfd_disable_global_interrupts(gpriv);
-fail_ram_clk:
- clk_disable_unprepare(gpriv->clk_ram);
-fail_clk:
- clk_disable_unprepare(gpriv->clkp);
fail_reset2:
reset_control_assert(gpriv->rstc2);
fail_reset1:
reset_control_assert(gpriv->rstc1);
+fail_ram_clk:
+ clk_disable_unprepare(gpriv->clk_ram);
+fail_clk:
+ clk_disable_unprepare(gpriv->clkp);
return err;
}
@@ -2090,10 +2090,10 @@ static void rcar_canfd_global_deinit(struct rcar_canfd_global *gpriv, bool full)
rcar_canfd_set_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GSLPR);
}
- clk_disable_unprepare(gpriv->clk_ram);
- clk_disable_unprepare(gpriv->clkp);
reset_control_assert(gpriv->rstc2);
reset_control_assert(gpriv->rstc1);
+ clk_disable_unprepare(gpriv->clk_ram);
+ clk_disable_unprepare(gpriv->clkp);
}
static int rcar_canfd_probe(struct platform_device *pdev)
diff --git a/drivers/net/can/softing/softing_fw.c b/drivers/net/can/softing/softing_fw.c
index 721df91cdbfb..282570daf3ef 100644
--- a/drivers/net/can/softing/softing_fw.c
+++ b/drivers/net/can/softing/softing_fw.c
@@ -91,12 +91,12 @@ int softing_bootloader_command(struct softing *card, int16_t cmd,
return ret;
}
-static int fw_parse(const uint8_t **pmem, uint16_t *ptype, uint32_t *paddr,
- uint16_t *plen, const uint8_t **pdat)
+static int fw_parse(const u8 **pmem, const u8 *limit, u16 *ptype,
+ u32 *paddr, u16 *plen, const u8 **pdat)
{
uint16_t checksum[2];
- const uint8_t *mem;
- const uint8_t *end;
+ const u8 *mem;
+ const u8 *record_end;
/*
* firmware records are a binary, unaligned stream composed of:
@@ -114,14 +114,21 @@ static int fw_parse(const uint8_t **pmem, uint16_t *ptype, uint32_t *paddr,
* endianness & alignment.
*/
mem = *pmem;
+ /* A record needs an 8-byte prefix and a 2-byte checksum. */
+ if (mem > limit || limit - mem < 10)
+ return -EINVAL;
+
*ptype = le16_to_cpup((void *)&mem[0]);
*paddr = le32_to_cpup((void *)&mem[2]);
*plen = le16_to_cpup((void *)&mem[6]);
+ if (*plen > limit - mem - 10)
+ return -EINVAL;
+
*pdat = &mem[8];
/* verify checksum */
- end = &mem[8 + *plen];
- checksum[0] = le16_to_cpup((void *)end);
- for (checksum[1] = 0; mem < end; ++mem)
+ record_end = &mem[8 + *plen];
+ checksum[0] = le16_to_cpup((void *)record_end);
+ for (checksum[1] = 0; mem < record_end; ++mem)
checksum[1] += *mem;
if (checksum[0] != checksum[1])
return -EINVAL;
@@ -139,6 +146,7 @@ int softing_load_fw(const char *file, struct softing *card,
uint16_t type, len;
uint32_t addr;
uint8_t *buf = NULL, *new_buf;
+ s64 dpram_offset;
int buflen = 0;
int8_t type_end = 0;
@@ -153,7 +161,7 @@ int softing_load_fw(const char *file, struct softing *card,
mem = fw->data;
end = &mem[fw->size];
/* look for header record */
- ret = fw_parse(&mem, &type, &addr, &len, &dat);
+ ret = fw_parse(&mem, end, &type, &addr, &len, &dat);
if (ret < 0)
goto failed;
if (type != 0xffff)
@@ -164,7 +172,7 @@ int softing_load_fw(const char *file, struct softing *card,
}
/* ok, we had a header */
while (mem < end) {
- ret = fw_parse(&mem, &type, &addr, &len, &dat);
+ ret = fw_parse(&mem, end, &type, &addr, &len, &dat);
if (ret < 0)
goto failed;
if (type == 3) {
@@ -179,9 +187,13 @@ int softing_load_fw(const char *file, struct softing *card,
goto failed;
}
- if ((addr + len + offset) > size)
+ dpram_offset = (s64)addr + offset;
+ if (dpram_offset < 0 || dpram_offset > size ||
+ len > size - dpram_offset) {
+ ret = -EINVAL;
goto failed;
- memcpy_toio(&dpram[addr + offset], dat, len);
+ }
+ memcpy_toio(&dpram[dpram_offset], dat, len);
/* be sure to flush caches from IO space */
mb();
if (len > buflen) {
@@ -195,7 +207,7 @@ int softing_load_fw(const char *file, struct softing *card,
buf = new_buf;
}
/* verify record data */
- memcpy_fromio(buf, &dpram[addr + offset], len);
+ memcpy_fromio(buf, &dpram[dpram_offset], len);
if (memcmp(buf, dat, len)) {
/* is not ok */
dev_alert(&card->pdev->dev, "DPRAM readback failed\n");
@@ -237,7 +249,7 @@ int softing_load_app_fw(const char *file, struct softing *card)
mem = fw->data;
end = &mem[fw->size];
/* look for header record */
- ret = fw_parse(&mem, &type, &addr, &len, &dat);
+ ret = fw_parse(&mem, end, &type, &addr, &len, &dat);
if (ret)
goto failed;
ret = -EINVAL;
@@ -253,7 +265,7 @@ int softing_load_app_fw(const char *file, struct softing *card)
}
/* ok, we had a header */
while (mem < end) {
- ret = fw_parse(&mem, &type, &addr, &len, &dat);
+ ret = fw_parse(&mem, end, &type, &addr, &len, &dat);
if (ret)
goto failed;
@@ -279,6 +291,12 @@ int softing_load_app_fw(const char *file, struct softing *card)
/* work in 16bit (target) */
sum &= 0xffff;
+ if (card->pdat->app.offs > card->dpram_size ||
+ len > card->dpram_size - card->pdat->app.offs) {
+ ret = -EINVAL;
+ goto failed;
+ }
+
memcpy_toio(&card->dpram[card->pdat->app.offs], dat, len);
iowrite32(card->pdat->app.offs + card->pdat->app.addr,
&card->dpram[DPRAM_COMMAND + 2]);
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index 9b25dda7c183..24cf8f651f8f 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -409,6 +409,40 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
netif_rx(skb);
}
+static bool ems_usb_rx_msg_len_valid(struct ems_cpc_msg *msg)
+{
+ size_t len = msg->length;
+ size_t can_len;
+
+ switch (msg->type) {
+ case CPC_MSG_TYPE_CAN_STATE:
+ return len >= sizeof(msg->msg.can_state);
+
+ case CPC_MSG_TYPE_CAN_FRAME:
+ case CPC_MSG_TYPE_EXT_CAN_FRAME:
+ case CPC_MSG_TYPE_RTR_FRAME:
+ case CPC_MSG_TYPE_EXT_RTR_FRAME:
+ if (len < CPC_CAN_MSG_MIN_SIZE)
+ return false;
+
+ if (msg->type == CPC_MSG_TYPE_RTR_FRAME ||
+ msg->type == CPC_MSG_TYPE_EXT_RTR_FRAME)
+ return true;
+
+ can_len = can_cc_dlc2len(msg->msg.can_msg.length & 0xf);
+ return len >= CPC_CAN_MSG_MIN_SIZE + can_len;
+
+ case CPC_MSG_TYPE_CAN_FRAME_ERROR:
+ return len >= sizeof(msg->msg.error);
+
+ case CPC_MSG_TYPE_OVERRUN:
+ return len >= sizeof(msg->msg.overrun);
+
+ default:
+ return true;
+ }
+}
+
/*
* callback for bulk IN urb
*/
@@ -451,6 +485,15 @@ static void ems_usb_read_bulk_callback(struct urb *urb)
}
msg = (struct ems_cpc_msg *)&ibuf[start];
+ if (msg->length >
+ urb->actual_length - start - CPC_MSG_HEADER_LEN) {
+ netdev_err(netdev, "format error\n");
+ break;
+ }
+ if (!ems_usb_rx_msg_len_valid(msg)) {
+ netdev_err(netdev, "format error\n");
+ break;
+ }
switch (msg->type) {
case CPC_MSG_TYPE_CAN_STATE:
diff --git a/drivers/net/can/usb/etas_es58x/es58x_core.c b/drivers/net/can/usb/etas_es58x/es58x_core.c
index b259f6109808..e1724ae79c5a 100644
--- a/drivers/net/can/usb/etas_es58x/es58x_core.c
+++ b/drivers/net/can/usb/etas_es58x/es58x_core.c
@@ -1476,7 +1476,6 @@ static void es58x_read_bulk_callback(struct urb *urb)
dev_err_ratelimited(dev,
"Failed resubmitting read bulk urb: %pe\n",
ERR_PTR(ret));
- return;
free_urb:
usb_free_coherent(urb->dev, urb->transfer_buffer_length,
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index ec9a7cbbbc69..82508a865095 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -674,7 +674,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
if (hf->flags & GS_CAN_FLAG_FD) {
skb = alloc_canfd_skb(netdev, &cfd);
if (!skb)
- return;
+ goto resubmit_urb;
cfd->can_id = le32_to_cpu(hf->can_id);
cfd->len = data_length;
@@ -687,7 +687,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
} else {
skb = alloc_can_skb(netdev, &cf);
if (!skb)
- return;
+ goto resubmit_urb;
cf->can_id = le32_to_cpu(hf->can_id);
can_frame_set_cc_len(cf, hf->can_dlc, dev->can.ctrlmode);
diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
index e09d663e362f..efbb7bed34c9 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
@@ -1626,6 +1626,7 @@ static int kvaser_usb_hydra_get_busparams(struct kvaser_usb_net_priv *priv,
reinit_completion(&priv->get_busparams_comp);
err = kvaser_usb_send_cmd(dev, cmd, cmd_len);
+ kfree(cmd);
if (err)
return err;
diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
index df737cfc5ea0..a876c7819b81 100644
--- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
+++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
@@ -691,13 +691,22 @@ static int kvaser_usb_leaf_wait_cmd(const struct kvaser_usb *dev, u8 id,
continue;
}
- if (pos + tmp->len > actual_len) {
+ if (tmp->len < CMD_HEADER_LEN ||
+ tmp->len > actual_len - pos) {
dev_err_ratelimited(&dev->intf->dev,
"Format error\n");
break;
}
if (tmp->id == id) {
+ if (tmp->len > sizeof(*cmd)) {
+ dev_err_ratelimited(&dev->intf->dev,
+ "Received command %u too large (%u)\n",
+ tmp->id, tmp->len);
+ err = -EIO;
+ goto end;
+ }
+
memcpy(cmd, tmp, tmp->len);
goto end;
}
@@ -1737,7 +1746,7 @@ static void kvaser_usb_leaf_read_bulk_callback(struct kvaser_usb *dev,
continue;
}
- if (pos + cmd->len > len) {
+ if (cmd->len < CMD_HEADER_LEN || cmd->len > len - pos) {
dev_err_ratelimited(&dev->intf->dev, "Format error\n");
break;
}
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
index c7933d1acc99..55aad01cd8ca 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -470,7 +470,6 @@ static int peak_usb_start(struct peak_usb_device *dev)
netif_device_detach(dev->netdev);
usb_unanchor_urb(urb);
- kfree(buf);
usb_free_urb(urb);
break;
}
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
index ef9fd693e9bd..0d46f4ce5dca 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
@@ -566,6 +566,13 @@ static int pcan_usb_fd_decode_canmsg(struct pcan_usb_fd_if *usb_if,
dev->can.ctrlmode);
}
+ if (!(rx_msg_flags & PUCAN_MSG_RTR) &&
+ le16_to_cpu(rx_msg->size) - offsetof(struct pucan_rx_msg, d) <
+ cfd->len) {
+ kfree_skb(skb);
+ return -EBADMSG;
+ }
+
cfd->can_id = le32_to_cpu(rm->can_id);
if (rx_msg_flags & PUCAN_MSG_EXT_ID)
@@ -714,6 +721,24 @@ static void pcan_usb_fd_decode_ts(struct pcan_usb_fd_if *usb_if,
peak_usb_set_ts_now(&usb_if->time_ref, le32_to_cpu(ts->ts_low));
}
+static size_t pcan_usb_fd_rx_msg_min_size(u16 rx_msg_type)
+{
+ switch (rx_msg_type) {
+ case PUCAN_MSG_CAN_RX:
+ return offsetof(struct pucan_rx_msg, d);
+ case PCAN_UFD_MSG_CALIBRATION:
+ return sizeof(struct pcan_ufd_ts_msg);
+ case PUCAN_MSG_ERROR:
+ return sizeof(struct pucan_error_msg);
+ case PUCAN_MSG_STATUS:
+ return sizeof(struct pucan_status_msg);
+ case PCAN_UFD_MSG_OVERRUN:
+ return sizeof(struct pcan_ufd_ovr_msg);
+ default:
+ return sizeof(struct pucan_msg);
+ }
+}
+
/* callback for bulk IN urb */
static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb)
{
@@ -728,6 +753,12 @@ static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb)
msg_end = urb->transfer_buffer + urb->actual_length;
for (; msg_ptr < msg_end;) {
u16 rx_msg_type, rx_msg_size;
+ size_t rx_msg_min_size;
+
+ if (msg_end - msg_ptr < sizeof(*rx_msg)) {
+ err = -EBADMSG;
+ break;
+ }
rx_msg = (struct pucan_msg *)msg_ptr;
if (!rx_msg->size) {
@@ -739,13 +770,20 @@ static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb)
rx_msg_type = le16_to_cpu(rx_msg->type);
/* check if the record goes out of current packet */
- if (msg_ptr + rx_msg_size > msg_end) {
+ if (rx_msg_size > msg_end - msg_ptr) {
netdev_err(netdev,
"got frag rec: should inc usb rx buf sze\n");
err = -EBADMSG;
break;
}
+ rx_msg_min_size = pcan_usb_fd_rx_msg_min_size(rx_msg_type);
+ if (rx_msg_size < rx_msg_min_size) {
+ netdev_err(netdev, "got short rec\n");
+ err = -EBADMSG;
+ break;
+ }
+
switch (rx_msg_type) {
case PUCAN_MSG_CAN_RX:
err = pcan_usb_fd_decode_canmsg(usb_if, rx_msg);
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
index aefcded8e12a..b6be8c19e537 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
@@ -534,12 +534,18 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if,
struct pcan_usb_pro_rxmsg *rx)
{
const unsigned int ctrl_idx = (rx->len >> 4) & 0x0f;
- struct peak_usb_device *dev = usb_if->dev[ctrl_idx];
- struct net_device *netdev = dev->netdev;
+ struct peak_usb_device *dev;
+ struct net_device *netdev;
struct can_frame *can_frame;
struct sk_buff *skb;
struct skb_shared_hwtstamps *hwts;
+ if (ctrl_idx >= ARRAY_SIZE(usb_if->dev))
+ return -EINVAL;
+
+ dev = usb_if->dev[ctrl_idx];
+ netdev = dev->netdev;
+
skb = alloc_can_skb(netdev, &can_frame);
if (!skb)
return -ENOMEM;
@@ -573,14 +579,20 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if,
{
const u16 raw_status = le16_to_cpu(er->status);
const unsigned int ctrl_idx = (er->channel >> 4) & 0x0f;
- struct peak_usb_device *dev = usb_if->dev[ctrl_idx];
- struct net_device *netdev = dev->netdev;
+ struct peak_usb_device *dev;
+ struct net_device *netdev;
struct can_frame *can_frame;
enum can_state new_state = CAN_STATE_ERROR_ACTIVE;
u8 err_mask = 0;
struct sk_buff *skb;
struct skb_shared_hwtstamps *hwts;
+ if (ctrl_idx >= ARRAY_SIZE(usb_if->dev))
+ return -EINVAL;
+
+ dev = usb_if->dev[ctrl_idx];
+ netdev = dev->netdev;
+
/* nothing should be sent while in BUS_OFF state */
if (dev->can.state == CAN_STATE_BUS_OFF)
return 0;
diff --git a/drivers/net/dsa/mt7530-mdio.c b/drivers/net/dsa/mt7530-mdio.c
index 11ea924a9f35..784dd58a7158 100644
--- a/drivers/net/dsa/mt7530-mdio.c
+++ b/drivers/net/dsa/mt7530-mdio.c
@@ -55,8 +55,15 @@ mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
if (ret < 0)
return ret;
- lo = bus->read(bus, priv->mdiodev->addr, r);
- hi = bus->read(bus, priv->mdiodev->addr, 0x10);
+ ret = bus->read(bus, priv->mdiodev->addr, r);
+ if (ret < 0)
+ return ret;
+ lo = ret;
+
+ ret = bus->read(bus, priv->mdiodev->addr, 0x10);
+ if (ret < 0)
+ return ret;
+ hi = ret;
*val = (hi << 16) | (lo & 0xffff);
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 3c2a3029b10c..aa33d94e11b5 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -192,12 +192,6 @@ mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)
}
static u32
-_mt7530_unlocked_read(struct mt7530_dummy_poll *p)
-{
- return mt7530_mii_read(p->priv, p->reg);
-}
-
-static u32
_mt7530_read(struct mt7530_dummy_poll *p)
{
u32 val;
@@ -248,15 +242,20 @@ mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp)
{
u32 val;
int ret;
- struct mt7530_dummy_poll p;
/* Set the command operating upon the MAC address entries */
val = ATC_BUSY | ATC_MAT(0) | cmd;
mt7530_write(priv, MT7530_ATC, val);
- INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_ATC);
- ret = readx_poll_timeout(_mt7530_read, &p, val,
- !(val & ATC_BUSY), 20, 20000);
+ mt7530_mutex_lock(priv);
+
+ ret = regmap_read_poll_timeout(priv->regmap, MT7530_ATC, val,
+ !(val & ATC_BUSY), 20, 20000);
+ if (!ret)
+ ret = regmap_read(priv->regmap, MT7530_ATC, &val);
+
+ mt7530_mutex_unlock(priv);
+
if (ret < 0) {
dev_err(priv->dev, "reset timeout\n");
return ret;
@@ -265,7 +264,6 @@ mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp)
/* Additional sanity for read command if the specified
* entry is invalid
*/
- val = mt7530_read(priv, MT7530_ATC);
if ((cmd == MT7530_FDB_READ) && (val & ATC_INVALID))
return -EINVAL;
@@ -549,16 +547,13 @@ static int
mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
int regnum)
{
- struct mt7530_dummy_poll p;
u32 reg, val;
int ret;
- INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-
mt7530_mutex_lock(priv);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -568,8 +563,8 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
MT7531_MDIO_DEV_ADDR(devad) | regnum;
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -579,8 +574,8 @@ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
MT7531_MDIO_DEV_ADDR(devad);
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -597,16 +592,13 @@ static int
mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
int regnum, u16 data)
{
- struct mt7530_dummy_poll p;
u32 val, reg;
int ret;
- INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-
mt7530_mutex_lock(priv);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -616,8 +608,8 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
MT7531_MDIO_DEV_ADDR(devad) | regnum;
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -627,8 +619,8 @@ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
MT7531_MDIO_DEV_ADDR(devad) | data;
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -643,16 +635,13 @@ out:
static int
mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
{
- struct mt7530_dummy_poll p;
int ret;
u32 val;
- INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-
mt7530_mutex_lock(priv);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -663,8 +652,8 @@ mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
mt7530_mii_write(priv, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -681,16 +670,13 @@ static int
mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
u16 data)
{
- struct mt7530_dummy_poll p;
int ret;
u32 reg;
- INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-
mt7530_mutex_lock(priv);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
- !(reg & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, reg,
+ !(reg & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -701,8 +687,8 @@ mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
- !(reg & MT7531_PHY_ACS_ST), 20, 100000);
+ ret = regmap_read_poll_timeout(priv->regmap, MT7531_PHY_IAC, reg,
+ !(reg & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
@@ -1626,22 +1612,26 @@ mt7530_port_bridge_join(struct dsa_switch *ds, int port,
static int
mt7530_vlan_cmd(struct mt7530_priv *priv, enum mt7530_vlan_cmd cmd, u16 vid)
{
- struct mt7530_dummy_poll p;
u32 val;
int ret;
val = VTCR_BUSY | VTCR_FUNC(cmd) | vid;
mt7530_write(priv, MT7530_VTCR, val);
- INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_VTCR);
- ret = readx_poll_timeout(_mt7530_read, &p, val,
- !(val & VTCR_BUSY), 20, 20000);
+ mt7530_mutex_lock(priv);
+
+ ret = regmap_read_poll_timeout(priv->regmap, MT7530_VTCR, val,
+ !(val & VTCR_BUSY), 20, 20000);
+ if (!ret)
+ ret = regmap_read(priv->regmap, MT7530_VTCR, &val);
+
+ mt7530_mutex_unlock(priv);
+
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
return ret;
}
- val = mt7530_read(priv, MT7530_VTCR);
if (val & VTCR_INVALID) {
dev_err(priv->dev, "read VTCR invalid\n");
return -EINVAL;
diff --git a/drivers/net/dsa/realtek/rtl8365mb_main.c b/drivers/net/dsa/realtek/rtl8365mb_main.c
index 5ac091bf93c9..aa05375b090a 100644
--- a/drivers/net/dsa/realtek/rtl8365mb_main.c
+++ b/drivers/net/dsa/realtek/rtl8365mb_main.c
@@ -1988,16 +1988,19 @@ static void rtl8365mb_get_stats64(struct dsa_switch *ds, int port,
spin_unlock(&p->stats_lock);
}
-static void rtl8365mb_stats_setup(struct realtek_priv *priv)
+static int rtl8365mb_stats_setup(struct realtek_priv *priv)
{
struct rtl8365mb *mb = priv->chip_data;
struct dsa_switch *ds = &priv->ds;
struct dsa_port *dp;
+ int ret;
/* Per-chip global mutex to protect MIB counter access, since doing
* so requires accessing a series of registers in a particular order.
*/
- mutex_init(&mb->mib_lock);
+ ret = devm_mutex_init(priv->dev, &mb->mib_lock);
+ if (ret)
+ return ret;
dsa_switch_for_each_available_port(dp, ds) {
struct rtl8365mb_port *p = &mb->ports[dp->index];
@@ -2010,6 +2013,8 @@ static void rtl8365mb_stats_setup(struct realtek_priv *priv)
*/
INIT_DELAYED_WORK(&p->mib_work, rtl8365mb_stats_poll);
}
+
+ return 0;
}
static void rtl8365mb_stats_teardown(struct realtek_priv *priv)
@@ -2567,7 +2572,12 @@ static int rtl8365mb_setup(struct dsa_switch *ds)
}
/* Start statistics counter polling */
- rtl8365mb_stats_setup(priv);
+ ret = rtl8365mb_stats_setup(priv);
+ if (ret) {
+ dev_err(priv->dev, "failed to setup stats: %pe\n",
+ ERR_PTR(ret));
+ goto out_teardown_irq;
+ }
return 0;
diff --git a/drivers/net/dsa/realtek/rtl83xx.c b/drivers/net/dsa/realtek/rtl83xx.c
index 71124ecca92f..9dd50b20c000 100644
--- a/drivers/net/dsa/realtek/rtl83xx.c
+++ b/drivers/net/dsa/realtek/rtl83xx.c
@@ -156,9 +156,17 @@ rtl83xx_probe(struct device *dev,
if (!priv)
return ERR_PTR(-ENOMEM);
- mutex_init(&priv->map_lock);
- mutex_init(&priv->vlan_lock);
- mutex_init(&priv->l2_lock);
+ ret = devm_mutex_init(dev, &priv->map_lock);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = devm_mutex_init(dev, &priv->vlan_lock);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = devm_mutex_init(dev, &priv->l2_lock);
+ if (ret)
+ return ERR_PTR(ret);
rc.lock_arg = priv;
priv->map = devm_regmap_init(dev, NULL, priv, &rc);
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 9b09eb144b81..d7f5c6f16142 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -1222,11 +1222,11 @@ err_eeprom:
if (hw->flash_address)
iounmap(hw->flash_address);
+err_mdio_ioremap:
kfree(adapter->tx_ring);
kfree(adapter->rx_ring);
err_dma:
err_sw_init:
-err_mdio_ioremap:
iounmap(hw->ce4100_gbe_mdio_base_virt);
iounmap(hw->hw_addr);
err_ioremap:
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c
index 30c3a4db7d61..85a74cd6ea1f 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.c
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
@@ -793,7 +793,7 @@ err:
ret,
libie_aq_str(pf->hw.adminq.sq_last_status),
pin_type_name[pin_type], pin->idx);
- else
+ else if (pf->hw.adminq.sq_last_status != LIBIE_AQ_RC_EBUSY)
dev_err_ratelimited(ice_pf_to_dev(pf),
"err:%d %s failed to update %s pin:%u\n",
ret,
@@ -3024,7 +3024,8 @@ static int ice_dpll_pps_update_phase_offsets(struct ice_pf *pf,
*phase_offset_pins_updated = 0;
ret = ice_aq_get_cgu_input_pin_measure(&pf->hw, DPLL_TYPE_PPS, meas,
ARRAY_SIZE(meas));
- if (ret && pf->hw.adminq.sq_last_status == LIBIE_AQ_RC_EAGAIN) {
+ if (ret && (pf->hw.adminq.sq_last_status == LIBIE_AQ_RC_EAGAIN ||
+ pf->hw.adminq.sq_last_status == LIBIE_AQ_RC_EBUSY)) {
return 0;
} else if (ret) {
dev_err(ice_pf_to_dev(pf),
@@ -3086,10 +3087,12 @@ ice_dpll_update_state(struct ice_pf *pf, struct ice_dpll *d, bool init)
d->dpll_idx, d->prev_input_idx, d->input_idx,
d->dpll_state, d->prev_dpll_state, d->mode);
if (ret) {
- dev_err(ice_pf_to_dev(pf),
- "update dpll=%d state failed, ret=%d %s\n",
- d->dpll_idx, ret,
- libie_aq_str(pf->hw.adminq.sq_last_status));
+ /* EBUSY is expected during reset recovery, don't log error */
+ if (pf->hw.adminq.sq_last_status != LIBIE_AQ_RC_EBUSY)
+ dev_err(ice_pf_to_dev(pf),
+ "update dpll=%d state failed, ret=%d %s\n",
+ d->dpll_idx, ret,
+ libie_aq_str(pf->hw.adminq.sq_last_status));
return ret;
}
if (init) {
@@ -3158,7 +3161,9 @@ static void ice_dpll_periodic_work(struct kthread_work *work)
d->periodic_counter % dp->phase_offset_monitor_period == 0)
ret = ice_dpll_pps_update_phase_offsets(pf, &phase_offset_ntf);
if (ret) {
- d->cgu_state_acq_err_num++;
+ /* EBUSY is expected during reset recovery */
+ if (pf->hw.adminq.sq_last_status != LIBIE_AQ_RC_EBUSY)
+ d->cgu_state_acq_err_num++;
/* stop rescheduling this worker */
if (d->cgu_state_acq_err_num >
ICE_CGU_STATE_ACQ_ERR_THRESHOLD) {
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index 49371b065845..7eb380be7ed2 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -1069,18 +1069,18 @@ static int ice_lbtest_prepare_rings(struct ice_vsi *vsi)
status = ice_vsi_cfg_lan(vsi);
if (status)
- goto err_setup_rx_ring;
+ goto err_cfg_lan;
status = ice_vsi_start_all_rx_rings(vsi);
if (status)
- goto err_start_rx_ring;
+ goto err_cfg_lan;
return 0;
-err_start_rx_ring:
- ice_vsi_free_rx_rings(vsi);
-err_setup_rx_ring:
+err_cfg_lan:
ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, 0);
+err_setup_rx_ring:
+ ice_vsi_free_rx_rings(vsi);
err_setup_tx_ring:
ice_vsi_free_tx_rings(vsi);
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index e2fd2dab03e3..d88835482d3a 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -5637,6 +5637,16 @@ static int ice_resume(struct device *dev)
/* Restart the service task */
mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
+ /* Best-effort wait for the scheduled reset to finish so that the
+ * device is operational before returning. Without this, userspace
+ * (e.g. NetworkManager) may try to open the net device while the
+ * asynchronous reset is still in progress, hitting -EBUSY.
+ */
+ ret = ice_wait_for_reset(pf, secs_to_jiffies(10));
+ if (ret)
+ dev_err(dev, "Wait for reset timed out (10s) during resume: %d\n",
+ ret);
+
return 0;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
index 9052e71e9c99..a54cb2b8d3c7 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
@@ -849,6 +849,30 @@ static void ice_notify_vf_reset(struct ice_vf *vf)
}
/**
+ * ice_reset_interrupts - clear all queue interrupt configuration for a VSI
+ * @vsi: the VSI whose interrupt registers should be cleared
+ *
+ * Zero the QINT_RQCTL and QINT_TQCTL registers for all allocated queues
+ * in the VSI. This clears the entire register including MSIX_INDX, ITR_INDX,
+ * CAUSE_ENA and NEXTQ fields, unlike ice_vf_dis_rxq_interrupt() which only
+ * clears the CAUSE_ENA bit.
+ */
+void ice_reset_interrupts(struct ice_vsi *vsi)
+{
+ struct ice_pf *pf = vsi->back;
+ struct ice_hw *hw = &pf->hw;
+ int i;
+
+ ice_for_each_alloc_rxq(vsi, i)
+ wr32(hw, QINT_RQCTL(vsi->rxq_map[i]), 0);
+
+ ice_for_each_alloc_txq(vsi, i)
+ wr32(hw, QINT_TQCTL(vsi->txq_map[i]), 0);
+
+ ice_flush(hw);
+}
+
+/**
* ice_reset_vf - Reset a particular VF
* @vf: pointer to the VF structure
* @flags: flags controlling behavior of the reset
@@ -919,6 +943,9 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags)
ice_dis_vf_qs(vf);
+ /* cleanup interrupt registers */
+ ice_reset_interrupts(vsi);
+
/* Call Disable LAN Tx queue AQ whether or not queues are
* enabled. This is needed for successful completion of VFR.
*/
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h b/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h
index 5392b0404986..321d29c25b7c 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h
@@ -26,6 +26,7 @@
void ice_initialize_vf_entry(struct ice_vf *vf);
void ice_deinitialize_vf_entry(struct ice_vf *vf);
void ice_dis_vf_qs(struct ice_vf *vf);
+void ice_reset_interrupts(struct ice_vsi *vsi);
int ice_check_vf_init(struct ice_vf *vf);
enum virtchnl_status_code ice_err_to_virt_err(int err);
struct ice_port_info *ice_vf_get_port_info(struct ice_vf *vf);
diff --git a/drivers/net/ethernet/intel/ice/virt/queues.c b/drivers/net/ethernet/intel/ice/virt/queues.c
index 31be2f76181c..431c9c546b04 100644
--- a/drivers/net/ethernet/intel/ice/virt/queues.c
+++ b/drivers/net/ethernet/intel/ice/virt/queues.c
@@ -225,6 +225,24 @@ void ice_vf_ena_rxq_interrupt(struct ice_vsi *vsi, u32 q_idx)
}
/**
+ * ice_vf_dis_rxq_interrupt - disable Rx queue interrupt via QINT_RQCTL
+ * @vsi: VSI of the VF to configure
+ * @q_idx: VF queue index used to determine the queue in the PF's space
+ */
+static void ice_vf_dis_rxq_interrupt(struct ice_vsi *vsi, u32 q_idx)
+{
+ struct ice_hw *hw = &vsi->back->hw;
+ u32 pfq = vsi->rxq_map[q_idx];
+ u32 reg;
+
+ reg = rd32(hw, QINT_RQCTL(pfq));
+ reg &= ~QINT_RQCTL_CAUSE_ENA_M;
+ wr32(hw, QINT_RQCTL(pfq), reg);
+
+ ice_flush(hw);
+}
+
+/**
* ice_vc_ena_qs_msg
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
@@ -416,6 +434,8 @@ int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg)
goto error_param;
}
+ for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF)
+ ice_vf_dis_rxq_interrupt(vsi, vf_q_id);
bitmap_zero(vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF);
} else if (q_map) {
for_each_set_bit(vf_q_id, &q_map, ICE_MAX_RSS_QS_PER_VF) {
@@ -436,6 +456,7 @@ int ice_vc_dis_qs_msg(struct ice_vf *vf, u8 *msg)
goto error_param;
}
+ ice_vf_dis_rxq_interrupt(vsi, vf_q_id);
/* Clear enabled queues flag */
clear_bit(vf_q_id, vf->rxq_ena);
}
diff --git a/drivers/net/ethernet/intel/idpf/idpf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_dev.c
index 1a0c71c95ef1..4079a787657f 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c
@@ -87,7 +87,7 @@ static int idpf_intr_reg_init(struct idpf_vport *vport,
if (!reg_vals)
return -ENOMEM;
- num_regs = idpf_get_reg_intr_vecs(adapter, reg_vals);
+ num_regs = idpf_get_reg_intr_vecs(adapter, reg_vals, total_vecs);
if (num_regs < num_vecs) {
err = -EINVAL;
goto free_reg_vals;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index cf966fe6c759..bb81e620c5c8 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -139,7 +139,7 @@ static int idpf_mb_intr_req_irq(struct idpf_adapter *adapter)
if (err) {
dev_err(&adapter->pdev->dev,
"IRQ request for mailbox failed, error: %d\n", err);
-
+ kfree(name);
return err;
}
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 7f9056404f64..c724d429a7aa 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -3097,10 +3097,7 @@ static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb,
tx_params.dtype = IDPF_TX_DESC_DTYPE_FLEX_FLOW_SCHE;
tx_params.eop_cmd = IDPF_TXD_FLEX_FLOW_CMD_EOP;
- /* Set the RE bit to periodically "clean" the descriptor ring.
- * MIN_GAP is set to MIN_RING size to ensure it will be set at
- * least once each time around the ring.
- */
+ /* Set the RE bit periodically to "clean" the descriptor ring */
if (idpf_tx_splitq_need_re(tx_q)) {
tx_params.eop_cmd |= IDPF_TXD_FLEX_FLOW_CMD_RE;
tx_q->txq_grp->num_completions_pending++;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
index 4be5b3b6d3ed..908dfa28674e 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -21,7 +21,7 @@
/* Mailbox Queue */
#define IDPF_MAX_MBXQ 1
-#define IDPF_MIN_TXQ_DESC 64
+#define IDPF_MIN_TXQ_DESC 128
#define IDPF_MIN_RXQ_DESC 64
#define IDPF_MIN_TXQ_COMPLQ_DESC 256
#define IDPF_MAX_QIDS 256
diff --git a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
index a07d7e808ca9..6726084f6cfa 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c
@@ -86,7 +86,7 @@ static int idpf_vf_intr_reg_init(struct idpf_vport *vport,
if (!reg_vals)
return -ENOMEM;
- num_regs = idpf_get_reg_intr_vecs(adapter, reg_vals);
+ num_regs = idpf_get_reg_intr_vecs(adapter, reg_vals, total_vecs);
if (num_regs < num_vecs) {
err = -EINVAL;
goto free_reg_vals;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index dc5ad784f456..8bd6cca64c9b 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -1318,11 +1318,12 @@ idpf_vport_init_queue_reg_chunks(struct idpf_vport_config *vport_config,
* idpf_get_reg_intr_vecs - Get vector queue register offset
* @adapter: adapter structure to get the vector chunks
* @reg_vals: Register offsets to store in
+ * @num_vecs: number of entries the @reg_vals array can hold
*
* Return: number of registers that got populated
*/
int idpf_get_reg_intr_vecs(struct idpf_adapter *adapter,
- struct idpf_vec_regs *reg_vals)
+ struct idpf_vec_regs *reg_vals, int num_vecs)
{
struct virtchnl2_vector_chunks *chunks;
struct idpf_vec_regs reg_val;
@@ -1346,7 +1347,7 @@ int idpf_get_reg_intr_vecs(struct idpf_adapter *adapter,
dynctl_reg_spacing = le32_to_cpu(chunk->dynctl_reg_spacing);
itrn_reg_spacing = le32_to_cpu(chunk->itrn_reg_spacing);
- for (i = 0; i < num_vec; i++) {
+ for (i = 0; i < num_vec && num_regs < num_vecs; i++) {
reg_vals[num_regs].dyn_ctl_reg = reg_val.dyn_ctl_reg;
reg_vals[num_regs].itrn_reg = reg_val.itrn_reg;
reg_vals[num_regs].itrn_index_spacing =
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
index 6876e3ed9d1b..9b1c9c86f6ea 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h
@@ -104,7 +104,7 @@ int idpf_vc_core_init(struct idpf_adapter *adapter);
void idpf_vc_core_deinit(struct idpf_adapter *adapter);
int idpf_get_reg_intr_vecs(struct idpf_adapter *adapter,
- struct idpf_vec_regs *reg_vals);
+ struct idpf_vec_regs *reg_vals, int num_vecs);
int idpf_queue_reg_init(struct idpf_vport *vport,
struct idpf_q_vec_rsrc *rsrc,
struct idpf_queue_id_reg_info *chunks);
diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
index 0a3d0a1cba43..c686ee120a14 100644
--- a/drivers/net/ethernet/intel/igbvf/netdev.c
+++ b/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -2190,8 +2190,6 @@ dma_error:
buffer_info->time_stamp = 0;
buffer_info->length = 0;
buffer_info->mapped_as_page = false;
- if (count)
- count--;
/* clear timestamp and dma mappings for remaining portion of packet */
while (count--) {
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 2c9e2dfd8499..b3883a5a7d7a 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -5352,9 +5352,8 @@ void igc_down(struct igc_adapter *adapter)
for (i = 0; i < adapter->num_q_vectors; i++) {
if (adapter->q_vector[i]) {
- napi_synchronize(&adapter->q_vector[i]->napi);
- igc_set_queue_napi(adapter, i, NULL);
napi_disable(&adapter->q_vector[i]->napi);
+ igc_set_queue_napi(adapter, i, NULL);
}
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
index 2e94d5105016..f5fd6138c352 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c
@@ -518,6 +518,18 @@ int cgx_set_pkind(void *cgxd, u8 lmac_id, int pkind)
return 0;
}
+int cgx_get_pkind(void *cgxd, u8 lmac_id, int *pkind)
+{
+ struct cgx *cgx = cgxd;
+
+ if (!is_lmac_valid(cgx, lmac_id))
+ return -ENODEV;
+
+ *pkind = cgx_read(cgx, lmac_id, cgx->mac_ops->rxid_map_offset);
+ *pkind = *pkind & 0x3F;
+ return 0;
+}
+
static u8 cgx_get_lmac_type(void *cgxd, int lmac_id)
{
struct cgx *cgx = cgxd;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
index 92ccf343dfe0..8411a75dd723 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h
@@ -141,6 +141,7 @@ int cgx_get_cgxid(void *cgxd);
int cgx_get_lmac_cnt(void *cgxd);
void *cgx_get_pdata(int cgx_id);
int cgx_set_pkind(void *cgxd, u8 lmac_id, int pkind);
+int cgx_get_pkind(void *cgxd, u8 lmac_id, int *pkind);
int cgx_lmac_evh_register(struct cgx_event_cb *cb, void *cgxd, int lmac_id);
int cgx_lmac_evh_unregister(void *cgxd, int lmac_id);
int cgx_get_tx_stats(void *cgxd, int lmac_id, int idx, u64 *tx_stat);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index 7f3505ae6860..9d5b7b51bdfa 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -1115,6 +1115,8 @@ void npc_read_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
u8 *intf, u8 *ena);
int npc_config_cntr_default_entries(struct rvu *rvu, bool enable);
bool is_cgx_config_permitted(struct rvu *rvu, u16 pcifunc);
+bool rvu_cgx_check_permission_and_set_pkind(struct rvu *rvu, u16 pcifunc, int pkind);
+bool rvu_cgx_is_pkind_config_permitted(struct rvu *rvu, u16 pcifunc);
bool is_mac_feature_supported(struct rvu *rvu, int pf, int feature);
u32 rvu_cgx_get_fifolen(struct rvu *rvu);
void *rvu_first_cgx_pdata(struct rvu *rvu);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
index 4ff3935ed3fe..87d21889dc49 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
@@ -1355,3 +1355,82 @@ void rvu_mac_reset(struct rvu *rvu, u16 pcifunc)
if (mac_ops->mac_reset(cgxd, lmac, !is_vf(pcifunc)))
dev_err(rvu->dev, "Failed to reset MAC\n");
}
+
+/* Do not allow CGX-mapped VFs to overwrite PKIND when special parse kinds
+ * (HiGig, EDSA, etc.) are in use on the shared LMAC. VFs must not program
+ * NPC_TX_DEF_PKIND on NIX_AF_LFX_TX_PARSE_CFG in that case: the PF owns
+ * parse mode and no separate NPC_TX_HIGIG_PKIND is installed on the VF LF.
+ * TX-parse callers skip the write when denied; rvu_lf_reset() clears each LF
+ * before alloc so the next permitted owner programs NPC_TX_DEF_PKIND.
+ */
+bool rvu_cgx_is_pkind_config_permitted(struct rvu *rvu, u16 pcifunc)
+{
+ int pf, err, rxpkind;
+ u8 cgx_id, lmac_id;
+ void *cgxd;
+
+ pf = rvu_get_pf(rvu->pdev, pcifunc);
+
+ if (!(pcifunc & RVU_PFVF_FUNC_MASK))
+ return true;
+
+ if (!is_pf_cgxmapped(rvu, pf))
+ return true;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+ cgxd = rvu_cgx_pdata(cgx_id, rvu);
+ err = cgx_get_pkind(cgxd, lmac_id, &rxpkind);
+ if (err)
+ return false;
+
+ switch (rxpkind) {
+ case NPC_RX_HIGIG_PKIND:
+ case NPC_RX_EDSA_PKIND:
+ return false;
+ default:
+ return true;
+ }
+}
+
+/* Do not allow CGX-mapped VFs to overwrite PKIND when special parse kinds
+ * (HiGig, EDSA, etc.) are in use on the shared LMAC.
+ */
+bool rvu_cgx_check_permission_and_set_pkind(struct rvu *rvu, u16 pcifunc, int pkind)
+{
+ int pf, err, rxpkind;
+ u8 cgx_id, lmac_id;
+ struct cgx *cgxd;
+
+ pf = rvu_get_pf(rvu->pdev, pcifunc);
+
+ if (!is_pf_cgxmapped(rvu, pf))
+ return false;
+
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+ cgxd = rvu_cgx_pdata(cgx_id, rvu);
+
+ mutex_lock(&cgxd->lock);
+ if (!is_vf(pcifunc))
+ goto set;
+
+ err = cgx_get_pkind(cgxd, lmac_id, &rxpkind);
+ if (err)
+ goto err;
+
+ switch (rxpkind) {
+ case NPC_RX_HIGIG_PKIND:
+ case NPC_RX_EDSA_PKIND:
+ goto err;
+ default:
+ break;
+ }
+
+set:
+ cgx_set_pkind(rvu_cgx_pdata(cgx_id, rvu), lmac_id, pkind);
+ mutex_unlock(&cgxd->lock);
+ return true;
+
+err:
+ mutex_unlock(&cgxd->lock);
+ return false;
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index 6a0ce2665031..964bcaae098e 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -363,8 +363,8 @@ static int nix_interface_init(struct rvu *rvu, u16 pcifunc, int type, int nixlf,
pfvf->tx_chan_cnt = 1;
rsp->tx_link = cgx_id * hw->lmac_per_cgx + lmac_id;
- cgx_set_pkind(rvu_cgx_pdata(cgx_id, rvu), lmac_id, pkind);
- rvu_npc_set_pkind(rvu, pkind, pfvf);
+ if (rvu_cgx_check_permission_and_set_pkind(rvu, pcifunc, pkind))
+ rvu_npc_set_pkind(rvu, pkind, pfvf);
break;
case NIX_INTF_TYPE_LBK:
vf = (pcifunc & RVU_PFVF_FUNC_MASK) - 1;
@@ -1505,13 +1505,15 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
struct nix_lf_alloc_req *req,
struct nix_lf_alloc_rsp *rsp)
{
- int nixlf, qints, hwctx_size, intf, rc = 0;
+ int nixlf, qints, hwctx_size, intf, rc = 0, pf;
u16 bcast, mcast, promisc, ucast;
struct rvu_hwinfo *hw = rvu->hw;
u16 pcifunc = req->hdr.pcifunc;
+ u8 cgx_id = 0, lmac_id = 0;
bool rules_created = false;
struct rvu_block *block;
struct rvu_pfvf *pfvf;
+ struct cgx *cgxd;
u64 cfg, ctx_cfg;
int blkaddr;
@@ -1685,8 +1687,20 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
rvu_write64(rvu, blkaddr, NIX_AF_LFX_RX_CFG(nixlf), req->rx_cfg);
/* Configure pkind for TX parse config */
+
+ pf = rvu_get_pf(rvu->pdev, pcifunc);
cfg = NPC_TX_DEF_PKIND;
- rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf), cfg);
+
+ if (is_pf_cgxmapped(rvu, pf) && is_vf(pcifunc)) {
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
+ cgxd = rvu_cgx_pdata(cgx_id, rvu);
+ mutex_lock(&cgxd->lock);
+ if (rvu_cgx_is_pkind_config_permitted(rvu, pcifunc))
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf), cfg);
+ mutex_unlock(&cgxd->lock);
+ } else {
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf), cfg);
+ }
if (is_rep_dev(rvu, pcifunc)) {
pfvf->tx_chan_base = RVU_SWITCH_LBK_CHAN;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index c7bc0b3a29b9..38554d51164e 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -19,6 +19,7 @@
#include "cn20k/npc.h"
#include "rvu_npc.h"
#include "cn20k/reg.h"
+#include "lmac_common.h"
#define RSVD_MCAM_ENTRIES_PER_PF 3 /* Broadcast, Promisc and AllMulticast */
#define RSVD_MCAM_ENTRIES_PER_NIXLF 1 /* Ucast for LFs */
@@ -4200,10 +4201,11 @@ int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir,
{
struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
- int blkaddr, nixlf, rc, intf_mode;
int pf = rvu_get_pf(rvu->pdev, pcifunc);
+ int blkaddr, nixlf, rc, intf_mode;
+ u8 cgx_id = 0, lmac_id = 0;
u64 rxpkind, txpkind;
- u8 cgx_id, lmac_id;
+ struct cgx *cgxd;
/* use default pkind to disable edsa/higig */
rxpkind = rvu_npc_get_pkind(rvu, pf);
@@ -4227,12 +4229,8 @@ int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir,
/* rx pkind set req valid only for cgx mapped PFs */
if (!is_cgx_config_permitted(rvu, pcifunc))
return 0;
- rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
-
- rc = cgx_set_pkind(rvu_cgx_pdata(cgx_id, rvu), lmac_id,
- rxpkind);
- if (rc)
- return rc;
+ if (!rvu_cgx_check_permission_and_set_pkind(rvu, pcifunc, rxpkind))
+ return -EINVAL;
}
if (dir & PKIND_TX) {
@@ -4241,8 +4239,19 @@ int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir,
if (rc)
return rc;
- rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf),
- txpkind);
+ if (is_pf_cgxmapped(rvu, pf) && is_vf(pcifunc)) {
+ rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id,
+ &lmac_id);
+ cgxd = rvu_cgx_pdata(cgx_id, rvu);
+ mutex_lock(&cgxd->lock);
+ if (rvu_cgx_is_pkind_config_permitted(rvu, pcifunc))
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf),
+ txpkind);
+ mutex_unlock(&cgxd->lock);
+ } else {
+ rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf),
+ txpkind);
+ }
}
pfvf->intf_mode = intf_mode;
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
index 2e33b33ec993..c995f2900859 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
@@ -889,8 +889,8 @@ static void otx2_handle_link_event(struct otx2_nic *pf)
netif_carrier_on(netdev);
netif_tx_start_all_queues(netdev);
} else {
- netif_tx_stop_all_queues(netdev);
netif_carrier_off(netdev);
+ netif_tx_stop_all_queues(netdev);
}
}
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 5d291e50a47b..351444fb4871 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -3467,7 +3467,7 @@ static void mtk_poll_controller(struct net_device *dev)
mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask);
- mtk_handle_irq_rx(eth->irq[MTK_FE_IRQ_RX], dev);
+ mtk_handle_irq_rx(eth->irq[MTK_FE_IRQ_RX], eth);
mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index d507289096c2..6867a5aed42c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -984,7 +984,6 @@ struct mlx5e_priv {
struct mlx5e_mqprio_rl *mqprio_rl;
struct dentry *dfs_root;
struct mlx5_devcom_comp_dev *devcom;
- struct ethtool_fec_hist_range *fec_ranges;
};
static inline u16 mlx5e_stats_nch_read(const struct mlx5e_priv *priv)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index c1acb9012d3f..7d47a1da8b6b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -6415,14 +6415,8 @@ int mlx5e_priv_init(struct mlx5e_priv *priv,
if (!priv->channel_stats)
goto err_free_tx_rates;
- priv->fec_ranges = kzalloc_objs(*priv->fec_ranges, ETHTOOL_FEC_HIST_MAX);
- if (!priv->fec_ranges)
- goto err_free_channel_stats;
-
return 0;
-err_free_channel_stats:
- kfree(priv->channel_stats);
err_free_tx_rates:
kfree(priv->tx_rates);
err_free_txq2sq_stats:
@@ -6447,7 +6441,6 @@ void mlx5e_priv_cleanup(struct mlx5e_priv *priv)
if (!priv->mdev)
return;
- kfree(priv->fec_ranges);
for (i = 0; i < priv->stats_nch; i++)
kvfree(priv->channel_stats[i]);
kfree(priv->channel_stats);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
index de38b60806c2..e7e6db7f6bf1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
@@ -1550,7 +1550,7 @@ static bool fec_rs_validate_hist_type(int mode, int hist_type)
static u8
fec_rs_histogram_fill_ranges(struct mlx5e_priv *priv, int mode,
- const struct ethtool_fec_hist_range **ranges)
+ struct ethtool_fec_hist_range *ranges)
{
struct mlx5_core_dev *mdev = priv->mdev;
u32 out[MLX5_ST_SZ_DW(pphcr_reg)] = {0};
@@ -1558,8 +1558,6 @@ fec_rs_histogram_fill_ranges(struct mlx5e_priv *priv, int mode,
int sz = MLX5_ST_SZ_BYTES(pphcr_reg);
u8 hist_type, num_of_bins;
- memset(priv->fec_ranges, 0,
- ETHTOOL_FEC_HIST_MAX * sizeof(*priv->fec_ranges));
MLX5_SET(pphcr_reg, in, local_port, 1);
if (mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPHCR, 0, 0))
return 0;
@@ -1575,12 +1573,11 @@ fec_rs_histogram_fill_ranges(struct mlx5e_priv *priv, int mode,
for (int i = 0; i < num_of_bins; i++) {
void *bin_range = MLX5_ADDR_OF(pphcr_reg, out, bin_range[i]);
- priv->fec_ranges[i].high = MLX5_GET(bin_range_layout, bin_range,
- high_val);
- priv->fec_ranges[i].low = MLX5_GET(bin_range_layout, bin_range,
- low_val);
+ ranges[i].high = MLX5_GET(bin_range_layout, bin_range,
+ high_val);
+ ranges[i].low = MLX5_GET(bin_range_layout, bin_range,
+ low_val);
}
- *ranges = priv->fec_ranges;
return num_of_bins;
}
@@ -1622,10 +1619,12 @@ static void fec_set_histograms_stats(struct mlx5e_priv *priv, int mode,
case MLX5E_FEC_LLRS_272_257_1:
case MLX5E_FEC_RS_544_514_INTERLEAVED_QUAD:
num_of_bins =
- fec_rs_histogram_fill_ranges(priv, mode, &hist->ranges);
- if (num_of_bins)
+ fec_rs_histogram_fill_ranges(priv, mode, hist->ranges_buf);
+ if (num_of_bins) {
+ hist->ranges = hist->ranges_buf;
return fec_rs_histogram_fill_stats(priv, num_of_bins,
hist);
+ }
break;
default:
return;
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 9d9bfd116dab..92bb55935c1c 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -2829,7 +2829,7 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,
rxq = kvzalloc_flex(*rxq, rx_oobs, apc->rx_queue_size);
if (!rxq)
- return NULL;
+ return ERR_PTR(-ENOMEM);
rxq->ndev = ndev;
rxq->num_rx_buf = apc->rx_queue_size;
@@ -2930,7 +2930,7 @@ out:
mana_destroy_rxq(apc, rxq, false);
- return NULL;
+ return ERR_PTR(err);
}
static void mana_create_rxq_debugfs(struct mana_port_context *apc, int idx)
@@ -2964,8 +2964,8 @@ static int mana_add_rx_queues(struct mana_port_context *apc,
for (i = 0; i < apc->num_queues; i++) {
rxq = mana_create_rxq(apc, i, &apc->eqs[i], ndev);
- if (!rxq) {
- err = -ENOMEM;
+ if (IS_ERR(rxq)) {
+ err = PTR_ERR(rxq);
netdev_err(ndev, "Failed to create rxq %d : %d\n", i, err);
goto out;
}
diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c
index 5b0435d7bc39..58d3e55def48 100644
--- a/drivers/net/ethernet/nvidia/forcedeth.c
+++ b/drivers/net/ethernet/nvidia/forcedeth.c
@@ -6187,10 +6187,10 @@ static void nv_remove(struct pci_dev *pci_dev)
struct net_device *dev = pci_get_drvdata(pci_dev);
struct fe_priv *np = netdev_priv(dev);
- free_percpu(np->txrx_stats);
-
unregister_netdev(dev);
+ free_percpu(np->txrx_stats);
+
nv_restore_mac_addr(pci_dev);
/* restore any phy related changes */
diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c
index cb0ae0650905..7ed17faced54 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_main.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_main.c
@@ -107,7 +107,7 @@ static void qede_remove(struct pci_dev *pdev);
static void qede_shutdown(struct pci_dev *pdev);
static void qede_link_update(void *dev, struct qed_link_output *link);
static void qede_schedule_recovery_handler(void *dev);
-static void qede_recovery_handler(struct qede_dev *edev);
+static bool qede_recovery_handler(struct qede_dev *edev);
static void qede_schedule_hw_err_handler(void *dev,
enum qed_hw_err_type err_type);
static void qede_get_eth_tlv_data(void *edev, void *data);
@@ -1043,21 +1043,6 @@ void __qede_unlock(struct qede_dev *edev)
mutex_unlock(&edev->qede_lock);
}
-/* This version of the lock should be used when acquiring the RTNL lock is also
- * needed in addition to the internal qede lock.
- */
-static void qede_lock(struct qede_dev *edev)
-{
- rtnl_lock();
- __qede_lock(edev);
-}
-
-static void qede_unlock(struct qede_dev *edev)
-{
- __qede_unlock(edev);
- rtnl_unlock();
-}
-
static void qede_periodic_task(struct work_struct *work)
{
struct qede_dev *edev = container_of(work, struct qede_dev,
@@ -1094,6 +1079,8 @@ static void qede_sp_task(struct work_struct *work)
*/
if (test_and_clear_bit(QEDE_SP_RECOVERY, &edev->sp_flags)) {
+ bool reloaded;
+
cancel_delayed_work_sync(&edev->periodic_task);
#ifdef CONFIG_QED_SRIOV
/* SRIOV must be disabled outside the lock to avoid a deadlock.
@@ -1102,9 +1089,17 @@ static void qede_sp_task(struct work_struct *work)
if (pci_num_vf(edev->pdev))
qede_sriov_configure(edev->pdev, 0);
#endif
- qede_lock(edev);
- qede_recovery_handler(edev);
- qede_unlock(edev);
+ rtnl_lock();
+ __qede_lock(edev);
+ reloaded = qede_recovery_handler(edev);
+ __qede_unlock(edev);
+
+ /* The udp_tunnel core synchronously calls back into
+ * qede_udp_tunnel_sync(), which takes the qede lock.
+ */
+ if (reloaded)
+ udp_tunnel_nic_reset_ntf(edev->ndev);
+ rtnl_unlock();
}
__qede_lock(edev);
@@ -2645,9 +2640,13 @@ static void qede_recovery_failed(struct qede_dev *edev)
edev->ops->common->set_power_state(edev->cdev, PCI_D3hot);
}
-static void qede_recovery_handler(struct qede_dev *edev)
+/* Returns true if an open device was successfully reloaded and its
+ * udp_tunnel ports need to be re-synced by the caller.
+ */
+static bool qede_recovery_handler(struct qede_dev *edev)
{
u32 curr_state = edev->state;
+ bool reloaded = false;
int rc;
DP_NOTICE(edev, "Starting a recovery process\n");
@@ -2677,17 +2676,18 @@ static void qede_recovery_handler(struct qede_dev *edev)
goto err;
qede_config_rx_mode(edev->ndev);
- udp_tunnel_nic_reset_ntf(edev->ndev);
+ reloaded = true;
}
edev->state = curr_state;
DP_NOTICE(edev, "Recovery handling is done\n");
- return;
+ return reloaded;
err:
qede_recovery_failed(edev);
+ return false;
}
static void qede_atomic_hw_err_handler(struct qede_dev *edev)
diff --git a/drivers/net/ethernet/realtek/rtase/rtase_main.c b/drivers/net/ethernet/realtek/rtase/rtase_main.c
index 4168ad9e48ea..e3cd4f7c1380 100644
--- a/drivers/net/ethernet/realtek/rtase/rtase_main.c
+++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c
@@ -1623,6 +1623,9 @@ static netdev_tx_t rtase_start_xmit(struct sk_buff *skb,
err_dma_1:
ring->skbuff[entry] = NULL;
rtase_tx_clear_range(ring, ring->cur_idx + 1, frags);
+ if (frags)
+ /* the frags were cleared above, along with the skb */
+ return NETDEV_TX_OK;
err_dma_0:
tp->stats.tx_dropped++;
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
index 5051ada43d2f..70cf3619555f 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
@@ -597,14 +597,13 @@ static int init_dma_desc_rings(struct net_device *netd)
return 0;
-txalloc_err:
- while (queue_num--)
- free_tx_ring(priv->device, priv->txq[queue_num], tx_rsize);
- return ret;
-
rxalloc_err:
while (queue_num--)
free_rx_ring(priv->device, priv->rxq[queue_num], rx_rsize);
+ queue_num = SXGBE_TX_QUEUES;
+txalloc_err:
+ while (queue_num--)
+ free_tx_ring(priv->device, priv->txq[queue_num], tx_rsize);
return ret;
}
@@ -1079,7 +1078,9 @@ static int sxgbe_open(struct net_device *dev)
priv->dma_buf_sz = SXGBE_ALIGN(DMA_BUFFER_SIZE);
priv->tx_tc = TC_DEFAULT;
priv->rx_tc = TC_DEFAULT;
- init_dma_desc_rings(dev);
+ ret = init_dma_desc_rings(dev);
+ if (ret)
+ goto init_phy_error;
/* DMA initialization and SW reset */
ret = sxgbe_init_dma_engine(priv);
@@ -1188,6 +1189,7 @@ static int sxgbe_open(struct net_device *dev)
init_error:
free_dma_desc_resources(priv);
+init_phy_error:
if (dev->phydev)
phy_disconnect(dev->phydev);
phy_error:
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 151c77713025..3801f9d45278 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -755,7 +755,8 @@ static int stmmac_hwtstamp_set(struct net_device *dev,
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
ptp_v2 = PTP_TCR_TSVER2ENA;
snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
- if (priv->synopsys_id < DWMAC_CORE_4_10)
+ if (priv->synopsys_id < DWMAC_CORE_3_70 &&
+ priv->plat->core_type != DWMAC_CORE_XGMAC)
ts_event_en = PTP_TCR_TSEVNTENA;
ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
index 814d88d2aee4..5d99e870de5e 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
@@ -1606,6 +1606,8 @@ static netdev_tx_t wx_xmit_frame_ring(struct sk_buff *skb,
if (skb_vlan_tag_present(skb)) {
tx_flags |= skb_vlan_tag_get(skb) << WX_TX_FLAGS_VLAN_SHIFT;
tx_flags |= WX_TX_FLAGS_HW_VLAN;
+ } else if (eth_type_vlan(skb->protocol)) {
+ tx_flags |= WX_TX_FLAGS_SW_VLAN;
}
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 087ac63f9193..18d2ead97aa5 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -1875,8 +1875,8 @@ struct phylink *phylink_create(struct phylink_config *config,
} else if (config->type == PHYLINK_DEV) {
pl->dev = config->dev;
} else {
- kfree(pl);
- return ERR_PTR(-EINVAL);
+ ret = -EINVAL;
+ goto free_pl;
}
pl->mac_supports_eee_ops = phylink_mac_implements_lpi(mac_ops);
@@ -1909,28 +1909,29 @@ struct phylink *phylink_create(struct phylink_config *config,
phylink_validate(pl, pl->supported, &pl->link_config);
ret = phylink_parse_mode(pl, fwnode);
- if (ret < 0) {
- kfree(pl);
- return ERR_PTR(ret);
- }
+ if (ret < 0)
+ goto free_pl;
if (pl->cfg_link_an_mode == MLO_AN_FIXED) {
ret = phylink_parse_fixedlink(pl, fwnode);
- if (ret < 0) {
- kfree(pl);
- return ERR_PTR(ret);
- }
+ if (ret < 0)
+ goto release_link_gpio;
}
pl->req_link_an_mode = pl->cfg_link_an_mode;
ret = phylink_register_sfp(pl, fwnode);
- if (ret < 0) {
- kfree(pl);
- return ERR_PTR(ret);
- }
+ if (ret < 0)
+ goto release_link_gpio;
return pl;
+
+release_link_gpio:
+ if (pl->link_gpio)
+ gpiod_put(pl->link_gpio);
+free_pl:
+ kfree(pl);
+ return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(phylink_create);
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index ffbe6f13fb1f..fed9dfdfcc3b 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -145,8 +145,6 @@ struct tun_file {
struct list_head next;
struct tun_struct *detached;
struct ptr_ring tx_ring;
- /* Protected by tx_ring.consumer_lock */
- int cons_cnt;
struct xdp_rxq_info xdp_rxq;
};
@@ -590,13 +588,8 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
rcu_assign_pointer(tun->tfiles[index],
tun->tfiles[tun->numqueues - 1]);
ntfile = rtnl_dereference(tun->tfiles[index]);
- spin_lock(&ntfile->tx_ring.consumer_lock);
ntfile->queue_index = index;
ntfile->xdp_rxq.queue_index = index;
- ntfile->cons_cnt = 0;
- if (__ptr_ring_empty(&ntfile->tx_ring))
- netif_wake_subqueue(tun->dev, index);
- spin_unlock(&ntfile->tx_ring.consumer_lock);
rcu_assign_pointer(tun->tfiles[tun->numqueues - 1],
NULL);
@@ -737,9 +730,6 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
goto out;
}
- spin_lock(&tfile->tx_ring.consumer_lock);
- tfile->cons_cnt = 0;
- spin_unlock(&tfile->tx_ring.consumer_lock);
tfile->queue_index = tun->numqueues;
tfile->socket.sk->sk_shutdown &= ~RCV_SHUTDOWN;
@@ -1018,7 +1008,6 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
struct netdev_queue *queue;
struct tun_file *tfile;
int len = skb->len;
- int ret;
rcu_read_lock();
tfile = rcu_dereference(tun->tfiles[txq]);
@@ -1073,33 +1062,13 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
nf_reset_ct(skb);
- queue = netdev_get_tx_queue(dev, txq);
-
- spin_lock(&tfile->tx_ring.producer_lock);
- ret = __ptr_ring_produce(&tfile->tx_ring, skb);
- if (!qdisc_txq_has_no_queue(queue) &&
- __ptr_ring_check_produce(&tfile->tx_ring) == -ENOSPC) {
- netif_tx_stop_queue(queue);
- /* Paired with smp_mb() in __tun_wake_queue() */
- smp_mb__after_atomic();
- if (!__ptr_ring_check_produce(&tfile->tx_ring))
- netif_tx_wake_queue(queue);
- }
- spin_unlock(&tfile->tx_ring.producer_lock);
-
- if (ret) {
- /* This should be a rare case if a qdisc is present, but
- * can happen due to lltx.
- * Since skb_tx_timestamp(), skb_orphan(),
- * run_ebpf_filter() and pskb_trim() could have tinkered
- * with the SKB, returning NETDEV_TX_BUSY is unsafe and
- * we must drop instead.
- */
+ if (ptr_ring_produce(&tfile->tx_ring, skb)) {
drop_reason = SKB_DROP_REASON_FULL_RING;
goto drop;
}
/* dev->lltx requires to do our own update of trans_start */
+ queue = netdev_get_tx_queue(dev, txq);
txq_trans_cond_update(queue);
/* Notify and wake up reader process */
@@ -2147,46 +2116,13 @@ done:
return total;
}
-/* Callers must hold ring.consumer_lock */
-static void __tun_wake_queue(struct tun_struct *tun,
- struct tun_file *tfile, int consumed)
-{
- struct netdev_queue *txq = netdev_get_tx_queue(tun->dev,
- tfile->queue_index);
-
- /* Paired with smp_mb__after_atomic() in tun_net_xmit() */
- smp_mb();
- if (netif_tx_queue_stopped(txq)) {
- tfile->cons_cnt += consumed;
- if (tfile->cons_cnt >= tfile->tx_ring.size / 2 ||
- __ptr_ring_empty(&tfile->tx_ring)) {
- netif_tx_wake_queue(txq);
- tfile->cons_cnt = 0;
- }
- }
-}
-
-static void *tun_ring_consume(struct tun_struct *tun, struct tun_file *tfile)
-{
- void *ptr;
-
- spin_lock(&tfile->tx_ring.consumer_lock);
- ptr = __ptr_ring_consume(&tfile->tx_ring);
- if (ptr)
- __tun_wake_queue(tun, tfile, 1);
-
- spin_unlock(&tfile->tx_ring.consumer_lock);
- return ptr;
-}
-
-static void *tun_ring_recv(struct tun_struct *tun, struct tun_file *tfile,
- int noblock, int *err)
+static void *tun_ring_recv(struct tun_file *tfile, int noblock, int *err)
{
DECLARE_WAITQUEUE(wait, current);
void *ptr = NULL;
int error = 0;
- ptr = tun_ring_consume(tun, tfile);
+ ptr = ptr_ring_consume(&tfile->tx_ring);
if (ptr)
goto out;
if (noblock) {
@@ -2198,7 +2134,7 @@ static void *tun_ring_recv(struct tun_struct *tun, struct tun_file *tfile,
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
- ptr = tun_ring_consume(tun, tfile);
+ ptr = ptr_ring_consume(&tfile->tx_ring);
if (ptr)
break;
if (signal_pending(current)) {
@@ -2235,7 +2171,7 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
if (!ptr) {
/* Read frames from ring */
- ptr = tun_ring_recv(tun, tfile, noblock, &err);
+ ptr = tun_ring_recv(tfile, noblock, &err);
if (!ptr)
return err;
}
@@ -3690,16 +3626,6 @@ static int tun_queue_resize(struct tun_struct *tun)
dev->tx_queue_len, GFP_KERNEL,
tun_ptr_free);
- if (!ret) {
- for (i = 0; i < tun->numqueues; i++) {
- tfile = rtnl_dereference(tun->tfiles[i]);
- spin_lock(&tfile->tx_ring.consumer_lock);
- netif_wake_subqueue(tun->dev, tfile->queue_index);
- tfile->cons_cnt = 0;
- spin_unlock(&tfile->tx_ring.consumer_lock);
- }
- }
-
kfree(rings);
return ret;
}
@@ -3808,29 +3734,6 @@ struct ptr_ring *tun_get_tx_ring(struct file *file)
}
EXPORT_SYMBOL_GPL(tun_get_tx_ring);
-/* Callers must hold ring.consumer_lock */
-void tun_wake_queue(struct file *file, int consumed)
-{
- struct tun_file *tfile;
- struct tun_struct *tun;
-
- if (file->f_op != &tun_fops)
- return;
-
- tfile = file->private_data;
- if (!tfile)
- return;
-
- rcu_read_lock();
-
- tun = rcu_dereference(tfile->tun);
- if (tun)
- __tun_wake_queue(tun, tfile, consumed);
-
- rcu_read_unlock();
-}
-EXPORT_SYMBOL_GPL(tun_wake_queue);
-
module_init(tun_init);
module_exit(tun_cleanup);
MODULE_DESCRIPTION(DRV_DESCRIPTION);
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 1c5142149175..00e34afd858e 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -756,7 +756,7 @@ static int veth_convert_skb_to_xdp_buff(struct veth_rq *rq,
u32 frame_sz;
if (skb_shared(skb) || skb_head_is_locked(skb) ||
- skb_shinfo(skb)->nr_frags ||
+ skb_is_nonlinear(skb) ||
skb_headroom(skb) < XDP_PACKET_HEADROOM) {
if (skb_pp_cow_data(rq->page_pool, pskb, XDP_PACKET_HEADROOM))
goto drop;
@@ -771,7 +771,7 @@ static int veth_convert_skb_to_xdp_buff(struct veth_rq *rq,
xdp_prepare_buff(xdp, skb->head, skb_headroom(skb),
skb_headlen(skb), true);
- if (skb_is_nonlinear(skb)) {
+ if (skb_shinfo(skb)->nr_frags) {
skb_shinfo(skb)->xdp_frags_size = skb->data_len;
xdp_buff_set_frags_flag(xdp);
} else {
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index d834a4865aec..1ded27768a97 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -1850,7 +1850,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
if (dev->flags & IFF_NOARP)
goto out;
- if (!pskb_may_pull(skb, arp_hdr_len(dev))) {
+ if (!pskb_network_may_pull(skb, arp_hdr_len(dev))) {
dev_dstats_tx_dropped(dev);
vxlan_vnifilter_count(vxlan, vni, NULL,
VXLAN_VNI_STATS_TX_DROPS, 0);
@@ -2111,7 +2111,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
{
struct iphdr *pip;
- if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+ if (!pskb_network_may_pull(skb, sizeof(struct iphdr)))
return false;
pip = ip_hdr(skb);
n = neigh_lookup(&arp_tbl, &pip->daddr, dev);
@@ -2137,7 +2137,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
*/
if (!ipv6_mod_enabled())
return false;
- if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+ if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
return false;
pip6 = ipv6_hdr(skb);
n = neigh_lookup(&nd_tbl, &pip6->daddr, dev);
@@ -2159,13 +2159,19 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
}
if (n) {
+ u8 haddr[ETH_ALEN];
bool diff;
- diff = !ether_addr_equal(eth_hdr(skb)->h_dest, n->ha);
+ neigh_ha_snapshot(haddr, n, dev);
+ diff = !ether_addr_equal_unaligned(eth_hdr(skb)->h_dest, haddr);
if (diff) {
+ if (skb_cow_head(skb, 0)) {
+ neigh_release(n);
+ return false;
+ }
memcpy(eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
dev->addr_len);
- memcpy(eth_hdr(skb)->h_dest, n->ha, dev->addr_len);
+ memcpy(eth_hdr(skb)->h_dest, haddr, dev->addr_len);
}
neigh_release(n);
return diff;
@@ -2757,8 +2763,8 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
return arp_reduce(dev, skb, vni);
#if IS_ENABLED(CONFIG_IPV6)
else if (ntohs(eth->h_proto) == ETH_P_IPV6 &&
- pskb_may_pull(skb, sizeof(struct ipv6hdr) +
- sizeof(struct nd_msg)) &&
+ pskb_network_may_pull(skb, sizeof(struct ipv6hdr) +
+ sizeof(struct nd_msg)) &&
ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) {
struct nd_msg *m = (struct nd_msg *)(ipv6_hdr(skb) + 1);
@@ -2796,6 +2802,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
(ntohs(eth->h_proto) == ETH_P_IP ||
ntohs(eth->h_proto) == ETH_P_IPV6)) {
did_rsc = route_shortcircuit(dev, skb);
+ eth = eth_hdr(skb);
if (did_rsc)
f = vxlan_find_mac_tx(vxlan, eth->h_dest, vni);
}
diff --git a/drivers/net/vxlan/vxlan_mdb.c b/drivers/net/vxlan/vxlan_mdb.c
index af7a0d7f95a5..9a9038ae90c1 100644
--- a/drivers/net/vxlan/vxlan_mdb.c
+++ b/drivers/net/vxlan/vxlan_mdb.c
@@ -1631,7 +1631,7 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan,
switch (skb->protocol) {
case htons(ETH_P_IP):
- if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+ if (!pskb_network_may_pull(skb, sizeof(struct iphdr)))
return NULL;
group.dst.sa.sa_family = AF_INET;
group.dst.sin.sin_addr.s_addr = ip_hdr(skb)->daddr;
@@ -1640,7 +1640,7 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan,
break;
#if IS_ENABLED(CONFIG_IPV6)
case htons(ETH_P_IPV6):
- if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+ if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
return NULL;
group.dst.sa.sa_family = AF_INET6;
group.dst.sin6.sin6_addr = ipv6_hdr(skb)->daddr;
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 742d4fd1b598..e87165e4f4b3 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -1544,6 +1544,8 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
}
wiphy_unlock(ah->hw->wiphy);
+
+ complete(&ah->peer_ml_id_done);
}
wake_up(&ab->wmi_ab.tx_credits_wq);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index fc5127b5c1a3..30726e580833 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -72,6 +72,7 @@
#define ATH12K_MAX_MLO_PEERS 256
#define ATH12K_MLO_PEER_ID_INVALID 0xFFFF
+#define ATH12K_MLO_PEER_ID_PENDING 0xFFFE
#define ATH12K_INVALID_RSSI_FULL -1
#define ATH12K_INVALID_RSSI_EMPTY -128
@@ -793,6 +794,8 @@ struct ath12k_hw {
enum ath12k_hw_state state;
bool regd_updated;
bool use_6ghz_regd;
+ bool host_alloc_ml_id;
+ struct completion peer_ml_id_done;
u8 num_radio;
diff --git a/drivers/net/wireless/ath/ath12k/dp_htt.c b/drivers/net/wireless/ath/ath12k/dp_htt.c
index 52e10059c6d5..68968f96b4f1 100644
--- a/drivers/net/wireless/ath/ath12k/dp_htt.c
+++ b/drivers/net/wireless/ath/ath12k/dp_htt.c
@@ -6,6 +6,7 @@
#include "core.h"
#include "peer.h"
+#include "dp_peer.h"
#include "htc.h"
#include "dp_htt.h"
#include "debugfs_htt_stats.h"
@@ -575,6 +576,51 @@ exit:
rcu_read_unlock();
}
+static void ath12k_dp_htt_mlo_peer_map_handler(struct ath12k_base *ab,
+ struct sk_buff *skb)
+{
+ struct htt_resp_msg *resp = (struct htt_resp_msg *)skb->data;
+ struct htt_t2h_mlo_peer_map_event *ev = &resp->mlo_peer_map_ev;
+ u16 raw_peer_id, peer_id, addr_h16;
+ u8 peer_addr[ETH_ALEN];
+ int ret;
+
+ if (skb->len < sizeof(*ev)) {
+ ath12k_warn(ab, "unexpected htt mlo peer map event len %u\n",
+ skb->len);
+ return;
+ }
+
+ raw_peer_id = le32_get_bits(ev->info0,
+ HTT_T2H_MLO_PEER_MAP_INFO0_MLO_PEER_ID);
+ peer_id = raw_peer_id | ATH12K_PEER_ML_ID_VALID;
+
+ addr_h16 = le32_get_bits(ev->info1,
+ HTT_T2H_MLO_PEER_MAP_INFO1_MAC_ADDR_H16);
+ ath12k_dp_get_mac_addr(le32_to_cpu(ev->mac_addr_l32), addr_h16,
+ peer_addr);
+
+ ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "htt mlo peer map peer %pM id %u\n",
+ peer_addr, peer_id);
+
+ /*
+ * Fix up the dp_peer entry created with ATH12K_MLO_PEER_ID_PENDING
+ * earlier; on chips with host_alloc_ml_id == false this is the only
+ * point at which the host learns the firmware-assigned ID. Chips
+ * that allocate the ID on the host also receive this event but the
+ * firmware-reported ID matches the host-allocated one, so there is
+ * nothing to fix up.
+ */
+ if (!ab->hw_params->host_alloc_ml_id) {
+ ret = ath12k_dp_peer_fixup_peer_id(ab, peer_addr,
+ peer_id);
+ if (ret)
+ ath12k_warn(ab,
+ "failed to fix up peer id %u for dp peer %pM: %d\n",
+ peer_id, peer_addr, ret);
+ }
+}
+
void ath12k_dp_htt_htc_t2h_msg_handler(struct ath12k_base *ab,
struct sk_buff *skb)
{
@@ -659,6 +705,9 @@ void ath12k_dp_htt_htc_t2h_msg_handler(struct ath12k_base *ab,
case HTT_T2H_MSG_TYPE_MLO_TIMESTAMP_OFFSET_IND:
ath12k_htt_mlo_offset_event_handler(ab, skb);
break;
+ case HTT_T2H_MSG_TYPE_MLO_RX_PEER_MAP:
+ ath12k_dp_htt_mlo_peer_map_handler(ab, skb);
+ break;
default:
ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "dp_htt event %d not handled\n",
type);
diff --git a/drivers/net/wireless/ath/ath12k/dp_htt.h b/drivers/net/wireless/ath/ath12k/dp_htt.h
index 987689f11cda..2db7fb27c036 100644
--- a/drivers/net/wireless/ath/ath12k/dp_htt.h
+++ b/drivers/net/wireless/ath/ath12k/dp_htt.h
@@ -930,6 +930,7 @@ enum htt_t2h_msg_type {
HTT_T2H_MSG_TYPE_EXT_STATS_CONF = 0x1c,
HTT_T2H_MSG_TYPE_BKPRESSURE_EVENT_IND = 0x24,
HTT_T2H_MSG_TYPE_MLO_TIMESTAMP_OFFSET_IND = 0x28,
+ HTT_T2H_MSG_TYPE_MLO_RX_PEER_MAP = 0x29,
HTT_T2H_MSG_TYPE_PEER_MAP3 = 0x2b,
HTT_T2H_MSG_TYPE_VDEV_TXRX_STATS_PERIODIC_IND = 0x2c,
};
@@ -974,11 +975,22 @@ struct htt_t2h_peer_unmap_event {
__le32 info1;
} __packed;
+#define HTT_T2H_MLO_PEER_MAP_INFO0_MLO_PEER_ID GENMASK(23, 8)
+#define HTT_T2H_MLO_PEER_MAP_INFO1_MAC_ADDR_H16 GENMASK(15, 0)
+
+struct htt_t2h_mlo_peer_map_event {
+ __le32 info0;
+ __le32 mac_addr_l32;
+ __le32 info1;
+ __le32 reserved[5];
+} __packed;
+
struct htt_resp_msg {
union {
struct htt_t2h_version_conf_msg version_msg;
struct htt_t2h_peer_map_event peer_map_ev;
struct htt_t2h_peer_unmap_event peer_unmap_ev;
+ struct htt_t2h_mlo_peer_map_event mlo_peer_map_ev;
};
} __packed;
diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.c b/drivers/net/wireless/ath/ath12k/dp_peer.c
index a12073afc307..bb5341b4251a 100644
--- a/drivers/net/wireless/ath/ath12k/dp_peer.c
+++ b/drivers/net/wireless/ath/ath12k/dp_peer.c
@@ -475,7 +475,9 @@ int ath12k_dp_peer_create(struct ath12k_dp_hw *dp_hw, u8 *addr,
dp_peer->is_mlo = params->is_mlo;
/*
- * For MLO client, the host assigns the ML peer ID, so set peer_id in dp_peer
+ * For MLO client, the ML peer ID, either known or PENDING, needs to be
+ * initialized here since the following logic depends on it.
+ *
* For non-MLO client, host gets link peer ID from firmware and will be
* assigned at the time of link peer creation
*/
@@ -491,13 +493,17 @@ int ath12k_dp_peer_create(struct ath12k_dp_hw *dp_hw, u8 *addr,
list_add(&dp_peer->list, &dp_hw->dp_peers_list);
/*
- * For MLO client, the peer_id for ath12k_dp_peer is allocated by host
- * and that peer_id is known at this point, and hence this ath12k_dp_peer
- * can be added to the RCU table using the peer_id.
- * For non-MLO client, this addition to RCU table shall be done at the
- * time of assignment of ath12k_dp_link_peer to ath12k_dp_peer.
+ * For an MLO client whose ML peer ID is allocated by the host, the
+ * peer_id is known here and the dp_peer can be added to the RCU
+ * table using it. For an MLO client on chips where the firmware
+ * allocates the ID, peer_id is ATH12K_MLO_PEER_ID_PENDING and the
+ * RCU table publish is deferred to the
+ * HTT_T2H_MSG_TYPE_MLO_RX_PEER_MAP handler. For a non-MLO client
+ * the publish happens later, at the time of assignment of
+ * ath12k_dp_link_peer to ath12k_dp_peer.
*/
- if (dp_peer->is_mlo)
+ if (dp_peer->is_mlo &&
+ dp_peer->peer_id != ATH12K_MLO_PEER_ID_PENDING)
rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], dp_peer);
spin_unlock_bh(&dp_hw->peer_lock);
@@ -518,7 +524,8 @@ void ath12k_dp_peer_delete(struct ath12k_dp_hw *dp_hw, u8 *addr,
return;
}
- if (dp_peer->is_mlo)
+ if (dp_peer->is_mlo &&
+ dp_peer->peer_id != ATH12K_MLO_PEER_ID_PENDING)
rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], NULL);
list_del(&dp_peer->list);
@@ -695,3 +702,55 @@ void ath12k_dp_link_peer_reset_rx_stats(struct ath12k_dp *dp, const u8 *addr)
if (rx_stats)
memset(rx_stats, 0, sizeof(*rx_stats));
}
+
+int ath12k_dp_peer_fixup_peer_id(struct ath12k_base *ab,
+ const u8 *peer_addr, u16 peer_id)
+{
+ struct ath12k_dp_link_peer *link_peer;
+ struct ath12k_dp_peer *dp_peer = NULL;
+ struct ath12k_hw_group *ag = ab->ag;
+ struct ath12k_dp_hw *dp_hw = NULL;
+ struct ath12k_hw *ah;
+ int i;
+
+ if (peer_id >= (ATH12K_PEER_ML_ID_VALID | ATH12K_MAX_MLO_PEERS))
+ return -EINVAL;
+
+ for (i = 0; i < ag->num_hw; i++) {
+ ah = ag->ah[i];
+ if (!ah)
+ continue;
+
+ spin_lock_bh(&ah->dp_hw.peer_lock);
+ dp_peer = ath12k_dp_peer_find_by_addr(&ah->dp_hw,
+ (u8 *)peer_addr);
+ if (dp_peer) {
+ dp_hw = &ah->dp_hw;
+ break;
+ }
+ spin_unlock_bh(&ah->dp_hw.peer_lock);
+ }
+
+ if (!dp_peer)
+ return -ENOENT;
+
+ /* dp_hw->peer_lock is held */
+
+ dp_peer->peer_id = peer_id;
+ rcu_assign_pointer(dp_hw->dp_peers[peer_id], dp_peer);
+
+ for (i = 0; i < ATH12K_NUM_MAX_LINKS; i++) {
+ link_peer = rcu_dereference_protected(dp_peer->link_peers[i],
+ lockdep_is_held(&dp_hw->peer_lock));
+ if (link_peer)
+ link_peer->ml_id = peer_id;
+ }
+
+ ath12k_sta_to_ahsta(dp_peer->sta)->ml_peer_id = peer_id;
+
+ spin_unlock_bh(&dp_hw->peer_lock);
+
+ complete(&ah->peer_ml_id_done);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.h b/drivers/net/wireless/ath/ath12k/dp_peer.h
index 7c9709bf717b..3503840b0329 100644
--- a/drivers/net/wireless/ath/ath12k/dp_peer.h
+++ b/drivers/net/wireless/ath/ath12k/dp_peer.h
@@ -181,4 +181,6 @@ struct ath12k_dp_peer *ath12k_dp_peer_find_by_peerid(struct ath12k_pdev_dp *dp_p
struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_peerid(struct ath12k_pdev_dp *dp_pdev, u16 peer_id);
void ath12k_dp_link_peer_free(struct ath12k_dp_link_peer *peer);
+int ath12k_dp_peer_fixup_peer_id(struct ath12k_base *ab, const u8 *peer_addr,
+ u16 peer_id);
#endif
diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index 86fb8b719613..8d2fa0bfb96c 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -236,6 +236,8 @@ struct ath12k_hw_params {
u32 max_client_dbs;
u32 max_client_dbs_sbs;
} client;
+
+ bool host_alloc_ml_id;
};
struct ath12k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 51c4df32e716..a0928890671a 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -1282,13 +1282,17 @@ void ath12k_mac_dp_peer_cleanup(struct ath12k_hw *ah)
struct ath12k_dp_peer *dp_peer, *tmp;
struct ath12k_dp_hw *dp_hw = &ah->dp_hw;
+ lockdep_assert_wiphy(ah->hw->wiphy);
+
INIT_LIST_HEAD(&peers);
spin_lock_bh(&dp_hw->peer_lock);
list_for_each_entry_safe(dp_peer, tmp, &dp_hw->dp_peers_list, list) {
if (dp_peer->is_mlo) {
- rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], NULL);
- clear_bit(dp_peer->peer_id, ah->free_ml_peer_id_map);
+ if (dp_peer->peer_id != ATH12K_MLO_PEER_ID_PENDING)
+ rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id],
+ NULL);
+ ath12k_peer_ml_free(ah, ath12k_sta_to_ahsta(dp_peer->sta));
}
list_move(&dp_peer->list, &peers);
@@ -3531,11 +3535,16 @@ static void ath12k_peer_assoc_h_mlo(struct ath12k_link_sta *arsta,
struct ath12k_sta *ahsta = arsta->ahsta;
struct ath12k_link_sta *arsta_p;
struct ath12k_link_vif *arvif;
+ struct ath12k_hw *ah = arsta->arvif->ar->ah;
unsigned long links;
u8 link_id;
int i;
- if (!sta->mlo || ahsta->ml_peer_id == ATH12K_MLO_PEER_ID_INVALID)
+ if (!sta->mlo)
+ return;
+
+ if (ah->host_alloc_ml_id &&
+ ahsta->ml_peer_id == ATH12K_MLO_PEER_ID_INVALID)
return;
ml->enabled = true;
@@ -3543,12 +3552,25 @@ static void ath12k_peer_assoc_h_mlo(struct ath12k_link_sta *arsta,
/* For now considering the primary umac based on assoc link */
ml->primary_umac = arsta->is_assoc_link;
- ml->peer_id_valid = true;
+ /*
+ * Only chips that allocate the MLD peer ID on the host send a valid
+ * ml_peer_id in WMI_PEER_ASSOC_CMDID. For chips where the firmware
+ * picks the ID, leave peer_id_valid false to avoid unexpected issues.
+ */
+ ml->peer_id_valid = ah->host_alloc_ml_id;
ml->logical_link_idx_valid = true;
ether_addr_copy(ml->mld_addr, sta->addr);
ml->logical_link_idx = arsta->link_idx;
- ml->ml_peer_id = ahsta->ml_peer_id;
+ /*
+ * WMI_MLO_PEER_ASSOC_PARAMS expects the raw ML peer ID without
+ * the host-side ATH12K_PEER_ML_ID_VALID bookkeeping bit. For chips
+ * where the firmware allocates the ID, the field is unused (the
+ * firmware always allocates regardless of the value here); send 0
+ * to make that intent explicit.
+ */
+ ml->ml_peer_id = ah->host_alloc_ml_id ?
+ (ahsta->ml_peer_id & ~ATH12K_PEER_ML_ID_VALID) : 0;
ml->ieee_link_id = arsta->link_id;
ml->num_partner_links = 0;
ml->eml_cap = sta->eml_cap;
@@ -3595,8 +3617,6 @@ static void ath12k_peer_assoc_prepare(struct ath12k *ar,
memset(arg, 0, sizeof(*arg));
- reinit_completion(&ar->peer_assoc_done);
-
arg->peer_new_assoc = !reassoc;
ath12k_peer_assoc_h_basic(ar, arvif, arsta, arg);
ath12k_peer_assoc_h_crypto(ar, arvif, arsta, arg);
@@ -3836,6 +3856,52 @@ static u32 ath12k_mac_ieee80211_sta_bw_to_wmi(struct ath12k *ar,
return bw;
}
+static int ath12k_mac_peer_assoc(struct ath12k *ar,
+ struct ath12k_wmi_peer_assoc_arg *peer_arg)
+{
+ struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
+ int ret;
+
+ reinit_completion(&ar->peer_assoc_done);
+ reinit_completion(&ah->peer_ml_id_done);
+
+ ret = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg);
+ if (ret) {
+ ath12k_warn(ar->ab, "failed to run peer assoc for %pM vdev %i: %d\n",
+ peer_arg->peer_mac, peer_arg->vdev_id, ret);
+ return ret;
+ }
+
+ if (!wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) {
+ ath12k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n",
+ peer_arg->peer_mac, peer_arg->vdev_id);
+ return -ETIMEDOUT;
+ }
+
+ /*
+ * For devices where the firmware allocates the MLD peer ID, the host
+ * learns the real ID only from the MLO_RX_PEER_MAP HTT event, which is
+ * handled in a softirq (BH workqueue) context that cannot take the
+ * wiphy lock. Block here, while still holding the wiphy lock, until
+ * that event has fixed up the ID. This serialises the fixup against
+ * all other wiphy-locked ml_peer_id accesses.
+ *
+ * The firmware sends the event only once, in response to the assoc-link
+ * peer assoc, so block only for that link.
+ */
+ if (!ah->host_alloc_ml_id &&
+ peer_arg->is_assoc &&
+ peer_arg->ml.enabled &&
+ peer_arg->ml.assoc_link &&
+ !wait_for_completion_timeout(&ah->peer_ml_id_done, 1 * HZ)) {
+ ath12k_warn(ar->ab, "failed to get MLO peer map event for %pM vdev %i\n",
+ peer_arg->peer_mac, peer_arg->vdev_id);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
static void ath12k_bss_assoc(struct ath12k *ar,
struct ath12k_link_vif *arvif,
struct ieee80211_bss_conf *bss_conf)
@@ -3916,18 +3982,10 @@ static void ath12k_bss_assoc(struct ath12k *ar,
}
peer_arg->is_assoc = true;
- ret = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg);
- if (ret) {
- ath12k_warn(ar->ab, "failed to run peer assoc for %pM vdev %i: %d\n",
- bss_conf->bssid, arvif->vdev_id, ret);
- return;
- }
- if (!wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) {
- ath12k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n",
- bss_conf->bssid, arvif->vdev_id);
+ ret = ath12k_mac_peer_assoc(ar, peer_arg);
+ if (ret)
return;
- }
ret = ath12k_setup_peer_smps(ar, arvif, bss_conf->bssid,
&link_sta->ht_cap, &link_sta->he_6ghz_capa);
@@ -6481,18 +6539,10 @@ static int ath12k_mac_station_assoc(struct ath12k *ar,
}
peer_arg->is_assoc = true;
- ret = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg);
- if (ret) {
- ath12k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n",
- arsta->addr, arvif->vdev_id, ret);
- return ret;
- }
- if (!wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) {
- ath12k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n",
- arsta->addr, arvif->vdev_id);
- return -ETIMEDOUT;
- }
+ ret = ath12k_mac_peer_assoc(ar, peer_arg);
+ if (ret)
+ return ret;
num_vht_rates = ath12k_mac_bitrate_mask_num_vht_rates(ar, band, mask);
num_he_rates = ath12k_mac_bitrate_mask_num_he_rates(ar, band, mask);
@@ -6841,14 +6891,8 @@ static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk)
peer_arg, true);
peer_arg->is_assoc = false;
- err = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg);
- if (err)
- ath12k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n",
- arsta->addr, arvif->vdev_id, err);
- if (!wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ))
- ath12k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n",
- arsta->addr, arvif->vdev_id);
+ ath12k_mac_peer_assoc(ar, peer_arg);
}
}
}
@@ -7266,10 +7310,8 @@ static void ath12k_mac_ml_station_remove(struct ath12k_vif *ahvif,
ath12k_mac_free_unassign_link_sta(ah, ahsta, link_id);
}
- if (sta->mlo) {
- clear_bit(ahsta->ml_peer_id, ah->free_ml_peer_id_map);
- ahsta->ml_peer_id = ATH12K_MLO_PEER_ID_INVALID;
- }
+ if (sta->mlo)
+ ath12k_peer_ml_free(ah, ahsta);
}
static int ath12k_mac_handle_link_sta_state(struct ieee80211_hw *hw,
@@ -7733,15 +7775,23 @@ int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
/* ML sta */
if (sta->mlo && !ahsta->links_map &&
(hweight16(sta->valid_links) == 1)) {
- ahsta->ml_peer_id = ath12k_peer_ml_alloc(ah);
- if (ahsta->ml_peer_id == ATH12K_MLO_PEER_ID_INVALID) {
- ath12k_hw_warn(ah, "unable to allocate ML peer id for sta %pM",
- sta->addr);
- goto exit;
+ if (ah->host_alloc_ml_id) {
+ ahsta->ml_peer_id = ath12k_peer_ml_alloc(ah);
+ if (ahsta->ml_peer_id == ATH12K_MLO_PEER_ID_INVALID) {
+ ath12k_hw_warn(ah, "unable to allocate ML peer id for sta %pM",
+ sta->addr);
+ goto exit;
+ }
+ } else {
+ /*
+ * firmware allocates the ML peer ID and notifies
+ * the host via HTT_T2H_MSG_TYPE_MLO_RX_PEER_MAP
+ */
+ ahsta->ml_peer_id = ATH12K_MLO_PEER_ID_PENDING;
}
dp_params.is_mlo = true;
- dp_params.peer_id = ahsta->ml_peer_id | ATH12K_PEER_ML_ID_VALID;
+ dp_params.peer_id = ahsta->ml_peer_id;
}
dp_params.sta = sta;
@@ -7878,10 +7928,8 @@ int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
peer_delete:
ath12k_dp_peer_delete(&ah->dp_hw, sta->addr, sta);
ml_peer_id_clear:
- if (sta->mlo) {
- clear_bit(ahsta->ml_peer_id, ah->free_ml_peer_id_map);
- ahsta->ml_peer_id = ATH12K_MLO_PEER_ID_INVALID;
- }
+ if (sta->mlo)
+ ath12k_peer_ml_free(ah, ahsta);
exit:
/* update the state if everything went well */
if (!ret)
@@ -15310,6 +15358,7 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_hw_group *ag,
ah->num_radio = num_pdev_map;
mutex_init(&ah->hw_mutex);
+ init_completion(&ah->peer_ml_id_done);
spin_lock_init(&ah->dp_hw.peer_lock);
INIT_LIST_HEAD(&ah->dp_hw.dp_peers_list);
@@ -15384,8 +15433,9 @@ int ath12k_mac_allocate(struct ath12k_hw_group *ag)
int mac_id, device_id, total_radio, num_hw;
struct ath12k_base *ab;
struct ath12k_hw *ah;
- int ret, i, j;
+ bool conf = false;
u8 radio_per_hw;
+ int ret, i, j;
total_radio = 0;
for (i = 0; i < ag->num_devices; i++) {
@@ -15425,6 +15475,20 @@ int ath12k_mac_allocate(struct ath12k_hw_group *ag)
}
ab = ag->ab[device_id];
+
+ /*
+ * the assumption is all devices within an ah
+ * share the same host_alloc_ml_id configuration
+ */
+ if (j == 0) {
+ conf = ab->hw_params->host_alloc_ml_id;
+ } else if (conf != ab->hw_params->host_alloc_ml_id) {
+ ath12k_warn(ab, "inconsistent ML ID config within ah, device 0 uses %s allocated ID, while device %u doesn't\n",
+ conf ? "host" : "firmware", device_id);
+ ret = -EINVAL;
+ goto err;
+ }
+
pdev_map[j].ab = ab;
pdev_map[j].pdev_idx = mac_id;
mac_id++;
@@ -15449,6 +15513,7 @@ int ath12k_mac_allocate(struct ath12k_hw_group *ag)
}
ah->dev = ab->dev;
+ ah->host_alloc_ml_id = conf;
ag->ah[i] = ah;
ag->num_hw++;
diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c
index 2681a047d4d5..ed0524ddff80 100644
--- a/drivers/net/wireless/ath/ath12k/peer.c
+++ b/drivers/net/wireless/ath/ath12k/peer.c
@@ -230,7 +230,16 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
/* Fill ML info into created peer */
if (sta->mlo) {
ml_peer_id = ahsta->ml_peer_id;
- peer->ml_id = ml_peer_id | ATH12K_PEER_ML_ID_VALID;
+ /*
+ * For chips where firmware allocates the ML peer ID,
+ * ml_peer_id is ATH12K_MLO_PEER_ID_PENDING here. The
+ * MLO_RX_PEER_MAP HTT event handler fixes up
+ * peer->ml_id once the ID is known.
+ */
+ if (ml_peer_id == ATH12K_MLO_PEER_ID_PENDING)
+ peer->ml_id = ATH12K_MLO_PEER_ID_INVALID;
+ else
+ peer->ml_id = ml_peer_id;
ether_addr_copy(peer->ml_addr, sta->addr);
/* the assoc link is considered primary for now */
@@ -276,9 +285,25 @@ u16 ath12k_peer_ml_alloc(struct ath12k_hw *ah)
}
if (ml_peer_id == ATH12K_MAX_MLO_PEERS)
- ml_peer_id = ATH12K_MLO_PEER_ID_INVALID;
+ return ATH12K_MLO_PEER_ID_INVALID;
- return ml_peer_id;
+ return ml_peer_id | ATH12K_PEER_ML_ID_VALID;
+}
+
+void ath12k_peer_ml_free(struct ath12k_hw *ah, struct ath12k_sta *ahsta)
+{
+ lockdep_assert_wiphy(ah->hw->wiphy);
+
+ /*
+ * Only devices that allocate the ID on the host own a slot in
+ * free_ml_peer_id_map.
+ */
+ if (ah->host_alloc_ml_id &&
+ (ahsta->ml_peer_id <
+ (ATH12K_MAX_MLO_PEERS | ATH12K_PEER_ML_ID_VALID)))
+ clear_bit(ahsta->ml_peer_id & ~ATH12K_PEER_ML_ID_VALID,
+ ah->free_ml_peer_id_map);
+ ahsta->ml_peer_id = ATH12K_MLO_PEER_ID_INVALID;
}
int ath12k_peer_mlo_link_peers_delete(struct ath12k_vif *ahvif, struct ath12k_sta *ahsta)
diff --git a/drivers/net/wireless/ath/ath12k/peer.h b/drivers/net/wireless/ath/ath12k/peer.h
index 49d89796bc46..0f7f25b8e89c 100644
--- a/drivers/net/wireless/ath/ath12k/peer.h
+++ b/drivers/net/wireless/ath/ath12k/peer.h
@@ -26,4 +26,5 @@ int ath12k_link_sta_rhash_add(struct ath12k_base *ab, struct ath12k_link_sta *ar
struct ath12k_link_sta *ath12k_link_sta_find_by_addr(struct ath12k_base *ab,
const u8 *addr);
u16 ath12k_peer_ml_alloc(struct ath12k_hw *ah);
+void ath12k_peer_ml_free(struct ath12k_hw *ah, struct ath12k_sta *ahsta);
#endif /* _PEER_H_ */
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hw.c b/drivers/net/wireless/ath/ath12k/wifi7/hw.c
index d9fdd2fc8298..03dedfd907fc 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hw.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hw.c
@@ -442,6 +442,8 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
+
+ .host_alloc_ml_id = true,
},
{
.name = "wcn7850 hw2.0",
@@ -533,6 +535,8 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
+
+ .host_alloc_ml_id = false,
},
{
.name = "qcn9274 hw2.0",
@@ -620,6 +624,8 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
+
+ .host_alloc_ml_id = true,
},
{
.name = "ipq5332 hw1.0",
@@ -700,6 +706,8 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
+
+ .host_alloc_ml_id = true,
},
{
.name = "qcc2072 hw1.0",
@@ -792,6 +800,8 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
+
+ .host_alloc_ml_id = false,
},
{
.name = "ipq5424 hw1.0",
@@ -876,6 +886,8 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
+
+ .host_alloc_ml_id = true,
},
};
diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c
index 8d0ff339ad08..0bb807ff8edf 100644
--- a/drivers/net/wireless/intel/iwlegacy/common.c
+++ b/drivers/net/wireless/intel/iwlegacy/common.c
@@ -2179,8 +2179,8 @@ il_remove_station(struct il_priv *il, const u8 sta_id, const u8 * addr)
il->stations[sta_id].used &= ~IL_STA_DRIVER_ACTIVE;
il->num_stations--;
-
- BUG_ON(il->num_stations < 0);
+ if (WARN_ON(il->num_stations < 0))
+ il->num_stations = 0;
spin_unlock_irqrestore(&il->sta_lock, flags);
@@ -2328,7 +2328,8 @@ il_dealloc_bcast_stations(struct il_priv *il)
il->stations[i].used &= ~IL_STA_UCODE_ACTIVE;
il->num_stations--;
- BUG_ON(il->num_stations < 0);
+ if (WARN_ON(il->num_stations < 0))
+ il->num_stations = 0;
kfree(il->stations[i].lq);
il->stations[i].lq = NULL;
}
diff --git a/drivers/net/wireless/intel/iwlegacy/debug.c b/drivers/net/wireless/intel/iwlegacy/debug.c
index d998a3f1b056..8a9f79ff1c6e 100644
--- a/drivers/net/wireless/intel/iwlegacy/debug.c
+++ b/drivers/net/wireless/intel/iwlegacy/debug.c
@@ -396,7 +396,7 @@ il_dbgfs_stations_read(struct file *file, char __user *user_buf, size_t count,
int i, j, pos = 0;
ssize_t ret;
/* Add 30 for initial string */
- const size_t bufsz = 30 + sizeof(char) * 500 * (il->num_stations);
+ const size_t bufsz = 30 + sizeof(char) * 500 * max_sta;
buf = kmalloc(bufsz, GFP_KERNEL);
if (!buf)
diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
index 610ec8302adf..9deb47f22a61 100644
--- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
@@ -44,7 +44,7 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
ntohs(rx_hdr->eth803_hdr.h_proto) == ETH_P_TDLS) {
mwifiex_process_tdls_action_frame(priv,
(u8 *)rx_hdr,
- skb->len);
+ rx_skb->len);
}
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
diff --git a/drivers/ptp/ptp_netc.c b/drivers/ptp/ptp_netc.c
index 5e381c354d74..1c20d7efab92 100644
--- a/drivers/ptp/ptp_netc.c
+++ b/drivers/ptp/ptp_netc.c
@@ -769,6 +769,7 @@ static void netc_timer_init(struct netc_timer *priv)
TMR_CTRL_TE | TMR_CTRL_FS;
netc_timer_wr(priv, NETC_TMR_CTRL, tmr_ctrl);
netc_timer_wr(priv, NETC_TMR_PRSC, priv->oclk_prsc);
+ netc_timer_wr(priv, NETC_TMR_TEMASK, 0);
/* Disable FIPER by default */
fiper_ctrl = netc_timer_rd(priv, NETC_TMR_FIPER_CTRL);
@@ -901,6 +902,11 @@ static irqreturn_t netc_timer_isr(int irq, void *data)
/* Clear interrupts status */
netc_timer_wr(priv, NETC_TMR_TEVENT, tmr_event);
+ if (!tmr_event) {
+ spin_unlock(&priv->lock);
+ return IRQ_NONE;
+ }
+
if (tmr_event & TMR_TEVENT_ALMEN(0))
netc_timer_alarm_write(priv, NETC_TMR_DEFAULT_ALARM, 0);
@@ -936,7 +942,8 @@ static int netc_timer_init_msix_irq(struct netc_timer *priv)
}
priv->irq = pci_irq_vector(pdev, 0);
- err = request_irq(priv->irq, netc_timer_isr, 0, priv->irq_name, priv);
+ err = request_irq(priv->irq, netc_timer_isr, IRQF_NO_AUTOEN,
+ priv->irq_name, priv);
if (err) {
dev_err(&pdev->dev, "request_irq() failed\n");
pci_free_irq_vectors(pdev);
@@ -951,7 +958,6 @@ static void netc_timer_free_msix_irq(struct netc_timer *priv)
{
struct pci_dev *pdev = priv->pdev;
- disable_irq(priv->irq);
free_irq(priv->irq, priv);
pci_free_irq_vectors(pdev);
}
@@ -1005,6 +1011,8 @@ static int netc_timer_probe(struct pci_dev *pdev,
goto free_msix_irq;
}
+ enable_irq(priv->irq);
+
return 0;
free_msix_irq:
@@ -1019,9 +1027,10 @@ static void netc_timer_remove(struct pci_dev *pdev)
{
struct netc_timer *priv = pci_get_drvdata(pdev);
+ disable_irq(priv->irq);
+ ptp_clock_unregister(priv->clock);
netc_timer_wr(priv, NETC_TMR_TEMASK, 0);
netc_timer_wr(priv, NETC_TMR_CTRL, 0);
- ptp_clock_unregister(priv->clock);
netc_timer_free_msix_irq(priv);
netc_timer_pci_remove(pdev);
}
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 20fb0d2e02a9..f18eed9df3c7 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -6525,6 +6525,9 @@ int qeth_siocdevprivate(struct net_device *dev, struct ifreq *rq, void __user *d
struct qeth_card *card = dev->ml_priv;
int rc = 0;
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
switch (cmd) {
case SIOC_QETH_ADP_SET_SNMP_CONTROL:
rc = qeth_snmp_command(card, data);
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 3e72b9c6af0c..6949b704166d 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -176,21 +176,13 @@ static void *vhost_net_buf_consume(struct vhost_net_buf *rxq)
return ret;
}
-static int vhost_net_buf_produce(struct sock *sk,
- struct vhost_net_virtqueue *nvq)
+static int vhost_net_buf_produce(struct vhost_net_virtqueue *nvq)
{
- struct file *file = sk->sk_socket->file;
struct vhost_net_buf *rxq = &nvq->rxq;
rxq->head = 0;
- spin_lock(&nvq->rx_ring->consumer_lock);
- rxq->tail = __ptr_ring_consume_batched(nvq->rx_ring, rxq->queue,
- VHOST_NET_BATCH);
-
- if (rxq->tail)
- tun_wake_queue(file, rxq->tail);
-
- spin_unlock(&nvq->rx_ring->consumer_lock);
+ rxq->tail = ptr_ring_consume_batched(nvq->rx_ring, rxq->queue,
+ VHOST_NET_BATCH);
return rxq->tail;
}
@@ -217,15 +209,14 @@ static int vhost_net_buf_peek_len(void *ptr)
return __skb_array_len_with_tag(ptr);
}
-static int vhost_net_buf_peek(struct sock *sk,
- struct vhost_net_virtqueue *nvq)
+static int vhost_net_buf_peek(struct vhost_net_virtqueue *nvq)
{
struct vhost_net_buf *rxq = &nvq->rxq;
if (!vhost_net_buf_is_empty(rxq))
goto out;
- if (!vhost_net_buf_produce(sk, nvq))
+ if (!vhost_net_buf_produce(nvq))
return 0;
out:
@@ -1013,7 +1004,7 @@ static int peek_head_len(struct vhost_net_virtqueue *rvq, struct sock *sk)
unsigned long flags;
if (rvq->rx_ring)
- return vhost_net_buf_peek(sk, rvq);
+ return vhost_net_buf_peek(rvq);
spin_lock_irqsave(&sk->sk_receive_queue.lock, flags);
head = skb_peek(&sk->sk_receive_queue);