Commit 5cc027f6 authored by Ben Skeggs's avatar Ben Skeggs

drm/nv50-/disp: handle supervisor tasks from workqueue

i2c_algo_bit sleeps...
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 7dcd060c
...@@ -940,7 +940,6 @@ nv50_disp_intr_unk10(struct nv50_disp_priv *priv, u32 super) ...@@ -940,7 +940,6 @@ nv50_disp_intr_unk10(struct nv50_disp_priv *priv, u32 super)
exec_script(priv, head, 1); exec_script(priv, head, 1);
} }
nv_wr32(priv, 0x610024, 0x00000010);
nv_wr32(priv, 0x610030, 0x80000000); nv_wr32(priv, 0x610030, 0x80000000);
} }
...@@ -1097,7 +1096,6 @@ nv50_disp_intr_unk20(struct nv50_disp_priv *priv, u32 super) ...@@ -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); nv_wr32(priv, 0x610030, 0x80000000);
} }
...@@ -1136,22 +1134,23 @@ nv50_disp_intr_unk40(struct nv50_disp_priv *priv, u32 super) ...@@ -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); nv_wr32(priv, 0x610030, 0x80000000);
} }
static void void
nv50_disp_intr_super(struct nv50_disp_priv *priv, u32 intr1) 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); 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); nv50_disp_intr_unk10(priv, super);
if (intr1 & 0x00000020) if (priv->super & 0x00000020)
nv50_disp_intr_unk20(priv, super); nv50_disp_intr_unk20(priv, super);
if (intr1 & 0x00000040) if (priv->super & 0x00000040)
nv50_disp_intr_unk40(priv, super); nv50_disp_intr_unk40(priv, super);
} }
...@@ -1180,7 +1179,9 @@ nv50_disp_intr(struct nouveau_subdev *subdev) ...@@ -1180,7 +1179,9 @@ nv50_disp_intr(struct nouveau_subdev *subdev)
} }
if (intr1 & 0x00000070) { 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; intr1 &= ~0x00000070;
} }
} }
...@@ -1202,6 +1203,7 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -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)->sclass = nv50_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass; nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr; nv_subdev(priv)->intr = nv50_disp_intr;
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
priv->sclass = nv50_disp_sclass; priv->sclass = nv50_disp_sclass;
priv->head.nr = 2; priv->head.nr = 2;
priv->dac.nr = 3; priv->dac.nr = 3;
......
...@@ -15,6 +15,10 @@ struct dcb_output; ...@@ -15,6 +15,10 @@ struct dcb_output;
struct nv50_disp_priv { struct nv50_disp_priv {
struct nouveau_disp base; struct nouveau_disp base;
struct nouveau_oclass *sclass; struct nouveau_oclass *sclass;
struct work_struct supervisor;
u32 super;
struct { struct {
int nr; int nr;
} head; } head;
...@@ -126,6 +130,7 @@ extern struct nouveau_ofuncs nv50_disp_oimm_ofuncs; ...@@ -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_curs_ofuncs;
extern struct nouveau_ofuncs nv50_disp_base_ofuncs; extern struct nouveau_ofuncs nv50_disp_base_ofuncs;
extern struct nouveau_oclass nv50_disp_cclass; extern struct nouveau_oclass nv50_disp_cclass;
void nv50_disp_intr_supervisor(struct work_struct *);
void nv50_disp_intr(struct nouveau_subdev *); void nv50_disp_intr(struct nouveau_subdev *);
extern struct nouveau_omthds nv84_disp_base_omthds[]; extern struct nouveau_omthds nv84_disp_base_omthds[];
...@@ -139,6 +144,7 @@ extern struct nouveau_ofuncs nvd0_disp_oimm_ofuncs; ...@@ -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_curs_ofuncs;
extern struct nouveau_ofuncs nvd0_disp_base_ofuncs; extern struct nouveau_ofuncs nvd0_disp_base_ofuncs;
extern struct nouveau_oclass nvd0_disp_cclass; extern struct nouveau_oclass nvd0_disp_cclass;
void nvd0_disp_intr_supervisor(struct work_struct *);
void nvd0_disp_intr(struct nouveau_subdev *); void nvd0_disp_intr(struct nouveau_subdev *);
#endif #endif
...@@ -72,6 +72,7 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -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)->sclass = nv84_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass; nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr; nv_subdev(priv)->intr = nv50_disp_intr;
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
priv->sclass = nv84_disp_sclass; priv->sclass = nv84_disp_sclass;
priv->head.nr = 2; priv->head.nr = 2;
priv->dac.nr = 3; priv->dac.nr = 3;
......
...@@ -78,6 +78,7 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -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)->sclass = nv94_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass; nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr; nv_subdev(priv)->intr = nv50_disp_intr;
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
priv->sclass = nv94_disp_sclass; priv->sclass = nv94_disp_sclass;
priv->head.nr = 2; priv->head.nr = 2;
priv->dac.nr = 3; priv->dac.nr = 3;
......
...@@ -62,6 +62,7 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -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)->sclass = nva0_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass; nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr; nv_subdev(priv)->intr = nv50_disp_intr;
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
priv->sclass = nva0_disp_sclass; priv->sclass = nva0_disp_sclass;
priv->head.nr = 2; priv->head.nr = 2;
priv->dac.nr = 3; priv->dac.nr = 3;
......
...@@ -79,6 +79,7 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -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)->sclass = nva3_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass; nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr; nv_subdev(priv)->intr = nv50_disp_intr;
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
priv->sclass = nva3_disp_sclass; priv->sclass = nva3_disp_sclass;
priv->head.nr = 2; priv->head.nr = 2;
priv->dac.nr = 3; priv->dac.nr = 3;
......
...@@ -835,6 +835,26 @@ nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask) ...@@ -835,6 +835,26 @@ nvd0_display_unk4_handler(struct nv50_disp_priv *priv, u32 head, u32 mask)
nv_wr32(priv, 0x6101d0, 0x80000000); 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 void
nvd0_disp_intr(struct nouveau_subdev *subdev) nvd0_disp_intr(struct nouveau_subdev *subdev)
{ {
...@@ -868,27 +888,11 @@ nvd0_disp_intr(struct nouveau_subdev *subdev) ...@@ -868,27 +888,11 @@ nvd0_disp_intr(struct nouveau_subdev *subdev)
if (intr & 0x00100000) { if (intr & 0x00100000) {
u32 stat = nv_rd32(priv, 0x6100ac); u32 stat = nv_rd32(priv, 0x6100ac);
u32 mask = 0, crtc = ~0; if (stat & 0x00000007) {
priv->super = (stat & 0x00000007);
while (!mask && ++crtc < priv->head.nr) schedule_work(&priv->supervisor);
mask = nv_rd32(priv, 0x6101d4 + (crtc * 0x800)); nv_wr32(priv, 0x6100ac, priv->super);
stat &= ~0x00000007;
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) { if (stat) {
...@@ -929,6 +933,7 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -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)->sclass = nvd0_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass; nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nvd0_disp_intr; nv_subdev(priv)->intr = nvd0_disp_intr;
INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
priv->sclass = nvd0_disp_sclass; priv->sclass = nvd0_disp_sclass;
priv->head.nr = heads; priv->head.nr = heads;
priv->dac.nr = 3; priv->dac.nr = 3;
......
...@@ -63,6 +63,7 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -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)->sclass = nve0_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass; nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nvd0_disp_intr; nv_subdev(priv)->intr = nvd0_disp_intr;
INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
priv->sclass = nve0_disp_sclass; priv->sclass = nve0_disp_sclass;
priv->head.nr = heads; priv->head.nr = heads;
priv->dac.nr = 3; priv->dac.nr = 3;
......
...@@ -424,7 +424,10 @@ evo_kick(u32 *push, void *evoc) ...@@ -424,7 +424,10 @@ evo_kick(u32 *push, void *evoc)
static bool static bool
evo_sync_wait(void *data) 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 static int
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment