drm fixes for 6.19-rc1

plane:
 - Handle IS_ERR vs NULL in drm_plane_create_hotspot_properties().
 
 ttm:
 - fix devcoredump for evicted bos
 
 panel:
 - Fix stack usage warning in novatek-nt35560.
 
 nouveau:
 - alloc fwsec sb at boot to avoid s/r problems
 - fix strcpy usage
 - fix i2c encoder crash
 
 bridge:
 - Ignore spurious PLL_UNLOCK bit in ti-sn65dsi83.
 
 mgag200:
 - Fix bigendian handling in mgag200.
 
 tilcdc:
 - Fix probe failure in tilcdc.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEEKbZHaGwW9KfbeusDHTzWXnEhr4FAmk8zQYACgkQDHTzWXnE
 hr5dsw/+Mp4jXl4VbQv6VA9ykpjuwepJHZXh8qcHAUNaku0qPa5j3PRK3qHbHKGA
 2sVROdEcJUIgDbkwxOEe4V9ygn+w6qC0vLM6JYQgulUc9Haz4Srcg9g0nyagcSPD
 vmJdEGQzeYOXG2onkYssHJxGh1u0bfES4PY+ps/zbl+DD6he9ZxiIipr9+9SI+B/
 gwbSny9OFM6gwBvvO8u8R2S7Jnad5Fa+WKniNDLgpjJ8FlcAJWcSK62vsoQKUpfk
 1pbFq0SoM06YDElKVPX3O68ZYj4JvOqoK52BMs+5H+DPweqTmXZGU4q66NmKj4RA
 0RRh4zTPwMSSuqy0Q2HNaccCL6E/kgvRxCbGqfm5MWu9zsicD1cC2pEFs7umAjGE
 5s5QZxyG3jHQDThAXBS/gFIQaGp4fPZsCEtRWW07I19y4lVztokBYjapeh8KetEL
 5kSACpHPPLsoqIwFwPyYKOz9bJQuKpQEQNQLUn3QaP6/AX5E32ogSH5vxtOgmJDQ
 2VfcZ4w7ol/s4m/mlWhyANElOwH6gDIZklyHHVrwyPzg10oau8owxaFFbEcmzVh4
 OU+JGfu5q84P9GP8aXuixr5/yK/346/37CHxwGxCoy6sLzNUXCDbw/OeIcOF6/qP
 JkyiTq84UqA6OS1M3Bku2s51CbFTuO+M/Hj9a8MQFZ01EIjr29Y=
 =B5M8
 -----END PGP SIGNATURE-----

Merge tag 'drm-fixes-2025-12-13' of https://gitlab.freedesktop.org/drm/kernel

Pull more drm fixes from Dave Airlie:
 "These are the enqueued fixes that ended up in our fixes branch,
  nouveau mostly, along with some small fixes in other places.

  plane:
   - Handle IS_ERR vs NULL in drm_plane_create_hotspot_properties()

  ttm:
   - fix devcoredump for evicted bos

  panel:
   - Fix stack usage warning in novatek-nt35560

  nouveau:
   - alloc fwsec sb at boot to avoid s/r problems
   - fix strcpy usage
   - fix i2c encoder crash

  bridge:
   - Ignore spurious PLL_UNLOCK bit in ti-sn65dsi83

  mgag200:
   - Fix bigendian handling in mgag200

  tilcdc:
   - Fix probe failure in tilcdc"

* tag 'drm-fixes-2025-12-13' of https://gitlab.freedesktop.org/drm/kernel:
  drm/mgag200: Fix big-endian support
  drm/tilcdc: Fix removal actions in case of failed probe
  drm/ttm: Avoid NULL pointer deref for evicted BOs
  drm: nouveau: Replace sprintf() with sysfs_emit()
  drm/nouveau: fix circular dep oops from vendored i2c encoder
  drm/nouveau: refactor deprecated strcpy
  drm/plane: Fix IS_ERR() vs NULL check in drm_plane_create_hotspot_properties()
  drm/bridge: ti-sn65dsi83: ignore PLL_UNLOCK errors
  drm/nouveau/gsp: Allocate fwsec-sb at boot
  drm/panel: novatek-nt35560: avoid on-stack device structure
master
Linus Torvalds 2025-12-13 17:39:28 +12:00
commit a859eca0e4
16 changed files with 166 additions and 76 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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:
*/

View File

@ -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:

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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;
@ -334,27 +336,48 @@ nvkm_gsp_fwsec_sb(struct nvkm_gsp *gsp)
return 0;
}
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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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;