On Wed, Dec 10, 2014 at 5:53 PM, Pierre Moreau pierre.morrow@free.fr wrote:
(This is a v3 of patch "drm/nouveau/fb/nv50: Add PFB writes")
This fix a GPU lockup on 9400M (NVAC) when using acceleration, see https://bugs.freedesktop.org/show_bug.cgi?id=27501
v2:
- Move code to subdev/fb/nv50.c as suggested by Roy Spliet;
- Remove arbitrary writes to 100c18/100c24
- Replace write to 100c1c of arbitrary value by the address of a scratch page as proposed by Ilia Mirkin;
- Remove enabling of bits 16 and 0 as they don't yield in any changes.
v3:
- Move code to subdev/fb/nvaa.c as suggested by Ilia Mirkin.
The following changes were made thanks to information provided by Robert Morell from NVidia:
- Allocate a dma page for use by the pollers;
- Re-enable pollers at bits 16 and 0;
- Set pollers address to a proper value.
Hey Pierre,
This patch is incorrect. As Robert pointed out in an older thread, the registers don't take the physical address of a page, but a somewhat odd "negative offset from the end of carveout".
See this example (referring to Robert's last email):
220.926392 read32 #3 +0x00100e10 -> 0x00070000 220.926406 read32 #3 +0x00100e14 -> 0x00010000
carveout_base = 0x70000000 carveout_size = 0x10000000
-- snip --
223.300495 read32 #3 +0x00100c14 -> 0x00000000 223.300521 read32 #3 +0x00100c18 -> 0x00000000 223.300547 write32 #3 +0x00100c18 <- 0x000027ff
base = (0x70000000 + 0x10000000) - ((0x27ff + 1) << 5) base = 0x7ffb0000 << in carveout
223.300573 read32 #3 +0x00100c14 -> 0x00000000 223.300599 write32 #3 +0x00100c14 <- 0x00000001 223.300625 read32 #3 +0x00100c1c -> 0x00000002 223.300651 write32 #3 +0x00100c1c <- 0x000027fe
base = (0x70000000 + 0x10000000) - ((0x27fe + 1) << 5) base = 0x7ffb0020 << in carveout
223.300677 read32 #3 +0x00100c14 -> 0x00000001 223.300702 write32 #3 +0x00100c14 <- 0x00000003 223.300728 read32 #3 +0x00100c24 -> 0x00000004 223.300754 write32 #3 +0x00100c24 <- 0x000027fd
base = (0x70000000 + 0x10000000) - ((0x27ff + 1) << 5) base = 0x7ffb0040 << in carveout
223.300780 read32 #3 +0x00100c14 -> 0x00000003 223.300806 write32 #3 +0x00100c14 <- 0x00010003
It's a bit tricky at that point in the nouveau init process to allocate device memory, but, we already reserve 1MiB of memory at the end of "VRAM" (carveout / stolen memory) so we can make use of that.
I've attached 3 patches. The first two of them, I'll probably merge as-is.
The third patch is an example of how this should probably be done, in case you want to continue tackling this some more :)
Cheers, Ben.
Signed-off-by: Pierre Moreau pierre.morrow@free.fr
drm/core/subdev/fb/nvaa.h | 1 + nvkm/subdev/fb/nv50.h | 4 +++ nvkm/subdev/fb/nvaa.c | 74 ++++++++++++++++++++++++++++++++++++++++++++--- nvkm/subdev/fb/nvaa.h | 19 ++++++++++++ 4 files changed, 94 insertions(+), 4 deletions(-) create mode 120000 drm/core/subdev/fb/nvaa.h create mode 100644 nvkm/subdev/fb/nvaa.h
diff --git a/drm/core/subdev/fb/nvaa.h b/drm/core/subdev/fb/nvaa.h new file mode 120000 index 0000000..b450e8c --- /dev/null +++ b/drm/core/subdev/fb/nvaa.h @@ -0,0 +1 @@ +../../../../nvkm/subdev/fb/nvaa.h \ No newline at end of file diff --git a/nvkm/subdev/fb/nv50.h b/nvkm/subdev/fb/nv50.h index c5e5a88..0b20975 100644 --- a/nvkm/subdev/fb/nv50.h +++ b/nvkm/subdev/fb/nv50.h @@ -9,6 +9,10 @@ struct nv50_fb_priv { dma_addr_t r100c08; };
+#define nv50_fb_create(p,e,c,d,o) \
nv50_fb_ctor((p), (e), (c), (d), sizeof(**o), \
(struct nouveau_object **)o)
int nv50_fb_ctor(struct nouveau_object *, struct nouveau_object *, struct nouveau_oclass *, void *, u32, struct nouveau_object **); diff --git a/nvkm/subdev/fb/nvaa.c b/nvkm/subdev/fb/nvaa.c index cba8e68..b70ab2f 100644 --- a/nvkm/subdev/fb/nvaa.c +++ b/nvkm/subdev/fb/nvaa.c @@ -22,15 +22,81 @@
- Authors: Ben Skeggs
*/
-#include "nv50.h" +#include "nvaa.h"
+int +nvaa_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 nvaa_fb_priv *priv;
int ret;
ret = nv50_fb_create(parent, engine, oclass, data, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv = (struct nvaa_fb_priv *)(*pobject);
priv->r100c18_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (priv->r100c18_page) {
priv->r100c18 = dma_map_page(nv_device_base(device),
priv->r100c18_page, 0, PAGE_SIZE,
DMA_BIDIRECTIONAL);
if (dma_mapping_error(nv_device_base(device), priv->r100c18))
return -EFAULT;
} else {
nv_warn(priv, "failed 0x100c18 page alloc\n");
}
return 0;
+}
+void +nvaa_fb_dtor(struct nouveau_object *object) +{
struct nouveau_device *device = nv_device(object);
struct nvaa_fb_priv *priv = (void *)object;
if (priv->r100c18_page) {
dma_unmap_page(nv_device_base(device), priv->r100c18, PAGE_SIZE,
DMA_BIDIRECTIONAL);
__free_page(priv->r100c18_page);
}
nv50_fb_dtor(object);
+}
+int +nvaa_fb_init(struct nouveau_object *object) +{
struct nvaa_fb_priv *priv = (void *)object;
int ret;
ret = nv50_fb_init(object);
if (ret)
return ret;
/* Enable NISO poller for various clients and set their associated
* read address, only for MCP77/78 and MCP79/7A. (fd#25701)
*/
nv_wr32(priv, 0x100c18, priv->r100c18 >> 8);
nv_mask(priv, 0x100c14, 0x00000000, 0x00000001);
nv_wr32(priv, 0x100c1c, (priv->r100c18 >> 8) + 1);
nv_mask(priv, 0x100c14, 0x00000000, 0x00000002);
nv_wr32(priv, 0x100c24, (priv->r100c18 >> 8) + 2);
nv_mask(priv, 0x100c14, 0x00000000, 0x00010000);
return 0;
+}
struct nouveau_oclass * nvaa_fb_oclass = &(struct nv50_fb_impl) { .base.base.handle = NV_SUBDEV(FB, 0xaa), .base.base.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_fb_ctor,
.dtor = nv50_fb_dtor,
.init = nv50_fb_init,
.ctor = nvaa_fb_ctor,
.dtor = nvaa_fb_dtor,
.init = nvaa_fb_init, .fini = _nouveau_fb_fini, }, .base.memtype = nv50_fb_memtype_valid,
diff --git a/nvkm/subdev/fb/nvaa.h b/nvkm/subdev/fb/nvaa.h new file mode 100644 index 0000000..84e1eca --- /dev/null +++ b/nvkm/subdev/fb/nvaa.h @@ -0,0 +1,19 @@ +#ifndef __NVKM_FB_NVAA_H__ +#define __NVKM_FB_NVAA_H__
+#include "nv50.h"
+struct nvaa_fb_priv {
struct nv50_fb_priv base;
struct page *r100c18_page;
dma_addr_t r100c18;
+};
+int nvaa_fb_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32,
struct nouveau_object **);
+void nvaa_fb_dtor(struct nouveau_object *); +int nvaa_fb_init(struct nouveau_object *);
+#endif
2.1.3
Nouveau mailing list Nouveau@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/nouveau