drm/nv50-/disp: handle supervisor tasks from workqueue
authorBen Skeggs <bskeggs@redhat.com>
Mon, 18 Feb 2013 22:50:51 +0000 (17:50 -0500)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 20 Feb 2013 06:01:02 +0000 (16:01 +1000)
i2c_algo_bit sleeps...

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
drivers/gpu/drm/nouveau/nv50_display.c

index c3806122d7713488375f818d960de73bb60333f7..d22f6569768c02309b604052a9a305d5abad21f1 100644 (file)
@@ -940,7 +940,6 @@ nv50_disp_intr_unk10(struct nv50_disp_priv *priv, u32 super)
                        exec_script(priv, head, 1);
        }
 
-       nv_wr32(priv, 0x610024, 0x00000010);
        nv_wr32(priv, 0x610030, 0x80000000);
 }
 
@@ -1097,7 +1096,6 @@ nv50_disp_intr_unk20(struct nv50_disp_priv *priv, u32 super)
                }
        }
 
-       nv_wr32(priv, 0x610024, 0x00000020);
        nv_wr32(priv, 0x610030, 0x80000000);
 }
 
@@ -1136,22 +1134,23 @@ nv50_disp_intr_unk40(struct nv50_disp_priv *priv, u32 super)
                }
        }
 
-       nv_wr32(priv, 0x610024, 0x00000040);
        nv_wr32(priv, 0x610030, 0x80000000);
 }
 
-static void
-nv50_disp_intr_super(struct nv50_disp_priv *priv, u32 intr1)
+void
+nv50_disp_intr_supervisor(struct work_struct *work)
 {
+       struct nv50_disp_priv *priv =
+               container_of(work, struct nv50_disp_priv, supervisor);
        u32 super = nv_rd32(priv, 0x610030);
 
-       nv_debug(priv, "supervisor 0x%08x 0x%08x\n", intr1, super);
+       nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super);
 
-       if (intr1 & 0x00000010)
+       if (priv->super & 0x00000010)
                nv50_disp_intr_unk10(priv, super);
-       if (intr1 & 0x00000020)
+       if (priv->super & 0x00000020)
                nv50_disp_intr_unk20(priv, super);
-       if (intr1 & 0x00000040)
+       if (priv->super & 0x00000040)
                nv50_disp_intr_unk40(priv, super);
 }
 
@@ -1180,7 +1179,9 @@ nv50_disp_intr(struct nouveau_subdev *subdev)
        }
 
        if (intr1 & 0x00000070) {
-               nv50_disp_intr_super(priv, intr1);
+               priv->super = (intr1 & 0x00000070);
+               schedule_work(&priv->supervisor);
+               nv_wr32(priv, 0x610024, priv->super);
                intr1 &= ~0x00000070;
        }
 }
@@ -1202,6 +1203,7 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        nv_engine(priv)->sclass = nv50_disp_base_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nv50_disp_intr;
+       INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
        priv->sclass = nv50_disp_sclass;
        priv->head.nr = 2;
        priv->dac.nr = 3;
index fc897181fa38424bf19a3f5e737fc6da1da7781d..b88a62129814904952554a7d478a3b6f6063e7e5 100644 (file)
@@ -15,6 +15,10 @@ struct dcb_output;
 struct nv50_disp_priv {
        struct nouveau_disp base;
        struct nouveau_oclass *sclass;
+
+       struct work_struct supervisor;
+       u32 super;
+
        struct {
                int nr;
        } head;
@@ -126,6 +130,7 @@ extern struct nouveau_ofuncs nv50_disp_oimm_ofuncs;
 extern struct nouveau_ofuncs nv50_disp_curs_ofuncs;
 extern struct nouveau_ofuncs nv50_disp_base_ofuncs;
 extern struct nouveau_oclass nv50_disp_cclass;
+void nv50_disp_intr_supervisor(struct work_struct *);
 void nv50_disp_intr(struct nouveau_subdev *);
 
 extern struct nouveau_omthds nv84_disp_base_omthds[];
@@ -139,6 +144,7 @@ extern struct nouveau_ofuncs nvd0_disp_oimm_ofuncs;
 extern struct nouveau_ofuncs nvd0_disp_curs_ofuncs;
 extern struct nouveau_ofuncs nvd0_disp_base_ofuncs;
 extern struct nouveau_oclass nvd0_disp_cclass;
+void nvd0_disp_intr_supervisor(struct work_struct *);
 void nvd0_disp_intr(struct nouveau_subdev *);
 
 #endif
index a2153424605d8df956f29333a066203f24954c1a..9ec942a0f9f66030c15b724605e39be308376190 100644 (file)
@@ -72,6 +72,7 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        nv_engine(priv)->sclass = nv84_disp_base_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nv50_disp_intr;
+       INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
        priv->sclass = nv84_disp_sclass;
        priv->head.nr = 2;
        priv->dac.nr = 3;
index a315e28ac17e7629f820fe3795f27f7d14620f64..a838bdd2019b28e1f94aa43b009a320dc8d442e1 100644 (file)
@@ -78,6 +78,7 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        nv_engine(priv)->sclass = nv94_disp_base_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nv50_disp_intr;
+       INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
        priv->sclass = nv94_disp_sclass;
        priv->head.nr = 2;
        priv->dac.nr = 3;
index 480e2ded95fa0d228cf487764ea616b8ae0bd52a..ce539ca1d308ad103f9b840e922571cb29f9711f 100644 (file)
@@ -62,6 +62,7 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        nv_engine(priv)->sclass = nva0_disp_base_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nv50_disp_intr;
+       INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
        priv->sclass = nva0_disp_sclass;
        priv->head.nr = 2;
        priv->dac.nr = 3;
index 718b4f66352e467b1491737441bcb5eb9253c245..bd2bb4751089d912b42b20eae60b04ff0ece7a3d 100644 (file)
@@ -79,6 +79,7 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        nv_engine(priv)->sclass = nva3_disp_base_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nv50_disp_intr;
+       INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
        priv->sclass = nva3_disp_sclass;
        priv->head.nr = 2;
        priv->dac.nr = 3;
index 77cc730240720d095239f42cc893a5ab4bad4f05..1c91eb1679a0e9ea7e14e27835779610c65cd542 100644 (file)
@@ -835,6 +835,26 @@ nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
        nv_wr32(priv, 0x6101d0, 0x80000000);
 }
 
+void
+nvd0_disp_intr_supervisor(struct work_struct *work)
+{
+       struct nv50_disp_priv *priv =
+               container_of(work, struct nv50_disp_priv, supervisor);
+       u32 mask = 0, head = ~0;
+
+       while (!mask && ++head < priv->head.nr)
+               mask = nv_rd32(priv, 0x6101d4 + (head * 0x800));
+
+       nv_debug(priv, "supervisor %08x %08x %d\n", priv->super, mask, head);
+
+       if (priv->super & 0x00000001)
+               nvd0_display_unk1_handler(priv, head, mask);
+       if (priv->super & 0x00000002)
+               nvd0_display_unk2_handler(priv, head, mask);
+       if (priv->super & 0x00000004)
+               nvd0_display_unk4_handler(priv, head, mask);
+}
+
 void
 nvd0_disp_intr(struct nouveau_subdev *subdev)
 {
@@ -868,27 +888,11 @@ nvd0_disp_intr(struct nouveau_subdev *subdev)
 
        if (intr & 0x00100000) {
                u32 stat = nv_rd32(priv, 0x6100ac);
-               u32 mask = 0, crtc = ~0;
-
-               while (!mask && ++crtc < priv->head.nr)
-                       mask = nv_rd32(priv, 0x6101d4 + (crtc * 0x800));
-
-               if (stat & 0x00000001) {
-                       nv_wr32(priv, 0x6100ac, 0x00000001);
-                       nvd0_display_unk1_handler(priv, crtc, mask);
-                       stat &= ~0x00000001;
-               }
-
-               if (stat & 0x00000002) {
-                       nv_wr32(priv, 0x6100ac, 0x00000002);
-                       nvd0_display_unk2_handler(priv, crtc, mask);
-                       stat &= ~0x00000002;
-               }
-
-               if (stat & 0x00000004) {
-                       nv_wr32(priv, 0x6100ac, 0x00000004);
-                       nvd0_display_unk4_handler(priv, crtc, mask);
-                       stat &= ~0x00000004;
+               if (stat & 0x00000007) {
+                       priv->super = (stat & 0x00000007);
+                       schedule_work(&priv->supervisor);
+                       nv_wr32(priv, 0x6100ac, priv->super);
+                       stat &= ~0x00000007;
                }
 
                if (stat) {
@@ -929,6 +933,7 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        nv_engine(priv)->sclass = nvd0_disp_base_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nvd0_disp_intr;
+       INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
        priv->sclass = nvd0_disp_sclass;
        priv->head.nr = heads;
        priv->dac.nr = 3;
index 5512296a61d7e7fe40ba426abcb16e2a524b6554..65c19ca073b1f6bb44fab95b9f881172d38bb5c3 100644 (file)
@@ -63,6 +63,7 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        nv_engine(priv)->sclass = nve0_disp_base_oclass;
        nv_engine(priv)->cclass = &nv50_disp_cclass;
        nv_subdev(priv)->intr = nvd0_disp_intr;
+       INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
        priv->sclass = nve0_disp_sclass;
        priv->head.nr = heads;
        priv->dac.nr = 3;
index 75d116137c0a75126ee087089ae62901c7050699..2cd37979dcd3f67c76a7b1b120e4ba33ef20c79a 100644 (file)
@@ -424,7 +424,10 @@ evo_kick(u32 *push, void *evoc)
 static bool
 evo_sync_wait(void *data)
 {
-       return nouveau_bo_rd32(data, EVO_MAST_NTFY) != 0x00000000;
+       if (nouveau_bo_rd32(data, EVO_MAST_NTFY) != 0x00000000)
+               return true;
+       usleep_range(1, 2);
+       return false;
 }
 
 static int