drm/msm/adreno: deal with linux-firmware fw paths
authorRob Clark <robdclark@gmail.com>
Mon, 16 Oct 2017 14:46:23 +0000 (10:46 -0400)
committerRob Clark <robdclark@gmail.com>
Sat, 28 Oct 2017 15:01:31 +0000 (11:01 -0400)
When firmware was added to linux-firmware, it was put in a qcom sub-
directory, unlike what we'd been using before.  For a300_pfp.fw and
a300_pm4.fw symlinks were created, but we'd prefer not to have to do
this in the future.  So add support to look in both places when
loading firmware.

Signed-off-by: Rob Clark <robdclark@gmail.com>
drivers/gpu/drm/msm/adreno/a5xx_gpu.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/adreno/adreno_gpu.h

index 4854c659927cb03f93f96801e07975cec6caf652..9fa90543459081b53e396072aaf84d3ea763d965 100644 (file)
@@ -76,9 +76,26 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname)
                goto out;
        }
 
-       /* Load the rest of the MDT */
-       ret = qcom_mdt_load(dev, fw, fwname, GPU_PAS_ID, mem_region, mem_phys,
-               mem_size);
+       /*
+        * Load the rest of the MDT
+        *
+        * Note that we could be dealing with two different paths, since
+        * with upstream linux-firmware it would be in a qcom/ subdir..
+        * adreno_request_fw() handles this, but qcom_mdt_load() does
+        * not.  But since we've already gotten thru adreno_request_fw()
+        * we know which of the two cases it is:
+        */
+       if (to_adreno_gpu(gpu)->fwloc == FW_LOCATION_LEGACY) {
+               ret = qcom_mdt_load(dev, fw, fwname, GPU_PAS_ID,
+                               mem_region, mem_phys, mem_size);
+       } else {
+               char newname[strlen("qcom/") + strlen(fwname) + 1];
+
+               sprintf(newname, "qcom/%s", fwname);
+
+               ret = qcom_mdt_load(dev, fw, newname, GPU_PAS_ID,
+                               mem_region, mem_phys, mem_size);
+       }
        if (ret)
                goto out;
 
index 54f77045ff607438222b706fbf3a596192424913..76416b5238adbbf95f3d0ad98df74638e7fc580c 100644 (file)
@@ -69,15 +69,72 @@ adreno_request_fw(struct adreno_gpu *adreno_gpu, const char *fwname)
 {
        struct drm_device *drm = adreno_gpu->base.dev;
        const struct firmware *fw = NULL;
+       char newname[strlen("qcom/") + strlen(fwname) + 1];
        int ret;
 
-       ret = request_firmware(&fw, fwname, drm->dev);
-       if (ret) {
-               dev_err(drm->dev, "failed to load %s: %d\n", fwname, ret);
-               return ERR_PTR(ret);
+       sprintf(newname, "qcom/%s", fwname);
+
+       /*
+        * Try first to load from qcom/$fwfile using a direct load (to avoid
+        * a potential timeout waiting for usermode helper)
+        */
+       if ((adreno_gpu->fwloc == FW_LOCATION_UNKNOWN) ||
+           (adreno_gpu->fwloc == FW_LOCATION_NEW)) {
+
+               ret = request_firmware_direct(&fw, newname, drm->dev);
+               if (!ret) {
+                       dev_info(drm->dev, "loaded %s from new location\n",
+                               newname);
+                       adreno_gpu->fwloc = FW_LOCATION_NEW;
+                       return fw;
+               } else if (adreno_gpu->fwloc != FW_LOCATION_UNKNOWN) {
+                       dev_err(drm->dev, "failed to load %s: %d\n",
+                               newname, ret);
+                       return ERR_PTR(ret);
+               }
+       }
+
+       /*
+        * Then try the legacy location without qcom/ prefix
+        */
+       if ((adreno_gpu->fwloc == FW_LOCATION_UNKNOWN) ||
+           (adreno_gpu->fwloc == FW_LOCATION_LEGACY)) {
+
+               ret = request_firmware_direct(&fw, fwname, drm->dev);
+               if (!ret) {
+                       dev_info(drm->dev, "loaded %s from legacy location\n",
+                               newname);
+                       adreno_gpu->fwloc = FW_LOCATION_LEGACY;
+                       return fw;
+               } else if (adreno_gpu->fwloc != FW_LOCATION_UNKNOWN) {
+                       dev_err(drm->dev, "failed to load %s: %d\n",
+                               fwname, ret);
+                       return ERR_PTR(ret);
+               }
+       }
+
+       /*
+        * Finally fall back to request_firmware() for cases where the
+        * usermode helper is needed (I think mainly android)
+        */
+       if ((adreno_gpu->fwloc == FW_LOCATION_UNKNOWN) ||
+           (adreno_gpu->fwloc == FW_LOCATION_HELPER)) {
+
+               ret = request_firmware(&fw, newname, drm->dev);
+               if (!ret) {
+                       dev_info(drm->dev, "loaded %s with helper\n",
+                               newname);
+                       adreno_gpu->fwloc = FW_LOCATION_HELPER;
+                       return fw;
+               } else if (adreno_gpu->fwloc != FW_LOCATION_UNKNOWN) {
+                       dev_err(drm->dev, "failed to load %s: %d\n",
+                               newname, ret);
+                       return ERR_PTR(ret);
+               }
        }
 
-       return fw;
+       dev_err(drm->dev, "failed to load %s\n", fwname);
+       return ERR_PTR(-ENOENT);
 }
 
 static int adreno_load_fw(struct adreno_gpu *adreno_gpu)
index 3eda98af546e8b3ef2608651c69f1e31fefe6fcd..b8c22658929da391926cede4c67aed846bad96f6 100644 (file)
@@ -101,6 +101,27 @@ struct adreno_gpu {
        /* interesting register offsets to dump: */
        const unsigned int *registers;
 
+       /*
+        * Are we loading fw from legacy path?  Prior to addition
+        * of gpu firmware to linux-firmware, the fw files were
+        * placed in toplevel firmware directory, following qcom's
+        * android kernel.  But linux-firmware preferred they be
+        * placed in a 'qcom' subdirectory.
+        *
+        * For backwards compatibility, we try first to load from
+        * the new path, using request_firmware_direct() to avoid
+        * any potential timeout waiting for usermode helper, then
+        * fall back to the old path (with direct load).  And
+        * finally fall back to request_firmware() with the new
+        * path to allow the usermode helper.
+        */
+       enum {
+               FW_LOCATION_UNKNOWN = 0,
+               FW_LOCATION_NEW,       /* /lib/firmware/qcom/$fwfile */
+               FW_LOCATION_LEGACY,    /* /lib/firmware/$fwfile */
+               FW_LOCATION_HELPER,
+       } fwloc;
+
        /* firmware: */
        const struct firmware *pm4, *pfp;