Skip to content
Browse files

gdev: added a patch file for nouveau

  • Loading branch information...
1 parent 6bcb97f commit 3530e5d7070458de2962e6972ae0a743833a1546 Shinpei Kato committed Mar 28, 2012
Showing with 669 additions and 0 deletions.
  1. +669 −0 driver/patches/gdev-nouveau.patch
View
669 driver/patches/gdev-nouveau.patch
@@ -0,0 +1,669 @@
+diff --git drivers/gpu/drm/nouveau/Makefile drivers/gpu/drm/nouveau/Makefile
+index 1a2ad7e..a88eec5 100644
+--- drivers/gpu/drm/nouveau/Makefile
++++ drivers/gpu/drm/nouveau/Makefile
+@@ -3,7 +3,8 @@
+ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ ccflags-y := -Iinclude/drm
+-nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
++nouveau-y := gdev_interface.o \
++ nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
+ nouveau_object.o nouveau_irq.o nouveau_notifier.o \
+ nouveau_sgdma.o nouveau_dma.o nouveau_util.o \
+ nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \
+diff --git drivers/gpu/drm/nouveau/gdev_interface.c drivers/gpu/drm/nouveau/gdev_interface.c
+new file mode 100644
+index 0000000..9489632
+--- /dev/null
++++ drivers/gpu/drm/nouveau/gdev_interface.c
+@@ -0,0 +1,456 @@
++#include <linux/module.h>
++#include "gdev_interface.h"
++#include "nouveau_drv.h"
++#include "nvc0_graph.h"
++
++#define VS_START 0x20000000
++#define VS_END (1ull << 40)
++
++extern int nouveau_device_count;
++extern struct drm_device **nouveau_drm;
++extern void (*nouveau_callback_notify)(int subc, uint32_t data);
++
++int gdev_drv_vspace_alloc(struct drm_device *drm, uint64_t size, struct gdev_drv_vspace *drv_vspace)
++{
++ struct nouveau_channel *chan;
++
++ if (nouveau_channel_alloc(drm, &chan, NULL, 0xbeef0201, 0xbeef0202)) {
++ printk("Failed to allocate nouveau channel\n");
++ return -ENOMEM;
++ }
++
++ drv_vspace->priv = (void *)chan;
++
++ return 0;
++}
++EXPORT_SYMBOL(gdev_drv_vspace_alloc);
++
++int gdev_drv_vspace_free(struct gdev_drv_vspace *drv_vspace)
++{
++ struct nouveau_channel *chan = (struct nouveau_channel *)drv_vspace->priv;
++
++ nouveau_channel_ref(NULL, &chan);
++
++ return 0;
++}
++EXPORT_SYMBOL(gdev_drv_vspace_free);
++
++int gdev_drv_chan_alloc(struct drm_device *drm, struct gdev_drv_vspace *drv_vspace, struct gdev_drv_chan *drv_chan)
++{
++ struct drm_nouveau_private *dev_priv = drm->dev_private;
++ struct nouveau_channel *chan = (struct nouveau_channel *)drv_vspace->priv;
++ struct nouveau_bo *ib_bo, *pb_bo;
++ uint32_t cid;
++ volatile uint32_t *regs;
++ uint32_t *ib_map, *pb_map;
++ uint32_t ib_order, pb_order;
++ uint64_t ib_base, pb_base;
++ uint32_t ib_mask, pb_mask;
++ uint32_t pb_size;
++ int ret;
++
++ /* channel ID. */
++ cid = chan->id;
++
++ /* FIFO push buffer setup. */
++ pb_order = 15; /* it's hardcoded. pscnv uses 20, nouveau uses 15. */
++ pb_bo = chan->pushbuf_bo;
++ pb_base = chan->pushbuf_vma.offset;
++ pb_map = chan->pushbuf_bo->kmap.virtual;
++ pb_mask = (1 << pb_order) - 1;
++ pb_size = (1 << pb_order);
++ if (chan->pushbuf_bo->bo.mem.size / 2 != pb_size)
++ printk("Pushbuf size mismatched!\n");
++
++ /* FIFO indirect buffer setup. */
++ ib_order = 12; /* it's hardcoded. pscnv uses 9, nouveau uses 12*/
++ ib_bo = NULL;
++ ib_base = pb_base + pb_size;
++ ib_map = (void *)((unsigned long)pb_bo->kmap.virtual + pb_size);
++ ib_mask = (1 << ib_order) - 1;
++
++ /* FIFO init: it has already been done in gdev_vas_new(). */
++
++ switch (dev_priv->chipset & 0xf0) {
++ case 0xc0:
++ /* FIFO command queue registers. */
++ regs = chan->user;
++ /* PCOPY engines. */
++ ret = dev_priv->eng[NVOBJ_ENGINE_COPY0]->context_new(chan, NVOBJ_ENGINE_COPY0);
++ if (ret)
++ goto fail_pcopy0;
++ ret = dev_priv->eng[NVOBJ_ENGINE_COPY1]->context_new(chan, NVOBJ_ENGINE_COPY1);
++ if (ret)
++ goto fail_pcopy1;
++ break;
++ default:
++ ret = -EINVAL;
++ goto fail_fifo_reg;
++ }
++
++ drv_chan->priv = chan;
++ drv_chan->cid = cid;
++ drv_chan->regs = regs;
++ drv_chan->ib_bo = ib_bo;
++ drv_chan->ib_map = ib_map;
++ drv_chan->ib_order = ib_order;
++ drv_chan->ib_base = ib_base;
++ drv_chan->ib_mask = ib_mask;
++ drv_chan->pb_bo = pb_bo;
++ drv_chan->pb_map = pb_map;
++ drv_chan->pb_order = pb_order;
++ drv_chan->pb_base = pb_base;
++ drv_chan->pb_mask = pb_mask;
++ drv_chan->pb_size = pb_size;
++
++ return 0;
++
++fail_fifo_reg:
++fail_pcopy1:
++ dev_priv->eng[NVOBJ_ENGINE_COPY0]->context_del(chan, NVOBJ_ENGINE_COPY0);
++fail_pcopy0:
++ return ret;
++}
++EXPORT_SYMBOL(gdev_drv_chan_alloc);
++
++int gdev_drv_chan_free(struct gdev_drv_vspace *drv_vspace, struct gdev_drv_chan *drv_chan)
++{
++ struct nouveau_channel *chan = (struct nouveau_channel *)drv_vspace->priv;
++ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
++
++ dev_priv->eng[NVOBJ_ENGINE_COPY1]->context_del(chan, NVOBJ_ENGINE_COPY1);
++ dev_priv->eng[NVOBJ_ENGINE_COPY0]->context_del(chan, NVOBJ_ENGINE_COPY0);
++
++ return 0;
++}
++EXPORT_SYMBOL(gdev_drv_chan_free);
++
++int gdev_drv_bo_alloc(struct drm_device *drm, uint64_t size, uint32_t drv_flags, struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo)
++{
++ struct drm_nouveau_private *dev_priv = drm->dev_private;
++ struct nouveau_channel *chan = (struct nouveau_channel *)drv_vspace->priv;
++ struct nouveau_bo *bo;
++ struct nouveau_vma *vma;
++ uint32_t flags = 0;
++ int ret;
++
++ /* set memory type. */
++ if (drv_flags & GDEV_DRV_BO_VRAM) {
++ flags |= TTM_PL_FLAG_VRAM;
++ }
++ if (drv_flags & GDEV_DRV_BO_SYSRAM) {
++ flags |= TTM_PL_FLAG_TT;
++ }
++
++ ret = nouveau_bo_new(drm, size, 0, flags, 0, 0, &bo);
++ if (ret)
++ goto fail_bo_new;
++
++ if (drv_flags & GDEV_DRV_BO_MAPPABLE) {
++ ret = nouveau_bo_map(bo);
++ if (ret)
++ goto fail_bo_map;
++ }
++ else
++ bo->kmap.virtual = NULL;
++
++ /* allocate virtual address space, if requested. */
++ if (drv_flags & GDEV_DRV_BO_VSPACE) {
++ if (dev_priv->card_type >= NV_50) {
++ vma = kzalloc(sizeof(*vma), GFP_KERNEL);
++ if (!vma) {
++ ret = -ENOMEM;
++ goto fail_vma_alloc;
++ }
++
++ ret = nouveau_bo_vma_add(bo, chan->vm, vma);
++ if (ret)
++ goto fail_vma_add;
++
++ drv_bo->addr = vma->offset;
++ }
++ else /* non-supported cards. */
++ drv_bo->addr = 0;
++ }
++ else
++ drv_bo->addr = 0;
++
++ /* address, size, and map. */
++ if (bo->kmap.virtual)
++ drv_bo->map = bo->kmap.virtual;
++ else
++ drv_bo->map = NULL;
++ drv_bo->size = bo->bo.mem.size;
++ drv_bo->priv = bo;
++
++ return 0;
++
++fail_vma_add:
++ kfree(vma);
++fail_vma_alloc:
++ nouveau_bo_unmap(bo);
++fail_bo_map:
++ nouveau_bo_ref(NULL, &bo);
++fail_bo_new:
++ return ret;
++
++}
++EXPORT_SYMBOL(gdev_drv_bo_alloc);
++
++int gdev_drv_bo_free(struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo)
++{
++ struct nouveau_channel *chan = (struct nouveau_channel *)drv_vspace->priv;
++ struct nouveau_bo *bo = (struct nouveau_bo *)drv_bo->priv;
++ struct nouveau_vma *vma;
++ uint64_t addr = drv_bo->addr;
++ void *map = drv_bo->map;
++
++ if (map && bo->kmap.bo) /* dirty validation.. */
++ nouveau_bo_unmap(bo);
++
++ if (addr) {
++ vma = nouveau_bo_vma_find(bo, chan->vm);
++#if 0 /* this function call crushes the system sometimes... */
++ if (vma) {
++ nouveau_bo_vma_del(bo, vma);
++ kfree(vma);
++ }
++ else {
++ return -ENOENT;
++ }
++#endif
++ }
++
++ nouveau_bo_ref(NULL, &bo);
++
++ return 0;
++}
++EXPORT_SYMBOL(gdev_drv_bo_free);
++
++int gdev_drv_bo_bind(struct drm_device *drm, struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo)
++{
++ struct drm_nouveau_private *dev_priv = drm->dev_private;
++ struct nouveau_channel *chan = (struct nouveau_channel *)drv_vspace->priv;
++ struct nouveau_bo *bo = (struct nouveau_bo *)drv_bo->priv;
++ struct nouveau_vma *vma;
++ int ret;
++
++ /* allocate virtual address space, if requested. */
++ if (dev_priv->card_type >= NV_50) {
++ vma = kzalloc(sizeof(*vma), GFP_KERNEL);
++ if (!vma) {
++ ret = -ENOMEM;
++ goto fail_vma_alloc;
++ }
++
++ ret = nouveau_bo_vma_add(bo, chan->vm, vma);
++ if (ret)
++ goto fail_vma_add;
++
++ drv_bo->addr = vma->offset;
++ }
++ else /* non-supported cards. */
++ drv_bo->addr = 0;
++
++ drv_bo->map = bo->kmap.virtual; /* could be NULL. */
++ drv_bo->size = bo->bo.mem.size;
++
++ return 0;
++
++fail_vma_add:
++ kfree(vma);
++fail_vma_alloc:
++ return ret;
++}
++EXPORT_SYMBOL(gdev_drv_bo_bind);
++
++int gdev_drv_bo_unbind(struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo)
++{
++ struct nouveau_channel *chan = (struct nouveau_channel *)drv_vspace->priv;
++ struct nouveau_bo *bo = (struct nouveau_bo *)drv_bo->priv;
++ struct nouveau_vma *vma;
++
++ vma = nouveau_bo_vma_find(bo, chan->vm);
++ if (vma) {
++#if 0 /* this function call crushes the system sometimes... */
++ nouveau_bo_vma_del(bo, vma);
++ kfree(vma);
++#endif
++ }
++ else
++ return -ENOENT;
++
++ return 0;
++}
++EXPORT_SYMBOL(gdev_drv_bo_unbind);
++
++int gdev_drv_bo_map(struct drm_device *drm, struct gdev_drv_bo *drv_bo)
++{
++ struct nouveau_bo *bo = (struct nouveau_bo *)drv_bo->priv;
++ int ret;
++
++ ret = nouveau_bo_map(bo);
++ if (ret)
++ return ret;
++
++ drv_bo->map = bo->kmap.virtual;
++
++ return 0;
++}
++EXPORT_SYMBOL(gdev_drv_bo_map);
++
++int gdev_drv_bo_unmap(struct gdev_drv_bo *drv_bo)
++{
++ struct nouveau_bo *bo = (struct nouveau_bo *)drv_bo->priv;
++
++ if (bo->kmap.bo) /* dirty validation.. */
++ nouveau_bo_unmap(bo);
++ else
++ return -ENOENT;
++
++ return 0;
++}
++EXPORT_SYMBOL(gdev_drv_bo_unmap);
++
++int gdev_drv_read32(struct drm_device *drm, struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo, uint64_t offset, uint32_t *p)
++{
++ if (drv_bo->map)
++ *p = ioread32_native(drv_bo->map + offset);
++ else
++ return -EINVAL;
++
++ return 0;
++}
++EXPORT_SYMBOL(gdev_drv_read32);
++
++int gdev_drv_write32(struct drm_device *drm, struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo, uint64_t offset, uint32_t val)
++{
++ if (drv_bo->map)
++ iowrite32_native(val, drv_bo->map + offset);
++ else
++ return -EINVAL;
++
++ return 0;
++}
++EXPORT_SYMBOL(gdev_drv_write32);
++
++int gdev_drv_read(struct drm_device *drm, struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo, uint64_t offset, uint64_t size, void *buf)
++{
++ if (drv_bo->map)
++ memcpy_fromio(buf, drv_bo->map + offset, size);
++ else
++ return -EINVAL;
++
++ return 0;
++}
++EXPORT_SYMBOL(gdev_drv_read);
++
++int gdev_drv_write(struct drm_device *drm, struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo, uint64_t offset, uint64_t size, const void *buf)
++{
++ if (drv_bo->map)
++ memcpy_toio(drv_bo->map + offset, buf, size);
++ else
++ return -EINVAL;
++
++ return 0;
++}
++EXPORT_SYMBOL(gdev_drv_write);
++
++int gdev_drv_getdevice(int *count)
++{
++ *count = nouveau_device_count;
++ return 0;
++}
++EXPORT_SYMBOL(gdev_drv_getdevice);
++
++int gdev_drv_getdrm(int minor, struct drm_device **pptr)
++{
++ if (minor < nouveau_device_count) {
++ if (nouveau_drm[minor]) {
++ *pptr = nouveau_drm[minor];
++ return 0;
++ }
++ }
++
++ *pptr = NULL;
++
++ return -ENODEV;
++}
++EXPORT_SYMBOL(gdev_drv_getdrm);
++
++int gdev_drv_getparam(struct drm_device *drm, uint32_t type, uint64_t *res)
++{
++ struct drm_nouveau_getparam getparam;
++ struct drm_nouveau_private *dev_priv = drm->dev_private;
++ int ret = 0;
++
++ switch (type) {
++ case GDEV_DRV_GETPARAM_MP_COUNT:
++ if ((dev_priv->chipset & 0xf0) == 0xc0) {
++ struct nvc0_graph_priv *priv = nv_engine(drm, NVOBJ_ENGINE_GR);
++ *res = priv->tp_total;
++ }
++ else {
++ *res = 0;
++ ret = -EINVAL;
++ }
++ break;
++ case GDEV_DRV_GETPARAM_FB_SIZE:
++ getparam.param = NOUVEAU_GETPARAM_FB_SIZE;
++ ret = nouveau_ioctl_getparam(drm, &getparam, NULL);
++ *res = getparam.value;
++ break;
++ case GDEV_DRV_GETPARAM_AGP_SIZE:
++ getparam.param = NOUVEAU_GETPARAM_AGP_SIZE;
++ ret = nouveau_ioctl_getparam(drm, &getparam, NULL);
++ *res = getparam.value;
++ break;
++ case GDEV_DRV_GETPARAM_CHIPSET_ID:
++ getparam.param = NOUVEAU_GETPARAM_CHIPSET_ID;
++ ret = nouveau_ioctl_getparam(drm, &getparam, NULL);
++ *res = getparam.value;
++ break;
++ default:
++ ret = -EINVAL;
++ }
++
++ return ret;
++}
++EXPORT_SYMBOL(gdev_drv_getparam);
++
++int gdev_drv_getaddr(struct drm_device *drm, struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo, uint64_t offset, uint64_t *addr)
++{
++ struct nouveau_bo *bo = (struct nouveau_bo *)drv_bo->priv;
++ int page = offset / PAGE_SIZE;
++ uint32_t x = offset - page * PAGE_SIZE;
++
++ if (drv_bo->map) {
++ if (bo->bo.mem.mem_type & TTM_PL_TT)
++ *addr = ((struct ttm_dma_tt *)bo->bo.ttm)->dma_address[page] + x;
++ else
++ *addr = bo->bo.mem.bus.base + bo->bo.mem.bus.offset + x;
++ }
++ else {
++ *addr = 0;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(gdev_drv_getaddr);
++
++int gdev_drv_setnotify(void (*func)(int subc, uint32_t data))
++{
++ nouveau_callback_notify = func;
++ return 0;
++}
++EXPORT_SYMBOL(gdev_drv_setnotify);
++
++int gdev_drv_unsetnotify(void (*func)(int subc, uint32_t data))
++{
++ if (nouveau_callback_notify != func)
++ return -EINVAL;
++ nouveau_callback_notify = NULL;
++
++ return 0;
++}
++EXPORT_SYMBOL(gdev_drv_unsetnotify);
+diff --git drivers/gpu/drm/nouveau/gdev_interface.h drivers/gpu/drm/nouveau/gdev_interface.h
+new file mode 100644
+index 0000000..9d11c25
+--- /dev/null
++++ drivers/gpu/drm/nouveau/gdev_interface.h
+@@ -0,0 +1,66 @@
++#ifndef __GDEV_INTERFACE_H__
++#define __GDEV_INTERFACE_H__
++
++#include "drmP.h"
++#include "drm.h"
++
++#define GDEV_DRV_BO_VRAM 0x1
++#define GDEV_DRV_BO_SYSRAM 0x2
++#define GDEV_DRV_BO_MAPPABLE 0x4
++#define GDEV_DRV_BO_VSPACE 0x8
++
++#define GDEV_DRV_GETPARAM_MP_COUNT 1
++#define GDEV_DRV_GETPARAM_FB_SIZE 2
++#define GDEV_DRV_GETPARAM_AGP_SIZE 3
++#define GDEV_DRV_GETPARAM_CHIPSET_ID 4
++
++struct gdev_drv_vspace {
++ void *priv;
++};
++
++struct gdev_drv_chan {
++ void *priv;
++ uint32_t cid;
++ volatile uint32_t *regs; /* channel control registers. */
++ void *ib_bo; /* driver private object. */
++ uint32_t *ib_map;
++ uint32_t ib_order;
++ uint64_t ib_base;
++ uint32_t ib_mask;
++ void *pb_bo; /* driver private object. */
++ uint32_t *pb_map;
++ uint32_t pb_order;
++ uint64_t pb_base;
++ uint32_t pb_mask;
++ uint32_t pb_size;
++};
++
++struct gdev_drv_bo {
++ void *priv;
++ uint64_t addr;
++ uint64_t size;
++ void *map;
++};
++
++int gdev_drv_vspace_alloc(struct drm_device *drm, uint64_t size, struct gdev_drv_vspace *drv_vspace);
++int gdev_drv_vspace_free(struct gdev_drv_vspace *drv_vspace);
++int gdev_drv_chan_alloc(struct drm_device *drm, struct gdev_drv_vspace *drv_vspace, struct gdev_drv_chan *drv_chan);
++int gdev_drv_chan_free(struct gdev_drv_vspace *drv_vspace, struct gdev_drv_chan *drv_chan);
++int gdev_drv_bo_alloc(struct drm_device *drm, uint64_t size, uint32_t flags, struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo);
++int gdev_drv_bo_free(struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo);
++int gdev_drv_bo_bind(struct drm_device *drm, struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo);
++int gdev_drv_bo_unbind(struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo);
++int gdev_drv_bo_map(struct drm_device *drm, struct gdev_drv_bo *drv_bo);
++int gdev_drv_bo_unmap(struct gdev_drv_bo *drv_bo);
++int gdev_drv_read32(struct drm_device *drm, struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo, uint64_t offset, uint32_t *p);
++int gdev_drv_write32(struct drm_device *drm, struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo, uint64_t offset, uint32_t val);
++int gdev_drv_read(struct drm_device *drm, struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo, uint64_t offset, uint64_t size, void *buf);
++int gdev_drv_write(struct drm_device *drm, struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo, uint64_t offset, uint64_t size, const void *buf);
++int gdev_drv_getdevice(int *count);
++int gdev_drv_getdrm(int minor, struct drm_device **pptr);
++int gdev_drv_getparam(struct drm_device *drm, uint32_t type, uint64_t *res);
++int gdev_drv_getaddr(struct drm_device *drm, struct gdev_drv_vspace *drv_vspace, struct gdev_drv_bo *drv_bo, uint64_t offset, uint64_t *addr);
++int gdev_drv_setnotify(void (*func)(int subc, uint32_t data));
++int gdev_drv_unsetnotify(void (*func)(int subc, uint32_t data));
++
++#endif
+diff --git drivers/gpu/drm/nouveau/nouveau_channel.c drivers/gpu/drm/nouveau/nouveau_channel.c
+index a018def..06a617f 100644
+--- drivers/gpu/drm/nouveau/nouveau_channel.c
++++ drivers/gpu/drm/nouveau/nouveau_channel.c
+@@ -188,7 +188,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
+ chan->user_put = 0x40;
+ chan->user_get = 0x44;
+ if (dev_priv->card_type >= NV_50)
+- chan->user_get_hi = 0x60;
++ chan->user_get_hi = 0x60;
+
+ /* disable the fifo caches */
+ pfifo->reassign(dev, false);
+diff --git drivers/gpu/drm/nouveau/nouveau_drv.c drivers/gpu/drm/nouveau/nouveau_drv.c
+index 4f2030b..e678716 100644
+--- drivers/gpu/drm/nouveau/nouveau_drv.c
++++ drivers/gpu/drm/nouveau/nouveau_drv.c
+@@ -460,8 +460,38 @@ static struct pci_driver nouveau_pci_driver = {
+ .resume = nouveau_pci_resume
+ };
+
++static int __get_device_count(void)
++{
++ struct pci_dev *pdev = NULL;
++ const struct pci_device_id *pid;
++ int i;
++ int count = 0;
++
++ for (i = 0; pciidlist[i].vendor != 0; i++) {
++ pid = &pciidlist[i];
++ while ((pdev = pci_get_subsys(pid->vendor, pid->device, pid->subvendor, pid->subdevice, pdev)) != NULL) {
++ if ((pdev->class & pid->class_mask) != pid->class)
++ continue;
++ count++; /* physical device count */
++ }
++ }
++
++ return count;
++}
++
++int nouveau_device_count = 0;
++struct drm_device **nouveau_drm;
++
+ static int __init nouveau_init(void)
+ {
++ nouveau_device_count = __get_device_count();
++
++ nouveau_drm = kzalloc(sizeof(*nouveau_drm) * nouveau_device_count, GFP_KERNEL);
++ if (!nouveau_drm) {
++ printk(KERN_INFO "Failed to allocate nouveau drm array\n");
++ return -ENOMEM;
++ }
++
+ driver.num_ioctls = nouveau_max_ioctl;
+
+ if (nouveau_modeset == -1) {
+diff --git drivers/gpu/drm/nouveau/nouveau_state.c drivers/gpu/drm/nouveau/nouveau_state.c
+index 1e04305..79a962c 100644
+--- drivers/gpu/drm/nouveau/nouveau_state.c
++++ drivers/gpu/drm/nouveau/nouveau_state.c
+@@ -990,6 +990,9 @@ static int nouveau_remove_conflicting_drivers(struct drm_device *dev)
+ return 0;
+ }
+
++extern int nouveau_device_count;
++extern struct drm_device **nouveau_drm;
++
+ int nouveau_load(struct drm_device *dev, unsigned long flags)
+ {
+ struct drm_nouveau_private *dev_priv;
+@@ -1161,6 +1164,9 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
+ if (ret)
+ goto err_ramin;
+
++ if (dev->primary->index < nouveau_device_count)
++ nouveau_drm[dev->primary->index] = dev;
++
+ return 0;
+
+ err_ramin:
+diff --git drivers/gpu/drm/nouveau/nv50_vm.c drivers/gpu/drm/nouveau/nv50_vm.c
+index f06f4ad..44fbac9 100644
+--- drivers/gpu/drm/nouveau/nv50_vm.c
++++ drivers/gpu/drm/nouveau/nv50_vm.c
+@@ -85,7 +85,7 @@ nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
+ target = 3;
+ }
+
+- phys = vm_addr(vma, phys, mem->memtype, 0);
++ phys = vm_addr(vma, phys, mem->memtype, target);
+ pte <<= 3;
+ cnt <<= 3;
+
+diff --git drivers/gpu/drm/nouveau/nvc0_graph.c drivers/gpu/drm/nouveau/nvc0_graph.c
+index 8ee3963..bbc6420 100644
+--- drivers/gpu/drm/nouveau/nvc0_graph.c
++++ drivers/gpu/drm/nouveau/nvc0_graph.c
+@@ -662,6 +662,8 @@ nvc0_graph_ctxctl_isr(struct drm_device *dev)
+ nv_wr32(dev, 0x409c20, ustat);
+ }
+
++void (*nouveau_callback_notify)(int subc, uint32_t data) = NULL;
++
+ static void
+ nvc0_graph_isr(struct drm_device *dev)
+ {
+@@ -675,6 +677,14 @@ nvc0_graph_isr(struct drm_device *dev)
+ u32 code = nv_rd32(dev, 0x400110);
+ u32 class = nv_rd32(dev, 0x404200 + (subc * 4));
+
++ if (stat & 0x00000001) {
++ if (nouveau_callback_notify) {
++ nouveau_callback_notify(subc, data);
++ }
++ nv_wr32(dev, 0x400100, 0x00000001);
++ stat &= ~0x00000001;
++ }
++
+ if (stat & 0x00000010) {
+ if (nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) {
+ NV_INFO(dev, "PGRAPH: ILLEGAL_MTHD ch %d [0x%010llx] "

0 comments on commit 3530e5d

Please sign in to comment.
Something went wrong with that request. Please try again.