diff options
Diffstat (limited to 'drivers')
519 files changed, 8334 insertions, 4874 deletions
diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 231f29bb5025..6a320a73e3cc 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -8,7 +8,6 @@ #include <linux/pci.h> #include <drm/drm_accel.h> -#include <drm/drm_drv.h> #include <drm/drm_file.h> #include <drm/drm_gem.h> #include <drm/drm_ioctl.h> @@ -118,6 +117,10 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f struct pci_dev *pdev = to_pci_dev(vdev->drm.dev); struct drm_ivpu_param *args = data; int ret = 0; + int idx; + + if (!drm_dev_enter(dev, &idx)) + return -ENODEV; switch (args->param) { case DRM_IVPU_PARAM_DEVICE_ID: @@ -171,6 +174,7 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f break; } + drm_dev_exit(idx); return ret; } @@ -470,8 +474,8 @@ static int ivpu_dev_init(struct ivpu_device *vdev) vdev->hw->ops = &ivpu_hw_mtl_ops; vdev->platform = IVPU_PLATFORM_INVALID; - vdev->context_xa_limit.min = IVPU_GLOBAL_CONTEXT_MMU_SSID + 1; - vdev->context_xa_limit.max = IVPU_CONTEXT_LIMIT; + vdev->context_xa_limit.min = IVPU_USER_CONTEXT_MIN_SSID; + vdev->context_xa_limit.max = IVPU_USER_CONTEXT_MAX_SSID; atomic64_set(&vdev->unique_id_counter, 0); xa_init_flags(&vdev->context_xa, XA_FLAGS_ALLOC); xa_init_flags(&vdev->submitted_jobs_xa, XA_FLAGS_ALLOC1); @@ -565,6 +569,8 @@ err_mmu_gctx_fini: ivpu_mmu_global_context_fini(vdev); err_power_down: ivpu_hw_power_down(vdev); + if (IVPU_WA(d3hot_after_power_off)) + pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D3hot); err_xa_destroy: xa_destroy(&vdev->submitted_jobs_xa); xa_destroy(&vdev->context_xa); @@ -575,7 +581,11 @@ static void ivpu_dev_fini(struct ivpu_device *vdev) { ivpu_pm_disable(vdev); ivpu_shutdown(vdev); + if (IVPU_WA(d3hot_after_power_off)) + pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D3hot); ivpu_job_done_thread_fini(vdev); + ivpu_pm_cancel_recovery(vdev); + ivpu_ipc_fini(vdev); ivpu_fw_fini(vdev); ivpu_mmu_global_context_fini(vdev); @@ -622,7 +632,7 @@ static void ivpu_remove(struct pci_dev *pdev) { struct ivpu_device *vdev = pci_get_drvdata(pdev); - drm_dev_unregister(&vdev->drm); + drm_dev_unplug(&vdev->drm); ivpu_dev_fini(vdev); } diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index f47b4965db2e..d3013fbd13b3 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -7,6 +7,7 @@ #define __IVPU_DRV_H__ #include <drm/drm_device.h> +#include <drm/drm_drv.h> #include <drm/drm_managed.h> #include <drm/drm_mm.h> #include <drm/drm_print.h> @@ -24,7 +25,10 @@ #define PCI_DEVICE_ID_MTL 0x7d1d #define IVPU_GLOBAL_CONTEXT_MMU_SSID 0 -#define IVPU_CONTEXT_LIMIT 64 +/* SSID 1 is used by the VPU to represent invalid context */ +#define IVPU_USER_CONTEXT_MIN_SSID 2 +#define IVPU_USER_CONTEXT_MAX_SSID (IVPU_USER_CONTEXT_MIN_SSID + 63) + #define IVPU_NUM_ENGINES 2 #define IVPU_PLATFORM_SILICON 0 @@ -70,6 +74,7 @@ struct ivpu_wa_table { bool punit_disabled; bool clear_runtime_mem; + bool d3hot_after_power_off; }; struct ivpu_hw_info; diff --git a/drivers/accel/ivpu/ivpu_hw_mtl.c b/drivers/accel/ivpu/ivpu_hw_mtl.c index 62bfaa9081c4..382ec127be8e 100644 --- a/drivers/accel/ivpu/ivpu_hw_mtl.c +++ b/drivers/accel/ivpu/ivpu_hw_mtl.c @@ -12,24 +12,23 @@ #include "ivpu_mmu.h" #include "ivpu_pm.h" -#define TILE_FUSE_ENABLE_BOTH 0x0 -#define TILE_FUSE_ENABLE_UPPER 0x1 -#define TILE_FUSE_ENABLE_LOWER 0x2 - -#define TILE_SKU_BOTH_MTL 0x3630 -#define TILE_SKU_LOWER_MTL 0x3631 -#define TILE_SKU_UPPER_MTL 0x3632 +#define TILE_FUSE_ENABLE_BOTH 0x0 +#define TILE_SKU_BOTH_MTL 0x3630 /* Work point configuration values */ -#define WP_CONFIG_1_TILE_5_3_RATIO 0x0101 -#define WP_CONFIG_1_TILE_4_3_RATIO 0x0102 -#define WP_CONFIG_2_TILE_5_3_RATIO 0x0201 -#define WP_CONFIG_2_TILE_4_3_RATIO 0x0202 -#define WP_CONFIG_0_TILE_PLL_OFF 0x0000 +#define CONFIG_1_TILE 0x01 +#define CONFIG_2_TILE 0x02 +#define PLL_RATIO_5_3 0x01 +#define PLL_RATIO_4_3 0x02 +#define WP_CONFIG(tile, ratio) (((tile) << 8) | (ratio)) +#define WP_CONFIG_1_TILE_5_3_RATIO WP_CONFIG(CONFIG_1_TILE, PLL_RATIO_5_3) +#define WP_CONFIG_1_TILE_4_3_RATIO WP_CONFIG(CONFIG_1_TILE, PLL_RATIO_4_3) +#define WP_CONFIG_2_TILE_5_3_RATIO WP_CONFIG(CONFIG_2_TILE, PLL_RATIO_5_3) +#define WP_CONFIG_2_TILE_4_3_RATIO WP_CONFIG(CONFIG_2_TILE, PLL_RATIO_4_3) +#define WP_CONFIG_0_TILE_PLL_OFF WP_CONFIG(0, 0) #define PLL_REF_CLK_FREQ (50 * 1000000) #define PLL_SIMULATION_FREQ (10 * 1000000) -#define PLL_RATIO_TO_FREQ(x) ((x) * PLL_REF_CLK_FREQ) #define PLL_DEFAULT_EPP_VALUE 0x80 #define TIM_SAFE_ENABLE 0xf1d0dead @@ -101,6 +100,7 @@ static void ivpu_hw_wa_init(struct ivpu_device *vdev) { vdev->wa.punit_disabled = ivpu_is_fpga(vdev); vdev->wa.clear_runtime_mem = false; + vdev->wa.d3hot_after_power_off = true; } static void ivpu_hw_timeouts_init(struct ivpu_device *vdev) @@ -218,7 +218,8 @@ static int ivpu_pll_drive(struct ivpu_device *vdev, bool enable) config = 0; } - ivpu_dbg(vdev, PM, "PLL workpoint request: %d Hz\n", PLL_RATIO_TO_FREQ(target_ratio)); + ivpu_dbg(vdev, PM, "PLL workpoint request: config 0x%04x pll ratio 0x%x\n", + config, target_ratio); ret = ivpu_pll_cmd_send(vdev, hw->pll.min_ratio, hw->pll.max_ratio, target_ratio, config); if (ret) { @@ -403,11 +404,6 @@ static int ivpu_boot_host_ss_axi_enable(struct ivpu_device *vdev) return ivpu_boot_host_ss_axi_drive(vdev, true); } -static int ivpu_boot_host_ss_axi_disable(struct ivpu_device *vdev) -{ - return ivpu_boot_host_ss_axi_drive(vdev, false); -} - static int ivpu_boot_host_ss_top_noc_drive(struct ivpu_device *vdev, bool enable) { int ret; @@ -441,11 +437,6 @@ static int ivpu_boot_host_ss_top_noc_enable(struct ivpu_device *vdev) return ivpu_boot_host_ss_top_noc_drive(vdev, true); } -static int ivpu_boot_host_ss_top_noc_disable(struct ivpu_device *vdev) -{ - return ivpu_boot_host_ss_top_noc_drive(vdev, false); -} - static void ivpu_boot_pwr_island_trickle_drive(struct ivpu_device *vdev, bool enable) { u32 val = REGV_RD32(MTL_VPU_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0); @@ -504,16 +495,6 @@ static void ivpu_boot_dpu_active_drive(struct ivpu_device *vdev, bool enable) REGV_WR32(MTL_VPU_HOST_SS_AON_DPU_ACTIVE, val); } -static int ivpu_boot_pwr_domain_disable(struct ivpu_device *vdev) -{ - ivpu_boot_dpu_active_drive(vdev, false); - ivpu_boot_pwr_island_isolation_drive(vdev, true); - ivpu_boot_pwr_island_trickle_drive(vdev, false); - ivpu_boot_pwr_island_drive(vdev, false); - - return ivpu_boot_wait_for_pwr_island_status(vdev, 0x0); -} - static int ivpu_boot_pwr_domain_enable(struct ivpu_device *vdev) { int ret; @@ -629,34 +610,10 @@ static int ivpu_boot_d0i3_drive(struct ivpu_device *vdev, bool enable) static int ivpu_hw_mtl_info_init(struct ivpu_device *vdev) { struct ivpu_hw_info *hw = vdev->hw; - u32 tile_fuse; - - tile_fuse = REGB_RD32(MTL_BUTTRESS_TILE_FUSE); - if (!REG_TEST_FLD(MTL_BUTTRESS_TILE_FUSE, VALID, tile_fuse)) - ivpu_warn(vdev, "Tile Fuse: Invalid (0x%x)\n", tile_fuse); - - hw->tile_fuse = REG_GET_FLD(MTL_BUTTRESS_TILE_FUSE, SKU, tile_fuse); - switch (hw->tile_fuse) { - case TILE_FUSE_ENABLE_LOWER: - hw->sku = TILE_SKU_LOWER_MTL; - hw->config = WP_CONFIG_1_TILE_5_3_RATIO; - ivpu_dbg(vdev, MISC, "Tile Fuse: Enable Lower\n"); - break; - case TILE_FUSE_ENABLE_UPPER: - hw->sku = TILE_SKU_UPPER_MTL; - hw->config = WP_CONFIG_1_TILE_4_3_RATIO; - ivpu_dbg(vdev, MISC, "Tile Fuse: Enable Upper\n"); - break; - case TILE_FUSE_ENABLE_BOTH: - hw->sku = TILE_SKU_BOTH_MTL; - hw->config = WP_CONFIG_2_TILE_5_3_RATIO; - ivpu_dbg(vdev, MISC, "Tile Fuse: Enable Both\n"); - break; - default: - hw->config = WP_CONFIG_0_TILE_PLL_OFF; - ivpu_dbg(vdev, MISC, "Tile Fuse: Disable\n"); - break; - } + + hw->tile_fuse = TILE_FUSE_ENABLE_BOTH; + hw->sku = TILE_SKU_BOTH_MTL; + hw->config = WP_CONFIG_2_TILE_4_3_RATIO; ivpu_pll_init_frequency_ratios(vdev); @@ -797,21 +754,8 @@ static int ivpu_hw_mtl_power_down(struct ivpu_device *vdev) { int ret = 0; - /* FPGA requires manual clearing of IP_Reset bit by enabling quiescent state */ - if (ivpu_is_fpga(vdev)) { - if (ivpu_boot_host_ss_top_noc_disable(vdev)) { - ivpu_err(vdev, "Failed to disable TOP NOC\n"); - ret = -EIO; - } - - if (ivpu_boot_host_ss_axi_disable(vdev)) { - ivpu_err(vdev, "Failed to disable AXI\n"); - ret = -EIO; - } - } - - if (ivpu_boot_pwr_domain_disable(vdev)) { - ivpu_err(vdev, "Failed to disable power domain\n"); + if (ivpu_hw_mtl_reset(vdev)) { + ivpu_err(vdev, "Failed to reset the VPU\n"); ret = -EIO; } @@ -844,6 +788,19 @@ static void ivpu_hw_mtl_wdt_disable(struct ivpu_device *vdev) REGV_WR32(MTL_VPU_CPU_SS_TIM_GEN_CONFIG, val); } +static u32 ivpu_hw_mtl_pll_to_freq(u32 ratio, u32 config) +{ + u32 pll_clock = PLL_REF_CLK_FREQ * ratio; + u32 cpu_clock; + + if ((config & 0xff) == PLL_RATIO_4_3) + cpu_clock = pll_clock * 2 / 4; + else + cpu_clock = pll_clock * 2 / 5; + + return cpu_clock; +} + /* Register indirect accesses */ static u32 ivpu_hw_mtl_reg_pll_freq_get(struct ivpu_device *vdev) { @@ -855,7 +812,7 @@ static u32 ivpu_hw_mtl_reg_pll_freq_get(struct ivpu_device *vdev) if (!ivpu_is_silicon(vdev)) return PLL_SIMULATION_FREQ; - return PLL_RATIO_TO_FREQ(pll_curr_ratio); + return ivpu_hw_mtl_pll_to_freq(pll_curr_ratio, vdev->hw->config); } static u32 ivpu_hw_mtl_reg_telemetry_offset_get(struct ivpu_device *vdev) diff --git a/drivers/accel/ivpu/ivpu_ipc.h b/drivers/accel/ivpu/ivpu_ipc.h index 9838202ecfad..68f5b6668e00 100644 --- a/drivers/accel/ivpu/ivpu_ipc.h +++ b/drivers/accel/ivpu/ivpu_ipc.h @@ -21,7 +21,7 @@ struct ivpu_bo; #define IVPU_IPC_ALIGNMENT 64 #define IVPU_IPC_HDR_FREE 0 -#define IVPU_IPC_HDR_ALLOCATED 0 +#define IVPU_IPC_HDR_ALLOCATED 1 /** * struct ivpu_ipc_hdr - The IPC message header structure, exchanged diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index 94068aedf97c..3c6f1e16cf2f 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -461,26 +461,22 @@ ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32 job->cmd_buf_vpu_addr = bo->vpu_addr + commands_offset; - ret = drm_gem_lock_reservations((struct drm_gem_object **)job->bos, buf_count, - &acquire_ctx); + ret = drm_gem_lock_reservations((struct drm_gem_object **)job->bos, 1, &acquire_ctx); if (ret) { ivpu_warn(vdev, "Failed to lock reservations: %d\n", ret); return ret; } - for (i = 0; i < buf_count; i++) { - ret = dma_resv_reserve_fences(job->bos[i]->base.resv, 1); - if (ret) { - ivpu_warn(vdev, "Failed to reserve fences: %d\n", ret); - goto unlock_reservations; - } + ret = dma_resv_reserve_fences(bo->base.resv, 1); + if (ret) { + ivpu_warn(vdev, "Failed to reserve fences: %d\n", ret); + goto unlock_reservations; } - for (i = 0; i < buf_count; i++) - dma_resv_add_fence(job->bos[i]->base.resv, job->done_fence, DMA_RESV_USAGE_WRITE); + dma_resv_add_fence(bo->base.resv, job->done_fence, DMA_RESV_USAGE_WRITE); unlock_reservations: - drm_gem_unlock_reservations((struct drm_gem_object **)job->bos, buf_count, &acquire_ctx); + drm_gem_unlock_reservations((struct drm_gem_object **)job->bos, 1, &acquire_ctx); wmb(); /* Flush write combining buffers */ @@ -489,12 +485,12 @@ unlock_reservations: int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { - int ret = 0; struct ivpu_file_priv *file_priv = file->driver_priv; struct ivpu_device *vdev = file_priv->vdev; struct drm_ivpu_submit *params = data; struct ivpu_job *job; u32 *buf_handles; + int idx, ret; if (params->engine > DRM_IVPU_ENGINE_COPY) return -EINVAL; @@ -523,6 +519,11 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file) goto free_handles; } + if (!drm_dev_enter(&vdev->drm, &idx)) { + ret = -ENODEV; + goto free_handles; + } + ivpu_dbg(vdev, JOB, "Submit ioctl: ctx %u buf_count %u\n", file_priv->ctx.id, params->buffer_count); @@ -530,7 +531,7 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file) if (!job) { ivpu_err(vdev, "Failed to create job\n"); ret = -ENOMEM; - goto free_handles; + goto dev_exit; } ret = ivpu_job_prepare_bos_for_submit(file, job, buf_handles, params->buffer_count, @@ -548,6 +549,8 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file) job_put: job_put(job); +dev_exit: + drm_dev_exit(idx); free_handles: kfree(buf_handles); diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index 553bcbd787b3..bde42d6383da 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -98,12 +98,18 @@ retry: static void ivpu_pm_recovery_work(struct work_struct *work) { struct ivpu_pm_info *pm = container_of(work, struct ivpu_pm_info, recovery_work); - struct ivpu_device *vdev = pm->vdev; + struct ivpu_device *vdev = pm->vdev; char *evt[2] = {"IVPU_PM_EVENT=IVPU_RECOVER", NULL}; int ret; - ret = pci_reset_function(to_pci_dev(vdev->drm.dev)); - if (ret) +retry: + ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev)); + if (ret == -EAGAIN && !drm_dev_is_unplugged(&vdev->drm)) { + cond_resched(); + goto retry; + } + + if (ret && ret != -EAGAIN) ivpu_err(vdev, "Failed to reset VPU: %d\n", ret); kobject_uevent_env(&vdev->drm.dev->kobj, KOBJ_CHANGE, evt); @@ -134,32 +140,28 @@ int ivpu_pm_suspend_cb(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); struct ivpu_device *vdev = to_ivpu_device(drm); - int ret; + unsigned long timeout; ivpu_dbg(vdev, PM, "Suspend..\n"); - ret = ivpu_suspend(vdev); - if (ret && vdev->pm->suspend_reschedule_counter) { - ivpu_dbg(vdev, PM, "Failed to enter idle, rescheduling suspend, retries left %d\n", - vdev->pm->suspend_reschedule_counter); - pm_schedule_suspend(dev, vdev->timeout.reschedule_suspend); - vdev->pm->suspend_reschedule_counter--; - return -EBUSY; - } else if (!vdev->pm->suspend_reschedule_counter) { - ivpu_warn(vdev, "Failed to enter idle, force suspend\n"); - ivpu_pm_prepare_cold_boot(vdev); - } else { - ivpu_pm_prepare_warm_boot(vdev); + timeout = jiffies + msecs_to_jiffies(vdev->timeout.tdr); + while (!ivpu_hw_is_idle(vdev)) { + cond_resched(); + if (time_after_eq(jiffies, timeout)) { + ivpu_err(vdev, "Failed to enter idle on system suspend\n"); + return -EBUSY; + } } - vdev->pm->suspend_reschedule_counter = PM_RESCHEDULE_LIMIT; + ivpu_suspend(vdev); + ivpu_pm_prepare_warm_boot(vdev); pci_save_state(to_pci_dev(dev)); pci_set_power_state(to_pci_dev(dev), PCI_D3hot); ivpu_dbg(vdev, PM, "Suspend done.\n"); - return ret; + return 0; } int ivpu_pm_resume_cb(struct device *dev) @@ -306,6 +308,11 @@ int ivpu_pm_init(struct ivpu_device *vdev) return 0; } +void ivpu_pm_cancel_recovery(struct ivpu_device *vdev) +{ + cancel_work_sync(&vdev->pm->recovery_work); +} + void ivpu_pm_enable(struct ivpu_device *vdev) { struct device *dev = vdev->drm.dev; diff --git a/drivers/accel/ivpu/ivpu_pm.h b/drivers/accel/ivpu/ivpu_pm.h index dc1b3758e13f..baca98187255 100644 --- a/drivers/accel/ivpu/ivpu_pm.h +++ b/drivers/accel/ivpu/ivpu_pm.h @@ -21,6 +21,7 @@ struct ivpu_pm_info { int ivpu_pm_init(struct ivpu_device *vdev); void ivpu_pm_enable(struct ivpu_device *vdev); void ivpu_pm_disable(struct ivpu_device *vdev); +void ivpu_pm_cancel_recovery(struct ivpu_device *vdev); int ivpu_pm_suspend_cb(struct device *dev); int ivpu_pm_resume_cb(struct device *dev); diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 97b711e57bff..c7a6d0b69dab 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -1984,6 +1984,7 @@ static int instance; static int acpi_video_bus_add(struct acpi_device *device) { struct acpi_video_bus *video; + bool auto_detect; int error; acpi_status status; @@ -2045,10 +2046,20 @@ static int acpi_video_bus_add(struct acpi_device *device) mutex_unlock(&video_list_lock); /* - * The userspace visible backlight_device gets registered separately - * from acpi_video_register_backlight(). + * If backlight-type auto-detection is used then a native backlight may + * show up later and this may change the result from video to native. + * Therefor normally the userspace visible /sys/class/backlight device + * gets registered separately by the GPU driver calling + * acpi_video_register_backlight() when an internal panel is detected. + * Register the backlight now when not using auto-detection, so that + * when the kernel cmdline or DMI-quirks are used the backlight will + * get registered even if acpi_video_register_backlight() is not called. */ acpi_video_run_bcl_for_osi(video); + if (__acpi_video_get_backlight_type(false, &auto_detect) == acpi_backlight_video && + !auto_detect) + acpi_video_bus_register_backlight(video); + acpi_video_bus_add_notify_handler(video); return 0; diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c index 82d1728b9bc6..df596d46dd97 100644 --- a/drivers/acpi/acpica/evevent.c +++ b/drivers/acpi/acpica/evevent.c @@ -142,9 +142,6 @@ static acpi_status acpi_ev_fixed_event_initialize(void) status = acpi_write_bit_register(acpi_gbl_fixed_event_info [i].enable_register_id, - (i == - ACPI_EVENT_PCIE_WAKE) ? - ACPI_ENABLE_EVENT : ACPI_DISABLE_EVENT); if (ACPI_FAILURE(status)) { return (status); @@ -188,11 +185,6 @@ u32 acpi_ev_fixed_event_detect(void) return (int_status); } - if (fixed_enable & ACPI_BITMASK_PCIEXP_WAKE_DISABLE) - fixed_enable &= ~ACPI_BITMASK_PCIEXP_WAKE_DISABLE; - else - fixed_enable |= ACPI_BITMASK_PCIEXP_WAKE_DISABLE; - ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, "Fixed Event Block: Enable %08X Status %08X\n", fixed_enable, fixed_status)); @@ -258,9 +250,6 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event) if (!acpi_gbl_fixed_event_handlers[event].handler) { (void)acpi_write_bit_register(acpi_gbl_fixed_event_info[event]. enable_register_id, - (event == - ACPI_EVENT_PCIE_WAKE) ? - ACPI_ENABLE_EVENT : ACPI_DISABLE_EVENT); ACPI_ERROR((AE_INFO, diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index 37b3f641feaa..bd936476dda9 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -311,20 +311,6 @@ acpi_status acpi_hw_legacy_wake(u8 sleep_state) [ACPI_EVENT_SLEEP_BUTTON]. status_register_id, ACPI_CLEAR_STATUS); - /* Enable pcie wake event if support */ - if ((acpi_gbl_FADT.flags & ACPI_FADT_PCI_EXPRESS_WAKE)) { - (void) - acpi_write_bit_register(acpi_gbl_fixed_event_info - [ACPI_EVENT_PCIE_WAKE]. - enable_register_id, - ACPI_DISABLE_EVENT); - (void) - acpi_write_bit_register(acpi_gbl_fixed_event_info - [ACPI_EVENT_PCIE_WAKE]. - status_register_id, - ACPI_CLEAR_STATUS); - } - acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index 53afa5edb6ec..cda6e16dddf7 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -186,10 +186,6 @@ struct acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS] = ACPI_BITREG_RT_CLOCK_ENABLE, ACPI_BITMASK_RT_CLOCK_STATUS, ACPI_BITMASK_RT_CLOCK_ENABLE}, - /* ACPI_EVENT_PCIE_WAKE */ {ACPI_BITREG_PCIEXP_WAKE_STATUS, - ACPI_BITREG_PCIEXP_WAKE_DISABLE, - ACPI_BITMASK_PCIEXP_WAKE_STATUS, - ACPI_BITMASK_PCIEXP_WAKE_DISABLE}, }; #endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/drivers/acpi/arm64/agdi.c b/drivers/acpi/arm64/agdi.c index cf31abd0ed1b..f605302395c3 100644 --- a/drivers/acpi/arm64/agdi.c +++ b/drivers/acpi/arm64/agdi.c @@ -64,8 +64,11 @@ static int agdi_remove(struct platform_device *pdev) int err, i; err = sdei_event_disable(adata->sdei_event); - if (err) - return err; + if (err) { + dev_err(&pdev->dev, "Failed to disable sdei-event #%d (%pe)\n", + adata->sdei_event, ERR_PTR(err)); + return 0; + } for (i = 0; i < 3; i++) { err = sdei_event_unregister(adata->sdei_event); @@ -75,7 +78,11 @@ static int agdi_remove(struct platform_device *pdev) schedule(); } - return err; + if (err) + dev_err(&pdev->dev, "Failed to unregister sdei-event #%d (%pe)\n", + adata->sdei_event, ERR_PTR(err)); + + return 0; } static struct platform_driver agdi_driver = { diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 9531dd0fef50..a96da65057b1 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -459,85 +459,67 @@ out_free: Notification Handling -------------------------------------------------------------------------- */ -/* - * acpi_bus_notify - * --------------- - * Callback for all 'system-level' device notifications (values 0x00-0x7F). +/** + * acpi_bus_notify - Global system-level (0x00-0x7F) notifications handler + * @handle: Target ACPI object. + * @type: Notification type. + * @data: Ignored. + * + * This only handles notifications related to device hotplug. */ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) { struct acpi_device *adev; - u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; - bool hotplug_event = false; switch (type) { case ACPI_NOTIFY_BUS_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); - hotplug_event = true; break; case ACPI_NOTIFY_DEVICE_CHECK: acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); - hotplug_event = true; break; case ACPI_NOTIFY_DEVICE_WAKE: acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_WAKE event\n"); - break; + return; case ACPI_NOTIFY_EJECT_REQUEST: acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); - hotplug_event = true; break; case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK_LIGHT event\n"); /* TBD: Exactly what does 'light' mean? */ - break; + return; case ACPI_NOTIFY_FREQUENCY_MISMATCH: acpi_handle_err(handle, "Device cannot be configured due " "to a frequency mismatch\n"); - break; + return; case ACPI_NOTIFY_BUS_MODE_MISMATCH: acpi_handle_err(handle, "Device cannot be configured due " "to a bus mode mismatch\n"); - break; + return; case ACPI_NOTIFY_POWER_FAULT: acpi_handle_err(handle, "Device has suffered a power fault\n"); - break; + return; default: acpi_handle_debug(handle, "Unknown event type 0x%x\n", type); - break; + return; } adev = acpi_get_acpi_dev(handle); - if (!adev) - goto err; - - if (adev->dev.driver) { - struct acpi_driver *driver = to_acpi_driver(adev->dev.driver); - - if (driver && driver->ops.notify && - (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) - driver->ops.notify(adev, type); - } - - if (!hotplug_event) { - acpi_put_acpi_dev(adev); - return; - } - if (ACPI_SUCCESS(acpi_hotplug_schedule(adev, type))) + if (adev && ACPI_SUCCESS(acpi_hotplug_schedule(adev, type))) return; acpi_put_acpi_dev(adev); - err: - acpi_evaluate_ost(handle, type, ost_code, NULL); + acpi_evaluate_ost(handle, type, ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); } static void acpi_notify_device(acpi_handle handle, u32 event, void *data) @@ -562,42 +544,51 @@ static u32 acpi_device_fixed_event(void *data) return ACPI_INTERRUPT_HANDLED; } -static int acpi_device_install_notify_handler(struct acpi_device *device) +static int acpi_device_install_notify_handler(struct acpi_device *device, + struct acpi_driver *acpi_drv) { acpi_status status; - if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) + if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) { status = acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, acpi_device_fixed_event, device); - else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) + } else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) { status = acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, acpi_device_fixed_event, device); - else - status = acpi_install_notify_handler(device->handle, - ACPI_DEVICE_NOTIFY, + } else { + u32 type = acpi_drv->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS ? + ACPI_ALL_NOTIFY : ACPI_DEVICE_NOTIFY; + + status = acpi_install_notify_handler(device->handle, type, acpi_notify_device, device); + } if (ACPI_FAILURE(status)) return -EINVAL; return 0; } -static void acpi_device_remove_notify_handler(struct acpi_device *device) +static void acpi_device_remove_notify_handler(struct acpi_device *device, + struct acpi_driver *acpi_drv) { - if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) + if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) { acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, acpi_device_fixed_event); - else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) + } else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) { acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, acpi_device_fixed_event); - else - acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, + } else { + u32 type = acpi_drv->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS ? + ACPI_ALL_NOTIFY : ACPI_DEVICE_NOTIFY; + + acpi_remove_notify_handler(device->handle, type, acpi_notify_device); + } } /* Handle events targeting \_SB device (at present only graceful shutdown) */ @@ -1039,7 +1030,7 @@ static int acpi_device_probe(struct device *dev) acpi_drv->name, acpi_dev->pnp.bus_id); if (acpi_drv->ops.notify) { - ret = acpi_device_install_notify_handler(acpi_dev); + ret = acpi_device_install_notify_handler(acpi_dev, acpi_drv); if (ret) { if (acpi_drv->ops.remove) acpi_drv->ops.remove(acpi_dev); @@ -1062,7 +1053,7 @@ static void acpi_device_remove(struct device *dev) struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver); if (acpi_drv->ops.notify) - acpi_device_remove_notify_handler(acpi_dev); + acpi_device_remove_notify_handler(acpi_dev, acpi_drv); if (acpi_drv->ops.remove) acpi_drv->ops.remove(acpi_dev); diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 7b4801ce62d6..e8492b3a393a 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -440,6 +440,13 @@ static const struct dmi_system_id asus_laptop[] = { }, }, { + .ident = "Asus ExpertBook B1502CBA", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_BOARD_NAME, "B1502CBA"), + }, + }, + { .ident = "Asus ExpertBook B2402CBA", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index fd7cbce8076e..e85729fc481f 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -277,6 +277,43 @@ static const struct dmi_system_id video_detect_dmi_table[] = { }, /* + * Models which need acpi_video backlight control where the GPU drivers + * do not call acpi_video_register_backlight() because no internal panel + * is detected. Typically these are all-in-ones (monitors with builtin + * PC) where the panel connection shows up as regular DP instead of eDP. + */ + { + .callback = video_detect_force_video, + /* Apple iMac14,1 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "iMac14,1"), + }, + }, + { + .callback = video_detect_force_video, + /* Apple iMac14,2 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "iMac14,2"), + }, + }, + + /* + * Older models with nvidia GPU which need acpi_video backlight + * control and where the old nvidia binary driver series does not + * call acpi_video_register_backlight(). + */ + { + .callback = video_detect_force_video, + /* ThinkPad W530 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W530"), + }, + }, + + /* * These models have a working acpi_video backlight control, and using * native backlight causes a regression where backlight does not work * when userspace is not handling brightness key events. Disable @@ -782,7 +819,7 @@ static bool prefer_native_over_acpi_video(void) * Determine which type of backlight interface to use on this system, * First check cmdline, then dmi quirks, then do autodetect. */ -static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native) +enum acpi_backlight_type __acpi_video_get_backlight_type(bool native, bool *auto_detect) { static DEFINE_MUTEX(init_mutex); static bool nvidia_wmi_ec_present; @@ -807,6 +844,9 @@ static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native) native_available = true; mutex_unlock(&init_mutex); + if (auto_detect) + *auto_detect = false; + /* * The below heuristics / detection steps are in order of descending * presedence. The commandline takes presedence over anything else. @@ -818,6 +858,9 @@ static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native) if (acpi_backlight_dmi != acpi_backlight_undef) return acpi_backlight_dmi; + if (auto_detect) + *auto_detect = true; + /* Special cases such as nvidia_wmi_ec and apple gmux. */ if (nvidia_wmi_ec_present) return acpi_backlight_nvidia_wmi_ec; @@ -837,15 +880,4 @@ static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native) /* No ACPI video/native (old hw), use vendor specific fw methods. */ return acpi_backlight_vendor; } - -enum acpi_backlight_type acpi_video_get_backlight_type(void) -{ - return __acpi_video_get_backlight_type(false); -} -EXPORT_SYMBOL(acpi_video_get_backlight_type); - -bool acpi_video_backlight_use_native(void) -{ - return __acpi_video_get_backlight_type(true) == acpi_backlight_native; -} -EXPORT_SYMBOL(acpi_video_backlight_use_native); +EXPORT_SYMBOL(__acpi_video_get_backlight_type); diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c index da5727069d85..ba420a28a4aa 100644 --- a/drivers/acpi/x86/utils.c +++ b/drivers/acpi/x86/utils.c @@ -213,6 +213,7 @@ bool acpi_device_override_status(struct acpi_device *adev, unsigned long long *s disk in the system. */ static const struct x86_cpu_id storage_d3_cpu_ids[] = { + X86_MATCH_VENDOR_FAM_MODEL(AMD, 23, 24, NULL), /* Picasso */ X86_MATCH_VENDOR_FAM_MODEL(AMD, 23, 96, NULL), /* Renoir */ X86_MATCH_VENDOR_FAM_MODEL(AMD, 23, 104, NULL), /* Lucienne */ X86_MATCH_VENDOR_FAM_MODEL(AMD, 25, 80, NULL), /* Cezanne */ diff --git a/drivers/amba/tegra-ahb.c b/drivers/amba/tegra-ahb.c index 0b2c20fddb7c..c0e8b765522d 100644 --- a/drivers/amba/tegra-ahb.c +++ b/drivers/amba/tegra-ahb.c @@ -285,5 +285,4 @@ module_platform_driver(tegra_ahb_driver); MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>"); MODULE_DESCRIPTION("Tegra AHB driver"); -MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index f6573c335f4c..f3903d002819 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -474,12 +474,18 @@ int detect_cache_attributes(unsigned int cpu) populate_leaves: /* - * populate_cache_leaves() may completely setup the cache leaves and - * shared_cpu_map or it may leave it partially setup. + * If LLC is valid the cache leaves were already populated so just go to + * update the cpu map. */ - ret = populate_cache_leaves(cpu); - if (ret) - goto free_ci; + if (!last_level_cache_is_valid(cpu)) { + /* + * populate_cache_leaves() may completely setup the cache leaves and + * shared_cpu_map or it may leave it partially setup. + */ + ret = populate_cache_leaves(cpu); + if (ret) + goto free_ci; + } /* * For systems using DT for cache hierarchy, fw_token diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 182c6122f815..c1815b9dae68 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -487,7 +487,8 @@ static const struct attribute_group *cpu_root_attr_groups[] = { bool cpu_is_hotpluggable(unsigned int cpu) { struct device *dev = get_cpu_device(cpu); - return dev && container_of(dev, struct cpu, dev)->hotpluggable; + return dev && container_of(dev, struct cpu, dev)->hotpluggable + && tick_nohz_cpu_hotpluggable(cpu); } EXPORT_SYMBOL_GPL(cpu_is_hotpluggable); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 60757ac31701..f49f2a5282e1 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1615,7 +1615,7 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info) drbd_send_sync_param(peer_device); } - kvfree_rcu(old_disk_conf); + kvfree_rcu_mightsleep(old_disk_conf); kfree(old_plan); mod_timer(&device->request_timer, jiffies + HZ); goto success; @@ -2446,7 +2446,7 @@ int drbd_adm_net_opts(struct sk_buff *skb, struct genl_info *info) mutex_unlock(&connection->resource->conf_update); mutex_unlock(&connection->data.mutex); - kvfree_rcu(old_net_conf); + kvfree_rcu_mightsleep(old_net_conf); if (connection->cstate >= C_WF_REPORT_PARAMS) { struct drbd_peer_device *peer_device; @@ -2860,7 +2860,7 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info) new_disk_conf->disk_size = (sector_t)rs.resize_size; rcu_assign_pointer(device->ldev->disk_conf, new_disk_conf); mutex_unlock(&device->resource->conf_update); - kvfree_rcu(old_disk_conf); + kvfree_rcu_mightsleep(old_disk_conf); new_disk_conf = NULL; } diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 757f4692b5bd..e197b2a465d2 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3759,7 +3759,7 @@ static int receive_protocol(struct drbd_connection *connection, struct packet_in drbd_info(connection, "peer data-integrity-alg: %s\n", integrity_alg[0] ? integrity_alg : "(none)"); - kvfree_rcu(old_net_conf); + kvfree_rcu_mightsleep(old_net_conf); return 0; disconnect_rcu_unlock: @@ -4127,7 +4127,7 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info rcu_assign_pointer(device->ldev->disk_conf, new_disk_conf); mutex_unlock(&connection->resource->conf_update); - kvfree_rcu(old_disk_conf); + kvfree_rcu_mightsleep(old_disk_conf); drbd_info(device, "Peer sets u_size to %lu sectors (old: %lu)\n", (unsigned long)p_usize, (unsigned long)my_usize); diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index 75d13ea0024f..2aeea295fa28 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c @@ -2071,7 +2071,7 @@ static int w_after_conn_state_ch(struct drbd_work *w, int unused) conn_free_crypto(connection); mutex_unlock(&connection->resource->conf_update); - kvfree_rcu(old_conf); + kvfree_rcu_mightsleep(old_conf); } if (ns_max.susp_fen) { diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 28eb59fd71ca..bc31bb7072a2 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1010,9 +1010,6 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, /* This is safe, since we have a reference from open(). */ __module_get(THIS_MODULE); - /* suppress uevents while reconfiguring the device */ - dev_set_uevent_suppress(disk_to_dev(lo->lo_disk), 1); - /* * If we don't hold exclusive handle for the device, upgrade to it * here to avoid changing device under exclusive owner. @@ -1067,6 +1064,9 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, } } + /* suppress uevents while reconfiguring the device */ + dev_set_uevent_suppress(disk_to_dev(lo->lo_disk), 1); + disk_force_media_change(lo->lo_disk, DISK_EVENT_MEDIA_CHANGE); set_disk_ro(lo->lo_disk, (lo->lo_flags & LO_FLAGS_READ_ONLY) != 0); @@ -1109,17 +1109,17 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, if (partscan) clear_bit(GD_SUPPRESS_PART_SCAN, &lo->lo_disk->state); + /* enable and uncork uevent now that we are done */ + dev_set_uevent_suppress(disk_to_dev(lo->lo_disk), 0); + loop_global_unlock(lo, is_loop); if (partscan) loop_reread_partitions(lo); + if (!(mode & FMODE_EXCL)) bd_abort_claiming(bdev, loop_configure); - error = 0; -done: - /* enable and uncork uevent now that we are done */ - dev_set_uevent_suppress(disk_to_dev(lo->lo_disk), 0); - return error; + return 0; out_unlock: loop_global_unlock(lo, is_loop); @@ -1130,7 +1130,7 @@ out_putf: fput(file); /* This is safe: open() is still holding a reference. */ module_put(THIS_MODULE); - goto done; + return error; } static void __loop_clr_fd(struct loop_device *lo, bool release) diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 2f1a92509271..5ae2a80db2c3 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -1869,12 +1869,12 @@ static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd) /* * enable/disable write caching on drive */ -static noinline_for_stack int pkt_write_caching(struct pktcdvd_device *pd, - int set) +static noinline_for_stack int pkt_write_caching(struct pktcdvd_device *pd) { struct packet_command cgc; struct scsi_sense_hdr sshdr; unsigned char buf[64]; + bool set = IS_ENABLED(CONFIG_CDROM_PKTCDVD_WCACHE); int ret; init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); @@ -1890,7 +1890,12 @@ static noinline_for_stack int pkt_write_caching(struct pktcdvd_device *pd, if (ret) return ret; - buf[pd->mode_offset + 10] |= (!!set << 2); + /* + * use drive write caching -- we need deferred error handling to be + * able to successfully recover with this option (drive will return good + * status as soon as the cdb is validated). + */ + buf[pd->mode_offset + 10] |= (set << 2); cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff)); ret = pkt_mode_select(pd, &cgc); @@ -2085,7 +2090,7 @@ static int pkt_open_write(struct pktcdvd_device *pd) return -EIO; } - pkt_write_caching(pd, USE_WCACHING); + pkt_write_caching(pd); ret = pkt_get_max_speed(pd, &write_speed); if (ret) diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index c73cc57ec547..604c1a13c76e 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -246,7 +246,7 @@ static int ublk_validate_params(const struct ublk_device *ub) if (ub->params.types & UBLK_PARAM_TYPE_BASIC) { const struct ublk_param_basic *p = &ub->params.basic; - if (p->logical_bs_shift > PAGE_SHIFT) + if (p->logical_bs_shift > PAGE_SHIFT || p->logical_bs_shift < 9) return -EINVAL; if (p->logical_bs_shift > p->physical_bs_shift) @@ -1261,9 +1261,10 @@ static void ublk_handle_need_get_data(struct ublk_device *ub, int q_id, ublk_queue_cmd(ubq, req); } -static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags) +static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd, + unsigned int issue_flags, + struct ublksrv_io_cmd *ub_cmd) { - struct ublksrv_io_cmd *ub_cmd = (struct ublksrv_io_cmd *)cmd->cmd; struct ublk_device *ub = cmd->file->private_data; struct ublk_queue *ubq; struct ublk_io *io; @@ -1362,6 +1363,23 @@ static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags) return -EIOCBQUEUED; } +static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags) +{ + struct ublksrv_io_cmd *ub_src = (struct ublksrv_io_cmd *) cmd->cmd; + struct ublksrv_io_cmd ub_cmd; + + /* + * Not necessary for async retry, but let's keep it simple and always + * copy the values to avoid any potential reuse. + */ + ub_cmd.q_id = READ_ONCE(ub_src->q_id); + ub_cmd.tag = READ_ONCE(ub_src->tag); + ub_cmd.result = READ_ONCE(ub_src->result); + ub_cmd.addr = READ_ONCE(ub_src->addr); + + return __ublk_ch_uring_cmd(cmd, issue_flags, &ub_cmd); +} + static const struct file_operations ublk_ch_fops = { .owner = THIS_MODULE, .open = ublk_ch_open, @@ -1952,6 +1970,8 @@ static int ublk_ctrl_set_params(struct ublk_device *ub, /* clear all we don't support yet */ ub->params.types &= UBLK_PARAM_TYPE_ALL; ret = ublk_validate_params(ub); + if (ret) + ub->params.types = 0; } mutex_unlock(&ub->mutex); diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 2723eede6f21..2b918e28acaa 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -96,16 +96,14 @@ struct virtblk_req { /* * The zone append command has an extended in header. - * The status field in zone_append_in_hdr must have - * the same offset in virtblk_req as the non-zoned - * status field above. + * The status field in zone_append_in_hdr must always + * be the last byte. */ struct { + __virtio64 sector; u8 status; - u8 reserved[7]; - __le64 append_sector; - } zone_append_in_hdr; - }; + } zone_append; + } in_hdr; size_t in_hdr_len; @@ -154,7 +152,7 @@ static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr) sgs[num_out + num_in++] = vbr->sg_table.sgl; } - sg_init_one(&in_hdr, &vbr->status, vbr->in_hdr_len); + sg_init_one(&in_hdr, &vbr->in_hdr.status, vbr->in_hdr_len); sgs[num_out + num_in++] = &in_hdr; return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC); @@ -242,11 +240,14 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev, struct request *req, struct virtblk_req *vbr) { - size_t in_hdr_len = sizeof(vbr->status); + size_t in_hdr_len = sizeof(vbr->in_hdr.status); bool unmap = false; u32 type; u64 sector = 0; + if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) && op_is_zone_mgmt(req_op(req))) + return BLK_STS_NOTSUPP; + /* Set fields for all request types */ vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req)); @@ -287,7 +288,7 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev, case REQ_OP_ZONE_APPEND: type = VIRTIO_BLK_T_ZONE_APPEND; sector = blk_rq_pos(req); - in_hdr_len = sizeof(vbr->zone_append_in_hdr); + in_hdr_len = sizeof(vbr->in_hdr.zone_append); break; case REQ_OP_ZONE_RESET: type = VIRTIO_BLK_T_ZONE_RESET; @@ -297,7 +298,10 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev, type = VIRTIO_BLK_T_ZONE_RESET_ALL; break; case REQ_OP_DRV_IN: - /* Out header already filled in, nothing to do */ + /* + * Out header has already been prepared by the caller (virtblk_get_id() + * or virtblk_submit_zone_report()), nothing to do here. + */ return 0; default: WARN_ON_ONCE(1); @@ -318,16 +322,28 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev, return 0; } +/* + * The status byte is always the last byte of the virtblk request + * in-header. This helper fetches its value for all in-header formats + * that are currently defined. + */ +static inline u8 virtblk_vbr_status(struct virtblk_req *vbr) +{ + return *((u8 *)&vbr->in_hdr + vbr->in_hdr_len - 1); +} + static inline void virtblk_request_done(struct request *req) { struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); - blk_status_t status = virtblk_result(vbr->status); + blk_status_t status = virtblk_result(virtblk_vbr_status(vbr)); + struct virtio_blk *vblk = req->mq_hctx->queue->queuedata; virtblk_unmap_data(req, vbr); virtblk_cleanup_cmd(req); if (req_op(req) == REQ_OP_ZONE_APPEND) - req->__sector = le64_to_cpu(vbr->zone_append_in_hdr.append_sector); + req->__sector = virtio64_to_cpu(vblk->vdev, + vbr->in_hdr.zone_append.sector); blk_mq_end_request(req, status); } @@ -355,7 +371,7 @@ static int virtblk_handle_req(struct virtio_blk_vq *vq, if (likely(!blk_should_fake_timeout(req->q)) && !blk_mq_complete_request_remote(req) && - !blk_mq_add_to_batch(req, iob, vbr->status, + !blk_mq_add_to_batch(req, iob, virtblk_vbr_status(vbr), virtblk_complete_batch)) virtblk_request_done(req); req_done++; @@ -550,7 +566,6 @@ static void virtio_queue_rqs(struct request **rqlist) #ifdef CONFIG_BLK_DEV_ZONED static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk, unsigned int nr_zones, - unsigned int zone_sectors, size_t *buflen) { struct request_queue *q = vblk->disk->queue; @@ -558,7 +573,7 @@ static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk, void *buf; nr_zones = min_t(unsigned int, nr_zones, - get_capacity(vblk->disk) >> ilog2(zone_sectors)); + get_capacity(vblk->disk) >> ilog2(vblk->zone_sectors)); bufsize = sizeof(struct virtio_blk_zone_report) + nr_zones * sizeof(struct virtio_blk_zone_descriptor); @@ -592,7 +607,7 @@ static int virtblk_submit_zone_report(struct virtio_blk *vblk, return PTR_ERR(req); vbr = blk_mq_rq_to_pdu(req); - vbr->in_hdr_len = sizeof(vbr->status); + vbr->in_hdr_len = sizeof(vbr->in_hdr.status); vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_ZONE_REPORT); vbr->out_hdr.sector = cpu_to_virtio64(vblk->vdev, sector); @@ -601,7 +616,7 @@ static int virtblk_submit_zone_report(struct virtio_blk *vblk, goto out; blk_execute_rq(req, false); - err = blk_status_to_errno(virtblk_result(vbr->status)); + err = blk_status_to_errno(virtblk_result(vbr->in_hdr.status)); out: blk_mq_free_request(req); return err; @@ -609,29 +624,72 @@ out: static int virtblk_parse_zone(struct virtio_blk *vblk, struct virtio_blk_zone_descriptor *entry, - unsigned int idx, unsigned int zone_sectors, - report_zones_cb cb, void *data) + unsigned int idx, report_zones_cb cb, void *data) { struct blk_zone zone = { }; - if (entry->z_type != VIRTIO_BLK_ZT_SWR && - entry->z_type != VIRTIO_BLK_ZT_SWP && - entry->z_type != VIRTIO_BLK_ZT_CONV) { - dev_err(&vblk->vdev->dev, "invalid zone type %#x\n", - entry->z_type); - return -EINVAL; + zone.start = virtio64_to_cpu(vblk->vdev, entry->z_start); + if (zone.start + vblk->zone_sectors <= get_capacity(vblk->disk)) + zone.len = vblk->zone_sectors; + else + zone.len = get_capacity(vblk->disk) - zone.start; + zone.capacity = virtio64_to_cpu(vblk->vdev, entry->z_cap); + zone.wp = virtio64_to_cpu(vblk->vdev, entry->z_wp); + + switch (entry->z_type) { + case VIRTIO_BLK_ZT_SWR: + zone.type = BLK_ZONE_TYPE_SEQWRITE_REQ; + break; + case VIRTIO_BLK_ZT_SWP: + zone.type = BLK_ZONE_TYPE_SEQWRITE_PREF; + break; + case VIRTIO_BLK_ZT_CONV: + zone.type = BLK_ZONE_TYPE_CONVENTIONAL; + break; + default: + dev_err(&vblk->vdev->dev, "zone %llu: invalid type %#x\n", + zone.start, entry->z_type); + return -EIO; } - zone.type = entry->z_type; - zone.cond = entry->z_state; - zone.len = zone_sectors; - zone.capacity = le64_to_cpu(entry->z_cap); - zone.start = le64_to_cpu(entry->z_start); - if (zone.cond == BLK_ZONE_COND_FULL) + switch (entry->z_state) { + case VIRTIO_BLK_ZS_EMPTY: + zone.cond = BLK_ZONE_COND_EMPTY; + break; + case VIRTIO_BLK_ZS_CLOSED: + zone.cond = BLK_ZONE_COND_CLOSED; + break; + case VIRTIO_BLK_ZS_FULL: + zone.cond = BLK_ZONE_COND_FULL; zone.wp = zone.start + zone.len; - else - zone.wp = le64_to_cpu(entry->z_wp); + break; + case VIRTIO_BLK_ZS_EOPEN: + zone.cond = BLK_ZONE_COND_EXP_OPEN; + break; + case VIRTIO_BLK_ZS_IOPEN: + zone.cond = BLK_ZONE_COND_IMP_OPEN; + break; + case VIRTIO_BLK_ZS_NOT_WP: + zone.cond = BLK_ZONE_COND_NOT_WP; + break; + case VIRTIO_BLK_ZS_RDONLY: + zone.cond = BLK_ZONE_COND_READONLY; + zone.wp = ULONG_MAX; + break; + case VIRTIO_BLK_ZS_OFFLINE: + zone.cond = BLK_ZONE_COND_OFFLINE; + zone.wp = ULONG_MAX; + break; + default: + dev_err(&vblk->vdev->dev, "zone %llu: invalid condition %#x\n", + zone.start, entry->z_state); + return -EIO; + } + /* + * The callback below checks the validity of the reported + * entry data, no need to further validate it here. + */ return cb(&zone, idx, data); } @@ -641,39 +699,47 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector, { struct virtio_blk *vblk = disk->private_data; struct virtio_blk_zone_report *report; - unsigned int zone_sectors = vblk->zone_sectors; - unsigned int nz, i; - int ret, zone_idx = 0; + unsigned long long nz, i; size_t buflen; + unsigned int zone_idx = 0; + int ret; if (WARN_ON_ONCE(!vblk->zone_sectors)) return -EOPNOTSUPP; - report = virtblk_alloc_report_buffer(vblk, nr_zones, - zone_sectors, &buflen); + report = virtblk_alloc_report_buffer(vblk, nr_zones, &buflen); if (!report) return -ENOMEM; + mutex_lock(&vblk->vdev_mutex); + + if (!vblk->vdev) { + ret = -ENXIO; + goto fail_report; + } + while (zone_idx < nr_zones && sector < get_capacity(vblk->disk)) { memset(report, 0, buflen); ret = virtblk_submit_zone_report(vblk, (char *)report, buflen, sector); - if (ret) { - if (ret > 0) - ret = -EIO; - goto out_free; - } - nz = min((unsigned int)le64_to_cpu(report->nr_zones), nr_zones); + if (ret) + goto fail_report; + + nz = min_t(u64, virtio64_to_cpu(vblk->vdev, report->nr_zones), + nr_zones); if (!nz) break; for (i = 0; i < nz && zone_idx < nr_zones; i++) { ret = virtblk_parse_zone(vblk, &report->zones[i], - zone_idx, zone_sectors, cb, data); + zone_idx, cb, data); if (ret) - goto out_free; - sector = le64_to_cpu(report->zones[i].z_start) + zone_sectors; + goto fail_report; + + sector = virtio64_to_cpu(vblk->vdev, + report->zones[i].z_start) + + vblk->zone_sectors; zone_idx++; } } @@ -682,7 +748,8 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector, ret = zone_idx; else ret = -EINVAL; -out_free: +fail_report: + mutex_unlock(&vblk->vdev_mutex); kvfree(report); return ret; } @@ -691,20 +758,28 @@ static void virtblk_revalidate_zones(struct virtio_blk *vblk) { u8 model; - if (!vblk->zone_sectors) - return; - virtio_cread(vblk->vdev, struct virtio_blk_config, zoned.model, &model); - if (!blk_revalidate_disk_zones(vblk->disk, NULL)) - set_capacity_and_notify(vblk->disk, 0); + switch (model) { + default: + dev_err(&vblk->vdev->dev, "unknown zone model %d\n", model); + fallthrough; + case VIRTIO_BLK_Z_NONE: + case VIRTIO_BLK_Z_HA: + disk_set_zoned(vblk->disk, BLK_ZONED_NONE); + return; + case VIRTIO_BLK_Z_HM: + WARN_ON_ONCE(!vblk->zone_sectors); + if (!blk_revalidate_disk_zones(vblk->disk, NULL)) + set_capacity_and_notify(vblk->disk, 0); + } } static int virtblk_probe_zoned_device(struct virtio_device *vdev, struct virtio_blk *vblk, struct request_queue *q) { - u32 v; + u32 v, wg; u8 model; int ret; @@ -713,16 +788,11 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev, switch (model) { case VIRTIO_BLK_Z_NONE: + case VIRTIO_BLK_Z_HA: + /* Present the host-aware device as non-zoned */ return 0; case VIRTIO_BLK_Z_HM: break; - case VIRTIO_BLK_Z_HA: - /* - * Present the host-aware device as a regular drive. - * TODO It is possible to add an option to make it appear - * in the system as a zoned drive. - */ - return 0; default: dev_err(&vdev->dev, "unsupported zone model %d\n", model); return -EINVAL; @@ -735,32 +805,31 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev, virtio_cread(vdev, struct virtio_blk_config, zoned.max_open_zones, &v); - disk_set_max_open_zones(vblk->disk, le32_to_cpu(v)); - - dev_dbg(&vdev->dev, "max open zones = %u\n", le32_to_cpu(v)); + disk_set_max_open_zones(vblk->disk, v); + dev_dbg(&vdev->dev, "max open zones = %u\n", v); virtio_cread(vdev, struct virtio_blk_config, zoned.max_active_zones, &v); - disk_set_max_active_zones(vblk->disk, le32_to_cpu(v)); - dev_dbg(&vdev->dev, "max active zones = %u\n", le32_to_cpu(v)); + disk_set_max_active_zones(vblk->disk, v); + dev_dbg(&vdev->dev, "max active zones = %u\n", v); virtio_cread(vdev, struct virtio_blk_config, - zoned.write_granularity, &v); - if (!v) { + zoned.write_granularity, &wg); + if (!wg) { dev_warn(&vdev->dev, "zero write granularity reported\n"); return -ENODEV; } - blk_queue_physical_block_size(q, le32_to_cpu(v)); - blk_queue_io_min(q, le32_to_cpu(v)); + blk_queue_physical_block_size(q, wg); + blk_queue_io_min(q, wg); - dev_dbg(&vdev->dev, "write granularity = %u\n", le32_to_cpu(v)); + dev_dbg(&vdev->dev, "write granularity = %u\n", wg); /* * virtio ZBD specification doesn't require zones to be a power of * two sectors in size, but the code in this driver expects that. */ - virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors, &v); - vblk->zone_sectors = le32_to_cpu(v); + virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors, + &vblk->zone_sectors); if (vblk->zone_sectors == 0 || !is_power_of_2(vblk->zone_sectors)) { dev_err(&vdev->dev, "zoned device with non power of two zone size %u\n", @@ -783,36 +852,46 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev, dev_warn(&vdev->dev, "zero max_append_sectors reported\n"); return -ENODEV; } - blk_queue_max_zone_append_sectors(q, le32_to_cpu(v)); - dev_dbg(&vdev->dev, "max append sectors = %u\n", le32_to_cpu(v)); + if ((v << SECTOR_SHIFT) < wg) { + dev_err(&vdev->dev, + "write granularity %u exceeds max_append_sectors %u limit\n", + wg, v); + return -ENODEV; + } + + blk_queue_max_zone_append_sectors(q, v); + dev_dbg(&vdev->dev, "max append sectors = %u\n", v); } return ret; } -static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev) -{ - return virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED); -} #else /* * Zoned block device support is not configured in this kernel. - * We only need to define a few symbols to avoid compilation errors. + * Host-managed zoned devices can't be supported, but others are + * good to go as regular block devices. */ #define virtblk_report_zones NULL + static inline void virtblk_revalidate_zones(struct virtio_blk *vblk) { } + static inline int virtblk_probe_zoned_device(struct virtio_device *vdev, struct virtio_blk *vblk, struct request_queue *q) { - return -EOPNOTSUPP; -} + u8 model; -static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev) -{ - return false; + virtio_cread(vdev, struct virtio_blk_config, zoned.model, &model); + if (model == VIRTIO_BLK_Z_HM) { + dev_err(&vdev->dev, + "virtio_blk: zoned devices are not supported"); + return -EOPNOTSUPP; + } + + return 0; } #endif /* CONFIG_BLK_DEV_ZONED */ @@ -831,7 +910,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str) return PTR_ERR(req); vbr = blk_mq_rq_to_pdu(req); - vbr->in_hdr_len = sizeof(vbr->status); + vbr->in_hdr_len = sizeof(vbr->in_hdr.status); vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID); vbr->out_hdr.sector = 0; @@ -840,7 +919,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str) goto out; blk_execute_rq(req, false); - err = blk_status_to_errno(virtblk_result(vbr->status)); + err = blk_status_to_errno(virtblk_result(vbr->in_hdr.status)); out: blk_mq_free_request(req); return err; @@ -1498,15 +1577,16 @@ static int virtblk_probe(struct virtio_device *vdev) virtblk_update_capacity(vblk, false); virtio_device_ready(vdev); - if (virtblk_has_zoned_feature(vdev)) { + /* + * All steps that follow use the VQs therefore they need to be + * placed after the virtio_device_ready() call above. + */ + if (virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED)) { err = virtblk_probe_zoned_device(vdev, vblk, q); if (err) goto out_cleanup_disk; } - dev_info(&vdev->dev, "blk config size: %zu\n", - sizeof(struct virtio_blk_config)); - err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups); if (err) goto out_cleanup_disk; @@ -1607,10 +1687,7 @@ static unsigned int features[] = { VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE, VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES, - VIRTIO_BLK_F_SECURE_ERASE, -#ifdef CONFIG_BLK_DEV_ZONED - VIRTIO_BLK_F_ZONED, -#endif /* CONFIG_BLK_DEV_ZONED */ + VIRTIO_BLK_F_SECURE_ERASE, VIRTIO_BLK_F_ZONED, }; static struct virtio_driver virtio_blk = { diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index 3006e2a0f37e..43e98a598bd9 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -511,7 +511,7 @@ static const char *btbcm_get_board_name(struct device *dev) len = strlen(tmp) + 1; board_type = devm_kzalloc(dev, len, GFP_KERNEL); strscpy(board_type, tmp, len); - for (i = 0; i < board_type[i]; i++) { + for (i = 0; i < len; i++) { if (board_type[i] == '/') board_type[i] = '-'; } diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c index 02893600db39..51000320e1ea 100644 --- a/drivers/bluetooth/btsdio.c +++ b/drivers/bluetooth/btsdio.c @@ -358,6 +358,7 @@ static void btsdio_remove(struct sdio_func *func) if (!data) return; + cancel_work_sync(&data->work); hdev = data->hdev; sdio_set_drvdata(func, NULL); diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 7bfe998f3514..fcfa280df98a 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -81,7 +81,7 @@ config MOXTET config HISILICON_LPC bool "Support for ISA I/O space on HiSilicon Hip06/7" depends on (ARM64 && ARCH_HISI) || (COMPILE_TEST && !ALPHA && !HEXAGON && !PARISC) - depends on HAS_IOMEM + depends on HAS_IOPORT select INDIRECT_PIO if ARM64 help Driver to enable I/O access to devices attached to the Low Pin diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c index b0c3704777e9..b6dfe4340da2 100644 --- a/drivers/bus/brcmstb_gisb.c +++ b/drivers/bus/brcmstb_gisb.c @@ -401,12 +401,10 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev) struct device_node *dn = pdev->dev.of_node; struct brcmstb_gisb_arb_device *gdev; const struct of_device_id *of_id; - struct resource *r; int err, timeout_irq, tea_irq, bp_irq; unsigned int num_masters, j = 0; int i, first, last; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); timeout_irq = platform_get_irq(pdev, 0); tea_irq = platform_get_irq(pdev, 1); bp_irq = platform_get_irq(pdev, 2); @@ -418,7 +416,7 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev) mutex_init(&gdev->lock); INIT_LIST_HEAD(&gdev->next); - gdev->base = devm_ioremap_resource(&pdev->dev, r); + gdev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(gdev->base)) return PTR_ERR(gdev->base); diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c index 36d42484142a..52a5d0447390 100644 --- a/drivers/bus/imx-weim.c +++ b/drivers/bus/imx-weim.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/of_address.h> #include <linux/of_device.h> #include <linux/mfd/syscon.h> #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> @@ -86,8 +87,8 @@ MODULE_DEVICE_TABLE(of, weim_id_table); static int imx_weim_gpr_setup(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct property *prop; - const __be32 *p; + struct of_range_parser parser; + struct of_range range; struct regmap *gpr; u32 gprvals[4] = { 05, /* CS0(128M) CS1(0M) CS2(0M) CS3(0M) */ @@ -106,13 +107,13 @@ static int imx_weim_gpr_setup(struct platform_device *pdev) return 0; } - of_property_for_each_u32(np, "ranges", prop, p, val) { - if (i % 4 == 0) { - cs = val; - } else if (i % 4 == 3 && val) { - val = (val / SZ_32M) | 1; - gprval |= val << cs * 3; - } + if (of_range_parser_init(&parser, np)) + goto err; + + for_each_of_range(&parser, &range) { + cs = range.bus_addr >> 32; + val = (range.size / SZ_32M) | 1; + gprval |= val << cs * 3; i++; } @@ -329,6 +330,12 @@ static int of_weim_notify(struct notifier_block *nb, unsigned long action, "Failed to setup timing for '%pOF'\n", rd->dn); if (!of_node_check_flag(rd->dn, OF_POPULATED)) { + /* + * Clear the flag before adding the device so that + * fw_devlink doesn't skip adding consumers to this + * device. + */ + rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE; if (!of_platform_device_create(rd->dn, NULL, &pdev->dev)) { dev_err(&pdev->dev, "Failed to create child device '%pOF'\n", diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 6afae9897843..6c49de37d5e9 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -648,43 +648,20 @@ static int sysc_init_resets(struct sysc *ddata) static int sysc_parse_and_check_child_range(struct sysc *ddata) { struct device_node *np = ddata->dev->of_node; - const __be32 *ranges; - u32 nr_addr, nr_size; - int len, error; - - ranges = of_get_property(np, "ranges", &len); - if (!ranges) { - dev_err(ddata->dev, "missing ranges for %pOF\n", np); - - return -ENOENT; - } - - len /= sizeof(*ranges); - - if (len < 3) { - dev_err(ddata->dev, "incomplete ranges for %pOF\n", np); - - return -EINVAL; - } - - error = of_property_read_u32(np, "#address-cells", &nr_addr); - if (error) - return -ENOENT; + struct of_range_parser parser; + struct of_range range; + int error; - error = of_property_read_u32(np, "#size-cells", &nr_size); + error = of_range_parser_init(&parser, np); if (error) - return -ENOENT; - - if (nr_addr != 1 || nr_size != 1) { - dev_err(ddata->dev, "invalid ranges for %pOF\n", np); + return error; - return -EINVAL; + for_each_of_range(&parser, &range) { + ddata->module_pa = range.cpu_addr; + ddata->module_size = range.size; + break; } - ranges++; - ddata->module_pa = of_translate_address(np, ranges++); - ddata->module_size = be32_to_cpup(ranges); - return 0; } @@ -913,7 +890,7 @@ static int sysc_check_registers(struct sysc *ddata) * within the interconnect target module range. For example, SGX has * them at offset 0x1fc00 in the 32MB module address space. And cpsw * has them at offset 0x1200 in the CPSW_WR child. Usually the - * the interconnect target module registers are at the beginning of + * interconnect target module registers are at the beginning of * the module range though. */ static int sysc_ioremap(struct sysc *ddata) @@ -964,7 +941,7 @@ static int sysc_map_and_check_registers(struct sysc *ddata) sysc_check_children(ddata); - if (!of_get_property(np, "reg", NULL)) + if (!of_property_present(np, "reg")) return 0; error = sysc_parse_registers(ddata); @@ -2530,11 +2507,9 @@ static struct dev_pm_domain sysc_child_pm_domain = { static void sysc_reinit_modules(struct sysc_soc_info *soc) { struct sysc_module *module; - struct list_head *pos; struct sysc *ddata; - list_for_each(pos, &sysc_soc->restored_modules) { - module = list_entry(pos, struct sysc_module, node); + list_for_each_entry(module, &sysc_soc->restored_modules, node) { ddata = module->ddata; sysc_reinit_module(ddata, ddata->enabled); } @@ -3214,12 +3189,10 @@ static void sysc_cleanup_static_data(void) static int sysc_check_disabled_devices(struct sysc *ddata) { struct sysc_address *disabled_module; - struct list_head *pos; int error = 0; mutex_lock(&sysc_soc->list_lock); - list_for_each(pos, &sysc_soc->disabled_modules) { - disabled_module = list_entry(pos, struct sysc_address, node); + list_for_each_entry(disabled_module, &sysc_soc->disabled_modules, node) { if (ddata->module_pa == disabled_module->base) { dev_dbg(ddata->dev, "module disabled for this SoC\n"); error = -ENODEV; diff --git a/drivers/bus/vexpress-config.c b/drivers/bus/vexpress-config.c index a58ac0c8e282..472a570bd53a 100644 --- a/drivers/bus/vexpress-config.c +++ b/drivers/bus/vexpress-config.c @@ -10,7 +10,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> -#include <linux/of_device.h> +#include <linux/of_platform.h> #include <linux/sched/signal.h> #include <linux/slab.h> #include <linux/vexpress.h> diff --git a/drivers/char/tpm/eventlog/common.c b/drivers/char/tpm/eventlog/common.c index 8512ec76d526..639c3f395a5a 100644 --- a/drivers/char/tpm/eventlog/common.c +++ b/drivers/char/tpm/eventlog/common.c @@ -36,7 +36,7 @@ static int tpm_bios_measurements_open(struct inode *inode, inode_unlock(inode); return -ENODEV; } - chip_seqops = (struct tpm_chip_seqops *)inode->i_private; + chip_seqops = inode->i_private; seqops = chip_seqops->seqops; chip = chip_seqops->chip; get_device(&chip->dev); @@ -55,8 +55,8 @@ static int tpm_bios_measurements_open(struct inode *inode, static int tpm_bios_measurements_release(struct inode *inode, struct file *file) { - struct seq_file *seq = (struct seq_file *)file->private_data; - struct tpm_chip *chip = (struct tpm_chip *)seq->private; + struct seq_file *seq = file->private_data; + struct tpm_chip *chip = seq->private; put_device(&chip->dev); diff --git a/drivers/char/tpm/st33zp24/i2c.c b/drivers/char/tpm/st33zp24/i2c.c index c4d0b744e3cc..2d28f55ef490 100644 --- a/drivers/char/tpm/st33zp24/i2c.c +++ b/drivers/char/tpm/st33zp24/i2c.c @@ -138,13 +138,13 @@ static const struct i2c_device_id st33zp24_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, st33zp24_i2c_id); -static const struct of_device_id of_st33zp24_i2c_match[] = { +static const struct of_device_id of_st33zp24_i2c_match[] __maybe_unused = { { .compatible = "st,st33zp24-i2c", }, {} }; MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match); -static const struct acpi_device_id st33zp24_i2c_acpi_match[] = { +static const struct acpi_device_id st33zp24_i2c_acpi_match[] __maybe_unused = { {"SMO3324"}, {} }; diff --git a/drivers/char/tpm/st33zp24/spi.c b/drivers/char/tpm/st33zp24/spi.c index 2154059f0235..f5811b301d3b 100644 --- a/drivers/char/tpm/st33zp24/spi.c +++ b/drivers/char/tpm/st33zp24/spi.c @@ -255,13 +255,13 @@ static const struct spi_device_id st33zp24_spi_id[] = { }; MODULE_DEVICE_TABLE(spi, st33zp24_spi_id); -static const struct of_device_id of_st33zp24_spi_match[] = { +static const struct of_device_id of_st33zp24_spi_match[] __maybe_unused = { { .compatible = "st,st33zp24-spi", }, {} }; MODULE_DEVICE_TABLE(of, of_st33zp24_spi_match); -static const struct acpi_device_id st33zp24_spi_acpi_match[] = { +static const struct acpi_device_id st33zp24_spi_acpi_match[] __maybe_unused = { {"SMO3324"}, {} }; diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 0601e6e5e326..6fdfa65a00c3 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -606,6 +606,30 @@ static int tpm_get_pcr_allocation(struct tpm_chip *chip) } /* + * tpm_chip_startup() - performs auto startup and allocates the PCRs + * @chip: TPM chip to use. + */ +int tpm_chip_startup(struct tpm_chip *chip) +{ + int rc; + + rc = tpm_chip_start(chip); + if (rc) + return rc; + + rc = tpm_auto_startup(chip); + if (rc) + goto stop; + + rc = tpm_get_pcr_allocation(chip); +stop: + tpm_chip_stop(chip); + + return rc; +} +EXPORT_SYMBOL_GPL(tpm_chip_startup); + +/* * tpm_chip_register() - create a character device for the TPM chip * @chip: TPM chip to use. * @@ -620,20 +644,6 @@ int tpm_chip_register(struct tpm_chip *chip) { int rc; - rc = tpm_chip_start(chip); - if (rc) - return rc; - rc = tpm_auto_startup(chip); - if (rc) { - tpm_chip_stop(chip); - return rc; - } - - rc = tpm_get_pcr_allocation(chip); - tpm_chip_stop(chip); - if (rc) - return rc; - tpm_sysfs_add_device(chip); tpm_bios_log_setup(chip); @@ -682,7 +692,8 @@ EXPORT_SYMBOL_GPL(tpm_chip_register); void tpm_chip_unregister(struct tpm_chip *chip) { tpm_del_legacy_sysfs(chip); - if (IS_ENABLED(CONFIG_HW_RANDOM_TPM) && !tpm_is_firmware_upgrade(chip)) + if (IS_ENABLED(CONFIG_HW_RANDOM_TPM) && !tpm_is_firmware_upgrade(chip) && + !tpm_amd_is_rng_defective(chip)) hwrng_unregister(&chip->hwrng); tpm_bios_log_teardown(chip); if (chip->flags & TPM_CHIP_FLAG_TPM2 && !tpm_is_firmware_upgrade(chip)) diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 830014a26609..88d3bd76e076 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -263,6 +263,7 @@ static inline void tpm_msleep(unsigned int delay_msec) delay_msec * 1000); }; +int tpm_chip_startup(struct tpm_chip *chip); int tpm_chip_start(struct tpm_chip *chip); void tpm_chip_stop(struct tpm_chip *chip); struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip); diff --git a/drivers/char/tpm/tpm_ftpm_tee.c b/drivers/char/tpm/tpm_ftpm_tee.c index deff23bb54bf..528f35b14fb6 100644 --- a/drivers/char/tpm/tpm_ftpm_tee.c +++ b/drivers/char/tpm/tpm_ftpm_tee.c @@ -334,11 +334,11 @@ static int ftpm_tee_remove(struct device *dev) return 0; } -static int ftpm_plat_tee_remove(struct platform_device *pdev) +static void ftpm_plat_tee_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; - return ftpm_tee_remove(dev); + ftpm_tee_remove(dev); } /** @@ -367,7 +367,7 @@ static struct platform_driver ftpm_tee_plat_driver = { }, .shutdown = ftpm_plat_tee_shutdown, .probe = ftpm_plat_tee_probe, - .remove = ftpm_plat_tee_remove, + .remove_new = ftpm_plat_tee_remove, }; /* UUID of the fTPM TA */ diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index ed5dabd3c72d..7af389806643 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -50,6 +50,45 @@ static inline struct tpm_tis_tcg_phy *to_tpm_tis_tcg_phy(struct tpm_tis_data *da return container_of(data, struct tpm_tis_tcg_phy, priv); } +#ifdef CONFIG_PREEMPT_RT +/* + * Flush previous write operations with a dummy read operation to the + * TPM MMIO base address. + */ +static inline void tpm_tis_flush(void __iomem *iobase) +{ + ioread8(iobase + TPM_ACCESS(0)); +} +#else +#define tpm_tis_flush(iobase) do { } while (0) +#endif + +/* + * Write a byte word to the TPM MMIO address, and flush the write queue. + * The flush ensures that the data is sent immediately over the bus and not + * aggregated with further requests and transferred later in a batch. The large + * write requests can lead to unwanted latency spikes by blocking the CPU until + * the complete batch has been transferred. + */ +static inline void tpm_tis_iowrite8(u8 b, void __iomem *iobase, u32 addr) +{ + iowrite8(b, iobase + addr); + tpm_tis_flush(iobase); +} + +/* + * Write a 32-bit word to the TPM MMIO address, and flush the write queue. + * The flush ensures that the data is sent immediately over the bus and not + * aggregated with further requests and transferred later in a batch. The large + * write requests can lead to unwanted latency spikes by blocking the CPU until + * the complete batch has been transferred. + */ +static inline void tpm_tis_iowrite32(u32 b, void __iomem *iobase, u32 addr) +{ + iowrite32(b, iobase + addr); + tpm_tis_flush(iobase); +} + static int interrupts = -1; module_param(interrupts, int, 0444); MODULE_PARM_DESC(interrupts, "Enable interrupts"); @@ -186,12 +225,12 @@ static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len, switch (io_mode) { case TPM_TIS_PHYS_8: while (len--) - iowrite8(*value++, phy->iobase + addr); + tpm_tis_iowrite8(*value++, phy->iobase, addr); break; case TPM_TIS_PHYS_16: return -EINVAL; case TPM_TIS_PHYS_32: - iowrite32(le32_to_cpu(*((__le32 *)value)), phy->iobase + addr); + tpm_tis_iowrite32(le32_to_cpu(*((__le32 *)value)), phy->iobase, addr); break; } @@ -227,7 +266,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info) irq = tpm_info->irq; if (itpm || is_itpm(ACPI_COMPANION(dev))) - phy->priv.flags |= TPM_TIS_ITPM_WORKAROUND; + set_bit(TPM_TIS_ITPM_WORKAROUND, &phy->priv.flags); return tpm_tis_core_init(dev, &phy->priv, irq, &tpm_tcg, ACPI_HANDLE(dev)); @@ -324,14 +363,12 @@ static int tpm_tis_plat_probe(struct platform_device *pdev) return tpm_tis_init(&pdev->dev, &tpm_info); } -static int tpm_tis_plat_remove(struct platform_device *pdev) +static void tpm_tis_plat_remove(struct platform_device *pdev) { struct tpm_chip *chip = dev_get_drvdata(&pdev->dev); tpm_chip_unregister(chip); tpm_tis_remove(chip); - - return 0; } #ifdef CONFIG_OF @@ -344,7 +381,7 @@ MODULE_DEVICE_TABLE(of, tis_of_platform_match); static struct platform_driver tis_drv = { .probe = tpm_tis_plat_probe, - .remove = tpm_tis_plat_remove, + .remove_new = tpm_tis_plat_remove, .driver = { .name = "tpm_tis", .pm = &tpm_tis_pm, diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index 3f98e587b3e8..c2421162cf34 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -44,6 +44,20 @@ static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, return false; } +static u8 tpm_tis_filter_sts_mask(u8 int_mask, u8 sts_mask) +{ + if (!(int_mask & TPM_INTF_STS_VALID_INT)) + sts_mask &= ~TPM_STS_VALID; + + if (!(int_mask & TPM_INTF_DATA_AVAIL_INT)) + sts_mask &= ~TPM_STS_DATA_AVAIL; + + if (!(int_mask & TPM_INTF_CMD_READY_INT)) + sts_mask &= ~TPM_STS_COMMAND_READY; + + return sts_mask; +} + static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, wait_queue_head_t *queue, bool check_cancel) @@ -53,41 +67,56 @@ static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, long rc; u8 status; bool canceled = false; + u8 sts_mask; + int ret = 0; /* check current status */ status = chip->ops->status(chip); if ((status & mask) == mask) return 0; - stop = jiffies + timeout; + sts_mask = mask & (TPM_STS_VALID | TPM_STS_DATA_AVAIL | + TPM_STS_COMMAND_READY); + /* check what status changes can be handled by irqs */ + sts_mask = tpm_tis_filter_sts_mask(priv->int_mask, sts_mask); - if (chip->flags & TPM_CHIP_FLAG_IRQ) { + stop = jiffies + timeout; + /* process status changes with irq support */ + if (sts_mask) { + ret = -ETIME; again: timeout = stop - jiffies; if ((long)timeout <= 0) return -ETIME; rc = wait_event_interruptible_timeout(*queue, - wait_for_tpm_stat_cond(chip, mask, check_cancel, + wait_for_tpm_stat_cond(chip, sts_mask, check_cancel, &canceled), timeout); if (rc > 0) { if (canceled) return -ECANCELED; - return 0; + ret = 0; } if (rc == -ERESTARTSYS && freezing(current)) { clear_thread_flag(TIF_SIGPENDING); goto again; } - } else { - do { - usleep_range(priv->timeout_min, - priv->timeout_max); - status = chip->ops->status(chip); - if ((status & mask) == mask) - return 0; - } while (time_before(jiffies, stop)); } + + if (ret) + return ret; + + mask &= ~sts_mask; + if (!mask) /* all done */ + return 0; + /* process status changes without irq support */ + do { + status = chip->ops->status(chip); + if ((status & mask) == mask) + return 0; + usleep_range(priv->timeout_min, + priv->timeout_max); + } while (time_before(jiffies, stop)); return -ETIME; } @@ -136,16 +165,27 @@ static bool check_locality(struct tpm_chip *chip, int l) return false; } -static int release_locality(struct tpm_chip *chip, int l) +static int __tpm_tis_relinquish_locality(struct tpm_tis_data *priv, int l) +{ + tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY); + + return 0; +} + +static int tpm_tis_relinquish_locality(struct tpm_chip *chip, int l) { struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); - tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY); + mutex_lock(&priv->locality_count_mutex); + priv->locality_count--; + if (priv->locality_count == 0) + __tpm_tis_relinquish_locality(priv, l); + mutex_unlock(&priv->locality_count_mutex); return 0; } -static int request_locality(struct tpm_chip *chip, int l) +static int __tpm_tis_request_locality(struct tpm_chip *chip, int l) { struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); unsigned long stop, timeout; @@ -186,6 +226,20 @@ again: return -1; } +static int tpm_tis_request_locality(struct tpm_chip *chip, int l) +{ + struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); + int ret = 0; + + mutex_lock(&priv->locality_count_mutex); + if (priv->locality_count == 0) + ret = __tpm_tis_request_locality(chip, l); + if (!ret) + priv->locality_count++; + mutex_unlock(&priv->locality_count_mutex); + return ret; +} + static u8 tpm_tis_status(struct tpm_chip *chip) { struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); @@ -351,7 +405,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len) struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); int rc, status, burstcnt; size_t count = 0; - bool itpm = priv->flags & TPM_TIS_ITPM_WORKAROUND; + bool itpm = test_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags); status = tpm_tis_status(chip); if ((status & TPM_STS_COMMAND_READY) == 0) { @@ -484,7 +538,8 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) int rc, irq; struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); - if (!(chip->flags & TPM_CHIP_FLAG_IRQ) || priv->irq_tested) + if (!(chip->flags & TPM_CHIP_FLAG_IRQ) || + test_bit(TPM_TIS_IRQ_TESTED, &priv->flags)) return tpm_tis_send_main(chip, buf, len); /* Verify receipt of the expected IRQ */ @@ -494,11 +549,11 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) rc = tpm_tis_send_main(chip, buf, len); priv->irq = irq; chip->flags |= TPM_CHIP_FLAG_IRQ; - if (!priv->irq_tested) + if (!test_bit(TPM_TIS_IRQ_TESTED, &priv->flags)) tpm_msleep(1); - if (!priv->irq_tested) + if (!test_bit(TPM_TIS_IRQ_TESTED, &priv->flags)) disable_interrupts(chip); - priv->irq_tested = true; + set_bit(TPM_TIS_IRQ_TESTED, &priv->flags); return rc; } @@ -641,7 +696,7 @@ static int probe_itpm(struct tpm_chip *chip) size_t len = sizeof(cmd_getticks); u16 vendor; - if (priv->flags & TPM_TIS_ITPM_WORKAROUND) + if (test_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags)) return 0; rc = tpm_tis_read16(priv, TPM_DID_VID(0), &vendor); @@ -652,7 +707,7 @@ static int probe_itpm(struct tpm_chip *chip) if (vendor != TPM_VID_INTEL) return 0; - if (request_locality(chip, 0) != 0) + if (tpm_tis_request_locality(chip, 0) != 0) return -EBUSY; rc = tpm_tis_send_data(chip, cmd_getticks, len); @@ -661,19 +716,19 @@ static int probe_itpm(struct tpm_chip *chip) tpm_tis_ready(chip); - priv->flags |= TPM_TIS_ITPM_WORKAROUND; + set_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags); rc = tpm_tis_send_data(chip, cmd_getticks, len); if (rc == 0) dev_info(&chip->dev, "Detected an iTPM.\n"); else { - priv->flags &= ~TPM_TIS_ITPM_WORKAROUND; + clear_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags); rc = -EFAULT; } out: tpm_tis_ready(chip); - release_locality(chip, priv->locality); + tpm_tis_relinquish_locality(chip, priv->locality); return rc; } @@ -702,7 +757,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) struct tpm_chip *chip = dev_id; struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); u32 interrupt; - int i, rc; + int rc; rc = tpm_tis_read32(priv, TPM_INT_STATUS(priv->locality), &interrupt); if (rc < 0) @@ -711,20 +766,19 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) if (interrupt == 0) return IRQ_NONE; - priv->irq_tested = true; + set_bit(TPM_TIS_IRQ_TESTED, &priv->flags); if (interrupt & TPM_INTF_DATA_AVAIL_INT) wake_up_interruptible(&priv->read_queue); - if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT) - for (i = 0; i < 5; i++) - if (check_locality(chip, i)) - break; + if (interrupt & (TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT | TPM_INTF_CMD_READY_INT)) wake_up_interruptible(&priv->int_queue); /* Clear interrupts handled with TPM_EOI */ + tpm_tis_request_locality(chip, 0); rc = tpm_tis_write32(priv, TPM_INT_STATUS(priv->locality), interrupt); + tpm_tis_relinquish_locality(chip, 0); if (rc < 0) return IRQ_NONE; @@ -732,25 +786,22 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) return IRQ_HANDLED; } -static int tpm_tis_gen_interrupt(struct tpm_chip *chip) +static void tpm_tis_gen_interrupt(struct tpm_chip *chip) { const char *desc = "attempting to generate an interrupt"; u32 cap2; cap_t cap; int ret; - ret = request_locality(chip, 0); - if (ret < 0) - return ret; + chip->flags |= TPM_CHIP_FLAG_IRQ; if (chip->flags & TPM_CHIP_FLAG_TPM2) ret = tpm2_get_tpm_pt(chip, 0x100, &cap2, desc); else ret = tpm1_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc, 0); - release_locality(chip, 0); - - return ret; + if (ret) + chip->flags &= ~TPM_CHIP_FLAG_IRQ; } /* Register the IRQ and issue a command that will cause an interrupt. If an @@ -765,60 +816,66 @@ static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask, int rc; u32 int_status; - if (devm_request_irq(chip->dev.parent, irq, tis_int_handler, flags, - dev_name(&chip->dev), chip) != 0) { + + rc = devm_request_threaded_irq(chip->dev.parent, irq, NULL, + tis_int_handler, IRQF_ONESHOT | flags, + dev_name(&chip->dev), chip); + if (rc) { dev_info(&chip->dev, "Unable to request irq: %d for probe\n", irq); return -1; } priv->irq = irq; + rc = tpm_tis_request_locality(chip, 0); + if (rc < 0) + return rc; + rc = tpm_tis_read8(priv, TPM_INT_VECTOR(priv->locality), &original_int_vec); - if (rc < 0) + if (rc < 0) { + tpm_tis_relinquish_locality(chip, priv->locality); return rc; + } rc = tpm_tis_write8(priv, TPM_INT_VECTOR(priv->locality), irq); if (rc < 0) - return rc; + goto restore_irqs; rc = tpm_tis_read32(priv, TPM_INT_STATUS(priv->locality), &int_status); if (rc < 0) - return rc; + goto restore_irqs; /* Clear all existing */ rc = tpm_tis_write32(priv, TPM_INT_STATUS(priv->locality), int_status); if (rc < 0) - return rc; - + goto restore_irqs; /* Turn on */ rc = tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask | TPM_GLOBAL_INT_ENABLE); if (rc < 0) - return rc; + goto restore_irqs; - priv->irq_tested = false; + clear_bit(TPM_TIS_IRQ_TESTED, &priv->flags); /* Generate an interrupt by having the core call through to * tpm_tis_send */ - rc = tpm_tis_gen_interrupt(chip); - if (rc < 0) - return rc; + tpm_tis_gen_interrupt(chip); +restore_irqs: /* tpm_tis_send will either confirm the interrupt is working or it * will call disable_irq which undoes all of the above. */ if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) { - rc = tpm_tis_write8(priv, original_int_vec, - TPM_INT_VECTOR(priv->locality)); - if (rc < 0) - return rc; - - return 1; + tpm_tis_write8(priv, original_int_vec, + TPM_INT_VECTOR(priv->locality)); + rc = -1; } - return 0; + tpm_tis_relinquish_locality(chip, priv->locality); + + return rc; } /* Try to find the IRQ the TPM is using. This is for legacy x86 systems that @@ -932,8 +989,8 @@ static const struct tpm_class_ops tpm_tis = { .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, .req_canceled = tpm_tis_req_canceled, - .request_locality = request_locality, - .relinquish_locality = release_locality, + .request_locality = tpm_tis_request_locality, + .relinquish_locality = tpm_tis_relinquish_locality, .clk_enable = tpm_tis_clkrun_enable, }; @@ -967,6 +1024,8 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, priv->timeout_min = TPM_TIMEOUT_USECS_MIN; priv->timeout_max = TPM_TIMEOUT_USECS_MAX; priv->phy_ops = phy_ops; + priv->locality_count = 0; + mutex_init(&priv->locality_count_mutex); dev_set_drvdata(&chip->dev, priv); @@ -1009,18 +1068,50 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, if (rc < 0) goto out_err; - intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT | - TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT; + /* Figure out the capabilities */ + rc = tpm_tis_read32(priv, TPM_INTF_CAPS(priv->locality), &intfcaps); + if (rc < 0) + goto out_err; + + dev_dbg(dev, "TPM interface capabilities (0x%x):\n", + intfcaps); + if (intfcaps & TPM_INTF_BURST_COUNT_STATIC) + dev_dbg(dev, "\tBurst Count Static\n"); + if (intfcaps & TPM_INTF_CMD_READY_INT) { + intmask |= TPM_INTF_CMD_READY_INT; + dev_dbg(dev, "\tCommand Ready Int Support\n"); + } + if (intfcaps & TPM_INTF_INT_EDGE_FALLING) + dev_dbg(dev, "\tInterrupt Edge Falling\n"); + if (intfcaps & TPM_INTF_INT_EDGE_RISING) + dev_dbg(dev, "\tInterrupt Edge Rising\n"); + if (intfcaps & TPM_INTF_INT_LEVEL_LOW) + dev_dbg(dev, "\tInterrupt Level Low\n"); + if (intfcaps & TPM_INTF_INT_LEVEL_HIGH) + dev_dbg(dev, "\tInterrupt Level High\n"); + if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT) { + intmask |= TPM_INTF_LOCALITY_CHANGE_INT; + dev_dbg(dev, "\tLocality Change Int Support\n"); + } + if (intfcaps & TPM_INTF_STS_VALID_INT) { + intmask |= TPM_INTF_STS_VALID_INT; + dev_dbg(dev, "\tSts Valid Int Support\n"); + } + if (intfcaps & TPM_INTF_DATA_AVAIL_INT) { + intmask |= TPM_INTF_DATA_AVAIL_INT; + dev_dbg(dev, "\tData Avail Int Support\n"); + } + intmask &= ~TPM_GLOBAL_INT_ENABLE; - rc = request_locality(chip, 0); + rc = tpm_tis_request_locality(chip, 0); if (rc < 0) { rc = -ENODEV; goto out_err; } tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask); - release_locality(chip, 0); + tpm_tis_relinquish_locality(chip, 0); rc = tpm_chip_start(chip); if (rc) @@ -1044,35 +1135,14 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, goto out_err; } - /* Figure out the capabilities */ - rc = tpm_tis_read32(priv, TPM_INTF_CAPS(priv->locality), &intfcaps); - if (rc < 0) - goto out_err; - - dev_dbg(dev, "TPM interface capabilities (0x%x):\n", - intfcaps); - if (intfcaps & TPM_INTF_BURST_COUNT_STATIC) - dev_dbg(dev, "\tBurst Count Static\n"); - if (intfcaps & TPM_INTF_CMD_READY_INT) - dev_dbg(dev, "\tCommand Ready Int Support\n"); - if (intfcaps & TPM_INTF_INT_EDGE_FALLING) - dev_dbg(dev, "\tInterrupt Edge Falling\n"); - if (intfcaps & TPM_INTF_INT_EDGE_RISING) - dev_dbg(dev, "\tInterrupt Edge Rising\n"); - if (intfcaps & TPM_INTF_INT_LEVEL_LOW) - dev_dbg(dev, "\tInterrupt Level Low\n"); - if (intfcaps & TPM_INTF_INT_LEVEL_HIGH) - dev_dbg(dev, "\tInterrupt Level High\n"); - if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT) - dev_dbg(dev, "\tLocality Change Int Support\n"); - if (intfcaps & TPM_INTF_STS_VALID_INT) - dev_dbg(dev, "\tSts Valid Int Support\n"); - if (intfcaps & TPM_INTF_DATA_AVAIL_INT) - dev_dbg(dev, "\tData Avail Int Support\n"); - /* INTERRUPT Setup */ init_waitqueue_head(&priv->read_queue); init_waitqueue_head(&priv->int_queue); + + rc = tpm_chip_startup(chip); + if (rc) + goto out_err; + if (irq != -1) { /* * Before doing irq testing issue a command to the TPM in polling mode @@ -1080,13 +1150,13 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, * proper timeouts for the driver. */ - rc = request_locality(chip, 0); + rc = tpm_tis_request_locality(chip, 0); if (rc < 0) goto out_err; rc = tpm_get_timeouts(chip); - release_locality(chip, 0); + tpm_tis_relinquish_locality(chip, 0); if (rc) { dev_err(dev, "Could not get TPM timeouts and durations\n"); @@ -1094,17 +1164,23 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, goto out_err; } - if (irq) { + if (irq) tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED, irq); - if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) { - dev_err(&chip->dev, FW_BUG - "TPM interrupt not working, polling instead\n"); + else + tpm_tis_probe_irq(chip, intmask); - disable_interrupts(chip); - } + if (chip->flags & TPM_CHIP_FLAG_IRQ) { + priv->int_mask = intmask; } else { - tpm_tis_probe_irq(chip, intmask); + dev_err(&chip->dev, FW_BUG + "TPM interrupt not working, polling instead\n"); + + rc = tpm_tis_request_locality(chip, 0); + if (rc < 0) + goto out_err; + disable_interrupts(chip); + tpm_tis_relinquish_locality(chip, 0); } } @@ -1143,13 +1219,7 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) if (rc < 0) goto out; - rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask); - if (rc < 0) - goto out; - - intmask |= TPM_INTF_CMD_READY_INT - | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT - | TPM_INTF_STS_VALID_INT | TPM_GLOBAL_INT_ENABLE; + intmask = priv->int_mask | TPM_GLOBAL_INT_ENABLE; tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask); @@ -1165,28 +1235,27 @@ int tpm_tis_resume(struct device *dev) struct tpm_chip *chip = dev_get_drvdata(dev); int ret; + ret = tpm_tis_request_locality(chip, 0); + if (ret < 0) + return ret; + if (chip->flags & TPM_CHIP_FLAG_IRQ) tpm_tis_reenable_interrupts(chip); ret = tpm_pm_resume(dev); if (ret) - return ret; + goto out; /* * TPM 1.2 requires self-test on resume. This function actually returns * an error code but for unknown reason it isn't handled. */ - if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { - ret = request_locality(chip, 0); - if (ret < 0) - return ret; - + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) tpm1_do_selftest(chip); +out: + tpm_tis_relinquish_locality(chip, 0); - release_locality(chip, 0); - } - - return 0; + return ret; } EXPORT_SYMBOL_GPL(tpm_tis_resume); #endif diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h index b68479e0de10..e978f457fd4d 100644 --- a/drivers/char/tpm/tpm_tis_core.h +++ b/drivers/char/tpm/tpm_tis_core.h @@ -87,13 +87,16 @@ enum tpm_tis_flags { TPM_TIS_ITPM_WORKAROUND = BIT(0), TPM_TIS_INVALID_STATUS = BIT(1), TPM_TIS_DEFAULT_CANCELLATION = BIT(2), + TPM_TIS_IRQ_TESTED = BIT(3), }; struct tpm_tis_data { u16 manufacturer_id; + struct mutex locality_count_mutex; + unsigned int locality_count; int locality; int irq; - bool irq_tested; + unsigned int int_mask; unsigned long flags; void __iomem *ilb_base_addr; u16 clkrun_enabled; diff --git a/drivers/char/tpm/tpm_tis_i2c_cr50.c b/drivers/char/tpm/tpm_tis_i2c_cr50.c index 77cea5b31c6e..376ae18a04eb 100644 --- a/drivers/char/tpm/tpm_tis_i2c_cr50.c +++ b/drivers/char/tpm/tpm_tis_i2c_cr50.c @@ -100,8 +100,7 @@ static int tpm_cr50_i2c_wait_tpm_ready(struct tpm_chip *chip) } /* Wait for interrupt to indicate TPM is ready to respond */ - if (!wait_for_completion_timeout(&priv->tpm_ready, - msecs_to_jiffies(chip->timeout_a))) { + if (!wait_for_completion_timeout(&priv->tpm_ready, chip->timeout_a)) { dev_warn(&chip->dev, "Timeout waiting for TPM ready\n"); return -ETIMEDOUT; } diff --git a/drivers/char/tpm/tpm_tis_spi_main.c b/drivers/char/tpm/tpm_tis_spi_main.c index a0963a3e92bd..1f5207974a17 100644 --- a/drivers/char/tpm/tpm_tis_spi_main.c +++ b/drivers/char/tpm/tpm_tis_spi_main.c @@ -231,7 +231,7 @@ static const struct spi_device_id tpm_tis_spi_id[] = { }; MODULE_DEVICE_TABLE(spi, tpm_tis_spi_id); -static const struct of_device_id of_tis_spi_match[] = { +static const struct of_device_id of_tis_spi_match[] __maybe_unused = { { .compatible = "st,st33htpm-spi", .data = tpm_tis_spi_probe }, { .compatible = "infineon,slb9670", .data = tpm_tis_spi_probe }, { .compatible = "tcg,tpm_tis-spi", .data = tpm_tis_spi_probe }, @@ -240,7 +240,7 @@ static const struct of_device_id of_tis_spi_match[] = { }; MODULE_DEVICE_TABLE(of, of_tis_spi_match); -static const struct acpi_device_id acpi_tis_spi_match[] = { +static const struct acpi_device_id acpi_tis_spi_match[] __maybe_unused = { {"SMO0768", 0}, {} }; diff --git a/drivers/char/tpm/tpm_tis_synquacer.c b/drivers/char/tpm/tpm_tis_synquacer.c index 679196c61401..49278746b0e2 100644 --- a/drivers/char/tpm/tpm_tis_synquacer.c +++ b/drivers/char/tpm/tpm_tis_synquacer.c @@ -127,14 +127,12 @@ static int tpm_tis_synquacer_probe(struct platform_device *pdev) return tpm_tis_synquacer_init(&pdev->dev, &tpm_info); } -static int tpm_tis_synquacer_remove(struct platform_device *pdev) +static void tpm_tis_synquacer_remove(struct platform_device *pdev) { struct tpm_chip *chip = dev_get_drvdata(&pdev->dev); tpm_chip_unregister(chip); tpm_tis_remove(chip); - - return 0; } #ifdef CONFIG_OF @@ -155,7 +153,7 @@ MODULE_DEVICE_TABLE(acpi, tpm_synquacer_acpi_tbl); static struct platform_driver tis_synquacer_drv = { .probe = tpm_tis_synquacer_probe, - .remove = tpm_tis_synquacer_remove, + .remove_new = tpm_tis_synquacer_remove, .driver = { .name = "tpm_tis_synquacer", .pm = &tpm_tis_synquacer_pm, diff --git a/drivers/clk/clk-renesas-pcie.c b/drivers/clk/clk-renesas-pcie.c index f91f30560820..ff3a52d48479 100644 --- a/drivers/clk/clk-renesas-pcie.c +++ b/drivers/clk/clk-renesas-pcie.c @@ -143,8 +143,9 @@ static int rs9_regmap_i2c_read(void *context, static const struct regmap_config rs9_regmap_config = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_NONE, + .cache_type = REGCACHE_FLAT, .max_register = RS9_REG_BCP, + .num_reg_defaults_raw = 0x8, .rd_table = &rs9_readable_table, .wr_table = &rs9_writeable_table, .reg_write = rs9_regmap_i2c_write, diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c index 2836adb817b7..e3696a88b5a3 100644 --- a/drivers/clk/imx/clk-imx6ul.c +++ b/drivers/clk/imx/clk-imx6ul.c @@ -95,14 +95,16 @@ static const struct clk_div_table video_div_table[] = { { } }; -static const char * enet1_ref_sels[] = { "enet1_ref_125m", "enet1_ref_pad", }; +static const char * enet1_ref_sels[] = { "enet1_ref_125m", "enet1_ref_pad", "dummy", "dummy"}; static const u32 enet1_ref_sels_table[] = { IMX6UL_GPR1_ENET1_TX_CLK_DIR, - IMX6UL_GPR1_ENET1_CLK_SEL }; + IMX6UL_GPR1_ENET1_CLK_SEL, 0, + IMX6UL_GPR1_ENET1_TX_CLK_DIR | IMX6UL_GPR1_ENET1_CLK_SEL }; static const u32 enet1_ref_sels_table_mask = IMX6UL_GPR1_ENET1_TX_CLK_DIR | IMX6UL_GPR1_ENET1_CLK_SEL; -static const char * enet2_ref_sels[] = { "enet2_ref_125m", "enet2_ref_pad", }; +static const char * enet2_ref_sels[] = { "enet2_ref_125m", "enet2_ref_pad", "dummy", "dummy"}; static const u32 enet2_ref_sels_table[] = { IMX6UL_GPR1_ENET2_TX_CLK_DIR, - IMX6UL_GPR1_ENET2_CLK_SEL }; + IMX6UL_GPR1_ENET2_CLK_SEL, 0, + IMX6UL_GPR1_ENET2_TX_CLK_DIR | IMX6UL_GPR1_ENET2_CLK_SEL }; static const u32 enet2_ref_sels_table_mask = IMX6UL_GPR1_ENET2_TX_CLK_DIR | IMX6UL_GPR1_ENET2_CLK_SEL; diff --git a/drivers/clk/sprd/common.c b/drivers/clk/sprd/common.c index ce81e4087a8f..2bfbab8db94b 100644 --- a/drivers/clk/sprd/common.c +++ b/drivers/clk/sprd/common.c @@ -17,7 +17,6 @@ static const struct regmap_config sprdclk_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = 0xffff, .fast_io = true, }; @@ -43,6 +42,8 @@ int sprd_clk_regmap_init(struct platform_device *pdev, struct device *dev = &pdev->dev; struct device_node *node = dev->of_node, *np; struct regmap *regmap; + struct resource *res; + struct regmap_config reg_config = sprdclk_regmap_config; if (of_find_property(node, "sprd,syscon", NULL)) { regmap = syscon_regmap_lookup_by_phandle(node, "sprd,syscon"); @@ -59,12 +60,14 @@ int sprd_clk_regmap_init(struct platform_device *pdev, return PTR_ERR(regmap); } } else { - base = devm_platform_ioremap_resource(pdev, 0); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) return PTR_ERR(base); + reg_config.max_register = resource_size(res) - reg_config.reg_stride; + regmap = devm_regmap_init_mmio(&pdev->dev, base, - &sprdclk_regmap_config); + ®_config); if (IS_ERR(regmap)) { pr_err("failed to init regmap\n"); return PTR_ERR(regmap); diff --git a/drivers/clocksource/timer-clint.c b/drivers/clocksource/timer-clint.c index 6cfe2ab73eb0..9a55e733ae99 100644 --- a/drivers/clocksource/timer-clint.c +++ b/drivers/clocksource/timer-clint.c @@ -17,6 +17,9 @@ #include <linux/sched_clock.h> #include <linux/io-64-nonatomic-lo-hi.h> #include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/irqdomain.h> #include <linux/of_irq.h> #include <linux/smp.h> #include <linux/timex.h> @@ -31,6 +34,7 @@ /* CLINT manages IPI and Timer for RISC-V M-mode */ static u32 __iomem *clint_ipi_base; +static unsigned int clint_ipi_irq; static u64 __iomem *clint_timer_cmp; static u64 __iomem *clint_timer_val; static unsigned long clint_timer_freq; @@ -41,12 +45,10 @@ u64 __iomem *clint_time_val; EXPORT_SYMBOL(clint_time_val); #endif -static void clint_send_ipi(const struct cpumask *target) +#ifdef CONFIG_SMP +static void clint_send_ipi(unsigned int cpu) { - unsigned int cpu; - - for_each_cpu(cpu, target) - writel(1, clint_ipi_base + cpuid_to_hartid_map(cpu)); + writel(1, clint_ipi_base + cpuid_to_hartid_map(cpu)); } static void clint_clear_ipi(void) @@ -54,10 +56,18 @@ static void clint_clear_ipi(void) writel(0, clint_ipi_base + cpuid_to_hartid_map(smp_processor_id())); } -static struct riscv_ipi_ops clint_ipi_ops = { - .ipi_inject = clint_send_ipi, - .ipi_clear = clint_clear_ipi, -}; +static void clint_ipi_interrupt(struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + + chained_irq_enter(chip, desc); + + clint_clear_ipi(); + ipi_mux_process(); + + chained_irq_exit(chip, desc); +} +#endif #ifdef CONFIG_64BIT #define clint_get_cycles() readq_relaxed(clint_timer_val) @@ -125,12 +135,19 @@ static int clint_timer_starting_cpu(unsigned int cpu) enable_percpu_irq(clint_timer_irq, irq_get_trigger_type(clint_timer_irq)); + enable_percpu_irq(clint_ipi_irq, + irq_get_trigger_type(clint_ipi_irq)); return 0; } static int clint_timer_dying_cpu(unsigned int cpu) { disable_percpu_irq(clint_timer_irq); + /* + * Don't disable IPI when CPU goes offline because + * the masking/unmasking of virtual IPIs is done + * via generic IPI-Mux + */ return 0; } @@ -170,6 +187,12 @@ static int __init clint_timer_init_dt(struct device_node *np) return -ENODEV; } + /* Find parent irq domain and map ipi irq */ + if (!clint_ipi_irq && + oirq.args[0] == RV_IRQ_SOFT && + irq_find_host(oirq.np)) + clint_ipi_irq = irq_of_parse_and_map(np, i); + /* Find parent irq domain and map timer irq */ if (!clint_timer_irq && oirq.args[0] == RV_IRQ_TIMER && @@ -177,9 +200,9 @@ static int __init clint_timer_init_dt(struct device_node *np) clint_timer_irq = irq_of_parse_and_map(np, i); } - /* If CLINT timer irq not found then fail */ - if (!clint_timer_irq) { - pr_err("%pOFP: timer irq not found\n", np); + /* If CLINT ipi or timer irq not found then fail */ + if (!clint_ipi_irq || !clint_timer_irq) { + pr_err("%pOFP: ipi/timer irq not found\n", np); return -ENODEV; } @@ -219,6 +242,19 @@ static int __init clint_timer_init_dt(struct device_node *np) goto fail_iounmap; } +#ifdef CONFIG_SMP + rc = ipi_mux_create(BITS_PER_BYTE, clint_send_ipi); + if (rc <= 0) { + pr_err("unable to create muxed IPIs\n"); + rc = (rc < 0) ? rc : -ENODEV; + goto fail_free_irq; + } + + irq_set_chained_handler(clint_ipi_irq, clint_ipi_interrupt); + riscv_ipi_set_virq_range(rc, BITS_PER_BYTE, true); + clint_clear_ipi(); +#endif + rc = cpuhp_setup_state(CPUHP_AP_CLINT_TIMER_STARTING, "clockevents/clint/timer:starting", clint_timer_starting_cpu, @@ -228,13 +264,10 @@ static int __init clint_timer_init_dt(struct device_node *np) goto fail_free_irq; } - riscv_set_ipi_ops(&clint_ipi_ops); - clint_clear_ipi(); - return 0; fail_free_irq: - free_irq(clint_timer_irq, &clint_clock_event); + free_percpu_irq(clint_timer_irq, &clint_clock_event); fail_iounmap: iounmap(base); return rc; diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c index deed4afadb29..d9cb937665cf 100644 --- a/drivers/counter/104-quad-8.c +++ b/drivers/counter/104-quad-8.c @@ -97,10 +97,6 @@ struct quad8 { struct quad8_reg __iomem *reg; }; -/* Borrow Toggle flip-flop */ -#define QUAD8_FLAG_BT BIT(0) -/* Carry Toggle flip-flop */ -#define QUAD8_FLAG_CT BIT(1) /* Error flag */ #define QUAD8_FLAG_E BIT(4) /* Up/Down flag */ @@ -133,6 +129,9 @@ struct quad8 { #define QUAD8_CMR_QUADRATURE_X2 0x10 #define QUAD8_CMR_QUADRATURE_X4 0x18 +/* Each Counter is 24 bits wide */ +#define LS7267_CNTR_MAX GENMASK(23, 0) + static int quad8_signal_read(struct counter_device *counter, struct counter_signal *signal, enum counter_signal_level *level) @@ -156,18 +155,10 @@ static int quad8_count_read(struct counter_device *counter, { struct quad8 *const priv = counter_priv(counter); struct channel_reg __iomem *const chan = priv->reg->channel + count->id; - unsigned int flags; - unsigned int borrow; - unsigned int carry; unsigned long irqflags; int i; - flags = ioread8(&chan->control); - borrow = flags & QUAD8_FLAG_BT; - carry = !!(flags & QUAD8_FLAG_CT); - - /* Borrow XOR Carry effectively doubles count range */ - *val = (unsigned long)(borrow ^ carry) << 24; + *val = 0; spin_lock_irqsave(&priv->lock, irqflags); @@ -191,8 +182,7 @@ static int quad8_count_write(struct counter_device *counter, unsigned long irqflags; int i; - /* Only 24-bit values are supported */ - if (val > 0xFFFFFF) + if (val > LS7267_CNTR_MAX) return -ERANGE; spin_lock_irqsave(&priv->lock, irqflags); @@ -378,7 +368,7 @@ static int quad8_action_read(struct counter_device *counter, /* Handle Index signals */ if (synapse->signal->id >= 16) { - if (priv->preset_enable[count->id]) + if (!priv->preset_enable[count->id]) *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE; else *action = COUNTER_SYNAPSE_ACTION_NONE; @@ -806,8 +796,7 @@ static int quad8_count_preset_write(struct counter_device *counter, struct quad8 *const priv = counter_priv(counter); unsigned long irqflags; - /* Only 24-bit values are supported */ - if (preset > 0xFFFFFF) + if (preset > LS7267_CNTR_MAX) return -ERANGE; spin_lock_irqsave(&priv->lock, irqflags); @@ -834,8 +823,7 @@ static int quad8_count_ceiling_read(struct counter_device *counter, *ceiling = priv->preset[count->id]; break; default: - /* By default 0x1FFFFFF (25 bits unsigned) is maximum count */ - *ceiling = 0x1FFFFFF; + *ceiling = LS7267_CNTR_MAX; break; } @@ -850,8 +838,7 @@ static int quad8_count_ceiling_write(struct counter_device *counter, struct quad8 *const priv = counter_priv(counter); unsigned long irqflags; - /* Only 24-bit values are supported */ - if (ceiling > 0xFFFFFF) + if (ceiling > LS7267_CNTR_MAX) return -ERANGE; spin_lock_irqsave(&priv->lock, irqflags); diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c index 73c7643b2697..8dd46fad151e 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c @@ -840,22 +840,20 @@ static int amd_pstate_update_status(const char *buf, size_t size) switch(mode_idx) { case AMD_PSTATE_DISABLE: - if (!current_pstate_driver) - return -EINVAL; - if (cppc_state == AMD_PSTATE_ACTIVE) - return -EBUSY; - cpufreq_unregister_driver(current_pstate_driver); - amd_pstate_driver_cleanup(); + if (current_pstate_driver) { + cpufreq_unregister_driver(current_pstate_driver); + amd_pstate_driver_cleanup(); + } break; case AMD_PSTATE_PASSIVE: if (current_pstate_driver) { if (current_pstate_driver == &amd_pstate_driver) return 0; cpufreq_unregister_driver(current_pstate_driver); - cppc_state = AMD_PSTATE_PASSIVE; - current_pstate_driver = &amd_pstate_driver; } + current_pstate_driver = &amd_pstate_driver; + cppc_state = AMD_PSTATE_PASSIVE; ret = cpufreq_register_driver(current_pstate_driver); break; case AMD_PSTATE_ACTIVE: @@ -863,10 +861,10 @@ static int amd_pstate_update_status(const char *buf, size_t size) if (current_pstate_driver == &amd_pstate_epp_driver) return 0; cpufreq_unregister_driver(current_pstate_driver); - current_pstate_driver = &amd_pstate_epp_driver; - cppc_state = AMD_PSTATE_ACTIVE; } + current_pstate_driver = &amd_pstate_epp_driver; + cppc_state = AMD_PSTATE_ACTIVE; ret = cpufreq_register_driver(current_pstate_driver); break; default: diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index e2f25926eb51..e346c00b132a 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -442,12 +442,19 @@ static int __sev_init_ex_locked(int *error) return __sev_do_cmd_locked(SEV_CMD_INIT_EX, &data, error); } +static inline int __sev_do_init_locked(int *psp_ret) +{ + if (sev_init_ex_buffer) + return __sev_init_ex_locked(psp_ret); + else + return __sev_init_locked(psp_ret); +} + static int __sev_platform_init_locked(int *error) { + int rc = 0, psp_ret = SEV_RET_NO_FW_CALL; struct psp_device *psp = psp_master; struct sev_device *sev; - int rc = 0, psp_ret = -1; - int (*init_function)(int *error); if (!psp || !psp->sev_data) return -ENODEV; @@ -458,15 +465,12 @@ static int __sev_platform_init_locked(int *error) return 0; if (sev_init_ex_buffer) { - init_function = __sev_init_ex_locked; rc = sev_read_init_ex_file(); if (rc) return rc; - } else { - init_function = __sev_init_locked; } - rc = init_function(&psp_ret); + rc = __sev_do_init_locked(&psp_ret); if (rc && psp_ret == SEV_RET_SECURE_DATA_INVALID) { /* * Initialization command returned an integrity check failure @@ -475,9 +479,11 @@ static int __sev_platform_init_locked(int *error) * initialization function should succeed by replacing the state * with a reset state. */ - dev_err(sev->dev, "SEV: retrying INIT command because of SECURE_DATA_INVALID error. Retrying once to reset PSP SEV state."); - rc = init_function(&psp_ret); + dev_err(sev->dev, +"SEV: retrying INIT command because of SECURE_DATA_INVALID error. Retrying once to reset PSP SEV state."); + rc = __sev_do_init_locked(&psp_ret); } + if (error) *error = psp_ret; diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index 45deda18ed32..02cc2c38b44b 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -101,25 +101,40 @@ static int map_hdm_decoder_regs(struct cxl_port *port, void __iomem *crb, BIT(CXL_CM_CAP_CAP_ID_HDM)); } -static struct cxl_hdm *devm_cxl_setup_emulated_hdm(struct cxl_port *port, - struct cxl_endpoint_dvsec_info *info) +static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info) { - struct device *dev = &port->dev; struct cxl_hdm *cxlhdm; + void __iomem *hdm; + u32 ctrl; + int i; - if (!info->mem_enabled) - return ERR_PTR(-ENODEV); + if (!info) + return false; - cxlhdm = devm_kzalloc(dev, sizeof(*cxlhdm), GFP_KERNEL); - if (!cxlhdm) - return ERR_PTR(-ENOMEM); + cxlhdm = dev_get_drvdata(&info->port->dev); + hdm = cxlhdm->regs.hdm_decoder; - cxlhdm->port = port; - cxlhdm->decoder_count = info->ranges; - cxlhdm->target_count = info->ranges; - dev_set_drvdata(&port->dev, cxlhdm); + if (!hdm) + return true; - return cxlhdm; + /* + * If HDM decoders are present and the driver is in control of + * Mem_Enable skip DVSEC based emulation + */ + if (!info->mem_enabled) + return false; + + /* + * If any decoders are committed already, there should not be any + * emulated DVSEC decoders. + */ + for (i = 0; i < cxlhdm->decoder_count; i++) { + ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(i)); + if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl)) + return false; + } + + return true; } /** @@ -138,13 +153,14 @@ struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port, cxlhdm = devm_kzalloc(dev, sizeof(*cxlhdm), GFP_KERNEL); if (!cxlhdm) return ERR_PTR(-ENOMEM); - cxlhdm->port = port; - crb = ioremap(port->component_reg_phys, CXL_COMPONENT_REG_BLOCK_SIZE); - if (!crb) { - if (info && info->mem_enabled) - return devm_cxl_setup_emulated_hdm(port, info); + dev_set_drvdata(dev, cxlhdm); + crb = ioremap(port->component_reg_phys, CXL_COMPONENT_REG_BLOCK_SIZE); + if (!crb && info && info->mem_enabled) { + cxlhdm->decoder_count = info->ranges; + return cxlhdm; + } else if (!crb) { dev_err(dev, "No component registers mapped\n"); return ERR_PTR(-ENXIO); } @@ -160,7 +176,15 @@ struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port, return ERR_PTR(-ENXIO); } - dev_set_drvdata(dev, cxlhdm); + /* + * Now that the hdm capability is parsed, decide if range + * register emulation is needed and fixup cxlhdm accordingly. + */ + if (should_emulate_decoders(info)) { + dev_dbg(dev, "Fallback map %d range register%s\n", info->ranges, + info->ranges > 1 ? "s" : ""); + cxlhdm->decoder_count = info->ranges; + } return cxlhdm; } @@ -714,14 +738,20 @@ static int cxl_decoder_reset(struct cxl_decoder *cxld) return 0; } -static int cxl_setup_hdm_decoder_from_dvsec(struct cxl_port *port, - struct cxl_decoder *cxld, int which, - struct cxl_endpoint_dvsec_info *info) +static int cxl_setup_hdm_decoder_from_dvsec( + struct cxl_port *port, struct cxl_decoder *cxld, u64 *dpa_base, + int which, struct cxl_endpoint_dvsec_info *info) { + struct cxl_endpoint_decoder *cxled; + u64 len; + int rc; + if (!is_cxl_endpoint(port)) return -EOPNOTSUPP; - if (!range_len(&info->dvsec_range[which])) + cxled = to_cxl_endpoint_decoder(&cxld->dev); + len = range_len(&info->dvsec_range[which]); + if (!len) return -ENOENT; cxld->target_type = CXL_DECODER_EXPANDER; @@ -736,40 +766,24 @@ static int cxl_setup_hdm_decoder_from_dvsec(struct cxl_port *port, cxld->flags |= CXL_DECODER_F_ENABLE | CXL_DECODER_F_LOCK; port->commit_end = cxld->id; - return 0; -} - -static bool should_emulate_decoders(struct cxl_port *port) -{ - struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev); - void __iomem *hdm = cxlhdm->regs.hdm_decoder; - u32 ctrl; - int i; - - if (!is_cxl_endpoint(cxlhdm->port)) - return false; - - if (!hdm) - return true; - - /* - * If any decoders are committed already, there should not be any - * emulated DVSEC decoders. - */ - for (i = 0; i < cxlhdm->decoder_count; i++) { - ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(i)); - if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl)) - return false; + rc = devm_cxl_dpa_reserve(cxled, *dpa_base, len, 0); + if (rc) { + dev_err(&port->dev, + "decoder%d.%d: Failed to reserve DPA range %#llx - %#llx\n (%d)", + port->id, cxld->id, *dpa_base, *dpa_base + len - 1, rc); + return rc; } + *dpa_base += len; + cxled->state = CXL_DECODER_STATE_AUTO; - return true; + return 0; } static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, int *target_map, void __iomem *hdm, int which, u64 *dpa_base, struct cxl_endpoint_dvsec_info *info) { - struct cxl_endpoint_decoder *cxled = NULL; + struct cxl_endpoint_decoder *cxled; u64 size, base, skip, dpa_size; bool committed; u32 remainder; @@ -780,11 +794,9 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, unsigned char target_id[8]; } target_list; - if (should_emulate_decoders(port)) - return cxl_setup_hdm_decoder_from_dvsec(port, cxld, which, info); - - if (is_endpoint_decoder(&cxld->dev)) - cxled = to_cxl_endpoint_decoder(&cxld->dev); + if (should_emulate_decoders(info)) + return cxl_setup_hdm_decoder_from_dvsec(port, cxld, dpa_base, + which, info); ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(which)); base = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(which)); @@ -806,9 +818,6 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, .end = base + size - 1, }; - if (cxled && !committed && range_len(&info->dvsec_range[which])) - return cxl_setup_hdm_decoder_from_dvsec(port, cxld, which, info); - /* decoders are enabled if committed */ if (committed) { cxld->flags |= CXL_DECODER_F_ENABLE; @@ -846,7 +855,7 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, if (rc) return rc; - if (!cxled) { + if (!info) { target_list.value = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_TL_LOW(which)); for (i = 0; i < cxld->interleave_ways; i++) @@ -866,6 +875,7 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, return -ENXIO; } skip = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_SKIP_LOW(which)); + cxled = to_cxl_endpoint_decoder(&cxld->dev); rc = devm_cxl_dpa_reserve(cxled, *dpa_base + skip, dpa_size, skip); if (rc) { dev_err(&port->dev, diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index 7328a2552411..523d5b9fd7fc 100644 --- a/drivers/cxl/core/pci.c +++ b/drivers/cxl/core/pci.c @@ -462,7 +462,7 @@ static struct pci_doe_mb *find_cdat_doe(struct device *uport) return NULL; } -#define CDAT_DOE_REQ(entry_handle) \ +#define CDAT_DOE_REQ(entry_handle) cpu_to_le32 \ (FIELD_PREP(CXL_DOE_TABLE_ACCESS_REQ_CODE, \ CXL_DOE_TABLE_ACCESS_REQ_CODE_READ) | \ FIELD_PREP(CXL_DOE_TABLE_ACCESS_TABLE_TYPE, \ @@ -475,8 +475,8 @@ static void cxl_doe_task_complete(struct pci_doe_task *task) } struct cdat_doe_task { - u32 request_pl; - u32 response_pl[32]; + __le32 request_pl; + __le32 response_pl[32]; struct completion c; struct pci_doe_task task; }; @@ -510,10 +510,10 @@ static int cxl_cdat_get_length(struct device *dev, return rc; } wait_for_completion(&t.c); - if (t.task.rv < sizeof(u32)) + if (t.task.rv < 2 * sizeof(__le32)) return -EIO; - *length = t.response_pl[1]; + *length = le32_to_cpu(t.response_pl[1]); dev_dbg(dev, "CDAT length %zu\n", *length); return 0; @@ -524,13 +524,13 @@ static int cxl_cdat_read_table(struct device *dev, struct cxl_cdat *cdat) { size_t length = cdat->length; - u32 *data = cdat->table; + __le32 *data = cdat->table; int entry_handle = 0; do { DECLARE_CDAT_DOE_TASK(CDAT_DOE_REQ(entry_handle), t); + struct cdat_entry_header *entry; size_t entry_dw; - u32 *entry; int rc; rc = pci_doe_submit_task(cdat_doe, &t.task); @@ -539,26 +539,34 @@ static int cxl_cdat_read_table(struct device *dev, return rc; } wait_for_completion(&t.c); - /* 1 DW header + 1 DW data min */ - if (t.task.rv < (2 * sizeof(u32))) + + /* 1 DW Table Access Response Header + CDAT entry */ + entry = (struct cdat_entry_header *)(t.response_pl + 1); + if ((entry_handle == 0 && + t.task.rv != sizeof(__le32) + sizeof(struct cdat_header)) || + (entry_handle > 0 && + (t.task.rv < sizeof(__le32) + sizeof(*entry) || + t.task.rv != sizeof(__le32) + le16_to_cpu(entry->length)))) return -EIO; /* Get the CXL table access header entry handle */ entry_handle = FIELD_GET(CXL_DOE_TABLE_ACCESS_ENTRY_HANDLE, - t.response_pl[0]); - entry = t.response_pl + 1; - entry_dw = t.task.rv / sizeof(u32); + le32_to_cpu(t.response_pl[0])); + entry_dw = t.task.rv / sizeof(__le32); /* Skip Header */ entry_dw -= 1; - entry_dw = min(length / sizeof(u32), entry_dw); + entry_dw = min(length / sizeof(__le32), entry_dw); /* Prevent length < 1 DW from causing a buffer overflow */ if (entry_dw) { - memcpy(data, entry, entry_dw * sizeof(u32)); - length -= entry_dw * sizeof(u32); + memcpy(data, entry, entry_dw * sizeof(__le32)); + length -= entry_dw * sizeof(__le32); data += entry_dw; } } while (entry_handle != CXL_DOE_TABLE_ACCESS_LAST_ENTRY); + /* Length in CDAT header may exceed concatenation of CDAT entries */ + cdat->length -= length; + return 0; } diff --git a/drivers/cxl/core/pmem.c b/drivers/cxl/core/pmem.c index c2e4b1093788..f8c38d997252 100644 --- a/drivers/cxl/core/pmem.c +++ b/drivers/cxl/core/pmem.c @@ -62,9 +62,9 @@ static int match_nvdimm_bridge(struct device *dev, void *data) return is_cxl_nvdimm_bridge(dev); } -struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *start) +struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_memdev *cxlmd) { - struct cxl_port *port = find_cxl_root(start); + struct cxl_port *port = find_cxl_root(dev_get_drvdata(&cxlmd->dev)); struct device *dev; if (!port) @@ -253,7 +253,7 @@ int devm_cxl_add_nvdimm(struct cxl_memdev *cxlmd) struct device *dev; int rc; - cxl_nvb = cxl_find_nvdimm_bridge(&cxlmd->dev); + cxl_nvb = cxl_find_nvdimm_bridge(cxlmd); if (!cxl_nvb) return -ENODEV; diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 8ee6b6e2e2a4..4d1f9c5b5029 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -823,41 +823,17 @@ static bool dev_is_cxl_root_child(struct device *dev) return false; } -/* Find a 2nd level CXL port that has a dport that is an ancestor of @match */ -static int match_root_child(struct device *dev, const void *match) +struct cxl_port *find_cxl_root(struct cxl_port *port) { - const struct device *iter = NULL; - struct cxl_dport *dport; - struct cxl_port *port; - - if (!dev_is_cxl_root_child(dev)) - return 0; - - port = to_cxl_port(dev); - iter = match; - while (iter) { - dport = cxl_find_dport_by_dev(port, iter); - if (dport) - break; - iter = iter->parent; - } - - return !!iter; -} + struct cxl_port *iter = port; -struct cxl_port *find_cxl_root(struct device *dev) -{ - struct device *port_dev; - struct cxl_port *root; + while (iter && !is_cxl_root(iter)) + iter = to_cxl_port(iter->dev.parent); - port_dev = bus_find_device(&cxl_bus_type, NULL, dev, match_root_child); - if (!port_dev) + if (!iter) return NULL; - - root = to_cxl_port(port_dev->parent); - get_device(&root->dev); - put_device(port_dev); - return root; + get_device(&iter->dev); + return iter; } EXPORT_SYMBOL_NS_GPL(find_cxl_root, CXL); diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index f29028148806..b2fd67fcebfb 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -134,9 +134,13 @@ static int cxl_region_decode_reset(struct cxl_region *cxlr, int count) struct cxl_endpoint_decoder *cxled = p->targets[i]; struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); struct cxl_port *iter = cxled_to_port(cxled); + struct cxl_dev_state *cxlds = cxlmd->cxlds; struct cxl_ep *ep; int rc = 0; + if (cxlds->rcd) + goto endpoint_reset; + while (!is_cxl_root(to_cxl_port(iter->dev.parent))) iter = to_cxl_port(iter->dev.parent); @@ -153,6 +157,7 @@ static int cxl_region_decode_reset(struct cxl_region *cxlr, int count) return rc; } +endpoint_reset: rc = cxled->cxld.reset(&cxled->cxld); if (rc) return rc; @@ -1199,6 +1204,7 @@ static void cxl_region_teardown_targets(struct cxl_region *cxlr) { struct cxl_region_params *p = &cxlr->params; struct cxl_endpoint_decoder *cxled; + struct cxl_dev_state *cxlds; struct cxl_memdev *cxlmd; struct cxl_port *iter; struct cxl_ep *ep; @@ -1214,6 +1220,10 @@ static void cxl_region_teardown_targets(struct cxl_region *cxlr) for (i = 0; i < p->nr_targets; i++) { cxled = p->targets[i]; cxlmd = cxled_to_memdev(cxled); + cxlds = cxlmd->cxlds; + + if (cxlds->rcd) + continue; iter = cxled_to_port(cxled); while (!is_cxl_root(to_cxl_port(iter->dev.parent))) @@ -1229,14 +1239,24 @@ static int cxl_region_setup_targets(struct cxl_region *cxlr) { struct cxl_region_params *p = &cxlr->params; struct cxl_endpoint_decoder *cxled; + struct cxl_dev_state *cxlds; + int i, rc, rch = 0, vh = 0; struct cxl_memdev *cxlmd; struct cxl_port *iter; struct cxl_ep *ep; - int i, rc; for (i = 0; i < p->nr_targets; i++) { cxled = p->targets[i]; cxlmd = cxled_to_memdev(cxled); + cxlds = cxlmd->cxlds; + + /* validate that all targets agree on topology */ + if (!cxlds->rcd) { + vh++; + } else { + rch++; + continue; + } iter = cxled_to_port(cxled); while (!is_cxl_root(to_cxl_port(iter->dev.parent))) @@ -1256,6 +1276,12 @@ static int cxl_region_setup_targets(struct cxl_region *cxlr) } } + if (rch && vh) { + dev_err(&cxlr->dev, "mismatched CXL topologies detected\n"); + cxl_region_teardown_targets(cxlr); + return -ENXIO; + } + return 0; } @@ -1648,6 +1674,7 @@ static int cxl_region_attach(struct cxl_region *cxlr, if (rc) goto err_decrement; p->state = CXL_CONFIG_ACTIVE; + set_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags); } cxled->cxld.interleave_ways = p->interleave_ways; @@ -1749,8 +1776,6 @@ static int attach_target(struct cxl_region *cxlr, down_read(&cxl_dpa_rwsem); rc = cxl_region_attach(cxlr, cxled, pos); - if (rc == 0) - set_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags); up_read(&cxl_dpa_rwsem); up_write(&cxl_region_rwsem); return rc; @@ -2251,7 +2276,7 @@ static struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr) * bridge for one device is the same for all. */ if (i == 0) { - cxl_nvb = cxl_find_nvdimm_bridge(&cxlmd->dev); + cxl_nvb = cxl_find_nvdimm_bridge(cxlmd); if (!cxl_nvb) { cxlr_pmem = ERR_PTR(-ENODEV); goto out; diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index f2b0962a552d..044a92d9813e 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -658,7 +658,7 @@ struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port); struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport, resource_size_t component_reg_phys, struct cxl_dport *parent_dport); -struct cxl_port *find_cxl_root(struct device *dev); +struct cxl_port *find_cxl_root(struct cxl_port *port); int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd); void cxl_bus_rescan(void); void cxl_bus_drain(void); @@ -695,13 +695,15 @@ int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint) /** * struct cxl_endpoint_dvsec_info - Cached DVSEC info - * @mem_enabled: cached value of mem_enabled in the DVSEC, PCIE_DEVICE + * @mem_enabled: cached value of mem_enabled in the DVSEC at init time * @ranges: Number of active HDM ranges this device uses. + * @port: endpoint port associated with this info instance * @dvsec_range: cached attributes of the ranges in the DVSEC, PCIE_DEVICE */ struct cxl_endpoint_dvsec_info { bool mem_enabled; int ranges; + struct cxl_port *port; struct range dvsec_range[2]; }; @@ -758,7 +760,7 @@ struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev); bool is_cxl_nvdimm(struct device *dev); bool is_cxl_nvdimm_bridge(struct device *dev); int devm_cxl_add_nvdimm(struct cxl_memdev *cxlmd); -struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *dev); +struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_memdev *cxlmd); #ifdef CONFIG_CXL_REGION bool is_cxl_pmem_region(struct device *dev); diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h index be6a2ef3cce3..0465ef963cd6 100644 --- a/drivers/cxl/cxlpci.h +++ b/drivers/cxl/cxlpci.h @@ -68,6 +68,20 @@ enum cxl_regloc_type { CXL_REGLOC_RBI_TYPES }; +struct cdat_header { + __le32 length; + u8 revision; + u8 checksum; + u8 reserved[6]; + __le32 sequence; +} __packed; + +struct cdat_entry_header { + u8 type; + u8 reserved; + __le16 length; +} __packed; + int devm_cxl_port_enumerate_dports(struct cxl_port *port); struct cxl_dev_state; int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm, diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c index 1049bb5ea496..22a7ab2bae7c 100644 --- a/drivers/cxl/port.c +++ b/drivers/cxl/port.c @@ -78,8 +78,8 @@ static int cxl_switch_port_probe(struct cxl_port *port) static int cxl_endpoint_port_probe(struct cxl_port *port) { + struct cxl_endpoint_dvsec_info info = { .port = port }; struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport); - struct cxl_endpoint_dvsec_info info = { 0 }; struct cxl_dev_state *cxlds = cxlmd->cxlds; struct cxl_hdm *cxlhdm; struct cxl_port *root; @@ -119,7 +119,7 @@ static int cxl_endpoint_port_probe(struct cxl_port *port) * This can't fail in practice as CXL root exit unregisters all * descendant ports and that in turn synchronizes with cxl_port_probe() */ - root = find_cxl_root(&cxlmd->dev); + root = find_cxl_root(port); /* * Now that all endpoint decoders are successfully enumerated, try to diff --git a/drivers/dma/apple-admac.c b/drivers/dma/apple-admac.c index 90f28bda29c8..4cf8da77bdd9 100644 --- a/drivers/dma/apple-admac.c +++ b/drivers/dma/apple-admac.c @@ -75,6 +75,7 @@ #define REG_TX_INTSTATE(idx) (0x0030 + (idx) * 4) #define REG_RX_INTSTATE(idx) (0x0040 + (idx) * 4) +#define REG_GLOBAL_INTSTATE(idx) (0x0050 + (idx) * 4) #define REG_CHAN_INTSTATUS(ch, idx) (0x8010 + (ch) * 0x200 + (idx) * 4) #define REG_CHAN_INTMASK(ch, idx) (0x8020 + (ch) * 0x200 + (idx) * 4) @@ -511,7 +512,10 @@ static int admac_terminate_all(struct dma_chan *chan) admac_stop_chan(adchan); admac_reset_rings(adchan); - adchan->current_tx = NULL; + if (adchan->current_tx) { + list_add_tail(&adchan->current_tx->node, &adchan->to_free); + adchan->current_tx = NULL; + } /* * Descriptors can only be freed after the tasklet * has been killed (in admac_synchronize). @@ -672,13 +676,14 @@ static void admac_handle_chan_int(struct admac_data *ad, int no) static irqreturn_t admac_interrupt(int irq, void *devid) { struct admac_data *ad = devid; - u32 rx_intstate, tx_intstate; + u32 rx_intstate, tx_intstate, global_intstate; int i; rx_intstate = readl_relaxed(ad->base + REG_RX_INTSTATE(ad->irq_index)); tx_intstate = readl_relaxed(ad->base + REG_TX_INTSTATE(ad->irq_index)); + global_intstate = readl_relaxed(ad->base + REG_GLOBAL_INTSTATE(ad->irq_index)); - if (!tx_intstate && !rx_intstate) + if (!tx_intstate && !rx_intstate && !global_intstate) return IRQ_NONE; for (i = 0; i < ad->nchannels; i += 2) { @@ -693,6 +698,12 @@ static irqreturn_t admac_interrupt(int irq, void *devid) rx_intstate >>= 1; } + if (global_intstate) { + dev_warn(ad->dev, "clearing unknown global interrupt flag: %x\n", + global_intstate); + writel_relaxed(~(u32) 0, ad->base + REG_GLOBAL_INTSTATE(ad->irq_index)); + } + return IRQ_HANDLED; } @@ -850,6 +861,9 @@ static int admac_probe(struct platform_device *pdev) dma->directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM); dma->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; + dma->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); dma->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index c24bca210104..826b98284fa1 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -1342,7 +1342,7 @@ int dmaenginem_async_device_register(struct dma_device *device) if (ret) return ret; - return devm_add_action(device->dev, dmaenginem_async_device_unregister, device); + return devm_add_action_or_reset(device->dev, dmaenginem_async_device_unregister, device); } EXPORT_SYMBOL(dmaenginem_async_device_register); diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c index 462109c61653..93ee298d52b8 100644 --- a/drivers/dma/xilinx/xdma.c +++ b/drivers/dma/xilinx/xdma.c @@ -277,7 +277,7 @@ failed: /** * xdma_xfer_start - Start DMA transfer - * @xdma_chan: DMA channel pointer + * @xchan: DMA channel pointer */ static int xdma_xfer_start(struct xdma_chan *xchan) { diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index e7e8e624a436..8b31cd54bdb6 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -2149,10 +2149,8 @@ static int altr_edac_a10_probe(struct platform_device *pdev) } edac->sb_irq = platform_get_irq(pdev, 0); - if (edac->sb_irq < 0) { - dev_err(&pdev->dev, "No SBERR IRQ resource\n"); + if (edac->sb_irq < 0) return edac->sb_irq; - } irq_set_chained_handler_and_data(edac->sb_irq, altr_edac_a10_irq_handler, @@ -2184,10 +2182,9 @@ static int altr_edac_a10_probe(struct platform_device *pdev) } #else edac->db_irq = platform_get_irq(pdev, 1); - if (edac->db_irq < 0) { - dev_err(&pdev->dev, "No DBERR IRQ resource\n"); + if (edac->db_irq < 0) return edac->db_irq; - } + irq_set_chained_handler_and_data(edac->db_irq, altr_edac_a10_irq_handler, edac); #endif @@ -2226,6 +2223,5 @@ static struct platform_driver altr_edac_a10_driver = { }; module_platform_driver(altr_edac_a10_driver); -MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Thor Thayer"); MODULE_DESCRIPTION("EDAC Driver for Altera Memories"); diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 5b42533f306a..5c4292e65b96 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -13,11 +13,9 @@ module_param(ecc_enable_override, int, 0644); static struct msr __percpu *msrs; -static struct amd64_family_type *fam_type; - -static inline u32 get_umc_reg(u32 reg) +static inline u32 get_umc_reg(struct amd64_pvt *pvt, u32 reg) { - if (!fam_type->flags.zn_regs_v2) + if (!pvt->flags.zn_regs_v2) return reg; switch (reg) { @@ -437,7 +435,7 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct, for (i = 0; i < pvt->csels[dct].m_cnt; i++) #define for_each_umc(i) \ - for (i = 0; i < fam_type->max_mcs; i++) + for (i = 0; i < pvt->max_mcs; i++) /* * @input_addr is an InputAddr associated with the node given by mci. Return the @@ -1258,40 +1256,102 @@ static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16); * Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs * are ECC capable. */ -static unsigned long determine_edac_cap(struct amd64_pvt *pvt) +static unsigned long dct_determine_edac_cap(struct amd64_pvt *pvt) { unsigned long edac_cap = EDAC_FLAG_NONE; u8 bit; - if (pvt->umc) { - u8 i, umc_en_mask = 0, dimm_ecc_en_mask = 0; + bit = (pvt->fam > 0xf || pvt->ext_model >= K8_REV_F) + ? 19 + : 17; - for_each_umc(i) { - if (!(pvt->umc[i].sdp_ctrl & UMC_SDP_INIT)) - continue; + if (pvt->dclr0 & BIT(bit)) + edac_cap = EDAC_FLAG_SECDED; - umc_en_mask |= BIT(i); + return edac_cap; +} - /* UMC Configuration bit 12 (DimmEccEn) */ - if (pvt->umc[i].umc_cfg & BIT(12)) - dimm_ecc_en_mask |= BIT(i); - } +static unsigned long umc_determine_edac_cap(struct amd64_pvt *pvt) +{ + u8 i, umc_en_mask = 0, dimm_ecc_en_mask = 0; + unsigned long edac_cap = EDAC_FLAG_NONE; - if (umc_en_mask == dimm_ecc_en_mask) - edac_cap = EDAC_FLAG_SECDED; - } else { - bit = (pvt->fam > 0xf || pvt->ext_model >= K8_REV_F) - ? 19 - : 17; + for_each_umc(i) { + if (!(pvt->umc[i].sdp_ctrl & UMC_SDP_INIT)) + continue; - if (pvt->dclr0 & BIT(bit)) - edac_cap = EDAC_FLAG_SECDED; + umc_en_mask |= BIT(i); + + /* UMC Configuration bit 12 (DimmEccEn) */ + if (pvt->umc[i].umc_cfg & BIT(12)) + dimm_ecc_en_mask |= BIT(i); } + if (umc_en_mask == dimm_ecc_en_mask) + edac_cap = EDAC_FLAG_SECDED; + return edac_cap; } -static void debug_display_dimm_sizes(struct amd64_pvt *, u8); +/* + * debug routine to display the memory sizes of all logical DIMMs and its + * CSROWs + */ +static void dct_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl) +{ + u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases; + u32 dbam = ctrl ? pvt->dbam1 : pvt->dbam0; + int dimm, size0, size1; + + if (pvt->fam == 0xf) { + /* K8 families < revF not supported yet */ + if (pvt->ext_model < K8_REV_F) + return; + + WARN_ON(ctrl != 0); + } + + if (pvt->fam == 0x10) { + dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1 + : pvt->dbam0; + dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? + pvt->csels[1].csbases : + pvt->csels[0].csbases; + } else if (ctrl) { + dbam = pvt->dbam0; + dcsb = pvt->csels[1].csbases; + } + edac_dbg(1, "F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n", + ctrl, dbam); + + edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:\n", ctrl); + + /* Dump memory sizes for DIMM and its CSROWs */ + for (dimm = 0; dimm < 4; dimm++) { + size0 = 0; + if (dcsb[dimm * 2] & DCSB_CS_ENABLE) + /* + * For F15m60h, we need multiplier for LRDIMM cs_size + * calculation. We pass dimm value to the dbam_to_cs + * mapper so we can find the multiplier from the + * corresponding DCSM. + */ + size0 = pvt->ops->dbam_to_cs(pvt, ctrl, + DBAM_DIMM(dimm, dbam), + dimm); + + size1 = 0; + if (dcsb[dimm * 2 + 1] & DCSB_CS_ENABLE) + size1 = pvt->ops->dbam_to_cs(pvt, ctrl, + DBAM_DIMM(dimm, dbam), + dimm); + + amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n", + dimm * 2, size0, + dimm * 2 + 1, size1); + } +} + static void debug_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan) { @@ -1334,7 +1394,7 @@ static void debug_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan) #define CS_EVEN (CS_EVEN_PRIMARY | CS_EVEN_SECONDARY) #define CS_ODD (CS_ODD_PRIMARY | CS_ODD_SECONDARY) -static int f17_get_cs_mode(int dimm, u8 ctrl, struct amd64_pvt *pvt) +static int umc_get_cs_mode(int dimm, u8 ctrl, struct amd64_pvt *pvt) { u8 base, count = 0; int cs_mode = 0; @@ -1366,7 +1426,85 @@ static int f17_get_cs_mode(int dimm, u8 ctrl, struct amd64_pvt *pvt) return cs_mode; } -static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl) +static int umc_addr_mask_to_cs_size(struct amd64_pvt *pvt, u8 umc, + unsigned int cs_mode, int csrow_nr) +{ + u32 addr_mask_orig, addr_mask_deinterleaved; + u32 msb, weight, num_zero_bits; + int cs_mask_nr = csrow_nr; + int dimm, size = 0; + + /* No Chip Selects are enabled. */ + if (!cs_mode) + return size; + + /* Requested size of an even CS but none are enabled. */ + if (!(cs_mode & CS_EVEN) && !(csrow_nr & 1)) + return size; + + /* Requested size of an odd CS but none are enabled. */ + if (!(cs_mode & CS_ODD) && (csrow_nr & 1)) + return size; + + /* + * Family 17h introduced systems with one mask per DIMM, + * and two Chip Selects per DIMM. + * + * CS0 and CS1 -> MASK0 / DIMM0 + * CS2 and CS3 -> MASK1 / DIMM1 + * + * Family 19h Model 10h introduced systems with one mask per Chip Select, + * and two Chip Selects per DIMM. + * + * CS0 -> MASK0 -> DIMM0 + * CS1 -> MASK1 -> DIMM0 + * CS2 -> MASK2 -> DIMM1 + * CS3 -> MASK3 -> DIMM1 + * + * Keep the mask number equal to the Chip Select number for newer systems, + * and shift the mask number for older systems. + */ + dimm = csrow_nr >> 1; + + if (!pvt->flags.zn_regs_v2) + cs_mask_nr >>= 1; + + /* Asymmetric dual-rank DIMM support. */ + if ((csrow_nr & 1) && (cs_mode & CS_ODD_SECONDARY)) + addr_mask_orig = pvt->csels[umc].csmasks_sec[cs_mask_nr]; + else + addr_mask_orig = pvt->csels[umc].csmasks[cs_mask_nr]; + + /* + * The number of zero bits in the mask is equal to the number of bits + * in a full mask minus the number of bits in the current mask. + * + * The MSB is the number of bits in the full mask because BIT[0] is + * always 0. + * + * In the special 3 Rank interleaving case, a single bit is flipped + * without swapping with the most significant bit. This can be handled + * by keeping the MSB where it is and ignoring the single zero bit. + */ + msb = fls(addr_mask_orig) - 1; + weight = hweight_long(addr_mask_orig); + num_zero_bits = msb - weight - !!(cs_mode & CS_3R_INTERLEAVE); + + /* Take the number of zero bits off from the top of the mask. */ + addr_mask_deinterleaved = GENMASK_ULL(msb - num_zero_bits, 1); + + edac_dbg(1, "CS%d DIMM%d AddrMasks:\n", csrow_nr, dimm); + edac_dbg(1, " Original AddrMask: 0x%x\n", addr_mask_orig); + edac_dbg(1, " Deinterleaved AddrMask: 0x%x\n", addr_mask_deinterleaved); + + /* Register [31:1] = Address [39:9]. Size is in kBs here. */ + size = (addr_mask_deinterleaved >> 2) + 1; + + /* Return size in MBs. */ + return size >> 10; +} + +static void umc_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl) { int dimm, size0, size1, cs0, cs1, cs_mode; @@ -1376,10 +1514,10 @@ static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl) cs0 = dimm * 2; cs1 = dimm * 2 + 1; - cs_mode = f17_get_cs_mode(dimm, ctrl, pvt); + cs_mode = umc_get_cs_mode(dimm, ctrl, pvt); - size0 = pvt->ops->dbam_to_cs(pvt, ctrl, cs_mode, cs0); - size1 = pvt->ops->dbam_to_cs(pvt, ctrl, cs_mode, cs1); + size0 = umc_addr_mask_to_cs_size(pvt, ctrl, cs_mode, cs0); + size1 = umc_addr_mask_to_cs_size(pvt, ctrl, cs_mode, cs1); amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n", cs0, size0, @@ -1387,7 +1525,7 @@ static void debug_display_dimm_sizes_df(struct amd64_pvt *pvt, u8 ctrl) } } -static void __dump_misc_regs_df(struct amd64_pvt *pvt) +static void umc_dump_misc_regs(struct amd64_pvt *pvt) { struct amd64_umc *umc; u32 i, tmp, umc_base; @@ -1420,18 +1558,17 @@ static void __dump_misc_regs_df(struct amd64_pvt *pvt) if (umc->dram_type == MEM_LRDDR4 || umc->dram_type == MEM_LRDDR5) { amd_smn_read(pvt->mc_node_id, - umc_base + get_umc_reg(UMCCH_ADDR_CFG), + umc_base + get_umc_reg(pvt, UMCCH_ADDR_CFG), &tmp); edac_dbg(1, "UMC%d LRDIMM %dx rank multiply\n", i, 1 << ((tmp >> 4) & 0x3)); } - debug_display_dimm_sizes_df(pvt, i); + umc_debug_display_dimm_sizes(pvt, i); } } -/* Display and decode various NB registers for debug purposes. */ -static void __dump_misc_regs(struct amd64_pvt *pvt) +static void dct_dump_misc_regs(struct amd64_pvt *pvt) { edac_dbg(1, "F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap); @@ -1451,28 +1588,19 @@ static void __dump_misc_regs(struct amd64_pvt *pvt) (pvt->fam == 0xf) ? k8_dhar_offset(pvt) : f10_dhar_offset(pvt)); - debug_display_dimm_sizes(pvt, 0); + dct_debug_display_dimm_sizes(pvt, 0); /* everything below this point is Fam10h and above */ if (pvt->fam == 0xf) return; - debug_display_dimm_sizes(pvt, 1); + dct_debug_display_dimm_sizes(pvt, 1); /* Only if NOT ganged does dclr1 have valid info */ if (!dct_ganging_enabled(pvt)) debug_dump_dramcfg_low(pvt, pvt->dclr1, 1); edac_dbg(1, " DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no"); -} - -/* Display and decode various NB registers for debug purposes. */ -static void dump_misc_regs(struct amd64_pvt *pvt) -{ - if (pvt->umc) - __dump_misc_regs_df(pvt); - else - __dump_misc_regs(pvt); amd64_info("using x%u syndromes.\n", pvt->ecc_sym_sz); } @@ -1480,7 +1608,7 @@ static void dump_misc_regs(struct amd64_pvt *pvt) /* * See BKDG, F2x[1,0][5C:40], F2[1,0][6C:60] */ -static void prep_chip_selects(struct amd64_pvt *pvt) +static void dct_prep_chip_selects(struct amd64_pvt *pvt) { if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) { pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8; @@ -1488,21 +1616,23 @@ static void prep_chip_selects(struct amd64_pvt *pvt) } else if (pvt->fam == 0x15 && pvt->model == 0x30) { pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 4; pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 2; - } else if (pvt->fam >= 0x17) { - int umc; - - for_each_umc(umc) { - pvt->csels[umc].b_cnt = 4; - pvt->csels[umc].m_cnt = fam_type->flags.zn_regs_v2 ? 4 : 2; - } - } else { pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8; pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4; } } -static void read_umc_base_mask(struct amd64_pvt *pvt) +static void umc_prep_chip_selects(struct amd64_pvt *pvt) +{ + int umc; + + for_each_umc(umc) { + pvt->csels[umc].b_cnt = 4; + pvt->csels[umc].m_cnt = pvt->flags.zn_regs_v2 ? 4 : 2; + } +} + +static void umc_read_base_mask(struct amd64_pvt *pvt) { u32 umc_base_reg, umc_base_reg_sec; u32 umc_mask_reg, umc_mask_reg_sec; @@ -1533,7 +1663,7 @@ static void read_umc_base_mask(struct amd64_pvt *pvt) } umc_mask_reg = get_umc_base(umc) + UMCCH_ADDR_MASK; - umc_mask_reg_sec = get_umc_base(umc) + get_umc_reg(UMCCH_ADDR_MASK_SEC); + umc_mask_reg_sec = get_umc_base(umc) + get_umc_reg(pvt, UMCCH_ADDR_MASK_SEC); for_each_chip_select_mask(cs, umc, pvt) { mask = &pvt->csels[umc].csmasks[cs]; @@ -1556,15 +1686,10 @@ static void read_umc_base_mask(struct amd64_pvt *pvt) /* * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask registers */ -static void read_dct_base_mask(struct amd64_pvt *pvt) +static void dct_read_base_mask(struct amd64_pvt *pvt) { int cs; - prep_chip_selects(pvt); - - if (pvt->umc) - return read_umc_base_mask(pvt); - for_each_chip_select(cs, 0, pvt) { int reg0 = DCSB0 + (cs * 4); int reg1 = DCSB1 + (cs * 4); @@ -1604,7 +1729,7 @@ static void read_dct_base_mask(struct amd64_pvt *pvt) } } -static void determine_memory_type_df(struct amd64_pvt *pvt) +static void umc_determine_memory_type(struct amd64_pvt *pvt) { struct amd64_umc *umc; u32 i; @@ -1621,7 +1746,7 @@ static void determine_memory_type_df(struct amd64_pvt *pvt) * Check if the system supports the "DDR Type" field in UMC Config * and has DDR5 DIMMs in use. */ - if (fam_type->flags.zn_regs_v2 && ((umc->umc_cfg & GENMASK(2, 0)) == 0x1)) { + if (pvt->flags.zn_regs_v2 && ((umc->umc_cfg & GENMASK(2, 0)) == 0x1)) { if (umc->dimm_cfg & BIT(5)) umc->dram_type = MEM_LRDDR5; else if (umc->dimm_cfg & BIT(4)) @@ -1641,13 +1766,10 @@ static void determine_memory_type_df(struct amd64_pvt *pvt) } } -static void determine_memory_type(struct amd64_pvt *pvt) +static void dct_determine_memory_type(struct amd64_pvt *pvt) { u32 dram_ctrl, dcsm; - if (pvt->umc) - return determine_memory_type_df(pvt); - switch (pvt->fam) { case 0xf: if (pvt->ext_model >= K8_REV_F) @@ -1697,6 +1819,8 @@ static void determine_memory_type(struct amd64_pvt *pvt) WARN(1, KERN_ERR "%s: Family??? 0x%x\n", __func__, pvt->fam); pvt->dram_type = MEM_EMPTY; } + + edac_dbg(1, " DIMM type: %s\n", edac_mem_types[pvt->dram_type]); return; ddr3: @@ -2081,84 +2205,6 @@ static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, return ddr3_cs_size(cs_mode, false); } -static int f17_addr_mask_to_cs_size(struct amd64_pvt *pvt, u8 umc, - unsigned int cs_mode, int csrow_nr) -{ - u32 addr_mask_orig, addr_mask_deinterleaved; - u32 msb, weight, num_zero_bits; - int cs_mask_nr = csrow_nr; - int dimm, size = 0; - - /* No Chip Selects are enabled. */ - if (!cs_mode) - return size; - - /* Requested size of an even CS but none are enabled. */ - if (!(cs_mode & CS_EVEN) && !(csrow_nr & 1)) - return size; - - /* Requested size of an odd CS but none are enabled. */ - if (!(cs_mode & CS_ODD) && (csrow_nr & 1)) - return size; - - /* - * Family 17h introduced systems with one mask per DIMM, - * and two Chip Selects per DIMM. - * - * CS0 and CS1 -> MASK0 / DIMM0 - * CS2 and CS3 -> MASK1 / DIMM1 - * - * Family 19h Model 10h introduced systems with one mask per Chip Select, - * and two Chip Selects per DIMM. - * - * CS0 -> MASK0 -> DIMM0 - * CS1 -> MASK1 -> DIMM0 - * CS2 -> MASK2 -> DIMM1 - * CS3 -> MASK3 -> DIMM1 - * - * Keep the mask number equal to the Chip Select number for newer systems, - * and shift the mask number for older systems. - */ - dimm = csrow_nr >> 1; - - if (!fam_type->flags.zn_regs_v2) - cs_mask_nr >>= 1; - - /* Asymmetric dual-rank DIMM support. */ - if ((csrow_nr & 1) && (cs_mode & CS_ODD_SECONDARY)) - addr_mask_orig = pvt->csels[umc].csmasks_sec[cs_mask_nr]; - else - addr_mask_orig = pvt->csels[umc].csmasks[cs_mask_nr]; - - /* - * The number of zero bits in the mask is equal to the number of bits - * in a full mask minus the number of bits in the current mask. - * - * The MSB is the number of bits in the full mask because BIT[0] is - * always 0. - * - * In the special 3 Rank interleaving case, a single bit is flipped - * without swapping with the most significant bit. This can be handled - * by keeping the MSB where it is and ignoring the single zero bit. - */ - msb = fls(addr_mask_orig) - 1; - weight = hweight_long(addr_mask_orig); - num_zero_bits = msb - weight - !!(cs_mode & CS_3R_INTERLEAVE); - - /* Take the number of zero bits off from the top of the mask. */ - addr_mask_deinterleaved = GENMASK_ULL(msb - num_zero_bits, 1); - - edac_dbg(1, "CS%d DIMM%d AddrMasks:\n", csrow_nr, dimm); - edac_dbg(1, " Original AddrMask: 0x%x\n", addr_mask_orig); - edac_dbg(1, " Deinterleaved AddrMask: 0x%x\n", addr_mask_deinterleaved); - - /* Register [31:1] = Address [39:9]. Size is in kBs here. */ - size = (addr_mask_deinterleaved >> 2) + 1; - - /* Return size in MBs. */ - return size >> 10; -} - static void read_dram_ctl_register(struct amd64_pvt *pvt) { @@ -2682,196 +2728,6 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, } /* - * debug routine to display the memory sizes of all logical DIMMs and its - * CSROWs - */ -static void debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl) -{ - int dimm, size0, size1; - u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases; - u32 dbam = ctrl ? pvt->dbam1 : pvt->dbam0; - - if (pvt->fam == 0xf) { - /* K8 families < revF not supported yet */ - if (pvt->ext_model < K8_REV_F) - return; - else - WARN_ON(ctrl != 0); - } - - if (pvt->fam == 0x10) { - dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1 - : pvt->dbam0; - dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? - pvt->csels[1].csbases : - pvt->csels[0].csbases; - } else if (ctrl) { - dbam = pvt->dbam0; - dcsb = pvt->csels[1].csbases; - } - edac_dbg(1, "F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n", - ctrl, dbam); - - edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:\n", ctrl); - - /* Dump memory sizes for DIMM and its CSROWs */ - for (dimm = 0; dimm < 4; dimm++) { - - size0 = 0; - if (dcsb[dimm*2] & DCSB_CS_ENABLE) - /* - * For F15m60h, we need multiplier for LRDIMM cs_size - * calculation. We pass dimm value to the dbam_to_cs - * mapper so we can find the multiplier from the - * corresponding DCSM. - */ - size0 = pvt->ops->dbam_to_cs(pvt, ctrl, - DBAM_DIMM(dimm, dbam), - dimm); - - size1 = 0; - if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE) - size1 = pvt->ops->dbam_to_cs(pvt, ctrl, - DBAM_DIMM(dimm, dbam), - dimm); - - amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n", - dimm * 2, size0, - dimm * 2 + 1, size1); - } -} - -static struct amd64_family_type family_types[] = { - [K8_CPUS] = { - .ctl_name = "K8", - .f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP, - .f2_id = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL, - .max_mcs = 2, - .ops = { - .map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow, - .dbam_to_cs = k8_dbam_to_chip_select, - } - }, - [F10_CPUS] = { - .ctl_name = "F10h", - .f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP, - .f2_id = PCI_DEVICE_ID_AMD_10H_NB_DRAM, - .max_mcs = 2, - .ops = { - .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, - .dbam_to_cs = f10_dbam_to_chip_select, - } - }, - [F15_CPUS] = { - .ctl_name = "F15h", - .f1_id = PCI_DEVICE_ID_AMD_15H_NB_F1, - .f2_id = PCI_DEVICE_ID_AMD_15H_NB_F2, - .max_mcs = 2, - .ops = { - .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, - .dbam_to_cs = f15_dbam_to_chip_select, - } - }, - [F15_M30H_CPUS] = { - .ctl_name = "F15h_M30h", - .f1_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1, - .f2_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F2, - .max_mcs = 2, - .ops = { - .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, - .dbam_to_cs = f16_dbam_to_chip_select, - } - }, - [F15_M60H_CPUS] = { - .ctl_name = "F15h_M60h", - .f1_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1, - .f2_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F2, - .max_mcs = 2, - .ops = { - .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, - .dbam_to_cs = f15_m60h_dbam_to_chip_select, - } - }, - [F16_CPUS] = { - .ctl_name = "F16h", - .f1_id = PCI_DEVICE_ID_AMD_16H_NB_F1, - .f2_id = PCI_DEVICE_ID_AMD_16H_NB_F2, - .max_mcs = 2, - .ops = { - .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, - .dbam_to_cs = f16_dbam_to_chip_select, - } - }, - [F16_M30H_CPUS] = { - .ctl_name = "F16h_M30h", - .f1_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F1, - .f2_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F2, - .max_mcs = 2, - .ops = { - .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, - .dbam_to_cs = f16_dbam_to_chip_select, - } - }, - [F17_CPUS] = { - .ctl_name = "F17h", - .max_mcs = 2, - .ops = { - .dbam_to_cs = f17_addr_mask_to_cs_size, - } - }, - [F17_M10H_CPUS] = { - .ctl_name = "F17h_M10h", - .max_mcs = 2, - .ops = { - .dbam_to_cs = f17_addr_mask_to_cs_size, - } - }, - [F17_M30H_CPUS] = { - .ctl_name = "F17h_M30h", - .max_mcs = 8, - .ops = { - .dbam_to_cs = f17_addr_mask_to_cs_size, - } - }, - [F17_M60H_CPUS] = { - .ctl_name = "F17h_M60h", - .max_mcs = 2, - .ops = { - .dbam_to_cs = f17_addr_mask_to_cs_size, - } - }, - [F17_M70H_CPUS] = { - .ctl_name = "F17h_M70h", - .max_mcs = 2, - .ops = { - .dbam_to_cs = f17_addr_mask_to_cs_size, - } - }, - [F19_CPUS] = { - .ctl_name = "F19h", - .max_mcs = 8, - .ops = { - .dbam_to_cs = f17_addr_mask_to_cs_size, - } - }, - [F19_M10H_CPUS] = { - .ctl_name = "F19h_M10h", - .max_mcs = 12, - .flags.zn_regs_v2 = 1, - .ops = { - .dbam_to_cs = f17_addr_mask_to_cs_size, - } - }, - [F19_M50H_CPUS] = { - .ctl_name = "F19h_M50h", - .max_mcs = 2, - .ops = { - .dbam_to_cs = f17_addr_mask_to_cs_size, - } - }, -}; - -/* * These are tables of eigenvectors (one per line) which can be used for the * construction of the syndrome tables. The modified syndrome search algorithm * uses those to find the symbol in error and thus the DIMM. @@ -3118,10 +2974,14 @@ static inline void decode_bus_error(int node_id, struct mce *m) * Currently, we can derive the channel number by looking at the 6th nibble in * 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 + * the MCA_SYND[ErrorInformation] field. */ -static int find_umc_channel(struct mce *m) +static void umc_get_err_info(struct mce *m, struct err_info *err) { - return (m->ipid & GENMASK(31, 0)) >> 20; + err->channel = (m->ipid & GENMASK(31, 0)) >> 20; + err->csrow = m->synd & 0x7; } static void decode_umc_error(int node_id, struct mce *m) @@ -3143,8 +3003,6 @@ static void decode_umc_error(int node_id, struct mce *m) if (m->status & MCI_STATUS_DEFERRED) ecc_type = 3; - err.channel = find_umc_channel(m); - if (!(m->status & MCI_STATUS_SYNDV)) { err.err_code = ERR_SYND; goto log_error; @@ -3159,7 +3017,7 @@ static void decode_umc_error(int node_id, struct mce *m) err.err_code = ERR_CHANNEL; } - err.csrow = m->synd & 0x7; + pvt->ops->get_err_info(m, &err); if (umc_normaddr_to_sysaddr(m->addr, pvt->mc_node_id, err.channel, &sys_addr)) { err.err_code = ERR_NORM_ADDR; @@ -3179,9 +3037,6 @@ log_error: static int reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 pci_id1, u16 pci_id2) { - if (pvt->umc) - return 0; - /* Reserve the ADDRESS MAP Device */ pvt->F1 = pci_get_related_function(pvt->F3->vendor, pci_id1, pvt->F3); if (!pvt->F1) { @@ -3209,36 +3064,11 @@ reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 pci_id1, u16 pci_id2) return 0; } -static void free_mc_sibling_devs(struct amd64_pvt *pvt) -{ - if (pvt->umc) { - return; - } else { - pci_dev_put(pvt->F1); - pci_dev_put(pvt->F2); - } -} - static void determine_ecc_sym_sz(struct amd64_pvt *pvt) { pvt->ecc_sym_sz = 4; - if (pvt->umc) { - u8 i; - - for_each_umc(i) { - /* Check enabled channels only: */ - if (pvt->umc[i].sdp_ctrl & UMC_SDP_INIT) { - if (pvt->umc[i].ecc_ctrl & BIT(9)) { - pvt->ecc_sym_sz = 16; - return; - } else if (pvt->umc[i].ecc_ctrl & BIT(7)) { - pvt->ecc_sym_sz = 8; - return; - } - } - } - } else if (pvt->fam >= 0x10) { + if (pvt->fam >= 0x10) { u32 tmp; amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp); @@ -3255,7 +3085,7 @@ static void determine_ecc_sym_sz(struct amd64_pvt *pvt) /* * Retrieve the hardware registers of the memory controller. */ -static void __read_mc_regs_df(struct amd64_pvt *pvt) +static void umc_read_mc_regs(struct amd64_pvt *pvt) { u8 nid = pvt->mc_node_id; struct amd64_umc *umc; @@ -3267,7 +3097,7 @@ static void __read_mc_regs_df(struct amd64_pvt *pvt) umc_base = get_umc_base(i); umc = &pvt->umc[i]; - amd_smn_read(nid, umc_base + get_umc_reg(UMCCH_DIMM_CFG), &umc->dimm_cfg); + amd_smn_read(nid, umc_base + get_umc_reg(pvt, UMCCH_DIMM_CFG), &umc->dimm_cfg); amd_smn_read(nid, umc_base + UMCCH_UMC_CFG, &umc->umc_cfg); amd_smn_read(nid, umc_base + UMCCH_SDP_CTRL, &umc->sdp_ctrl); amd_smn_read(nid, umc_base + UMCCH_ECC_CTRL, &umc->ecc_ctrl); @@ -3279,7 +3109,7 @@ static void __read_mc_regs_df(struct amd64_pvt *pvt) * Retrieve the hardware registers of the memory controller (this includes the * 'Address Map' and 'Misc' device regs) */ -static void read_mc_regs(struct amd64_pvt *pvt) +static void dct_read_mc_regs(struct amd64_pvt *pvt) { unsigned int range; u64 msr_val; @@ -3300,12 +3130,6 @@ static void read_mc_regs(struct amd64_pvt *pvt) edac_dbg(0, " TOP_MEM2 disabled\n"); } - if (pvt->umc) { - __read_mc_regs_df(pvt); - - goto skip; - } - amd64_read_pci_cfg(pvt->F3, NBCAP, &pvt->nbcap); read_dram_ctl_register(pvt); @@ -3346,14 +3170,6 @@ static void read_mc_regs(struct amd64_pvt *pvt) amd64_read_dct_pci_cfg(pvt, 1, DCHR0, &pvt->dchr1); } -skip: - read_dct_base_mask(pvt); - - determine_memory_type(pvt); - - if (!pvt->umc) - edac_dbg(1, " DIMM type: %s\n", edac_mem_types[pvt->dram_type]); - determine_ecc_sym_sz(pvt); } @@ -3391,36 +3207,47 @@ skip: * encompasses * */ -static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr_orig) +static u32 dct_get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr) { u32 dbam = dct ? pvt->dbam1 : pvt->dbam0; - int csrow_nr = csrow_nr_orig; u32 cs_mode, nr_pages; - if (!pvt->umc) { - csrow_nr >>= 1; - cs_mode = DBAM_DIMM(csrow_nr, dbam); - } else { - cs_mode = f17_get_cs_mode(csrow_nr >> 1, dct, pvt); - } + csrow_nr >>= 1; + cs_mode = DBAM_DIMM(csrow_nr, dbam); nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode, csrow_nr); nr_pages <<= 20 - PAGE_SHIFT; edac_dbg(0, "csrow: %d, channel: %d, DBAM idx: %d\n", - csrow_nr_orig, dct, cs_mode); + csrow_nr, dct, cs_mode); edac_dbg(0, "nr_pages/channel: %u\n", nr_pages); return nr_pages; } -static int init_csrows_df(struct mem_ctl_info *mci) +static u32 umc_get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr_orig) +{ + int csrow_nr = csrow_nr_orig; + u32 cs_mode, nr_pages; + + cs_mode = umc_get_cs_mode(csrow_nr >> 1, dct, pvt); + + nr_pages = umc_addr_mask_to_cs_size(pvt, dct, cs_mode, csrow_nr); + nr_pages <<= 20 - PAGE_SHIFT; + + edac_dbg(0, "csrow: %d, channel: %d, cs_mode %d\n", + csrow_nr_orig, dct, cs_mode); + edac_dbg(0, "nr_pages/channel: %u\n", nr_pages); + + return nr_pages; +} + +static void umc_init_csrows(struct mem_ctl_info *mci) { struct amd64_pvt *pvt = mci->pvt_info; enum edac_type edac_mode = EDAC_NONE; enum dev_type dev_type = DEV_UNKNOWN; struct dimm_info *dimm; - int empty = 1; u8 umc, cs; if (mci->edac_ctl_cap & EDAC_FLAG_S16ECD16ED) { @@ -3441,40 +3268,34 @@ static int init_csrows_df(struct mem_ctl_info *mci) if (!csrow_enabled(cs, umc, pvt)) continue; - empty = 0; dimm = mci->csrows[cs]->channels[umc]->dimm; edac_dbg(1, "MC node: %d, csrow: %d\n", pvt->mc_node_id, cs); - dimm->nr_pages = get_csrow_nr_pages(pvt, umc, cs); + dimm->nr_pages = umc_get_csrow_nr_pages(pvt, umc, cs); dimm->mtype = pvt->umc[umc].dram_type; dimm->edac_mode = edac_mode; dimm->dtype = dev_type; dimm->grain = 64; } } - - return empty; } /* * Initialize the array of csrow attribute instances, based on the values * from pci config hardware registers. */ -static int init_csrows(struct mem_ctl_info *mci) +static void dct_init_csrows(struct mem_ctl_info *mci) { struct amd64_pvt *pvt = mci->pvt_info; enum edac_type edac_mode = EDAC_NONE; struct csrow_info *csrow; struct dimm_info *dimm; - int i, j, empty = 1; int nr_pages = 0; + int i, j; u32 val; - if (pvt->umc) - return init_csrows_df(mci); - amd64_read_pci_cfg(pvt->F3, NBCFG, &val); pvt->nbcfg = val; @@ -3497,19 +3318,18 @@ static int init_csrows(struct mem_ctl_info *mci) continue; csrow = mci->csrows[i]; - empty = 0; edac_dbg(1, "MC node: %d, csrow: %d\n", pvt->mc_node_id, i); if (row_dct0) { - nr_pages = get_csrow_nr_pages(pvt, 0, i); + nr_pages = dct_get_csrow_nr_pages(pvt, 0, i); csrow->channels[0]->dimm->nr_pages = nr_pages; } /* K8 has only one DCT */ if (pvt->fam != 0xf && row_dct1) { - int row_dct1_pages = get_csrow_nr_pages(pvt, 1, i); + int row_dct1_pages = dct_get_csrow_nr_pages(pvt, 1, i); csrow->channels[1]->dimm->nr_pages = row_dct1_pages; nr_pages += row_dct1_pages; @@ -3524,15 +3344,13 @@ static int init_csrows(struct mem_ctl_info *mci) : EDAC_SECDED; } - for (j = 0; j < fam_type->max_mcs; j++) { + for (j = 0; j < pvt->max_mcs; j++) { dimm = csrow->channels[j]->dimm; dimm->mtype = pvt->dram_type; dimm->edac_mode = edac_mode; dimm->grain = 64; } } - - return empty; } /* get all cores on this DCT */ @@ -3695,59 +3513,66 @@ static void restore_ecc_error_reporting(struct ecc_settings *s, u16 nid, amd64_warn("Error restoring NB MCGCTL settings!\n"); } -static bool ecc_enabled(struct amd64_pvt *pvt) +static bool dct_ecc_enabled(struct amd64_pvt *pvt) { u16 nid = pvt->mc_node_id; bool nb_mce_en = false; - u8 ecc_en = 0, i; + u8 ecc_en = 0; u32 value; - if (boot_cpu_data.x86 >= 0x17) { - u8 umc_en_mask = 0, ecc_en_mask = 0; - struct amd64_umc *umc; + amd64_read_pci_cfg(pvt->F3, NBCFG, &value); - for_each_umc(i) { - umc = &pvt->umc[i]; + ecc_en = !!(value & NBCFG_ECC_ENABLE); - /* Only check enabled UMCs. */ - if (!(umc->sdp_ctrl & UMC_SDP_INIT)) - continue; + nb_mce_en = nb_mce_bank_enabled_on_node(nid); + if (!nb_mce_en) + edac_dbg(0, "NB MCE bank disabled, set MSR 0x%08x[4] on node %d to enable.\n", + MSR_IA32_MCG_CTL, nid); - umc_en_mask |= BIT(i); + edac_dbg(3, "Node %d: DRAM ECC %s.\n", nid, (ecc_en ? "enabled" : "disabled")); - if (umc->umc_cap_hi & UMC_ECC_ENABLED) - ecc_en_mask |= BIT(i); - } + if (!ecc_en || !nb_mce_en) + return false; + else + return true; +} - /* Check whether at least one UMC is enabled: */ - if (umc_en_mask) - ecc_en = umc_en_mask == ecc_en_mask; - else - edac_dbg(0, "Node %d: No enabled UMCs.\n", nid); +static bool umc_ecc_enabled(struct amd64_pvt *pvt) +{ + u8 umc_en_mask = 0, ecc_en_mask = 0; + u16 nid = pvt->mc_node_id; + struct amd64_umc *umc; + u8 ecc_en = 0, i; - /* Assume UMC MCA banks are enabled. */ - nb_mce_en = true; - } else { - amd64_read_pci_cfg(pvt->F3, NBCFG, &value); + for_each_umc(i) { + umc = &pvt->umc[i]; - ecc_en = !!(value & NBCFG_ECC_ENABLE); + /* Only check enabled UMCs. */ + if (!(umc->sdp_ctrl & UMC_SDP_INIT)) + continue; + + umc_en_mask |= BIT(i); - nb_mce_en = nb_mce_bank_enabled_on_node(nid); - if (!nb_mce_en) - edac_dbg(0, "NB MCE bank disabled, set MSR 0x%08x[4] on node %d to enable.\n", - MSR_IA32_MCG_CTL, nid); + if (umc->umc_cap_hi & UMC_ECC_ENABLED) + ecc_en_mask |= BIT(i); } + /* Check whether at least one UMC is enabled: */ + if (umc_en_mask) + ecc_en = umc_en_mask == ecc_en_mask; + else + edac_dbg(0, "Node %d: No enabled UMCs.\n", nid); + edac_dbg(3, "Node %d: DRAM ECC %s.\n", nid, (ecc_en ? "enabled" : "disabled")); - if (!ecc_en || !nb_mce_en) + if (!ecc_en) return false; else return true; } static inline void -f17h_determine_edac_ctl_cap(struct mem_ctl_info *mci, struct amd64_pvt *pvt) +umc_determine_edac_ctl_cap(struct mem_ctl_info *mci, struct amd64_pvt *pvt) { u8 i, ecc_en = 1, cpk_en = 1, dev_x4 = 1, dev_x16 = 1; @@ -3777,145 +3602,234 @@ f17h_determine_edac_ctl_cap(struct mem_ctl_info *mci, struct amd64_pvt *pvt) } } -static void setup_mci_misc_attrs(struct mem_ctl_info *mci) +static void dct_setup_mci_misc_attrs(struct mem_ctl_info *mci) { struct amd64_pvt *pvt = mci->pvt_info; mci->mtype_cap = MEM_FLAG_DDR2 | MEM_FLAG_RDDR2; mci->edac_ctl_cap = EDAC_FLAG_NONE; - if (pvt->umc) { - f17h_determine_edac_ctl_cap(mci, pvt); - } else { - if (pvt->nbcap & NBCAP_SECDED) - mci->edac_ctl_cap |= EDAC_FLAG_SECDED; + if (pvt->nbcap & NBCAP_SECDED) + mci->edac_ctl_cap |= EDAC_FLAG_SECDED; - if (pvt->nbcap & NBCAP_CHIPKILL) - mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED; - } + if (pvt->nbcap & NBCAP_CHIPKILL) + mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED; - mci->edac_cap = determine_edac_cap(pvt); + mci->edac_cap = dct_determine_edac_cap(pvt); mci->mod_name = EDAC_MOD_STR; - mci->ctl_name = fam_type->ctl_name; + mci->ctl_name = pvt->ctl_name; mci->dev_name = pci_name(pvt->F3); mci->ctl_page_to_phys = NULL; - if (pvt->fam >= 0x17) - return; - /* memory scrubber interface */ mci->set_sdram_scrub_rate = set_scrub_rate; mci->get_sdram_scrub_rate = get_scrub_rate; + + dct_init_csrows(mci); } -/* - * returns a pointer to the family descriptor on success, NULL otherwise. - */ -static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt) +static void umc_setup_mci_misc_attrs(struct mem_ctl_info *mci) +{ + struct amd64_pvt *pvt = mci->pvt_info; + + mci->mtype_cap = MEM_FLAG_DDR4 | MEM_FLAG_RDDR4; + mci->edac_ctl_cap = EDAC_FLAG_NONE; + + umc_determine_edac_ctl_cap(mci, pvt); + + mci->edac_cap = umc_determine_edac_cap(pvt); + mci->mod_name = EDAC_MOD_STR; + mci->ctl_name = pvt->ctl_name; + mci->dev_name = pci_name(pvt->F3); + mci->ctl_page_to_phys = NULL; + + umc_init_csrows(mci); +} + +static int dct_hw_info_get(struct amd64_pvt *pvt) +{ + int ret = reserve_mc_sibling_devs(pvt, pvt->f1_id, pvt->f2_id); + + if (ret) + return ret; + + dct_prep_chip_selects(pvt); + dct_read_base_mask(pvt); + dct_read_mc_regs(pvt); + dct_determine_memory_type(pvt); + + return 0; +} + +static int umc_hw_info_get(struct amd64_pvt *pvt) +{ + pvt->umc = kcalloc(pvt->max_mcs, sizeof(struct amd64_umc), GFP_KERNEL); + if (!pvt->umc) + return -ENOMEM; + + umc_prep_chip_selects(pvt); + umc_read_base_mask(pvt); + umc_read_mc_regs(pvt); + umc_determine_memory_type(pvt); + + return 0; +} + +static void hw_info_put(struct amd64_pvt *pvt) +{ + pci_dev_put(pvt->F1); + pci_dev_put(pvt->F2); + kfree(pvt->umc); +} + +static struct low_ops umc_ops = { + .hw_info_get = umc_hw_info_get, + .ecc_enabled = umc_ecc_enabled, + .setup_mci_misc_attrs = umc_setup_mci_misc_attrs, + .dump_misc_regs = umc_dump_misc_regs, + .get_err_info = umc_get_err_info, +}; + +/* Use Family 16h versions for defaults and adjust as needed below. */ +static struct low_ops dct_ops = { + .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, + .dbam_to_cs = f16_dbam_to_chip_select, + .hw_info_get = dct_hw_info_get, + .ecc_enabled = dct_ecc_enabled, + .setup_mci_misc_attrs = dct_setup_mci_misc_attrs, + .dump_misc_regs = dct_dump_misc_regs, +}; + +static int per_family_init(struct amd64_pvt *pvt) { pvt->ext_model = boot_cpu_data.x86_model >> 4; pvt->stepping = boot_cpu_data.x86_stepping; pvt->model = boot_cpu_data.x86_model; pvt->fam = boot_cpu_data.x86; + pvt->max_mcs = 2; + + /* + * Decide on which ops group to use here and do any family/model + * overrides below. + */ + if (pvt->fam >= 0x17) + pvt->ops = &umc_ops; + else + pvt->ops = &dct_ops; switch (pvt->fam) { case 0xf: - fam_type = &family_types[K8_CPUS]; - pvt->ops = &family_types[K8_CPUS].ops; + pvt->ctl_name = (pvt->ext_model >= K8_REV_F) ? + "K8 revF or later" : "K8 revE or earlier"; + pvt->f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP; + pvt->f2_id = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL; + pvt->ops->map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow; + pvt->ops->dbam_to_cs = k8_dbam_to_chip_select; break; case 0x10: - fam_type = &family_types[F10_CPUS]; - pvt->ops = &family_types[F10_CPUS].ops; + pvt->ctl_name = "F10h"; + pvt->f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP; + pvt->f2_id = PCI_DEVICE_ID_AMD_10H_NB_DRAM; + pvt->ops->dbam_to_cs = f10_dbam_to_chip_select; break; case 0x15: - if (pvt->model == 0x30) { - fam_type = &family_types[F15_M30H_CPUS]; - pvt->ops = &family_types[F15_M30H_CPUS].ops; + switch (pvt->model) { + case 0x30: + pvt->ctl_name = "F15h_M30h"; + pvt->f1_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1; + pvt->f2_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F2; break; - } else if (pvt->model == 0x60) { - fam_type = &family_types[F15_M60H_CPUS]; - pvt->ops = &family_types[F15_M60H_CPUS].ops; + case 0x60: + pvt->ctl_name = "F15h_M60h"; + pvt->f1_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1; + pvt->f2_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F2; + pvt->ops->dbam_to_cs = f15_m60h_dbam_to_chip_select; + break; + case 0x13: + /* Richland is only client */ + return -ENODEV; + default: + pvt->ctl_name = "F15h"; + pvt->f1_id = PCI_DEVICE_ID_AMD_15H_NB_F1; + pvt->f2_id = PCI_DEVICE_ID_AMD_15H_NB_F2; + pvt->ops->dbam_to_cs = f15_dbam_to_chip_select; break; - /* Richland is only client */ - } else if (pvt->model == 0x13) { - return NULL; - } else { - fam_type = &family_types[F15_CPUS]; - pvt->ops = &family_types[F15_CPUS].ops; } break; case 0x16: - if (pvt->model == 0x30) { - fam_type = &family_types[F16_M30H_CPUS]; - pvt->ops = &family_types[F16_M30H_CPUS].ops; + switch (pvt->model) { + case 0x30: + pvt->ctl_name = "F16h_M30h"; + pvt->f1_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F1; + pvt->f2_id = PCI_DEVICE_ID_AMD_16H_M30H_NB_F2; + break; + default: + pvt->ctl_name = "F16h"; + pvt->f1_id = PCI_DEVICE_ID_AMD_16H_NB_F1; + pvt->f2_id = PCI_DEVICE_ID_AMD_16H_NB_F2; break; } - fam_type = &family_types[F16_CPUS]; - pvt->ops = &family_types[F16_CPUS].ops; break; case 0x17: - if (pvt->model >= 0x10 && pvt->model <= 0x2f) { - fam_type = &family_types[F17_M10H_CPUS]; - pvt->ops = &family_types[F17_M10H_CPUS].ops; + switch (pvt->model) { + case 0x10 ... 0x2f: + pvt->ctl_name = "F17h_M10h"; break; - } else if (pvt->model >= 0x30 && pvt->model <= 0x3f) { - fam_type = &family_types[F17_M30H_CPUS]; - pvt->ops = &family_types[F17_M30H_CPUS].ops; + case 0x30 ... 0x3f: + pvt->ctl_name = "F17h_M30h"; + pvt->max_mcs = 8; break; - } else if (pvt->model >= 0x60 && pvt->model <= 0x6f) { - fam_type = &family_types[F17_M60H_CPUS]; - pvt->ops = &family_types[F17_M60H_CPUS].ops; + case 0x60 ... 0x6f: + pvt->ctl_name = "F17h_M60h"; break; - } else if (pvt->model >= 0x70 && pvt->model <= 0x7f) { - fam_type = &family_types[F17_M70H_CPUS]; - pvt->ops = &family_types[F17_M70H_CPUS].ops; + case 0x70 ... 0x7f: + pvt->ctl_name = "F17h_M70h"; + break; + default: + pvt->ctl_name = "F17h"; break; } - fallthrough; - case 0x18: - fam_type = &family_types[F17_CPUS]; - pvt->ops = &family_types[F17_CPUS].ops; + break; - if (pvt->fam == 0x18) - family_types[F17_CPUS].ctl_name = "F18h"; + case 0x18: + pvt->ctl_name = "F18h"; break; case 0x19: - if (pvt->model >= 0x10 && pvt->model <= 0x1f) { - fam_type = &family_types[F19_M10H_CPUS]; - pvt->ops = &family_types[F19_M10H_CPUS].ops; + switch (pvt->model) { + case 0x00 ... 0x0f: + pvt->ctl_name = "F19h"; + pvt->max_mcs = 8; break; - } else if (pvt->model >= 0x20 && pvt->model <= 0x2f) { - fam_type = &family_types[F17_M70H_CPUS]; - pvt->ops = &family_types[F17_M70H_CPUS].ops; - fam_type->ctl_name = "F19h_M20h"; + case 0x10 ... 0x1f: + pvt->ctl_name = "F19h_M10h"; + pvt->max_mcs = 12; + pvt->flags.zn_regs_v2 = 1; break; - } else if (pvt->model >= 0x50 && pvt->model <= 0x5f) { - fam_type = &family_types[F19_M50H_CPUS]; - pvt->ops = &family_types[F19_M50H_CPUS].ops; - fam_type->ctl_name = "F19h_M50h"; + case 0x20 ... 0x2f: + pvt->ctl_name = "F19h_M20h"; break; - } else if (pvt->model >= 0xa0 && pvt->model <= 0xaf) { - fam_type = &family_types[F19_M10H_CPUS]; - pvt->ops = &family_types[F19_M10H_CPUS].ops; - fam_type->ctl_name = "F19h_MA0h"; + case 0x50 ... 0x5f: + pvt->ctl_name = "F19h_M50h"; + break; + case 0xa0 ... 0xaf: + pvt->ctl_name = "F19h_MA0h"; + pvt->max_mcs = 12; + pvt->flags.zn_regs_v2 = 1; break; } - fam_type = &family_types[F19_CPUS]; - pvt->ops = &family_types[F19_CPUS].ops; - family_types[F19_CPUS].ctl_name = "F19h"; break; default: amd64_err("Unsupported family!\n"); - return NULL; + return -ENODEV; } - return fam_type; + return 0; } static const struct attribute_group *amd64_edac_attr_groups[] = { @@ -3926,37 +3840,6 @@ static const struct attribute_group *amd64_edac_attr_groups[] = { NULL }; -static int hw_info_get(struct amd64_pvt *pvt) -{ - u16 pci_id1 = 0, pci_id2 = 0; - int ret; - - if (pvt->fam >= 0x17) { - pvt->umc = kcalloc(fam_type->max_mcs, sizeof(struct amd64_umc), GFP_KERNEL); - if (!pvt->umc) - return -ENOMEM; - } else { - pci_id1 = fam_type->f1_id; - pci_id2 = fam_type->f2_id; - } - - ret = reserve_mc_sibling_devs(pvt, pci_id1, pci_id2); - if (ret) - return ret; - - read_mc_regs(pvt); - - return 0; -} - -static void hw_info_put(struct amd64_pvt *pvt) -{ - if (pvt->F1) - free_mc_sibling_devs(pvt); - - kfree(pvt->umc); -} - static int init_one_instance(struct amd64_pvt *pvt) { struct mem_ctl_info *mci = NULL; @@ -3967,7 +3850,7 @@ static int init_one_instance(struct amd64_pvt *pvt) layers[0].size = pvt->csels[0].b_cnt; layers[0].is_virt_csrow = true; layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = fam_type->max_mcs; + layers[1].size = pvt->max_mcs; layers[1].is_virt_csrow = false; mci = edac_mc_alloc(pvt->mc_node_id, ARRAY_SIZE(layers), layers, 0); @@ -3977,10 +3860,7 @@ static int init_one_instance(struct amd64_pvt *pvt) mci->pvt_info = pvt; mci->pdev = &pvt->F3->dev; - setup_mci_misc_attrs(mci); - - if (init_csrows(mci)) - mci->edac_cap = EDAC_FLAG_NONE; + pvt->ops->setup_mci_misc_attrs(mci); ret = -ENODEV; if (edac_mc_add_mc_with_groups(mci, amd64_edac_attr_groups)) { @@ -3997,7 +3877,7 @@ static bool instance_has_memory(struct amd64_pvt *pvt) bool cs_enabled = false; int cs = 0, dct = 0; - for (dct = 0; dct < fam_type->max_mcs; dct++) { + for (dct = 0; dct < pvt->max_mcs; dct++) { for_each_chip_select(cs, dct, pvt) cs_enabled |= csrow_enabled(cs, dct, pvt); } @@ -4026,12 +3906,11 @@ static int probe_one_instance(unsigned int nid) pvt->mc_node_id = nid; pvt->F3 = F3; - ret = -ENODEV; - fam_type = per_family_init(pvt); - if (!fam_type) + ret = per_family_init(pvt); + if (ret < 0) goto err_enable; - ret = hw_info_get(pvt); + ret = pvt->ops->hw_info_get(pvt); if (ret < 0) goto err_enable; @@ -4041,7 +3920,7 @@ static int probe_one_instance(unsigned int nid) goto err_enable; } - if (!ecc_enabled(pvt)) { + if (!pvt->ops->ecc_enabled(pvt)) { ret = -ENODEV; if (!ecc_enable_override) @@ -4067,13 +3946,10 @@ static int probe_one_instance(unsigned int nid) goto err_enable; } - amd64_info("%s %sdetected (node %d).\n", fam_type->ctl_name, - (pvt->fam == 0xf ? - (pvt->ext_model >= K8_REV_F ? "revF or later " - : "revE or earlier ") - : ""), pvt->mc_node_id); + amd64_info("%s detected (node %d).\n", pvt->ctl_name, pvt->mc_node_id); - dump_misc_regs(pvt); + /* Display and decode various registers for debug purposes. */ + pvt->ops->dump_misc_regs(pvt); return ret; @@ -4244,10 +4120,8 @@ module_init(amd64_edac_init); module_exit(amd64_edac_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("SoftwareBitMaker: Doug Thompson, " - "Dave Peterson, Thayne Harbaugh"); -MODULE_DESCRIPTION("MC support for AMD64 memory controllers - " - EDAC_AMD64_VERSION); +MODULE_AUTHOR("SoftwareBitMaker: Doug Thompson, Dave Peterson, Thayne Harbaugh; AMD"); +MODULE_DESCRIPTION("MC support for AMD64 memory controllers - " EDAC_AMD64_VERSION); module_param(edac_op_state, int, 0444); MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index e4329dff8cf2..e84fe0d4120a 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -273,25 +273,6 @@ #define UMC_SDP_INIT BIT(31) -enum amd_families { - K8_CPUS = 0, - F10_CPUS, - F15_CPUS, - F15_M30H_CPUS, - F15_M60H_CPUS, - F16_CPUS, - F16_M30H_CPUS, - F17_CPUS, - F17_M10H_CPUS, - F17_M30H_CPUS, - F17_M60H_CPUS, - F17_M70H_CPUS, - F19_CPUS, - F19_M10H_CPUS, - F19_M50H_CPUS, - NUM_FAMILIES, -}; - /* Error injection control structure */ struct error_injection { u32 section; @@ -334,6 +315,16 @@ struct amd64_umc { enum mem_type dram_type; }; +struct amd64_family_flags { + /* + * Indicates that the system supports the new register offsets, etc. + * first introduced with Family 19h Model 10h. + */ + __u64 zn_regs_v2 : 1, + + __reserved : 63; +}; + struct amd64_pvt { struct low_ops *ops; @@ -375,6 +366,12 @@ struct amd64_pvt { /* x4, x8, or x16 syndromes in use */ u8 ecc_sym_sz; + const char *ctl_name; + u16 f1_id, f2_id; + /* Maximum number of memory controllers per die/node. */ + u8 max_mcs; + + struct amd64_family_flags flags; /* place to store error injection parameters prior to issue */ struct error_injection injection; @@ -465,29 +462,15 @@ struct ecc_settings { * functions and per device encoding/decoding logic. */ struct low_ops { - void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci, u64 sys_addr, - struct err_info *); - int (*dbam_to_cs) (struct amd64_pvt *pvt, u8 dct, - unsigned cs_mode, int cs_mask_nr); -}; - -struct amd64_family_flags { - /* - * Indicates that the system supports the new register offsets, etc. - * first introduced with Family 19h Model 10h. - */ - __u64 zn_regs_v2 : 1, - - __reserved : 63; -}; - -struct amd64_family_type { - const char *ctl_name; - u16 f1_id, f2_id; - /* Maximum number of memory controllers per die/node. */ - u8 max_mcs; - struct amd64_family_flags flags; - struct low_ops ops; + void (*map_sysaddr_to_csrow)(struct mem_ctl_info *mci, u64 sys_addr, + struct err_info *err); + int (*dbam_to_cs)(struct amd64_pvt *pvt, u8 dct, + unsigned int cs_mode, int cs_mask_nr); + int (*hw_info_get)(struct amd64_pvt *pvt); + bool (*ecc_enabled)(struct amd64_pvt *pvt); + void (*setup_mci_misc_attrs)(struct mem_ctl_info *mci); + void (*dump_misc_regs)(struct amd64_pvt *pvt); + void (*get_err_info)(struct mce *m, struct err_info *err); }; int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset, diff --git a/drivers/edac/amd8111_edac.c b/drivers/edac/amd8111_edac.c index 7508aa416ddb..ca718f63fcbc 100644 --- a/drivers/edac/amd8111_edac.c +++ b/drivers/edac/amd8111_edac.c @@ -593,5 +593,5 @@ module_init(amd8111_edac_init); module_exit(amd8111_edac_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Cao Qingtao <qingtao.cao@windriver.com>\n"); +MODULE_AUTHOR("Cao Qingtao <qingtao.cao@windriver.com>"); MODULE_DESCRIPTION("AMD8111 HyperTransport I/O Hub EDAC kernel module"); diff --git a/drivers/edac/amd8131_edac.c b/drivers/edac/amd8131_edac.c index 169353710982..28610ba514f4 100644 --- a/drivers/edac/amd8131_edac.c +++ b/drivers/edac/amd8131_edac.c @@ -354,5 +354,5 @@ module_init(amd8131_edac_init); module_exit(amd8131_edac_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Cao Qingtao <qingtao.cao@windriver.com>\n"); +MODULE_AUTHOR("Cao Qingtao <qingtao.cao@windriver.com>"); MODULE_DESCRIPTION("AMD8131 HyperTransport PCI-X Tunnel EDAC kernel module"); diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index ac7c9b42d4c7..7221b4bb6df2 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c @@ -1462,7 +1462,7 @@ module_init(e752x_init); module_exit(e752x_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n"); +MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman"); MODULE_DESCRIPTION("MC support for Intel e752x/3100 memory controllers"); module_param(force_function_unhide, int, 0444); diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c index 497e710fca3d..5852b95fa470 100644 --- a/drivers/edac/e7xxx_edac.c +++ b/drivers/edac/e7xxx_edac.c @@ -596,8 +596,7 @@ module_init(e7xxx_init); module_exit(e7xxx_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n" - "Based on.work by Dan Hollis et al"); +MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al"); MODULE_DESCRIPTION("MC support for Intel e7xxx memory controllers"); module_param(edac_op_state, int, 0444); MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c index 0a4691792801..a897b6aff368 100644 --- a/drivers/edac/i10nm_base.c +++ b/drivers/edac/i10nm_base.c @@ -906,6 +906,7 @@ static const struct x86_cpu_id i10nm_cpuids[] = { X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SAPPHIRERAPIDS_X, X86_STEPPINGS(0x0, 0xf), &spr_cfg), X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(EMERALDRAPIDS_X, X86_STEPPINGS(0x0, 0xf), &spr_cfg), X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(GRANITERAPIDS_X, X86_STEPPINGS(0x0, 0xf), &gnr_cfg), + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SIERRAFOREST_X, X86_STEPPINGS(0x0, 0xf), &gnr_cfg), {} }; MODULE_DEVICE_TABLE(x86cpu, i10nm_cpuids); diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c index ba46057d4220..4b5a71f8739d 100644 --- a/drivers/edac/i5000_edac.c +++ b/drivers/edac/i5000_edac.c @@ -1573,13 +1573,10 @@ module_init(i5000_init); module_exit(i5000_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR - ("Linux Networx (http://lnxi.com) Doug Thompson <norsk5@xmission.com>"); -MODULE_DESCRIPTION("MC Driver for Intel I5000 memory controllers - " - I5000_REVISION); +MODULE_AUTHOR("Linux Networx (http://lnxi.com) Doug Thompson <norsk5@xmission.com>"); +MODULE_DESCRIPTION("MC Driver for Intel I5000 memory controllers - " I5000_REVISION); module_param(edac_op_state, int, 0444); MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); module_param(misc_messages, int, 0444); MODULE_PARM_DESC(misc_messages, "Log miscellaneous non fatal messages"); - diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c index f5d82518c15e..d470afe65001 100644 --- a/drivers/edac/i5100_edac.c +++ b/drivers/edac/i5100_edac.c @@ -909,7 +909,7 @@ static void i5100_do_inject(struct mem_ctl_info *mci) * * The injection code don't work without setting this register. * The register needs to be flipped off then on else the hardware - * will only preform the first injection. + * will only perform the first injection. * * Stop condition bits 7:4 * 1010 - Stop after one injection @@ -1220,6 +1220,5 @@ module_init(i5100_init); module_exit(i5100_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR - ("Arthur Jones <ajones@riverbed.com>"); +MODULE_AUTHOR("Arthur Jones <ajones@riverbed.com>"); MODULE_DESCRIPTION("MC Driver for Intel I5100 memory controllers"); diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c index fbec90d00f1e..b8a497f0de28 100644 --- a/drivers/edac/i82860_edac.c +++ b/drivers/edac/i82860_edac.c @@ -355,8 +355,7 @@ module_init(i82860_init); module_exit(i82860_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) " - "Ben Woodard <woodard@redhat.com>"); +MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) Ben Woodard <woodard@redhat.com>"); MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers"); module_param(edac_op_state, int, 0444); diff --git a/drivers/edac/layerscape_edac.c b/drivers/edac/layerscape_edac.c index 35ceaca578e1..7c5e2b3c0daa 100644 --- a/drivers/edac/layerscape_edac.c +++ b/drivers/edac/layerscape_edac.c @@ -72,5 +72,4 @@ module_exit(fsl_ddr_mc_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("NXP Semiconductor"); module_param(edac_op_state, int, 0444); -MODULE_PARM_DESC(edac_op_state, - "EDAC Error Reporting state: 0=Poll, 2=Interrupt"); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll, 2=Interrupt"); diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index e50d7928bf8f..55320546c174 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -711,5 +711,4 @@ module_exit(mpc85xx_mc_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Montavista Software, Inc."); module_param(edac_op_state, int, 0444); -MODULE_PARM_DESC(edac_op_state, - "EDAC Error Reporting state: 0=Poll, 2=Interrupt"); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll, 2=Interrupt"); diff --git a/drivers/edac/qcom_edac.c b/drivers/edac/qcom_edac.c index 3256254c3722..265e0fb39bc7 100644 --- a/drivers/edac/qcom_edac.c +++ b/drivers/edac/qcom_edac.c @@ -76,6 +76,8 @@ #define DRP0_INTERRUPT_ENABLE BIT(6) #define SB_DB_DRP_INTERRUPT_ENABLE 0x3 +#define ECC_POLL_MSEC 5000 + enum { LLCC_DRAM_CE = 0, LLCC_DRAM_UE, @@ -213,7 +215,7 @@ dump_syn_reg_values(struct llcc_drv_data *drv, u32 bank, int err_type) for (i = 0; i < reg_data.reg_cnt; i++) { synd_reg = reg_data.synd_reg + (i * 4); - ret = regmap_read(drv->regmap, drv->offsets[bank] + synd_reg, + ret = regmap_read(drv->regmaps[bank], synd_reg, &synd_val); if (ret) goto clear; @@ -222,8 +224,7 @@ dump_syn_reg_values(struct llcc_drv_data *drv, u32 bank, int err_type) reg_data.name, i, synd_val); } - ret = regmap_read(drv->regmap, - drv->offsets[bank] + reg_data.count_status_reg, + ret = regmap_read(drv->regmaps[bank], reg_data.count_status_reg, &err_cnt); if (ret) goto clear; @@ -233,8 +234,7 @@ dump_syn_reg_values(struct llcc_drv_data *drv, u32 bank, int err_type) edac_printk(KERN_CRIT, EDAC_LLCC, "%s: Error count: 0x%4x\n", reg_data.name, err_cnt); - ret = regmap_read(drv->regmap, - drv->offsets[bank] + reg_data.ways_status_reg, + ret = regmap_read(drv->regmaps[bank], reg_data.ways_status_reg, &err_ways); if (ret) goto clear; @@ -285,8 +285,7 @@ dump_syn_reg(struct edac_device_ctl_info *edev_ctl, int err_type, u32 bank) return ret; } -static irqreturn_t -llcc_ecc_irq_handler(int irq, void *edev_ctl) +static irqreturn_t llcc_ecc_irq_handler(int irq, void *edev_ctl) { struct edac_device_ctl_info *edac_dev_ctl = edev_ctl; struct llcc_drv_data *drv = edac_dev_ctl->dev->platform_data; @@ -296,8 +295,7 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl) /* Iterate over the banks and look for Tag RAM or Data RAM errors */ for (i = 0; i < drv->num_banks; i++) { - ret = regmap_read(drv->regmap, - drv->offsets[i] + DRP_INTERRUPT_STATUS, + ret = regmap_read(drv->regmaps[i], DRP_INTERRUPT_STATUS, &drp_error); if (!ret && (drp_error & SB_ECC_ERROR)) { @@ -312,8 +310,7 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl) if (!ret) irq_rc = IRQ_HANDLED; - ret = regmap_read(drv->regmap, - drv->offsets[i] + TRP_INTERRUPT_0_STATUS, + ret = regmap_read(drv->regmaps[i], TRP_INTERRUPT_0_STATUS, &trp_error); if (!ret && (trp_error & SB_ECC_ERROR)) { @@ -332,6 +329,11 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl) return irq_rc; } +static void llcc_ecc_check(struct edac_device_ctl_info *edev_ctl) +{ + llcc_ecc_irq_handler(0, edev_ctl); +} + static int qcom_llcc_edac_probe(struct platform_device *pdev) { struct llcc_drv_data *llcc_driv_data = pdev->dev.platform_data; @@ -359,29 +361,31 @@ static int qcom_llcc_edac_probe(struct platform_device *pdev) edev_ctl->ctl_name = "llcc"; edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE; - rc = edac_device_add_device(edev_ctl); - if (rc) - goto out_mem; - - platform_set_drvdata(pdev, edev_ctl); - - /* Request for ecc irq */ + /* Check if LLCC driver has passed ECC IRQ */ ecc_irq = llcc_driv_data->ecc_irq; - if (ecc_irq < 0) { - rc = -ENODEV; - goto out_dev; - } - rc = devm_request_irq(dev, ecc_irq, llcc_ecc_irq_handler, + if (ecc_irq > 0) { + /* Use interrupt mode if IRQ is available */ + rc = devm_request_irq(dev, ecc_irq, llcc_ecc_irq_handler, IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl); - if (rc) - goto out_dev; + if (!rc) { + edac_op_state = EDAC_OPSTATE_INT; + goto irq_done; + } + } - return rc; + /* Fall back to polling mode otherwise */ + edev_ctl->poll_msec = ECC_POLL_MSEC; + edev_ctl->edac_check = llcc_ecc_check; + edac_op_state = EDAC_OPSTATE_POLL; -out_dev: - edac_device_del_device(edev_ctl->dev); -out_mem: - edac_device_free_ctl_info(edev_ctl); +irq_done: + rc = edac_device_add_device(edev_ctl); + if (rc) { + edac_device_free_ctl_info(edev_ctl); + return rc; + } + + platform_set_drvdata(pdev, edev_ctl); return rc; } diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c index d0aef83dca2a..61e979d5437a 100644 --- a/drivers/edac/r82600_edac.c +++ b/drivers/edac/r82600_edac.c @@ -415,8 +415,7 @@ module_init(r82600_init); module_exit(r82600_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD Ltd. " - "on behalf of EADS Astrium"); +MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD Ltd. on behalf of EADS Astrium"); MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers"); module_param(disable_hardware_scrub, bool, 0644); diff --git a/drivers/edac/skx_base.c b/drivers/edac/skx_base.c index 9397abb42c49..0a862336a7ce 100644 --- a/drivers/edac/skx_base.c +++ b/drivers/edac/skx_base.c @@ -510,7 +510,7 @@ rir_found: } static u8 skx_close_row[] = { - 15, 16, 17, 18, 20, 21, 22, 28, 10, 11, 12, 13, 29, 30, 31, 32, 33 + 15, 16, 17, 18, 20, 21, 22, 28, 10, 11, 12, 13, 29, 30, 31, 32, 33, 34 }; static u8 skx_close_column[] = { @@ -518,7 +518,7 @@ static u8 skx_close_column[] = { }; static u8 skx_open_row[] = { - 14, 15, 16, 20, 28, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33 + 14, 15, 16, 20, 28, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34 }; static u8 skx_open_column[] = { diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index dbc474ff62b7..e7d97b59963b 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -2289,7 +2289,7 @@ static int scmi_xfer_info_init(struct scmi_info *sinfo) return ret; ret = __scmi_xfer_info_init(sinfo, &sinfo->tx_minfo); - if (!ret && idr_find(&sinfo->rx_idr, SCMI_PROTOCOL_BASE)) + if (!ret && !idr_is_empty(&sinfo->rx_idr)) ret = __scmi_xfer_info_init(sinfo, &sinfo->rx_minfo); return ret; diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/mailbox.c index 112c285deb97..1efa5e9392c4 100644 --- a/drivers/firmware/arm_scmi/mailbox.c +++ b/drivers/firmware/arm_scmi/mailbox.c @@ -19,13 +19,15 @@ * struct scmi_mailbox - Structure representing a SCMI mailbox transport * * @cl: Mailbox Client - * @chan: Transmit/Receive mailbox channel + * @chan: Transmit/Receive mailbox uni/bi-directional channel + * @chan_receiver: Optional Receiver mailbox unidirectional channel * @cinfo: SCMI channel info * @shmem: Transmit/Receive shared memory area */ struct scmi_mailbox { struct mbox_client cl; struct mbox_chan *chan; + struct mbox_chan *chan_receiver; struct scmi_chan_info *cinfo; struct scmi_shared_mem __iomem *shmem; }; @@ -48,30 +50,62 @@ static void rx_callback(struct mbox_client *cl, void *m) static bool mailbox_chan_available(struct device_node *of_node, int idx) { + int num_mb; + + /* + * Just check if bidirrectional channels are involved, and check the + * index accordingly; proper full validation will be made later + * in mailbox_chan_setup(). + */ + num_mb = of_count_phandle_with_args(of_node, "mboxes", "#mbox-cells"); + if (num_mb == 3 && idx == 1) + idx = 2; + return !of_parse_phandle_with_args(of_node, "mboxes", "#mbox-cells", idx, NULL); } -static int mailbox_chan_validate(struct device *cdev) +/** + * mailbox_chan_validate - Validate transport configuration and map channels + * + * @cdev: Reference to the underlying transport device carrying the + * of_node descriptor to analyze. + * @a2p_rx_chan: A reference to an optional unidirectional channel to use + * for replies on the a2p channel. Set as zero if not present. + * @p2a_chan: A reference to the optional p2a channel. + * Set as zero if not present. + * + * At first, validate the transport configuration as described in terms of + * 'mboxes' and 'shmem', then determin which mailbox channel indexes are + * appropriate to be use in the current configuration. + * + * Return: 0 on Success or error + */ +static int mailbox_chan_validate(struct device *cdev, + int *a2p_rx_chan, int *p2a_chan) { int num_mb, num_sh, ret = 0; struct device_node *np = cdev->of_node; num_mb = of_count_phandle_with_args(np, "mboxes", "#mbox-cells"); num_sh = of_count_phandle_with_args(np, "shmem", NULL); + dev_dbg(cdev, "Found %d mboxes and %d shmems !\n", num_mb, num_sh); + /* Bail out if mboxes and shmem descriptors are inconsistent */ - if (num_mb <= 0 || num_sh > 2 || num_mb != num_sh) { - dev_warn(cdev, "Invalid channel descriptor for '%s'\n", - of_node_full_name(np)); + if (num_mb <= 0 || num_sh <= 0 || num_sh > 2 || num_mb > 3 || + (num_mb == 1 && num_sh != 1) || (num_mb == 3 && num_sh != 2)) { + dev_warn(cdev, + "Invalid channel descriptor for '%s' - mbs:%d shm:%d\n", + of_node_full_name(np), num_mb, num_sh); return -EINVAL; } + /* Bail out if provided shmem descriptors do not refer distinct areas */ if (num_sh > 1) { struct device_node *np_tx, *np_rx; np_tx = of_parse_phandle(np, "shmem", 0); np_rx = of_parse_phandle(np, "shmem", 1); - /* SCMI Tx and Rx shared mem areas have to be distinct */ if (!np_tx || !np_rx || np_tx == np_rx) { dev_warn(cdev, "Invalid shmem descriptor for '%s'\n", of_node_full_name(np)); @@ -82,6 +116,29 @@ static int mailbox_chan_validate(struct device *cdev) of_node_put(np_rx); } + /* Calculate channels IDs to use depending on mboxes/shmem layout */ + if (!ret) { + switch (num_mb) { + case 1: + *a2p_rx_chan = 0; + *p2a_chan = 0; + break; + case 2: + if (num_sh == 2) { + *a2p_rx_chan = 0; + *p2a_chan = 1; + } else { + *a2p_rx_chan = 1; + *p2a_chan = 0; + } + break; + case 3: + *a2p_rx_chan = 1; + *p2a_chan = 2; + break; + } + } + return ret; } @@ -92,15 +149,18 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, struct device *cdev = cinfo->dev; struct scmi_mailbox *smbox; struct device_node *shmem; - int ret, idx = tx ? 0 : 1; + int ret, a2p_rx_chan, p2a_chan, idx = tx ? 0 : 1; struct mbox_client *cl; resource_size_t size; struct resource res; - ret = mailbox_chan_validate(cdev); + ret = mailbox_chan_validate(cdev, &a2p_rx_chan, &p2a_chan); if (ret) return ret; + if (!tx && !p2a_chan) + return -ENODEV; + smbox = devm_kzalloc(dev, sizeof(*smbox), GFP_KERNEL); if (!smbox) return -ENOMEM; @@ -130,15 +190,26 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, cl->tx_block = false; cl->knows_txdone = tx; - smbox->chan = mbox_request_channel(cl, tx ? 0 : 1); + smbox->chan = mbox_request_channel(cl, tx ? 0 : p2a_chan); if (IS_ERR(smbox->chan)) { ret = PTR_ERR(smbox->chan); if (ret != -EPROBE_DEFER) - dev_err(cdev, "failed to request SCMI %s mailbox\n", - tx ? "Tx" : "Rx"); + dev_err(cdev, + "failed to request SCMI %s mailbox\n", desc); return ret; } + /* Additional unidirectional channel for TX if needed */ + if (tx && a2p_rx_chan) { + smbox->chan_receiver = mbox_request_channel(cl, a2p_rx_chan); + if (IS_ERR(smbox->chan_receiver)) { + ret = PTR_ERR(smbox->chan_receiver); + if (ret != -EPROBE_DEFER) + dev_err(cdev, "failed to request SCMI Tx Receiver mailbox\n"); + return ret; + } + } + cinfo->transport_info = smbox; smbox->cinfo = cinfo; @@ -152,8 +223,10 @@ static int mailbox_chan_free(int id, void *p, void *data) if (smbox && !IS_ERR(smbox->chan)) { mbox_free_channel(smbox->chan); + mbox_free_channel(smbox->chan_receiver); cinfo->transport_info = NULL; smbox->chan = NULL; + smbox->chan_receiver = NULL; smbox->cinfo = NULL; } diff --git a/drivers/firmware/arm_scmi/optee.c b/drivers/firmware/arm_scmi/optee.c index 929720387102..e123de6e8c67 100644 --- a/drivers/firmware/arm_scmi/optee.c +++ b/drivers/firmware/arm_scmi/optee.c @@ -403,7 +403,7 @@ out: static int setup_shmem(struct device *dev, struct scmi_chan_info *cinfo, struct scmi_optee_channel *channel) { - if (of_find_property(cinfo->dev->of_node, "shmem", NULL)) + if (of_property_present(cinfo->dev->of_node, "shmem")) return setup_static_shmem(dev, cinfo, channel); else return setup_dynamic_shmem(dev, channel); diff --git a/drivers/firmware/arm_sdei.c b/drivers/firmware/arm_sdei.c index 1e1a51510e83..f9040bd61081 100644 --- a/drivers/firmware/arm_sdei.c +++ b/drivers/firmware/arm_sdei.c @@ -43,6 +43,8 @@ static asmlinkage void (*sdei_firmware_call)(unsigned long function_id, /* entry point from firmware to arch asm code */ static unsigned long sdei_entry_point; +static int sdei_hp_state; + struct sdei_event { /* These three are protected by the sdei_list_lock */ struct list_head list; @@ -301,8 +303,6 @@ int sdei_mask_local_cpu(void) { int err; - WARN_ON_ONCE(preemptible()); - err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_MASK, 0, 0, 0, 0, 0, NULL); if (err && err != -EIO) { pr_warn_once("failed to mask CPU[%u]: %d\n", @@ -315,6 +315,7 @@ int sdei_mask_local_cpu(void) static void _ipi_mask_cpu(void *ignored) { + WARN_ON_ONCE(preemptible()); sdei_mask_local_cpu(); } @@ -322,8 +323,6 @@ int sdei_unmask_local_cpu(void) { int err; - WARN_ON_ONCE(preemptible()); - err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_UNMASK, 0, 0, 0, 0, 0, NULL); if (err && err != -EIO) { pr_warn_once("failed to unmask CPU[%u]: %d\n", @@ -336,6 +335,7 @@ int sdei_unmask_local_cpu(void) static void _ipi_unmask_cpu(void *ignored) { + WARN_ON_ONCE(preemptible()); sdei_unmask_local_cpu(); } @@ -343,6 +343,8 @@ static void _ipi_private_reset(void *ignored) { int err; + WARN_ON_ONCE(preemptible()); + err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PRIVATE_RESET, 0, 0, 0, 0, 0, NULL); if (err && err != -EIO) @@ -389,8 +391,6 @@ static void _local_event_enable(void *data) int err; struct sdei_crosscall_args *arg = data; - WARN_ON_ONCE(preemptible()); - err = sdei_api_event_enable(arg->event->event_num); sdei_cross_call_return(arg, err); @@ -479,8 +479,6 @@ static void _local_event_unregister(void *data) int err; struct sdei_crosscall_args *arg = data; - WARN_ON_ONCE(preemptible()); - err = sdei_api_event_unregister(arg->event->event_num); sdei_cross_call_return(arg, err); @@ -561,8 +559,6 @@ static void _local_event_register(void *data) struct sdei_registered_event *reg; struct sdei_crosscall_args *arg = data; - WARN_ON(preemptible()); - reg = per_cpu_ptr(arg->event->private_registered, smp_processor_id()); err = sdei_api_event_register(arg->event->event_num, sdei_entry_point, reg, 0, 0); @@ -717,6 +713,8 @@ static int sdei_pm_notifier(struct notifier_block *nb, unsigned long action, { int rv; + WARN_ON_ONCE(preemptible()); + switch (action) { case CPU_PM_ENTER: rv = sdei_mask_local_cpu(); @@ -765,7 +763,7 @@ static int sdei_device_freeze(struct device *dev) int err; /* unregister private events */ - cpuhp_remove_state(CPUHP_AP_ARM_SDEI_STARTING); + cpuhp_remove_state(sdei_entry_point); err = sdei_unregister_shared(); if (err) @@ -786,12 +784,15 @@ static int sdei_device_thaw(struct device *dev) return err; } - err = cpuhp_setup_state(CPUHP_AP_ARM_SDEI_STARTING, "SDEI", + err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "SDEI", &sdei_cpuhp_up, &sdei_cpuhp_down); - if (err) + if (err < 0) { pr_warn("Failed to re-register CPU hotplug notifier...\n"); + return err; + } - return err; + sdei_hp_state = err; + return 0; } static int sdei_device_restore(struct device *dev) @@ -823,7 +824,7 @@ static int sdei_reboot_notifier(struct notifier_block *nb, unsigned long action, * We are going to reset the interface, after this there is no point * doing work when we take CPUs offline. */ - cpuhp_remove_state(CPUHP_AP_ARM_SDEI_STARTING); + cpuhp_remove_state(sdei_hp_state); sdei_platform_reset(); @@ -1003,13 +1004,15 @@ static int sdei_probe(struct platform_device *pdev) goto remove_cpupm; } - err = cpuhp_setup_state(CPUHP_AP_ARM_SDEI_STARTING, "SDEI", + err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "SDEI", &sdei_cpuhp_up, &sdei_cpuhp_down); - if (err) { + if (err < 0) { pr_warn("Failed to register CPU hotplug notifier...\n"); goto remove_reboot; } + sdei_hp_state = err; + return 0; remove_reboot: diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c index dca79caccd01..47db49911e7b 100644 --- a/drivers/firmware/imx/imx-scu.c +++ b/drivers/firmware/imx/imx-scu.c @@ -310,9 +310,8 @@ static int imx_scu_probe(struct platform_device *pdev) sc_chan->ch = mbox_request_channel_byname(cl, chan_name); if (IS_ERR(sc_chan->ch)) { ret = PTR_ERR(sc_chan->ch); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to request mbox chan %s ret %d\n", - chan_name, ret); + dev_err_probe(dev, ret, "Failed to request mbox chan %s\n", + chan_name); kfree(chan_name); return ret; } diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c index 2a4f07423365..84b673427073 100644 --- a/drivers/firmware/imx/scu-pd.c +++ b/drivers/firmware/imx/scu-pd.c @@ -180,7 +180,11 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { /* LVDS SS */ { "lvds0", IMX_SC_R_LVDS_0, 1, false, 0 }, + { "lvds0-pwm", IMX_SC_R_LVDS_0_PWM_0, 1, false, 0 }, + { "lvds0-lpi2c", IMX_SC_R_LVDS_0_I2C_0, 2, true, 0 }, { "lvds1", IMX_SC_R_LVDS_1, 1, false, 0 }, + { "lvds1-pwm", IMX_SC_R_LVDS_1_PWM_0, 1, false, 0 }, + { "lvds1-lpi2c", IMX_SC_R_LVDS_1_I2C_0, 2, true, 0 }, /* DC SS */ { "dc0", IMX_SC_R_DC_0, 1, false, 0 }, diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c index 3f5ff9ed668e..798bcdb05d84 100644 --- a/drivers/firmware/meson/meson_sm.c +++ b/drivers/firmware/meson/meson_sm.c @@ -311,11 +311,14 @@ static int __init meson_sm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, fw); - pr_info("secure-monitor enabled\n"); + if (devm_of_platform_populate(dev)) + goto out_in_base; if (sysfs_create_group(&pdev->dev.kobj, &meson_sm_sysfs_attr_group)) goto out_in_base; + pr_info("secure-monitor enabled\n"); + return 0; out_in_base: diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c index 29619f49873a..d9629ff87861 100644 --- a/drivers/firmware/psci/psci.c +++ b/drivers/firmware/psci/psci.c @@ -167,7 +167,8 @@ int psci_set_osi_mode(bool enable) err = invoke_psci_fn(PSCI_1_0_FN_SET_SUSPEND_MODE, suspend_mode, 0, 0); if (err < 0) - pr_warn("failed to set %s mode: %d\n", enable ? "OSI" : "PC", err); + pr_info(FW_BUG "failed to set %s mode: %d\n", + enable ? "OSI" : "PC", err); return psci_to_linux_errno(err); } diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index b1e11f85b805..fde33acd46b7 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -905,7 +905,7 @@ static int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region, * Return negative errno on failure or 0 on success with @srcvm updated. */ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, - unsigned int *srcvm, + u64 *srcvm, const struct qcom_scm_vmperm *newvm, unsigned int dest_cnt) { @@ -922,9 +922,9 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, __le32 *src; void *ptr; int ret, i, b; - unsigned long srcvm_bits = *srcvm; + u64 srcvm_bits = *srcvm; - src_sz = hweight_long(srcvm_bits) * sizeof(*src); + src_sz = hweight64(srcvm_bits) * sizeof(*src); mem_to_map_sz = sizeof(*mem_to_map); dest_sz = dest_cnt * sizeof(*destvm); ptr_sz = ALIGN(src_sz, SZ_64) + ALIGN(mem_to_map_sz, SZ_64) + @@ -937,8 +937,10 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, /* Fill source vmid detail */ src = ptr; i = 0; - for_each_set_bit(b, &srcvm_bits, BITS_PER_LONG) - src[i++] = cpu_to_le32(b); + for (b = 0; b < BITS_PER_TYPE(u64); b++) { + if (srcvm_bits & BIT(b)) + src[i++] = cpu_to_le32(b); + } /* Fill details of mem buff to map */ mem_to_map = ptr + ALIGN(src_sz, SZ_64); @@ -1506,8 +1508,7 @@ static int qcom_scm_probe(struct platform_device *pdev) static void qcom_scm_shutdown(struct platform_device *pdev) { /* Clean shutdown, disable download mode to allow normal restart */ - if (download_mode) - qcom_scm_set_download_mode(false); + qcom_scm_set_download_mode(false); } static const struct of_device_id qcom_scm_dt_match[] = { @@ -1542,6 +1543,7 @@ static const struct of_device_id qcom_scm_dt_match[] = { }, { .compatible = "qcom,scm-msm8994" }, { .compatible = "qcom,scm-msm8996" }, + { .compatible = "qcom,scm-sm6375", .data = (void *)SCM_HAS_CORE_CLK }, { .compatible = "qcom,scm" }, {} }; diff --git a/drivers/firmware/smccc/smccc.c b/drivers/firmware/smccc/smccc.c index 60ccf3e90d7d..db818f9dcb8e 100644 --- a/drivers/firmware/smccc/smccc.c +++ b/drivers/firmware/smccc/smccc.c @@ -17,9 +17,13 @@ static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE; bool __ro_after_init smccc_trng_available = false; u64 __ro_after_init smccc_has_sve_hint = false; +s32 __ro_after_init smccc_soc_id_version = SMCCC_RET_NOT_SUPPORTED; +s32 __ro_after_init smccc_soc_id_revision = SMCCC_RET_NOT_SUPPORTED; void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit) { + struct arm_smccc_res res; + smccc_version = version; smccc_conduit = conduit; @@ -27,6 +31,18 @@ void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit) if (IS_ENABLED(CONFIG_ARM64_SVE) && smccc_version >= ARM_SMCCC_VERSION_1_3) smccc_has_sve_hint = true; + + if ((smccc_version >= ARM_SMCCC_VERSION_1_2) && + (smccc_conduit != SMCCC_CONDUIT_NONE)) { + arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, + ARM_SMCCC_ARCH_SOC_ID, &res); + if ((s32)res.a0 >= 0) { + arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 0, &res); + smccc_soc_id_version = (s32)res.a0; + arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 1, &res); + smccc_soc_id_revision = (s32)res.a0; + } + } } enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void) @@ -44,6 +60,16 @@ u32 arm_smccc_get_version(void) } EXPORT_SYMBOL_GPL(arm_smccc_get_version); +s32 arm_smccc_get_soc_id_version(void) +{ + return smccc_soc_id_version; +} + +s32 arm_smccc_get_soc_id_revision(void) +{ + return smccc_soc_id_revision; +} + static int __init smccc_devices_init(void) { struct platform_device *pdev; diff --git a/drivers/firmware/smccc/soc_id.c b/drivers/firmware/smccc/soc_id.c index dd7c3d5e8b0b..890eb454599a 100644 --- a/drivers/firmware/smccc/soc_id.c +++ b/drivers/firmware/smccc/soc_id.c @@ -42,41 +42,23 @@ static int __init smccc_soc_init(void) if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2) return 0; - if (arm_smccc_1_1_get_conduit() == SMCCC_CONDUIT_NONE) { - pr_err("%s: invalid SMCCC conduit\n", __func__); - return -EOPNOTSUPP; - } - - arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, - ARM_SMCCC_ARCH_SOC_ID, &res); - - if ((int)res.a0 == SMCCC_RET_NOT_SUPPORTED) { + soc_id_version = arm_smccc_get_soc_id_version(); + if (soc_id_version == SMCCC_RET_NOT_SUPPORTED) { pr_info("ARCH_SOC_ID not implemented, skipping ....\n"); return 0; } - if ((int)res.a0 < 0) { - pr_info("ARCH_FEATURES(ARCH_SOC_ID) returned error: %lx\n", - res.a0); - return -EINVAL; - } - - arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 0, &res); - if ((int)res.a0 < 0) { + if (soc_id_version < 0) { pr_err("ARCH_SOC_ID(0) returned error: %lx\n", res.a0); return -EINVAL; } - soc_id_version = res.a0; - - arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 1, &res); - if ((int)res.a0 < 0) { + soc_id_rev = arm_smccc_get_soc_id_revision(); + if (soc_id_rev < 0) { pr_err("ARCH_SOC_ID(1) returned error: %lx\n", res.a0); return -EINVAL; } - soc_id_rev = res.a0; - soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); if (!soc_dev_attr) return -ENOMEM; diff --git a/drivers/firmware/tegra/bpmp-debugfs.c b/drivers/firmware/tegra/bpmp-debugfs.c index 3ca2b5d9e66f..6dfe3d34109e 100644 --- a/drivers/firmware/tegra/bpmp-debugfs.c +++ b/drivers/firmware/tegra/bpmp-debugfs.c @@ -193,7 +193,7 @@ static int mrq_debug_read(struct tegra_bpmp *bpmp, const char *name, }, }; u32 fd = 0, len = 0; - int remaining, err; + int remaining, err, close_err; mutex_lock(&bpmp_debug_lock); err = mrq_debug_open(bpmp, name, &fd, &len, 0); @@ -231,7 +231,9 @@ static int mrq_debug_read(struct tegra_bpmp *bpmp, const char *name, *nbytes = len; close: - err = mrq_debug_close(bpmp, fd); + close_err = mrq_debug_close(bpmp, fd); + if (!err) + err = close_err; out: mutex_unlock(&bpmp_debug_lock); return err; @@ -319,7 +321,7 @@ static int bpmp_debug_show(struct seq_file *m, void *p) }, }; u32 fd = 0, len = 0; - int remaining, err; + int remaining, err, close_err; filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf)); if (!filename) @@ -353,7 +355,9 @@ static int bpmp_debug_show(struct seq_file *m, void *p) } close: - err = mrq_debug_close(bpmp, fd); + close_err = mrq_debug_close(bpmp, fd); + if (!err) + err = close_err; out: mutex_unlock(&bpmp_debug_lock); return err; diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index 042c2043929d..8b5e5daa9fae 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c @@ -764,19 +764,19 @@ static int tegra_bpmp_probe(struct platform_device *pdev) if (err < 0) goto free_mrq; - if (of_find_property(pdev->dev.of_node, "#clock-cells", NULL)) { + if (of_property_present(pdev->dev.of_node, "#clock-cells")) { err = tegra_bpmp_init_clocks(bpmp); if (err < 0) goto free_mrq; } - if (of_find_property(pdev->dev.of_node, "#reset-cells", NULL)) { + if (of_property_present(pdev->dev.of_node, "#reset-cells")) { err = tegra_bpmp_init_resets(bpmp); if (err < 0) goto free_mrq; } - if (of_find_property(pdev->dev.of_node, "#power-domain-cells", NULL)) { + if (of_property_present(pdev->dev.of_node, "#power-domain-cells")) { err = tegra_bpmp_init_powergates(bpmp); if (err < 0) goto free_mrq; diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index 6ea5789a89e2..2de0fb139ce1 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -104,7 +104,7 @@ static void mox_kobj_release(struct kobject *kobj) kfree(to_rwtm(kobj)->kobj); } -static struct kobj_type mox_kobj_ktype = { +static const struct kobj_type mox_kobj_ktype = { .release = mox_kobj_release, .sysfs_ops = &kobj_sysfs_ops, }; diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c index 0914e7328b1a..1bc04378118c 100644 --- a/drivers/fpga/dfl-pci.c +++ b/drivers/fpga/dfl-pci.c @@ -21,7 +21,6 @@ #include <linux/module.h> #include <linux/stddef.h> #include <linux/errno.h> -#include <linux/aer.h> #include "dfl.h" @@ -376,10 +375,6 @@ int cci_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *pcidevid) return ret; } - ret = pci_enable_pcie_error_reporting(pcidev); - if (ret && ret != -EINVAL) - dev_info(&pcidev->dev, "PCIE AER unavailable %d.\n", ret); - pci_set_master(pcidev); ret = dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(64)); @@ -387,24 +382,22 @@ int cci_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *pcidevid) ret = dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32)); if (ret) { dev_err(&pcidev->dev, "No suitable DMA support available.\n"); - goto disable_error_report_exit; + return ret; } ret = cci_init_drvdata(pcidev); if (ret) { dev_err(&pcidev->dev, "Fail to init drvdata %d.\n", ret); - goto disable_error_report_exit; + return ret; } ret = cci_enumerate_feature_devs(pcidev); - if (!ret) + if (ret) { + dev_err(&pcidev->dev, "enumeration failure %d.\n", ret); return ret; + } - dev_err(&pcidev->dev, "enumeration failure %d.\n", ret); - -disable_error_report_exit: - pci_disable_pcie_error_reporting(pcidev); - return ret; + return 0; } static int cci_pci_sriov_configure(struct pci_dev *pcidev, int num_vfs) @@ -448,7 +441,6 @@ static void cci_pci_remove(struct pci_dev *pcidev) cci_pci_sriov_configure(pcidev, 0); cci_remove_feature_devs(pcidev); - pci_disable_pcie_error_reporting(pcidev); } static struct pci_driver cci_pci_driver = { diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c index 5cd40acab5bf..0953e6e4db04 100644 --- a/drivers/fpga/fpga-bridge.c +++ b/drivers/fpga/fpga-bridge.c @@ -363,7 +363,6 @@ fpga_bridge_register(struct device *parent, const char *name, bridge->dev.parent = parent; bridge->dev.of_node = parent->of_node; bridge->dev.id = id; - of_platform_populate(bridge->dev.of_node, NULL, NULL, &bridge->dev); ret = dev_set_name(&bridge->dev, "br%d", id); if (ret) @@ -375,6 +374,8 @@ fpga_bridge_register(struct device *parent, const char *name, return ERR_PTR(ret); } + of_platform_populate(bridge->dev.of_node, NULL, NULL, &bridge->dev); + return bridge; error_device: diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c index f0acedc80182..d7e2f9f461bc 100644 --- a/drivers/fpga/intel-m10-bmc-sec-update.c +++ b/drivers/fpga/intel-m10-bmc-sec-update.c @@ -474,7 +474,7 @@ static enum fw_upload_err rsu_send_data(struct m10bmc_sec *sec) ret = sec->ops->rsu_status(sec); if (ret < 0) - return ret; + return FW_UPLOAD_ERR_HW_ERROR; status = ret; if (!rsu_status_ok(status)) { diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c index 2d9c491f7be9..b76d85449b8f 100644 --- a/drivers/fpga/xilinx-pr-decoupler.c +++ b/drivers/fpga/xilinx-pr-decoupler.c @@ -69,7 +69,7 @@ static int xlnx_pr_decoupler_enable_show(struct fpga_bridge *bridge) if (err) return err; - status = readl(priv->io_base); + status = xlnx_pr_decouple_read(priv, CTRL_OFFSET); clk_disable(priv->clk); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 13be729710f2..badbe0582318 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -100,7 +100,7 @@ config GPIO_GENERIC tristate config GPIO_REGMAP - depends on REGMAP + select REGMAP tristate # put drivers in the right section, in alphabetical order diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index a3846faf3780..11c48130bb8f 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -86,6 +86,7 @@ static const struct regmap_config dio48e_regmap_config = { .volatile_table = &dio48e_volatile_table, .precious_table = &dio48e_precious_table, .cache_type = REGCACHE_FLAT, + .use_raw_spinlock = true, }; /* only bit 3 on each respective Port C supports interrupts */ diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index ca2175b84e24..ba73ee9c0c29 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -81,6 +81,7 @@ static const struct regmap_config idi48_regmap_config = { .wr_table = &idi_48_wr_table, .rd_table = &idi_48_rd_table, .precious_table = &idi_48_precious_table, + .use_raw_spinlock = true, }; #define IDI48_NGPIO 48 diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 26b1f7465e09..43b2dc8821e6 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -324,7 +324,7 @@ static struct irq_chip gpio_irqchip = { .irq_enable = gpio_irq_enable, .irq_disable = gpio_irq_disable, .irq_set_type = gpio_irq_type, - .flags = IRQCHIP_SET_TYPE_MASKED, + .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_SKIP_SET_WAKE, }; static void gpio_irq_handler(struct irq_desc *desc) @@ -641,9 +641,6 @@ static void davinci_gpio_save_context(struct davinci_gpio_controller *chips, context->set_falling = readl_relaxed(&g->set_falling); } - /* Clear Bank interrupt enable bit */ - writel_relaxed(0, base + BINTEN); - /* Clear all interrupt status registers */ writel_relaxed(GENMASK(31, 0), &g->intstat); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 60b1857f469e..aeeec211861c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -981,7 +981,12 @@ static bool amdgpu_atcs_pci_probe_handle(struct pci_dev *pdev) */ bool amdgpu_acpi_should_gpu_reset(struct amdgpu_device *adev) { - if (adev->flags & AMD_IS_APU) + if ((adev->flags & AMD_IS_APU) && + adev->gfx.imu.funcs) /* Not need to do mode2 reset for IMU enabled APUs */ + return false; + + if ((adev->flags & AMD_IS_APU) && + amdgpu_acpi_is_s3_active(adev)) return false; if (amdgpu_sriov_vf(adev)) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c index d0a1cc88832c..fafebec5b7b6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c @@ -596,6 +596,9 @@ int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src, if (!src->enabled_types || !src->funcs->set) return -EINVAL; + if (WARN_ON(!amdgpu_irq_enabled(adev, src, type))) + return -EINVAL; + if (atomic_dec_and_test(&src->enabled_types[type])) return amdgpu_irq_update(adev, src, type); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index dc4f37240beb..8af70feca720 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c @@ -169,10 +169,21 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable) if (rc) return rc; - irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst; + if (amdgpu_in_reset(adev)) { + irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst; + /* During gpu-reset we disable and then enable vblank irq, so + * don't use amdgpu_irq_get/put() to avoid refcount change. + */ + if (!dc_interrupt_set(adev->dm.dc, irq_source, enable)) + rc = -EBUSY; + } else { + rc = (enable) + ? amdgpu_irq_get(adev, &adev->crtc_irq, acrtc->crtc_id) + : amdgpu_irq_put(adev, &adev->crtc_irq, acrtc->crtc_id); + } - if (!dc_interrupt_set(adev->dm.dc, irq_source, enable)) - return -EBUSY; + if (rc) + return rc; skip: if (amdgpu_in_reset(adev)) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index 1583157da355..efd025d8961e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -177,6 +177,40 @@ void dm_helpers_dp_update_branch_info( const struct dc_link *link) {} +static void dm_helpers_construct_old_payload( + struct dc_link *link, + int pbn_per_slot, + struct drm_dp_mst_atomic_payload *new_payload, + struct drm_dp_mst_atomic_payload *old_payload) +{ + struct link_mst_stream_allocation_table current_link_table = + link->mst_stream_alloc_table; + struct link_mst_stream_allocation *dc_alloc; + int i; + + *old_payload = *new_payload; + + /* Set correct time_slots/PBN of old payload. + * other fields (delete & dsc_enabled) in + * struct drm_dp_mst_atomic_payload are don't care fields + * while calling drm_dp_remove_payload() + */ + for (i = 0; i < current_link_table.stream_count; i++) { + dc_alloc = + ¤t_link_table.stream_allocations[i]; + + if (dc_alloc->vcp_id == new_payload->vcpi) { + old_payload->time_slots = dc_alloc->slot_count; + old_payload->pbn = dc_alloc->slot_count * pbn_per_slot; + break; + } + } + + /* make sure there is an old payload*/ + ASSERT(i != current_link_table.stream_count); + +} + /* * Writes payload allocation table in immediate downstream device. */ @@ -188,7 +222,7 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( { struct amdgpu_dm_connector *aconnector; struct drm_dp_mst_topology_state *mst_state; - struct drm_dp_mst_atomic_payload *payload; + struct drm_dp_mst_atomic_payload *target_payload, *new_payload, old_payload; struct drm_dp_mst_topology_mgr *mst_mgr; aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; @@ -204,17 +238,26 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state); /* It's OK for this to fail */ - payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port); - if (enable) - drm_dp_add_payload_part1(mst_mgr, mst_state, payload); - else - drm_dp_remove_payload(mst_mgr, mst_state, payload, payload); + new_payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port); + + if (enable) { + target_payload = new_payload; + + drm_dp_add_payload_part1(mst_mgr, mst_state, new_payload); + } else { + /* construct old payload by VCPI*/ + dm_helpers_construct_old_payload(stream->link, mst_state->pbn_div, + new_payload, &old_payload); + target_payload = &old_payload; + + drm_dp_remove_payload(mst_mgr, mst_state, &old_payload, new_payload); + } /* mst_mgr->->payloads are VC payload notify MST branch using DPCD or * AUX message. The sequence is slot 1-63 allocated sequence for each * stream. AMD ASIC stream slot allocation should follow the same * sequence. copy DRM MST allocation to dc */ - fill_dc_mst_payload_table_from_drm(stream->link, enable, payload, proposed_table); + fill_dc_mst_payload_table_from_drm(stream->link, enable, target_payload, proposed_table); return true; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index e25e1b2bf194..8dc442f90eaf 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -212,6 +212,21 @@ bool needs_dsc_aux_workaround(struct dc_link *link) return false; } +bool is_synaptics_cascaded_panamera(struct dc_link *link, struct drm_dp_mst_port *port) +{ + u8 branch_vendor_data[4] = { 0 }; // Vendor data 0x50C ~ 0x50F + + if (drm_dp_dpcd_read(port->mgr->aux, DP_BRANCH_VENDOR_SPECIFIC_START, &branch_vendor_data, 4) == 4) { + if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC24 && + IS_SYNAPTICS_CASCADED_PANAMERA(link->dpcd_caps.branch_dev_name, branch_vendor_data)) { + DRM_INFO("Synaptics Cascaded MST hub\n"); + return true; + } + } + + return false; +} + static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnector) { struct dc_sink *dc_sink = aconnector->dc_sink; @@ -235,6 +250,10 @@ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnecto needs_dsc_aux_workaround(aconnector->dc_link)) aconnector->dsc_aux = &aconnector->mst_root->dm_dp_aux.aux; + /* synaptics cascaded MST hub case */ + if (!aconnector->dsc_aux && is_synaptics_cascaded_panamera(aconnector->dc_link, port)) + aconnector->dsc_aux = port->mgr->aux; + if (!aconnector->dsc_aux) return false; @@ -662,12 +681,25 @@ struct dsc_mst_fairness_params { struct amdgpu_dm_connector *aconnector; }; -static int kbps_to_peak_pbn(int kbps) +static uint16_t get_fec_overhead_multiplier(struct dc_link *dc_link) +{ + u8 link_coding_cap; + uint16_t fec_overhead_multiplier_x1000 = PBN_FEC_OVERHEAD_MULTIPLIER_8B_10B; + + link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(dc_link); + if (link_coding_cap == DP_128b_132b_ENCODING) + fec_overhead_multiplier_x1000 = PBN_FEC_OVERHEAD_MULTIPLIER_128B_132B; + + return fec_overhead_multiplier_x1000; +} + +static int kbps_to_peak_pbn(int kbps, uint16_t fec_overhead_multiplier_x1000) { u64 peak_kbps = kbps; peak_kbps *= 1006; - peak_kbps = div_u64(peak_kbps, 1000); + peak_kbps *= fec_overhead_multiplier_x1000; + peak_kbps = div_u64(peak_kbps, 1000 * 1000); return (int) DIV64_U64_ROUND_UP(peak_kbps * 64, (54 * 8 * 1000)); } @@ -761,11 +793,12 @@ static int increase_dsc_bpp(struct drm_atomic_state *state, int link_timeslots_used; int fair_pbn_alloc; int ret = 0; + uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link); for (i = 0; i < count; i++) { if (vars[i + k].dsc_enabled) { initial_slack[i] = - kbps_to_peak_pbn(params[i].bw_range.max_kbps) - vars[i + k].pbn; + kbps_to_peak_pbn(params[i].bw_range.max_kbps, fec_overhead_multiplier_x1000) - vars[i + k].pbn; bpp_increased[i] = false; remaining_to_increase += 1; } else { @@ -861,6 +894,7 @@ static int try_disable_dsc(struct drm_atomic_state *state, int next_index; int remaining_to_try = 0; int ret; + uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link); for (i = 0; i < count; i++) { if (vars[i + k].dsc_enabled @@ -890,7 +924,7 @@ static int try_disable_dsc(struct drm_atomic_state *state, if (next_index == -1) break; - vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.stream_kbps); + vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.stream_kbps, fec_overhead_multiplier_x1000); ret = drm_dp_atomic_find_time_slots(state, params[next_index].port->mgr, params[next_index].port, @@ -903,7 +937,7 @@ static int try_disable_dsc(struct drm_atomic_state *state, vars[next_index].dsc_enabled = false; vars[next_index].bpp_x16 = 0; } else { - vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.max_kbps); + vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.max_kbps, fec_overhead_multiplier_x1000); ret = drm_dp_atomic_find_time_slots(state, params[next_index].port->mgr, params[next_index].port, @@ -932,6 +966,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, int count = 0; int i, k, ret; bool debugfs_overwrite = false; + uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link); memset(params, 0, sizeof(params)); @@ -993,7 +1028,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, /* Try no compression */ for (i = 0; i < count; i++) { vars[i + k].aconnector = params[i].aconnector; - vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps); + vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps, fec_overhead_multiplier_x1000); vars[i + k].dsc_enabled = false; vars[i + k].bpp_x16 = 0; ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, params[i].port, @@ -1012,7 +1047,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, /* Try max compression */ for (i = 0; i < count; i++) { if (params[i].compression_possible && params[i].clock_force_enable != DSC_CLK_FORCE_DISABLE) { - vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps); + vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps, fec_overhead_multiplier_x1000); vars[i + k].dsc_enabled = true; vars[i + k].bpp_x16 = params[i].bw_range.min_target_bpp_x16; ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, @@ -1020,7 +1055,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, if (ret < 0) return ret; } else { - vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps); + vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps, fec_overhead_multiplier_x1000); vars[i + k].dsc_enabled = false; vars[i + k].bpp_x16 = 0; ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h index 97fd70df531b..1e4ede1e57ab 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h @@ -34,6 +34,21 @@ #define SYNAPTICS_RC_OFFSET 0x4BC #define SYNAPTICS_RC_DATA 0x4C0 +#define DP_BRANCH_VENDOR_SPECIFIC_START 0x50C + +/** + * Panamera MST Hub detection + * Offset DPCD 050Eh == 0x5A indicates cascaded MST hub case + * Check from beginning of branch device vendor specific field (050Ch) + */ +#define IS_SYNAPTICS_PANAMERA(branchDevName) (((int)branchDevName[4] & 0xF0) == 0x50 ? 1 : 0) +#define BRANCH_HW_REVISION_PANAMERA_A2 0x10 +#define SYNAPTICS_CASCADED_HUB_ID 0x5A +#define IS_SYNAPTICS_CASCADED_PANAMERA(devName, data) ((IS_SYNAPTICS_PANAMERA(devName) && ((int)data[2] == SYNAPTICS_CASCADED_HUB_ID)) ? 1 : 0) + +#define PBN_FEC_OVERHEAD_MULTIPLIER_8B_10B 1031 +#define PBN_FEC_OVERHEAD_MULTIPLIER_128B_132B 1000 + struct amdgpu_display_manager; struct amdgpu_dm_connector; diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c index 54ed3de869d3..9ffba4c6fe55 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c @@ -1697,6 +1697,23 @@ static void dcn314_get_panel_config_defaults(struct dc_panel_config *panel_confi *panel_config = panel_config_defaults; } +static bool filter_modes_for_single_channel_workaround(struct dc *dc, + struct dc_state *context) +{ + // Filter 2K@240Hz+8K@24fps above combination timing if memory only has single dimm LPDDR + if (dc->clk_mgr->bw_params->vram_type == 34 && dc->clk_mgr->bw_params->num_channels < 2) { + int total_phy_pix_clk = 0; + + for (int i = 0; i < context->stream_count; i++) + if (context->res_ctx.pipe_ctx[i].stream) + total_phy_pix_clk += context->res_ctx.pipe_ctx[i].stream->phy_pix_clk; + + if (total_phy_pix_clk >= (1148928+826260)) //2K@240Hz+8K@24fps + return true; + } + return false; +} + bool dcn314_validate_bandwidth(struct dc *dc, struct dc_state *context, bool fast_validate) @@ -1712,6 +1729,9 @@ bool dcn314_validate_bandwidth(struct dc *dc, BW_VAL_TRACE_COUNT(); + if (filter_modes_for_single_channel_workaround(dc, context)) + goto validate_fail; + DC_FP_START(); // do not support self refresh only out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate, false); diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c index b37d14369a62..59836570603a 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c @@ -222,7 +222,7 @@ struct _vcs_dpi_ip_params_st dcn3_15_ip = { .maximum_dsc_bits_per_component = 10, .dsc422_native_support = false, .is_line_buffer_bpp_fixed = true, - .line_buffer_fixed_bpp = 49, + .line_buffer_fixed_bpp = 48, .line_buffer_size_bits = 789504, .max_line_buffer_lines = 12, .writeback_interface_buffer_size_kbytes = 90, diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c index e39b133d05af..b56f07f99d09 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c @@ -934,6 +934,10 @@ bool psr_su_set_dsc_slice_height(struct dc *dc, struct dc_link *link, pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; + + if (stream->timing.dsc_cfg.num_slices_v == 0) + return false; + slice_height = pic_height / stream->timing.dsc_cfg.num_slices_v; config->dsc_slice_height = slice_height; diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h index f085cb97a620..85a090b9e3d9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h @@ -61,6 +61,12 @@ #define CTF_OFFSET_HOTSPOT 5 #define CTF_OFFSET_MEM 5 +static const int pmfw_decoded_link_speed[5] = {1, 2, 3, 4, 5}; +static const int pmfw_decoded_link_width[7] = {0, 1, 2, 4, 8, 12, 16}; + +#define DECODE_GEN_SPEED(gen_speed_idx) (pmfw_decoded_link_speed[gen_speed_idx]) +#define DECODE_LANE_WIDTH(lane_width_idx) (pmfw_decoded_link_width[lane_width_idx]) + struct smu_13_0_max_sustainable_clocks { uint32_t display_clock; uint32_t phy_clock; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index 27448ffe60a4..a5c97d61e92a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -1144,8 +1144,8 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu, (pcie_table->pcie_lane[i] == 5) ? "x12" : (pcie_table->pcie_lane[i] == 6) ? "x16" : "", pcie_table->clk_freq[i], - ((gen_speed - 1) == pcie_table->pcie_gen[i]) && - (lane_width == link_width[pcie_table->pcie_lane[i]]) ? + (gen_speed == DECODE_GEN_SPEED(pcie_table->pcie_gen[i])) && + (lane_width == DECODE_LANE_WIDTH(link_width[pcie_table->pcie_lane[i]])) ? "*" : ""); break; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index 9e1967d8049e..4399416dd9b8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -575,6 +575,14 @@ static int smu_v13_0_7_set_default_dpm_table(struct smu_context *smu) dpm_table); if (ret) return ret; + + if (skutable->DriverReportedClocks.GameClockAc && + (dpm_table->dpm_levels[dpm_table->count - 1].value > + skutable->DriverReportedClocks.GameClockAc)) { + dpm_table->dpm_levels[dpm_table->count - 1].value = + skutable->DriverReportedClocks.GameClockAc; + dpm_table->max = skutable->DriverReportedClocks.GameClockAc; + } } else { dpm_table->count = 1; dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100; @@ -828,6 +836,57 @@ static int smu_v13_0_7_get_smu_metrics_data(struct smu_context *smu, return ret; } +static int smu_v13_0_7_get_dpm_ultimate_freq(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *min, + uint32_t *max) +{ + struct smu_13_0_dpm_context *dpm_context = + smu->smu_dpm.dpm_context; + struct smu_13_0_dpm_table *dpm_table; + + switch (clk_type) { + case SMU_MCLK: + case SMU_UCLK: + /* uclk dpm table */ + dpm_table = &dpm_context->dpm_tables.uclk_table; + break; + case SMU_GFXCLK: + case SMU_SCLK: + /* gfxclk dpm table */ + dpm_table = &dpm_context->dpm_tables.gfx_table; + break; + case SMU_SOCCLK: + /* socclk dpm table */ + dpm_table = &dpm_context->dpm_tables.soc_table; + break; + case SMU_FCLK: + /* fclk dpm table */ + dpm_table = &dpm_context->dpm_tables.fclk_table; + break; + case SMU_VCLK: + case SMU_VCLK1: + /* vclk dpm table */ + dpm_table = &dpm_context->dpm_tables.vclk_table; + break; + case SMU_DCLK: + case SMU_DCLK1: + /* dclk dpm table */ + dpm_table = &dpm_context->dpm_tables.dclk_table; + break; + default: + dev_err(smu->adev->dev, "Unsupported clock type!\n"); + return -EINVAL; + } + + if (min) + *min = dpm_table->min; + if (max) + *max = dpm_table->max; + + return 0; +} + static int smu_v13_0_7_read_sensor(struct smu_context *smu, enum amd_pp_sensors sensor, void *data, @@ -1074,8 +1133,8 @@ static int smu_v13_0_7_print_clk_levels(struct smu_context *smu, (pcie_table->pcie_lane[i] == 5) ? "x12" : (pcie_table->pcie_lane[i] == 6) ? "x16" : "", pcie_table->clk_freq[i], - (gen_speed == pcie_table->pcie_gen[i]) && - (lane_width == pcie_table->pcie_lane[i]) ? + (gen_speed == DECODE_GEN_SPEED(pcie_table->pcie_gen[i])) && + (lane_width == DECODE_LANE_WIDTH(pcie_table->pcie_lane[i])) ? "*" : ""); break; @@ -1329,9 +1388,17 @@ static int smu_v13_0_7_populate_umd_state_clk(struct smu_context *smu) &dpm_context->dpm_tables.fclk_table; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; + struct smu_table_context *table_context = &smu->smu_table; + PPTable_t *pptable = table_context->driver_pptable; + DriverReportedClocks_t driver_clocks = + pptable->SkuTable.DriverReportedClocks; pstate_table->gfxclk_pstate.min = gfx_table->min; - pstate_table->gfxclk_pstate.peak = gfx_table->max; + if (driver_clocks.GameClockAc && + (driver_clocks.GameClockAc < gfx_table->max)) + pstate_table->gfxclk_pstate.peak = driver_clocks.GameClockAc; + else + pstate_table->gfxclk_pstate.peak = gfx_table->max; pstate_table->uclk_pstate.min = mem_table->min; pstate_table->uclk_pstate.peak = mem_table->max; @@ -1348,12 +1415,12 @@ static int smu_v13_0_7_populate_umd_state_clk(struct smu_context *smu) pstate_table->fclk_pstate.min = fclk_table->min; pstate_table->fclk_pstate.peak = fclk_table->max; - /* - * For now, just use the mininum clock frequency. - * TODO: update them when the real pstate settings available - */ - pstate_table->gfxclk_pstate.standard = gfx_table->min; - pstate_table->uclk_pstate.standard = mem_table->min; + if (driver_clocks.BaseClockAc && + driver_clocks.BaseClockAc < gfx_table->max) + pstate_table->gfxclk_pstate.standard = driver_clocks.BaseClockAc; + else + pstate_table->gfxclk_pstate.standard = gfx_table->max; + pstate_table->uclk_pstate.standard = mem_table->max; pstate_table->socclk_pstate.standard = soc_table->min; pstate_table->vclk_pstate.standard = vclk_table->min; pstate_table->dclk_pstate.standard = dclk_table->min; @@ -1676,7 +1743,7 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .dpm_set_jpeg_enable = smu_v13_0_set_jpeg_enable, .init_pptable_microcode = smu_v13_0_init_pptable_microcode, .populate_umd_state_clk = smu_v13_0_7_populate_umd_state_clk, - .get_dpm_ultimate_freq = smu_v13_0_get_dpm_ultimate_freq, + .get_dpm_ultimate_freq = smu_v13_0_7_get_dpm_ultimate_freq, .get_vbios_bootup_values = smu_v13_0_get_vbios_bootup_values, .read_sensor = smu_v13_0_7_read_sensor, .feature_is_enabled = smu_cmn_feature_is_enabled, diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index 0643887800b4..142668cd6d7c 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -99,7 +99,6 @@ static int armada_drm_bind(struct device *dev) if (ret) { dev_err(dev, "[" DRM_NAME ":%s] can't kick out simple-fb: %d\n", __func__, ret); - kfree(priv); return ret; } diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index 3d1f50f481cf..7098f125b54a 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -146,8 +146,8 @@ int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size) unsigned int order; u64 root_size; - root_size = rounddown_pow_of_two(size); - order = ilog2(root_size) - ilog2(chunk_size); + order = ilog2(size) - ilog2(chunk_size); + root_size = chunk_size << order; root = drm_block_alloc(mm, NULL, order, offset); if (!root) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index 44ca803237a5..31a7f59ccb49 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -22,7 +22,6 @@ #include "etnaviv_gem.h" #include "etnaviv_mmu.h" #include "etnaviv_perfmon.h" -#include "common.xml.h" /* * DRM operations: @@ -476,47 +475,7 @@ static const struct drm_ioctl_desc etnaviv_ioctls[] = { ETNA_IOCTL(PM_QUERY_SIG, pm_query_sig, DRM_RENDER_ALLOW), }; -static void etnaviv_fop_show_fdinfo(struct seq_file *m, struct file *f) -{ - struct drm_file *file = f->private_data; - struct drm_device *dev = file->minor->dev; - struct etnaviv_drm_private *priv = dev->dev_private; - struct etnaviv_file_private *ctx = file->driver_priv; - - /* - * For a description of the text output format used here, see - * Documentation/gpu/drm-usage-stats.rst. - */ - seq_printf(m, "drm-driver:\t%s\n", dev->driver->name); - seq_printf(m, "drm-client-id:\t%u\n", ctx->id); - - for (int i = 0; i < ETNA_MAX_PIPES; i++) { - struct etnaviv_gpu *gpu = priv->gpu[i]; - char engine[10] = "UNK"; - int cur = 0; - - if (!gpu) - continue; - - if (gpu->identity.features & chipFeatures_PIPE_2D) - cur = snprintf(engine, sizeof(engine), "2D"); - if (gpu->identity.features & chipFeatures_PIPE_3D) - cur = snprintf(engine + cur, sizeof(engine) - cur, - "%s3D", cur ? "/" : ""); - if (gpu->identity.nn_core_count > 0) - cur = snprintf(engine + cur, sizeof(engine) - cur, - "%sNN", cur ? "/" : ""); - - seq_printf(m, "drm-engine-%s:\t%llu ns\n", engine, - ctx->sched_entity[i].elapsed_ns); - } -} - -static const struct file_operations fops = { - .owner = THIS_MODULE, - DRM_GEM_FOPS, - .show_fdinfo = etnaviv_fop_show_fdinfo, -}; +DEFINE_DRM_GEM_FOPS(fops); static const struct drm_driver etnaviv_drm_driver = { .driver_features = DRIVER_GEM | DRIVER_RENDER, diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c index 7031db145a77..3524b5811682 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c @@ -91,7 +91,15 @@ static void *etnaviv_gem_prime_vmap_impl(struct etnaviv_gem_object *etnaviv_obj) static int etnaviv_gem_prime_mmap_obj(struct etnaviv_gem_object *etnaviv_obj, struct vm_area_struct *vma) { - return dma_buf_mmap(etnaviv_obj->base.dma_buf, vma, 0); + int ret; + + ret = dma_buf_mmap(etnaviv_obj->base.dma_buf, vma, 0); + if (!ret) { + /* Drop the reference acquired by drm_gem_mmap_obj(). */ + drm_gem_object_put(&etnaviv_obj->base); + } + + return ret; } static const struct etnaviv_gem_ops etnaviv_gem_prime_ops = { diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 468a792e6a40..fc0eaf40dc94 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -300,9 +300,21 @@ static void configure_dual_link_mode(struct intel_encoder *encoder, { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); + i915_reg_t dss_ctl1_reg, dss_ctl2_reg; u32 dss_ctl1; - dss_ctl1 = intel_de_read(dev_priv, DSS_CTL1); + /* FIXME: Move all DSS handling to intel_vdsc.c */ + if (DISPLAY_VER(dev_priv) >= 12) { + struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); + + dss_ctl1_reg = ICL_PIPE_DSS_CTL1(crtc->pipe); + dss_ctl2_reg = ICL_PIPE_DSS_CTL2(crtc->pipe); + } else { + dss_ctl1_reg = DSS_CTL1; + dss_ctl2_reg = DSS_CTL2; + } + + dss_ctl1 = intel_de_read(dev_priv, dss_ctl1_reg); dss_ctl1 |= SPLITTER_ENABLE; dss_ctl1 &= ~OVERLAP_PIXELS_MASK; dss_ctl1 |= OVERLAP_PIXELS(intel_dsi->pixel_overlap); @@ -323,16 +335,16 @@ static void configure_dual_link_mode(struct intel_encoder *encoder, dss_ctl1 &= ~LEFT_DL_BUF_TARGET_DEPTH_MASK; dss_ctl1 |= LEFT_DL_BUF_TARGET_DEPTH(dl_buffer_depth); - dss_ctl2 = intel_de_read(dev_priv, DSS_CTL2); + dss_ctl2 = intel_de_read(dev_priv, dss_ctl2_reg); dss_ctl2 &= ~RIGHT_DL_BUF_TARGET_DEPTH_MASK; dss_ctl2 |= RIGHT_DL_BUF_TARGET_DEPTH(dl_buffer_depth); - intel_de_write(dev_priv, DSS_CTL2, dss_ctl2); + intel_de_write(dev_priv, dss_ctl2_reg, dss_ctl2); } else { /* Interleave */ dss_ctl1 |= DUAL_LINK_MODE_INTERLEAVE; } - intel_de_write(dev_priv, DSS_CTL1, dss_ctl1); + intel_de_write(dev_priv, dss_ctl1_reg, dss_ctl1); } /* aka DSI 8X clock */ diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 8d97c299e657..bd598a7f5047 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -47,6 +47,11 @@ struct intel_color_funcs { */ void (*color_commit_arm)(const struct intel_crtc_state *crtc_state); /* + * Perform any extra tasks needed after all the + * double buffered registers have been latched. + */ + void (*color_post_update)(const struct intel_crtc_state *crtc_state); + /* * Load LUTs (and other single buffered color management * registers). Will (hopefully) be called during the vblank * following the latching of any double buffered registers @@ -614,9 +619,33 @@ static void ilk_lut_12p4_pack(struct drm_color_lut *entry, u32 ldw, u32 udw) static void icl_color_commit_noarm(const struct intel_crtc_state *crtc_state) { + /* + * Despite Wa_1406463849, ICL no longer suffers from the SKL + * DC5/PSR CSC black screen issue (see skl_color_commit_noarm()). + * Possibly due to the extra sticky CSC arming + * (see icl_color_post_update()). + * + * On TGL+ all CSC arming issues have been properly fixed. + */ icl_load_csc_matrix(crtc_state); } +static void skl_color_commit_noarm(const struct intel_crtc_state *crtc_state) +{ + /* + * Possibly related to display WA #1184, SKL CSC loses the latched + * CSC coeff/offset register values if the CSC registers are disarmed + * between DC5 exit and PSR exit. This will cause the plane(s) to + * output all black (until CSC_MODE is rearmed and properly latched). + * Once PSR exit (and proper register latching) has occurred the + * danger is over. Thus when PSR is enabled the CSC coeff/offset + * register programming will be peformed from skl_color_commit_arm() + * which is called after PSR exit. + */ + if (!crtc_state->has_psr) + ilk_load_csc_matrix(crtc_state); +} + static void ilk_color_commit_noarm(const struct intel_crtc_state *crtc_state) { ilk_load_csc_matrix(crtc_state); @@ -659,6 +688,9 @@ static void skl_color_commit_arm(const struct intel_crtc_state *crtc_state) enum pipe pipe = crtc->pipe; u32 val = 0; + if (crtc_state->has_psr) + ilk_load_csc_matrix(crtc_state); + /* * We don't (yet) allow userspace to control the pipe background color, * so force it to black, but apply pipe gamma and CSC appropriately @@ -677,6 +709,47 @@ static void skl_color_commit_arm(const struct intel_crtc_state *crtc_state) crtc_state->csc_mode); } +static void icl_color_commit_arm(const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + + /* + * We don't (yet) allow userspace to control the pipe background color, + * so force it to black. + */ + intel_de_write(i915, SKL_BOTTOM_COLOR(pipe), 0); + + intel_de_write(i915, GAMMA_MODE(crtc->pipe), + crtc_state->gamma_mode); + + intel_de_write_fw(i915, PIPE_CSC_MODE(crtc->pipe), + crtc_state->csc_mode); +} + +static void icl_color_post_update(const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + + /* + * Despite Wa_1406463849, ICL CSC is no longer disarmed by + * coeff/offset register *writes*. Instead, once CSC_MODE + * is armed it stays armed, even after it has been latched. + * Afterwards the coeff/offset registers become effectively + * self-arming. That self-arming must be disabled before the + * next icl_color_commit_noarm() tries to write the next set + * of coeff/offset registers. Fortunately register *reads* + * do still disarm the CSC. Naturally this must not be done + * until the previously written CSC registers have actually + * been latched. + * + * TGL+ no longer need this workaround. + */ + intel_de_read_fw(i915, PIPE_CSC_PREOFF_HI(crtc->pipe)); +} + static struct drm_property_blob * create_linear_lut(struct drm_i915_private *i915, int lut_size) { @@ -1373,6 +1446,14 @@ void intel_color_commit_arm(const struct intel_crtc_state *crtc_state) i915->display.funcs.color->color_commit_arm(crtc_state); } +void intel_color_post_update(const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + + if (i915->display.funcs.color->color_post_update) + i915->display.funcs.color->color_post_update(crtc_state); +} + void intel_color_prepare_commit(struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); @@ -3064,10 +3145,20 @@ static const struct intel_color_funcs i9xx_color_funcs = { .lut_equal = i9xx_lut_equal, }; +static const struct intel_color_funcs tgl_color_funcs = { + .color_check = icl_color_check, + .color_commit_noarm = icl_color_commit_noarm, + .color_commit_arm = icl_color_commit_arm, + .load_luts = icl_load_luts, + .read_luts = icl_read_luts, + .lut_equal = icl_lut_equal, +}; + static const struct intel_color_funcs icl_color_funcs = { .color_check = icl_color_check, .color_commit_noarm = icl_color_commit_noarm, - .color_commit_arm = skl_color_commit_arm, + .color_commit_arm = icl_color_commit_arm, + .color_post_update = icl_color_post_update, .load_luts = icl_load_luts, .read_luts = icl_read_luts, .lut_equal = icl_lut_equal, @@ -3075,7 +3166,7 @@ static const struct intel_color_funcs icl_color_funcs = { static const struct intel_color_funcs glk_color_funcs = { .color_check = glk_color_check, - .color_commit_noarm = ilk_color_commit_noarm, + .color_commit_noarm = skl_color_commit_noarm, .color_commit_arm = skl_color_commit_arm, .load_luts = glk_load_luts, .read_luts = glk_read_luts, @@ -3084,7 +3175,7 @@ static const struct intel_color_funcs glk_color_funcs = { static const struct intel_color_funcs skl_color_funcs = { .color_check = ivb_color_check, - .color_commit_noarm = ilk_color_commit_noarm, + .color_commit_noarm = skl_color_commit_noarm, .color_commit_arm = skl_color_commit_arm, .load_luts = bdw_load_luts, .read_luts = bdw_read_luts, @@ -3180,7 +3271,9 @@ void intel_color_init_hooks(struct drm_i915_private *i915) else i915->display.funcs.color = &i9xx_color_funcs; } else { - if (DISPLAY_VER(i915) >= 11) + if (DISPLAY_VER(i915) >= 12) + i915->display.funcs.color = &tgl_color_funcs; + else if (DISPLAY_VER(i915) == 11) i915->display.funcs.color = &icl_color_funcs; else if (DISPLAY_VER(i915) == 10) i915->display.funcs.color = &glk_color_funcs; diff --git a/drivers/gpu/drm/i915/display/intel_color.h b/drivers/gpu/drm/i915/display/intel_color.h index d620b5b1e2a6..8002492be709 100644 --- a/drivers/gpu/drm/i915/display/intel_color.h +++ b/drivers/gpu/drm/i915/display/intel_color.h @@ -21,6 +21,7 @@ void intel_color_prepare_commit(struct intel_crtc_state *crtc_state); void intel_color_cleanup_commit(struct intel_crtc_state *crtc_state); void intel_color_commit_noarm(const struct intel_crtc_state *crtc_state); void intel_color_commit_arm(const struct intel_crtc_state *crtc_state); +void intel_color_post_update(const struct intel_crtc_state *crtc_state); void intel_color_load_luts(const struct intel_crtc_state *crtc_state); void intel_color_get_config(struct intel_crtc_state *crtc_state); bool intel_color_lut_equal(const struct intel_crtc_state *crtc_state, diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 208b1b5b15dd..63b4b73f47c6 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -1209,6 +1209,9 @@ static void intel_post_plane_update(struct intel_atomic_state *state, if (needs_cursorclk_wa(old_crtc_state) && !needs_cursorclk_wa(new_crtc_state)) icl_wa_cursorclkgating(dev_priv, pipe, false); + + if (intel_crtc_needs_color_update(new_crtc_state)) + intel_color_post_update(new_crtc_state); } static void intel_crtc_enable_flip_done(struct intel_atomic_state *state, @@ -7091,6 +7094,8 @@ static void intel_update_crtc(struct intel_atomic_state *state, intel_fbc_update(state, crtc); + drm_WARN_ON(&i915->drm, !intel_display_power_is_enabled(i915, POWER_DOMAIN_DC_OFF)); + if (!modeset && intel_crtc_needs_color_update(new_crtc_state)) intel_color_commit_noarm(new_crtc_state); @@ -7458,8 +7463,28 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) drm_atomic_helper_wait_for_dependencies(&state->base); drm_dp_mst_atomic_wait_for_dependencies(&state->base); - if (state->modeset) - wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET); + /* + * During full modesets we write a lot of registers, wait + * for PLLs, etc. Doing that while DC states are enabled + * is not a good idea. + * + * During fastsets and other updates we also need to + * disable DC states due to the following scenario: + * 1. DC5 exit and PSR exit happen + * 2. Some or all _noarm() registers are written + * 3. Due to some long delay PSR is re-entered + * 4. DC5 entry -> DMC saves the already written new + * _noarm() registers and the old not yet written + * _arm() registers + * 5. DC5 exit -> DMC restores a mixture of old and + * new register values and arms the update + * 6. PSR exit -> hardware latches a mixture of old and + * new register values -> corrupted frame, or worse + * 7. New _arm() registers are finally written + * 8. Hardware finally latches a complete set of new + * register values, and subsequent frames will be OK again + */ + wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_DC_OFF); intel_atomic_prepare_plane_clear_colors(state); @@ -7608,8 +7633,8 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) * the culprit. */ intel_uncore_arm_unclaimed_mmio_detection(&dev_priv->uncore); - intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET, wakeref); } + intel_display_power_put(dev_priv, POWER_DOMAIN_DC_OFF, wakeref); intel_runtime_pm_put(&dev_priv->runtime_pm, state->wakeref); /* diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c index 5a176bfb10a2..30c98810e28b 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c @@ -163,7 +163,7 @@ static u32 skl_get_aux_send_ctl(struct intel_dp *intel_dp, DP_AUX_CH_CTL_TIME_OUT_MAX | DP_AUX_CH_CTL_RECEIVE_ERROR | (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | - DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(32) | + DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(24) | DP_AUX_CH_CTL_SYNC_PULSE_SKL(32); if (intel_tc_port_in_tbt_alt_mode(dig_port)) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 2106b3de225a..7c9b328bc2d7 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -232,7 +232,7 @@ static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder, return slots; } - intel_link_compute_m_n(crtc_state->pipe_bpp, + intel_link_compute_m_n(crtc_state->dsc.compressed_bpp, crtc_state->lane_count, adjusted_mode->crtc_clock, crtc_state->port_clock, diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c index ad1a37b515fb..2a9f40a2b3ed 100644 --- a/drivers/gpu/drm/i915/display/intel_dpt.c +++ b/drivers/gpu/drm/i915/display/intel_dpt.c @@ -301,6 +301,7 @@ intel_dpt_create(struct intel_framebuffer *fb) vm->pte_encode = gen8_ggtt_pte_encode; dpt->obj = dpt_obj; + dpt->obj->is_dpt = true; return &dpt->vm; } @@ -309,5 +310,6 @@ void intel_dpt_destroy(struct i915_address_space *vm) { struct i915_dpt *dpt = i915_vm_to_dpt(vm); + dpt->obj->is_dpt = false; i915_vm_put(&dpt->vm); } diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index f45328712bff..be510b9c0d07 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -418,9 +418,9 @@ static bool icl_tc_phy_is_owned(struct intel_digital_port *dig_port) val = intel_de_read(i915, PORT_TX_DFLEXDPCSSS(dig_port->tc_phy_fia)); if (val == 0xffffffff) { drm_dbg_kms(&i915->drm, - "Port %s: PHY in TCCOLD, assume safe mode\n", + "Port %s: PHY in TCCOLD, assume not owned\n", dig_port->tc_port_name); - return true; + return false; } return val & DP_PHY_MODE_STATUS_NOT_SAFE(dig_port->tc_phy_fia_idx); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c index 8949fb0a944f..3198b64ad7db 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c @@ -127,7 +127,8 @@ i915_gem_object_create_lmem_from_data(struct drm_i915_private *i915, memcpy(map, data, size); - i915_gem_object_unpin_map(obj); + i915_gem_object_flush_map(obj); + __i915_gem_object_release_map(obj); return obj; } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h index f9a8acbba715..885ccde9dc3c 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -303,7 +303,7 @@ i915_gem_object_never_mmap(const struct drm_i915_gem_object *obj) static inline bool i915_gem_object_is_framebuffer(const struct drm_i915_gem_object *obj) { - return READ_ONCE(obj->frontbuffer); + return READ_ONCE(obj->frontbuffer) || obj->is_dpt; } static inline unsigned int diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h index 19c9bdd8f905..5dcbbef31d44 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h @@ -491,6 +491,9 @@ struct drm_i915_gem_object { */ unsigned int cache_dirty:1; + /* @is_dpt: Object houses a display page table (DPT) */ + unsigned int is_dpt:1; + /** * @read_domains: Read memory domains. * diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index 7420276827a5..4758f21c91e1 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -1067,11 +1067,12 @@ static vm_fault_t vm_fault_ttm(struct vm_fault *vmf) .interruptible = true, .no_wait_gpu = true, /* should be idle already */ }; + int err; GEM_BUG_ON(!bo->ttm || !(bo->ttm->page_flags & TTM_TT_FLAG_SWAPPED)); - ret = ttm_bo_validate(bo, i915_ttm_sys_placement(), &ctx); - if (ret) { + err = ttm_bo_validate(bo, i915_ttm_sys_placement(), &ctx); + if (err) { dma_resv_unlock(bo->base.resv); return VM_FAULT_SIGBUS; } diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c index 1bbe6708d0a7..750326434677 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c @@ -2018,6 +2018,8 @@ process_csb(struct intel_engine_cs *engine, struct i915_request **inactive) * inspecting the queue to see if we need to resumbit. */ if (*prev != *execlists->active) { /* elide lite-restores */ + struct intel_context *prev_ce = NULL, *active_ce = NULL; + /* * Note the inherent discrepancy between the HW runtime, * recorded as part of the context switch, and the CPU @@ -2029,9 +2031,15 @@ process_csb(struct intel_engine_cs *engine, struct i915_request **inactive) * and correct overselves later when updating from HW. */ if (*prev) - lrc_runtime_stop((*prev)->context); + prev_ce = (*prev)->context; if (*execlists->active) - lrc_runtime_start((*execlists->active)->context); + active_ce = (*execlists->active)->context; + if (prev_ce != active_ce) { + if (prev_ce) + lrc_runtime_stop(prev_ce); + if (active_ce) + lrc_runtime_start(active_ce); + } new_timeslice(execlists); } diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c index f5d7b5126433..2c92fa9d1942 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.c +++ b/drivers/gpu/drm/i915/gt/intel_rps.c @@ -2075,16 +2075,6 @@ void intel_rps_sanitize(struct intel_rps *rps) rps_disable_interrupts(rps); } -u32 intel_rps_read_rpstat_fw(struct intel_rps *rps) -{ - struct drm_i915_private *i915 = rps_to_i915(rps); - i915_reg_t rpstat; - - rpstat = (GRAPHICS_VER(i915) >= 12) ? GEN12_RPSTAT1 : GEN6_RPSTAT1; - - return intel_uncore_read_fw(rps_to_gt(rps)->uncore, rpstat); -} - u32 intel_rps_read_rpstat(struct intel_rps *rps) { struct drm_i915_private *i915 = rps_to_i915(rps); @@ -2095,7 +2085,7 @@ u32 intel_rps_read_rpstat(struct intel_rps *rps) return intel_uncore_read(rps_to_gt(rps)->uncore, rpstat); } -u32 intel_rps_get_cagf(struct intel_rps *rps, u32 rpstat) +static u32 intel_rps_get_cagf(struct intel_rps *rps, u32 rpstat) { struct drm_i915_private *i915 = rps_to_i915(rps); u32 cagf; @@ -2118,10 +2108,11 @@ u32 intel_rps_get_cagf(struct intel_rps *rps, u32 rpstat) return cagf; } -static u32 read_cagf(struct intel_rps *rps) +static u32 __read_cagf(struct intel_rps *rps, bool take_fw) { struct drm_i915_private *i915 = rps_to_i915(rps); struct intel_uncore *uncore = rps_to_uncore(rps); + i915_reg_t r = INVALID_MMIO_REG; u32 freq; /* @@ -2129,22 +2120,30 @@ static u32 read_cagf(struct intel_rps *rps) * registers will return 0 freq when GT is in RC6 */ if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) { - freq = intel_uncore_read(uncore, MTL_MIRROR_TARGET_WP1); + r = MTL_MIRROR_TARGET_WP1; } else if (GRAPHICS_VER(i915) >= 12) { - freq = intel_uncore_read(uncore, GEN12_RPSTAT1); + r = GEN12_RPSTAT1; } else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { vlv_punit_get(i915); freq = vlv_punit_read(i915, PUNIT_REG_GPU_FREQ_STS); vlv_punit_put(i915); } else if (GRAPHICS_VER(i915) >= 6) { - freq = intel_uncore_read(uncore, GEN6_RPSTAT1); + r = GEN6_RPSTAT1; } else { - freq = intel_uncore_read(uncore, MEMSTAT_ILK); + r = MEMSTAT_ILK; } + if (i915_mmio_reg_valid(r)) + freq = take_fw ? intel_uncore_read(uncore, r) : intel_uncore_read_fw(uncore, r); + return intel_rps_get_cagf(rps, freq); } +static u32 read_cagf(struct intel_rps *rps) +{ + return __read_cagf(rps, true); +} + u32 intel_rps_read_actual_frequency(struct intel_rps *rps) { struct intel_runtime_pm *rpm = rps_to_uncore(rps)->rpm; @@ -2157,7 +2156,12 @@ u32 intel_rps_read_actual_frequency(struct intel_rps *rps) return freq; } -u32 intel_rps_read_punit_req(struct intel_rps *rps) +u32 intel_rps_read_actual_frequency_fw(struct intel_rps *rps) +{ + return intel_gpu_freq(rps, __read_cagf(rps, false)); +} + +static u32 intel_rps_read_punit_req(struct intel_rps *rps) { struct intel_uncore *uncore = rps_to_uncore(rps); struct intel_runtime_pm *rpm = rps_to_uncore(rps)->rpm; diff --git a/drivers/gpu/drm/i915/gt/intel_rps.h b/drivers/gpu/drm/i915/gt/intel_rps.h index c622962c6bef..a3fa987aa91f 100644 --- a/drivers/gpu/drm/i915/gt/intel_rps.h +++ b/drivers/gpu/drm/i915/gt/intel_rps.h @@ -37,8 +37,8 @@ void intel_rps_mark_interactive(struct intel_rps *rps, bool interactive); int intel_gpu_freq(struct intel_rps *rps, int val); int intel_freq_opcode(struct intel_rps *rps, int val); -u32 intel_rps_get_cagf(struct intel_rps *rps, u32 rpstat1); u32 intel_rps_read_actual_frequency(struct intel_rps *rps); +u32 intel_rps_read_actual_frequency_fw(struct intel_rps *rps); u32 intel_rps_get_requested_frequency(struct intel_rps *rps); u32 intel_rps_get_min_frequency(struct intel_rps *rps); u32 intel_rps_get_min_raw_freq(struct intel_rps *rps); @@ -49,10 +49,8 @@ int intel_rps_set_max_frequency(struct intel_rps *rps, u32 val); u32 intel_rps_get_rp0_frequency(struct intel_rps *rps); u32 intel_rps_get_rp1_frequency(struct intel_rps *rps); u32 intel_rps_get_rpn_frequency(struct intel_rps *rps); -u32 intel_rps_read_punit_req(struct intel_rps *rps); u32 intel_rps_read_punit_req_frequency(struct intel_rps *rps); u32 intel_rps_read_rpstat(struct intel_rps *rps); -u32 intel_rps_read_rpstat_fw(struct intel_rps *rps); void gen6_rps_get_freq_caps(struct intel_rps *rps, struct intel_rps_freq_caps *caps); void intel_rps_raise_unslice(struct intel_rps *rps); void intel_rps_lower_unslice(struct intel_rps *rps); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.c b/drivers/gpu/drm/i915/gt/uc/intel_huc.c index 410905da8e97..0c103ca160d1 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.c @@ -235,6 +235,13 @@ static void delayed_huc_load_fini(struct intel_huc *huc) i915_sw_fence_fini(&huc->delayed_load.fence); } +int intel_huc_sanitize(struct intel_huc *huc) +{ + delayed_huc_load_complete(huc); + intel_uc_fw_sanitize(&huc->fw); + return 0; +} + static bool vcs_supported(struct intel_gt *gt) { intel_engine_mask_t mask = gt->info.engine_mask; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_huc.h b/drivers/gpu/drm/i915/gt/uc/intel_huc.h index 52db03620c60..db555b3c1f56 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_huc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_huc.h @@ -41,6 +41,7 @@ struct intel_huc { } delayed_load; }; +int intel_huc_sanitize(struct intel_huc *huc); void intel_huc_init_early(struct intel_huc *huc); int intel_huc_init(struct intel_huc *huc); void intel_huc_fini(struct intel_huc *huc); @@ -54,12 +55,6 @@ bool intel_huc_is_authenticated(struct intel_huc *huc); void intel_huc_register_gsc_notifier(struct intel_huc *huc, struct bus_type *bus); void intel_huc_unregister_gsc_notifier(struct intel_huc *huc, struct bus_type *bus); -static inline int intel_huc_sanitize(struct intel_huc *huc) -{ - intel_uc_fw_sanitize(&huc->fw); - return 0; -} - static inline bool intel_huc_is_supported(struct intel_huc *huc) { return intel_uc_fw_is_supported(&huc->fw); diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 824a34ec0b83..004074936300 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -1592,9 +1592,7 @@ static void i915_oa_stream_destroy(struct i915_perf_stream *stream) /* * Wa_16011777198:dg2: Unset the override of GUCRC mode to enable rc6. */ - if (intel_uc_uses_guc_rc(>->uc) && - (IS_DG2_GRAPHICS_STEP(gt->i915, G10, STEP_A0, STEP_C0) || - IS_DG2_GRAPHICS_STEP(gt->i915, G11, STEP_A0, STEP_B0))) + if (stream->override_gucrc) drm_WARN_ON(>->i915->drm, intel_guc_slpc_unset_gucrc_mode(>->uc.guc.slpc)); @@ -3305,8 +3303,10 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, if (ret) { drm_dbg(&stream->perf->i915->drm, "Unable to override gucrc mode\n"); - goto err_config; + goto err_gucrc; } + + stream->override_gucrc = true; } ret = alloc_oa_buffer(stream); @@ -3345,11 +3345,15 @@ err_enable: free_oa_buffer(stream); err_oa_buf_alloc: - free_oa_configs(stream); + if (stream->override_gucrc) + intel_guc_slpc_unset_gucrc_mode(>->uc.guc.slpc); +err_gucrc: intel_uncore_forcewake_put(stream->uncore, FORCEWAKE_ALL); intel_engine_pm_put(stream->engine); + free_oa_configs(stream); + err_config: free_noa_wait(stream); @@ -4634,13 +4638,13 @@ int i915_perf_add_config_ioctl(struct drm_device *dev, void *data, err = oa_config->id; goto sysfs_err; } - - mutex_unlock(&perf->metrics_lock); + id = oa_config->id; drm_dbg(&perf->i915->drm, "Added config %s id=%i\n", oa_config->uuid, oa_config->id); + mutex_unlock(&perf->metrics_lock); - return oa_config->id; + return id; sysfs_err: mutex_unlock(&perf->metrics_lock); diff --git a/drivers/gpu/drm/i915/i915_perf_types.h b/drivers/gpu/drm/i915/i915_perf_types.h index ca150b7af3f2..4d5d8c365d9e 100644 --- a/drivers/gpu/drm/i915/i915_perf_types.h +++ b/drivers/gpu/drm/i915/i915_perf_types.h @@ -316,6 +316,12 @@ struct i915_perf_stream { * buffer should be checked for available data. */ u64 poll_oa_period; + + /** + * @override_gucrc: GuC RC has been overridden for the perf stream, + * and we need to restore the default configuration on release. + */ + bool override_gucrc; }; /** diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 52531ab28c5f..6d422b056f8a 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -393,14 +393,12 @@ frequency_sample(struct intel_gt *gt, unsigned int period_ns) * case we assume the system is running at the intended * frequency. Fortunately, the read should rarely fail! */ - val = intel_rps_read_rpstat_fw(rps); - if (val) - val = intel_rps_get_cagf(rps, val); - else - val = rps->cur_freq; + val = intel_rps_read_actual_frequency_fw(rps); + if (!val) + val = intel_gpu_freq(rps, rps->cur_freq); add_sample_mult(&pmu->sample[__I915_SAMPLE_FREQ_ACT], - intel_gpu_freq(rps, val), period_ns / 1000); + val, period_ns / 1000); } if (pmu->enable & config_mask(I915_PMU_REQUESTED_FREQUENCY)) { diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index ed9d374147b8..5bb777ff1313 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -363,6 +363,35 @@ nv50_outp_atomic_check_view(struct drm_encoder *encoder, return 0; } +static void +nv50_outp_atomic_fix_depth(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state) +{ + struct nv50_head_atom *asyh = nv50_head_atom(crtc_state); + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_display_mode *mode = &asyh->state.adjusted_mode; + unsigned int max_rate, mode_rate; + + switch (nv_encoder->dcb->type) { + case DCB_OUTPUT_DP: + max_rate = nv_encoder->dp.link_nr * nv_encoder->dp.link_bw; + + /* we don't support more than 10 anyway */ + asyh->or.bpc = min_t(u8, asyh->or.bpc, 10); + + /* reduce the bpc until it works out */ + while (asyh->or.bpc > 6) { + mode_rate = DIV_ROUND_UP(mode->clock * asyh->or.bpc * 3, 8); + if (mode_rate <= max_rate) + break; + + asyh->or.bpc -= 2; + } + break; + default: + break; + } +} + static int nv50_outp_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, @@ -381,6 +410,9 @@ nv50_outp_atomic_check(struct drm_encoder *encoder, if (crtc_state->mode_changed || crtc_state->connectors_changed) asyh->or.bpc = connector->display_info.bpc; + /* We might have to reduce the bpc */ + nv50_outp_atomic_fix_depth(encoder, crtc_state); + return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index 40409a29f5b6..91b5ecc57538 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -33,6 +33,7 @@ #include <linux/apple-gmux.h> #include <linux/backlight.h> #include <linux/idr.h> +#include <drm/drm_probe_helper.h> #include "nouveau_drv.h" #include "nouveau_reg.h" @@ -299,8 +300,12 @@ nv50_backlight_init(struct nouveau_backlight *bl, struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); struct nvif_object *device = &drm->client.device.object; + /* + * Note when this runs the connectors have not been probed yet, + * so nv_conn->base.status is not set yet. + */ if (!nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(ffs(nv_encoder->dcb->or) - 1)) || - nv_conn->base.status != connector_status_connected) + drm_helper_probe_detect(&nv_conn->base, NULL, false) != connector_status_connected) return -ENODEV; if (nv_conn->type == DCB_CONNECTOR_eDP) { diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index e00876f92aee..d49b4875fc3c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -263,8 +263,6 @@ nouveau_dp_irq(struct work_struct *work) } /* TODO: - * - Use the minimum possible BPC here, once we add support for the max bpc - * property. * - Validate against the DP caps advertised by the GPU (we don't check these * yet) */ @@ -276,7 +274,11 @@ nv50_dp_mode_valid(struct drm_connector *connector, { const unsigned int min_clock = 25000; unsigned int max_rate, mode_rate, ds_max_dotclock, clock = mode->clock; - const u8 bpp = connector->display_info.bpc * 3; + /* Check with the minmum bpc always, so we can advertise better modes. + * In particlar not doing this causes modes to be dropped on HDR + * displays as we might check with a bpc of 16 even. + */ + const u8 bpp = 6 * 3; if (mode->flags & DRM_MODE_FLAG_INTERLACE && !outp->caps.dp_interlace) return MODE_NO_INTERLACE; diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index f77e44958037..ab9062e50977 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -645,7 +645,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, struct drm_nouveau_gem_pushbuf_reloc *reloc, struct drm_nouveau_gem_pushbuf_bo *bo) { - long ret = 0; + int ret = 0; unsigned i; for (i = 0; i < req->nr_relocs; i++) { @@ -653,6 +653,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, struct drm_nouveau_gem_pushbuf_bo *b; struct nouveau_bo *nvbo; uint32_t data; + long lret; if (unlikely(r->bo_index >= req->nr_buffers)) { NV_PRINTK(err, cli, "reloc bo index invalid\n"); @@ -703,13 +704,18 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, data |= r->vor; } - ret = dma_resv_wait_timeout(nvbo->bo.base.resv, - DMA_RESV_USAGE_BOOKKEEP, - false, 15 * HZ); - if (ret == 0) + lret = dma_resv_wait_timeout(nvbo->bo.base.resv, + DMA_RESV_USAGE_BOOKKEEP, + false, 15 * HZ); + if (!lret) ret = -EBUSY; + else if (lret > 0) + ret = 0; + else + ret = lret; + if (ret) { - NV_PRINTK(err, cli, "reloc wait_idle failed: %ld\n", + NV_PRINTK(err, cli, "reloc wait_idle failed: %d\n", ret); break; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf108.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf108.c index 76678dd60f93..c4c6f67af7cc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf108.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf108.c @@ -31,6 +31,7 @@ gf108_fb = { .init = gf100_fb_init, .init_page = gf100_fb_init_page, .intr = gf100_fb_intr, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, .ram_new = gf108_ram_new, .default_bigpage = 17, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c index f73442ccb424..433fa966ba23 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c @@ -77,6 +77,7 @@ gk104_fb = { .init = gf100_fb_init, .init_page = gf100_fb_init_page, .intr = gf100_fb_intr, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, .ram_new = gk104_ram_new, .default_bigpage = 17, .clkgate_pack = gk104_fb_clkgate_pack, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk110.c index 45d6cdffafee..4dc283dedf8b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk110.c @@ -59,6 +59,7 @@ gk110_fb = { .init = gf100_fb_init, .init_page = gf100_fb_init_page, .intr = gf100_fb_intr, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, .ram_new = gk104_ram_new, .default_bigpage = 17, .clkgate_pack = gk110_fb_clkgate_pack, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c index de52462a92bf..90bfff616d35 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c @@ -31,6 +31,7 @@ gm107_fb = { .init = gf100_fb_init, .init_page = gf100_fb_init_page, .intr = gf100_fb_intr, + .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init, .ram_new = gm107_ram_new, .default_bigpage = 17, }; diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c index 666a5e53fe19..e961fa27702c 100644 --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c @@ -504,6 +504,7 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as, if (IS_ERR(pages[i])) { mutex_unlock(&bo->base.pages_lock); ret = PTR_ERR(pages[i]); + pages[i] = NULL; goto err_pages; } } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index ba3b81789509..293c228a83f9 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -839,6 +839,8 @@ static void vop2_enable(struct vop2 *vop2) return; } + regcache_sync(vop2->map); + if (vop2->data->soc_id == 3566) vop2_writel(vop2, RK3568_OTP_WIN_EN, 1); @@ -867,6 +869,8 @@ static void vop2_disable(struct vop2 *vop2) pm_runtime_put_sync(vop2->dev); + regcache_mark_dirty(vop2->map); + clk_disable_unprepare(vop2->aclk); clk_disable_unprepare(vop2->hclk); } diff --git a/drivers/gpu/drm/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c index 15d04a0ec623..e0a8890a62e2 100644 --- a/drivers/gpu/drm/scheduler/sched_entity.c +++ b/drivers/gpu/drm/scheduler/sched_entity.c @@ -507,12 +507,19 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job) { struct drm_sched_entity *entity = sched_job->entity; bool first; + ktime_t submit_ts; trace_drm_sched_job(sched_job, entity); atomic_inc(entity->rq->sched->score); WRITE_ONCE(entity->last_user, current->group_leader); + + /* + * After the sched_job is pushed into the entity queue, it may be + * completed and freed up at any time. We can no longer access it. + * Make sure to set the submit_ts first, to avoid a race. + */ + sched_job->submit_ts = submit_ts = ktime_get(); first = spsc_queue_push(&entity->job_queue, &sched_job->queue_node); - sched_job->submit_ts = ktime_get(); /* first job wakes up scheduler */ if (first) { @@ -529,7 +536,7 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job) spin_unlock(&entity->rq_lock); if (drm_sched_policy == DRM_SCHED_POLICY_FIFO) - drm_sched_rq_update_fifo(entity, sched_job->submit_ts); + drm_sched_rq_update_fifo(entity, submit_ts); drm_sched_wakeup(entity->rq->sched); } diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 4e6ad6e122bc..1e08cc5a1702 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -308,7 +308,8 @@ static void drm_sched_start_timeout(struct drm_gpu_scheduler *sched) */ void drm_sched_fault(struct drm_gpu_scheduler *sched) { - mod_delayed_work(sched->timeout_wq, &sched->work_tdr, 0); + if (sched->ready) + mod_delayed_work(sched->timeout_wq, &sched->work_tdr, 0); } EXPORT_SYMBOL(drm_sched_fault); @@ -906,12 +907,6 @@ drm_sched_get_cleanup_job(struct drm_gpu_scheduler *sched) spin_unlock(&sched->job_list_lock); - if (job) { - job->entity->elapsed_ns += ktime_to_ns( - ktime_sub(job->s_fence->finished.timestamp, - job->s_fence->scheduled.timestamp)); - } - return job; } diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c b/drivers/gpu/drm/tests/drm_buddy_test.c index f8ee714df396..09ee6f6af896 100644 --- a/drivers/gpu/drm/tests/drm_buddy_test.c +++ b/drivers/gpu/drm/tests/drm_buddy_test.c @@ -89,7 +89,8 @@ static int check_block(struct kunit *test, struct drm_buddy *mm, err = -EINVAL; } - if (!is_power_of_2(block_size)) { + /* We can't use is_power_of_2() for a u64 on 32-bit systems. */ + if (block_size & (block_size - 1)) { kunit_err(test, "block size not power of two\n"); err = -EINVAL; } diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 82f64fb31fda..4ce012f83253 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1122,7 +1122,7 @@ config HID_TOPRE tristate "Topre REALFORCE keyboards" depends on HID help - Say Y for N-key rollover support on Topre REALFORCE R2 108 key keyboards. + Say Y for N-key rollover support on Topre REALFORCE R2 108/87 key keyboards. config HID_THINGM tristate "ThingM blink(1) USB RGB LED" diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 63545cd307e5..c2e9b6d1fd7d 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -420,6 +420,9 @@ #define I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN 0x261A #define I2C_DEVICE_ID_SURFACE_GO2_TOUCHSCREEN 0x2A1C #define I2C_DEVICE_ID_LENOVO_YOGA_C630_TOUCHSCREEN 0x279F +#define I2C_DEVICE_ID_HP_SPECTRE_X360_13T_AW100 0x29F5 +#define I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V1 0x2BED +#define I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V2 0x2BEE #define USB_VENDOR_ID_ELECOM 0x056e #define USB_DEVICE_ID_ELECOM_BM084 0x0061 @@ -1249,6 +1252,7 @@ #define USB_VENDOR_ID_TOPRE 0x0853 #define USB_DEVICE_ID_TOPRE_REALFORCE_R2_108 0x0148 +#define USB_DEVICE_ID_TOPRE_REALFORCE_R2_87 0x0146 #define USB_VENDOR_ID_TOPSEED 0x0766 #define USB_DEVICE_ID_TOPSEED_CYBERLINK 0x0204 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 7fc967964dd8..5c65a584b3fa 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -398,6 +398,12 @@ static const struct hid_device_id hid_battery_quirks[] = { HID_BATTERY_QUIRK_IGNORE }, { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_LENOVO_YOGA_C630_TOUCHSCREEN), HID_BATTERY_QUIRK_IGNORE }, + { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_13T_AW100), + HID_BATTERY_QUIRK_IGNORE }, + { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V1), + HID_BATTERY_QUIRK_IGNORE }, + { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V2), + HID_BATTERY_QUIRK_IGNORE }, {} }; diff --git a/drivers/hid/hid-sensor-custom.c b/drivers/hid/hid-sensor-custom.c index 3e3f89e01d81..d85398721659 100644 --- a/drivers/hid/hid-sensor-custom.c +++ b/drivers/hid/hid-sensor-custom.c @@ -940,7 +940,7 @@ hid_sensor_register_platform_device(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, const struct hid_sensor_custom_match *match) { - char real_usage[HID_SENSOR_USAGE_LENGTH]; + char real_usage[HID_SENSOR_USAGE_LENGTH] = { 0 }; struct platform_device *custom_pdev; const char *dev_name; char *c; diff --git a/drivers/hid/hid-topre.c b/drivers/hid/hid-topre.c index 88a91cdad5f8..d1d5ca310ead 100644 --- a/drivers/hid/hid-topre.c +++ b/drivers/hid/hid-topre.c @@ -36,6 +36,8 @@ static __u8 *topre_report_fixup(struct hid_device *hdev, __u8 *rdesc, static const struct hid_device_id topre_id_table[] = { { HID_USB_DEVICE(USB_VENDOR_ID_TOPRE, USB_DEVICE_ID_TOPRE_REALFORCE_R2_108) }, + { HID_USB_DEVICE(USB_VENDOR_ID_TOPRE, + USB_DEVICE_ID_TOPRE_REALFORCE_R2_87) }, { } }; MODULE_DEVICE_TABLE(hid, topre_id_table); diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c index 81385ab37fa9..7fc738a22375 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.c +++ b/drivers/hid/intel-ish-hid/ishtp/bus.c @@ -241,8 +241,8 @@ static int ishtp_cl_bus_match(struct device *dev, struct device_driver *drv) struct ishtp_cl_device *device = to_ishtp_cl_device(dev); struct ishtp_cl_driver *driver = to_ishtp_cl_driver(drv); - return guid_equal(&driver->id[0].guid, - &device->fw_client->props.protocol_name); + return(device->fw_client ? guid_equal(&driver->id[0].guid, + &device->fw_client->props.protocol_name) : 0); } /** diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index 9dc27e5d367a..da51b50787df 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -409,6 +409,10 @@ void vmbus_disconnect(void) */ struct vmbus_channel *relid2channel(u32 relid) { + if (vmbus_connection.channels == NULL) { + pr_warn_once("relid2channel: relid=%d: No channels mapped!\n", relid); + return NULL; + } if (WARN_ON(relid >= MAX_CHANNEL_RELIDS)) return NULL; return READ_ONCE(vmbus_connection.channels[relid]); diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index c6692fd5ab15..2111e97c3b63 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -211,7 +211,7 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, ring_info->ring_buffer = (struct hv_ring_buffer *) vmap_pfn(pfns_wraparound, page_cnt * 2 - 1, - PAGE_KERNEL); + pgprot_decrypted(PAGE_KERNEL)); kfree(pfns_wraparound); if (!ring_info->ring_buffer) diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index d24dd65b33d4..e9e1c4139e0d 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -2156,7 +2156,6 @@ void vmbus_device_unregister(struct hv_device *device_obj) * VMBUS is an acpi enumerated device. Get the information we * need from DSDT. */ -#define VTPM_BASE_ADDRESS 0xfed40000 static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) { resource_size_t start = 0; diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 1ea8f173cca0..4c15fae534f3 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -472,7 +472,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata) if (etm4x_sspcicrn_present(drvdata, i)) etm4x_relaxed_write32(csa, config->ss_pe_cmp[i], TRCSSPCICRn(i)); } - for (i = 0; i < drvdata->nr_addr_cmp; i++) { + for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) { etm4x_relaxed_write64(csa, config->addr_val[i], TRCACVRn(i)); etm4x_relaxed_write64(csa, config->addr_acc[i], TRCACATRn(i)); } @@ -1070,25 +1070,21 @@ static bool etm4_init_iomem_access(struct etmv4_drvdata *drvdata, struct csdev_access *csa) { u32 devarch = readl_relaxed(drvdata->base + TRCDEVARCH); - u32 idr1 = readl_relaxed(drvdata->base + TRCIDR1); /* * All ETMs must implement TRCDEVARCH to indicate that - * the component is an ETMv4. To support any broken - * implementations we fall back to TRCIDR1 check, which - * is not really reliable. + * the component is an ETMv4. Even though TRCIDR1 also + * contains the information, it is part of the "Trace" + * register and must be accessed with the OSLK cleared, + * with MMIO. But we cannot touch the OSLK until we are + * sure this is an ETM. So rely only on the TRCDEVARCH. */ - if ((devarch & ETM_DEVARCH_ID_MASK) == ETM_DEVARCH_ETMv4x_ARCH) { - drvdata->arch = etm_devarch_to_arch(devarch); - } else { - pr_warn("CPU%d: ETM4x incompatible TRCDEVARCH: %x, falling back to TRCIDR1\n", - smp_processor_id(), devarch); - - if (ETM_TRCIDR1_ARCH_MAJOR(idr1) != ETM_TRCIDR1_ARCH_ETMv4) - return false; - drvdata->arch = etm_trcidr_to_arch(idr1); + if ((devarch & ETM_DEVARCH_ID_MASK) != ETM_DEVARCH_ETMv4x_ARCH) { + pr_warn_once("TRCDEVARCH doesn't match ETMv4 architecture\n"); + return false; } + drvdata->arch = etm_devarch_to_arch(devarch); *csa = CSDEV_ACCESS_IOMEM(drvdata->base); return true; } diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index 434f4e95ee17..27c8a9901868 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -753,14 +753,12 @@ * TRCDEVARCH - CoreSight architected register * - Bits[15:12] - Major version * - Bits[19:16] - Minor version - * TRCIDR1 - ETM architected register - * - Bits[11:8] - Major version - * - Bits[7:4] - Minor version - * We must rely on TRCDEVARCH for the version information, - * however we don't want to break the support for potential - * old implementations which might not implement it. Thus - * we fall back to TRCIDR1 if TRCDEVARCH is not implemented - * for memory mapped components. + * + * We must rely only on TRCDEVARCH for the version information. Even though, + * TRCIDR1 also provides the architecture version, it is a "Trace" register + * and as such must be accessed only with Trace power domain ON. This may + * not be available at probe time. + * * Now to make certain decisions easier based on the version * we use an internal representation of the version in the * driver, as follows : @@ -786,12 +784,6 @@ static inline u8 etm_devarch_to_arch(u32 devarch) ETM_DEVARCH_REVISION(devarch)); } -static inline u8 etm_trcidr_to_arch(u32 trcidr1) -{ - return ETM_ARCH_VERSION(ETM_TRCIDR1_ARCH_MAJOR(trcidr1), - ETM_TRCIDR1_ARCH_MINOR(trcidr1)); -} - enum etm_impdef_type { ETM4_IMPDEF_HISI_CORE_COMMIT, ETM4_IMPDEF_FEATURE_MAX, diff --git a/drivers/i2c/busses/i2c-mchp-pci1xxxx.c b/drivers/i2c/busses/i2c-mchp-pci1xxxx.c index 09af75921147..b21ffd6df927 100644 --- a/drivers/i2c/busses/i2c-mchp-pci1xxxx.c +++ b/drivers/i2c/busses/i2c-mchp-pci1xxxx.c @@ -48,9 +48,9 @@ * SR_HOLD_TIME_XK_TICKS field will indicate the number of ticks of the * baud clock required to program 'Hold Time' at X KHz. */ -#define SR_HOLD_TIME_100K_TICKS 133 -#define SR_HOLD_TIME_400K_TICKS 20 -#define SR_HOLD_TIME_1000K_TICKS 11 +#define SR_HOLD_TIME_100K_TICKS 150 +#define SR_HOLD_TIME_400K_TICKS 20 +#define SR_HOLD_TIME_1000K_TICKS 12 #define SMB_CORE_COMPLETION_REG_OFF3 (SMBUS_MAST_CORE_ADDR_BASE + 0x23) @@ -65,17 +65,17 @@ * the baud clock required to program 'fair idle delay' at X KHz. Fair idle * delay establishes the MCTP T(IDLE_DELAY) period. */ -#define FAIR_BUS_IDLE_MIN_100K_TICKS 969 -#define FAIR_BUS_IDLE_MIN_400K_TICKS 157 -#define FAIR_BUS_IDLE_MIN_1000K_TICKS 157 +#define FAIR_BUS_IDLE_MIN_100K_TICKS 992 +#define FAIR_BUS_IDLE_MIN_400K_TICKS 500 +#define FAIR_BUS_IDLE_MIN_1000K_TICKS 500 /* * FAIR_IDLE_DELAY_XK_TICKS field will indicate the number of ticks of the * baud clock required to satisfy the fairness protocol at X KHz. */ -#define FAIR_IDLE_DELAY_100K_TICKS 1000 -#define FAIR_IDLE_DELAY_400K_TICKS 500 -#define FAIR_IDLE_DELAY_1000K_TICKS 500 +#define FAIR_IDLE_DELAY_100K_TICKS 963 +#define FAIR_IDLE_DELAY_400K_TICKS 156 +#define FAIR_IDLE_DELAY_1000K_TICKS 156 #define SMB_IDLE_SCALING_100K \ ((FAIR_IDLE_DELAY_100K_TICKS << 16) | FAIR_BUS_IDLE_MIN_100K_TICKS) @@ -105,7 +105,7 @@ */ #define BUS_CLK_100K_LOW_PERIOD_TICKS 156 #define BUS_CLK_400K_LOW_PERIOD_TICKS 41 -#define BUS_CLK_1000K_LOW_PERIOD_TICKS 15 +#define BUS_CLK_1000K_LOW_PERIOD_TICKS 15 /* * BUS_CLK_XK_HIGH_PERIOD_TICKS field defines the number of I2C Baud Clock @@ -131,7 +131,7 @@ */ #define CLK_SYNC_100K 4 #define CLK_SYNC_400K 4 -#define CLK_SYNC_1000K 4 +#define CLK_SYNC_1000K 4 #define SMB_CORE_DATA_TIMING_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x40) @@ -142,25 +142,25 @@ * determines the SCLK hold time following SDAT driven low during the first * START bit in a transfer. */ -#define FIRST_START_HOLD_100K_TICKS 22 -#define FIRST_START_HOLD_400K_TICKS 16 -#define FIRST_START_HOLD_1000K_TICKS 6 +#define FIRST_START_HOLD_100K_TICKS 23 +#define FIRST_START_HOLD_400K_TICKS 8 +#define FIRST_START_HOLD_1000K_TICKS 12 /* * STOP_SETUP_XK_TICKS will indicate the number of ticks of the baud clock * required to program 'STOP_SETUP' timer at X KHz. This timer determines the * SDAT setup time from the rising edge of SCLK for a STOP condition. */ -#define STOP_SETUP_100K_TICKS 157 +#define STOP_SETUP_100K_TICKS 150 #define STOP_SETUP_400K_TICKS 20 -#define STOP_SETUP_1000K_TICKS 12 +#define STOP_SETUP_1000K_TICKS 12 /* * RESTART_SETUP_XK_TICKS will indicate the number of ticks of the baud clock * required to program 'RESTART_SETUP' timer at X KHz. This timer determines the * SDAT setup time from the rising edge of SCLK for a repeated START condition. */ -#define RESTART_SETUP_100K_TICKS 157 +#define RESTART_SETUP_100K_TICKS 156 #define RESTART_SETUP_400K_TICKS 20 #define RESTART_SETUP_1000K_TICKS 12 @@ -169,7 +169,7 @@ * required to program 'DATA_HOLD' timer at X KHz. This timer determines the * SDAT hold time following SCLK driven low. */ -#define DATA_HOLD_100K_TICKS 2 +#define DATA_HOLD_100K_TICKS 12 #define DATA_HOLD_400K_TICKS 2 #define DATA_HOLD_1000K_TICKS 2 @@ -190,35 +190,35 @@ * Bus Idle Minimum time = BUS_IDLE_MIN[7:0] x Baud_Clock_Period x * (BUS_IDLE_MIN_XK_TICKS[7] ? 4,1) */ -#define BUS_IDLE_MIN_100K_TICKS 167UL -#define BUS_IDLE_MIN_400K_TICKS 139UL -#define BUS_IDLE_MIN_1000K_TICKS 133UL +#define BUS_IDLE_MIN_100K_TICKS 36UL +#define BUS_IDLE_MIN_400K_TICKS 10UL +#define BUS_IDLE_MIN_1000K_TICKS 4UL /* * CTRL_CUM_TIME_OUT_XK_TICKS defines SMBus Controller Cumulative Time-Out. * SMBus Controller Cumulative Time-Out duration = * CTRL_CUM_TIME_OUT_XK_TICKS[7:0] x Baud_Clock_Period x 2048 */ -#define CTRL_CUM_TIME_OUT_100K_TICKS 159 -#define CTRL_CUM_TIME_OUT_400K_TICKS 159 -#define CTRL_CUM_TIME_OUT_1000K_TICKS 159 +#define CTRL_CUM_TIME_OUT_100K_TICKS 76 +#define CTRL_CUM_TIME_OUT_400K_TICKS 76 +#define CTRL_CUM_TIME_OUT_1000K_TICKS 76 /* * TARGET_CUM_TIME_OUT_XK_TICKS defines SMBus Target Cumulative Time-Out duration. * SMBus Target Cumulative Time-Out duration = TARGET_CUM_TIME_OUT_XK_TICKS[7:0] x * Baud_Clock_Period x 4096 */ -#define TARGET_CUM_TIME_OUT_100K_TICKS 199 -#define TARGET_CUM_TIME_OUT_400K_TICKS 199 -#define TARGET_CUM_TIME_OUT_1000K_TICKS 199 +#define TARGET_CUM_TIME_OUT_100K_TICKS 95 +#define TARGET_CUM_TIME_OUT_400K_TICKS 95 +#define TARGET_CUM_TIME_OUT_1000K_TICKS 95 /* * CLOCK_HIGH_TIME_OUT_XK defines Clock High time out period. * Clock High time out period = CLOCK_HIGH_TIME_OUT_XK[7:0] x Baud_Clock_Period x 8 */ -#define CLOCK_HIGH_TIME_OUT_100K_TICKS 204 -#define CLOCK_HIGH_TIME_OUT_400K_TICKS 204 -#define CLOCK_HIGH_TIME_OUT_1000K_TICKS 204 +#define CLOCK_HIGH_TIME_OUT_100K_TICKS 97 +#define CLOCK_HIGH_TIME_OUT_400K_TICKS 97 +#define CLOCK_HIGH_TIME_OUT_1000K_TICKS 97 #define TO_SCALING_100K \ ((BUS_IDLE_MIN_100K_TICKS << 24) | (CTRL_CUM_TIME_OUT_100K_TICKS << 16) | \ diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index a0af027db04c..2e575856c5cd 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -342,18 +342,18 @@ static int ocores_poll_wait(struct ocores_i2c *i2c) * ocores_isr(), we just add our polling code around it. * * It can run in atomic context + * + * Return: 0 on success, -ETIMEDOUT on timeout */ -static void ocores_process_polling(struct ocores_i2c *i2c) +static int ocores_process_polling(struct ocores_i2c *i2c) { - while (1) { - irqreturn_t ret; - int err; + irqreturn_t ret; + int err = 0; + while (1) { err = ocores_poll_wait(i2c); - if (err) { - i2c->state = STATE_ERROR; + if (err) break; /* timeout */ - } ret = ocores_isr(-1, i2c); if (ret == IRQ_NONE) @@ -364,13 +364,15 @@ static void ocores_process_polling(struct ocores_i2c *i2c) break; } } + + return err; } static int ocores_xfer_core(struct ocores_i2c *i2c, struct i2c_msg *msgs, int num, bool polling) { - int ret; + int ret = 0; u8 ctrl; ctrl = oc_getreg(i2c, OCI2C_CONTROL); @@ -388,15 +390,16 @@ static int ocores_xfer_core(struct ocores_i2c *i2c, oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); if (polling) { - ocores_process_polling(i2c); + ret = ocores_process_polling(i2c); } else { - ret = wait_event_timeout(i2c->wait, - (i2c->state == STATE_ERROR) || - (i2c->state == STATE_DONE), HZ); - if (ret == 0) { - ocores_process_timeout(i2c); - return -ETIMEDOUT; - } + if (wait_event_timeout(i2c->wait, + (i2c->state == STATE_ERROR) || + (i2c->state == STATE_DONE), HZ) == 0) + ret = -ETIMEDOUT; + } + if (ret) { + ocores_process_timeout(i2c); + return ret; } return (i2c->state == STATE_DONE) ? num : -EIO; diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index bce6b796e04c..545436b7dd53 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -178,6 +178,11 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action, return NOTIFY_OK; } + /* + * Clear the flag before adding the device so that fw_devlink + * doesn't skip adding consumers to this device. + */ + rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE; client = of_i2c_register_device(adap, rd->dn); if (IS_ERR(client)) { dev_err(&adap->dev, "failed to create client for '%pOF'\n", diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c index f866859855cd..1c3a72380fb8 100644 --- a/drivers/iio/accel/kionix-kx022a.c +++ b/drivers/iio/accel/kionix-kx022a.c @@ -864,7 +864,7 @@ static irqreturn_t kx022a_trigger_handler(int irq, void *p) if (ret < 0) goto err_read; - iio_push_to_buffers_with_timestamp(idev, data->buffer, pf->timestamp); + iio_push_to_buffers_with_timestamp(idev, data->buffer, data->timestamp); err_read: iio_trigger_notify_done(idev->trig); diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c index fee8d129a5f0..86effe8501b4 100644 --- a/drivers/iio/adc/ad7791.c +++ b/drivers/iio/adc/ad7791.c @@ -253,7 +253,7 @@ static const struct ad_sigma_delta_info ad7791_sigma_delta_info = { .has_registers = true, .addr_shift = 4, .read_mask = BIT(3), - .irq_flags = IRQF_TRIGGER_LOW, + .irq_flags = IRQF_TRIGGER_FALLING, }; static int ad7791_read_raw(struct iio_dev *indio_dev, diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index 50d02e5fc6fc..7258912fe17b 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -1409,7 +1409,7 @@ static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *indio, trig = devm_iio_trigger_alloc(&indio->dev, "%s-dev%d-%s", indio->name, iio_device_id(indio), trigger_name); if (!trig) - return NULL; + return ERR_PTR(-ENOMEM); trig->dev.parent = indio->dev.parent; iio_trigger_set_drvdata(trig, indio); diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c index 17370c5eb6fe..ec198c6f13d6 100644 --- a/drivers/iio/adc/ltc2497.c +++ b/drivers/iio/adc/ltc2497.c @@ -28,7 +28,6 @@ struct ltc2497_driverdata { struct ltc2497core_driverdata common_ddata; struct i2c_client *client; u32 recv_size; - u32 sub_lsb; /* * DMA (thus cache coherency maintenance) may require the * transfer buffers to live in their own cache lines. @@ -65,10 +64,10 @@ static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata, * equivalent to a sign extension. */ if (st->recv_size == 3) { - *val = (get_unaligned_be24(st->data.d8) >> st->sub_lsb) + *val = (get_unaligned_be24(st->data.d8) >> 6) - BIT(ddata->chip_info->resolution + 1); } else { - *val = (be32_to_cpu(st->data.d32) >> st->sub_lsb) + *val = (be32_to_cpu(st->data.d32) >> 6) - BIT(ddata->chip_info->resolution + 1); } @@ -122,7 +121,6 @@ static int ltc2497_probe(struct i2c_client *client) st->common_ddata.chip_info = chip_info; resolution = chip_info->resolution; - st->sub_lsb = 31 - (resolution + 1); st->recv_size = BITS_TO_BYTES(resolution) + 1; return ltc2497core_probe(dev, indio_dev); diff --git a/drivers/iio/adc/max11410.c b/drivers/iio/adc/max11410.c index b74b689ee7de..f6895bc9fc4b 100644 --- a/drivers/iio/adc/max11410.c +++ b/drivers/iio/adc/max11410.c @@ -414,13 +414,17 @@ static int max11410_sample(struct max11410_state *st, int *sample_raw, if (!ret) return -ETIMEDOUT; } else { + int ret2; + /* Wait for status register Conversion Ready flag */ - ret = read_poll_timeout(max11410_read_reg, ret, - ret || (val & MAX11410_STATUS_CONV_READY_BIT), + ret = read_poll_timeout(max11410_read_reg, ret2, + ret2 || (val & MAX11410_STATUS_CONV_READY_BIT), 5000, MAX11410_CONVERSION_TIMEOUT_MS * 1000, true, st, MAX11410_REG_STATUS, &val); if (ret) return ret; + if (ret2) + return ret2; } /* Read ADC Data */ @@ -851,17 +855,21 @@ static int max11410_init_vref(struct device *dev, static int max11410_calibrate(struct max11410_state *st, u32 cal_type) { - int ret, val; + int ret, ret2, val; ret = max11410_write_reg(st, MAX11410_REG_CAL_START, cal_type); if (ret) return ret; /* Wait for status register Calibration Ready flag */ - return read_poll_timeout(max11410_read_reg, ret, - ret || (val & MAX11410_STATUS_CAL_READY_BIT), - 50000, MAX11410_CALIB_TIMEOUT_MS * 1000, true, - st, MAX11410_REG_STATUS, &val); + ret = read_poll_timeout(max11410_read_reg, ret2, + ret2 || (val & MAX11410_STATUS_CAL_READY_BIT), + 50000, MAX11410_CALIB_TIMEOUT_MS * 1000, true, + st, MAX11410_REG_STATUS, &val); + if (ret) + return ret; + + return ret2; } static int max11410_self_calibrate(struct max11410_state *st) diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index fd000345ec5c..849a697a467e 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -639,7 +639,7 @@ out: static int palmas_gpadc_remove(struct platform_device *pdev) { - struct iio_dev *indio_dev = dev_to_iio_dev(&pdev->dev); + struct iio_dev *indio_dev = dev_get_drvdata(&pdev->dev); struct palmas_gpadc *adc = iio_priv(indio_dev); if (adc->wakeup1_enable || adc->wakeup2_enable) diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index e90c299c913a..c2d5e06f137a 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -628,12 +628,20 @@ static int adc5_get_fw_channel_data(struct adc5_chip *adc, struct fwnode_handle *fwnode, const struct adc5_data *data) { - const char *name = fwnode_get_name(fwnode), *channel_name; + const char *channel_name; + char *name; u32 chan, value, varr[2]; u32 sid = 0; int ret; struct device *dev = adc->dev; + name = devm_kasprintf(dev, GFP_KERNEL, "%pfwP", fwnode); + if (!name) + return -ENOMEM; + + /* Cut the address part */ + name[strchrnul(name, '@') - name] = '\0'; + ret = fwnode_property_read_u32(fwnode, "reg", &chan); if (ret) { dev_err(dev, "invalid channel number %s\n", name); diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c index 2cc9a9bd9db6..263fc3a1b87e 100644 --- a/drivers/iio/adc/ti-ads7950.c +++ b/drivers/iio/adc/ti-ads7950.c @@ -634,6 +634,7 @@ static int ti_ads7950_probe(struct spi_device *spi) st->chip.label = dev_name(&st->spi->dev); st->chip.parent = &st->spi->dev; st->chip.owner = THIS_MODULE; + st->chip.can_sleep = true; st->chip.base = -1; st->chip.ngpio = TI_ADS7950_NUM_GPIOS; st->chip.get_direction = ti_ads7950_get_direction; diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index beadfa938d2d..404865e35460 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -802,6 +802,7 @@ static struct ad5755_platform_data *ad5755_parse_fw(struct device *dev) return pdata; error_out: + fwnode_handle_put(pp); devm_kfree(dev, pdata); return NULL; } diff --git a/drivers/iio/dac/cio-dac.c b/drivers/iio/dac/cio-dac.c index 791dd999cf29..18a64f72fc18 100644 --- a/drivers/iio/dac/cio-dac.c +++ b/drivers/iio/dac/cio-dac.c @@ -66,8 +66,8 @@ static int cio_dac_write_raw(struct iio_dev *indio_dev, if (mask != IIO_CHAN_INFO_RAW) return -EINVAL; - /* DAC can only accept up to a 16-bit value */ - if ((unsigned int)val > 65535) + /* DAC can only accept up to a 12-bit value */ + if ((unsigned int)val > 4095) return -EINVAL; priv->chan_out_states[chan->channel] = val; diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index f1d7d4b5e222..c2f97629e9cd 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -47,6 +47,7 @@ config ADIS16480 depends on SPI select IIO_ADIS_LIB select IIO_ADIS_LIB_BUFFER if IIO_BUFFER + select CRC32 help Say yes here to build support for Analog Devices ADIS16375, ADIS16480, ADIS16485, ADIS16488 inertial sensors. diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 80c78bd6bbef..a7a080bed180 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -203,24 +203,27 @@ static ssize_t iio_buffer_write(struct file *filp, const char __user *buf, break; } + if (filp->f_flags & O_NONBLOCK) { + if (!written) + ret = -EAGAIN; + break; + } + wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); continue; } ret = rb->access->write(rb, n - written, buf + written); - if (ret == 0 && (filp->f_flags & O_NONBLOCK)) - ret = -EAGAIN; + if (ret < 0) + break; - if (ret > 0) { - written += ret; - if (written != n && !(filp->f_flags & O_NONBLOCK)) - continue; - } - } while (ret == 0); + written += ret; + + } while (written != n); remove_wait_queue(&rb->pollq, &wait); - return ret < 0 ? ret : n; + return ret < 0 ? ret : written; } /** diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c index b1674a5bfa36..d4a34a3bf00d 100644 --- a/drivers/iio/light/cm32181.c +++ b/drivers/iio/light/cm32181.c @@ -429,6 +429,14 @@ static const struct iio_info cm32181_info = { .attrs = &cm32181_attribute_group, }; +static void cm32181_unregister_dummy_client(void *data) +{ + struct i2c_client *client = data; + + /* Unregister the dummy client */ + i2c_unregister_device(client); +} + static int cm32181_probe(struct i2c_client *client) { struct device *dev = &client->dev; @@ -460,6 +468,10 @@ static int cm32181_probe(struct i2c_client *client) client = i2c_acpi_new_device(dev, 1, &board_info); if (IS_ERR(client)) return PTR_ERR(client); + + ret = devm_add_action_or_reset(dev, cm32181_unregister_dummy_client, client); + if (ret) + return ret; } cm32181 = iio_priv(indio_dev); diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c index ad50baa0202c..e823c145f679 100644 --- a/drivers/iio/light/tsl2772.c +++ b/drivers/iio/light/tsl2772.c @@ -601,6 +601,7 @@ static int tsl2772_read_prox_diodes(struct tsl2772_chip *chip) return -EINVAL; } } + chip->settings.prox_diode = prox_diode_mask; return 0; } diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 6bdfce9747f9..5c44a36ab5b3 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -208,7 +208,6 @@ static int vcnl4000_init(struct vcnl4000_data *data) data->rev = ret & 0xf; data->al_scale = 250000; - mutex_init(&data->vcnl4000_lock); return data->chip_spec->set_power_state(data, true); }; @@ -1367,6 +1366,8 @@ static int vcnl4000_probe(struct i2c_client *client) data->id = id->driver_data; data->chip_spec = &vcnl4000_chip_spec_cfg[data->id]; + mutex_init(&data->vcnl4000_lock); + ret = data->chip_spec->init(data); if (ret < 0) return ret; diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 308155937713..6b9563d4f23c 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -624,22 +624,11 @@ static inline unsigned short cma_family(struct rdma_id_private *id_priv) return id_priv->id.route.addr.src_addr.ss_family; } -static int cma_set_qkey(struct rdma_id_private *id_priv, u32 qkey) +static int cma_set_default_qkey(struct rdma_id_private *id_priv) { struct ib_sa_mcmember_rec rec; int ret = 0; - if (id_priv->qkey) { - if (qkey && id_priv->qkey != qkey) - return -EINVAL; - return 0; - } - - if (qkey) { - id_priv->qkey = qkey; - return 0; - } - switch (id_priv->id.ps) { case RDMA_PS_UDP: case RDMA_PS_IB: @@ -659,6 +648,16 @@ static int cma_set_qkey(struct rdma_id_private *id_priv, u32 qkey) return ret; } +static int cma_set_qkey(struct rdma_id_private *id_priv, u32 qkey) +{ + if (!qkey || + (id_priv->qkey && (id_priv->qkey != qkey))) + return -EINVAL; + + id_priv->qkey = qkey; + return 0; +} + static void cma_translate_ib(struct sockaddr_ib *sib, struct rdma_dev_addr *dev_addr) { dev_addr->dev_type = ARPHRD_INFINIBAND; @@ -1229,7 +1228,7 @@ static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv, *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT; if (id_priv->id.qp_type == IB_QPT_UD) { - ret = cma_set_qkey(id_priv, 0); + ret = cma_set_default_qkey(id_priv); if (ret) return ret; @@ -4569,7 +4568,10 @@ static int cma_send_sidr_rep(struct rdma_id_private *id_priv, memset(&rep, 0, sizeof rep); rep.status = status; if (status == IB_SIDR_SUCCESS) { - ret = cma_set_qkey(id_priv, qkey); + if (qkey) + ret = cma_set_qkey(id_priv, qkey); + else + ret = cma_set_default_qkey(id_priv); if (ret) return ret; rep.qp_num = id_priv->qp_num; @@ -4774,9 +4776,7 @@ static void cma_make_mc_event(int status, struct rdma_id_private *id_priv, enum ib_gid_type gid_type; struct net_device *ndev; - if (!status) - status = cma_set_qkey(id_priv, be32_to_cpu(multicast->rec.qkey)); - else + if (status) pr_debug_ratelimited("RDMA CM: MULTICAST_ERROR: failed to join multicast. status %d\n", status); @@ -4804,7 +4804,7 @@ static void cma_make_mc_event(int status, struct rdma_id_private *id_priv, } event->param.ud.qp_num = 0xFFFFFF; - event->param.ud.qkey = be32_to_cpu(multicast->rec.qkey); + event->param.ud.qkey = id_priv->qkey; out: if (ndev) @@ -4823,8 +4823,11 @@ static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast) READ_ONCE(id_priv->state) == RDMA_CM_DESTROYING) goto out; - cma_make_mc_event(status, id_priv, multicast, &event, mc); - ret = cma_cm_event_handler(id_priv, &event); + ret = cma_set_qkey(id_priv, be32_to_cpu(multicast->rec.qkey)); + if (!ret) { + cma_make_mc_event(status, id_priv, multicast, &event, mc); + ret = cma_cm_event_handler(id_priv, &event); + } rdma_destroy_ah_attr(&event.param.ud.ah_attr); WARN_ON(ret); @@ -4877,9 +4880,11 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv, if (ret) return ret; - ret = cma_set_qkey(id_priv, 0); - if (ret) - return ret; + if (!id_priv->qkey) { + ret = cma_set_default_qkey(id_priv); + if (ret) + return ret; + } cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid); rec.qkey = cpu_to_be32(id_priv->qkey); @@ -4956,9 +4961,6 @@ static int cma_iboe_join_multicast(struct rdma_id_private *id_priv, cma_iboe_set_mgid(addr, &ib.rec.mgid, gid_type); ib.rec.pkey = cpu_to_be16(0xffff); - if (id_priv->id.ps == RDMA_PS_UDP) - ib.rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); - if (dev_addr->bound_dev_if) ndev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if); if (!ndev) @@ -4984,6 +4986,9 @@ static int cma_iboe_join_multicast(struct rdma_id_private *id_priv, if (err || !ib.rec.mtu) return err ?: -EINVAL; + if (!id_priv->qkey) + cma_set_default_qkey(id_priv); + rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr, &ib.rec.port_gid); INIT_WORK(&mc->iboe_join.work, cma_iboe_join_work_handler); @@ -5009,6 +5014,9 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, READ_ONCE(id_priv->state) != RDMA_CM_ADDR_RESOLVED)) return -EINVAL; + if (id_priv->id.qp_type != IB_QPT_UD) + return -EINVAL; + mc = kzalloc(sizeof(*mc), GFP_KERNEL); if (!mc) return -ENOMEM; diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 11b1c1603aeb..b99b3cc283b6 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -532,6 +532,8 @@ static struct ib_ah *_rdma_create_ah(struct ib_pd *pd, else ret = device->ops.create_ah(ah, &init_attr, NULL); if (ret) { + if (ah->sgid_attr) + rdma_put_gid_attr(ah->sgid_attr); kfree(ah); return ERR_PTR(ret); } diff --git a/drivers/infiniband/hw/erdma/erdma_cq.c b/drivers/infiniband/hw/erdma/erdma_cq.c index cabd8678b355..7bc354273d4e 100644 --- a/drivers/infiniband/hw/erdma/erdma_cq.c +++ b/drivers/infiniband/hw/erdma/erdma_cq.c @@ -65,7 +65,7 @@ static const enum ib_wc_opcode wc_mapping_table[ERDMA_NUM_OPCODES] = { [ERDMA_OP_LOCAL_INV] = IB_WC_LOCAL_INV, [ERDMA_OP_READ_WITH_INV] = IB_WC_RDMA_READ, [ERDMA_OP_ATOMIC_CAS] = IB_WC_COMP_SWAP, - [ERDMA_OP_ATOMIC_FAD] = IB_WC_FETCH_ADD, + [ERDMA_OP_ATOMIC_FAA] = IB_WC_FETCH_ADD, }; static const struct { diff --git a/drivers/infiniband/hw/erdma/erdma_hw.h b/drivers/infiniband/hw/erdma/erdma_hw.h index 4c38d99c73f1..37ad1bb1917c 100644 --- a/drivers/infiniband/hw/erdma/erdma_hw.h +++ b/drivers/infiniband/hw/erdma/erdma_hw.h @@ -441,7 +441,7 @@ struct erdma_reg_mr_sqe { }; /* EQ related. */ -#define ERDMA_DEFAULT_EQ_DEPTH 256 +#define ERDMA_DEFAULT_EQ_DEPTH 4096 /* ceqe */ #define ERDMA_CEQE_HDR_DB_MASK BIT_ULL(63) @@ -491,7 +491,7 @@ enum erdma_opcode { ERDMA_OP_LOCAL_INV = 15, ERDMA_OP_READ_WITH_INV = 16, ERDMA_OP_ATOMIC_CAS = 17, - ERDMA_OP_ATOMIC_FAD = 18, + ERDMA_OP_ATOMIC_FAA = 18, ERDMA_NUM_OPCODES = 19, ERDMA_OP_INVALID = ERDMA_NUM_OPCODES + 1 }; diff --git a/drivers/infiniband/hw/erdma/erdma_main.c b/drivers/infiniband/hw/erdma/erdma_main.c index 5dc31e5df5cb..4a29a53a6652 100644 --- a/drivers/infiniband/hw/erdma/erdma_main.c +++ b/drivers/infiniband/hw/erdma/erdma_main.c @@ -56,7 +56,7 @@ done: static int erdma_enum_and_get_netdev(struct erdma_dev *dev) { struct net_device *netdev; - int ret = -ENODEV; + int ret = -EPROBE_DEFER; /* Already binded to a net_device, so we skip. */ if (dev->netdev) diff --git a/drivers/infiniband/hw/erdma/erdma_qp.c b/drivers/infiniband/hw/erdma/erdma_qp.c index d088d6bef431..44923c51a01b 100644 --- a/drivers/infiniband/hw/erdma/erdma_qp.c +++ b/drivers/infiniband/hw/erdma/erdma_qp.c @@ -405,7 +405,7 @@ static int erdma_push_one_sqe(struct erdma_qp *qp, u16 *pi, FIELD_PREP(ERDMA_SQE_MR_MTT_CNT_MASK, mr->mem.mtt_nents); - if (mr->mem.mtt_nents < ERDMA_MAX_INLINE_MTT_ENTRIES) { + if (mr->mem.mtt_nents <= ERDMA_MAX_INLINE_MTT_ENTRIES) { attrs |= FIELD_PREP(ERDMA_SQE_MR_MTT_TYPE_MASK, 0); /* Copy SGLs to SQE content to accelerate */ memcpy(get_queue_entry(qp->kern_qp.sq_buf, idx + 1, @@ -439,7 +439,7 @@ static int erdma_push_one_sqe(struct erdma_qp *qp, u16 *pi, cpu_to_le64(atomic_wr(send_wr)->compare_add); } else { wqe_hdr |= FIELD_PREP(ERDMA_SQE_HDR_OPCODE_MASK, - ERDMA_OP_ATOMIC_FAD); + ERDMA_OP_ATOMIC_FAA); atomic_sqe->fetchadd_swap_data = cpu_to_le64(atomic_wr(send_wr)->compare_add); } diff --git a/drivers/infiniband/hw/erdma/erdma_verbs.h b/drivers/infiniband/hw/erdma/erdma_verbs.h index e0a993bc032a..131cf5f40982 100644 --- a/drivers/infiniband/hw/erdma/erdma_verbs.h +++ b/drivers/infiniband/hw/erdma/erdma_verbs.h @@ -11,7 +11,7 @@ /* RDMA Capability. */ #define ERDMA_MAX_PD (128 * 1024) -#define ERDMA_MAX_SEND_WR 4096 +#define ERDMA_MAX_SEND_WR 8192 #define ERDMA_MAX_ORD 128 #define ERDMA_MAX_IRD 128 #define ERDMA_MAX_SGE_RD 1 diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c index b1d6ca7e9708..f3d6ce45c397 100644 --- a/drivers/infiniband/hw/hfi1/file_ops.c +++ b/drivers/infiniband/hw/hfi1/file_ops.c @@ -267,6 +267,8 @@ static ssize_t hfi1_write_iter(struct kiocb *kiocb, struct iov_iter *from) if (!HFI1_CAP_IS_KSET(SDMA)) return -EINVAL; + if (!from->user_backed) + return -EINVAL; idx = srcu_read_lock(&fd->pq_srcu); pq = srcu_dereference(fd->pq, &fd->pq_srcu); if (!cq || !pq) { @@ -274,11 +276,6 @@ static ssize_t hfi1_write_iter(struct kiocb *kiocb, struct iov_iter *from) return -EIO; } - if (!iter_is_iovec(from) || !dim) { - srcu_read_unlock(&fd->pq_srcu, idx); - return -EINVAL; - } - trace_hfi1_sdma_request(fd->dd, fd->uctxt->ctxt, fd->subctxt, dim); if (atomic_read(&pq->n_reqs) == pq->n_max_reqs) { @@ -287,11 +284,12 @@ static ssize_t hfi1_write_iter(struct kiocb *kiocb, struct iov_iter *from) } while (dim) { + const struct iovec *iov = iter_iov(from); int ret; unsigned long count = 0; ret = hfi1_user_sdma_process_request( - fd, (struct iovec *)(from->iov + done), + fd, (struct iovec *)(iov + done), dim, &count); if (ret) { reqs = ret; diff --git a/drivers/infiniband/hw/irdma/cm.c b/drivers/infiniband/hw/irdma/cm.c index 195aa9ea18b6..8817864154af 100644 --- a/drivers/infiniband/hw/irdma/cm.c +++ b/drivers/infiniband/hw/irdma/cm.c @@ -1458,13 +1458,15 @@ static int irdma_send_fin(struct irdma_cm_node *cm_node) * irdma_find_listener - find a cm node listening on this addr-port pair * @cm_core: cm's core * @dst_addr: listener ip addr + * @ipv4: flag indicating IPv4 when true * @dst_port: listener tcp port num * @vlan_id: virtual LAN ID * @listener_state: state to match with listen node's */ static struct irdma_cm_listener * -irdma_find_listener(struct irdma_cm_core *cm_core, u32 *dst_addr, u16 dst_port, - u16 vlan_id, enum irdma_cm_listener_state listener_state) +irdma_find_listener(struct irdma_cm_core *cm_core, u32 *dst_addr, bool ipv4, + u16 dst_port, u16 vlan_id, + enum irdma_cm_listener_state listener_state) { struct irdma_cm_listener *listen_node; static const u32 ip_zero[4] = { 0, 0, 0, 0 }; @@ -1477,7 +1479,7 @@ irdma_find_listener(struct irdma_cm_core *cm_core, u32 *dst_addr, u16 dst_port, list_for_each_entry (listen_node, &cm_core->listen_list, list) { memcpy(listen_addr, listen_node->loc_addr, sizeof(listen_addr)); listen_port = listen_node->loc_port; - if (listen_port != dst_port || + if (listen_node->ipv4 != ipv4 || listen_port != dst_port || !(listener_state & listen_node->listener_state)) continue; /* compare node pair, return node handle if a match */ @@ -2902,9 +2904,10 @@ irdma_make_listen_node(struct irdma_cm_core *cm_core, unsigned long flags; /* cannot have multiple matching listeners */ - listener = irdma_find_listener(cm_core, cm_info->loc_addr, - cm_info->loc_port, cm_info->vlan_id, - IRDMA_CM_LISTENER_EITHER_STATE); + listener = + irdma_find_listener(cm_core, cm_info->loc_addr, cm_info->ipv4, + cm_info->loc_port, cm_info->vlan_id, + IRDMA_CM_LISTENER_EITHER_STATE); if (listener && listener->listener_state == IRDMA_CM_LISTENER_ACTIVE_STATE) { refcount_dec(&listener->refcnt); @@ -3153,6 +3156,7 @@ void irdma_receive_ilq(struct irdma_sc_vsi *vsi, struct irdma_puda_buf *rbuf) listener = irdma_find_listener(cm_core, cm_info.loc_addr, + cm_info.ipv4, cm_info.loc_port, cm_info.vlan_id, IRDMA_CM_LISTENER_ACTIVE_STATE); diff --git a/drivers/infiniband/hw/irdma/cm.h b/drivers/infiniband/hw/irdma/cm.h index 19c284975fc7..7feadb3e1eda 100644 --- a/drivers/infiniband/hw/irdma/cm.h +++ b/drivers/infiniband/hw/irdma/cm.h @@ -41,7 +41,7 @@ #define TCP_OPTIONS_PADDING 3 #define IRDMA_DEFAULT_RETRYS 64 -#define IRDMA_DEFAULT_RETRANS 8 +#define IRDMA_DEFAULT_RETRANS 32 #define IRDMA_DEFAULT_TTL 0x40 #define IRDMA_DEFAULT_RTT_VAR 6 #define IRDMA_DEFAULT_SS_THRESH 0x3fffffff diff --git a/drivers/infiniband/hw/irdma/hw.c b/drivers/infiniband/hw/irdma/hw.c index 2e1e2bad0401..43dfa4761f06 100644 --- a/drivers/infiniband/hw/irdma/hw.c +++ b/drivers/infiniband/hw/irdma/hw.c @@ -41,6 +41,7 @@ static enum irdma_hmc_rsrc_type iw_hmc_obj_types[] = { IRDMA_HMC_IW_XFFL, IRDMA_HMC_IW_Q1, IRDMA_HMC_IW_Q1FL, + IRDMA_HMC_IW_PBLE, IRDMA_HMC_IW_TIMER, IRDMA_HMC_IW_FSIMC, IRDMA_HMC_IW_FSIAV, @@ -827,6 +828,8 @@ static int irdma_create_hmc_objs(struct irdma_pci_f *rf, bool privileged, info.entry_type = rf->sd_type; for (i = 0; i < IW_HMC_OBJ_TYPE_NUM; i++) { + if (iw_hmc_obj_types[i] == IRDMA_HMC_IW_PBLE) + continue; if (dev->hmc_info->hmc_obj[iw_hmc_obj_types[i]].cnt) { info.rsrc_type = iw_hmc_obj_types[i]; info.count = dev->hmc_info->hmc_obj[info.rsrc_type].cnt; diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c index 445e69e86409..7887230c867b 100644 --- a/drivers/infiniband/hw/irdma/utils.c +++ b/drivers/infiniband/hw/irdma/utils.c @@ -2595,7 +2595,10 @@ void irdma_generate_flush_completions(struct irdma_qp *iwqp) /* remove the SQ WR by moving SQ tail*/ IRDMA_RING_SET_TAIL(*sq_ring, sq_ring->tail + qp->sq_wrtrk_array[sq_ring->tail].quanta); - + if (cmpl->cpi.op_type == IRDMAQP_OP_NOP) { + kfree(cmpl); + continue; + } ibdev_dbg(iwqp->iwscq->ibcq.device, "DEV: %s: adding wr_id = 0x%llx SQ Completion to list qp_id=%d\n", __func__, cmpl->cpi.wr_id, qp->qp_id); diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 5b988db66b8f..5d45de223c43 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -442,6 +442,10 @@ static int translate_eth_ext_proto_oper(u32 eth_proto_oper, u16 *active_speed, *active_width = IB_WIDTH_2X; *active_speed = IB_SPEED_NDR; break; + case MLX5E_PROT_MASK(MLX5E_400GAUI_8): + *active_width = IB_WIDTH_8X; + *active_speed = IB_SPEED_HDR; + break; case MLX5E_PROT_MASK(MLX5E_400GAUI_4_400GBASE_CR4_KR4): *active_width = IB_WIDTH_4X; *active_speed = IB_SPEED_NDR; diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index 80fe92a21f96..815ea72ad473 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -2245,10 +2245,10 @@ static ssize_t qib_write_iter(struct kiocb *iocb, struct iov_iter *from) struct qib_ctxtdata *rcd = ctxt_fp(iocb->ki_filp); struct qib_user_sdma_queue *pq = fp->pq; - if (!iter_is_iovec(from) || !from->nr_segs || !pq) + if (!from->user_backed || !from->nr_segs || !pq) return -EINVAL; - return qib_user_sdma_writev(rcd, pq, from->iov, from->nr_segs); + return qib_user_sdma_writev(rcd, pq, iter_iov(from), from->nr_segs); } static struct class *qib_class; diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c index 3acab569fbb9..9b4c0389d2c0 100644 --- a/drivers/infiniband/sw/rdmavt/qp.c +++ b/drivers/infiniband/sw/rdmavt/qp.c @@ -97,7 +97,7 @@ static void cacheless_memcpy(void *dst, void *src, size_t n) * there are no security issues. The extra fault recovery machinery * is not invoked. */ - __copy_user_nocache(dst, (void __user *)src, n, 0); + __copy_user_nocache(dst, (void __user *)src, n); } void rvt_wss_exit(struct rvt_dev_info *rdi) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index f642ec8e92dd..29131f1a2f06 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -781,9 +781,6 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d input_report_key(dev, BTN_C, data[8]); input_report_key(dev, BTN_Z, data[9]); - /* Profile button has a value of 0-3, so it is reported as an axis */ - if (xpad->mapping & MAP_PROFILE_BUTTON) - input_report_abs(dev, ABS_PROFILE, data[34]); input_sync(dev); } @@ -1061,6 +1058,10 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char (__u16) le16_to_cpup((__le16 *)(data + 8))); } + /* Profile button has a value of 0-3, so it is reported as an axis */ + if (xpad->mapping & MAP_PROFILE_BUTTON) + input_report_abs(dev, ABS_PROFILE, data[34]); + /* paddle handling */ /* based on SDL's SDL_hidapi_xboxone.c */ if (xpad->mapping & MAP_PADDLES) { diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 989228b5a0a4..e2c11d9f3868 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -852,8 +852,8 @@ static void alps_process_packet_v6(struct psmouse *psmouse) x = y = z = 0; /* Divide 4 since trackpoint's speed is too fast */ - input_report_rel(dev2, REL_X, (char)x / 4); - input_report_rel(dev2, REL_Y, -((char)y / 4)); + input_report_rel(dev2, REL_X, (s8)x / 4); + input_report_rel(dev2, REL_Y, -((s8)y / 4)); psmouse_report_standard_buttons(dev2, packet[3]); @@ -1104,8 +1104,8 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse) ((packet[3] & 0x20) << 1); z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1); - input_report_rel(dev2, REL_X, (char)x); - input_report_rel(dev2, REL_Y, -((char)y)); + input_report_rel(dev2, REL_X, (s8)x); + input_report_rel(dev2, REL_Y, -((s8)y)); input_report_abs(dev2, ABS_PRESSURE, z); psmouse_report_standard_buttons(dev2, packet[1]); @@ -2294,20 +2294,20 @@ static int alps_get_v3_v7_resolution(struct psmouse *psmouse, int reg_pitch) if (reg < 0) return reg; - x_pitch = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */ + x_pitch = (s8)(reg << 4) >> 4; /* sign extend lower 4 bits */ x_pitch = 50 + 2 * x_pitch; /* In 0.1 mm units */ - y_pitch = (char)reg >> 4; /* sign extend upper 4 bits */ + y_pitch = (s8)reg >> 4; /* sign extend upper 4 bits */ y_pitch = 36 + 2 * y_pitch; /* In 0.1 mm units */ reg = alps_command_mode_read_reg(psmouse, reg_pitch + 1); if (reg < 0) return reg; - x_electrode = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */ + x_electrode = (s8)(reg << 4) >> 4; /* sign extend lower 4 bits */ x_electrode = 17 + x_electrode; - y_electrode = (char)reg >> 4; /* sign extend upper 4 bits */ + y_electrode = (s8)reg >> 4; /* sign extend upper 4 bits */ y_electrode = 13 + y_electrode; x_phys = x_pitch * (x_electrode - 1); /* In 0.1 mm units */ diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c index 6fd5fff0cbff..c74b99077d16 100644 --- a/drivers/input/mouse/focaltech.c +++ b/drivers/input/mouse/focaltech.c @@ -202,8 +202,8 @@ static void focaltech_process_rel_packet(struct psmouse *psmouse, state->pressed = packet[0] >> 7; finger1 = ((packet[0] >> 4) & 0x7) - 1; if (finger1 < FOC_MAX_FINGERS) { - state->fingers[finger1].x += (char)packet[1]; - state->fingers[finger1].y += (char)packet[2]; + state->fingers[finger1].x += (s8)packet[1]; + state->fingers[finger1].y += (s8)packet[2]; } else { psmouse_err(psmouse, "First finger in rel packet invalid: %d\n", finger1); @@ -218,8 +218,8 @@ static void focaltech_process_rel_packet(struct psmouse *psmouse, */ finger2 = ((packet[3] >> 4) & 0x7) - 1; if (finger2 < FOC_MAX_FINGERS) { - state->fingers[finger2].x += (char)packet[4]; - state->fingers[finger2].y += (char)packet[5]; + state->fingers[finger2].x += (s8)packet[4]; + state->fingers[finger2].y += (s8)packet[5]; } } diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h index efc61736099b..028e45bd050b 100644 --- a/drivers/input/serio/i8042-acpipnpio.h +++ b/drivers/input/serio/i8042-acpipnpio.h @@ -611,6 +611,14 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { .driver_data = (void *)(SERIO_QUIRK_NOMUX) }, { + /* Fujitsu Lifebook A574/H */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "FMVA0501PZ"), + }, + .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, + { /* Gigabyte M912 */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), @@ -1117,6 +1125,20 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) }, { + /* + * Setting SERIO_QUIRK_NOMUX or SERIO_QUIRK_RESET_ALWAYS makes + * the keyboard very laggy for ~5 seconds after boot and + * sometimes also after resume. + * However both are required for the keyboard to not fail + * completely sometimes after boot or resume. + */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "N150CU"), + }, + .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | + SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, + { .matches = { DMI_MATCH(DMI_BOARD_NAME, "NH5xAx"), }, @@ -1124,6 +1146,20 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) }, { + /* + * Setting SERIO_QUIRK_NOMUX or SERIO_QUIRK_RESET_ALWAYS makes + * the keyboard very laggy for ~5 seconds after boot and + * sometimes also after resume. + * However both are required for the keyboard to not fail + * completely sometimes after boot or resume. + */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "NHxxRZQ"), + }, + .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | + SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, + { .matches = { DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"), }, diff --git a/drivers/input/tablet/pegasus_notetaker.c b/drivers/input/tablet/pegasus_notetaker.c index d836d3dcc6a2..a68da2988f9c 100644 --- a/drivers/input/tablet/pegasus_notetaker.c +++ b/drivers/input/tablet/pegasus_notetaker.c @@ -296,6 +296,12 @@ static int pegasus_probe(struct usb_interface *intf, pegasus->intf = intf; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + /* Sanity check that pipe's type matches endpoint's type */ + if (usb_pipe_type_check(dev, pipe)) { + error = -EINVAL; + goto err_free_mem; + } + pegasus->data_len = usb_maxpacket(dev, pipe); pegasus->data = usb_alloc_coherent(dev, pegasus->data_len, GFP_KERNEL, diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c index 16caffa35dd9..30102cb80fac 100644 --- a/drivers/input/touchscreen/cyttsp5.c +++ b/drivers/input/touchscreen/cyttsp5.c @@ -111,6 +111,7 @@ struct cyttsp5_sensing_conf_data_dev { __le16 max_z; u8 origin_x; u8 origin_y; + u8 panel_id; u8 btn; u8 scan_mode; u8 max_num_of_tch_per_refresh_cycle; diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index b348172f19c3..d77f116680a0 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -124,10 +124,18 @@ static const unsigned long goodix_irq_flags[] = { static const struct dmi_system_id nine_bytes_report[] = { #if defined(CONFIG_DMI) && defined(CONFIG_X86) { - .ident = "Lenovo YogaBook", - /* YB1-X91L/F and YB1-X90L/F */ + /* Lenovo Yoga Book X90F / X90L */ .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9") + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"), + } + }, + { + /* Lenovo Yoga Book X91F / X91L */ + .matches = { + /* Non exact match to match F + L versions */ + DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"), } }, #endif diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 483aaaeb6dae..1abd187c6075 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -1415,23 +1415,26 @@ static struct iommu_device *exynos_iommu_probe_device(struct device *dev) return &data->iommu; } -static void exynos_iommu_release_device(struct device *dev) +static void exynos_iommu_set_platform_dma(struct device *dev) { struct exynos_iommu_owner *owner = dev_iommu_priv_get(dev); - struct sysmmu_drvdata *data; if (owner->domain) { struct iommu_group *group = iommu_group_get(dev); if (group) { -#ifndef CONFIG_ARM - WARN_ON(owner->domain != - iommu_group_default_domain(group)); -#endif exynos_iommu_detach_device(owner->domain, dev); iommu_group_put(group); } } +} + +static void exynos_iommu_release_device(struct device *dev) +{ + struct exynos_iommu_owner *owner = dev_iommu_priv_get(dev); + struct sysmmu_drvdata *data; + + exynos_iommu_set_platform_dma(dev); list_for_each_entry(data, &owner->controllers, owner_node) device_link_del(data->link); @@ -1479,7 +1482,7 @@ static const struct iommu_ops exynos_iommu_ops = { .domain_alloc = exynos_iommu_domain_alloc, .device_group = generic_device_group, #ifdef CONFIG_ARM - .set_platform_dma_ops = exynos_iommu_release_device, + .set_platform_dma_ops = exynos_iommu_set_platform_dma, #endif .probe_device = exynos_iommu_probe_device, .release_device = exynos_iommu_release_device, diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c index 6acfe879589c..23828d189c2a 100644 --- a/drivers/iommu/intel/dmar.c +++ b/drivers/iommu/intel/dmar.c @@ -1071,7 +1071,8 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd) } err = -EINVAL; - if (cap_sagaw(iommu->cap) == 0) { + if (!cap_sagaw(iommu->cap) && + (!ecap_smts(iommu->ecap) || ecap_slts(iommu->ecap))) { pr_info("%s: No supported address widths. Not attempting DMA translation.\n", iommu->name); drhd->ignored = 1; diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h index d6df3b865812..694ab9b7d3e9 100644 --- a/drivers/iommu/intel/iommu.h +++ b/drivers/iommu/intel/iommu.h @@ -641,6 +641,8 @@ struct iommu_pmu { DECLARE_BITMAP(used_mask, IOMMU_PMU_IDX_MAX); struct perf_event *event_list[IOMMU_PMU_IDX_MAX]; unsigned char irq_name[16]; + struct hlist_node cpuhp_node; + int cpu; }; #define IOMMU_IRQ_ID_OFFSET_PRQ (DMAR_UNITS_SUPPORTED) diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c index 6d01fa078c36..df9e261af0b5 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c @@ -311,14 +311,12 @@ static int set_ioapic_sid(struct irte *irte, int apic) if (!irte) return -1; - down_read(&dmar_global_lock); for (i = 0; i < MAX_IO_APICS; i++) { if (ir_ioapic[i].iommu && ir_ioapic[i].id == apic) { sid = (ir_ioapic[i].bus << 8) | ir_ioapic[i].devfn; break; } } - up_read(&dmar_global_lock); if (sid == 0) { pr_warn("Failed to set source-id of IOAPIC (%d)\n", apic); @@ -338,14 +336,12 @@ static int set_hpet_sid(struct irte *irte, u8 id) if (!irte) return -1; - down_read(&dmar_global_lock); for (i = 0; i < MAX_HPET_TBS; i++) { if (ir_hpet[i].iommu && ir_hpet[i].id == id) { sid = (ir_hpet[i].bus << 8) | ir_hpet[i].devfn; break; } } - up_read(&dmar_global_lock); if (sid == 0) { pr_warn("Failed to set source-id of HPET block (%d)\n", id); @@ -1339,9 +1335,7 @@ static int intel_irq_remapping_alloc(struct irq_domain *domain, if (!data) goto out_free_parent; - down_read(&dmar_global_lock); index = alloc_irte(iommu, &data->irq_2_iommu, nr_irqs); - up_read(&dmar_global_lock); if (index < 0) { pr_warn("Failed to allocate IRTE\n"); kfree(data); diff --git a/drivers/iommu/intel/perfmon.c b/drivers/iommu/intel/perfmon.c index e17d9743a0d8..cf43e798eca4 100644 --- a/drivers/iommu/intel/perfmon.c +++ b/drivers/iommu/intel/perfmon.c @@ -773,19 +773,34 @@ static void iommu_pmu_unset_interrupt(struct intel_iommu *iommu) iommu->perf_irq = 0; } -static int iommu_pmu_cpu_online(unsigned int cpu) +static int iommu_pmu_cpu_online(unsigned int cpu, struct hlist_node *node) { + struct iommu_pmu *iommu_pmu = hlist_entry_safe(node, typeof(*iommu_pmu), cpuhp_node); + if (cpumask_empty(&iommu_pmu_cpu_mask)) cpumask_set_cpu(cpu, &iommu_pmu_cpu_mask); + if (cpumask_test_cpu(cpu, &iommu_pmu_cpu_mask)) + iommu_pmu->cpu = cpu; + return 0; } -static int iommu_pmu_cpu_offline(unsigned int cpu) +static int iommu_pmu_cpu_offline(unsigned int cpu, struct hlist_node *node) { - struct dmar_drhd_unit *drhd; - struct intel_iommu *iommu; - int target; + struct iommu_pmu *iommu_pmu = hlist_entry_safe(node, typeof(*iommu_pmu), cpuhp_node); + int target = cpumask_first(&iommu_pmu_cpu_mask); + + /* + * The iommu_pmu_cpu_mask has been updated when offline the CPU + * for the first iommu_pmu. Migrate the other iommu_pmu to the + * new target. + */ + if (target < nr_cpu_ids && target != iommu_pmu->cpu) { + perf_pmu_migrate_context(&iommu_pmu->pmu, cpu, target); + iommu_pmu->cpu = target; + return 0; + } if (!cpumask_test_and_clear_cpu(cpu, &iommu_pmu_cpu_mask)) return 0; @@ -795,45 +810,50 @@ static int iommu_pmu_cpu_offline(unsigned int cpu) if (target < nr_cpu_ids) cpumask_set_cpu(target, &iommu_pmu_cpu_mask); else - target = -1; + return 0; - rcu_read_lock(); - - for_each_iommu(iommu, drhd) { - if (!iommu->pmu) - continue; - perf_pmu_migrate_context(&iommu->pmu->pmu, cpu, target); - } - rcu_read_unlock(); + perf_pmu_migrate_context(&iommu_pmu->pmu, cpu, target); + iommu_pmu->cpu = target; return 0; } static int nr_iommu_pmu; +static enum cpuhp_state iommu_cpuhp_slot; static int iommu_pmu_cpuhp_setup(struct iommu_pmu *iommu_pmu) { int ret; - if (nr_iommu_pmu++) - return 0; + if (!nr_iommu_pmu) { + ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, + "driver/iommu/intel/perfmon:online", + iommu_pmu_cpu_online, + iommu_pmu_cpu_offline); + if (ret < 0) + return ret; + iommu_cpuhp_slot = ret; + } - ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_IOMMU_PERF_ONLINE, - "driver/iommu/intel/perfmon:online", - iommu_pmu_cpu_online, - iommu_pmu_cpu_offline); - if (ret) - nr_iommu_pmu = 0; + ret = cpuhp_state_add_instance(iommu_cpuhp_slot, &iommu_pmu->cpuhp_node); + if (ret) { + if (!nr_iommu_pmu) + cpuhp_remove_multi_state(iommu_cpuhp_slot); + return ret; + } + nr_iommu_pmu++; - return ret; + return 0; } static void iommu_pmu_cpuhp_free(struct iommu_pmu *iommu_pmu) { + cpuhp_state_remove_instance(iommu_cpuhp_slot, &iommu_pmu->cpuhp_node); + if (--nr_iommu_pmu) return; - cpuhp_remove_state(CPUHP_AP_PERF_X86_IOMMU_PERF_ONLINE); + cpuhp_remove_multi_state(iommu_cpuhp_slot); } void iommu_pmu_register(struct intel_iommu *iommu) diff --git a/drivers/iommu/iommufd/pages.c b/drivers/iommu/iommufd/pages.c index f8d92c9bb65b..3c47846cc5ef 100644 --- a/drivers/iommu/iommufd/pages.c +++ b/drivers/iommu/iommufd/pages.c @@ -294,9 +294,9 @@ static void batch_clear_carry(struct pfn_batch *batch, unsigned int keep_pfns) batch->npfns[batch->end - 1] < keep_pfns); batch->total_pfns = keep_pfns; - batch->npfns[0] = keep_pfns; batch->pfns[0] = batch->pfns[batch->end - 1] + (batch->npfns[batch->end - 1] - keep_pfns); + batch->npfns[0] = keep_pfns; batch->end = 0; } @@ -1142,6 +1142,7 @@ struct iopt_pages *iopt_alloc_pages(void __user *uptr, unsigned long length, bool writable) { struct iopt_pages *pages; + unsigned long end; /* * The iommu API uses size_t as the length, and protect the DIV_ROUND_UP @@ -1150,6 +1151,9 @@ struct iopt_pages *iopt_alloc_pages(void __user *uptr, unsigned long length, if (length > SIZE_MAX - PAGE_SIZE || length == 0) return ERR_PTR(-EINVAL); + if (check_add_overflow((unsigned long)uptr, length, &end)) + return ERR_PTR(-EOVERFLOW); + pages = kzalloc(sizeof(*pages), GFP_KERNEL_ACCOUNT); if (!pages) return ERR_PTR(-ENOMEM); @@ -1203,13 +1207,21 @@ iopt_area_unpin_domain(struct pfn_batch *batch, struct iopt_area *area, unsigned long start = max(start_index, *unmapped_end_index); + if (IS_ENABLED(CONFIG_IOMMUFD_TEST) && + batch->total_pfns) + WARN_ON(*unmapped_end_index - + batch->total_pfns != + start_index); batch_from_domain(batch, domain, area, start, last_index); - batch_last_index = start + batch->total_pfns - 1; + batch_last_index = start_index + batch->total_pfns - 1; } else { batch_last_index = last_index; } + if (IS_ENABLED(CONFIG_IOMMUFD_TEST)) + WARN_ON(batch_last_index > real_last_index); + /* * unmaps must always 'cut' at a place where the pfns are not * contiguous to pair with the maps that always install diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 7dc990eb2c9b..09e422da482f 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -7,6 +7,7 @@ config IRQCHIP config ARM_GIC bool + depends on OF select IRQ_DOMAIN_HIERARCHY select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP @@ -35,6 +36,7 @@ config ARM_GIC_V3 select IRQ_DOMAIN_HIERARCHY select PARTITION_PERCPU select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP + select HAVE_ARM_SMCCC_DISCOVERY config ARM_GIC_V3_ITS bool @@ -535,6 +537,7 @@ config TI_PRUSS_INTC config RISCV_INTC bool depends on RISCV + select IRQ_DOMAIN_HIERARCHY config SIFIVE_PLIC bool diff --git a/drivers/irqchip/irq-bcm6345-l1.c b/drivers/irqchip/irq-bcm6345-l1.c index 6899e37810a8..fa113cb2529a 100644 --- a/drivers/irqchip/irq-bcm6345-l1.c +++ b/drivers/irqchip/irq-bcm6345-l1.c @@ -257,6 +257,9 @@ static int __init bcm6345_l1_init_one(struct device_node *dn, if (!cpu->map_base) return -ENOMEM; + if (!request_mem_region(res.start, sz, res.name)) + pr_err("failed to request intc memory"); + for (i = 0; i < n_words; i++) { cpu->enable_cache[i] = 0; __raw_writel(0, cpu->map_base + reg_enable(intc, i)); @@ -335,8 +338,7 @@ static int __init bcm6345_l1_of_init(struct device_node *dn, for_each_cpu(idx, &intc->cpumask) { struct bcm6345_l1_cpu *cpu = intc->cpus[idx]; - pr_info(" CPU%u at MMIO 0x%p (irq = %d)\n", idx, - cpu->map_base, cpu->parent_irq); + pr_info(" CPU%u (irq = %d)\n", idx, cpu->parent_irq); } return 0; diff --git a/drivers/irqchip/irq-csky-apb-intc.c b/drivers/irqchip/irq-csky-apb-intc.c index 42d8a2438ebc..6710691e4c25 100644 --- a/drivers/irqchip/irq-csky-apb-intc.c +++ b/drivers/irqchip/irq-csky-apb-intc.c @@ -68,7 +68,7 @@ static void __init ck_set_gc(struct device_node *node, void __iomem *reg_base, gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit; gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; - if (of_find_property(node, "csky,support-pulse-signal", NULL)) + if (of_property_read_bool(node, "csky,support-pulse-signal")) gc->chip_types[0].chip.irq_unmask = irq_ck_mask_set_bit; } diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index f1e75b35a52a..f2ff4387870d 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -421,7 +421,7 @@ static int __init gicv2m_of_init(struct fwnode_handle *parent_handle, u32 spi_start = 0, nr_spis = 0; struct resource res; - if (!of_find_property(child, "msi-controller", NULL)) + if (!of_property_read_bool(child, "msi-controller")) continue; ret = of_address_to_resource(child, 0, &res); diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 586271b8aa39..fa4641a5dfd8 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -42,9 +42,11 @@ #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1ULL << 0) #define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1) #define ITS_FLAGS_WORKAROUND_CAVIUM_23144 (1ULL << 2) +#define ITS_FLAGS_FORCE_NON_SHAREABLE (1ULL << 3) #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) #define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1 << 1) +#define RDIST_FLAGS_FORCE_NON_SHAREABLE (1 << 2) #define RD_LOCAL_LPI_ENABLED BIT(0) #define RD_LOCAL_PENDTABLE_PREALLOCATED BIT(1) @@ -2359,6 +2361,9 @@ retry_baser: its_write_baser(its, baser, val); tmp = baser->val; + if (its->flags & ITS_FLAGS_FORCE_NON_SHAREABLE) + tmp &= ~GITS_BASER_SHAREABILITY_MASK; + if ((val ^ tmp) & GITS_BASER_SHAREABILITY_MASK) { /* * Shareability didn't stick. Just use @@ -3096,6 +3101,9 @@ static void its_cpu_init_lpis(void) gicr_write_propbaser(val, rbase + GICR_PROPBASER); tmp = gicr_read_propbaser(rbase + GICR_PROPBASER); + if (gic_rdists->flags & RDIST_FLAGS_FORCE_NON_SHAREABLE) + tmp &= ~GICR_PROPBASER_SHAREABILITY_MASK; + if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) { if (!(tmp & GICR_PROPBASER_SHAREABILITY_MASK)) { /* @@ -3120,6 +3128,9 @@ static void its_cpu_init_lpis(void) gicr_write_pendbaser(val, rbase + GICR_PENDBASER); tmp = gicr_read_pendbaser(rbase + GICR_PENDBASER); + if (gic_rdists->flags & RDIST_FLAGS_FORCE_NON_SHAREABLE) + tmp &= ~GICR_PENDBASER_SHAREABILITY_MASK; + if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) { /* * The HW reports non-shareable, we must remove the @@ -4710,6 +4721,19 @@ static bool __maybe_unused its_enable_quirk_hip07_161600802(void *data) return true; } +static bool __maybe_unused its_enable_rk3588001(void *data) +{ + struct its_node *its = data; + + if (!of_machine_is_compatible("rockchip,rk3588")) + return false; + + its->flags |= ITS_FLAGS_FORCE_NON_SHAREABLE; + gic_rdists->flags |= RDIST_FLAGS_FORCE_NON_SHAREABLE; + + return true; +} + static const struct gic_quirk its_quirks[] = { #ifdef CONFIG_CAVIUM_ERRATUM_22375 { @@ -4756,6 +4780,14 @@ static const struct gic_quirk its_quirks[] = { .init = its_enable_quirk_hip07_161600802, }, #endif +#ifdef CONFIG_ROCKCHIP_ERRATUM_3588001 + { + .desc = "ITS: Rockchip erratum RK3588001", + .iidr = 0x0201743b, + .mask = 0xffffffff, + .init = its_enable_rk3588001, + }, +#endif { } }; @@ -5096,6 +5128,9 @@ static int __init its_probe_one(struct resource *res, gits_write_cbaser(baser, its->base + GITS_CBASER); tmp = gits_read_cbaser(its->base + GITS_CBASER); + if (its->flags & ITS_FLAGS_FORCE_NON_SHAREABLE) + tmp &= ~GITS_CBASER_SHAREABILITY_MASK; + if ((tmp ^ baser) & GITS_CBASER_SHAREABILITY_MASK) { if (!(tmp & GITS_CBASER_SHAREABILITY_MASK)) { /* diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index fd134e1f481a..6fcee221f201 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -24,6 +24,9 @@ #include <linux/irqchip/arm-gic-common.h> #include <linux/irqchip/arm-gic-v3.h> #include <linux/irqchip/irq-partition-percpu.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/arm-smccc.h> #include <asm/cputype.h> #include <asm/exception.h> @@ -47,6 +50,7 @@ struct redist_region { struct gic_chip_data { struct fwnode_handle *fwnode; + phys_addr_t dist_phys_base; void __iomem *dist_base; struct redist_region *redist_regions; struct rdists rdists; @@ -59,6 +63,10 @@ struct gic_chip_data { struct partition_desc **ppi_descs; }; +#define T241_CHIPS_MAX 4 +static void __iomem *t241_dist_base_alias[T241_CHIPS_MAX] __read_mostly; +static DEFINE_STATIC_KEY_FALSE(gic_nvidia_t241_erratum); + static struct gic_chip_data gic_data __read_mostly; static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key); @@ -179,6 +187,39 @@ static inline bool gic_irq_in_rdist(struct irq_data *d) } } +static inline void __iomem *gic_dist_base_alias(struct irq_data *d) +{ + if (static_branch_unlikely(&gic_nvidia_t241_erratum)) { + irq_hw_number_t hwirq = irqd_to_hwirq(d); + u32 chip; + + /* + * For the erratum T241-FABRIC-4, read accesses to GICD_In{E} + * registers are directed to the chip that owns the SPI. The + * the alias region can also be used for writes to the + * GICD_In{E} except GICD_ICENABLERn. Each chip has support + * for 320 {E}SPIs. Mappings for all 4 chips: + * Chip0 = 32-351 + * Chip1 = 352-671 + * Chip2 = 672-991 + * Chip3 = 4096-4415 + */ + switch (__get_intid_range(hwirq)) { + case SPI_RANGE: + chip = (hwirq - 32) / 320; + break; + case ESPI_RANGE: + chip = 3; + break; + default: + unreachable(); + } + return t241_dist_base_alias[chip]; + } + + return gic_data.dist_base; +} + static inline void __iomem *gic_dist_base(struct irq_data *d) { switch (get_intid_range(d)) { @@ -337,7 +378,7 @@ static int gic_peek_irq(struct irq_data *d, u32 offset) if (gic_irq_in_rdist(d)) base = gic_data_rdist_sgi_base(); else - base = gic_data.dist_base; + base = gic_dist_base_alias(d); return !!(readl_relaxed(base + offset + (index / 32) * 4) & mask); } @@ -588,7 +629,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) if (gic_irq_in_rdist(d)) base = gic_data_rdist_sgi_base(); else - base = gic_data.dist_base; + base = gic_dist_base_alias(d); offset = convert_offset_index(d, GICD_ICFGR, &index); @@ -1708,6 +1749,43 @@ static bool gic_enable_quirk_hip06_07(void *data) return false; } +#define T241_CHIPN_MASK GENMASK_ULL(45, 44) +#define T241_CHIP_GICDA_OFFSET 0x1580000 +#define SMCCC_SOC_ID_T241 0x036b0241 + +static bool gic_enable_quirk_nvidia_t241(void *data) +{ + s32 soc_id = arm_smccc_get_soc_id_version(); + unsigned long chip_bmask = 0; + phys_addr_t phys; + u32 i; + + /* Check JEP106 code for NVIDIA T241 chip (036b:0241) */ + if ((soc_id < 0) || (soc_id != SMCCC_SOC_ID_T241)) + return false; + + /* Find the chips based on GICR regions PHYS addr */ + for (i = 0; i < gic_data.nr_redist_regions; i++) { + chip_bmask |= BIT(FIELD_GET(T241_CHIPN_MASK, + (u64)gic_data.redist_regions[i].phys_base)); + } + + if (hweight32(chip_bmask) < 3) + return false; + + /* Setup GICD alias regions */ + for (i = 0; i < ARRAY_SIZE(t241_dist_base_alias); i++) { + if (chip_bmask & BIT(i)) { + phys = gic_data.dist_phys_base + T241_CHIP_GICDA_OFFSET; + phys |= FIELD_PREP(T241_CHIPN_MASK, i); + t241_dist_base_alias[i] = ioremap(phys, SZ_64K); + WARN_ON_ONCE(!t241_dist_base_alias[i]); + } + } + static_branch_enable(&gic_nvidia_t241_erratum); + return true; +} + static const struct gic_quirk gic_quirks[] = { { .desc = "GICv3: Qualcomm MSM8996 broken firmware", @@ -1740,6 +1818,12 @@ static const struct gic_quirk gic_quirks[] = { .init = gic_enable_quirk_cavium_38539, }, { + .desc = "GICv3: NVIDIA erratum T241-FABRIC-4", + .iidr = 0x0402043b, + .mask = 0xffffffff, + .init = gic_enable_quirk_nvidia_t241, + }, + { } }; @@ -1798,7 +1882,8 @@ static void gic_enable_nmi_support(void) gic_chip.flags |= IRQCHIP_SUPPORTS_NMI; } -static int __init gic_init_bases(void __iomem *dist_base, +static int __init gic_init_bases(phys_addr_t dist_phys_base, + void __iomem *dist_base, struct redist_region *rdist_regs, u32 nr_redist_regions, u64 redist_stride, @@ -1814,6 +1899,7 @@ static int __init gic_init_bases(void __iomem *dist_base, pr_info("GIC: Using split EOI/Deactivate mode\n"); gic_data.fwnode = handle; + gic_data.dist_phys_base = dist_phys_base; gic_data.dist_base = dist_base; gic_data.redist_regions = rdist_regs; gic_data.nr_redist_regions = nr_redist_regions; @@ -1841,10 +1927,13 @@ static int __init gic_init_bases(void __iomem *dist_base, gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops, &gic_data); gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist)); - gic_data.rdists.has_rvpeid = true; - gic_data.rdists.has_vlpis = true; - gic_data.rdists.has_direct_lpi = true; - gic_data.rdists.has_vpend_valid_dirty = true; + if (!static_branch_unlikely(&gic_nvidia_t241_erratum)) { + /* Disable GICv4.x features for the erratum T241-FABRIC-4 */ + gic_data.rdists.has_rvpeid = true; + gic_data.rdists.has_vlpis = true; + gic_data.rdists.has_direct_lpi = true; + gic_data.rdists.has_vpend_valid_dirty = true; + } if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) { err = -ENOMEM; @@ -2050,6 +2139,7 @@ static void __iomem *gic_of_iomap(struct device_node *node, int idx, static int __init gic_of_init(struct device_node *node, struct device_node *parent) { + phys_addr_t dist_phys_base; void __iomem *dist_base; struct redist_region *rdist_regs; struct resource res; @@ -2063,6 +2153,8 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare return PTR_ERR(dist_base); } + dist_phys_base = res.start; + err = gic_validate_dist_version(dist_base); if (err) { pr_err("%pOF: no distributor detected, giving up\n", node); @@ -2094,8 +2186,8 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare gic_enable_of_quirks(node, gic_quirks, &gic_data); - err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions, - redist_stride, &node->fwnode); + err = gic_init_bases(dist_phys_base, dist_base, rdist_regs, + nr_redist_regions, redist_stride, &node->fwnode); if (err) goto out_unmap_rdist; @@ -2411,8 +2503,9 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end) goto out_redist_unmap; } - err = gic_init_bases(acpi_data.dist_base, acpi_data.redist_regs, - acpi_data.nr_redist_regions, 0, gsi_domain_handle); + err = gic_init_bases(dist->base_address, acpi_data.dist_base, + acpi_data.redist_regs, acpi_data.nr_redist_regions, + 0, gsi_domain_handle); if (err) goto out_fwhandle_free; diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 95e3d2a71db6..412196a7dad5 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1081,10 +1081,6 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, return 0; } -static void gic_irq_domain_unmap(struct irq_domain *d, unsigned int irq) -{ -} - static int gic_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec, unsigned long *hwirq, @@ -1167,11 +1163,6 @@ static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = { .free = irq_domain_free_irqs_top, }; -static const struct irq_domain_ops gic_irq_domain_ops = { - .map = gic_irq_domain_map, - .unmap = gic_irq_domain_unmap, -}; - static int gic_init_bases(struct gic_chip_data *gic, struct fwnode_handle *handle) { @@ -1219,30 +1210,9 @@ static int gic_init_bases(struct gic_chip_data *gic, gic_irqs = 1020; gic->gic_irqs = gic_irqs; - if (handle) { /* DT/ACPI */ - gic->domain = irq_domain_create_linear(handle, gic_irqs, - &gic_irq_domain_hierarchy_ops, - gic); - } else { /* Legacy support */ - /* - * For primary GICs, skip over SGIs. - * No secondary GIC support whatsoever. - */ - int irq_base; - - gic_irqs -= 16; /* calculate # of irqs to allocate */ - - irq_base = irq_alloc_descs(16, 16, gic_irqs, - numa_node_id()); - if (irq_base < 0) { - WARN(1, "Cannot allocate irq_descs @ IRQ16, assuming pre-allocated\n"); - irq_base = 16; - } - - gic->domain = irq_domain_add_legacy(NULL, gic_irqs, irq_base, - 16, &gic_irq_domain_ops, gic); - } - + gic->domain = irq_domain_create_linear(handle, gic_irqs, + &gic_irq_domain_hierarchy_ops, + gic); if (WARN_ON(!gic->domain)) { ret = -ENODEV; goto error; @@ -1297,23 +1267,6 @@ static int __init __gic_init_bases(struct gic_chip_data *gic, return ret; } -void __init gic_init(void __iomem *dist_base, void __iomem *cpu_base) -{ - struct gic_chip_data *gic; - - /* - * Non-DT/ACPI systems won't run a hypervisor, so let's not - * bother with these... - */ - static_branch_disable(&supports_deactivate_key); - - gic = &gic_data[0]; - gic->raw_dist_base = dist_base; - gic->raw_cpu_base = cpu_base; - - __gic_init_bases(gic, NULL); -} - static void gic_teardown(struct gic_chip_data *gic) { if (WARN_ON(!gic)) @@ -1325,7 +1278,6 @@ static void gic_teardown(struct gic_chip_data *gic) iounmap(gic->raw_cpu_base); } -#ifdef CONFIG_OF static int gic_cnt __initdata; static bool gicv2_force_probe; @@ -1570,12 +1522,6 @@ IRQCHIP_DECLARE(cortex_a7_gic, "arm,cortex-a7-gic", gic_of_init); IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init); IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init); IRQCHIP_DECLARE(pl390, "arm,pl390", gic_of_init); -#else -int gic_of_init_child(struct device *dev, struct gic_chip_data **gic, int irq) -{ - return -ENOTSUPP; -} -#endif #ifdef CONFIG_ACPI static struct diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c index d15fd38c1756..90181c42840b 100644 --- a/drivers/irqchip/irq-loongson-eiointc.c +++ b/drivers/irqchip/irq-loongson-eiointc.c @@ -280,9 +280,6 @@ static void acpi_set_vec_parent(int node, struct irq_domain *parent, struct acpi { int i; - if (cpu_has_flatmode) - node = cpu_to_node(node * CORES_PER_EIO_NODE); - for (i = 0; i < MAX_IO_PICS; i++) { if (node == vec_group[i].node) { vec_group[i].parent = parent; @@ -343,19 +340,27 @@ static int __init pch_pic_parse_madt(union acpi_subtable_headers *header, if (parent) return pch_pic_acpi_init(parent, pchpic_entry); - return -EINVAL; + return 0; } static int __init pch_msi_parse_madt(union acpi_subtable_headers *header, const unsigned long end) { + struct irq_domain *parent; struct acpi_madt_msi_pic *pchmsi_entry = (struct acpi_madt_msi_pic *)header; - struct irq_domain *parent = acpi_get_vec_parent(eiointc_priv[nr_pics - 1]->node, msi_group); + int node; + + if (cpu_has_flatmode) + node = cpu_to_node(eiointc_priv[nr_pics - 1]->node * CORES_PER_EIO_NODE); + else + node = eiointc_priv[nr_pics - 1]->node; + + parent = acpi_get_vec_parent(node, msi_group); if (parent) return pch_msi_acpi_init(parent, pchmsi_entry); - return -EINVAL; + return 0; } static int __init acpi_cascade_irqdomain_init(void) @@ -379,6 +384,7 @@ int __init eiointc_acpi_init(struct irq_domain *parent, int i, ret, parent_irq; unsigned long node_map; struct eiointc_priv *priv; + int node; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) @@ -416,13 +422,19 @@ int __init eiointc_acpi_init(struct irq_domain *parent, parent_irq = irq_create_mapping(parent, acpi_eiointc->cascade); irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv); - register_syscore_ops(&eiointc_syscore_ops); - cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING, + if (nr_pics == 1) { + register_syscore_ops(&eiointc_syscore_ops); + cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING, "irqchip/loongarch/intc:starting", eiointc_router_init, NULL); + } - acpi_set_vec_parent(acpi_eiointc->node, priv->eiointc_domain, pch_group); - acpi_set_vec_parent(acpi_eiointc->node, priv->eiointc_domain, msi_group); + if (cpu_has_flatmode) + node = cpu_to_node(acpi_eiointc->node * CORES_PER_EIO_NODE); + else + node = acpi_eiointc->node; + acpi_set_vec_parent(node, priv->eiointc_domain, pch_group); + acpi_set_vec_parent(node, priv->eiointc_domain, msi_group); ret = acpi_cascade_irqdomain_init(); return ret; diff --git a/drivers/irqchip/irq-loongson-pch-pic.c b/drivers/irqchip/irq-loongson-pch-pic.c index 437f1af693d0..e5fe4d50be05 100644 --- a/drivers/irqchip/irq-loongson-pch-pic.c +++ b/drivers/irqchip/irq-loongson-pch-pic.c @@ -311,7 +311,8 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base, pch_pic_handle[nr_pics] = domain_handle; pch_pic_priv[nr_pics++] = priv; - register_syscore_ops(&pch_pic_syscore_ops); + if (nr_pics == 1) + register_syscore_ops(&pch_pic_syscore_ops); return 0; @@ -403,6 +404,9 @@ int __init pch_pic_acpi_init(struct irq_domain *parent, int ret, vec_base; struct fwnode_handle *domain_handle; + if (find_pch_pic(acpi_pchpic->gsi_base) >= 0) + return 0; + vec_base = acpi_pchpic->gsi_base - GSI_MIN_PCH_IRQ; domain_handle = irq_domain_alloc_fwnode(&acpi_pchpic->address); diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c index 499e5f81b3fe..f229e3e66387 100644 --- a/drivers/irqchip/irq-riscv-intc.c +++ b/drivers/irqchip/irq-riscv-intc.c @@ -26,20 +26,7 @@ static asmlinkage void riscv_intc_irq(struct pt_regs *regs) if (unlikely(cause >= BITS_PER_LONG)) panic("unexpected interrupt cause"); - switch (cause) { -#ifdef CONFIG_SMP - case RV_IRQ_SOFT: - /* - * We only use software interrupts to pass IPIs, so if a - * non-SMP system gets one, then we don't know what to do. - */ - handle_IPI(regs); - break; -#endif - default: - generic_handle_domain_irq(intc_domain, cause); - break; - } + generic_handle_domain_irq(intc_domain, cause); } /* @@ -59,22 +46,27 @@ static void riscv_intc_irq_unmask(struct irq_data *d) csr_set(CSR_IE, BIT(d->hwirq)); } -static int riscv_intc_cpu_starting(unsigned int cpu) -{ - csr_set(CSR_IE, BIT(RV_IRQ_SOFT)); - return 0; -} - -static int riscv_intc_cpu_dying(unsigned int cpu) +static void riscv_intc_irq_eoi(struct irq_data *d) { - csr_clear(CSR_IE, BIT(RV_IRQ_SOFT)); - return 0; + /* + * The RISC-V INTC driver uses handle_percpu_devid_irq() flow + * for the per-HART local interrupts and child irqchip drivers + * (such as PLIC, SBI IPI, CLINT, APLIC, IMSIC, etc) implement + * chained handlers for the per-HART local interrupts. + * + * In the absence of irq_eoi(), the chained_irq_enter() and + * chained_irq_exit() functions (used by child irqchip drivers) + * will do unnecessary mask/unmask of per-HART local interrupts + * at the time of handling interrupts. To avoid this, we provide + * an empty irq_eoi() callback for RISC-V INTC irqchip. + */ } static struct irq_chip riscv_intc_chip = { .name = "RISC-V INTC", .irq_mask = riscv_intc_irq_mask, .irq_unmask = riscv_intc_irq_unmask, + .irq_eoi = riscv_intc_irq_eoi, }; static int riscv_intc_domain_map(struct irq_domain *d, unsigned int irq, @@ -87,11 +79,39 @@ static int riscv_intc_domain_map(struct irq_domain *d, unsigned int irq, return 0; } +static int riscv_intc_domain_alloc(struct irq_domain *domain, + unsigned int virq, unsigned int nr_irqs, + void *arg) +{ + int i, ret; + irq_hw_number_t hwirq; + unsigned int type = IRQ_TYPE_NONE; + struct irq_fwspec *fwspec = arg; + + ret = irq_domain_translate_onecell(domain, fwspec, &hwirq, &type); + if (ret) + return ret; + + for (i = 0; i < nr_irqs; i++) { + ret = riscv_intc_domain_map(domain, virq + i, hwirq + i); + if (ret) + return ret; + } + + return 0; +} + static const struct irq_domain_ops riscv_intc_domain_ops = { .map = riscv_intc_domain_map, .xlate = irq_domain_xlate_onecell, + .alloc = riscv_intc_domain_alloc }; +static struct fwnode_handle *riscv_intc_hwnode(void) +{ + return intc_domain->fwnode; +} + static int __init riscv_intc_init(struct device_node *node, struct device_node *parent) { @@ -126,10 +146,7 @@ static int __init riscv_intc_init(struct device_node *node, return rc; } - cpuhp_setup_state(CPUHP_AP_IRQ_RISCV_STARTING, - "irqchip/riscv/intc:starting", - riscv_intc_cpu_starting, - riscv_intc_cpu_dying); + riscv_set_intc_hwnode_fn(riscv_intc_hwnode); pr_info("%d local interrupts mapped\n", BITS_PER_LONG); diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index ff47bd0dec45..e1484905b7bd 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -17,6 +17,7 @@ #include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/spinlock.h> +#include <linux/syscore_ops.h> #include <asm/smp.h> /* @@ -67,6 +68,8 @@ struct plic_priv { struct irq_domain *irqdomain; void __iomem *regs; unsigned long plic_quirks; + unsigned int nr_irqs; + unsigned long *prio_save; }; struct plic_handler { @@ -78,6 +81,7 @@ struct plic_handler { */ raw_spinlock_t enable_lock; void __iomem *enable_base; + u32 *enable_save; struct plic_priv *priv; }; static int plic_parent_irq __ro_after_init; @@ -229,6 +233,71 @@ static int plic_irq_set_type(struct irq_data *d, unsigned int type) return IRQ_SET_MASK_OK; } +static int plic_irq_suspend(void) +{ + unsigned int i, cpu; + u32 __iomem *reg; + struct plic_priv *priv; + + priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv; + + for (i = 0; i < priv->nr_irqs; i++) + if (readl(priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID)) + __set_bit(i, priv->prio_save); + else + __clear_bit(i, priv->prio_save); + + for_each_cpu(cpu, cpu_present_mask) { + struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu); + + if (!handler->present) + continue; + + raw_spin_lock(&handler->enable_lock); + for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) { + reg = handler->enable_base + i * sizeof(u32); + handler->enable_save[i] = readl(reg); + } + raw_spin_unlock(&handler->enable_lock); + } + + return 0; +} + +static void plic_irq_resume(void) +{ + unsigned int i, index, cpu; + u32 __iomem *reg; + struct plic_priv *priv; + + priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv; + + for (i = 0; i < priv->nr_irqs; i++) { + index = BIT_WORD(i); + writel((priv->prio_save[index] & BIT_MASK(i)) ? 1 : 0, + priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID); + } + + for_each_cpu(cpu, cpu_present_mask) { + struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu); + + if (!handler->present) + continue; + + raw_spin_lock(&handler->enable_lock); + for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) { + reg = handler->enable_base + i * sizeof(u32); + writel(handler->enable_save[i], reg); + } + raw_spin_unlock(&handler->enable_lock); + } +} + +static struct syscore_ops plic_irq_syscore_ops = { + .suspend = plic_irq_suspend, + .resume = plic_irq_resume, +}; + static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { @@ -345,6 +414,7 @@ static int __init __plic_init(struct device_node *node, u32 nr_irqs; struct plic_priv *priv; struct plic_handler *handler; + unsigned int cpu; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) @@ -363,15 +433,21 @@ static int __init __plic_init(struct device_node *node, if (WARN_ON(!nr_irqs)) goto out_iounmap; + priv->nr_irqs = nr_irqs; + + priv->prio_save = bitmap_alloc(nr_irqs, GFP_KERNEL); + if (!priv->prio_save) + goto out_free_priority_reg; + nr_contexts = of_irq_count(node); if (WARN_ON(!nr_contexts)) - goto out_iounmap; + goto out_free_priority_reg; error = -ENOMEM; priv->irqdomain = irq_domain_add_linear(node, nr_irqs + 1, &plic_irqdomain_ops, priv); if (WARN_ON(!priv->irqdomain)) - goto out_iounmap; + goto out_free_priority_reg; for (i = 0; i < nr_contexts; i++) { struct of_phandle_args parent; @@ -441,6 +517,11 @@ static int __init __plic_init(struct device_node *node, handler->enable_base = priv->regs + CONTEXT_ENABLE_BASE + i * CONTEXT_ENABLE_SIZE; handler->priv = priv; + + handler->enable_save = kcalloc(DIV_ROUND_UP(nr_irqs, 32), + sizeof(*handler->enable_save), GFP_KERNEL); + if (!handler->enable_save) + goto out_free_enable_reg; done: for (hwirq = 1; hwirq <= nr_irqs; hwirq++) { plic_toggle(handler, hwirq, 0); @@ -461,11 +542,19 @@ done: plic_starting_cpu, plic_dying_cpu); plic_cpuhp_setup_done = true; } + register_syscore_ops(&plic_irq_syscore_ops); pr_info("%pOFP: mapped %d interrupts with %d handlers for" " %d contexts.\n", node, nr_irqs, nr_handlers, nr_contexts); return 0; +out_free_enable_reg: + for_each_cpu(cpu, cpu_present_mask) { + handler = per_cpu_ptr(&plic_handlers, cpu); + kfree(handler->enable_save); + } +out_free_priority_reg: + kfree(priv->prio_save); out_iounmap: iounmap(priv->regs); out_free_priv: diff --git a/drivers/irqchip/irq-st.c b/drivers/irqchip/irq-st.c index 1b83512b29c6..819a12297b58 100644 --- a/drivers/irqchip/irq-st.c +++ b/drivers/irqchip/irq-st.c @@ -15,10 +15,7 @@ #include <linux/regmap.h> #include <linux/slab.h> -#define STIH415_SYSCFG_642 0x0a8 -#define STIH416_SYSCFG_7543 0x87c #define STIH407_SYSCFG_5102 0x198 -#define STID127_SYSCFG_734 0x088 #define ST_A9_IRQ_MASK 0x001FFFFF #define ST_A9_IRQ_MAX_CHANS 2 @@ -45,21 +42,9 @@ struct st_irq_syscfg { static const struct of_device_id st_irq_syscfg_match[] = { { - .compatible = "st,stih415-irq-syscfg", - .data = (void *)STIH415_SYSCFG_642, - }, - { - .compatible = "st,stih416-irq-syscfg", - .data = (void *)STIH416_SYSCFG_7543, - }, - { .compatible = "st,stih407-irq-syscfg", .data = (void *)STIH407_SYSCFG_5102, }, - { - .compatible = "st,stid127-irq-syscfg", - .data = (void *)STID127_SYSCFG_734, - }, {} }; diff --git a/drivers/mailbox/mailbox-mpfs.c b/drivers/mailbox/mailbox-mpfs.c index 853901acaeec..162df49654fb 100644 --- a/drivers/mailbox/mailbox-mpfs.c +++ b/drivers/mailbox/mailbox-mpfs.c @@ -39,7 +39,7 @@ #define SCB_CTRL_NOTIFY_MASK BIT(SCB_CTRL_NOTIFY) #define SCB_CTRL_POS (16) -#define SCB_CTRL_MASK GENMASK_ULL(SCB_CTRL_POS + SCB_MASK_WIDTH, SCB_CTRL_POS) +#define SCB_CTRL_MASK GENMASK(SCB_CTRL_POS + SCB_MASK_WIDTH - 1, SCB_CTRL_POS) /* SCBCTRL service status register */ @@ -79,6 +79,27 @@ static bool mpfs_mbox_busy(struct mpfs_mbox *mbox) return status & SCB_STATUS_BUSY_MASK; } +static bool mpfs_mbox_last_tx_done(struct mbox_chan *chan) +{ + struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv; + struct mpfs_mss_response *response = mbox->response; + u32 val; + + if (mpfs_mbox_busy(mbox)) + return false; + + /* + * The service status is stored in bits 31:16 of the SERVICES_SR + * register & is only valid when the system controller is not busy. + * Failed services are intended to generated interrupts, but in reality + * this does not happen, so the status must be checked here. + */ + val = readl_relaxed(mbox->ctrl_base + SERVICES_SR_OFFSET); + response->resp_status = (val & SCB_STATUS_MASK) >> SCB_STATUS_POS; + + return true; +} + static int mpfs_mbox_send_data(struct mbox_chan *chan, void *data) { struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv; @@ -118,6 +139,7 @@ static int mpfs_mbox_send_data(struct mbox_chan *chan, void *data) } opt_sel = ((msg->mbox_offset << 7u) | (msg->cmd_opcode & 0x7fu)); + tx_trigger = (opt_sel << SCB_CTRL_POS) & SCB_CTRL_MASK; tx_trigger |= SCB_CTRL_REQ_MASK | SCB_STATUS_NOTIFY_MASK; writel_relaxed(tx_trigger, mbox->ctrl_base + SERVICES_CR_OFFSET); @@ -130,7 +152,7 @@ static void mpfs_mbox_rx_data(struct mbox_chan *chan) struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv; struct mpfs_mss_response *response = mbox->response; u16 num_words = ALIGN((response->resp_size), (4)) / 4U; - u32 i, status; + u32 i; if (!response->resp_msg) { dev_err(mbox->dev, "failed to assign memory for response %d\n", -ENOMEM); @@ -138,8 +160,6 @@ static void mpfs_mbox_rx_data(struct mbox_chan *chan) } /* - * The status is stored in bits 31:16 of the SERVICES_SR register. - * It is only valid when BUSY == 0. * We should *never* get an interrupt while the controller is * still in the busy state. If we do, something has gone badly * wrong & the content of the mailbox would not be valid. @@ -150,24 +170,10 @@ static void mpfs_mbox_rx_data(struct mbox_chan *chan) return; } - status = readl_relaxed(mbox->ctrl_base + SERVICES_SR_OFFSET); - - /* - * If the status of the individual servers is non-zero, the service has - * failed. The contents of the mailbox at this point are not be valid, - * so don't bother reading them. Set the status so that the driver - * implementing the service can handle the result. - */ - response->resp_status = (status & SCB_STATUS_MASK) >> SCB_STATUS_POS; - if (response->resp_status) - return; - - if (!mpfs_mbox_busy(mbox)) { - for (i = 0; i < num_words; i++) { - response->resp_msg[i] = - readl_relaxed(mbox->mbox_base - + mbox->resp_offset + i * 0x4); - } + for (i = 0; i < num_words; i++) { + response->resp_msg[i] = + readl_relaxed(mbox->mbox_base + + mbox->resp_offset + i * 0x4); } mbox_chan_received_data(chan, response); @@ -182,7 +188,6 @@ static irqreturn_t mpfs_mbox_inbox_isr(int irq, void *data) mpfs_mbox_rx_data(chan); - mbox_chan_txdone(chan, 0); return IRQ_HANDLED; } @@ -212,6 +217,7 @@ static const struct mbox_chan_ops mpfs_mbox_ops = { .send_data = mpfs_mbox_send_data, .startup = mpfs_mbox_startup, .shutdown = mpfs_mbox_shutdown, + .last_tx_done = mpfs_mbox_last_tx_done, }; static int mpfs_mbox_probe(struct platform_device *pdev) @@ -247,7 +253,8 @@ static int mpfs_mbox_probe(struct platform_device *pdev) mbox->controller.num_chans = 1; mbox->controller.chans = mbox->chans; mbox->controller.ops = &mpfs_mbox_ops; - mbox->controller.txdone_irq = true; + mbox->controller.txdone_poll = true; + mbox->controller.txpoll_period = 10u; ret = devm_mbox_controller_register(&pdev->dev, &mbox->controller); if (ret) { diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 2d0f934ba6e6..dfde0088147a 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1467,7 +1467,8 @@ static void setup_split_accounting(struct clone_info *ci, unsigned int len) } static void alloc_multiple_bios(struct bio_list *blist, struct clone_info *ci, - struct dm_target *ti, unsigned int num_bios) + struct dm_target *ti, unsigned int num_bios, + unsigned *len) { struct bio *bio; int try; @@ -1478,7 +1479,7 @@ static void alloc_multiple_bios(struct bio_list *blist, struct clone_info *ci, if (try) mutex_lock(&ci->io->md->table_devices_lock); for (bio_nr = 0; bio_nr < num_bios; bio_nr++) { - bio = alloc_tio(ci, ti, bio_nr, NULL, + bio = alloc_tio(ci, ti, bio_nr, len, try ? GFP_NOIO : GFP_NOWAIT); if (!bio) break; @@ -1513,8 +1514,10 @@ static int __send_duplicate_bios(struct clone_info *ci, struct dm_target *ti, ret = 1; break; default: + if (len) + setup_split_accounting(ci, *len); /* dm_accept_partial_bio() is not supported with shared tio->len_ptr */ - alloc_multiple_bios(&blist, ci, ti, num_bios); + alloc_multiple_bios(&blist, ci, ti, num_bios, len); while ((clone = bio_list_pop(&blist))) { dm_tio_set_flag(clone_to_tio(clone), DM_TIO_IS_DUPLICATE_BIO); __map_bio(clone); diff --git a/drivers/md/md.c b/drivers/md/md.c index 39e49e5d7182..13321dbb5fbc 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -6260,7 +6260,6 @@ static void __md_stop(struct mddev *mddev) module_put(pers->owner); clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); - percpu_ref_exit(&mddev->writes_pending); percpu_ref_exit(&mddev->active_io); bioset_exit(&mddev->bio_set); bioset_exit(&mddev->sync_set); @@ -6273,6 +6272,7 @@ void md_stop(struct mddev *mddev) */ __md_stop_writes(mddev); __md_stop(mddev); + percpu_ref_exit(&mddev->writes_pending); } EXPORT_SYMBOL_GPL(md_stop); @@ -7843,6 +7843,7 @@ static void md_free_disk(struct gendisk *disk) { struct mddev *mddev = disk->private_data; + percpu_ref_exit(&mddev->writes_pending); mddev_free(mddev); } diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 49d6c8bdec41..48ae2e0adf9e 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -1098,7 +1098,7 @@ static int imx290_runtime_suspend(struct device *dev) } static const struct dev_pm_ops imx290_pm_ops = { - SET_RUNTIME_PM_OPS(imx290_runtime_suspend, imx290_runtime_resume, NULL) + RUNTIME_PM_OPS(imx290_runtime_suspend, imx290_runtime_resume, NULL) }; /* ---------------------------------------------------------------------------- @@ -1362,8 +1362,8 @@ static struct i2c_driver imx290_i2c_driver = { .remove = imx290_remove, .driver = { .name = "imx290", - .pm = &imx290_pm_ops, - .of_match_table = of_match_ptr(imx290_of_match), + .pm = pm_ptr(&imx290_pm_ops), + .of_match_table = imx290_of_match, }, }; diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 61ff20a7e935..cfb11c551167 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -38,8 +38,8 @@ static void venus_reset_cpu(struct venus_core *core) writel(fw_size, wrapper_base + WRAPPER_FW_END_ADDR); writel(0, wrapper_base + WRAPPER_CPA_START_ADDR); writel(fw_size, wrapper_base + WRAPPER_CPA_END_ADDR); - writel(0, wrapper_base + WRAPPER_NONPIX_START_ADDR); - writel(0, wrapper_base + WRAPPER_NONPIX_END_ADDR); + writel(fw_size, wrapper_base + WRAPPER_NONPIX_START_ADDR); + writel(fw_size, wrapper_base + WRAPPER_NONPIX_END_ADDR); if (IS_V6(core)) { /* Bring XTSS out of reset */ diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index fac290e48e0b..91774e6ee624 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -228,7 +228,7 @@ config RENESAS_RPCIF config STM32_FMC2_EBI tristate "Support for FMC2 External Bus Interface on STM32MP SoCs" - depends on MACH_STM32MP157 || COMPILE_TEST + depends on ARCH_STM32 || COMPILE_TEST select MFD_SYSCON help Select this option to enable the STM32 FMC2 External Bus Interface diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c index e749dcb3ddea..635966d705cb 100644 --- a/drivers/memory/atmel-ebi.c +++ b/drivers/memory/atmel-ebi.c @@ -598,7 +598,7 @@ static int atmel_ebi_probe(struct platform_device *pdev) reg_cells += val; for_each_available_child_of_node(np, child) { - if (!of_find_property(child, "reg", NULL)) + if (!of_property_present(child, "reg")) continue; ret = atmel_ebi_dev_setup(ebi, child, reg_cells); diff --git a/drivers/memory/bt1-l2-ctl.c b/drivers/memory/bt1-l2-ctl.c index 85965fa26e0b..78bd71b203f2 100644 --- a/drivers/memory/bt1-l2-ctl.c +++ b/drivers/memory/bt1-l2-ctl.c @@ -321,4 +321,3 @@ module_platform_driver(l2_ctl_driver); MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>"); MODULE_DESCRIPTION("Baikal-T1 L2-cache driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/memory/da8xx-ddrctl.c b/drivers/memory/da8xx-ddrctl.c index b32005bf269c..0ef8cc878b95 100644 --- a/drivers/memory/da8xx-ddrctl.c +++ b/drivers/memory/da8xx-ddrctl.c @@ -164,4 +164,3 @@ module_platform_driver(da8xx_ddrctl_driver); MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>"); MODULE_DESCRIPTION("TI da8xx DDR2/mDDR controller driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c index e83b61c925a4..9e8d8e9c5ad8 100644 --- a/drivers/memory/fsl_ifc.c +++ b/drivers/memory/fsl_ifc.c @@ -327,6 +327,5 @@ static int __init fsl_ifc_init(void) } subsys_initcall(fsl_ifc_init); -MODULE_LICENSE("GPL"); MODULE_AUTHOR("Freescale Semiconductor"); MODULE_DESCRIPTION("Freescale Integrated Flash Controller driver"); diff --git a/drivers/memory/mtk-smi.c b/drivers/memory/mtk-smi.c index 5a9754442bc7..6523cb510518 100644 --- a/drivers/memory/mtk-smi.c +++ b/drivers/memory/mtk-smi.c @@ -713,6 +713,11 @@ static const struct mtk_smi_common_plat mtk_smi_sub_common_mt8195 = { .has_gals = true, }; +static const struct mtk_smi_common_plat mtk_smi_common_mt8365 = { + .type = MTK_SMI_GEN2, + .bus_sel = F_MMU1_LARB(2) | F_MMU1_LARB(4), +}; + static const struct of_device_id mtk_smi_common_of_ids[] = { {.compatible = "mediatek,mt2701-smi-common", .data = &mtk_smi_common_gen1}, {.compatible = "mediatek,mt2712-smi-common", .data = &mtk_smi_common_gen2}, @@ -728,6 +733,7 @@ static const struct of_device_id mtk_smi_common_of_ids[] = { {.compatible = "mediatek,mt8195-smi-common-vdo", .data = &mtk_smi_common_mt8195_vdo}, {.compatible = "mediatek,mt8195-smi-common-vpp", .data = &mtk_smi_common_mt8195_vpp}, {.compatible = "mediatek,mt8195-smi-sub-common", .data = &mtk_smi_sub_common_mt8195}, + {.compatible = "mediatek,mt8365-smi-common", .data = &mtk_smi_common_mt8365}, {} }; diff --git a/drivers/memory/mvebu-devbus.c b/drivers/memory/mvebu-devbus.c index efc6c08db2b7..406fddcdba02 100644 --- a/drivers/memory/mvebu-devbus.c +++ b/drivers/memory/mvebu-devbus.c @@ -341,6 +341,5 @@ static int __init mvebu_devbus_init(void) } module_init(mvebu_devbus_init); -MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@free-electrons.com>"); MODULE_DESCRIPTION("Marvell EBU SoC Device Bus controller"); diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 5cd28619ea9f..9082b6c3763d 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -983,4 +983,3 @@ arch_initcall(tegra_mc_init); MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); MODULE_DESCRIPTION("NVIDIA Tegra Memory Controller driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/tegra186-emc.c index 26e763bde92a..e935ad4e95b6 100644 --- a/drivers/memory/tegra/tegra186-emc.c +++ b/drivers/memory/tegra/tegra186-emc.c @@ -280,4 +280,3 @@ module_platform_driver(tegra186_emc_driver); MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); MODULE_DESCRIPTION("NVIDIA Tegra186 External Memory Controller driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/memory/tegra/tegra210-emc-cc-r21021.c b/drivers/memory/tegra/tegra210-emc-cc-r21021.c index cc76adb8d7e8..4cb608c71ead 100644 --- a/drivers/memory/tegra/tegra210-emc-cc-r21021.c +++ b/drivers/memory/tegra/tegra210-emc-cc-r21021.c @@ -277,7 +277,7 @@ static u32 update_clock_tree_delay(struct tegra210_emc *emc, int type) /* * Dev1 LSB. */ - value = tegra210_emc_mrr_read(emc, 2, 18); + value = tegra210_emc_mrr_read(emc, 1, 18); for (i = 0; i < emc->num_channels; i++) { temp[i][0] |= (value & 0x00ff) >> 0; diff --git a/drivers/memory/tegra/tegra210-emc-table.c b/drivers/memory/tegra/tegra210-emc-table.c index 3e0598363b87..34a8785d2861 100644 --- a/drivers/memory/tegra/tegra210-emc-table.c +++ b/drivers/memory/tegra/tegra210-emc-table.c @@ -22,8 +22,6 @@ static int tegra210_emc_table_device_init(struct reserved_mem *rmem, return -ENOMEM; } - count = 0; - for (i = 0; i < TEGRA_EMC_MAX_FREQS; i++) { if (timings[i].revision == 0) break; diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c index bf7667845459..bbfaf6536903 100644 --- a/drivers/memstick/core/memstick.c +++ b/drivers/memstick/core/memstick.c @@ -410,6 +410,7 @@ static struct memstick_dev *memstick_alloc_card(struct memstick_host *host) return card; err_out: host->card = old_card; + kfree_const(card->dev.kobj.name); kfree(card); return NULL; } @@ -468,8 +469,10 @@ static void memstick_check(struct work_struct *work) put_device(&card->dev); host->card = NULL; } - } else + } else { + kfree_const(card->dev.kobj.name); kfree(card); + } } out_power_off: diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index a701132638cf..f48466960f1b 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -262,7 +262,7 @@ struct fastrpc_channel_ctx { int domain_id; int sesscount; int vmcount; - u32 perms; + u64 perms; struct qcom_scm_vmperm vmperms[FASTRPC_MAX_VMIDS]; struct rpmsg_device *rpdev; struct fastrpc_session_ctx session[FASTRPC_MAX_SESSIONS]; diff --git a/drivers/misc/vmw_vmci/vmci_context.c b/drivers/misc/vmw_vmci/vmci_context.c index 172696abce31..f22b44827e92 100644 --- a/drivers/misc/vmw_vmci/vmci_context.c +++ b/drivers/misc/vmw_vmci/vmci_context.c @@ -687,7 +687,7 @@ int vmci_ctx_remove_notification(u32 context_id, u32 remote_cid) spin_unlock(&context->lock); if (notifier) - kvfree_rcu(notifier); + kvfree_rcu_mightsleep(notifier); vmci_ctx_put(context); diff --git a/drivers/misc/vmw_vmci/vmci_event.c b/drivers/misc/vmw_vmci/vmci_event.c index 2100297c94ad..5d7ac07623c2 100644 --- a/drivers/misc/vmw_vmci/vmci_event.c +++ b/drivers/misc/vmw_vmci/vmci_event.c @@ -209,7 +209,7 @@ int vmci_event_unsubscribe(u32 sub_id) if (!s) return VMCI_ERROR_NOT_FOUND; - kvfree_rcu(s); + kvfree_rcu_mightsleep(s); return VMCI_SUCCESS; } diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index 89953093e20c..672d37ea98d0 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -351,8 +351,6 @@ static void sdhci_am654_write_b(struct sdhci_host *host, u8 val, int reg) */ case MMC_TIMING_SD_HS: case MMC_TIMING_MMC_HS: - case MMC_TIMING_UHS_SDR12: - case MMC_TIMING_UHS_SDR25: val &= ~SDHCI_CTRL_HISPD; } } diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 1e94e7d10b8b..a0a1194dc1d9 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -153,7 +153,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, mtdblk->cache_state = STATE_EMPTY; ret = mtd_read(mtd, sect_start, sect_size, &retlen, mtdblk->cache_data); - if (ret) + if (ret && !mtd_is_bitflip(ret)) return ret; if (retlen != sect_size) return -EIO; @@ -188,8 +188,12 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, pr_debug("mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", mtd->name, pos, len); - if (!sect_size) - return mtd_read(mtd, pos, len, &retlen, buf); + if (!sect_size) { + ret = mtd_read(mtd, pos, len, &retlen, buf); + if (ret && !mtd_is_bitflip(ret)) + return ret; + return 0; + } while (len > 0) { unsigned long sect_start = (pos/sect_size)*sect_size; @@ -209,7 +213,7 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, memcpy (buf, mtdblk->cache_data + offset, size); } else { ret = mtd_read(mtd, pos, size, &retlen, buf); - if (ret) + if (ret && !mtd_is_bitflip(ret)) return ret; if (retlen != size) return -EIO; diff --git a/drivers/mtd/nand/ecc-mxic.c b/drivers/mtd/nand/ecc-mxic.c index 8afdca731b87..6b487ffe2f2d 100644 --- a/drivers/mtd/nand/ecc-mxic.c +++ b/drivers/mtd/nand/ecc-mxic.c @@ -429,6 +429,7 @@ static int mxic_ecc_data_xfer_wait_for_completion(struct mxic_ecc_engine *mxic) mxic_ecc_enable_int(mxic); ret = wait_for_completion_timeout(&mxic->complete, msecs_to_jiffies(1000)); + ret = ret ? 0 : -ETIMEDOUT; mxic_ecc_disable_int(mxic); } else { ret = readl_poll_timeout(mxic->regs + INTRPT_STS, val, diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index 5ee01231ac4c..074e14225c06 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -176,6 +176,7 @@ struct meson_nfc { dma_addr_t daddr; dma_addr_t iaddr; + u32 info_bytes; unsigned long assigned_cs; }; @@ -279,7 +280,7 @@ static void meson_nfc_cmd_access(struct nand_chip *nand, int raw, bool dir, if (raw) { len = mtd->writesize + mtd->oobsize; - cmd = (len & GENMASK(5, 0)) | scrambler | DMA_DIR(dir); + cmd = (len & GENMASK(13, 0)) | scrambler | DMA_DIR(dir); writel(cmd, nfc->reg_base + NFC_REG_CMD); return; } @@ -503,6 +504,7 @@ static int meson_nfc_dma_buffer_setup(struct nand_chip *nand, void *databuf, nfc->daddr, datalen, dir); return ret; } + nfc->info_bytes = infolen; cmd = GENCMDIADDRL(NFC_CMD_AIL, nfc->iaddr); writel(cmd, nfc->reg_base + NFC_REG_CMD); @@ -520,8 +522,10 @@ static void meson_nfc_dma_buffer_release(struct nand_chip *nand, struct meson_nfc *nfc = nand_get_controller_data(nand); dma_unmap_single(nfc->dev, nfc->daddr, datalen, dir); - if (infolen) + if (infolen) { dma_unmap_single(nfc->dev, nfc->iaddr, infolen, dir); + nfc->info_bytes = 0; + } } static int meson_nfc_read_buf(struct nand_chip *nand, u8 *buf, int len) @@ -540,7 +544,7 @@ static int meson_nfc_read_buf(struct nand_chip *nand, u8 *buf, int len) if (ret) goto out; - cmd = NFC_CMD_N2M | (len & GENMASK(5, 0)); + cmd = NFC_CMD_N2M | (len & GENMASK(13, 0)); writel(cmd, nfc->reg_base + NFC_REG_CMD); meson_nfc_drain_cmd(nfc); @@ -564,7 +568,7 @@ static int meson_nfc_write_buf(struct nand_chip *nand, u8 *buf, int len) if (ret) return ret; - cmd = NFC_CMD_M2N | (len & GENMASK(5, 0)); + cmd = NFC_CMD_M2N | (len & GENMASK(13, 0)); writel(cmd, nfc->reg_base + NFC_REG_CMD); meson_nfc_drain_cmd(nfc); @@ -710,6 +714,8 @@ static void meson_nfc_check_ecc_pages_valid(struct meson_nfc *nfc, usleep_range(10, 15); /* info is updated by nfc dma engine*/ smp_rmb(); + dma_sync_single_for_cpu(nfc->dev, nfc->iaddr, nfc->info_bytes, + DMA_FROM_DEVICE); ret = *info & ECC_COMPLETE; } while (!ret); } @@ -991,7 +997,7 @@ static const struct mtd_ooblayout_ops meson_ooblayout_ops = { static int meson_nfc_clk_init(struct meson_nfc *nfc) { - struct clk_parent_data nfc_divider_parent_data[1]; + struct clk_parent_data nfc_divider_parent_data[1] = {0}; struct clk_init_data init = {0}; int ret; diff --git a/drivers/mtd/nand/raw/nandsim.c b/drivers/mtd/nand/raw/nandsim.c index c21abf748948..179b28459b4b 100644 --- a/drivers/mtd/nand/raw/nandsim.c +++ b/drivers/mtd/nand/raw/nandsim.c @@ -2160,8 +2160,23 @@ static int ns_exec_op(struct nand_chip *chip, const struct nand_operation *op, const struct nand_op_instr *instr = NULL; struct nandsim *ns = nand_get_controller_data(chip); - if (check_only) + if (check_only) { + /* The current implementation of nandsim needs to know the + * ongoing operation when performing the address cycles. This + * means it cannot make the difference between a regular read + * and a continuous read. Hence, this hack to manually refuse + * supporting sequential cached operations. + */ + for (op_id = 0; op_id < op->ninstrs; op_id++) { + instr = &op->instrs[op_id]; + if (instr->type == NAND_OP_CMD_INSTR && + (instr->ctx.cmd.opcode == NAND_CMD_READCACHEEND || + instr->ctx.cmd.opcode == NAND_CMD_READCACHESEQ)) + return -EOPNOTSUPP; + } + return 0; + } ns->lines.ce = 1; diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index 5d627048c420..9e74bcd90aaa 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -1531,6 +1531,9 @@ static int stm32_fmc2_nfc_setup_interface(struct nand_chip *chip, int chipnr, if (IS_ERR(sdrt)) return PTR_ERR(sdrt); + if (conf->timings.mode > 3) + return -EOPNOTSUPP; + if (chipnr == NAND_DATA_IFACE_CHECK_ONLY) return 0; diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 0a78045ca1d9..522d375aeccf 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -3343,7 +3343,19 @@ static struct spi_mem_driver spi_nor_driver = { .remove = spi_nor_remove, .shutdown = spi_nor_shutdown, }; -module_spi_mem_driver(spi_nor_driver); + +static int __init spi_nor_module_init(void) +{ + return spi_mem_driver_register(&spi_nor_driver); +} +module_init(spi_nor_module_init); + +static void __exit spi_nor_module_exit(void) +{ + spi_mem_driver_unregister(&spi_nor_driver); + spi_nor_debugfs_shutdown(); +} +module_exit(spi_nor_module_exit); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Huang Shijie <shijie8@gmail.com>"); diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 25423225c29d..e0cc42a4a0c8 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -711,8 +711,10 @@ static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd) #ifdef CONFIG_DEBUG_FS void spi_nor_debugfs_register(struct spi_nor *nor); +void spi_nor_debugfs_shutdown(void); #else static inline void spi_nor_debugfs_register(struct spi_nor *nor) {} +static inline void spi_nor_debugfs_shutdown(void) {} #endif #endif /* __LINUX_MTD_SPI_NOR_INTERNAL_H */ diff --git a/drivers/mtd/spi-nor/debugfs.c b/drivers/mtd/spi-nor/debugfs.c index 845b78c7ecc7..fc7ad203df12 100644 --- a/drivers/mtd/spi-nor/debugfs.c +++ b/drivers/mtd/spi-nor/debugfs.c @@ -226,13 +226,13 @@ static void spi_nor_debugfs_unregister(void *data) nor->debugfs_root = NULL; } +static struct dentry *rootdir; + void spi_nor_debugfs_register(struct spi_nor *nor) { - struct dentry *rootdir, *d; + struct dentry *d; int ret; - /* Create rootdir once. Will never be deleted again. */ - rootdir = debugfs_lookup(SPI_NOR_DEBUGFS_ROOT, NULL); if (!rootdir) rootdir = debugfs_create_dir(SPI_NOR_DEBUGFS_ROOT, NULL); @@ -247,3 +247,8 @@ void spi_nor_debugfs_register(struct spi_nor *nor) debugfs_create_file("capabilities", 0444, d, nor, &spi_nor_capabilities_fops); } + +void spi_nor_debugfs_shutdown(void) +{ + debugfs_remove(rootdir); +} diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 0904eb40c95f..ad025b2ee417 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -666,12 +666,6 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) ubi->ec_hdr_alsize = ALIGN(UBI_EC_HDR_SIZE, ubi->hdrs_min_io_size); ubi->vid_hdr_alsize = ALIGN(UBI_VID_HDR_SIZE, ubi->hdrs_min_io_size); - if (ubi->vid_hdr_offset && ((ubi->vid_hdr_offset + UBI_VID_HDR_SIZE) > - ubi->vid_hdr_alsize)) { - ubi_err(ubi, "VID header offset %d too large.", ubi->vid_hdr_offset); - return -EINVAL; - } - dbg_gen("min_io_size %d", ubi->min_io_size); dbg_gen("max_write_size %d", ubi->max_write_size); dbg_gen("hdrs_min_io_size %d", ubi->hdrs_min_io_size); @@ -689,6 +683,21 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) ubi->vid_hdr_aloffset; } + /* + * Memory allocation for VID header is ubi->vid_hdr_alsize + * which is described in comments in io.c. + * Make sure VID header shift + UBI_VID_HDR_SIZE not exceeds + * ubi->vid_hdr_alsize, so that all vid header operations + * won't access memory out of bounds. + */ + if ((ubi->vid_hdr_shift + UBI_VID_HDR_SIZE) > ubi->vid_hdr_alsize) { + ubi_err(ubi, "Invalid VID header offset %d, VID header shift(%d)" + " + VID header size(%zu) > VID header aligned size(%d).", + ubi->vid_hdr_offset, ubi->vid_hdr_shift, + UBI_VID_HDR_SIZE, ubi->vid_hdr_alsize); + return -EINVAL; + } + /* Similar for the data offset */ ubi->leb_start = ubi->vid_hdr_offset + UBI_VID_HDR_SIZE; ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size); diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 40f39e5d6dfc..26a214f016c1 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -575,7 +575,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, * @vol_id: the volume ID that last used this PEB * @lnum: the last used logical eraseblock number for the PEB * @torture: if the physical eraseblock has to be tortured - * @nested: denotes whether the work_sem is already held in read mode + * @nested: denotes whether the work_sem is already held * * This function returns zero in case of success and a %-ENOMEM in case of * failure. @@ -1131,7 +1131,7 @@ static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk) int err1; /* Re-schedule the LEB for erasure */ - err1 = schedule_erase(ubi, e, vol_id, lnum, 0, false); + err1 = schedule_erase(ubi, e, vol_id, lnum, 0, true); if (err1) { spin_lock(&ubi->wl_lock); wl_entry_destroy(ubi, e); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 236e5219c811..7a7d584f378a 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1777,14 +1777,15 @@ void bond_lower_state_changed(struct slave *slave) /* The bonding driver uses ether_setup() to convert a master bond device * to ARPHRD_ETHER, that resets the target netdevice's flags so we always - * have to restore the IFF_MASTER flag, and only restore IFF_SLAVE if it was set + * have to restore the IFF_MASTER flag, and only restore IFF_SLAVE and IFF_UP + * if they were set */ static void bond_ether_setup(struct net_device *bond_dev) { - unsigned int slave_flag = bond_dev->flags & IFF_SLAVE; + unsigned int flags = bond_dev->flags & (IFF_SLAVE | IFF_UP); ether_setup(bond_dev); - bond_dev->flags |= IFF_MASTER | slave_flag; + bond_dev->flags |= IFF_MASTER | flags; bond_dev->priv_flags &= ~IFF_TX_SKB_SHARING; } @@ -3269,7 +3270,8 @@ static int bond_na_rcv(const struct sk_buff *skb, struct bonding *bond, combined = skb_header_pointer(skb, 0, sizeof(_combined), &_combined); if (!combined || combined->ip6.nexthdr != NEXTHDR_ICMP || - combined->icmp6.icmp6_type != NDISC_NEIGHBOUR_ADVERTISEMENT) + (combined->icmp6.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION && + combined->icmp6.icmp6_type != NDISC_NEIGHBOUR_ADVERTISEMENT)) goto out; saddr = &combined->ip6.saddr; @@ -3291,7 +3293,7 @@ static int bond_na_rcv(const struct sk_buff *skb, struct bonding *bond, else if (curr_active_slave && time_after(slave_last_rx(bond, curr_active_slave), curr_active_slave->last_link_up)) - bond_validate_na(bond, slave, saddr, daddr); + bond_validate_na(bond, slave, daddr, saddr); else if (curr_arp_slave && bond_time_in_interval(bond, slave_last_tx(curr_arp_slave), 1)) bond_validate_na(bond, slave, saddr, daddr); diff --git a/drivers/net/dsa/b53/b53_mmap.c b/drivers/net/dsa/b53/b53_mmap.c index 70887e0aece3..d9434ed9450d 100644 --- a/drivers/net/dsa/b53/b53_mmap.c +++ b/drivers/net/dsa/b53/b53_mmap.c @@ -216,6 +216,18 @@ static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg, return 0; } +static int b53_mmap_phy_read16(struct b53_device *dev, int addr, int reg, + u16 *value) +{ + return -EIO; +} + +static int b53_mmap_phy_write16(struct b53_device *dev, int addr, int reg, + u16 value) +{ + return -EIO; +} + static const struct b53_io_ops b53_mmap_ops = { .read8 = b53_mmap_read8, .read16 = b53_mmap_read16, @@ -227,6 +239,8 @@ static const struct b53_io_ops b53_mmap_ops = { .write32 = b53_mmap_write32, .write48 = b53_mmap_write48, .write64 = b53_mmap_write64, + .phy_read16 = b53_mmap_phy_read16, + .phy_write16 = b53_mmap_phy_write16, }; static int b53_mmap_probe_of(struct platform_device *pdev, diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index 003b0ac2854c..ffcad057d065 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -96,7 +96,7 @@ static int ksz8795_change_mtu(struct ksz_device *dev, int frame_size) if (frame_size > KSZ8_LEGAL_PACKET_SIZE) ctrl2 |= SW_LEGAL_PACKET_DISABLE; - else if (frame_size > KSZ8863_NORMAL_PACKET_SIZE) + if (frame_size > KSZ8863_NORMAL_PACKET_SIZE) ctrl1 |= SW_HUGE_PACKET; ret = ksz_rmw8(dev, REG_SW_CTRL_1, SW_HUGE_PACKET, ctrl1); @@ -958,15 +958,14 @@ int ksz8_fdb_dump(struct ksz_device *dev, int port, u16 entries = 0; u8 timestamp = 0; u8 fid; - u8 member; - struct alu_struct alu; + u8 src_port; + u8 mac[ETH_ALEN]; do { - alu.is_static = false; - ret = ksz8_r_dyn_mac_table(dev, i, alu.mac, &fid, &member, + ret = ksz8_r_dyn_mac_table(dev, i, mac, &fid, &src_port, ×tamp, &entries); - if (!ret && (member & BIT(port))) { - ret = cb(alu.mac, alu.fid, alu.is_static, data); + if (!ret && port == src_port) { + ret = cb(mac, fid, false, data); if (ret) break; } diff --git a/drivers/net/dsa/microchip/ksz8863_smi.c b/drivers/net/dsa/microchip/ksz8863_smi.c index 2f4623f3bd85..3698112138b7 100644 --- a/drivers/net/dsa/microchip/ksz8863_smi.c +++ b/drivers/net/dsa/microchip/ksz8863_smi.c @@ -82,22 +82,16 @@ static const struct regmap_bus regmap_smi[] = { { .read = ksz8863_mdio_read, .write = ksz8863_mdio_write, - .max_raw_read = 1, - .max_raw_write = 1, }, { .read = ksz8863_mdio_read, .write = ksz8863_mdio_write, .val_format_endian_default = REGMAP_ENDIAN_BIG, - .max_raw_read = 2, - .max_raw_write = 2, }, { .read = ksz8863_mdio_read, .write = ksz8863_mdio_write, .val_format_endian_default = REGMAP_ENDIAN_BIG, - .max_raw_read = 4, - .max_raw_write = 4, } }; @@ -108,7 +102,6 @@ static const struct regmap_config ksz8863_regmap_config[] = { .pad_bits = 24, .val_bits = 8, .cache_type = REGCACHE_NONE, - .use_single_read = 1, .lock = ksz_regmap_lock, .unlock = ksz_regmap_unlock, }, @@ -118,7 +111,6 @@ static const struct regmap_config ksz8863_regmap_config[] = { .pad_bits = 24, .val_bits = 16, .cache_type = REGCACHE_NONE, - .use_single_read = 1, .lock = ksz_regmap_lock, .unlock = ksz_regmap_unlock, }, @@ -128,7 +120,6 @@ static const struct regmap_config ksz8863_regmap_config[] = { .pad_bits = 24, .val_bits = 32, .cache_type = REGCACHE_NONE, - .use_single_read = 1, .lock = ksz_regmap_lock, .unlock = ksz_regmap_unlock, } diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 7fc2155d93d6..74c56d05ab0b 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -404,13 +404,13 @@ static const u32 ksz8863_masks[] = { [VLAN_TABLE_VALID] = BIT(19), [STATIC_MAC_TABLE_VALID] = BIT(19), [STATIC_MAC_TABLE_USE_FID] = BIT(21), - [STATIC_MAC_TABLE_FID] = GENMASK(29, 26), + [STATIC_MAC_TABLE_FID] = GENMASK(25, 22), [STATIC_MAC_TABLE_OVERRIDE] = BIT(20), [STATIC_MAC_TABLE_FWD_PORTS] = GENMASK(18, 16), - [DYNAMIC_MAC_TABLE_ENTRIES_H] = GENMASK(5, 0), - [DYNAMIC_MAC_TABLE_MAC_EMPTY] = BIT(7), + [DYNAMIC_MAC_TABLE_ENTRIES_H] = GENMASK(1, 0), + [DYNAMIC_MAC_TABLE_MAC_EMPTY] = BIT(2), [DYNAMIC_MAC_TABLE_NOT_READY] = BIT(7), - [DYNAMIC_MAC_TABLE_ENTRIES] = GENMASK(31, 28), + [DYNAMIC_MAC_TABLE_ENTRIES] = GENMASK(31, 24), [DYNAMIC_MAC_TABLE_FID] = GENMASK(19, 16), [DYNAMIC_MAC_TABLE_SRC_PORT] = GENMASK(21, 20), [DYNAMIC_MAC_TABLE_TIMESTAMP] = GENMASK(23, 22), @@ -420,10 +420,10 @@ static u8 ksz8863_shifts[] = { [VLAN_TABLE_MEMBERSHIP_S] = 16, [STATIC_MAC_FWD_PORTS] = 16, [STATIC_MAC_FID] = 22, - [DYNAMIC_MAC_ENTRIES_H] = 3, + [DYNAMIC_MAC_ENTRIES_H] = 8, [DYNAMIC_MAC_ENTRIES] = 24, [DYNAMIC_MAC_FID] = 16, - [DYNAMIC_MAC_TIMESTAMP] = 24, + [DYNAMIC_MAC_TIMESTAMP] = 22, [DYNAMIC_MAC_SRC_PORT] = 20, }; diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 30383c4f8fd0..7108f745fbf0 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3354,9 +3354,14 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) * If this is the upstream port for this switch, enable * forwarding of unknown unicasts and multicasts. */ - reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP | - MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP | + reg = MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP | MV88E6XXX_PORT_CTL0_STATE_FORWARDING; + /* Forward any IPv4 IGMP or IPv6 MLD frames received + * by a USER port to the CPU port to allow snooping. + */ + if (dsa_is_user_port(ds, port)) + reg |= MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP; + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); if (err) return err; @@ -5596,7 +5601,7 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = { * .port_set_upstream_port method. */ .set_egress_port = mv88e6393x_set_egress_port, - .watchdog_ops = &mv88e6390_watchdog_ops, + .watchdog_ops = &mv88e6393x_watchdog_ops, .mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index ed3b2f88e783..a7af3cebae97 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -943,6 +943,26 @@ const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = { .irq_free = mv88e6390_watchdog_free, }; +static int mv88e6393x_watchdog_action(struct mv88e6xxx_chip *chip, int irq) +{ + mv88e6390_watchdog_action(chip, irq); + + /* Fix for clearing the force WD event bit. + * Unreleased erratum on mv88e6393x. + */ + mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL, + MV88E6390_G2_WDOG_CTL_UPDATE | + MV88E6390_G2_WDOG_CTL_PTR_EVENT); + + return IRQ_HANDLED; +} + +const struct mv88e6xxx_irq_ops mv88e6393x_watchdog_ops = { + .irq_action = mv88e6393x_watchdog_action, + .irq_setup = mv88e6390_watchdog_setup, + .irq_free = mv88e6390_watchdog_free, +}; + static irqreturn_t mv88e6xxx_g2_watchdog_thread_fn(int irq, void *dev_id) { struct mv88e6xxx_chip *chip = dev_id; diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index e973114d6890..7e091965582b 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -369,6 +369,7 @@ int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, int target, extern const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops; extern const struct mv88e6xxx_irq_ops mv88e6250_watchdog_ops; extern const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops; +extern const struct mv88e6xxx_irq_ops mv88e6393x_watchdog_ops; extern const struct mv88e6xxx_avb_ops mv88e6165_avb_ops; extern const struct mv88e6xxx_avb_ops mv88e6352_avb_ops; diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realtek/realtek-mdio.c index 3e54fac5f902..5a8fe707ca25 100644 --- a/drivers/net/dsa/realtek/realtek-mdio.c +++ b/drivers/net/dsa/realtek/realtek-mdio.c @@ -21,6 +21,7 @@ #include <linux/module.h> #include <linux/of_device.h> +#include <linux/overflow.h> #include <linux/regmap.h> #include "realtek.h" @@ -152,7 +153,9 @@ static int realtek_mdio_probe(struct mdio_device *mdiodev) if (!var) return -EINVAL; - priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(&mdiodev->dev, + size_add(sizeof(*priv), var->chip_data_sz), + GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 16c490692f42..12083b9679b5 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -672,6 +672,18 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp, return 0; } +static struct sk_buff * +bnx2x_build_skb(const struct bnx2x_fastpath *fp, void *data) +{ + struct sk_buff *skb; + + if (fp->rx_frag_size) + skb = build_skb(data, fp->rx_frag_size); + else + skb = slab_build_skb(data); + return skb; +} + static void bnx2x_frag_free(const struct bnx2x_fastpath *fp, void *data) { if (fp->rx_frag_size) @@ -779,7 +791,7 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp, dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping), fp->rx_buf_size, DMA_FROM_DEVICE); if (likely(new_data)) - skb = build_skb(data, fp->rx_frag_size); + skb = bnx2x_build_skb(fp, data); if (likely(skb)) { #ifdef BNX2X_STOP_ON_ERROR @@ -1046,7 +1058,7 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) dma_unmap_addr(rx_buf, mapping), fp->rx_buf_size, DMA_FROM_DEVICE); - skb = build_skb(data, fp->rx_frag_size); + skb = bnx2x_build_skb(fp, data); if (unlikely(!skb)) { bnx2x_frag_free(fp, data); bnx2x_fp_qstats(bp, fp)-> diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index e2e2c986c82b..651b79ce5d80 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -175,12 +175,12 @@ static const struct pci_device_id bnxt_pci_tbl[] = { { PCI_VDEVICE(BROADCOM, 0x1750), .driver_data = BCM57508 }, { PCI_VDEVICE(BROADCOM, 0x1751), .driver_data = BCM57504 }, { PCI_VDEVICE(BROADCOM, 0x1752), .driver_data = BCM57502 }, - { PCI_VDEVICE(BROADCOM, 0x1800), .driver_data = BCM57508_NPAR }, + { PCI_VDEVICE(BROADCOM, 0x1800), .driver_data = BCM57502_NPAR }, { PCI_VDEVICE(BROADCOM, 0x1801), .driver_data = BCM57504_NPAR }, - { PCI_VDEVICE(BROADCOM, 0x1802), .driver_data = BCM57502_NPAR }, - { PCI_VDEVICE(BROADCOM, 0x1803), .driver_data = BCM57508_NPAR }, + { PCI_VDEVICE(BROADCOM, 0x1802), .driver_data = BCM57508_NPAR }, + { PCI_VDEVICE(BROADCOM, 0x1803), .driver_data = BCM57502_NPAR }, { PCI_VDEVICE(BROADCOM, 0x1804), .driver_data = BCM57504_NPAR }, - { PCI_VDEVICE(BROADCOM, 0x1805), .driver_data = BCM57502_NPAR }, + { PCI_VDEVICE(BROADCOM, 0x1805), .driver_data = BCM57508_NPAR }, { PCI_VDEVICE(BROADCOM, 0xd802), .driver_data = BCM58802 }, { PCI_VDEVICE(BROADCOM, 0xd804), .driver_data = BCM58804 }, #ifdef CONFIG_BNXT_SRIOV @@ -2388,7 +2388,7 @@ static int bnxt_async_event_process(struct bnxt *bp, case ASYNC_EVENT_CMPL_EVENT_ID_PHC_UPDATE: { switch (BNXT_EVENT_PHC_EVENT_TYPE(data1)) { case ASYNC_EVENT_CMPL_PHC_UPDATE_EVENT_DATA1_FLAGS_PHC_RTC_UPDATE: - if (bp->fw_cap & BNXT_FW_CAP_PTP_RTC) { + if (BNXT_PTP_USE_RTC(bp)) { struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; u64 ns; @@ -7627,7 +7627,7 @@ static int __bnxt_hwrm_ptp_qcfg(struct bnxt *bp) u8 flags; int rc; - if (bp->hwrm_spec_code < 0x10801) { + if (bp->hwrm_spec_code < 0x10801 || !BNXT_CHIP_P5_THOR(bp)) { rc = -ENODEV; goto no_ptp; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index c0628ac1b798..5928430f6f51 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1226,6 +1226,7 @@ struct bnxt_link_info { #define BNXT_LINK_SPEED_40GB PORT_PHY_QCFG_RESP_LINK_SPEED_40GB #define BNXT_LINK_SPEED_50GB PORT_PHY_QCFG_RESP_LINK_SPEED_50GB #define BNXT_LINK_SPEED_100GB PORT_PHY_QCFG_RESP_LINK_SPEED_100GB +#define BNXT_LINK_SPEED_200GB PORT_PHY_QCFG_RESP_LINK_SPEED_200GB u16 support_speeds; u16 support_pam4_speeds; u16 auto_link_speeds; /* fw adv setting */ diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index ec573127b707..6bd18eb5137f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1714,6 +1714,8 @@ u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed) return SPEED_50000; case BNXT_LINK_SPEED_100GB: return SPEED_100000; + case BNXT_LINK_SPEED_200GB: + return SPEED_200000; default: return SPEED_UNKNOWN; } @@ -3738,6 +3740,7 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, bnxt_ulp_stop(bp); rc = bnxt_close_nic(bp, true, false); if (rc) { + etest->flags |= ETH_TEST_FL_FAILED; bnxt_ulp_start(bp, rc); return; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c index e7b5e28ee29f..852eb449ccae 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c @@ -304,7 +304,7 @@ void bnxt_rdma_aux_device_uninit(struct bnxt *bp) struct auxiliary_device *adev; /* Skip if no auxiliary device init was done. */ - if (!(bp->flags & BNXT_FLAG_ROCE_CAP)) + if (!bp->aux_priv) return; aux_priv = bp->aux_priv; @@ -324,6 +324,7 @@ static void bnxt_aux_dev_release(struct device *dev) bp->edev = NULL; kfree(aux_priv->edev); kfree(aux_priv); + bp->aux_priv = NULL; } static void bnxt_set_edev_info(struct bnxt_en_dev *edev, struct bnxt *bp) @@ -359,19 +360,18 @@ void bnxt_rdma_aux_device_init(struct bnxt *bp) if (!(bp->flags & BNXT_FLAG_ROCE_CAP)) return; - bp->aux_priv = kzalloc(sizeof(*bp->aux_priv), GFP_KERNEL); - if (!bp->aux_priv) + aux_priv = kzalloc(sizeof(*bp->aux_priv), GFP_KERNEL); + if (!aux_priv) goto exit; - bp->aux_priv->id = ida_alloc(&bnxt_aux_dev_ids, GFP_KERNEL); - if (bp->aux_priv->id < 0) { + aux_priv->id = ida_alloc(&bnxt_aux_dev_ids, GFP_KERNEL); + if (aux_priv->id < 0) { netdev_warn(bp->dev, "ida alloc failed for ROCE auxiliary device\n"); - kfree(bp->aux_priv); + kfree(aux_priv); goto exit; } - aux_priv = bp->aux_priv; aux_dev = &aux_priv->aux_dev; aux_dev->id = aux_priv->id; aux_dev->name = "rdma"; @@ -380,10 +380,11 @@ void bnxt_rdma_aux_device_init(struct bnxt *bp) rc = auxiliary_device_init(aux_dev); if (rc) { - ida_free(&bnxt_aux_dev_ids, bp->aux_priv->id); - kfree(bp->aux_priv); + ida_free(&bnxt_aux_dev_ids, aux_priv->id); + kfree(aux_priv); goto exit; } + bp->aux_priv = aux_priv; /* From this point, all cleanup will happen via the .release callback & * any error unwinding will need to include a call to diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 66e30561569e..e43d99ec50ba 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -1064,6 +1064,10 @@ static dma_addr_t macb_get_addr(struct macb *bp, struct macb_dma_desc *desc) } #endif addr |= MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr)); +#ifdef CONFIG_MACB_USE_HWSTAMP + if (bp->hw_dma_cap & HW_DMA_CAP_PTP) + addr &= ~GEM_BIT(DMA_RXVALID); +#endif return addr; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c index dd9be229819a..d3541159487d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c @@ -1135,7 +1135,7 @@ void cxgb4_cleanup_tc_flower(struct adapter *adap) return; if (adap->flower_stats_timer.function) - del_timer_sync(&adap->flower_stats_timer); + timer_shutdown_sync(&adap->flower_stats_timer); cancel_work_sync(&adap->flower_stats_work); rhashtable_destroy(&adap->flower_tbl); adap->tc_flower_initialized = false; diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c index da9d4b310fcd..838750a03cf6 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c @@ -989,6 +989,20 @@ static int enetc_get_mm(struct net_device *ndev, struct ethtool_mm_state *state) return 0; } +/* FIXME: Workaround for the link partner's verification failing if ENETC + * priorly received too much express traffic. The documentation doesn't + * suggest this is needed. + */ +static void enetc_restart_emac_rx(struct enetc_si *si) +{ + u32 val = enetc_port_rd(&si->hw, ENETC_PM0_CMD_CFG); + + enetc_port_wr(&si->hw, ENETC_PM0_CMD_CFG, val & ~ENETC_PM0_RX_EN); + + if (val & ENETC_PM0_RX_EN) + enetc_port_wr(&si->hw, ENETC_PM0_CMD_CFG, val); +} + static int enetc_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg, struct netlink_ext_ack *extack) { @@ -1040,6 +1054,8 @@ static int enetc_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg, enetc_port_wr(hw, ENETC_MMCSR, val); + enetc_restart_emac_rx(priv->si); + mutex_unlock(&priv->mm_lock); return 0; diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 5ba1e0d71c68..9939ccafb556 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -507,6 +507,11 @@ struct bufdesc_ex { /* i.MX6Q adds pm_qos support */ #define FEC_QUIRK_HAS_PMQOS BIT(23) +/* Not all FEC hardware block MDIOs support accesses in C45 mode. + * Older blocks in the ColdFire parts do not support it. + */ +#define FEC_QUIRK_HAS_MDIO_C45 BIT(24) + struct bufdesc_prop { int qid; /* Address of Rx and Tx buffers */ diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index f3b16a6673e2..160c1b3525f5 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -100,18 +100,19 @@ struct fec_devinfo { static const struct fec_devinfo fec_imx25_info = { .quirks = FEC_QUIRK_USE_GASKET | FEC_QUIRK_MIB_CLEAR | - FEC_QUIRK_HAS_FRREG, + FEC_QUIRK_HAS_FRREG | FEC_QUIRK_HAS_MDIO_C45, }; static const struct fec_devinfo fec_imx27_info = { - .quirks = FEC_QUIRK_MIB_CLEAR | FEC_QUIRK_HAS_FRREG, + .quirks = FEC_QUIRK_MIB_CLEAR | FEC_QUIRK_HAS_FRREG | + FEC_QUIRK_HAS_MDIO_C45, }; static const struct fec_devinfo fec_imx28_info = { .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME | FEC_QUIRK_SINGLE_MDIO | FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_FRREG | FEC_QUIRK_CLEAR_SETUP_MII | - FEC_QUIRK_NO_HARD_RESET, + FEC_QUIRK_NO_HARD_RESET | FEC_QUIRK_HAS_MDIO_C45, }; static const struct fec_devinfo fec_imx6q_info = { @@ -119,11 +120,12 @@ static const struct fec_devinfo fec_imx6q_info = { FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 | FEC_QUIRK_HAS_RACC | FEC_QUIRK_CLEAR_SETUP_MII | - FEC_QUIRK_HAS_PMQOS, + FEC_QUIRK_HAS_PMQOS | FEC_QUIRK_HAS_MDIO_C45, }; static const struct fec_devinfo fec_mvf600_info = { - .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_RACC, + .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_RACC | + FEC_QUIRK_HAS_MDIO_C45, }; static const struct fec_devinfo fec_imx6x_info = { @@ -132,7 +134,8 @@ static const struct fec_devinfo fec_imx6x_info = { FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB | FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE | FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE | - FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES, + FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES | + FEC_QUIRK_HAS_MDIO_C45, }; static const struct fec_devinfo fec_imx6ul_info = { @@ -140,7 +143,8 @@ static const struct fec_devinfo fec_imx6ul_info = { FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE | FEC_QUIRK_HAS_RACC | - FEC_QUIRK_HAS_COALESCE | FEC_QUIRK_CLEAR_SETUP_MII, + FEC_QUIRK_HAS_COALESCE | FEC_QUIRK_CLEAR_SETUP_MII | + FEC_QUIRK_HAS_MDIO_C45, }; static const struct fec_devinfo fec_imx8mq_info = { @@ -150,7 +154,8 @@ static const struct fec_devinfo fec_imx8mq_info = { FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE | FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE | FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES | - FEC_QUIRK_HAS_EEE | FEC_QUIRK_WAKEUP_FROM_INT2, + FEC_QUIRK_HAS_EEE | FEC_QUIRK_WAKEUP_FROM_INT2 | + FEC_QUIRK_HAS_MDIO_C45, }; static const struct fec_devinfo fec_imx8qm_info = { @@ -160,14 +165,15 @@ static const struct fec_devinfo fec_imx8qm_info = { FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE | FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE | FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES | - FEC_QUIRK_DELAYED_CLKS_SUPPORT, + FEC_QUIRK_DELAYED_CLKS_SUPPORT | FEC_QUIRK_HAS_MDIO_C45, }; static const struct fec_devinfo fec_s32v234_info = { .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB | - FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE, + FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE | + FEC_QUIRK_HAS_MDIO_C45, }; static struct platform_device_id fec_devtype[] = { @@ -2434,8 +2440,10 @@ static int fec_enet_mii_init(struct platform_device *pdev) fep->mii_bus->name = "fec_enet_mii_bus"; fep->mii_bus->read = fec_enet_mdio_read_c22; fep->mii_bus->write = fec_enet_mdio_write_c22; - fep->mii_bus->read_c45 = fec_enet_mdio_read_c45; - fep->mii_bus->write_c45 = fec_enet_mdio_write_c45; + if (fep->quirks & FEC_QUIRK_HAS_MDIO_C45) { + fep->mii_bus->read_c45 = fec_enet_mdio_read_c45; + fep->mii_bus->write_c45 = fec_enet_mdio_write_c45; + } snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", pdev->name, fep->dev_id + 1); fep->mii_bus->priv = fep; diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h index 64eb0442c82f..005cb9dfe078 100644 --- a/drivers/net/ethernet/google/gve/gve.h +++ b/drivers/net/ethernet/google/gve/gve.h @@ -47,6 +47,8 @@ #define GVE_RX_BUFFER_SIZE_DQO 2048 +#define GVE_GQ_TX_MIN_PKT_DESC_BYTES 182 + /* Each slot in the desc ring has a 1:1 mapping to a slot in the data ring */ struct gve_rx_desc_queue { struct gve_rx_desc *desc_ring; /* the descriptor ring */ diff --git a/drivers/net/ethernet/google/gve/gve_tx.c b/drivers/net/ethernet/google/gve/gve_tx.c index 4888bf05fbed..5e11b8236754 100644 --- a/drivers/net/ethernet/google/gve/gve_tx.c +++ b/drivers/net/ethernet/google/gve/gve_tx.c @@ -284,8 +284,8 @@ static inline int gve_skb_fifo_bytes_required(struct gve_tx_ring *tx, int bytes; int hlen; - hlen = skb_is_gso(skb) ? skb_checksum_start_offset(skb) + - tcp_hdrlen(skb) : skb_headlen(skb); + hlen = skb_is_gso(skb) ? skb_checksum_start_offset(skb) + tcp_hdrlen(skb) : + min_t(int, GVE_GQ_TX_MIN_PKT_DESC_BYTES, skb->len); pad_bytes = gve_tx_fifo_pad_alloc_one_frag(&tx->tx_fifo, hlen); @@ -454,13 +454,11 @@ static int gve_tx_add_skb_copy(struct gve_priv *priv, struct gve_tx_ring *tx, st pkt_desc = &tx->desc[idx]; l4_hdr_offset = skb_checksum_start_offset(skb); - /* If the skb is gso, then we want the tcp header in the first segment - * otherwise we want the linear portion of the skb (which will contain - * the checksum because skb->csum_start and skb->csum_offset are given - * relative to skb->head) in the first segment. + /* If the skb is gso, then we want the tcp header alone in the first segment + * otherwise we want the minimum required by the gVNIC spec. */ hlen = is_gso ? l4_hdr_offset + tcp_hdrlen(skb) : - skb_headlen(skb); + min_t(int, GVE_GQ_TX_MIN_PKT_DESC_BYTES, skb->len); info->skb = skb; /* We don't want to split the header, so if necessary, pad to the end diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index e1eb1de88bf9..e14d1e45318f 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -5288,31 +5288,6 @@ static void e1000_watchdog_task(struct work_struct *work) ew32(TARC(0), tarc0); } - /* disable TSO for pcie and 10/100 speeds, to avoid - * some hardware issues - */ - if (!(adapter->flags & FLAG_TSO_FORCE)) { - switch (adapter->link_speed) { - case SPEED_10: - case SPEED_100: - e_info("10/100 speed: disabling TSO\n"); - netdev->features &= ~NETIF_F_TSO; - netdev->features &= ~NETIF_F_TSO6; - break; - case SPEED_1000: - netdev->features |= NETIF_F_TSO; - netdev->features |= NETIF_F_TSO6; - break; - default: - /* oops */ - break; - } - if (hw->mac.type == e1000_pch_spt) { - netdev->features &= ~NETIF_F_TSO; - netdev->features &= ~NETIF_F_TSO6; - } - } - /* enable transmits in the hardware, need to do this * after setting TARC(0) */ @@ -7526,6 +7501,32 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) NETIF_F_RXCSUM | NETIF_F_HW_CSUM); + /* disable TSO for pcie and 10/100 speeds to avoid + * some hardware issues and for i219 to fix transfer + * speed being capped at 60% + */ + if (!(adapter->flags & FLAG_TSO_FORCE)) { + switch (adapter->link_speed) { + case SPEED_10: + case SPEED_100: + e_info("10/100 speed: disabling TSO\n"); + netdev->features &= ~NETIF_F_TSO; + netdev->features &= ~NETIF_F_TSO6; + break; + case SPEED_1000: + netdev->features |= NETIF_F_TSO; + netdev->features |= NETIF_F_TSO6; + break; + default: + /* oops */ + break; + } + if (hw->mac.type == e1000_pch_spt) { + netdev->features &= ~NETIF_F_TSO; + netdev->features &= ~NETIF_F_TSO6; + } + } + /* Set user-changeable features (subset of all device features) */ netdev->hw_features = netdev->features; netdev->hw_features |= NETIF_F_RXFCS; diff --git a/drivers/net/ethernet/intel/i40e/i40e_diag.c b/drivers/net/ethernet/intel/i40e/i40e_diag.c index 5b3519c6e362..97fe1787a8f4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_diag.c +++ b/drivers/net/ethernet/intel/i40e/i40e_diag.c @@ -44,7 +44,7 @@ static int i40e_diag_reg_pattern_test(struct i40e_hw *hw, return 0; } -struct i40e_diag_reg_test_info i40e_reg_list[] = { +const struct i40e_diag_reg_test_info i40e_reg_list[] = { /* offset mask elements stride */ {I40E_QTX_CTL(0), 0x0000FFBF, 1, I40E_QTX_CTL(1) - I40E_QTX_CTL(0)}, @@ -78,27 +78,28 @@ int i40e_diag_reg_test(struct i40e_hw *hw) { int ret_code = 0; u32 reg, mask; + u32 elements; u32 i, j; for (i = 0; i40e_reg_list[i].offset != 0 && !ret_code; i++) { + elements = i40e_reg_list[i].elements; /* set actual reg range for dynamically allocated resources */ if (i40e_reg_list[i].offset == I40E_QTX_CTL(0) && hw->func_caps.num_tx_qp != 0) - i40e_reg_list[i].elements = hw->func_caps.num_tx_qp; + elements = hw->func_caps.num_tx_qp; if ((i40e_reg_list[i].offset == I40E_PFINT_ITRN(0, 0) || i40e_reg_list[i].offset == I40E_PFINT_ITRN(1, 0) || i40e_reg_list[i].offset == I40E_PFINT_ITRN(2, 0) || i40e_reg_list[i].offset == I40E_QINT_TQCTL(0) || i40e_reg_list[i].offset == I40E_QINT_RQCTL(0)) && hw->func_caps.num_msix_vectors != 0) - i40e_reg_list[i].elements = - hw->func_caps.num_msix_vectors - 1; + elements = hw->func_caps.num_msix_vectors - 1; /* test register access */ mask = i40e_reg_list[i].mask; - for (j = 0; j < i40e_reg_list[i].elements && !ret_code; j++) { + for (j = 0; j < elements && !ret_code; j++) { reg = i40e_reg_list[i].offset + (j * i40e_reg_list[i].stride); ret_code = i40e_diag_reg_pattern_test(hw, reg, mask); diff --git a/drivers/net/ethernet/intel/i40e/i40e_diag.h b/drivers/net/ethernet/intel/i40e/i40e_diag.h index e641035c7297..c3ce5f35211f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_diag.h +++ b/drivers/net/ethernet/intel/i40e/i40e_diag.h @@ -20,7 +20,7 @@ struct i40e_diag_reg_test_info { u32 stride; /* bytes between each element */ }; -extern struct i40e_diag_reg_test_info i40e_reg_list[]; +extern const struct i40e_diag_reg_test_info i40e_reg_list[]; int i40e_diag_reg_test(struct i40e_hw *hw); int i40e_diag_eeprom_test(struct i40e_hw *hw); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 228cd502bb48..7c30abd0dfc2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -11059,8 +11059,11 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired) pf->hw.aq.asq_last_status)); } /* reinit the misc interrupt */ - if (pf->flags & I40E_FLAG_MSIX_ENABLED) + if (pf->flags & I40E_FLAG_MSIX_ENABLED) { ret = i40e_setup_misc_vector(pf); + if (ret) + goto end_unlock; + } /* Add a filter to drop all Flow control frames from any VSI from being * transmitted. By doing so we stop a malicious VF from sending out @@ -14133,15 +14136,15 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) vsi->id = ctxt.vsi_number; } - vsi->active_filters = 0; - clear_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state); spin_lock_bh(&vsi->mac_filter_hash_lock); + vsi->active_filters = 0; /* If macvlan filters already exist, force them to get loaded */ hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) { f->state = I40E_FILTER_NEW; f_count++; } spin_unlock_bh(&vsi->mac_filter_hash_lock); + clear_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state); if (f_count) { vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED; diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h index 232bc61d9eee..746ff76f2fb1 100644 --- a/drivers/net/ethernet/intel/iavf/iavf.h +++ b/drivers/net/ethernet/intel/iavf/iavf.h @@ -59,8 +59,6 @@ enum iavf_vsi_state_t { struct iavf_vsi { struct iavf_adapter *back; struct net_device *netdev; - unsigned long active_cvlans[BITS_TO_LONGS(VLAN_N_VID)]; - unsigned long active_svlans[BITS_TO_LONGS(VLAN_N_VID)]; u16 seid; u16 id; DECLARE_BITMAP(state, __IAVF_VSI_STATE_SIZE__); @@ -158,15 +156,20 @@ struct iavf_vlan { u16 tpid; }; +enum iavf_vlan_state_t { + IAVF_VLAN_INVALID, + IAVF_VLAN_ADD, /* filter needs to be added */ + IAVF_VLAN_IS_NEW, /* filter is new, wait for PF answer */ + IAVF_VLAN_ACTIVE, /* filter is accepted by PF */ + IAVF_VLAN_DISABLE, /* filter needs to be deleted by PF, then marked INACTIVE */ + IAVF_VLAN_INACTIVE, /* filter is inactive, we are in IFF_DOWN */ + IAVF_VLAN_REMOVE, /* filter needs to be removed from list */ +}; + struct iavf_vlan_filter { struct list_head list; struct iavf_vlan vlan; - struct { - u8 is_new_vlan:1; /* filter is new, wait for PF answer */ - u8 remove:1; /* filter needs to be removed */ - u8 add:1; /* filter needs to be added */ - u8 padding:5; - }; + enum iavf_vlan_state_t state; }; #define IAVF_MAX_TRAFFIC_CLASS 4 @@ -258,6 +261,7 @@ struct iavf_adapter { wait_queue_head_t vc_waitqueue; struct iavf_q_vector *q_vectors; struct list_head vlan_filter_list; + int num_vlan_filters; struct list_head mac_filter_list; struct mutex crit_lock; struct mutex client_lock; diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 095201e83c9d..2de4baff4c20 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -791,7 +791,8 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, f->vlan = vlan; list_add_tail(&f->list, &adapter->vlan_filter_list); - f->add = true; + f->state = IAVF_VLAN_ADD; + adapter->num_vlan_filters++; adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER; } @@ -813,7 +814,7 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan) f = iavf_find_vlan(adapter, vlan); if (f) { - f->remove = true; + f->state = IAVF_VLAN_REMOVE; adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER; } @@ -828,14 +829,18 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan) **/ static void iavf_restore_filters(struct iavf_adapter *adapter) { - u16 vid; + struct iavf_vlan_filter *f; /* re-add all VLAN filters */ - for_each_set_bit(vid, adapter->vsi.active_cvlans, VLAN_N_VID) - iavf_add_vlan(adapter, IAVF_VLAN(vid, ETH_P_8021Q)); + spin_lock_bh(&adapter->mac_vlan_list_lock); - for_each_set_bit(vid, adapter->vsi.active_svlans, VLAN_N_VID) - iavf_add_vlan(adapter, IAVF_VLAN(vid, ETH_P_8021AD)); + list_for_each_entry(f, &adapter->vlan_filter_list, list) { + if (f->state == IAVF_VLAN_INACTIVE) + f->state = IAVF_VLAN_ADD; + } + + spin_unlock_bh(&adapter->mac_vlan_list_lock); + adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER; } /** @@ -844,8 +849,7 @@ static void iavf_restore_filters(struct iavf_adapter *adapter) */ u16 iavf_get_num_vlans_added(struct iavf_adapter *adapter) { - return bitmap_weight(adapter->vsi.active_cvlans, VLAN_N_VID) + - bitmap_weight(adapter->vsi.active_svlans, VLAN_N_VID); + return adapter->num_vlan_filters; } /** @@ -928,11 +932,6 @@ static int iavf_vlan_rx_kill_vid(struct net_device *netdev, return 0; iavf_del_vlan(adapter, IAVF_VLAN(vid, be16_to_cpu(proto))); - if (proto == cpu_to_be16(ETH_P_8021Q)) - clear_bit(vid, adapter->vsi.active_cvlans); - else - clear_bit(vid, adapter->vsi.active_svlans); - return 0; } @@ -1293,16 +1292,11 @@ static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) } } - /* remove all VLAN filters */ + /* disable all VLAN filters */ list_for_each_entry_safe(vlf, vlftmp, &adapter->vlan_filter_list, - list) { - if (vlf->add) { - list_del(&vlf->list); - kfree(vlf); - } else { - vlf->remove = true; - } - } + list) + vlf->state = IAVF_VLAN_DISABLE; + spin_unlock_bh(&adapter->mac_vlan_list_lock); } @@ -2914,6 +2908,7 @@ static void iavf_disable_vf(struct iavf_adapter *adapter) list_del(&fv->list); kfree(fv); } + adapter->num_vlan_filters = 0; spin_unlock_bh(&adapter->mac_vlan_list_lock); @@ -3131,9 +3126,6 @@ continue_reset: adapter->aq_required |= IAVF_FLAG_AQ_ADD_CLOUD_FILTER; iavf_misc_irq_enable(adapter); - bitmap_clear(adapter->vsi.active_cvlans, 0, VLAN_N_VID); - bitmap_clear(adapter->vsi.active_svlans, 0, VLAN_N_VID); - mod_delayed_work(adapter->wq, &adapter->watchdog_task, 2); /* We were running when the reset started, so we need to restore some diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c index 4e17d006c52d..9afbbdac3590 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c @@ -642,16 +642,10 @@ static void iavf_vlan_add_reject(struct iavf_adapter *adapter) spin_lock_bh(&adapter->mac_vlan_list_lock); list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { - if (f->is_new_vlan) { - if (f->vlan.tpid == ETH_P_8021Q) - clear_bit(f->vlan.vid, - adapter->vsi.active_cvlans); - else - clear_bit(f->vlan.vid, - adapter->vsi.active_svlans); - + if (f->state == IAVF_VLAN_IS_NEW) { list_del(&f->list); kfree(f); + adapter->num_vlan_filters--; } } spin_unlock_bh(&adapter->mac_vlan_list_lock); @@ -679,7 +673,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) spin_lock_bh(&adapter->mac_vlan_list_lock); list_for_each_entry(f, &adapter->vlan_filter_list, list) { - if (f->add) + if (f->state == IAVF_VLAN_ADD) count++; } if (!count || !VLAN_FILTERING_ALLOWED(adapter)) { @@ -710,11 +704,10 @@ void iavf_add_vlans(struct iavf_adapter *adapter) vvfl->vsi_id = adapter->vsi_res->vsi_id; vvfl->num_elements = count; list_for_each_entry(f, &adapter->vlan_filter_list, list) { - if (f->add) { + if (f->state == IAVF_VLAN_ADD) { vvfl->vlan_id[i] = f->vlan.vid; i++; - f->add = false; - f->is_new_vlan = true; + f->state = IAVF_VLAN_IS_NEW; if (i == count) break; } @@ -760,7 +753,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) vvfl_v2->vport_id = adapter->vsi_res->vsi_id; vvfl_v2->num_elements = count; list_for_each_entry(f, &adapter->vlan_filter_list, list) { - if (f->add) { + if (f->state == IAVF_VLAN_ADD) { struct virtchnl_vlan_supported_caps *filtering_support = &adapter->vlan_v2_caps.filtering.filtering_support; struct virtchnl_vlan *vlan; @@ -778,8 +771,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) vlan->tpid = f->vlan.tpid; i++; - f->add = false; - f->is_new_vlan = true; + f->state = IAVF_VLAN_IS_NEW; } } @@ -822,10 +814,16 @@ void iavf_del_vlans(struct iavf_adapter *adapter) * filters marked for removal to enable bailing out before * sending a virtchnl message */ - if (f->remove && !VLAN_FILTERING_ALLOWED(adapter)) { + if (f->state == IAVF_VLAN_REMOVE && + !VLAN_FILTERING_ALLOWED(adapter)) { list_del(&f->list); kfree(f); - } else if (f->remove) { + adapter->num_vlan_filters--; + } else if (f->state == IAVF_VLAN_DISABLE && + !VLAN_FILTERING_ALLOWED(adapter)) { + f->state = IAVF_VLAN_INACTIVE; + } else if (f->state == IAVF_VLAN_REMOVE || + f->state == IAVF_VLAN_DISABLE) { count++; } } @@ -857,11 +855,18 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vvfl->vsi_id = adapter->vsi_res->vsi_id; vvfl->num_elements = count; list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { - if (f->remove) { + if (f->state == IAVF_VLAN_DISABLE) { vvfl->vlan_id[i] = f->vlan.vid; + f->state = IAVF_VLAN_INACTIVE; i++; + if (i == count) + break; + } else if (f->state == IAVF_VLAN_REMOVE) { + vvfl->vlan_id[i] = f->vlan.vid; list_del(&f->list); kfree(f); + adapter->num_vlan_filters--; + i++; if (i == count) break; } @@ -901,7 +906,8 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vvfl_v2->vport_id = adapter->vsi_res->vsi_id; vvfl_v2->num_elements = count; list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) { - if (f->remove) { + if (f->state == IAVF_VLAN_DISABLE || + f->state == IAVF_VLAN_REMOVE) { struct virtchnl_vlan_supported_caps *filtering_support = &adapter->vlan_v2_caps.filtering.filtering_support; struct virtchnl_vlan *vlan; @@ -915,8 +921,13 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vlan->tci = f->vlan.vid; vlan->tpid = f->vlan.tpid; - list_del(&f->list); - kfree(f); + if (f->state == IAVF_VLAN_DISABLE) { + f->state = IAVF_VLAN_INACTIVE; + } else { + list_del(&f->list); + kfree(f); + adapter->num_vlan_filters--; + } i++; if (i == count) break; @@ -2192,7 +2203,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, list_for_each_entry(vlf, &adapter->vlan_filter_list, list) - vlf->add = true; + vlf->state = IAVF_VLAN_ADD; adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER; @@ -2260,7 +2271,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, list_for_each_entry(vlf, &adapter->vlan_filter_list, list) - vlf->add = true; + vlf->state = IAVF_VLAN_ADD; aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER; } @@ -2444,15 +2455,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, spin_lock_bh(&adapter->mac_vlan_list_lock); list_for_each_entry(f, &adapter->vlan_filter_list, list) { - if (f->is_new_vlan) { - f->is_new_vlan = false; - if (f->vlan.tpid == ETH_P_8021Q) - set_bit(f->vlan.vid, - adapter->vsi.active_cvlans); - else - set_bit(f->vlan.vid, - adapter->vsi.active_svlans); - } + if (f->state == IAVF_VLAN_IS_NEW) + f->state = IAVF_VLAN_ACTIVE; } spin_unlock_bh(&adapter->mac_vlan_list_lock); } diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c index 4eca8d195ef0..b7682de0ae05 100644 --- a/drivers/net/ethernet/intel/ice/ice_sched.c +++ b/drivers/net/ethernet/intel/ice/ice_sched.c @@ -2788,7 +2788,7 @@ static int ice_sched_assoc_vsi_to_agg(struct ice_port_info *pi, u32 agg_id, u16 vsi_handle, unsigned long *tc_bitmap) { - struct ice_sched_agg_vsi_info *agg_vsi_info, *old_agg_vsi_info = NULL; + struct ice_sched_agg_vsi_info *agg_vsi_info, *iter, *old_agg_vsi_info = NULL; struct ice_sched_agg_info *agg_info, *old_agg_info; struct ice_hw *hw = pi->hw; int status = 0; @@ -2806,11 +2806,13 @@ ice_sched_assoc_vsi_to_agg(struct ice_port_info *pi, u32 agg_id, if (old_agg_info && old_agg_info != agg_info) { struct ice_sched_agg_vsi_info *vtmp; - list_for_each_entry_safe(old_agg_vsi_info, vtmp, + list_for_each_entry_safe(iter, vtmp, &old_agg_info->agg_vsi_list, list_entry) - if (old_agg_vsi_info->vsi_handle == vsi_handle) + if (iter->vsi_handle == vsi_handle) { + old_agg_vsi_info = iter; break; + } } /* check if entry already exist */ diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 61f844d22512..46b36851af46 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -1780,18 +1780,36 @@ ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, int ice_cfg_rdma_fltr(struct ice_hw *hw, u16 vsi_handle, bool enable) { - struct ice_vsi_ctx *ctx; + struct ice_vsi_ctx *ctx, *cached_ctx; + int status; + + cached_ctx = ice_get_vsi_ctx(hw, vsi_handle); + if (!cached_ctx) + return -ENOENT; - ctx = ice_get_vsi_ctx(hw, vsi_handle); + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) - return -EIO; + return -ENOMEM; + + ctx->info.q_opt_rss = cached_ctx->info.q_opt_rss; + ctx->info.q_opt_tc = cached_ctx->info.q_opt_tc; + ctx->info.q_opt_flags = cached_ctx->info.q_opt_flags; + + ctx->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_Q_OPT_VALID); if (enable) ctx->info.q_opt_flags |= ICE_AQ_VSI_Q_OPT_PE_FLTR_EN; else ctx->info.q_opt_flags &= ~ICE_AQ_VSI_Q_OPT_PE_FLTR_EN; - return ice_update_vsi(hw, vsi_handle, ctx, NULL); + status = ice_update_vsi(hw, vsi_handle, ctx, NULL); + if (!status) { + cached_ctx->info.q_opt_flags = ctx->info.q_opt_flags; + cached_ctx->info.valid_sections |= ctx->info.valid_sections; + } + + kfree(ctx); + return status; } /** diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index b61dd9f01540..4fcf2d07eb85 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -938,6 +938,7 @@ ice_reuse_rx_page(struct ice_rx_ring *rx_ring, struct ice_rx_buf *old_buf) * ice_get_rx_buf - Fetch Rx buffer and synchronize data for use * @rx_ring: Rx descriptor ring to transact packets on * @size: size of buffer to add to skb + * @ntc: index of next to clean element * * This function will pull an Rx buffer from the ring and synchronize it * for use by the CPU. @@ -1026,7 +1027,6 @@ ice_build_skb(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp) /** * ice_construct_skb - Allocate skb and populate it * @rx_ring: Rx descriptor ring to transact packets on - * @rx_buf: Rx buffer to pull data from * @xdp: xdp_buff pointing to the data * * This function allocates an skb. It then populates it with the page diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c index 7bc5aa340c7d..c8322fb6f2b3 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c @@ -438,6 +438,7 @@ busy: * ice_finalize_xdp_rx - Bump XDP Tx tail and/or flush redirect map * @xdp_ring: XDP ring * @xdp_res: Result of the receive batch + * @first_idx: index to write from caller * * This function bumps XDP Tx tail and/or flush redirect map, and * should be called when a batch of packets has been processed in the diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c index e6ef6b303222..daa6a1e894cf 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c @@ -542,6 +542,87 @@ static void ice_vc_fdir_rem_prof_all(struct ice_vf *vf) } /** + * ice_vc_fdir_reset_cnt_all - reset all FDIR counters for this VF FDIR + * @fdir: pointer to the VF FDIR structure + */ +static void ice_vc_fdir_reset_cnt_all(struct ice_vf_fdir *fdir) +{ + enum ice_fltr_ptype flow; + + for (flow = ICE_FLTR_PTYPE_NONF_NONE; + flow < ICE_FLTR_PTYPE_MAX; flow++) { + fdir->fdir_fltr_cnt[flow][0] = 0; + fdir->fdir_fltr_cnt[flow][1] = 0; + } +} + +/** + * ice_vc_fdir_has_prof_conflict + * @vf: pointer to the VF structure + * @conf: FDIR configuration for each filter + * + * Check if @conf has conflicting profile with existing profiles + * + * Return: true on success, and false on error. + */ +static bool +ice_vc_fdir_has_prof_conflict(struct ice_vf *vf, + struct virtchnl_fdir_fltr_conf *conf) +{ + struct ice_fdir_fltr *desc; + + list_for_each_entry(desc, &vf->fdir.fdir_rule_list, fltr_node) { + struct virtchnl_fdir_fltr_conf *existing_conf; + enum ice_fltr_ptype flow_type_a, flow_type_b; + struct ice_fdir_fltr *a, *b; + + existing_conf = to_fltr_conf_from_desc(desc); + a = &existing_conf->input; + b = &conf->input; + flow_type_a = a->flow_type; + flow_type_b = b->flow_type; + + /* No need to compare two rules with different tunnel types or + * with the same protocol type. + */ + if (existing_conf->ttype != conf->ttype || + flow_type_a == flow_type_b) + continue; + + switch (flow_type_a) { + case ICE_FLTR_PTYPE_NONF_IPV4_UDP: + case ICE_FLTR_PTYPE_NONF_IPV4_TCP: + case ICE_FLTR_PTYPE_NONF_IPV4_SCTP: + if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_OTHER) + return true; + break; + case ICE_FLTR_PTYPE_NONF_IPV4_OTHER: + if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_UDP || + flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_TCP || + flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_SCTP) + return true; + break; + case ICE_FLTR_PTYPE_NONF_IPV6_UDP: + case ICE_FLTR_PTYPE_NONF_IPV6_TCP: + case ICE_FLTR_PTYPE_NONF_IPV6_SCTP: + if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_OTHER) + return true; + break; + case ICE_FLTR_PTYPE_NONF_IPV6_OTHER: + if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_UDP || + flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_TCP || + flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_SCTP) + return true; + break; + default: + break; + } + } + + return false; +} + +/** * ice_vc_fdir_write_flow_prof * @vf: pointer to the VF structure * @flow: filter flow type @@ -677,6 +758,13 @@ ice_vc_fdir_config_input_set(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, enum ice_fltr_ptype flow; int ret; + ret = ice_vc_fdir_has_prof_conflict(vf, conf); + if (ret) { + dev_dbg(dev, "Found flow profile conflict for VF %d\n", + vf->vf_id); + return ret; + } + flow = input->flow_type; ret = ice_vc_fdir_alloc_prof(vf, flow); if (ret) { @@ -1798,7 +1886,7 @@ int ice_vc_add_fdir_fltr(struct ice_vf *vf, u8 *msg) v_ret = VIRTCHNL_STATUS_SUCCESS; stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; dev_dbg(dev, "VF %d: set FDIR context failed\n", vf->vf_id); - goto err_free_conf; + goto err_rem_entry; } ret = ice_vc_fdir_write_fltr(vf, conf, true, is_tun); @@ -1807,15 +1895,16 @@ int ice_vc_add_fdir_fltr(struct ice_vf *vf, u8 *msg) stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; dev_err(dev, "VF %d: writing FDIR rule failed, ret:%d\n", vf->vf_id, ret); - goto err_rem_entry; + goto err_clr_irq; } exit: kfree(stat); return ret; -err_rem_entry: +err_clr_irq: ice_vc_fdir_clear_irq_ctx(vf); +err_rem_entry: ice_vc_fdir_remove_entry(vf, conf, conf->flow_id); err_free_conf: devm_kfree(dev, conf); @@ -1924,6 +2013,7 @@ void ice_vf_fdir_init(struct ice_vf *vf) spin_lock_init(&fdir->ctx_lock); fdir->ctx_irq.flags = 0; fdir->ctx_done.flags = 0; + ice_vc_fdir_reset_cnt_all(fdir); } /** diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 0e39d199ff06..2cad76d0a50e 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -3549,6 +3549,8 @@ static void mvneta_txq_sw_deinit(struct mvneta_port *pp, netdev_tx_reset_queue(nq); + txq->buf = NULL; + txq->tso_hdrs = NULL; txq->descs = NULL; txq->last_desc = 0; txq->next_desc_to_proc = 0; diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c index 41d935d1aaf6..40aeaa7bd739 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c @@ -62,35 +62,38 @@ static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = { MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG, MVPP22_CLS_HEK_IP4_2T, MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 | - MVPP2_PRS_RI_L4_TCP, + MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP, MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK), MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG, MVPP22_CLS_HEK_IP4_2T, MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT | - MVPP2_PRS_RI_L4_TCP, + MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP, MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK), MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG, MVPP22_CLS_HEK_IP4_2T, MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER | - MVPP2_PRS_RI_L4_TCP, + MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP, MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK), /* TCP over IPv4 flows, fragmented, with vlan tag */ MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG, MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED, - MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_TCP, + MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_IP_FRAG_TRUE | + MVPP2_PRS_RI_L4_TCP, MVPP2_PRS_IP_MASK), MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG, MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED, - MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_TCP, + MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_IP_FRAG_TRUE | + MVPP2_PRS_RI_L4_TCP, MVPP2_PRS_IP_MASK), MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG, MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED, - MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_TCP, + MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_IP_FRAG_TRUE | + MVPP2_PRS_RI_L4_TCP, MVPP2_PRS_IP_MASK), /* UDP over IPv4 flows, Not fragmented, no vlan tag */ @@ -132,35 +135,38 @@ static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = { MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG, MVPP22_CLS_HEK_IP4_2T, MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 | - MVPP2_PRS_RI_L4_UDP, + MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP, MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK), MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG, MVPP22_CLS_HEK_IP4_2T, MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT | - MVPP2_PRS_RI_L4_UDP, + MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP, MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK), MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG, MVPP22_CLS_HEK_IP4_2T, MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER | - MVPP2_PRS_RI_L4_UDP, + MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP, MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK), /* UDP over IPv4 flows, fragmented, with vlan tag */ MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG, MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED, - MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_UDP, + MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_IP_FRAG_TRUE | + MVPP2_PRS_RI_L4_UDP, MVPP2_PRS_IP_MASK), MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG, MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED, - MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_UDP, + MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_IP_FRAG_TRUE | + MVPP2_PRS_RI_L4_UDP, MVPP2_PRS_IP_MASK), MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG, MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED, - MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_UDP, + MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_IP_FRAG_TRUE | + MVPP2_PRS_RI_L4_UDP, MVPP2_PRS_IP_MASK), /* TCP over IPv6 flows, not fragmented, no vlan tag */ diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c index 75ba57bd1d46..9af22f497a40 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c @@ -1539,8 +1539,8 @@ static int mvpp2_prs_vlan_init(struct platform_device *pdev, struct mvpp2 *priv) if (!priv->prs_double_vlans) return -ENOMEM; - /* Double VLAN: 0x8100, 0x88A8 */ - err = mvpp2_prs_double_vlan_add(priv, ETH_P_8021Q, ETH_P_8021AD, + /* Double VLAN: 0x88A8, 0x8100 */ + err = mvpp2_prs_double_vlan_add(priv, ETH_P_8021AD, ETH_P_8021Q, MVPP2_PRS_PORT_MASK); if (err) return err; @@ -1607,59 +1607,45 @@ static int mvpp2_prs_vlan_init(struct platform_device *pdev, struct mvpp2 *priv) static int mvpp2_prs_pppoe_init(struct mvpp2 *priv) { struct mvpp2_prs_entry pe; - int tid; - - /* IPv4 over PPPoE with options */ - tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, - MVPP2_PE_LAST_FREE_TID); - if (tid < 0) - return tid; - - memset(&pe, 0, sizeof(pe)); - mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE); - pe.index = tid; - - mvpp2_prs_match_etype(&pe, 0, PPP_IP); - - mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4); - mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4_OPT, - MVPP2_PRS_RI_L3_PROTO_MASK); - /* goto ipv4 dest-address (skip eth_type + IP-header-size - 4) */ - mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + - sizeof(struct iphdr) - 4, - MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); - /* Set L3 offset */ - mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, - MVPP2_ETH_TYPE_LEN, - MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); - - /* Update shadow table and hw entry */ - mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE); - mvpp2_prs_hw_write(priv, &pe); + int tid, ihl; - /* IPv4 over PPPoE without options */ - tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, - MVPP2_PE_LAST_FREE_TID); - if (tid < 0) - return tid; + /* IPv4 over PPPoE with header length >= 5 */ + for (ihl = MVPP2_PRS_IPV4_IHL_MIN; ihl <= MVPP2_PRS_IPV4_IHL_MAX; ihl++) { + tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, + MVPP2_PE_LAST_FREE_TID); + if (tid < 0) + return tid; - pe.index = tid; + memset(&pe, 0, sizeof(pe)); + mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE); + pe.index = tid; - mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN, - MVPP2_PRS_IPV4_HEAD | - MVPP2_PRS_IPV4_IHL_MIN, - MVPP2_PRS_IPV4_HEAD_MASK | - MVPP2_PRS_IPV4_IHL_MASK); + mvpp2_prs_match_etype(&pe, 0, PPP_IP); + mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN, + MVPP2_PRS_IPV4_HEAD | ihl, + MVPP2_PRS_IPV4_HEAD_MASK | + MVPP2_PRS_IPV4_IHL_MASK); - /* Clear ri before updating */ - pe.sram[MVPP2_PRS_SRAM_RI_WORD] = 0x0; - pe.sram[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0; - mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4, - MVPP2_PRS_RI_L3_PROTO_MASK); + mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4); + mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4, + MVPP2_PRS_RI_L3_PROTO_MASK); + /* goto ipv4 dst-address (skip eth_type + IP-header-size - 4) */ + mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + + sizeof(struct iphdr) - 4, + MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD); + /* Set L3 offset */ + mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, + MVPP2_ETH_TYPE_LEN, + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); + /* Set L4 offset */ + mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4, + MVPP2_ETH_TYPE_LEN + (ihl * 4), + MVPP2_PRS_SRAM_OP_SEL_UDF_ADD); - /* Update shadow table and hw entry */ - mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE); - mvpp2_prs_hw_write(priv, &pe); + /* Update shadow table and hw entry */ + mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE); + mvpp2_prs_hw_write(priv, &pe); + } /* IPv6 over PPPoE */ tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID, diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 3cb43623d3db..e14050e17862 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -753,6 +753,7 @@ static void mtk_mac_link_up(struct phylink_config *config, MAC_MCR_FORCE_RX_FC); /* Configure speed */ + mac->speed = speed; switch (speed) { case SPEED_2500: case SPEED_1000: @@ -763,8 +764,6 @@ static void mtk_mac_link_up(struct phylink_config *config, break; } - mtk_set_queue_speed(mac->hw, mac->id, speed); - /* Configure duplex */ if (duplex == DUPLEX_FULL) mcr |= MAC_MCR_FORCE_DPX; @@ -2059,9 +2058,6 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, skb_checksum_none_assert(skb); skb->protocol = eth_type_trans(skb, netdev); - if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) - mtk_ppe_check_skb(eth->ppe[0], skb, hash); - if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { if (trxd.rxd3 & RX_DMA_VTAG_V2) { @@ -2089,6 +2085,9 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, __vlan_hwaccel_put_tag(skb, htons(vlan_proto), vlan_tci); } + if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) + mtk_ppe_check_skb(eth->ppe[0], skb, hash); + skb_record_rx_queue(skb, 0); napi_gro_receive(napi, skb); @@ -3237,6 +3236,9 @@ found: if (dp->index >= MTK_QDMA_NUM_QUEUES) return NOTIFY_DONE; + if (mac->speed > 0 && mac->speed <= s.base.speed) + s.base.speed = 0; + mtk_set_queue_speed(eth, dp->index + 3, s.base.speed); return NOTIFY_DONE; diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c index 6883eb34cd8b..fd07d6e14273 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c @@ -8,6 +8,7 @@ #include <linux/platform_device.h> #include <linux/if_ether.h> #include <linux/if_vlan.h> +#include <net/dst_metadata.h> #include <net/dsa.h> #include "mtk_eth_soc.h" #include "mtk_ppe.h" @@ -458,6 +459,7 @@ __mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) hwe->ib1 &= ~MTK_FOE_IB1_STATE; hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); dma_wmb(); + mtk_ppe_cache_clear(ppe); } entry->hash = 0xffff; @@ -699,7 +701,9 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) skb->dev->dsa_ptr->tag_ops->proto != DSA_TAG_PROTO_MTK) goto out; - tag += 4; + if (!skb_metadata_dst(skb)) + tag += 4; + if (get_unaligned_be16(tag) != ETH_P_8021Q) break; diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c index 81afd5ee3fbf..161751bb36c9 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c @@ -576,6 +576,7 @@ mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f) if (IS_ERR(block_cb)) return PTR_ERR(block_cb); + flow_block_cb_incref(block_cb); flow_block_cb_add(block_cb, f); list_add_tail(&block_cb->driver_list, &block_cb_list); return 0; @@ -584,7 +585,7 @@ mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f) if (!block_cb) return -ENOENT; - if (flow_block_cb_decref(block_cb)) { + if (!flow_block_cb_decref(block_cb)) { flow_block_cb_remove(block_cb, f); list_del(&block_cb->driver_list); } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 4b5e459b6d49..332472fe4990 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -681,14 +681,32 @@ int mlx4_en_xdp_rx_timestamp(const struct xdp_md *ctx, u64 *timestamp) return 0; } -int mlx4_en_xdp_rx_hash(const struct xdp_md *ctx, u32 *hash) +int mlx4_en_xdp_rx_hash(const struct xdp_md *ctx, u32 *hash, + enum xdp_rss_hash_type *rss_type) { struct mlx4_en_xdp_buff *_ctx = (void *)ctx; + struct mlx4_cqe *cqe = _ctx->cqe; + enum xdp_rss_hash_type xht = 0; + __be16 status; if (unlikely(!(_ctx->dev->features & NETIF_F_RXHASH))) return -ENODATA; - *hash = be32_to_cpu(_ctx->cqe->immed_rss_invalid); + *hash = be32_to_cpu(cqe->immed_rss_invalid); + status = cqe->status; + if (status & cpu_to_be16(MLX4_CQE_STATUS_TCP)) + xht = XDP_RSS_L4_TCP; + if (status & cpu_to_be16(MLX4_CQE_STATUS_UDP)) + xht = XDP_RSS_L4_UDP; + if (status & cpu_to_be16(MLX4_CQE_STATUS_IPV4 | MLX4_CQE_STATUS_IPV4F)) + xht |= XDP_RSS_L3_IPV4; + if (status & cpu_to_be16(MLX4_CQE_STATUS_IPV6)) { + xht |= XDP_RSS_L3_IPV6; + if (cqe->ipv6_ext_mask) + xht |= XDP_RSS_L3_DYNHDR; + } + *rss_type = xht; + return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 544e09b97483..4ac4d883047b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -798,7 +798,8 @@ int mlx4_en_netdev_event(struct notifier_block *this, struct xdp_md; int mlx4_en_xdp_rx_timestamp(const struct xdp_md *ctx, u64 *timestamp); -int mlx4_en_xdp_rx_hash(const struct xdp_md *ctx, u32 *hash); +int mlx4_en_xdp_rx_hash(const struct xdp_md *ctx, u32 *hash, + enum xdp_rss_hash_type *rss_type); /* * Functions for time stamping diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/dev.c index 445fe30c3d0b..2e7806001fdc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dev.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dev.c @@ -59,9 +59,6 @@ bool mlx5_eth_supported(struct mlx5_core_dev *dev) if (!IS_ENABLED(CONFIG_MLX5_CORE_EN)) return false; - if (mlx5_core_is_management_pf(dev)) - return false; - if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH) return false; @@ -201,9 +198,6 @@ bool mlx5_rdma_supported(struct mlx5_core_dev *dev) if (!IS_ENABLED(CONFIG_MLX5_INFINIBAND)) return false; - if (mlx5_core_is_management_pf(dev)) - return false; - if (dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_IB_ADEV) return false; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c b/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c index 7c9c4e40c019..d000236ddbac 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c @@ -75,10 +75,6 @@ int mlx5_ec_init(struct mlx5_core_dev *dev) if (!mlx5_core_is_ecpf(dev)) return 0; - /* Management PF don't have a peer PF */ - if (mlx5_core_is_management_pf(dev)) - return 0; - return mlx5_host_pf_init(dev); } @@ -89,10 +85,6 @@ void mlx5_ec_cleanup(struct mlx5_core_dev *dev) if (!mlx5_core_is_ecpf(dev)) return; - /* Management PF don't have a peer PF */ - if (mlx5_core_is_management_pf(dev)) - return; - mlx5_host_pf_cleanup(dev); err = mlx5_wait_for_pages(dev, &dev->priv.page_counters[MLX5_HOST_PF]); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/int_port.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/int_port.c index ca834bbcb44f..8afcec0c5d3c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/int_port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/int_port.c @@ -242,7 +242,7 @@ mlx5e_int_port_remove(struct mlx5e_tc_int_port_priv *priv, mlx5_del_flow_rules(int_port->rx_rule); mapping_remove(ctx, int_port->mapping); mlx5e_int_port_metadata_free(priv, int_port->match_metadata); - kfree_rcu(int_port); + kfree_rcu_mightsleep(int_port); priv->num_ports--; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c index c5dae48b7932..d9d3b9e1f15a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c @@ -34,6 +34,7 @@ #include <net/xdp_sock_drv.h> #include "en/xdp.h" #include "en/params.h" +#include <linux/bitfield.h> int mlx5e_xdp_max_mtu(struct mlx5e_params *params, struct mlx5e_xsk_param *xsk) { @@ -169,14 +170,72 @@ static int mlx5e_xdp_rx_timestamp(const struct xdp_md *ctx, u64 *timestamp) return 0; } -static int mlx5e_xdp_rx_hash(const struct xdp_md *ctx, u32 *hash) +/* Mapping HW RSS Type bits CQE_RSS_HTYPE_IP + CQE_RSS_HTYPE_L4 into 4-bits*/ +#define RSS_TYPE_MAX_TABLE 16 /* 4-bits max 16 entries */ +#define RSS_L4 GENMASK(1, 0) +#define RSS_L3 GENMASK(3, 2) /* Same as CQE_RSS_HTYPE_IP */ + +/* Valid combinations of CQE_RSS_HTYPE_IP + CQE_RSS_HTYPE_L4 sorted numerical */ +enum mlx5_rss_hash_type { + RSS_TYPE_NO_HASH = (FIELD_PREP_CONST(RSS_L3, CQE_RSS_IP_NONE) | + FIELD_PREP_CONST(RSS_L4, CQE_RSS_L4_NONE)), + RSS_TYPE_L3_IPV4 = (FIELD_PREP_CONST(RSS_L3, CQE_RSS_IPV4) | + FIELD_PREP_CONST(RSS_L4, CQE_RSS_L4_NONE)), + RSS_TYPE_L4_IPV4_TCP = (FIELD_PREP_CONST(RSS_L3, CQE_RSS_IPV4) | + FIELD_PREP_CONST(RSS_L4, CQE_RSS_L4_TCP)), + RSS_TYPE_L4_IPV4_UDP = (FIELD_PREP_CONST(RSS_L3, CQE_RSS_IPV4) | + FIELD_PREP_CONST(RSS_L4, CQE_RSS_L4_UDP)), + RSS_TYPE_L4_IPV4_IPSEC = (FIELD_PREP_CONST(RSS_L3, CQE_RSS_IPV4) | + FIELD_PREP_CONST(RSS_L4, CQE_RSS_L4_IPSEC)), + RSS_TYPE_L3_IPV6 = (FIELD_PREP_CONST(RSS_L3, CQE_RSS_IPV6) | + FIELD_PREP_CONST(RSS_L4, CQE_RSS_L4_NONE)), + RSS_TYPE_L4_IPV6_TCP = (FIELD_PREP_CONST(RSS_L3, CQE_RSS_IPV6) | + FIELD_PREP_CONST(RSS_L4, CQE_RSS_L4_TCP)), + RSS_TYPE_L4_IPV6_UDP = (FIELD_PREP_CONST(RSS_L3, CQE_RSS_IPV6) | + FIELD_PREP_CONST(RSS_L4, CQE_RSS_L4_UDP)), + RSS_TYPE_L4_IPV6_IPSEC = (FIELD_PREP_CONST(RSS_L3, CQE_RSS_IPV6) | + FIELD_PREP_CONST(RSS_L4, CQE_RSS_L4_IPSEC)), +}; + +/* Invalid combinations will simply return zero, allows no boundary checks */ +static const enum xdp_rss_hash_type mlx5_xdp_rss_type[RSS_TYPE_MAX_TABLE] = { + [RSS_TYPE_NO_HASH] = XDP_RSS_TYPE_NONE, + [1] = XDP_RSS_TYPE_NONE, /* Implicit zero */ + [2] = XDP_RSS_TYPE_NONE, /* Implicit zero */ + [3] = XDP_RSS_TYPE_NONE, /* Implicit zero */ + [RSS_TYPE_L3_IPV4] = XDP_RSS_TYPE_L3_IPV4, + [RSS_TYPE_L4_IPV4_TCP] = XDP_RSS_TYPE_L4_IPV4_TCP, + [RSS_TYPE_L4_IPV4_UDP] = XDP_RSS_TYPE_L4_IPV4_UDP, + [RSS_TYPE_L4_IPV4_IPSEC] = XDP_RSS_TYPE_L4_IPV4_IPSEC, + [RSS_TYPE_L3_IPV6] = XDP_RSS_TYPE_L3_IPV6, + [RSS_TYPE_L4_IPV6_TCP] = XDP_RSS_TYPE_L4_IPV6_TCP, + [RSS_TYPE_L4_IPV6_UDP] = XDP_RSS_TYPE_L4_IPV6_UDP, + [RSS_TYPE_L4_IPV6_IPSEC] = XDP_RSS_TYPE_L4_IPV6_IPSEC, + [12] = XDP_RSS_TYPE_NONE, /* Implicit zero */ + [13] = XDP_RSS_TYPE_NONE, /* Implicit zero */ + [14] = XDP_RSS_TYPE_NONE, /* Implicit zero */ + [15] = XDP_RSS_TYPE_NONE, /* Implicit zero */ +}; + +static int mlx5e_xdp_rx_hash(const struct xdp_md *ctx, u32 *hash, + enum xdp_rss_hash_type *rss_type) { const struct mlx5e_xdp_buff *_ctx = (void *)ctx; + const struct mlx5_cqe64 *cqe = _ctx->cqe; + u32 hash_type, l4_type, ip_type, lookup; if (unlikely(!(_ctx->xdp.rxq->dev->features & NETIF_F_RXHASH))) return -ENODATA; - *hash = be32_to_cpu(_ctx->cqe->rss_hash_result); + *hash = be32_to_cpu(cqe->rss_hash_result); + + hash_type = cqe->rss_hash_type; + BUILD_BUG_ON(CQE_RSS_HTYPE_IP != RSS_L3); /* same mask */ + ip_type = hash_type & CQE_RSS_HTYPE_IP; + l4_type = FIELD_GET(CQE_RSS_HTYPE_L4, hash_type); + lookup = ip_type | l4_type; + *rss_type = mlx5_xdp_rss_type[lookup]; + return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c index 33b3620ea45c..51f1cd8364c2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c @@ -670,7 +670,7 @@ static int mlx5e_macsec_del_txsa(struct macsec_context *ctx) mlx5e_macsec_cleanup_sa(macsec, tx_sa, true); mlx5_destroy_encryption_key(macsec->mdev, tx_sa->enc_key_id); - kfree_rcu(tx_sa); + kfree_rcu_mightsleep(tx_sa); macsec_device->tx_sa[assoc_num] = NULL; out: @@ -849,7 +849,7 @@ static void macsec_del_rxsc_ctx(struct mlx5e_macsec *macsec, struct mlx5e_macsec xa_erase(&macsec->sc_xarray, rx_sc->sc_xarray_element->fs_id); metadata_dst_free(rx_sc->md_dst); kfree(rx_sc->sc_xarray_element); - kfree_rcu(rx_sc); + kfree_rcu_mightsleep(rx_sc); } static int mlx5e_macsec_del_rxsc(struct macsec_context *ctx) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 8bdf28762f41..19fed514fc17 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1488,7 +1488,7 @@ int mlx5_esw_sf_max_hpf_functions(struct mlx5_core_dev *dev, u16 *max_sfs, u16 * void *hca_caps; int err; - if (!mlx5_core_is_ecpf(dev) || mlx5_core_is_management_pf(dev)) { + if (!mlx5_core_is_ecpf(dev)) { *max_sfs = 0; return 0; } diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.c b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.c index 017d68f1e123..972c571b4158 100644 --- a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.c +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.c @@ -31,6 +31,8 @@ mlxfw_mfa2_tlv_next(const struct mlxfw_mfa2_file *mfa2_file, if (tlv->type == MLXFW_MFA2_TLV_MULTI_PART) { multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, tlv); + if (!multi) + return NULL; tlv_len = NLA_ALIGN(tlv_len + be16_to_cpu(multi->total_len)); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h index 48dbfea0a2a1..7cdf0ce24f28 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h +++ b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h @@ -26,7 +26,7 @@ #define MLXSW_PCI_CIR_TIMEOUT_MSECS 1000 #define MLXSW_PCI_SW_RESET_TIMEOUT_MSECS 900000 -#define MLXSW_PCI_SW_RESET_WAIT_MSECS 200 +#define MLXSW_PCI_SW_RESET_WAIT_MSECS 400 #define MLXSW_PCI_FW_READY 0xA1844 #define MLXSW_PCI_FW_READY_MASK 0xFFFF #define MLXSW_PCI_FW_READY_MAGIC 0x5E diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c index 87f76bac2e46..eb827b86ecae 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c @@ -628,7 +628,13 @@ int qlcnic_fw_create_ctx(struct qlcnic_adapter *dev) int i, err, ring; if (dev->flags & QLCNIC_NEED_FLR) { - pci_reset_function(dev->pdev); + err = pci_reset_function(dev->pdev); + if (err) { + dev_err(&dev->pdev->dev, + "Adapter reset failed (%d). Please reboot\n", + err); + return err; + } dev->flags &= ~QLCNIC_NEED_FLR; } diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index 930496cd34ed..b50f16786c24 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -826,6 +826,9 @@ static void rtl8168h_2_hw_phy_config(struct rtl8169_private *tp, /* disable phy pfm mode */ phy_modify_paged(phydev, 0x0a44, 0x11, BIT(7), 0); + /* disable 10m pll off */ + phy_modify_paged(phydev, 0x0a43, 0x10, BIT(0), 0); + rtl8168g_disable_aldps(phydev); rtl8168g_config_eee_phy(phydev); } diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 7022fb2005a2..d30459dbfe8f 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -1304,7 +1304,8 @@ static void efx_ef10_fini_nic(struct efx_nic *efx) static int efx_ef10_init_nic(struct efx_nic *efx) { struct efx_ef10_nic_data *nic_data = efx->nic_data; - netdev_features_t hw_enc_features = 0; + struct net_device *net_dev = efx->net_dev; + netdev_features_t tun_feats, tso_feats; int rc; if (nic_data->must_check_datapath_caps) { @@ -1349,20 +1350,30 @@ static int efx_ef10_init_nic(struct efx_nic *efx) nic_data->must_restore_piobufs = false; } - /* add encapsulated checksum offload features */ + /* encap features might change during reset if fw variant changed */ if (efx_has_cap(efx, VXLAN_NVGRE) && !efx_ef10_is_vf(efx)) - hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - /* add encapsulated TSO features */ - if (efx_has_cap(efx, TX_TSO_V2_ENCAP)) { - netdev_features_t encap_tso_features; + net_dev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + else + net_dev->hw_enc_features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); - encap_tso_features = NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_GRE | - NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_GSO_GRE_CSUM; + tun_feats = NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_GRE | + NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_GSO_GRE_CSUM; + tso_feats = NETIF_F_TSO | NETIF_F_TSO6; - hw_enc_features |= encap_tso_features | NETIF_F_TSO; - efx->net_dev->features |= encap_tso_features; + if (efx_has_cap(efx, TX_TSO_V2_ENCAP)) { + /* If this is first nic_init, or if it is a reset and a new fw + * variant has added new features, enable them by default. + * If the features are not new, maintain their current value. + */ + if (!(net_dev->hw_features & tun_feats)) + net_dev->features |= tun_feats; + net_dev->hw_enc_features |= tun_feats | tso_feats; + net_dev->hw_features |= tun_feats; + } else { + net_dev->hw_enc_features &= ~(tun_feats | tso_feats); + net_dev->hw_features &= ~tun_feats; + net_dev->features &= ~tun_feats; } - efx->net_dev->hw_enc_features = hw_enc_features; /* don't fail init if RSS setup doesn't work */ rc = efx->type->rx_push_rss_config(efx, false, @@ -4021,7 +4032,10 @@ static unsigned int efx_ef10_recycle_ring_size(const struct efx_nic *efx) NETIF_F_HW_VLAN_CTAG_FILTER | \ NETIF_F_IPV6_CSUM | \ NETIF_F_RXHASH | \ - NETIF_F_NTUPLE) + NETIF_F_NTUPLE | \ + NETIF_F_SG | \ + NETIF_F_RXCSUM | \ + NETIF_F_RXALL) const struct efx_nic_type efx_hunt_a0_vf_nic_type = { .is_vf = true, diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 02c2adeb0a12..1eceffa02b55 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -541,7 +541,6 @@ int efx_net_open(struct net_device *net_dev) else efx->state = STATE_NET_UP; - efx_selftest_async_start(efx); return 0; } @@ -1001,21 +1000,18 @@ static int efx_pci_probe_post_io(struct efx_nic *efx) } /* Determine netdevice features */ - net_dev->features |= (efx->type->offload_features | NETIF_F_SG | - NETIF_F_TSO | NETIF_F_RXCSUM | NETIF_F_RXALL); - if (efx->type->offload_features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM)) { - net_dev->features |= NETIF_F_TSO6; - if (efx_has_cap(efx, TX_TSO_V2_ENCAP)) - net_dev->hw_enc_features |= NETIF_F_TSO6; - } - /* Check whether device supports TSO */ - if (!efx->type->tso_versions || !efx->type->tso_versions(efx)) - net_dev->features &= ~NETIF_F_ALL_TSO; + net_dev->features |= efx->type->offload_features; + + /* Add TSO features */ + if (efx->type->tso_versions && efx->type->tso_versions(efx)) + net_dev->features |= NETIF_F_TSO | NETIF_F_TSO6; + /* Mask for features that also apply to VLAN devices */ net_dev->vlan_features |= (NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_ALL_TSO | NETIF_F_RXCSUM); + /* Determine user configurable features */ net_dev->hw_features |= net_dev->features & ~efx->fixed_features; /* Disable receiving frames with bad FCS, by default. */ diff --git a/drivers/net/ethernet/sfc/efx_common.c b/drivers/net/ethernet/sfc/efx_common.c index cc30524c2fe4..361687de308d 100644 --- a/drivers/net/ethernet/sfc/efx_common.c +++ b/drivers/net/ethernet/sfc/efx_common.c @@ -544,6 +544,8 @@ void efx_start_all(struct efx_nic *efx) /* Start the hardware monitor if there is one */ efx_start_monitor(efx); + efx_selftest_async_start(efx); + /* Link state detection is normally event-driven; we have * to poll now because we could have missed a change */ diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index a2e511912e6a..a690d139e177 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -1037,8 +1037,6 @@ static int smsc911x_mii_probe(struct net_device *dev) return ret; } - /* Indicate that the MAC is responsible for managing PHY PM */ - phydev->mac_managed_pm = true; phy_attached_info(phydev); phy_set_max_speed(phydev, SPEED_100); @@ -1066,6 +1064,7 @@ static int smsc911x_mii_init(struct platform_device *pdev, struct net_device *dev) { struct smsc911x_data *pdata = netdev_priv(dev); + struct phy_device *phydev; int err = -ENXIO; pdata->mii_bus = mdiobus_alloc(); @@ -1108,6 +1107,10 @@ static int smsc911x_mii_init(struct platform_device *pdev, goto err_out_free_bus_2; } + phydev = phy_find_first(pdata->mii_bus); + if (phydev) + phydev->mac_managed_pm = true; + return 0; err_out_free_bus_2: diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index ec9c130276d8..54bb072aeb2d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -532,7 +532,6 @@ struct mac_device_info { unsigned int xlgmac; unsigned int num_vlan; u32 vlan_filter[32]; - unsigned int promisc; bool vlan_fail_q_en; u8 vlan_fail_q; }; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c index 13aa919633b4..ab9f876b6df7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c @@ -251,7 +251,6 @@ static void intel_speed_mode_2500(struct net_device *ndev, void *intel_data) priv->plat->mdio_bus_data->xpcs_an_inband = false; } else { priv->plat->max_speed = 1000; - priv->plat->mdio_bus_data->xpcs_an_inband = true; } } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 8c7a0b7c9952..36251ec2589c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -472,12 +472,6 @@ static int dwmac4_add_hw_vlan_rx_fltr(struct net_device *dev, if (vid > 4095) return -EINVAL; - if (hw->promisc) { - netdev_err(dev, - "Adding VLAN in promisc mode not supported\n"); - return -EPERM; - } - /* Single Rx VLAN Filter */ if (hw->num_vlan == 1) { /* For single VLAN filter, VID 0 means VLAN promiscuous */ @@ -527,12 +521,6 @@ static int dwmac4_del_hw_vlan_rx_fltr(struct net_device *dev, { int i, ret = 0; - if (hw->promisc) { - netdev_err(dev, - "Deleting VLAN in promisc mode not supported\n"); - return -EPERM; - } - /* Single Rx VLAN Filter */ if (hw->num_vlan == 1) { if ((hw->vlan_filter[0] & GMAC_VLAN_TAG_VID) == vid) { @@ -557,39 +545,6 @@ static int dwmac4_del_hw_vlan_rx_fltr(struct net_device *dev, return ret; } -static void dwmac4_vlan_promisc_enable(struct net_device *dev, - struct mac_device_info *hw) -{ - void __iomem *ioaddr = hw->pcsr; - u32 value; - u32 hash; - u32 val; - int i; - - /* Single Rx VLAN Filter */ - if (hw->num_vlan == 1) { - dwmac4_write_single_vlan(dev, 0); - return; - } - - /* Extended Rx VLAN Filter Enable */ - for (i = 0; i < hw->num_vlan; i++) { - if (hw->vlan_filter[i] & GMAC_VLAN_TAG_DATA_VEN) { - val = hw->vlan_filter[i] & ~GMAC_VLAN_TAG_DATA_VEN; - dwmac4_write_vlan_filter(dev, hw, i, val); - } - } - - hash = readl(ioaddr + GMAC_VLAN_HASH_TABLE); - if (hash & GMAC_VLAN_VLHT) { - value = readl(ioaddr + GMAC_VLAN_TAG); - if (value & GMAC_VLAN_VTHM) { - value &= ~GMAC_VLAN_VTHM; - writel(value, ioaddr + GMAC_VLAN_TAG); - } - } -} - static void dwmac4_restore_hw_vlan_rx_fltr(struct net_device *dev, struct mac_device_info *hw) { @@ -709,22 +664,12 @@ static void dwmac4_set_filter(struct mac_device_info *hw, } /* VLAN filtering */ - if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) + if (dev->flags & IFF_PROMISC && !hw->vlan_fail_q_en) + value &= ~GMAC_PACKET_FILTER_VTFE; + else if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) value |= GMAC_PACKET_FILTER_VTFE; writel(value, ioaddr + GMAC_PACKET_FILTER); - - if (dev->flags & IFF_PROMISC && !hw->vlan_fail_q_en) { - if (!hw->promisc) { - hw->promisc = 1; - dwmac4_vlan_promisc_enable(dev, hw); - } - } else { - if (hw->promisc) { - hw->promisc = 0; - dwmac4_restore_hw_vlan_rx_fltr(dev, hw); - } - } } static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 17310ade88dd..d7fcab057032 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1134,20 +1134,26 @@ static void stmmac_check_pcs_mode(struct stmmac_priv *priv) static int stmmac_init_phy(struct net_device *dev) { struct stmmac_priv *priv = netdev_priv(dev); + struct fwnode_handle *phy_fwnode; struct fwnode_handle *fwnode; int ret; + if (!phylink_expects_phy(priv->phylink)) + return 0; + fwnode = of_fwnode_handle(priv->plat->phylink_node); if (!fwnode) fwnode = dev_fwnode(priv->device); if (fwnode) - ret = phylink_fwnode_phy_connect(priv->phylink, fwnode, 0); + phy_fwnode = fwnode_get_phy_node(fwnode); + else + phy_fwnode = NULL; /* Some DT bindings do not set-up the PHY handle. Let's try to * manually parse it */ - if (!fwnode || ret) { + if (!phy_fwnode || IS_ERR(phy_fwnode)) { int addr = priv->plat->phy_addr; struct phy_device *phydev; @@ -1163,6 +1169,9 @@ static int stmmac_init_phy(struct net_device *dev) } ret = phylink_connect_phy(priv->phylink, phydev); + } else { + fwnode_handle_put(phy_fwnode); + ret = phylink_fwnode_phy_connect(priv->phylink, fwnode, 0); } if (!priv->plat->pmt) { @@ -6622,6 +6631,8 @@ int stmmac_xdp_open(struct net_device *dev) goto init_error; } + stmmac_reset_queues_param(priv); + /* DMA CSR Channel configuration */ for (chan = 0; chan < dma_csr_ch; chan++) { stmmac_init_chan(priv, priv->ioaddr, priv->plat->dma_cfg, chan); @@ -6948,7 +6959,7 @@ static void stmmac_napi_del(struct net_device *dev) int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt) { struct stmmac_priv *priv = netdev_priv(dev); - int ret = 0; + int ret = 0, i; if (netif_running(dev)) stmmac_release(dev); @@ -6957,6 +6968,10 @@ int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt) priv->plat->rx_queues_to_use = rx_cnt; priv->plat->tx_queues_to_use = tx_cnt; + if (!netif_is_rxfh_configured(dev)) + for (i = 0; i < ARRAY_SIZE(priv->rss.table); i++) + priv->rss.table[i] = ethtool_rxfh_indir_default(i, + rx_cnt); stmmac_napi_add(dev); diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c index ab8b09a9ef61..7a2e76776297 100644 --- a/drivers/net/ethernet/sun/niu.c +++ b/drivers/net/ethernet/sun/niu.c @@ -4522,7 +4522,7 @@ static int niu_alloc_channels(struct niu *np) err = niu_rbr_fill(np, rp, GFP_KERNEL); if (err) - return err; + goto out_err; } tx_rings = kcalloc(num_tx_rings, sizeof(struct tx_ring_info), diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c index 4e3861c47708..bcea87b7151c 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -2926,7 +2926,8 @@ err_free_phylink: am65_cpsw_nuss_phylink_cleanup(common); am65_cpts_release(common->cpts); err_of_clear: - of_platform_device_destroy(common->mdio_dev, NULL); + if (common->mdio_dev) + of_platform_device_destroy(common->mdio_dev, NULL); err_pm_clear: pm_runtime_put_sync(dev); pm_runtime_disable(dev); @@ -2956,7 +2957,8 @@ static int am65_cpsw_nuss_remove(struct platform_device *pdev) am65_cpts_release(common->cpts); am65_cpsw_disable_serdes_phy(common); - of_platform_device_destroy(common->mdio_dev, NULL); + if (common->mdio_dev) + of_platform_device_destroy(common->mdio_dev, NULL); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 37f0b62ec5d6..f9cd566d1c9b 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -27,7 +27,7 @@ #include <linux/of.h> #include <linux/of_mdio.h> #include <linux/of_net.h> -#include <linux/of_device.h> +#include <linux/of_platform.h> #include <linux/if_vlan.h> #include <linux/kmemleak.h> #include <linux/sys_soc.h> diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c index 35128dd45ffc..c61e4e44a78f 100644 --- a/drivers/net/ethernet/ti/cpsw_new.c +++ b/drivers/net/ethernet/ti/cpsw_new.c @@ -7,6 +7,7 @@ #include <linux/io.h> #include <linux/clk.h> +#include <linux/platform_device.h> #include <linux/timer.h> #include <linux/module.h> #include <linux/irqreturn.h> @@ -23,7 +24,7 @@ #include <linux/of.h> #include <linux/of_mdio.h> #include <linux/of_net.h> -#include <linux/of_device.h> +#include <linux/of_platform.h> #include <linux/if_vlan.h> #include <linux/kmemleak.h> #include <linux/sys_soc.h> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index 77d8d7f1707e..97e2c1e13b80 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -222,7 +222,7 @@ #define WX_PX_INTA 0x110 #define WX_PX_GPIE 0x118 #define WX_PX_GPIE_MODEL BIT(0) -#define WX_PX_IC 0x120 +#define WX_PX_IC(_i) (0x120 + (_i) * 4) #define WX_PX_IMS(_i) (0x140 + (_i) * 4) #define WX_PX_IMC(_i) (0x150 + (_i) * 4) #define WX_PX_ISB_ADDR_L 0x160 diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c index 5b564d348c09..17412e5282de 100644 --- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c +++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c @@ -352,7 +352,7 @@ static void ngbe_up(struct wx *wx) netif_tx_start_all_queues(wx->netdev); /* clear any pending interrupts, may auto mask */ - rd32(wx, WX_PX_IC); + rd32(wx, WX_PX_IC(0)); rd32(wx, WX_PX_MISC_IC); ngbe_irq_enable(wx, true); if (wx->gpio_ctrl) diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index 6c0a98230557..a58ce5463686 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -229,7 +229,8 @@ static void txgbe_up_complete(struct wx *wx) wx_napi_enable_all(wx); /* clear any pending interrupts, may auto mask */ - rd32(wx, WX_PX_IC); + rd32(wx, WX_PX_IC(0)); + rd32(wx, WX_PX_IC(1)); rd32(wx, WX_PX_MISC_IC); txgbe_irq_enable(wx, true); diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig index a9c44f08199d..a94c7bd5db2e 100644 --- a/drivers/net/hamradio/Kconfig +++ b/drivers/net/hamradio/Kconfig @@ -47,7 +47,7 @@ config BPQETHER config SCC tristate "Z8530 SCC driver" - depends on ISA && AX25 && ISA_DMA_API + depends on ISA && AX25 help These cards are used to connect your Linux box to an amateur radio in order to communicate with other computers. If you want to use diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c index 0b0c6c0764fe..d0b5129439ed 100644 --- a/drivers/net/ieee802154/ca8210.c +++ b/drivers/net/ieee802154/ca8210.c @@ -1902,10 +1902,9 @@ static int ca8210_skb_tx( struct ca8210_priv *priv ) { - int status; struct ieee802154_hdr header = { }; struct secspec secspec; - unsigned int mac_len; + int mac_len, status; dev_dbg(&priv->spi->dev, "%s called\n", __func__); diff --git a/drivers/net/ipa/gsi_trans.c b/drivers/net/ipa/gsi_trans.c index 0f52c068c46d..ee6fb00b71eb 100644 --- a/drivers/net/ipa/gsi_trans.c +++ b/drivers/net/ipa/gsi_trans.c @@ -156,7 +156,7 @@ int gsi_trans_pool_init_dma(struct device *dev, struct gsi_trans_pool *pool, * gsi_trans_pool_exit_dma() can assume the total allocated * size is exactly (count * size). */ - total_size = get_order(total_size) << PAGE_SHIFT; + total_size = PAGE_SIZE << get_order(total_size); virt = dma_alloc_coherent(dev, total_size, &addr, GFP_KERNEL); if (!virt) diff --git a/drivers/net/net_failover.c b/drivers/net/net_failover.c index 7a28e082436e..d0c916a53d7c 100644 --- a/drivers/net/net_failover.c +++ b/drivers/net/net_failover.c @@ -130,14 +130,10 @@ static u16 net_failover_select_queue(struct net_device *dev, txq = ops->ndo_select_queue(primary_dev, skb, sb_dev); else txq = netdev_pick_tx(primary_dev, skb, NULL); - - qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb->queue_mapping; - - return txq; + } else { + txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0; } - txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0; - /* Save the original txq to restore before passing to the driver */ qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb->queue_mapping; diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c index b4ff9c5073a3..9ab5eff502b7 100644 --- a/drivers/net/phy/dp83869.c +++ b/drivers/net/phy/dp83869.c @@ -588,15 +588,13 @@ static int dp83869_of_init(struct phy_device *phydev) &dp83869_internal_delay[0], delay_size, true); if (dp83869->rx_int_delay < 0) - dp83869->rx_int_delay = - dp83869_internal_delay[DP83869_CLK_DELAY_DEF]; + dp83869->rx_int_delay = DP83869_CLK_DELAY_DEF; dp83869->tx_int_delay = phy_get_internal_delay(phydev, dev, &dp83869_internal_delay[0], delay_size, false); if (dp83869->tx_int_delay < 0) - dp83869->tx_int_delay = - dp83869_internal_delay[DP83869_CLK_DELAY_DEF]; + dp83869->tx_int_delay = DP83869_CLK_DELAY_DEF; return ret; } diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 2c84fccef4f6..4e884e4ba0ea 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -4151,6 +4151,7 @@ static struct phy_driver ksphy_driver[] = { .resume = kszphy_resume, .cable_test_start = ksz9x31_cable_test_start, .cable_test_get_status = ksz9x31_cable_test_get_status, + .get_features = ksz9477_get_features, }, { .phy_id = PHY_ID_KSZ8873MLL, .phy_id_mask = MICREL_PHY_ID_MASK, diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c index 5813b07242ce..029875a59ff8 100644 --- a/drivers/net/phy/nxp-c45-tja11xx.c +++ b/drivers/net/phy/nxp-c45-tja11xx.c @@ -191,7 +191,7 @@ #define MAX_ID_PS 2260U #define DEFAULT_ID_PS 2000U -#define PPM_TO_SUBNS_INC(ppb) div_u64(GENMASK(31, 0) * (ppb) * \ +#define PPM_TO_SUBNS_INC(ppb) div_u64(GENMASK_ULL(31, 0) * (ppb) * \ PTP_CLK_PERIOD_100BT1, NSEC_PER_SEC) #define NXP_C45_SKB_CB(skb) ((struct nxp_c45_skb_cb *)(skb)->cb) @@ -1337,6 +1337,17 @@ no_ptp_support: return ret; } +static void nxp_c45_remove(struct phy_device *phydev) +{ + struct nxp_c45_phy *priv = phydev->priv; + + if (priv->ptp_clock) + ptp_clock_unregister(priv->ptp_clock); + + skb_queue_purge(&priv->tx_queue); + skb_queue_purge(&priv->rx_queue); +} + static struct phy_driver nxp_c45_driver[] = { { PHY_ID_MATCH_MODEL(PHY_ID_TJA_1103), @@ -1359,6 +1370,7 @@ static struct phy_driver nxp_c45_driver[] = { .set_loopback = genphy_c45_loopback, .get_sqi = nxp_c45_get_sqi, .get_sqi_max = nxp_c45_get_sqi_max, + .remove = nxp_c45_remove, }, }; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 1785f1cead97..1de3e339b31a 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -3057,7 +3057,7 @@ EXPORT_SYMBOL_GPL(device_phy_find_device); * and "phy-device" are not supported in ACPI. DT supports all the three * named references to the phy node. */ -struct fwnode_handle *fwnode_get_phy_node(struct fwnode_handle *fwnode) +struct fwnode_handle *fwnode_get_phy_node(const struct fwnode_handle *fwnode) { struct fwnode_handle *phy_node; diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 1a2f074685fa..30c166b33468 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1586,6 +1586,25 @@ void phylink_destroy(struct phylink *pl) } EXPORT_SYMBOL_GPL(phylink_destroy); +/** + * phylink_expects_phy() - Determine if phylink expects a phy to be attached + * @pl: a pointer to a &struct phylink returned from phylink_create() + * + * When using fixed-link mode, or in-band mode with 1000base-X or 2500base-X, + * no PHY is needed. + * + * Returns true if phylink will be expecting a PHY. + */ +bool phylink_expects_phy(struct phylink *pl) +{ + if (pl->cfg_link_an_mode == MLO_AN_FIXED || + (pl->cfg_link_an_mode == MLO_AN_INBAND && + phy_interface_mode_is_8023z(pl->link_config.interface))) + return false; + return true; +} +EXPORT_SYMBOL_GPL(phylink_expects_phy); + static void phylink_phy_change(struct phy_device *phydev, bool up) { struct phylink *pl = phydev->phylink; diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c index daac293e8ede..9fc50fcc8fc9 100644 --- a/drivers/net/phy/sfp-bus.c +++ b/drivers/net/phy/sfp-bus.c @@ -17,7 +17,7 @@ struct sfp_bus { /* private: */ struct kref kref; struct list_head node; - struct fwnode_handle *fwnode; + const struct fwnode_handle *fwnode; const struct sfp_socket_ops *socket_ops; struct device *sfp_dev; @@ -390,7 +390,7 @@ static const struct sfp_upstream_ops *sfp_get_upstream_ops(struct sfp_bus *bus) return bus->registered ? bus->upstream_ops : NULL; } -static struct sfp_bus *sfp_bus_get(struct fwnode_handle *fwnode) +static struct sfp_bus *sfp_bus_get(const struct fwnode_handle *fwnode) { struct sfp_bus *sfp, *new, *found = NULL; @@ -593,7 +593,7 @@ static void sfp_upstream_clear(struct sfp_bus *bus) * - %-ENOMEM if we failed to allocate the bus. * - an error from the upstream's connect_phy() method. */ -struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode) +struct sfp_bus *sfp_bus_find_fwnode(const struct fwnode_handle *fwnode) { struct fwnode_reference_args ref; struct sfp_bus *bus; diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index fb98db61e06c..bf345032d450 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -210,6 +210,12 @@ static const enum gpiod_flags gpio_flags[] = { #define SFP_PHY_ADDR 22 #define SFP_PHY_ADDR_ROLLBALL 17 +/* SFP_EEPROM_BLOCK_SIZE is the size of data chunk to read the EEPROM + * at a time. Some SFP modules and also some Linux I2C drivers do not like + * reads longer than 16 bytes. + */ +#define SFP_EEPROM_BLOCK_SIZE 16 + struct sff_data { unsigned int gpios; bool (*module_supported)(const struct sfp_eeprom_id *id); @@ -387,6 +393,10 @@ static const struct sfp_quirk sfp_quirks[] = { SFP_QUIRK_F("HALNy", "HL-GSFP", sfp_fixup_halny_gsfp), + // HG MXPD-483II-F 2.5G supports 2500Base-X, but incorrectly reports + // 2600MBd in their EERPOM + SFP_QUIRK_M("HG GENUINE", "MXPD-483II", sfp_quirk_2500basex), + // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd NRZ in // their EEPROM SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex, @@ -1925,11 +1935,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) u8 check; int ret; - /* Some SFP modules and also some Linux I2C drivers do not like reads - * longer than 16 bytes, so read the EEPROM in chunks of 16 bytes at - * a time. - */ - sfp->i2c_block_size = 16; + sfp->i2c_block_size = SFP_EEPROM_BLOCK_SIZE; ret = sfp_read(sfp, false, 0, &id.base, sizeof(id.base)); if (ret < 0) { @@ -2481,6 +2487,9 @@ static int sfp_module_eeprom(struct sfp *sfp, struct ethtool_eeprom *ee, unsigned int first, last, len; int ret; + if (!(sfp->state & SFP_F_PRESENT)) + return -ENODEV; + if (ee->len == 0) return -EINVAL; @@ -2513,6 +2522,9 @@ static int sfp_module_eeprom_by_page(struct sfp *sfp, const struct ethtool_module_eeprom *page, struct netlink_ext_ack *extack) { + if (!(sfp->state & SFP_F_PRESENT)) + return -ENODEV; + if (page->bank) { NL_SET_ERR_MSG(extack, "Banks not supported"); return -EOPNOTSUPP; @@ -2617,6 +2629,7 @@ static struct sfp *sfp_alloc(struct device *dev) return ERR_PTR(-ENOMEM); sfp->dev = dev; + sfp->i2c_block_size = SFP_EEPROM_BLOCK_SIZE; mutex_init(&sfp->sm_mutex); mutex_init(&sfp->st_mutex); diff --git a/drivers/net/tun.c b/drivers/net/tun.c index ad653b32b2f0..5df1eba7b30a 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1486,7 +1486,8 @@ static struct sk_buff *tun_napi_alloc_frags(struct tun_file *tfile, skb->truesize += skb->data_len; for (i = 1; i < it->nr_segs; i++) { - size_t fragsz = it->iov[i].iov_len; + const struct iovec *iov = iter_iov(it); + size_t fragsz = iov->iov_len; struct page *page; void *frag; diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index decb5ba56a25..0fc4b959edc1 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1943,7 +1943,7 @@ static struct rx_agg *alloc_rx_agg(struct r8152 *tp, gfp_t mflags) if (!rx_agg) return NULL; - rx_agg->page = alloc_pages(mflags | __GFP_COMP, order); + rx_agg->page = alloc_pages(mflags | __GFP_COMP | __GFP_NOWARN, order); if (!rx_agg->page) goto free_rx; diff --git a/drivers/net/veth.c b/drivers/net/veth.c index c1178915496d..4b3c6647edc6 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -1262,11 +1262,12 @@ static void veth_set_xdp_features(struct net_device *dev) peer = rtnl_dereference(priv->peer); if (peer && peer->real_num_tx_queues <= dev->real_num_rx_queues) { + struct veth_priv *priv_peer = netdev_priv(peer); xdp_features_t val = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | NETDEV_XDP_ACT_RX_SG; - if (priv->_xdp_prog || veth_gro_requested(dev)) + if (priv_peer->_xdp_prog || veth_gro_requested(peer)) val |= NETDEV_XDP_ACT_NDO_XMIT | NETDEV_XDP_ACT_NDO_XMIT_SG; xdp_set_features_flag(dev, val); @@ -1504,19 +1505,23 @@ static int veth_set_features(struct net_device *dev, { netdev_features_t changed = features ^ dev->features; struct veth_priv *priv = netdev_priv(dev); + struct net_device *peer; int err; if (!(changed & NETIF_F_GRO) || !(dev->flags & IFF_UP) || priv->_xdp_prog) return 0; + peer = rtnl_dereference(priv->peer); if (features & NETIF_F_GRO) { err = veth_napi_enable(dev); if (err) return err; - xdp_features_set_redirect_target(dev, true); + if (peer) + xdp_features_set_redirect_target(peer, true); } else { - xdp_features_clear_redirect_target(dev); + if (peer) + xdp_features_clear_redirect_target(peer); veth_napi_del(dev); } return 0; @@ -1598,13 +1603,13 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog, peer->max_mtu = max_mtu; } - xdp_features_set_redirect_target(dev, true); + xdp_features_set_redirect_target(peer, true); } if (old_prog) { if (!prog) { - if (!veth_gro_requested(dev)) - xdp_features_clear_redirect_target(dev); + if (peer && !veth_gro_requested(dev)) + xdp_features_clear_redirect_target(peer); if (dev->flags & IFF_UP) veth_disable_xdp(dev); @@ -1648,14 +1653,18 @@ static int veth_xdp_rx_timestamp(const struct xdp_md *ctx, u64 *timestamp) return 0; } -static int veth_xdp_rx_hash(const struct xdp_md *ctx, u32 *hash) +static int veth_xdp_rx_hash(const struct xdp_md *ctx, u32 *hash, + enum xdp_rss_hash_type *rss_type) { struct veth_xdp_buff *_ctx = (void *)ctx; + struct sk_buff *skb = _ctx->skb; - if (!_ctx->skb) + if (!skb) return -ENODATA; - *hash = skb_get_hash(_ctx->skb); + *hash = skb_get_hash(skb); + *rss_type = skb->l4_hash ? XDP_RSS_TYPE_L4_ANY : XDP_RSS_TYPE_NONE; + return 0; } diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 2396c28c0122..ea1bd4bb326d 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -814,8 +814,13 @@ static struct page *xdp_linearize_page(struct receive_queue *rq, int page_off, unsigned int *len) { - struct page *page = alloc_page(GFP_ATOMIC); + int tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + struct page *page; + + if (page_off + *len + tailroom > PAGE_SIZE) + return NULL; + page = alloc_page(GFP_ATOMIC); if (!page) return NULL; @@ -823,7 +828,6 @@ static struct page *xdp_linearize_page(struct receive_queue *rq, page_off += *len; while (--*num_buf) { - int tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); unsigned int buflen; void *buf; int off; diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 682987040ea8..f2b76ee866a4 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -1504,7 +1504,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, goto rcd_done; } - if (rxDataRingUsed) { + if (rxDataRingUsed && adapter->rxdataring_enabled) { size_t sz; BUG_ON(rcd->len > rq->data_ring.desc_size); @@ -1688,7 +1688,9 @@ not_lro: if (unlikely(rcd->ts)) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rcd->tci); - if (adapter->netdev->features & NETIF_F_LRO) + /* Use GRO callback if UPT is enabled */ + if ((adapter->netdev->features & NETIF_F_LRO) && + !rq->shared->updateRxProd) netif_receive_skb(skb); else napi_gro_receive(&rq->napi, skb); diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index 90f457b8e1fe..038c5903c0dc 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -33,7 +33,7 @@ static int ath10k_qmi_map_msa_permission(struct ath10k_qmi *qmi, { struct qcom_scm_vmperm dst_perms[3]; struct ath10k *ar = qmi->ar; - unsigned int src_perms; + u64 src_perms; u32 perm_count; int ret; @@ -65,7 +65,7 @@ static int ath10k_qmi_unmap_msa_permission(struct ath10k_qmi *qmi, { struct qcom_scm_vmperm dst_perms; struct ath10k *ar = qmi->ar; - unsigned int src_perms; + u64 src_perms; int ret; src_perms = BIT(QCOM_SCM_VMID_MSS_MSA) | BIT(QCOM_SCM_VMID_WLAN); diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index 86995e8dc913..a62ee05c5409 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -16,7 +16,7 @@ #include "pci.h" #include "pcic.h" -#define MHI_TIMEOUT_DEFAULT_MS 90000 +#define MHI_TIMEOUT_DEFAULT_MS 20000 #define RDDM_DUMP_SIZE 0x420000 static struct mhi_channel_config ath11k_mhi_channels_qca6390[] = { diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 3363fc4e8966..a0845002d6fe 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -646,9 +646,7 @@ void ath9k_mci_update_wlan_channels(struct ath_softc *sc, bool allow_all) struct ath_hw *ah = sc->sc_ah; struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; struct ath9k_channel *chan = ah->curchan; - static const u32 channelmap[] = { - 0x00000000, 0xffff0000, 0xffffffff, 0x7fffffff - }; + u32 channelmap[] = {0x00000000, 0xffff0000, 0xffffffff, 0x7fffffff}; int i; s16 chan_start, chan_end; u16 wlan_chan; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index b7c918f241c9..65d4799a5658 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -994,15 +994,34 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); -static void brcmf_sdiod_acpi_set_power_manageable(struct device *dev, - int val) +static void brcmf_sdiod_acpi_save_power_manageable(struct brcmf_sdio_dev *sdiodev) { #if IS_ENABLED(CONFIG_ACPI) struct acpi_device *adev; - adev = ACPI_COMPANION(dev); + adev = ACPI_COMPANION(&sdiodev->func1->dev); if (adev) - adev->flags.power_manageable = 0; + sdiodev->func1_power_manageable = adev->flags.power_manageable; + + adev = ACPI_COMPANION(&sdiodev->func2->dev); + if (adev) + sdiodev->func2_power_manageable = adev->flags.power_manageable; +#endif +} + +static void brcmf_sdiod_acpi_set_power_manageable(struct brcmf_sdio_dev *sdiodev, + int enable) +{ +#if IS_ENABLED(CONFIG_ACPI) + struct acpi_device *adev; + + adev = ACPI_COMPANION(&sdiodev->func1->dev); + if (adev) + adev->flags.power_manageable = enable ? sdiodev->func1_power_manageable : 0; + + adev = ACPI_COMPANION(&sdiodev->func2->dev); + if (adev) + adev->flags.power_manageable = enable ? sdiodev->func2_power_manageable : 0; #endif } @@ -1012,7 +1031,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, int err; struct brcmf_sdio_dev *sdiodev; struct brcmf_bus *bus_if; - struct device *dev; brcmf_dbg(SDIO, "Enter\n"); brcmf_dbg(SDIO, "Class=%x\n", func->class); @@ -1020,14 +1038,9 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device); brcmf_dbg(SDIO, "Function#: %d\n", func->num); - dev = &func->dev; - /* Set MMC_QUIRK_LENIENT_FN0 for this card */ func->card->quirks |= MMC_QUIRK_LENIENT_FN0; - /* prohibit ACPI power management for this device */ - brcmf_sdiod_acpi_set_power_manageable(dev, 0); - /* Consume func num 1 but dont do anything with it. */ if (func->num == 1) return 0; @@ -1059,6 +1072,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, dev_set_drvdata(&sdiodev->func1->dev, bus_if); sdiodev->dev = &sdiodev->func1->dev; + brcmf_sdiod_acpi_save_power_manageable(sdiodev); brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_DOWN); brcmf_dbg(SDIO, "F2 found, calling brcmf_sdiod_probe...\n"); @@ -1124,6 +1138,8 @@ void brcmf_sdio_wowl_config(struct device *dev, bool enabled) if (sdiodev->settings->bus.sdio.oob_irq_supported || pm_caps & MMC_PM_WAKE_SDIO_IRQ) { + /* Stop ACPI from turning off the device when wowl is enabled */ + brcmf_sdiod_acpi_set_power_manageable(sdiodev, !enabled); sdiodev->wowl_enabled = enabled; brcmf_dbg(SDIO, "Configuring WOWL, enabled=%d\n", enabled); return; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h index b76d34d36bde..0d18ed15b403 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h @@ -188,6 +188,8 @@ struct brcmf_sdio_dev { char nvram_name[BRCMF_FW_NAME_LEN]; char clm_name[BRCMF_FW_NAME_LEN]; bool wowl_enabled; + bool func1_power_manageable; + bool func2_power_manageable; enum brcmf_sdiod_state state; struct brcmf_sdiod_freezer *freezer; const struct firmware *clm_fw; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index ca50feb0b3a9..1b1358c6bb46 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -512,15 +512,15 @@ mt7603_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) return -EOPNOTSUPP; - if (cmd == SET_KEY) { - key->hw_key_idx = wcid->idx; - wcid->hw_key_idx = idx; - } else { + if (cmd != SET_KEY) { if (idx == wcid->hw_key_idx) wcid->hw_key_idx = -1; - key = NULL; + return 0; } + + key->hw_key_idx = wcid->idx; + wcid->hw_key_idx = idx; mt76_wcid_key_setup(&dev->mt76, wcid, key); return mt7603_wtbl_set_key(dev, wcid->idx, key); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index a95602473359..51a968a6afdc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1193,8 +1193,7 @@ EXPORT_SYMBOL_GPL(mt7615_mac_enable_rtscts); static int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, - enum mt76_cipher_type cipher, u16 cipher_mask, - enum set_key_cmd cmd) + enum mt76_cipher_type cipher, u16 cipher_mask) { u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx) + 30 * 4; u8 data[32] = {}; @@ -1203,27 +1202,18 @@ mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, return -EINVAL; mt76_rr_copy(dev, addr, data, sizeof(data)); - if (cmd == SET_KEY) { - if (cipher == MT_CIPHER_TKIP) { - /* Rx/Tx MIC keys are swapped */ - memcpy(data, key->key, 16); - memcpy(data + 16, key->key + 24, 8); - memcpy(data + 24, key->key + 16, 8); - } else { - if (cipher_mask == BIT(cipher)) - memcpy(data, key->key, key->keylen); - else if (cipher != MT_CIPHER_BIP_CMAC_128) - memcpy(data, key->key, 16); - if (cipher == MT_CIPHER_BIP_CMAC_128) - memcpy(data + 16, key->key, 16); - } + if (cipher == MT_CIPHER_TKIP) { + /* Rx/Tx MIC keys are swapped */ + memcpy(data, key->key, 16); + memcpy(data + 16, key->key + 24, 8); + memcpy(data + 24, key->key + 16, 8); } else { + if (cipher_mask == BIT(cipher)) + memcpy(data, key->key, key->keylen); + else if (cipher != MT_CIPHER_BIP_CMAC_128) + memcpy(data, key->key, 16); if (cipher == MT_CIPHER_BIP_CMAC_128) - memset(data + 16, 0, 16); - else if (cipher_mask) - memset(data, 0, 16); - if (!cipher_mask) - memset(data, 0, sizeof(data)); + memcpy(data + 16, key->key, 16); } mt76_wr_copy(dev, addr, data, sizeof(data)); @@ -1234,7 +1224,7 @@ mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, static int mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid, enum mt76_cipher_type cipher, u16 cipher_mask, - int keyidx, enum set_key_cmd cmd) + int keyidx) { u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx), w0, w1; @@ -1253,9 +1243,7 @@ mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid, else w0 &= ~MT_WTBL_W0_RX_IK_VALID; - if (cmd == SET_KEY && - (cipher != MT_CIPHER_BIP_CMAC_128 || - cipher_mask == BIT(cipher))) { + if (cipher != MT_CIPHER_BIP_CMAC_128 || cipher_mask == BIT(cipher)) { w0 &= ~MT_WTBL_W0_KEY_IDX; w0 |= FIELD_PREP(MT_WTBL_W0_KEY_IDX, keyidx); } @@ -1272,19 +1260,10 @@ mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid, static void mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev, struct mt76_wcid *wcid, - enum mt76_cipher_type cipher, u16 cipher_mask, - enum set_key_cmd cmd) + enum mt76_cipher_type cipher, u16 cipher_mask) { u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx); - if (!cipher_mask) { - mt76_clear(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE); - return; - } - - if (cmd != SET_KEY) - return; - if (cipher == MT_CIPHER_BIP_CMAC_128 && cipher_mask & ~BIT(MT_CIPHER_BIP_CMAC_128)) return; @@ -1295,8 +1274,7 @@ mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev, struct mt76_wcid *wcid, int __mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, - struct ieee80211_key_conf *key, - enum set_key_cmd cmd) + struct ieee80211_key_conf *key) { enum mt76_cipher_type cipher; u16 cipher_mask = wcid->cipher; @@ -1306,19 +1284,14 @@ int __mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, if (cipher == MT_CIPHER_NONE) return -EOPNOTSUPP; - if (cmd == SET_KEY) - cipher_mask |= BIT(cipher); - else - cipher_mask &= ~BIT(cipher); - - mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, cipher_mask, cmd); - err = mt7615_mac_wtbl_update_key(dev, wcid, key, cipher, cipher_mask, - cmd); + cipher_mask |= BIT(cipher); + mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, cipher_mask); + err = mt7615_mac_wtbl_update_key(dev, wcid, key, cipher, cipher_mask); if (err < 0) return err; err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, cipher_mask, - key->keyidx, cmd); + key->keyidx); if (err < 0) return err; @@ -1329,13 +1302,12 @@ int __mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, - struct ieee80211_key_conf *key, - enum set_key_cmd cmd) + struct ieee80211_key_conf *key) { int err; spin_lock_bh(&dev->mt76.lock); - err = __mt7615_mac_wtbl_set_key(dev, wcid, key, cmd); + err = __mt7615_mac_wtbl_set_key(dev, wcid, key); spin_unlock_bh(&dev->mt76.lock); return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index ab4c1b4478aa..dadb13f2ca09 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -391,18 +391,17 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (cmd == SET_KEY) *wcid_keyidx = idx; - else if (idx == *wcid_keyidx) - *wcid_keyidx = -1; - else + else { + if (idx == *wcid_keyidx) + *wcid_keyidx = -1; goto out; + } - mt76_wcid_key_setup(&dev->mt76, wcid, - cmd == SET_KEY ? key : NULL); - + mt76_wcid_key_setup(&dev->mt76, wcid, key); if (mt76_is_mmio(&dev->mt76)) - err = mt7615_mac_wtbl_set_key(dev, wcid, key, cmd); + err = mt7615_mac_wtbl_set_key(dev, wcid, key); else - err = __mt7615_mac_wtbl_set_key(dev, wcid, key, cmd); + err = __mt7615_mac_wtbl_set_key(dev, wcid, key); out: mt7615_mutex_release(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 43591b4c1d9a..9e58f6924493 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -490,11 +490,9 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, void mt7615_mac_set_timing(struct mt7615_phy *phy); int __mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, - struct ieee80211_key_conf *key, - enum set_key_cmd cmd); + struct ieee80211_key_conf *key); int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, - struct ieee80211_key_conf *key, - enum set_key_cmd cmd); + struct ieee80211_key_conf *key); void mt7615_mac_reset_work(struct work_struct *work); u32 mt7615_mac_get_sta_tid_sn(struct mt7615_dev *dev, int wcid, u8 tid); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 7451a63206a5..dcbb5c605dfe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -454,20 +454,20 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, msta = sta ? (struct mt76x02_sta *)sta->drv_priv : NULL; wcid = msta ? &msta->wcid : &mvif->group_wcid; - if (cmd == SET_KEY) { - key->hw_key_idx = wcid->idx; - wcid->hw_key_idx = idx; - if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) { - key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; - wcid->sw_iv = true; - } - } else { + if (cmd != SET_KEY) { if (idx == wcid->hw_key_idx) { wcid->hw_key_idx = -1; wcid->sw_iv = false; } - key = NULL; + return 0; + } + + key->hw_key_idx = wcid->idx; + wcid->hw_key_idx = idx; + if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) { + key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; + wcid->sw_iv = true; } mt76_wcid_key_setup(&dev->mt76, wcid, key); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 3bbccbdfc5eb..784191ec4802 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -410,16 +410,15 @@ static int mt7915_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mt7915_mcu_add_bss_info(phy, vif, true); } - if (cmd == SET_KEY) + if (cmd == SET_KEY) { *wcid_keyidx = idx; - else if (idx == *wcid_keyidx) - *wcid_keyidx = -1; - else + } else { + if (idx == *wcid_keyidx) + *wcid_keyidx = -1; goto out; + } - mt76_wcid_key_setup(&dev->mt76, wcid, - cmd == SET_KEY ? key : NULL); - + mt76_wcid_key_setup(&dev->mt76, wcid, key); err = mt76_connac_mcu_add_key(&dev->mt76, vif, &msta->bip, key, MCU_EXT_CMD(STA_REC_UPDATE), &msta->wcid, cmd); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 80c71acfe159..cc94531185da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -171,12 +171,12 @@ mt7921_mac_init_band(struct mt7921_dev *dev, u8 band) u8 mt7921_check_offload_capability(struct device *dev, const char *fw_wm) { - struct mt7921_fw_features *features = NULL; const struct mt76_connac2_fw_trailer *hdr; struct mt7921_realease_info *rel_info; const struct firmware *fw; int ret, i, offset = 0; const u8 *data, *end; + u8 offload_caps = 0; ret = request_firmware(&fw, fw_wm, dev); if (ret) @@ -208,7 +208,10 @@ u8 mt7921_check_offload_capability(struct device *dev, const char *fw_wm) data += sizeof(*rel_info); if (rel_info->tag == MT7921_FW_TAG_FEATURE) { + struct mt7921_fw_features *features; + features = (struct mt7921_fw_features *)data; + offload_caps = features->data; break; } @@ -218,7 +221,7 @@ u8 mt7921_check_offload_capability(struct device *dev, const char *fw_wm) out: release_firmware(fw); - return features ? features->data : 0; + return offload_caps; } EXPORT_SYMBOL_GPL(mt7921_check_offload_capability); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 75eaf86c6a78..42933a6b7334 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -569,16 +569,15 @@ static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mt7921_mutex_acquire(dev); - if (cmd == SET_KEY) + if (cmd == SET_KEY) { *wcid_keyidx = idx; - else if (idx == *wcid_keyidx) - *wcid_keyidx = -1; - else + } else { + if (idx == *wcid_keyidx) + *wcid_keyidx = -1; goto out; + } - mt76_wcid_key_setup(&dev->mt76, wcid, - cmd == SET_KEY ? key : NULL); - + mt76_wcid_key_setup(&dev->mt76, wcid, key); err = mt76_connac_mcu_add_key(&dev->mt76, vif, &msta->bip, key, MCU_UNI_CMD(STA_REC_UPDATE), &msta->wcid, cmd); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index cb72ded37256..5c23c827abe4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -20,7 +20,7 @@ static const struct pci_device_id mt7921_pci_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0608), .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM }, { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0616), - .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM }, + .driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM }, { }, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 3e4da0350d96..1ba22d147949 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -351,16 +351,15 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mt7996_mcu_add_bss_info(phy, vif, true); } - if (cmd == SET_KEY) + if (cmd == SET_KEY) { *wcid_keyidx = idx; - else if (idx == *wcid_keyidx) - *wcid_keyidx = -1; - else + } else { + if (idx == *wcid_keyidx) + *wcid_keyidx = -1; goto out; + } - mt76_wcid_key_setup(&dev->mt76, wcid, - cmd == SET_KEY ? key : NULL); - + mt76_wcid_key_setup(&dev->mt76, wcid, key); err = mt7996_mcu_add_key(&dev->mt76, vif, &msta->bip, key, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), &msta->wcid, cmd); diff --git a/drivers/net/wwan/iosm/iosm_ipc_imem.c b/drivers/net/wwan/iosm/iosm_ipc_imem.c index 1e6a47976642..c066b0040a3f 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_imem.c +++ b/drivers/net/wwan/iosm/iosm_ipc_imem.c @@ -587,6 +587,13 @@ static void ipc_imem_run_state_worker(struct work_struct *instance) while (ctrl_chl_idx < IPC_MEM_MAX_CHANNELS) { if (!ipc_chnl_cfg_get(&chnl_cfg_port, ctrl_chl_idx)) { ipc_imem->ipc_port[ctrl_chl_idx] = NULL; + + if (ipc_imem->pcie->pci->device == INTEL_CP_DEVICE_7560_ID && + chnl_cfg_port.wwan_port_type == WWAN_PORT_XMMRPC) { + ctrl_chl_idx++; + continue; + } + if (ipc_imem->pcie->pci->device == INTEL_CP_DEVICE_7360_ID && chnl_cfg_port.wwan_port_type == WWAN_PORT_MBIM) { ctrl_chl_idx++; diff --git a/drivers/net/wwan/iosm/iosm_ipc_pcie.c b/drivers/net/wwan/iosm/iosm_ipc_pcie.c index 5bf5a93937c9..04517bd3325a 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_pcie.c +++ b/drivers/net/wwan/iosm/iosm_ipc_pcie.c @@ -295,7 +295,7 @@ static int ipc_pcie_probe(struct pci_dev *pci, ret = dma_set_mask(ipc_pcie->dev, DMA_BIT_MASK(64)); if (ret) { dev_err(ipc_pcie->dev, "Could not set PCI DMA mask: %d", ret); - return ret; + goto set_mask_fail; } ipc_pcie_config_aspm(ipc_pcie); @@ -323,6 +323,7 @@ static int ipc_pcie_probe(struct pci_dev *pci, imem_init_fail: ipc_pcie_resources_release(ipc_pcie); resources_req_fail: +set_mask_fail: pci_disable_device(pci); pci_enable_fail: kfree(ipc_pcie); diff --git a/drivers/net/wwan/t7xx/Makefile b/drivers/net/wwan/t7xx/Makefile index 268ff9e87e5b..2652cd00504e 100644 --- a/drivers/net/wwan/t7xx/Makefile +++ b/drivers/net/wwan/t7xx/Makefile @@ -1,7 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -ccflags-y += -Werror - obj-${CONFIG_MTK_T7XX} := mtk_t7xx.o mtk_t7xx-y:= t7xx_pci.o \ t7xx_pcie_mac.o \ diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 3dbfc8a6924e..1fcbd83f7ff2 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -166,7 +166,7 @@ struct xenvif_queue { /* Per-queue data for xenvif */ struct pending_tx_info pending_tx_info[MAX_PENDING_REQS]; grant_handle_t grant_tx_handle[MAX_PENDING_REQS]; - struct gnttab_copy tx_copy_ops[MAX_PENDING_REQS]; + struct gnttab_copy tx_copy_ops[2 * MAX_PENDING_REQS]; struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS]; struct gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS]; /* passed to gnttab_[un]map_refs with pages under (un)mapping */ diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 1b42676ca141..c1501f41e2d8 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -334,6 +334,7 @@ static int xenvif_count_requests(struct xenvif_queue *queue, struct xenvif_tx_cb { u16 copy_pending_idx[XEN_NETBK_LEGACY_SLOTS_MAX + 1]; u8 copy_count; + u32 split_mask; }; #define XENVIF_TX_CB(skb) ((struct xenvif_tx_cb *)(skb)->cb) @@ -361,6 +362,8 @@ static inline struct sk_buff *xenvif_alloc_skb(unsigned int size) struct sk_buff *skb = alloc_skb(size + NET_SKB_PAD + NET_IP_ALIGN, GFP_ATOMIC | __GFP_NOWARN); + + BUILD_BUG_ON(sizeof(*XENVIF_TX_CB(skb)) > sizeof(skb->cb)); if (unlikely(skb == NULL)) return NULL; @@ -396,11 +399,13 @@ static void xenvif_get_requests(struct xenvif_queue *queue, nr_slots = shinfo->nr_frags + 1; copy_count(skb) = 0; + XENVIF_TX_CB(skb)->split_mask = 0; /* Create copy ops for exactly data_len bytes into the skb head. */ __skb_put(skb, data_len); while (data_len > 0) { int amount = data_len > txp->size ? txp->size : data_len; + bool split = false; cop->source.u.ref = txp->gref; cop->source.domid = queue->vif->domid; @@ -413,6 +418,13 @@ static void xenvif_get_requests(struct xenvif_queue *queue, cop->dest.u.gmfn = virt_to_gfn(skb->data + skb_headlen(skb) - data_len); + /* Don't cross local page boundary! */ + if (cop->dest.offset + amount > XEN_PAGE_SIZE) { + amount = XEN_PAGE_SIZE - cop->dest.offset; + XENVIF_TX_CB(skb)->split_mask |= 1U << copy_count(skb); + split = true; + } + cop->len = amount; cop->flags = GNTCOPY_source_gref; @@ -420,7 +432,8 @@ static void xenvif_get_requests(struct xenvif_queue *queue, pending_idx = queue->pending_ring[index]; callback_param(queue, pending_idx).ctx = NULL; copy_pending_idx(skb, copy_count(skb)) = pending_idx; - copy_count(skb)++; + if (!split) + copy_count(skb)++; cop++; data_len -= amount; @@ -441,7 +454,8 @@ static void xenvif_get_requests(struct xenvif_queue *queue, nr_slots--; } else { /* The copy op partially covered the tx_request. - * The remainder will be mapped. + * The remainder will be mapped or copied in the next + * iteration. */ txp->offset += amount; txp->size -= amount; @@ -539,6 +553,13 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue, pending_idx = copy_pending_idx(skb, i); newerr = (*gopp_copy)->status; + + /* Split copies need to be handled together. */ + if (XENVIF_TX_CB(skb)->split_mask & (1U << i)) { + (*gopp_copy)++; + if (!newerr) + newerr = (*gopp_copy)->status; + } if (likely(!newerr)) { /* The first frag might still have this slot mapped */ if (i < copy_count(skb) - 1 || !sharedslot) @@ -973,10 +994,8 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, /* No crossing a page as the payload mustn't fragment. */ if (unlikely((txreq.offset + txreq.size) > XEN_PAGE_SIZE)) { - netdev_err(queue->vif->dev, - "txreq.offset: %u, size: %u, end: %lu\n", - txreq.offset, txreq.size, - (unsigned long)(txreq.offset&~XEN_PAGE_MASK) + txreq.size); + netdev_err(queue->vif->dev, "Cross page boundary, txreq.offset: %u, size: %u\n", + txreq.offset, txreq.size); xenvif_fatal_tx_err(queue->vif); break; } @@ -1061,10 +1080,6 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, __skb_queue_tail(&queue->tx_queue, skb); queue->tx.req_cons = idx; - - if ((*map_ops >= ARRAY_SIZE(queue->tx_map_ops)) || - (*copy_ops >= ARRAY_SIZE(queue->tx_copy_ops))) - break; } return; diff --git a/drivers/nubus/bus.c b/drivers/nubus/bus.c index 17fad660032c..72921e4f35f6 100644 --- a/drivers/nubus/bus.c +++ b/drivers/nubus/bus.c @@ -14,11 +14,6 @@ #define to_nubus_board(d) container_of(d, struct nubus_board, dev) #define to_nubus_driver(d) container_of(d, struct nubus_driver, driver) -static int nubus_bus_match(struct device *dev, struct device_driver *driver) -{ - return 1; -} - static int nubus_device_probe(struct device *dev) { struct nubus_driver *ndrv = to_nubus_driver(dev->driver); @@ -39,7 +34,6 @@ static void nubus_device_remove(struct device *dev) struct bus_type nubus_bus_type = { .name = "nubus", - .match = nubus_bus_match, .probe = nubus_device_probe, .remove = nubus_device_remove, }; diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 53ef028596c6..d6a9bac91a4c 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1674,6 +1674,9 @@ static void nvme_config_discard(struct gendisk *disk, struct nvme_ns *ns) struct request_queue *queue = disk->queue; u32 size = queue_logical_block_size(queue); + if (ctrl->dmrsl && ctrl->dmrsl <= nvme_sect_to_lba(ns, UINT_MAX)) + ctrl->max_discard_sectors = nvme_lba_to_sect(ns, ctrl->dmrsl); + if (ctrl->max_discard_sectors == 0) { blk_queue_max_discard_sectors(queue, 0); return; @@ -1688,9 +1691,6 @@ static void nvme_config_discard(struct gendisk *disk, struct nvme_ns *ns) if (queue->limits.max_discard_sectors) return; - if (ctrl->dmrsl && ctrl->dmrsl <= nvme_sect_to_lba(ns, UINT_MAX)) - ctrl->max_discard_sectors = nvme_lba_to_sect(ns, ctrl->dmrsl); - blk_queue_max_discard_sectors(queue, ctrl->max_discard_sectors); blk_queue_max_discard_segments(queue, ctrl->max_discard_segments); diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index b615906263f3..cd7873de3121 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -3441,6 +3441,9 @@ static const struct pci_device_id nvme_id_table[] = { { PCI_DEVICE(0x1d97, 0x1d97), /* Lexar NM620 */ .driver_data = NVME_QUIRK_BOGUS_NID, }, { PCI_DEVICE(0x1d97, 0x2269), /* Lexar NM760 */ + .driver_data = NVME_QUIRK_BOGUS_NID | + NVME_QUIRK_IGNORE_DEV_SUBNQN, }, + { PCI_DEVICE(0x10ec, 0x5763), /* TEAMGROUP T-FORCE CARDEA ZERO Z330 SSD */ .driver_data = NVME_QUIRK_BOGUS_NID, }, { PCI_DEVICE(PCI_VENDOR_ID_AMAZON, 0x0061), .driver_data = NVME_QUIRK_DMA_ADDRESS_BITS_48, }, diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 42c0598c31f2..49c9e7bc9116 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -1620,22 +1620,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid) if (ret) goto err_init_connect; - queue->rd_enabled = true; set_bit(NVME_TCP_Q_ALLOCATED, &queue->flags); - nvme_tcp_init_recv_ctx(queue); - - write_lock_bh(&queue->sock->sk->sk_callback_lock); - queue->sock->sk->sk_user_data = queue; - queue->state_change = queue->sock->sk->sk_state_change; - queue->data_ready = queue->sock->sk->sk_data_ready; - queue->write_space = queue->sock->sk->sk_write_space; - queue->sock->sk->sk_data_ready = nvme_tcp_data_ready; - queue->sock->sk->sk_state_change = nvme_tcp_state_change; - queue->sock->sk->sk_write_space = nvme_tcp_write_space; -#ifdef CONFIG_NET_RX_BUSY_POLL - queue->sock->sk->sk_ll_usec = 1; -#endif - write_unlock_bh(&queue->sock->sk->sk_callback_lock); return 0; @@ -1655,7 +1640,7 @@ err_destroy_mutex: return ret; } -static void nvme_tcp_restore_sock_calls(struct nvme_tcp_queue *queue) +static void nvme_tcp_restore_sock_ops(struct nvme_tcp_queue *queue) { struct socket *sock = queue->sock; @@ -1670,7 +1655,7 @@ static void nvme_tcp_restore_sock_calls(struct nvme_tcp_queue *queue) static void __nvme_tcp_stop_queue(struct nvme_tcp_queue *queue) { kernel_sock_shutdown(queue->sock, SHUT_RDWR); - nvme_tcp_restore_sock_calls(queue); + nvme_tcp_restore_sock_ops(queue); cancel_work_sync(&queue->io_work); } @@ -1688,21 +1673,42 @@ static void nvme_tcp_stop_queue(struct nvme_ctrl *nctrl, int qid) mutex_unlock(&queue->queue_lock); } +static void nvme_tcp_setup_sock_ops(struct nvme_tcp_queue *queue) +{ + write_lock_bh(&queue->sock->sk->sk_callback_lock); + queue->sock->sk->sk_user_data = queue; + queue->state_change = queue->sock->sk->sk_state_change; + queue->data_ready = queue->sock->sk->sk_data_ready; + queue->write_space = queue->sock->sk->sk_write_space; + queue->sock->sk->sk_data_ready = nvme_tcp_data_ready; + queue->sock->sk->sk_state_change = nvme_tcp_state_change; + queue->sock->sk->sk_write_space = nvme_tcp_write_space; +#ifdef CONFIG_NET_RX_BUSY_POLL + queue->sock->sk->sk_ll_usec = 1; +#endif + write_unlock_bh(&queue->sock->sk->sk_callback_lock); +} + static int nvme_tcp_start_queue(struct nvme_ctrl *nctrl, int idx) { struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl); + struct nvme_tcp_queue *queue = &ctrl->queues[idx]; int ret; + queue->rd_enabled = true; + nvme_tcp_init_recv_ctx(queue); + nvme_tcp_setup_sock_ops(queue); + if (idx) ret = nvmf_connect_io_queue(nctrl, idx); else ret = nvmf_connect_admin_queue(nctrl); if (!ret) { - set_bit(NVME_TCP_Q_LIVE, &ctrl->queues[idx].flags); + set_bit(NVME_TCP_Q_LIVE, &queue->flags); } else { - if (test_bit(NVME_TCP_Q_ALLOCATED, &ctrl->queues[idx].flags)) - __nvme_tcp_stop_queue(&ctrl->queues[idx]); + if (test_bit(NVME_TCP_Q_ALLOCATED, &queue->flags)) + __nvme_tcp_stop_queue(queue); dev_err(nctrl->device, "failed to connect queue: %d ret=%d\n", idx, ret); } diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index 07d93753b12f..e311d406b170 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c @@ -226,6 +226,7 @@ static void __of_attach_node(struct device_node *np) np->sibling = np->parent->child; np->parent->child = np; of_node_clear_flag(np, OF_DETACHED); + np->fwnode.flags |= FWNODE_FLAG_NOT_DEVICE; } /** diff --git a/drivers/of/platform.c b/drivers/of/platform.c index b2bd2e783445..78ae84187449 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -737,6 +737,11 @@ static int of_platform_notify(struct notifier_block *nb, if (of_node_check_flag(rd->dn, OF_POPULATED)) return NOTIFY_OK; + /* + * Clear the flag before adding the device so that fw_devlink + * doesn't skip adding consumers to this device. + */ + rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE; /* pdev_parent may be NULL when no bus platform device */ pdev_parent = of_find_device_by_node(rd->dn->parent); pdev = of_platform_device_create(rd->dn, NULL, diff --git a/drivers/parisc/Kconfig b/drivers/parisc/Kconfig index 9eb2c1b5de7d..2fc3222d2634 100644 --- a/drivers/parisc/Kconfig +++ b/drivers/parisc/Kconfig @@ -4,6 +4,7 @@ menu "Bus options (PCI, PCMCIA, EISA, GSC, ISA)" config GSC bool "VSC/GSC/HSC bus support" select HAVE_EISA + select HAS_IOPORT default y help The VSC, GSC and HSC busses were used from the earliest 700-series diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 53a16b8b6ac2..8e33e6e59e68 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -1001,11 +1001,6 @@ void dw_pcie_setup(struct dw_pcie *pci) dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); } - val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL); - val &= ~PORT_LINK_FAST_LINK_MODE; - val |= PORT_LINK_DLL_LINK_EN; - dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val); - if (dw_pcie_cap_is(pci, CDM_CHECK)) { val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS); val |= PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS | @@ -1013,6 +1008,11 @@ void dw_pcie_setup(struct dw_pcie *pci) dw_pcie_writel_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS, val); } + val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL); + val &= ~PORT_LINK_FAST_LINK_MODE; + val |= PORT_LINK_DLL_LINK_EN; + dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val); + if (!pci->num_lanes) { dev_dbg(pci->dev, "Using h/w default number of lanes\n"); return; diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c index 66d9ab288646..e5e9b287b976 100644 --- a/drivers/pci/doe.c +++ b/drivers/pci/doe.c @@ -128,7 +128,7 @@ static int pci_doe_send_req(struct pci_doe_mb *doe_mb, return -EIO; /* Length is 2 DW of header + length of payload in DW */ - length = 2 + task->request_pl_sz / sizeof(u32); + length = 2 + task->request_pl_sz / sizeof(__le32); if (length > PCI_DOE_MAX_LENGTH) return -EIO; if (length == PCI_DOE_MAX_LENGTH) @@ -141,9 +141,9 @@ static int pci_doe_send_req(struct pci_doe_mb *doe_mb, pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH, length)); - for (i = 0; i < task->request_pl_sz / sizeof(u32); i++) + for (i = 0; i < task->request_pl_sz / sizeof(__le32); i++) pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, - task->request_pl[i]); + le32_to_cpu(task->request_pl[i])); pci_doe_write_ctrl(doe_mb, PCI_DOE_CTRL_GO); @@ -195,11 +195,11 @@ static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *tas /* First 2 dwords have already been read */ length -= 2; - payload_length = min(length, task->response_pl_sz / sizeof(u32)); + payload_length = min(length, task->response_pl_sz / sizeof(__le32)); /* Read the rest of the response payload */ for (i = 0; i < payload_length; i++) { - pci_read_config_dword(pdev, offset + PCI_DOE_READ, - &task->response_pl[i]); + pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val); + task->response_pl[i] = cpu_to_le32(val); /* Prior to the last ack, ensure Data Object Ready */ if (i == (payload_length - 1) && !pci_doe_data_obj_ready(doe_mb)) return -EIO; @@ -217,13 +217,14 @@ static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *tas if (FIELD_GET(PCI_DOE_STATUS_ERROR, val)) return -EIO; - return min(length, task->response_pl_sz / sizeof(u32)) * sizeof(u32); + return min(length, task->response_pl_sz / sizeof(__le32)) * sizeof(__le32); } static void signal_task_complete(struct pci_doe_task *task, int rv) { task->rv = rv; task->complete(task); + destroy_work_on_stack(&task->work); } static void signal_task_abort(struct pci_doe_task *task, int rv) @@ -317,14 +318,16 @@ static int pci_doe_discovery(struct pci_doe_mb *doe_mb, u8 *index, u16 *vid, { u32 request_pl = FIELD_PREP(PCI_DOE_DATA_OBJECT_DISC_REQ_3_INDEX, *index); + __le32 request_pl_le = cpu_to_le32(request_pl); + __le32 response_pl_le; u32 response_pl; DECLARE_COMPLETION_ONSTACK(c); struct pci_doe_task task = { .prot.vid = PCI_VENDOR_ID_PCI_SIG, .prot.type = PCI_DOE_PROTOCOL_DISCOVERY, - .request_pl = &request_pl, + .request_pl = &request_pl_le, .request_pl_sz = sizeof(request_pl), - .response_pl = &response_pl, + .response_pl = &response_pl_le, .response_pl_sz = sizeof(response_pl), .complete = pci_doe_task_complete, .private = &c, @@ -340,6 +343,7 @@ static int pci_doe_discovery(struct pci_doe_mb *doe_mb, u8 *index, u16 *vid, if (task.rv != sizeof(response_pl)) return -EIO; + response_pl = le32_to_cpu(response_pl_le); *vid = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_VID, response_pl); *protocol = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL, response_pl); @@ -520,6 +524,8 @@ EXPORT_SYMBOL_GPL(pci_doe_supports_prot); * task->complete will be called when the state machine is done processing this * task. * + * @task must be allocated on the stack. + * * Excess data will be discarded. * * RETURNS: 0 when task has been successfully queued, -ERRNO on error @@ -533,15 +539,15 @@ int pci_doe_submit_task(struct pci_doe_mb *doe_mb, struct pci_doe_task *task) * DOE requests must be a whole number of DW and the response needs to * be big enough for at least 1 DW */ - if (task->request_pl_sz % sizeof(u32) || - task->response_pl_sz < sizeof(u32)) + if (task->request_pl_sz % sizeof(__le32) || + task->response_pl_sz < sizeof(__le32)) return -EINVAL; if (test_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags)) return -EIO; task->doe_mb = doe_mb; - INIT_WORK(&task->work, doe_statemachine_work); + INIT_WORK_ONSTACK(&task->work, doe_statemachine_work); queue_work(doe_mb->work_queue, &task->work); return 0; } diff --git a/drivers/pci/msi/msi.c b/drivers/pci/msi/msi.c index 1f716624ca56..ef1d8857a51b 100644 --- a/drivers/pci/msi/msi.c +++ b/drivers/pci/msi/msi.c @@ -750,8 +750,7 @@ out_disable: return ret; } -static bool pci_msix_validate_entries(struct pci_dev *dev, struct msix_entry *entries, - int nvec, int hwsize) +static bool pci_msix_validate_entries(struct pci_dev *dev, struct msix_entry *entries, int nvec) { bool nogap; int i, j; @@ -762,10 +761,6 @@ static bool pci_msix_validate_entries(struct pci_dev *dev, struct msix_entry *en nogap = pci_msi_domain_supports(dev, MSI_FLAG_MSIX_CONTIGUOUS, DENY_LEGACY); for (i = 0; i < nvec; i++) { - /* Entry within hardware limit? */ - if (entries[i].entry >= hwsize) - return false; - /* Check for duplicate entries */ for (j = i + 1; j < nvec; j++) { if (entries[i].entry == entries[j].entry) @@ -805,7 +800,7 @@ int __pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int if (hwsize < 0) return hwsize; - if (!pci_msix_validate_entries(dev, entries, nvec, hwsize)) + if (!pci_msix_validate_entries(dev, entries, nvec)) return -EINVAL; if (hwsize < nvec) { diff --git a/drivers/pci/of.c b/drivers/pci/of.c index 196834ed44fe..4c2ef2e28fb5 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -16,14 +16,32 @@ #include "pci.h" #ifdef CONFIG_PCI -void pci_set_of_node(struct pci_dev *dev) +/** + * pci_set_of_node - Find and set device's DT device_node + * @dev: the PCI device structure to fill + * + * Returns 0 on success with of_node set or when no device is described in the + * DT. Returns -ENODEV if the device is present, but disabled in the DT. + */ +int pci_set_of_node(struct pci_dev *dev) { + struct device_node *node; + if (!dev->bus->dev.of_node) - return; - dev->dev.of_node = of_pci_find_child_device(dev->bus->dev.of_node, - dev->devfn); - if (dev->dev.of_node) - dev->dev.fwnode = &dev->dev.of_node->fwnode; + return 0; + + node = of_pci_find_child_device(dev->bus->dev.of_node, dev->devfn); + if (!node) + return 0; + + if (!of_device_is_available(node)) { + of_node_put(node); + return -ENODEV; + } + + dev->dev.of_node = node; + dev->dev.fwnode = &node->fwnode; + return 0; } void pci_release_of_node(struct pci_dev *dev) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index d2c08670a20e..2b48a0aa8008 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -624,7 +624,7 @@ int of_pci_get_max_link_speed(struct device_node *node); u32 of_pci_get_slot_power_limit(struct device_node *node, u8 *slot_power_limit_value, u8 *slot_power_limit_scale); -void pci_set_of_node(struct pci_dev *dev); +int pci_set_of_node(struct pci_dev *dev); void pci_release_of_node(struct pci_dev *dev); void pci_set_bus_of_node(struct pci_bus *bus); void pci_release_bus_of_node(struct pci_bus *bus); @@ -662,7 +662,7 @@ of_pci_get_slot_power_limit(struct device_node *node, return 0; } -static inline void pci_set_of_node(struct pci_dev *dev) { } +static inline int pci_set_of_node(struct pci_dev *dev) { return 0; } static inline void pci_release_of_node(struct pci_dev *dev) { } static inline void pci_set_bus_of_node(struct pci_bus *bus) { } static inline void pci_release_bus_of_node(struct pci_bus *bus) { } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a3f68b6ba6ac..f96fa83f2627 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1826,7 +1826,7 @@ int pci_setup_device(struct pci_dev *dev) u32 class; u16 cmd; u8 hdr_type; - int pos = 0; + int err, pos = 0; struct pci_bus_region region; struct resource *res; @@ -1840,10 +1840,10 @@ int pci_setup_device(struct pci_dev *dev) dev->error_state = pci_channel_io_normal; set_pcie_port_type(dev); - pci_set_of_node(dev); + err = pci_set_of_node(dev); + if (err) + return err; pci_set_acpi_fwnode(dev); - if (dev->dev.fwnode && !fwnode_device_is_available(dev->dev.fwnode)) - return -ENODEV; pci_dev_assign_slot(dev); diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 0145aef1b930..22d39e12b236 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -157,8 +157,6 @@ void pci_remove_root_bus(struct pci_bus *bus) list_for_each_entry_safe(child, tmp, &bus->devices, bus_list) pci_remove_bus_device(child); - pci_remove_bus(bus); - host_bridge->bus = NULL; #ifdef CONFIG_PCI_DOMAINS_GENERIC /* Release domain_nr if it was dynamically allocated */ @@ -166,6 +164,9 @@ void pci_remove_root_bus(struct pci_bus *bus) pci_bus_release_domain_nr(bus, host_bridge->dev.parent); #endif + pci_remove_bus(bus); + host_bridge->bus = NULL; + /* remove the host bridge */ device_del(&host_bridge->dev); } diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig index 66c259000a44..711f82400086 100644 --- a/drivers/perf/Kconfig +++ b/drivers/perf/Kconfig @@ -100,6 +100,16 @@ config ARM_SMMU_V3_PMU through the SMMU and allow the resulting information to be filtered based on the Stream ID of the corresponding master. +config ARM_PMUV3 + depends on HW_PERF_EVENTS && ((ARM && CPU_V7) || ARM64) + bool "ARM PMUv3 support" if !ARM64 + default ARM64 + help + Say y if you want to use the ARM performance monitor unit (PMU) + version 3. The PMUv3 is the CPU performance monitors on ARMv8 + (aarch32 and aarch64) systems that implement the PMUv3 + architecture. + config ARM_DSU_PMU tristate "ARM DynamIQ Shared Unit (DSU) PMU" depends on ARM64 diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile index 13e45da61100..dabc859540ce 100644 --- a/drivers/perf/Makefile +++ b/drivers/perf/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_ARM_CMN) += arm-cmn.o obj-$(CONFIG_ARM_DSU_PMU) += arm_dsu_pmu.o obj-$(CONFIG_ARM_PMU) += arm_pmu.o arm_pmu_platform.o obj-$(CONFIG_ARM_PMU_ACPI) += arm_pmu_acpi.o +obj-$(CONFIG_ARM_PMUV3) += arm_pmuv3.o obj-$(CONFIG_ARM_SMMU_V3_PMU) += arm_smmuv3_pmu.o obj-$(CONFIG_FSL_IMX8_DDR_PMU) += fsl_imx8_ddr_perf.o obj-$(CONFIG_HISI_PMU) += hisilicon/ diff --git a/drivers/perf/alibaba_uncore_drw_pmu.c b/drivers/perf/alibaba_uncore_drw_pmu.c index a7689fecb49d..5c5be9fc1b15 100644 --- a/drivers/perf/alibaba_uncore_drw_pmu.c +++ b/drivers/perf/alibaba_uncore_drw_pmu.c @@ -656,8 +656,7 @@ static int ali_drw_pmu_probe(struct platform_device *pdev) drw_pmu->dev = &pdev->dev; platform_set_drvdata(pdev, drw_pmu); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - drw_pmu->cfg_base = devm_ioremap_resource(&pdev->dev, res); + drw_pmu->cfg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(drw_pmu->cfg_base)) return PTR_ERR(drw_pmu->cfg_base); diff --git a/drivers/perf/amlogic/meson_ddr_pmu_core.c b/drivers/perf/amlogic/meson_ddr_pmu_core.c index b84346dbac2c..0b24dee1ed3c 100644 --- a/drivers/perf/amlogic/meson_ddr_pmu_core.c +++ b/drivers/perf/amlogic/meson_ddr_pmu_core.c @@ -156,10 +156,14 @@ static int meson_ddr_perf_event_add(struct perf_event *event, int flags) u64 config2 = event->attr.config2; int i; - for_each_set_bit(i, (const unsigned long *)&config1, sizeof(config1)) + for_each_set_bit(i, + (const unsigned long *)&config1, + BITS_PER_TYPE(config1)) meson_ddr_set_axi_filter(event, i); - for_each_set_bit(i, (const unsigned long *)&config2, sizeof(config2)) + for_each_set_bit(i, + (const unsigned long *)&config2, + BITS_PER_TYPE(config2)) meson_ddr_set_axi_filter(event, i + 64); if (flags & PERF_EF_START) diff --git a/drivers/perf/amlogic/meson_g12_ddr_pmu.c b/drivers/perf/amlogic/meson_g12_ddr_pmu.c index a78fdb15e26c..8b643888d503 100644 --- a/drivers/perf/amlogic/meson_g12_ddr_pmu.c +++ b/drivers/perf/amlogic/meson_g12_ddr_pmu.c @@ -21,23 +21,23 @@ #define DMC_QOS_IRQ BIT(30) /* DMC bandwidth monitor register address offset */ -#define DMC_MON_G12_CTRL0 (0x20 << 2) -#define DMC_MON_G12_CTRL1 (0x21 << 2) -#define DMC_MON_G12_CTRL2 (0x22 << 2) -#define DMC_MON_G12_CTRL3 (0x23 << 2) -#define DMC_MON_G12_CTRL4 (0x24 << 2) -#define DMC_MON_G12_CTRL5 (0x25 << 2) -#define DMC_MON_G12_CTRL6 (0x26 << 2) -#define DMC_MON_G12_CTRL7 (0x27 << 2) -#define DMC_MON_G12_CTRL8 (0x28 << 2) - -#define DMC_MON_G12_ALL_REQ_CNT (0x29 << 2) -#define DMC_MON_G12_ALL_GRANT_CNT (0x2a << 2) -#define DMC_MON_G12_ONE_GRANT_CNT (0x2b << 2) -#define DMC_MON_G12_SEC_GRANT_CNT (0x2c << 2) -#define DMC_MON_G12_THD_GRANT_CNT (0x2d << 2) -#define DMC_MON_G12_FOR_GRANT_CNT (0x2e << 2) -#define DMC_MON_G12_TIMER (0x2f << 2) +#define DMC_MON_G12_CTRL0 (0x0 << 2) +#define DMC_MON_G12_CTRL1 (0x1 << 2) +#define DMC_MON_G12_CTRL2 (0x2 << 2) +#define DMC_MON_G12_CTRL3 (0x3 << 2) +#define DMC_MON_G12_CTRL4 (0x4 << 2) +#define DMC_MON_G12_CTRL5 (0x5 << 2) +#define DMC_MON_G12_CTRL6 (0x6 << 2) +#define DMC_MON_G12_CTRL7 (0x7 << 2) +#define DMC_MON_G12_CTRL8 (0x8 << 2) + +#define DMC_MON_G12_ALL_REQ_CNT (0x9 << 2) +#define DMC_MON_G12_ALL_GRANT_CNT (0xa << 2) +#define DMC_MON_G12_ONE_GRANT_CNT (0xb << 2) +#define DMC_MON_G12_SEC_GRANT_CNT (0xc << 2) +#define DMC_MON_G12_THD_GRANT_CNT (0xd << 2) +#define DMC_MON_G12_FOR_GRANT_CNT (0xe << 2) +#define DMC_MON_G12_TIMER (0xf << 2) /* Each bit represent a axi line */ PMU_FORMAT_ATTR(event, "config:0-7"); diff --git a/drivers/perf/apple_m1_cpu_pmu.c b/drivers/perf/apple_m1_cpu_pmu.c index 979a7c2b4f56..8574c6e58c83 100644 --- a/drivers/perf/apple_m1_cpu_pmu.c +++ b/drivers/perf/apple_m1_cpu_pmu.c @@ -559,7 +559,21 @@ static int m1_pmu_fire_init(struct arm_pmu *cpu_pmu) return m1_pmu_init(cpu_pmu); } +static int m2_pmu_avalanche_init(struct arm_pmu *cpu_pmu) +{ + cpu_pmu->name = "apple_avalanche_pmu"; + return m1_pmu_init(cpu_pmu); +} + +static int m2_pmu_blizzard_init(struct arm_pmu *cpu_pmu) +{ + cpu_pmu->name = "apple_blizzard_pmu"; + return m1_pmu_init(cpu_pmu); +} + static const struct of_device_id m1_pmu_of_device_ids[] = { + { .compatible = "apple,avalanche-pmu", .data = m2_pmu_avalanche_init, }, + { .compatible = "apple,blizzard-pmu", .data = m2_pmu_blizzard_init, }, { .compatible = "apple,icestorm-pmu", .data = m1_pmu_ice_init, }, { .compatible = "apple,firestorm-pmu", .data = m1_pmu_fire_init, }, { }, @@ -581,4 +595,3 @@ static struct platform_driver m1_pmu_driver = { }; module_platform_driver(m1_pmu_driver); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c index c9689861be3f..47d359f72957 100644 --- a/drivers/perf/arm-cmn.c +++ b/drivers/perf/arm-cmn.c @@ -57,14 +57,12 @@ #define CMN_INFO_REQ_VC_NUM GENMASK_ULL(1, 0) /* XPs also have some local topology info which has uses too */ -#define CMN_MXP__CONNECT_INFO_P0 0x0008 -#define CMN_MXP__CONNECT_INFO_P1 0x0010 -#define CMN_MXP__CONNECT_INFO_P2 0x0028 -#define CMN_MXP__CONNECT_INFO_P3 0x0030 -#define CMN_MXP__CONNECT_INFO_P4 0x0038 -#define CMN_MXP__CONNECT_INFO_P5 0x0040 +#define CMN_MXP__CONNECT_INFO(p) (0x0008 + 8 * (p)) #define CMN__CONNECT_INFO_DEVICE_TYPE GENMASK_ULL(4, 0) +#define CMN_MAX_PORTS 6 +#define CI700_CONNECT_INFO_P2_5_OFFSET 0x10 + /* PMU registers occupy the 3rd 4KB page of each node's region */ #define CMN_PMU_OFFSET 0x2000 @@ -166,7 +164,7 @@ #define CMN_EVENT_BYNODEID(event) FIELD_GET(CMN_CONFIG_BYNODEID, (event)->attr.config) #define CMN_EVENT_NODEID(event) FIELD_GET(CMN_CONFIG_NODEID, (event)->attr.config) -#define CMN_CONFIG_WP_COMBINE GENMASK_ULL(27, 24) +#define CMN_CONFIG_WP_COMBINE GENMASK_ULL(30, 27) #define CMN_CONFIG_WP_DEV_SEL GENMASK_ULL(50, 48) #define CMN_CONFIG_WP_CHN_SEL GENMASK_ULL(55, 51) /* Note that we don't yet support the tertiary match group on newer IPs */ @@ -396,6 +394,25 @@ static struct arm_cmn_node *arm_cmn_node(const struct arm_cmn *cmn, return NULL; } +static u32 arm_cmn_device_connect_info(const struct arm_cmn *cmn, + const struct arm_cmn_node *xp, int port) +{ + int offset = CMN_MXP__CONNECT_INFO(port); + + if (port >= 2) { + if (cmn->model & (CMN600 | CMN650)) + return 0; + /* + * CI-700 may have extra ports, but still has the + * mesh_port_connect_info registers in the way. + */ + if (cmn->model == CI700) + offset += CI700_CONNECT_INFO_P2_5_OFFSET; + } + + return readl_relaxed(xp->pmu_base - CMN_PMU_OFFSET + offset); +} + static struct dentry *arm_cmn_debugfs; #ifdef CONFIG_DEBUG_FS @@ -469,7 +486,7 @@ static int arm_cmn_map_show(struct seq_file *s, void *data) y = cmn->mesh_y; while (y--) { int xp_base = cmn->mesh_x * y; - u8 port[6][CMN_MAX_DIMENSION]; + u8 port[CMN_MAX_PORTS][CMN_MAX_DIMENSION]; for (x = 0; x < cmn->mesh_x; x++) seq_puts(s, "--------+"); @@ -477,14 +494,9 @@ static int arm_cmn_map_show(struct seq_file *s, void *data) seq_printf(s, "\n%d |", y); for (x = 0; x < cmn->mesh_x; x++) { struct arm_cmn_node *xp = cmn->xps + xp_base + x; - void __iomem *base = xp->pmu_base - CMN_PMU_OFFSET; - - port[0][x] = readl_relaxed(base + CMN_MXP__CONNECT_INFO_P0); - port[1][x] = readl_relaxed(base + CMN_MXP__CONNECT_INFO_P1); - port[2][x] = readl_relaxed(base + CMN_MXP__CONNECT_INFO_P2); - port[3][x] = readl_relaxed(base + CMN_MXP__CONNECT_INFO_P3); - port[4][x] = readl_relaxed(base + CMN_MXP__CONNECT_INFO_P4); - port[5][x] = readl_relaxed(base + CMN_MXP__CONNECT_INFO_P5); + + for (p = 0; p < CMN_MAX_PORTS; p++) + port[p][x] = arm_cmn_device_connect_info(cmn, xp, p); seq_printf(s, " XP #%-2d |", xp_base + x); } @@ -1546,7 +1558,7 @@ static int arm_cmn_event_init(struct perf_event *event) type = CMN_EVENT_TYPE(event); /* DTC events (i.e. cycles) already have everything they need */ if (type == CMN_TYPE_DTC) - return 0; + return arm_cmn_validate_group(cmn, event); eventid = CMN_EVENT_EVENTID(event); /* For watchpoints we need the actual XP node here */ @@ -2083,18 +2095,9 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset) * from this, since in that case we will see at least one XP * with port 2 connected, for the HN-D. */ - if (readq_relaxed(xp_region + CMN_MXP__CONNECT_INFO_P0)) - xp_ports |= BIT(0); - if (readq_relaxed(xp_region + CMN_MXP__CONNECT_INFO_P1)) - xp_ports |= BIT(1); - if (readq_relaxed(xp_region + CMN_MXP__CONNECT_INFO_P2)) - xp_ports |= BIT(2); - if (readq_relaxed(xp_region + CMN_MXP__CONNECT_INFO_P3)) - xp_ports |= BIT(3); - if (readq_relaxed(xp_region + CMN_MXP__CONNECT_INFO_P4)) - xp_ports |= BIT(4); - if (readq_relaxed(xp_region + CMN_MXP__CONNECT_INFO_P5)) - xp_ports |= BIT(5); + for (int p = 0; p < CMN_MAX_PORTS; p++) + if (arm_cmn_device_connect_info(cmn, xp, p)) + xp_ports |= BIT(p); if (cmn->multi_dtm && (xp_ports & 0xc)) arm_cmn_init_dtm(dtm++, xp, 1); diff --git a/drivers/perf/arm_cspmu/arm_cspmu.c b/drivers/perf/arm_cspmu/arm_cspmu.c index e31302ab7e37..a3f1c410b417 100644 --- a/drivers/perf/arm_cspmu/arm_cspmu.c +++ b/drivers/perf/arm_cspmu/arm_cspmu.c @@ -1078,12 +1078,14 @@ static int arm_cspmu_request_irq(struct arm_cspmu *cspmu) static inline int arm_cspmu_find_cpu_container(int cpu, u32 container_uid) { u32 acpi_uid; - struct device *cpu_dev = get_cpu_device(cpu); - struct acpi_device *acpi_dev = ACPI_COMPANION(cpu_dev); + struct device *cpu_dev; + struct acpi_device *acpi_dev; + cpu_dev = get_cpu_device(cpu); if (!cpu_dev) return -ENODEV; + acpi_dev = ACPI_COMPANION(cpu_dev); while (acpi_dev) { if (!strcmp(acpi_device_hid(acpi_dev), ACPI_PROCESSOR_CONTAINER_HID) && diff --git a/drivers/perf/arm_dmc620_pmu.c b/drivers/perf/arm_dmc620_pmu.c index 54aa4658fb36..5de06f9a4dd3 100644 --- a/drivers/perf/arm_dmc620_pmu.c +++ b/drivers/perf/arm_dmc620_pmu.c @@ -655,8 +655,7 @@ static int dmc620_pmu_device_probe(struct platform_device *pdev) .attr_groups = dmc620_pmu_attr_groups, }; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dmc620_pmu->base = devm_ioremap_resource(&pdev->dev, res); + dmc620_pmu->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(dmc620_pmu->base)) return PTR_ERR(dmc620_pmu->base); diff --git a/drivers/perf/arm_pmuv3.c b/drivers/perf/arm_pmuv3.c new file mode 100644 index 000000000000..c98e4039386d --- /dev/null +++ b/drivers/perf/arm_pmuv3.c @@ -0,0 +1,1419 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ARMv8 PMUv3 Performance Events handling code. + * + * Copyright (C) 2012 ARM Limited + * Author: Will Deacon <will.deacon@arm.com> + * + * This code is based heavily on the ARMv7 perf event code. + */ + +#include <asm/irq_regs.h> +#include <asm/perf_event.h> +#include <asm/virt.h> + +#include <clocksource/arm_arch_timer.h> + +#include <linux/acpi.h> +#include <linux/clocksource.h> +#include <linux/of.h> +#include <linux/perf/arm_pmu.h> +#include <linux/perf/arm_pmuv3.h> +#include <linux/platform_device.h> +#include <linux/sched_clock.h> +#include <linux/smp.h> + +#include <asm/arm_pmuv3.h> + +/* ARMv8 Cortex-A53 specific event types. */ +#define ARMV8_A53_PERFCTR_PREF_LINEFILL 0xC2 + +/* ARMv8 Cavium ThunderX specific event types. */ +#define ARMV8_THUNDER_PERFCTR_L1D_CACHE_MISS_ST 0xE9 +#define ARMV8_THUNDER_PERFCTR_L1D_CACHE_PREF_ACCESS 0xEA +#define ARMV8_THUNDER_PERFCTR_L1D_CACHE_PREF_MISS 0xEB +#define ARMV8_THUNDER_PERFCTR_L1I_CACHE_PREF_ACCESS 0xEC +#define ARMV8_THUNDER_PERFCTR_L1I_CACHE_PREF_MISS 0xED + +/* + * ARMv8 Architectural defined events, not all of these may + * be supported on any given implementation. Unsupported events will + * be disabled at run-time based on the PMCEID registers. + */ +static const unsigned armv8_pmuv3_perf_map[PERF_COUNT_HW_MAX] = { + PERF_MAP_ALL_UNSUPPORTED, + [PERF_COUNT_HW_CPU_CYCLES] = ARMV8_PMUV3_PERFCTR_CPU_CYCLES, + [PERF_COUNT_HW_INSTRUCTIONS] = ARMV8_PMUV3_PERFCTR_INST_RETIRED, + [PERF_COUNT_HW_CACHE_REFERENCES] = ARMV8_PMUV3_PERFCTR_L1D_CACHE, + [PERF_COUNT_HW_CACHE_MISSES] = ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL, + [PERF_COUNT_HW_BRANCH_MISSES] = ARMV8_PMUV3_PERFCTR_BR_MIS_PRED, + [PERF_COUNT_HW_BUS_CYCLES] = ARMV8_PMUV3_PERFCTR_BUS_CYCLES, + [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = ARMV8_PMUV3_PERFCTR_STALL_FRONTEND, + [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = ARMV8_PMUV3_PERFCTR_STALL_BACKEND, +}; + +static const unsigned armv8_pmuv3_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { + PERF_CACHE_MAP_ALL_UNSUPPORTED, + + [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1D_CACHE, + [C(L1D)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL, + + [C(L1I)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1I_CACHE, + [C(L1I)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1I_CACHE_REFILL, + + [C(DTLB)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1D_TLB_REFILL, + [C(DTLB)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1D_TLB, + + [C(ITLB)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1I_TLB_REFILL, + [C(ITLB)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1I_TLB, + + [C(LL)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_LL_CACHE_MISS_RD, + [C(LL)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_LL_CACHE_RD, + + [C(BPU)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_BR_PRED, + [C(BPU)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_BR_MIS_PRED, +}; + +static const unsigned armv8_a53_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { + PERF_CACHE_MAP_ALL_UNSUPPORTED, + + [C(L1D)][C(OP_PREFETCH)][C(RESULT_MISS)] = ARMV8_A53_PERFCTR_PREF_LINEFILL, + + [C(NODE)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_RD, + [C(NODE)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_WR, +}; + +static const unsigned armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { + PERF_CACHE_MAP_ALL_UNSUPPORTED, + + [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_RD, + [C(L1D)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_REFILL_RD, + [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_WR, + [C(L1D)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_REFILL_WR, + + [C(DTLB)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_RD, + [C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_WR, + + [C(NODE)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_RD, + [C(NODE)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_WR, +}; + +static const unsigned armv8_a73_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { + PERF_CACHE_MAP_ALL_UNSUPPORTED, + + [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_RD, + [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_WR, +}; + +static const unsigned armv8_thunder_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { + PERF_CACHE_MAP_ALL_UNSUPPORTED, + + [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_RD, + [C(L1D)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_REFILL_RD, + [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_WR, + [C(L1D)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_THUNDER_PERFCTR_L1D_CACHE_MISS_ST, + [C(L1D)][C(OP_PREFETCH)][C(RESULT_ACCESS)] = ARMV8_THUNDER_PERFCTR_L1D_CACHE_PREF_ACCESS, + [C(L1D)][C(OP_PREFETCH)][C(RESULT_MISS)] = ARMV8_THUNDER_PERFCTR_L1D_CACHE_PREF_MISS, + + [C(L1I)][C(OP_PREFETCH)][C(RESULT_ACCESS)] = ARMV8_THUNDER_PERFCTR_L1I_CACHE_PREF_ACCESS, + [C(L1I)][C(OP_PREFETCH)][C(RESULT_MISS)] = ARMV8_THUNDER_PERFCTR_L1I_CACHE_PREF_MISS, + + [C(DTLB)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_RD, + [C(DTLB)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_RD, + [C(DTLB)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_WR, + [C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_WR, +}; + +static const unsigned armv8_vulcan_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { + PERF_CACHE_MAP_ALL_UNSUPPORTED, + + [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_RD, + [C(L1D)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_REFILL_RD, + [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_WR, + [C(L1D)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_CACHE_REFILL_WR, + + [C(DTLB)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_RD, + [C(DTLB)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_WR, + [C(DTLB)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_RD, + [C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_IMPDEF_PERFCTR_L1D_TLB_REFILL_WR, + + [C(NODE)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_RD, + [C(NODE)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_IMPDEF_PERFCTR_BUS_ACCESS_WR, +}; + +static ssize_t +armv8pmu_events_sysfs_show(struct device *dev, + struct device_attribute *attr, char *page) +{ + struct perf_pmu_events_attr *pmu_attr; + + pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr); + + return sprintf(page, "event=0x%04llx\n", pmu_attr->id); +} + +#define ARMV8_EVENT_ATTR(name, config) \ + PMU_EVENT_ATTR_ID(name, armv8pmu_events_sysfs_show, config) + +static struct attribute *armv8_pmuv3_event_attrs[] = { + ARMV8_EVENT_ATTR(sw_incr, ARMV8_PMUV3_PERFCTR_SW_INCR), + ARMV8_EVENT_ATTR(l1i_cache_refill, ARMV8_PMUV3_PERFCTR_L1I_CACHE_REFILL), + ARMV8_EVENT_ATTR(l1i_tlb_refill, ARMV8_PMUV3_PERFCTR_L1I_TLB_REFILL), + ARMV8_EVENT_ATTR(l1d_cache_refill, ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL), + ARMV8_EVENT_ATTR(l1d_cache, ARMV8_PMUV3_PERFCTR_L1D_CACHE), + ARMV8_EVENT_ATTR(l1d_tlb_refill, ARMV8_PMUV3_PERFCTR_L1D_TLB_REFILL), + ARMV8_EVENT_ATTR(ld_retired, ARMV8_PMUV3_PERFCTR_LD_RETIRED), + ARMV8_EVENT_ATTR(st_retired, ARMV8_PMUV3_PERFCTR_ST_RETIRED), + ARMV8_EVENT_ATTR(inst_retired, ARMV8_PMUV3_PERFCTR_INST_RETIRED), + ARMV8_EVENT_ATTR(exc_taken, ARMV8_PMUV3_PERFCTR_EXC_TAKEN), + ARMV8_EVENT_ATTR(exc_return, ARMV8_PMUV3_PERFCTR_EXC_RETURN), + ARMV8_EVENT_ATTR(cid_write_retired, ARMV8_PMUV3_PERFCTR_CID_WRITE_RETIRED), + ARMV8_EVENT_ATTR(pc_write_retired, ARMV8_PMUV3_PERFCTR_PC_WRITE_RETIRED), + ARMV8_EVENT_ATTR(br_immed_retired, ARMV8_PMUV3_PERFCTR_BR_IMMED_RETIRED), + ARMV8_EVENT_ATTR(br_return_retired, ARMV8_PMUV3_PERFCTR_BR_RETURN_RETIRED), + ARMV8_EVENT_ATTR(unaligned_ldst_retired, ARMV8_PMUV3_PERFCTR_UNALIGNED_LDST_RETIRED), + ARMV8_EVENT_ATTR(br_mis_pred, ARMV8_PMUV3_PERFCTR_BR_MIS_PRED), + ARMV8_EVENT_ATTR(cpu_cycles, ARMV8_PMUV3_PERFCTR_CPU_CYCLES), + ARMV8_EVENT_ATTR(br_pred, ARMV8_PMUV3_PERFCTR_BR_PRED), + ARMV8_EVENT_ATTR(mem_access, ARMV8_PMUV3_PERFCTR_MEM_ACCESS), + ARMV8_EVENT_ATTR(l1i_cache, ARMV8_PMUV3_PERFCTR_L1I_CACHE), + ARMV8_EVENT_ATTR(l1d_cache_wb, ARMV8_PMUV3_PERFCTR_L1D_CACHE_WB), + ARMV8_EVENT_ATTR(l2d_cache, ARMV8_PMUV3_PERFCTR_L2D_CACHE), + ARMV8_EVENT_ATTR(l2d_cache_refill, ARMV8_PMUV3_PERFCTR_L2D_CACHE_REFILL), + ARMV8_EVENT_ATTR(l2d_cache_wb, ARMV8_PMUV3_PERFCTR_L2D_CACHE_WB), + ARMV8_EVENT_ATTR(bus_access, ARMV8_PMUV3_PERFCTR_BUS_ACCESS), + ARMV8_EVENT_ATTR(memory_error, ARMV8_PMUV3_PERFCTR_MEMORY_ERROR), + ARMV8_EVENT_ATTR(inst_spec, ARMV8_PMUV3_PERFCTR_INST_SPEC), + ARMV8_EVENT_ATTR(ttbr_write_retired, ARMV8_PMUV3_PERFCTR_TTBR_WRITE_RETIRED), + ARMV8_EVENT_ATTR(bus_cycles, ARMV8_PMUV3_PERFCTR_BUS_CYCLES), + /* Don't expose the chain event in /sys, since it's useless in isolation */ + ARMV8_EVENT_ATTR(l1d_cache_allocate, ARMV8_PMUV3_PERFCTR_L1D_CACHE_ALLOCATE), + ARMV8_EVENT_ATTR(l2d_cache_allocate, ARMV8_PMUV3_PERFCTR_L2D_CACHE_ALLOCATE), + ARMV8_EVENT_ATTR(br_retired, ARMV8_PMUV3_PERFCTR_BR_RETIRED), + ARMV8_EVENT_ATTR(br_mis_pred_retired, ARMV8_PMUV3_PERFCTR_BR_MIS_PRED_RETIRED), + ARMV8_EVENT_ATTR(stall_frontend, ARMV8_PMUV3_PERFCTR_STALL_FRONTEND), + ARMV8_EVENT_ATTR(stall_backend, ARMV8_PMUV3_PERFCTR_STALL_BACKEND), + ARMV8_EVENT_ATTR(l1d_tlb, ARMV8_PMUV3_PERFCTR_L1D_TLB), + ARMV8_EVENT_ATTR(l1i_tlb, ARMV8_PMUV3_PERFCTR_L1I_TLB), + ARMV8_EVENT_ATTR(l2i_cache, ARMV8_PMUV3_PERFCTR_L2I_CACHE), + ARMV8_EVENT_ATTR(l2i_cache_refill, ARMV8_PMUV3_PERFCTR_L2I_CACHE_REFILL), + ARMV8_EVENT_ATTR(l3d_cache_allocate, ARMV8_PMUV3_PERFCTR_L3D_CACHE_ALLOCATE), + ARMV8_EVENT_ATTR(l3d_cache_refill, ARMV8_PMUV3_PERFCTR_L3D_CACHE_REFILL), + ARMV8_EVENT_ATTR(l3d_cache, ARMV8_PMUV3_PERFCTR_L3D_CACHE), + ARMV8_EVENT_ATTR(l3d_cache_wb, ARMV8_PMUV3_PERFCTR_L3D_CACHE_WB), + ARMV8_EVENT_ATTR(l2d_tlb_refill, ARMV8_PMUV3_PERFCTR_L2D_TLB_REFILL), + ARMV8_EVENT_ATTR(l2i_tlb_refill, ARMV8_PMUV3_PERFCTR_L2I_TLB_REFILL), + ARMV8_EVENT_ATTR(l2d_tlb, ARMV8_PMUV3_PERFCTR_L2D_TLB), + ARMV8_EVENT_ATTR(l2i_tlb, ARMV8_PMUV3_PERFCTR_L2I_TLB), + ARMV8_EVENT_ATTR(remote_access, ARMV8_PMUV3_PERFCTR_REMOTE_ACCESS), + ARMV8_EVENT_ATTR(ll_cache, ARMV8_PMUV3_PERFCTR_LL_CACHE), + ARMV8_EVENT_ATTR(ll_cache_miss, ARMV8_PMUV3_PERFCTR_LL_CACHE_MISS), + ARMV8_EVENT_ATTR(dtlb_walk, ARMV8_PMUV3_PERFCTR_DTLB_WALK), + ARMV8_EVENT_ATTR(itlb_walk, ARMV8_PMUV3_PERFCTR_ITLB_WALK), + ARMV8_EVENT_ATTR(ll_cache_rd, ARMV8_PMUV3_PERFCTR_LL_CACHE_RD), + ARMV8_EVENT_ATTR(ll_cache_miss_rd, ARMV8_PMUV3_PERFCTR_LL_CACHE_MISS_RD), + ARMV8_EVENT_ATTR(remote_access_rd, ARMV8_PMUV3_PERFCTR_REMOTE_ACCESS_RD), + ARMV8_EVENT_ATTR(l1d_cache_lmiss_rd, ARMV8_PMUV3_PERFCTR_L1D_CACHE_LMISS_RD), + ARMV8_EVENT_ATTR(op_retired, ARMV8_PMUV3_PERFCTR_OP_RETIRED), + ARMV8_EVENT_ATTR(op_spec, ARMV8_PMUV3_PERFCTR_OP_SPEC), + ARMV8_EVENT_ATTR(stall, ARMV8_PMUV3_PERFCTR_STALL), + ARMV8_EVENT_ATTR(stall_slot_backend, ARMV8_PMUV3_PERFCTR_STALL_SLOT_BACKEND), + ARMV8_EVENT_ATTR(stall_slot_frontend, ARMV8_PMUV3_PERFCTR_STALL_SLOT_FRONTEND), + ARMV8_EVENT_ATTR(stall_slot, ARMV8_PMUV3_PERFCTR_STALL_SLOT), + ARMV8_EVENT_ATTR(sample_pop, ARMV8_SPE_PERFCTR_SAMPLE_POP), + ARMV8_EVENT_ATTR(sample_feed, ARMV8_SPE_PERFCTR_SAMPLE_FEED), + ARMV8_EVENT_ATTR(sample_filtrate, ARMV8_SPE_PERFCTR_SAMPLE_FILTRATE), + ARMV8_EVENT_ATTR(sample_collision, ARMV8_SPE_PERFCTR_SAMPLE_COLLISION), + ARMV8_EVENT_ATTR(cnt_cycles, ARMV8_AMU_PERFCTR_CNT_CYCLES), + ARMV8_EVENT_ATTR(stall_backend_mem, ARMV8_AMU_PERFCTR_STALL_BACKEND_MEM), + ARMV8_EVENT_ATTR(l1i_cache_lmiss, ARMV8_PMUV3_PERFCTR_L1I_CACHE_LMISS), + ARMV8_EVENT_ATTR(l2d_cache_lmiss_rd, ARMV8_PMUV3_PERFCTR_L2D_CACHE_LMISS_RD), + ARMV8_EVENT_ATTR(l2i_cache_lmiss, ARMV8_PMUV3_PERFCTR_L2I_CACHE_LMISS), + ARMV8_EVENT_ATTR(l3d_cache_lmiss_rd, ARMV8_PMUV3_PERFCTR_L3D_CACHE_LMISS_RD), + ARMV8_EVENT_ATTR(trb_wrap, ARMV8_PMUV3_PERFCTR_TRB_WRAP), + ARMV8_EVENT_ATTR(trb_trig, ARMV8_PMUV3_PERFCTR_TRB_TRIG), + ARMV8_EVENT_ATTR(trcextout0, ARMV8_PMUV3_PERFCTR_TRCEXTOUT0), + ARMV8_EVENT_ATTR(trcextout1, ARMV8_PMUV3_PERFCTR_TRCEXTOUT1), + ARMV8_EVENT_ATTR(trcextout2, ARMV8_PMUV3_PERFCTR_TRCEXTOUT2), + ARMV8_EVENT_ATTR(trcextout3, ARMV8_PMUV3_PERFCTR_TRCEXTOUT3), + ARMV8_EVENT_ATTR(cti_trigout4, ARMV8_PMUV3_PERFCTR_CTI_TRIGOUT4), + ARMV8_EVENT_ATTR(cti_trigout5, ARMV8_PMUV3_PERFCTR_CTI_TRIGOUT5), + ARMV8_EVENT_ATTR(cti_trigout6, ARMV8_PMUV3_PERFCTR_CTI_TRIGOUT6), + ARMV8_EVENT_ATTR(cti_trigout7, ARMV8_PMUV3_PERFCTR_CTI_TRIGOUT7), + ARMV8_EVENT_ATTR(ldst_align_lat, ARMV8_PMUV3_PERFCTR_LDST_ALIGN_LAT), + ARMV8_EVENT_ATTR(ld_align_lat, ARMV8_PMUV3_PERFCTR_LD_ALIGN_LAT), + ARMV8_EVENT_ATTR(st_align_lat, ARMV8_PMUV3_PERFCTR_ST_ALIGN_LAT), + ARMV8_EVENT_ATTR(mem_access_checked, ARMV8_MTE_PERFCTR_MEM_ACCESS_CHECKED), + ARMV8_EVENT_ATTR(mem_access_checked_rd, ARMV8_MTE_PERFCTR_MEM_ACCESS_CHECKED_RD), + ARMV8_EVENT_ATTR(mem_access_checked_wr, ARMV8_MTE_PERFCTR_MEM_ACCESS_CHECKED_WR), + NULL, +}; + +static umode_t +armv8pmu_event_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int unused) +{ + struct device *dev = kobj_to_dev(kobj); + struct pmu *pmu = dev_get_drvdata(dev); + struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu); + struct perf_pmu_events_attr *pmu_attr; + + pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr.attr); + + if (pmu_attr->id < ARMV8_PMUV3_MAX_COMMON_EVENTS && + test_bit(pmu_attr->id, cpu_pmu->pmceid_bitmap)) + return attr->mode; + + if (pmu_attr->id >= ARMV8_PMUV3_EXT_COMMON_EVENT_BASE) { + u64 id = pmu_attr->id - ARMV8_PMUV3_EXT_COMMON_EVENT_BASE; + + if (id < ARMV8_PMUV3_MAX_COMMON_EVENTS && + test_bit(id, cpu_pmu->pmceid_ext_bitmap)) + return attr->mode; + } + + return 0; +} + +static const struct attribute_group armv8_pmuv3_events_attr_group = { + .name = "events", + .attrs = armv8_pmuv3_event_attrs, + .is_visible = armv8pmu_event_attr_is_visible, +}; + +PMU_FORMAT_ATTR(event, "config:0-15"); +PMU_FORMAT_ATTR(long, "config1:0"); +PMU_FORMAT_ATTR(rdpmc, "config1:1"); + +static int sysctl_perf_user_access __read_mostly; + +static inline bool armv8pmu_event_is_64bit(struct perf_event *event) +{ + return event->attr.config1 & 0x1; +} + +static inline bool armv8pmu_event_want_user_access(struct perf_event *event) +{ + return event->attr.config1 & 0x2; +} + +static struct attribute *armv8_pmuv3_format_attrs[] = { + &format_attr_event.attr, + &format_attr_long.attr, + &format_attr_rdpmc.attr, + NULL, +}; + +static const struct attribute_group armv8_pmuv3_format_attr_group = { + .name = "format", + .attrs = armv8_pmuv3_format_attrs, +}; + +static ssize_t slots_show(struct device *dev, struct device_attribute *attr, + char *page) +{ + struct pmu *pmu = dev_get_drvdata(dev); + struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu); + u32 slots = cpu_pmu->reg_pmmir & ARMV8_PMU_SLOTS_MASK; + + return sysfs_emit(page, "0x%08x\n", slots); +} + +static DEVICE_ATTR_RO(slots); + +static ssize_t bus_slots_show(struct device *dev, struct device_attribute *attr, + char *page) +{ + struct pmu *pmu = dev_get_drvdata(dev); + struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu); + u32 bus_slots = (cpu_pmu->reg_pmmir >> ARMV8_PMU_BUS_SLOTS_SHIFT) + & ARMV8_PMU_BUS_SLOTS_MASK; + + return sysfs_emit(page, "0x%08x\n", bus_slots); +} + +static DEVICE_ATTR_RO(bus_slots); + +static ssize_t bus_width_show(struct device *dev, struct device_attribute *attr, + char *page) +{ + struct pmu *pmu = dev_get_drvdata(dev); + struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu); + u32 bus_width = (cpu_pmu->reg_pmmir >> ARMV8_PMU_BUS_WIDTH_SHIFT) + & ARMV8_PMU_BUS_WIDTH_MASK; + u32 val = 0; + + /* Encoded as Log2(number of bytes), plus one */ + if (bus_width > 2 && bus_width < 13) + val = 1 << (bus_width - 1); + + return sysfs_emit(page, "0x%08x\n", val); +} + +static DEVICE_ATTR_RO(bus_width); + +static struct attribute *armv8_pmuv3_caps_attrs[] = { + &dev_attr_slots.attr, + &dev_attr_bus_slots.attr, + &dev_attr_bus_width.attr, + NULL, +}; + +static const struct attribute_group armv8_pmuv3_caps_attr_group = { + .name = "caps", + .attrs = armv8_pmuv3_caps_attrs, +}; + +/* + * Perf Events' indices + */ +#define ARMV8_IDX_CYCLE_COUNTER 0 +#define ARMV8_IDX_COUNTER0 1 +#define ARMV8_IDX_CYCLE_COUNTER_USER 32 + +/* + * We unconditionally enable ARMv8.5-PMU long event counter support + * (64-bit events) where supported. Indicate if this arm_pmu has long + * event counter support. + * + * On AArch32, long counters make no sense (you can't access the top + * bits), so we only enable this on AArch64. + */ +static bool armv8pmu_has_long_event(struct arm_pmu *cpu_pmu) +{ + return (IS_ENABLED(CONFIG_ARM64) && is_pmuv3p5(cpu_pmu->pmuver)); +} + +static inline bool armv8pmu_event_has_user_read(struct perf_event *event) +{ + return event->hw.flags & PERF_EVENT_FLAG_USER_READ_CNT; +} + +/* + * We must chain two programmable counters for 64 bit events, + * except when we have allocated the 64bit cycle counter (for CPU + * cycles event) or when user space counter access is enabled. + */ +static inline bool armv8pmu_event_is_chained(struct perf_event *event) +{ + int idx = event->hw.idx; + struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); + + return !armv8pmu_event_has_user_read(event) && + armv8pmu_event_is_64bit(event) && + !armv8pmu_has_long_event(cpu_pmu) && + (idx != ARMV8_IDX_CYCLE_COUNTER); +} + +/* + * ARMv8 low level PMU access + */ + +/* + * Perf Event to low level counters mapping + */ +#define ARMV8_IDX_TO_COUNTER(x) \ + (((x) - ARMV8_IDX_COUNTER0) & ARMV8_PMU_COUNTER_MASK) + +static inline u32 armv8pmu_pmcr_read(void) +{ + return read_pmcr(); +} + +static inline void armv8pmu_pmcr_write(u32 val) +{ + val &= ARMV8_PMU_PMCR_MASK; + isb(); + write_pmcr(val); +} + +static inline int armv8pmu_has_overflowed(u32 pmovsr) +{ + return pmovsr & ARMV8_PMU_OVERFLOWED_MASK; +} + +static inline int armv8pmu_counter_has_overflowed(u32 pmnc, int idx) +{ + return pmnc & BIT(ARMV8_IDX_TO_COUNTER(idx)); +} + +static inline u64 armv8pmu_read_evcntr(int idx) +{ + u32 counter = ARMV8_IDX_TO_COUNTER(idx); + + return read_pmevcntrn(counter); +} + +static inline u64 armv8pmu_read_hw_counter(struct perf_event *event) +{ + int idx = event->hw.idx; + u64 val = armv8pmu_read_evcntr(idx); + + if (armv8pmu_event_is_chained(event)) + val = (val << 32) | armv8pmu_read_evcntr(idx - 1); + return val; +} + +/* + * The cycle counter is always a 64-bit counter. When ARMV8_PMU_PMCR_LP + * is set the event counters also become 64-bit counters. Unless the + * user has requested a long counter (attr.config1) then we want to + * interrupt upon 32-bit overflow - we achieve this by applying a bias. + */ +static bool armv8pmu_event_needs_bias(struct perf_event *event) +{ + struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + + if (armv8pmu_event_is_64bit(event)) + return false; + + if (armv8pmu_has_long_event(cpu_pmu) || + idx == ARMV8_IDX_CYCLE_COUNTER) + return true; + + return false; +} + +static u64 armv8pmu_bias_long_counter(struct perf_event *event, u64 value) +{ + if (armv8pmu_event_needs_bias(event)) + value |= GENMASK_ULL(63, 32); + + return value; +} + +static u64 armv8pmu_unbias_long_counter(struct perf_event *event, u64 value) +{ + if (armv8pmu_event_needs_bias(event)) + value &= ~GENMASK_ULL(63, 32); + + return value; +} + +static u64 armv8pmu_read_counter(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + u64 value; + + if (idx == ARMV8_IDX_CYCLE_COUNTER) + value = read_pmccntr(); + else + value = armv8pmu_read_hw_counter(event); + + return armv8pmu_unbias_long_counter(event, value); +} + +static inline void armv8pmu_write_evcntr(int idx, u64 value) +{ + u32 counter = ARMV8_IDX_TO_COUNTER(idx); + + write_pmevcntrn(counter, value); +} + +static inline void armv8pmu_write_hw_counter(struct perf_event *event, + u64 value) +{ + int idx = event->hw.idx; + + if (armv8pmu_event_is_chained(event)) { + armv8pmu_write_evcntr(idx, upper_32_bits(value)); + armv8pmu_write_evcntr(idx - 1, lower_32_bits(value)); + } else { + armv8pmu_write_evcntr(idx, value); + } +} + +static void armv8pmu_write_counter(struct perf_event *event, u64 value) +{ + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + + value = armv8pmu_bias_long_counter(event, value); + + if (idx == ARMV8_IDX_CYCLE_COUNTER) + write_pmccntr(value); + else + armv8pmu_write_hw_counter(event, value); +} + +static inline void armv8pmu_write_evtype(int idx, u32 val) +{ + u32 counter = ARMV8_IDX_TO_COUNTER(idx); + + val &= ARMV8_PMU_EVTYPE_MASK; + write_pmevtypern(counter, val); +} + +static inline void armv8pmu_write_event_type(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + + /* + * For chained events, the low counter is programmed to count + * the event of interest and the high counter is programmed + * with CHAIN event code with filters set to count at all ELs. + */ + if (armv8pmu_event_is_chained(event)) { + u32 chain_evt = ARMV8_PMUV3_PERFCTR_CHAIN | + ARMV8_PMU_INCLUDE_EL2; + + armv8pmu_write_evtype(idx - 1, hwc->config_base); + armv8pmu_write_evtype(idx, chain_evt); + } else { + if (idx == ARMV8_IDX_CYCLE_COUNTER) + write_pmccfiltr(hwc->config_base); + else + armv8pmu_write_evtype(idx, hwc->config_base); + } +} + +static u32 armv8pmu_event_cnten_mask(struct perf_event *event) +{ + int counter = ARMV8_IDX_TO_COUNTER(event->hw.idx); + u32 mask = BIT(counter); + + if (armv8pmu_event_is_chained(event)) + mask |= BIT(counter - 1); + return mask; +} + +static inline void armv8pmu_enable_counter(u32 mask) +{ + /* + * Make sure event configuration register writes are visible before we + * enable the counter. + * */ + isb(); + write_pmcntenset(mask); +} + +static inline void armv8pmu_enable_event_counter(struct perf_event *event) +{ + struct perf_event_attr *attr = &event->attr; + u32 mask = armv8pmu_event_cnten_mask(event); + + kvm_set_pmu_events(mask, attr); + + /* We rely on the hypervisor switch code to enable guest counters */ + if (!kvm_pmu_counter_deferred(attr)) + armv8pmu_enable_counter(mask); +} + +static inline void armv8pmu_disable_counter(u32 mask) +{ + write_pmcntenclr(mask); + /* + * Make sure the effects of disabling the counter are visible before we + * start configuring the event. + */ + isb(); +} + +static inline void armv8pmu_disable_event_counter(struct perf_event *event) +{ + struct perf_event_attr *attr = &event->attr; + u32 mask = armv8pmu_event_cnten_mask(event); + + kvm_clr_pmu_events(mask); + + /* We rely on the hypervisor switch code to disable guest counters */ + if (!kvm_pmu_counter_deferred(attr)) + armv8pmu_disable_counter(mask); +} + +static inline void armv8pmu_enable_intens(u32 mask) +{ + write_pmintenset(mask); +} + +static inline void armv8pmu_enable_event_irq(struct perf_event *event) +{ + u32 counter = ARMV8_IDX_TO_COUNTER(event->hw.idx); + armv8pmu_enable_intens(BIT(counter)); +} + +static inline void armv8pmu_disable_intens(u32 mask) +{ + write_pmintenclr(mask); + isb(); + /* Clear the overflow flag in case an interrupt is pending. */ + write_pmovsclr(mask); + isb(); +} + +static inline void armv8pmu_disable_event_irq(struct perf_event *event) +{ + u32 counter = ARMV8_IDX_TO_COUNTER(event->hw.idx); + armv8pmu_disable_intens(BIT(counter)); +} + +static inline u32 armv8pmu_getreset_flags(void) +{ + u32 value; + + /* Read */ + value = read_pmovsclr(); + + /* Write to clear flags */ + value &= ARMV8_PMU_OVSR_MASK; + write_pmovsclr(value); + + return value; +} + +static void armv8pmu_disable_user_access(void) +{ + write_pmuserenr(0); +} + +static void armv8pmu_enable_user_access(struct arm_pmu *cpu_pmu) +{ + int i; + struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events); + + /* Clear any unused counters to avoid leaking their contents */ + for_each_clear_bit(i, cpuc->used_mask, cpu_pmu->num_events) { + if (i == ARMV8_IDX_CYCLE_COUNTER) + write_pmccntr(0); + else + armv8pmu_write_evcntr(i, 0); + } + + write_pmuserenr(0); + write_pmuserenr(ARMV8_PMU_USERENR_ER | ARMV8_PMU_USERENR_CR); +} + +static void armv8pmu_enable_event(struct perf_event *event) +{ + /* + * Enable counter and interrupt, and set the counter to count + * the event that we're interested in. + */ + + /* + * Disable counter + */ + armv8pmu_disable_event_counter(event); + + /* + * Set event. + */ + armv8pmu_write_event_type(event); + + /* + * Enable interrupt for this counter + */ + armv8pmu_enable_event_irq(event); + + /* + * Enable counter + */ + armv8pmu_enable_event_counter(event); +} + +static void armv8pmu_disable_event(struct perf_event *event) +{ + /* + * Disable counter + */ + armv8pmu_disable_event_counter(event); + + /* + * Disable interrupt for this counter + */ + armv8pmu_disable_event_irq(event); +} + +static void armv8pmu_start(struct arm_pmu *cpu_pmu) +{ + struct perf_event_context *ctx; + int nr_user = 0; + + ctx = perf_cpu_task_ctx(); + if (ctx) + nr_user = ctx->nr_user; + + if (sysctl_perf_user_access && nr_user) + armv8pmu_enable_user_access(cpu_pmu); + else + armv8pmu_disable_user_access(); + + /* Enable all counters */ + armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMU_PMCR_E); +} + +static void armv8pmu_stop(struct arm_pmu *cpu_pmu) +{ + /* Disable all counters */ + armv8pmu_pmcr_write(armv8pmu_pmcr_read() & ~ARMV8_PMU_PMCR_E); +} + +static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu) +{ + u32 pmovsr; + struct perf_sample_data data; + struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events); + struct pt_regs *regs; + int idx; + + /* + * Get and reset the IRQ flags + */ + pmovsr = armv8pmu_getreset_flags(); + + /* + * Did an overflow occur? + */ + if (!armv8pmu_has_overflowed(pmovsr)) + return IRQ_NONE; + + /* + * Handle the counter(s) overflow(s) + */ + regs = get_irq_regs(); + + /* + * Stop the PMU while processing the counter overflows + * to prevent skews in group events. + */ + armv8pmu_stop(cpu_pmu); + for (idx = 0; idx < cpu_pmu->num_events; ++idx) { + struct perf_event *event = cpuc->events[idx]; + struct hw_perf_event *hwc; + + /* Ignore if we don't have an event. */ + if (!event) + continue; + + /* + * We have a single interrupt for all counters. Check that + * each counter has overflowed before we process it. + */ + if (!armv8pmu_counter_has_overflowed(pmovsr, idx)) + continue; + + hwc = &event->hw; + armpmu_event_update(event); + perf_sample_data_init(&data, 0, hwc->last_period); + if (!armpmu_event_set_period(event)) + continue; + + /* + * Perf event overflow will queue the processing of the event as + * an irq_work which will be taken care of in the handling of + * IPI_IRQ_WORK. + */ + if (perf_event_overflow(event, &data, regs)) + cpu_pmu->disable(event); + } + armv8pmu_start(cpu_pmu); + + return IRQ_HANDLED; +} + +static int armv8pmu_get_single_idx(struct pmu_hw_events *cpuc, + struct arm_pmu *cpu_pmu) +{ + int idx; + + for (idx = ARMV8_IDX_COUNTER0; idx < cpu_pmu->num_events; idx++) { + if (!test_and_set_bit(idx, cpuc->used_mask)) + return idx; + } + return -EAGAIN; +} + +static int armv8pmu_get_chain_idx(struct pmu_hw_events *cpuc, + struct arm_pmu *cpu_pmu) +{ + int idx; + + /* + * Chaining requires two consecutive event counters, where + * the lower idx must be even. + */ + for (idx = ARMV8_IDX_COUNTER0 + 1; idx < cpu_pmu->num_events; idx += 2) { + if (!test_and_set_bit(idx, cpuc->used_mask)) { + /* Check if the preceding even counter is available */ + if (!test_and_set_bit(idx - 1, cpuc->used_mask)) + return idx; + /* Release the Odd counter */ + clear_bit(idx, cpuc->used_mask); + } + } + return -EAGAIN; +} + +static int armv8pmu_get_event_idx(struct pmu_hw_events *cpuc, + struct perf_event *event) +{ + struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + unsigned long evtype = hwc->config_base & ARMV8_PMU_EVTYPE_EVENT; + + /* Always prefer to place a cycle counter into the cycle counter. */ + if (evtype == ARMV8_PMUV3_PERFCTR_CPU_CYCLES) { + if (!test_and_set_bit(ARMV8_IDX_CYCLE_COUNTER, cpuc->used_mask)) + return ARMV8_IDX_CYCLE_COUNTER; + else if (armv8pmu_event_is_64bit(event) && + armv8pmu_event_want_user_access(event) && + !armv8pmu_has_long_event(cpu_pmu)) + return -EAGAIN; + } + + /* + * Otherwise use events counters + */ + if (armv8pmu_event_is_chained(event)) + return armv8pmu_get_chain_idx(cpuc, cpu_pmu); + else + return armv8pmu_get_single_idx(cpuc, cpu_pmu); +} + +static void armv8pmu_clear_event_idx(struct pmu_hw_events *cpuc, + struct perf_event *event) +{ + int idx = event->hw.idx; + + clear_bit(idx, cpuc->used_mask); + if (armv8pmu_event_is_chained(event)) + clear_bit(idx - 1, cpuc->used_mask); +} + +static int armv8pmu_user_event_idx(struct perf_event *event) +{ + if (!sysctl_perf_user_access || !armv8pmu_event_has_user_read(event)) + return 0; + + /* + * We remap the cycle counter index to 32 to + * match the offset applied to the rest of + * the counter indices. + */ + if (event->hw.idx == ARMV8_IDX_CYCLE_COUNTER) + return ARMV8_IDX_CYCLE_COUNTER_USER; + + return event->hw.idx; +} + +/* + * Add an event filter to a given event. + */ +static int armv8pmu_set_event_filter(struct hw_perf_event *event, + struct perf_event_attr *attr) +{ + unsigned long config_base = 0; + + if (attr->exclude_idle) + return -EPERM; + + /* + * If we're running in hyp mode, then we *are* the hypervisor. + * Therefore we ignore exclude_hv in this configuration, since + * there's no hypervisor to sample anyway. This is consistent + * with other architectures (x86 and Power). + */ + if (is_kernel_in_hyp_mode()) { + if (!attr->exclude_kernel && !attr->exclude_host) + config_base |= ARMV8_PMU_INCLUDE_EL2; + if (attr->exclude_guest) + config_base |= ARMV8_PMU_EXCLUDE_EL1; + if (attr->exclude_host) + config_base |= ARMV8_PMU_EXCLUDE_EL0; + } else { + if (!attr->exclude_hv && !attr->exclude_host) + config_base |= ARMV8_PMU_INCLUDE_EL2; + } + + /* + * Filter out !VHE kernels and guest kernels + */ + if (attr->exclude_kernel) + config_base |= ARMV8_PMU_EXCLUDE_EL1; + + if (attr->exclude_user) + config_base |= ARMV8_PMU_EXCLUDE_EL0; + + /* + * Install the filter into config_base as this is used to + * construct the event type. + */ + event->config_base = config_base; + + return 0; +} + +static void armv8pmu_reset(void *info) +{ + struct arm_pmu *cpu_pmu = (struct arm_pmu *)info; + u32 pmcr; + + /* The counter and interrupt enable registers are unknown at reset. */ + armv8pmu_disable_counter(U32_MAX); + armv8pmu_disable_intens(U32_MAX); + + /* Clear the counters we flip at guest entry/exit */ + kvm_clr_pmu_events(U32_MAX); + + /* + * Initialize & Reset PMNC. Request overflow interrupt for + * 64 bit cycle counter but cheat in armv8pmu_write_counter(). + */ + pmcr = ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C | ARMV8_PMU_PMCR_LC; + + /* Enable long event counter support where available */ + if (armv8pmu_has_long_event(cpu_pmu)) + pmcr |= ARMV8_PMU_PMCR_LP; + + armv8pmu_pmcr_write(pmcr); +} + +static int __armv8_pmuv3_map_event_id(struct arm_pmu *armpmu, + struct perf_event *event) +{ + if (event->attr.type == PERF_TYPE_HARDWARE && + event->attr.config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) { + + if (test_bit(ARMV8_PMUV3_PERFCTR_PC_WRITE_RETIRED, + armpmu->pmceid_bitmap)) + return ARMV8_PMUV3_PERFCTR_PC_WRITE_RETIRED; + + if (test_bit(ARMV8_PMUV3_PERFCTR_BR_RETIRED, + armpmu->pmceid_bitmap)) + return ARMV8_PMUV3_PERFCTR_BR_RETIRED; + + return HW_OP_UNSUPPORTED; + } + + return armpmu_map_event(event, &armv8_pmuv3_perf_map, + &armv8_pmuv3_perf_cache_map, + ARMV8_PMU_EVTYPE_EVENT); +} + +static int __armv8_pmuv3_map_event(struct perf_event *event, + const unsigned (*extra_event_map) + [PERF_COUNT_HW_MAX], + const unsigned (*extra_cache_map) + [PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX]) +{ + int hw_event_id; + struct arm_pmu *armpmu = to_arm_pmu(event->pmu); + + hw_event_id = __armv8_pmuv3_map_event_id(armpmu, event); + + /* + * CHAIN events only work when paired with an adjacent counter, and it + * never makes sense for a user to open one in isolation, as they'll be + * rotated arbitrarily. + */ + if (hw_event_id == ARMV8_PMUV3_PERFCTR_CHAIN) + return -EINVAL; + + if (armv8pmu_event_is_64bit(event)) + event->hw.flags |= ARMPMU_EVT_64BIT; + + /* + * User events must be allocated into a single counter, and so + * must not be chained. + * + * Most 64-bit events require long counter support, but 64-bit + * CPU_CYCLES events can be placed into the dedicated cycle + * counter when this is free. + */ + if (armv8pmu_event_want_user_access(event)) { + if (!(event->attach_state & PERF_ATTACH_TASK)) + return -EINVAL; + if (armv8pmu_event_is_64bit(event) && + (hw_event_id != ARMV8_PMUV3_PERFCTR_CPU_CYCLES) && + !armv8pmu_has_long_event(armpmu)) + return -EOPNOTSUPP; + + event->hw.flags |= PERF_EVENT_FLAG_USER_READ_CNT; + } + + /* Only expose micro/arch events supported by this PMU */ + if ((hw_event_id > 0) && (hw_event_id < ARMV8_PMUV3_MAX_COMMON_EVENTS) + && test_bit(hw_event_id, armpmu->pmceid_bitmap)) { + return hw_event_id; + } + + return armpmu_map_event(event, extra_event_map, extra_cache_map, + ARMV8_PMU_EVTYPE_EVENT); +} + +static int armv8_pmuv3_map_event(struct perf_event *event) +{ + return __armv8_pmuv3_map_event(event, NULL, NULL); +} + +static int armv8_a53_map_event(struct perf_event *event) +{ + return __armv8_pmuv3_map_event(event, NULL, &armv8_a53_perf_cache_map); +} + +static int armv8_a57_map_event(struct perf_event *event) +{ + return __armv8_pmuv3_map_event(event, NULL, &armv8_a57_perf_cache_map); +} + +static int armv8_a73_map_event(struct perf_event *event) +{ + return __armv8_pmuv3_map_event(event, NULL, &armv8_a73_perf_cache_map); +} + +static int armv8_thunder_map_event(struct perf_event *event) +{ + return __armv8_pmuv3_map_event(event, NULL, + &armv8_thunder_perf_cache_map); +} + +static int armv8_vulcan_map_event(struct perf_event *event) +{ + return __armv8_pmuv3_map_event(event, NULL, + &armv8_vulcan_perf_cache_map); +} + +struct armv8pmu_probe_info { + struct arm_pmu *pmu; + bool present; +}; + +static void __armv8pmu_probe_pmu(void *info) +{ + struct armv8pmu_probe_info *probe = info; + struct arm_pmu *cpu_pmu = probe->pmu; + u64 pmceid_raw[2]; + u32 pmceid[2]; + int pmuver; + + pmuver = read_pmuver(); + if (!pmuv3_implemented(pmuver)) + return; + + cpu_pmu->pmuver = pmuver; + probe->present = true; + + /* Read the nb of CNTx counters supported from PMNC */ + cpu_pmu->num_events = (armv8pmu_pmcr_read() >> ARMV8_PMU_PMCR_N_SHIFT) + & ARMV8_PMU_PMCR_N_MASK; + + /* Add the CPU cycles counter */ + cpu_pmu->num_events += 1; + + pmceid[0] = pmceid_raw[0] = read_pmceid0(); + pmceid[1] = pmceid_raw[1] = read_pmceid1(); + + bitmap_from_arr32(cpu_pmu->pmceid_bitmap, + pmceid, ARMV8_PMUV3_MAX_COMMON_EVENTS); + + pmceid[0] = pmceid_raw[0] >> 32; + pmceid[1] = pmceid_raw[1] >> 32; + + bitmap_from_arr32(cpu_pmu->pmceid_ext_bitmap, + pmceid, ARMV8_PMUV3_MAX_COMMON_EVENTS); + + /* store PMMIR register for sysfs */ + if (is_pmuv3p4(pmuver) && (pmceid_raw[1] & BIT(31))) + cpu_pmu->reg_pmmir = read_pmmir(); + else + cpu_pmu->reg_pmmir = 0; +} + +static int armv8pmu_probe_pmu(struct arm_pmu *cpu_pmu) +{ + struct armv8pmu_probe_info probe = { + .pmu = cpu_pmu, + .present = false, + }; + int ret; + + ret = smp_call_function_any(&cpu_pmu->supported_cpus, + __armv8pmu_probe_pmu, + &probe, 1); + if (ret) + return ret; + + return probe.present ? 0 : -ENODEV; +} + +static void armv8pmu_disable_user_access_ipi(void *unused) +{ + armv8pmu_disable_user_access(); +} + +static int armv8pmu_proc_user_access_handler(struct ctl_table *table, int write, + void *buffer, size_t *lenp, loff_t *ppos) +{ + int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); + if (ret || !write || sysctl_perf_user_access) + return ret; + + on_each_cpu(armv8pmu_disable_user_access_ipi, NULL, 1); + return 0; +} + +static struct ctl_table armv8_pmu_sysctl_table[] = { + { + .procname = "perf_user_access", + .data = &sysctl_perf_user_access, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = armv8pmu_proc_user_access_handler, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, + { } +}; + +static void armv8_pmu_register_sysctl_table(void) +{ + static u32 tbl_registered = 0; + + if (!cmpxchg_relaxed(&tbl_registered, 0, 1)) + register_sysctl("kernel", armv8_pmu_sysctl_table); +} + +static int armv8_pmu_init(struct arm_pmu *cpu_pmu, char *name, + int (*map_event)(struct perf_event *event), + const struct attribute_group *events, + const struct attribute_group *format, + const struct attribute_group *caps) +{ + int ret = armv8pmu_probe_pmu(cpu_pmu); + if (ret) + return ret; + + cpu_pmu->handle_irq = armv8pmu_handle_irq; + cpu_pmu->enable = armv8pmu_enable_event; + cpu_pmu->disable = armv8pmu_disable_event; + cpu_pmu->read_counter = armv8pmu_read_counter; + cpu_pmu->write_counter = armv8pmu_write_counter; + cpu_pmu->get_event_idx = armv8pmu_get_event_idx; + cpu_pmu->clear_event_idx = armv8pmu_clear_event_idx; + cpu_pmu->start = armv8pmu_start; + cpu_pmu->stop = armv8pmu_stop; + cpu_pmu->reset = armv8pmu_reset; + cpu_pmu->set_event_filter = armv8pmu_set_event_filter; + + cpu_pmu->pmu.event_idx = armv8pmu_user_event_idx; + + cpu_pmu->name = name; + cpu_pmu->map_event = map_event; + cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = events ? + events : &armv8_pmuv3_events_attr_group; + cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = format ? + format : &armv8_pmuv3_format_attr_group; + cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_CAPS] = caps ? + caps : &armv8_pmuv3_caps_attr_group; + + armv8_pmu_register_sysctl_table(); + return 0; +} + +static int armv8_pmu_init_nogroups(struct arm_pmu *cpu_pmu, char *name, + int (*map_event)(struct perf_event *event)) +{ + return armv8_pmu_init(cpu_pmu, name, map_event, NULL, NULL, NULL); +} + +#define PMUV3_INIT_SIMPLE(name) \ +static int name##_pmu_init(struct arm_pmu *cpu_pmu) \ +{ \ + return armv8_pmu_init_nogroups(cpu_pmu, #name, armv8_pmuv3_map_event);\ +} + +PMUV3_INIT_SIMPLE(armv8_pmuv3) + +PMUV3_INIT_SIMPLE(armv8_cortex_a34) +PMUV3_INIT_SIMPLE(armv8_cortex_a55) +PMUV3_INIT_SIMPLE(armv8_cortex_a65) +PMUV3_INIT_SIMPLE(armv8_cortex_a75) +PMUV3_INIT_SIMPLE(armv8_cortex_a76) +PMUV3_INIT_SIMPLE(armv8_cortex_a77) +PMUV3_INIT_SIMPLE(armv8_cortex_a78) +PMUV3_INIT_SIMPLE(armv9_cortex_a510) +PMUV3_INIT_SIMPLE(armv9_cortex_a710) +PMUV3_INIT_SIMPLE(armv8_cortex_x1) +PMUV3_INIT_SIMPLE(armv9_cortex_x2) +PMUV3_INIT_SIMPLE(armv8_neoverse_e1) +PMUV3_INIT_SIMPLE(armv8_neoverse_n1) +PMUV3_INIT_SIMPLE(armv9_neoverse_n2) +PMUV3_INIT_SIMPLE(armv8_neoverse_v1) + +PMUV3_INIT_SIMPLE(armv8_nvidia_carmel) +PMUV3_INIT_SIMPLE(armv8_nvidia_denver) + +static int armv8_a35_pmu_init(struct arm_pmu *cpu_pmu) +{ + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a35", + armv8_a53_map_event); +} + +static int armv8_a53_pmu_init(struct arm_pmu *cpu_pmu) +{ + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a53", + armv8_a53_map_event); +} + +static int armv8_a57_pmu_init(struct arm_pmu *cpu_pmu) +{ + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a57", + armv8_a57_map_event); +} + +static int armv8_a72_pmu_init(struct arm_pmu *cpu_pmu) +{ + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a72", + armv8_a57_map_event); +} + +static int armv8_a73_pmu_init(struct arm_pmu *cpu_pmu) +{ + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a73", + armv8_a73_map_event); +} + +static int armv8_thunder_pmu_init(struct arm_pmu *cpu_pmu) +{ + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cavium_thunder", + armv8_thunder_map_event); +} + +static int armv8_vulcan_pmu_init(struct arm_pmu *cpu_pmu) +{ + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_brcm_vulcan", + armv8_vulcan_map_event); +} + +static const struct of_device_id armv8_pmu_of_device_ids[] = { + {.compatible = "arm,armv8-pmuv3", .data = armv8_pmuv3_pmu_init}, + {.compatible = "arm,cortex-a34-pmu", .data = armv8_cortex_a34_pmu_init}, + {.compatible = "arm,cortex-a35-pmu", .data = armv8_a35_pmu_init}, + {.compatible = "arm,cortex-a53-pmu", .data = armv8_a53_pmu_init}, + {.compatible = "arm,cortex-a55-pmu", .data = armv8_cortex_a55_pmu_init}, + {.compatible = "arm,cortex-a57-pmu", .data = armv8_a57_pmu_init}, + {.compatible = "arm,cortex-a65-pmu", .data = armv8_cortex_a65_pmu_init}, + {.compatible = "arm,cortex-a72-pmu", .data = armv8_a72_pmu_init}, + {.compatible = "arm,cortex-a73-pmu", .data = armv8_a73_pmu_init}, + {.compatible = "arm,cortex-a75-pmu", .data = armv8_cortex_a75_pmu_init}, + {.compatible = "arm,cortex-a76-pmu", .data = armv8_cortex_a76_pmu_init}, + {.compatible = "arm,cortex-a77-pmu", .data = armv8_cortex_a77_pmu_init}, + {.compatible = "arm,cortex-a78-pmu", .data = armv8_cortex_a78_pmu_init}, + {.compatible = "arm,cortex-a510-pmu", .data = armv9_cortex_a510_pmu_init}, + {.compatible = "arm,cortex-a710-pmu", .data = armv9_cortex_a710_pmu_init}, + {.compatible = "arm,cortex-x1-pmu", .data = armv8_cortex_x1_pmu_init}, + {.compatible = "arm,cortex-x2-pmu", .data = armv9_cortex_x2_pmu_init}, + {.compatible = "arm,neoverse-e1-pmu", .data = armv8_neoverse_e1_pmu_init}, + {.compatible = "arm,neoverse-n1-pmu", .data = armv8_neoverse_n1_pmu_init}, + {.compatible = "arm,neoverse-n2-pmu", .data = armv9_neoverse_n2_pmu_init}, + {.compatible = "arm,neoverse-v1-pmu", .data = armv8_neoverse_v1_pmu_init}, + {.compatible = "cavium,thunder-pmu", .data = armv8_thunder_pmu_init}, + {.compatible = "brcm,vulcan-pmu", .data = armv8_vulcan_pmu_init}, + {.compatible = "nvidia,carmel-pmu", .data = armv8_nvidia_carmel_pmu_init}, + {.compatible = "nvidia,denver-pmu", .data = armv8_nvidia_denver_pmu_init}, + {}, +}; + +static int armv8_pmu_device_probe(struct platform_device *pdev) +{ + return arm_pmu_device_probe(pdev, armv8_pmu_of_device_ids, NULL); +} + +static struct platform_driver armv8_pmu_driver = { + .driver = { + .name = ARMV8_PMU_PDEV_NAME, + .of_match_table = armv8_pmu_of_device_ids, + .suppress_bind_attrs = true, + }, + .probe = armv8_pmu_device_probe, +}; + +static int __init armv8_pmu_driver_init(void) +{ + if (acpi_disabled) + return platform_driver_register(&armv8_pmu_driver); + else + return arm_pmu_acpi_probe(armv8_pmuv3_pmu_init); +} +device_initcall(armv8_pmu_driver_init) + +void arch_perf_update_userpage(struct perf_event *event, + struct perf_event_mmap_page *userpg, u64 now) +{ + struct clock_read_data *rd; + unsigned int seq; + u64 ns; + + userpg->cap_user_time = 0; + userpg->cap_user_time_zero = 0; + userpg->cap_user_time_short = 0; + userpg->cap_user_rdpmc = armv8pmu_event_has_user_read(event); + + if (userpg->cap_user_rdpmc) { + if (event->hw.flags & ARMPMU_EVT_64BIT) + userpg->pmc_width = 64; + else + userpg->pmc_width = 32; + } + + do { + rd = sched_clock_read_begin(&seq); + + if (rd->read_sched_clock != arch_timer_read_counter) + return; + + userpg->time_mult = rd->mult; + userpg->time_shift = rd->shift; + userpg->time_zero = rd->epoch_ns; + userpg->time_cycles = rd->epoch_cyc; + userpg->time_mask = rd->sched_clock_mask; + + /* + * Subtract the cycle base, such that software that + * doesn't know about cap_user_time_short still 'works' + * assuming no wraps. + */ + ns = mul_u64_u32_shr(rd->epoch_cyc, rd->mult, rd->shift); + userpg->time_zero -= ns; + + } while (sched_clock_read_retry(seq)); + + userpg->time_offset = userpg->time_zero - now; + + /* + * time_shift is not expected to be greater than 31 due to + * the original published conversion algorithm shifting a + * 32-bit value (now specifies a 64-bit value) - refer + * perf_event_mmap_page documentation in perf_event.h. + */ + if (userpg->time_shift == 32) { + userpg->time_shift = 31; + userpg->time_mult >>= 1; + } + + /* + * Internal timekeeping for enabled/running/stopped times + * is always computed with the sched_clock. + */ + userpg->cap_user_time = 1; + userpg->cap_user_time_zero = 1; + userpg->cap_user_time_short = 1; +} diff --git a/drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c b/drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c index 4c67d57217a7..40f1bc9f9b91 100644 --- a/drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c @@ -316,7 +316,7 @@ static int hisi_cpa_pmu_probe(struct platform_device *pdev) if (!name) return -ENOMEM; - hisi_pmu_init(cpa_pmu, name, THIS_MODULE); + hisi_pmu_init(cpa_pmu, THIS_MODULE); /* Power Management should be disabled before using CPA PMU. */ hisi_cpa_pmu_disable_pm(cpa_pmu); diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c index 8c3ffcbfd4c0..ffb039d05d07 100644 --- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c @@ -499,13 +499,6 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev) if (ret) return ret; - ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE, - &ddrc_pmu->node); - if (ret) { - dev_err(&pdev->dev, "Error %d registering hotplug;\n", ret); - return ret; - } - if (ddrc_pmu->identifier >= HISI_PMU_V2) name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_ddrc%u_%u", @@ -516,7 +509,17 @@ static int hisi_ddrc_pmu_probe(struct platform_device *pdev) "hisi_sccl%u_ddrc%u", ddrc_pmu->sccl_id, ddrc_pmu->index_id); - hisi_pmu_init(ddrc_pmu, name, THIS_MODULE); + if (!name) + return -ENOMEM; + + ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_DDRC_ONLINE, + &ddrc_pmu->node); + if (ret) { + dev_err(&pdev->dev, "Error %d registering hotplug;\n", ret); + return ret; + } + + hisi_pmu_init(ddrc_pmu, THIS_MODULE); ret = perf_pmu_register(&ddrc_pmu->pmu, name, -1); if (ret) { diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c index 806698b9eabf..15caf99e1eef 100644 --- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c @@ -510,6 +510,11 @@ static int hisi_hha_pmu_probe(struct platform_device *pdev) if (ret) return ret; + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_hha%u", + hha_pmu->sccl_id, hha_pmu->index_id); + if (!name) + return -ENOMEM; + ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE, &hha_pmu->node); if (ret) { @@ -517,9 +522,7 @@ static int hisi_hha_pmu_probe(struct platform_device *pdev) return ret; } - name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_hha%u", - hha_pmu->sccl_id, hha_pmu->index_id); - hisi_pmu_init(hha_pmu, name, THIS_MODULE); + hisi_pmu_init(hha_pmu, THIS_MODULE); ret = perf_pmu_register(&hha_pmu->pmu, name, -1); if (ret) { diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c index 5b2c35f1658a..794dbcd19b7a 100644 --- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c @@ -544,6 +544,11 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev) if (ret) return ret; + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_l3c%u", + l3c_pmu->sccl_id, l3c_pmu->ccl_id); + if (!name) + return -ENOMEM; + ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE, &l3c_pmu->node); if (ret) { @@ -551,13 +556,7 @@ static int hisi_l3c_pmu_probe(struct platform_device *pdev) return ret; } - /* - * CCL_ID is used to identify the L3C in the same SCCL which was - * used _UID by mistake. - */ - name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_l3c%u", - l3c_pmu->sccl_id, l3c_pmu->ccl_id); - hisi_pmu_init(l3c_pmu, name, THIS_MODULE); + hisi_pmu_init(l3c_pmu, THIS_MODULE); ret = perf_pmu_register(&l3c_pmu->pmu, name, -1); if (ret) { diff --git a/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c index afe3419f3f6d..71b6687d6696 100644 --- a/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c @@ -412,7 +412,7 @@ static int hisi_pa_pmu_probe(struct platform_device *pdev) return ret; } - hisi_pmu_init(pa_pmu, name, THIS_MODULE); + hisi_pmu_init(pa_pmu, THIS_MODULE); ret = perf_pmu_register(&pa_pmu->pmu, name, -1); if (ret) { dev_err(pa_pmu->dev, "PMU register failed, ret = %d\n", ret); diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pmu.c index f1b0f5e1a28f..2823f381930d 100644 --- a/drivers/perf/hisilicon/hisi_uncore_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.c @@ -531,12 +531,10 @@ int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node) } EXPORT_SYMBOL_GPL(hisi_uncore_pmu_offline_cpu); -void hisi_pmu_init(struct hisi_pmu *hisi_pmu, const char *name, - struct module *module) +void hisi_pmu_init(struct hisi_pmu *hisi_pmu, struct module *module) { struct pmu *pmu = &hisi_pmu->pmu; - pmu->name = name; pmu->module = module; pmu->task_ctx_nr = perf_invalid_context; pmu->event_init = hisi_uncore_pmu_event_init; diff --git a/drivers/perf/hisilicon/hisi_uncore_pmu.h b/drivers/perf/hisilicon/hisi_uncore_pmu.h index f8e3cc6903d7..07890a8e96ca 100644 --- a/drivers/perf/hisilicon/hisi_uncore_pmu.h +++ b/drivers/perf/hisilicon/hisi_uncore_pmu.h @@ -121,6 +121,5 @@ ssize_t hisi_uncore_pmu_identifier_attr_show(struct device *dev, int hisi_uncore_pmu_init_irq(struct hisi_pmu *hisi_pmu, struct platform_device *pdev); -void hisi_pmu_init(struct hisi_pmu *hisi_pmu, const char *name, - struct module *module); +void hisi_pmu_init(struct hisi_pmu *hisi_pmu, struct module *module); #endif /* __HISI_UNCORE_PMU_H__ */ diff --git a/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c index 1e354433776a..6fe534a665ed 100644 --- a/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c @@ -445,7 +445,7 @@ static int hisi_sllc_pmu_probe(struct platform_device *pdev) return ret; } - hisi_pmu_init(sllc_pmu, name, THIS_MODULE); + hisi_pmu_init(sllc_pmu, THIS_MODULE); ret = perf_pmu_register(&sllc_pmu->pmu, name, -1); if (ret) { diff --git a/drivers/perf/qcom_l3_pmu.c b/drivers/perf/qcom_l3_pmu.c index 346311a05460..2887edb4eb0b 100644 --- a/drivers/perf/qcom_l3_pmu.c +++ b/drivers/perf/qcom_l3_pmu.c @@ -763,8 +763,7 @@ static int qcom_l3_cache_pmu_probe(struct platform_device *pdev) .capabilities = PERF_PMU_CAP_NO_EXCLUDE, }; - memrc = platform_get_resource(pdev, IORESOURCE_MEM, 0); - l3pmu->regs = devm_ioremap_resource(&pdev->dev, memrc); + l3pmu->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &memrc); if (IS_ERR(l3pmu->regs)) return PTR_ERR(l3pmu->regs); diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig index f20c28334bcb..a71874fed3d6 100644 --- a/drivers/pinctrl/mediatek/Kconfig +++ b/drivers/pinctrl/mediatek/Kconfig @@ -45,35 +45,35 @@ config PINCTRL_MTK_PARIS # For ARMv7 SoCs config PINCTRL_MT2701 - bool "Mediatek MT2701 pin control" + bool "MediaTek MT2701 pin control" depends on MACH_MT7623 || MACH_MT2701 || COMPILE_TEST depends on OF default MACH_MT2701 select PINCTRL_MTK config PINCTRL_MT7623 - bool "Mediatek MT7623 pin control with generic binding" + bool "MediaTek MT7623 pin control with generic binding" depends on MACH_MT7623 || COMPILE_TEST depends on OF default MACH_MT7623 select PINCTRL_MTK_MOORE config PINCTRL_MT7629 - bool "Mediatek MT7629 pin control" + bool "MediaTek MT7629 pin control" depends on MACH_MT7629 || COMPILE_TEST depends on OF default MACH_MT7629 select PINCTRL_MTK_MOORE config PINCTRL_MT8135 - bool "Mediatek MT8135 pin control" + bool "MediaTek MT8135 pin control" depends on MACH_MT8135 || COMPILE_TEST depends on OF default MACH_MT8135 select PINCTRL_MTK config PINCTRL_MT8127 - bool "Mediatek MT8127 pin control" + bool "MediaTek MT8127 pin control" depends on MACH_MT8127 || COMPILE_TEST depends on OF default MACH_MT8127 @@ -88,33 +88,33 @@ config PINCTRL_MT2712 select PINCTRL_MTK config PINCTRL_MT6765 - tristate "Mediatek MT6765 pin control" + tristate "MediaTek MT6765 pin control" depends on OF depends on ARM64 || COMPILE_TEST default ARM64 && ARCH_MEDIATEK select PINCTRL_MTK_PARIS config PINCTRL_MT6779 - tristate "Mediatek MT6779 pin control" + tristate "MediaTek MT6779 pin control" depends on OF depends on ARM64 || COMPILE_TEST default ARM64 && ARCH_MEDIATEK select PINCTRL_MTK_PARIS help Say yes here to support pin controller and gpio driver - on Mediatek MT6779 SoC. + on MediaTek MT6779 SoC. In MTK platform, we support virtual gpio and use it to map specific eint which doesn't have real gpio pin. config PINCTRL_MT6795 - bool "Mediatek MT6795 pin control" + bool "MediaTek MT6795 pin control" depends on OF depends on ARM64 || COMPILE_TEST default ARM64 && ARCH_MEDIATEK select PINCTRL_MTK_PARIS config PINCTRL_MT6797 - bool "Mediatek MT6797 pin control" + bool "MediaTek MT6797 pin control" depends on OF depends on ARM64 || COMPILE_TEST default ARM64 && ARCH_MEDIATEK @@ -128,40 +128,42 @@ config PINCTRL_MT7622 select PINCTRL_MTK_MOORE config PINCTRL_MT7981 - bool "Mediatek MT7981 pin control" + bool "MediaTek MT7981 pin control" depends on OF + depends on ARM64 || COMPILE_TEST + default ARM64 && ARCH_MEDIATEK select PINCTRL_MTK_MOORE config PINCTRL_MT7986 - bool "Mediatek MT7986 pin control" + bool "MediaTek MT7986 pin control" depends on OF depends on ARM64 || COMPILE_TEST default ARM64 && ARCH_MEDIATEK select PINCTRL_MTK_MOORE config PINCTRL_MT8167 - bool "Mediatek MT8167 pin control" + bool "MediaTek MT8167 pin control" depends on OF depends on ARM64 || COMPILE_TEST default ARM64 && ARCH_MEDIATEK select PINCTRL_MTK config PINCTRL_MT8173 - bool "Mediatek MT8173 pin control" + bool "MediaTek MT8173 pin control" depends on OF depends on ARM64 || COMPILE_TEST default ARM64 && ARCH_MEDIATEK select PINCTRL_MTK config PINCTRL_MT8183 - bool "Mediatek MT8183 pin control" + bool "MediaTek MT8183 pin control" depends on OF depends on ARM64 || COMPILE_TEST default ARM64 && ARCH_MEDIATEK select PINCTRL_MTK_PARIS config PINCTRL_MT8186 - bool "Mediatek MT8186 pin control" + bool "MediaTek MT8186 pin control" depends on OF depends on ARM64 || COMPILE_TEST default ARM64 && ARCH_MEDIATEK @@ -180,28 +182,28 @@ config PINCTRL_MT8188 map specific eint which doesn't have real gpio pin. config PINCTRL_MT8192 - bool "Mediatek MT8192 pin control" + bool "MediaTek MT8192 pin control" depends on OF depends on ARM64 || COMPILE_TEST default ARM64 && ARCH_MEDIATEK select PINCTRL_MTK_PARIS config PINCTRL_MT8195 - bool "Mediatek MT8195 pin control" + bool "MediaTek MT8195 pin control" depends on OF depends on ARM64 || COMPILE_TEST default ARM64 && ARCH_MEDIATEK select PINCTRL_MTK_PARIS config PINCTRL_MT8365 - bool "Mediatek MT8365 pin control" + bool "MediaTek MT8365 pin control" depends on OF depends on ARM64 || COMPILE_TEST default ARM64 && ARCH_MEDIATEK select PINCTRL_MTK config PINCTRL_MT8516 - bool "Mediatek MT8516 pin control" + bool "MediaTek MT8516 pin control" depends on OF depends on ARM64 || COMPILE_TEST default ARM64 && ARCH_MEDIATEK @@ -209,7 +211,7 @@ config PINCTRL_MT8516 # For PMIC config PINCTRL_MT6397 - bool "Mediatek MT6397 pin control" + bool "MediaTek MT6397 pin control" depends on MFD_MT6397 || COMPILE_TEST depends on OF default MFD_MT6397 diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c index 373eed8bc4be..c775d239444a 100644 --- a/drivers/pinctrl/pinctrl-at91-pio4.c +++ b/drivers/pinctrl/pinctrl-at91-pio4.c @@ -1206,7 +1206,6 @@ static int atmel_pinctrl_probe(struct platform_device *pdev) dev_err(dev, "can't add the irq domain\n"); return -ENODEV; } - atmel_pioctrl->irq_domain->name = "atmel gpio"; for (i = 0; i < atmel_pioctrl->npins; i++) { int irq = irq_create_mapping(atmel_pioctrl->irq_domain, i); diff --git a/drivers/pinctrl/pinctrl-ocelot.c b/drivers/pinctrl/pinctrl-ocelot.c index 29e4a6282a64..1dcbd0937ef5 100644 --- a/drivers/pinctrl/pinctrl-ocelot.c +++ b/drivers/pinctrl/pinctrl-ocelot.c @@ -1204,7 +1204,7 @@ static int ocelot_pinmux_set_mux(struct pinctrl_dev *pctldev, regmap_update_bits(info->map, REG_ALT(0, info, pin->pin), BIT(p), f << p); regmap_update_bits(info->map, REG_ALT(1, info, pin->pin), - BIT(p), f << (p - 1)); + BIT(p), (f >> 1) << p); return 0; } diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index daeb79a9a602..4515f375c5e8 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -323,6 +323,7 @@ static int msm_config_reg(struct msm_pinctrl *pctrl, break; case PIN_CONFIG_OUTPUT: case PIN_CONFIG_INPUT_ENABLE: + case PIN_CONFIG_OUTPUT_ENABLE: *bit = g->oe_bit; *mask = 1; break; @@ -414,11 +415,9 @@ static int msm_config_group_get(struct pinctrl_dev *pctldev, val = msm_readl_io(pctrl, g); arg = !!(val & BIT(g->in_bit)); break; - case PIN_CONFIG_INPUT_ENABLE: - /* Pin is output */ - if (arg) + case PIN_CONFIG_OUTPUT_ENABLE: + if (!arg) return -EINVAL; - arg = 1; break; default: return -ENOTSUPP; @@ -502,9 +501,36 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev, arg = 1; break; case PIN_CONFIG_INPUT_ENABLE: - /* disable output */ + /* + * According to pinctrl documentation this should + * actually be a no-op. + * + * The docs are explicit that "this does not affect + * the pin's ability to drive output" but what we do + * here is to modify the output enable bit. Thus, to + * follow the docs we should remove that. + * + * The docs say that we should enable any relevant + * input buffer, but TLMM there is no input buffer that + * can be enabled/disabled. It's always on. + * + * The points above, explain why this _should_ be a + * no-op. However, for historical reasons and to + * support old device trees, we'll violate the docs + * still affect the output. + * + * It should further be noted that this old historical + * behavior actually overrides arg to 0. That means + * that "input-enable" and "input-disable" in a device + * tree would _both_ disable the output. We'll + * continue to preserve this behavior as well since + * we have no other use for this attribute. + */ arg = 0; break; + case PIN_CONFIG_OUTPUT_ENABLE: + arg = !!arg; + break; default: dev_err(pctrl->dev, "Unsupported config parameter: %x\n", param); diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c index cb33a23ab0c1..04ace4c7bd58 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32.c @@ -1330,7 +1330,7 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, struct fwnode if (fwnode_property_read_u32(fwnode, "st,bank-ioport", &bank_ioport_nr)) bank_ioport_nr = bank_nr; - bank->gpio_chip.base = bank_nr * STM32_GPIO_PINS_PER_BANK; + bank->gpio_chip.base = -1; bank->gpio_chip.ngpio = npins; bank->gpio_chip.fwnode = fwnode; diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c index aaad41294200..42ccd7f1c9b9 100644 --- a/drivers/platform/surface/aggregator/bus.c +++ b/drivers/platform/surface/aggregator/bus.c @@ -485,8 +485,10 @@ int __ssam_register_clients(struct device *parent, struct ssam_controller *ctrl, * device, so ignore it and continue with the next one. */ status = ssam_add_client_device(parent, ctrl, child); - if (status && status != -ENODEV) + if (status && status != -ENODEV) { + fwnode_handle_put(child); goto err; + } } return 0; diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index cb15acdf14a3..e2c9a68d12df 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -464,7 +464,8 @@ static const struct dmi_system_id asus_quirks[] = { .ident = "ASUS ROG FLOW X13", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "GV301Q"), + /* Match GV301** */ + DMI_MATCH(DMI_PRODUCT_NAME, "GV301"), }, .driver_data = &quirk_asus_tablet_mode, }, diff --git a/drivers/platform/x86/gigabyte-wmi.c b/drivers/platform/x86/gigabyte-wmi.c index 322cfaeda17b..2a426040f749 100644 --- a/drivers/platform/x86/gigabyte-wmi.c +++ b/drivers/platform/x86/gigabyte-wmi.c @@ -140,6 +140,7 @@ static u8 gigabyte_wmi_detect_sensor_usability(struct wmi_device *wdev) }} static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = { + DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("A320M-S2H V2-CF"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B450M DS3H-CF"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B450M DS3H WIFI-CF"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B450M S2H V2"), @@ -150,6 +151,7 @@ static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = { DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550I AORUS PRO AX"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M AORUS PRO-P"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M DS3H"), + DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B650 AORUS ELITE AX"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B660 GAMING X DDR4"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B660I AORUS PRO DDR4"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("Z390 I AORUS PRO WIFI-CF"), @@ -159,6 +161,7 @@ static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = { DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 GAMING X"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 I AORUS PRO WIFI"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 UD"), + DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570S AORUS ELITE"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("Z690M AORUS ELITE AX DDR4"), { } }; diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 0eb5bfdd823a..959ec3c5f376 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -1170,7 +1170,6 @@ static const struct key_entry ideapad_keymap[] = { { KE_KEY, 65, { KEY_PROG4 } }, { KE_KEY, 66, { KEY_TOUCHPAD_OFF } }, { KE_KEY, 67, { KEY_TOUCHPAD_ON } }, - { KE_KEY, 68, { KEY_TOUCHPAD_TOGGLE } }, { KE_KEY, 128, { KEY_ESC } }, /* @@ -1526,18 +1525,16 @@ static void ideapad_sync_touchpad_state(struct ideapad_private *priv, bool send_ if (priv->features.ctrl_ps2_aux_port) i8042_command(¶m, value ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE); - if (send_events) { - /* - * On older models the EC controls the touchpad and toggles it - * on/off itself, in this case we report KEY_TOUCHPAD_ON/_OFF. - * If the EC did not toggle, report KEY_TOUCHPAD_TOGGLE. - */ - if (value != priv->r_touchpad_val) { - ideapad_input_report(priv, value ? 67 : 66); - sysfs_notify(&priv->platform_device->dev.kobj, NULL, "touchpad"); - } else { - ideapad_input_report(priv, 68); - } + /* + * On older models the EC controls the touchpad and toggles it on/off + * itself, in this case we report KEY_TOUCHPAD_ON/_OFF. Some models do + * an acpi-notify with VPC bit 5 set on resume, so this function get + * called with send_events=true on every resume. Therefor if the EC did + * not toggle, do nothing to avoid sending spurious KEY_TOUCHPAD_TOGGLE. + */ + if (send_events && value != priv->r_touchpad_val) { + ideapad_input_report(priv, value ? 67 : 66); + sysfs_notify(&priv->platform_device->dev.kobj, NULL, "touchpad"); } priv->r_touchpad_val = value; diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c index 3a15d32d7644..b9591969e0fa 100644 --- a/drivers/platform/x86/intel/pmc/core.c +++ b/drivers/platform/x86/intel/pmc/core.c @@ -66,7 +66,18 @@ static inline void pmc_core_reg_write(struct pmc_dev *pmcdev, int reg_offset, static inline u64 pmc_core_adjust_slp_s0_step(struct pmc_dev *pmcdev, u32 value) { - return (u64)value * pmcdev->map->slp_s0_res_counter_step; + /* + * ADL PCH does not have the SLP_S0 counter and LPM Residency counters are + * used as a workaround which uses 30.5 usec tick. All other client + * programs have the legacy SLP_S0 residency counter that is using the 122 + * usec tick. + */ + const int lpm_adj_x2 = pmcdev->map->lpm_res_counter_step_x2; + + if (pmcdev->map == &adl_reg_map) + return (u64)value * GET_X2_COUNTER((u64)lpm_adj_x2); + else + return (u64)value * pmcdev->map->slp_s0_res_counter_step; } static int set_etr3(struct pmc_dev *pmcdev) diff --git a/drivers/platform/x86/intel/tpmi.c b/drivers/platform/x86/intel/tpmi.c index c999732b0f1e..a5227951decc 100644 --- a/drivers/platform/x86/intel/tpmi.c +++ b/drivers/platform/x86/intel/tpmi.c @@ -203,7 +203,7 @@ static int tpmi_create_device(struct intel_tpmi_info *tpmi_info, struct intel_vsec_device *feature_vsec_dev; struct resource *res, *tmp; const char *name; - int ret, i; + int i; name = intel_tpmi_name(pfs->pfs_header.tpmi_id); if (!name) @@ -215,8 +215,8 @@ static int tpmi_create_device(struct intel_tpmi_info *tpmi_info, feature_vsec_dev = kzalloc(sizeof(*feature_vsec_dev), GFP_KERNEL); if (!feature_vsec_dev) { - ret = -ENOMEM; - goto free_res; + kfree(res); + return -ENOMEM; } snprintf(feature_id_name, sizeof(feature_id_name), "tpmi-%s", name); @@ -239,20 +239,11 @@ static int tpmi_create_device(struct intel_tpmi_info *tpmi_info, /* * intel_vsec_add_aux() is resource managed, no explicit * delete is required on error or on module unload. - * feature_vsec_dev memory is also freed as part of device - * delete. + * feature_vsec_dev and res memory are also freed as part of + * device deletion. */ - ret = intel_vsec_add_aux(vsec_dev->pcidev, &vsec_dev->auxdev.dev, - feature_vsec_dev, feature_id_name); - if (ret) - goto free_res; - - return 0; - -free_res: - kfree(res); - - return ret; + return intel_vsec_add_aux(vsec_dev->pcidev, &vsec_dev->auxdev.dev, + feature_vsec_dev, feature_id_name); } static int tpmi_create_devices(struct intel_tpmi_info *tpmi_info) diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c index 13decf36c6de..2311c16cb975 100644 --- a/drivers/platform/x86/intel/vsec.c +++ b/drivers/platform/x86/intel/vsec.c @@ -154,6 +154,7 @@ int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent, ret = ida_alloc(intel_vsec_dev->ida, GFP_KERNEL); mutex_unlock(&vsec_ida_lock); if (ret < 0) { + kfree(intel_vsec_dev->resource); kfree(intel_vsec_dev); return ret; } diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c index 86b33b74519b..78dc82bda4dd 100644 --- a/drivers/platform/x86/think-lmi.c +++ b/drivers/platform/x86/think-lmi.c @@ -920,7 +920,7 @@ static ssize_t display_name_show(struct kobject *kobj, struct kobj_attribute *at static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj); - char *item, *value; + char *item, *value, *p; int ret; ret = tlmi_setting(setting->index, &item, LENOVO_BIOS_SETTING_GUID); @@ -930,10 +930,15 @@ static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *a /* validate and split from `item,value` -> `value` */ value = strpbrk(item, ","); if (!value || value == item || !strlen(value + 1)) - return -EINVAL; - - ret = sysfs_emit(buf, "%s\n", value + 1); + ret = -EINVAL; + else { + /* On Workstations remove the Options part after the value */ + p = strchrnul(value, ';'); + *p = '\0'; + ret = sysfs_emit(buf, "%s\n", value + 1); + } kfree(item); + return ret; } @@ -941,12 +946,23 @@ static ssize_t possible_values_show(struct kobject *kobj, struct kobj_attribute { struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj); - if (!tlmi_priv.can_get_bios_selections) - return -EOPNOTSUPP; - return sysfs_emit(buf, "%s\n", setting->possible_values); } +static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj); + + if (setting->possible_values) { + /* Figure out what setting type is as BIOS does not return this */ + if (strchr(setting->possible_values, ';')) + return sysfs_emit(buf, "enumeration\n"); + } + /* Anything else is going to be a string */ + return sysfs_emit(buf, "string\n"); +} + static ssize_t current_value_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) @@ -1036,14 +1052,30 @@ static struct kobj_attribute attr_possible_values = __ATTR_RO(possible_values); static struct kobj_attribute attr_current_val = __ATTR_RW_MODE(current_value, 0600); +static struct kobj_attribute attr_type = __ATTR_RO(type); + +static umode_t attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj); + + /* We don't want to display possible_values attributes if not available */ + if ((attr == &attr_possible_values.attr) && (!setting->possible_values)) + return 0; + + return attr->mode; +} + static struct attribute *tlmi_attrs[] = { &attr_displ_name.attr, &attr_current_val.attr, &attr_possible_values.attr, + &attr_type.attr, NULL }; static const struct attribute_group tlmi_attr_group = { + .is_visible = attr_is_visible, .attrs = tlmi_attrs, }; @@ -1423,7 +1455,35 @@ static int tlmi_analyze(void) if (ret || !setting->possible_values) pr_info("Error retrieving possible values for %d : %s\n", i, setting->display_name); + } else { + /* + * Older Thinkstations don't support the bios_selections API. + * Instead they store this as a [Optional:Option1,Option2] section of the + * name string. + * Try and pull that out if it's available. + */ + char *optitem, *optstart, *optend; + + if (!tlmi_setting(setting->index, &optitem, LENOVO_BIOS_SETTING_GUID)) { + optstart = strstr(optitem, "[Optional:"); + if (optstart) { + optstart += strlen("[Optional:"); + optend = strstr(optstart, "]"); + if (optend) + setting->possible_values = + kstrndup(optstart, optend - optstart, + GFP_KERNEL); + } + kfree(optitem); + } } + /* + * firmware-attributes requires that possible_values are separated by ';' but + * Lenovo FW uses ','. Replace appropriately. + */ + if (setting->possible_values) + strreplace(setting->possible_values, ',', ';'); + kobject_init(&setting->kobj, &tlmi_attr_setting_ktype); tlmi_priv.setting[i] = setting; kfree(item); diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 32c10457399e..7191ff2625b1 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -4479,6 +4479,14 @@ static const struct dmi_system_id fwbug_list[] __initconst = { } }, { + .ident = "T14s Gen1 AMD", + .driver_data = &quirk_s2idle_bug, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "20UJ"), + } + }, + { .ident = "P14s Gen1 AMD", .driver_data = &quirk_s2idle_bug, .matches = { diff --git a/drivers/ptp/ptp_qoriq.c b/drivers/ptp/ptp_qoriq.c index 61530167efe4..350154e4c2b5 100644 --- a/drivers/ptp/ptp_qoriq.c +++ b/drivers/ptp/ptp_qoriq.c @@ -637,7 +637,7 @@ static int ptp_qoriq_probe(struct platform_device *dev) return 0; no_clock: - iounmap(ptp_qoriq->base); + iounmap(base); no_ioremap: release_resource(ptp_qoriq->rsrc); no_resource: diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index e01147f66e15..474725714a05 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -115,7 +115,14 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) } if (pwm->chip->ops->get_state) { - struct pwm_state state; + /* + * Zero-initialize state because most drivers are unaware of + * .usage_power. The other members of state are supposed to be + * set by lowlevel drivers. We still initialize the whole + * structure for simplicity even though this might paper over + * faulty implementations of .get_state(). + */ + struct pwm_state state = { 0, }; err = pwm->chip->ops->get_state(pwm->chip, pwm, &state); trace_pwm_get(pwm, &state, err); @@ -448,7 +455,7 @@ static void pwm_apply_state_debug(struct pwm_device *pwm, { struct pwm_state *last = &pwm->last; struct pwm_chip *chip = pwm->chip; - struct pwm_state s1, s2; + struct pwm_state s1 = { 0 }, s2 = { 0 }; int err; if (!IS_ENABLED(CONFIG_PWM_DEBUG)) @@ -530,6 +537,7 @@ static void pwm_apply_state_debug(struct pwm_device *pwm, return; } + *last = (struct pwm_state){ 0 }; err = chip->ops->get_state(chip, pwm, last); trace_pwm_get(pwm, last, err); if (err) diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c index 86df6702cb83..ad18b0ebe3f1 100644 --- a/drivers/pwm/pwm-cros-ec.c +++ b/drivers/pwm/pwm-cros-ec.c @@ -198,6 +198,7 @@ static int cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, state->enabled = (ret > 0); state->period = EC_PWM_MAX_DUTY; + state->polarity = PWM_POLARITY_NORMAL; /* * Note that "disabled" and "duty cycle == 0" are treated the same. If diff --git a/drivers/pwm/pwm-hibvt.c b/drivers/pwm/pwm-hibvt.c index 12c05c155cab..1b9274c5ad87 100644 --- a/drivers/pwm/pwm-hibvt.c +++ b/drivers/pwm/pwm-hibvt.c @@ -146,6 +146,7 @@ static int hibvt_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, value = readl(base + PWM_CTRL_ADDR(pwm->hwpwm)); state->enabled = (PWM_ENABLE_MASK & value); + state->polarity = (PWM_POLARITY_MASK & value) ? PWM_POLARITY_INVERSED : PWM_POLARITY_NORMAL; return 0; } diff --git a/drivers/pwm/pwm-iqs620a.c b/drivers/pwm/pwm-iqs620a.c index 8362b4870c66..47b3141135f3 100644 --- a/drivers/pwm/pwm-iqs620a.c +++ b/drivers/pwm/pwm-iqs620a.c @@ -126,6 +126,7 @@ static int iqs620_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, mutex_unlock(&iqs620_pwm->lock); state->period = IQS620_PWM_PERIOD_NS; + state->polarity = PWM_POLARITY_NORMAL; return 0; } diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 16d79ca5d8f5..5cd7b90872c6 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -162,6 +162,12 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm, duty = state->duty_cycle; period = state->period; + /* + * Note this is wrong. The result is an output wave that isn't really + * inverted and so is wrongly identified by .get_state as normal. + * Fixing this needs some care however as some machines might rely on + * this. + */ if (state->polarity == PWM_POLARITY_INVERSED) duty = period - duty; @@ -358,6 +364,8 @@ static int meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, state->duty_cycle = 0; } + state->polarity = PWM_POLARITY_NORMAL; + return 0; } diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c index d866ce345f97..bde579a338c2 100644 --- a/drivers/pwm/pwm-sprd.c +++ b/drivers/pwm/pwm-sprd.c @@ -109,6 +109,7 @@ static int sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, duty = val & SPRD_PWM_DUTY_MSK; tmp = (prescale + 1) * NSEC_PER_SEC * duty; state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, chn->clk_rate); + state->polarity = PWM_POLARITY_NORMAL; /* Disable PWM clocks if the PWM channel is not in enable state. */ if (!state->enabled) diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 529963a7e4f5..41537c45f036 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -8,18 +8,19 @@ // Copyright (c) 2012 Marvell Technology Ltd. // Yunfan Zhang <yfzhang@marvell.com> +#include <linux/bits.h> +#include <linux/err.h> +#include <linux/i2c.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/param.h> -#include <linux/err.h> #include <linux/platform_device.h> +#include <linux/regmap.h> #include <linux/regulator/driver.h> +#include <linux/regulator/fan53555.h> #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> -#include <linux/of_device.h> -#include <linux/i2c.h> #include <linux/slab.h> -#include <linux/regmap.h> -#include <linux/regulator/fan53555.h> /* Voltage setting */ #define FAN53555_VSEL0 0x00 @@ -60,7 +61,7 @@ #define TCS_VSEL1_MODE (1 << 6) #define TCS_SLEW_SHIFT 3 -#define TCS_SLEW_MASK (0x3 < 3) +#define TCS_SLEW_MASK GENMASK(4, 3) enum fan53555_vendor { FAN53526_VENDOR_FAIRCHILD = 0, diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 2a9867abba20..e6724a229d23 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -215,7 +215,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) drvdata->enable_clock = devm_clk_get(dev, NULL); if (IS_ERR(drvdata->enable_clock)) { dev_err(dev, "Can't get enable-clock from devicetree\n"); - return -ENOENT; + return PTR_ERR(drvdata->enable_clock); } } else if (drvtype && drvtype->has_performance_state) { drvdata->desc.ops = &fixed_voltage_domain_ops; diff --git a/drivers/regulator/sm5703-regulator.c b/drivers/regulator/sm5703-regulator.c index 05ad28fc4da8..229df7170792 100644 --- a/drivers/regulator/sm5703-regulator.c +++ b/drivers/regulator/sm5703-regulator.c @@ -42,6 +42,7 @@ static const int sm5703_buck_voltagemap[] = { .type = REGULATOR_VOLTAGE, \ .id = SM5703_USBLDO ## _id, \ .ops = &sm5703_regulator_ops_fixed, \ + .n_voltages = 1, \ .fixed_uV = SM5703_USBLDO_MICROVOLT, \ .enable_reg = SM5703_REG_USBLDO12, \ .enable_mask = SM5703_REG_EN_USBLDO ##_id, \ @@ -56,6 +57,7 @@ static const int sm5703_buck_voltagemap[] = { .type = REGULATOR_VOLTAGE, \ .id = SM5703_VBUS, \ .ops = &sm5703_regulator_ops_fixed, \ + .n_voltages = 1, \ .fixed_uV = SM5703_VBUS_MICROVOLT, \ .enable_reg = SM5703_REG_CNTL, \ .enable_mask = SM5703_OPERATION_MODE_MASK, \ diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index ab053084f7a2..1ba711bc0100 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -235,8 +235,8 @@ struct q6v5 { bool has_qaccept_regs; bool has_ext_cntl_regs; bool has_vq6; - int mpss_perm; - int mba_perm; + u64 mpss_perm; + u64 mba_perm; const char *hexagon_mdt_image; int version; }; @@ -414,7 +414,7 @@ static void q6v5_pds_disable(struct q6v5 *qproc, struct device **pds, } } -static int q6v5_xfer_mem_ownership(struct q6v5 *qproc, int *current_perm, +static int q6v5_xfer_mem_ownership(struct q6v5 *qproc, u64 *current_perm, bool local, bool remote, phys_addr_t addr, size_t size) { @@ -967,7 +967,7 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw, unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS; dma_addr_t phys; void *metadata; - int mdata_perm; + u64 mdata_perm; int xferop_ret; size_t size; void *ptr; diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 0871108fb4dc..c99a20542685 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -94,7 +94,7 @@ struct qcom_adsp { size_t region_assign_size; int region_assign_idx; - int region_assign_perms; + u64 region_assign_perms; struct qcom_rproc_glink glink_subdev; struct qcom_rproc_subdev smd_subdev; diff --git a/drivers/s390/crypto/vfio_ap_drv.c b/drivers/s390/crypto/vfio_ap_drv.c index 997b524bdd2b..a48c6938ae68 100644 --- a/drivers/s390/crypto/vfio_ap_drv.c +++ b/drivers/s390/crypto/vfio_ap_drv.c @@ -54,8 +54,9 @@ static struct ap_driver vfio_ap_drv = { static void vfio_ap_matrix_dev_release(struct device *dev) { - struct ap_matrix_dev *matrix_dev = dev_get_drvdata(dev); + struct ap_matrix_dev *matrix_dev; + matrix_dev = container_of(dev, struct ap_matrix_dev, device); kfree(matrix_dev); } diff --git a/drivers/sbus/char/oradax.c b/drivers/sbus/char/oradax.c index e300cf26bc2a..d698ca506cca 100644 --- a/drivers/sbus/char/oradax.c +++ b/drivers/sbus/char/oradax.c @@ -18,7 +18,7 @@ * the recommended way for applications to use the coprocessor, and * the driver interface is not intended for general use. * - * See Documentation/sparc/oradax/oracle-dax.rst for more details. + * See Documentation/arch/sparc/oradax/oracle-dax.rst for more details. */ #include <linux/uaccess.h> diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index c76f82fb8b63..15f452908926 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -771,13 +771,12 @@ static int iscsi_sw_tcp_conn_set_param(struct iscsi_cls_conn *cls_conn, iscsi_set_param(cls_conn, param, buf, buflen); break; case ISCSI_PARAM_DATADGST_EN: - iscsi_set_param(cls_conn, param, buf, buflen); - mutex_lock(&tcp_sw_conn->sock_lock); if (!tcp_sw_conn->sock) { mutex_unlock(&tcp_sw_conn->sock_lock); return -ENOTCONN; } + iscsi_set_param(cls_conn, param, buf, buflen); tcp_sw_conn->sendpage = conn->datadgst_en ? sock_no_sendpage : tcp_sw_conn->sock->ops->sendpage; mutex_unlock(&tcp_sw_conn->sock_lock); diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 3ceece988338..c895189375e2 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -3298,7 +3298,7 @@ fw_crash_buffer_show(struct device *cdev, spin_lock_irqsave(&instance->crashdump_lock, flags); buff_offset = instance->fw_crash_buffer_offset; - if (!instance->crash_dump_buf && + if (!instance->crash_dump_buf || !((instance->fw_crash_state == AVAILABLE) || (instance->fw_crash_state == COPYING))) { dev_err(&instance->pdev->dev, diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 84c9a55a5794..8a83f3fc2b86 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -4771,7 +4771,7 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd) devhandle = megasas_get_tm_devhandle(scmd->device); if (devhandle == (u16)ULONG_MAX) { - ret = SUCCESS; + ret = FAILED; sdev_printk(KERN_INFO, scmd->device, "task abort issued for invalid devhandle\n"); mutex_unlock(&instance->reset_mutex); @@ -4841,7 +4841,7 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd) devhandle = megasas_get_tm_devhandle(scmd->device); if (devhandle == (u16)ULONG_MAX) { - ret = SUCCESS; + ret = FAILED; sdev_printk(KERN_INFO, scmd->device, "target reset issued for invalid devhandle\n"); mutex_unlock(&instance->reset_mutex); diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index a565817aa56d..d109a4ceb72b 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -2526,7 +2526,7 @@ static void mpi3mr_watchdog_work(struct work_struct *work) mrioc->unrecoverable = 1; goto schedule_work; case MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS: - return; + goto schedule_work; case MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET: reset_reason = MPI3MR_RESET_FROM_CIACTIV_FAULT; break; diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 2ee9ea57554d..14ae0a9c5d3d 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -6616,11 +6616,6 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) else if (rc == -EAGAIN) goto try_32bit_dma; total_sz += sense_sz; - ioc_info(ioc, - "sense pool(0x%p)- dma(0x%llx): depth(%d)," - "element_size(%d), pool_size(%d kB)\n", - ioc->sense, (unsigned long long)ioc->sense_dma, ioc->scsiio_depth, - SCSI_SENSE_BUFFERSIZE, sz / 1024); /* reply pool, 4 byte align */ sz = ioc->reply_free_queue_depth * ioc->reply_sz; rc = _base_allocate_reply_pool(ioc, sz); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index bee1b8a82020..d0cdbfe771a9 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3617,6 +3617,7 @@ skip_dpc: probe_failed: qla_enode_stop(base_vha); qla_edb_stop(base_vha); + vfree(base_vha->scan.l); if (base_vha->gnl.l) { dma_free_coherent(&ha->pdev->dev, base_vha->gnl.size, base_vha->gnl.l, base_vha->gnl.ldma); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 5cce1ba70fc6..09ef0b31dfc0 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -314,11 +314,18 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer, if (result) return -EIO; - /* Sanity check that we got the page back that we asked for */ + /* + * Sanity check that we got the page back that we asked for and that + * the page size is not 0. + */ if (buffer[1] != page) return -EIO; - return get_unaligned_be16(&buffer[2]) + 4; + result = get_unaligned_be16(&buffer[2]); + if (!result) + return -EIO; + + return result + 4; } static int scsi_get_vpd_size(struct scsi_device *sdev, u8 page) diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index b11a9162e73a..b54f2c6c08c3 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -509,9 +509,6 @@ static int ses_enclosure_find_by_addr(struct enclosure_device *edev, int i; struct ses_component *scomp; - if (!edev->component[0].scratch) - return 0; - for (i = 0; i < edev->components; i++) { scomp = edev->component[i].scratch; if (scomp->addr != efd->addr) @@ -602,8 +599,10 @@ static void ses_enclosure_data_process(struct enclosure_device *edev, components++, type_ptr[0], name); - else + else if (components < edev->components) ecomp = &edev->component[components++]; + else + ecomp = ERR_PTR(-EINVAL); if (!IS_ERR(ecomp)) { if (addl_desc_ptr) { @@ -734,11 +733,6 @@ static int ses_intf_add(struct device *cdev, components += type_ptr[1]; } - if (components == 0) { - sdev_printk(KERN_WARNING, sdev, "enclosure has no enumerated components\n"); - goto err_free; - } - ses_dev->page1 = buf; ses_dev->page1_len = len; buf = NULL; @@ -780,9 +774,11 @@ static int ses_intf_add(struct device *cdev, buf = NULL; } page2_not_supported: - scomp = kcalloc(components, sizeof(struct ses_component), GFP_KERNEL); - if (!scomp) - goto err_free; + if (components > 0) { + scomp = kcalloc(components, sizeof(struct ses_component), GFP_KERNEL); + if (!scomp) + goto err_free; + } edev = enclosure_register(cdev->parent, dev_name(&sdev->sdev_gendev), components, &ses_enclosure_callbacks); diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c index 312fd9afccb0..5d4f12800d93 100644 --- a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c +++ b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c @@ -308,11 +308,9 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev) } rstc = devm_reset_control_array_get_exclusive(&pdev->dev); - if (IS_ERR(rstc)) { - if (PTR_ERR(rstc) != -EPROBE_DEFER) - dev_err(&pdev->dev, "failed to get reset lines\n"); - return PTR_ERR(rstc); - } + if (IS_ERR(rstc)) + return dev_err_probe(&pdev->dev, PTR_ERR(rstc), + "failed to get reset lines\n"); vpu_clk = devm_clk_get(&pdev->dev, "vpu"); if (IS_ERR(vpu_clk)) { diff --git a/drivers/soc/apple/rtkit.c b/drivers/soc/apple/rtkit.c index 35ec35aa500d..d9f19dc99da5 100644 --- a/drivers/soc/apple/rtkit.c +++ b/drivers/soc/apple/rtkit.c @@ -55,7 +55,7 @@ enum { #define APPLE_RTKIT_BUFFER_REQUEST 1 #define APPLE_RTKIT_BUFFER_REQUEST_SIZE GENMASK_ULL(51, 44) -#define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK_ULL(41, 0) +#define APPLE_RTKIT_BUFFER_REQUEST_IOVA GENMASK_ULL(43, 0) #define APPLE_RTKIT_SYSLOG_TYPE GENMASK_ULL(59, 52) @@ -409,11 +409,17 @@ static void apple_rtkit_syslog_rx_init(struct apple_rtkit *rtk, u64 msg) rtk->syslog_n_entries, rtk->syslog_msg_size); } +static bool should_crop_syslog_char(char c) +{ + return c == '\n' || c == '\r' || c == ' ' || c == '\0'; +} + static void apple_rtkit_syslog_rx_log(struct apple_rtkit *rtk, u64 msg) { u8 idx = msg & 0xff; char log_context[24]; size_t entry_size = 0x20 + rtk->syslog_msg_size; + int msglen; if (!rtk->syslog_msg_buffer) { dev_warn( @@ -446,7 +452,13 @@ static void apple_rtkit_syslog_rx_log(struct apple_rtkit *rtk, u64 msg) rtk->syslog_msg_size); log_context[sizeof(log_context) - 1] = 0; - rtk->syslog_msg_buffer[rtk->syslog_msg_size - 1] = 0; + + msglen = rtk->syslog_msg_size - 1; + while (msglen > 0 && + should_crop_syslog_char(rtk->syslog_msg_buffer[msglen - 1])) + msglen--; + + rtk->syslog_msg_buffer[msglen] = 0; dev_info(rtk->dev, "RTKit: syslog message: %s: %s\n", log_context, rtk->syslog_msg_buffer); diff --git a/drivers/soc/bcm/bcm2835-power.c b/drivers/soc/bcm/bcm2835-power.c index bf51f03f77d6..1a179d4e011c 100644 --- a/drivers/soc/bcm/bcm2835-power.c +++ b/drivers/soc/bcm/bcm2835-power.c @@ -711,4 +711,3 @@ module_platform_driver(bcm2835_power_driver); MODULE_AUTHOR("Eric Anholt <eric@anholt.net>"); MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM power domains and reset"); -MODULE_LICENSE("GPL"); diff --git a/drivers/soc/bcm/brcmstb/Kconfig b/drivers/soc/bcm/brcmstb/Kconfig index 38e476905d96..c68d0e5267c4 100644 --- a/drivers/soc/bcm/brcmstb/Kconfig +++ b/drivers/soc/bcm/brcmstb/Kconfig @@ -4,8 +4,6 @@ if SOC_BRCMSTB config BRCMSTB_PM bool "Support suspend/resume for STB platforms" default y - depends on PM - depends on ARCH_BRCMSTB || BMIPS_GENERIC - select ARM_CPU_SUSPEND if ARM + depends on PM && BMIPS_GENERIC endif # SOC_BRCMSTB diff --git a/drivers/soc/bcm/brcmstb/biuctrl.c b/drivers/soc/bcm/brcmstb/biuctrl.c index e1d7b4543248..364ddbe365c2 100644 --- a/drivers/soc/bcm/brcmstb/biuctrl.c +++ b/drivers/soc/bcm/brcmstb/biuctrl.c @@ -288,6 +288,10 @@ static int __init setup_hifcpubiuctrl_regs(struct device_node *np) if (BRCM_ID(family_id) == 0x7260 && BRCM_REV(family_id) == 0) cpubiuctrl_regs = b53_cpubiuctrl_no_wb_regs; out: + if (ret && cpubiuctrl_base) { + iounmap(cpubiuctrl_base); + cpubiuctrl_base = NULL; + } return ret; } diff --git a/drivers/soc/bcm/brcmstb/pm/Makefile b/drivers/soc/bcm/brcmstb/pm/Makefile index f849cfa69446..9133a9ee0782 100644 --- a/drivers/soc/bcm/brcmstb/pm/Makefile +++ b/drivers/soc/bcm/brcmstb/pm/Makefile @@ -1,3 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_ARM) += s2-arm.o pm-arm.o obj-$(CONFIG_BMIPS_GENERIC) += s2-mips.o s3-mips.o pm-mips.o diff --git a/drivers/soc/bcm/brcmstb/pm/aon_defs.h b/drivers/soc/bcm/brcmstb/pm/aon_defs.h deleted file mode 100644 index f695262ac930..000000000000 --- a/drivers/soc/bcm/brcmstb/pm/aon_defs.h +++ /dev/null @@ -1,105 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Always ON (AON) register interface between bootloader and Linux - * - * Copyright © 2014-2017 Broadcom - */ - -#ifndef __BRCMSTB_AON_DEFS_H__ -#define __BRCMSTB_AON_DEFS_H__ - -#include <linux/compiler.h> - -/* Magic number in upper 16-bits */ -#define BRCMSTB_S3_MAGIC_MASK 0xffff0000 -#define BRCMSTB_S3_MAGIC_SHORT 0x5AFE0000 - -enum { - /* Restore random key for AES memory verification (off = fixed key) */ - S3_FLAG_LOAD_RANDKEY = (1 << 0), - - /* Scratch buffer page table is present */ - S3_FLAG_SCRATCH_BUFFER_TABLE = (1 << 1), - - /* Skip all memory verification */ - S3_FLAG_NO_MEM_VERIFY = (1 << 2), - - /* - * Modification of this bit reserved for bootloader only. - * 1=PSCI started Linux, 0=Direct jump to Linux. - */ - S3_FLAG_PSCI_BOOT = (1 << 3), - - /* - * Modification of this bit reserved for bootloader only. - * 1=64 bit boot, 0=32 bit boot. - */ - S3_FLAG_BOOTED64 = (1 << 4), -}; - -#define BRCMSTB_HASH_LEN (128 / 8) /* 128-bit hash */ - -#define AON_REG_MAGIC_FLAGS 0x00 -#define AON_REG_CONTROL_LOW 0x04 -#define AON_REG_CONTROL_HIGH 0x08 -#define AON_REG_S3_HASH 0x0c /* hash of S3 params */ -#define AON_REG_CONTROL_HASH_LEN 0x1c -#define AON_REG_PANIC 0x20 - -#define BRCMSTB_S3_MAGIC 0x5AFEB007 -#define BRCMSTB_PANIC_MAGIC 0x512E115E -#define BOOTLOADER_SCRATCH_SIZE 64 -#define BRCMSTB_DTU_STATE_MAP_ENTRIES (8*1024) -#define BRCMSTB_DTU_CONFIG_ENTRIES (512) -#define BRCMSTB_DTU_COUNT (2) - -#define IMAGE_DESCRIPTORS_BUFSIZE (2 * 1024) -#define S3_BOOTLOADER_RESERVED (S3_FLAG_PSCI_BOOT | S3_FLAG_BOOTED64) - -struct brcmstb_bootloader_dtu_table { - uint32_t dtu_state_map[BRCMSTB_DTU_STATE_MAP_ENTRIES]; - uint32_t dtu_config[BRCMSTB_DTU_CONFIG_ENTRIES]; -}; - -/* - * Bootloader utilizes a custom parameter block left in DRAM for handling S3 - * warm resume - */ -struct brcmstb_s3_params { - /* scratch memory for bootloader */ - uint8_t scratch[BOOTLOADER_SCRATCH_SIZE]; - - uint32_t magic; /* BRCMSTB_S3_MAGIC */ - uint64_t reentry; /* PA */ - - /* descriptors */ - uint32_t hash[BRCMSTB_HASH_LEN / 4]; - - /* - * If 0, then ignore this parameter (there is only one set of - * descriptors) - * - * If non-0, then a second set of descriptors is stored at: - * - * descriptors + desc_offset_2 - * - * The MAC result of both descriptors is XOR'd and stored in @hash - */ - uint32_t desc_offset_2; - - /* - * (Physical) address of a brcmstb_bootloader_scratch_table, for - * providing a large DRAM buffer to the bootloader - */ - uint64_t buffer_table; - - uint32_t spare[70]; - - uint8_t descriptors[IMAGE_DESCRIPTORS_BUFSIZE]; - /* - * Must be last member of struct. See brcmstb_pm_s3_finish() for reason. - */ - struct brcmstb_bootloader_dtu_table dtu[BRCMSTB_DTU_COUNT]; -} __packed; - -#endif /* __BRCMSTB_AON_DEFS_H__ */ diff --git a/drivers/soc/bcm/brcmstb/pm/pm-arm.c b/drivers/soc/bcm/brcmstb/pm/pm-arm.c deleted file mode 100644 index d681cd24c6e1..000000000000 --- a/drivers/soc/bcm/brcmstb/pm/pm-arm.c +++ /dev/null @@ -1,874 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * ARM-specific support for Broadcom STB S2/S3/S5 power management - * - * S2: clock gate CPUs and as many peripherals as possible - * S3: power off all of the chip except the Always ON (AON) island; keep DDR is - * self-refresh - * S5: (a.k.a. S3 cold boot) much like S3, except DDR is powered down, so we - * treat this mode like a soft power-off, with wakeup allowed from AON - * - * Copyright © 2014-2017 Broadcom - */ - -#define pr_fmt(fmt) "brcmstb-pm: " fmt - -#include <linux/bitops.h> -#include <linux/compiler.h> -#include <linux/delay.h> -#include <linux/dma-mapping.h> -#include <linux/err.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/ioport.h> -#include <linux/kconfig.h> -#include <linux/kernel.h> -#include <linux/memblock.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/panic_notifier.h> -#include <linux/platform_device.h> -#include <linux/pm.h> -#include <linux/printk.h> -#include <linux/proc_fs.h> -#include <linux/sizes.h> -#include <linux/slab.h> -#include <linux/sort.h> -#include <linux/suspend.h> -#include <linux/types.h> -#include <linux/uaccess.h> -#include <linux/soc/brcmstb/brcmstb.h> - -#include <asm/fncpy.h> -#include <asm/setup.h> -#include <asm/suspend.h> - -#include "pm.h" -#include "aon_defs.h" - -#define SHIMPHY_DDR_PAD_CNTRL 0x8c - -/* Method #0 */ -#define SHIMPHY_PAD_PLL_SEQUENCE BIT(8) -#define SHIMPHY_PAD_GATE_PLL_S3 BIT(9) - -/* Method #1 */ -#define PWRDWN_SEQ_NO_SEQUENCING 0 -#define PWRDWN_SEQ_HOLD_CHANNEL 1 -#define PWRDWN_SEQ_RESET_PLL 2 -#define PWRDWN_SEQ_POWERDOWN_PLL 3 - -#define SHIMPHY_PAD_S3_PWRDWN_SEQ_MASK 0x00f00000 -#define SHIMPHY_PAD_S3_PWRDWN_SEQ_SHIFT 20 - -#define DDR_FORCE_CKE_RST_N BIT(3) -#define DDR_PHY_RST_N BIT(2) -#define DDR_PHY_CKE BIT(1) - -#define DDR_PHY_NO_CHANNEL 0xffffffff - -#define MAX_NUM_MEMC 3 - -struct brcmstb_memc { - void __iomem *ddr_phy_base; - void __iomem *ddr_shimphy_base; - void __iomem *ddr_ctrl; -}; - -struct brcmstb_pm_control { - void __iomem *aon_ctrl_base; - void __iomem *aon_sram; - struct brcmstb_memc memcs[MAX_NUM_MEMC]; - - void __iomem *boot_sram; - size_t boot_sram_len; - - bool support_warm_boot; - size_t pll_status_offset; - int num_memc; - - struct brcmstb_s3_params *s3_params; - dma_addr_t s3_params_pa; - int s3entry_method; - u32 warm_boot_offset; - u32 phy_a_standby_ctrl_offs; - u32 phy_b_standby_ctrl_offs; - bool needs_ddr_pad; - struct platform_device *pdev; -}; - -enum bsp_initiate_command { - BSP_CLOCK_STOP = 0x00, - BSP_GEN_RANDOM_KEY = 0x4A, - BSP_RESTORE_RANDOM_KEY = 0x55, - BSP_GEN_FIXED_KEY = 0x63, -}; - -#define PM_INITIATE 0x01 -#define PM_INITIATE_SUCCESS 0x00 -#define PM_INITIATE_FAIL 0xfe - -static struct brcmstb_pm_control ctrl; - -noinline int brcmstb_pm_s3_finish(void); - -static int (*brcmstb_pm_do_s2_sram)(void __iomem *aon_ctrl_base, - void __iomem *ddr_phy_pll_status); - -static int brcmstb_init_sram(struct device_node *dn) -{ - void __iomem *sram; - struct resource res; - int ret; - - ret = of_address_to_resource(dn, 0, &res); - if (ret) - return ret; - - /* Uncached, executable remapping of SRAM */ - sram = __arm_ioremap_exec(res.start, resource_size(&res), false); - if (!sram) - return -ENOMEM; - - ctrl.boot_sram = sram; - ctrl.boot_sram_len = resource_size(&res); - - return 0; -} - -static const struct of_device_id sram_dt_ids[] = { - { .compatible = "mmio-sram" }, - { /* sentinel */ } -}; - -static int do_bsp_initiate_command(enum bsp_initiate_command cmd) -{ - void __iomem *base = ctrl.aon_ctrl_base; - int ret; - int timeo = 1000 * 1000; /* 1 second */ - - writel_relaxed(0, base + AON_CTRL_PM_INITIATE); - (void)readl_relaxed(base + AON_CTRL_PM_INITIATE); - - /* Go! */ - writel_relaxed((cmd << 1) | PM_INITIATE, base + AON_CTRL_PM_INITIATE); - - /* - * If firmware doesn't support the 'ack', then just assume it's done - * after 10ms. Note that this only works for command 0, BSP_CLOCK_STOP - */ - if (of_machine_is_compatible("brcm,bcm74371a0")) { - (void)readl_relaxed(base + AON_CTRL_PM_INITIATE); - mdelay(10); - return 0; - } - - for (;;) { - ret = readl_relaxed(base + AON_CTRL_PM_INITIATE); - if (!(ret & PM_INITIATE)) - break; - if (timeo <= 0) { - pr_err("error: timeout waiting for BSP (%x)\n", ret); - break; - } - timeo -= 50; - udelay(50); - } - - return (ret & 0xff) != PM_INITIATE_SUCCESS; -} - -static int brcmstb_pm_handshake(void) -{ - void __iomem *base = ctrl.aon_ctrl_base; - u32 tmp; - int ret; - - /* BSP power handshake, v1 */ - tmp = readl_relaxed(base + AON_CTRL_HOST_MISC_CMDS); - tmp &= ~1UL; - writel_relaxed(tmp, base + AON_CTRL_HOST_MISC_CMDS); - (void)readl_relaxed(base + AON_CTRL_HOST_MISC_CMDS); - - ret = do_bsp_initiate_command(BSP_CLOCK_STOP); - if (ret) - pr_err("BSP handshake failed\n"); - - /* - * HACK: BSP may have internal race on the CLOCK_STOP command. - * Avoid touching the BSP for a few milliseconds. - */ - mdelay(3); - - return ret; -} - -static inline void shimphy_set(u32 value, u32 mask) -{ - int i; - - if (!ctrl.needs_ddr_pad) - return; - - for (i = 0; i < ctrl.num_memc; i++) { - u32 tmp; - - tmp = readl_relaxed(ctrl.memcs[i].ddr_shimphy_base + - SHIMPHY_DDR_PAD_CNTRL); - tmp = value | (tmp & mask); - writel_relaxed(tmp, ctrl.memcs[i].ddr_shimphy_base + - SHIMPHY_DDR_PAD_CNTRL); - } - wmb(); /* Complete sequence in order. */ -} - -static inline void ddr_ctrl_set(bool warmboot) -{ - int i; - - for (i = 0; i < ctrl.num_memc; i++) { - u32 tmp; - - tmp = readl_relaxed(ctrl.memcs[i].ddr_ctrl + - ctrl.warm_boot_offset); - if (warmboot) - tmp |= 1; - else - tmp &= ~1; /* Cold boot */ - writel_relaxed(tmp, ctrl.memcs[i].ddr_ctrl + - ctrl.warm_boot_offset); - } - /* Complete sequence in order */ - wmb(); -} - -static inline void s3entry_method0(void) -{ - shimphy_set(SHIMPHY_PAD_GATE_PLL_S3 | SHIMPHY_PAD_PLL_SEQUENCE, - 0xffffffff); -} - -static inline void s3entry_method1(void) -{ - /* - * S3 Entry Sequence - * ----------------- - * Step 1: SHIMPHY_ADDR_CNTL_0_DDR_PAD_CNTRL [ S3_PWRDWN_SEQ ] = 3 - * Step 2: MEMC_DDR_0_WARM_BOOT [ WARM_BOOT ] = 1 - */ - shimphy_set((PWRDWN_SEQ_POWERDOWN_PLL << - SHIMPHY_PAD_S3_PWRDWN_SEQ_SHIFT), - ~SHIMPHY_PAD_S3_PWRDWN_SEQ_MASK); - - ddr_ctrl_set(true); -} - -static inline void s5entry_method1(void) -{ - int i; - - /* - * S5 Entry Sequence - * ----------------- - * Step 1: SHIMPHY_ADDR_CNTL_0_DDR_PAD_CNTRL [ S3_PWRDWN_SEQ ] = 3 - * Step 2: MEMC_DDR_0_WARM_BOOT [ WARM_BOOT ] = 0 - * Step 3: DDR_PHY_CONTROL_REGS_[AB]_0_STANDBY_CONTROL[ CKE ] = 0 - * DDR_PHY_CONTROL_REGS_[AB]_0_STANDBY_CONTROL[ RST_N ] = 0 - */ - shimphy_set((PWRDWN_SEQ_POWERDOWN_PLL << - SHIMPHY_PAD_S3_PWRDWN_SEQ_SHIFT), - ~SHIMPHY_PAD_S3_PWRDWN_SEQ_MASK); - - ddr_ctrl_set(false); - - for (i = 0; i < ctrl.num_memc; i++) { - u32 tmp; - - /* Step 3: Channel A (RST_N = CKE = 0) */ - tmp = readl_relaxed(ctrl.memcs[i].ddr_phy_base + - ctrl.phy_a_standby_ctrl_offs); - tmp &= ~(DDR_PHY_RST_N | DDR_PHY_RST_N); - writel_relaxed(tmp, ctrl.memcs[i].ddr_phy_base + - ctrl.phy_a_standby_ctrl_offs); - - /* Step 3: Channel B? */ - if (ctrl.phy_b_standby_ctrl_offs != DDR_PHY_NO_CHANNEL) { - tmp = readl_relaxed(ctrl.memcs[i].ddr_phy_base + - ctrl.phy_b_standby_ctrl_offs); - tmp &= ~(DDR_PHY_RST_N | DDR_PHY_RST_N); - writel_relaxed(tmp, ctrl.memcs[i].ddr_phy_base + - ctrl.phy_b_standby_ctrl_offs); - } - } - /* Must complete */ - wmb(); -} - -/* - * Run a Power Management State Machine (PMSM) shutdown command and put the CPU - * into a low-power mode - */ -static void brcmstb_do_pmsm_power_down(unsigned long base_cmd, bool onewrite) -{ - void __iomem *base = ctrl.aon_ctrl_base; - - if ((ctrl.s3entry_method == 1) && (base_cmd == PM_COLD_CONFIG)) - s5entry_method1(); - - /* pm_start_pwrdn transition 0->1 */ - writel_relaxed(base_cmd, base + AON_CTRL_PM_CTRL); - - if (!onewrite) { - (void)readl_relaxed(base + AON_CTRL_PM_CTRL); - - writel_relaxed(base_cmd | PM_PWR_DOWN, base + AON_CTRL_PM_CTRL); - (void)readl_relaxed(base + AON_CTRL_PM_CTRL); - } - wfi(); -} - -/* Support S5 cold boot out of "poweroff" */ -static void brcmstb_pm_poweroff(void) -{ - brcmstb_pm_handshake(); - - /* Clear magic S3 warm-boot value */ - writel_relaxed(0, ctrl.aon_sram + AON_REG_MAGIC_FLAGS); - (void)readl_relaxed(ctrl.aon_sram + AON_REG_MAGIC_FLAGS); - - /* Skip wait-for-interrupt signal; just use a countdown */ - writel_relaxed(0x10, ctrl.aon_ctrl_base + AON_CTRL_PM_CPU_WAIT_COUNT); - (void)readl_relaxed(ctrl.aon_ctrl_base + AON_CTRL_PM_CPU_WAIT_COUNT); - - if (ctrl.s3entry_method == 1) { - shimphy_set((PWRDWN_SEQ_POWERDOWN_PLL << - SHIMPHY_PAD_S3_PWRDWN_SEQ_SHIFT), - ~SHIMPHY_PAD_S3_PWRDWN_SEQ_MASK); - ddr_ctrl_set(false); - brcmstb_do_pmsm_power_down(M1_PM_COLD_CONFIG, true); - return; /* We should never actually get here */ - } - - brcmstb_do_pmsm_power_down(PM_COLD_CONFIG, false); -} - -static void *brcmstb_pm_copy_to_sram(void *fn, size_t len) -{ - unsigned int size = ALIGN(len, FNCPY_ALIGN); - - if (ctrl.boot_sram_len < size) { - pr_err("standby code will not fit in SRAM\n"); - return NULL; - } - - return fncpy(ctrl.boot_sram, fn, size); -} - -/* - * S2 suspend/resume picks up where we left off, so we must execute carefully - * from SRAM, in order to allow DDR to come back up safely before we continue. - */ -static int brcmstb_pm_s2(void) -{ - /* A previous S3 can set a value hazardous to S2, so make sure. */ - if (ctrl.s3entry_method == 1) { - shimphy_set((PWRDWN_SEQ_NO_SEQUENCING << - SHIMPHY_PAD_S3_PWRDWN_SEQ_SHIFT), - ~SHIMPHY_PAD_S3_PWRDWN_SEQ_MASK); - ddr_ctrl_set(false); - } - - brcmstb_pm_do_s2_sram = brcmstb_pm_copy_to_sram(&brcmstb_pm_do_s2, - brcmstb_pm_do_s2_sz); - if (!brcmstb_pm_do_s2_sram) - return -EINVAL; - - return brcmstb_pm_do_s2_sram(ctrl.aon_ctrl_base, - ctrl.memcs[0].ddr_phy_base + - ctrl.pll_status_offset); -} - -/* - * This function is called on a new stack, so don't allow inlining (which will - * generate stack references on the old stack). It cannot be made static because - * it is referenced from brcmstb_pm_s3() - */ -noinline int brcmstb_pm_s3_finish(void) -{ - struct brcmstb_s3_params *params = ctrl.s3_params; - dma_addr_t params_pa = ctrl.s3_params_pa; - phys_addr_t reentry = virt_to_phys(&cpu_resume_arm); - enum bsp_initiate_command cmd; - u32 flags; - - /* - * Clear parameter structure, but not DTU area, which has already been - * filled in. We know DTU is a the end, so we can just subtract its - * size. - */ - memset(params, 0, sizeof(*params) - sizeof(params->dtu)); - - flags = readl_relaxed(ctrl.aon_sram + AON_REG_MAGIC_FLAGS); - - flags &= S3_BOOTLOADER_RESERVED; - flags |= S3_FLAG_NO_MEM_VERIFY; - flags |= S3_FLAG_LOAD_RANDKEY; - - /* Load random / fixed key */ - if (flags & S3_FLAG_LOAD_RANDKEY) - cmd = BSP_GEN_RANDOM_KEY; - else - cmd = BSP_GEN_FIXED_KEY; - if (do_bsp_initiate_command(cmd)) { - pr_info("key loading failed\n"); - return -EIO; - } - - params->magic = BRCMSTB_S3_MAGIC; - params->reentry = reentry; - - /* No more writes to DRAM */ - flush_cache_all(); - - flags |= BRCMSTB_S3_MAGIC_SHORT; - - writel_relaxed(flags, ctrl.aon_sram + AON_REG_MAGIC_FLAGS); - writel_relaxed(lower_32_bits(params_pa), - ctrl.aon_sram + AON_REG_CONTROL_LOW); - writel_relaxed(upper_32_bits(params_pa), - ctrl.aon_sram + AON_REG_CONTROL_HIGH); - - switch (ctrl.s3entry_method) { - case 0: - s3entry_method0(); - brcmstb_do_pmsm_power_down(PM_WARM_CONFIG, false); - break; - case 1: - s3entry_method1(); - brcmstb_do_pmsm_power_down(M1_PM_WARM_CONFIG, true); - break; - default: - return -EINVAL; - } - - /* Must have been interrupted from wfi()? */ - return -EINTR; -} - -static int brcmstb_pm_do_s3(unsigned long sp) -{ - unsigned long save_sp; - int ret; - - asm volatile ( - "mov %[save], sp\n" - "mov sp, %[new]\n" - "bl brcmstb_pm_s3_finish\n" - "mov %[ret], r0\n" - "mov %[new], sp\n" - "mov sp, %[save]\n" - : [save] "=&r" (save_sp), [ret] "=&r" (ret) - : [new] "r" (sp) - ); - - return ret; -} - -static int brcmstb_pm_s3(void) -{ - void __iomem *sp = ctrl.boot_sram + ctrl.boot_sram_len; - - return cpu_suspend((unsigned long)sp, brcmstb_pm_do_s3); -} - -static int brcmstb_pm_standby(bool deep_standby) -{ - int ret; - - if (brcmstb_pm_handshake()) - return -EIO; - - if (deep_standby) - ret = brcmstb_pm_s3(); - else - ret = brcmstb_pm_s2(); - if (ret) - pr_err("%s: standby failed\n", __func__); - - return ret; -} - -static int brcmstb_pm_enter(suspend_state_t state) -{ - int ret = -EINVAL; - - switch (state) { - case PM_SUSPEND_STANDBY: - ret = brcmstb_pm_standby(false); - break; - case PM_SUSPEND_MEM: - ret = brcmstb_pm_standby(true); - break; - } - - return ret; -} - -static int brcmstb_pm_valid(suspend_state_t state) -{ - switch (state) { - case PM_SUSPEND_STANDBY: - return true; - case PM_SUSPEND_MEM: - return ctrl.support_warm_boot; - default: - return false; - } -} - -static const struct platform_suspend_ops brcmstb_pm_ops = { - .enter = brcmstb_pm_enter, - .valid = brcmstb_pm_valid, -}; - -static const struct of_device_id aon_ctrl_dt_ids[] = { - { .compatible = "brcm,brcmstb-aon-ctrl" }, - {} -}; - -struct ddr_phy_ofdata { - bool supports_warm_boot; - size_t pll_status_offset; - int s3entry_method; - u32 warm_boot_offset; - u32 phy_a_standby_ctrl_offs; - u32 phy_b_standby_ctrl_offs; -}; - -static struct ddr_phy_ofdata ddr_phy_71_1 = { - .supports_warm_boot = true, - .pll_status_offset = 0x0c, - .s3entry_method = 1, - .warm_boot_offset = 0x2c, - .phy_a_standby_ctrl_offs = 0x198, - .phy_b_standby_ctrl_offs = DDR_PHY_NO_CHANNEL -}; - -static struct ddr_phy_ofdata ddr_phy_72_0 = { - .supports_warm_boot = true, - .pll_status_offset = 0x10, - .s3entry_method = 1, - .warm_boot_offset = 0x40, - .phy_a_standby_ctrl_offs = 0x2a4, - .phy_b_standby_ctrl_offs = 0x8a4 -}; - -static struct ddr_phy_ofdata ddr_phy_225_1 = { - .supports_warm_boot = false, - .pll_status_offset = 0x4, - .s3entry_method = 0 -}; - -static struct ddr_phy_ofdata ddr_phy_240_1 = { - .supports_warm_boot = true, - .pll_status_offset = 0x4, - .s3entry_method = 0 -}; - -static const struct of_device_id ddr_phy_dt_ids[] = { - { - .compatible = "brcm,brcmstb-ddr-phy-v71.1", - .data = &ddr_phy_71_1, - }, - { - .compatible = "brcm,brcmstb-ddr-phy-v72.0", - .data = &ddr_phy_72_0, - }, - { - .compatible = "brcm,brcmstb-ddr-phy-v225.1", - .data = &ddr_phy_225_1, - }, - { - .compatible = "brcm,brcmstb-ddr-phy-v240.1", - .data = &ddr_phy_240_1, - }, - { - /* Same as v240.1, for the registers we care about */ - .compatible = "brcm,brcmstb-ddr-phy-v240.2", - .data = &ddr_phy_240_1, - }, - {} -}; - -struct ddr_seq_ofdata { - bool needs_ddr_pad; - u32 warm_boot_offset; -}; - -static const struct ddr_seq_ofdata ddr_seq_b22 = { - .needs_ddr_pad = false, - .warm_boot_offset = 0x2c, -}; - -static const struct ddr_seq_ofdata ddr_seq = { - .needs_ddr_pad = true, -}; - -static const struct of_device_id ddr_shimphy_dt_ids[] = { - { .compatible = "brcm,brcmstb-ddr-shimphy-v1.0" }, - {} -}; - -static const struct of_device_id brcmstb_memc_of_match[] = { - { - .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.1", - .data = &ddr_seq, - }, - { - .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.2", - .data = &ddr_seq_b22, - }, - { - .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.3", - .data = &ddr_seq_b22, - }, - { - .compatible = "brcm,brcmstb-memc-ddr-rev-b.3.0", - .data = &ddr_seq_b22, - }, - { - .compatible = "brcm,brcmstb-memc-ddr-rev-b.3.1", - .data = &ddr_seq_b22, - }, - { - .compatible = "brcm,brcmstb-memc-ddr", - .data = &ddr_seq, - }, - {}, -}; - -static void __iomem *brcmstb_ioremap_match(const struct of_device_id *matches, - int index, const void **ofdata) -{ - struct device_node *dn; - const struct of_device_id *match; - - dn = of_find_matching_node_and_match(NULL, matches, &match); - if (!dn) - return ERR_PTR(-EINVAL); - - if (ofdata) - *ofdata = match->data; - - return of_io_request_and_map(dn, index, dn->full_name); -} -/* - * The AON is a small domain in the SoC that can retain its state across - * various system wide sleep states and specific reset conditions; the - * AON DATA RAM is a small RAM of a few words (< 1KB) which can store - * persistent information across such events. - * - * The purpose of the below panic notifier is to help with notifying - * the bootloader that a panic occurred and so that it should try its - * best to preserve the DRAM contents holding that buffer for recovery - * by the kernel as opposed to wiping out DRAM clean again. - * - * Reference: comment from Florian Fainelli, at - * https://lore.kernel.org/lkml/781cafb0-8d06-8b56-907a-5175c2da196a@gmail.com - */ -static int brcmstb_pm_panic_notify(struct notifier_block *nb, - unsigned long action, void *data) -{ - writel_relaxed(BRCMSTB_PANIC_MAGIC, ctrl.aon_sram + AON_REG_PANIC); - - return NOTIFY_DONE; -} - -static struct notifier_block brcmstb_pm_panic_nb = { - .notifier_call = brcmstb_pm_panic_notify, -}; - -static int brcmstb_pm_probe(struct platform_device *pdev) -{ - const struct ddr_phy_ofdata *ddr_phy_data; - const struct ddr_seq_ofdata *ddr_seq_data; - const struct of_device_id *of_id = NULL; - struct device_node *dn; - void __iomem *base; - int ret, i, s; - - /* AON ctrl registers */ - base = brcmstb_ioremap_match(aon_ctrl_dt_ids, 0, NULL); - if (IS_ERR(base)) { - pr_err("error mapping AON_CTRL\n"); - ret = PTR_ERR(base); - goto aon_err; - } - ctrl.aon_ctrl_base = base; - - /* AON SRAM registers */ - base = brcmstb_ioremap_match(aon_ctrl_dt_ids, 1, NULL); - if (IS_ERR(base)) { - /* Assume standard offset */ - ctrl.aon_sram = ctrl.aon_ctrl_base + - AON_CTRL_SYSTEM_DATA_RAM_OFS; - s = 0; - } else { - ctrl.aon_sram = base; - s = 1; - } - - writel_relaxed(0, ctrl.aon_sram + AON_REG_PANIC); - - /* DDR PHY registers */ - base = brcmstb_ioremap_match(ddr_phy_dt_ids, 0, - (const void **)&ddr_phy_data); - if (IS_ERR(base)) { - pr_err("error mapping DDR PHY\n"); - ret = PTR_ERR(base); - goto ddr_phy_err; - } - ctrl.support_warm_boot = ddr_phy_data->supports_warm_boot; - ctrl.pll_status_offset = ddr_phy_data->pll_status_offset; - /* Only need DDR PHY 0 for now? */ - ctrl.memcs[0].ddr_phy_base = base; - ctrl.s3entry_method = ddr_phy_data->s3entry_method; - ctrl.phy_a_standby_ctrl_offs = ddr_phy_data->phy_a_standby_ctrl_offs; - ctrl.phy_b_standby_ctrl_offs = ddr_phy_data->phy_b_standby_ctrl_offs; - /* - * Slightly gross to use the phy ver to get a memc, - * offset but that is the only versioned things so far - * we can test for. - */ - ctrl.warm_boot_offset = ddr_phy_data->warm_boot_offset; - - /* DDR SHIM-PHY registers */ - for_each_matching_node(dn, ddr_shimphy_dt_ids) { - i = ctrl.num_memc; - if (i >= MAX_NUM_MEMC) { - of_node_put(dn); - pr_warn("too many MEMCs (max %d)\n", MAX_NUM_MEMC); - break; - } - - base = of_io_request_and_map(dn, 0, dn->full_name); - if (IS_ERR(base)) { - of_node_put(dn); - if (!ctrl.support_warm_boot) - break; - - pr_err("error mapping DDR SHIMPHY %d\n", i); - ret = PTR_ERR(base); - goto ddr_shimphy_err; - } - ctrl.memcs[i].ddr_shimphy_base = base; - ctrl.num_memc++; - } - - /* Sequencer DRAM Param and Control Registers */ - i = 0; - for_each_matching_node(dn, brcmstb_memc_of_match) { - base = of_iomap(dn, 0); - if (!base) { - of_node_put(dn); - pr_err("error mapping DDR Sequencer %d\n", i); - ret = -ENOMEM; - goto brcmstb_memc_err; - } - - of_id = of_match_node(brcmstb_memc_of_match, dn); - if (!of_id) { - iounmap(base); - of_node_put(dn); - ret = -EINVAL; - goto brcmstb_memc_err; - } - - ddr_seq_data = of_id->data; - ctrl.needs_ddr_pad = ddr_seq_data->needs_ddr_pad; - /* Adjust warm boot offset based on the DDR sequencer */ - if (ddr_seq_data->warm_boot_offset) - ctrl.warm_boot_offset = ddr_seq_data->warm_boot_offset; - - ctrl.memcs[i].ddr_ctrl = base; - i++; - } - - pr_debug("PM: supports warm boot:%d, method:%d, wboffs:%x\n", - ctrl.support_warm_boot, ctrl.s3entry_method, - ctrl.warm_boot_offset); - - dn = of_find_matching_node(NULL, sram_dt_ids); - if (!dn) { - pr_err("SRAM not found\n"); - ret = -EINVAL; - goto brcmstb_memc_err; - } - - ret = brcmstb_init_sram(dn); - of_node_put(dn); - if (ret) { - pr_err("error setting up SRAM for PM\n"); - goto brcmstb_memc_err; - } - - ctrl.pdev = pdev; - - ctrl.s3_params = kmalloc(sizeof(*ctrl.s3_params), GFP_KERNEL); - if (!ctrl.s3_params) { - ret = -ENOMEM; - goto s3_params_err; - } - ctrl.s3_params_pa = dma_map_single(&pdev->dev, ctrl.s3_params, - sizeof(*ctrl.s3_params), - DMA_TO_DEVICE); - if (dma_mapping_error(&pdev->dev, ctrl.s3_params_pa)) { - pr_err("error mapping DMA memory\n"); - ret = -ENOMEM; - goto out; - } - - atomic_notifier_chain_register(&panic_notifier_list, - &brcmstb_pm_panic_nb); - - pm_power_off = brcmstb_pm_poweroff; - suspend_set_ops(&brcmstb_pm_ops); - - return 0; - -out: - kfree(ctrl.s3_params); -s3_params_err: - iounmap(ctrl.boot_sram); -brcmstb_memc_err: - for (i--; i >= 0; i--) - iounmap(ctrl.memcs[i].ddr_ctrl); -ddr_shimphy_err: - for (i = 0; i < ctrl.num_memc; i++) - iounmap(ctrl.memcs[i].ddr_shimphy_base); - - iounmap(ctrl.memcs[0].ddr_phy_base); -ddr_phy_err: - iounmap(ctrl.aon_ctrl_base); - if (s) - iounmap(ctrl.aon_sram); -aon_err: - pr_warn("PM: initialization failed with code %d\n", ret); - - return ret; -} - -static struct platform_driver brcmstb_pm_driver = { - .driver = { - .name = "brcmstb-pm", - .of_match_table = aon_ctrl_dt_ids, - }, -}; - -static int __init brcmstb_pm_init(void) -{ - return platform_driver_probe(&brcmstb_pm_driver, - brcmstb_pm_probe); -} -module_init(brcmstb_pm_init); diff --git a/drivers/soc/bcm/brcmstb/pm/s2-arm.S b/drivers/soc/bcm/brcmstb/pm/s2-arm.S deleted file mode 100644 index 0d693795de27..000000000000 --- a/drivers/soc/bcm/brcmstb/pm/s2-arm.S +++ /dev/null @@ -1,69 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright © 2014-2017 Broadcom - */ - -#include <linux/linkage.h> -#include <asm/assembler.h> - -#include "pm.h" - - .arch armv7-a - .text - .align 3 - -#define AON_CTRL_REG r10 -#define DDR_PHY_STATUS_REG r11 - -/* - * r0: AON_CTRL base address - * r1: DDRY PHY PLL status register address - */ -ENTRY(brcmstb_pm_do_s2) - stmfd sp!, {r4-r11, lr} - mov AON_CTRL_REG, r0 - mov DDR_PHY_STATUS_REG, r1 - - /* Flush memory transactions */ - dsb - - /* Cache DDR_PHY_STATUS_REG translation */ - ldr r0, [DDR_PHY_STATUS_REG] - - /* power down request */ - ldr r0, =PM_S2_COMMAND - ldr r1, =0 - str r1, [AON_CTRL_REG, #AON_CTRL_PM_CTRL] - ldr r1, [AON_CTRL_REG, #AON_CTRL_PM_CTRL] - str r0, [AON_CTRL_REG, #AON_CTRL_PM_CTRL] - ldr r0, [AON_CTRL_REG, #AON_CTRL_PM_CTRL] - - /* Wait for interrupt */ - wfi - nop - - /* Bring MEMC back up */ -1: ldr r0, [DDR_PHY_STATUS_REG] - ands r0, #1 - beq 1b - - /* Power-up handshake */ - ldr r0, =1 - str r0, [AON_CTRL_REG, #AON_CTRL_HOST_MISC_CMDS] - ldr r0, [AON_CTRL_REG, #AON_CTRL_HOST_MISC_CMDS] - - ldr r0, =0 - str r0, [AON_CTRL_REG, #AON_CTRL_PM_CTRL] - ldr r0, [AON_CTRL_REG, #AON_CTRL_PM_CTRL] - - /* Return to caller */ - ldr r0, =0 - ldmfd sp!, {r4-r11, pc} - - ENDPROC(brcmstb_pm_do_s2) - - /* Place literal pool here */ - .ltorg - -ENTRY(brcmstb_pm_do_s2_sz) - .word . - brcmstb_pm_do_s2 diff --git a/drivers/soc/bcm/raspberrypi-power.c b/drivers/soc/bcm/raspberrypi-power.c index 068715d6e66d..58175af982a0 100644 --- a/drivers/soc/bcm/raspberrypi-power.c +++ b/drivers/soc/bcm/raspberrypi-power.c @@ -243,4 +243,3 @@ builtin_platform_driver(rpi_power_driver); MODULE_AUTHOR("Alexander Aring <aar@pengutronix.de>"); MODULE_AUTHOR("Eric Anholt <eric@anholt.net>"); MODULE_DESCRIPTION("Raspberry Pi power domain driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/canaan/Kconfig b/drivers/soc/canaan/Kconfig index 2527cf5757ec..43ced2bf8444 100644 --- a/drivers/soc/canaan/Kconfig +++ b/drivers/soc/canaan/Kconfig @@ -3,8 +3,9 @@ config SOC_K210_SYSCTL bool "Canaan Kendryte K210 SoC system controller" depends on RISCV && SOC_CANAAN && OF + depends on COMMON_CLK_K210 default SOC_CANAAN - select PM - select MFD_SYSCON + select PM + select MFD_SYSCON help Canaan Kendryte K210 SoC system controller driver. diff --git a/drivers/soc/fsl/qbman/dpaa_sys.c b/drivers/soc/fsl/qbman/dpaa_sys.c index 9dd8bb571dbc..33751450047e 100644 --- a/drivers/soc/fsl/qbman/dpaa_sys.c +++ b/drivers/soc/fsl/qbman/dpaa_sys.c @@ -39,8 +39,7 @@ int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr, { struct device_node *mem_node; struct reserved_mem *rmem; - struct property *prop; - int len, err; + int err; __be32 *res_array; mem_node = of_parse_phandle(dev->of_node, "memory-region", idx); @@ -63,8 +62,9 @@ int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr, * This is needed because QBMan HW does not allow the base address/ * size to be modified once set. */ - prop = of_find_property(mem_node, "reg", &len); - if (!prop) { + if (!of_property_present(mem_node, "reg")) { + struct property *prop; + prop = devm_kzalloc(dev, sizeof(*prop), GFP_KERNEL); if (!prop) return -ENOMEM; diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig index a8742fc58f01..76a4593baf0a 100644 --- a/drivers/soc/imx/Kconfig +++ b/drivers/soc/imx/Kconfig @@ -10,7 +10,7 @@ config IMX_GPCV2_PM_DOMAINS default y if SOC_IMX7D config SOC_IMX8M - bool "i.MX8M SoC family support" + tristate "i.MX8M SoC family support" depends on ARCH_MXC || COMPILE_TEST default ARCH_MXC && ARM64 select SOC_BUS diff --git a/drivers/soc/imx/imx8m-blk-ctrl.c b/drivers/soc/imx/imx8m-blk-ctrl.c index 399cb85105a1..afbca0d48c14 100644 --- a/drivers/soc/imx/imx8m-blk-ctrl.c +++ b/drivers/soc/imx/imx8m-blk-ctrl.c @@ -38,10 +38,10 @@ struct imx8m_blk_ctrl { struct imx8m_blk_ctrl_domain_data { const char *name; const char * const *clk_names; - int num_clks; const char * const *path_names; - int num_paths; const char *gpc_name; + int num_clks; + int num_paths; u32 rst_mask; u32 clk_mask; @@ -210,7 +210,7 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev) if (!bc->onecell_data.domains) return -ENOMEM; - bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus"); + bc->bus_power_dev = dev_pm_domain_attach_by_name(dev, "bus"); if (IS_ERR(bc->bus_power_dev)) { if (PTR_ERR(bc->bus_power_dev) == -ENODEV) return dev_err_probe(dev, -EPROBE_DEFER, @@ -310,6 +310,10 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev) dev_set_drvdata(dev, bc); + ret = devm_of_platform_populate(dev); + if (ret) + goto cleanup_provider; + return 0; cleanup_provider: @@ -891,3 +895,4 @@ static struct platform_driver imx8m_blk_ctrl_driver = { }, }; module_platform_driver(imx8m_blk_ctrl_driver); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/imx/imx8mp-blk-ctrl.c b/drivers/soc/imx/imx8mp-blk-ctrl.c index a0592db8fa86..870aecc0202a 100644 --- a/drivers/soc/imx/imx8mp-blk-ctrl.c +++ b/drivers/soc/imx/imx8mp-blk-ctrl.c @@ -642,7 +642,7 @@ static int imx8mp_blk_ctrl_probe(struct platform_device *pdev) if (!bc->onecell_data.domains) return -ENOMEM; - bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus"); + bc->bus_power_dev = dev_pm_domain_attach_by_name(dev, "bus"); if (IS_ERR(bc->bus_power_dev)) return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev), "failed to attach bus power domain\n"); @@ -852,7 +852,7 @@ static const struct of_device_id imx8mp_blk_ctrl_of_match[] = { /* Sentinel */ } }; -MODULE_DEVICE_TABLE(of, imx8m_blk_ctrl_of_match); +MODULE_DEVICE_TABLE(of, imx8mp_blk_ctrl_of_match); static struct platform_driver imx8mp_blk_ctrl_driver = { .probe = imx8mp_blk_ctrl_probe, @@ -864,3 +864,4 @@ static struct platform_driver imx8mp_blk_ctrl_driver = { }, }; module_platform_driver(imx8mp_blk_ctrl_driver); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/imx/soc-imx8m.c b/drivers/soc/imx/soc-imx8m.c index 32ed9dc88e45..1dcd243df567 100644 --- a/drivers/soc/imx/soc-imx8m.c +++ b/drivers/soc/imx/soc-imx8m.c @@ -242,3 +242,4 @@ free_soc: return ret; } device_initcall(imx8_soc_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig index d6b83a5508ca..a88cf04fc803 100644 --- a/drivers/soc/mediatek/Kconfig +++ b/drivers/soc/mediatek/Kconfig @@ -76,6 +76,7 @@ config MTK_MMSYS tristate "MediaTek MMSYS Support" default ARCH_MEDIATEK depends on HAS_IOMEM + depends on MTK_CMDQ || MTK_CMDQ=n help Say yes here to add support for the MediaTek Multimedia Subsystem (MMSYS). diff --git a/drivers/soc/mediatek/mt8173-mmsys.h b/drivers/soc/mediatek/mt8173-mmsys.h new file mode 100644 index 000000000000..9d24e381271e --- /dev/null +++ b/drivers/soc/mediatek/mt8173-mmsys.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __SOC_MEDIATEK_MT8173_MMSYS_H +#define __SOC_MEDIATEK_MT8173_MMSYS_H + +#define MT8173_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0x040 +#define MT8173_DISP_REG_CONFIG_DISP_OVL1_MOUT_EN 0x044 +#define MT8173_DISP_REG_CONFIG_DISP_OD_MOUT_EN 0x048 +#define MT8173_DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN 0x04c +#define MT8173_DISP_REG_CONFIG_DISP_UFOE_MOUT_EN 0x050 +#define MT8173_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x084 +#define MT8173_DISP_REG_CONFIG_DISP_COLOR1_SEL_IN 0x088 +#define MT8173_DISP_REG_CONFIG_DISP_AAL_SEL_IN 0x08c +#define MT8173_DISP_REG_CONFIG_DISP_UFOE_SEL_IN 0x0a0 +#define MT8173_DISP_REG_CONFIG_DSI0_SEL_IN 0x0a4 +#define MT8173_DISP_REG_CONFIG_DPI_SEL_IN 0x0ac +#define MT8173_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN 0x0b0 +#define MT8173_DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN 0x0c8 +#define MT8173_DISP_REG_CONFIG_DISP_COLOR0_SOUT_SEL_IN 0x0bc + +#define MT8173_AAL_SEL_IN_MERGE BIT(0) +#define MT8173_COLOR0_SEL_IN_OVL0 BIT(0) +#define MT8173_COLOR0_SOUT_MERGE BIT(0) +#define MT8173_DPI0_SEL_IN_MASK GENMASK(1, 0) +#define MT8173_DPI0_SEL_IN_RDMA1 BIT(0) +#define MT8173_DSI0_SEL_IN_UFOE BIT(0) +#define MT8173_GAMMA_MOUT_EN_RDMA1 BIT(0) +#define MT8173_OD0_MOUT_EN_RDMA0 BIT(0) +#define MT8173_OVL0_MOUT_EN_COLOR0 BIT(0) +#define MT8173_OVL1_MOUT_EN_COLOR1 BIT(0) +#define MT8173_UFOE_MOUT_EN_DSI0 BIT(0) +#define MT8173_UFOE_SEL_IN_RDMA0 BIT(0) +#define MT8173_RDMA0_SOUT_COLOR0 BIT(0) + +static const struct mtk_mmsys_routes mt8173_mmsys_routing_table[] = { + { + DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0, + MT8173_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, + MT8173_OVL0_MOUT_EN_COLOR0, MT8173_OVL0_MOUT_EN_COLOR0 + }, { + DDP_COMPONENT_OD0, DDP_COMPONENT_RDMA0, + MT8173_DISP_REG_CONFIG_DISP_OD_MOUT_EN, + MT8173_OD0_MOUT_EN_RDMA0, MT8173_OD0_MOUT_EN_RDMA0 + }, { + DDP_COMPONENT_UFOE, DDP_COMPONENT_DSI0, + MT8173_DISP_REG_CONFIG_DISP_UFOE_MOUT_EN, + MT8173_UFOE_MOUT_EN_DSI0, MT8173_UFOE_MOUT_EN_DSI0 + }, { + DDP_COMPONENT_COLOR0, DDP_COMPONENT_AAL0, + MT8173_DISP_REG_CONFIG_DISP_COLOR0_SOUT_SEL_IN, + MT8173_COLOR0_SOUT_MERGE, 0 /* SOUT to AAL */ + }, { + DDP_COMPONENT_RDMA0, DDP_COMPONENT_UFOE, + MT8173_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN, + MT8173_RDMA0_SOUT_COLOR0, 0 /* SOUT to UFOE */ + }, { + DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0, + MT8173_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, + MT8173_COLOR0_SEL_IN_OVL0, MT8173_COLOR0_SEL_IN_OVL0 + }, { + DDP_COMPONENT_AAL0, DDP_COMPONENT_COLOR0, + MT8173_DISP_REG_CONFIG_DISP_AAL_SEL_IN, + MT8173_AAL_SEL_IN_MERGE, 0 /* SEL_IN from COLOR0 */ + }, { + DDP_COMPONENT_RDMA0, DDP_COMPONENT_UFOE, + MT8173_DISP_REG_CONFIG_DISP_UFOE_SEL_IN, + MT8173_UFOE_SEL_IN_RDMA0, 0 /* SEL_IN from RDMA0 */ + }, { + DDP_COMPONENT_UFOE, DDP_COMPONENT_DSI0, + MT8173_DISP_REG_CONFIG_DSI0_SEL_IN, + MT8173_DSI0_SEL_IN_UFOE, 0, /* SEL_IN from UFOE */ + }, { + DDP_COMPONENT_OVL1, DDP_COMPONENT_COLOR1, + MT8173_DISP_REG_CONFIG_DISP_OVL1_MOUT_EN, + MT8173_OVL1_MOUT_EN_COLOR1, MT8173_OVL1_MOUT_EN_COLOR1 + }, { + DDP_COMPONENT_GAMMA, DDP_COMPONENT_RDMA1, + MT8173_DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN, + MT8173_GAMMA_MOUT_EN_RDMA1, MT8173_GAMMA_MOUT_EN_RDMA1 + }, { + DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0, + MT8173_DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, + RDMA1_SOUT_MASK, RDMA1_SOUT_DPI0 + }, { + DDP_COMPONENT_OVL1, DDP_COMPONENT_COLOR1, + MT8173_DISP_REG_CONFIG_DISP_COLOR1_SEL_IN, + COLOR1_SEL_IN_OVL1, COLOR1_SEL_IN_OVL1 + }, { + DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0, + MT8173_DISP_REG_CONFIG_DPI_SEL_IN, + MT8173_DPI0_SEL_IN_MASK, MT8173_DPI0_SEL_IN_RDMA1 + } +}; + +#endif /* __SOC_MEDIATEK_MT8173_MMSYS_H */ diff --git a/drivers/soc/mediatek/mt8195-mmsys.h b/drivers/soc/mediatek/mt8195-mmsys.h index a6652ae63431..9be2df2832a4 100644 --- a/drivers/soc/mediatek/mt8195-mmsys.h +++ b/drivers/soc/mediatek/mt8195-mmsys.h @@ -146,6 +146,19 @@ #define MT8195_VDO1_MIXER_SOUT_SEL_IN 0xf68 #define MT8195_MIXER_SOUT_SEL_IN_FROM_DISP_MIXER 0 +/* VPPSYS1 */ +#define MT8195_VPP1_HW_DCM_1ST_DIS0 0x150 +#define MT8195_VPP1_HW_DCM_1ST_DIS1 0x160 +#define MT8195_VPP1_HW_DCM_2ND_DIS0 0x1a0 +#define MT8195_VPP1_HW_DCM_2ND_DIS1 0x1b0 +#define MT8195_SVPP2_BUF_BF_RSZ_SWITCH 0xf48 +#define MT8195_SVPP3_BUF_BF_RSZ_SWITCH 0xf74 + +/* VPPSYS1 HW DCM client*/ +#define MT8195_SVPP1_MDP_RSZ BIT(25) +#define MT8195_SVPP2_MDP_RSZ BIT(4) +#define MT8195_SVPP3_MDP_RSZ BIT(5) + static const struct mtk_mmsys_routes mmsys_mt8195_routing_table[] = { { DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0, diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c index eb4c7e57896c..9619faa796e8 100644 --- a/drivers/soc/mediatek/mtk-mmsys.c +++ b/drivers/soc/mediatek/mtk-mmsys.c @@ -15,6 +15,7 @@ #include "mtk-mmsys.h" #include "mt8167-mmsys.h" +#include "mt8173-mmsys.h" #include "mt8183-mmsys.h" #include "mt8186-mmsys.h" #include "mt8188-mmsys.h" @@ -40,6 +41,14 @@ static const struct mtk_mmsys_driver_data mt6779_mmsys_driver_data = { .clk_driver = "clk-mt6779-mm", }; +static const struct mtk_mmsys_driver_data mt6795_mmsys_driver_data = { + .clk_driver = "clk-mt6795-mm", + .routes = mt8173_mmsys_routing_table, + .num_routes = ARRAY_SIZE(mt8173_mmsys_routing_table), + .sw0_rst_offset = MT8183_MMSYS_SW0_RST_B, + .num_resets = 64, +}; + static const struct mtk_mmsys_driver_data mt6797_mmsys_driver_data = { .clk_driver = "clk-mt6797-mm", }; @@ -52,10 +61,10 @@ static const struct mtk_mmsys_driver_data mt8167_mmsys_driver_data = { static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = { .clk_driver = "clk-mt8173-mm", - .routes = mmsys_default_routing_table, - .num_routes = ARRAY_SIZE(mmsys_default_routing_table), + .routes = mt8173_mmsys_routing_table, + .num_routes = ARRAY_SIZE(mt8173_mmsys_routing_table), .sw0_rst_offset = MT8183_MMSYS_SW0_RST_B, - .num_resets = 32, + .num_resets = 64, }; static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = { @@ -121,6 +130,8 @@ static const struct mtk_mmsys_driver_data mt8365_mmsys_driver_data = { struct mtk_mmsys { void __iomem *regs; const struct mtk_mmsys_driver_data *data; + struct platform_device *clks_pdev; + struct platform_device *drm_pdev; spinlock_t lock; /* protects mmsys_sw_rst_b reg */ struct reset_controller_dev rcdev; struct cmdq_client_reg cmdq_base; @@ -129,21 +140,18 @@ struct mtk_mmsys { static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask, u32 val, struct cmdq_pkt *cmdq_pkt) { + int ret; u32 tmp; -#if IS_REACHABLE(CONFIG_MTK_CMDQ) - if (cmdq_pkt) { - if (mmsys->cmdq_base.size == 0) { - pr_err("mmsys lose gce property, failed to update mmsys bits with cmdq"); + if (mmsys->cmdq_base.size && cmdq_pkt) { + ret = cmdq_pkt_write_mask(cmdq_pkt, mmsys->cmdq_base.subsys, + mmsys->cmdq_base.offset + offset, val, + mask); + if (ret) + pr_debug("CMDQ unavailable: using CPU write\n"); + else return; - } - cmdq_pkt_write_mask(cmdq_pkt, mmsys->cmdq_base.subsys, - mmsys->cmdq_base.offset + offset, val, - mask); - return; } -#endif - tmp = readl_relaxed(mmsys->regs + offset); tmp = (tmp & ~mask) | (val & mask); writel_relaxed(tmp, mmsys->regs + offset); @@ -242,6 +250,50 @@ void mtk_mmsys_ddp_dpi_fmt_config(struct device *dev, u32 val) } EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_dpi_fmt_config); +void mtk_mmsys_vpp_rsz_merge_config(struct device *dev, u32 id, bool enable, + struct cmdq_pkt *cmdq_pkt) +{ + u32 reg; + + switch (id) { + case 2: + reg = MT8195_SVPP2_BUF_BF_RSZ_SWITCH; + break; + case 3: + reg = MT8195_SVPP3_BUF_BF_RSZ_SWITCH; + break; + default: + dev_err(dev, "Invalid id %d\n", id); + return; + } + + mtk_mmsys_update_bits(dev_get_drvdata(dev), reg, ~0, enable, cmdq_pkt); +} +EXPORT_SYMBOL_GPL(mtk_mmsys_vpp_rsz_merge_config); + +void mtk_mmsys_vpp_rsz_dcm_config(struct device *dev, bool enable, + struct cmdq_pkt *cmdq_pkt) +{ + u32 client; + + client = MT8195_SVPP1_MDP_RSZ; + mtk_mmsys_update_bits(dev_get_drvdata(dev), + MT8195_VPP1_HW_DCM_1ST_DIS0, client, + ((enable) ? client : 0), cmdq_pkt); + mtk_mmsys_update_bits(dev_get_drvdata(dev), + MT8195_VPP1_HW_DCM_2ND_DIS0, client, + ((enable) ? client : 0), cmdq_pkt); + + client = MT8195_SVPP2_MDP_RSZ | MT8195_SVPP3_MDP_RSZ; + mtk_mmsys_update_bits(dev_get_drvdata(dev), + MT8195_VPP1_HW_DCM_1ST_DIS1, client, + ((enable) ? client : 0), cmdq_pkt); + mtk_mmsys_update_bits(dev_get_drvdata(dev), + MT8195_VPP1_HW_DCM_2ND_DIS1, client, + ((enable) ? client : 0), cmdq_pkt); +} +EXPORT_SYMBOL_GPL(mtk_mmsys_vpp_rsz_dcm_config); + static int mtk_mmsys_reset_update(struct reset_controller_dev *rcdev, unsigned long id, bool assert) { @@ -330,11 +382,10 @@ static int mtk_mmsys_probe(struct platform_device *pdev) } } -#if IS_REACHABLE(CONFIG_MTK_CMDQ) + /* CMDQ is optional */ ret = cmdq_dev_get_client_reg(dev, &mmsys->cmdq_base, 0); if (ret) dev_dbg(dev, "No mediatek,gce-client-reg!\n"); -#endif platform_set_drvdata(pdev, mmsys); @@ -342,6 +393,7 @@ static int mtk_mmsys_probe(struct platform_device *pdev) PLATFORM_DEVID_AUTO, NULL, 0); if (IS_ERR(clks)) return PTR_ERR(clks); + mmsys->clks_pdev = clks; if (mmsys->data->is_vppsys) goto out_probe_done; @@ -352,78 +404,44 @@ static int mtk_mmsys_probe(struct platform_device *pdev) platform_device_unregister(clks); return PTR_ERR(drm); } + mmsys->drm_pdev = drm; out_probe_done: return 0; } +static int mtk_mmsys_remove(struct platform_device *pdev) +{ + struct mtk_mmsys *mmsys = platform_get_drvdata(pdev); + + platform_device_unregister(mmsys->drm_pdev); + platform_device_unregister(mmsys->clks_pdev); + + return 0; +} + static const struct of_device_id of_match_mtk_mmsys[] = { - { - .compatible = "mediatek,mt2701-mmsys", - .data = &mt2701_mmsys_driver_data, - }, - { - .compatible = "mediatek,mt2712-mmsys", - .data = &mt2712_mmsys_driver_data, - }, - { - .compatible = "mediatek,mt6779-mmsys", - .data = &mt6779_mmsys_driver_data, - }, - { - .compatible = "mediatek,mt6797-mmsys", - .data = &mt6797_mmsys_driver_data, - }, - { - .compatible = "mediatek,mt8167-mmsys", - .data = &mt8167_mmsys_driver_data, - }, - { - .compatible = "mediatek,mt8173-mmsys", - .data = &mt8173_mmsys_driver_data, - }, - { - .compatible = "mediatek,mt8183-mmsys", - .data = &mt8183_mmsys_driver_data, - }, - { - .compatible = "mediatek,mt8186-mmsys", - .data = &mt8186_mmsys_driver_data, - }, - { - .compatible = "mediatek,mt8188-vdosys0", - .data = &mt8188_vdosys0_driver_data, - }, - { - .compatible = "mediatek,mt8192-mmsys", - .data = &mt8192_mmsys_driver_data, - }, - { /* deprecated compatible */ - .compatible = "mediatek,mt8195-mmsys", - .data = &mt8195_vdosys0_driver_data, - }, - { - .compatible = "mediatek,mt8195-vdosys0", - .data = &mt8195_vdosys0_driver_data, - }, - { - .compatible = "mediatek,mt8195-vdosys1", - .data = &mt8195_vdosys1_driver_data, - }, - { - .compatible = "mediatek,mt8195-vppsys0", - .data = &mt8195_vppsys0_driver_data, - }, - { - .compatible = "mediatek,mt8195-vppsys1", - .data = &mt8195_vppsys1_driver_data, - }, - { - .compatible = "mediatek,mt8365-mmsys", - .data = &mt8365_mmsys_driver_data, - }, - { } + { .compatible = "mediatek,mt2701-mmsys", .data = &mt2701_mmsys_driver_data }, + { .compatible = "mediatek,mt2712-mmsys", .data = &mt2712_mmsys_driver_data }, + { .compatible = "mediatek,mt6779-mmsys", .data = &mt6779_mmsys_driver_data }, + { .compatible = "mediatek,mt6795-mmsys", .data = &mt6795_mmsys_driver_data }, + { .compatible = "mediatek,mt6797-mmsys", .data = &mt6797_mmsys_driver_data }, + { .compatible = "mediatek,mt8167-mmsys", .data = &mt8167_mmsys_driver_data }, + { .compatible = "mediatek,mt8173-mmsys", .data = &mt8173_mmsys_driver_data }, + { .compatible = "mediatek,mt8183-mmsys", .data = &mt8183_mmsys_driver_data }, + { .compatible = "mediatek,mt8186-mmsys", .data = &mt8186_mmsys_driver_data }, + { .compatible = "mediatek,mt8188-vdosys0", .data = &mt8188_vdosys0_driver_data }, + { .compatible = "mediatek,mt8192-mmsys", .data = &mt8192_mmsys_driver_data }, + /* "mediatek,mt8195-mmsys" compatible is deprecated */ + { .compatible = "mediatek,mt8195-mmsys", .data = &mt8195_vdosys0_driver_data }, + { .compatible = "mediatek,mt8195-vdosys0", .data = &mt8195_vdosys0_driver_data }, + { .compatible = "mediatek,mt8195-vdosys1", .data = &mt8195_vdosys1_driver_data }, + { .compatible = "mediatek,mt8195-vppsys0", .data = &mt8195_vppsys0_driver_data }, + { .compatible = "mediatek,mt8195-vppsys1", .data = &mt8195_vppsys1_driver_data }, + { .compatible = "mediatek,mt8365-mmsys", .data = &mt8365_mmsys_driver_data }, + { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, of_match_mtk_mmsys); static struct platform_driver mtk_mmsys_drv = { .driver = { @@ -431,20 +449,9 @@ static struct platform_driver mtk_mmsys_drv = { .of_match_table = of_match_mtk_mmsys, }, .probe = mtk_mmsys_probe, + .remove = mtk_mmsys_remove, }; - -static int __init mtk_mmsys_init(void) -{ - return platform_driver_register(&mtk_mmsys_drv); -} - -static void __exit mtk_mmsys_exit(void) -{ - platform_driver_unregister(&mtk_mmsys_drv); -} - -module_init(mtk_mmsys_init); -module_exit(mtk_mmsys_exit); +module_platform_driver(mtk_mmsys_drv); MODULE_AUTHOR("Yongqiang Niu <yongqiang.niu@mediatek.com>"); MODULE_DESCRIPTION("MediaTek SoC MMSYS driver"); diff --git a/drivers/soc/mediatek/mtk-mmsys.h b/drivers/soc/mediatek/mtk-mmsys.h index 56f8cc3a97b7..6725403d2e3a 100644 --- a/drivers/soc/mediatek/mtk-mmsys.h +++ b/drivers/soc/mediatek/mtk-mmsys.h @@ -96,7 +96,7 @@ struct mtk_mmsys_driver_data { }; /* - * Routes in mt8173, mt2701, mt2712 are different. That means + * Routes in mt2701 and mt2712 are different. That means * in the same register address, it controls different input/output * selection for each SoC. But, right now, they use the same table as * default routes meet their requirements. But we don't have the complete diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c index c5b1b42303ac..26f3d9a41496 100644 --- a/drivers/soc/mediatek/mtk-mutex.c +++ b/drivers/soc/mediatek/mtk-mutex.c @@ -14,6 +14,8 @@ #include <linux/soc/mediatek/mtk-mutex.h> #include <linux/soc/mediatek/mtk-cmdq.h> +#define MTK_MUTEX_MAX_HANDLES 10 + #define MT2701_MUTEX0_MOD0 0x2c #define MT2701_MUTEX0_SOF0 0x30 #define MT8183_MUTEX0_MOD0 0x30 @@ -23,6 +25,7 @@ #define DISP_REG_MUTEX(n) (0x24 + 0x20 * (n)) #define DISP_REG_MUTEX_RST(n) (0x28 + 0x20 * (n)) #define DISP_REG_MUTEX_MOD(mutex_mod_reg, n) (mutex_mod_reg + 0x20 * (n)) +#define DISP_REG_MUTEX_MOD1(mutex_mod_reg, n) ((mutex_mod_reg) + 0x20 * (n) + 0x4) #define DISP_REG_MUTEX_SOF(mutex_sof_reg, n) (mutex_sof_reg + 0x20 * (n)) #define DISP_REG_MUTEX_MOD2(n) (0x34 + 0x20 * (n)) @@ -163,6 +166,53 @@ #define MT8195_MUTEX_MOD_DISP1_DPI1 26 #define MT8195_MUTEX_MOD_DISP1_DP_INTF0 27 +/* VPPSYS0 */ +#define MT8195_MUTEX_MOD_MDP_RDMA0 0 +#define MT8195_MUTEX_MOD_MDP_FG0 1 +#define MT8195_MUTEX_MOD_MDP_STITCH0 2 +#define MT8195_MUTEX_MOD_MDP_HDR0 3 +#define MT8195_MUTEX_MOD_MDP_AAL0 4 +#define MT8195_MUTEX_MOD_MDP_RSZ0 5 +#define MT8195_MUTEX_MOD_MDP_TDSHP0 6 +#define MT8195_MUTEX_MOD_MDP_COLOR0 7 +#define MT8195_MUTEX_MOD_MDP_OVL0 8 +#define MT8195_MUTEX_MOD_MDP_PAD0 9 +#define MT8195_MUTEX_MOD_MDP_TCC0 10 +#define MT8195_MUTEX_MOD_MDP_WROT0 11 + +/* VPPSYS1 */ +#define MT8195_MUTEX_MOD_MDP_TCC1 3 +#define MT8195_MUTEX_MOD_MDP_RDMA1 4 +#define MT8195_MUTEX_MOD_MDP_RDMA2 5 +#define MT8195_MUTEX_MOD_MDP_RDMA3 6 +#define MT8195_MUTEX_MOD_MDP_FG1 7 +#define MT8195_MUTEX_MOD_MDP_FG2 8 +#define MT8195_MUTEX_MOD_MDP_FG3 9 +#define MT8195_MUTEX_MOD_MDP_HDR1 10 +#define MT8195_MUTEX_MOD_MDP_HDR2 11 +#define MT8195_MUTEX_MOD_MDP_HDR3 12 +#define MT8195_MUTEX_MOD_MDP_AAL1 13 +#define MT8195_MUTEX_MOD_MDP_AAL2 14 +#define MT8195_MUTEX_MOD_MDP_AAL3 15 +#define MT8195_MUTEX_MOD_MDP_RSZ1 16 +#define MT8195_MUTEX_MOD_MDP_RSZ2 17 +#define MT8195_MUTEX_MOD_MDP_RSZ3 18 +#define MT8195_MUTEX_MOD_MDP_TDSHP1 19 +#define MT8195_MUTEX_MOD_MDP_TDSHP2 20 +#define MT8195_MUTEX_MOD_MDP_TDSHP3 21 +#define MT8195_MUTEX_MOD_MDP_MERGE2 22 +#define MT8195_MUTEX_MOD_MDP_MERGE3 23 +#define MT8195_MUTEX_MOD_MDP_COLOR1 24 +#define MT8195_MUTEX_MOD_MDP_COLOR2 25 +#define MT8195_MUTEX_MOD_MDP_COLOR3 26 +#define MT8195_MUTEX_MOD_MDP_OVL1 27 +#define MT8195_MUTEX_MOD_MDP_PAD1 28 +#define MT8195_MUTEX_MOD_MDP_PAD2 29 +#define MT8195_MUTEX_MOD_MDP_PAD3 30 +#define MT8195_MUTEX_MOD_MDP_WROT1 31 +#define MT8195_MUTEX_MOD_MDP_WROT2 32 +#define MT8195_MUTEX_MOD_MDP_WROT3 33 + #define MT8365_MUTEX_MOD_DISP_OVL0 7 #define MT8365_MUTEX_MOD_DISP_OVL0_2L 8 #define MT8365_MUTEX_MOD_DISP_RDMA0 9 @@ -234,7 +284,7 @@ #define MT8195_MUTEX_EOF_DPI1 (MT8195_MUTEX_SOF_DPI1 << 7) struct mtk_mutex { - int id; + u8 id; bool claimed; }; @@ -264,7 +314,7 @@ struct mtk_mutex_ctx { struct device *dev; struct clk *clk; void __iomem *regs; - struct mtk_mutex mutex[10]; + struct mtk_mutex mutex[MTK_MUTEX_MAX_HANDLES]; const struct mtk_mutex_data *data; phys_addr_t addr; struct cmdq_client_reg cmdq_reg; @@ -443,6 +493,52 @@ static const unsigned int mt8195_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_DP_INTF1] = MT8195_MUTEX_MOD_DISP1_DP_INTF0, }; +static const unsigned int mt8195_mutex_table_mod[MUTEX_MOD_IDX_MAX] = { + [MUTEX_MOD_IDX_MDP_RDMA0] = MT8195_MUTEX_MOD_MDP_RDMA0, + [MUTEX_MOD_IDX_MDP_RDMA1] = MT8195_MUTEX_MOD_MDP_RDMA1, + [MUTEX_MOD_IDX_MDP_RDMA2] = MT8195_MUTEX_MOD_MDP_RDMA2, + [MUTEX_MOD_IDX_MDP_RDMA3] = MT8195_MUTEX_MOD_MDP_RDMA3, + [MUTEX_MOD_IDX_MDP_STITCH0] = MT8195_MUTEX_MOD_MDP_STITCH0, + [MUTEX_MOD_IDX_MDP_FG0] = MT8195_MUTEX_MOD_MDP_FG0, + [MUTEX_MOD_IDX_MDP_FG1] = MT8195_MUTEX_MOD_MDP_FG1, + [MUTEX_MOD_IDX_MDP_FG2] = MT8195_MUTEX_MOD_MDP_FG2, + [MUTEX_MOD_IDX_MDP_FG3] = MT8195_MUTEX_MOD_MDP_FG3, + [MUTEX_MOD_IDX_MDP_HDR0] = MT8195_MUTEX_MOD_MDP_HDR0, + [MUTEX_MOD_IDX_MDP_HDR1] = MT8195_MUTEX_MOD_MDP_HDR1, + [MUTEX_MOD_IDX_MDP_HDR2] = MT8195_MUTEX_MOD_MDP_HDR2, + [MUTEX_MOD_IDX_MDP_HDR3] = MT8195_MUTEX_MOD_MDP_HDR3, + [MUTEX_MOD_IDX_MDP_AAL0] = MT8195_MUTEX_MOD_MDP_AAL0, + [MUTEX_MOD_IDX_MDP_AAL1] = MT8195_MUTEX_MOD_MDP_AAL1, + [MUTEX_MOD_IDX_MDP_AAL2] = MT8195_MUTEX_MOD_MDP_AAL2, + [MUTEX_MOD_IDX_MDP_AAL3] = MT8195_MUTEX_MOD_MDP_AAL3, + [MUTEX_MOD_IDX_MDP_RSZ0] = MT8195_MUTEX_MOD_MDP_RSZ0, + [MUTEX_MOD_IDX_MDP_RSZ1] = MT8195_MUTEX_MOD_MDP_RSZ1, + [MUTEX_MOD_IDX_MDP_RSZ2] = MT8195_MUTEX_MOD_MDP_RSZ2, + [MUTEX_MOD_IDX_MDP_RSZ3] = MT8195_MUTEX_MOD_MDP_RSZ3, + [MUTEX_MOD_IDX_MDP_MERGE2] = MT8195_MUTEX_MOD_MDP_MERGE2, + [MUTEX_MOD_IDX_MDP_MERGE3] = MT8195_MUTEX_MOD_MDP_MERGE3, + [MUTEX_MOD_IDX_MDP_TDSHP0] = MT8195_MUTEX_MOD_MDP_TDSHP0, + [MUTEX_MOD_IDX_MDP_TDSHP1] = MT8195_MUTEX_MOD_MDP_TDSHP1, + [MUTEX_MOD_IDX_MDP_TDSHP2] = MT8195_MUTEX_MOD_MDP_TDSHP2, + [MUTEX_MOD_IDX_MDP_TDSHP3] = MT8195_MUTEX_MOD_MDP_TDSHP3, + [MUTEX_MOD_IDX_MDP_COLOR0] = MT8195_MUTEX_MOD_MDP_COLOR0, + [MUTEX_MOD_IDX_MDP_COLOR1] = MT8195_MUTEX_MOD_MDP_COLOR1, + [MUTEX_MOD_IDX_MDP_COLOR2] = MT8195_MUTEX_MOD_MDP_COLOR2, + [MUTEX_MOD_IDX_MDP_COLOR3] = MT8195_MUTEX_MOD_MDP_COLOR3, + [MUTEX_MOD_IDX_MDP_OVL0] = MT8195_MUTEX_MOD_MDP_OVL0, + [MUTEX_MOD_IDX_MDP_OVL1] = MT8195_MUTEX_MOD_MDP_OVL1, + [MUTEX_MOD_IDX_MDP_PAD0] = MT8195_MUTEX_MOD_MDP_PAD0, + [MUTEX_MOD_IDX_MDP_PAD1] = MT8195_MUTEX_MOD_MDP_PAD1, + [MUTEX_MOD_IDX_MDP_PAD2] = MT8195_MUTEX_MOD_MDP_PAD2, + [MUTEX_MOD_IDX_MDP_PAD3] = MT8195_MUTEX_MOD_MDP_PAD3, + [MUTEX_MOD_IDX_MDP_TCC0] = MT8195_MUTEX_MOD_MDP_TCC0, + [MUTEX_MOD_IDX_MDP_TCC1] = MT8195_MUTEX_MOD_MDP_TCC1, + [MUTEX_MOD_IDX_MDP_WROT0] = MT8195_MUTEX_MOD_MDP_WROT0, + [MUTEX_MOD_IDX_MDP_WROT1] = MT8195_MUTEX_MOD_MDP_WROT1, + [MUTEX_MOD_IDX_MDP_WROT2] = MT8195_MUTEX_MOD_MDP_WROT2, + [MUTEX_MOD_IDX_MDP_WROT3] = MT8195_MUTEX_MOD_MDP_WROT3, +}; + static const unsigned int mt8365_mutex_mod[DDP_COMPONENT_ID_MAX] = { [DDP_COMPONENT_AAL0] = MT8365_MUTEX_MOD_DISP_AAL, [DDP_COMPONENT_CCORR] = MT8365_MUTEX_MOD_DISP_CCORR, @@ -603,6 +699,13 @@ static const struct mtk_mutex_data mt8195_mutex_driver_data = { .mutex_sof_reg = MT8183_MUTEX0_SOF0, }; +static const struct mtk_mutex_data mt8195_vpp_mutex_driver_data = { + .mutex_sof = mt8195_mutex_sof, + .mutex_mod_reg = MT8183_MUTEX0_MOD0, + .mutex_sof_reg = MT8183_MUTEX0_SOF0, + .mutex_table_mod = mt8195_mutex_table_mod, +}; + static const struct mtk_mutex_data mt8365_mutex_driver_data = { .mutex_mod = mt8365_mutex_mod, .mutex_sof = mt8183_mutex_sof, @@ -616,7 +719,7 @@ struct mtk_mutex *mtk_mutex_get(struct device *dev) struct mtk_mutex_ctx *mtx = dev_get_drvdata(dev); int i; - for (i = 0; i < 10; i++) + for (i = 0; i < MTK_MUTEX_MAX_HANDLES; i++) if (!mtx->mutex[i].claimed) { mtx->mutex[i].claimed = true; return &mtx->mutex[i]; @@ -768,23 +871,18 @@ int mtk_mutex_enable_by_cmdq(struct mtk_mutex *mutex, void *pkt) { struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, mutex[mutex->id]); -#if IS_REACHABLE(CONFIG_MTK_CMDQ) struct cmdq_pkt *cmdq_pkt = (struct cmdq_pkt *)pkt; WARN_ON(&mtx->mutex[mutex->id] != mutex); if (!mtx->cmdq_reg.size) { dev_err(mtx->dev, "mediatek,gce-client-reg hasn't been set"); - return -EINVAL; + return -ENODEV; } cmdq_pkt_write(cmdq_pkt, mtx->cmdq_reg.subsys, mtx->addr + DISP_REG_MUTEX_EN(mutex->id), 1); return 0; -#else - dev_err(mtx->dev, "Not support for enable MUTEX by CMDQ"); - return -ENODEV; -#endif } EXPORT_SYMBOL_GPL(mtk_mutex_enable_by_cmdq); @@ -828,7 +926,7 @@ int mtk_mutex_write_mod(struct mtk_mutex *mutex, struct mtk_mutex_ctx *mtx = container_of(mutex, struct mtk_mutex_ctx, mutex[mutex->id]); unsigned int reg; - unsigned int offset; + u32 reg_offset, id_offset = 0; WARN_ON(&mtx->mutex[mutex->id] != mutex); @@ -838,16 +936,34 @@ int mtk_mutex_write_mod(struct mtk_mutex *mutex, return -EINVAL; } - offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg, - mutex->id); - reg = readl_relaxed(mtx->regs + offset); + /* + * Some SoCs may have multiple MUTEX_MOD registers as more than 32 mods + * are present, hence requiring multiple 32-bits registers. + * + * The mutex_table_mod fully represents that by defining the number of + * the mod sequentially, later used as a bit number, which can be more + * than 0..31. + * + * In order to retain compatibility with older SoCs, we perform R/W on + * the single 32 bits registers, but this requires us to translate the + * mutex ID bit accordingly. + */ + if (mtx->data->mutex_table_mod[idx] < 32) { + reg_offset = DISP_REG_MUTEX_MOD(mtx->data->mutex_mod_reg, + mutex->id); + } else { + reg_offset = DISP_REG_MUTEX_MOD1(mtx->data->mutex_mod_reg, + mutex->id); + id_offset = 32; + } + reg = readl_relaxed(mtx->regs + reg_offset); if (clear) - reg &= ~BIT(mtx->data->mutex_table_mod[idx]); + reg &= ~BIT(mtx->data->mutex_table_mod[idx] - id_offset); else - reg |= BIT(mtx->data->mutex_table_mod[idx]); + reg |= BIT(mtx->data->mutex_table_mod[idx] - id_offset); - writel_relaxed(reg, mtx->regs + offset); + writel_relaxed(reg, mtx->regs + reg_offset); return 0; } @@ -879,27 +995,21 @@ static int mtk_mutex_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct mtk_mutex_ctx *mtx; struct resource *regs; - int i; -#if IS_REACHABLE(CONFIG_MTK_CMDQ) - int ret; -#endif + int i, ret; mtx = devm_kzalloc(dev, sizeof(*mtx), GFP_KERNEL); if (!mtx) return -ENOMEM; - for (i = 0; i < 10; i++) + for (i = 0; i < MTK_MUTEX_MAX_HANDLES; i++) mtx->mutex[i].id = i; mtx->data = of_device_get_match_data(dev); if (!mtx->data->no_clk) { mtx->clk = devm_clk_get(dev, NULL); - if (IS_ERR(mtx->clk)) { - if (PTR_ERR(mtx->clk) != -EPROBE_DEFER) - dev_err(dev, "Failed to get clock\n"); - return PTR_ERR(mtx->clk); - } + if (IS_ERR(mtx->clk)) + return dev_err_probe(dev, PTR_ERR(mtx->clk), "Failed to get clock\n"); } mtx->regs = devm_platform_get_and_ioremap_resource(pdev, 0, ®s); @@ -909,11 +1019,10 @@ static int mtk_mutex_probe(struct platform_device *pdev) } mtx->addr = regs->start; -#if IS_REACHABLE(CONFIG_MTK_CMDQ) + /* CMDQ is optional */ ret = cmdq_dev_get_client_reg(dev, &mtx->cmdq_reg, 0); if (ret) dev_dbg(dev, "No mediatek,gce-client-reg!\n"); -#endif platform_set_drvdata(pdev, mtx); @@ -921,31 +1030,20 @@ static int mtk_mutex_probe(struct platform_device *pdev) } static const struct of_device_id mutex_driver_dt_match[] = { - { .compatible = "mediatek,mt2701-disp-mutex", - .data = &mt2701_mutex_driver_data}, - { .compatible = "mediatek,mt2712-disp-mutex", - .data = &mt2712_mutex_driver_data}, - { .compatible = "mediatek,mt6795-disp-mutex", - .data = &mt6795_mutex_driver_data}, - { .compatible = "mediatek,mt8167-disp-mutex", - .data = &mt8167_mutex_driver_data}, - { .compatible = "mediatek,mt8173-disp-mutex", - .data = &mt8173_mutex_driver_data}, - { .compatible = "mediatek,mt8183-disp-mutex", - .data = &mt8183_mutex_driver_data}, - { .compatible = "mediatek,mt8186-disp-mutex", - .data = &mt8186_mutex_driver_data}, - { .compatible = "mediatek,mt8186-mdp3-mutex", - .data = &mt8186_mdp_mutex_driver_data}, - { .compatible = "mediatek,mt8188-disp-mutex", - .data = &mt8188_mutex_driver_data}, - { .compatible = "mediatek,mt8192-disp-mutex", - .data = &mt8192_mutex_driver_data}, - { .compatible = "mediatek,mt8195-disp-mutex", - .data = &mt8195_mutex_driver_data}, - { .compatible = "mediatek,mt8365-disp-mutex", - .data = &mt8365_mutex_driver_data}, - {}, + { .compatible = "mediatek,mt2701-disp-mutex", .data = &mt2701_mutex_driver_data }, + { .compatible = "mediatek,mt2712-disp-mutex", .data = &mt2712_mutex_driver_data }, + { .compatible = "mediatek,mt6795-disp-mutex", .data = &mt6795_mutex_driver_data }, + { .compatible = "mediatek,mt8167-disp-mutex", .data = &mt8167_mutex_driver_data }, + { .compatible = "mediatek,mt8173-disp-mutex", .data = &mt8173_mutex_driver_data }, + { .compatible = "mediatek,mt8183-disp-mutex", .data = &mt8183_mutex_driver_data }, + { .compatible = "mediatek,mt8186-disp-mutex", .data = &mt8186_mutex_driver_data }, + { .compatible = "mediatek,mt8186-mdp3-mutex", .data = &mt8186_mdp_mutex_driver_data }, + { .compatible = "mediatek,mt8188-disp-mutex", .data = &mt8188_mutex_driver_data }, + { .compatible = "mediatek,mt8192-disp-mutex", .data = &mt8192_mutex_driver_data }, + { .compatible = "mediatek,mt8195-disp-mutex", .data = &mt8195_mutex_driver_data }, + { .compatible = "mediatek,mt8195-vpp-mutex", .data = &mt8195_vpp_mutex_driver_data }, + { .compatible = "mediatek,mt8365-disp-mutex", .data = &mt8365_mutex_driver_data }, + { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, mutex_driver_dt_match); @@ -957,19 +1055,7 @@ static struct platform_driver mtk_mutex_driver = { .of_match_table = mutex_driver_dt_match, }, }; - -static int __init mtk_mutex_init(void) -{ - return platform_driver_register(&mtk_mutex_driver); -} - -static void __exit mtk_mutex_exit(void) -{ - platform_driver_unregister(&mtk_mutex_driver); -} - -module_init(mtk_mutex_init); -module_exit(mtk_mutex_exit); +module_platform_driver(mtk_mutex_driver); MODULE_AUTHOR("Yongqiang Niu <yongqiang.niu@mediatek.com>"); MODULE_DESCRIPTION("MediaTek SoC MUTEX driver"); diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c index f26eb2f637d5..b9c96182a46a 100644 --- a/drivers/soc/mediatek/mtk-svs.c +++ b/drivers/soc/mediatek/mtk-svs.c @@ -558,7 +558,7 @@ static int svs_adjust_pm_opp_volts(struct svs_bank *svsb) } /* Get thermal effect */ - if (svsb->phase == SVSB_PHASE_MON) { + if (!IS_ERR_OR_NULL(svsb->tzd)) { ret = thermal_zone_get_temp(svsb->tzd, &tzone_temp); if (ret || (svsb->temp > SVSB_TEMP_UPPER_BOUND && svsb->temp < SVSB_TEMP_LOWER_BOUND)) { @@ -573,7 +573,8 @@ static int svs_adjust_pm_opp_volts(struct svs_bank *svsb) temp_voffset += svsb->tzone_ltemp_voffset; /* 2-line bank update all opp volts when running mon mode */ - if (svsb->type == SVSB_HIGH || svsb->type == SVSB_LOW) { + if (svsb->phase == SVSB_PHASE_MON && (svsb->type == SVSB_HIGH || + svsb->type == SVSB_LOW)) { opp_start = 0; opp_stop = svsb->opp_count; } @@ -589,11 +590,6 @@ static int svs_adjust_pm_opp_volts(struct svs_bank *svsb) /* do nothing */ goto unlock_mutex; case SVSB_PHASE_INIT02: - svsb_volt = max(svsb->volt[i], svsb->vmin); - opp_volt = svs_bank_volt_to_opp_volt(svsb_volt, - svsb->volt_step, - svsb->volt_base); - break; case SVSB_PHASE_MON: svsb_volt = max(svsb->volt[i] + temp_voffset, svsb->vmin); opp_volt = svs_bank_volt_to_opp_volt(svsb_volt, @@ -624,6 +620,25 @@ unlock_mutex: return ret; } +static void svs_bank_disable_and_restore_default_volts(struct svs_platform *svsp, + struct svs_bank *svsb) +{ + unsigned long flags; + + if (svsb->mode_support == SVSB_MODE_ALL_DISABLE) + return; + + spin_lock_irqsave(&svs_lock, flags); + svsp->pbank = svsb; + svs_switch_bank(svsp); + svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN); + svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS); + spin_unlock_irqrestore(&svs_lock, flags); + + svsb->phase = SVSB_PHASE_ERROR; + svs_adjust_pm_opp_volts(svsb); +} + #ifdef CONFIG_DEBUG_FS static int svs_dump_debug_show(struct seq_file *m, void *p) { @@ -700,7 +715,6 @@ static ssize_t svs_enable_debug_write(struct file *filp, { struct svs_bank *svsb = file_inode(filp)->i_private; struct svs_platform *svsp = dev_get_drvdata(svsb->dev); - unsigned long flags; int enabled, ret; char *buf = NULL; @@ -716,16 +730,8 @@ static ssize_t svs_enable_debug_write(struct file *filp, return ret; if (!enabled) { - spin_lock_irqsave(&svs_lock, flags); - svsp->pbank = svsb; + svs_bank_disable_and_restore_default_volts(svsp, svsb); svsb->mode_support = SVSB_MODE_ALL_DISABLE; - svs_switch_bank(svsp); - svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN); - svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS); - spin_unlock_irqrestore(&svs_lock, flags); - - svsb->phase = SVSB_PHASE_ERROR; - svs_adjust_pm_opp_volts(svsb); } kfree(buf); @@ -1508,16 +1514,7 @@ static int svs_init02(struct svs_platform *svsp) out_of_init02: for (idx = 0; idx < svsp->bank_max; idx++) { svsb = &svsp->banks[idx]; - - spin_lock_irqsave(&svs_lock, flags); - svsp->pbank = svsb; - svs_switch_bank(svsp); - svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN); - svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS); - spin_unlock_irqrestore(&svs_lock, flags); - - svsb->phase = SVSB_PHASE_ERROR; - svs_adjust_pm_opp_volts(svsb); + svs_bank_disable_and_restore_default_volts(svsp, svsb); } return ret; @@ -1563,23 +1560,12 @@ static int svs_suspend(struct device *dev) { struct svs_platform *svsp = dev_get_drvdata(dev); struct svs_bank *svsb; - unsigned long flags; int ret; u32 idx; for (idx = 0; idx < svsp->bank_max; idx++) { svsb = &svsp->banks[idx]; - - /* This might wait for svs_isr() process */ - spin_lock_irqsave(&svs_lock, flags); - svsp->pbank = svsb; - svs_switch_bank(svsp); - svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN); - svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS); - spin_unlock_irqrestore(&svs_lock, flags); - - svsb->phase = SVSB_PHASE_ERROR; - svs_adjust_pm_opp_volts(svsb); + svs_bank_disable_and_restore_default_volts(svsp, svsb); } ret = reset_control_assert(svsp->rst); @@ -1693,7 +1679,7 @@ static int svs_bank_resource_setup(struct svs_platform *svsp) } } - if (svsb->mode_support & SVSB_MODE_MON) { + if (!IS_ERR_OR_NULL(svsb->tzone_name)) { svsb->tzd = thermal_zone_get_zone_by_name(svsb->tzone_name); if (IS_ERR(svsb->tzd)) { dev_err(svsb->dev, "cannot get \"%s\" thermal zone\n", @@ -1729,26 +1715,28 @@ static int svs_bank_resource_setup(struct svs_platform *svsp) return 0; } -static int svs_thermal_efuse_get_data(struct svs_platform *svsp) +static int svs_get_efuse_data(struct svs_platform *svsp, + const char *nvmem_cell_name, + u32 **svsp_efuse, size_t *svsp_efuse_max) { struct nvmem_cell *cell; - /* Thermal efuse parsing */ - cell = nvmem_cell_get(svsp->dev, "t-calibration-data"); - if (IS_ERR_OR_NULL(cell)) { - dev_err(svsp->dev, "no \"t-calibration-data\"? %ld\n", PTR_ERR(cell)); + cell = nvmem_cell_get(svsp->dev, nvmem_cell_name); + if (IS_ERR(cell)) { + dev_err(svsp->dev, "no \"%s\"? %ld\n", + nvmem_cell_name, PTR_ERR(cell)); return PTR_ERR(cell); } - svsp->tefuse = nvmem_cell_read(cell, &svsp->tefuse_max); - if (IS_ERR(svsp->tefuse)) { - dev_err(svsp->dev, "cannot read thermal efuse: %ld\n", - PTR_ERR(svsp->tefuse)); + *svsp_efuse = nvmem_cell_read(cell, svsp_efuse_max); + if (IS_ERR(*svsp_efuse)) { + dev_err(svsp->dev, "cannot read \"%s\" efuse: %ld\n", + nvmem_cell_name, PTR_ERR(*svsp_efuse)); nvmem_cell_put(cell); - return PTR_ERR(svsp->tefuse); + return PTR_ERR(*svsp_efuse); } - svsp->tefuse_max /= sizeof(u32); + *svsp_efuse_max /= sizeof(u32); nvmem_cell_put(cell); return 0; @@ -1796,7 +1784,8 @@ static bool svs_mt8192_efuse_parsing(struct svs_platform *svsp) svsb->vmax += svsb->dvt_fixed; } - ret = svs_thermal_efuse_get_data(svsp); + ret = svs_get_efuse_data(svsp, "t-calibration-data", + &svsp->tefuse, &svsp->tefuse_max); if (ret) return false; @@ -1901,7 +1890,8 @@ static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp) } } - ret = svs_thermal_efuse_get_data(svsp); + ret = svs_get_efuse_data(svsp, "t-calibration-data", + &svsp->tefuse, &svsp->tefuse_max); if (ret) return false; @@ -2003,32 +1993,6 @@ remove_mt8183_svsb_mon_mode: return true; } -static bool svs_is_efuse_data_correct(struct svs_platform *svsp) -{ - struct nvmem_cell *cell; - - /* Get svs efuse by nvmem */ - cell = nvmem_cell_get(svsp->dev, "svs-calibration-data"); - if (IS_ERR(cell)) { - dev_err(svsp->dev, "no \"svs-calibration-data\"? %ld\n", - PTR_ERR(cell)); - return false; - } - - svsp->efuse = nvmem_cell_read(cell, &svsp->efuse_max); - if (IS_ERR(svsp->efuse)) { - dev_err(svsp->dev, "cannot read svs efuse: %ld\n", - PTR_ERR(svsp->efuse)); - nvmem_cell_put(cell); - return false; - } - - svsp->efuse_max /= sizeof(u32); - nvmem_cell_put(cell); - - return true; -} - static struct device *svs_get_subsys_device(struct svs_platform *svsp, const char *node_name) { @@ -2059,11 +2023,6 @@ static struct device *svs_add_device_link(struct svs_platform *svsp, struct device *dev; struct device_link *sup_link; - if (!node_name) { - dev_err(svsp->dev, "node name cannot be null\n"); - return ERR_PTR(-EINVAL); - } - dev = svs_get_subsys_device(svsp, node_name); if (IS_ERR(dev)) return dev; @@ -2159,6 +2118,7 @@ static struct svs_bank svs_mt8192_banks[] = { .type = SVSB_LOW, .set_freq_pct = svs_set_bank_freq_pct_v3, .get_volts = svs_get_bank_volts_v3, + .tzone_name = "gpu1", .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT, .mode_support = SVSB_MODE_INIT02, .opp_count = MAX_OPP_ENTRIES, @@ -2176,6 +2136,10 @@ static struct svs_bank svs_mt8192_banks[] = { .core_sel = 0x0fff0100, .int_st = BIT(0), .ctl0 = 0x00540003, + .tzone_htemp = 85000, + .tzone_htemp_voffset = 0, + .tzone_ltemp = 25000, + .tzone_ltemp_voffset = 7, }, { .sw_id = SVSB_GPU, @@ -2364,8 +2328,9 @@ static int svs_probe(struct platform_device *pdev) if (ret) return ret; - if (!svs_is_efuse_data_correct(svsp)) { - dev_notice(svsp->dev, "efuse data isn't correct\n"); + ret = svs_get_efuse_data(svsp, "svs-calibration-data", + &svsp->efuse, &svsp->efuse_max); + if (ret) { ret = -EPERM; goto svs_probe_free_efuse; } @@ -2373,19 +2338,19 @@ static int svs_probe(struct platform_device *pdev) if (!svsp_data->efuse_parsing(svsp)) { dev_err(svsp->dev, "efuse data parsing failed\n"); ret = -EPERM; - goto svs_probe_free_resource; + goto svs_probe_free_tefuse; } ret = svs_bank_resource_setup(svsp); if (ret) { dev_err(svsp->dev, "svs bank resource setup fail: %d\n", ret); - goto svs_probe_free_resource; + goto svs_probe_free_tefuse; } svsp_irq = platform_get_irq(pdev, 0); if (svsp_irq < 0) { ret = svsp_irq; - goto svs_probe_free_resource; + goto svs_probe_free_tefuse; } svsp->main_clk = devm_clk_get(svsp->dev, "main"); @@ -2393,13 +2358,13 @@ static int svs_probe(struct platform_device *pdev) dev_err(svsp->dev, "failed to get clock: %ld\n", PTR_ERR(svsp->main_clk)); ret = PTR_ERR(svsp->main_clk); - goto svs_probe_free_resource; + goto svs_probe_free_tefuse; } ret = clk_prepare_enable(svsp->main_clk); if (ret) { dev_err(svsp->dev, "cannot enable main clk: %d\n", ret); - goto svs_probe_free_resource; + goto svs_probe_free_tefuse; } svsp->base = of_iomap(svsp->dev->of_node, 0); @@ -2439,7 +2404,7 @@ svs_probe_iounmap: svs_probe_clk_disable: clk_disable_unprepare(svsp->main_clk); -svs_probe_free_resource: +svs_probe_free_tefuse: if (!IS_ERR_OR_NULL(svsp->tefuse)) kfree(svsp->tefuse); diff --git a/drivers/soc/microchip/mpfs-sys-controller.c b/drivers/soc/microchip/mpfs-sys-controller.c index 6e20207b5756..216d9f4ea0ce 100644 --- a/drivers/soc/microchip/mpfs-sys-controller.c +++ b/drivers/soc/microchip/mpfs-sys-controller.c @@ -11,12 +11,19 @@ #include <linux/slab.h> #include <linux/kref.h> #include <linux/module.h> +#include <linux/jiffies.h> #include <linux/interrupt.h> #include <linux/of_platform.h> #include <linux/mailbox_client.h> #include <linux/platform_device.h> #include <soc/microchip/mpfs.h> +/* + * This timeout must be long, as some services (example: image authentication) + * take significant time to complete + */ +#define MPFS_SYS_CTRL_TIMEOUT_MS 30000 + static DEFINE_MUTEX(transaction_lock); struct mpfs_sys_controller { @@ -28,35 +35,47 @@ struct mpfs_sys_controller { int mpfs_blocking_transaction(struct mpfs_sys_controller *sys_controller, struct mpfs_mss_msg *msg) { - int ret, err; + unsigned long timeout = msecs_to_jiffies(MPFS_SYS_CTRL_TIMEOUT_MS); + int ret; - err = mutex_lock_interruptible(&transaction_lock); - if (err) - return err; + ret = mutex_lock_interruptible(&transaction_lock); + if (ret) + return ret; reinit_completion(&sys_controller->c); ret = mbox_send_message(sys_controller->chan, msg); - if (ret >= 0) { - if (wait_for_completion_timeout(&sys_controller->c, HZ)) { - ret = 0; - } else { - ret = -ETIMEDOUT; - dev_warn(sys_controller->client.dev, - "MPFS sys controller transaction timeout\n"); - } + if (ret < 0) { + dev_warn(sys_controller->client.dev, "MPFS sys controller service timeout\n"); + goto out; + } + + /* + * Unfortunately, the system controller will only deliver an interrupt + * if a service succeeds. mbox_send_message() will block until the busy + * flag is gone. If the busy flag is gone but no interrupt has arrived + * to trigger the rx callback then the service can be deemed to have + * failed. + * The caller can then interrogate msg::response::resp_status to + * determine the cause of the failure. + * mbox_send_message() returns positive integers in the success path, so + * ret needs to be cleared if we do get an interrupt. + */ + if (!wait_for_completion_timeout(&sys_controller->c, timeout)) { + ret = -EBADMSG; + dev_warn(sys_controller->client.dev, "MPFS sys controller service failed\n"); } else { - dev_err(sys_controller->client.dev, - "mpfs sys controller transaction returned %d\n", ret); + ret = 0; } +out: mutex_unlock(&transaction_lock); return ret; } EXPORT_SYMBOL(mpfs_blocking_transaction); -static void rx_callback(struct mbox_client *client, void *msg) +static void mpfs_sys_controller_rx_callback(struct mbox_client *client, void *msg) { struct mpfs_sys_controller *sys_controller = container_of(client, struct mpfs_sys_controller, client); @@ -66,8 +85,8 @@ static void rx_callback(struct mbox_client *client, void *msg) static void mpfs_sys_controller_delete(struct kref *kref) { - struct mpfs_sys_controller *sys_controller = container_of(kref, struct mpfs_sys_controller, - consumers); + struct mpfs_sys_controller *sys_controller = + container_of(kref, struct mpfs_sys_controller, consumers); mbox_free_channel(sys_controller->chan); kfree(sys_controller); @@ -102,8 +121,9 @@ static int mpfs_sys_controller_probe(struct platform_device *pdev) return -ENOMEM; sys_controller->client.dev = dev; - sys_controller->client.rx_callback = rx_callback; + sys_controller->client.rx_callback = mpfs_sys_controller_rx_callback; sys_controller->client.tx_block = 1U; + sys_controller->client.tx_tout = msecs_to_jiffies(MPFS_SYS_CTRL_TIMEOUT_MS); sys_controller->chan = mbox_request_channel(&sys_controller->client, 0); if (IS_ERR(sys_controller->chan)) { diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index a8f283086a21..a491718f8064 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -72,7 +72,7 @@ config QCOM_LLCC config QCOM_KRYO_L2_ACCESSORS bool - depends on ARCH_QCOM && ARM64 || COMPILE_TEST + depends on (ARCH_QCOM || COMPILE_TEST) && ARM64 config QCOM_MDT_LOADER tristate @@ -275,4 +275,8 @@ config QCOM_ICC_BWMON the fixed bandwidth votes from cpufreq (CPU nodes) thus achieve high memory throughput even with lower CPU frequencies. +config QCOM_INLINE_CRYPTO_ENGINE + tristate + select QCOM_SCM + endmenu diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 6e88da899f60..0f43a88b4894 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -32,3 +32,4 @@ obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) += kryo-l2-accessors.o obj-$(CONFIG_QCOM_ICC_BWMON) += icc-bwmon.o +obj-$(CONFIG_QCOM_INLINE_CRYPTO_ENGINE) += ice.o diff --git a/drivers/soc/qcom/icc-bwmon.c b/drivers/soc/qcom/icc-bwmon.c index d07be3700db6..fd58c5b69897 100644 --- a/drivers/soc/qcom/icc-bwmon.c +++ b/drivers/soc/qcom/icc-bwmon.c @@ -34,14 +34,27 @@ /* Internal sampling clock frequency */ #define HW_TIMER_HZ 19200000 -#define BWMON_V4_GLOBAL_IRQ_CLEAR 0x008 -#define BWMON_V4_GLOBAL_IRQ_ENABLE 0x00c +#define BWMON_V4_GLOBAL_IRQ_CLEAR 0x108 +#define BWMON_V4_GLOBAL_IRQ_ENABLE 0x10c /* * All values here and further are matching regmap fields, so without absolute * register offsets. */ #define BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE BIT(0) +/* + * Starting with SDM845, the BWMON4 register space has changed a bit: + * the global registers were jammed into the beginning of the monitor region. + * To keep the proper offsets, one would have to map <GLOBAL_BASE 0x200> and + * <GLOBAL_BASE+0x100 0x300>, which is straight up wrong. + * To facilitate for that, while allowing the older, arguably more proper + * implementations to work, offset the global registers by -0x100 to avoid + * having to map half of the global registers twice. + */ +#define BWMON_V4_845_OFFSET 0x100 +#define BWMON_V4_GLOBAL_IRQ_CLEAR_845 (BWMON_V4_GLOBAL_IRQ_CLEAR - BWMON_V4_845_OFFSET) +#define BWMON_V4_GLOBAL_IRQ_ENABLE_845 (BWMON_V4_GLOBAL_IRQ_ENABLE - BWMON_V4_845_OFFSET) + #define BWMON_V4_IRQ_STATUS 0x100 #define BWMON_V4_IRQ_CLEAR 0x108 @@ -118,9 +131,13 @@ #define BWMON_NEEDS_FORCE_CLEAR BIT(1) enum bwmon_fields { + /* Global region fields, keep them at the top */ F_GLOBAL_IRQ_CLEAR, F_GLOBAL_IRQ_ENABLE, - F_IRQ_STATUS, + F_NUM_GLOBAL_FIELDS, + + /* Monitor region fields */ + F_IRQ_STATUS = F_NUM_GLOBAL_FIELDS, F_IRQ_CLEAR, F_IRQ_ENABLE, F_ENABLE, @@ -157,6 +174,9 @@ struct icc_bwmon_data { const struct regmap_config *regmap_cfg; const struct reg_field *regmap_fields; + + const struct regmap_config *global_regmap_cfg; + const struct reg_field *global_regmap_fields; }; struct icc_bwmon { @@ -164,8 +184,8 @@ struct icc_bwmon { const struct icc_bwmon_data *data; int irq; - struct regmap *regmap; struct regmap_field *regs[F_NUM_FIELDS]; + struct regmap_field *global_regs[F_NUM_GLOBAL_FIELDS]; unsigned int max_bw_kbps; unsigned int min_bw_kbps; @@ -175,8 +195,8 @@ struct icc_bwmon { /* BWMON v4 */ static const struct reg_field msm8998_bwmon_reg_fields[] = { - [F_GLOBAL_IRQ_CLEAR] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_CLEAR, 0, 0), - [F_GLOBAL_IRQ_ENABLE] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_ENABLE, 0, 0), + [F_GLOBAL_IRQ_CLEAR] = {}, + [F_GLOBAL_IRQ_ENABLE] = {}, [F_IRQ_STATUS] = REG_FIELD(BWMON_V4_IRQ_STATUS, 4, 7), [F_IRQ_CLEAR] = REG_FIELD(BWMON_V4_IRQ_CLEAR, 4, 7), [F_IRQ_ENABLE] = REG_FIELD(BWMON_V4_IRQ_ENABLE, 4, 7), @@ -202,7 +222,6 @@ static const struct reg_field msm8998_bwmon_reg_fields[] = { }; static const struct regmap_range msm8998_bwmon_reg_noread_ranges[] = { - regmap_reg_range(BWMON_V4_GLOBAL_IRQ_CLEAR, BWMON_V4_GLOBAL_IRQ_CLEAR), regmap_reg_range(BWMON_V4_IRQ_CLEAR, BWMON_V4_IRQ_CLEAR), regmap_reg_range(BWMON_V4_CLEAR, BWMON_V4_CLEAR), }; @@ -222,16 +241,33 @@ static const struct regmap_access_table msm8998_bwmon_reg_volatile_table = { .n_yes_ranges = ARRAY_SIZE(msm8998_bwmon_reg_volatile_ranges), }; +static const struct reg_field msm8998_bwmon_global_reg_fields[] = { + [F_GLOBAL_IRQ_CLEAR] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_CLEAR, 0, 0), + [F_GLOBAL_IRQ_ENABLE] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_ENABLE, 0, 0), +}; + +static const struct regmap_range msm8998_bwmon_global_reg_noread_ranges[] = { + regmap_reg_range(BWMON_V4_GLOBAL_IRQ_CLEAR, BWMON_V4_GLOBAL_IRQ_CLEAR), +}; + +static const struct regmap_access_table msm8998_bwmon_global_reg_read_table = { + .no_ranges = msm8998_bwmon_global_reg_noread_ranges, + .n_no_ranges = ARRAY_SIZE(msm8998_bwmon_global_reg_noread_ranges), +}; + /* * Fill the cache for non-readable registers only as rest does not really * matter and can be read from the device. */ static const struct reg_default msm8998_bwmon_reg_defaults[] = { - { BWMON_V4_GLOBAL_IRQ_CLEAR, 0x0 }, { BWMON_V4_IRQ_CLEAR, 0x0 }, { BWMON_V4_CLEAR, 0x0 }, }; +static const struct reg_default msm8998_bwmon_global_reg_defaults[] = { + { BWMON_V4_GLOBAL_IRQ_CLEAR, 0x0 }, +}; + static const struct regmap_config msm8998_bwmon_regmap_cfg = { .reg_bits = 32, .reg_stride = 4, @@ -252,6 +288,93 @@ static const struct regmap_config msm8998_bwmon_regmap_cfg = { .cache_type = REGCACHE_RBTREE, }; +static const struct regmap_config msm8998_bwmon_global_regmap_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + /* + * No concurrent access expected - driver has one interrupt handler, + * regmap is not shared, no driver or user-space API. + */ + .disable_locking = true, + .rd_table = &msm8998_bwmon_global_reg_read_table, + .reg_defaults = msm8998_bwmon_global_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(msm8998_bwmon_global_reg_defaults), + /* + * Cache is necessary for using regmap fields with non-readable + * registers. + */ + .cache_type = REGCACHE_RBTREE, +}; + +static const struct reg_field sdm845_cpu_bwmon_reg_fields[] = { + [F_GLOBAL_IRQ_CLEAR] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_CLEAR_845, 0, 0), + [F_GLOBAL_IRQ_ENABLE] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_ENABLE_845, 0, 0), + [F_IRQ_STATUS] = REG_FIELD(BWMON_V4_IRQ_STATUS, 4, 7), + [F_IRQ_CLEAR] = REG_FIELD(BWMON_V4_IRQ_CLEAR, 4, 7), + [F_IRQ_ENABLE] = REG_FIELD(BWMON_V4_IRQ_ENABLE, 4, 7), + /* F_ENABLE covers entire register to disable other features */ + [F_ENABLE] = REG_FIELD(BWMON_V4_ENABLE, 0, 31), + [F_CLEAR] = REG_FIELD(BWMON_V4_CLEAR, 0, 1), + [F_SAMPLE_WINDOW] = REG_FIELD(BWMON_V4_SAMPLE_WINDOW, 0, 23), + [F_THRESHOLD_HIGH] = REG_FIELD(BWMON_V4_THRESHOLD_HIGH, 0, 11), + [F_THRESHOLD_MED] = REG_FIELD(BWMON_V4_THRESHOLD_MED, 0, 11), + [F_THRESHOLD_LOW] = REG_FIELD(BWMON_V4_THRESHOLD_LOW, 0, 11), + [F_ZONE_ACTIONS_ZONE0] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 0, 7), + [F_ZONE_ACTIONS_ZONE1] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 8, 15), + [F_ZONE_ACTIONS_ZONE2] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 16, 23), + [F_ZONE_ACTIONS_ZONE3] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 24, 31), + [F_THRESHOLD_COUNT_ZONE0] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 0, 7), + [F_THRESHOLD_COUNT_ZONE1] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 8, 15), + [F_THRESHOLD_COUNT_ZONE2] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 16, 23), + [F_THRESHOLD_COUNT_ZONE3] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 24, 31), + [F_ZONE0_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(0), 0, 11), + [F_ZONE1_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(1), 0, 11), + [F_ZONE2_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(2), 0, 11), + [F_ZONE3_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(3), 0, 11), +}; + +static const struct regmap_range sdm845_cpu_bwmon_reg_noread_ranges[] = { + regmap_reg_range(BWMON_V4_GLOBAL_IRQ_CLEAR_845, BWMON_V4_GLOBAL_IRQ_CLEAR_845), + regmap_reg_range(BWMON_V4_IRQ_CLEAR, BWMON_V4_IRQ_CLEAR), + regmap_reg_range(BWMON_V4_CLEAR, BWMON_V4_CLEAR), +}; + +static const struct regmap_access_table sdm845_cpu_bwmon_reg_read_table = { + .no_ranges = sdm845_cpu_bwmon_reg_noread_ranges, + .n_no_ranges = ARRAY_SIZE(sdm845_cpu_bwmon_reg_noread_ranges), +}; + +/* + * Fill the cache for non-readable registers only as rest does not really + * matter and can be read from the device. + */ +static const struct reg_default sdm845_cpu_bwmon_reg_defaults[] = { + { BWMON_V4_GLOBAL_IRQ_CLEAR_845, 0x0 }, + { BWMON_V4_IRQ_CLEAR, 0x0 }, + { BWMON_V4_CLEAR, 0x0 }, +}; + +static const struct regmap_config sdm845_cpu_bwmon_regmap_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + /* + * No concurrent access expected - driver has one interrupt handler, + * regmap is not shared, no driver or user-space API. + */ + .disable_locking = true, + .rd_table = &sdm845_cpu_bwmon_reg_read_table, + .volatile_table = &msm8998_bwmon_reg_volatile_table, + .reg_defaults = sdm845_cpu_bwmon_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(sdm845_cpu_bwmon_reg_defaults), + /* + * Cache is necessary for using regmap fields with non-readable + * registers. + */ + .cache_type = REGCACHE_RBTREE, +}; + /* BWMON v5 */ static const struct reg_field sdm845_llcc_bwmon_reg_fields[] = { [F_GLOBAL_IRQ_CLEAR] = {}, @@ -350,6 +473,13 @@ static void bwmon_clear_counters(struct icc_bwmon *bwmon, bool clear_all) static void bwmon_clear_irq(struct icc_bwmon *bwmon) { + struct regmap_field *global_irq_clr; + + if (bwmon->data->global_regmap_fields) + global_irq_clr = bwmon->global_regs[F_GLOBAL_IRQ_CLEAR]; + else + global_irq_clr = bwmon->regs[F_GLOBAL_IRQ_CLEAR]; + /* * Clear zone and global interrupts. The order and barriers are * important. Quoting downstream Qualcomm msm-4.9 tree: @@ -370,15 +500,22 @@ static void bwmon_clear_irq(struct icc_bwmon *bwmon) if (bwmon->data->quirks & BWMON_NEEDS_FORCE_CLEAR) regmap_field_force_write(bwmon->regs[F_IRQ_CLEAR], 0); if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ) - regmap_field_force_write(bwmon->regs[F_GLOBAL_IRQ_CLEAR], + regmap_field_force_write(global_irq_clr, BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE); } static void bwmon_disable(struct icc_bwmon *bwmon) { + struct regmap_field *global_irq_en; + + if (bwmon->data->global_regmap_fields) + global_irq_en = bwmon->global_regs[F_GLOBAL_IRQ_ENABLE]; + else + global_irq_en = bwmon->regs[F_GLOBAL_IRQ_ENABLE]; + /* Disable interrupts. Strict ordering, see bwmon_clear_irq(). */ if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ) - regmap_field_write(bwmon->regs[F_GLOBAL_IRQ_ENABLE], 0x0); + regmap_field_write(global_irq_en, 0x0); regmap_field_write(bwmon->regs[F_IRQ_ENABLE], 0x0); /* @@ -390,10 +527,18 @@ static void bwmon_disable(struct icc_bwmon *bwmon) static void bwmon_enable(struct icc_bwmon *bwmon, unsigned int irq_enable) { + struct regmap_field *global_irq_en; + + if (bwmon->data->global_regmap_fields) + global_irq_en = bwmon->global_regs[F_GLOBAL_IRQ_ENABLE]; + else + global_irq_en = bwmon->regs[F_GLOBAL_IRQ_ENABLE]; + /* Enable interrupts */ if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ) - regmap_field_write(bwmon->regs[F_GLOBAL_IRQ_ENABLE], + regmap_field_write(global_irq_en, BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE); + regmap_field_write(bwmon->regs[F_IRQ_ENABLE], irq_enable); /* Enable bwmon */ @@ -556,7 +701,9 @@ static int bwmon_init_regmap(struct platform_device *pdev, struct device *dev = &pdev->dev; void __iomem *base; struct regmap *map; + int ret; + /* Map the monitor base */ base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return dev_err_probe(dev, PTR_ERR(base), @@ -567,12 +714,35 @@ static int bwmon_init_regmap(struct platform_device *pdev, return dev_err_probe(dev, PTR_ERR(map), "failed to initialize regmap\n"); + BUILD_BUG_ON(ARRAY_SIZE(msm8998_bwmon_global_reg_fields) != F_NUM_GLOBAL_FIELDS); BUILD_BUG_ON(ARRAY_SIZE(msm8998_bwmon_reg_fields) != F_NUM_FIELDS); + BUILD_BUG_ON(ARRAY_SIZE(sdm845_cpu_bwmon_reg_fields) != F_NUM_FIELDS); BUILD_BUG_ON(ARRAY_SIZE(sdm845_llcc_bwmon_reg_fields) != F_NUM_FIELDS); - return devm_regmap_field_bulk_alloc(dev, map, bwmon->regs, + ret = devm_regmap_field_bulk_alloc(dev, map, bwmon->regs, bwmon->data->regmap_fields, F_NUM_FIELDS); + if (ret) + return ret; + + if (bwmon->data->global_regmap_cfg) { + /* Map the global base, if separate */ + base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(base)) + return dev_err_probe(dev, PTR_ERR(base), + "failed to map bwmon global registers\n"); + + map = devm_regmap_init_mmio(dev, base, bwmon->data->global_regmap_cfg); + if (IS_ERR(map)) + return dev_err_probe(dev, PTR_ERR(map), + "failed to initialize global regmap\n"); + + ret = devm_regmap_field_bulk_alloc(dev, map, bwmon->global_regs, + bwmon->data->global_regmap_fields, + F_NUM_GLOBAL_FIELDS); + } + + return ret; } static int bwmon_probe(struct platform_device *pdev) @@ -645,6 +815,21 @@ static const struct icc_bwmon_data msm8998_bwmon_data = { .quirks = BWMON_HAS_GLOBAL_IRQ, .regmap_fields = msm8998_bwmon_reg_fields, .regmap_cfg = &msm8998_bwmon_regmap_cfg, + .global_regmap_fields = msm8998_bwmon_global_reg_fields, + .global_regmap_cfg = &msm8998_bwmon_global_regmap_cfg, +}; + +static const struct icc_bwmon_data sdm845_cpu_bwmon_data = { + .sample_ms = 4, + .count_unit_kb = 64, + .default_highbw_kbps = 4800 * 1024, /* 4.8 GBps */ + .default_medbw_kbps = 512 * 1024, /* 512 MBps */ + .default_lowbw_kbps = 0, + .zone1_thres_count = 16, + .zone3_thres_count = 1, + .quirks = BWMON_HAS_GLOBAL_IRQ, + .regmap_fields = sdm845_cpu_bwmon_reg_fields, + .regmap_cfg = &sdm845_cpu_bwmon_regmap_cfg, }; static const struct icc_bwmon_data sdm845_llcc_bwmon_data = { @@ -673,16 +858,18 @@ static const struct icc_bwmon_data sc7280_llcc_bwmon_data = { }; static const struct of_device_id bwmon_of_match[] = { - { - .compatible = "qcom,msm8998-bwmon", - .data = &msm8998_bwmon_data - }, { - .compatible = "qcom,sdm845-llcc-bwmon", - .data = &sdm845_llcc_bwmon_data - }, { - .compatible = "qcom,sc7280-llcc-bwmon", - .data = &sc7280_llcc_bwmon_data - }, + /* BWMONv4, separate monitor and global register spaces */ + { .compatible = "qcom,msm8998-bwmon", .data = &msm8998_bwmon_data }, + /* BWMONv4, unified register space */ + { .compatible = "qcom,sdm845-bwmon", .data = &sdm845_cpu_bwmon_data }, + /* BWMONv5 */ + { .compatible = "qcom,sdm845-llcc-bwmon", .data = &sdm845_llcc_bwmon_data }, + { .compatible = "qcom,sc7280-llcc-bwmon", .data = &sc7280_llcc_bwmon_data }, + + /* Compatibles kept for legacy reasons */ + { .compatible = "qcom,sc7280-cpu-bwmon", .data = &sdm845_cpu_bwmon_data }, + { .compatible = "qcom,sc8280xp-cpu-bwmon", .data = &sdm845_cpu_bwmon_data }, + { .compatible = "qcom,sm8550-cpu-bwmon", .data = &sdm845_cpu_bwmon_data }, {} }; MODULE_DEVICE_TABLE(of, bwmon_of_match); diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c new file mode 100644 index 000000000000..a6123ea96272 --- /dev/null +++ b/drivers/soc/qcom/ice.c @@ -0,0 +1,366 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Qualcomm ICE (Inline Crypto Engine) support. + * + * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019, Google LLC + * Copyright (c) 2023, Linaro Limited + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <linux/of_platform.h> + +#include <linux/firmware/qcom/qcom_scm.h> + +#include <soc/qcom/ice.h> + +#define AES_256_XTS_KEY_SIZE 64 + +/* QCOM ICE registers */ +#define QCOM_ICE_REG_VERSION 0x0008 +#define QCOM_ICE_REG_FUSE_SETTING 0x0010 +#define QCOM_ICE_REG_BIST_STATUS 0x0070 +#define QCOM_ICE_REG_ADVANCED_CONTROL 0x1000 + +/* BIST ("built-in self-test") status flags */ +#define QCOM_ICE_BIST_STATUS_MASK GENMASK(31, 28) + +#define QCOM_ICE_FUSE_SETTING_MASK 0x1 +#define QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK 0x2 +#define QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK 0x4 + +#define qcom_ice_writel(engine, val, reg) \ + writel((val), (engine)->base + (reg)) + +#define qcom_ice_readl(engine, reg) \ + readl((engine)->base + (reg)) + +struct qcom_ice { + struct device *dev; + void __iomem *base; + struct device_link *link; + + struct clk *core_clk; +}; + +static bool qcom_ice_check_supported(struct qcom_ice *ice) +{ + u32 regval = qcom_ice_readl(ice, QCOM_ICE_REG_VERSION); + struct device *dev = ice->dev; + int major = FIELD_GET(GENMASK(31, 24), regval); + int minor = FIELD_GET(GENMASK(23, 16), regval); + int step = FIELD_GET(GENMASK(15, 0), regval); + + /* For now this driver only supports ICE version 3 and 4. */ + if (major != 3 && major != 4) { + dev_warn(dev, "Unsupported ICE version: v%d.%d.%d\n", + major, minor, step); + return false; + } + + dev_info(dev, "Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n", + major, minor, step); + + /* If fuses are blown, ICE might not work in the standard way. */ + regval = qcom_ice_readl(ice, QCOM_ICE_REG_FUSE_SETTING); + if (regval & (QCOM_ICE_FUSE_SETTING_MASK | + QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK | + QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK)) { + dev_warn(dev, "Fuses are blown; ICE is unusable!\n"); + return false; + } + + return true; +} + +static void qcom_ice_low_power_mode_enable(struct qcom_ice *ice) +{ + u32 regval; + + regval = qcom_ice_readl(ice, QCOM_ICE_REG_ADVANCED_CONTROL); + + /* Enable low power mode sequence */ + regval |= 0x7000; + qcom_ice_writel(ice, regval, QCOM_ICE_REG_ADVANCED_CONTROL); +} + +static void qcom_ice_optimization_enable(struct qcom_ice *ice) +{ + u32 regval; + + /* ICE Optimizations Enable Sequence */ + regval = qcom_ice_readl(ice, QCOM_ICE_REG_ADVANCED_CONTROL); + regval |= 0xd807100; + /* ICE HPG requires delay before writing */ + udelay(5); + qcom_ice_writel(ice, regval, QCOM_ICE_REG_ADVANCED_CONTROL); + udelay(5); +} + +/* + * Wait until the ICE BIST (built-in self-test) has completed. + * + * This may be necessary before ICE can be used. + * Note that we don't really care whether the BIST passed or failed; + * we really just want to make sure that it isn't still running. This is + * because (a) the BIST is a FIPS compliance thing that never fails in + * practice, (b) ICE is documented to reject crypto requests if the BIST + * fails, so we needn't do it in software too, and (c) properly testing + * storage encryption requires testing the full storage stack anyway, + * and not relying on hardware-level self-tests. + */ +static int qcom_ice_wait_bist_status(struct qcom_ice *ice) +{ + u32 regval; + int err; + + err = readl_poll_timeout(ice->base + QCOM_ICE_REG_BIST_STATUS, + regval, !(regval & QCOM_ICE_BIST_STATUS_MASK), + 50, 5000); + if (err) + dev_err(ice->dev, "Timed out waiting for ICE self-test to complete\n"); + + return err; +} + +int qcom_ice_enable(struct qcom_ice *ice) +{ + qcom_ice_low_power_mode_enable(ice); + qcom_ice_optimization_enable(ice); + + return qcom_ice_wait_bist_status(ice); +} +EXPORT_SYMBOL_GPL(qcom_ice_enable); + +int qcom_ice_resume(struct qcom_ice *ice) +{ + struct device *dev = ice->dev; + int err; + + err = clk_prepare_enable(ice->core_clk); + if (err) { + dev_err(dev, "failed to enable core clock (%d)\n", + err); + return err; + } + + return qcom_ice_wait_bist_status(ice); +} +EXPORT_SYMBOL_GPL(qcom_ice_resume); + +int qcom_ice_suspend(struct qcom_ice *ice) +{ + clk_disable_unprepare(ice->core_clk); + + return 0; +} +EXPORT_SYMBOL_GPL(qcom_ice_suspend); + +int qcom_ice_program_key(struct qcom_ice *ice, + u8 algorithm_id, u8 key_size, + const u8 crypto_key[], u8 data_unit_size, + int slot) +{ + struct device *dev = ice->dev; + union { + u8 bytes[AES_256_XTS_KEY_SIZE]; + u32 words[AES_256_XTS_KEY_SIZE / sizeof(u32)]; + } key; + int i; + int err; + + /* Only AES-256-XTS has been tested so far. */ + if (algorithm_id != QCOM_ICE_CRYPTO_ALG_AES_XTS || + key_size != QCOM_ICE_CRYPTO_KEY_SIZE_256) { + dev_err_ratelimited(dev, + "Unhandled crypto capability; algorithm_id=%d, key_size=%d\n", + algorithm_id, key_size); + return -EINVAL; + } + + memcpy(key.bytes, crypto_key, AES_256_XTS_KEY_SIZE); + + /* The SCM call requires that the key words are encoded in big endian */ + for (i = 0; i < ARRAY_SIZE(key.words); i++) + __cpu_to_be32s(&key.words[i]); + + err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE, + QCOM_SCM_ICE_CIPHER_AES_256_XTS, + data_unit_size); + + memzero_explicit(&key, sizeof(key)); + + return err; +} +EXPORT_SYMBOL_GPL(qcom_ice_program_key); + +int qcom_ice_evict_key(struct qcom_ice *ice, int slot) +{ + return qcom_scm_ice_invalidate_key(slot); +} +EXPORT_SYMBOL_GPL(qcom_ice_evict_key); + +static struct qcom_ice *qcom_ice_create(struct device *dev, + void __iomem *base) +{ + struct qcom_ice *engine; + + if (!qcom_scm_is_available()) + return ERR_PTR(-EPROBE_DEFER); + + if (!qcom_scm_ice_available()) { + dev_warn(dev, "ICE SCM interface not found\n"); + return NULL; + } + + engine = devm_kzalloc(dev, sizeof(*engine), GFP_KERNEL); + if (!engine) + return ERR_PTR(-ENOMEM); + + engine->dev = dev; + engine->base = base; + + /* + * Legacy DT binding uses different clk names for each consumer, + * so lets try those first. If none of those are a match, it means + * the we only have one clock and it is part of the dedicated DT node. + * Also, enable the clock before we check what HW version the driver + * supports. + */ + engine->core_clk = devm_clk_get_optional_enabled(dev, "ice_core_clk"); + if (!engine->core_clk) + engine->core_clk = devm_clk_get_optional_enabled(dev, "ice"); + if (!engine->core_clk) + engine->core_clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(engine->core_clk)) + return ERR_CAST(engine->core_clk); + + if (!qcom_ice_check_supported(engine)) + return ERR_PTR(-EOPNOTSUPP); + + dev_dbg(dev, "Registered Qualcomm Inline Crypto Engine\n"); + + return engine; +} + +/** + * of_qcom_ice_get() - get an ICE instance from a DT node + * @dev: device pointer for the consumer device + * + * This function will provide an ICE instance either by creating one for the + * consumer device if its DT node provides the 'ice' reg range and the 'ice' + * clock (for legacy DT style). On the other hand, if consumer provides a + * phandle via 'qcom,ice' property to an ICE DT, the ICE instance will already + * be created and so this function will return that instead. + * + * Return: ICE pointer on success, NULL if there is no ICE data provided by the + * consumer or ERR_PTR() on error. + */ +struct qcom_ice *of_qcom_ice_get(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct qcom_ice *ice; + struct device_node *node; + struct resource *res; + void __iomem *base; + + if (!dev || !dev->of_node) + return ERR_PTR(-ENODEV); + + /* + * In order to support legacy style devicetree bindings, we need + * to create the ICE instance using the consumer device and the reg + * range called 'ice' it provides. + */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ice"); + if (res) { + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return ERR_CAST(base); + + /* create ICE instance using consumer dev */ + return qcom_ice_create(&pdev->dev, base); + } + + /* + * If the consumer node does not provider an 'ice' reg range + * (legacy DT binding), then it must at least provide a phandle + * to the ICE devicetree node, otherwise ICE is not supported. + */ + node = of_parse_phandle(dev->of_node, "qcom,ice", 0); + if (!node) + return NULL; + + pdev = of_find_device_by_node(node); + if (!pdev) { + dev_err(dev, "Cannot find device node %s\n", node->name); + ice = ERR_PTR(-EPROBE_DEFER); + goto out; + } + + ice = platform_get_drvdata(pdev); + if (!ice) { + dev_err(dev, "Cannot get ice instance from %s\n", + dev_name(&pdev->dev)); + platform_device_put(pdev); + ice = ERR_PTR(-EPROBE_DEFER); + goto out; + } + + ice->link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER); + if (!ice->link) { + dev_err(&pdev->dev, + "Failed to create device link to consumer %s\n", + dev_name(dev)); + platform_device_put(pdev); + ice = ERR_PTR(-EINVAL); + } + +out: + of_node_put(node); + + return ice; +} +EXPORT_SYMBOL_GPL(of_qcom_ice_get); + +static int qcom_ice_probe(struct platform_device *pdev) +{ + struct qcom_ice *engine; + void __iomem *base; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) { + dev_warn(&pdev->dev, "ICE registers not found\n"); + return PTR_ERR(base); + } + + engine = qcom_ice_create(&pdev->dev, base); + if (IS_ERR(engine)) + return PTR_ERR(engine); + + platform_set_drvdata(pdev, engine); + + return 0; +} + +static const struct of_device_id qcom_ice_of_match_table[] = { + { .compatible = "qcom,inline-crypto-engine" }, + { }, +}; +MODULE_DEVICE_TABLE(of, qcom_ice_of_match_table); + +static struct platform_driver qcom_ice_driver = { + .probe = qcom_ice_probe, + .driver = { + .name = "qcom-ice", + .of_match_table = qcom_ice_of_match_table, + }, +}; + +module_platform_driver(qcom_ice_driver); + +MODULE_DESCRIPTION("Qualcomm Inline Crypto Engine driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 26efe12012a0..67c19ed2219a 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -62,8 +62,6 @@ #define LLCC_TRP_WRSC_CACHEABLE_EN 0x21f2c #define LLCC_TRP_ALGO_CFG8 0x21f30 -#define BANK_OFFSET_STRIDE 0x80000 - #define LLCC_VERSION_2_0_0_0 0x02000000 #define LLCC_VERSION_2_1_0_0 0x02010000 #define LLCC_VERSION_4_1_0_0 0x04010000 @@ -122,10 +120,11 @@ struct llcc_slice_config { struct qcom_llcc_config { const struct llcc_slice_config *sct_data; - int size; - bool need_llcc_cfg; const u32 *reg_offset; const struct llcc_edac_reg_offset *edac_reg_offset; + int size; + bool need_llcc_cfg; + bool no_edac; }; enum llcc_reg_offset { @@ -227,6 +226,14 @@ static const struct llcc_slice_config sm6350_data[] = { { LLCC_MODPE, 29, 64, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, }; +static const struct llcc_slice_config sm7150_data[] = { + { LLCC_CPUSS, 1, 512, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 1 }, + { LLCC_MDM, 8, 128, 2, 0, 0xF, 0x0, 0, 0, 0, 1, 0 }, + { LLCC_GPUHTW, 11, 256, 1, 1, 0xF, 0x0, 0, 0, 0, 1, 0 }, + { LLCC_GPU, 12, 256, 1, 1, 0xF, 0x0, 0, 0, 0, 1, 0 }, + { LLCC_NPU, 23, 512, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 0 }, +}; + static const struct llcc_slice_config sm8150_data[] = { { LLCC_CPUSS, 1, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 1 }, { LLCC_VIDSC0, 2, 512, 2, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 }, @@ -454,6 +461,7 @@ static const struct qcom_llcc_config sdm845_cfg = { .need_llcc_cfg = false, .reg_offset = llcc_v1_reg_offset, .edac_reg_offset = &llcc_v1_edac_reg_offset, + .no_edac = true, }; static const struct qcom_llcc_config sm6350_cfg = { @@ -464,6 +472,14 @@ static const struct qcom_llcc_config sm6350_cfg = { .edac_reg_offset = &llcc_v1_edac_reg_offset, }; +static const struct qcom_llcc_config sm7150_cfg = { + .sct_data = sm7150_data, + .size = ARRAY_SIZE(sm7150_data), + .need_llcc_cfg = true, + .reg_offset = llcc_v1_reg_offset, + .edac_reg_offset = &llcc_v1_edac_reg_offset, +}; + static const struct qcom_llcc_config sm8150_cfg = { .sct_data = sm8150_data, .size = ARRAY_SIZE(sm8150_data), @@ -898,8 +914,8 @@ static int qcom_llcc_remove(struct platform_device *pdev) return 0; } -static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev, - const char *name) +static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev, u8 index, + const char *name) { void __iomem *base; struct regmap_config llcc_regmap_config = { @@ -909,7 +925,7 @@ static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev, .fast_io = true, }; - base = devm_platform_ioremap_resource_byname(pdev, name); + base = devm_platform_ioremap_resource(pdev, index); if (IS_ERR(base)) return ERR_CAST(base); @@ -927,6 +943,7 @@ static int qcom_llcc_probe(struct platform_device *pdev) const struct llcc_slice_config *llcc_cfg; u32 sz; u32 version; + struct regmap *regmap; drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL); if (!drv_data) { @@ -934,21 +951,51 @@ static int qcom_llcc_probe(struct platform_device *pdev) goto err; } - drv_data->regmap = qcom_llcc_init_mmio(pdev, "llcc_base"); - if (IS_ERR(drv_data->regmap)) { - ret = PTR_ERR(drv_data->regmap); + /* Initialize the first LLCC bank regmap */ + regmap = qcom_llcc_init_mmio(pdev, 0, "llcc0_base"); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + goto err; + } + + cfg = of_device_get_match_data(&pdev->dev); + + ret = regmap_read(regmap, cfg->reg_offset[LLCC_COMMON_STATUS0], &num_banks); + if (ret) + goto err; + + num_banks &= LLCC_LB_CNT_MASK; + num_banks >>= LLCC_LB_CNT_SHIFT; + drv_data->num_banks = num_banks; + + drv_data->regmaps = devm_kcalloc(dev, num_banks, sizeof(*drv_data->regmaps), GFP_KERNEL); + if (!drv_data->regmaps) { + ret = -ENOMEM; goto err; } - drv_data->bcast_regmap = - qcom_llcc_init_mmio(pdev, "llcc_broadcast_base"); + drv_data->regmaps[0] = regmap; + + /* Initialize rest of LLCC bank regmaps */ + for (i = 1; i < num_banks; i++) { + char *base = kasprintf(GFP_KERNEL, "llcc%d_base", i); + + drv_data->regmaps[i] = qcom_llcc_init_mmio(pdev, i, base); + if (IS_ERR(drv_data->regmaps[i])) { + ret = PTR_ERR(drv_data->regmaps[i]); + kfree(base); + goto err; + } + + kfree(base); + } + + drv_data->bcast_regmap = qcom_llcc_init_mmio(pdev, i, "llcc_broadcast_base"); if (IS_ERR(drv_data->bcast_regmap)) { ret = PTR_ERR(drv_data->bcast_regmap); goto err; } - cfg = of_device_get_match_data(&pdev->dev); - /* Extract version of the IP */ ret = regmap_read(drv_data->bcast_regmap, cfg->reg_offset[LLCC_COMMON_HW_INFO], &version); @@ -957,15 +1004,6 @@ static int qcom_llcc_probe(struct platform_device *pdev) drv_data->version = version; - ret = regmap_read(drv_data->regmap, cfg->reg_offset[LLCC_COMMON_STATUS0], - &num_banks); - if (ret) - goto err; - - num_banks &= LLCC_LB_CNT_MASK; - num_banks >>= LLCC_LB_CNT_SHIFT; - drv_data->num_banks = num_banks; - llcc_cfg = cfg->sct_data; sz = cfg->size; @@ -973,16 +1011,6 @@ static int qcom_llcc_probe(struct platform_device *pdev) if (llcc_cfg[i].slice_id > drv_data->max_slices) drv_data->max_slices = llcc_cfg[i].slice_id; - drv_data->offsets = devm_kcalloc(dev, num_banks, sizeof(u32), - GFP_KERNEL); - if (!drv_data->offsets) { - ret = -ENOMEM; - goto err; - } - - for (i = 0; i < num_banks; i++) - drv_data->offsets[i] = i * BANK_OFFSET_STRIDE; - drv_data->bitmap = devm_bitmap_zalloc(dev, drv_data->max_slices, GFP_KERNEL); if (!drv_data->bitmap) { @@ -1001,7 +1029,14 @@ static int qcom_llcc_probe(struct platform_device *pdev) goto err; drv_data->ecc_irq = platform_get_irq_optional(pdev, 0); - if (drv_data->ecc_irq >= 0) { + + /* + * On some platforms, the access to EDAC registers will be locked by + * the bootloader. So probing the EDAC driver will result in a crash. + * Hence, disable the creation of EDAC platform device for the + * problematic platforms. + */ + if (!cfg->no_edac) { llcc_edac = platform_device_register_data(&pdev->dev, "qcom_llcc_edac", -1, drv_data, sizeof(*drv_data)); @@ -1022,6 +1057,7 @@ static const struct of_device_id qcom_llcc_of_match[] = { { .compatible = "qcom,sc8280xp-llcc", .data = &sc8280xp_cfg }, { .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfg }, { .compatible = "qcom,sm6350-llcc", .data = &sm6350_cfg }, + { .compatible = "qcom,sm7150-llcc", .data = &sm7150_cfg }, { .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfg }, { .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfg }, { .compatible = "qcom,sm8350-llcc", .data = &sm8350_cfg }, diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c index bb3fb57abcc6..8bf95df0a56a 100644 --- a/drivers/soc/qcom/pmic_glink.c +++ b/drivers/soc/qcom/pmic_glink.c @@ -4,6 +4,7 @@ * Copyright (c) 2022, Linaro Ltd */ #include <linux/auxiliary_bus.h> +#include <linux/of_device.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/rpmsg.h> @@ -11,12 +12,23 @@ #include <linux/soc/qcom/pdr.h> #include <linux/soc/qcom/pmic_glink.h> +enum { + PMIC_GLINK_CLIENT_BATT = 0, + PMIC_GLINK_CLIENT_ALTMODE, + PMIC_GLINK_CLIENT_UCSI, +}; + +#define PMIC_GLINK_CLIENT_DEFAULT (BIT(PMIC_GLINK_CLIENT_BATT) | \ + BIT(PMIC_GLINK_CLIENT_ALTMODE)) + struct pmic_glink { struct device *dev; struct pdr_handle *pdr; struct rpmsg_endpoint *ept; + unsigned long client_mask; + struct auxiliary_device altmode_aux; struct auxiliary_device ps_aux; struct auxiliary_device ucsi_aux; @@ -233,6 +245,7 @@ static struct rpmsg_driver pmic_glink_rpmsg_driver = { static int pmic_glink_probe(struct platform_device *pdev) { + const unsigned long *match_data; struct pdr_service *service; struct pmic_glink *pg; int ret; @@ -249,12 +262,27 @@ static int pmic_glink_probe(struct platform_device *pdev) mutex_init(&pg->client_lock); mutex_init(&pg->state_lock); - ret = pmic_glink_add_aux_device(pg, &pg->altmode_aux, "altmode"); - if (ret) - return ret; - ret = pmic_glink_add_aux_device(pg, &pg->ps_aux, "power-supply"); - if (ret) - goto out_release_altmode_aux; + match_data = (unsigned long *)of_device_get_match_data(&pdev->dev); + if (match_data) + pg->client_mask = *match_data; + else + pg->client_mask = PMIC_GLINK_CLIENT_DEFAULT; + + if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) { + ret = pmic_glink_add_aux_device(pg, &pg->ucsi_aux, "ucsi"); + if (ret) + return ret; + } + if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) { + ret = pmic_glink_add_aux_device(pg, &pg->altmode_aux, "altmode"); + if (ret) + goto out_release_ucsi_aux; + } + if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) { + ret = pmic_glink_add_aux_device(pg, &pg->ps_aux, "power-supply"); + if (ret) + goto out_release_altmode_aux; + } pg->pdr = pdr_handle_alloc(pmic_glink_pdr_callback, pg); if (IS_ERR(pg->pdr)) { @@ -278,9 +306,14 @@ static int pmic_glink_probe(struct platform_device *pdev) out_release_pdr_handle: pdr_handle_release(pg->pdr); out_release_aux_devices: - pmic_glink_del_aux_device(pg, &pg->ps_aux); + if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) + pmic_glink_del_aux_device(pg, &pg->ps_aux); out_release_altmode_aux: - pmic_glink_del_aux_device(pg, &pg->altmode_aux); + if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) + pmic_glink_del_aux_device(pg, &pg->altmode_aux); +out_release_ucsi_aux: + if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) + pmic_glink_del_aux_device(pg, &pg->ucsi_aux); return ret; } @@ -291,8 +324,12 @@ static int pmic_glink_remove(struct platform_device *pdev) pdr_handle_release(pg->pdr); - pmic_glink_del_aux_device(pg, &pg->ps_aux); - pmic_glink_del_aux_device(pg, &pg->altmode_aux); + if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) + pmic_glink_del_aux_device(pg, &pg->ps_aux); + if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) + pmic_glink_del_aux_device(pg, &pg->altmode_aux); + if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) + pmic_glink_del_aux_device(pg, &pg->ucsi_aux); mutex_lock(&__pmic_glink_lock); __pmic_glink = NULL; @@ -301,8 +338,14 @@ static int pmic_glink_remove(struct platform_device *pdev) return 0; } +/* Do not handle altmode for now on those platforms */ +static const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | + BIT(PMIC_GLINK_CLIENT_UCSI); + static const struct of_device_id pmic_glink_of_match[] = { - { .compatible = "qcom,pmic-glink", }, + { .compatible = "qcom,sm8450-pmic-glink", .data = &pmic_glink_sm8450_client_mask }, + { .compatible = "qcom,sm8550-pmic-glink", .data = &pmic_glink_sm8450_client_mask }, + { .compatible = "qcom,pmic-glink" }, {} }; MODULE_DEVICE_TABLE(of, pmic_glink_of_match); diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index 18c856056475..e376c32cc16e 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -395,7 +395,7 @@ static int qmp_cooling_devices_register(struct qmp *qmp) return -ENOMEM; for_each_available_child_of_node(np, child) { - if (!of_find_property(child, "#cooling-cells", NULL)) + if (!of_property_present(child, "#cooling-cells")) continue; ret = qmp_cooling_device_add(qmp, &qmp->cooling_devs[count++], child); diff --git a/drivers/soc/qcom/qcom_gsbi.c b/drivers/soc/qcom/qcom_gsbi.c index 290bdefbf28a..f1742e5bddb9 100644 --- a/drivers/soc/qcom/qcom_gsbi.c +++ b/drivers/soc/qcom/qcom_gsbi.c @@ -114,7 +114,7 @@ struct gsbi_info { struct regmap *tcsr; }; -static const struct of_device_id tcsr_dt_match[] = { +static const struct of_device_id tcsr_dt_match[] __maybe_unused = { { .compatible = "qcom,tcsr-ipq8064", .data = &config_ipq8064}, { .compatible = "qcom,tcsr-apq8064", .data = &config_apq8064}, { .compatible = "qcom,tcsr-msm8960", .data = &config_msm8960}, diff --git a/drivers/soc/qcom/rmtfs_mem.c b/drivers/soc/qcom/rmtfs_mem.c index 538fa182169a..0d31377f178d 100644 --- a/drivers/soc/qcom/rmtfs_mem.c +++ b/drivers/soc/qcom/rmtfs_mem.c @@ -31,7 +31,7 @@ struct qcom_rmtfs_mem { unsigned int client_id; - unsigned int perms; + u64 perms; }; static ssize_t qcom_rmtfs_mem_show(struct device *dev, diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index 0f8b2249f889..f93544f6d796 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -1073,7 +1073,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev) drv->ver.minor = rsc_id & (MINOR_VER_MASK << MINOR_VER_SHIFT); drv->ver.minor >>= MINOR_VER_SHIFT; - if (drv->ver.major == 3 && drv->ver.minor == 0) + if (drv->ver.major == 3 && drv->ver.minor >= 0) drv->regs = rpmh_rsc_reg_offset_ver_3_0; else drv->regs = rpmh_rsc_reg_offset_ver_2_7; diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c index 337b1ad1cd3b..f8397dcb146c 100644 --- a/drivers/soc/qcom/rpmpd.c +++ b/drivers/soc/qcom/rpmpd.c @@ -40,57 +40,6 @@ #define MAX_CORNER_RPMPD_STATE 6 -#define DEFINE_RPMPD_PAIR(_platform, _name, _active, r_type, r_key, \ - r_id) \ - static struct rpmpd _platform##_##_active; \ - static struct rpmpd _platform##_##_name = { \ - .pd = { .name = #_name, }, \ - .peer = &_platform##_##_active, \ - .res_type = RPMPD_##r_type, \ - .res_id = r_id, \ - .key = KEY_##r_key, \ - }; \ - static struct rpmpd _platform##_##_active = { \ - .pd = { .name = #_active, }, \ - .peer = &_platform##_##_name, \ - .active_only = true, \ - .res_type = RPMPD_##r_type, \ - .res_id = r_id, \ - .key = KEY_##r_key, \ - } - -#define DEFINE_RPMPD_CORNER(_platform, _name, r_type, r_id) \ - static struct rpmpd _platform##_##_name = { \ - .pd = { .name = #_name, }, \ - .res_type = RPMPD_##r_type, \ - .res_id = r_id, \ - .key = KEY_CORNER, \ - } - -#define DEFINE_RPMPD_LEVEL(_platform, _name, r_type, r_id) \ - static struct rpmpd _platform##_##_name = { \ - .pd = { .name = #_name, }, \ - .res_type = RPMPD_##r_type, \ - .res_id = r_id, \ - .key = KEY_LEVEL, \ - } - -#define DEFINE_RPMPD_VFC(_platform, _name, r_type, r_id) \ - static struct rpmpd _platform##_##_name = { \ - .pd = { .name = #_name, }, \ - .res_type = RPMPD_##r_type, \ - .res_id = r_id, \ - .key = KEY_FLOOR_CORNER, \ - } - -#define DEFINE_RPMPD_VFL(_platform, _name, r_type, r_id) \ - static struct rpmpd _platform##_##_name = { \ - .pd = { .name = #_name, }, \ - .res_type = RPMPD_##r_type, \ - .res_id = r_id, \ - .key = KEY_FLOOR_LEVEL, \ - } - struct rpmpd_req { __le32 key; __le32 nbytes; @@ -99,6 +48,7 @@ struct rpmpd_req { struct rpmpd { struct generic_pm_domain pd; + struct generic_pm_domain *parent; struct rpmpd *peer; const bool active_only; unsigned int corner; @@ -118,19 +68,459 @@ struct rpmpd_desc { static DEFINE_MUTEX(rpmpd_lock); -/* mdm9607 RPM Power Domains */ -DEFINE_RPMPD_PAIR(mdm9607, vddcx, vddcx_ao, SMPA, LEVEL, 3); -DEFINE_RPMPD_VFL(mdm9607, vddcx_vfl, SMPA, 3); +/* CX */ +static struct rpmpd cx_rwcx0_lvl_ao; +static struct rpmpd cx_rwcx0_lvl = { + .pd = { .name = "cx", }, + .peer = &cx_rwcx0_lvl_ao, + .res_type = RPMPD_RWCX, + .res_id = 0, + .key = KEY_LEVEL, +}; + +static struct rpmpd cx_rwcx0_lvl_ao = { + .pd = { .name = "cx_ao", }, + .peer = &cx_rwcx0_lvl, + .active_only = true, + .res_type = RPMPD_RWCX, + .res_id = 0, + .key = KEY_LEVEL, +}; + +static struct rpmpd cx_s1a_corner_ao; +static struct rpmpd cx_s1a_corner = { + .pd = { .name = "cx", }, + .peer = &cx_s1a_corner_ao, + .res_type = RPMPD_SMPA, + .res_id = 1, + .key = KEY_CORNER, +}; + +static struct rpmpd cx_s1a_corner_ao = { + .pd = { .name = "cx_ao", }, + .peer = &cx_s1a_corner, + .active_only = true, + .res_type = RPMPD_SMPA, + .res_id = 1, + .key = KEY_CORNER, +}; + +static struct rpmpd cx_s2a_corner_ao; +static struct rpmpd cx_s2a_corner = { + .pd = { .name = "cx", }, + .peer = &cx_s2a_corner_ao, + .res_type = RPMPD_SMPA, + .res_id = 2, + .key = KEY_CORNER, +}; + +static struct rpmpd cx_s2a_corner_ao = { + .pd = { .name = "cx_ao", }, + .peer = &cx_s2a_corner, + .active_only = true, + .res_type = RPMPD_SMPA, + .res_id = 2, + .key = KEY_CORNER, +}; + +static struct rpmpd cx_s2a_lvl_ao; +static struct rpmpd cx_s2a_lvl = { + .pd = { .name = "cx", }, + .peer = &cx_s2a_lvl_ao, + .res_type = RPMPD_SMPA, + .res_id = 2, + .key = KEY_LEVEL, +}; + +static struct rpmpd cx_s2a_lvl_ao = { + .pd = { .name = "cx_ao", }, + .peer = &cx_s2a_lvl, + .active_only = true, + .res_type = RPMPD_SMPA, + .res_id = 2, + .key = KEY_LEVEL, +}; + +static struct rpmpd cx_s3a_lvl_ao; +static struct rpmpd cx_s3a_lvl = { + .pd = { .name = "cx", }, + .peer = &cx_s3a_lvl_ao, + .res_type = RPMPD_SMPA, + .res_id = 3, + .key = KEY_LEVEL, +}; + +static struct rpmpd cx_s3a_lvl_ao = { + .pd = { .name = "cx_ao", }, + .peer = &cx_s3a_lvl, + .active_only = true, + .res_type = RPMPD_SMPA, + .res_id = 3, + .key = KEY_LEVEL, +}; + +static struct rpmpd cx_rwcx0_vfl = { + .pd = { .name = "cx_vfl", }, + .res_type = RPMPD_RWCX, + .res_id = 0, + .key = KEY_FLOOR_LEVEL, +}; + +static struct rpmpd cx_rwsc2_vfl = { + .pd = { .name = "cx_vfl", }, + .res_type = RPMPD_RWSC, + .res_id = 2, + .key = KEY_FLOOR_LEVEL, +}; + +static struct rpmpd cx_s1a_vfc = { + .pd = { .name = "cx_vfc", }, + .res_type = RPMPD_SMPA, + .res_id = 1, + .key = KEY_FLOOR_CORNER, +}; + +static struct rpmpd cx_s2a_vfc = { + .pd = { .name = "cx_vfc", }, + .res_type = RPMPD_SMPA, + .res_id = 2, + .key = KEY_FLOOR_CORNER, +}; + +static struct rpmpd cx_s2a_vfl = { + .pd = { .name = "cx_vfl", }, + .res_type = RPMPD_SMPA, + .res_id = 2, + .key = KEY_FLOOR_LEVEL, +}; + +static struct rpmpd cx_s3a_vfl = { + .pd = { .name = "cx_vfl", }, + .res_type = RPMPD_SMPA, + .res_id = 3, + .key = KEY_FLOOR_LEVEL, +}; + +/* G(F)X */ +static struct rpmpd gfx_s2b_corner = { + .pd = { .name = "gfx", }, + .res_type = RPMPD_SMPB, + .res_id = 2, + .key = KEY_CORNER, +}; + +static struct rpmpd gfx_s2b_vfc = { + .pd = { .name = "gfx_vfc", }, + .res_type = RPMPD_SMPB, + .res_id = 2, + .key = KEY_FLOOR_CORNER, +}; + +static struct rpmpd mx_rwmx0_lvl; +static struct rpmpd gx_rwgx0_lvl_ao; +static struct rpmpd gx_rwgx0_lvl = { + .pd = { .name = "gx", }, + .peer = &gx_rwgx0_lvl_ao, + .res_type = RPMPD_RWGX, + .parent = &mx_rwmx0_lvl.pd, + .res_id = 0, + .key = KEY_LEVEL, +}; + +static struct rpmpd mx_rwmx0_lvl_ao; +static struct rpmpd gx_rwgx0_lvl_ao = { + .pd = { .name = "gx_ao", }, + .peer = &gx_rwgx0_lvl, + .parent = &mx_rwmx0_lvl_ao.pd, + .active_only = true, + .res_type = RPMPD_RWGX, + .res_id = 0, + .key = KEY_LEVEL, +}; + +/* MX */ +static struct rpmpd mx_l3a_corner_ao; +static struct rpmpd mx_l3a_corner = { + .pd = { .name = "mx", }, + .peer = &mx_l3a_corner_ao, + .res_type = RPMPD_LDOA, + .res_id = 3, + .key = KEY_CORNER, +}; + +static struct rpmpd mx_l3a_corner_ao = { + .pd = { .name = "mx_ao", }, + .peer = &mx_l3a_corner, + .active_only = true, + .res_type = RPMPD_LDOA, + .res_id = 3, + .key = KEY_CORNER, +}; + +static struct rpmpd mx_l12a_lvl_ao; +static struct rpmpd mx_l12a_lvl = { + .pd = { .name = "mx", }, + .peer = &mx_l12a_lvl_ao, + .res_type = RPMPD_LDOA, + .res_id = 12, + .key = KEY_LEVEL, +}; + +static struct rpmpd mx_l12a_lvl_ao = { + .pd = { .name = "mx_ao", }, + .peer = &mx_l12a_lvl, + .active_only = true, + .res_type = RPMPD_LDOA, + .res_id = 12, + .key = KEY_LEVEL, +}; + +static struct rpmpd mx_s2a_corner_ao; +static struct rpmpd mx_s2a_corner = { + .pd = { .name = "mx", }, + .peer = &mx_s2a_corner_ao, + .res_type = RPMPD_SMPA, + .res_id = 2, + .key = KEY_CORNER, +}; + +static struct rpmpd mx_s2a_corner_ao = { + .pd = { .name = "mx_ao", }, + .peer = &mx_s2a_corner, + .active_only = true, + .res_type = RPMPD_SMPA, + .res_id = 2, + .key = KEY_CORNER, +}; + +static struct rpmpd mx_rwmx0_lvl_ao; +static struct rpmpd mx_rwmx0_lvl = { + .pd = { .name = "mx", }, + .peer = &mx_rwmx0_lvl_ao, + .res_type = RPMPD_RWMX, + .res_id = 0, + .key = KEY_LEVEL, +}; + +static struct rpmpd mx_rwmx0_lvl_ao = { + .pd = { .name = "mx_ao", }, + .peer = &mx_rwmx0_lvl, + .active_only = true, + .res_type = RPMPD_RWMX, + .res_id = 0, + .key = KEY_LEVEL, +}; + +static struct rpmpd mx_s6a_lvl_ao; +static struct rpmpd mx_s6a_lvl = { + .pd = { .name = "mx", }, + .peer = &mx_s6a_lvl_ao, + .res_type = RPMPD_SMPA, + .res_id = 6, + .key = KEY_LEVEL, +}; + +static struct rpmpd mx_s6a_lvl_ao = { + .pd = { .name = "mx_ao", }, + .peer = &mx_s6a_lvl, + .active_only = true, + .res_type = RPMPD_SMPA, + .res_id = 6, + .key = KEY_LEVEL, +}; + +static struct rpmpd mx_s7a_lvl_ao; +static struct rpmpd mx_s7a_lvl = { + .pd = { .name = "mx", }, + .peer = &mx_s7a_lvl_ao, + .res_type = RPMPD_SMPA, + .res_id = 7, + .key = KEY_LEVEL, +}; + +static struct rpmpd mx_s7a_lvl_ao = { + .pd = { .name = "mx_ao", }, + .peer = &mx_s7a_lvl, + .active_only = true, + .res_type = RPMPD_SMPA, + .res_id = 7, + .key = KEY_LEVEL, +}; + +static struct rpmpd mx_l12a_vfl = { + .pd = { .name = "mx_vfl", }, + .res_type = RPMPD_LDOA, + .res_id = 12, + .key = KEY_FLOOR_LEVEL, +}; + +static struct rpmpd mx_rwmx0_vfl = { + .pd = { .name = "mx_vfl", }, + .res_type = RPMPD_RWMX, + .res_id = 0, + .key = KEY_FLOOR_LEVEL, +}; + +static struct rpmpd mx_rwsm6_vfl = { + .pd = { .name = "mx_vfl", }, + .res_type = RPMPD_RWSM, + .res_id = 6, + .key = KEY_FLOOR_LEVEL, +}; + +/* MD */ +static struct rpmpd md_s1a_corner_ao; +static struct rpmpd md_s1a_corner = { + .pd = { .name = "md", }, + .peer = &md_s1a_corner_ao, + .res_type = RPMPD_SMPA, + .res_id = 1, + .key = KEY_CORNER, +}; + +static struct rpmpd md_s1a_corner_ao = { + .pd = { .name = "md_ao", }, + .peer = &md_s1a_corner, + .active_only = true, + .res_type = RPMPD_SMPA, + .res_id = 1, + .key = KEY_CORNER, +}; + +static struct rpmpd md_s1a_lvl_ao; +static struct rpmpd md_s1a_lvl = { + .pd = { .name = "md", }, + .peer = &md_s1a_lvl_ao, + .res_type = RPMPD_SMPA, + .res_id = 1, + .key = KEY_LEVEL, +}; + +static struct rpmpd md_s1a_lvl_ao = { + .pd = { .name = "md_ao", }, + .peer = &md_s1a_lvl, + .active_only = true, + .res_type = RPMPD_SMPA, + .res_id = 1, + .key = KEY_LEVEL, +}; + +static struct rpmpd md_s1a_vfc = { + .pd = { .name = "md_vfc", }, + .res_type = RPMPD_SMPA, + .res_id = 1, + .key = KEY_FLOOR_CORNER, +}; + +/* LPI_CX */ +static struct rpmpd lpi_cx_rwlc0_lvl = { + .pd = { .name = "lpi_cx", }, + .res_type = RPMPD_RWLC, + .res_id = 0, + .key = KEY_LEVEL, +}; + +static struct rpmpd lpi_cx_rwlc0_vfl = { + .pd = { .name = "lpi_cx_vfl", }, + .res_type = RPMPD_RWLC, + .res_id = 0, + .key = KEY_FLOOR_LEVEL, +}; + +/* LPI_MX */ +static struct rpmpd lpi_mx_rwlm0_lvl = { + .pd = { .name = "lpi_mx", }, + .res_type = RPMPD_RWLM, + .res_id = 0, + .key = KEY_LEVEL, +}; + +static struct rpmpd lpi_mx_rwlm0_vfl = { + .pd = { .name = "lpi_mx_vfl", }, + .res_type = RPMPD_RWLM, + .res_id = 0, + .key = KEY_FLOOR_LEVEL, +}; + +/* SSC_CX */ +static struct rpmpd ssc_cx_l26a_corner = { + .pd = { .name = "ssc_cx", }, + .res_type = RPMPD_LDOA, + .res_id = 26, + .key = KEY_CORNER, +}; + +static struct rpmpd ssc_cx_rwlc0_lvl = { + .pd = { .name = "ssc_cx", }, + .res_type = RPMPD_RWLC, + .res_id = 0, + .key = KEY_LEVEL, +}; + +static struct rpmpd ssc_cx_rwsc0_lvl = { + .pd = { .name = "ssc_cx", }, + .res_type = RPMPD_RWSC, + .res_id = 0, + .key = KEY_LEVEL, +}; + +static struct rpmpd ssc_cx_l26a_vfc = { + .pd = { .name = "ssc_cx_vfc", }, + .res_type = RPMPD_LDOA, + .res_id = 26, + .key = KEY_FLOOR_CORNER, +}; + +static struct rpmpd ssc_cx_rwlc0_vfl = { + .pd = { .name = "ssc_cx_vfl", }, + .res_type = RPMPD_RWLC, + .res_id = 0, + .key = KEY_FLOOR_LEVEL, +}; + +static struct rpmpd ssc_cx_rwsc0_vfl = { + .pd = { .name = "ssc_cx_vfl", }, + .res_type = RPMPD_RWSC, + .res_id = 0, + .key = KEY_FLOOR_LEVEL, +}; + +/* SSC_MX */ +static struct rpmpd ssc_mx_rwlm0_lvl = { + .pd = { .name = "ssc_mx", }, + .res_type = RPMPD_RWLM, + .res_id = 0, + .key = KEY_LEVEL, +}; + +static struct rpmpd ssc_mx_rwsm0_lvl = { + .pd = { .name = "ssc_mx", }, + .res_type = RPMPD_RWSM, + .res_id = 0, + .key = KEY_LEVEL, +}; + +static struct rpmpd ssc_mx_rwlm0_vfl = { + .pd = { .name = "ssc_mx_vfl", }, + .res_type = RPMPD_RWLM, + .res_id = 0, + .key = KEY_FLOOR_LEVEL, +}; + +static struct rpmpd ssc_mx_rwsm0_vfl = { + .pd = { .name = "ssc_mx_vfl", }, + .res_type = RPMPD_RWSM, + .res_id = 0, + .key = KEY_FLOOR_LEVEL, +}; -DEFINE_RPMPD_PAIR(mdm9607, vddmx, vddmx_ao, LDOA, LEVEL, 12); -DEFINE_RPMPD_VFL(mdm9607, vddmx_vfl, LDOA, 12); static struct rpmpd *mdm9607_rpmpds[] = { - [MDM9607_VDDCX] = &mdm9607_vddcx, - [MDM9607_VDDCX_AO] = &mdm9607_vddcx_ao, - [MDM9607_VDDCX_VFL] = &mdm9607_vddcx_vfl, - [MDM9607_VDDMX] = &mdm9607_vddmx, - [MDM9607_VDDMX_AO] = &mdm9607_vddmx_ao, - [MDM9607_VDDMX_VFL] = &mdm9607_vddmx_vfl, + [MDM9607_VDDCX] = &cx_s3a_lvl, + [MDM9607_VDDCX_AO] = &cx_s3a_lvl_ao, + [MDM9607_VDDCX_VFL] = &cx_s3a_vfl, + [MDM9607_VDDMX] = &mx_l12a_lvl, + [MDM9607_VDDMX_AO] = &mx_l12a_lvl_ao, + [MDM9607_VDDMX_VFL] = &mx_l12a_vfl, }; static const struct rpmpd_desc mdm9607_desc = { @@ -139,14 +529,10 @@ static const struct rpmpd_desc mdm9607_desc = { .max_state = RPM_SMD_LEVEL_TURBO, }; -/* msm8226 RPM Power Domains */ -DEFINE_RPMPD_PAIR(msm8226, vddcx, vddcx_ao, SMPA, CORNER, 1); -DEFINE_RPMPD_VFC(msm8226, vddcx_vfc, SMPA, 1); - static struct rpmpd *msm8226_rpmpds[] = { - [MSM8226_VDDCX] = &msm8226_vddcx, - [MSM8226_VDDCX_AO] = &msm8226_vddcx_ao, - [MSM8226_VDDCX_VFC] = &msm8226_vddcx_vfc, + [MSM8226_VDDCX] = &cx_s1a_corner, + [MSM8226_VDDCX_AO] = &cx_s1a_corner_ao, + [MSM8226_VDDCX_VFC] = &cx_s1a_vfc, }; static const struct rpmpd_desc msm8226_desc = { @@ -155,24 +541,15 @@ static const struct rpmpd_desc msm8226_desc = { .max_state = MAX_CORNER_RPMPD_STATE, }; -/* msm8939 RPM Power Domains */ -DEFINE_RPMPD_PAIR(msm8939, vddmd, vddmd_ao, SMPA, CORNER, 1); -DEFINE_RPMPD_VFC(msm8939, vddmd_vfc, SMPA, 1); - -DEFINE_RPMPD_PAIR(msm8939, vddcx, vddcx_ao, SMPA, CORNER, 2); -DEFINE_RPMPD_VFC(msm8939, vddcx_vfc, SMPA, 2); - -DEFINE_RPMPD_PAIR(msm8939, vddmx, vddmx_ao, LDOA, CORNER, 3); - static struct rpmpd *msm8939_rpmpds[] = { - [MSM8939_VDDMDCX] = &msm8939_vddmd, - [MSM8939_VDDMDCX_AO] = &msm8939_vddmd_ao, - [MSM8939_VDDMDCX_VFC] = &msm8939_vddmd_vfc, - [MSM8939_VDDCX] = &msm8939_vddcx, - [MSM8939_VDDCX_AO] = &msm8939_vddcx_ao, - [MSM8939_VDDCX_VFC] = &msm8939_vddcx_vfc, - [MSM8939_VDDMX] = &msm8939_vddmx, - [MSM8939_VDDMX_AO] = &msm8939_vddmx_ao, + [MSM8939_VDDMDCX] = &md_s1a_corner, + [MSM8939_VDDMDCX_AO] = &md_s1a_corner_ao, + [MSM8939_VDDMDCX_VFC] = &md_s1a_vfc, + [MSM8939_VDDCX] = &cx_s2a_corner, + [MSM8939_VDDCX_AO] = &cx_s2a_corner_ao, + [MSM8939_VDDCX_VFC] = &cx_s2a_vfc, + [MSM8939_VDDMX] = &mx_l3a_corner, + [MSM8939_VDDMX_AO] = &mx_l3a_corner_ao, }; static const struct rpmpd_desc msm8939_desc = { @@ -181,18 +558,12 @@ static const struct rpmpd_desc msm8939_desc = { .max_state = MAX_CORNER_RPMPD_STATE, }; -/* msm8916 RPM Power Domains */ -DEFINE_RPMPD_PAIR(msm8916, vddcx, vddcx_ao, SMPA, CORNER, 1); -DEFINE_RPMPD_PAIR(msm8916, vddmx, vddmx_ao, LDOA, CORNER, 3); - -DEFINE_RPMPD_VFC(msm8916, vddcx_vfc, SMPA, 1); - static struct rpmpd *msm8916_rpmpds[] = { - [MSM8916_VDDCX] = &msm8916_vddcx, - [MSM8916_VDDCX_AO] = &msm8916_vddcx_ao, - [MSM8916_VDDCX_VFC] = &msm8916_vddcx_vfc, - [MSM8916_VDDMX] = &msm8916_vddmx, - [MSM8916_VDDMX_AO] = &msm8916_vddmx_ao, + [MSM8916_VDDCX] = &cx_s1a_corner, + [MSM8916_VDDCX_AO] = &cx_s1a_corner_ao, + [MSM8916_VDDCX_VFC] = &cx_s1a_vfc, + [MSM8916_VDDMX] = &mx_l3a_corner, + [MSM8916_VDDMX_AO] = &mx_l3a_corner_ao, }; static const struct rpmpd_desc msm8916_desc = { @@ -201,21 +572,14 @@ static const struct rpmpd_desc msm8916_desc = { .max_state = MAX_CORNER_RPMPD_STATE, }; -/* msm8953 RPM Power Domains */ -DEFINE_RPMPD_PAIR(msm8953, vddmd, vddmd_ao, SMPA, LEVEL, 1); -DEFINE_RPMPD_PAIR(msm8953, vddcx, vddcx_ao, SMPA, LEVEL, 2); -DEFINE_RPMPD_PAIR(msm8953, vddmx, vddmx_ao, SMPA, LEVEL, 7); - -DEFINE_RPMPD_VFL(msm8953, vddcx_vfl, SMPA, 2); - static struct rpmpd *msm8953_rpmpds[] = { - [MSM8953_VDDMD] = &msm8953_vddmd, - [MSM8953_VDDMD_AO] = &msm8953_vddmd_ao, - [MSM8953_VDDCX] = &msm8953_vddcx, - [MSM8953_VDDCX_AO] = &msm8953_vddcx_ao, - [MSM8953_VDDCX_VFL] = &msm8953_vddcx_vfl, - [MSM8953_VDDMX] = &msm8953_vddmx, - [MSM8953_VDDMX_AO] = &msm8953_vddmx_ao, + [MSM8953_VDDMD] = &md_s1a_lvl, + [MSM8953_VDDMD_AO] = &md_s1a_lvl_ao, + [MSM8953_VDDCX] = &cx_s2a_lvl, + [MSM8953_VDDCX_AO] = &cx_s2a_lvl_ao, + [MSM8953_VDDCX_VFL] = &cx_s2a_vfl, + [MSM8953_VDDMX] = &mx_s7a_lvl, + [MSM8953_VDDMX_AO] = &mx_s7a_lvl_ao, }; static const struct rpmpd_desc msm8953_desc = { @@ -224,20 +588,13 @@ static const struct rpmpd_desc msm8953_desc = { .max_state = RPM_SMD_LEVEL_TURBO, }; -/* msm8976 RPM Power Domains */ -DEFINE_RPMPD_PAIR(msm8976, vddcx, vddcx_ao, SMPA, LEVEL, 2); -DEFINE_RPMPD_PAIR(msm8976, vddmx, vddmx_ao, SMPA, LEVEL, 6); - -DEFINE_RPMPD_VFL(msm8976, vddcx_vfl, RWSC, 2); -DEFINE_RPMPD_VFL(msm8976, vddmx_vfl, RWSM, 6); - static struct rpmpd *msm8976_rpmpds[] = { - [MSM8976_VDDCX] = &msm8976_vddcx, - [MSM8976_VDDCX_AO] = &msm8976_vddcx_ao, - [MSM8976_VDDCX_VFL] = &msm8976_vddcx_vfl, - [MSM8976_VDDMX] = &msm8976_vddmx, - [MSM8976_VDDMX_AO] = &msm8976_vddmx_ao, - [MSM8976_VDDMX_VFL] = &msm8976_vddmx_vfl, + [MSM8976_VDDCX] = &cx_s2a_lvl, + [MSM8976_VDDCX_AO] = &cx_s2a_lvl_ao, + [MSM8976_VDDCX_VFL] = &cx_rwsc2_vfl, + [MSM8976_VDDMX] = &mx_s6a_lvl, + [MSM8976_VDDMX_AO] = &mx_s6a_lvl_ao, + [MSM8976_VDDMX_VFL] = &mx_rwsm6_vfl, }; static const struct rpmpd_desc msm8976_desc = { @@ -246,23 +603,16 @@ static const struct rpmpd_desc msm8976_desc = { .max_state = RPM_SMD_LEVEL_TURBO_HIGH, }; -/* msm8994 RPM Power domains */ -DEFINE_RPMPD_PAIR(msm8994, vddcx, vddcx_ao, SMPA, CORNER, 1); -DEFINE_RPMPD_PAIR(msm8994, vddmx, vddmx_ao, SMPA, CORNER, 2); -/* Attention! *Some* 8994 boards with pm8004 may use SMPC here! */ -DEFINE_RPMPD_CORNER(msm8994, vddgfx, SMPB, 2); - -DEFINE_RPMPD_VFC(msm8994, vddcx_vfc, SMPA, 1); -DEFINE_RPMPD_VFC(msm8994, vddgfx_vfc, SMPB, 2); - static struct rpmpd *msm8994_rpmpds[] = { - [MSM8994_VDDCX] = &msm8994_vddcx, - [MSM8994_VDDCX_AO] = &msm8994_vddcx_ao, - [MSM8994_VDDCX_VFC] = &msm8994_vddcx_vfc, - [MSM8994_VDDMX] = &msm8994_vddmx, - [MSM8994_VDDMX_AO] = &msm8994_vddmx_ao, - [MSM8994_VDDGFX] = &msm8994_vddgfx, - [MSM8994_VDDGFX_VFC] = &msm8994_vddgfx_vfc, + [MSM8994_VDDCX] = &cx_s1a_corner, + [MSM8994_VDDCX_AO] = &cx_s1a_corner_ao, + [MSM8994_VDDCX_VFC] = &cx_s1a_vfc, + [MSM8994_VDDMX] = &mx_s2a_corner, + [MSM8994_VDDMX_AO] = &mx_s2a_corner_ao, + + /* Attention! *Some* 8994 boards with pm8004 may use SMPC here! */ + [MSM8994_VDDGFX] = &gfx_s2b_corner, + [MSM8994_VDDGFX_VFC] = &gfx_s2b_vfc, }; static const struct rpmpd_desc msm8994_desc = { @@ -271,22 +621,14 @@ static const struct rpmpd_desc msm8994_desc = { .max_state = MAX_CORNER_RPMPD_STATE, }; -/* msm8996 RPM Power domains */ -DEFINE_RPMPD_PAIR(msm8996, vddcx, vddcx_ao, SMPA, CORNER, 1); -DEFINE_RPMPD_PAIR(msm8996, vddmx, vddmx_ao, SMPA, CORNER, 2); -DEFINE_RPMPD_CORNER(msm8996, vddsscx, LDOA, 26); - -DEFINE_RPMPD_VFC(msm8996, vddcx_vfc, SMPA, 1); -DEFINE_RPMPD_VFC(msm8996, vddsscx_vfc, LDOA, 26); - static struct rpmpd *msm8996_rpmpds[] = { - [MSM8996_VDDCX] = &msm8996_vddcx, - [MSM8996_VDDCX_AO] = &msm8996_vddcx_ao, - [MSM8996_VDDCX_VFC] = &msm8996_vddcx_vfc, - [MSM8996_VDDMX] = &msm8996_vddmx, - [MSM8996_VDDMX_AO] = &msm8996_vddmx_ao, - [MSM8996_VDDSSCX] = &msm8996_vddsscx, - [MSM8996_VDDSSCX_VFC] = &msm8996_vddsscx_vfc, + [MSM8996_VDDCX] = &cx_s1a_corner, + [MSM8996_VDDCX_AO] = &cx_s1a_corner_ao, + [MSM8996_VDDCX_VFC] = &cx_s1a_vfc, + [MSM8996_VDDMX] = &mx_s2a_corner, + [MSM8996_VDDMX_AO] = &mx_s2a_corner_ao, + [MSM8996_VDDSSCX] = &ssc_cx_l26a_corner, + [MSM8996_VDDSSCX_VFC] = &ssc_cx_l26a_vfc, }; static const struct rpmpd_desc msm8996_desc = { @@ -295,30 +637,17 @@ static const struct rpmpd_desc msm8996_desc = { .max_state = MAX_CORNER_RPMPD_STATE, }; -/* msm8998 RPM Power domains */ -DEFINE_RPMPD_PAIR(msm8998, vddcx, vddcx_ao, RWCX, LEVEL, 0); -DEFINE_RPMPD_VFL(msm8998, vddcx_vfl, RWCX, 0); - -DEFINE_RPMPD_PAIR(msm8998, vddmx, vddmx_ao, RWMX, LEVEL, 0); -DEFINE_RPMPD_VFL(msm8998, vddmx_vfl, RWMX, 0); - -DEFINE_RPMPD_LEVEL(msm8998, vdd_ssccx, RWSC, 0); -DEFINE_RPMPD_VFL(msm8998, vdd_ssccx_vfl, RWSC, 0); - -DEFINE_RPMPD_LEVEL(msm8998, vdd_sscmx, RWSM, 0); -DEFINE_RPMPD_VFL(msm8998, vdd_sscmx_vfl, RWSM, 0); - static struct rpmpd *msm8998_rpmpds[] = { - [MSM8998_VDDCX] = &msm8998_vddcx, - [MSM8998_VDDCX_AO] = &msm8998_vddcx_ao, - [MSM8998_VDDCX_VFL] = &msm8998_vddcx_vfl, - [MSM8998_VDDMX] = &msm8998_vddmx, - [MSM8998_VDDMX_AO] = &msm8998_vddmx_ao, - [MSM8998_VDDMX_VFL] = &msm8998_vddmx_vfl, - [MSM8998_SSCCX] = &msm8998_vdd_ssccx, - [MSM8998_SSCCX_VFL] = &msm8998_vdd_ssccx_vfl, - [MSM8998_SSCMX] = &msm8998_vdd_sscmx, - [MSM8998_SSCMX_VFL] = &msm8998_vdd_sscmx_vfl, + [MSM8998_VDDCX] = &cx_rwcx0_lvl, + [MSM8998_VDDCX_AO] = &cx_rwcx0_lvl_ao, + [MSM8998_VDDCX_VFL] = &cx_rwcx0_vfl, + [MSM8998_VDDMX] = &mx_rwmx0_lvl, + [MSM8998_VDDMX_AO] = &mx_rwmx0_lvl_ao, + [MSM8998_VDDMX_VFL] = &mx_rwmx0_vfl, + [MSM8998_SSCCX] = &ssc_cx_rwsc0_lvl, + [MSM8998_SSCCX_VFL] = &ssc_cx_rwsc0_vfl, + [MSM8998_SSCMX] = &ssc_mx_rwsm0_lvl, + [MSM8998_SSCMX_VFL] = &ssc_mx_rwsm0_vfl, }; static const struct rpmpd_desc msm8998_desc = { @@ -327,24 +656,14 @@ static const struct rpmpd_desc msm8998_desc = { .max_state = RPM_SMD_LEVEL_BINNING, }; -/* qcs404 RPM Power domains */ -DEFINE_RPMPD_PAIR(qcs404, vddmx, vddmx_ao, RWMX, LEVEL, 0); -DEFINE_RPMPD_VFL(qcs404, vddmx_vfl, RWMX, 0); - -DEFINE_RPMPD_LEVEL(qcs404, vdd_lpicx, RWLC, 0); -DEFINE_RPMPD_VFL(qcs404, vdd_lpicx_vfl, RWLC, 0); - -DEFINE_RPMPD_LEVEL(qcs404, vdd_lpimx, RWLM, 0); -DEFINE_RPMPD_VFL(qcs404, vdd_lpimx_vfl, RWLM, 0); - static struct rpmpd *qcs404_rpmpds[] = { - [QCS404_VDDMX] = &qcs404_vddmx, - [QCS404_VDDMX_AO] = &qcs404_vddmx_ao, - [QCS404_VDDMX_VFL] = &qcs404_vddmx_vfl, - [QCS404_LPICX] = &qcs404_vdd_lpicx, - [QCS404_LPICX_VFL] = &qcs404_vdd_lpicx_vfl, - [QCS404_LPIMX] = &qcs404_vdd_lpimx, - [QCS404_LPIMX_VFL] = &qcs404_vdd_lpimx_vfl, + [QCS404_VDDMX] = &mx_rwmx0_lvl, + [QCS404_VDDMX_AO] = &mx_rwmx0_lvl_ao, + [QCS404_VDDMX_VFL] = &mx_rwmx0_vfl, + [QCS404_LPICX] = &lpi_cx_rwlc0_lvl, + [QCS404_LPICX_VFL] = &lpi_cx_rwlc0_vfl, + [QCS404_LPIMX] = &lpi_mx_rwlm0_lvl, + [QCS404_LPIMX_VFL] = &lpi_mx_rwlm0_vfl, }; static const struct rpmpd_desc qcs404_desc = { @@ -353,30 +672,17 @@ static const struct rpmpd_desc qcs404_desc = { .max_state = RPM_SMD_LEVEL_BINNING, }; -/* sdm660 RPM Power domains */ -DEFINE_RPMPD_PAIR(sdm660, vddcx, vddcx_ao, RWCX, LEVEL, 0); -DEFINE_RPMPD_VFL(sdm660, vddcx_vfl, RWCX, 0); - -DEFINE_RPMPD_PAIR(sdm660, vddmx, vddmx_ao, RWMX, LEVEL, 0); -DEFINE_RPMPD_VFL(sdm660, vddmx_vfl, RWMX, 0); - -DEFINE_RPMPD_LEVEL(sdm660, vdd_ssccx, RWLC, 0); -DEFINE_RPMPD_VFL(sdm660, vdd_ssccx_vfl, RWLC, 0); - -DEFINE_RPMPD_LEVEL(sdm660, vdd_sscmx, RWLM, 0); -DEFINE_RPMPD_VFL(sdm660, vdd_sscmx_vfl, RWLM, 0); - static struct rpmpd *sdm660_rpmpds[] = { - [SDM660_VDDCX] = &sdm660_vddcx, - [SDM660_VDDCX_AO] = &sdm660_vddcx_ao, - [SDM660_VDDCX_VFL] = &sdm660_vddcx_vfl, - [SDM660_VDDMX] = &sdm660_vddmx, - [SDM660_VDDMX_AO] = &sdm660_vddmx_ao, - [SDM660_VDDMX_VFL] = &sdm660_vddmx_vfl, - [SDM660_SSCCX] = &sdm660_vdd_ssccx, - [SDM660_SSCCX_VFL] = &sdm660_vdd_ssccx_vfl, - [SDM660_SSCMX] = &sdm660_vdd_sscmx, - [SDM660_SSCMX_VFL] = &sdm660_vdd_sscmx_vfl, + [SDM660_VDDCX] = &cx_rwcx0_lvl, + [SDM660_VDDCX_AO] = &cx_rwcx0_lvl_ao, + [SDM660_VDDCX_VFL] = &cx_rwcx0_vfl, + [SDM660_VDDMX] = &mx_rwmx0_lvl, + [SDM660_VDDMX_AO] = &mx_rwmx0_lvl_ao, + [SDM660_VDDMX_VFL] = &mx_rwmx0_vfl, + [SDM660_SSCCX] = &ssc_cx_rwlc0_lvl, + [SDM660_SSCCX_VFL] = &ssc_cx_rwlc0_vfl, + [SDM660_SSCMX] = &ssc_mx_rwlm0_lvl, + [SDM660_SSCMX_VFL] = &ssc_mx_rwlm0_vfl, }; static const struct rpmpd_desc sdm660_desc = { @@ -385,25 +691,15 @@ static const struct rpmpd_desc sdm660_desc = { .max_state = RPM_SMD_LEVEL_TURBO, }; -/* sm4250/6115 RPM Power domains */ -DEFINE_RPMPD_PAIR(sm6115, vddcx, vddcx_ao, RWCX, LEVEL, 0); -DEFINE_RPMPD_VFL(sm6115, vddcx_vfl, RWCX, 0); - -DEFINE_RPMPD_PAIR(sm6115, vddmx, vddmx_ao, RWMX, LEVEL, 0); -DEFINE_RPMPD_VFL(sm6115, vddmx_vfl, RWMX, 0); - -DEFINE_RPMPD_LEVEL(sm6115, vdd_lpi_cx, RWLC, 0); -DEFINE_RPMPD_LEVEL(sm6115, vdd_lpi_mx, RWLM, 0); - static struct rpmpd *sm6115_rpmpds[] = { - [SM6115_VDDCX] = &sm6115_vddcx, - [SM6115_VDDCX_AO] = &sm6115_vddcx_ao, - [SM6115_VDDCX_VFL] = &sm6115_vddcx_vfl, - [SM6115_VDDMX] = &sm6115_vddmx, - [SM6115_VDDMX_AO] = &sm6115_vddmx_ao, - [SM6115_VDDMX_VFL] = &sm6115_vddmx_vfl, - [SM6115_VDD_LPI_CX] = &sm6115_vdd_lpi_cx, - [SM6115_VDD_LPI_MX] = &sm6115_vdd_lpi_mx, + [SM6115_VDDCX] = &cx_rwcx0_lvl, + [SM6115_VDDCX_AO] = &cx_rwcx0_lvl_ao, + [SM6115_VDDCX_VFL] = &cx_rwcx0_vfl, + [SM6115_VDDMX] = &mx_rwmx0_lvl, + [SM6115_VDDMX_AO] = &mx_rwmx0_lvl_ao, + [SM6115_VDDMX_VFL] = &mx_rwmx0_vfl, + [SM6115_VDD_LPI_CX] = &lpi_cx_rwlc0_lvl, + [SM6115_VDD_LPI_MX] = &lpi_mx_rwlm0_lvl, }; static const struct rpmpd_desc sm6115_desc = { @@ -412,20 +708,13 @@ static const struct rpmpd_desc sm6115_desc = { .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR, }; -/* sm6125 RPM Power domains */ -DEFINE_RPMPD_PAIR(sm6125, vddcx, vddcx_ao, RWCX, LEVEL, 0); -DEFINE_RPMPD_VFL(sm6125, vddcx_vfl, RWCX, 0); - -DEFINE_RPMPD_PAIR(sm6125, vddmx, vddmx_ao, RWMX, LEVEL, 0); -DEFINE_RPMPD_VFL(sm6125, vddmx_vfl, RWMX, 0); - static struct rpmpd *sm6125_rpmpds[] = { - [SM6125_VDDCX] = &sm6125_vddcx, - [SM6125_VDDCX_AO] = &sm6125_vddcx_ao, - [SM6125_VDDCX_VFL] = &sm6125_vddcx_vfl, - [SM6125_VDDMX] = &sm6125_vddmx, - [SM6125_VDDMX_AO] = &sm6125_vddmx_ao, - [SM6125_VDDMX_VFL] = &sm6125_vddmx_vfl, + [SM6125_VDDCX] = &cx_rwcx0_lvl, + [SM6125_VDDCX_AO] = &cx_rwcx0_lvl_ao, + [SM6125_VDDCX_VFL] = &cx_rwcx0_vfl, + [SM6125_VDDMX] = &mx_rwmx0_lvl, + [SM6125_VDDMX_AO] = &mx_rwmx0_lvl_ao, + [SM6125_VDDMX_VFL] = &mx_rwmx0_vfl, }; static const struct rpmpd_desc sm6125_desc = { @@ -434,18 +723,17 @@ static const struct rpmpd_desc sm6125_desc = { .max_state = RPM_SMD_LEVEL_BINNING, }; -DEFINE_RPMPD_PAIR(sm6375, vddgx, vddgx_ao, RWGX, LEVEL, 0); static struct rpmpd *sm6375_rpmpds[] = { - [SM6375_VDDCX] = &sm6125_vddcx, - [SM6375_VDDCX_AO] = &sm6125_vddcx_ao, - [SM6375_VDDCX_VFL] = &sm6125_vddcx_vfl, - [SM6375_VDDMX] = &sm6125_vddmx, - [SM6375_VDDMX_AO] = &sm6125_vddmx_ao, - [SM6375_VDDMX_VFL] = &sm6125_vddmx_vfl, - [SM6375_VDDGX] = &sm6375_vddgx, - [SM6375_VDDGX_AO] = &sm6375_vddgx_ao, - [SM6375_VDD_LPI_CX] = &sm6115_vdd_lpi_cx, - [SM6375_VDD_LPI_MX] = &sm6115_vdd_lpi_mx, + [SM6375_VDDCX] = &cx_rwcx0_lvl, + [SM6375_VDDCX_AO] = &cx_rwcx0_lvl_ao, + [SM6375_VDDCX_VFL] = &cx_rwcx0_vfl, + [SM6375_VDDMX] = &mx_rwmx0_lvl, + [SM6375_VDDMX_AO] = &mx_rwmx0_lvl_ao, + [SM6375_VDDMX_VFL] = &mx_rwmx0_vfl, + [SM6375_VDDGX] = &gx_rwgx0_lvl, + [SM6375_VDDGX_AO] = &gx_rwgx0_lvl_ao, + [SM6375_VDD_LPI_CX] = &lpi_cx_rwlc0_lvl, + [SM6375_VDD_LPI_MX] = &lpi_mx_rwlm0_lvl, }; static const struct rpmpd_desc sm6375_desc = { @@ -455,14 +743,14 @@ static const struct rpmpd_desc sm6375_desc = { }; static struct rpmpd *qcm2290_rpmpds[] = { - [QCM2290_VDDCX] = &sm6115_vddcx, - [QCM2290_VDDCX_AO] = &sm6115_vddcx_ao, - [QCM2290_VDDCX_VFL] = &sm6115_vddcx_vfl, - [QCM2290_VDDMX] = &sm6115_vddmx, - [QCM2290_VDDMX_AO] = &sm6115_vddmx_ao, - [QCM2290_VDDMX_VFL] = &sm6115_vddmx_vfl, - [QCM2290_VDD_LPI_CX] = &sm6115_vdd_lpi_cx, - [QCM2290_VDD_LPI_MX] = &sm6115_vdd_lpi_mx, + [QCM2290_VDDCX] = &cx_rwcx0_lvl, + [QCM2290_VDDCX_AO] = &cx_rwcx0_lvl_ao, + [QCM2290_VDDCX_VFL] = &cx_rwcx0_vfl, + [QCM2290_VDDMX] = &mx_rwmx0_lvl, + [QCM2290_VDDMX_AO] = &mx_rwmx0_lvl_ao, + [QCM2290_VDDMX_VFL] = &mx_rwmx0_vfl, + [QCM2290_VDD_LPI_CX] = &lpi_cx_rwlc0_lvl, + [QCM2290_VDD_LPI_MX] = &lpi_mx_rwlm0_lvl, }; static const struct rpmpd_desc qcm2290_desc = { @@ -673,6 +961,15 @@ static int rpmpd_probe(struct platform_device *pdev) data->domains[i] = &rpmpds[i]->pd; } + /* Add subdomains */ + for (i = 0; i < num; i++) { + if (!rpmpds[i]) + continue; + + if (rpmpds[i]->parent) + pm_genpd_add_subdomain(rpmpds[i]->parent, &rpmpds[i]->pd); + } + return of_genpd_add_provider_onecell(pdev->dev.of_node, data); } diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c index 523627d5d398..0c1aa809cc4e 100644 --- a/drivers/soc/qcom/smd-rpm.c +++ b/drivers/soc/qcom/smd-rpm.c @@ -113,7 +113,7 @@ int qcom_rpm_smd_write(struct qcom_smd_rpm *rpm, if (WARN_ON(size >= 256)) return -EINVAL; - pkt = kmalloc(size, GFP_KERNEL); + pkt = kmalloc(size, GFP_ATOMIC); if (!pkt) return -ENOMEM; diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 4f163d62942c..6be7ea93c78c 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -85,7 +85,7 @@ #define SMEM_GLOBAL_HOST 0xfffe /* Max number of processors/hosts in a system */ -#define SMEM_HOST_COUNT 15 +#define SMEM_HOST_COUNT 20 /** * struct smem_proc_comm - proc_comm communication struct (legacy) @@ -1045,7 +1045,7 @@ static int qcom_smem_probe(struct platform_device *pdev) int i; num_regions = 1; - if (of_find_property(pdev->dev.of_node, "qcom,rpm-msg-ram", NULL)) + if (of_property_present(pdev->dev.of_node, "qcom,rpm-msg-ram")) num_regions++; array_size = num_regions * sizeof(struct smem_region); diff --git a/drivers/soc/qcom/smsm.c b/drivers/soc/qcom/smsm.c index 3e8994d6110e..c58cfff64856 100644 --- a/drivers/soc/qcom/smsm.c +++ b/drivers/soc/qcom/smsm.c @@ -452,11 +452,10 @@ static int smsm_get_size_info(struct qcom_smsm *smsm) } *info; info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_SMSM_SIZE_INFO, &size); - if (IS_ERR(info) && PTR_ERR(info) != -ENOENT) { - if (PTR_ERR(info) != -EPROBE_DEFER) - dev_err(smsm->dev, "unable to retrieve smsm size info\n"); - return PTR_ERR(info); - } else if (IS_ERR(info) || size != sizeof(*info)) { + if (IS_ERR(info) && PTR_ERR(info) != -ENOENT) + return dev_err_probe(smsm->dev, PTR_ERR(info), + "unable to retrieve smsm size info\n"); + else if (IS_ERR(info) || size != sizeof(*info)) { dev_warn(smsm->dev, "no smsm size info, using defaults\n"); smsm->num_entries = SMSM_DEFAULT_NUM_ENTRIES; smsm->num_hosts = SMSM_DEFAULT_NUM_HOSTS; @@ -510,7 +509,7 @@ static int qcom_smsm_probe(struct platform_device *pdev) return -ENOMEM; for_each_child_of_node(pdev->dev.of_node, local_node) { - if (of_find_property(local_node, "#qcom,smem-state-cells", NULL)) + if (of_property_present(local_node, "#qcom,smem-state-cells")) break; } if (!local_node) { diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index e9012ca1a87b..c2e4a57dd666 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -109,15 +109,20 @@ static const char *const pmic_models[] = { [32] = "PM8150B", [33] = "PMK8002", [36] = "PM8009", + [37] = "PMI632", [38] = "PM8150C", + [40] = "PM6150", [41] = "SMB2351", + [44] = "PM8008", [45] = "PM6125", + [46] = "PM7250B", [47] = "PMK8350", [48] = "PM8350", [49] = "PM8350C", [50] = "PM8350B", [51] = "PMR735A", [52] = "PMR735B", + [55] = "PM2250", [58] = "PM8450", [65] = "PM8010", }; @@ -405,6 +410,7 @@ static const struct soc_id soc_id[] = { { qcom_board_id(SA8155) }, { qcom_board_id(SDA439) }, { qcom_board_id(SDA429) }, + { qcom_board_id(SM7150) }, { qcom_board_id(IPQ8070) }, { qcom_board_id(IPQ8071) }, { qcom_board_id(QM215) }, @@ -426,6 +432,7 @@ static const struct soc_id soc_id[] = { { qcom_board_id(QCM2150) }, { qcom_board_id(SDA429W) }, { qcom_board_id(SM8350) }, + { qcom_board_id(QCM2290) }, { qcom_board_id(SM6115) }, { qcom_board_id(SC8280XP) }, { qcom_board_id(IPQ6005) }, @@ -441,7 +448,16 @@ static const struct soc_id soc_id[] = { { qcom_board_id(SC7280) }, { qcom_board_id(SC7180P) }, { qcom_board_id(SM6375) }, + { qcom_board_id(IPQ9514) }, + { qcom_board_id(IPQ9550) }, + { qcom_board_id(IPQ9554) }, + { qcom_board_id(IPQ9570) }, + { qcom_board_id(IPQ9574) }, { qcom_board_id(SM8550) }, + { qcom_board_id(IPQ9510) }, + { qcom_board_id(QRB4210) }, + { qcom_board_id(QRB2210) }, + { qcom_board_id(SA8775P) }, { qcom_board_id(QRU1000) }, { qcom_board_id(QDU1000) }, { qcom_board_id(QDU1010) }, diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig index 4e8b51ba2266..de31589ed054 100644 --- a/drivers/soc/renesas/Kconfig +++ b/drivers/soc/renesas/Kconfig @@ -206,13 +206,6 @@ config ARCH_R8A77990 This enables support for the Renesas R-Car E3 SoC. This includes different gradings like R-Car E3e. -config ARCH_R8A77950 - bool "ARM64 Platform support for R-Car H3 ES1.x" - select ARCH_RCAR_GEN3 - select SYSC_R8A7795 - help - This enables support for the Renesas R-Car H3 SoC (revision 1.x). - config ARCH_R8A77951 bool "ARM64 Platform support for R-Car H3 ES2.0+" select ARCH_RCAR_GEN3 diff --git a/drivers/soc/renesas/pwc-rzv2m.c b/drivers/soc/renesas/pwc-rzv2m.c index c83bdbdabb64..452cee8d68be 100644 --- a/drivers/soc/renesas/pwc-rzv2m.c +++ b/drivers/soc/renesas/pwc-rzv2m.c @@ -131,7 +131,7 @@ static struct platform_driver rzv2m_pwc_driver = { .probe = rzv2m_pwc_probe, .driver = { .name = "rzv2m_pwc", - .of_match_table = of_match_ptr(rzv2m_pwc_of_match), + .of_match_table = rzv2m_pwc_of_match, }, }; module_platform_driver(rzv2m_pwc_driver); diff --git a/drivers/soc/renesas/r8a7795-sysc.c b/drivers/soc/renesas/r8a7795-sysc.c index 91074411b8cf..cbe1ff0fc583 100644 --- a/drivers/soc/renesas/r8a7795-sysc.c +++ b/drivers/soc/renesas/r8a7795-sysc.c @@ -38,8 +38,6 @@ static struct rcar_sysc_area r8a7795_areas[] __initdata = { { "a3vp", 0x340, 0, R8A7795_PD_A3VP, R8A7795_PD_ALWAYS_ON }, { "cr7", 0x240, 0, R8A7795_PD_CR7, R8A7795_PD_ALWAYS_ON }, { "a3vc", 0x380, 0, R8A7795_PD_A3VC, R8A7795_PD_ALWAYS_ON }, - /* A2VC0 exists on ES1.x only */ - { "a2vc0", 0x3c0, 0, R8A7795_PD_A2VC0, R8A7795_PD_A3VC }, { "a2vc1", 0x3c0, 1, R8A7795_PD_A2VC1, R8A7795_PD_A3VC }, { "3dg-a", 0x100, 0, R8A7795_PD_3DG_A, R8A7795_PD_ALWAYS_ON }, { "3dg-b", 0x100, 1, R8A7795_PD_3DG_B, R8A7795_PD_3DG_A }, @@ -54,14 +52,10 @@ static struct rcar_sysc_area r8a7795_areas[] __initdata = { * Fixups for R-Car H3 revisions */ -#define HAS_A2VC0 BIT(0) /* Power domain A2VC0 is present */ #define NO_EXTMASK BIT(1) /* Missing SYSCEXTMASK register */ static const struct soc_device_attribute r8a7795_quirks_match[] __initconst = { { - .soc_id = "r8a7795", .revision = "ES1.*", - .data = (void *)(HAS_A2VC0 | NO_EXTMASK), - }, { .soc_id = "r8a7795", .revision = "ES2.*", .data = (void *)(NO_EXTMASK), }, @@ -77,10 +71,6 @@ static int __init r8a7795_sysc_init(void) if (attr) quirks = (uintptr_t)attr->data; - if (!(quirks & HAS_A2VC0)) - rcar_sysc_nullify(r8a7795_areas, ARRAY_SIZE(r8a7795_areas), - R8A7795_PD_A2VC0); - if (quirks & NO_EXTMASK) r8a7795_sysc_info.extmask_val = 0; diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c index 468ebce1ea88..42af7c09f743 100644 --- a/drivers/soc/renesas/renesas-soc.c +++ b/drivers/soc/renesas/renesas-soc.c @@ -269,7 +269,7 @@ static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = { }; -static const struct of_device_id renesas_socs[] __initconst = { +static const struct of_device_id renesas_socs[] __initconst __maybe_unused = { #ifdef CONFIG_ARCH_R7S72100 { .compatible = "renesas,r7s72100", .data = &soc_rz_a1h }, #endif @@ -330,10 +330,8 @@ static const struct of_device_id renesas_socs[] __initconst = { #ifdef CONFIG_ARCH_R8A7794 { .compatible = "renesas,r8a7794", .data = &soc_rcar_e2 }, #endif -#if defined(CONFIG_ARCH_R8A77950) || defined(CONFIG_ARCH_R8A77951) - { .compatible = "renesas,r8a7795", .data = &soc_rcar_h3 }, -#endif #ifdef CONFIG_ARCH_R8A77951 + { .compatible = "renesas,r8a7795", .data = &soc_rcar_h3 }, { .compatible = "renesas,r8a779m0", .data = &soc_rcar_h3 }, { .compatible = "renesas,r8a779m1", .data = &soc_rcar_h3 }, { .compatible = "renesas,r8a779m8", .data = &soc_rcar_h3 }, @@ -375,20 +373,20 @@ static const struct of_device_id renesas_socs[] __initconst = { #ifdef CONFIG_ARCH_R8A779G0 { .compatible = "renesas,r8a779g0", .data = &soc_rcar_v4h }, #endif -#if defined(CONFIG_ARCH_R9A07G043) +#ifdef CONFIG_ARCH_R9A07G043 #ifdef CONFIG_RISCV { .compatible = "renesas,r9a07g043", .data = &soc_rz_five }, #else { .compatible = "renesas,r9a07g043", .data = &soc_rz_g2ul }, #endif #endif -#if defined(CONFIG_ARCH_R9A07G044) +#ifdef CONFIG_ARCH_R9A07G044 { .compatible = "renesas,r9a07g044", .data = &soc_rz_g2l }, #endif -#if defined(CONFIG_ARCH_R9A07G054) +#ifdef CONFIG_ARCH_R9A07G054 { .compatible = "renesas,r9a07g054", .data = &soc_rz_v2l }, #endif -#if defined(CONFIG_ARCH_R9A09G011) +#ifdef CONFIG_ARCH_R9A09G011 { .compatible = "renesas,r9a09g011", .data = &soc_rz_v2m }, #endif #ifdef CONFIG_ARCH_SH73A0 @@ -471,8 +469,11 @@ static int __init renesas_soc_init(void) } soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); - if (!soc_dev_attr) + if (!soc_dev_attr) { + if (chipid) + iounmap(chipid); return -ENOMEM; + } np = of_find_node_by_path("/"); of_property_read_string(np, "model", &soc_dev_attr->machine); diff --git a/drivers/soc/renesas/rmobile-sysc.c b/drivers/soc/renesas/rmobile-sysc.c index 204e6135180b..728ebac98e14 100644 --- a/drivers/soc/renesas/rmobile-sysc.c +++ b/drivers/soc/renesas/rmobile-sysc.c @@ -343,7 +343,7 @@ static int __init rmobile_init_pm_domains(void) break; } - fwnode_dev_initialized(&np->fwnode, true); + fwnode_dev_initialized(of_fwnode_handle(np), true); } put_special_pds(); diff --git a/drivers/soc/sunxi/sunxi_mbus.c b/drivers/soc/sunxi/sunxi_mbus.c index d90e4a264b6f..1734da357ca2 100644 --- a/drivers/soc/sunxi/sunxi_mbus.c +++ b/drivers/soc/sunxi/sunxi_mbus.c @@ -82,7 +82,7 @@ static int sunxi_mbus_notifier(struct notifier_block *nb, * Older DTs or SoCs who are not clearly understood need to set * that DMA offset though. */ - if (of_find_property(dev->of_node, "interconnects", NULL)) + if (of_property_present(dev->of_node, "interconnects")) return NOTIFY_DONE; ret = dma_direct_set_offset(dev, PHYS_OFFSET, 0, SZ_4G); diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c index f09918c59042..4c4864cd2342 100644 --- a/drivers/soc/sunxi/sunxi_sram.c +++ b/drivers/soc/sunxi/sunxi_sram.c @@ -424,4 +424,3 @@ builtin_platform_driver_probe(sunxi_sram_driver, sunxi_sram_probe); MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); MODULE_DESCRIPTION("Allwinner sunXi SRAM Controller Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/soc/tegra/cbb/tegra-cbb.c b/drivers/soc/tegra/cbb/tegra-cbb.c index a8566b9dd8de..bd96204a68ee 100644 --- a/drivers/soc/tegra/cbb/tegra-cbb.c +++ b/drivers/soc/tegra/cbb/tegra-cbb.c @@ -16,7 +16,6 @@ #include <linux/of_address.h> #include <linux/interrupt.h> #include <linux/ioport.h> -#include <linux/version.h> #include <soc/tegra/fuse.h> #include <soc/tegra/tegra-cbb.h> diff --git a/drivers/soc/tegra/cbb/tegra194-cbb.c b/drivers/soc/tegra/cbb/tegra194-cbb.c index d4112b683f00..54d7ce05c636 100644 --- a/drivers/soc/tegra/cbb/tegra194-cbb.c +++ b/drivers/soc/tegra/cbb/tegra194-cbb.c @@ -23,7 +23,6 @@ #include <linux/of_address.h> #include <linux/interrupt.h> #include <linux/ioport.h> -#include <linux/version.h> #include <soc/tegra/fuse.h> #include <soc/tegra/tegra-cbb.h> @@ -2191,7 +2190,6 @@ MODULE_DEVICE_TABLE(of, tegra194_cbb_match); static int tegra194_cbb_get_bridges(struct tegra194_cbb *cbb, struct device_node *np) { struct tegra_cbb *entry; - struct resource res; unsigned long flags; unsigned int i; int err; @@ -2211,8 +2209,7 @@ static int tegra194_cbb_get_bridges(struct tegra194_cbb *cbb, struct device_node spin_unlock_irqrestore(&cbb_lock, flags); if (!cbb->bridges) { - while (of_address_to_resource(np, cbb->num_bridges, &res) == 0) - cbb->num_bridges++; + cbb->num_bridges = of_address_count(np); cbb->bridges = devm_kcalloc(cbb->base.dev, cbb->num_bridges, sizeof(*cbb->bridges), GFP_KERNEL); @@ -2359,4 +2356,3 @@ module_exit(tegra194_cbb_exit); MODULE_AUTHOR("Sumit Gupta <sumitg@nvidia.com>"); MODULE_DESCRIPTION("Control Backbone error handling driver for Tegra194"); -MODULE_LICENSE("GPL"); diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c index f33d094e5ea6..5d16161b2566 100644 --- a/drivers/soc/tegra/cbb/tegra234-cbb.c +++ b/drivers/soc/tegra/cbb/tegra234-cbb.c @@ -24,7 +24,6 @@ #include <linux/of_address.h> #include <linux/interrupt.h> #include <linux/ioport.h> -#include <linux/version.h> #include <soc/tegra/fuse.h> #include <soc/tegra/tegra-cbb.h> @@ -1174,11 +1173,6 @@ static int tegra234_cbb_probe(struct platform_device *pdev) return tegra_cbb_register(&cbb->base); } -static int tegra234_cbb_remove(struct platform_device *pdev) -{ - return 0; -} - static int __maybe_unused tegra234_cbb_resume_noirq(struct device *dev) { struct tegra234_cbb *cbb = dev_get_drvdata(dev); @@ -1196,7 +1190,6 @@ static const struct dev_pm_ops tegra234_cbb_pm = { static struct platform_driver tegra234_cbb_driver = { .probe = tegra234_cbb_probe, - .remove = tegra234_cbb_remove, .driver = { .name = "tegra234-cbb", .of_match_table = tegra234_cbb_dt_ids, @@ -1218,4 +1211,3 @@ static void __exit tegra234_cbb_exit(void) module_exit(tegra234_cbb_exit); MODULE_DESCRIPTION("Control Backbone 2.0 error handling driver for Tegra234"); -MODULE_LICENSE("GPL"); diff --git a/drivers/soc/tegra/flowctrl.c b/drivers/soc/tegra/flowctrl.c index 5db919d96aba..221202db3313 100644 --- a/drivers/soc/tegra/flowctrl.c +++ b/drivers/soc/tegra/flowctrl.c @@ -156,10 +156,8 @@ void flowctrl_cpu_suspend_exit(unsigned int cpuid) static int tegra_flowctrl_probe(struct platform_device *pdev) { void __iomem *base = tegra_flowctrl_base; - struct resource *res; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - tegra_flowctrl_base = devm_ioremap_resource(&pdev->dev, res); + tegra_flowctrl_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(tegra_flowctrl_base)) return PTR_ERR(tegra_flowctrl_base); diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index f02953f793e9..d7a37f5d4527 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2013-2022, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2023, NVIDIA CORPORATION. All rights reserved. */ #include <linux/clk.h> @@ -166,7 +166,7 @@ static int tegra_fuse_probe(struct platform_device *pdev) nvmem.nkeepout = fuse->soc->num_keepouts; nvmem.type = NVMEM_TYPE_OTP; nvmem.read_only = true; - nvmem.root_only = true; + nvmem.root_only = false; nvmem.reg_read = tegra_fuse_read; nvmem.size = fuse->soc->info->size; nvmem.word_size = 4; diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index cf4cfbf9f7c5..5d17799524c9 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -3,7 +3,7 @@ * drivers/soc/tegra/pmc.c * * Copyright (c) 2010 Google, Inc - * Copyright (c) 2018-2022, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. * * Author: * Colin Cross <ccross@google.com> @@ -177,6 +177,7 @@ /* Tegra186 and later */ #define WAKE_AOWAKE_CNTRL(x) (0x000 + ((x) << 2)) #define WAKE_AOWAKE_CNTRL_LEVEL (1 << 3) +#define WAKE_AOWAKE_CNTRL_SR_CAPTURE_EN (1 << 1) #define WAKE_AOWAKE_MASK_W(x) (0x180 + ((x) << 2)) #define WAKE_AOWAKE_MASK_R(x) (0x300 + ((x) << 2)) #define WAKE_AOWAKE_STATUS_W(x) (0x30c + ((x) << 2)) @@ -191,6 +192,8 @@ #define WAKE_AOWAKE_CTRL 0x4f4 #define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0) +#define SW_WAKE_ID 83 /* wake83 */ + /* for secure PMC */ #define TEGRA_SMC_PMC 0xc2fffe00 #define TEGRA_SMC_PMC_READ 0xaa @@ -355,6 +358,7 @@ struct tegra_pmc_soc { void (*setup_irq_polarity)(struct tegra_pmc *pmc, struct device_node *np, bool invert); + void (*set_wake_filters)(struct tegra_pmc *pmc); int (*irq_set_wake)(struct irq_data *data, unsigned int on); int (*irq_set_type)(struct irq_data *data, unsigned int type); int (*powergate_set)(struct tegra_pmc *pmc, unsigned int id, @@ -2416,6 +2420,17 @@ static int tegra210_pmc_irq_set_type(struct irq_data *data, unsigned int type) return 0; } +static void tegra186_pmc_set_wake_filters(struct tegra_pmc *pmc) +{ + u32 value; + + /* SW Wake (wake83) needs SR_CAPTURE filter to be enabled */ + value = readl(pmc->wake + WAKE_AOWAKE_CNTRL(SW_WAKE_ID)); + value |= WAKE_AOWAKE_CNTRL_SR_CAPTURE_EN; + writel(value, pmc->wake + WAKE_AOWAKE_CNTRL(SW_WAKE_ID)); + dev_dbg(pmc->dev, "WAKE_AOWAKE_CNTRL_83 = 0x%x\n", value); +} + static int tegra186_pmc_irq_set_wake(struct irq_data *data, unsigned int on) { struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data); @@ -3042,6 +3057,10 @@ static int tegra_pmc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pmc); tegra_pm_init_suspend(); + /* Some wakes require specific filter configuration */ + if (pmc->soc->set_wake_filters) + pmc->soc->set_wake_filters(pmc); + return 0; cleanup_powergates: @@ -3938,6 +3957,7 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = { .regs = &tegra186_pmc_regs, .init = tegra186_pmc_init, .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, + .set_wake_filters = tegra186_pmc_set_wake_filters, .irq_set_wake = tegra186_pmc_irq_set_wake, .irq_set_type = tegra186_pmc_irq_set_type, .reset_sources = tegra186_reset_sources, @@ -4122,6 +4142,7 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = { .regs = &tegra194_pmc_regs, .init = tegra186_pmc_init, .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, + .set_wake_filters = tegra186_pmc_set_wake_filters, .irq_set_wake = tegra186_pmc_irq_set_wake, .irq_set_type = tegra186_pmc_irq_set_type, .reset_sources = tegra194_reset_sources, @@ -4225,7 +4246,9 @@ static const char * const tegra234_reset_sources[] = { }; static const struct tegra_wake_event tegra234_wake_events[] = { + TEGRA_WAKE_IRQ("pmu", 24, 209), TEGRA_WAKE_GPIO("power", 29, 1, TEGRA234_AON_GPIO(EE, 4)), + TEGRA_WAKE_GPIO("mgbe", 56, 0, TEGRA234_MAIN_GPIO(Y, 3)), TEGRA_WAKE_IRQ("rtc", 73, 10), }; @@ -4247,6 +4270,7 @@ static const struct tegra_pmc_soc tegra234_pmc_soc = { .regs = &tegra234_pmc_regs, .init = tegra186_pmc_init, .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, + .set_wake_filters = tegra186_pmc_set_wake_filters, .irq_set_wake = tegra186_pmc_irq_set_wake, .irq_set_type = tegra186_pmc_irq_set_type, .reset_sources = tegra234_reset_sources, diff --git a/drivers/soc/tegra/powergate-bpmp.c b/drivers/soc/tegra/powergate-bpmp.c index 8eaf50d0b6af..179ed895c279 100644 --- a/drivers/soc/tegra/powergate-bpmp.c +++ b/drivers/soc/tegra/powergate-bpmp.c @@ -286,7 +286,7 @@ remove: tegra_powergate_remove(powergate); } - kfree(genpd->domains); + kfree(domains); return err; } diff --git a/drivers/soc/ti/k3-ringacc.c b/drivers/soc/ti/k3-ringacc.c index e01e4d815230..8f131368a758 100644 --- a/drivers/soc/ti/k3-ringacc.c +++ b/drivers/soc/ti/k3-ringacc.c @@ -406,6 +406,11 @@ static int k3_dmaring_request_dual_ring(struct k3_ringacc *ringacc, int fwd_id, mutex_lock(&ringacc->req_lock); + if (!try_module_get(ringacc->dev->driver->owner)) { + ret = -EINVAL; + goto err_module_get; + } + if (test_bit(fwd_id, ringacc->rings_inuse)) { ret = -EBUSY; goto error; @@ -421,6 +426,8 @@ static int k3_dmaring_request_dual_ring(struct k3_ringacc *ringacc, int fwd_id, return 0; error: + module_put(ringacc->dev->driver->owner); +err_module_get: mutex_unlock(&ringacc->req_lock); return ret; } diff --git a/drivers/soc/ti/k3-socinfo.c b/drivers/soc/ti/k3-socinfo.c index d15764e19d96..ad97e08a25f6 100644 --- a/drivers/soc/ti/k3-socinfo.c +++ b/drivers/soc/ti/k3-socinfo.c @@ -43,6 +43,7 @@ static const struct k3_soc_id { { 0xBB38, "AM64X" }, { 0xBB75, "J721S2"}, { 0xBB7E, "AM62X" }, + { 0xBB80, "J784S4" }, { 0xBB8D, "AM62AX" }, }; diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c index 84afebd355be..0fbc37cd5123 100644 --- a/drivers/soc/ti/knav_dma.c +++ b/drivers/soc/ti/knav_dma.c @@ -666,8 +666,8 @@ static int dma_init(struct device_node *cloud, struct device_node *dma_node) dma->rx_priority = DMA_PRIO_DEFAULT; dma->tx_priority = DMA_PRIO_DEFAULT; - dma->enable_all = (of_get_property(node, "ti,enable-all", NULL) != NULL); - dma->loopback = (of_get_property(node, "ti,loop-back", NULL) != NULL); + dma->enable_all = of_property_read_bool(node, "ti,enable-all"); + dma->loopback = of_property_read_bool(node, "ti,loop-back"); ret = of_property_read_u32(node, "ti,rx-retry-timeout", &timeout); if (ret < 0) { diff --git a/drivers/soc/ti/knav_qmss_acc.c b/drivers/soc/ti/knav_qmss_acc.c index fde66e28e046..3d388646ed43 100644 --- a/drivers/soc/ti/knav_qmss_acc.c +++ b/drivers/soc/ti/knav_qmss_acc.c @@ -521,7 +521,7 @@ int knav_init_acc_range(struct knav_device *kdev, info->pdsp = pdsp; channels = range->num_queues; - if (of_get_property(node, "multi-queue", NULL)) { + if (of_property_read_bool(node, "multi-queue")) { range->flags |= RANGE_MULTI_QUEUE; channels = 1; if (range->queue_base & (32 - 1)) { diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index 8fb76908be70..0f252c2549ba 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -1264,10 +1264,10 @@ static int knav_setup_queue_range(struct knav_device *kdev, if (range->num_irqs) range->flags |= RANGE_HAS_IRQ; - if (of_get_property(node, "qalloc-by-id", NULL)) + if (of_property_read_bool(node, "qalloc-by-id")) range->flags |= RANGE_RESERVED; - if (of_get_property(node, "accumulator", NULL)) { + if (of_property_present(node, "accumulator")) { ret = knav_init_acc_range(kdev, node, range); if (ret < 0) { devm_kfree(dev, range); diff --git a/drivers/soc/ti/omap_prm.c b/drivers/soc/ti/omap_prm.c index 913b964374a4..ecd9a8bdd7c0 100644 --- a/drivers/soc/ti/omap_prm.c +++ b/drivers/soc/ti/omap_prm.c @@ -684,7 +684,7 @@ static int omap_prm_domain_init(struct device *dev, struct omap_prm *prm) const char *name; int error; - if (!of_find_property(dev->of_node, "#power-domain-cells", NULL)) + if (!of_property_present(dev->of_node, "#power-domain-cells")) return 0; of_node_put(dev->of_node); diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c index ce09c42eaed2..f04c21157904 100644 --- a/drivers/soc/ti/pm33xx.c +++ b/drivers/soc/ti/pm33xx.c @@ -527,7 +527,7 @@ static int am33xx_pm_probe(struct platform_device *pdev) ret = am33xx_pm_alloc_sram(); if (ret) - return ret; + goto err_wkup_m3_ipc_put; ret = am33xx_pm_rtc_setup(); if (ret) @@ -572,13 +572,14 @@ err_pm_runtime_put: pm_runtime_put_sync(dev); err_pm_runtime_disable: pm_runtime_disable(dev); - wkup_m3_ipc_put(m3_ipc); err_unsetup_rtc: iounmap(rtc_base_virt); clk_put(rtc_fck); err_free_sram: am33xx_pm_free_sram(); pm33xx_dev = NULL; +err_wkup_m3_ipc_put: + wkup_m3_ipc_put(m3_ipc); return ret; } diff --git a/drivers/soc/ti/smartreflex.c b/drivers/soc/ti/smartreflex.c index 9d9496e0a94c..da7898239a46 100644 --- a/drivers/soc/ti/smartreflex.c +++ b/drivers/soc/ti/smartreflex.c @@ -937,21 +937,8 @@ err_list_del: static int omap_sr_remove(struct platform_device *pdev) { - struct omap_sr_data *pdata = pdev->dev.platform_data; struct device *dev = &pdev->dev; - struct omap_sr *sr_info; - - if (!pdata) { - dev_err(&pdev->dev, "%s: platform data missing\n", __func__); - return -EINVAL; - } - - sr_info = _sr_lookup(pdata->voltdm); - if (IS_ERR(sr_info)) { - dev_warn(&pdev->dev, "%s: omap_sr struct not found\n", - __func__); - return PTR_ERR(sr_info); - } + struct omap_sr *sr_info = platform_get_drvdata(pdev); if (sr_info->autocomp_active) sr_stop_vddautocomp(sr_info); @@ -965,20 +952,7 @@ static int omap_sr_remove(struct platform_device *pdev) static void omap_sr_shutdown(struct platform_device *pdev) { - struct omap_sr_data *pdata = pdev->dev.platform_data; - struct omap_sr *sr_info; - - if (!pdata) { - dev_err(&pdev->dev, "%s: platform data missing\n", __func__); - return; - } - - sr_info = _sr_lookup(pdata->voltdm); - if (IS_ERR(sr_info)) { - dev_warn(&pdev->dev, "%s: omap_sr struct not found\n", - __func__); - return; - } + struct omap_sr *sr_info = platform_get_drvdata(pdev); if (sr_info->autocomp_active) sr_stop_vddautocomp(sr_info); diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index 343c58ed5896..c9197912ec24 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -615,7 +615,6 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev) int irq, ret, temp; phandle rproc_phandle; struct rproc *m3_rproc; - struct resource *res; struct task_struct *task; struct wkup_m3_ipc *m3_ipc; struct device_node *np = dev->of_node; @@ -624,8 +623,7 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev) if (!m3_ipc) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - m3_ipc->ipc_mem_base = devm_ioremap_resource(dev, res); + m3_ipc->ipc_mem_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(m3_ipc->ipc_mem_base)) return PTR_ERR(m3_ipc->ipc_mem_base); @@ -681,7 +679,7 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev) dev_warn(dev, "Invalid VTT GPIO(%d) pin\n", temp); } - if (of_find_property(np, "ti,set-io-isolation", NULL)) + if (of_property_read_bool(np, "ti,set-io-isolation")) wkup_m3_set_io_isolation(m3_ipc); ret = of_property_read_string(np, "firmware-name", diff --git a/drivers/spi/spi-rockchip-sfc.c b/drivers/spi/spi-rockchip-sfc.c index bd87d3c92dd3..69347b6bf60c 100644 --- a/drivers/spi/spi-rockchip-sfc.c +++ b/drivers/spi/spi-rockchip-sfc.c @@ -632,7 +632,7 @@ static int rockchip_sfc_probe(struct platform_device *pdev) if (ret) { dev_err(dev, "Failed to request irq\n"); - return ret; + goto err_irq; } ret = rockchip_sfc_init(sfc); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 44b85a8d47f1..7bc14fb309a6 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -4456,6 +4456,11 @@ static int of_spi_notify(struct notifier_block *nb, unsigned long action, return NOTIFY_OK; } + /* + * Clear the flag before adding the device so that fw_devlink + * doesn't skip adding consumers to this device. + */ + rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE; spi = of_register_spi_device(ctlr, rd->dn); put_device(&ctlr->dev); diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig index f121c224e682..70898bbd5809 100644 --- a/drivers/tee/optee/Kconfig +++ b/drivers/tee/optee/Kconfig @@ -7,3 +7,20 @@ config OPTEE help This implements the OP-TEE Trusted Execution Environment (TEE) driver. + +config OPTEE_INSECURE_LOAD_IMAGE + bool "Load OP-TEE image as firmware" + default n + depends on OPTEE && ARM64 + help + This loads the BL32 image for OP-TEE as firmware when the driver is + probed. This returns -EPROBE_DEFER until the firmware is loadable from + the filesystem which is determined by checking the system_state until + it is in SYSTEM_RUNNING. This also requires enabling the corresponding + option in Trusted Firmware for Arm. The documentation there explains + the security threat associated with enabling this as well as + mitigations at the firmware and platform level. + https://trustedfirmware-a.readthedocs.io/en/latest/threat_model/threat_model.html + + Additional documentation on kernel security risks are at + Documentation/staging/tee.rst. diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c index 290b1bb0e9cd..df5fb5410b72 100644 --- a/drivers/tee/optee/call.c +++ b/drivers/tee/optee/call.c @@ -488,7 +488,7 @@ static bool is_normal_memory(pgprot_t p) #elif defined(CONFIG_ARM64) return (pgprot_val(p) & PTE_ATTRINDX_MASK) == PTE_ATTRINDX(MT_NORMAL); #else -#error "Unuspported architecture" +#error "Unsupported architecture" #endif } diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h index 70e9cc2ee96b..e8840a82b983 100644 --- a/drivers/tee/optee/optee_msg.h +++ b/drivers/tee/optee/optee_msg.h @@ -241,11 +241,23 @@ struct optee_msg_arg { * 384fb3e0-e7f8-11e3-af63-0002a5d5c51b. * Represented in 4 32-bit words in OPTEE_MSG_UID_0, OPTEE_MSG_UID_1, * OPTEE_MSG_UID_2, OPTEE_MSG_UID_3. + * + * In the case where the OP-TEE image is loaded by the kernel, this will + * initially return an alternate UID to reflect that we are communicating with + * the TF-A image loading service at that time instead of OP-TEE. That UID is: + * a3fbeab1-1246-315d-c7c4-06b9c03cbea4. + * Represented in 4 32-bit words in OPTEE_MSG_IMAGE_LOAD_UID_0, + * OPTEE_MSG_IMAGE_LOAD_UID_1, OPTEE_MSG_IMAGE_LOAD_UID_2, + * OPTEE_MSG_IMAGE_LOAD_UID_3. */ #define OPTEE_MSG_UID_0 0x384fb3e0 #define OPTEE_MSG_UID_1 0xe7f811e3 #define OPTEE_MSG_UID_2 0xaf630002 #define OPTEE_MSG_UID_3 0xa5d5c51b +#define OPTEE_MSG_IMAGE_LOAD_UID_0 0xa3fbeab1 +#define OPTEE_MSG_IMAGE_LOAD_UID_1 0x1246315d +#define OPTEE_MSG_IMAGE_LOAD_UID_2 0xc7c406b9 +#define OPTEE_MSG_IMAGE_LOAD_UID_3 0xc03cbea4 #define OPTEE_MSG_FUNCID_CALLS_UID 0xFF01 /* diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index 04ae58892608..72685ee0d53f 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h @@ -94,11 +94,35 @@ struct optee_supp { struct completion reqs_c; }; +/* + * struct optee_pcpu - per cpu notif private struct passed to work functions + * @optee optee device reference + */ +struct optee_pcpu { + struct optee *optee; +}; + +/* + * struct optee_smc - optee smc communication struct + * @invoke_fn handler function to invoke secure monitor + * @memremaped_shm virtual address of memory in shared memory pool + * @sec_caps: secure world capabilities defined by + * OPTEE_SMC_SEC_CAP_* in optee_smc.h + * @notif_irq interrupt used as async notification by OP-TEE or 0 + * @optee_pcpu per_cpu optee instance for per cpu work or NULL + * @notif_pcpu_wq workqueue for per cpu asynchronous notification or NULL + * @notif_pcpu_work work for per cpu asynchronous notification + * @notif_cpuhp_state CPU hotplug state assigned for pcpu interrupt management + */ struct optee_smc { optee_invoke_fn *invoke_fn; void *memremaped_shm; u32 sec_caps; unsigned int notif_irq; + struct optee_pcpu __percpu *optee_pcpu; + struct workqueue_struct *notif_pcpu_wq; + struct work_struct notif_pcpu_work; + unsigned int notif_cpuhp_state; }; /** diff --git a/drivers/tee/optee/optee_smc.h b/drivers/tee/optee/optee_smc.h index 73b5e7760d10..7d9fa426505b 100644 --- a/drivers/tee/optee/optee_smc.h +++ b/drivers/tee/optee/optee_smc.h @@ -105,6 +105,30 @@ struct optee_smc_call_get_os_revision_result { }; /* + * Load Trusted OS from optee/tee.bin in the Linux firmware. + * + * WARNING: Use this cautiously as it could lead to insecure loading of the + * Trusted OS. + * This SMC instructs EL3 to load a binary and execute it as the Trusted OS. + * + * Call register usage: + * a0 SMC Function ID, OPTEE_SMC_CALL_LOAD_IMAGE + * a1 Upper 32bit of a 64bit size for the payload + * a2 Lower 32bit of a 64bit size for the payload + * a3 Upper 32bit of the physical address for the payload + * a4 Lower 32bit of the physical address for the payload + * + * The payload is in the OP-TEE image format. + * + * Returns result in a0, 0 on success and an error code otherwise. + */ +#define OPTEE_SMC_FUNCID_LOAD_IMAGE 2 +#define OPTEE_SMC_CALL_LOAD_IMAGE \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_TRUSTED_OS_END, \ + OPTEE_SMC_FUNCID_LOAD_IMAGE) + +/* * Call with struct optee_msg_arg as argument * * When called with OPTEE_SMC_CALL_WITH_RPC_ARG or diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c index a1c1fa1a9c28..49702cb08f4f 100644 --- a/drivers/tee/optee/smc_abi.c +++ b/drivers/tee/optee/smc_abi.c @@ -7,10 +7,13 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/arm-smccc.h> +#include <linux/cpuhotplug.h> #include <linux/errno.h> +#include <linux/firmware.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/irqdomain.h> +#include <linux/kernel.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/of.h> @@ -52,6 +55,23 @@ */ #define OPTEE_MIN_STATIC_POOL_ALIGN 9 /* 512 bytes aligned */ +/* SMC ABI considers at most a single TEE firmware */ +static unsigned int pcpu_irq_num; + +static int optee_cpuhp_enable_pcpu_irq(unsigned int cpu) +{ + enable_percpu_irq(pcpu_irq_num, IRQ_TYPE_NONE); + + return 0; +} + +static int optee_cpuhp_disable_pcpu_irq(unsigned int cpu) +{ + disable_percpu_irq(pcpu_irq_num); + + return 0; +} + /* * 1. Convert between struct tee_param and struct optee_msg_param * @@ -991,9 +1011,8 @@ static u32 get_async_notif_value(optee_invoke_fn *invoke_fn, bool *value_valid, return res.a1; } -static irqreturn_t notif_irq_handler(int irq, void *dev_id) +static irqreturn_t irq_handler(struct optee *optee) { - struct optee *optee = dev_id; bool do_bottom_half = false; bool value_valid; bool value_pending; @@ -1016,6 +1035,13 @@ static irqreturn_t notif_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t notif_irq_handler(int irq, void *dev_id) +{ + struct optee *optee = dev_id; + + return irq_handler(optee); +} + static irqreturn_t notif_irq_thread_fn(int irq, void *dev_id) { struct optee *optee = dev_id; @@ -1025,7 +1051,7 @@ static irqreturn_t notif_irq_thread_fn(int irq, void *dev_id) return IRQ_HANDLED; } -static int optee_smc_notif_init_irq(struct optee *optee, u_int irq) +static int init_irq(struct optee *optee, u_int irq) { int rc; @@ -1040,12 +1066,103 @@ static int optee_smc_notif_init_irq(struct optee *optee, u_int irq) return 0; } +static irqreturn_t notif_pcpu_irq_handler(int irq, void *dev_id) +{ + struct optee_pcpu *pcpu = dev_id; + struct optee *optee = pcpu->optee; + + if (irq_handler(optee) == IRQ_WAKE_THREAD) + queue_work(optee->smc.notif_pcpu_wq, + &optee->smc.notif_pcpu_work); + + return IRQ_HANDLED; +} + +static void notif_pcpu_irq_work_fn(struct work_struct *work) +{ + struct optee_smc *optee_smc = container_of(work, struct optee_smc, + notif_pcpu_work); + struct optee *optee = container_of(optee_smc, struct optee, smc); + + optee_smc_do_bottom_half(optee->ctx); +} + +static int init_pcpu_irq(struct optee *optee, u_int irq) +{ + struct optee_pcpu __percpu *optee_pcpu; + int cpu, rc; + + optee_pcpu = alloc_percpu(struct optee_pcpu); + if (!optee_pcpu) + return -ENOMEM; + + for_each_present_cpu(cpu) + per_cpu_ptr(optee_pcpu, cpu)->optee = optee; + + rc = request_percpu_irq(irq, notif_pcpu_irq_handler, + "optee_pcpu_notification", optee_pcpu); + if (rc) + goto err_free_pcpu; + + INIT_WORK(&optee->smc.notif_pcpu_work, notif_pcpu_irq_work_fn); + optee->smc.notif_pcpu_wq = create_workqueue("optee_pcpu_notification"); + if (!optee->smc.notif_pcpu_wq) { + rc = -EINVAL; + goto err_free_pcpu_irq; + } + + optee->smc.optee_pcpu = optee_pcpu; + optee->smc.notif_irq = irq; + + pcpu_irq_num = irq; + rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "optee/pcpu-notif:starting", + optee_cpuhp_enable_pcpu_irq, + optee_cpuhp_disable_pcpu_irq); + if (!rc) + rc = -EINVAL; + if (rc < 0) + goto err_free_pcpu_irq; + + optee->smc.notif_cpuhp_state = rc; + + return 0; + +err_free_pcpu_irq: + free_percpu_irq(irq, optee_pcpu); +err_free_pcpu: + free_percpu(optee_pcpu); + + return rc; +} + +static int optee_smc_notif_init_irq(struct optee *optee, u_int irq) +{ + if (irq_is_percpu_devid(irq)) + return init_pcpu_irq(optee, irq); + else + return init_irq(optee, irq); +} + +static void uninit_pcpu_irq(struct optee *optee) +{ + cpuhp_remove_state(optee->smc.notif_cpuhp_state); + + destroy_workqueue(optee->smc.notif_pcpu_wq); + + free_percpu_irq(optee->smc.notif_irq, optee->smc.optee_pcpu); + free_percpu(optee->smc.optee_pcpu); +} + static void optee_smc_notif_uninit_irq(struct optee *optee) { if (optee->smc.sec_caps & OPTEE_SMC_SEC_CAP_ASYNC_NOTIF) { optee_smc_stop_async_notif(optee->ctx); if (optee->smc.notif_irq) { - free_irq(optee->smc.notif_irq, optee); + if (irq_is_percpu_devid(optee->smc.notif_irq)) + uninit_pcpu_irq(optee); + else + free_irq(optee->smc.notif_irq, optee); + irq_dispose_mapping(optee->smc.notif_irq); } } @@ -1149,6 +1266,22 @@ static bool optee_msg_api_uid_is_optee_api(optee_invoke_fn *invoke_fn) return false; } +#ifdef CONFIG_OPTEE_INSECURE_LOAD_IMAGE +static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn) +{ + struct arm_smccc_res res; + + invoke_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &res); + + if (res.a0 == OPTEE_MSG_IMAGE_LOAD_UID_0 && + res.a1 == OPTEE_MSG_IMAGE_LOAD_UID_1 && + res.a2 == OPTEE_MSG_IMAGE_LOAD_UID_2 && + res.a3 == OPTEE_MSG_IMAGE_LOAD_UID_3) + return true; + return false; +} +#endif + static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn) { union { @@ -1354,6 +1487,120 @@ static void optee_shutdown(struct platform_device *pdev) optee_disable_shm_cache(optee); } +#ifdef CONFIG_OPTEE_INSECURE_LOAD_IMAGE + +#define OPTEE_FW_IMAGE "optee/tee.bin" + +static optee_invoke_fn *cpuhp_invoke_fn; + +static int optee_cpuhp_probe(unsigned int cpu) +{ + /* + * Invoking a call on a CPU will cause OP-TEE to perform the required + * setup for that CPU. Just invoke the call to get the UID since that + * has no side effects. + */ + if (optee_msg_api_uid_is_optee_api(cpuhp_invoke_fn)) + return 0; + else + return -EINVAL; +} + +static int optee_load_fw(struct platform_device *pdev, + optee_invoke_fn *invoke_fn) +{ + const struct firmware *fw = NULL; + struct arm_smccc_res res; + phys_addr_t data_pa; + u8 *data_buf = NULL; + u64 data_size; + u32 data_pa_high, data_pa_low; + u32 data_size_high, data_size_low; + int rc; + int hp_state; + + if (!optee_msg_api_uid_is_optee_image_load(invoke_fn)) + return 0; + + rc = request_firmware(&fw, OPTEE_FW_IMAGE, &pdev->dev); + if (rc) { + /* + * The firmware in the rootfs will not be accessible until we + * are in the SYSTEM_RUNNING state, so return EPROBE_DEFER until + * that point. + */ + if (system_state < SYSTEM_RUNNING) + return -EPROBE_DEFER; + goto fw_err; + } + + data_size = fw->size; + /* + * This uses the GFP_DMA flag to ensure we are allocated memory in the + * 32-bit space since TF-A cannot map memory beyond the 32-bit boundary. + */ + data_buf = kmalloc(fw->size, GFP_KERNEL | GFP_DMA); + if (!data_buf) { + rc = -ENOMEM; + goto fw_err; + } + memcpy(data_buf, fw->data, fw->size); + data_pa = virt_to_phys(data_buf); + reg_pair_from_64(&data_pa_high, &data_pa_low, data_pa); + reg_pair_from_64(&data_size_high, &data_size_low, data_size); + goto fw_load; + +fw_err: + pr_warn("image loading failed\n"); + data_pa_high = 0; + data_pa_low = 0; + data_size_high = 0; + data_size_low = 0; + +fw_load: + /* + * Always invoke the SMC, even if loading the image fails, to indicate + * to EL3 that we have passed the point where it should allow invoking + * this SMC. + */ + pr_warn("OP-TEE image loaded from kernel, this can be insecure"); + invoke_fn(OPTEE_SMC_CALL_LOAD_IMAGE, data_size_high, data_size_low, + data_pa_high, data_pa_low, 0, 0, 0, &res); + if (!rc) + rc = res.a0; + if (fw) + release_firmware(fw); + kfree(data_buf); + + if (!rc) { + /* + * We need to initialize OP-TEE on all other running cores as + * well. Any cores that aren't running yet will get initialized + * when they are brought up by the power management functions in + * TF-A which are registered by the OP-TEE SPD. Due to that we + * can un-register the callback right after registering it. + */ + cpuhp_invoke_fn = invoke_fn; + hp_state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "optee:probe", + optee_cpuhp_probe, NULL); + if (hp_state < 0) { + pr_warn("Failed with CPU hotplug setup for OP-TEE"); + return -EINVAL; + } + cpuhp_remove_state(hp_state); + cpuhp_invoke_fn = NULL; + } + + return rc; +} +#else +static inline int optee_load_fw(struct platform_device *pdev, + optee_invoke_fn *invoke_fn) +{ + return 0; +} +#endif + static int optee_probe(struct platform_device *pdev) { optee_invoke_fn *invoke_fn; @@ -1372,6 +1619,10 @@ static int optee_probe(struct platform_device *pdev) if (IS_ERR(invoke_fn)) return PTR_ERR(invoke_fn); + rc = optee_load_fw(pdev, invoke_fn); + if (rc) + return rc; + if (!optee_msg_api_uid_is_optee_api(invoke_fn)) { pr_warn("api uid mismatch\n"); return -EINVAL; diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c index b1c6231defad..673cf0359494 100644 --- a/drivers/tee/tee_shm.c +++ b/drivers/tee/tee_shm.c @@ -32,7 +32,7 @@ static int shm_get_kernel_pages(unsigned long start, size_t page_count, is_kmap_addr((void *)start))) return -EINVAL; - page = virt_to_page(start); + page = virt_to_page((void *)start); for (n = 0; n < page_count; n++) { pages[n] = page + n; get_page(pages[n]); diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c index 90526f46c9b1..d71ee50e7878 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c @@ -153,7 +153,6 @@ static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, int temp cancel_delayed_work_sync(&pci_info->work); proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0); proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_THRES_0, 0); - thermal_zone_device_disable(tzd); pci_info->stored_thres = 0; return 0; } diff --git a/drivers/thermal/intel/intel_powerclamp.c b/drivers/thermal/intel/intel_powerclamp.c index c7ba5680cd48..91fc7e239497 100644 --- a/drivers/thermal/intel/intel_powerclamp.c +++ b/drivers/thermal/intel/intel_powerclamp.c @@ -235,6 +235,12 @@ static int max_idle_set(const char *arg, const struct kernel_param *kp) goto skip_limit_set; } + if (!cpumask_available(idle_injection_cpu_mask)) { + ret = allocate_copy_idle_injection_mask(cpu_present_mask); + if (ret) + goto skip_limit_set; + } + if (check_invalid(idle_injection_cpu_mask, new_max_idle)) { ret = -EINVAL; goto skip_limit_set; @@ -791,7 +797,8 @@ static int __init powerclamp_init(void) return retval; mutex_lock(&powerclamp_lock); - retval = allocate_copy_idle_injection_mask(cpu_present_mask); + if (!cpumask_available(idle_injection_cpu_mask)) + retval = allocate_copy_idle_injection_mask(cpu_present_mask); mutex_unlock(&powerclamp_lock); if (retval) diff --git a/drivers/thermal/intel/therm_throt.c b/drivers/thermal/intel/therm_throt.c index 2e22bb82b738..e69868e868eb 100644 --- a/drivers/thermal/intel/therm_throt.c +++ b/drivers/thermal/intel/therm_throt.c @@ -193,8 +193,67 @@ static const struct attribute_group thermal_attr_group = { #define THERM_THROT_POLL_INTERVAL HZ #define THERM_STATUS_PROCHOT_LOG BIT(1) -#define THERM_STATUS_CLEAR_CORE_MASK (BIT(1) | BIT(3) | BIT(5) | BIT(7) | BIT(9) | BIT(11) | BIT(13) | BIT(15)) -#define THERM_STATUS_CLEAR_PKG_MASK (BIT(1) | BIT(3) | BIT(5) | BIT(7) | BIT(9) | BIT(11)) +static u64 therm_intr_core_clear_mask; +static u64 therm_intr_pkg_clear_mask; + +static void thermal_intr_init_core_clear_mask(void) +{ + if (therm_intr_core_clear_mask) + return; + + /* + * Reference: Intel SDM Volume 4 + * "Table 2-2. IA-32 Architectural MSRs", MSR 0x19C + * IA32_THERM_STATUS. + */ + + /* + * Bit 1, 3, 5: CPUID.01H:EDX[22] = 1. This driver will not + * enable interrupts, when 0 as it checks for X86_FEATURE_ACPI. + */ + therm_intr_core_clear_mask = (BIT(1) | BIT(3) | BIT(5)); + + /* + * Bit 7 and 9: Thermal Threshold #1 and #2 log + * If CPUID.01H:ECX[8] = 1 + */ + if (boot_cpu_has(X86_FEATURE_TM2)) + therm_intr_core_clear_mask |= (BIT(7) | BIT(9)); + + /* Bit 11: Power Limitation log (R/WC0) If CPUID.06H:EAX[4] = 1 */ + if (boot_cpu_has(X86_FEATURE_PLN)) + therm_intr_core_clear_mask |= BIT(11); + + /* + * Bit 13: Current Limit log (R/WC0) If CPUID.06H:EAX[7] = 1 + * Bit 15: Cross Domain Limit log (R/WC0) If CPUID.06H:EAX[7] = 1 + */ + if (boot_cpu_has(X86_FEATURE_HWP)) + therm_intr_core_clear_mask |= (BIT(13) | BIT(15)); +} + +static void thermal_intr_init_pkg_clear_mask(void) +{ + if (therm_intr_pkg_clear_mask) + return; + + /* + * Reference: Intel SDM Volume 4 + * "Table 2-2. IA-32 Architectural MSRs", MSR 0x1B1 + * IA32_PACKAGE_THERM_STATUS. + */ + + /* All bits except BIT 26 depend on CPUID.06H: EAX[6] = 1 */ + if (boot_cpu_has(X86_FEATURE_PTS)) + therm_intr_pkg_clear_mask = (BIT(1) | BIT(3) | BIT(5) | BIT(7) | BIT(9) | BIT(11)); + + /* + * Intel SDM Volume 2A: Thermal and Power Management Leaf + * Bit 26: CPUID.06H: EAX[19] = 1 + */ + if (boot_cpu_has(X86_FEATURE_HFI)) + therm_intr_pkg_clear_mask |= BIT(26); +} /* * Clear the bits in package thermal status register for bit = 1 @@ -207,13 +266,10 @@ void thermal_clear_package_intr_status(int level, u64 bit_mask) if (level == CORE_LEVEL) { msr = MSR_IA32_THERM_STATUS; - msr_val = THERM_STATUS_CLEAR_CORE_MASK; + msr_val = therm_intr_core_clear_mask; } else { msr = MSR_IA32_PACKAGE_THERM_STATUS; - msr_val = THERM_STATUS_CLEAR_PKG_MASK; - if (boot_cpu_has(X86_FEATURE_HFI)) - msr_val |= BIT(26); - + msr_val = therm_intr_pkg_clear_mask; } msr_val &= ~bit_mask; @@ -708,6 +764,9 @@ void intel_init_thermal(struct cpuinfo_x86 *c) h = THERMAL_APIC_VECTOR | APIC_DM_FIXED | APIC_LVT_MASKED; apic_write(APIC_LVTTHMR, h); + thermal_intr_init_core_clear_mask(); + thermal_intr_init_pkg_clear_mask(); + rdmsr(MSR_IA32_THERM_INTERRUPT, l, h); if (cpu_has(c, X86_FEATURE_PLN) && !int_pln_enable) wrmsr(MSR_IA32_THERM_INTERRUPT, diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index a4aba7b8bb8b..6c20c9f90a05 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -876,8 +876,6 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev) unsigned long states = cdev->max_state + 1; int var; - lockdep_assert_held(&cdev->lock); - var = sizeof(*stats); var += sizeof(*stats->time_in_state) * states; var += sizeof(*stats->trans_table) * states * states; @@ -903,8 +901,6 @@ out: static void cooling_device_stats_destroy(struct thermal_cooling_device *cdev) { - lockdep_assert_held(&cdev->lock); - kfree(cdev->stats); cdev->stats = NULL; } @@ -931,6 +927,8 @@ void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev) void thermal_cooling_device_stats_reinit(struct thermal_cooling_device *cdev) { + lockdep_assert_held(&cdev->lock); + cooling_device_stats_destroy(cdev); cooling_device_stats_setup(cdev); } diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index fa43df05342b..3ba9c8b93ae6 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1903,6 +1903,17 @@ EXPORT_SYMBOL_GPL(serial8250_modem_status); static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir) { switch (iir & 0x3f) { + case UART_IIR_THRI: + /* + * Postpone DMA or not decision to IIR_RDI or IIR_RX_TIMEOUT + * because it's impossible to do an informed decision about + * that with IIR_THRI. + * + * This also fixes one known DMA Rx corruption issue where + * DR is asserted but DMA Rx only gets a corrupted zero byte + * (too early DR?). + */ + return false; case UART_IIR_RDI: if (!up->dma->rx_running) break; diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 56e6ba3250cd..074bfed57fc9 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -858,11 +858,17 @@ static unsigned int lpuart32_tx_empty(struct uart_port *port) struct lpuart_port, port); unsigned long stat = lpuart32_read(port, UARTSTAT); unsigned long sfifo = lpuart32_read(port, UARTFIFO); + unsigned long ctrl = lpuart32_read(port, UARTCTRL); if (sport->dma_tx_in_progress) return 0; - if (stat & UARTSTAT_TC && sfifo & UARTFIFO_TXEMPT) + /* + * LPUART Transmission Complete Flag may never be set while queuing a break + * character, so avoid checking for transmission complete when UARTCTRL_SBK + * is asserted. + */ + if ((stat & UARTSTAT_TC && sfifo & UARTFIFO_TXEMPT) || ctrl & UARTCTRL_SBK) return TIOCSER_TEMT; return 0; @@ -2942,7 +2948,7 @@ static bool lpuart_uport_is_active(struct lpuart_port *sport) tty = tty_port_tty_get(port); if (tty) { tty_dev = tty->dev; - may_wake = device_may_wakeup(tty_dev); + may_wake = tty_dev && device_may_wakeup(tty_dev); tty_kref_put(tty); } diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 7bd080720929..caa09a0c48f4 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -31,6 +31,7 @@ #include <linux/ioport.h> #include <linux/ktime.h> #include <linux/major.h> +#include <linux/minmax.h> #include <linux/module.h> #include <linux/mm.h> #include <linux/of.h> @@ -2864,6 +2865,13 @@ static int sci_init_single(struct platform_device *dev, sci_port->irqs[i] = platform_get_irq(dev, i); } + /* + * The fourth interrupt on SCI port is transmit end interrupt, so + * shuffle the interrupts. + */ + if (p->type == PORT_SCI) + swap(sci_port->irqs[SCIx_BRI_IRQ], sci_port->irqs[SCIx_TEI_IRQ]); + /* The SCI generates several interrupts. They can be muxed together or * connected to different interrupt lines. In the muxed case only one * interrupt resource is specified as there is only one interrupt ID. @@ -2929,7 +2937,7 @@ static int sci_init_single(struct platform_device *dev, port->flags = UPF_FIXED_PORT | UPF_BOOT_AUTOCONF | p->flags; port->fifosize = sci_port->params->fifosize; - if (port->type == PORT_SCI) { + if (port->type == PORT_SCI && !dev->dev.of_node) { if (sci_port->reg_size >= 0x20) port->regshift = 2; else diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 37e178a9ac47..70b112038792 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -1409,13 +1409,6 @@ static int ufshcd_devfreq_target(struct device *dev, struct ufs_clk_info *clki; unsigned long irq_flags; - /* - * Skip devfreq if UFS initialization is not finished. - * Otherwise ufs could be in a inconsistent state. - */ - if (!smp_load_acquire(&hba->logical_unit_scan_finished)) - return 0; - if (!ufshcd_is_clkscaling_supported(hba)) return -EINVAL; @@ -8399,6 +8392,22 @@ static int ufshcd_add_lus(struct ufs_hba *hba) if (ret) goto out; + /* Initialize devfreq after UFS device is detected */ + if (ufshcd_is_clkscaling_supported(hba)) { + memcpy(&hba->clk_scaling.saved_pwr_info.info, + &hba->pwr_info, + sizeof(struct ufs_pa_layer_attr)); + hba->clk_scaling.saved_pwr_info.is_valid = true; + hba->clk_scaling.is_allowed = true; + + ret = ufshcd_devfreq_init(hba); + if (ret) + goto out; + + hba->clk_scaling.is_enabled = true; + ufshcd_init_clk_scaling_sysfs(hba); + } + ufs_bsg_probe(hba); ufshpb_init(hba); scsi_scan_host(hba->host); @@ -8670,12 +8679,6 @@ out: if (ret) { pm_runtime_put_sync(hba->dev); ufshcd_hba_exit(hba); - } else { - /* - * Make sure that when reader code sees UFS initialization has finished, - * all initialization steps have really been executed. - */ - smp_store_release(&hba->logical_unit_scan_finished, true); } } @@ -10316,30 +10319,12 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) */ ufshcd_set_ufs_dev_active(hba); - /* Initialize devfreq */ - if (ufshcd_is_clkscaling_supported(hba)) { - memcpy(&hba->clk_scaling.saved_pwr_info.info, - &hba->pwr_info, - sizeof(struct ufs_pa_layer_attr)); - hba->clk_scaling.saved_pwr_info.is_valid = true; - hba->clk_scaling.is_allowed = true; - - err = ufshcd_devfreq_init(hba); - if (err) - goto rpm_put_sync; - - hba->clk_scaling.is_enabled = true; - ufshcd_init_clk_scaling_sysfs(hba); - } - async_schedule(ufshcd_async_scan, hba); ufs_sysfs_add_nodes(hba->dev); device_enable_async_suspend(dev); return 0; -rpm_put_sync: - pm_runtime_put_sync(dev); free_tmf_queue: blk_mq_destroy_queue(hba->tmf_queue); blk_put_queue(hba->tmf_queue); diff --git a/drivers/usb/cdns3/cdnsp-ep0.c b/drivers/usb/cdns3/cdnsp-ep0.c index d63d5d92f255..f317d3c84781 100644 --- a/drivers/usb/cdns3/cdnsp-ep0.c +++ b/drivers/usb/cdns3/cdnsp-ep0.c @@ -414,7 +414,7 @@ static int cdnsp_ep0_std_request(struct cdnsp_device *pdev, void cdnsp_setup_analyze(struct cdnsp_device *pdev) { struct usb_ctrlrequest *ctrl = &pdev->setup; - int ret = 0; + int ret = -EINVAL; u16 len; trace_cdnsp_ctrl_req(ctrl); @@ -424,7 +424,6 @@ void cdnsp_setup_analyze(struct cdnsp_device *pdev) if (pdev->gadget.state == USB_STATE_NOTATTACHED) { dev_err(pdev->dev, "ERR: Setup detected in unattached state\n"); - ret = -EINVAL; goto out; } diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index a23ddbb81979..560793545362 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -49,6 +49,7 @@ #define PCI_DEVICE_ID_INTEL_RPLS 0x7a61 #define PCI_DEVICE_ID_INTEL_MTLM 0x7eb1 #define PCI_DEVICE_ID_INTEL_MTLP 0x7ec1 +#define PCI_DEVICE_ID_INTEL_MTLS 0x7f6f #define PCI_DEVICE_ID_INTEL_MTL 0x7e7e #define PCI_DEVICE_ID_INTEL_TGL 0x9a15 #define PCI_DEVICE_ID_AMD_MR 0x163a @@ -474,6 +475,9 @@ static const struct pci_device_id dwc3_pci_id_table[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLP), (kernel_ulong_t) &dwc3_pci_intel_swnode, }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLS), + (kernel_ulong_t) &dwc3_pci_intel_swnode, }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL), (kernel_ulong_t) &dwc3_pci_intel_swnode, }, diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index ddfc537c7526..56cdfb2e4211 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1251,7 +1251,7 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) p->kiocb = kiocb; if (p->aio) { p->to_free = dup_iter(&p->data, to, GFP_KERNEL); - if (!p->to_free) { + if (!iter_is_ubuf(&p->data) && !p->to_free) { kfree(p); return -ENOMEM; } diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index d605bc2e7e8f..28249d0bf062 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -614,7 +614,7 @@ ep_read_iter(struct kiocb *iocb, struct iov_iter *to) if (!priv) goto fail; priv->to_free = dup_iter(&priv->to, to, GFP_KERNEL); - if (!priv->to_free) { + if (!iter_is_ubuf(&priv->to) && !priv->to_free) { kfree(priv); goto fail; } diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index fb988e4ea924..6db07ca419c3 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -771,12 +771,11 @@ static struct pci_driver xhci_pci_driver = { /* suspend and resume implemented later */ .shutdown = usb_hcd_pci_shutdown, - .driver = { #ifdef CONFIG_PM - .pm = &usb_hcd_pci_pm_ops, -#endif - .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .driver = { + .pm = &usb_hcd_pci_pm_ops }, +#endif }; static int __init xhci_pci_init(void) diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 1ff22f675930..a88c39e525c2 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -1360,6 +1360,9 @@ static void tegra_xhci_id_work(struct work_struct *work) mutex_unlock(&tegra->lock); + tegra->otg_usb3_port = tegra_xusb_padctl_get_usb3_companion(tegra->padctl, + tegra->otg_usb2_port); + if (tegra->host_mode) { /* switch to host mode */ if (tegra->otg_usb3_port >= 0) { @@ -1474,9 +1477,6 @@ static int tegra_xhci_id_notify(struct notifier_block *nb, } tegra->otg_usb2_port = tegra_xusb_get_usb2_port(tegra, usbphy); - tegra->otg_usb3_port = tegra_xusb_padctl_get_usb3_companion( - tegra->padctl, - tegra->otg_usb2_port); tegra->host_mode = (usbphy->last_event == USB_EVENT_ID) ? true : false; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 6183ce8574b1..6307bae9cddf 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -9,6 +9,7 @@ */ #include <linux/pci.h> +#include <linux/iommu.h> #include <linux/iopoll.h> #include <linux/irq.h> #include <linux/log2.h> @@ -228,6 +229,7 @@ int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us) static void xhci_zero_64b_regs(struct xhci_hcd *xhci) { struct device *dev = xhci_to_hcd(xhci)->self.sysdev; + struct iommu_domain *domain; int err, i; u64 val; u32 intrs; @@ -246,7 +248,9 @@ static void xhci_zero_64b_regs(struct xhci_hcd *xhci) * an iommu. Doing anything when there is no iommu is definitely * unsafe... */ - if (!(xhci->quirks & XHCI_ZERO_64B_REGS) || !device_iommu_mapped(dev)) + domain = iommu_get_domain_for_dev(dev); + if (!(xhci->quirks & XHCI_ZERO_64B_REGS) || !domain || + domain->type == IOMMU_DOMAIN_IDENTITY) return; xhci_info(xhci, "Zeroing 64bit base registers, expecting fault\n"); @@ -4438,6 +4442,7 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci, if (!virt_dev || max_exit_latency == virt_dev->current_mel) { spin_unlock_irqrestore(&xhci->lock, flags); + xhci_free_command(xhci, command); return 0; } diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 832ad592b7ef..cdea1bff3b70 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -120,6 +120,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */ { USB_DEVICE(0x10C4, 0x8281) }, /* Nanotec Plug & Drive */ { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */ + { USB_DEVICE(0x10C4, 0x82AA) }, /* Silicon Labs IFS-USB-DATACABLE used with Quint UPS */ { USB_DEVICE(0x10C4, 0x82EF) }, /* CESINEL FALCO 6105 AC Power Supply */ { USB_DEVICE(0x10C4, 0x82F1) }, /* CESINEL MEDCAL EFD Earth Fault Detector */ { USB_DEVICE(0x10C4, 0x82F2) }, /* CESINEL MEDCAL ST Network Analyzer */ diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index e6d8d9b35ad0..f31cc3c76329 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1198,6 +1198,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, 0x0900, 0xff, 0, 0), /* RM500U-CN */ + .driver_info = ZLP }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200U, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200S_CN, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200T, 0xff, 0, 0) }, @@ -1300,6 +1302,14 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(0) | RSVD(1) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1075, 0xff), /* Telit FN990 (PCIe) */ .driver_info = RSVD(0) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1080, 0xff), /* Telit FE990 (rmnet) */ + .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1081, 0xff), /* Telit FE990 (MBIM) */ + .driver_info = NCTRL(0) | RSVD(1) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1082, 0xff), /* Telit FE990 (RNDIS) */ + .driver_info = NCTRL(2) | RSVD(3) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1083, 0xff), /* Telit FE990 (ECM) */ + .driver_info = NCTRL(0) | RSVD(1) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910), .driver_info = NCTRL(0) | RSVD(1) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM), diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index 662cd043b50e..8f3e884222ad 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -112,8 +112,12 @@ static int dp_altmode_configure(struct dp_altmode *dp, u8 con) if (dp->data.status & DP_STATUS_PREFER_MULTI_FUNC && pin_assign & DP_PIN_ASSIGN_MULTI_FUNC_MASK) pin_assign &= DP_PIN_ASSIGN_MULTI_FUNC_MASK; - else if (pin_assign & DP_PIN_ASSIGN_DP_ONLY_MASK) + else if (pin_assign & DP_PIN_ASSIGN_DP_ONLY_MASK) { pin_assign &= DP_PIN_ASSIGN_DP_ONLY_MASK; + /* Default to pin assign C if available */ + if (pin_assign & BIT(DP_PIN_ASSIGN_C)) + pin_assign = BIT(DP_PIN_ASSIGN_C); + } if (!pin_assign) return -EINVAL; diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 520646ae7fa0..195963b82b63 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -2467,10 +2467,11 @@ static int setup_driver(struct mlx5_vdpa_dev *mvdev) err = 0; goto out; } + mlx5_vdpa_add_debugfs(ndev); err = setup_virtqueues(mvdev); if (err) { mlx5_vdpa_warn(mvdev, "setup_virtqueues\n"); - goto out; + goto err_setup; } err = create_rqt(ndev); @@ -2500,6 +2501,8 @@ err_tir: destroy_rqt(ndev); err_rqt: teardown_virtqueues(ndev); +err_setup: + mlx5_vdpa_remove_debugfs(ndev->debugfs); out: return err; } @@ -2513,6 +2516,8 @@ static void teardown_driver(struct mlx5_vdpa_net *ndev) if (!ndev->setup) return; + mlx5_vdpa_remove_debugfs(ndev->debugfs); + ndev->debugfs = NULL; teardown_steering(ndev); destroy_tir(ndev); destroy_rqt(ndev); @@ -3261,7 +3266,6 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name, if (err) goto err_reg; - mlx5_vdpa_add_debugfs(ndev); mgtdev->ndev = ndev; return 0; diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c index 862f405362de..dfe2ce341803 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c @@ -466,16 +466,21 @@ static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, vdpasim_net_setup_config(simdev, config); - ret = _vdpa_register_device(&simdev->vdpa, VDPASIM_NET_VQ_NUM); - if (ret) - goto reg_err; - net = sim_to_net(simdev); u64_stats_init(&net->tx_stats.syncp); u64_stats_init(&net->rx_stats.syncp); u64_stats_init(&net->cq_stats.syncp); + /* + * Initialization must be completed before this call, since it can + * connect the device to the vDPA bus, so requests can arrive after + * this call. + */ + ret = _vdpa_register_device(&simdev->vdpa, VDPASIM_NET_VQ_NUM); + if (ret) + goto reg_err; + return 0; reg_err: diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig index 587fbae06182..b455d9ab6f3d 100644 --- a/drivers/vhost/Kconfig +++ b/drivers/vhost/Kconfig @@ -13,9 +13,14 @@ config VHOST_RING This option is selected by any driver which needs to access the host side of a virtio ring. +config VHOST_TASK + bool + default n + config VHOST tristate select VHOST_IOTLB + select VHOST_TASK help This option is selected by any driver which needs to access the core of vhost. diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index b244e7c0f514..e68f7d226bc9 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -125,7 +125,6 @@ struct vhost_scsi_tpg { struct se_portal_group se_tpg; /* Pointer back to vhost_scsi, protected by tv_tpg_mutex */ struct vhost_scsi *vhost_scsi; - struct list_head tmf_queue; }; struct vhost_scsi_tport { @@ -206,10 +205,8 @@ struct vhost_scsi { struct vhost_scsi_tmf { struct vhost_work vwork; - struct vhost_scsi_tpg *tpg; struct vhost_scsi *vhost; struct vhost_scsi_virtqueue *svq; - struct list_head queue_entry; struct se_cmd se_cmd; u8 scsi_resp; @@ -352,12 +349,9 @@ static void vhost_scsi_release_cmd_res(struct se_cmd *se_cmd) static void vhost_scsi_release_tmf_res(struct vhost_scsi_tmf *tmf) { - struct vhost_scsi_tpg *tpg = tmf->tpg; struct vhost_scsi_inflight *inflight = tmf->inflight; - mutex_lock(&tpg->tv_tpg_mutex); - list_add_tail(&tpg->tmf_queue, &tmf->queue_entry); - mutex_unlock(&tpg->tv_tpg_mutex); + kfree(tmf); vhost_scsi_put_inflight(inflight); } @@ -671,7 +665,7 @@ vhost_scsi_calc_sgls(struct iov_iter *iter, size_t bytes, int max_sgls) { int sgl_count = 0; - if (!iter || !iter->iov) { + if (!iter || !iter_iov(iter)) { pr_err("%s: iter->iov is NULL, but expected bytes: %zu" " present\n", __func__, bytes); return -EINVAL; @@ -1194,19 +1188,11 @@ vhost_scsi_handle_tmf(struct vhost_scsi *vs, struct vhost_scsi_tpg *tpg, goto send_reject; } - mutex_lock(&tpg->tv_tpg_mutex); - if (list_empty(&tpg->tmf_queue)) { - pr_err("Missing reserve TMF. Could not handle LUN RESET.\n"); - mutex_unlock(&tpg->tv_tpg_mutex); + tmf = kzalloc(sizeof(*tmf), GFP_KERNEL); + if (!tmf) goto send_reject; - } - - tmf = list_first_entry(&tpg->tmf_queue, struct vhost_scsi_tmf, - queue_entry); - list_del_init(&tmf->queue_entry); - mutex_unlock(&tpg->tv_tpg_mutex); - tmf->tpg = tpg; + vhost_work_init(&tmf->vwork, vhost_scsi_tmf_resp_work); tmf->vhost = vs; tmf->svq = svq; tmf->resp_iov = vq->iov[vc->out]; @@ -1658,7 +1644,10 @@ undepend: for (i = 0; i < VHOST_SCSI_MAX_TARGET; i++) { tpg = vs_tpg[i]; if (tpg) { + mutex_lock(&tpg->tv_tpg_mutex); + tpg->vhost_scsi = NULL; tpg->tv_tpg_vhost_count--; + mutex_unlock(&tpg->tv_tpg_mutex); target_undepend_item(&tpg->se_tpg.tpg_group.cg_item); } } @@ -2032,19 +2021,11 @@ static int vhost_scsi_port_link(struct se_portal_group *se_tpg, { struct vhost_scsi_tpg *tpg = container_of(se_tpg, struct vhost_scsi_tpg, se_tpg); - struct vhost_scsi_tmf *tmf; - - tmf = kzalloc(sizeof(*tmf), GFP_KERNEL); - if (!tmf) - return -ENOMEM; - INIT_LIST_HEAD(&tmf->queue_entry); - vhost_work_init(&tmf->vwork, vhost_scsi_tmf_resp_work); mutex_lock(&vhost_scsi_mutex); mutex_lock(&tpg->tv_tpg_mutex); tpg->tv_tpg_port_count++; - list_add_tail(&tmf->queue_entry, &tpg->tmf_queue); mutex_unlock(&tpg->tv_tpg_mutex); vhost_scsi_hotplug(tpg, lun); @@ -2059,16 +2040,11 @@ static void vhost_scsi_port_unlink(struct se_portal_group *se_tpg, { struct vhost_scsi_tpg *tpg = container_of(se_tpg, struct vhost_scsi_tpg, se_tpg); - struct vhost_scsi_tmf *tmf; mutex_lock(&vhost_scsi_mutex); mutex_lock(&tpg->tv_tpg_mutex); tpg->tv_tpg_port_count--; - tmf = list_first_entry(&tpg->tmf_queue, struct vhost_scsi_tmf, - queue_entry); - list_del(&tmf->queue_entry); - kfree(tmf); mutex_unlock(&tpg->tv_tpg_mutex); vhost_scsi_hotunplug(tpg, lun); @@ -2329,7 +2305,6 @@ vhost_scsi_make_tpg(struct se_wwn *wwn, const char *name) } mutex_init(&tpg->tv_tpg_mutex); INIT_LIST_HEAD(&tpg->tv_tpg_list); - INIT_LIST_HEAD(&tpg->tmf_queue); tpg->tport = tport; tpg->tport_tpgt = tpgt; diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index f11bdbe4c2c5..6d07b42833be 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -22,11 +22,11 @@ #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/kthread.h> -#include <linux/cgroup.h> #include <linux/module.h> #include <linux/sort.h> #include <linux/sched/mm.h> #include <linux/sched/signal.h> +#include <linux/sched/vhost_task.h> #include <linux/interval_tree_generic.h> #include <linux/nospec.h> #include <linux/kcov.h> @@ -255,8 +255,8 @@ void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work) * sure it was not in the list. * test_and_set_bit() implies a memory barrier. */ - llist_add(&work->node, &dev->work_list); - wake_up_process(dev->worker); + llist_add(&work->node, &dev->worker->work_list); + wake_up_process(dev->worker->vtsk->task); } } EXPORT_SYMBOL_GPL(vhost_work_queue); @@ -264,7 +264,7 @@ EXPORT_SYMBOL_GPL(vhost_work_queue); /* A lockless hint for busy polling code to exit the loop */ bool vhost_has_work(struct vhost_dev *dev) { - return !llist_empty(&dev->work_list); + return dev->worker && !llist_empty(&dev->worker->work_list); } EXPORT_SYMBOL_GPL(vhost_has_work); @@ -335,22 +335,20 @@ static void vhost_vq_reset(struct vhost_dev *dev, static int vhost_worker(void *data) { - struct vhost_dev *dev = data; + struct vhost_worker *worker = data; struct vhost_work *work, *work_next; struct llist_node *node; - kthread_use_mm(dev->mm); - for (;;) { /* mb paired w/ kthread_stop */ set_current_state(TASK_INTERRUPTIBLE); - if (kthread_should_stop()) { + if (vhost_task_should_stop(worker->vtsk)) { __set_current_state(TASK_RUNNING); break; } - node = llist_del_all(&dev->work_list); + node = llist_del_all(&worker->work_list); if (!node) schedule(); @@ -360,14 +358,14 @@ static int vhost_worker(void *data) llist_for_each_entry_safe(work, work_next, node, node) { clear_bit(VHOST_WORK_QUEUED, &work->flags); __set_current_state(TASK_RUNNING); - kcov_remote_start_common(dev->kcov_handle); + kcov_remote_start_common(worker->kcov_handle); work->fn(work); kcov_remote_stop(); if (need_resched()) schedule(); } } - kthread_unuse_mm(dev->mm); + return 0; } @@ -479,7 +477,6 @@ void vhost_dev_init(struct vhost_dev *dev, dev->byte_weight = byte_weight; dev->use_worker = use_worker; dev->msg_handler = msg_handler; - init_llist_head(&dev->work_list); init_waitqueue_head(&dev->wait); INIT_LIST_HEAD(&dev->read_list); INIT_LIST_HEAD(&dev->pending_list); @@ -509,31 +506,6 @@ long vhost_dev_check_owner(struct vhost_dev *dev) } EXPORT_SYMBOL_GPL(vhost_dev_check_owner); -struct vhost_attach_cgroups_struct { - struct vhost_work work; - struct task_struct *owner; - int ret; -}; - -static void vhost_attach_cgroups_work(struct vhost_work *work) -{ - struct vhost_attach_cgroups_struct *s; - - s = container_of(work, struct vhost_attach_cgroups_struct, work); - s->ret = cgroup_attach_task_all(s->owner, current); -} - -static int vhost_attach_cgroups(struct vhost_dev *dev) -{ - struct vhost_attach_cgroups_struct attach; - - attach.owner = current; - vhost_work_init(&attach.work, vhost_attach_cgroups_work); - vhost_work_queue(dev, &attach.work); - vhost_dev_flush(dev); - return attach.ret; -} - /* Caller should have device mutex */ bool vhost_dev_has_owner(struct vhost_dev *dev) { @@ -571,10 +543,54 @@ static void vhost_detach_mm(struct vhost_dev *dev) dev->mm = NULL; } +static void vhost_worker_free(struct vhost_dev *dev) +{ + struct vhost_worker *worker = dev->worker; + + if (!worker) + return; + + dev->worker = NULL; + WARN_ON(!llist_empty(&worker->work_list)); + vhost_task_stop(worker->vtsk); + kfree(worker); +} + +static int vhost_worker_create(struct vhost_dev *dev) +{ + struct vhost_worker *worker; + struct vhost_task *vtsk; + char name[TASK_COMM_LEN]; + int ret; + + worker = kzalloc(sizeof(*worker), GFP_KERNEL_ACCOUNT); + if (!worker) + return -ENOMEM; + + dev->worker = worker; + worker->kcov_handle = kcov_common_handle(); + init_llist_head(&worker->work_list); + snprintf(name, sizeof(name), "vhost-%d", current->pid); + + vtsk = vhost_task_create(vhost_worker, worker, name); + if (!vtsk) { + ret = -ENOMEM; + goto free_worker; + } + + worker->vtsk = vtsk; + vhost_task_start(vtsk); + return 0; + +free_worker: + kfree(worker); + dev->worker = NULL; + return ret; +} + /* Caller should have device mutex */ long vhost_dev_set_owner(struct vhost_dev *dev) { - struct task_struct *worker; int err; /* Is there an owner already? */ @@ -585,36 +601,21 @@ long vhost_dev_set_owner(struct vhost_dev *dev) vhost_attach_mm(dev); - dev->kcov_handle = kcov_common_handle(); if (dev->use_worker) { - worker = kthread_create(vhost_worker, dev, - "vhost-%d", current->pid); - if (IS_ERR(worker)) { - err = PTR_ERR(worker); - goto err_worker; - } - - dev->worker = worker; - wake_up_process(worker); /* avoid contributing to loadavg */ - - err = vhost_attach_cgroups(dev); + err = vhost_worker_create(dev); if (err) - goto err_cgroup; + goto err_worker; } err = vhost_dev_alloc_iovecs(dev); if (err) - goto err_cgroup; + goto err_iovecs; return 0; -err_cgroup: - if (dev->worker) { - kthread_stop(dev->worker); - dev->worker = NULL; - } +err_iovecs: + vhost_worker_free(dev); err_worker: vhost_detach_mm(dev); - dev->kcov_handle = 0; err_mm: return err; } @@ -705,12 +706,7 @@ void vhost_dev_cleanup(struct vhost_dev *dev) dev->iotlb = NULL; vhost_clear_msg(dev); wake_up_interruptible_poll(&dev->wait, EPOLLIN | EPOLLRDNORM); - WARN_ON(!llist_empty(&dev->work_list)); - if (dev->worker) { - kthread_stop(dev->worker); - dev->worker = NULL; - dev->kcov_handle = 0; - } + vhost_worker_free(dev); vhost_detach_mm(dev); } EXPORT_SYMBOL_GPL(vhost_dev_cleanup); @@ -1831,7 +1827,7 @@ EXPORT_SYMBOL_GPL(vhost_dev_ioctl); /* TODO: This is really inefficient. We need something like get_user() * (instruction directly accesses the data, with an exception table entry - * returning -EFAULT). See Documentation/x86/exception-tables.rst. + * returning -EFAULT). See Documentation/arch/x86/exception-tables.rst. */ static int set_bit_to_user(int nr, void __user *addr) { diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 1647b750169c..0308638cdeee 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -16,6 +16,7 @@ #include <linux/irqbypass.h> struct vhost_work; +struct vhost_task; typedef void (*vhost_work_fn_t)(struct vhost_work *work); #define VHOST_WORK_QUEUED 1 @@ -25,6 +26,12 @@ struct vhost_work { unsigned long flags; }; +struct vhost_worker { + struct vhost_task *vtsk; + struct llist_head work_list; + u64 kcov_handle; +}; + /* Poll a file (eventfd or socket) */ /* Note: there's nothing vhost specific about this structure. */ struct vhost_poll { @@ -147,8 +154,7 @@ struct vhost_dev { struct vhost_virtqueue **vqs; int nvqs; struct eventfd_ctx *log_ctx; - struct llist_head work_list; - struct task_struct *worker; + struct vhost_worker *worker; struct vhost_iotlb *umem; struct vhost_iotlb *iotlb; spinlock_t iotlb_lock; @@ -158,7 +164,6 @@ struct vhost_dev { int iov_limit; int weight; int byte_weight; - u64 kcov_handle; bool use_worker; int (*msg_handler)(struct vhost_dev *dev, u32 asid, struct vhost_iotlb_msg *msg); diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 0a2c47df01f4..eb565a10e5cd 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -823,7 +823,7 @@ static int set_con2fb_map(int unit, int newidx, int user) int oldidx = con2fb_map[unit]; struct fb_info *info = fbcon_registered_fb[newidx]; struct fb_info *oldinfo = NULL; - int found, err = 0, show_logo; + int err = 0, show_logo; WARN_CONSOLE_UNLOCKED(); @@ -841,26 +841,26 @@ static int set_con2fb_map(int unit, int newidx, int user) if (oldidx != -1) oldinfo = fbcon_registered_fb[oldidx]; - found = search_fb_in_map(newidx); - - if (!err && !found) { + if (!search_fb_in_map(newidx)) { err = con2fb_acquire_newinfo(vc, info, unit); - if (!err) - con2fb_map[unit] = newidx; + if (err) + return err; + + fbcon_add_cursor_work(info); } + con2fb_map[unit] = newidx; + /* * If old fb is not mapped to any of the consoles, * fbcon should release it. */ - if (!err && oldinfo && !search_fb_in_map(oldidx)) + if (oldinfo && !search_fb_in_map(oldidx)) con2fb_release_oldinfo(vc, oldinfo, info); show_logo = (fg_console == 0 && !user && logo_shown != FBCON_LOGO_DONTSHOW); - if (!found) - fbcon_add_cursor_work(info); con2fb_map_boot[unit] = newidx; con2fb_init_display(vc, info, unit, show_logo); diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 875541ff185b..3fd95a79e4c3 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1116,6 +1116,8 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, case FBIOPUT_VSCREENINFO: if (copy_from_user(&var, argp, sizeof(var))) return -EFAULT; + /* only for kernel-internal use */ + var.activate &= ~FB_ACTIVATE_KD_TEXT; console_lock(); lock_fb_info(info); ret = fbcon_modechange_possible(info, &var); diff --git a/drivers/virt/coco/sev-guest/sev-guest.c b/drivers/virt/coco/sev-guest/sev-guest.c index 46f1a8d558b0..97dbe715e96a 100644 --- a/drivers/virt/coco/sev-guest/sev-guest.c +++ b/drivers/virt/coco/sev-guest/sev-guest.c @@ -46,7 +46,15 @@ struct snp_guest_dev { void *certs_data; struct snp_guest_crypto *crypto; + /* request and response are in unencrypted memory */ struct snp_guest_msg *request, *response; + + /* + * Avoid information leakage by double-buffering shared messages + * in fields that are in regular encrypted memory. + */ + struct snp_guest_msg secret_request, secret_response; + struct snp_secrets_page_layout *layout; struct snp_req_data input; u32 *os_area_msg_seqno; @@ -266,14 +274,17 @@ static int dec_payload(struct snp_guest_dev *snp_dev, struct snp_guest_msg *msg, static int verify_and_dec_payload(struct snp_guest_dev *snp_dev, void *payload, u32 sz) { struct snp_guest_crypto *crypto = snp_dev->crypto; - struct snp_guest_msg *resp = snp_dev->response; - struct snp_guest_msg *req = snp_dev->request; + struct snp_guest_msg *resp = &snp_dev->secret_response; + struct snp_guest_msg *req = &snp_dev->secret_request; struct snp_guest_msg_hdr *req_hdr = &req->hdr; struct snp_guest_msg_hdr *resp_hdr = &resp->hdr; dev_dbg(snp_dev->dev, "response [seqno %lld type %d version %d sz %d]\n", resp_hdr->msg_seqno, resp_hdr->msg_type, resp_hdr->msg_version, resp_hdr->msg_sz); + /* Copy response from shared memory to encrypted memory. */ + memcpy(resp, snp_dev->response, sizeof(*resp)); + /* Verify that the sequence counter is incremented by 1 */ if (unlikely(resp_hdr->msg_seqno != (req_hdr->msg_seqno + 1))) return -EBADMSG; @@ -297,7 +308,7 @@ static int verify_and_dec_payload(struct snp_guest_dev *snp_dev, void *payload, static int enc_payload(struct snp_guest_dev *snp_dev, u64 seqno, int version, u8 type, void *payload, size_t sz) { - struct snp_guest_msg *req = snp_dev->request; + struct snp_guest_msg *req = &snp_dev->secret_request; struct snp_guest_msg_hdr *hdr = &req->hdr; memset(req, 0, sizeof(*req)); @@ -321,11 +332,12 @@ static int enc_payload(struct snp_guest_dev *snp_dev, u64 seqno, int version, u8 return __enc_payload(snp_dev, req, payload, sz); } -static int __handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, __u64 *fw_err) +static int __handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, + struct snp_guest_request_ioctl *rio) { - unsigned long err = 0xff, override_err = 0; unsigned long req_start = jiffies; unsigned int override_npages = 0; + u64 override_err = 0; int rc; retry_request: @@ -335,7 +347,7 @@ retry_request: * sequence number must be incremented or the VMPCK must be deleted to * prevent reuse of the IV. */ - rc = snp_issue_guest_request(exit_code, &snp_dev->input, &err); + rc = snp_issue_guest_request(exit_code, &snp_dev->input, rio); switch (rc) { case -ENOSPC: /* @@ -353,7 +365,7 @@ retry_request: * request buffer size was too small and give the caller the * required buffer size. */ - override_err = SNP_GUEST_REQ_INVALID_LEN; + override_err = SNP_GUEST_VMM_ERR(SNP_GUEST_VMM_ERR_INVALID_LEN); /* * If this call to the firmware succeeds, the sequence number can @@ -366,7 +378,7 @@ retry_request: goto retry_request; /* - * The host may return SNP_GUEST_REQ_ERR_EBUSY if the request has been + * The host may return SNP_GUEST_VMM_ERR_BUSY if the request has been * throttled. Retry in the driver to avoid returning and reusing the * message sequence number on a different message. */ @@ -387,27 +399,29 @@ retry_request: */ snp_inc_msg_seqno(snp_dev); - if (fw_err) - *fw_err = override_err ?: err; + if (override_err) { + rio->exitinfo2 = override_err; + + /* + * If an extended guest request was issued and the supplied certificate + * buffer was not large enough, a standard guest request was issued to + * prevent IV reuse. If the standard request was successful, return -EIO + * back to the caller as would have originally been returned. + */ + if (!rc && override_err == SNP_GUEST_VMM_ERR(SNP_GUEST_VMM_ERR_INVALID_LEN)) + rc = -EIO; + } if (override_npages) snp_dev->input.data_npages = override_npages; - /* - * If an extended guest request was issued and the supplied certificate - * buffer was not large enough, a standard guest request was issued to - * prevent IV reuse. If the standard request was successful, return -EIO - * back to the caller as would have originally been returned. - */ - if (!rc && override_err == SNP_GUEST_REQ_INVALID_LEN) - return -EIO; - return rc; } -static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, int msg_ver, - u8 type, void *req_buf, size_t req_sz, void *resp_buf, - u32 resp_sz, __u64 *fw_err) +static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, + struct snp_guest_request_ioctl *rio, u8 type, + void *req_buf, size_t req_sz, void *resp_buf, + u32 resp_sz) { u64 seqno; int rc; @@ -417,19 +431,31 @@ static int handle_guest_request(struct snp_guest_dev *snp_dev, u64 exit_code, in if (!seqno) return -EIO; + /* Clear shared memory's response for the host to populate. */ memset(snp_dev->response, 0, sizeof(struct snp_guest_msg)); - /* Encrypt the userspace provided payload */ - rc = enc_payload(snp_dev, seqno, msg_ver, type, req_buf, req_sz); + /* Encrypt the userspace provided payload in snp_dev->secret_request. */ + rc = enc_payload(snp_dev, seqno, rio->msg_version, type, req_buf, req_sz); if (rc) return rc; - rc = __handle_guest_request(snp_dev, exit_code, fw_err); + /* + * Write the fully encrypted request to the shared unencrypted + * request page. + */ + memcpy(snp_dev->request, &snp_dev->secret_request, + sizeof(snp_dev->secret_request)); + + rc = __handle_guest_request(snp_dev, exit_code, rio); if (rc) { - if (rc == -EIO && *fw_err == SNP_GUEST_REQ_INVALID_LEN) + if (rc == -EIO && + rio->exitinfo2 == SNP_GUEST_VMM_ERR(SNP_GUEST_VMM_ERR_INVALID_LEN)) return rc; - dev_alert(snp_dev->dev, "Detected error from ASP request. rc: %d, fw_err: %llu\n", rc, *fw_err); + dev_alert(snp_dev->dev, + "Detected error from ASP request. rc: %d, exitinfo2: 0x%llx\n", + rc, rio->exitinfo2); + snp_disable_vmpck(snp_dev); return rc; } @@ -469,9 +495,9 @@ static int get_report(struct snp_guest_dev *snp_dev, struct snp_guest_request_io if (!resp) return -ENOMEM; - rc = handle_guest_request(snp_dev, SVM_VMGEXIT_GUEST_REQUEST, arg->msg_version, + rc = handle_guest_request(snp_dev, SVM_VMGEXIT_GUEST_REQUEST, arg, SNP_MSG_REPORT_REQ, &req, sizeof(req), resp->data, - resp_len, &arg->fw_err); + resp_len); if (rc) goto e_free; @@ -509,9 +535,8 @@ static int get_derived_key(struct snp_guest_dev *snp_dev, struct snp_guest_reque if (copy_from_user(&req, (void __user *)arg->req_data, sizeof(req))) return -EFAULT; - rc = handle_guest_request(snp_dev, SVM_VMGEXIT_GUEST_REQUEST, arg->msg_version, - SNP_MSG_KEY_REQ, &req, sizeof(req), buf, resp_len, - &arg->fw_err); + rc = handle_guest_request(snp_dev, SVM_VMGEXIT_GUEST_REQUEST, arg, + SNP_MSG_KEY_REQ, &req, sizeof(req), buf, resp_len); if (rc) return rc; @@ -571,12 +596,12 @@ cmd: return -ENOMEM; snp_dev->input.data_npages = npages; - ret = handle_guest_request(snp_dev, SVM_VMGEXIT_EXT_GUEST_REQUEST, arg->msg_version, + ret = handle_guest_request(snp_dev, SVM_VMGEXIT_EXT_GUEST_REQUEST, arg, SNP_MSG_REPORT_REQ, &req.data, - sizeof(req.data), resp->data, resp_len, &arg->fw_err); + sizeof(req.data), resp->data, resp_len); /* If certs length is invalid then copy the returned length */ - if (arg->fw_err == SNP_GUEST_REQ_INVALID_LEN) { + if (arg->vmm_error == SNP_GUEST_VMM_ERR_INVALID_LEN) { req.certs_len = snp_dev->input.data_npages << PAGE_SHIFT; if (copy_to_user((void __user *)arg->req_data, &req, sizeof(req))) @@ -611,7 +636,7 @@ static long snp_guest_ioctl(struct file *file, unsigned int ioctl, unsigned long if (copy_from_user(&input, argp, sizeof(input))) return -EFAULT; - input.fw_err = 0xff; + input.exitinfo2 = 0xff; /* Message version must be non-zero */ if (!input.msg_version) @@ -642,7 +667,7 @@ static long snp_guest_ioctl(struct file *file, unsigned int ioctl, unsigned long mutex_unlock(&snp_cmd_mutex); - if (input.fw_err && copy_to_user(argp, &input, sizeof(input))) + if (input.exitinfo2 && copy_to_user(argp, &input, sizeof(input))) return -EFAULT; return ret; |