[PATCH 2/2] drm/imagination: Don't map FW interface structures unnecessarily
From: Alexandru Dadu
Date: Tue Sep 15 2026 - 04:12:38 EST
From: Alessio Belle <alessio.belle@xxxxxxxxxx>
Connection control, OS init and HWR info buffer structures are
currently not accessed by the driver during or after firmware
initialisation.
OS init is accessed during hard reset, but the common hard reset logic
already takes care of temporarily mapping it again.
Signed-off-by: Alessio Belle <alessio.belle@xxxxxxxxxx>
Signed-off-by: Alexandru Dadu <alexandru.dadu@xxxxxxxxxx>
---
drivers/gpu/drm/imagination/pvr_fw.c | 97 ++++++++++++++++++++++++------------
drivers/gpu/drm/imagination/pvr_fw.h | 18 +++----
2 files changed, 72 insertions(+), 43 deletions(-)
diff --git a/drivers/gpu/drm/imagination/pvr_fw.c b/drivers/gpu/drm/imagination/pvr_fw.c
index b2a5ea001474..ad5e8d68defe 100644
--- a/drivers/gpu/drm/imagination/pvr_fw.c
+++ b/drivers/gpu/drm/imagination/pvr_fw.c
@@ -428,19 +428,17 @@ pvr_fw_create_structures(struct pvr_device *pvr_dev)
struct pvr_fw_mem *fw_mem = &fw_dev->mem;
int err;
- fw_dev->fwif_connection_ctl =
- pvr_fw_object_create_and_map_offset(pvr_dev,
- fw_dev->fw_heap_info.config_offset +
- PVR_ROGUE_FWIF_CONNECTION_CTL_OFFSET,
- sizeof(*fw_dev->fwif_connection_ctl),
- PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
- NULL, NULL,
- &fw_mem->fwif_connection_ctl_obj);
-
- if (IS_ERR(fw_dev->fwif_connection_ctl)) {
+ err = pvr_fw_object_create_offset(pvr_dev,
+ fw_dev->fw_heap_info.config_offset +
+ PVR_ROGUE_FWIF_CONNECTION_CTL_OFFSET,
+ sizeof(struct rogue_fwif_connection_ctl),
+ PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
+ NULL, NULL,
+ &fw_mem->fwif_connection_ctl_obj);
+ if (err) {
drm_err(drm_dev,
"Unable to allocate FWIF connection control memory\n");
- return PTR_ERR(fw_dev->fwif_connection_ctl);
+ return err;
}
fw_dev->power_sync = pvr_fw_object_create_and_map(pvr_dev, sizeof(*fw_dev->power_sync),
@@ -452,13 +450,12 @@ pvr_fw_create_structures(struct pvr_device *pvr_dev)
goto err_release_connection_ctl;
}
- fw_dev->hwrinfobuf = pvr_fw_object_create_and_map(pvr_dev, sizeof(*fw_dev->hwrinfobuf),
- PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
- NULL, NULL, &fw_mem->hwrinfobuf_obj);
- if (IS_ERR(fw_dev->hwrinfobuf)) {
+ err = pvr_fw_object_create(pvr_dev, sizeof(struct rogue_fwif_hwrinfobuf),
+ PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
+ NULL, NULL, &fw_mem->hwrinfobuf_obj);
+ if (err) {
drm_err(drm_dev,
"Unable to allocate FW hwrinfobuf structure\n");
- err = PTR_ERR(fw_dev->hwrinfobuf);
goto err_release_power_sync;
}
@@ -521,16 +518,14 @@ pvr_fw_create_structures(struct pvr_device *pvr_dev)
goto err_fw_trace_fini;
}
- fw_dev->fwif_osinit =
- pvr_fw_object_create_and_map_offset(pvr_dev,
- fw_dev->fw_heap_info.config_offset +
- PVR_ROGUE_FWIF_OSINIT_OFFSET,
- sizeof(*fw_dev->fwif_osinit),
- PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
- fw_osinit_init, pvr_dev, &fw_mem->osinit_obj);
- if (IS_ERR(fw_dev->fwif_osinit)) {
+ err = pvr_fw_object_create_offset(pvr_dev,
+ fw_dev->fw_heap_info.config_offset +
+ PVR_ROGUE_FWIF_OSINIT_OFFSET,
+ sizeof(struct rogue_fwif_osinit),
+ PVR_BO_FW_FLAGS_DEVICE_UNCACHED,
+ fw_osinit_init, pvr_dev, &fw_mem->osinit_obj);
+ if (err) {
drm_err(drm_dev, "Unable to allocate FW OSINIT structure\n");
- err = PTR_ERR(fw_dev->fwif_osinit);
goto err_release_osdata;
}
@@ -550,7 +545,7 @@ pvr_fw_create_structures(struct pvr_device *pvr_dev)
return 0;
err_release_osinit:
- pvr_fw_object_unmap_and_destroy(fw_mem->osinit_obj);
+ pvr_fw_object_destroy(fw_mem->osinit_obj);
err_release_osdata:
pvr_fw_object_unmap_and_destroy(fw_mem->osdata_obj);
@@ -574,13 +569,13 @@ pvr_fw_create_structures(struct pvr_device *pvr_dev)
pvr_fw_object_destroy(fw_mem->mmucache_sync_obj);
err_release_hwrinfobuf:
- pvr_fw_object_unmap_and_destroy(fw_mem->hwrinfobuf_obj);
+ pvr_fw_object_destroy(fw_mem->hwrinfobuf_obj);
err_release_power_sync:
pvr_fw_object_unmap_and_destroy(fw_mem->power_sync_obj);
err_release_connection_ctl:
- pvr_fw_object_unmap_and_destroy(fw_mem->fwif_connection_ctl_obj);
+ pvr_fw_object_destroy(fw_mem->fwif_connection_ctl_obj);
return err;
}
@@ -599,11 +594,11 @@ pvr_fw_destroy_structures(struct pvr_device *pvr_dev)
pvr_fw_object_unmap_and_destroy(fw_mem->sysinit_obj);
pvr_fw_object_destroy(fw_mem->mmucache_sync_obj);
- pvr_fw_object_unmap_and_destroy(fw_mem->hwrinfobuf_obj);
+ pvr_fw_object_destroy(fw_mem->hwrinfobuf_obj);
pvr_fw_object_unmap_and_destroy(fw_mem->power_sync_obj);
pvr_fw_object_unmap_and_destroy(fw_mem->osdata_obj);
- pvr_fw_object_unmap_and_destroy(fw_mem->osinit_obj);
- pvr_fw_object_unmap_and_destroy(fw_mem->fwif_connection_ctl_obj);
+ pvr_fw_object_destroy(fw_mem->osinit_obj);
+ pvr_fw_object_destroy(fw_mem->fwif_connection_ctl_obj);
}
/**
@@ -1402,6 +1397,46 @@ pvr_fw_object_create_and_map_offset(struct pvr_device *pvr_dev,
fw_obj_out);
}
+/**
+ * pvr_fw_object_create_offset() - Create a FW object and map to firmware
+ * at the provided offset.
+ * @pvr_dev: PowerVR device pointer.
+ * @fw_addr: Base address of desired FW mapping, offset from start of FW heap.
+ * If a specific FW address is not required, pass %U32_MAX.
+ * @size: Size of object, in bytes.
+ * @flags: Options which affect both this operation and future mapping
+ * operations performed on the returned object. Must be a combination of
+ * DRM_PVR_BO_* and/or PVR_BO_* flags.
+ * @init: Initialisation callback.
+ * @init_priv: Private pointer to pass to initialisation callback.
+ * @fw_obj_out: Pointer to location to store created object pointer.
+ *
+ * %DRM_PVR_BO_DEVICE_PM_FW_PROTECT is implied for all FW objects. Consequently,
+ * this function will fail if @flags has %DRM_PVR_BO_CPU_ALLOW_USERSPACE_ACCESS
+ * set.
+ *
+ * Returns:
+ * * 0 on success, or
+ * * Any error returned by pvr_fw_object_create_and_map().
+ */
+int
+pvr_fw_object_create_offset(struct pvr_device *pvr_dev, u32 fw_addr,
+ size_t size, u64 flags,
+ void (*init)(void *cpu_ptr, void *priv),
+ void *init_priv, struct pvr_fw_object **fw_obj_out)
+{
+ void *cpu_ptr;
+
+ cpu_ptr = pvr_fw_object_create_and_map_offset(pvr_dev, fw_addr, size, flags,
+ init, init_priv, fw_obj_out);
+ if (IS_ERR(cpu_ptr))
+ return PTR_ERR(cpu_ptr);
+
+ pvr_fw_object_vunmap(*fw_obj_out);
+
+ return 0;
+}
+
/**
* pvr_fw_object_destroy() - Destroy a pvr_fw_object
* @fw_obj: Pointer to object to destroy.
diff --git a/drivers/gpu/drm/imagination/pvr_fw.h b/drivers/gpu/drm/imagination/pvr_fw.h
index 3390c84e4fd3..67d1e63669f1 100644
--- a/drivers/gpu/drm/imagination/pvr_fw.h
+++ b/drivers/gpu/drm/imagination/pvr_fw.h
@@ -349,30 +349,18 @@ struct pvr_fw_device {
/** @fw_mm_base: Base address of address space managed by @fw_mm. */
u64 fw_mm_base;
- /**
- * @fwif_connection_ctl: Pointer to CPU mapping of FWIF connection
- * control structure.
- */
- struct rogue_fwif_connection_ctl *fwif_connection_ctl;
-
/** @fwif_sysinit: Pointer to CPU mapping of FW SYSINIT structure. */
struct rogue_fwif_sysinit *fwif_sysinit;
/** @fwif_sysdata: Pointer to CPU mapping of FW SYSDATA structure. */
struct rogue_fwif_sysdata *fwif_sysdata;
- /** @fwif_osinit: Pointer to CPU mapping of FW OSINIT structure. */
- struct rogue_fwif_osinit *fwif_osinit;
-
/** @fwif_osdata: Pointer to CPU mapping of FW OSDATA structure. */
struct rogue_fwif_osdata *fwif_osdata;
/** @power_sync: Pointer to CPU mapping of power sync state. */
u32 *power_sync;
- /** @hwrinfobuf: Pointer to CPU mapping of FW HWR info buffer. */
- struct rogue_fwif_hwrinfobuf *hwrinfobuf;
-
/** @fw_trace: Device firmware trace buffer state. */
struct pvr_fw_trace fw_trace;
@@ -430,6 +418,12 @@ void *pvr_fw_object_create_and_map(struct pvr_device *pvr_dev, size_t size, u64
void (*init)(void *cpu_ptr, void *priv),
void *init_priv, struct pvr_fw_object **pvr_obj_out);
+int
+pvr_fw_object_create_offset(struct pvr_device *pvr_dev, u32 fw_addr,
+ size_t size, u64 flags,
+ void (*init)(void *cpu_ptr, void *priv),
+ void *init_priv, struct pvr_fw_object **pvr_obj_out);
+
void *
pvr_fw_object_create_and_map_offset(struct pvr_device *pvr_dev, u32 dev_offset, size_t size,
u64 flags, void (*init)(void *cpu_ptr, void *priv),
--
2.43.0