summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bluetooth/btintel_pcie.c17
-rw-r--r--drivers/edac/amd64_edac.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c77
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c17
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/mes_userqueue.c9
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c32
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_priv.h7
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c19
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c7
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c20
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c42
-rw-r--r--drivers/gpu/drm/aspeed/aspeed_gfx_drv.c5
-rw-r--r--drivers/gpu/drm/bridge/th1520-dw-hdmi.c8
-rw-r--r--drivers/gpu/drm/display/drm_dp_helper.c4
-rw-r--r--drivers/gpu/drm/drm_bridge.c8
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c6
-rw-r--r--drivers/gpu/drm/gud/gud_pipe.c1
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c2
-rw-r--r--drivers/gpu/drm/i915/gt/intel_rps.c3
-rw-r--r--drivers/gpu/drm/imagination/pvr_mmu.c25
-rw-r--r--drivers/gpu/drm/imagination/pvr_vm.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_abi16.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/user.c2
-rw-r--r--drivers/gpu/drm/panthor/panthor_sched.c3
-rw-r--r--drivers/gpu/drm/vc4/vc4_bo.c5
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.c5
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.h2
-rw-r--r--drivers/gpu/drm/vc4/vc4_gem.c8
-rw-r--r--drivers/gpu/drm/vc4/vc4_irq.c24
-rw-r--r--drivers/gpu/drm/vc4/vc4_v3d.c65
-rw-r--r--drivers/gpu/drm/vc4/vc4_validate.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c26
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c8
-rw-r--r--drivers/gpu/drm/xe/display/xe_fb_pin.c6
-rw-r--r--drivers/gpu/drm/xe/xe_bo.c139
-rw-r--r--drivers/gpu/drm/xe/xe_bo.h2
-rw-r--r--drivers/gpu/drm/xe/xe_i2c.c5
-rw-r--r--drivers/gpu/drm/xe/xe_lrc.c38
-rw-r--r--drivers/gpu/drm/xe/xe_mmio.c5
-rw-r--r--drivers/gpu/drm/xe/xe_sysctrl_mailbox.c16
-rw-r--r--drivers/i2c/busses/i2c-qcom-geni.c3
-rw-r--r--drivers/input/joystick/xpad.c4
-rw-r--r--drivers/input/misc/ati_remote2.c12
-rw-r--r--drivers/iommu/dma-iommu.c4
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c4
-rw-r--r--drivers/memstick/core/memstick.c8
-rw-r--r--drivers/memstick/host/rtsx_usb_ms.c31
-rw-r--r--drivers/mmc/host/cavium-octeon.c5
-rw-r--r--drivers/mmc/host/cavium-thunderx.c5
-rw-r--r--drivers/mmc/host/mtk-sd.c1
-rw-r--r--drivers/mmc/host/sdhci-sprd.c4
-rw-r--r--drivers/net/amt.c48
-rw-r--r--drivers/net/bareudp.c3
-rw-r--r--drivers/net/bonding/bond_main.c8
-rw-r--r--drivers/net/can/dev/skb.c4
-rw-r--r--drivers/net/can/usb/f81604.c2
-rw-r--r--drivers/net/can/vxcan.c3
-rw-r--r--drivers/net/dsa/microchip/ksz_common.h2
-rw-r--r--drivers/net/ethernet/airoha/airoha_eth.c32
-rw-r--r--drivers/net/ethernet/airoha/airoha_eth.h2
-rw-r--r--drivers/net/ethernet/allwinner/sun4i-emac.c5
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c189
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h1
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c11
-rw-r--r--drivers/net/ethernet/cadence/macb_main.c80
-rw-r--r--drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c4
-rw-r--r--drivers/net/ethernet/google/gve/gve_main.c8
-rw-r--r--drivers/net/ethernet/google/gve/gve_rx_dqo.c13
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c22
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c7
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c35
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf.h11
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_main.c85
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_virtchnl.c99
-rw-r--r--drivers/net/ethernet/intel/ice/devlink/port.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_eswitch.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sriov.c32
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rx.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/adj_vport.c20
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c79
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/vport.c24
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c9
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c28
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c1
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_bpf.c8
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_en.c63
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_ethtool.c10
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/hwif.h2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c60
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c30
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c65
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet.h7
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c51
-rw-r--r--drivers/net/pfcp.c7
-rw-r--r--drivers/net/team/team_core.c16
-rw-r--r--drivers/net/team/team_mode_broadcast.c2
-rw-r--r--drivers/net/tun.c23
-rw-r--r--drivers/net/usb/ax88179_178a.c6
-rw-r--r--drivers/net/veth.c1
-rw-r--r--drivers/net/virtio_net.c2
-rw-r--r--drivers/net/wireguard/noise.c7
-rw-r--r--drivers/net/wireguard/queueing.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/core.c33
-rw-r--r--drivers/net/wireless/ath/ath12k/core.h3
-rw-r--r--drivers/net/wireless/ath/ath12k/hif.h9
-rw-r--r--drivers/net/wireless/ath/ath12k/pci.c8
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c27
-rw-r--r--drivers/net/wireless/marvell/libertas/tx.c7
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76.h7
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/init.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/init.c6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/main.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/mac.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/main.c12
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c128
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/init.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/main.c10
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mcu.h3
-rw-r--r--drivers/net/wireless/mediatek/mt76/tx.c14
-rw-r--r--drivers/net/wireless/nxp/nxpwifi/11n.c2
-rw-r--r--drivers/net/wireless/nxp/nxpwifi/11n_aggr.c1
-rw-r--r--drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.c11
-rw-r--r--drivers/net/wireless/nxp/nxpwifi/cfg80211.c31
-rw-r--r--drivers/net/wireless/nxp/nxpwifi/init.c2
-rw-r--r--drivers/net/wireless/nxp/nxpwifi/main.c4
-rw-r--r--drivers/net/wireless/nxp/nxpwifi/uap_event.c1
-rw-r--r--drivers/net/wireless/nxp/nxpwifi/util.c8
-rw-r--r--drivers/net/xen-netfront.c16
-rw-r--r--drivers/pci/pcie/aer.c22
-rw-r--r--drivers/pmdomain/imx/imx8m-blk-ctrl.c15
-rw-r--r--drivers/pmdomain/rockchip/pm-domains.c20
-rw-r--r--drivers/ptp/ptp_ocp.c2
140 files changed, 1588 insertions, 873 deletions
diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c
index f333b01f7465..ac7193400769 100644
--- a/drivers/bluetooth/btintel_pcie.c
+++ b/drivers/bluetooth/btintel_pcie.c
@@ -401,7 +401,7 @@ static int btintel_pcie_send_sync(struct btintel_pcie_data *data,
tfd_index = data->ia.tr_hia[BTINTEL_PCIE_TXQ_NUM];
- if (tfd_index > txq->count)
+ if (tfd_index >= txq->count)
return -ERANGE;
if (skb->len > BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN) {
@@ -1777,7 +1777,7 @@ static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id)
static int btintel_pcie_setup_irq(struct btintel_pcie_data *data)
{
int err;
- int num_irqs, i;
+ int num_irqs, i, j;
for (i = 0; i < BTINTEL_PCIE_MSIX_VEC_MAX; i++)
data->msix_entries[i].entry = i;
@@ -1806,6 +1806,10 @@ static int btintel_pcie_setup_irq(struct btintel_pcie_data *data)
KBUILD_MODNAME,
msix_entry);
if (err) {
+ for (j = 0; j < i; j++)
+ devm_free_irq(&data->pdev->dev,
+ data->msix_entries[j].vector,
+ &data->msix_entries[j]);
pci_free_irq_vectors(data->pdev);
data->alloc_vecs = 0;
return err;
@@ -1877,6 +1881,13 @@ static int btintel_pcie_config_pcie(struct pci_dev *pdev,
if (IS_ERR(data->base_addr))
return PTR_ERR(data->base_addr);
+ /* Do shared hardware reset to ensure a clean start before
+ * configuring interrupts.
+ */
+ err = btintel_pcie_reset_bt(data);
+ if (err)
+ return err;
+
err = btintel_pcie_setup_irq(data);
if (err)
return err;
@@ -3138,7 +3149,7 @@ static void btintel_pcie_remove(struct pci_dev *pdev)
struct msix_entry *msix_entry;
msix_entry = &data->msix_entries[i];
- free_irq(msix_entry->vector, msix_entry);
+ devm_free_irq(&pdev->dev, msix_entry->vector, msix_entry);
}
pci_free_irq_vectors(pdev);
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 475235c402e8..0c0d11c72925 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -2796,13 +2796,13 @@ static inline void decode_bus_error(int node_id, struct mce *m)
* the instance_id. For example, instance_id=0xYXXXXX where Y is the channel
* number.
*
- * For DRAM ECC errors, the Chip Select number is given in bits [2:0] of
+ * For DRAM ECC errors, the Chip Select number is given in bits [1:0] of
* the MCA_SYND[ErrorInformation] field.
*/
static void umc_get_err_info(struct mce *m, struct err_info *err)
{
err->channel = (m->ipid & GENMASK(31, 0)) >> 20;
- err->csrow = m->synd & 0x7;
+ err->csrow = m->synd & 0x3;
}
static void decode_umc_error(int node_id, struct mce *m)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
index 054870e9078d..ca5860e493a6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
@@ -598,14 +598,18 @@ int amdgpu_amdkfd_get_dmabuf_info(struct amdgpu_device *adev, int dma_buf_fd,
/* first get metadata_size by buffer = NULL */
r = amdgpu_bo_get_metadata(bo, NULL, 0,
metadata_size, NULL);
+ if (r)
+ goto out_put;
/* user buf_size is bigger than bo metadata_size
* allocate a buf at kernel space and copy */
if (*metadata_size <= buffer_size) {
*metadata_buffer = kzalloc(*metadata_size, GFP_KERNEL);
- if (!*metadata_buffer)
- return -ENOMEM;
+ if (!*metadata_buffer) {
+ r = -ENOMEM;
+ goto out_put;
+ }
r = amdgpu_bo_get_metadata(bo, *metadata_buffer, *metadata_size,
NULL, &metadata_flags);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
index aca1a8045afa..ab7ccfaea22a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
@@ -121,6 +121,20 @@ static int amdgpu_debugfs_process_reg_op(bool read, struct file *f,
*pos &= (1UL << 22) - 1;
+ if (size > PAGE_SIZE)
+ return -EINVAL;
+
+ /*
+ * Access the user buffer only while none of the locks below are held:
+ * a fault takes mmap_lock, and grbm_idx_mutex and srbm_mutex nest
+ * inside it.
+ */
+ u32 *data __free(kfree) = kmalloc(size, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ if (!read && copy_from_user(data, buf, size))
+ return -EFAULT;
+
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
if (r < 0) {
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
@@ -152,28 +166,16 @@ static int amdgpu_debugfs_process_reg_op(bool read, struct file *f,
mutex_lock(&adev->pm.mutex);
while (size) {
- uint32_t value;
-
- if (read) {
- value = RREG32(*pos >> 2);
- r = put_user(value, (uint32_t *)buf);
- } else {
- r = get_user(value, (uint32_t *)buf);
- if (!r)
- amdgpu_mm_wreg_mmio_rlc(adev, *pos >> 2, value, 0);
- }
- if (r) {
- result = r;
- goto end;
- }
+ if (read)
+ data[result >> 2] = RREG32(*pos >> 2);
+ else
+ amdgpu_mm_wreg_mmio_rlc(adev, *pos >> 2, data[result >> 2], 0);
result += 4;
- buf += 4;
*pos += 4;
size -= 4;
}
-end:
if (use_bank) {
amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, 0);
mutex_unlock(&adev->grbm_idx_mutex);
@@ -188,6 +190,10 @@ end:
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
amdgpu_virt_disable_access_debugfs(adev);
+
+ if (read && copy_to_user(buf, data, result))
+ return -EFAULT;
+
return result;
}
@@ -238,11 +244,24 @@ static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 off
struct amdgpu_device *adev = rd->adev;
ssize_t result = 0;
int r;
- uint32_t value;
if (size & 0x3 || offset & 0x3)
return -EINVAL;
+ if (size > PAGE_SIZE)
+ return -EINVAL;
+
+ /*
+ * Access the user buffer only while none of the locks below are held:
+ * a fault takes mmap_lock, and grbm_idx_mutex and srbm_mutex nest
+ * inside it.
+ */
+ u32 *data __free(kfree) = kmalloc(size, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ if (write_en && copy_from_user(data, buf, size))
+ return -EFAULT;
+
r = pm_runtime_get_sync(adev_to_drm(adev)->dev);
if (r < 0) {
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
@@ -281,24 +300,16 @@ static ssize_t amdgpu_debugfs_regs2_op(struct file *f, char __user *buf, u32 off
mutex_lock(&adev->pm.mutex);
while (size) {
- if (!write_en) {
- value = RREG32(offset >> 2);
- r = put_user(value, (uint32_t *)buf);
- } else {
- r = get_user(value, (uint32_t *)buf);
- if (!r)
- amdgpu_mm_wreg_mmio_rlc(adev, offset >> 2, value, rd->id.xcc_id);
- }
- if (r) {
- result = r;
- goto end;
- }
+ if (!write_en)
+ data[result >> 2] = RREG32(offset >> 2);
+ else
+ amdgpu_mm_wreg_mmio_rlc(adev, offset >> 2, data[result >> 2],
+ rd->id.xcc_id);
offset += 4;
size -= 4;
result += 4;
- buf += 4;
}
-end:
+
if (rd->id.use_grbm) {
amdgpu_gfx_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, rd->id.xcc_id);
mutex_unlock(&adev->grbm_idx_mutex);
@@ -317,6 +328,10 @@ end:
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
amdgpu_virt_disable_access_debugfs(adev);
+
+ if (!write_en && copy_to_user(buf, data, result))
+ return -EFAULT;
+
return result;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
index 3dc8faa091d7..61dc2a6be7e7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c
@@ -1080,20 +1080,17 @@ void amdgpu_gmc_init_vga_resv_regions(struct amdgpu_device *adev)
case CHIP_RENOIR:
adev->mman.keep_stolen_vga_memory = true;
break;
- case CHIP_POLARIS10:
- case CHIP_POLARIS11:
- case CHIP_POLARIS12:
- /* MacBookPros with switchable graphics put VRAM at 0 when
- * the iGPU is enabled which results in cursor issues if
- * the cursor ends up at 0. Reserve vram at 0 in that case.
- */
- if (adev->gmc.vram_start == 0)
- adev->mman.keep_stolen_vga_memory = true;
- break;
default:
adev->mman.keep_stolen_vga_memory = false;
break;
}
+ /* MacBookPros with switchable graphics put VRAM at 0 when
+ * the iGPU is enabled which results in cursor issues if
+ * the cursor ends up at 0. Reserve vram at 0 in that case.
+ */
+ if ((adev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) &&
+ (adev->gmc.vram_start == 0))
+ adev->mman.keep_stolen_vga_memory = true;
if (amdgpu_sriov_vf(adev) ||
!amdgpu_device_has_display_hardware(adev)) {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index 242c48e85912..7c081b338fe2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -30,6 +30,7 @@
#include <drm/amdgpu_drm.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_vblank.h>
#include "amdgpu_uvd.h"
#include "amdgpu_vce.h"
#include "atom.h"
@@ -1660,6 +1661,9 @@ u32 amdgpu_get_vblank_counter_kms(struct drm_crtc *crtc)
DRM_ERROR("Invalid crtc %u\n", pipe);
return -EINVAL;
}
+ if (!down_read_trylock(&adev->reset_domain->sem))
+ return drm_crtc_vblank_count(crtc);
+
/* The hw increments its frame counter at start of vsync, not at start
* of vblank, as is required by DRM core vblank counter handling.
@@ -1705,6 +1709,7 @@ u32 amdgpu_get_vblank_counter_kms(struct drm_crtc *crtc)
DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n");
}
+ up_read(&adev->reset_domain->sem);
return count;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index cc8e7af18834..9316423f9340 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -472,6 +472,7 @@ amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
u64 doorbell_index;
struct drm_gem_object *gobj;
struct amdgpu_userq_obj *db_obj = db_info->db_obj;
+ struct amdgpu_bo *abo;
int r, db_size;
gobj = drm_gem_object_lookup(filp, db_info->doorbell_handle);
@@ -480,7 +481,17 @@ amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr,
return -EINVAL;
}
- db_obj->obj = amdgpu_bo_ref(gem_to_amdgpu_bo(gobj));
+ /*
+ * Pinning a regular BO into the doorbell domain would discard its
+ * contents, possibly those of a buffer shared by another client.
+ */
+ abo = gem_to_amdgpu_bo(gobj);
+ if (!(abo->preferred_domains & AMDGPU_GEM_DOMAIN_DOORBELL)) {
+ drm_gem_object_put(gobj);
+ return -EINVAL;
+ }
+
+ db_obj->obj = amdgpu_bo_ref(abo);
drm_gem_object_put(gobj);
r = amdgpu_bo_reserve(db_obj->obj, true);
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
index 14a5abe42d1f..8d5dcaf4fea6 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c
@@ -361,8 +361,7 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
compute_mqd = memdup_user(u64_to_user_ptr(mqd_user->mqd), mqd_user->mqd_size);
if (IS_ERR(compute_mqd)) {
- DRM_ERROR("Failed to read user MQD\n");
- r = -ENOMEM;
+ r = PTR_ERR(compute_mqd);
goto free_mqd;
}
@@ -406,8 +405,7 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
mqd_gfx_v11 = memdup_user(u64_to_user_ptr(mqd_user->mqd), mqd_user->mqd_size);
if (IS_ERR(mqd_gfx_v11)) {
- DRM_ERROR("Failed to read user MQD\n");
- r = -ENOMEM;
+ r = PTR_ERR(mqd_gfx_v11);
goto free_mqd;
}
@@ -451,8 +449,7 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue,
mqd_sdma_v11 = memdup_user(u64_to_user_ptr(mqd_user->mqd), mqd_user->mqd_size);
if (IS_ERR(mqd_sdma_v11)) {
- DRM_ERROR("Failed to read sdma user MQD\n");
- r = -ENOMEM;
+ r = PTR_ERR(mqd_sdma_v11);
goto free_mqd;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
index 2f78395a0c31..4594824985e1 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
@@ -572,12 +572,32 @@ static int allocate_doorbell(struct qcm_process_device *qpd,
* we need the physical sdma engine id in order to get the
* correct doorbell offset.
*/
- uint32_t valid_id = idx_offset[qpd->dqm->dev->node_id *
- get_num_all_sdma_engines(qpd->dqm) +
- q->properties.sdma_engine_id]
- + (q->properties.sdma_queue_id & 1)
- * KFD_QUEUE_DOORBELL_MIRROR_OFFSET
- + (q->properties.sdma_queue_id >> 1);
+ u32 engine_base = idx_offset[dev->node_id *
+ get_num_all_sdma_engines(qpd->dqm) +
+ q->properties.sdma_engine_id];
+ u32 valid_id;
+
+ /*
+ * With the aqua_vanjaram doorbell layout, a shader doorbell
+ * write whose 32-byte block starts in the previous engine's
+ * range rings that engine instead. Engine ranges are 10
+ * indices apart (sdma_doorbell_range = 20 dwords, halved for
+ * 8-byte doorbells, in aqua_vanjaram_doorbell_index_init()),
+ * which puts odd engines 2 indices into a shared block.
+ * Aligning costs at most 2 indices, and 8 queues per engine use
+ * only 4 of the 10, so the aligned base stays in range. The
+ * 512-index mirror offset keeps the alignment.
+ */
+ if (KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 3) ||
+ KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 4) ||
+ KFD_GC_VERSION(dev) == IP_VERSION(9, 5, 0))
+ engine_base = ALIGN(engine_base,
+ KFD_SDMA_SHADER_DOORBELL_GRANULARITY);
+
+ valid_id = engine_base +
+ (q->properties.sdma_queue_id & 1) *
+ KFD_QUEUE_DOORBELL_MIRROR_OFFSET +
+ (q->properties.sdma_queue_id >> 1);
if (restore_id && *restore_id != valid_id)
return -EINVAL;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index d8631847f0eb..435bf2692968 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -133,6 +133,13 @@
*/
#define KFD_QUEUE_DOORBELL_MIRROR_OFFSET 512
+/*
+ * On GC 9.4.3, 9.4.4 and 9.5.0, doorbell writes issued from shaders are
+ * routed to an SDMA engine at 32-byte granularity, i.e. 4 indices with the
+ * 8-byte SDMA doorbells used on SOC15.
+ */
+#define KFD_SDMA_SHADER_DOORBELL_GRANULARITY 4
+
/**
* enum kfd_ioctl_flags - KFD ioctl flags
* Various flags that can be set in &amdkfd_ioctl_desc.flags to control how
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 1b42c4606002..47a0ff2ed035 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3708,6 +3708,13 @@ static void amdgpu_dm_enable_self_refresh(struct amdgpu_display_manager *dm,
struct amdgpu_dm_connector *aconn =
(struct amdgpu_dm_connector *)acrtc_state->stream->dm_stream_context;
+ if (!acrtc_state->base.async_flip) {
+ amdgpu_dm_psr_set_event(dm, acrtc_state->stream, false,
+ psr_event_immediate_flip, false);
+ amdgpu_dm_replay_set_event(dm, acrtc_state->stream, false,
+ replay_event_immediate_flip, false);
+ }
+
/* Decrement skip count when SR is enabled and we're doing fast updates. */
if (acrtc_state->update_type == UPDATE_TYPE_FAST &&
(psr->psr_feature_enabled || pr->replay_feature_enabled)) {
@@ -4118,6 +4125,18 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
}
mutex_lock(&dm->dc_lock);
+ /*
+ * Tearing (immediate) flips cannot work with panel self-refresh
+ * features. The event is cleared by
+ * amdgpu_dm_enable_self_refresh() once async flips stop.
+ */
+ if (immediate_flip) {
+ dc_exit_ips_for_hw_access(dm->dc);
+ amdgpu_dm_psr_set_event(dm, acrtc_state->stream, true,
+ psr_event_immediate_flip, true);
+ amdgpu_dm_replay_set_event(dm, acrtc_state->stream, true,
+ replay_event_immediate_flip, true);
+ }
update_planes_and_stream_adapter(dm->dc,
acrtc_state->update_type,
planes_count,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index d386bb1475bb..45a69bf43971 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -1012,10 +1012,15 @@ decide_crtc_timing_for_drm_display_mode(struct drm_display_mode *drm_mode,
const struct drm_display_mode *native_mode,
bool scale_enabled)
{
+ /* Inserted modes copy the native sync; a sink mode with equal totals may not */
if (scale_enabled || (
native_mode->clock == drm_mode->clock &&
native_mode->htotal == drm_mode->htotal &&
- native_mode->vtotal == drm_mode->vtotal)) {
+ native_mode->vtotal == drm_mode->vtotal &&
+ native_mode->hsync_start == drm_mode->hsync_start &&
+ native_mode->hsync_end == drm_mode->hsync_end &&
+ native_mode->vsync_start == drm_mode->vsync_start &&
+ native_mode->vsync_end == drm_mode->vsync_end)) {
if (native_mode->crtc_clock)
copy_crtc_timing_for_drm_display_mode(native_mode, drm_mode);
} else {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index e13b96358208..a2b8f7033616 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -112,25 +112,7 @@ void amdgpu_dm_plane_fill_blending_from_plane_state(const struct drm_plane_state
if (plane_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI ||
plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) {
- static const uint32_t alpha_formats[] = {
- DRM_FORMAT_ARGB8888,
- DRM_FORMAT_RGBA8888,
- DRM_FORMAT_ABGR8888,
- DRM_FORMAT_ARGB2101010,
- DRM_FORMAT_ABGR2101010,
- DRM_FORMAT_ARGB16161616,
- DRM_FORMAT_ABGR16161616,
- DRM_FORMAT_ARGB16161616F,
- };
- uint32_t format = plane_state->fb->format->format;
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(alpha_formats); ++i) {
- if (format == alpha_formats[i]) {
- *per_pixel_alpha = true;
- break;
- }
- }
+ *per_pixel_alpha = plane_state->fb->format->has_alpha;
if (*per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE)
*pre_multiplied_alpha = false;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index 59ce682f491b..b61771749ca0 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -1572,6 +1572,46 @@ static void dm_test_decide_crtc_timing_no_crtc_clock(struct kunit *test)
KUNIT_EXPECT_EQ(test, drm_mode.crtc_hdisplay, 0);
}
+static void dm_test_decide_crtc_timing_sink_mode_same_totals(struct kunit *test)
+{
+ struct drm_display_mode native_mode = {
+ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016, 4104,
+ 4400, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) };
+ struct drm_display_mode drm_mode = {
+ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 4184, 4272,
+ 4400, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) };
+
+ drm_mode_set_crtcinfo(&native_mode, 0);
+ drm_mode_set_crtcinfo(&drm_mode, 0);
+
+ decide_crtc_timing_for_drm_display_mode(&drm_mode, &native_mode, false);
+
+ KUNIT_EXPECT_EQ(test, drm_mode.crtc_hdisplay, 4096);
+ KUNIT_EXPECT_EQ(test, drm_mode.crtc_hsync_start, 4184);
+}
+
+static void dm_test_decide_crtc_timing_inserted_mode(struct kunit *test)
+{
+ struct drm_display_mode native_mode = {
+ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016, 4104,
+ 4400, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) };
+ struct drm_display_mode drm_mode;
+
+ drm_mode_set_crtcinfo(&native_mode, 0);
+ drm_mode = native_mode;
+ drm_mode.hdisplay = 1920;
+ drm_mode.vdisplay = 1080;
+ drm_mode_set_crtcinfo(&drm_mode, 0);
+
+ decide_crtc_timing_for_drm_display_mode(&drm_mode, &native_mode, false);
+
+ KUNIT_EXPECT_EQ(test, drm_mode.crtc_hdisplay, 3840);
+ KUNIT_EXPECT_EQ(test, drm_mode.crtc_vdisplay, 2160);
+}
+
/* Tests for amdgpu_dm_connector_funcs_reset() */
static const struct drm_connector_funcs dm_test_connector_funcs = {
@@ -5635,6 +5675,8 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_decide_crtc_timing_matching_mode),
KUNIT_CASE(dm_test_decide_crtc_timing_no_copy),
KUNIT_CASE(dm_test_decide_crtc_timing_no_crtc_clock),
+ KUNIT_CASE(dm_test_decide_crtc_timing_sink_mode_same_totals),
+ KUNIT_CASE(dm_test_decide_crtc_timing_inserted_mode),
/* amdgpu_dm_connector_funcs_reset */
KUNIT_CASE(dm_test_funcs_reset_sets_defaults),
KUNIT_CASE(dm_test_funcs_reset_edp_abm_level),
diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
index d4577663a1f0..aa36b79d0f6c 100644
--- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
+++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
@@ -189,13 +189,12 @@ static int aspeed_gfx_load(struct drm_device *drm)
}
reset_control_deassert(priv->rst);
- priv->clk = devm_clk_get(drm->dev, NULL);
+ priv->clk = devm_clk_get_enabled(drm->dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(&pdev->dev,
- "missing or invalid clk device tree entry");
+ "failed to get and enable clock\n");
return PTR_ERR(priv->clk);
}
- clk_prepare_enable(priv->clk);
/* Sanitize control registers */
writel(0, priv->base + CRT_CTRL1);
diff --git a/drivers/gpu/drm/bridge/th1520-dw-hdmi.c b/drivers/gpu/drm/bridge/th1520-dw-hdmi.c
index cbea8b14cd4b..2fa7f2d46b3d 100644
--- a/drivers/gpu/drm/bridge/th1520-dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/th1520-dw-hdmi.c
@@ -135,8 +135,8 @@ static int th1520_dw_hdmi_probe(struct platform_device *pdev)
plat_data->priv_data = hdmi;
hdmi->dw_hdmi = dw_hdmi_probe(pdev, plat_data);
- if (IS_ERR(hdmi))
- return PTR_ERR(hdmi);
+ if (IS_ERR(hdmi->dw_hdmi))
+ return PTR_ERR(hdmi->dw_hdmi);
platform_set_drvdata(pdev, hdmi);
@@ -145,9 +145,9 @@ static int th1520_dw_hdmi_probe(struct platform_device *pdev)
static void th1520_dw_hdmi_remove(struct platform_device *pdev)
{
- struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
+ struct th1520_hdmi *hdmi = platform_get_drvdata(pdev);
- dw_hdmi_remove(hdmi);
+ dw_hdmi_remove(hdmi->dw_hdmi);
}
static const struct of_device_id th1520_dw_hdmi_of_table[] = {
diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c
index e623ccb4c1d8..488fd123a01a 100644
--- a/drivers/gpu/drm/display/drm_dp_helper.c
+++ b/drivers/gpu/drm/display/drm_dp_helper.c
@@ -4634,7 +4634,9 @@ static int dp_aux_backlight_update_status(struct backlight_device *bd)
if (!backlight_is_blank(bd)) {
if (!bl->enabled) {
- drm_edp_backlight_enable(bl->aux, &bl->info, brightness);
+ ret = drm_edp_backlight_enable(bl->aux, &bl->info, brightness);
+ if (ret)
+ return ret;
bl->enabled = true;
return 0;
}
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 83f1809a5d37..a52d5f5b9f05 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -454,8 +454,10 @@ void drm_bridge_add(struct drm_bridge *bridge)
* in bridge_lingering_list. Remove it or bridge_lingering_list will be
* corrupted when adding this bridge to bridge_list below.
*/
+ mutex_lock(&bridge_lock);
if (!list_empty(&bridge->list))
list_del_init(&bridge->list);
+ mutex_unlock(&bridge_lock);
mutex_init(&bridge->hpd_state_mutex);
mutex_init(&bridge->hpd_mutex);
@@ -593,8 +595,10 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
if (!bridge->container)
DRM_WARN("DRM bridge corrupted or not allocated by devm_drm_bridge_alloc()\n");
- if (list_empty(&bridge->list))
- DRM_WARN("Missing drm_bridge_add() before attach\n");
+ scoped_guard(mutex, &bridge_lock) {
+ if (list_empty(&bridge->list))
+ DRM_WARN("Missing drm_bridge_add() before attach\n");
+ }
drm_bridge_get(bridge);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index d4664ed468b2..0817b639b3fa 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1724,10 +1724,10 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper)
ret = drm_fb_helper_single_fb_probe(fb_helper);
if (ret < 0) {
- if (ret == -EAGAIN) {
- fb_helper->deferred_setup = true;
+ /* modesets are probed but fb_helper->fb isn't; defer restore too */
+ fb_helper->deferred_setup = true;
+ if (ret == -EAGAIN)
ret = 0;
- }
mutex_unlock(&fb_helper->lock);
goto err_drm_fb_helper_release_info;
diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c
index aa7792966287..5aa5ac2f3727 100644
--- a/drivers/gpu/drm/gud/gud_pipe.c
+++ b/drivers/gpu/drm/gud/gud_pipe.c
@@ -507,6 +507,7 @@ int gud_plane_atomic_check(struct drm_plane *plane,
for_each_new_connector_in_state(state, connector, connector_state, i) {
if (connector_state->crtc)
break;
+ connector_state = NULL;
}
/*
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index 1f303d4eaa4d..d5aadced7da0 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -1766,6 +1766,7 @@ static int eb_reinit_userptr(struct i915_execbuffer *eb)
static noinline int eb_relocate_parse_slow(struct i915_execbuffer *eb)
{
+ const unsigned int count = eb->buffer_count;
bool have_copy = false;
struct eb_vma *ev;
int err = 0;
@@ -1868,7 +1869,6 @@ err:
out:
if (have_copy) {
- const unsigned int count = eb->buffer_count;
unsigned int i;
for (i = 0; i < count; i++) {
diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c
index a33b19c04737..0f9b4f1dd3cb 100644
--- a/drivers/gpu/drm/i915/gt/intel_rps.c
+++ b/drivers/gpu/drm/i915/gt/intel_rps.c
@@ -1904,7 +1904,8 @@ static void rps_work(struct work_struct *work)
out:
spin_lock_irq(gt->irq_lock);
- gen6_gt_pm_unmask_irq(gt, rps->pm_events);
+ if (intel_rps_is_active(rps))
+ gen6_gt_pm_unmask_irq(gt, rps->pm_events);
spin_unlock_irq(gt->irq_lock);
}
diff --git a/drivers/gpu/drm/imagination/pvr_mmu.c b/drivers/gpu/drm/imagination/pvr_mmu.c
index 62eae7fcd5a2..67e73d7d5d0e 100644
--- a/drivers/gpu/drm/imagination/pvr_mmu.c
+++ b/drivers/gpu/drm/imagination/pvr_mmu.c
@@ -2337,7 +2337,7 @@ void pvr_mmu_op_context_destroy(struct pvr_mmu_op_context *op_ctx)
* @ctx: MMU context associated with owning VM context.
* @sgt: Scatter gather table containing pages pinned for use by this context.
* @device_addr: Virtual device address at the start of the requested mapping.
- * @sgt_offset: Start offset of the requested device-virtual memory mapping.
+ * @sgt_offset: Offset into @sgt of the start of the requested mapping.
* @size: Size in bytes of the requested device-virtual memory mapping. For an
* unmapping, this should be zero so that no page tables are allocated.
*
@@ -2350,7 +2350,6 @@ struct pvr_mmu_op_context *
pvr_mmu_op_context_create(struct pvr_mmu_context *ctx, struct sg_table *sgt,
u64 device_addr, u64 sgt_offset, u64 size)
{
- u64 start_addr = device_addr + sgt_offset;
int err;
struct pvr_mmu_op_context *op_ctx = kzalloc_obj(*op_ctx);
@@ -2365,18 +2364,18 @@ pvr_mmu_op_context_create(struct pvr_mmu_context *ctx, struct sg_table *sgt,
if (size) {
/*
- * The number of page table objects we need to prealloc is
- * indicated by the mapping size, start address and the sizes
- * of the areas mapped per PT or PD. The range calculation is
- * identical to that for the index into a table for a device
- * address, so we reuse those functions here.
+ * The page tables needed are set by the device-virtual range
+ * being mapped: one level 1 table per 1GiB region and one
+ * level 0 table per 2MiB region the range touches. Tables that
+ * already exist are not consumed, so this is an upper bound.
*/
- const u32 l1_start_idx = pvr_page_table_l2_idx(start_addr);
- const u32 l1_end_idx = pvr_page_table_l2_idx(start_addr + size);
- const u32 l1_count = l1_end_idx - l1_start_idx + 1;
- const u32 l0_start_idx = pvr_page_table_l1_idx(start_addr);
- const u32 l0_end_idx = pvr_page_table_l1_idx(start_addr + size);
- const u32 l0_count = l0_end_idx - l0_start_idx + 1;
+ const u64 last_addr = device_addr + size - 1;
+ const u64 l1_count =
+ (last_addr >> ROGUE_MMUCTRL_VADDR_PC_INDEX_SHIFT) -
+ (device_addr >> ROGUE_MMUCTRL_VADDR_PC_INDEX_SHIFT) + 1;
+ const u64 l0_count =
+ (last_addr >> ROGUE_MMUCTRL_VADDR_PD_INDEX_SHIFT) -
+ (device_addr >> ROGUE_MMUCTRL_VADDR_PD_INDEX_SHIFT) + 1;
/*
* Alloc and push page table entries until we have enough of
diff --git a/drivers/gpu/drm/imagination/pvr_vm.c b/drivers/gpu/drm/imagination/pvr_vm.c
index 55cc999f3708..cbdd15ed74fd 100644
--- a/drivers/gpu/drm/imagination/pvr_vm.c
+++ b/drivers/gpu/drm/imagination/pvr_vm.c
@@ -418,6 +418,8 @@ pvr_vm_gpuva_unmap(struct drm_gpuva_op *op, void *op_ctx)
static int
pvr_vm_gpuva_remap(struct drm_gpuva_op *op, void *op_ctx)
{
+ /* The split parts belong to the object of the mapping being split. */
+ struct drm_gpuvm_bo *vm_bo = op->remap.unmap->va->vm_bo;
struct pvr_vm_bind_op *ctx = op_ctx;
u64 va_start = 0, va_range = 0;
int err;
@@ -433,14 +435,12 @@ pvr_vm_gpuva_remap(struct drm_gpuva_op *op, void *op_ctx)
drm_gpuva_remap(&ctx->prev_va->base, &ctx->next_va->base, &op->remap);
if (op->remap.prev) {
- pvr_gem_object_get(gem_to_pvr_gem(ctx->prev_va->base.gem.obj));
- drm_gpuva_link(&ctx->prev_va->base, ctx->gpuvm_bo);
+ drm_gpuva_link(&ctx->prev_va->base, vm_bo);
ctx->prev_va = NULL;
}
if (op->remap.next) {
- pvr_gem_object_get(gem_to_pvr_gem(ctx->next_va->base.gem.obj));
- drm_gpuva_link(&ctx->next_va->base, ctx->gpuvm_bo);
+ drm_gpuva_link(&ctx->next_va->base, vm_bo);
ctx->next_va = NULL;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index 4542d5f4ded8..b776030460f7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -488,7 +488,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
goto done;
break;
case NV_DEVICE_INFO_V0_TURING:
- if (engine != NV_DEVICE_HOST_RUNLIST_ENGINES_NVDEC) {
+ if (engine == NV_DEVICE_HOST_RUNLIST_ENGINES_GR) {
ret = nvif_object_ctor(&chan->chan->user, "abi16CeWar",
0, TURING_DMA_COPY_A, NULL, 0,
&chan->ce);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
index f78e6b9b4292..b841d66f8bb3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
@@ -201,7 +201,7 @@ nvkm_udevice_gcx_ready(struct nvkm_udevice *udev, void *data, u32 size)
} *args = data;
int ret = -ENOSYS;
- if (!gsp) {
+ if (!gsp || !gsp->rm) {
args->v0.ready = NV_DEVICE_GC6_READY | NV_DEVICE_GCOFF_READY;
return 0;
}
diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c
index 5778e23e20a0..653c6755896c 100644
--- a/drivers/gpu/drm/panthor/panthor_sched.c
+++ b/drivers/gpu/drm/panthor/panthor_sched.c
@@ -3674,6 +3674,9 @@ int panthor_group_create(struct panthor_file *pfile,
hweight64(group_args->tiler_core_mask) < group_args->max_tiler_cores)
return -EINVAL;
+ if (group_args->queues.count > sched->cs_slot_count)
+ return -EINVAL;
+
group = kzalloc_obj(*group);
if (!group)
return -ENOMEM;
diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
index 49ea2ed0996b..7b8b3364000f 100644
--- a/drivers/gpu/drm/vc4/vc4_bo.c
+++ b/drivers/gpu/drm/vc4/vc4_bo.c
@@ -204,7 +204,7 @@ static struct list_head *vc4_get_cache_list_for_size(struct drm_device *dev,
struct list_head *new_list;
uint32_t i;
- new_list = kmalloc_objs(struct list_head, new_size);
+ new_list = kvmalloc_objs(struct list_head, new_size);
if (!new_list)
return NULL;
@@ -224,7 +224,7 @@ static struct list_head *vc4_get_cache_list_for_size(struct drm_device *dev,
for (i = vc4->bo_cache.size_list_size; i < new_size; i++)
INIT_LIST_HEAD(&new_list[i]);
- kfree(vc4->bo_cache.size_list);
+ kvfree(vc4->bo_cache.size_list);
vc4->bo_cache.size_list = new_list;
vc4->bo_cache.size_list_size = new_size;
}
@@ -1052,6 +1052,7 @@ static void vc4_bo_cache_destroy(struct drm_device *dev, void *unused)
cancel_work_sync(&vc4->bo_cache.time_work);
vc4_bo_cache_purge(dev);
+ kvfree(vc4->bo_cache.size_list);
for (i = 0; i < vc4->num_labels; i++) {
if (vc4->bo_labels[i].num_allocated) {
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 616caf9d9915..7b64e1ed02d4 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -360,8 +360,11 @@ static int vc4_drm_bind(struct device *dev)
}
ret = aperture_remove_all_conflicting_devices(driver->name);
- if (ret)
+ if (ret) {
+ if (firmware)
+ rpi_firmware_put(firmware);
goto err;
+ }
if (firmware) {
ret = rpi_firmware_property(firmware,
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 0f5958c1e6b6..b0e82c2dc1ba 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -1051,7 +1051,7 @@ void vc4_plane_async_set_fb(struct drm_plane *plane,
/* vc4_v3d.c */
extern struct platform_driver vc4_v3d_driver;
extern const struct of_device_id vc4_v3d_dt_match[];
-int vc4_v3d_get_bin_slot(struct vc4_dev *vc4);
+int vc4_v3d_get_bin_slot(struct vc4_dev *vc4, long timeout);
int vc4_v3d_bin_bo_get(struct vc4_dev *vc4, bool *used);
void vc4_v3d_bin_bo_put(struct vc4_dev *vc4);
int vc4_v3d_pm_get(struct vc4_dev *vc4);
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index e231c906709c..6ee4bd77d433 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -877,11 +877,17 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
drm_gem_object_put(&bo->base.base);
}
- /* Free up the allocation of any bin slots we used. */
+ /* Free up the allocation of any bin slots we used. Jobs that ran to
+ * completion had their slots released in vc4_irq_finish_render_job().
+ * Only jobs that never completed still have slots to be released here.
+ */
spin_lock_irqsave(&vc4->job_lock, irqflags);
vc4->bin_alloc_used &= ~exec->bin_slots;
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ /* Let anyone waiting on the binner pool retry. */
+ wake_up_all(&vc4->job_wait_queue);
+
/* Release the reference on the binner BO if needed. */
if (exec->bin_bo_used)
vc4_v3d_bin_bo_put(vc4);
diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c
index 7877d493d80e..dc10d3a4d90f 100644
--- a/drivers/gpu/drm/vc4/vc4_irq.c
+++ b/drivers/gpu/drm/vc4/vc4_irq.c
@@ -74,7 +74,7 @@ vc4_overflow_mem_work(struct work_struct *work)
bo = vc4->bin_bo;
- bin_bo_slot = vc4_v3d_get_bin_slot(vc4);
+ bin_bo_slot = vc4_v3d_get_bin_slot(vc4, msecs_to_jiffies(500));
if (bin_bo_slot < 0) {
drm_err(&vc4->base, "Couldn't allocate binner overflow mem\n");
goto complete;
@@ -165,6 +165,10 @@ vc4_irq_finish_render_job(struct drm_device *dev)
trace_vc4_rcl_end_irq(dev, exec->seqno);
vc4->finished_seqno++;
+
+ vc4->bin_alloc_used &= ~exec->bin_slots;
+ exec->bin_slots = 0;
+
list_move_tail(&exec->head, &vc4->job_done_list);
nextbin = vc4_first_bin_job(vc4);
@@ -276,7 +280,7 @@ vc4_irq_disable(struct drm_device *dev)
V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
/* Finish any interrupt handler still in flight. */
- synchronize_irq(vc4->irq);
+ disable_irq(vc4->irq);
cancel_work_sync(&vc4->overflow_mem_work);
}
@@ -284,7 +288,6 @@ vc4_irq_disable(struct drm_device *dev)
int vc4_irq_install(struct drm_device *dev, int irq)
{
struct vc4_dev *vc4 = to_vc4_dev(dev);
- int ret;
if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
return -ENODEV;
@@ -298,19 +301,8 @@ int vc4_irq_install(struct drm_device *dev, int irq)
init_waitqueue_head(&vc4->job_wait_queue);
INIT_WORK(&vc4->overflow_mem_work, vc4_overflow_mem_work);
- /* Clear any pending interrupts someone might have left around
- * for us.
- */
- V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
-
- ret = devm_request_irq(dev->dev, irq, vc4_irq, 0,
- dev_name(dev->dev), dev);
- if (ret)
- return ret;
-
- vc4_irq_enable(dev);
-
- return 0;
+ return devm_request_irq(dev->dev, irq, vc4_irq, IRQF_NO_AUTOEN,
+ dev_name(dev->dev), dev);
}
void vc4_irq_uninstall(struct drm_device *dev)
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c
index f32410420d3e..6844e8f3948c 100644
--- a/drivers/gpu/drm/vc4/vc4_v3d.c
+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
@@ -9,6 +9,7 @@
#include <linux/component.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/timer.h>
#include <drm/drm_print.h>
@@ -172,46 +173,42 @@ static void vc4_v3d_init_hw(struct drm_device *dev)
V3D_WRITE(V3D_VPMBASE, 0);
}
-int vc4_v3d_get_bin_slot(struct vc4_dev *vc4)
+static int bin_slot_try_alloc(struct vc4_dev *vc4)
{
- struct drm_device *dev = &vc4->base;
- unsigned long irqflags;
int slot;
- uint64_t seqno = 0;
- struct vc4_exec_info *exec;
- if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
- return -ENODEV;
+ guard(spinlock_irqsave)(&vc4->job_lock);
-try_again:
- spin_lock_irqsave(&vc4->job_lock, irqflags);
slot = ffs(~vc4->bin_alloc_used);
if (slot != 0) {
/* Switch from ffs() bit index to a 0-based index. */
slot--;
vc4->bin_alloc_used |= BIT(slot);
- spin_unlock_irqrestore(&vc4->job_lock, irqflags);
- return slot;
+ } else {
+ slot = -ENOMEM;
}
- /* Couldn't find an open slot. Wait for render to complete
- * and try again.
- */
- exec = vc4_last_render_job(vc4);
- if (exec)
- seqno = exec->seqno;
- spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ return slot;
+}
- if (seqno) {
- int ret = vc4_wait_for_seqno(dev, seqno, ~0ull, true);
+int vc4_v3d_get_bin_slot(struct vc4_dev *vc4, long timeout)
+{
+ int slot;
+ long ret;
- if (ret == 0)
- goto try_again;
+ if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
+ return -ENODEV;
+ /* If the pool is full, wait for a job to release its slots. */
+ ret = wait_event_interruptible_timeout(vc4->job_wait_queue,
+ (slot = bin_slot_try_alloc(vc4)) >= 0,
+ timeout);
+ if (ret < 0)
return ret;
- }
+ if (ret == 0)
+ return -ENOMEM;
- return -ENOMEM;
+ return slot;
}
/*
@@ -396,6 +393,7 @@ static int vc4_v3d_runtime_resume(struct device *dev)
vc4_v3d_init_hw(&vc4->base);
vc4_irq_enable(&vc4->base);
+ enable_irq(vc4->irq);
return 0;
}
@@ -452,6 +450,12 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
return ret;
vc4->irq = ret;
+ ret = vc4_irq_install(drm, vc4->irq);
+ if (ret) {
+ drm_err(drm, "Failed to install IRQ handler\n");
+ return ret;
+ }
+
ret = devm_pm_runtime_enable(dev);
if (ret)
return ret;
@@ -473,12 +477,6 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
V3D_WRITE(V3D_BPOA, 0);
V3D_WRITE(V3D_BPOS, 0);
- ret = vc4_irq_install(drm, vc4->irq);
- if (ret) {
- drm_err(drm, "Failed to install IRQ handler\n");
- goto err_put_runtime_pm;
- }
-
pm_runtime_use_autosuspend(dev);
pm_runtime_set_autosuspend_delay(dev, 40); /* a little over 2 frames. */
pm_runtime_put_autosuspend(dev);
@@ -497,8 +495,15 @@ static void vc4_v3d_unbind(struct device *dev, struct device *master,
struct drm_device *drm = data;
struct vc4_dev *vc4 = to_vc4_dev(drm);
+ /* A straggler vc4_reset() re-enables the interrupt. */
+ timer_shutdown_sync(&vc4->hangcheck.timer);
+ cancel_work_sync(&vc4->hangcheck.reset_work);
+
vc4_irq_uninstall(drm);
+ /* Flush rather than cancel, so queued completions release their jobs. */
+ flush_work(&vc4->job_done_work);
+
/* Disable the binner's overflow memory address, so the next
* driver probe (if any) doesn't try to reuse our old
* allocation.
diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c
index d2a65c968b1f..565227657b43 100644
--- a/drivers/gpu/drm/vc4/vc4_validate.c
+++ b/drivers/gpu/drm/vc4/vc4_validate.c
@@ -402,7 +402,7 @@ validate_tile_binning_config(VALIDATE_ARGS)
return -EINVAL;
}
- bin_slot = vc4_v3d_get_bin_slot(vc4);
+ bin_slot = vc4_v3d_get_bin_slot(vc4, MAX_SCHEDULE_TIMEOUT);
if (bin_slot < 0) {
if (bin_slot != -EINTR && bin_slot != -ERESTARTSYS) {
drm_err(dev, "Failed to allocate binner memory: %d\n",
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c
index d1e7df500190..5a69606a0593 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cursor_plane.c
@@ -324,6 +324,7 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
unsigned long kmap_num;
SVGA3dCopyBox *box;
u32 box_count;
+ u64 src_extent;
void *virtual;
bool is_iomem;
struct vmw_dma_cmd {
@@ -335,6 +336,8 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
vmw_surface_get_desc(VMW_CURSOR_SNOOP_FORMAT);
const u32 image_pitch = VMW_CURSOR_SNOOP_WIDTH * desc->pitchBytesPerBlock;
+ BUILD_BUG_ON(sizeof(*srf->snooper.image) != desc->pitchBytesPerBlock);
+
cmd = container_of(header, struct vmw_dma_cmd, header);
/* No snooper installed, nothing to copy */
@@ -372,8 +375,19 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
return;
}
+ if (box->w == 0 || box->h == 0)
+ return;
+
+ src_extent = (u64)(box->h - 1) * cmd->dma.guest.pitch +
+ (u64)box->w * desc->pitchBytesPerBlock;
+ if (src_extent > bo->base.size) {
+ DRM_ERROR("Cursor snoop source of %llu bytes exceeds the %zu byte buffer\n",
+ src_extent, bo->base.size);
+ return;
+ }
+
kmap_offset = cmd->dma.guest.ptr.offset >> PAGE_SHIFT;
- kmap_num = (VMW_CURSOR_SNOOP_HEIGHT * image_pitch) >> PAGE_SHIFT;
+ kmap_num = PFN_UP(src_extent);
ret = ttm_bo_reserve(bo, true, false, NULL);
if (unlikely(ret != 0)) {
@@ -387,14 +401,16 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
virtual = ttm_kmap_obj_virtual(&map, &is_iomem);
- if (box->w == VMW_CURSOR_SNOOP_WIDTH && cmd->dma.guest.pitch == image_pitch) {
+ if (box->w == VMW_CURSOR_SNOOP_WIDTH &&
+ box->h == VMW_CURSOR_SNOOP_HEIGHT &&
+ cmd->dma.guest.pitch == image_pitch) {
memcpy(srf->snooper.image, virtual,
VMW_CURSOR_SNOOP_HEIGHT * image_pitch);
} else {
- /* Image is unsigned pointer. */
+ /* The destination stride is in pixels. */
for (i = 0; i < box->h; i++)
- memcpy(srf->snooper.image + i * image_pitch,
- virtual + i * cmd->dma.guest.pitch,
+ memcpy(srf->snooper.image + i * VMW_CURSOR_SNOOP_WIDTH,
+ virtual + (size_t)i * cmd->dma.guest.pitch,
box->w * desc->pitchBytesPerBlock);
}
srf->snooper.id++;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 1b407b61f683..31d3ee0825ca 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -20,10 +20,18 @@
#include <drm/drm_rect.h>
#include <drm/drm_sysfs.h>
#include <drm/drm_edid.h>
+#include <drm/drm_blend.h>
void vmw_du_init(struct vmw_display_unit *du)
{
vmw_vkms_crtc_init(&du->crtc);
+ drm_plane_create_blend_mode_property(&du->primary,
+ BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+ BIT(DRM_MODE_BLEND_PREMULTI));
+ // Check that the cursor plane was actually initialized
+ if (du->crtc.cursor == &du->cursor.base)
+ drm_plane_create_blend_mode_property(&du->cursor.base,
+ BIT(DRM_MODE_BLEND_PREMULTI));
}
void vmw_du_cleanup(struct vmw_display_unit *du)
diff --git a/drivers/gpu/drm/xe/display/xe_fb_pin.c b/drivers/gpu/drm/xe/display/xe_fb_pin.c
index 73469ea5f333..f1dbdc802df8 100644
--- a/drivers/gpu/drm/xe/display/xe_fb_pin.c
+++ b/drivers/gpu/drm/xe/display/xe_fb_pin.c
@@ -356,7 +356,7 @@ static struct i915_vma *__xe_pin_fb_vma(struct drm_gem_object *obj, bool is_dpt,
drm_exec_retry_on_contention(&exec);
xe_validation_retry_on_oom(&ctx, &ret);
if (!ret)
- ttm_bo_pin(&bo->ttm);
+ xe_bo_pin_account(bo);
}
if (ret)
goto err;
@@ -373,7 +373,7 @@ static struct i915_vma *__xe_pin_fb_vma(struct drm_gem_object *obj, bool is_dpt,
err_unpin:
ttm_bo_reserve(&bo->ttm, false, false, NULL);
- ttm_bo_unpin(&bo->ttm);
+ xe_bo_unpin_account(bo);
ttm_bo_unreserve(&bo->ttm);
err:
kfree(vma);
@@ -393,7 +393,7 @@ static void __xe_unpin_fb_vma(struct i915_vma *vma)
xe_ggtt_node_remove(vma->node, false);
ttm_bo_reserve(&vma->bo->ttm, false, false, NULL);
- ttm_bo_unpin(&vma->bo->ttm);
+ xe_bo_unpin_account(vma->bo);
ttm_bo_unreserve(&vma->bo->ttm);
kfree(vma);
}
diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c
index b4921a627ff3..7b95ce0445a9 100644
--- a/drivers/gpu/drm/xe/xe_bo.c
+++ b/drivers/gpu/drm/xe/xe_bo.c
@@ -455,6 +455,100 @@ static void xe_ttm_tt_account_subtract(struct xe_device *xe, struct ttm_tt *tt)
xe_shrinker_mod_pages(xe->mem.shrinker, -(long)tt->num_pages, 0);
}
+static bool xe_ttm_bo_is_imported(struct ttm_buffer_object *tbo)
+{
+ dma_resv_assert_held(tbo->base.resv);
+
+ return tbo->ttm &&
+ (tbo->ttm->page_flags & (TTM_TT_FLAG_EXTERNAL | TTM_TT_FLAG_EXTERNAL_MAPPABLE)) ==
+ TTM_TT_FLAG_EXTERNAL;
+}
+
+/*
+ * Account @bo's pages as pinned for the shrinker. Removes @bo's pages
+ * from the shrinker's shrinkable / purgeable counts on the transition
+ * from unpinned to pinned. Must be called with @bo's dma-resv held,
+ * after &ttm_buffer_object.pin_count has been incremented by
+ * ttm_bo_pin(). Safe to call unconditionally regardless of which pin
+ * path (kernel, external, framebuffer, backup object, ...) is pinning
+ * @bo, since it only acts on the true 0->1 pin_count transition.
+ *
+ * Imported bos (xe_ttm_bo_is_imported()) are excluded: for those,
+ * xe_ttm_tt_populate() never actually populates the tt or calls
+ * xe_ttm_tt_account_add(), but TTM core's ttm_tt_populate() still
+ * unconditionally marks the tt as populated on driver-hook success.
+ * Relying on ttm_tt_is_populated() for these would subtract pages that
+ * were never added, underflowing the shrinker's counts.
+ */
+static void xe_bo_account_pin(struct xe_bo *bo)
+{
+ struct xe_device *xe = xe_bo_device(bo);
+
+ if (bo->ttm.pin_count == 1 && bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm) &&
+ !xe_ttm_bo_is_imported(&bo->ttm))
+ xe_ttm_tt_account_subtract(xe, bo->ttm.ttm);
+}
+
+/*
+ * Counterpart to xe_bo_account_pin(). Must be called with @bo's dma-resv
+ * held, before &ttm_buffer_object.pin_count is decremented by
+ * ttm_bo_unpin(), so that the check against the true 1->0 transition sees
+ * the pin count that is about to be released. See xe_bo_account_pin() for
+ * why imported bos are excluded.
+ *
+ * On the true last unpin, also removes @bo from whichever pinned-bo list
+ * (external or kernel_bo_present) it may currently be linked on, since a
+ * bo's final unpin can happen through a pin path (e.g. framebuffer,
+ * backup object) that has no notion of, or ownership over, that list.
+ * This is safe and list-agnostic: list_del_init() only needs the node
+ * itself, not knowledge of which list it is threaded through, and is a
+ * no-op if @bo is not linked.
+ */
+static void xe_bo_account_unpin(struct xe_bo *bo)
+{
+ struct xe_device *xe = xe_bo_device(bo);
+ bool last_unpin = bo->ttm.pin_count == 1;
+
+ if (last_unpin && !list_empty(&bo->pinned_link)) {
+ spin_lock(&xe->pinned.lock);
+ list_del_init(&bo->pinned_link);
+ spin_unlock(&xe->pinned.lock);
+ }
+
+ if (last_unpin && bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm) &&
+ !xe_ttm_bo_is_imported(&bo->ttm))
+ xe_ttm_tt_account_add(xe, bo->ttm.ttm);
+}
+
+/**
+ * xe_bo_pin_account() - Pin a bo and account its pages for the shrinker
+ * @bo: The buffer object to pin.
+ *
+ * Pins @bo via ttm_bo_pin() and updates the shrinker's shrinkable /
+ * purgeable page accounting to match. Must be called with @bo's dma-resv
+ * held. Safe to call regardless of which pin path (kernel, external,
+ * framebuffer, backup object, ...) is pinning @bo.
+ */
+void xe_bo_pin_account(struct xe_bo *bo)
+{
+ ttm_bo_pin(&bo->ttm);
+ xe_bo_account_pin(bo);
+}
+
+/**
+ * xe_bo_unpin_account() - Unpin a bo and account its pages for the shrinker
+ * @bo: The buffer object to unpin.
+ *
+ * Counterpart to xe_bo_pin_account(). Updates the shrinker's shrinkable /
+ * purgeable page accounting to match, then unpins @bo via ttm_bo_unpin().
+ * Must be called with @bo's dma-resv held.
+ */
+void xe_bo_unpin_account(struct xe_bo *bo)
+{
+ xe_bo_account_unpin(bo);
+ ttm_bo_unpin(&bo->ttm);
+}
+
static void update_global_total_pages(struct ttm_device *ttm_dev,
long num_pages)
{
@@ -1389,7 +1483,8 @@ int xe_bo_notifier_prepare_pinned(struct xe_bo *bo)
}
backup->parent_obj = xe_bo_get(bo); /* Released by bo_destroy */
- ttm_bo_pin(&backup->ttm);
+ /* Note: XE_BO_FLAG_SYSTEM resolves to XE_PL_TT so already populated. */
+ xe_bo_pin_account(backup);
bo->backup_obj = backup;
}
@@ -1409,7 +1504,7 @@ int xe_bo_notifier_unprepare_pinned(struct xe_bo *bo)
{
xe_bo_lock(bo, false);
if (bo->backup_obj) {
- ttm_bo_unpin(&bo->backup_obj->ttm);
+ xe_bo_unpin_account(bo->backup_obj);
xe_bo_put(bo->backup_obj);
bo->backup_obj = NULL;
}
@@ -1620,7 +1715,7 @@ out_backup:
xe_bo_vunmap(backup);
if (!bo->backup_obj) {
if (xe_bo_is_pinned(backup))
- ttm_bo_unpin(&backup->ttm);
+ xe_bo_unpin_account(backup);
xe_bo_put(backup);
}
out_unlock_bo:
@@ -2012,15 +2107,6 @@ static vm_fault_t xe_err_to_fault_t(int err)
return VM_FAULT_SIGBUS;
}
-static bool xe_ttm_bo_is_imported(struct ttm_buffer_object *tbo)
-{
- dma_resv_assert_held(tbo->base.resv);
-
- return tbo->ttm &&
- (tbo->ttm->page_flags & (TTM_TT_FLAG_EXTERNAL | TTM_TT_FLAG_EXTERNAL_MAPPABLE)) ==
- TTM_TT_FLAG_EXTERNAL;
-}
-
static vm_fault_t xe_bo_cpu_fault_fastpath(struct vm_fault *vmf, struct xe_device *xe,
struct xe_bo *bo, bool needs_rpm)
{
@@ -3141,12 +3227,13 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res)
int xe_bo_pin_external(struct xe_bo *bo, bool in_place, struct drm_exec *exec)
{
struct xe_device *xe = xe_bo_device(bo);
+ bool first_pin = !xe_bo_is_pinned(bo);
int err;
xe_assert(xe, !bo->vm);
xe_assert(xe, xe_bo_is_user(bo));
- if (!xe_bo_is_pinned(bo)) {
+ if (first_pin) {
if (!in_place) {
err = xe_bo_validate(bo, NULL, false, exec);
if (err)
@@ -3158,9 +3245,7 @@ int xe_bo_pin_external(struct xe_bo *bo, bool in_place, struct drm_exec *exec)
spin_unlock(&xe->pinned.lock);
}
- ttm_bo_pin(&bo->ttm);
- if (bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm))
- xe_ttm_tt_account_subtract(xe, bo->ttm.ttm);
+ xe_bo_pin_account(bo);
/*
* FIXME: If we always use the reserve / unreserve functions for locking
@@ -3216,9 +3301,7 @@ int xe_bo_pin(struct xe_bo *bo, struct drm_exec *exec)
spin_unlock(&xe->pinned.lock);
}
- ttm_bo_pin(&bo->ttm);
- if (bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm))
- xe_ttm_tt_account_subtract(xe, bo->ttm.ttm);
+ xe_bo_pin_account(bo);
/*
* FIXME: If we always use the reserve / unreserve functions for locking
@@ -3247,14 +3330,7 @@ void xe_bo_unpin_external(struct xe_bo *bo)
xe_assert(xe, xe_bo_is_pinned(bo));
xe_assert(xe, xe_bo_is_user(bo));
- spin_lock(&xe->pinned.lock);
- if (bo->ttm.pin_count == 1 && !list_empty(&bo->pinned_link))
- list_del_init(&bo->pinned_link);
- spin_unlock(&xe->pinned.lock);
-
- ttm_bo_unpin(&bo->ttm);
- if (bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm))
- xe_ttm_tt_account_add(xe, bo->ttm.ttm);
+ xe_bo_unpin_account(bo);
/*
* FIXME: If we always use the reserve / unreserve functions for locking
@@ -3272,21 +3348,16 @@ void xe_bo_unpin(struct xe_bo *bo)
xe_assert(xe, xe_bo_is_pinned(bo));
if (mem_type_is_vram(place->mem_type) || bo->flags & XE_BO_FLAG_GGTT) {
- spin_lock(&xe->pinned.lock);
xe_assert(xe, !list_empty(&bo->pinned_link));
- list_del_init(&bo->pinned_link);
- spin_unlock(&xe->pinned.lock);
if (bo->backup_obj) {
if (xe_bo_is_pinned(bo->backup_obj))
- ttm_bo_unpin(&bo->backup_obj->ttm);
+ xe_bo_unpin_account(bo->backup_obj);
xe_bo_put(bo->backup_obj);
bo->backup_obj = NULL;
}
}
- ttm_bo_unpin(&bo->ttm);
- if (bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm))
- xe_ttm_tt_account_add(xe, bo->ttm.ttm);
+ xe_bo_unpin_account(bo);
}
/**
diff --git a/drivers/gpu/drm/xe/xe_bo.h b/drivers/gpu/drm/xe/xe_bo.h
index 152bfcffe399..53a701d3d242 100644
--- a/drivers/gpu/drm/xe/xe_bo.h
+++ b/drivers/gpu/drm/xe/xe_bo.h
@@ -229,6 +229,8 @@ int xe_bo_pin_external(struct xe_bo *bo, bool in_place, struct drm_exec *exec);
int xe_bo_pin(struct xe_bo *bo, struct drm_exec *exec);
void xe_bo_unpin_external(struct xe_bo *bo);
void xe_bo_unpin(struct xe_bo *bo);
+void xe_bo_pin_account(struct xe_bo *bo);
+void xe_bo_unpin_account(struct xe_bo *bo);
int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict,
struct drm_exec *exec);
diff --git a/drivers/gpu/drm/xe/xe_i2c.c b/drivers/gpu/drm/xe/xe_i2c.c
index f4f381988289..b82caaff80d7 100644
--- a/drivers/gpu/drm/xe/xe_i2c.c
+++ b/drivers/gpu/drm/xe/xe_i2c.c
@@ -324,12 +324,15 @@ static void xe_i2c_remove(void *data)
xe_i2c_irq_reset(xe);
xe_amc_exit(i2c);
+ /* Stop the notifier from arming the client work before teardown. */
+ bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier);
+ cancel_work_sync(&i2c->work);
+
for (i = 0; i < XE_I2C_MAX_CLIENTS; i++) {
i2c_unregister_device(i2c->client[i]);
i2c->client[i] = NULL;
}
- bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier);
xe_i2c_unregister_adapter(i2c);
xe->i2c = NULL;
}
diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c
index 35b4e8289b5f..e4388a960490 100644
--- a/drivers/gpu/drm/xe/xe_lrc.c
+++ b/drivers/gpu/drm/xe/xe_lrc.c
@@ -1099,8 +1099,7 @@ static void xe_lrc_finish(struct xe_lrc *lrc)
#define CONTEXT_ACTIVE XE_LRC_CTX_TIMESTAMP_ACTIVE
static ssize_t setup_utilization_wa(struct xe_lrc *lrc,
struct xe_hw_engine *hwe,
- u32 *batch,
- size_t max_len)
+ u32 *batch, size_t max_len, bool indirect)
{
u32 *cmd = batch;
@@ -1131,19 +1130,25 @@ static ssize_t setup_utilization_wa(struct xe_lrc *lrc,
}
static ssize_t setup_timestamp_wa(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
- u32 *batch, size_t max_len)
+ u32 *batch, size_t max_len, bool indirect)
{
const u32 ts_addr = __xe_lrc_ctx_timestamp_ggtt_addr(lrc);
u32 *cmd = batch;
- if (!XE_GT_WA(lrc->gt, 16010904313) ||
- !(hwe->class == XE_ENGINE_CLASS_RENDER ||
- hwe->class == XE_ENGINE_CLASS_COMPUTE ||
- hwe->class == XE_ENGINE_CLASS_COPY ||
+ if (!XE_GT_WA(lrc->gt, 16010904313))
+ return 0;
+
+ if (!indirect &&
+ !(hwe->class == XE_ENGINE_CLASS_COPY ||
hwe->class == XE_ENGINE_CLASS_VIDEO_DECODE ||
hwe->class == XE_ENGINE_CLASS_VIDEO_ENHANCE))
return 0;
+ if (indirect &&
+ !(hwe->class == XE_ENGINE_CLASS_RENDER ||
+ hwe->class == XE_ENGINE_CLASS_COMPUTE))
+ return 0;
+
if (xe_gt_WARN_ON(lrc->gt, max_len < 12))
return -ENOSPC;
@@ -1169,7 +1174,8 @@ static ssize_t setup_timestamp_wa(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
static ssize_t setup_configfs_post_ctx_restore_bb(struct xe_lrc *lrc,
struct xe_hw_engine *hwe,
- u32 *batch, size_t max_len)
+ u32 *batch, size_t max_len,
+ bool indirect)
{
struct xe_device *xe = gt_to_xe(lrc->gt);
const u32 *user_batch;
@@ -1198,7 +1204,8 @@ static ssize_t setup_configfs_post_ctx_restore_bb(struct xe_lrc *lrc,
static ssize_t setup_configfs_mid_ctx_restore_bb(struct xe_lrc *lrc,
struct xe_hw_engine *hwe,
- u32 *batch, size_t max_len)
+ u32 *batch, size_t max_len,
+ bool indirect)
{
struct xe_device *xe = gt_to_xe(lrc->gt);
const u32 *user_batch;
@@ -1227,7 +1234,8 @@ static ssize_t setup_configfs_mid_ctx_restore_bb(struct xe_lrc *lrc,
static ssize_t setup_invalidate_state_cache_wa(struct xe_lrc *lrc,
struct xe_hw_engine *hwe,
- u32 *batch, size_t max_len)
+ u32 *batch, size_t max_len,
+ bool indirect)
{
u32 *cmd = batch;
@@ -1247,7 +1255,8 @@ static ssize_t setup_invalidate_state_cache_wa(struct xe_lrc *lrc,
static ssize_t setup_invalidate_auxccs_wa(struct xe_lrc *lrc,
struct xe_hw_engine *hwe,
- u32 *batch, size_t max_len)
+ u32 *batch, size_t max_len,
+ bool indirect)
{
struct xe_gt *gt = lrc->gt;
u32 *(*emit)(struct xe_gt *gt, u32 *cmd) =
@@ -1264,7 +1273,7 @@ static ssize_t setup_invalidate_auxccs_wa(struct xe_lrc *lrc,
struct bo_setup {
ssize_t (*setup)(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
- u32 *batch, size_t max_size);
+ u32 *batch, size_t max_size, bool indirect);
};
struct bo_setup_state {
@@ -1273,6 +1282,7 @@ struct bo_setup_state {
struct xe_hw_engine *hwe;
size_t max_size;
size_t reserve_dw;
+ bool indirect;
unsigned int offset;
const struct bo_setup *funcs;
unsigned int num_funcs;
@@ -1298,7 +1308,8 @@ static int setup_bo(struct bo_setup_state *state)
for (size_t i = 0; i < state->num_funcs; i++) {
ssize_t len = state->funcs[i].setup(state->lrc, state->hwe,
- state->ptr, remain);
+ state->ptr, remain,
+ state->indirect);
remain -= len;
@@ -1404,6 +1415,7 @@ setup_indirect_ctx(struct xe_lrc *lrc, struct xe_hw_engine *hwe)
struct bo_setup_state state = {
.lrc = lrc,
.hwe = hwe,
+ .indirect = true,
.max_size = (63 * 64) /* max 63 cachelines */,
.buffer = NULL,
.offset = __xe_lrc_indirect_ctx_offset(lrc),
diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c
index 7fa18dfcb5a2..455a07d79cd9 100644
--- a/drivers/gpu/drm/xe/xe_mmio.c
+++ b/drivers/gpu/drm/xe/xe_mmio.c
@@ -320,6 +320,7 @@ u64 xe_mmio_read64_2x32(struct xe_mmio *mmio, struct xe_reg reg)
return (u64)udw << 32 | ldw;
}
+#define __XE_MMIO_WAIT_MAX_BACKOFF_100MS (100 * USEC_PER_MSEC)
static int __xe_mmio_wait32(struct xe_mmio *mmio, struct xe_reg reg, u32 mask, u32 val,
u32 timeout_us, u32 *out_val, bool atomic, bool expect_match)
{
@@ -350,10 +351,10 @@ static int __xe_mmio_wait32(struct xe_mmio *mmio, struct xe_reg reg, u32 mask, u
wait = ktime_us_delta(end, cur);
if (atomic)
- udelay(wait);
+ udelay(min_t(s64, wait, (MAX_UDELAY_MS * 1000)));
else
usleep_range(wait, wait << 1);
- wait <<= 1;
+ wait = min_t(s64, wait << 1, __XE_MMIO_WAIT_MAX_BACKOFF_100MS);
}
if (ret != 0) {
diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c
index 72baf1aa4b3a..a0179e62abaa 100644
--- a/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c
+++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c
@@ -19,20 +19,20 @@
#include "xe_sysctrl_mailbox_types.h"
struct xe_sysctrl_mailbox_msg_hdr {
- __le32 data;
-} __packed;
+ u32 data;
+};
#define XE_SYSCTRL_HDR_GROUP_ID(hdr) \
- FIELD_GET(SYSCTRL_HDR_GROUP_ID_MASK, le32_to_cpu((hdr)->data))
+ FIELD_GET(SYSCTRL_HDR_GROUP_ID_MASK, (hdr)->data)
#define XE_SYSCTRL_HDR_COMMAND(hdr) \
- FIELD_GET(SYSCTRL_HDR_COMMAND_MASK, le32_to_cpu((hdr)->data))
+ FIELD_GET(SYSCTRL_HDR_COMMAND_MASK, (hdr)->data)
#define XE_SYSCTRL_HDR_IS_RESPONSE(hdr) \
- FIELD_GET(SYSCTRL_HDR_IS_RESPONSE, le32_to_cpu((hdr)->data))
+ FIELD_GET(SYSCTRL_HDR_IS_RESPONSE, (hdr)->data)
#define XE_SYSCTRL_HDR_RESULT(hdr) \
- FIELD_GET(SYSCTRL_HDR_RESULT_MASK, le32_to_cpu((hdr)->data))
+ FIELD_GET(SYSCTRL_HDR_RESULT_MASK, (hdr)->data)
static bool sysctrl_wait_bit_clear(struct xe_sysctrl *sc, u32 bit_mask,
unsigned int timeout_ms)
@@ -126,8 +126,8 @@ static int sysctrl_prepare_command(struct xe_device *xe,
return -ENOMEM;
hdr = (struct xe_sysctrl_mailbox_msg_hdr *)buffer;
- hdr->data = cpu_to_le32(FIELD_PREP(SYSCTRL_HDR_GROUP_ID_MASK, group_id) |
- FIELD_PREP(SYSCTRL_HDR_COMMAND_MASK, command));
+ hdr->data = FIELD_PREP(SYSCTRL_HDR_GROUP_ID_MASK, group_id) |
+ FIELD_PREP(SYSCTRL_HDR_COMMAND_MASK, command);
if (data_in && data_in_len)
memcpy(buffer + sizeof(*hdr), data_in, data_in_len);
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 6a39e21d5ed4..ed6495ef811c 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -1003,13 +1003,14 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
ret = gi2c->dev_data->set_rate(&gi2c->se, gi2c->clk_freq_out);
if (ret)
- return ret;
+ goto out_pm;
if (gi2c->gpi_mode)
ret = geni_i2c_gpi_xfer(gi2c, msgs, num);
else
ret = geni_i2c_fifo_xfer(gi2c, msgs, num);
+out_pm:
pm_runtime_put_autosuspend(gi2c->se.dev);
gi2c->cur = NULL;
gi2c->err = 0;
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 6406ceab988a..810e52782ae8 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -302,6 +302,8 @@ static const struct xpad_device {
{ 0x17ef, 0x6182, "Lenovo Legion Controller for Windows", 0, XTYPE_XBOX360 },
{ 0x1949, 0x041a, "Amazon Game Controller", 0, XTYPE_XBOX360 },
{ 0x1a86, 0xe310, "Legion Go S", 0, XTYPE_XBOX360 },
+ { 0x1b1c, 0x2b1f, "Corsair Novablade Pro (Wired)", 0, XTYPE_XBOX360 },
+ { 0x1b1c, 0x2b2b, "Corsair Novablade Pro (2.4 GHz Receiver)", 0, XTYPE_XBOX360 },
{ 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 },
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0x0130, "Ion Drum Rocker", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
@@ -379,6 +381,7 @@ static const struct xpad_device {
{ 0x2993, 0x2001, "TECNO Pocket Go", 0, XTYPE_XBOX360 },
{ 0x2dc8, 0x2000, "8BitDo Pro 2 Wired Controller fox Xbox", 0, XTYPE_XBOXONE },
{ 0x2dc8, 0x200f, "8BitDo Ultimate 3-mode Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
+ { 0x2dc8, 0x201e, "8BitDo Pro 2 Wired Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
{ 0x2dc8, 0x3106, "8BitDo Ultimate Wireless / Pro 2 Wired Controller", 0, XTYPE_XBOX360 },
{ 0x2dc8, 0x3109, "8BitDo Ultimate Wireless Bluetooth", 0, XTYPE_XBOX360 },
{ 0x2dc8, 0x310a, "8BitDo Ultimate 2C Wireless Controller", 0, XTYPE_XBOX360 },
@@ -545,6 +548,7 @@ static const struct usb_device_id xpad_table[] = {
XPAD_XBOX360_VENDOR(0x17ef), /* Lenovo */
XPAD_XBOX360_VENDOR(0x1949), /* Amazon controllers */
XPAD_XBOX360_VENDOR(0x1a86), /* Nanjing Qinheng Microelectronics (WCH) */
+ XPAD_XBOX360_VENDOR(0x1b1c), /* Corsair controllers */
XPAD_XBOX360_VENDOR(0x1bad), /* Harmonix Rock Band guitar and drums */
XPAD_XBOX360_VENDOR(0x1ee9), /* ZOTAC Technology Limited */
XPAD_XBOX360_VENDOR(0x20bc), /* BETOP wireless dongles */
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
index 8db2dca84975..3e0f874e9b16 100644
--- a/drivers/input/misc/ati_remote2.c
+++ b/drivers/input/misc/ati_remote2.c
@@ -672,8 +672,7 @@ static ssize_t ati_remote2_show_channel_mask(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct usb_device *udev = to_usb_device(dev);
- struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
+ struct usb_interface *intf = to_usb_interface(dev);
struct ati_remote2 *ar2 = usb_get_intfdata(intf);
return sprintf(buf, "0x%04x\n", ar2->channel_mask);
@@ -683,8 +682,7 @@ static ssize_t ati_remote2_store_channel_mask(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct usb_device *udev = to_usb_device(dev);
- struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
+ struct usb_interface *intf = to_usb_interface(dev);
struct ati_remote2 *ar2 = usb_get_intfdata(intf);
unsigned int mask;
int r;
@@ -720,8 +718,7 @@ static ssize_t ati_remote2_show_mode_mask(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct usb_device *udev = to_usb_device(dev);
- struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
+ struct usb_interface *intf = to_usb_interface(dev);
struct ati_remote2 *ar2 = usb_get_intfdata(intf);
return sprintf(buf, "0x%02x\n", ar2->mode_mask);
@@ -731,8 +728,7 @@ static ssize_t ati_remote2_store_mode_mask(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct usb_device *udev = to_usb_device(dev);
- struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
+ struct usb_interface *intf = to_usb_interface(dev);
struct ati_remote2 *ar2 = usb_get_intfdata(intf);
unsigned int mask;
int err;
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 58c624513cd4..68ee57800fef 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -1228,9 +1228,9 @@ dma_addr_t iommu_dma_map_phys(struct device *dev, phys_addr_t phys, size_t size,
* If both the physical buffer start address and size are page aligned,
* we don't need to use a bounce page.
*/
- if (dev_use_swiotlb(dev, size, dir) &&
+ if (!(attrs & DMA_ATTR_MMIO) && dev_use_swiotlb(dev, size, dir) &&
iova_unaligned(iovad, phys, size)) {
- if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT))
+ if (attrs & DMA_ATTR_REQUIRE_COHERENT)
return DMA_MAPPING_ERROR;
phys = iommu_dma_map_swiotlb(dev, phys, size, dir, attrs);
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index c418add65bb5..79af154767c1 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -2416,7 +2416,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
if (video_is_registered(&v4l2->radio_dev)) {
dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n",
video_device_node_name(&v4l2->radio_dev));
- vb2_video_unregister_device(&v4l2->radio_dev);
+ video_unregister_device(&v4l2->radio_dev);
}
if (video_is_registered(&v4l2->vbi_dev)) {
dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n",
@@ -3082,7 +3082,7 @@ unregister_dev:
dev_info(&dev->intf->dev,
"V4L2 device %s deregistered\n",
video_device_node_name(&v4l2->radio_dev));
- vb2_video_unregister_device(&v4l2->radio_dev);
+ video_unregister_device(&v4l2->radio_dev);
}
if (video_is_registered(&v4l2->vbi_dev)) {
dev_info(&dev->intf->dev,
diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c
index e03989c4e99e..0d15f48ef51d 100644
--- a/drivers/memstick/core/memstick.c
+++ b/drivers/memstick/core/memstick.c
@@ -370,9 +370,7 @@ int memstick_set_rw_addr(struct memstick_dev *card)
{
card->next_request = h_memstick_set_rw_addr;
memstick_new_req(card->host);
- if (!wait_for_completion_timeout(&card->mrq_complete,
- msecs_to_jiffies(500)))
- card->current_mrq.error = -ETIMEDOUT;
+ wait_for_completion(&card->mrq_complete);
return card->current_mrq.error;
}
@@ -405,9 +403,7 @@ static struct memstick_dev *memstick_alloc_card(struct memstick_host *host)
card->next_request = h_memstick_read_dev_id;
memstick_new_req(host);
- if (!wait_for_completion_timeout(&card->mrq_complete,
- msecs_to_jiffies(500)))
- card->current_mrq.error = -ETIMEDOUT;
+ wait_for_completion(&card->mrq_complete);
if (card->current_mrq.error)
goto err_out;
diff --git a/drivers/memstick/host/rtsx_usb_ms.c b/drivers/memstick/host/rtsx_usb_ms.c
index beadc389f15f..d5b3a96fc609 100644
--- a/drivers/memstick/host/rtsx_usb_ms.c
+++ b/drivers/memstick/host/rtsx_usb_ms.c
@@ -27,7 +27,6 @@ struct rtsx_usb_ms {
struct memstick_host *msh;
struct memstick_request *req;
- struct mutex host_mutex;
struct work_struct handle_req;
struct delayed_work poll_card;
@@ -514,6 +513,13 @@ static void rtsx_usb_ms_handle_req(struct work_struct *work)
struct memstick_host *msh = host->msh;
int rc;
+ /* Fail requests after eject so their waiters are released. */
+ if (host->eject) {
+ while (!memstick_next_req(msh, &host->req))
+ host->req->error = -ENOMEDIUM;
+ return;
+ }
+
if (!host->req) {
pm_runtime_get_sync(ms_dev(host));
do {
@@ -547,8 +553,7 @@ static void rtsx_usb_ms_request(struct memstick_host *msh)
dev_dbg(ms_dev(host), "--> %s\n", __func__);
- if (!host->eject)
- schedule_work(&host->handle_req);
+ schedule_work(&host->handle_req);
}
static int rtsx_usb_ms_set_param(struct memstick_host *msh,
@@ -781,7 +786,6 @@ static int rtsx_usb_ms_drv_probe(struct platform_device *pdev)
host->power_mode = MEMSTICK_POWER_OFF;
platform_set_drvdata(pdev, host);
- mutex_init(&host->host_mutex);
INIT_WORK(&host->handle_req, rtsx_usb_ms_handle_req);
INIT_DELAYED_WORK(&host->poll_card, rtsx_usb_ms_poll_card);
@@ -812,27 +816,12 @@ static void rtsx_usb_ms_drv_remove(struct platform_device *pdev)
{
struct rtsx_usb_ms *host = platform_get_drvdata(pdev);
struct memstick_host *msh = host->msh;
- int err;
host->eject = true;
msh->removing = true;
- cancel_work_sync(&host->handle_req);
+ flush_work(&host->handle_req);
cancel_delayed_work_sync(&host->poll_card);
- mutex_lock(&host->host_mutex);
- if (host->req) {
- dev_dbg(ms_dev(host),
- "%s: Controller removed during transfer\n",
- dev_name(&msh->dev));
- host->req->error = -ENOMEDIUM;
- do {
- err = memstick_next_req(msh, &host->req);
- if (!err)
- host->req->error = -ENOMEDIUM;
- } while (!err);
- }
- mutex_unlock(&host->host_mutex);
-
/* Balance possible unbalanced usage count
* e.g. unconditional module removal
*/
@@ -841,6 +830,8 @@ static void rtsx_usb_ms_drv_remove(struct platform_device *pdev)
pm_runtime_disable(ms_dev(host));
memstick_remove_host(msh);
+ /* No card, no new requests; wait for the last failed one to finish. */
+ cancel_work_sync(&host->handle_req);
dev_dbg(ms_dev(host),
": Realtek USB Memstick controller has been removed\n");
memstick_free_host(msh);
diff --git a/drivers/mmc/host/cavium-octeon.c b/drivers/mmc/host/cavium-octeon.c
index 1bfc1a4f9fe9..671dd1a36a74 100644
--- a/drivers/mmc/host/cavium-octeon.c
+++ b/drivers/mmc/host/cavium-octeon.c
@@ -295,9 +295,12 @@ static void octeon_mmc_remove(struct platform_device *pdev)
u64 dma_cfg;
int i;
- for (i = 0; i < CAVIUM_MAX_MMC; i++)
+ for (i = 0; i < CAVIUM_MAX_MMC; i++) {
if (host->slot[i])
cvm_mmc_of_slot_remove(host->slot[i]);
+ if (host->slot_pdev[i])
+ of_platform_device_destroy(&host->slot_pdev[i]->dev, NULL);
+ }
dma_cfg = readq(host->dma_base + MIO_EMM_DMA_CFG(host));
dma_cfg &= ~MIO_EMM_DMA_CFG_EN;
diff --git a/drivers/mmc/host/cavium-thunderx.c b/drivers/mmc/host/cavium-thunderx.c
index 84ff6d82ae3c..2635ac94ec5d 100644
--- a/drivers/mmc/host/cavium-thunderx.c
+++ b/drivers/mmc/host/cavium-thunderx.c
@@ -173,9 +173,12 @@ static void thunder_mmc_remove(struct pci_dev *pdev)
u64 dma_cfg;
int i;
- for (i = 0; i < CAVIUM_MAX_MMC; i++)
+ for (i = 0; i < CAVIUM_MAX_MMC; i++) {
if (host->slot[i])
cvm_mmc_of_slot_remove(host->slot[i]);
+ if (host->slot_pdev[i])
+ of_platform_device_destroy(&host->slot_pdev[i]->dev, NULL);
+ }
dma_cfg = readq(host->dma_base + MIO_EMM_DMA_CFG(host));
dma_cfg &= ~MIO_EMM_DMA_CFG_EN;
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 01ea3adbdf3b..5b160fdad3f0 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -3216,6 +3216,7 @@ static void msdc_drv_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
mmc_remove_host(mmc);
+ cancel_delayed_work_sync(&host->req_timeout);
msdc_deinit_hw(host);
msdc_gate_clock(host);
diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c
index 3584a2b314a9..0c8f389fe584 100644
--- a/drivers/mmc/host/sdhci-sprd.c
+++ b/drivers/mmc/host/sdhci-sprd.c
@@ -890,6 +890,10 @@ static void sdhci_sprd_remove(struct platform_device *pdev)
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);
+ pm_runtime_get_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+
sdhci_remove_host(host, 0);
clk_disable_unprepare(sprd_host->clk_sdio);
diff --git a/drivers/net/amt.c b/drivers/net/amt.c
index bddc24e1856d..b53f8ec55661 100644
--- a/drivers/net/amt.c
+++ b/drivers/net/amt.c
@@ -80,15 +80,6 @@ static struct in6_addr mld2_all_node = MLD2_ALL_NODE_INIT;
static struct mld2_grec mldv2_zero_grec;
#endif
-static struct amt_skb_cb *amt_skb_cb(struct sk_buff *skb)
-{
- BUILD_BUG_ON(sizeof(struct amt_skb_cb) + sizeof(struct tc_skb_cb) >
- sizeof_field(struct sk_buff, cb));
-
- return (struct amt_skb_cb *)((void *)skb->cb +
- sizeof(struct tc_skb_cb));
-}
-
static void __amt_source_gc_work(void)
{
struct amt_source_node *snode;
@@ -791,6 +782,11 @@ out:
rcu_read_unlock();
}
+static bool amt_send_membership_query(struct amt_dev *amt,
+ struct sk_buff *skb,
+ struct amt_tunnel_list *tunnel,
+ bool v6);
+
static void amt_send_igmp_gq(struct amt_dev *amt,
struct amt_tunnel_list *tunnel)
{
@@ -800,8 +796,11 @@ static void amt_send_igmp_gq(struct amt_dev *amt,
if (!skb)
return;
- amt_skb_cb(skb)->tunnel = tunnel;
- dev_queue_xmit(skb);
+ skb_pull(skb, sizeof(struct ethhdr));
+ if (amt_send_membership_query(amt, skb, tunnel, false)) {
+ amt->dev->stats.tx_dropped++;
+ kfree_skb(skb);
+ }
}
#if IS_ENABLED(CONFIG_IPV6)
@@ -885,8 +884,11 @@ static void amt_send_mld_gq(struct amt_dev *amt, struct amt_tunnel_list *tunnel)
if (!skb)
return;
- amt_skb_cb(skb)->tunnel = tunnel;
- dev_queue_xmit(skb);
+ skb_pull(skb, sizeof(struct ethhdr));
+ if (amt_send_membership_query(amt, skb, tunnel, true)) {
+ amt->dev->stats.tx_dropped++;
+ kfree_skb(skb);
+ }
}
#else
static void amt_send_mld_gq(struct amt_dev *amt, struct amt_tunnel_list *tunnel)
@@ -1186,7 +1188,6 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
bool report = false;
struct igmphdr *ih;
- bool query = false;
struct iphdr *iph;
bool data = false;
bool v6 = false;
@@ -1204,9 +1205,6 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
case IGMP_HOST_MEMBERSHIP_REPORT:
report = true;
break;
- case IGMP_HOST_MEMBERSHIP_QUERY:
- query = true;
- break;
default:
goto free;
}
@@ -1228,9 +1226,6 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
case ICMPV6_MLD2_REPORT:
report = true;
break;
- case ICMPV6_MGM_QUERY:
- query = true;
- break;
default:
goto free;
}
@@ -1261,19 +1256,6 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
goto free;
goto unlock;
} else if (amt->mode == AMT_MODE_RELAY) {
- if (query) {
- tunnel = amt_skb_cb(skb)->tunnel;
- if (!tunnel) {
- WARN_ON(1);
- goto free;
- }
-
- /* Do not forward unexpected query */
- if (amt_send_membership_query(amt, skb, tunnel, v6))
- goto free;
- goto unlock;
- }
-
if (!data)
goto free;
list_for_each_entry_rcu(tunnel, &amt->tunnel_list, list) {
diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c
index c3b5ed52d877..b9fe54151e1a 100644
--- a/drivers/net/bareudp.c
+++ b/drivers/net/bareudp.c
@@ -356,7 +356,7 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev,
if (err)
goto free_dst;
- skb_set_inner_protocol(skb, bareudp->ethertype);
+ skb_set_inner_protocol(skb, skb->protocol);
udp_tunnel_xmit_skb(rt, sk, skb, saddr, info->key.u.ipv4.dst,
tos, ttl, df, sport, bareudp->port,
!net_eq(bareudp->net, dev_net(bareudp->dev)),
@@ -424,6 +424,7 @@ static int bareudp6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
if (err)
goto free_dst;
+ skb_set_inner_protocol(skb, skb->protocol);
daddr = info->key.u.ipv6.dst;
udp_tunnel6_xmit_skb(dst, sk, skb, dev,
&saddr, &daddr, prio, ttl,
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index de2489c3d9bf..09aa45d71fab 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -5732,12 +5732,12 @@ static int bond_xdp_set(struct net_device *dev, struct bpf_prog *prog,
bpf_prog_inc(prog);
}
- if (prog) {
+ if (prog && !old_prog)
static_branch_inc(&bpf_master_redirect_enabled_key);
- } else if (old_prog) {
- bpf_prog_put(old_prog);
+ else if (!prog && old_prog)
static_branch_dec(&bpf_master_redirect_enabled_key);
- }
+ if (old_prog)
+ bpf_prog_put(old_prog);
return 0;
diff --git a/drivers/net/can/dev/skb.c b/drivers/net/can/dev/skb.c
index 95fcdc1026f8..14edec5afb57 100644
--- a/drivers/net/can/dev/skb.c
+++ b/drivers/net/can/dev/skb.c
@@ -210,6 +210,10 @@ static void init_can_skb(struct sk_buff *skb)
{
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ skb_reset_mac_header(skb);
+ skb_reset_network_header(skb);
+ skb_reset_transport_header(skb);
}
struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
diff --git a/drivers/net/can/usb/f81604.c b/drivers/net/can/usb/f81604.c
index f12318268e46..4c147b9d6d69 100644
--- a/drivers/net/can/usb/f81604.c
+++ b/drivers/net/can/usb/f81604.c
@@ -169,7 +169,7 @@ struct f81604_int_data {
u8 rxerr;
u8 txerr;
u8 val;
-} __packed __aligned(4);
+} __packed;
struct f81604_sff {
__be16 id;
diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c
index 9e2e25d02471..51148a81d1d9 100644
--- a/drivers/net/can/vxcan.c
+++ b/drivers/net/can/vxcan.c
@@ -79,6 +79,9 @@ static netdev_tx_t vxcan_xmit(struct sk_buff *oskb, struct net_device *dev)
/* reset CAN GW hop counter */
csx->can_gw_hops = 0;
+ /* start with new CAN skb UID in the other namespace */
+ csx->can_skb_uid = 0;
+
skb->pkt_type = PACKET_BROADCAST;
skb->dev = peer;
skb->ip_summed = CHECKSUM_UNNECESSARY;
diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
index cbe98494578c..f6104f714a8d 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -853,7 +853,7 @@ static inline bool ksz_is_sgmii_port(struct ksz_device *dev, int port)
#define KSZ88_FAMILY_ID 0x88
#define KSZ8895_FAMILY_ID 0x95
-#define KSZ8_PORT_STATUS_0 0x08
+#define KSZ8_PORT_STATUS_0 0x18
#define KSZ8_PORT_FIBER_MODE BIT(7)
#define SW_CHIP_ID_M GENMASK(7, 4)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 64619e9a704d..6ca57875b6d6 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -2800,14 +2800,34 @@ static int airoha_qdma_set_trtcm_param(struct airoha_qdma *qdma, int channel,
FIELD_PREP(TRTCM_METER_GROUP_MASK, group) |
FIELD_PREP(TRTCM_PARAM_INDEX_MASK, idx) |
FIELD_PREP(TRTCM_PARAM_RATE_TYPE_MASK, mode);
+ int i;
- airoha_qdma_wr(qdma, REG_TRTCM_DATA_LOW(addr), val);
- airoha_qdma_wr(qdma, REG_TRTCM_CFG_PARAM(addr), config);
+ /*
+ * HW might be in the middle of bucket handling and might
+ * require an additional try to actually apply the new TRTCM
+ * config.
+ */
+ for (i = 0; i < TRTCM_CONFIG_RETRY_MAX; i++) {
+ u32 data = 0;
- return read_poll_timeout(airoha_qdma_rr, val,
- val & TRTCM_PARAM_RW_DONE_MASK,
- USEC_PER_MSEC, 10 * USEC_PER_MSEC, true,
- qdma, REG_TRTCM_CFG_PARAM(addr));
+ airoha_qdma_wr(qdma, REG_TRTCM_DATA_LOW(addr), val);
+ airoha_qdma_wr(qdma, REG_TRTCM_CFG_PARAM(addr), config);
+
+ if (read_poll_timeout(airoha_qdma_rr, data,
+ data & TRTCM_PARAM_RW_DONE_MASK,
+ USEC_PER_MSEC, 10 * USEC_PER_MSEC,
+ true, qdma, REG_TRTCM_CFG_PARAM(addr)))
+ continue;
+
+ if (airoha_qdma_get_trtcm_param(qdma, channel, addr, param,
+ mode, &data, NULL))
+ continue;
+
+ if (data == val)
+ return 0;
+ }
+
+ return -EBUSY;
}
static int airoha_qdma_set_trtcm_config(struct airoha_qdma *qdma, int channel,
diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
index 8277c1c87bb3..338fde03a149 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -171,6 +171,8 @@ enum trtcm_param {
#define TRTCM_TOKEN_RATE_MASK GENMASK(23, 6)
#define TRTCM_TOKEN_RATE_FRACTION_MASK GENMASK(5, 0)
+#define TRTCM_CONFIG_RETRY_MAX 2
+
enum airoha_dma_map_type {
AIROHA_DMA_UNMAPPED,
AIROHA_DMA_MAP_SINGLE,
diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c
index 0ba67a55705d..09b2abdfc9e8 100644
--- a/drivers/net/ethernet/allwinner/sun4i-emac.c
+++ b/drivers/net/ethernet/allwinner/sun4i-emac.c
@@ -300,7 +300,7 @@ static int emac_dma_inblk_32bit(struct emac_board_info *db,
if (!req) {
dev_err(db->dev, "alloc emac dma req error.\n");
ret = -ENOMEM;
- goto alloc_req_err;
+ goto prepare_err;
}
desc->callback_param = req;
@@ -319,9 +319,6 @@ static int emac_dma_inblk_32bit(struct emac_board_info *db,
submit_err:
emac_free_dma_req(req);
-alloc_req_err:
- dmaengine_desc_free(desc);
-
prepare_err:
dma_unmap_single(db->dev, rxbuf, count, DMA_FROM_DEVICE);
return ret;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index d7728d0c5b6e..15a8349ccf7b 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -486,7 +486,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct netdev_queue *txq;
int i;
dma_addr_t mapping;
- unsigned int length, pad = 0;
+ unsigned int length;
u32 len, free_size, vlan_tag_flags, cfa_action, flags;
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
struct pci_dev *pdev = bp->pdev;
@@ -536,6 +536,16 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
return rc < 0 ? NETDEV_TX_BUSY : NETDEV_TX_OK;
}
+ /* Pad after the SW USO branch: bnxt_sw_udp_gso_xmit() would
+ * otherwise account the padding as UDP payload.
+ * Must be done before skb_shinfo(skb)->nr_frags is sampled,
+ * because skb_put_padto() might linearize the skb.
+ */
+ if (skb_put_padto(skb, BNXT_MIN_PKT_SIZE)) {
+ /* SKB already freed. */
+ goto tx_kick_pending;
+ }
+
free_size = bnxt_tx_avail(bp, txr);
if (unlikely(free_size < skb_shinfo(skb)->nr_frags + 2)) {
/* We must have raced with NAPI cleanup */
@@ -672,14 +682,6 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
normal_tx:
- if (length < BNXT_MIN_PKT_SIZE) {
- pad = BNXT_MIN_PKT_SIZE - length;
- if (skb_pad(skb, pad))
- /* SKB already freed. */
- goto tx_kick_pending;
- length = BNXT_MIN_PKT_SIZE;
- }
-
mapping = dma_map_single(&pdev->dev, skb->data, len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(&pdev->dev, mapping)))
@@ -759,10 +761,7 @@ normal_tx:
txbd->tx_bd_len_flags_type = cpu_to_le32(flags);
}
- flags &= ~TX_BD_LEN;
- txbd->tx_bd_len_flags_type =
- cpu_to_le32(((len + pad) << TX_BD_LEN_SHIFT) | flags |
- TX_BD_FLAGS_PACKET_END);
+ txbd->tx_bd_len_flags_type |= cpu_to_le32(TX_BD_FLAGS_PACKET_END);
netdev_tx_sent_queue(txq, skb->len);
@@ -15547,7 +15546,7 @@ static void bnxt_fw_reset_task(struct work_struct *work)
if (test_and_clear_bit(BNXT_STATE_FW_ACTIVATE_RESET, &bp->state) &&
!test_bit(BNXT_STATE_FW_ACTIVATE, &bp->state))
bnxt_dl_remote_reload(bp);
- if (pci_enable_device(bp->pdev)) {
+ if (!pci_is_enabled(bp->pdev) && pci_enable_device(bp->pdev)) {
netdev_err(bp->dev, "Cannot re-enable PCI device\n");
rc = -ENODEV;
goto fw_reset_abort;
@@ -17111,6 +17110,51 @@ void bnxt_print_device_info(struct bnxt *bp)
pcie_print_link_status(bp->pdev);
}
+static void bnxt_clear_bars(struct pci_dev *pdev)
+{
+ int off;
+
+ for (off = PCI_BASE_ADDRESS_0; off <= PCI_BASE_ADDRESS_5; off += 4)
+ pci_write_config_dword(pdev, off, 0);
+}
+
+/* Clear any pending DMA transactions from crash kernel while loading driver in
+ * capture kernel.
+ */
+static int bnxt_kdump_reset(struct pci_dev *pdev)
+{
+ int rc, i;
+ u16 cmd;
+
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
+
+ if (pci_save_state(pdev))
+ dev_warn(&pdev->dev, "Failed to save PCI state, PCI restore may be incomplete\n");
+
+ rc = pcie_flr(pdev);
+ if (rc)
+ dev_warn(&pdev->dev, "pcie_flr() failed (rc: %d), trying to continue\n",
+ rc);
+
+ /* In case device is not returning CRS, wait 5 seconds longer */
+ for (i = 0; i < 50; i++) {
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ if (!PCI_POSSIBLE_ERROR(cmd))
+ break;
+ msleep(100);
+ }
+ if (PCI_POSSIBLE_ERROR(cmd)) {
+ dev_err(&pdev->dev, "PCI config space inaccessible after FLR, aborting\n");
+ return -ENODEV;
+ }
+
+ bnxt_clear_bars(pdev);
+ pci_restore_state(pdev);
+ return 0;
+}
+
static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct bnxt_hw_resc *hw_resc;
@@ -17126,12 +17170,10 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return -ENODEV;
}
- /* Clear any pending DMA transactions from crash kernel
- * while loading driver in capture kernel.
- */
if (is_kdump_kernel()) {
- pci_clear_master(pdev);
- pcie_flr(pdev);
+ rc = bnxt_kdump_reset(pdev);
+ if (rc)
+ return rc;
}
max_irqs = bnxt_get_max_irq(pdev);
@@ -17565,10 +17607,8 @@ static pci_ers_result_t bnxt_io_error_detected(struct pci_dev *pdev,
* so we disable bus master to prevent any potential bad DMAs before
* freeing kernel memory.
*/
- if (state == pci_channel_io_frozen) {
- set_bit(BNXT_STATE_PCI_CHANNEL_IO_FROZEN, &bp->state);
+ if (state == pci_channel_io_frozen)
bnxt_fw_fatal_close(bp);
- }
if (netif_running(netdev))
__bnxt_close_nic(bp, true, true);
@@ -17598,69 +17638,80 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev)
struct bnxt *bp = netdev_priv(netdev);
int retry = 0;
int err = 0;
- int off;
+ u16 cmd;
netdev_info(bp->dev, "PCI Slot Reset\n");
- if (test_bit(BNXT_STATE_PCI_CHANNEL_IO_FROZEN, &bp->state)) {
- /* After DPC, the chip should return CRS when the vendor ID
- * config register is read until it is ready. On all chips,
- * this is not happening reliably so add a 5-second delay as a
- * workaround.
- */
- msleep(5000);
- }
+ /* After a PCIe hot reset, the chip should return CRS when the
+ * vendor ID config register is read until it is ready. On all
+ * chips, this is not happening reliably so add a 5-second delay
+ * as a workaround.
+ */
+ msleep(5000);
netdev_lock(netdev);
- if (pci_enable_device(pdev)) {
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ if (PCI_POSSIBLE_ERROR(cmd)) {
dev_err(&pdev->dev,
- "Cannot re-enable PCI device after reset.\n");
- } else {
- pci_set_master(pdev);
- /* Upon fatal error, our device internal logic that latches to
- * BAR value is getting reset and will restore only upon
- * rewriting the BARs.
- *
- * As pci_restore_state() does not re-write the BARs if the
- * value is same as saved value earlier, driver needs to
- * write the BARs to 0 to force restore, in case of fatal error.
- */
- if (test_and_clear_bit(BNXT_STATE_PCI_CHANNEL_IO_FROZEN,
- &bp->state)) {
- for (off = PCI_BASE_ADDRESS_0;
- off <= PCI_BASE_ADDRESS_5; off += 4)
- pci_write_config_dword(bp->pdev, off, 0);
- }
- pci_restore_state(pdev);
+ "PCI config space inaccessible after reset\n");
+ goto reset_exit;
+ }
- bnxt_inv_fw_health_reg(bp);
- bnxt_try_map_fw_health_reg(bp);
+ /* Upon PCIe error, our device internal logic that latches to
+ * BAR value is getting reset and will restore only upon
+ * rewriting the BARs.
+ *
+ * As pci_restore_state() does not re-write the BARs if the
+ * value is same as saved value earlier, driver needs to
+ * write the BARs to 0 to force restore.
+ */
+ pci_clear_master(pdev);
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ cmd &= ~PCI_COMMAND_MEMORY;
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
- /* In some PCIe AER scenarios, firmware may take up to
- * 10 seconds to become ready in the worst case.
- */
- do {
- err = bnxt_try_recover_fw(bp);
- if (!err)
- break;
- retry++;
- } while (retry < BNXT_FW_SLOT_RESET_RETRY);
+ bnxt_clear_bars(pdev);
+ pci_restore_state(pdev);
- if (err) {
- dev_err(&pdev->dev, "Firmware not ready\n");
- goto reset_exit;
+ if (!pci_is_enabled(pdev) && pci_enable_device(pdev)) {
+ dev_err(&pdev->dev,
+ "Cannot re-enable PCI device after reset.\n");
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ if (!PCI_POSSIBLE_ERROR(cmd)) {
+ cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
}
+ goto reset_exit;
+ }
+ pci_set_master(pdev);
- err = bnxt_hwrm_func_reset(bp);
+ bnxt_inv_fw_health_reg(bp);
+ bnxt_try_map_fw_health_reg(bp);
+
+ /* In some PCIe AER scenarios, firmware may take up to
+ * 10 seconds to become ready in the worst case.
+ */
+ do {
+ err = bnxt_try_recover_fw(bp);
if (!err)
- result = PCI_ERS_RESULT_RECOVERED;
+ break;
+ retry++;
+ } while (retry < BNXT_FW_SLOT_RESET_RETRY);
- /* IRQ will be initialized later in bnxt_io_resume */
- bnxt_ulp_irq_stop(bp);
- bnxt_clear_int_mode(bp);
+ if (err) {
+ dev_err(&pdev->dev, "Firmware not ready\n");
+ goto reset_exit;
}
+ err = bnxt_hwrm_func_reset(bp);
+ if (!err)
+ result = PCI_ERS_RESULT_RECOVERED;
+
+ /* IRQ will be initialized later in bnxt_io_resume */
+ bnxt_ulp_irq_stop(bp);
+ bnxt_clear_int_mode(bp);
+
reset_exit:
clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
bnxt_clear_reservations(bp, true);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index c673b2ce4a0d..41d05efd6307 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -2468,7 +2468,6 @@ struct bnxt {
#define BNXT_STATE_ABORT_ERR 5
#define BNXT_STATE_FW_FATAL_COND 6
#define BNXT_STATE_DRV_REGISTERED 7
-#define BNXT_STATE_PCI_CHANNEL_IO_FROZEN 8
#define BNXT_STATE_NAPI_DISABLED 9
#define BNXT_STATE_FW_ACTIVATE 11
#define BNXT_STATE_RECOVER 12
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
index 96d5d4f7f51f..984432952963 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
@@ -253,6 +253,17 @@ int bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
reg &= ~CMD_CRC_FWD;
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+
+ /*
+ * Mirror wol_power_down_cfg(). If only UMAC_RX
+ * is enabled, then we must place the UMAC back
+ * into SW_RESET.
+ */
+ reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+ if ((reg & CMD_RX_EN) && !(reg & CMD_TX_EN)) {
+ reg |= CMD_SW_RESET;
+ bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+ }
spin_unlock_bh(&priv->reg_lock);
/* Resume link status tracking */
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index 8e5c034dc3a4..261a7e87520a 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -2421,34 +2421,40 @@ static inline int macb_clear_csum(struct sk_buff *skb)
return 0;
}
+static bool macb_needs_sw_fcs(struct sk_buff *skb, struct net_device *netdev)
+{
+ return netdev->features & NETIF_F_HW_CSUM &&
+ skb->ip_summed != CHECKSUM_PARTIAL &&
+ !skb_shinfo(skb)->gso_size && !ptp_one_step_sync(skb);
+}
+
/* Returns a negative errno, or the FCS bytes appended (0 or ETH_FCS_LEN). */
-static int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *netdev)
+static int macb_pad_and_fcs(struct sk_buff **skb, bool add_fcs)
{
bool cloned = skb_cloned(*skb) || skb_header_cloned(*skb) ||
skb_is_nonlinear(*skb);
int padlen = ETH_ZLEN - (*skb)->len;
int tailroom = skb_tailroom(*skb);
+ bool shared = skb_shared(*skb);
struct sk_buff *nskb;
u32 fcs;
- if (!(netdev->features & NETIF_F_HW_CSUM) ||
- !((*skb)->ip_summed != CHECKSUM_PARTIAL) ||
- skb_shinfo(*skb)->gso_size || ptp_one_step_sync(*skb))
+ if (!add_fcs)
return 0;
if (padlen <= 0) {
- /* FCS could be appeded to tailroom. */
- if (tailroom >= ETH_FCS_LEN)
+ /* FCS could be appended to tailroom. */
+ if (!shared && !skb_is_nonlinear(*skb) &&
+ tailroom >= ETH_FCS_LEN)
goto add_fcs;
- /* No room for FCS, need to reallocate skb. */
- else
- padlen = ETH_FCS_LEN;
+ /* Reallocate with room for the FCS. */
+ padlen = ETH_FCS_LEN;
} else {
/* Add room for FCS. */
padlen += ETH_FCS_LEN;
}
- if (cloned || tailroom < padlen) {
+ if (shared || cloned || tailroom < padlen) {
nskb = skb_copy_expand(*skb, 0, padlen, GFP_ATOMIC);
if (!nskb)
return -ENOMEM;
@@ -2481,27 +2487,15 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb,
unsigned int desc_cnt, nr_frags, frag_size, f;
struct macb_queue *queue = &bp->queues[q];
netdev_tx_t ret = NETDEV_TX_OK;
- unsigned int hdrlen;
+ unsigned int hdrlen, tx_len;
+ bool add_fcs, is_lso;
unsigned long flags;
int fcs_len;
- bool is_lso;
-
- if (macb_clear_csum(skb)) {
- dev_kfree_skb_any(skb);
- return ret;
- }
-
- fcs_len = macb_pad_and_fcs(&skb, netdev);
- if (fcs_len < 0) {
- dev_kfree_skb_any(skb);
- return ret;
- }
-
- if (macb_dma_ptp(bp) &&
- (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
- skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ add_fcs = macb_needs_sw_fcs(skb, netdev);
is_lso = (skb_shinfo(skb)->gso_size != 0);
+ tx_len = add_fcs ? max_t(unsigned int, skb->len, ETH_ZLEN) +
+ ETH_FCS_LEN : skb->len;
if (is_lso) {
/* length of headers */
@@ -2515,8 +2509,11 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb,
/* if this is required, would need to copy to single buffer */
return NETDEV_TX_BUSY;
}
- } else
+ } else if (add_fcs) {
+ hdrlen = umin(tx_len, bp->max_tx_length);
+ } else {
hdrlen = umin(skb_headlen(skb), bp->max_tx_length);
+ }
#if defined(DEBUG) && defined(VERBOSE_DEBUG)
netdev_vdbg(bp->netdev,
@@ -2531,12 +2528,18 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb,
* socket buffer: skb fragments of jumbo frames may need to be
* split into many buffer descriptors.
*/
- if (is_lso && (skb_headlen(skb) > hdrlen))
+ if (add_fcs) {
+ /* macb_pad_and_fcs() linearizes the skb before adding the FCS. */
+ desc_cnt = DIV_ROUND_UP(tx_len, bp->max_tx_length);
+ nr_frags = 0;
+ } else if (is_lso && (skb_headlen(skb) > hdrlen)) {
/* extra header descriptor if also payload in first buffer */
desc_cnt = DIV_ROUND_UP((skb_headlen(skb) - hdrlen), bp->max_tx_length) + 1;
- else
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ } else {
desc_cnt = DIV_ROUND_UP(skb_headlen(skb), bp->max_tx_length);
- nr_frags = skb_shinfo(skb)->nr_frags;
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ }
for (f = 0; f < nr_frags; f++) {
frag_size = skb_frag_size(&skb_shinfo(skb)->frags[f]);
desc_cnt += DIV_ROUND_UP(frag_size, bp->max_tx_length);
@@ -2554,6 +2557,21 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb,
goto unlock;
}
+ if (macb_clear_csum(skb)) {
+ dev_kfree_skb_any(skb);
+ goto unlock;
+ }
+
+ fcs_len = macb_pad_and_fcs(&skb, add_fcs);
+ if (fcs_len < 0) {
+ dev_kfree_skb_any(skb);
+ goto unlock;
+ }
+
+ if (macb_dma_ptp(bp) &&
+ (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+
/* Map socket buffer for DMA transfer */
if (macb_tx_map(bp, queue, skb, hdrlen, fcs_len)) {
dev_kfree_skb_any(skb);
diff --git a/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c b/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c
index f5acd4be1e69..dbec95b49777 100644
--- a/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c
+++ b/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c
@@ -389,7 +389,7 @@ static void chcr_ktls_dev_del(struct net_device *netdev,
cxgb4_remove_tid(&tx_info->adap->tids, tx_info->tx_chan,
tx_info->tid, tx_info->ip_family);
- xa_erase(&u_ctx->tid_list, tx_info->tid);
+ xa_erase_bh(&u_ctx->tid_list, tx_info->tid);
}
port_stats = &tx_info->adap->ch_ktls_stats.ktls_port[tx_info->port_id];
@@ -577,7 +577,7 @@ free_tid:
cxgb4_remove_tid(&tx_info->adap->tids, tx_info->tx_chan,
tx_info->tid, tx_info->ip_family);
- xa_erase(&u_ctx->tid_list, tx_info->tid);
+ xa_erase_bh(&u_ctx->tid_list, tx_info->tid);
put_module:
/* release module refcount */
diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c
index 9cc343a16271..a6c18e2431cc 100644
--- a/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -1708,17 +1708,17 @@ static int gve_xsk_pool_disable(struct net_device *dev,
}
napi_rx = &priv->ntfy_blocks[priv->rx[qid].ntfy_id].napi;
- napi_disable(napi_rx); /* make sure current rx poll is done */
+ napi_disable_locked(napi_rx); /* make sure current rx poll is done */
tx_qid = gve_xdp_tx_queue_id(priv, qid);
napi_tx = &priv->ntfy_blocks[priv->tx[tx_qid].ntfy_id].napi;
- napi_disable(napi_tx); /* make sure current tx poll is done */
+ napi_disable_locked(napi_tx); /* make sure current tx poll is done */
gve_unreg_xsk_pool(priv, qid);
smp_mb(); /* Make sure it is visible to the workers on datapath */
- napi_enable(napi_rx);
- napi_enable(napi_tx);
+ napi_enable_locked(napi_rx);
+ napi_enable_locked(napi_tx);
if (gve_is_gqi(priv)) {
if (gve_rx_work_pending(&priv->rx[qid]))
napi_schedule(napi_rx);
diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
index 5cf242b28557..82ed5e48b00a 100644
--- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
@@ -113,6 +113,12 @@ static void gve_rx_reset_ring_dqo(struct gve_priv *priv, int idx)
gve_free_to_page_pool(rx, bs, false);
else
gve_free_qpl_page_dqo(bs);
+
+ if (gve_buf_state_is_allocated(rx, bs) &&
+ bs->xsk_buff) {
+ xsk_buff_free(bs->xsk_buff);
+ bs->xsk_buff = NULL;
+ }
}
}
@@ -836,7 +842,12 @@ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx,
}
if (unlikely(compl_desc->rx_error)) {
- gve_free_buffer(rx, buf_state);
+ if (buf_state->xsk_buff) {
+ xsk_buff_free(buf_state->xsk_buff);
+ gve_free_buf_state(rx, buf_state);
+ } else {
+ gve_free_buffer(rx, buf_state);
+ }
return -EINVAL;
}
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 73e051d26b9d..abebdb1fc262 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -553,10 +553,15 @@ static int ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter,
static void ibmveth_free_tx_ltb(struct ibmveth_adapter *adapter, int idx)
{
+ void *ptr = adapter->tx_ltb_ptr[idx];
+
+ if (!ptr)
+ return;
+
+ adapter->tx_ltb_ptr[idx] = NULL;
dma_unmap_single(&adapter->vdev->dev, adapter->tx_ltb_dma[idx],
adapter->tx_ltb_size, DMA_TO_DEVICE);
- kfree(adapter->tx_ltb_ptr[idx]);
- adapter->tx_ltb_ptr[idx] = NULL;
+ kfree(ptr);
}
static int ibmveth_allocate_tx_ltb(struct ibmveth_adapter *adapter, int idx)
@@ -667,7 +672,7 @@ static int ibmveth_open(struct net_device *netdev)
for (i = 0; i < netdev->real_num_tx_queues; i++) {
if (ibmveth_allocate_tx_ltb(adapter, i))
- goto out_free_tx_ltb;
+ goto out_unmap_filter_list;
}
adapter->rx_queue.index = 0;
@@ -718,10 +723,6 @@ static int ibmveth_open(struct net_device *netdev)
if (rc != 0) {
netdev_err(netdev, "unable to request irq 0x%x, rc %d\n",
netdev->irq, rc);
- do {
- lpar_rc = h_free_logical_lan(adapter->vdev->unit_address);
- } while (H_IS_LONG_BUSY(lpar_rc) || (lpar_rc == H_BUSY));
-
goto out_free_buffer_pools;
}
@@ -737,6 +738,9 @@ static int ibmveth_open(struct net_device *netdev)
return 0;
out_free_buffer_pools:
+ do {
+ lpar_rc = h_free_logical_lan(adapter->vdev->unit_address);
+ } while (H_IS_LONG_BUSY(lpar_rc) || (lpar_rc == H_BUSY));
while (--i >= 0) {
if (adapter->rx_buff_pool[i].active)
ibmveth_free_buffer_pool(adapter,
@@ -746,10 +750,8 @@ out_unmap_filter_list:
dma_unmap_single(dev, adapter->filter_list_dma, 4096,
DMA_BIDIRECTIONAL);
-out_free_tx_ltb:
- while (--i >= 0) {
+ for (i = netdev->real_num_tx_queues - 1; i >= 0; i--)
ibmveth_free_tx_ltb(adapter, i);
- }
out_unmap_buffer_list:
dma_unmap_single(dev, adapter->buffer_list_dma, 4096,
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 844f31ab37ad..c282f65199e4 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -67,6 +67,13 @@ static const struct dmi_system_id disable_k1_list[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Dell Pro 16 Plus PB16250"),
},
},
+ {
+ .ident = "Lenovo ThinkPad P14s Gen 5",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad P14s Gen 5"),
+ },
+ },
{}
};
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index a26c3d47ec15..c6732a24b640 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -4944,6 +4944,20 @@ out:
}
/**
+ * i40e_setup_vf_trust - Enable/disable VF trust mode without reset
+ * @vf: VF to configure
+ * @setting: trust setting
+ *
+ * Update VF flags when changing trust without performing a VF reset.
+ * This is only called when it's safe to skip the reset (VF has no advanced
+ * features configured that need cleanup).
+ */
+static void i40e_setup_vf_trust(struct i40e_vf *vf, bool setting)
+{
+ assign_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps, setting);
+}
+
+/**
* i40e_ndo_set_vf_trust
* @netdev: network interface device structure of the pf
* @vf_id: VF identifier
@@ -4987,19 +5001,20 @@ int i40e_ndo_set_vf_trust(struct net_device *netdev, int vf_id, bool setting)
set_bit(__I40E_MACVLAN_SYNC_PENDING, pf->state);
pf->vsi[vf->lan_vsi_idx]->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
- i40e_vc_reset_vf(vf, true);
+ /* Reset only if revoking trust and VF has advanced features configured */
+ if (!setting &&
+ (vf->adq_enabled || vf->num_cloud_filters > 0 ||
+ test_bit(I40E_VF_STATE_UC_PROMISC, &vf->vf_states) ||
+ test_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states))) {
+ i40e_vc_reset_vf(vf, true);
+ i40e_del_all_cloud_filters(vf);
+ } else {
+ i40e_setup_vf_trust(vf, setting);
+ }
+
dev_info(&pf->pdev->dev, "VF %u is now %strusted\n",
vf_id, setting ? "" : "un");
- if (vf->adq_enabled) {
- if (!vf->trusted) {
- dev_info(&pf->pdev->dev,
- "VF %u no longer Trusted, deleting all cloud filters\n",
- vf_id);
- i40e_del_all_cloud_filters(vf);
- }
- }
-
out:
clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
return ret;
diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
index dc31202b2a94..8c45536fd502 100644
--- a/drivers/net/ethernet/intel/iavf/iavf.h
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -259,7 +259,6 @@ struct iavf_adapter {
struct work_struct adminq_task;
struct work_struct finish_config;
wait_queue_head_t down_waitqueue;
- wait_queue_head_t vc_waitqueue;
struct iavf_q_vector *q_vectors;
struct list_head vlan_filter_list;
int num_vlan_filters;
@@ -588,8 +587,9 @@ void iavf_configure_queues(struct iavf_adapter *adapter);
void iavf_enable_queues(struct iavf_adapter *adapter);
void iavf_disable_queues(struct iavf_adapter *adapter);
void iavf_map_queues(struct iavf_adapter *adapter);
-void iavf_add_ether_addrs(struct iavf_adapter *adapter);
+int iavf_add_ether_addrs(struct iavf_adapter *adapter);
void iavf_del_ether_addrs(struct iavf_adapter *adapter);
+void iavf_mac_add_reject(struct iavf_adapter *adapter);
void iavf_add_vlans(struct iavf_adapter *adapter);
void iavf_del_vlans(struct iavf_adapter *adapter);
void iavf_set_promiscuous(struct iavf_adapter *adapter);
@@ -606,6 +606,13 @@ void iavf_disable_vlan_stripping(struct iavf_adapter *adapter);
void iavf_virtchnl_completion(struct iavf_adapter *adapter,
enum virtchnl_ops v_opcode,
enum iavf_status v_retval, u8 *msg, u16 msglen);
+int iavf_poll_virtchnl_response(struct iavf_adapter *adapter,
+ struct iavf_arq_event_info *event,
+ bool (*condition)(struct iavf_adapter *adapter,
+ const void *data,
+ enum virtchnl_ops v_op),
+ const void *cond_data,
+ unsigned int timeout_ms);
int iavf_config_rss(struct iavf_adapter *adapter);
void iavf_cfg_queues_bw(struct iavf_adapter *adapter);
void iavf_cfg_queues_quanta_size(struct iavf_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index 29b8403a066b..2f8a80a11336 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -1030,6 +1030,60 @@ static bool iavf_is_mac_set_handled(struct net_device *netdev,
}
/**
+ * iavf_mac_change_done - Check if MAC change completed
+ * @adapter: board private structure
+ * @data: MAC address being checked (as const void *)
+ * @v_op: virtchnl opcode from processed message
+ *
+ * Callback for iavf_poll_virtchnl_response() to check if MAC change completed.
+ *
+ * Return: true if MAC change completed, false otherwise
+ */
+static bool iavf_mac_change_done(struct iavf_adapter *adapter,
+ const void *data, enum virtchnl_ops v_op)
+{
+ const u8 *addr = data;
+
+ return iavf_is_mac_set_handled(adapter->netdev, addr);
+}
+
+/**
+ * iavf_set_mac_sync - Synchronously change MAC address
+ * @adapter: board private structure
+ * @addr: MAC address to set
+ *
+ * Send MAC change request to PF and poll admin queue for response.
+ * Caller must hold netdev_lock. This can sleep for up to 2.5 seconds.
+ * Event buffer is allocated before sending to avoid state mismatch if
+ * allocation fails after message is sent to PF.
+ *
+ * Return: 0 on success, negative on failure
+ */
+static int iavf_set_mac_sync(struct iavf_adapter *adapter, const u8 *addr)
+{
+ struct iavf_arq_event_info event;
+ int ret;
+
+ netdev_assert_locked(adapter->netdev);
+
+ event.buf_len = IAVF_MAX_AQ_BUF_SIZE;
+ event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL);
+ if (!event.msg_buf)
+ return -ENOMEM;
+
+ ret = iavf_add_ether_addrs(adapter);
+ if (ret)
+ goto out;
+
+ ret = iavf_poll_virtchnl_response(adapter, &event,
+ iavf_mac_change_done, addr, 2500);
+
+out:
+ kfree(event.msg_buf);
+ return ret;
+}
+
+/**
* iavf_set_mac - NDO callback to set port MAC address
* @netdev: network interface device structure
* @p: pointer to an address structure
@@ -1046,25 +1100,23 @@ static int iavf_set_mac(struct net_device *netdev, void *p)
return -EADDRNOTAVAIL;
ret = iavf_replace_primary_mac(adapter, addr->sa_data);
-
if (ret)
return ret;
- ret = wait_event_interruptible_timeout(adapter->vc_waitqueue,
- iavf_is_mac_set_handled(netdev, addr->sa_data),
- msecs_to_jiffies(2500));
-
- /* If ret < 0 then it means wait was interrupted.
- * If ret == 0 then it means we got a timeout.
- * else it means we got response for set MAC from PF,
- * check if netdev MAC was updated to requested MAC,
- * if yes then set MAC succeeded otherwise it failed return -EACCES
- */
- if (ret < 0)
+ ret = iavf_set_mac_sync(adapter, addr->sa_data);
+ if (ret) {
+ /* Rollback only if send failed (message never reached PF).
+ * Don't rollback on timeout (-EAGAIN) because the message was
+ * sent and PF will eventually respond. When the response arrives,
+ * iavf_virtchnl_completion() will handle rollback (on PF error)
+ * or acceptance (on PF success) automatically.
+ */
+ if (ret != -EAGAIN) {
+ iavf_mac_add_reject(adapter);
+ ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
+ }
return ret;
-
- if (!ret)
- return -EAGAIN;
+ }
if (!ether_addr_equal(netdev->dev_addr, addr->sa_data))
return -EACCES;
@@ -5394,9 +5446,6 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Setup the wait queue for indicating transition to down status */
init_waitqueue_head(&adapter->down_waitqueue);
- /* Setup the wait queue for indicating virtchannel events */
- init_waitqueue_head(&adapter->vc_waitqueue);
-
INIT_LIST_HEAD(&adapter->ptp.aq_cmds);
init_waitqueue_head(&adapter->ptp.phc_time_waitqueue);
mutex_init(&adapter->ptp.aq_cmd_lock);
diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index ec234cc8bd9d..e6b7e8f82c7c 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -2,6 +2,7 @@
/* Copyright(c) 2013 - 2018 Intel Corporation. */
#include <linux/net/intel/libie/rx.h>
+#include <net/netdev_lock.h>
#include "iavf.h"
#include "iavf_ptp.h"
@@ -555,20 +556,23 @@ iavf_set_mac_addr_type(struct virtchnl_ether_addr *virtchnl_ether_addr,
* @adapter: adapter structure
*
* Request that the PF add one or more addresses to our filters.
- **/
-void iavf_add_ether_addrs(struct iavf_adapter *adapter)
+ *
+ * Return: 0 on success, negative on failure
+ */
+int iavf_add_ether_addrs(struct iavf_adapter *adapter)
{
struct virtchnl_ether_addr_list *veal;
struct iavf_mac_filter *f;
int i = 0, count = 0;
bool more = false;
size_t len;
+ int ret;
if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
/* bail because we already have a command pending */
dev_err(&adapter->pdev->dev, "Cannot add filters, command %d pending\n",
adapter->current_op);
- return;
+ return -EBUSY;
}
spin_lock_bh(&adapter->mac_vlan_list_lock);
@@ -580,7 +584,7 @@ void iavf_add_ether_addrs(struct iavf_adapter *adapter)
if (!count) {
adapter->aq_required &= ~IAVF_FLAG_AQ_ADD_MAC_FILTER;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
- return;
+ return 0;
}
adapter->current_op = VIRTCHNL_OP_ADD_ETH_ADDR;
@@ -594,8 +598,9 @@ void iavf_add_ether_addrs(struct iavf_adapter *adapter)
veal = kzalloc(len, GFP_ATOMIC);
if (!veal) {
+ adapter->current_op = VIRTCHNL_OP_UNKNOWN;
spin_unlock_bh(&adapter->mac_vlan_list_lock);
- return;
+ return -ENOMEM;
}
veal->vsi_id = adapter->vsi_res->vsi_id;
@@ -615,8 +620,15 @@ void iavf_add_ether_addrs(struct iavf_adapter *adapter)
spin_unlock_bh(&adapter->mac_vlan_list_lock);
- iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_ETH_ADDR, (u8 *)veal, len);
+ ret = iavf_send_pf_msg(adapter, VIRTCHNL_OP_ADD_ETH_ADDR, (u8 *)veal, len);
kfree(veal);
+ if (ret) {
+ dev_err(&adapter->pdev->dev,
+ "Unable to send ADD_ETH_ADDR message to PF, error %d\n", ret);
+ adapter->current_op = VIRTCHNL_OP_UNKNOWN;
+ }
+
+ return ret;
}
/**
@@ -712,8 +724,8 @@ static void iavf_mac_add_ok(struct iavf_adapter *adapter)
* @adapter: adapter structure
*
* Remove filters from list based on PF response.
- **/
-static void iavf_mac_add_reject(struct iavf_adapter *adapter)
+ */
+void iavf_mac_add_reject(struct iavf_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct iavf_mac_filter *f, *ftmp;
@@ -2364,7 +2376,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
iavf_mac_add_reject(adapter);
/* restore administratively set MAC address */
ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
- wake_up(&adapter->vc_waitqueue);
break;
case VIRTCHNL_OP_DEL_ETH_ADDR:
dev_err(&adapter->pdev->dev, "Failed to delete MAC filter, error %s\n",
@@ -2555,7 +2566,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
eth_hw_addr_set(netdev, adapter->hw.mac.addr);
netif_addr_unlock_bh(netdev);
}
- wake_up(&adapter->vc_waitqueue);
break;
case VIRTCHNL_OP_GET_STATS: {
struct iavf_eth_stats *stats =
@@ -2950,3 +2960,72 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
} /* switch v_opcode */
adapter->current_op = VIRTCHNL_OP_UNKNOWN;
}
+
+/**
+ * iavf_poll_virtchnl_response - Poll admin queue for virtchnl response
+ * @adapter: adapter structure
+ * @event: pre-allocated event buffer to use for polling
+ * @condition: callback to check if desired response received
+ * @cond_data: context data passed to condition callback
+ * @timeout_ms: maximum time to wait in milliseconds
+ *
+ * Polls the admin queue and processes all incoming virtchnl messages.
+ * After processing each valid message, calls the condition callback to check
+ * if the expected response has been received. The callback receives the opcode
+ * of the processed message to identify which response was received. Continues
+ * polling until the callback returns true or timeout expires.
+ *
+ * Caller must allocate event buffer before sending any messages to PF to avoid
+ * state mismatch if allocation fails after message is sent.
+ *
+ * Caller must hold netdev_lock. This can sleep for up to timeout_ms while
+ * polling hardware.
+ *
+ * Return: 0 on success (condition met), -EAGAIN on timeout, or error code
+ */
+int iavf_poll_virtchnl_response(struct iavf_adapter *adapter,
+ struct iavf_arq_event_info *event,
+ bool (*condition)(struct iavf_adapter *adapter,
+ const void *data,
+ enum virtchnl_ops v_op),
+ const void *cond_data,
+ unsigned int timeout_ms)
+{
+ struct iavf_hw *hw = &adapter->hw;
+ enum virtchnl_ops received_op;
+ unsigned long timeout;
+ int ret = -EAGAIN;
+ u16 pending = 0;
+ u32 v_retval;
+
+ netdev_assert_locked(adapter->netdev);
+
+ timeout = jiffies + msecs_to_jiffies(timeout_ms);
+ do {
+ if (!pending)
+ usleep_range(50, 75);
+
+ if (iavf_clean_arq_element(hw, event, &pending) == IAVF_SUCCESS) {
+ received_op = (enum virtchnl_ops)le32_to_cpu(event->desc.cookie_high);
+ if (received_op != VIRTCHNL_OP_UNKNOWN) {
+ v_retval = le32_to_cpu(event->desc.cookie_low);
+
+ iavf_virtchnl_completion(adapter, received_op,
+ (enum iavf_status)v_retval,
+ event->msg_buf, event->msg_len);
+
+ if (condition(adapter, cond_data, received_op)) {
+ ret = 0;
+ break;
+ }
+ }
+
+ memset(event->msg_buf, 0, IAVF_MAX_AQ_BUF_SIZE);
+
+ if (pending)
+ continue;
+ }
+ } while (time_before(jiffies, timeout));
+
+ return ret;
+}
diff --git a/drivers/net/ethernet/intel/ice/devlink/port.c b/drivers/net/ethernet/intel/ice/devlink/port.c
index 2a2e56777f9f..3ede24649002 100644
--- a/drivers/net/ethernet/intel/ice/devlink/port.c
+++ b/drivers/net/ethernet/intel/ice/devlink/port.c
@@ -590,8 +590,8 @@ static void ice_dealloc_dynamic_port(struct ice_dynamic_port *dyn_port)
xa_erase(&pf->sf_nums, devlink_port->attrs.pci_sf.sf);
ice_eswitch_detach_sf(pf, dyn_port);
- ice_vsi_free(dyn_port->vsi);
xa_erase(&pf->dyn_ports, dyn_port->vsi->idx);
+ ice_vsi_free(dyn_port->vsi);
kfree(dyn_port);
}
diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c
index b069e6c514fb..6e7bba473898 100644
--- a/drivers/net/ethernet/intel/ice/ice_eswitch.c
+++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c
@@ -95,7 +95,7 @@ ice_eswitch_release_repr(struct ice_pf *pf, struct ice_repr *repr)
return;
ice_vsi_update_security(vsi, ice_vsi_ctx_set_antispoof);
- metadata_dst_free(repr->dst);
+ dst_release(&repr->dst->dst);
repr->dst = NULL;
ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac,
ICE_FWD_TO_VSI);
diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c
index e04de0215596..f893dff39aac 100644
--- a/drivers/net/ethernet/intel/ice/ice_sriov.c
+++ b/drivers/net/ethernet/intel/ice/ice_sriov.c
@@ -1367,6 +1367,20 @@ int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
}
/**
+ * ice_setup_vf_trust - Enable/disable VF trust mode without reset
+ * @vf: VF to configure
+ * @setting: trust setting
+ *
+ * Update VF flags when changing trust without performing a VF reset.
+ * This is only called when it's safe to skip the reset (VF has no advanced
+ * features configured that need cleanup).
+ */
+static void ice_setup_vf_trust(struct ice_vf *vf, bool setting)
+{
+ assign_bit(ICE_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps, setting);
+}
+
+/**
* ice_set_vf_trust
* @netdev: network interface device structure
* @vf_id: VF identifier
@@ -1401,11 +1415,19 @@ int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted)
mutex_lock(&vf->cfg_lock);
- while (!trusted && vf->num_mac_lldp)
- ice_vf_update_mac_lldp_num(vf, ice_get_vf_vsi(vf), false);
-
- vf->trusted = trusted;
- ice_reset_vf(vf, ICE_VF_RESET_NOTIFY);
+ /* Reset only if revoking trust and VF has advanced features configured */
+ if (!trusted &&
+ (vf->num_mac_lldp > 0 ||
+ test_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states) ||
+ test_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states))) {
+ while (vf->num_mac_lldp)
+ ice_vf_update_mac_lldp_num(vf, ice_get_vf_vsi(vf), false);
+ vf->trusted = trusted;
+ ice_reset_vf(vf, ICE_VF_RESET_NOTIFY);
+ } else {
+ vf->trusted = trusted;
+ ice_setup_vf_trust(vf, trusted);
+ }
dev_info(ice_pf_to_dev(pf), "VF %u is now %strusted\n",
vf_id, trusted ? "" : "un");
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index 31303ab5be17..a2c7c4962882 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -1561,10 +1561,10 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first,
}
}
tstamp_ring->next_to_use = j;
- writel_relaxed(j, tstamp_ring->tail);
+ writel(j, tstamp_ring->tail);
} else {
ring_kick:
- writel_relaxed(i, tx_ring->tail);
+ writel(i, tx_ring->tail);
}
return;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 7bd0606a5253..903af3b3e779 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -908,10 +908,12 @@ int mlx5e_poll_ico_cq(struct mlx5e_cq *cq)
} while (!last_wqe);
} while ((++i < MLX5E_TX_CQ_POLL_BUDGET) && (cqe = mlx5_cqwq_get_cqe(&cq->wq)));
- sq->cc = sqcc;
-
mlx5_cqwq_update_db_record(&cq->wq);
+ /* ensure cq space is freed before enabling more cqes */
+ dma_wmb();
+
+ sq->cc = sqcc;
return i;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/adj_vport.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/adj_vport.c
index 7950b82d8b8a..3624c680a861 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/adj_vport.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/adj_vport.c
@@ -11,26 +11,6 @@ int mlx5_esw_adj_vport_modify(struct mlx5_core_dev *dev, u16 vport,
lockdep_assert_held(&dev->priv.eswitch->state_lock);
- if (MLX5_CAP_ESW(dev, esw_vport_state_max_tx_speed)) {
- u8 op_mod = MLX5_VPORT_STATE_OP_MOD_ESW_VPORT;
- struct mlx5_vport *esw_vport;
- u32 speed = 0;
- int err;
-
- err = mlx5_query_vport_max_tx_speed(dev, op_mod, vport,
- true, &speed, NULL);
- if (err) {
- esw_vport = mlx5_eswitch_get_vport(dev->priv.eswitch,
- vport);
- speed = IS_ERR(esw_vport) ? 0 :
- esw_vport->agg_max_tx_speed;
- mlx5_core_dbg(dev,
- "Failed to query vport %d max tx speed, err=%d, using cached %u\n",
- vport, err, speed);
- }
- MLX5_SET(modify_vport_state_in, in, max_tx_speed, speed);
- }
-
MLX5_SET(modify_vport_state_in, in, opcode,
MLX5_CMD_OP_MODIFY_VPORT_STATE);
MLX5_SET(modify_vport_state_in, in, op_mod,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
index 3b34bec559e0..4e173b08cb37 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -1432,30 +1432,40 @@ static bool mlx5_lag_should_disable_lag(struct mlx5_lag *ldev, bool do_bond)
}
#ifdef CONFIG_MLX5_ESWITCH
-static int
-mlx5_lag_sum_devices_speed(struct mlx5_lag *ldev, u32 *sum_speed,
- int (*get_speed)(struct mlx5_core_dev *, u32 *))
+static int mlx5_lag_get_devices_oper_speed(struct mlx5_lag *ldev,
+ u32 *sum_speed)
{
- struct mlx5_core_dev *pf_mdev;
- struct lag_func *pf;
int pf_idx;
- u32 speed;
- int ret;
*sum_speed = 0;
mlx5_ldev_for_each(pf_idx, 0, ldev) {
+ u8 opmod = MLX5_VPORT_STATE_OP_MOD_VNIC_VPORT;
+ struct mlx5_core_dev *pf_mdev;
+ struct lag_func *pf;
+ u32 speed;
+ u8 state;
+ int ret;
+
pf = mlx5_lag_pf(ldev, pf_idx);
if (!pf)
continue;
pf_mdev = pf->dev;
if (!pf_mdev)
continue;
+ ret = mlx5_query_vport_max_tx_speed(pf_mdev, opmod, 0, 0,
+ &speed, &state);
+ if (ret) {
+ mlx5_core_dbg(pf_mdev, "State query failed (err=%d)\n",
+ ret);
+ return ret;
+ }
+ if (state != VPORT_STATE_UP)
+ continue;
- ret = get_speed(pf_mdev, &speed);
+ ret = mlx5_port_oper_linkspeed(pf_mdev, &speed);
if (ret) {
mlx5_core_dbg(pf_mdev,
- "Failed to get device speed using %ps. Device %s speed is not available (err=%d)\n",
- get_speed, dev_name(pf_mdev->device),
+ "Failed to get oper speed (err=%d)\n",
ret);
return ret;
}
@@ -1466,17 +1476,42 @@ mlx5_lag_sum_devices_speed(struct mlx5_lag *ldev, u32 *sum_speed,
return 0;
}
-static int mlx5_lag_sum_devices_max_speed(struct mlx5_lag *ldev, u32 *max_speed)
+static int mlx5_lag_get_devices_max_speed(struct mlx5_lag *ldev, u32 *max_speed)
{
- return mlx5_lag_sum_devices_speed(ldev, max_speed,
- mlx5_port_max_linkspeed);
-}
+ bool take_max;
+ int pf_idx;
-static int mlx5_lag_sum_devices_oper_speed(struct mlx5_lag *ldev,
- u32 *oper_speed)
-{
- return mlx5_lag_sum_devices_speed(ldev, oper_speed,
- mlx5_port_oper_linkspeed);
+ take_max = ldev->tracker.tx_type == NETDEV_LAG_TX_TYPE_ACTIVEBACKUP;
+ if (ldev->mode == MLX5_LAG_MODE_MPESW)
+ take_max = false;
+
+ *max_speed = 0;
+ mlx5_ldev_for_each(pf_idx, 0, ldev) {
+ struct mlx5_core_dev *pf_mdev;
+ struct lag_func *pf;
+ u32 speed;
+ int ret;
+
+ pf = mlx5_lag_pf(ldev, pf_idx);
+ if (!pf)
+ continue;
+ pf_mdev = pf->dev;
+ if (!pf_mdev)
+ continue;
+
+ ret = mlx5_port_max_linkspeed(pf_mdev, &speed);
+ if (ret) {
+ mlx5_core_dbg(pf_mdev,
+ "Failed to get max speed (err=%d)\n",
+ ret);
+ return ret;
+ }
+
+ *max_speed = take_max ?
+ max(*max_speed, speed) : *max_speed + speed;
+ }
+
+ return 0;
}
static void mlx5_lag_modify_device_vports_speed(struct mlx5_core_dev *mdev,
@@ -1525,7 +1560,7 @@ void mlx5_lag_set_vports_agg_speed(struct mlx5_lag *ldev)
int pf_idx;
if (ldev->mode == MLX5_LAG_MODE_MPESW) {
- if (mlx5_lag_sum_devices_oper_speed(ldev, &speed))
+ if (mlx5_lag_get_devices_oper_speed(ldev, &speed))
return;
} else {
speed = ldev->tracker.bond_speed_mbps;
@@ -1533,8 +1568,8 @@ void mlx5_lag_set_vports_agg_speed(struct mlx5_lag *ldev)
return;
}
- /* If speed is not set, use the sum of max speeds of all PFs */
- if (!speed && mlx5_lag_sum_devices_max_speed(ldev, &speed))
+ /* If speed is not set, fall back to the max achievable speed */
+ if (!speed && mlx5_lag_get_devices_max_speed(ldev, &speed))
return;
speed = speed / MLX5_MAX_TX_SPEED_UNIT;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c
index 5774ec117428..78f3d15b599d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c
@@ -93,30 +93,6 @@ int mlx5_modify_vport_admin_state(struct mlx5_core_dev *mdev, u8 opmod,
lockdep_assert_held(&mdev->priv.eswitch->state_lock);
#endif
- if (MLX5_CAP_ESW(mdev, esw_vport_state_max_tx_speed) &&
- opmod == MLX5_VPORT_STATE_OP_MOD_ESW_VPORT &&
- vport != MLX5_VPORT_UPLINK) {
- u32 speed = 0;
- int err;
-
- err = mlx5_query_vport_max_tx_speed(mdev, opmod, vport,
- other_vport, &speed, NULL);
- if (err) {
-#ifdef CONFIG_MLX5_ESWITCH
- struct mlx5_vport *esw_vport;
-
- esw_vport = mlx5_eswitch_get_vport(mdev->priv.eswitch,
- vport);
- speed = IS_ERR(esw_vport) ? 0 :
- esw_vport->agg_max_tx_speed;
-#endif
- mlx5_core_dbg(mdev,
- "Failed to query vport %d max tx speed, err=%d, using cached %u\n",
- vport, err, speed);
- }
- MLX5_SET(modify_vport_state_in, in, max_tx_speed, speed);
- }
-
MLX5_SET(modify_vport_state_in, in, opcode,
MLX5_CMD_OP_MODIFY_VPORT_STATE);
MLX5_SET(modify_vport_state_in, in, op_mod, opmod);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index b03ff9e044f9..10af08ce72ef 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -989,6 +989,8 @@ void mlxsw_sp_acl_ruleset_prio_get(struct mlxsw_sp_acl_ruleset *ruleset,
struct mlxsw_sp_acl_rule_info *
mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl,
struct mlxsw_afa_block *afa_block);
+void mlxsw_sp_acl_rulei_free(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_acl_rule_info *rulei);
void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei);
int mlxsw_sp_acl_rulei_commit(struct mlxsw_sp_acl_rule_info *rulei);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
index cb232accb296..f7be4f3a1518 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
@@ -340,8 +340,8 @@ err_afa_block_create:
return ERR_PTR(err);
}
-void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp *mlxsw_sp,
- struct mlxsw_sp_acl_rule_info *rulei)
+void mlxsw_sp_acl_rulei_free(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_acl_rule_info *rulei)
{
if (rulei->action_created)
mlxsw_afa_block_destroy(rulei->act_block);
@@ -351,6 +351,12 @@ void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp *mlxsw_sp,
if (rulei->dst_port_range_reg_valid)
mlxsw_sp_port_range_reg_put(mlxsw_sp,
rulei->dst_port_range_reg_index);
+}
+
+void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp *mlxsw_sp,
+ struct mlxsw_sp_acl_rule_info *rulei)
+{
+ mlxsw_sp_acl_rulei_free(mlxsw_sp, rulei);
kfree(rulei);
}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
index 353fd9ca89a6..5e4632cb792d 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
@@ -862,14 +862,19 @@ int mlxsw_sp_flower_tmplt_create(struct mlxsw_sp *mlxsw_sp,
memset(&rulei, 0, sizeof(rulei));
err = mlxsw_sp_flower_parse(mlxsw_sp, block, &rulei, f);
if (err)
- return err;
+ goto out;
+
ruleset = mlxsw_sp_acl_ruleset_get(mlxsw_sp, block,
f->common.chain_index,
MLXSW_SP_ACL_PROFILE_FLOWER,
&rulei.values.elusage);
+ err = PTR_ERR_OR_ZERO(ruleset);
+
+out:
+ mlxsw_sp_acl_rulei_free(mlxsw_sp, &rulei);
/* keep the reference to the ruleset */
- return PTR_ERR_OR_ZERO(ruleset);
+ return err;
}
void mlxsw_sp_flower_tmplt_destroy(struct mlxsw_sp *mlxsw_sp,
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c b/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c
index 5953e04ef14e..2826e48af103 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c
@@ -622,18 +622,9 @@ int sparx5_ptp_init(struct sparx5 *sparx5)
sparx5->ptp = 1;
}
- if (!sparx5->ptp)
- return 0;
-
- for (i = 0; i < SPARX5_PHC_COUNT; ++i) {
- err = sparx5_ptp_phc_init(sparx5, i, &sparx5_ptp_clock_info);
- if (err)
- return err;
- }
-
- spin_lock_init(&sparx5->ptp_clock_lock);
- spin_lock_init(&sparx5->ptp_ts_id_lock);
- mutex_init(&sparx5->ptp_lock);
+ /* The base, non-PTP-capable lan969x variants need the
+ * first TOD counter running to forward frames.
+ */
/* Disable master counters */
spx5_wr(PTP_PTP_DOM_CFG_PTP_ENA_SET(0), sparx5, PTP_PTP_DOM_CFG);
@@ -657,6 +648,19 @@ int sparx5_ptp_init(struct sparx5 *sparx5)
/* Enable master counters */
spx5_wr(PTP_PTP_DOM_CFG_PTP_ENA_SET(0x7), sparx5, PTP_PTP_DOM_CFG);
+ if (!sparx5->ptp)
+ return 0;
+
+ for (i = 0; i < SPARX5_PHC_COUNT; ++i) {
+ err = sparx5_ptp_phc_init(sparx5, i, &sparx5_ptp_clock_info);
+ if (err)
+ return err;
+ }
+
+ spin_lock_init(&sparx5->ptp_clock_lock);
+ spin_lock_init(&sparx5->ptp_ts_id_lock);
+ mutex_init(&sparx5->ptp_lock);
+
for (i = 0; i < sparx5->data->consts->n_ports; i++) {
port = sparx5->ports[i];
if (!port)
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c
index 702257979462..146d7f28e8f3 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_matchall.c
@@ -160,6 +160,7 @@ static int sparx5_tc_matchall_destroy(struct net_device *ndev,
}
list_del(&entry->list);
+ kfree(entry);
return err;
}
diff --git a/drivers/net/ethernet/microsoft/mana/mana_bpf.c b/drivers/net/ethernet/microsoft/mana/mana_bpf.c
index 5c9961ee9747..b27fd9b8c4f6 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_bpf.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_bpf.c
@@ -91,7 +91,7 @@ u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq,
goto out;
xdp_init_buff(xdp, PAGE_SIZE, &rxq->xdp_rxq);
- xdp_prepare_buff(xdp, buf_va, XDP_PACKET_HEADROOM, pkt_len, true);
+ xdp_prepare_buff(xdp, buf_va, rxq->headroom, pkt_len, true);
act = bpf_prog_run_xdp(prog, xdp);
@@ -183,9 +183,9 @@ static int mana_xdp_set(struct net_device *ndev, struct bpf_prog *prog,
if (!old_prog && !prog)
return 0;
- if (prog && ndev->mtu > MANA_XDP_MTU_MAX) {
+ if (prog && ndev->mtu > MANA_XDP_MTU_MAX(ndev)) {
netdev_err(ndev, "XDP: mtu:%u too large, mtu_max:%lu\n",
- ndev->mtu, MANA_XDP_MTU_MAX);
+ ndev->mtu, MANA_XDP_MTU_MAX(ndev));
NL_SET_ERR_MSG_MOD(extack, "XDP: mtu too large");
return -EOPNOTSUPP;
@@ -238,7 +238,7 @@ static int mana_xdp_set(struct net_device *ndev, struct bpf_prog *prog,
bpf_prog_put(old_prog);
if (prog)
- ndev->max_mtu = min_t(unsigned int, MANA_XDP_MTU_MAX,
+ ndev->max_mtu = min_t(unsigned int, MANA_XDP_MTU_MAX(ndev),
gc->adapter_mtu - ETH_HLEN);
else
ndev->max_mtu = gc->adapter_mtu - ETH_HLEN;
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 591fb4191d90..a1fb06b23947 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -758,6 +758,44 @@ static void *mana_get_rxbuf_pre(struct mana_rxq *rxq, dma_addr_t *da)
return va;
}
+/* Reserve enough headroom to satisfy the skb_cow() in ip_forward() and avoid
+ * reallocation: the TX path keeps the SGE DMA mappings in struct mana_skb_head
+ * at skb->head, so the port advertises ndev->needed_headroom = MANA_HEADROOM.
+ */
+static u32 mana_get_rxbuf_headroom(struct mana_port_context *apc)
+{
+ if (mana_xdp_get(apc))
+ return mana_xdp_headroom(apc->ndev);
+
+ return LL_RESERVED_SPACE(apc->ndev);
+}
+
+static u32 mana_get_rxbuf_size(struct mana_port_context *apc, u32 mtu)
+{
+ u32 len = SKB_DATA_ALIGN(mtu + MANA_RXBUF_PAD +
+ mana_get_rxbuf_headroom(apc));
+
+ return ALIGN(len, MANA_RX_FRAG_ALIGNMENT);
+}
+
+/* Returns true when one RX buffer per page is already required by XDP or by
+ * the buffer size implied by the MTU, i.e. regardless of the
+ * MANA_PRIV_FLAG_USE_FULL_PAGE_RXBUF private flag.
+ */
+bool mana_single_rxbuf_per_page_forced(struct mana_port_context *apc, u32 mtu)
+{
+ /* For xdp make sure only one packet fits per page. */
+ if (mana_xdp_get(apc))
+ return true;
+
+ /* Only use the page_pool fragment path when at least two buffers,
+ * including the headroom each of them has to reserve, actually fit
+ * into one page. Otherwise the fragment path degenerates into one
+ * buffer per page while still paying the fragment accounting cost.
+ */
+ return PAGE_SIZE / mana_get_rxbuf_size(apc, mtu) < 2;
+}
+
static bool
mana_use_single_rxbuf_per_page(struct mana_port_context *apc, u32 mtu)
{
@@ -770,32 +808,27 @@ mana_use_single_rxbuf_per_page(struct mana_port_context *apc, u32 mtu)
if (apc->priv_flags & BIT(MANA_PRIV_FLAG_USE_FULL_PAGE_RXBUF))
return true;
- /* For xdp and jumbo frames make sure only one packet fits per page. */
- if (mtu + MANA_RXBUF_PAD > PAGE_SIZE / 2 || mana_xdp_get(apc))
- return true;
-
- return false;
+ return mana_single_rxbuf_per_page_forced(apc, mtu);
}
-/* Get RX buffer's data size, alloc size, XDP headroom based on MTU */
+/* Get RX buffer's data size, alloc size, headroom and frag count based on MTU */
static void mana_get_rxbuf_cfg(struct mana_port_context *apc,
int mtu, u32 *datasize, u32 *alloc_size,
u32 *headroom, u32 *frag_count)
{
- u32 len, buf_size;
+ u32 buf_size;
/* Calculate datasize first (consistent across all cases) */
*datasize = mtu + ETH_HLEN;
+ *headroom = mana_get_rxbuf_headroom(apc);
+
if (mana_use_single_rxbuf_per_page(apc, mtu)) {
- if (mana_xdp_get(apc)) {
- *headroom = XDP_PACKET_HEADROOM;
+ if (mana_xdp_get(apc))
*alloc_size = PAGE_SIZE;
- } else {
- *headroom = 0; /* no support for XDP */
+ else
*alloc_size = SKB_DATA_ALIGN(mtu + MANA_RXBUF_PAD +
*headroom);
- }
*frag_count = 1;
@@ -809,11 +842,7 @@ static void mana_get_rxbuf_cfg(struct mana_port_context *apc,
}
/* Standard MTU case - optimize for multiple packets per page */
- *headroom = 0;
-
- /* Calculate base buffer size needed */
- len = SKB_DATA_ALIGN(mtu + MANA_RXBUF_PAD + *headroom);
- buf_size = ALIGN(len, MANA_RX_FRAG_ALIGNMENT);
+ buf_size = mana_get_rxbuf_size(apc, mtu);
/* Calculate how many packets can fit in a page */
*frag_count = PAGE_SIZE / buf_size;
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index ece7ff9cc409..33db79569d3b 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -815,12 +815,12 @@ static int mana_set_priv_flags(struct net_device *ndev, u32 priv_flags)
if (!apc->port_is_up)
return 0;
- /* If XDP is attached or MTU is jumbo, single-buffer-per-page
- * is already forced regardless of this flag. Skip the
- * expensive detach/attach cycle since nothing changes.
+ /* If XDP is attached or the MTU already forces one buffer per
+ * page, single-buffer-per-page is used regardless of this
+ * flag. Skip the expensive detach/attach cycle since nothing
+ * changes.
*/
- if (ndev->mtu + MANA_RXBUF_PAD > PAGE_SIZE / 2 ||
- mana_xdp_get(apc))
+ if (mana_single_rxbuf_per_page_forced(apc, ndev->mtu))
return 0;
/* Block RDMA from grabbing the vport during detach/attach */
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 857f7562c6c6..5e2654c91b41 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -633,7 +633,7 @@ struct stmmac_est_ops {
struct stmmac_vlan_ops {
/* VLAN */
void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash,
- u16 perfect_match, bool is_double);
+ bool is_svlan);
void (*enable_vlan)(struct mac_device_info *hw, u32 type);
void (*rx_hw_vlan)(struct mac_device_info *hw, struct dma_desc *rx_desc,
struct sk_buff *skb);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 7582fca63741..d2d387f45c10 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -344,7 +344,7 @@ struct stmmac_priv {
void __iomem *ptpaddr;
void __iomem *estaddr;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
- unsigned int num_double_vlans;
+ unsigned int num_svlans;
int sfty_irq;
struct stmmac_msi *msi;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index ec62fa7418f4..b837e8e27a35 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -6226,6 +6226,13 @@ static netdev_features_t stmmac_fix_features(struct net_device *dev,
if (priv->plat->bugged_jumbo && (dev->mtu > ETH_DATA_LEN))
features &= ~NETIF_F_CSUM_MASK;
+ if (priv->plat->core_type == DWMAC_CORE_XGMAC) {
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
+ features |= NETIF_F_HW_VLAN_STAG_RX;
+ else
+ features &= ~NETIF_F_HW_VLAN_STAG_RX;
+ }
+
return features;
}
@@ -6850,32 +6857,21 @@ static u32 stmmac_vid_crc32_le(__le16 vid_le)
return crc;
}
-static int stmmac_vlan_update(struct stmmac_priv *priv, bool is_double)
+static int stmmac_vlan_update(struct stmmac_priv *priv, bool is_svlan)
{
u32 crc, hash = 0;
- u16 pmatch = 0;
- int count = 0;
u16 vid = 0;
for_each_set_bit(vid, priv->active_vlans, VLAN_N_VID) {
__le16 vid_le = cpu_to_le16(vid);
crc = bitrev32(~stmmac_vid_crc32_le(vid_le)) >> 28;
hash |= (1 << crc);
- count++;
- }
-
- if (!priv->dma_cap.vlhash) {
- if (count > 2) /* VID = 0 always passes filter */
- return -EOPNOTSUPP;
-
- pmatch = vid;
- hash = 0;
}
if (!netif_running(priv->dev))
return 0;
- return stmmac_update_vlan_hash(priv, priv->hw, hash, pmatch, is_double);
+ return stmmac_update_vlan_hash(priv, priv->hw, hash, is_svlan);
}
/* FIXME: This may need RXC to be running, but it may be called with BH
@@ -6884,8 +6880,8 @@ static int stmmac_vlan_update(struct stmmac_priv *priv, bool is_double)
static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid)
{
struct stmmac_priv *priv = netdev_priv(ndev);
- unsigned int num_double_vlans;
- bool is_double = false;
+ unsigned int num_svlans;
+ bool is_svlan = false;
int ret;
ret = pm_runtime_resume_and_get(priv->device);
@@ -6893,11 +6889,11 @@ static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid
return ret;
if (be16_to_cpu(proto) == ETH_P_8021AD)
- is_double = true;
+ is_svlan = true;
set_bit(vid, priv->active_vlans);
- num_double_vlans = priv->num_double_vlans + is_double;
- ret = stmmac_vlan_update(priv, num_double_vlans);
+ num_svlans = priv->num_svlans + is_svlan;
+ ret = stmmac_vlan_update(priv, num_svlans);
if (ret) {
clear_bit(vid, priv->active_vlans);
goto err_pm_put;
@@ -6907,12 +6903,12 @@ static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid
ret = stmmac_add_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, vid);
if (ret) {
clear_bit(vid, priv->active_vlans);
- stmmac_vlan_update(priv, priv->num_double_vlans);
+ stmmac_vlan_update(priv, priv->num_svlans);
goto err_pm_put;
}
}
- priv->num_double_vlans = num_double_vlans;
+ priv->num_svlans = num_svlans;
err_pm_put:
pm_runtime_put(priv->device);
@@ -6926,8 +6922,8 @@ err_pm_put:
static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid)
{
struct stmmac_priv *priv = netdev_priv(ndev);
- unsigned int num_double_vlans;
- bool is_double = false;
+ unsigned int num_svlans;
+ bool is_svlan = false;
int ret;
ret = pm_runtime_resume_and_get(priv->device);
@@ -6935,11 +6931,11 @@ static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vi
return ret;
if (be16_to_cpu(proto) == ETH_P_8021AD)
- is_double = true;
+ is_svlan = true;
clear_bit(vid, priv->active_vlans);
- num_double_vlans = priv->num_double_vlans - is_double;
- ret = stmmac_vlan_update(priv, num_double_vlans);
+ num_svlans = priv->num_svlans - is_svlan;
+ ret = stmmac_vlan_update(priv, num_svlans);
if (ret) {
set_bit(vid, priv->active_vlans);
goto del_vlan_error;
@@ -6949,12 +6945,12 @@ static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vi
ret = stmmac_del_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, vid);
if (ret) {
set_bit(vid, priv->active_vlans);
- stmmac_vlan_update(priv, priv->num_double_vlans);
+ stmmac_vlan_update(priv, priv->num_svlans);
goto del_vlan_error;
}
}
- priv->num_double_vlans = num_double_vlans;
+ priv->num_svlans = num_svlans;
del_vlan_error:
pm_runtime_put(priv->device);
@@ -6970,7 +6966,7 @@ static void stmmac_vlan_restore(struct stmmac_priv *priv)
if (priv->hw->num_vlan)
stmmac_restore_hw_vlan_rx_fltr(priv, priv->dev, priv->hw);
- stmmac_vlan_update(priv, priv->num_double_vlans);
+ stmmac_vlan_update(priv, priv->num_svlans);
}
static int stmmac_bpf(struct net_device *dev, struct netdev_bpf *bpf)
@@ -8009,14 +8005,18 @@ static int __stmmac_dvr_probe(struct device *device,
ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
#ifdef STMMAC_VLAN_TAG_USED
/* Both mac100 and gmac support receive VLAN tag detection */
- ndev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_STAG_RX;
+ ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
+ if (priv->plat->core_type == DWMAC_CORE_XGMAC)
+ ndev->features |= NETIF_F_HW_VLAN_STAG_RX;
+
if (dwmac_is_xmac(priv->plat->core_type)) {
ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
priv->hw->hw_vlan_en = true;
}
if (priv->dma_cap.vlhash) {
ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
- ndev->features |= NETIF_F_HW_VLAN_STAG_FILTER;
+ if (priv->plat->core_type == DWMAC_CORE_XGMAC)
+ ndev->features |= NETIF_F_HW_VLAN_STAG_FILTER;
}
if (priv->dma_cap.vlins)
ndev->features |= NETIF_F_HW_VLAN_CTAG_TX;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
index c25dc9f89270..c485217ba880 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
@@ -243,7 +243,7 @@ struct stmmac_test_priv {
int (*func)(struct sk_buff *skb, struct net_device *ndev,
struct packet_type *pt, struct net_device *orig_ndev);
bool capture_all;
- int double_vlan;
+ int svlan;
int vlan_id;
int ok;
};
@@ -285,7 +285,7 @@ static int stmmac_test_loopback_validate(struct sk_buff *skb,
}
ihdr = ip_hdr(skb);
- if (tpriv->double_vlan)
+ if (tpriv->svlan)
ihdr = (struct iphdr *)(skb_network_header(skb) + 4);
if (tpriv->packet->tcp) {
@@ -936,7 +936,7 @@ static int stmmac_test_vlan_validate(struct sk_buff *skb,
struct iphdr *ihdr;
u16 proto;
- proto = tpriv->double_vlan ? ETH_P_8021AD : ETH_P_8021Q;
+ proto = tpriv->svlan ? ETH_P_8021AD : ETH_P_8021Q;
skb = skb_unshare(skb, GFP_ATOMIC);
if (!skb)
@@ -963,7 +963,7 @@ static int stmmac_test_vlan_validate(struct sk_buff *skb,
}
ihdr = ip_hdr(skb);
- if (tpriv->double_vlan)
+ if (tpriv->svlan)
ihdr = (struct iphdr *)(skb_network_header(skb) + 4);
if (ihdr->protocol != IPPROTO_UDP)
goto out;
@@ -1080,7 +1080,7 @@ static int stmmac_test_vlanfilt_perfect(struct stmmac_priv *priv)
return ret;
}
-static int __stmmac_test_dvlanfilt(struct stmmac_priv *priv)
+static int __stmmac_test_svlanfilt(struct stmmac_priv *priv)
{
struct stmmac_packet_attrs attr = { };
struct stmmac_test_priv *tpriv;
@@ -1092,7 +1092,7 @@ static int __stmmac_test_dvlanfilt(struct stmmac_priv *priv)
return -ENOMEM;
tpriv->ok = false;
- tpriv->double_vlan = true;
+ tpriv->svlan = true;
init_completion(&tpriv->comp);
tpriv->pt.type = htons(ETH_P_8021Q);
@@ -1155,15 +1155,15 @@ cleanup:
return ret;
}
-static int stmmac_test_dvlanfilt(struct stmmac_priv *priv)
+static int stmmac_test_svlanfilt(struct stmmac_priv *priv)
{
if (!priv->dma_cap.vlhash)
return -EOPNOTSUPP;
- return __stmmac_test_dvlanfilt(priv);
+ return __stmmac_test_svlanfilt(priv);
}
-static int stmmac_test_dvlanfilt_perfect(struct stmmac_priv *priv)
+static int stmmac_test_svlanfilt_perfect(struct stmmac_priv *priv)
{
int ret, prev_cap = priv->dma_cap.vlhash;
@@ -1171,7 +1171,7 @@ static int stmmac_test_dvlanfilt_perfect(struct stmmac_priv *priv)
return -EOPNOTSUPP;
priv->dma_cap.vlhash = 0;
- ret = __stmmac_test_dvlanfilt(priv);
+ ret = __stmmac_test_svlanfilt(priv);
priv->dma_cap.vlhash = prev_cap;
return ret;
@@ -1372,7 +1372,7 @@ static int stmmac_test_vlanoff_common(struct stmmac_priv *priv, bool svlan)
proto = svlan ? ETH_P_8021AD : ETH_P_8021Q;
tpriv->ok = false;
- tpriv->double_vlan = svlan;
+ tpriv->svlan = svlan;
init_completion(&tpriv->comp);
tpriv->pt.type = svlan ? htons(ETH_P_8021Q) : htons(ETH_P_IP);
@@ -1960,11 +1960,11 @@ static const struct stmmac_test {
.name = "VLAN Filtering (perf) ",
.fn = stmmac_test_vlanfilt_perfect,
}, {
- .name = "Double VLAN Filter ",
- .fn = stmmac_test_dvlanfilt,
+ .name = "SVLAN Filtering ",
+ .fn = stmmac_test_svlanfilt,
}, {
- .name = "Double VLAN Filter (perf) ",
- .fn = stmmac_test_dvlanfilt_perfect,
+ .name = "SVLAN Filtering (perf) ",
+ .fn = stmmac_test_svlanfilt_perfect,
}, {
.name = "Flexible RX Parser ",
.fn = stmmac_test_rxp,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
index e24efe3bfedb..fb9aad748cb3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
@@ -162,7 +162,7 @@ static void vlan_restore_hw_rx_fltr(struct net_device *dev,
}
static void vlan_update_hash(struct mac_device_info *hw, u32 hash,
- u16 perfect_match, bool is_double)
+ bool is_svlan)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
@@ -173,34 +173,17 @@ static void vlan_update_hash(struct mac_device_info *hw, u32 hash,
if (hash) {
value |= VLAN_VTHM | VLAN_ETV;
- if (is_double) {
- value |= VLAN_EDVLP;
+ if (is_svlan) {
value |= VLAN_ESVL;
value |= VLAN_DOVLTC;
} else {
- value &= ~VLAN_EDVLP;
value &= ~VLAN_ESVL;
value &= ~VLAN_DOVLTC;
}
writel(value, ioaddr + VLAN_TAG);
- } else if (perfect_match) {
- u32 value = VLAN_ETV;
-
- if (is_double) {
- value |= VLAN_EDVLP;
- value |= VLAN_ESVL;
- value |= VLAN_DOVLTC;
- } else {
- value &= ~VLAN_EDVLP;
- value &= ~VLAN_ESVL;
- value &= ~VLAN_DOVLTC;
- }
-
- writel(value | perfect_match, ioaddr + VLAN_TAG);
} else {
- value &= ~(VLAN_VTHM | VLAN_ETV);
- value &= ~(VLAN_EDVLP | VLAN_ESVL);
+ value &= ~(VLAN_VTHM | VLAN_ETV | VLAN_ESVL);
value &= ~VLAN_DOVLTC;
value &= ~VLAN_VID;
@@ -236,6 +219,7 @@ static void vlan_set_hw_mode(struct mac_device_info *hw)
void __iomem *ioaddr = hw->pcsr;
u32 value = readl(ioaddr + VLAN_TAG);
+ value |= VLAN_EDVLP;
value &= ~VLAN_TAG_CTRL_EVLS_MASK;
if (hw->hw_vlan_en)
@@ -251,7 +235,7 @@ static void vlan_set_hw_mode(struct mac_device_info *hw)
}
static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash,
- u16 perfect_match, bool is_double)
+ bool is_svlan)
{
void __iomem *ioaddr = hw->pcsr;
@@ -267,41 +251,16 @@ static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash,
value = readl(ioaddr + VLAN_TAG);
value |= VLAN_VTHM | VLAN_ETV;
- if (is_double) {
- value |= VLAN_EDVLP;
+ if (is_svlan) {
value |= VLAN_ESVL;
value |= VLAN_DOVLTC;
} else {
- value &= ~VLAN_EDVLP;
value &= ~VLAN_ESVL;
value &= ~VLAN_DOVLTC;
}
value &= ~VLAN_VID;
writel(value, ioaddr + VLAN_TAG);
- } else if (perfect_match) {
- u32 value = readl(ioaddr + XGMAC_PACKET_FILTER);
-
- value |= XGMAC_FILTER_VTFE;
-
- writel(value, ioaddr + XGMAC_PACKET_FILTER);
-
- value = readl(ioaddr + VLAN_TAG);
-
- value &= ~VLAN_VTHM;
- value |= VLAN_ETV;
- if (is_double) {
- value |= VLAN_EDVLP;
- value |= VLAN_ESVL;
- value |= VLAN_DOVLTC;
- } else {
- value &= ~VLAN_EDVLP;
- value &= ~VLAN_ESVL;
- value &= ~VLAN_DOVLTC;
- }
-
- value &= ~VLAN_VID;
- writel(value | perfect_match, ioaddr + VLAN_TAG);
} else {
u32 value = readl(ioaddr + XGMAC_PACKET_FILTER);
@@ -311,8 +270,7 @@ static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash,
value = readl(ioaddr + VLAN_TAG);
- value &= ~(VLAN_VTHM | VLAN_ETV);
- value &= ~(VLAN_EDVLP | VLAN_ESVL);
+ value &= ~(VLAN_VTHM | VLAN_ETV | VLAN_ESVL);
value &= ~VLAN_DOVLTC;
value &= ~VLAN_VID;
@@ -320,6 +278,14 @@ static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash,
}
}
+static void dwxlgmac2_set_hw_vlan_mode(struct mac_device_info *hw)
+{
+ void __iomem *ioaddr = hw->pcsr;
+ u32 value = readl(ioaddr + VLAN_TAG);
+
+ writel(value | VLAN_EDVLP, ioaddr + VLAN_TAG);
+}
+
const struct stmmac_vlan_ops dwmac_vlan_ops = {
.update_vlan_hash = vlan_update_hash,
.enable_vlan = vlan_enable,
@@ -333,6 +299,7 @@ const struct stmmac_vlan_ops dwmac_vlan_ops = {
const struct stmmac_vlan_ops dwxlgmac2_vlan_ops = {
.update_vlan_hash = dwxgmac2_update_vlan_hash,
.enable_vlan = vlan_enable,
+ .set_hw_vlan_mode = dwxlgmac2_set_hw_vlan_mode,
};
const struct stmmac_vlan_ops dwxgmac210_vlan_ops = {
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index fcd3aaef27fc..c63d99686d0b 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -523,8 +523,9 @@ struct skbuf_dma_descriptor {
* @stats_work: Work for reading the hardware statistics counters often enough
* to catch overflows.
* @dma_err_task: Work structure to process Axi DMA errors
- * @stopping: Set when @dma_err_task shouldn't do anything because we are
- * about to stop the device.
+ * @stopping: Set when we are about to stop the device: makes @dma_err_task
+ * a no-op (legacy DMA path) and fences RX descriptor
+ * resubmission in axienet_dma_rx_cb() (dmaengine path).
* @tx_irq: Axidma TX IRQ number
* @rx_irq: Axidma RX IRQ number
* @eth_irq: Ethernet core IRQ number
@@ -545,6 +546,7 @@ struct skbuf_dma_descriptor {
* @tx_ring_tail: TX skb ring buffer tail index.
* @rx_ring_head: RX skb ring buffer head index.
* @rx_ring_tail: RX skb ring buffer tail index.
+ * @rx_submit_lock: Protects RX ring resubmission vs teardown in dmaengine path.
*/
struct axienet_local {
struct net_device *ndev;
@@ -626,6 +628,7 @@ struct axienet_local {
int tx_ring_tail;
int rx_ring_head;
int rx_ring_tail;
+ spinlock_t rx_submit_lock;
};
/**
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 1722b7038f34..09443623a3e2 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -881,6 +881,7 @@ static void axienet_dma_tx_cb(void *data, const struct dmaengine_result *result)
u64_stats_update_end(&lp->tx_stat_sync);
dma_unmap_sg(lp->dev, skbuf_dma->sgl, skbuf_dma->sg_len, DMA_TO_DEVICE);
dev_consume_skb_any(skbuf_dma->skb);
+ skbuf_dma->skb = NULL;
netif_txq_completed_wake(txq, 1, len,
CIRC_SPACE(lp->tx_ring_head, lp->tx_ring_tail, TX_BD_NUM_MAX),
2);
@@ -1171,6 +1172,7 @@ static void axienet_dma_rx_cb(void *data, const struct dmaengine_result *result)
&meta_max_len);
dma_unmap_single(lp->dev, skbuf_dma->dma_address, lp->max_frm_size,
DMA_FROM_DEVICE);
+ skbuf_dma->skb = NULL;
if (IS_ERR(app_metadata)) {
if (net_ratelimit())
@@ -1193,10 +1195,17 @@ static void axienet_dma_rx_cb(void *data, const struct dmaengine_result *result)
u64_stats_update_end(&lp->rx_stat_sync);
rx_submit:
+ spin_lock(&lp->rx_submit_lock);
+ if (lp->stopping) {
+ spin_unlock(&lp->rx_submit_lock);
+ return;
+ }
+
for (i = 0; i < CIRC_SPACE(lp->rx_ring_head, lp->rx_ring_tail,
RX_BUF_NUM_DEFAULT); i++)
axienet_rx_submit_desc(lp->ndev);
dma_async_issue_pending(lp->rx_chan);
+ spin_unlock(&lp->rx_submit_lock);
}
/**
@@ -1541,6 +1550,7 @@ static int axienet_init_dmaengine(struct net_device *ndev)
lp->tx_ring_head = 0;
lp->rx_ring_tail = 0;
lp->rx_ring_head = 0;
+ lp->stopping = false;
lp->tx_skb_ring = kzalloc_objs(*lp->tx_skb_ring, TX_BD_NUM_MAX);
if (!lp->tx_skb_ring) {
ret = -ENOMEM;
@@ -1752,20 +1762,42 @@ static int axienet_stop(struct net_device *ndev)
free_irq(lp->rx_irq, ndev);
axienet_dma_bd_release(ndev);
} else {
+ struct skbuf_dma_descriptor *skbuf_dma;
+
+ spin_lock_bh(&lp->rx_submit_lock);
+ lp->stopping = true;
+ spin_unlock_bh(&lp->rx_submit_lock);
+
dmaengine_terminate_sync(lp->tx_chan);
- dmaengine_synchronize(lp->tx_chan);
dmaengine_terminate_sync(lp->rx_chan);
- dmaengine_synchronize(lp->rx_chan);
-
- for (i = 0; i < TX_BD_NUM_MAX; i++)
- kfree(lp->tx_skb_ring[i]);
- kfree(lp->tx_skb_ring);
- for (i = 0; i < RX_BUF_NUM_DEFAULT; i++)
- kfree(lp->rx_skb_ring[i]);
- kfree(lp->rx_skb_ring);
dma_release_channel(lp->rx_chan);
dma_release_channel(lp->tx_chan);
+
+ /* Unmap and free any buffer the terminate did not reclaim, so it
+ * is not leaked; a non-NULL skb marks such a slot.
+ */
+ for (i = 0; i < TX_BD_NUM_MAX; i++) {
+ skbuf_dma = lp->tx_skb_ring[i];
+ if (skbuf_dma && skbuf_dma->skb) {
+ dma_unmap_sg(lp->dev, skbuf_dma->sgl,
+ skbuf_dma->sg_len, DMA_TO_DEVICE);
+ dev_kfree_skb_any(skbuf_dma->skb);
+ }
+ kfree(skbuf_dma);
+ }
+ kfree(lp->tx_skb_ring);
+
+ for (i = 0; i < RX_BUF_NUM_DEFAULT; i++) {
+ skbuf_dma = lp->rx_skb_ring[i];
+ if (skbuf_dma && skbuf_dma->skb) {
+ dma_unmap_single(lp->dev, skbuf_dma->dma_address,
+ lp->max_frm_size, DMA_FROM_DEVICE);
+ dev_kfree_skb_any(skbuf_dma->skb);
+ }
+ kfree(skbuf_dma);
+ }
+ kfree(lp->rx_skb_ring);
}
netdev_reset_queue(ndev);
@@ -3065,6 +3097,7 @@ static int axienet_probe(struct platform_device *pdev)
spin_lock_init(&lp->rx_cr_lock);
spin_lock_init(&lp->tx_cr_lock);
+ spin_lock_init(&lp->rx_submit_lock);
INIT_WORK(&lp->rx_dim.work, axienet_rx_dim_work);
lp->rx_dim_enabled = true;
lp->rx_dim.profile_ix = 1;
diff --git a/drivers/net/pfcp.c b/drivers/net/pfcp.c
index 3ecd43cafdf0..51c67c914fad 100644
--- a/drivers/net/pfcp.c
+++ b/drivers/net/pfcp.c
@@ -65,6 +65,13 @@ static int pfcp_encap_recv(struct sock *sk, struct sk_buff *skb)
goto drop;
unparsed = pfcp_hdr(skb);
+ if (unparsed->flags & PFCP_SEID_FLAG) {
+ if (unlikely(!pskb_may_pull(skb, PFCP_HLEN +
+ offsetofend(struct pfcphdr_session,
+ seid))))
+ goto drop;
+ unparsed = pfcp_hdr(skb);
+ }
ip_tunnel_flags_zero(flags);
tun_dst = udp_tun_rx_dst(skb, sk->sk_family, flags, 0,
diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c
index beffbe450612..ca75f08e3c59 100644
--- a/drivers/net/team/team_core.c
+++ b/drivers/net/team/team_core.c
@@ -820,7 +820,8 @@ static struct list_head *__team_get_qom_list(struct team *team, u16 queue_id)
/*
* note: already called with rcu_read_lock
*/
-static bool team_queue_override_transmit(struct team *team, struct sk_buff *skb)
+static bool team_queue_override_transmit(struct team *team, struct sk_buff *skb,
+ bool *tx_success)
{
struct list_head *qom_list;
struct team_port *port;
@@ -828,11 +829,11 @@ static bool team_queue_override_transmit(struct team *team, struct sk_buff *skb)
if (!team->queue_override_enabled || !skb->queue_mapping)
return false;
qom_list = __team_get_qom_list(team, skb->queue_mapping);
- list_for_each_entry_rcu(port, qom_list, qom_list) {
- if (!team_dev_queue_xmit(team, port, skb))
- return true;
- }
- return false;
+ port = list_first_or_null_rcu(qom_list, struct team_port, qom_list);
+ if (!port)
+ return false;
+ *tx_success = !team_dev_queue_xmit(team, port, skb);
+ return true;
}
static void __team_queue_override_port_del(struct team *team,
@@ -1864,8 +1865,7 @@ static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
bool tx_success;
unsigned int len = skb->len;
- tx_success = team_queue_override_transmit(team, skb);
- if (!tx_success)
+ if (!team_queue_override_transmit(team, skb, &tx_success))
tx_success = READ_ONCE(team->ops.transmit)(team, skb);
if (tx_success) {
struct team_pcpu_stats *pcpu_stats;
diff --git a/drivers/net/team/team_mode_broadcast.c b/drivers/net/team/team_mode_broadcast.c
index 61d7d79f0c36..69dc25a5847a 100644
--- a/drivers/net/team/team_mode_broadcast.c
+++ b/drivers/net/team/team_mode_broadcast.c
@@ -37,6 +37,8 @@ static bool bc_transmit(struct team *team, struct sk_buff *skb)
ret = !team_dev_queue_xmit(team, last, skb);
if (!sum_ret)
sum_ret = ret;
+ } else {
+ dev_kfree_skb_any(skb);
}
return sum_ret;
}
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 5a302709a68a..242899f7fd07 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1897,12 +1897,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
}
}
- if (tun_vnet_hdr_tnl_to_skb(tun->flags, features, skb, &hdr)) {
- atomic_long_inc(&tun->rx_frame_errors);
- err = -EINVAL;
- goto free_skb;
- }
-
+ skb->dev = tun->dev;
switch (tun->flags & TUN_TYPE_MASK) {
case IFF_TUN:
if (tun->flags & IFF_NO_PI) {
@@ -1927,9 +1922,8 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
}
}
- skb_reset_mac_header(skb);
+ skb_reset_network_header(skb);
skb->protocol = pi.proto;
- skb->dev = tun->dev;
break;
case IFF_TAP:
if (!pskb_may_pull(skb, ETH_HLEN)) {
@@ -1937,10 +1931,19 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
drop_reason = SKB_DROP_REASON_HDR_TRUNC;
goto drop;
}
- skb->protocol = eth_type_trans(skb, tun->dev);
+ skb_set_network_header(skb, ETH_HLEN);
break;
}
+ if (tun_vnet_hdr_tnl_to_skb(tun->flags, features, skb, &hdr)) {
+ atomic_long_inc(&tun->rx_frame_errors);
+ err = -EINVAL;
+ goto free_skb;
+ }
+
+ if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP)
+ skb->protocol = eth_type_trans(skb, tun->dev);
+
/* copy skb_ubuf_info for callback when skb has no error */
if (zerocopy) {
skb_zcopy_init(skb, msg_control);
@@ -2600,6 +2603,8 @@ build:
features = tun_vnet_hdr_guest_features(READ_ONCE(tun->vnet_hdr_sz));
tnl_hdr = (struct virtio_net_hdr_v1_hash_tunnel *)gso;
+ skb->dev = tun->dev;
+ skb_set_network_header(skb, ETH_HLEN);
if (tun_vnet_hdr_tnl_to_skb(tun->flags, features, skb, tnl_hdr)) {
atomic_long_inc(&tun->rx_frame_errors);
kfree_skb(skb);
diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
index 81d8412ce8e2..cba1dc95d359 100644
--- a/drivers/net/usb/ax88179_178a.c
+++ b/drivers/net/usb/ax88179_178a.c
@@ -1457,11 +1457,11 @@ static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
return 1;
}
- ax_skb = netdev_alloc_skb_ip_align(dev->net, pkt_len);
+ ax_skb = netdev_alloc_skb_ip_align(dev->net, pkt_len - 2);
if (!ax_skb)
return 0;
- skb_put(ax_skb, pkt_len);
- memcpy(ax_skb->data, skb->data + 2, pkt_len);
+ skb_put(ax_skb, pkt_len - 2);
+ memcpy(ax_skb->data, skb->data + 2, pkt_len - 2);
ax88179_rx_checksum(ax_skb, pkt_hdr);
usbnet_skb_return(dev, ax_skb);
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 71227d0389aa..643b97dc5245 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -1415,6 +1415,7 @@ static int veth_open(struct net_device *dev)
}
veth_set_xdp_features(dev);
+ veth_set_xdp_features(peer);
return 0;
}
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index bf82ef9874ab..daab43ac92ce 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -2515,6 +2515,8 @@ static void virtnet_receive_done(struct virtnet_info *vi, struct receive_queue *
goto frame_err;
}
+ skb->dev = dev;
+ skb_set_network_header(skb, ETH_HLEN);
if (virtio_net_hdr_tnl_to_skb(skb, &hdr->tnl_hdr, vi->rx_tnl,
vi->rx_tnl_csum,
virtio_is_little_endian(vi->vdev))) {
diff --git a/drivers/net/wireguard/noise.c b/drivers/net/wireguard/noise.c
index 9c0a09bf6c95..ec2513d6dfab 100644
--- a/drivers/net/wireguard/noise.c
+++ b/drivers/net/wireguard/noise.c
@@ -784,10 +784,11 @@ wg_noise_handshake_consume_response(struct message_handshake_response *src,
/* Success! Copy everything to peer */
down_write(&handshake->lock);
- /* It's important to check that the state is still the same, while we
- * have an exclusive lock.
+ /* Check that the state is the same and that this is still the
+ * initiation we started with, while we have an exclusive lock.
*/
- if (handshake->state != state) {
+ if (handshake->state != state ||
+ crypto_memneq(handshake->ephemeral_private, ephemeral_private, NOISE_PUBLIC_KEY_LEN)) {
up_write(&handshake->lock);
goto fail;
}
diff --git a/drivers/net/wireguard/queueing.h b/drivers/net/wireguard/queueing.h
index 79b6d70de236..663b19b78395 100644
--- a/drivers/net/wireguard/queueing.h
+++ b/drivers/net/wireguard/queueing.h
@@ -78,12 +78,14 @@ static inline void wg_reset_packet(struct sk_buff *skb, bool encapsulating)
u8 l4_hash = skb->l4_hash;
u8 sw_hash = skb->sw_hash;
u32 hash = skb->hash;
+ u8 tstamp_type = skb->tstamp_type;
skb_scrub_packet(skb, true);
memset(&skb->headers, 0, sizeof(skb->headers));
if (encapsulating) {
skb->l4_hash = l4_hash;
skb->sw_hash = sw_hash;
skb->hash = hash;
+ skb->tstamp_type = tstamp_type;
}
skb->queue_mapping = 0;
skb->nohdr = 0;
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 262a2045309b..b0107cde99ff 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -1776,29 +1776,6 @@ int ath12k_core_pre_init(struct ath12k_base *ab)
return 0;
}
-static int ath12k_core_panic_handler(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct ath12k_base *ab = container_of(nb, struct ath12k_base,
- panic_nb);
-
- return ath12k_hif_panic_handler(ab);
-}
-
-static int ath12k_core_panic_notifier_register(struct ath12k_base *ab)
-{
- ab->panic_nb.notifier_call = ath12k_core_panic_handler;
-
- return atomic_notifier_chain_register(&panic_notifier_list,
- &ab->panic_nb);
-}
-
-static void ath12k_core_panic_notifier_unregister(struct ath12k_base *ab)
-{
- atomic_notifier_chain_unregister(&panic_notifier_list,
- &ab->panic_nb);
-}
-
static inline
bool ath12k_core_hw_group_create_ready(struct ath12k_hw_group *ag)
{
@@ -2214,18 +2191,13 @@ int ath12k_core_init(struct ath12k_base *ab)
struct ath12k_hw_group *ag;
int ret;
- ret = ath12k_core_panic_notifier_register(ab);
- if (ret)
- ath12k_warn(ab, "failed to register panic handler: %d\n", ret);
-
mutex_lock(&ath12k_hw_group_mutex);
ag = ath12k_core_hw_group_assign(ab);
if (!ag) {
mutex_unlock(&ath12k_hw_group_mutex);
ath12k_warn(ab, "unable to get hw group\n");
- ret = -ENODEV;
- goto err_unregister_notifier;
+ return -ENODEV;
}
mutex_unlock(&ath12k_hw_group_mutex);
@@ -2250,8 +2222,6 @@ int ath12k_core_init(struct ath12k_base *ab)
err_unassign_hw_group:
ath12k_core_hw_group_unassign(ab);
-err_unregister_notifier:
- ath12k_core_panic_notifier_unregister(ab);
return ret;
}
@@ -2260,7 +2230,6 @@ void ath12k_core_deinit(struct ath12k_base *ab)
{
ath12k_core_hw_group_destroy(ab->ag);
ath12k_core_hw_group_unassign(ab);
- ath12k_core_panic_notifier_unregister(ab);
}
void ath12k_core_free(struct ath12k_base *ab)
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index a98fc6e0699d..93fd227b4d19 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -15,7 +15,6 @@
#include <linux/ctype.h>
#include <linux/firmware.h>
#include <linux/of_reserved_mem.h>
-#include <linux/panic_notifier.h>
#include <linux/average.h>
#include <linux/of.h>
#include <linux/rhashtable.h>
@@ -1139,8 +1138,6 @@ struct ath12k_base {
#endif /* CONFIG_ACPI */
- struct notifier_block panic_nb;
-
struct ath12k_hw_group *ag;
struct ath12k_wsi_info wsi_info;
enum ath12k_qmi_firmware_mode fw_mode;
diff --git a/drivers/net/wireless/ath/ath12k/hif.h b/drivers/net/wireless/ath/ath12k/hif.h
index 4de8667690e9..aecdb0c5f285 100644
--- a/drivers/net/wireless/ath/ath12k/hif.h
+++ b/drivers/net/wireless/ath/ath12k/hif.h
@@ -30,7 +30,6 @@ struct ath12k_hif_ops {
void (*ce_irq_enable)(struct ath12k_base *ab);
void (*ce_irq_disable)(struct ath12k_base *ab);
void (*get_ce_msi_idx)(struct ath12k_base *ab, u32 ce_id, u32 *msi_idx);
- int (*panic_handler)(struct ath12k_base *ab);
void (*coredump_download)(struct ath12k_base *ab);
};
@@ -149,14 +148,6 @@ static inline void ath12k_hif_power_down(struct ath12k_base *ab, bool is_suspend
ab->hif.ops->power_down(ab, is_suspend);
}
-static inline int ath12k_hif_panic_handler(struct ath12k_base *ab)
-{
- if (!ab->hif.ops->panic_handler)
- return NOTIFY_DONE;
-
- return ab->hif.ops->panic_handler(ab);
-}
-
static inline void ath12k_hif_coredump_download(struct ath12k_base *ab)
{
if (ab->hif.ops->coredump_download)
diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index 6441927b5382..8978edb44cec 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -1484,13 +1484,6 @@ void ath12k_pci_power_down(struct ath12k_base *ab, bool is_suspend)
ath12k_pci_sw_reset(ab_pci->ab, false);
}
-static int ath12k_pci_panic_handler(struct ath12k_base *ab)
-{
- ath12k_pci_sw_reset(ab, false);
-
- return NOTIFY_OK;
-}
-
static const struct ath12k_hif_ops ath12k_pci_hif_ops = {
.start = ath12k_pci_start,
.stop = ath12k_pci_stop,
@@ -1508,7 +1501,6 @@ static const struct ath12k_hif_ops ath12k_pci_hif_ops = {
.ce_irq_enable = ath12k_pci_hif_ce_irq_enable,
.ce_irq_disable = ath12k_pci_hif_ce_irq_disable,
.get_ce_msi_idx = ath12k_pci_get_ce_msi_idx,
- .panic_handler = ath12k_pci_panic_handler,
#ifdef CONFIG_ATH12K_COREDUMP
.coredump_download = ath12k_pci_coredump_download,
#endif
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index d2ae67985606..92ec269f43b2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -1489,8 +1489,31 @@ void brcmf_detach(struct device *dev)
brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN);
/* make sure primary interface removed last */
for (i = BRCMF_MAX_IFS - 1; i > -1; i--) {
- if (drvr->iflist[i])
- brcmf_remove_interface(drvr->iflist[i], false);
+ struct brcmf_if *ifp = drvr->iflist[i];
+
+ if (!ifp)
+ continue;
+
+ if (ifp->ndev) {
+ brcmf_remove_interface(ifp, false);
+ continue;
+ }
+
+ /* The P2P device interface has no netdev. Its removal can
+ * race with NL80211_CMD_DEL_INTERFACE issued by a user space
+ * process that is exiting (e.g. wpa_supplicant), which ends
+ * in brcmf_p2p_del_vif() under RTNL and the wiphy mutex. If
+ * both paths remove the interface, the wdev is unregistered
+ * twice and the vif is used after being freed. Take the same
+ * locks and re-read iflist, so only one path removes it.
+ */
+ rtnl_lock();
+ wiphy_lock(drvr->wiphy);
+ ifp = drvr->iflist[i];
+ if (ifp)
+ brcmf_remove_interface(ifp, true);
+ wiphy_unlock(drvr->wiphy);
+ rtnl_unlock();
}
brcmf_bus_stop(drvr->bus_if);
diff --git a/drivers/net/wireless/marvell/libertas/tx.c b/drivers/net/wireless/marvell/libertas/tx.c
index 13d08022e414..27304a98787d 100644
--- a/drivers/net/wireless/marvell/libertas/tx.c
+++ b/drivers/net/wireless/marvell/libertas/tx.c
@@ -117,13 +117,6 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data;
- if (skb->len < sizeof(*rtap_hdr) + 4 + ETH_ALEN) {
- lbs_deb_tx("tx err: short monitor frame %u\n", skb->len);
- dev->stats.tx_dropped++;
- dev->stats.tx_errors++;
- goto free;
- }
-
/* set txpd fields from the radiotap header */
txpd->tx_control = cpu_to_le32(convert_radiotap_rate_to_mv(rtap_hdr->rate));
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 62b41c8bb7c0..2ade848fe3bb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -1426,6 +1426,13 @@ mtxq_to_txq(struct mt76_txq *mtxq)
return container_of(ptr, struct ieee80211_txq, drv_priv);
}
+/* peer-wide state uses the wcid of the primary link */
+static inline struct mt76_wcid *
+mt76_wcid_primary(struct mt76_wcid *wcid)
+{
+ return wcid->def_wcid ? wcid->def_wcid : wcid;
+}
+
static inline struct ieee80211_sta *
wcid_to_sta(struct mt76_wcid *wcid)
{
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
index 10f2ec70c792..218ec406d2a8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
@@ -230,6 +230,7 @@ mt7603_mac_init(struct mt7603_dev *dev)
eth_broadcast_addr(bc_addr);
mt7603_wtbl_init(dev, MT7603_WTBL_RESERVED, -1, bc_addr);
+ mt76_wcid_init(&dev->global_sta.wcid, 0);
dev->global_sta.wcid.idx = MT7603_WTBL_RESERVED;
rcu_assign_pointer(dev->mt76.wcid[MT7603_WTBL_RESERVED],
&dev->global_sta.wcid);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
index ca46a203aa48..c8e389db63a7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
@@ -1238,6 +1238,12 @@ static void mt7915_unregister_ext_phy(struct mt7915_dev *dev)
static void mt7915_stop_hardware(struct mt7915_dev *dev)
{
+ int i;
+
+ mt76_for_each_q_rx(&dev->mt76, i) {
+ if (!mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]))
+ napi_disable(&dev->mt76.napi[i]);
+ }
mt7915_mcu_exit(dev);
mt76_connac2_tx_token_put(&dev->mt76);
mt7915_dma_cleanup(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index a8286f8becf9..a03d89aabe80 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -805,6 +805,7 @@ __mt7915_drop_sta(void *ptr, u8 *mac, struct ieee80211_vif *vif)
msta = (struct mt7915_sta *)sta->drv_priv;
mt7915_mcu_add_sta(data->dev, vif, sta, CONN_STATE_DISCONNECT, false);
+ msta->wcid.tx_info &= ~MT_WCID_TX_INFO_SET;
msta->wcid.sta_disabled = 1;
msta->wcid.sta = 0;
}
@@ -871,6 +872,7 @@ int mt7915_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif,
mutex_unlock(&dev->mt76.mutex);
mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_DISCONNECT, false);
+ msta->wcid.tx_info &= ~MT_WCID_TX_INFO_SET;
msta->wcid.sta_disabled = 1;
msta->wcid.sta = 0;
return 0;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
index 101f571b027f..3b82c9de26c5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
@@ -798,7 +798,8 @@ mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
- if (band_idx)
+ /* 0xff means BAND_AUTO to the firmware, and TGID cannot encode it */
+ if (band_idx && band_idx != 0xff)
val |= FIELD_PREP(MT_TXD1_TGID, band_idx);
txwi[1] = cpu_to_le32(val);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 5993b31e1aae..549f9c06b363 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -2294,6 +2294,18 @@ mt7925_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mvif->valid_links = new_links;
+ /* Restore the legacy BSS after disabling MLO */
+ if (old_links && !new_links) {
+ mt792x_mac_link_bss_remove(dev, &mvif->bss_conf,
+ &mvif->sta.deflink);
+ err = mt7925_mac_link_bss_add(dev, &vif->bss_conf,
+ &mvif->sta.deflink);
+ if (err < 0) {
+ mt792x_mutex_release(dev);
+ return err;
+ }
+ }
+
mt792x_mutex_release(dev);
return 0;
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c
index b468051fbe68..e87dfb0f1b3a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c
@@ -108,68 +108,98 @@ mt792x_asar_acpi_read_mtcl(struct mt792x_dev *dev, u8 **table, u8 *version)
return ret;
}
+/* A table's layout is decided by the version byte in MTCL, but some firmware
+ * labels a version 2 table as version 1. Accept whichever layout the table
+ * actually has: for every accepted entry count the two do not overlap, since
+ * one is 6 + 5n bytes and the other 7 + 7n.
+ */
+static bool
+mt792x_asar_fits(u8 *table, int len, int prelen, int sarlen, int nr_off,
+ int min, int max)
+{
+ int tblcnt;
+
+ if (len < prelen || (len - prelen) % sarlen)
+ return false;
+
+ tblcnt = (len - prelen) / sarlen;
+ if (tblcnt < min || tblcnt > max)
+ return false;
+
+ return tblcnt == table[nr_off];
+}
+
/* MTDS : Dynamic SAR Power Table */
static int
-mt792x_asar_acpi_read_mtds(struct mt792x_dev *dev, u8 **table, u8 version)
+mt792x_asar_acpi_read_mtds(struct mt792x_dev *dev, u8 **table, u8 version,
+ u8 *used)
{
- int len, ret, sarlen, prelen, tblcnt;
- bool enable;
+ int len, ret;
+ u8 *t;
ret = mt792x_acpi_read(dev, MT792x_ACPI_MTDS, table, &len);
if (ret)
return ret;
+ t = *table;
+
/* Table content validation */
- switch (version) {
- case 1:
- enable = ((struct mt792x_asar_dyn *)*table)->enable;
- sarlen = sizeof(struct mt792x_asar_dyn_limit);
- prelen = sizeof(struct mt792x_asar_dyn);
- break;
- case 2:
- enable = ((struct mt792x_asar_dyn_v2 *)*table)->enable;
- sarlen = sizeof(struct mt792x_asar_dyn_limit_v2);
- prelen = sizeof(struct mt792x_asar_dyn_v2);
- break;
- default:
+ if (mt792x_asar_fits(t, len, sizeof(struct mt792x_asar_dyn),
+ sizeof(struct mt792x_asar_dyn_limit),
+ offsetof(struct mt792x_asar_dyn, nr_tbl),
+ MT792x_ASAR_MIN_DYN, MT792x_ASAR_MAX_DYN))
+ *used = 1;
+ else if (mt792x_asar_fits(t, len, sizeof(struct mt792x_asar_dyn_v2),
+ sizeof(struct mt792x_asar_dyn_limit_v2),
+ offsetof(struct mt792x_asar_dyn_v2, nr_tbl),
+ MT792x_ASAR_MIN_DYN, MT792x_ASAR_MAX_DYN))
+ *used = 2;
+ else
return -EINVAL;
- }
- tblcnt = (len - prelen) / sarlen;
- if (!enable ||
- tblcnt > MT792x_ASAR_MAX_DYN || tblcnt < MT792x_ASAR_MIN_DYN)
+ if (!t[offsetof(struct mt792x_asar_dyn, enable)])
return -EINVAL;
+ if (version && *used != version)
+ dev_info(dev->mt76.dev,
+ "MTDS is v%u, MTCL says v%u; using v%u\n",
+ *used, version, *used);
+
return 0;
}
/* MTGS : Geo SAR Power Table */
static int
-mt792x_asar_acpi_read_mtgs(struct mt792x_dev *dev, u8 **table, u8 version)
+mt792x_asar_acpi_read_mtgs(struct mt792x_dev *dev, u8 **table, u8 version,
+ u8 *used)
{
- int len, ret, sarlen, prelen, tblcnt;
+ int len, ret;
+ u8 *t;
ret = mt792x_acpi_read(dev, MT792x_ACPI_MTGS, table, &len);
if (ret)
return ret;
+ t = *table;
+
/* Table content validation */
- switch (version) {
- case 1:
- sarlen = sizeof(struct mt792x_asar_geo_limit);
- prelen = sizeof(struct mt792x_asar_geo);
- break;
- case 2:
- sarlen = sizeof(struct mt792x_asar_geo_limit_v2);
- prelen = sizeof(struct mt792x_asar_geo_v2);
- break;
- default:
+ if (mt792x_asar_fits(t, len, sizeof(struct mt792x_asar_geo),
+ sizeof(struct mt792x_asar_geo_limit),
+ offsetof(struct mt792x_asar_geo, nr_tbl),
+ MT792x_ASAR_MIN_GEO, MT792x_ASAR_MAX_GEO))
+ *used = 1;
+ else if (mt792x_asar_fits(t, len, sizeof(struct mt792x_asar_geo_v2),
+ sizeof(struct mt792x_asar_geo_limit_v2),
+ offsetof(struct mt792x_asar_geo_v2, nr_tbl),
+ MT792x_ASAR_MIN_GEO, MT792x_ASAR_MAX_GEO))
+ *used = 2;
+ else
return -EINVAL;
- }
- tblcnt = (len - prelen) / sarlen;
- if (tblcnt > MT792x_ASAR_MAX_GEO || tblcnt < MT792x_ASAR_MIN_GEO)
- return -EINVAL;
+ if (version && *used != version)
+ dev_info(dev->mt76.dev,
+ "MTGS is v%u, MTCL says v%u; using v%u\n",
+ *used, version, *used);
return 0;
}
@@ -205,14 +235,16 @@ int mt792x_init_acpi_sar(struct mt792x_dev *dev)
asar->countrylist = NULL;
}
- ret = mt792x_asar_acpi_read_mtds(dev, (u8 **)&asar->dyn, asar->ver);
+ ret = mt792x_asar_acpi_read_mtds(dev, (u8 **)&asar->dyn, asar->ver,
+ &asar->dyn_ver);
if (ret) {
devm_kfree(dev->mt76.dev, asar->dyn);
asar->dyn = NULL;
}
/* MTGS is optional */
- ret = mt792x_asar_acpi_read_mtgs(dev, (u8 **)&asar->geo, asar->ver);
+ ret = mt792x_asar_acpi_read_mtgs(dev, (u8 **)&asar->geo, asar->ver,
+ &asar->geo_ver);
if (ret) {
devm_kfree(dev->mt76.dev, asar->geo);
asar->geo = NULL;
@@ -254,7 +286,7 @@ mt792x_asar_get_geo_pwr(struct mt792x_phy *phy,
break;
}
- if (asar->ver == 1) {
+ if (asar->geo_ver == 1) {
band_pwr = &asar->geo->tbl[idx].band[0];
max = ARRAY_SIZE(asar->geo->tbl[idx].band);
} else {
@@ -279,10 +311,18 @@ mt792x_asar_get_geo_pwr(struct mt792x_phy *phy,
if (idx >= max)
return dyn_power;
- geo_power = (band_pwr + idx)->pwr;
- dyn_power += (band_pwr + idx)->offset;
+ band_pwr += idx;
+
+ /* Some OEM tables carry 0xff here; narrowed to s8 that is -1 and
+ * wins the min() below. Take it as no limit.
+ */
+ if (band_pwr->pwr == 0xff)
+ return dyn_power;
+
+ geo_power = band_pwr->pwr;
- return min(geo_power, dyn_power);
+ return min_t(int, geo_power,
+ min_t(int, dyn_power + band_pwr->offset, 127));
}
static s8
@@ -297,7 +337,7 @@ mt792x_asar_range_pwr(struct mt792x_phy *phy,
if (!capa)
return 127;
- if (asar->ver == 1) {
+ if (asar->dyn_ver == 1) {
limit = &asar->dyn->tbl[0].frp[0];
max = ARRAY_SIZE(asar->dyn->tbl[0].frp);
} else {
@@ -315,7 +355,9 @@ mt792x_asar_range_pwr(struct mt792x_phy *phy,
else
band = NL80211_BAND_2GHZ;
- return mt792x_asar_get_geo_pwr(phy, band, limit[idx]);
+ /* 0xff: no dynamic limit, see mt792x_asar_get_geo_pwr() */
+ return mt792x_asar_get_geo_pwr(phy, band,
+ limit[idx] == 0xff ? 127 : limit[idx]);
}
int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default)
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h
index 474033073831..1d42f24b05f6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h
@@ -105,6 +105,8 @@ struct mt792x_asar_fg {
struct mt792x_acpi_sar {
u8 ver;
+ u8 dyn_ver;
+ u8 geo_ver;
union {
struct mt792x_asar_dyn *dyn;
struct mt792x_asar_dyn_v2 *dyn_v2;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
index fb635a092584..c1d860029801 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
@@ -540,6 +540,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR);
ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
ieee80211_hw_set(hw, CHANCTX_STA_CSA);
+ ieee80211_hw_set(hw, CONNECTION_MONITOR);
hw->max_tx_fragments = 4;
wiphy->txq_memory_limit = 32 << 20; /* 32 MiB */
@@ -1247,7 +1248,7 @@ static int mt7996_variant_fem_init(struct mt7996_dev *dev)
adie_ver = u32_get_bits(regval, MT_ADIE_VERSION_MASK);
idx = MT7976C_EFUSE_OFFSET % MT7996_EEPROM_BLOCK_SIZE;
is_7976c = adie_ver == 0x8a10 || adie_ver == 0x8b00 ||
- adie_ver == 0x8c10 || buf[idx] == 0xc;
+ adie_ver == 0x8c10 || (!ret && buf[idx] == 0xc);
adie_id = u32_get_bits(regval, MT_ADIE_CHIP_ID_MASK);
if (adie_id == 0x7975 || adie_id == 0x7979 ||
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index e218856b0c45..dd7a01c02a7c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -310,7 +310,14 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
if (vif->type == NL80211_IFTYPE_AP)
return mt7996_mcu_mld_link_oper(dev, link_conf, link,
true);
- return 0;
+
+ /* update the link address */
+ ret = mt7996_mcu_add_dev_info(phy, vif, link_conf, mlink, true);
+ if (ret)
+ return ret;
+
+ return mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink,
+ msta_link, true);
}
mlink->idx = __ffs64(~dev->mt76.vif_mask);
@@ -1426,6 +1433,7 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif,
else if (sta->mlo && links == BIT(link_id)) /* last link */
mt7996_mcu_teardown_mld_sta(dev, link,
msta_link);
+ msta_link->wcid.tx_info &= ~MT_WCID_TX_INFO_SET;
msta_link->wcid.sta_disabled = 1;
msta_link->wcid.sta = 0;
links = links & ~BIT(link_id);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
index 74b70fb6da3d..1b272e904100 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
@@ -284,6 +284,9 @@ struct mt7996_mcu_wed_rro_ba_delete_event {
__le16 len;
__le16 session_id;
+ __le16 wlan_id;
+ u8 tid;
+ u8 __rsv1;
u8 __rsv2[2];
} __packed;
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 3707ee19e4ae..3c623df2e741 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -234,6 +234,8 @@ mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid,
if (!wcid || info->tx_time_est)
return;
+ wcid = mt76_wcid_primary(wcid);
+
pending = atomic_dec_return(&wcid->non_aql_packets);
if (pending < 0)
atomic_cmpxchg(&wcid->non_aql_packets, pending, 0);
@@ -344,7 +346,8 @@ __mt76_tx_queue_skb(struct mt76_phy *phy, int qid, struct sk_buff *skb,
if (!non_aql)
return idx;
- pending = atomic_inc_return(&wcid->non_aql_packets);
+ /* the hardware can report the completion on a different link */
+ pending = atomic_inc_return(&mt76_wcid_primary(wcid)->non_aql_packets);
if (stop && pending >= MT_MAX_NON_AQL_PKT)
*stop = true;
@@ -506,7 +509,8 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
return 0;
}
- if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT)
+ if (atomic_read(&mt76_wcid_primary(wcid)->non_aql_packets) >=
+ MT_MAX_NON_AQL_PKT)
return 0;
skb = mt76_txq_dequeue(phy, mtxq);
@@ -603,7 +607,8 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid)
continue;
}
- if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT)
+ if (atomic_read(&mt76_wcid_primary(wcid)->non_aql_packets) >=
+ MT_MAX_NON_AQL_PKT)
continue;
if (dev->queue_ops->tx_cleanup &&
q->queued + 2 * MT_TXQ_FREE_THR >= q->ndesc) {
@@ -675,7 +680,8 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid,
if ((dev->drv->drv_flags & MT_DRV_HW_MGMT_TXQ) &&
!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
!ieee80211_is_data_present(hdr->frame_control) &&
- (!ieee80211_is_bufferable_mmpdu(skb) ||
+ (!(wcid->tx_info & MT_WCID_TX_INFO_SET) ||
+ !ieee80211_is_bufferable_mmpdu(skb) ||
ieee80211_is_deauth(hdr->frame_control) ||
ieee80211_is_disassoc(hdr->frame_control) ||
head == &wcid->tx_offchannel))
diff --git a/drivers/net/wireless/nxp/nxpwifi/11n.c b/drivers/net/wireless/nxp/nxpwifi/11n.c
index c2a54d781b42..25b2e430f3f9 100644
--- a/drivers/net/wireless/nxp/nxpwifi/11n.c
+++ b/drivers/net/wireless/nxp/nxpwifi/11n.c
@@ -451,7 +451,7 @@ void
nxpwifi_11n_delete_tx_ba_stream_tbl_entry(struct nxpwifi_private *priv,
struct nxpwifi_tx_ba_stream_tbl *tbl)
{
- if (!tbl || nxpwifi_is_tx_ba_stream_ptr_valid(priv, tbl))
+ if (!tbl || !nxpwifi_is_tx_ba_stream_ptr_valid(priv, tbl))
return;
nxpwifi_dbg(priv->adapter, INFO,
diff --git a/drivers/net/wireless/nxp/nxpwifi/11n_aggr.c b/drivers/net/wireless/nxp/nxpwifi/11n_aggr.c
index be7080f2a6ce..54933c42c960 100644
--- a/drivers/net/wireless/nxp/nxpwifi/11n_aggr.c
+++ b/drivers/net/wireless/nxp/nxpwifi/11n_aggr.c
@@ -168,6 +168,7 @@ nxpwifi_11n_aggregate_pkt(struct nxpwifi_private *priv,
if (!nxpwifi_is_ralist_valid(priv, pra_list, ptrindex)) {
spin_unlock_bh(&priv->wmm.ra_list_spinlock);
+ nxpwifi_write_data_complete(adapter, skb_aggr, 1, -1);
return -ENOENT;
}
diff --git a/drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.c b/drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.c
index 65b628411543..87cf2ec85991 100644
--- a/drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.c
+++ b/drivers/net/wireless/nxp/nxpwifi/11n_rxreorder.c
@@ -205,11 +205,12 @@ void nxpwifi_11n_del_rx_reorder_tbl_by_ta(struct nxpwifi_private *priv, u8 *ta)
return;
for (i = 0; i < MAX_NUM_TID; i++) {
- guard(rcu)();
- list_for_each_entry_rcu(tbl, &priv->rx_reorder_tbl_ptr[i], list) {
- if (!memcmp(tbl->ta, ta, ETH_ALEN)) {
- INIT_LIST_HEAD(&tbl->tmp_list);
- list_add_tail(&tbl->tmp_list, &to_delete);
+ scoped_guard(rcu) {
+ list_for_each_entry_rcu(tbl, &priv->rx_reorder_tbl_ptr[i], list) {
+ if (!memcmp(tbl->ta, ta, ETH_ALEN)) {
+ INIT_LIST_HEAD(&tbl->tmp_list);
+ list_add_tail(&tbl->tmp_list, &to_delete);
+ }
}
}
diff --git a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c
index 86304ea3331c..473e81304ca8 100644
--- a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c
+++ b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c
@@ -1539,9 +1539,11 @@ nxpwifi_cfg80211_del_station(struct wiphy *wiphy, struct wireless_dev *wdev,
eth_zero_addr(deauth_mac);
+ rcu_read_lock();
sta_node = nxpwifi_get_sta_entry(priv, params->mac);
if (sta_node)
ether_addr_copy(deauth_mac, params->mac);
+ rcu_read_unlock();
if (is_valid_ether_addr(deauth_mac)) {
ret = nxpwifi_uap_sta_deauth(priv, deauth_mac);
@@ -3323,6 +3325,7 @@ nxpwifi_cfg80211_authenticate(struct wiphy *wiphy,
struct nxpwifi_adapter *adapter = priv->adapter;
struct sk_buff *skb;
u16 pkt_len, auth_alg;
+ size_t frame_len;
int ret;
struct ieee80211_mgmt *mgmt;
struct nxpwifi_txinfo *tx_info;
@@ -3396,13 +3399,25 @@ nxpwifi_cfg80211_authenticate(struct wiphy *wiphy,
nxpwifi_cancel_scan(adapter);
- pkt_len = (u16)req->ie_len + req->auth_data_len +
- NXPWIFI_MGMT_HEADER_LEN + NXPWIFI_AUTH_BODY_LEN;
+ frame_len = req->ie_len + req->auth_data_len +
+ sizeof(struct ieee80211_hdr_3addr) + NXPWIFI_AUTH_BODY_LEN;
if (req->auth_data_len >= 4)
- pkt_len -= 4;
+ frame_len -= 4;
+
+ /* nxpwifi_form_mgmt_frame() inserts address4, so the frame handed to
+ * the firmware is ETH_ALEN longer than the one built here.
+ */
+ if (frame_len > U16_MAX - ETH_ALEN) {
+ nxpwifi_dbg(adapter, ERROR,
+ "auth frame too long: %zu bytes\n", frame_len);
+ return -EINVAL;
+ }
+ pkt_len = frame_len + ETH_ALEN;
- mgmt = kzalloc(pkt_len, GFP_KERNEL);
+ mgmt = kzalloc(frame_len, GFP_KERNEL);
+ if (!mgmt)
+ return -ENOMEM;
skb = dev_alloc_skb(NXPWIFI_MIN_DATA_HEADER_LEN +
NXPWIFI_MGMT_FRAME_HEADER_SIZE +
@@ -3410,6 +3425,7 @@ nxpwifi_cfg80211_authenticate(struct wiphy *wiphy,
if (!skb) {
nxpwifi_dbg(adapter, ERROR,
"allocate skb failed for management frame\n");
+ kfree(mgmt);
return -ENOMEM;
}
@@ -3448,7 +3464,7 @@ nxpwifi_cfg80211_authenticate(struct wiphy *wiphy,
memcpy((u8 *)varptr, req->ie, req->ie_len);
}
- nxpwifi_form_mgmt_frame(skb, (const u8 *)mgmt, pkt_len);
+ nxpwifi_form_mgmt_frame(skb, (const u8 *)mgmt, frame_len);
kfree(mgmt);
priv->auth_flag = HOST_MLME_AUTH_PENDING;
priv->auth_alg = auth_alg;
@@ -3729,8 +3745,9 @@ int nxpwifi_init_channel_scan_gap(struct nxpwifi_adapter *adapter)
* additional active scan request for hidden SSIDs on passive channels.
*/
adapter->num_in_chan_stats = 2 * (n_channels_bg + n_channels_a);
- adapter->chan_stats = vmalloc(array_size(sizeof(*adapter->chan_stats),
- adapter->num_in_chan_stats));
+ adapter->chan_stats = kcalloc(adapter->num_in_chan_stats,
+ sizeof(*adapter->chan_stats),
+ GFP_KERNEL);
if (!adapter->chan_stats)
return -ENOMEM;
diff --git a/drivers/net/wireless/nxp/nxpwifi/init.c b/drivers/net/wireless/nxp/nxpwifi/init.c
index 7c75dca5d0a8..3c4df37333d8 100644
--- a/drivers/net/wireless/nxp/nxpwifi/init.c
+++ b/drivers/net/wireless/nxp/nxpwifi/init.c
@@ -328,7 +328,7 @@ static void nxpwifi_invalidate_lists(struct nxpwifi_adapter *adapter)
static void
nxpwifi_adapter_cleanup(struct nxpwifi_adapter *adapter)
{
- timer_delete(&adapter->wakeup_timer);
+ timer_delete_sync(&adapter->wakeup_timer);
nxpwifi_cancel_all_pending_cmd(adapter);
wake_up_interruptible(&adapter->cmd_wait_q.wait);
wake_up_interruptible(&adapter->hs_activate_wait_q);
diff --git a/drivers/net/wireless/nxp/nxpwifi/main.c b/drivers/net/wireless/nxp/nxpwifi/main.c
index 55b962430f37..9e13348105c3 100644
--- a/drivers/net/wireless/nxp/nxpwifi/main.c
+++ b/drivers/net/wireless/nxp/nxpwifi/main.c
@@ -644,7 +644,7 @@ static int _nxpwifi_fw_dpc(const struct firmware *firmware, void *context)
goto done;
err_add_intf:
- vfree(adapter->chan_stats);
+ kfree(adapter->chan_stats);
err_init_chan_scan:
wiphy_unregister(adapter->wiphy);
wiphy_free(adapter->wiphy);
@@ -1384,7 +1384,7 @@ static void nxpwifi_uninit_sw(struct nxpwifi_adapter *adapter)
wiphy_free(adapter->wiphy);
adapter->wiphy = NULL;
- vfree(adapter->chan_stats);
+ kfree(adapter->chan_stats);
nxpwifi_free_cmd_buffers(adapter);
}
diff --git a/drivers/net/wireless/nxp/nxpwifi/uap_event.c b/drivers/net/wireless/nxp/nxpwifi/uap_event.c
index ab5c15686f54..20b7b53db236 100644
--- a/drivers/net/wireless/nxp/nxpwifi/uap_event.c
+++ b/drivers/net/wireless/nxp/nxpwifi/uap_event.c
@@ -75,6 +75,7 @@ nxpwifi_uap_event_sta_deauth(struct nxpwifi_private *priv)
nxpwifi_del_tx_ba_stream_tbl_by_ra(priv, deauth_mac);
}
nxpwifi_wmm_del_peer_ra_list(priv, deauth_mac);
+ nxpwifi_del_sta_entry(priv, deauth_mac);
return 0;
}
diff --git a/drivers/net/wireless/nxp/nxpwifi/util.c b/drivers/net/wireless/nxp/nxpwifi/util.c
index bbfefb81d8d3..ae8444a14105 100644
--- a/drivers/net/wireless/nxp/nxpwifi/util.c
+++ b/drivers/net/wireless/nxp/nxpwifi/util.c
@@ -1041,19 +1041,23 @@ nxpwifi_set_sta_ht_cap(struct nxpwifi_private *priv, const u8 *ies,
}
}
-/* Delete a station from list; called under cfg80211 mutex. */
+/* Delete a station from list. */
void nxpwifi_del_sta_entry(struct nxpwifi_private *priv, const u8 *mac)
{
struct nxpwifi_sta_node *node;
- list_for_each_entry_rcu(node, &priv->sta_list, list) {
+ spin_lock_bh(&priv->sta_list_spinlock);
+
+ list_for_each_entry(node, &priv->sta_list, list) {
if (!memcmp(node->mac_addr, mac, ETH_ALEN)) {
list_del_rcu(&node->list);
kfree_rcu(node, rcu);
break;
}
}
+
+ spin_unlock_bh(&priv->sta_list_spinlock);
}
/* Delete all stations from list. */
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 2ed673649c48..fdcb91042f29 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1234,8 +1234,16 @@ static int handle_incoming_queue(struct netfront_queue *queue,
while ((skb = __skb_dequeue(rxq)) != NULL) {
int pull_to = NETFRONT_SKB_CB(skb)->pull_to;
- if (pull_to > skb_headlen(skb))
- __pskb_pull_tail(skb, pull_to - skb_headlen(skb));
+ /* pull_to comes from the first slot's length, which the
+ * backend controls. Make sure the head holds at least an
+ * Ethernet header for eth_type_trans().
+ */
+ if (!pskb_may_pull(skb, max(pull_to, ETH_HLEN))) {
+ kfree_skb(skb);
+ packets_dropped++;
+ queue->info->netdev->stats.rx_errors++;
+ continue;
+ }
/* Ethernet work: Delayed to here as it peeks the header. */
skb->protocol = eth_type_trans(skb, queue->info->netdev);
@@ -1338,8 +1346,10 @@ err:
skb->data_len = rx->status;
skb->len += rx->status;
- if (unlikely(xennet_fill_frags(queue, skb, &tmpq)))
+ if (unlikely(xennet_fill_frags(queue, skb, &tmpq))) {
+ __skb_queue_head(&tmpq, skb);
goto err;
+ }
if (rx->flags & XEN_NETRXF_csum_blank)
skb->ip_summed = CHECKSUM_PARTIAL;
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index d8dcd238fda1..922a726a52a5 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -1360,8 +1360,10 @@ static DEFINE_KFIFO(aer_recover_ring, struct aer_recover_entry,
static void aer_recover_work_func(struct work_struct *work)
{
+ struct aer_capability_regs *regs;
struct aer_recover_entry entry;
struct pci_dev *pdev;
+ u32 err;
while (kfifo_get(&aer_recover_ring, &entry)) {
pdev = pci_get_domain_bus_and_slot(entry.domain, entry.bus,
@@ -1375,6 +1377,12 @@ static void aer_recover_work_func(struct work_struct *work)
}
pci_print_aer(pdev, entry.severity, entry.regs);
+ regs = entry.regs;
+ if (entry.severity == AER_CORRECTABLE)
+ err = regs->cor_status & ~regs->cor_mask;
+ else
+ err = regs->uncor_status & ~regs->uncor_mask;
+
/*
* Memory for aer_capability_regs(entry.regs) is being
* allocated from the ghes_estatus_pool to protect it from
@@ -1385,12 +1393,14 @@ static void aer_recover_work_func(struct work_struct *work)
ghes_estatus_pool_region_free((unsigned long)entry.regs,
sizeof(struct aer_capability_regs));
- if (entry.severity == AER_NONFATAL)
- pcie_do_recovery(pdev, pci_channel_io_normal,
- aer_root_reset);
- else if (entry.severity == AER_FATAL)
- pcie_do_recovery(pdev, pci_channel_io_frozen,
- aer_root_reset);
+ if (err) {
+ if (entry.severity == AER_NONFATAL)
+ pcie_do_recovery(pdev, pci_channel_io_normal,
+ aer_root_reset);
+ else if (entry.severity == AER_FATAL)
+ pcie_do_recovery(pdev, pci_channel_io_frozen,
+ aer_root_reset);
+ }
pci_dev_put(pdev);
}
}
diff --git a/drivers/pmdomain/imx/imx8m-blk-ctrl.c b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
index 479789009c7f..f8105e87ea3c 100644
--- a/drivers/pmdomain/imx/imx8m-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
@@ -15,6 +15,7 @@
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/clk.h>
+#include <linux/mutex.h>
#include <dt-bindings/power/imx8mm-power.h>
#include <dt-bindings/power/imx8mn-power.h>
@@ -34,6 +35,12 @@ struct imx8m_blk_ctrl {
struct regmap *regmap;
struct imx8m_blk_ctrl_domain *domains;
struct genpd_onecell_data onecell_data;
+ /*
+ * Serializes the blk-ctrl reset/clock sequence across sibling domains;
+ * their transitions interact through the shared VPUMIX bus domain,
+ * VPU_NOC and the not-ack-verified ADB400 handshake (ERR050531).
+ */
+ struct mutex power_lock;
};
struct imx8m_blk_ctrl_domain_data {
@@ -98,6 +105,8 @@ static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd)
struct imx8m_blk_ctrl *bc = domain->bc;
int ret;
+ guard(mutex)(&bc->power_lock);
+
/* make sure bus domain is awake */
ret = pm_runtime_get_sync(bc->bus_power_dev);
if (ret < 0) {
@@ -164,6 +173,8 @@ static int imx8m_blk_ctrl_power_off(struct generic_pm_domain *genpd)
const struct imx8m_blk_ctrl_domain_data *data = domain->data;
struct imx8m_blk_ctrl *bc = domain->bc;
+ guard(mutex)(&bc->power_lock);
+
/* put devices into reset and disable clocks */
if (data->mipi_phy_rst_mask)
regmap_clear_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
@@ -202,6 +213,10 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
bc->dev = dev;
+ ret = devm_mutex_init(dev, &bc->power_lock);
+ if (ret)
+ return ret;
+
bc_data = of_device_get_match_data(dev);
base = devm_platform_ioremap_resource(pdev, 0);
diff --git a/drivers/pmdomain/rockchip/pm-domains.c b/drivers/pmdomain/rockchip/pm-domains.c
index ba66ae719428..e193f978d5f3 100644
--- a/drivers/pmdomain/rockchip/pm-domains.c
+++ b/drivers/pmdomain/rockchip/pm-domains.c
@@ -759,7 +759,19 @@ static int rockchip_pd_attach_dev(struct generic_pm_domain *genpd,
}
i = 0;
- while ((clk = of_clk_get(dev->of_node, i++)) && !IS_ERR(clk)) {
+ while (1) {
+ clk = of_clk_get(dev->of_node, i++);
+ if (IS_ERR(clk)) {
+ error = PTR_ERR(clk);
+ if (error == -ENOENT)
+ break;
+
+ dev_err(dev, "failed to get clock %d: %d\n", i - 1,
+ error);
+ pm_clk_destroy(dev);
+ return error;
+ }
+
dev_dbg(dev, "adding clock '%pC' to list of PM clocks\n", clk);
error = pm_clk_add_clk(dev, clk);
if (error) {
@@ -842,7 +854,7 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
dev_err(pmu->dev,
"%pOFn: failed to get clk at index %d: %d\n",
node, i, error);
- return error;
+ goto err_put_clocks;
}
}
@@ -1018,7 +1030,9 @@ static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu,
parent_domain->name, child_domain->name);
}
- rockchip_pm_add_subdomain(pmu, np);
+ error = rockchip_pm_add_subdomain(pmu, np);
+ if (error)
+ return error;
}
return 0;
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 3d26ec1f7b9e..a8cba2f64b98 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -1825,7 +1825,7 @@ ptp_ocp_watchdog(struct timer_list *t)
static void
ptp_ocp_estimate_pci_timing(struct ptp_ocp *bp)
{
- ktime_t start, end, delay = U64_MAX;
+ ktime_t start, end, delay = KTIME_MAX;
u32 ctrl;
int i;