diff options
Diffstat (limited to 'drivers')
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; |
