drm/nouveau/falcon: delay construction of falcons to oneinit()
authorAlexandre Courbot <acourbot@nvidia.com>
Wed, 22 Feb 2017 11:48:30 +0000 (20:48 +0900)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 7 Mar 2017 07:05:12 +0000 (17:05 +1000)
Reading registers at device construction time can be harmful, as there
is no guarantee the underlying engine will be up, or in its runtime
configuration. Defer register reading to the oneinit() hook and update
users accordingly.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
drivers/gpu/drm/nouveau/nvkm/falcon/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c

index 9384dff814942ebda6661479f975b087ad48a18b..b04d3a0e82e68e4dae8a57b2be7c208cd27dfcfb 100644 (file)
@@ -46,8 +46,14 @@ struct nvkm_falcon {
        struct nvkm_engine engine;
 };
 
+/* This constructor must be called from the owner's oneinit() hook and
+ * *not* its constructor.  This is to ensure that DEVINIT has been
+ * completed, and that the device is correctly enabled before we touch
+ * falcon registers.
+ */
 int nvkm_falcon_v1_new(struct nvkm_subdev *owner, const char *name, u32 addr,
                       struct nvkm_falcon **);
+
 void nvkm_falcon_del(struct nvkm_falcon **);
 int nvkm_falcon_get(struct nvkm_falcon *, const struct nvkm_subdev *);
 void nvkm_falcon_put(struct nvkm_falcon *, const struct nvkm_subdev *);
index f9acb8a944d2d0b72a5ab9b02c4a92d590ab76a6..a4410ef19db53f1ab783862171447ca2e38d0489 100644 (file)
@@ -1647,8 +1647,18 @@ static int
 gf100_gr_oneinit(struct nvkm_gr *base)
 {
        struct gf100_gr *gr = gf100_gr(base);
-       struct nvkm_device *device = gr->base.engine.subdev.device;
+       struct nvkm_subdev *subdev = &gr->base.engine.subdev;
+       struct nvkm_device *device = subdev->device;
        int i, j;
+       int ret;
+
+       ret = nvkm_falcon_v1_new(subdev, "FECS", 0x409000, &gr->fecs);
+       if (ret)
+               return ret;
+
+       ret = nvkm_falcon_v1_new(subdev, "GPCCS", 0x41a000, &gr->gpccs);
+       if (ret)
+               return ret;
 
        nvkm_pmu_pgob(device->pmu, false);
 
@@ -1856,24 +1866,13 @@ int
 gf100_gr_ctor(const struct gf100_gr_func *func, struct nvkm_device *device,
              int index, struct gf100_gr *gr)
 {
-       struct nvkm_subdev *subdev = &gr->base.engine.subdev;
-       int ret;
-
        gr->func = func;
        gr->firmware = nvkm_boolopt(device->cfgopt, "NvGrUseFW",
                                    func->fecs.ucode == NULL);
 
-       ret = nvkm_gr_ctor(&gf100_gr_, device, index,
-                          gr->firmware || func->fecs.ucode != NULL,
-                          &gr->base);
-       if (ret)
-               return ret;
-
-       ret = nvkm_falcon_v1_new(subdev, "FECS", 0x409000, &gr->fecs);
-       if (ret)
-               return ret;
-
-       return nvkm_falcon_v1_new(subdev, "GPCCS", 0x41a000, &gr->gpccs);
+       return nvkm_gr_ctor(&gf100_gr_, device, index,
+                           gr->firmware || func->fecs.ucode != NULL,
+                           &gr->base);
 }
 
 int
index ee25fdc21e1f697430b7b03da42ae1e70759aa72..19b9d44ae1a964f77fe12a8d4275806655e7fd8b 100644 (file)
@@ -137,6 +137,9 @@ nvkm_falcon_clear_interrupt(struct nvkm_falcon *falcon, u32 mask)
 void
 nvkm_falcon_put(struct nvkm_falcon *falcon, const struct nvkm_subdev *user)
 {
+       if (unlikely(!falcon))
+               return;
+
        mutex_lock(&falcon->mutex);
        if (falcon->user == user) {
                nvkm_debug(falcon->user, "released %s falcon\n", falcon->name);
index 1871a92e8f2f1448db19427fdce1646f08f2d2c8..3306f9fe7140c6258106fd52c120dae0f737300f 100644 (file)
@@ -115,6 +115,13 @@ nvkm_pmu_init(struct nvkm_subdev *subdev)
        return ret;
 }
 
+static int
+nvkm_pmu_oneinit(struct nvkm_subdev *subdev)
+{
+       struct nvkm_pmu *pmu = nvkm_pmu(subdev);
+       return nvkm_falcon_v1_new(&pmu->subdev, "PMU", 0x10a000, &pmu->falcon);
+}
+
 static void *
 nvkm_pmu_dtor(struct nvkm_subdev *subdev)
 {
@@ -128,6 +135,7 @@ static const struct nvkm_subdev_func
 nvkm_pmu = {
        .dtor = nvkm_pmu_dtor,
        .preinit = nvkm_pmu_preinit,
+       .oneinit = nvkm_pmu_oneinit,
        .init = nvkm_pmu_init,
        .fini = nvkm_pmu_fini,
        .intr = nvkm_pmu_intr,
@@ -141,7 +149,7 @@ nvkm_pmu_ctor(const struct nvkm_pmu_func *func, struct nvkm_device *device,
        pmu->func = func;
        INIT_WORK(&pmu->recv.work, nvkm_pmu_recv);
        init_waitqueue_head(&pmu->recv.wait);
-       return nvkm_falcon_v1_new(&pmu->subdev, "PMU", 0x10a000, &pmu->falcon);
+       return 0;
 }
 
 int