diff options
Diffstat (limited to 'drivers')
36 files changed, 332 insertions, 136 deletions
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 77d694448990..858320b6ebb7 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -316,9 +316,6 @@ config BLK_DEV_RBD tristate "Rados block device (RBD)" depends on INET && BLOCK select CEPH_LIB - select CRC32 - select CRYPTO_AES - select CRYPTO help Say Y here if you want include the Rados block device, which stripes a block device over objects stored in the Ceph distributed object diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 033c44326552..fffb47b62f43 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -429,7 +429,14 @@ static void sn65dsi83_handle_errors(struct sn65dsi83 *ctx) */ ret = regmap_read(ctx->regmap, REG_IRQ_STAT, &irq_stat); - if (ret || irq_stat) { + + /* + * Some hardware (Toradex Verdin AM62) is known to report the + * PLL_UNLOCK error interrupt while working without visible + * problems. In lack of a reliable way to discriminate such cases + * from user-visible PLL_UNLOCK cases, ignore that bit entirely. + */ + if (ret || irq_stat & ~REG_IRQ_STAT_CHA_PLL_UNLOCK) { /* * IRQ acknowledged is not always possible (the bridge can be in * a state where it doesn't answer anymore). To prevent an @@ -654,7 +661,7 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, if (ctx->irq) { /* Enable irq to detect errors */ regmap_write(ctx->regmap, REG_IRQ_GLOBAL, REG_IRQ_GLOBAL_IRQ_EN); - regmap_write(ctx->regmap, REG_IRQ_EN, 0xff); + regmap_write(ctx->regmap, REG_IRQ_EN, 0xff & ~REG_IRQ_EN_CHA_PLL_UNLOCK_EN); } else { /* Use the polling task */ sn65dsi83_monitor_start(ctx); diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index ce76c55913f7..b143589717e6 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -338,14 +338,14 @@ static int drm_plane_create_hotspot_properties(struct drm_plane *plane) prop_x = drm_property_create_signed_range(plane->dev, 0, "HOTSPOT_X", INT_MIN, INT_MAX); - if (IS_ERR(prop_x)) - return PTR_ERR(prop_x); + if (!prop_x) + return -ENOMEM; prop_y = drm_property_create_signed_range(plane->dev, 0, "HOTSPOT_Y", INT_MIN, INT_MAX); - if (IS_ERR(prop_y)) { + if (!prop_y) { drm_property_destroy(plane->dev, prop_x); - return PTR_ERR(prop_y); + return -ENOMEM; } drm_object_attach_property(&plane->base, prop_x, 0); diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 951d715dea30..d019177462cf 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -161,6 +161,30 @@ static void mgag200_set_startadd(struct mga_device *mdev, WREG_ECRT(0x00, crtcext0); } +/* + * Set the opmode for the hardware swapper for Big-Endian processor + * support for the frame buffer aperture and DMAWIN space. + */ +static void mgag200_set_datasiz(struct mga_device *mdev, u32 format) +{ +#if defined(__BIG_ENDIAN) + u32 opmode = RREG32(MGAREG_OPMODE); + + opmode &= ~(GENMASK(17, 16) | GENMASK(9, 8) | GENMASK(3, 2)); + + /* Big-endian byte-swapping */ + switch (format) { + case DRM_FORMAT_RGB565: + opmode |= 0x10100; + break; + case DRM_FORMAT_XRGB8888: + opmode |= 0x20200; + break; + } + WREG32(MGAREG_OPMODE, opmode); +#endif +} + void mgag200_init_registers(struct mga_device *mdev) { u8 crtc11, misc; @@ -496,6 +520,7 @@ void mgag200_primary_plane_helper_atomic_update(struct drm_plane *plane, struct drm_atomic_helper_damage_iter iter; struct drm_rect damage; + mgag200_set_datasiz(mdev, fb->format->format); drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); drm_atomic_for_each_plane_damage(&iter, &damage) { mgag200_handle_damage(mdev, shadow_plane_state->data, fb, &damage); diff --git a/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c b/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c index e2bf99c43336..a60209097a20 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c +++ b/drivers/gpu/drm/nouveau/dispnv04/nouveau_i2c_encoder.c @@ -94,26 +94,6 @@ fail_unregister: return err; } -/** - * nouveau_i2c_encoder_destroy - Unregister the I2C device backing an encoder - * @drm_encoder: Encoder to be unregistered. - * - * This should be called from the @destroy method of an I2C slave - * encoder driver once I2C access is no longer needed. - */ -void nouveau_i2c_encoder_destroy(struct drm_encoder *drm_encoder) -{ - struct nouveau_i2c_encoder *encoder = to_encoder_i2c(drm_encoder); - struct i2c_client *client = nouveau_i2c_encoder_get_client(drm_encoder); - struct module *module = client->dev.driver->owner; - - i2c_unregister_device(client); - encoder->i2c_client = NULL; - - module_put(module); -} -EXPORT_SYMBOL(nouveau_i2c_encoder_destroy); - /* * Wrapper fxns which can be plugged in to drm_encoder_helper_funcs: */ diff --git a/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h b/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h index 31334aa90781..869820701a56 100644 --- a/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h +++ b/drivers/gpu/drm/nouveau/include/dispnv04/i2c/encoder_i2c.h @@ -202,7 +202,24 @@ static inline struct i2c_client *nouveau_i2c_encoder_get_client(struct drm_encod return to_encoder_i2c(encoder)->i2c_client; } -void nouveau_i2c_encoder_destroy(struct drm_encoder *encoder); +/** + * nouveau_i2c_encoder_destroy - Unregister the I2C device backing an encoder + * @drm_encoder: Encoder to be unregistered. + * + * This should be called from the @destroy method of an I2C slave + * encoder driver once I2C access is no longer needed. + */ +static __always_inline void nouveau_i2c_encoder_destroy(struct drm_encoder *drm_encoder) +{ + struct nouveau_i2c_encoder *encoder = to_encoder_i2c(drm_encoder); + struct i2c_client *client = nouveau_i2c_encoder_get_client(drm_encoder); + struct module *module = client->dev.driver->owner; + + i2c_unregister_device(client); + encoder->i2c_client = NULL; + + module_put(module); +} /* * Wrapper fxns which can be plugged in to drm_encoder_helper_funcs: diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h index 226c7ec56b8e..b8b97e10ae83 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h @@ -73,6 +73,10 @@ struct nvkm_gsp { const struct firmware *bl; const struct firmware *rm; + + struct { + struct nvkm_falcon_fw sb; + } falcon; } fws; struct nvkm_firmware fw; diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 869d4335c0f4..4a193b7d6d9e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -183,11 +183,11 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha fctx->context = drm->runl[chan->runlist].context_base + chan->chid; if (chan == drm->cechan) - strcpy(fctx->name, "copy engine channel"); + strscpy(fctx->name, "copy engine channel"); else if (chan == drm->channel) - strcpy(fctx->name, "generic kernel channel"); + strscpy(fctx->name, "generic kernel channel"); else - strcpy(fctx->name, cli->name); + strscpy(fctx->name, cli->name); kref_init(&fctx->fence_ref); if (!priv->uevent) diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c index 5c07a9ee8b77..34effe6d86ad 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c @@ -125,7 +125,7 @@ nouveau_hwmon_get_pwm1_max(struct device *d, if (ret < 0) return ret; - return sprintf(buf, "%i\n", ret); + return sysfs_emit(buf, "%i\n", ret); } static ssize_t @@ -141,7 +141,7 @@ nouveau_hwmon_get_pwm1_min(struct device *d, if (ret < 0) return ret; - return sprintf(buf, "%i\n", ret); + return sysfs_emit(buf, "%i\n", ret); } static ssize_t diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c index 5b721bd9d799..503760246660 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/fwsec.c @@ -259,18 +259,16 @@ nvkm_gsp_fwsec_v3(struct nvkm_gsp *gsp, const char *name, } static int -nvkm_gsp_fwsec(struct nvkm_gsp *gsp, const char *name, u32 init_cmd) +nvkm_gsp_fwsec_init(struct nvkm_gsp *gsp, struct nvkm_falcon_fw *fw, const char *name, u32 init_cmd) { struct nvkm_subdev *subdev = &gsp->subdev; struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; const union nvfw_falcon_ucode_desc *desc; struct nvbios_pmuE flcn_ucode; - u8 idx, ver, hdr; u32 data; u16 size, vers; - struct nvkm_falcon_fw fw = {}; - u32 mbox0 = 0; + u8 idx, ver, hdr; int ret; /* Lookup in VBIOS. */ @@ -291,8 +289,8 @@ nvkm_gsp_fwsec(struct nvkm_gsp *gsp, const char *name, u32 init_cmd) vers = (desc->v2.Hdr & 0x0000ff00) >> 8; switch (vers) { - case 2: ret = nvkm_gsp_fwsec_v2(gsp, name, &desc->v2, size, init_cmd, &fw); break; - case 3: ret = nvkm_gsp_fwsec_v3(gsp, name, &desc->v3, size, init_cmd, &fw); break; + case 2: ret = nvkm_gsp_fwsec_v2(gsp, name, &desc->v2, size, init_cmd, fw); break; + case 3: ret = nvkm_gsp_fwsec_v3(gsp, name, &desc->v3, size, init_cmd, fw); break; default: nvkm_error(subdev, "%s(v%d): version unknown\n", name, vers); return -EINVAL; @@ -303,15 +301,19 @@ nvkm_gsp_fwsec(struct nvkm_gsp *gsp, const char *name, u32 init_cmd) return ret; } - /* Boot. */ - ret = nvkm_falcon_fw_boot(&fw, subdev, true, &mbox0, NULL, 0, 0); - nvkm_falcon_fw_dtor(&fw); - if (ret) - return ret; - return 0; } +static int +nvkm_gsp_fwsec_boot(struct nvkm_gsp *gsp, struct nvkm_falcon_fw *fw) +{ + struct nvkm_subdev *subdev = &gsp->subdev; + u32 mbox0 = 0; + + /* Boot */ + return nvkm_falcon_fw_boot(fw, subdev, true, &mbox0, NULL, 0, 0); +} + int nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp) { @@ -320,7 +322,7 @@ nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp) int ret; u32 err; - ret = nvkm_gsp_fwsec(gsp, "fwsec-sb", NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB); + ret = nvkm_gsp_fwsec_boot(gsp, &gsp->fws.falcon.sb); if (ret) return ret; @@ -335,26 +337,47 @@ nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp) } int +nvkm_gsp_fwsec_sb_ctor(struct nvkm_gsp *gsp) +{ + return nvkm_gsp_fwsec_init(gsp, &gsp->fws.falcon.sb, "fwsec-sb", + NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB); +} + +void +nvkm_gsp_fwsec_sb_dtor(struct nvkm_gsp *gsp) +{ + nvkm_falcon_fw_dtor(&gsp->fws.falcon.sb); +} + +int nvkm_gsp_fwsec_frts(struct nvkm_gsp *gsp) { struct nvkm_subdev *subdev = &gsp->subdev; struct nvkm_device *device = subdev->device; + struct nvkm_falcon_fw fw = {}; int ret; u32 err, wpr2_lo, wpr2_hi; - ret = nvkm_gsp_fwsec(gsp, "fwsec-frts", NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS); + ret = nvkm_gsp_fwsec_init(gsp, &fw, "fwsec-frts", NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS); if (ret) return ret; + ret = nvkm_gsp_fwsec_boot(gsp, &fw); + if (ret) + goto fwsec_dtor; + /* Verify. */ err = nvkm_rd32(device, 0x001400 + (0xe * 4)) >> 16; if (err) { nvkm_error(subdev, "fwsec-frts: 0x%04x\n", err); - return -EIO; + ret = -EIO; + } else { + wpr2_lo = nvkm_rd32(device, 0x1fa824); + wpr2_hi = nvkm_rd32(device, 0x1fa828); + nvkm_debug(subdev, "fwsec-frts: WPR2 @ %08x - %08x\n", wpr2_lo, wpr2_hi); } - wpr2_lo = nvkm_rd32(device, 0x1fa824); - wpr2_hi = nvkm_rd32(device, 0x1fa828); - nvkm_debug(subdev, "fwsec-frts: WPR2 @ %08x - %08x\n", wpr2_lo, wpr2_hi); - return 0; +fwsec_dtor: + nvkm_falcon_fw_dtor(&fw); + return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h index c3494b7ac572..86bdd203bc10 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/priv.h @@ -6,7 +6,10 @@ enum nvkm_acr_lsf_id; int nvkm_gsp_fwsec_frts(struct nvkm_gsp *); + +int nvkm_gsp_fwsec_sb_ctor(struct nvkm_gsp *); int nvkm_gsp_fwsec_sb(struct nvkm_gsp *); +void nvkm_gsp_fwsec_sb_dtor(struct nvkm_gsp *); struct nvkm_gsp_fwif { int version; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c index 32e6a065d6d7..2a7e80c6d70f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c @@ -1817,12 +1817,16 @@ r535_gsp_rm_boot_ctor(struct nvkm_gsp *gsp) RM_RISCV_UCODE_DESC *desc; int ret; + ret = nvkm_gsp_fwsec_sb_ctor(gsp); + if (ret) + return ret; + hdr = nvfw_bin_hdr(&gsp->subdev, fw->data); desc = (void *)fw->data + hdr->header_offset; ret = nvkm_gsp_mem_ctor(gsp, hdr->data_size, &gsp->boot.fw); if (ret) - return ret; + goto dtor_fwsec; memcpy(gsp->boot.fw.data, fw->data + hdr->data_offset, hdr->data_size); @@ -1831,6 +1835,9 @@ r535_gsp_rm_boot_ctor(struct nvkm_gsp *gsp) gsp->boot.manifest_offset = desc->manifestOffset; gsp->boot.app_version = desc->appVersion; return 0; +dtor_fwsec: + nvkm_gsp_fwsec_sb_dtor(gsp); + return ret; } static const struct nvkm_firmware_func @@ -2101,6 +2108,7 @@ r535_gsp_dtor(struct nvkm_gsp *gsp) mutex_destroy(&gsp->cmdq.mutex); nvkm_gsp_dtor_fws(gsp); + nvkm_gsp_fwsec_sb_dtor(gsp); nvkm_gsp_mem_dtor(&gsp->rmargs); nvkm_gsp_mem_dtor(&gsp->wpr_meta); diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35560.c b/drivers/gpu/drm/panel/panel-novatek-nt35560.c index 561e6643dcbb..6e5173f98a22 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35560.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35560.c @@ -213,7 +213,7 @@ static const struct backlight_properties nt35560_bl_props = { static void nt35560_read_id(struct mipi_dsi_multi_context *dsi_ctx) { - struct device dev = dsi_ctx->dsi->dev; + struct device *dev = &dsi_ctx->dsi->dev; u8 vendor, version, panel; u16 val; @@ -225,7 +225,7 @@ static void nt35560_read_id(struct mipi_dsi_multi_context *dsi_ctx) return; if (vendor == 0x00) { - dev_err(&dev, "device vendor ID is zero\n"); + dev_err(dev, "device vendor ID is zero\n"); dsi_ctx->accum_err = -ENODEV; return; } @@ -236,12 +236,12 @@ static void nt35560_read_id(struct mipi_dsi_multi_context *dsi_ctx) case DISPLAY_SONY_ACX424AKP_ID2: case DISPLAY_SONY_ACX424AKP_ID3: case DISPLAY_SONY_ACX424AKP_ID4: - dev_info(&dev, + dev_info(dev, "MTP vendor: %02x, version: %02x, panel: %02x\n", vendor, version, panel); break; default: - dev_info(&dev, + dev_info(dev, "unknown vendor: %02x, version: %02x, panel: %02x\n", vendor, version, panel); break; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 5718d9d83a49..52c95131af5a 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -586,7 +586,7 @@ out: drm_modeset_unlock(&crtc->mutex); } -static void tilcdc_crtc_destroy(struct drm_crtc *crtc) +void tilcdc_crtc_destroy(struct drm_crtc *crtc) { struct tilcdc_drm_private *priv = crtc->dev->dev_private; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 7caec4d38ddf..3dcbec312bac 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -172,8 +172,7 @@ static void tilcdc_fini(struct drm_device *dev) if (priv->crtc) tilcdc_crtc_shutdown(priv->crtc); - if (priv->is_registered) - drm_dev_unregister(dev); + drm_dev_unregister(dev); drm_kms_helper_poll_fini(dev); drm_atomic_helper_shutdown(dev); @@ -220,21 +219,21 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) priv->wq = alloc_ordered_workqueue("tilcdc", 0); if (!priv->wq) { ret = -ENOMEM; - goto init_failed; + goto put_drm; } priv->mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->mmio)) { dev_err(dev, "failed to request / ioremap\n"); ret = PTR_ERR(priv->mmio); - goto init_failed; + goto free_wq; } priv->clk = clk_get(dev, "fck"); if (IS_ERR(priv->clk)) { dev_err(dev, "failed to get functional clock\n"); ret = -ENODEV; - goto init_failed; + goto free_wq; } pm_runtime_enable(dev); @@ -313,7 +312,7 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) ret = tilcdc_crtc_create(ddev); if (ret < 0) { dev_err(dev, "failed to create crtc\n"); - goto init_failed; + goto disable_pm; } modeset_init(ddev); @@ -324,46 +323,46 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) if (ret) { dev_err(dev, "failed to register cpufreq notifier\n"); priv->freq_transition.notifier_call = NULL; - goto init_failed; + goto destroy_crtc; } #endif if (priv->is_componentized) { ret = component_bind_all(dev, ddev); if (ret < 0) - goto init_failed; + goto unregister_cpufreq_notif; ret = tilcdc_add_component_encoder(ddev); if (ret < 0) - goto init_failed; + goto unbind_component; } else { ret = tilcdc_attach_external_device(ddev); if (ret) - goto init_failed; + goto unregister_cpufreq_notif; } if (!priv->external_connector && ((priv->num_encoders == 0) || (priv->num_connectors == 0))) { dev_err(dev, "no encoders/connectors found\n"); ret = -EPROBE_DEFER; - goto init_failed; + goto unbind_component; } ret = drm_vblank_init(ddev, 1); if (ret < 0) { dev_err(dev, "failed to initialize vblank\n"); - goto init_failed; + goto unbind_component; } ret = platform_get_irq(pdev, 0); if (ret < 0) - goto init_failed; + goto unbind_component; priv->irq = ret; ret = tilcdc_irq_install(ddev, priv->irq); if (ret < 0) { dev_err(dev, "failed to install IRQ handler\n"); - goto init_failed; + goto unbind_component; } drm_mode_config_reset(ddev); @@ -372,16 +371,34 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) ret = drm_dev_register(ddev, 0); if (ret) - goto init_failed; - priv->is_registered = true; + goto stop_poll; drm_client_setup_with_color_mode(ddev, bpp); return 0; -init_failed: - tilcdc_fini(ddev); +stop_poll: + drm_kms_helper_poll_fini(ddev); + tilcdc_irq_uninstall(ddev); +unbind_component: + if (priv->is_componentized) + component_unbind_all(dev, ddev); +unregister_cpufreq_notif: +#ifdef CONFIG_CPU_FREQ + cpufreq_unregister_notifier(&priv->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +destroy_crtc: +#endif + tilcdc_crtc_destroy(priv->crtc); +disable_pm: + pm_runtime_disable(dev); + clk_put(priv->clk); +free_wq: + destroy_workqueue(priv->wq); +put_drm: platform_set_drvdata(pdev, NULL); + ddev->dev_private = NULL; + drm_dev_put(ddev); return ret; } diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index b818448c83f6..58b276f82a66 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -82,7 +82,6 @@ struct tilcdc_drm_private { struct drm_encoder *external_encoder; struct drm_connector *external_connector; - bool is_registered; bool is_componentized; bool irq_enabled; }; @@ -164,6 +163,7 @@ void tilcdc_crtc_set_panel_info(struct drm_crtc *crtc, void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc, bool simulate_vesa_sync); void tilcdc_crtc_shutdown(struct drm_crtc *crtc); +void tilcdc_crtc_destroy(struct drm_crtc *crtc); int tilcdc_crtc_update_fb(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event); diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index b47020fca199..e6abc7b40b18 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -434,6 +434,11 @@ int ttm_bo_access(struct ttm_buffer_object *bo, unsigned long offset, if (ret) return ret; + if (!bo->resource) { + ret = -ENODATA; + goto unlock; + } + switch (bo->resource->mem_type) { case TTM_PL_SYSTEM: fallthrough; @@ -448,6 +453,7 @@ int ttm_bo_access(struct ttm_buffer_object *bo, unsigned long offset, ret = -EIO; } +unlock: ttm_bo_unreserve(bo); return ret; diff --git a/drivers/irqchip/irq-mchp-eic.c b/drivers/irqchip/irq-mchp-eic.c index 2474fa467a05..31093a8ab67c 100644 --- a/drivers/irqchip/irq-mchp-eic.c +++ b/drivers/irqchip/irq-mchp-eic.c @@ -170,7 +170,7 @@ static int mchp_eic_domain_alloc(struct irq_domain *domain, unsigned int virq, ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type); if (ret || hwirq >= MCHP_EIC_NIRQ) - return ret; + return ret ?: -EINVAL; switch (type) { case IRQ_TYPE_EDGE_RISING: diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index c18358271618..d5d6ef7ba838 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -950,6 +950,19 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps q = bdev_get_queue(p->path.dev->bdev); attached_handler_name = scsi_dh_attached_handler_name(q, GFP_KERNEL); + if (IS_ERR(attached_handler_name)) { + if (PTR_ERR(attached_handler_name) == -ENODEV) { + if (m->hw_handler_name) { + DMERR("hardware handlers are only allowed for SCSI devices"); + kfree(m->hw_handler_name); + m->hw_handler_name = NULL; + } + attached_handler_name = NULL; + } else { + r = PTR_ERR(attached_handler_name); + goto bad; + } + } if (attached_handler_name || m->hw_handler_name) { INIT_DELAYED_WORK(&p->activate_path, activate_path_work); r = setup_scsi_dh(p->path.dev->bdev, m, &attached_handler_name, &ti->error); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 9d1de68dee27..d7d41b054b98 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -106,7 +106,6 @@ config PHANTOM config RPMB tristate "RPMB partition interface" - depends on MMC || SCSI_UFSHCD help Unified RPMB unit interface for RPMB capable devices such as eMMC and UFS. Provides interface for in-kernel security controllers to access diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 5c602c057798..45b0e33293a5 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -1260,6 +1260,7 @@ static void imm_detach(struct parport *pb) imm_struct *dev; list_for_each_entry(dev, &imm_hosts, list) { if (dev->dev->port == pb) { + disable_delayed_work_sync(&dev->imm_tq); list_del_init(&dev->list); scsi_remove_host(dev->host); scsi_host_put(dev->host); diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 95123689e9d1..dbd58a7e7bc1 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -61,8 +61,8 @@ #include <linux/hdreg.h> #include <linux/reboot.h> #include <linux/stringify.h> +#include <linux/irq.h> #include <asm/io.h> -#include <asm/irq.h> #include <asm/processor.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> @@ -7844,6 +7844,30 @@ static int ipr_dump_mailbox_wait(struct ipr_cmnd *ipr_cmd) } /** + * ipr_set_affinity_nobalance + * @ioa_cfg: ipr_ioa_cfg struct for an ipr device + * @flag: bool + * true: ensable "IRQ_NO_BALANCING" bit for msix interrupt + * false: disable "IRQ_NO_BALANCING" bit for msix interrupt + * Description: This function will be called to disable/enable + * "IRQ_NO_BALANCING" to avoid irqbalance daemon + * kicking in during adapter reset. + **/ +static void ipr_set_affinity_nobalance(struct ipr_ioa_cfg *ioa_cfg, bool flag) +{ + int irq, i; + + for (i = 0; i < ioa_cfg->nvectors; i++) { + irq = pci_irq_vector(ioa_cfg->pdev, i); + + if (flag) + irq_set_status_flags(irq, IRQ_NO_BALANCING); + else + irq_clear_status_flags(irq, IRQ_NO_BALANCING); + } +} + +/** * ipr_reset_restore_cfg_space - Restore PCI config space. * @ipr_cmd: ipr command struct * @@ -7866,6 +7890,7 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) return IPR_RC_JOB_CONTINUE; } + ipr_set_affinity_nobalance(ioa_cfg, false); ipr_fail_all_ops(ioa_cfg); if (ioa_cfg->sis64) { @@ -7945,6 +7970,7 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START); if (rc == PCIBIOS_SUCCESSFUL) { + ipr_set_affinity_nobalance(ioa_cfg, true); ipr_cmd->job_step = ipr_reset_bist_done; ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT); rc = IPR_RC_JOB_RETURN; diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 8566bb1208a0..6b15ad1bcada 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -141,6 +141,7 @@ Undo_event_q: Undo_ports: sas_unregister_ports(sas_ha); Undo_phys: + sas_unregister_phys(sas_ha); return error; } diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index 6706f2be8d27..d104c87f04f5 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -54,6 +54,7 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev); void sas_scsi_recover_host(struct Scsi_Host *shost); int sas_register_phys(struct sas_ha_struct *sas_ha); +void sas_unregister_phys(struct sas_ha_struct *sas_ha); struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy, gfp_t gfp_flags); void sas_free_event(struct asd_sas_event *event); @@ -145,20 +146,6 @@ static inline void sas_fail_probe(struct domain_device *dev, const char *func, i func, dev->parent ? "exp-attached" : "direct-attached", SAS_ADDR(dev->sas_addr), err); - - /* - * If the device probe failed, the expander phy attached address - * needs to be reset so that the phy will not be treated as flutter - * in the next revalidation - */ - if (dev->parent && !dev_is_expander(dev->dev_type)) { - struct sas_phy *phy = dev->phy; - struct domain_device *parent = dev->parent; - struct ex_phy *ex_phy = &parent->ex_dev.ex_phy[phy->number]; - - memset(ex_phy->attached_sas_addr, 0, SAS_ADDR_SIZE); - } - sas_unregister_dev(dev->port, dev); } diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c index 635835c28ecd..58f08dc2c187 100644 --- a/drivers/scsi/libsas/sas_phy.c +++ b/drivers/scsi/libsas/sas_phy.c @@ -116,6 +116,7 @@ static void sas_phye_shutdown(struct work_struct *work) int sas_register_phys(struct sas_ha_struct *sas_ha) { int i; + int err; /* Now register the phys. */ for (i = 0; i < sas_ha->num_phys; i++) { @@ -132,8 +133,10 @@ int sas_register_phys(struct sas_ha_struct *sas_ha) phy->frame_rcvd_size = 0; phy->phy = sas_phy_alloc(&sas_ha->shost->shost_gendev, i); - if (!phy->phy) - return -ENOMEM; + if (!phy->phy) { + err = -ENOMEM; + goto rollback; + } phy->phy->identify.initiator_port_protocols = phy->iproto; @@ -146,10 +149,34 @@ int sas_register_phys(struct sas_ha_struct *sas_ha) phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN; phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; - sas_phy_add(phy->phy); + err = sas_phy_add(phy->phy); + if (err) { + sas_phy_free(phy->phy); + goto rollback; + } } return 0; +rollback: + for (i-- ; i >= 0 ; i--) { + struct asd_sas_phy *phy = sas_ha->sas_phy[i]; + + sas_phy_delete(phy->phy); + sas_phy_free(phy->phy); + } + return err; +} + +void sas_unregister_phys(struct sas_ha_struct *sas_ha) +{ + int i; + + for (i = 0 ; i < sas_ha->num_phys ; i++) { + struct asd_sas_phy *phy = sas_ha->sas_phy[i]; + + sas_phy_delete(phy->phy); + sas_phy_free(phy->phy); + } } const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = { diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 6742684e2990..31d68c151b20 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -56,8 +56,8 @@ extern struct list_head mrioc_list; extern int prot_mask; extern atomic64_t event_counter; -#define MPI3MR_DRIVER_VERSION "8.15.0.5.50" -#define MPI3MR_DRIVER_RELDATE "12-August-2025" +#define MPI3MR_DRIVER_VERSION "8.15.0.5.51" +#define MPI3MR_DRIVER_RELDATE "18-November-2025" #define MPI3MR_DRIVER_NAME "mpi3mr" #define MPI3MR_DRIVER_LICENSE "GPL" diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index b88633e1efe2..d4ca878d0886 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -1184,6 +1184,8 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, if (is_added == true) tgtdev->io_throttle_enabled = (flags & MPI3_DEVICE0_FLAGS_IO_THROTTLING_REQUIRED) ? 1 : 0; + if (!mrioc->sas_transport_enabled) + tgtdev->non_stl = 1; switch (flags & MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_MASK) { case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_256_LB: @@ -4844,7 +4846,7 @@ static int mpi3mr_target_alloc(struct scsi_target *starget) spin_lock_irqsave(&mrioc->tgtdev_lock, flags); if (starget->channel == mrioc->scsi_device_channel) { tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id); - if (tgt_dev && !tgt_dev->is_hidden) { + if (tgt_dev && !tgt_dev->is_hidden && tgt_dev->non_stl) { scsi_tgt_priv_data->starget = starget; scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle; scsi_tgt_priv_data->perst_id = tgt_dev->perst_id; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 3a57f07d73f5..16a44c0917e1 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -17,6 +17,7 @@ #include <linux/crash_dump.h> #include <linux/trace_events.h> #include <linux/trace.h> +#include <linux/irq.h> #include <scsi/scsi_tcq.h> #include <scsi/scsicam.h> @@ -7776,6 +7777,31 @@ static void qla_pci_error_cleanup(scsi_qla_host_t *vha) } +/** + * qla2xxx_set_affinity_nobalance + * @pdev: pci_dev struct for a qla2xxx device + * @flag: bool + * true: enable "IRQ_NO_BALANCING" bit for msix interrupt + * false: disable "IRQ_NO_BALANCING" bit for msix interrupt + * Description: This function will be called to disable/enable + * "IRQ_NO_BALANCING" to avoid irqbalance daemon + * kicking in during adapter reset. + **/ + +static void qla2xxx_set_affinity_nobalance(struct pci_dev *pdev, bool flag) +{ + int irq, i; + + for (i = 0; i < QLA_BASE_VECTORS; i++) { + irq = pci_irq_vector(pdev, i); + + if (flag) + irq_set_status_flags(irq, IRQ_NO_BALANCING); + else + irq_clear_status_flags(irq, IRQ_NO_BALANCING); + } +} + static pci_ers_result_t qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { @@ -7794,6 +7820,8 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) goto out; } + qla2xxx_set_affinity_nobalance(pdev, false); + switch (state) { case pci_channel_io_normal: qla_pci_set_eeh_busy(vha); @@ -7930,6 +7958,8 @@ exit_slot_reset: ql_dbg(ql_dbg_aer, base_vha, 0x900e, "Slot Reset returning %x.\n", ret); + qla2xxx_set_affinity_nobalance(pdev, true); + return ret; } diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index da2fc66ffedd..b0a62aaa1cca 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -1552,7 +1552,7 @@ static int qla4_82xx_cmdpeg_ready(struct scsi_qla_host *ha, int pegtune_val) (val == PHAN_INITIALIZE_ACK)) return 0; set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(500); + schedule_timeout(msecs_to_jiffies(500)); } while (--retries); diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index 7b56e00c7df6..b9d805317814 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -353,7 +353,8 @@ EXPORT_SYMBOL_GPL(scsi_dh_attach); * that may have a device handler attached * @gfp - the GFP mask used in the kmalloc() call when allocating memory * - * Returns name of attached handler, NULL if no handler is attached. + * Returns name of attached handler, NULL if no handler is attached, or + * and error pointer if an error occurred. * Caller must take care to free the returned string. */ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp) @@ -363,10 +364,11 @@ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp) sdev = scsi_device_from_queue(q); if (!sdev) - return NULL; + return ERR_PTR(-ENODEV); if (sdev->handler) - handler_name = kstrdup(sdev->handler->name, gfp); + handler_name = kstrdup(sdev->handler->name, gfp) ? : + ERR_PTR(-ENOMEM); put_device(&sdev->sdev_gendev); return handler_name; } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 51ad2ad07e43..93031326ac3e 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2801,7 +2801,7 @@ EXPORT_SYMBOL_GPL(sdev_evt_send_simple); * * Must be called with user context, may sleep. * - * Returns zero if unsuccessful or an error if not. + * Returns zero if successful or an error if not. */ int scsi_device_quiesce(struct scsi_device *sdev) diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index b8457477cee9..9f167ff8da7b 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -5,8 +5,7 @@ * Copyright (C) 2011 Chris Boot <bootc@bootc.net> */ -#define KMSG_COMPONENT "sbp_target" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#define pr_fmt(fmt) "sbp_target: " fmt #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index e8b7955d40f2..50d21888a0c9 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1524,6 +1524,7 @@ target_cmd_init_cdb(struct se_cmd *cmd, unsigned char *cdb, gfp_t gfp) if (scsi_command_size(cdb) > sizeof(cmd->__t_task_cdb)) { cmd->t_task_cdb = kzalloc(scsi_command_size(cdb), gfp); if (!cmd->t_task_cdb) { + cmd->t_task_cdb = &cmd->__t_task_cdb[0]; pr_err("Unable to allocate cmd->t_task_cdb" " %u > sizeof(cmd->__t_task_cdb): %lu ops\n", scsi_command_size(cdb), diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig index 90226f72c158..f662e7ce71f1 100644 --- a/drivers/ufs/Kconfig +++ b/drivers/ufs/Kconfig @@ -6,6 +6,7 @@ menuconfig SCSI_UFSHCD tristate "Universal Flash Storage Controller" depends on SCSI && SCSI_DMA + depends on RPMB || !RPMB select PM_DEVFREQ select DEVFREQ_GOV_SIMPLE_ONDEMAND select NLS diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 040a0ceb170a..80c0b49f30b0 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -1455,15 +1455,14 @@ out: static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, int err) { up_write(&hba->clk_scaling_lock); + mutex_unlock(&hba->wb_mutex); + blk_mq_unquiesce_tagset(&hba->host->tag_set); + mutex_unlock(&hba->host->scan_mutex); /* Enable Write Booster if current gear requires it else disable it */ if (ufshcd_enable_wb_if_scaling_up(hba) && !err) ufshcd_wb_toggle(hba, hba->pwr_info.gear_rx >= hba->clk_scaling.wb_gear); - mutex_unlock(&hba->wb_mutex); - - blk_mq_unquiesce_tagset(&hba->host->tag_set); - mutex_unlock(&hba->host->scan_mutex); ufshcd_release(hba); } @@ -6504,6 +6503,11 @@ static void ufshcd_clk_scaling_suspend(struct ufs_hba *hba, bool suspend) static void ufshcd_err_handling_prepare(struct ufs_hba *hba) { + /* + * A WLUN resume failure could potentially lead to the HBA being + * runtime suspended, so take an extra reference on hba->dev. + */ + pm_runtime_get_sync(hba->dev); ufshcd_rpm_get_sync(hba); if (pm_runtime_status_suspended(&hba->ufs_device_wlun->sdev_gendev) || hba->is_sys_suspended) { @@ -6543,6 +6547,7 @@ static void ufshcd_err_handling_unprepare(struct ufs_hba *hba) if (ufshcd_is_clkscaling_supported(hba)) ufshcd_clk_scaling_suspend(hba, false); ufshcd_rpm_put(hba); + pm_runtime_put(hba->dev); } static inline bool ufshcd_err_handling_should_stop(struct ufs_hba *hba) @@ -6557,28 +6562,42 @@ static inline bool ufshcd_err_handling_should_stop(struct ufs_hba *hba) #ifdef CONFIG_PM static void ufshcd_recover_pm_error(struct ufs_hba *hba) { + struct scsi_target *starget = hba->ufs_device_wlun->sdev_target; struct Scsi_Host *shost = hba->host; struct scsi_device *sdev; struct request_queue *q; - int ret; + bool resume_sdev_queues = false; hba->is_sys_suspended = false; + /* - * Set RPM status of wlun device to RPM_ACTIVE, - * this also clears its runtime error. + * Ensure the parent's error status is cleared before proceeding + * to the child, as the parent must be active to activate the child. */ - ret = pm_runtime_set_active(&hba->ufs_device_wlun->sdev_gendev); + if (hba->dev->power.runtime_error) { + /* hba->dev has no functional parent thus simplily set RPM_ACTIVE */ + pm_runtime_set_active(hba->dev); + resume_sdev_queues = true; + } + + if (hba->ufs_device_wlun->sdev_gendev.power.runtime_error) { + /* + * starget, parent of wlun, might be suspended if wlun resume failed. + * Make sure parent is resumed before set child (wlun) active. + */ + pm_runtime_get_sync(&starget->dev); + pm_runtime_set_active(&hba->ufs_device_wlun->sdev_gendev); + pm_runtime_put_sync(&starget->dev); + resume_sdev_queues = true; + } - /* hba device might have a runtime error otherwise */ - if (ret) - ret = pm_runtime_set_active(hba->dev); /* * If wlun device had runtime error, we also need to resume those * consumer scsi devices in case any of them has failed to be * resumed due to supplier runtime resume failure. This is to unblock * blk_queue_enter in case there are bios waiting inside it. */ - if (!ret) { + if (resume_sdev_queues) { shost_for_each_device(sdev, shost) { q = sdev->request_queue; if (q->dev && (q->rpm_status == RPM_SUSPENDED || @@ -6679,19 +6698,22 @@ static void ufshcd_err_handler(struct work_struct *work) hba->saved_uic_err, hba->force_reset, ufshcd_is_link_broken(hba) ? "; link is broken" : ""); - /* - * Use ufshcd_rpm_get_noresume() here to safely perform link recovery - * even if an error occurs during runtime suspend or runtime resume. - * This avoids potential deadlocks that could happen if we tried to - * resume the device while a PM operation is already in progress. - */ - ufshcd_rpm_get_noresume(hba); - if (hba->pm_op_in_progress) { - ufshcd_link_recovery(hba); + if (hba->ufs_device_wlun) { + /* + * Use ufshcd_rpm_get_noresume() here to safely perform link + * recovery even if an error occurs during runtime suspend or + * runtime resume. This avoids potential deadlocks that could + * happen if we tried to resume the device while a PM operation + * is already in progress. + */ + ufshcd_rpm_get_noresume(hba); + if (hba->pm_op_in_progress) { + ufshcd_link_recovery(hba); + ufshcd_rpm_put(hba); + return; + } ufshcd_rpm_put(hba); - return; } - ufshcd_rpm_put(hba); down(&hba->host_sem); spin_lock_irqsave(hba->host->host_lock, flags); diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 8d119b3223cb..8ebee0cc5313 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1769,10 +1769,9 @@ static void ufs_qcom_dump_testbus(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); int i, j, nminor = 0, testbus_len = 0; - u32 *testbus __free(kfree) = NULL; char *prefix; - testbus = kmalloc_array(256, sizeof(u32), GFP_KERNEL); + u32 *testbus __free(kfree) = kmalloc_array(256, sizeof(u32), GFP_KERNEL); if (!testbus) return; @@ -1794,13 +1793,12 @@ static void ufs_qcom_dump_testbus(struct ufs_hba *hba) static int ufs_qcom_dump_regs(struct ufs_hba *hba, size_t offset, size_t len, const char *prefix, void __iomem *base) { - u32 *regs __free(kfree) = NULL; size_t pos; if (offset % 4 != 0 || len % 4 != 0) return -EINVAL; - regs = kzalloc(len, GFP_ATOMIC); + u32 *regs __free(kfree) = kzalloc(len, GFP_ATOMIC); if (!regs) return -ENOMEM; |
