drm/nv50/fb: implement trap handler as subdev interrupt handler
nv50_fb_trap() will now be called automagically by the mc intr handler, rather than each engine's handler having to check for traps manually. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
Родитель
e0cdd1e545
Коммит
874309a5b7
|
@ -133,7 +133,6 @@ nva3_copy_intr(struct nouveau_subdev *subdev)
|
||||||
nv_wr32(priv, 0x104004, stat);
|
nv_wr32(priv, 0x104004, stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
nv50_fb_trap(nouveau_fb(priv), 1);
|
|
||||||
nouveau_engctx_put(engctx);
|
nouveau_engctx_put(engctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -157,7 +157,6 @@ nv84_crypt_intr(struct nouveau_subdev *subdev)
|
||||||
nv_wr32(priv, 0x102130, stat);
|
nv_wr32(priv, 0x102130, stat);
|
||||||
nv_wr32(priv, 0x10200c, 0x10);
|
nv_wr32(priv, 0x10200c, 0x10);
|
||||||
|
|
||||||
nv50_fb_trap(nouveau_fb(priv), 1);
|
|
||||||
nouveau_engctx_put(engctx);
|
nouveau_engctx_put(engctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -135,7 +135,6 @@ nv98_crypt_intr(struct nouveau_subdev *subdev)
|
||||||
nv_wr32(priv, 0x087004, stat);
|
nv_wr32(priv, 0x087004, stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
nv50_fb_trap(nouveau_fb(priv), 1);
|
|
||||||
nouveau_engctx_put(engctx);
|
nouveau_engctx_put(engctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -525,7 +525,6 @@ nv04_fifo_intr(struct nouveau_subdev *subdev)
|
||||||
|
|
||||||
if (device->card_type == NV_50) {
|
if (device->card_type == NV_50) {
|
||||||
if (status & 0x00000010) {
|
if (status & 0x00000010) {
|
||||||
nv50_fb_trap(nouveau_fb(priv), 1);
|
|
||||||
status &= ~0x00000010;
|
status &= ~0x00000010;
|
||||||
nv_wr32(priv, 0x002100, 0x00000010);
|
nv_wr32(priv, 0x002100, 0x00000010);
|
||||||
}
|
}
|
||||||
|
|
|
@ -792,7 +792,6 @@ nv50_graph_intr(struct nouveau_subdev *subdev)
|
||||||
nv_error(priv, "ch %d [0x%010llx] subc %d class 0x%04x "
|
nv_error(priv, "ch %d [0x%010llx] subc %d class 0x%04x "
|
||||||
"mthd 0x%04x data 0x%08x\n",
|
"mthd 0x%04x data 0x%08x\n",
|
||||||
chid, (u64)inst << 12, subc, class, mthd, data);
|
chid, (u64)inst << 12, subc, class, mthd, data);
|
||||||
nv50_fb_trap(nouveau_fb(priv), 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nv_rd32(priv, 0x400824) & (1 << 31))
|
if (nv_rd32(priv, 0x400824) & (1 << 31))
|
||||||
|
|
|
@ -157,7 +157,6 @@ nv50_mpeg_intr(struct nouveau_subdev *subdev)
|
||||||
|
|
||||||
nv_wr32(priv, 0x00b100, stat);
|
nv_wr32(priv, 0x00b100, stat);
|
||||||
nv_wr32(priv, 0x00b230, 0x00000001);
|
nv_wr32(priv, 0x00b230, 0x00000001);
|
||||||
nv50_fb_trap(nouveau_fb(priv), 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -167,6 +167,5 @@ void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
|
||||||
u32 pitch, u32 flags, struct nouveau_fb_tile *);
|
u32 pitch, u32 flags, struct nouveau_fb_tile *);
|
||||||
|
|
||||||
void nv50_fb_vram_del(struct nouveau_fb *, struct nouveau_mem **);
|
void nv50_fb_vram_del(struct nouveau_fb *, struct nouveau_mem **);
|
||||||
void nv50_fb_trap(struct nouveau_fb *, int display);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -235,103 +235,6 @@ nv50_fb_vram_del(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
|
||||||
kfree(mem);
|
kfree(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
|
||||||
struct nouveau_oclass *oclass, void *data, u32 size,
|
|
||||||
struct nouveau_object **pobject)
|
|
||||||
{
|
|
||||||
struct nouveau_device *device = nv_device(parent);
|
|
||||||
struct nv50_fb_priv *priv;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = nouveau_fb_create(parent, engine, oclass, &priv);
|
|
||||||
*pobject = nv_object(priv);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
|
|
||||||
if (priv->r100c08_page) {
|
|
||||||
priv->r100c08 = pci_map_page(device->pdev, priv->r100c08_page,
|
|
||||||
0, PAGE_SIZE,
|
|
||||||
PCI_DMA_BIDIRECTIONAL);
|
|
||||||
if (pci_dma_mapping_error(device->pdev, priv->r100c08))
|
|
||||||
nv_warn(priv, "failed 0x100c08 page map\n");
|
|
||||||
} else {
|
|
||||||
nv_warn(priv, "failed 0x100c08 page alloc\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->base.memtype_valid = nv50_fb_memtype_valid;
|
|
||||||
priv->base.ram.init = nv50_fb_vram_init;
|
|
||||||
priv->base.ram.get = nv50_fb_vram_new;
|
|
||||||
priv->base.ram.put = nv50_fb_vram_del;
|
|
||||||
return nouveau_fb_preinit(&priv->base);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
nv50_fb_dtor(struct nouveau_object *object)
|
|
||||||
{
|
|
||||||
struct nouveau_device *device = nv_device(object);
|
|
||||||
struct nv50_fb_priv *priv = (void *)object;
|
|
||||||
|
|
||||||
if (priv->r100c08_page) {
|
|
||||||
pci_unmap_page(device->pdev, priv->r100c08, PAGE_SIZE,
|
|
||||||
PCI_DMA_BIDIRECTIONAL);
|
|
||||||
__free_page(priv->r100c08_page);
|
|
||||||
}
|
|
||||||
|
|
||||||
nouveau_fb_destroy(&priv->base);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
nv50_fb_init(struct nouveau_object *object)
|
|
||||||
{
|
|
||||||
struct nouveau_device *device = nv_device(object);
|
|
||||||
struct nv50_fb_priv *priv = (void *)object;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = nouveau_fb_init(&priv->base);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* Not a clue what this is exactly. Without pointing it at a
|
|
||||||
* scratch page, VRAM->GART blits with M2MF (as in DDX DFS)
|
|
||||||
* cause IOMMU "read from address 0" errors (rh#561267)
|
|
||||||
*/
|
|
||||||
nv_wr32(priv, 0x100c08, priv->r100c08 >> 8);
|
|
||||||
|
|
||||||
/* This is needed to get meaningful information from 100c90
|
|
||||||
* on traps. No idea what these values mean exactly. */
|
|
||||||
switch (device->chipset) {
|
|
||||||
case 0x50:
|
|
||||||
nv_wr32(priv, 0x100c90, 0x000707ff);
|
|
||||||
break;
|
|
||||||
case 0xa3:
|
|
||||||
case 0xa5:
|
|
||||||
case 0xa8:
|
|
||||||
nv_wr32(priv, 0x100c90, 0x000d0fff);
|
|
||||||
break;
|
|
||||||
case 0xaf:
|
|
||||||
nv_wr32(priv, 0x100c90, 0x089d1fff);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
nv_wr32(priv, 0x100c90, 0x001d07ff);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct nouveau_oclass
|
|
||||||
nv50_fb_oclass = {
|
|
||||||
.handle = NV_SUBDEV(FB, 0x50),
|
|
||||||
.ofuncs = &(struct nouveau_ofuncs) {
|
|
||||||
.ctor = nv50_fb_ctor,
|
|
||||||
.dtor = nv50_fb_dtor,
|
|
||||||
.init = nv50_fb_init,
|
|
||||||
.fini = _nouveau_fb_fini,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct nouveau_enum vm_dispatch_subclients[] = {
|
static const struct nouveau_enum vm_dispatch_subclients[] = {
|
||||||
{ 0x00000000, "GRCTX", NULL },
|
{ 0x00000000, "GRCTX", NULL },
|
||||||
{ 0x00000001, "NOTIFY", NULL },
|
{ 0x00000001, "NOTIFY", NULL },
|
||||||
|
@ -427,11 +330,11 @@ static const struct nouveau_enum vm_fault[] = {
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
static void
|
||||||
nv50_fb_trap(struct nouveau_fb *pfb, int display)
|
nv50_fb_intr(struct nouveau_subdev *subdev)
|
||||||
{
|
{
|
||||||
struct nouveau_device *device = nv_device(pfb);
|
struct nouveau_device *device = nv_device(subdev);
|
||||||
struct nv50_fb_priv *priv = (void *)pfb;
|
struct nv50_fb_priv *priv = (void *)subdev;
|
||||||
const struct nouveau_enum *en, *cl;
|
const struct nouveau_enum *en, *cl;
|
||||||
u32 trap[6], idx, chan;
|
u32 trap[6], idx, chan;
|
||||||
u8 st0, st1, st2, st3;
|
u8 st0, st1, st2, st3;
|
||||||
|
@ -448,9 +351,6 @@ nv50_fb_trap(struct nouveau_fb *pfb, int display)
|
||||||
}
|
}
|
||||||
nv_wr32(priv, 0x100c90, idx | 0x80000000);
|
nv_wr32(priv, 0x100c90, idx | 0x80000000);
|
||||||
|
|
||||||
if (!display)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* decode status bits into something more useful */
|
/* decode status bits into something more useful */
|
||||||
if (device->chipset < 0xa3 ||
|
if (device->chipset < 0xa3 ||
|
||||||
device->chipset == 0xaa || device->chipset == 0xac) {
|
device->chipset == 0xaa || device->chipset == 0xac) {
|
||||||
|
@ -497,3 +397,101 @@ nv50_fb_trap(struct nouveau_fb *pfb, int display)
|
||||||
else
|
else
|
||||||
printk("0x%08x\n", st1);
|
printk("0x%08x\n", st1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||||
|
struct nouveau_oclass *oclass, void *data, u32 size,
|
||||||
|
struct nouveau_object **pobject)
|
||||||
|
{
|
||||||
|
struct nouveau_device *device = nv_device(parent);
|
||||||
|
struct nv50_fb_priv *priv;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = nouveau_fb_create(parent, engine, oclass, &priv);
|
||||||
|
*pobject = nv_object(priv);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
|
||||||
|
if (priv->r100c08_page) {
|
||||||
|
priv->r100c08 = pci_map_page(device->pdev, priv->r100c08_page,
|
||||||
|
0, PAGE_SIZE,
|
||||||
|
PCI_DMA_BIDIRECTIONAL);
|
||||||
|
if (pci_dma_mapping_error(device->pdev, priv->r100c08))
|
||||||
|
nv_warn(priv, "failed 0x100c08 page map\n");
|
||||||
|
} else {
|
||||||
|
nv_warn(priv, "failed 0x100c08 page alloc\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->base.memtype_valid = nv50_fb_memtype_valid;
|
||||||
|
priv->base.ram.init = nv50_fb_vram_init;
|
||||||
|
priv->base.ram.get = nv50_fb_vram_new;
|
||||||
|
priv->base.ram.put = nv50_fb_vram_del;
|
||||||
|
nv_subdev(priv)->intr = nv50_fb_intr;
|
||||||
|
return nouveau_fb_preinit(&priv->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nv50_fb_dtor(struct nouveau_object *object)
|
||||||
|
{
|
||||||
|
struct nouveau_device *device = nv_device(object);
|
||||||
|
struct nv50_fb_priv *priv = (void *)object;
|
||||||
|
|
||||||
|
if (priv->r100c08_page) {
|
||||||
|
pci_unmap_page(device->pdev, priv->r100c08, PAGE_SIZE,
|
||||||
|
PCI_DMA_BIDIRECTIONAL);
|
||||||
|
__free_page(priv->r100c08_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
nouveau_fb_destroy(&priv->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nv50_fb_init(struct nouveau_object *object)
|
||||||
|
{
|
||||||
|
struct nouveau_device *device = nv_device(object);
|
||||||
|
struct nv50_fb_priv *priv = (void *)object;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = nouveau_fb_init(&priv->base);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Not a clue what this is exactly. Without pointing it at a
|
||||||
|
* scratch page, VRAM->GART blits with M2MF (as in DDX DFS)
|
||||||
|
* cause IOMMU "read from address 0" errors (rh#561267)
|
||||||
|
*/
|
||||||
|
nv_wr32(priv, 0x100c08, priv->r100c08 >> 8);
|
||||||
|
|
||||||
|
/* This is needed to get meaningful information from 100c90
|
||||||
|
* on traps. No idea what these values mean exactly. */
|
||||||
|
switch (device->chipset) {
|
||||||
|
case 0x50:
|
||||||
|
nv_wr32(priv, 0x100c90, 0x000707ff);
|
||||||
|
break;
|
||||||
|
case 0xa3:
|
||||||
|
case 0xa5:
|
||||||
|
case 0xa8:
|
||||||
|
nv_wr32(priv, 0x100c90, 0x000d0fff);
|
||||||
|
break;
|
||||||
|
case 0xaf:
|
||||||
|
nv_wr32(priv, 0x100c90, 0x089d1fff);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nv_wr32(priv, 0x100c90, 0x001d07ff);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct nouveau_oclass
|
||||||
|
nv50_fb_oclass = {
|
||||||
|
.handle = NV_SUBDEV(FB, 0x50),
|
||||||
|
.ofuncs = &(struct nouveau_ofuncs) {
|
||||||
|
.ctor = nv50_fb_ctor,
|
||||||
|
.dtor = nv50_fb_dtor,
|
||||||
|
.init = nv50_fb_init,
|
||||||
|
.fini = _nouveau_fb_fini,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
|
@ -39,6 +39,7 @@ nv50_mc_intr[] = {
|
||||||
{ 0x00200000, NVDEV_SUBDEV_GPIO },
|
{ 0x00200000, NVDEV_SUBDEV_GPIO },
|
||||||
{ 0x04000000, NVDEV_ENGINE_DISP },
|
{ 0x04000000, NVDEV_ENGINE_DISP },
|
||||||
{ 0x80000000, NVDEV_ENGINE_SW },
|
{ 0x80000000, NVDEV_ENGINE_SW },
|
||||||
|
{ 0x0000d101, NVDEV_SUBDEV_FB },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ nv98_mc_intr[] = {
|
||||||
{ 0x00400000, NVDEV_ENGINE_COPY0 }, /* NVA3- */
|
{ 0x00400000, NVDEV_ENGINE_COPY0 }, /* NVA3- */
|
||||||
{ 0x04000000, NVDEV_ENGINE_DISP },
|
{ 0x04000000, NVDEV_ENGINE_DISP },
|
||||||
{ 0x80000000, NVDEV_ENGINE_SW },
|
{ 0x80000000, NVDEV_ENGINE_SW },
|
||||||
|
{ 0x0040d101, NVDEV_SUBDEV_FB },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче