support for platform devices
authorAlexandre Courbot <acourbot@nvidia.com>
Mon, 17 Feb 2014 06:17:26 +0000 (15:17 +0900)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 26 Mar 2014 04:08:04 +0000 (14:08 +1000)
Upcoming mobile Kepler GPUs (such as GK20A) use the platform bus instead
of PCI to which Nouveau is tightly dependent. This patch allows Nouveau
to handle platform devices by:

- abstracting PCI-dependent functions that were typically used for
  resource querying and page mapping,
- introducing a nv_device_is_pci() function that allows to make
  PCI-dependent code conditional,
- providing a nouveau_drm_platform_probe() function that takes a GPU
  platform device to be probed.

Core code as well as engine/subdev drivers are updated wherever possible
to make use of these functions. Some older drivers are too dependent on
PCI to be properly updated, but all newer code on which future chips may
depend should at least be runnable with platform devices.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
35 files changed:
drivers/gpu/drm/nouveau/core/engine/device/base.c
drivers/gpu/drm/nouveau/core/engine/falcon.c
drivers/gpu/drm/nouveau/core/engine/fifo/base.c
drivers/gpu/drm/nouveau/core/engine/graph/nv20.c
drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
drivers/gpu/drm/nouveau/core/engine/xtensa.c
drivers/gpu/drm/nouveau/core/include/core/device.h
drivers/gpu/drm/nouveau/core/include/engine/device.h
drivers/gpu/drm/nouveau/core/include/subdev/mc.h
drivers/gpu/drm/nouveau/core/os.h
drivers/gpu/drm/nouveau/core/subdev/bar/base.c
drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c
drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h
drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c
drivers/gpu/drm/nouveau/core/subdev/mc/base.c
drivers/gpu/drm/nouveau/core/subdev/mxm/base.c
drivers/gpu/drm/nouveau/nouveau_abi16.c
drivers/gpu/drm/nouveau/nouveau_agp.c
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_chan.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_sysfs.c
drivers/gpu/drm/nouveau/nouveau_ttm.c
drivers/gpu/drm/nouveau/nouveau_vga.c

index 96559ac400dc334121be3e95727eb59604d7e00c..18c8c7245b73b2b1e12ec3fe921266621763f8ee 100644 (file)
@@ -131,8 +131,8 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
        if (ret)
                return ret;
 
-       mmio_base = pci_resource_start(device->pdev, 0);
-       mmio_size = pci_resource_len(device->pdev, 0);
+       mmio_base = nv_device_resource_start(device, 0);
+       mmio_size = nv_device_resource_len(device, 0);
 
        /* translate api disable mask into internal mapping */
        disable = args->debug0;
@@ -448,6 +448,72 @@ nouveau_device_dtor(struct nouveau_object *object)
        nouveau_engine_destroy(&device->base);
 }
 
+resource_size_t
+nv_device_resource_start(struct nouveau_device *device, unsigned int bar)
+{
+       if (nv_device_is_pci(device)) {
+               return pci_resource_start(device->pdev, bar);
+       } else {
+               struct resource *res;
+               res = platform_get_resource(device->platformdev,
+                                           IORESOURCE_MEM, bar);
+               if (!res)
+                       return 0;
+               return res->start;
+       }
+}
+
+resource_size_t
+nv_device_resource_len(struct nouveau_device *device, unsigned int bar)
+{
+       if (nv_device_is_pci(device)) {
+               return pci_resource_len(device->pdev, bar);
+       } else {
+               struct resource *res;
+               res = platform_get_resource(device->platformdev,
+                                           IORESOURCE_MEM, bar);
+               if (!res)
+                       return 0;
+               return resource_size(res);
+       }
+}
+
+dma_addr_t
+nv_device_map_page(struct nouveau_device *device, struct page *page)
+{
+       dma_addr_t ret;
+
+       if (nv_device_is_pci(device)) {
+               ret = pci_map_page(device->pdev, page, 0, PAGE_SIZE,
+                                  PCI_DMA_BIDIRECTIONAL);
+               if (pci_dma_mapping_error(device->pdev, ret))
+                       ret = 0;
+       } else {
+               ret = page_to_phys(page);
+       }
+
+       return ret;
+}
+
+void
+nv_device_unmap_page(struct nouveau_device *device, dma_addr_t addr)
+{
+       if (nv_device_is_pci(device))
+               pci_unmap_page(device->pdev, addr, PAGE_SIZE,
+                              PCI_DMA_BIDIRECTIONAL);
+}
+
+int
+nv_device_get_irq(struct nouveau_device *device, bool stall)
+{
+       if (nv_device_is_pci(device)) {
+               return device->pdev->irq;
+       } else {
+               return platform_get_irq_byname(device->platformdev,
+                                              stall ? "stall" : "nonstall");
+       }
+}
+
 static struct nouveau_oclass
 nouveau_device_oclass = {
        .handle = NV_ENGINE(DEVICE, 0x00),
@@ -459,8 +525,8 @@ nouveau_device_oclass = {
 };
 
 int
-nouveau_device_create_(struct pci_dev *pdev, u64 name, const char *sname,
-                      const char *cfg, const char *dbg,
+nouveau_device_create_(void *dev, enum nv_bus_type type, u64 name,
+                      const char *sname, const char *cfg, const char *dbg,
                       int length, void **pobject)
 {
        struct nouveau_device *device;
@@ -478,7 +544,14 @@ nouveau_device_create_(struct pci_dev *pdev, u64 name, const char *sname,
        if (ret)
                goto done;
 
-       device->pdev = pdev;
+       switch (type) {
+       case NOUVEAU_BUS_PCI:
+               device->pdev = dev;
+               break;
+       case NOUVEAU_BUS_PLATFORM:
+               device->platformdev = dev;
+               break;
+       }
        device->handle = name;
        device->cfgopt = cfg;
        device->dbgopt = dbg;
index 5e077e4ed7f6aa23d0e8ed3fde50ad58c2fd99d7..2914646c87094868e41e9ee38db9e2eb881f20b8 100644 (file)
@@ -119,7 +119,7 @@ _nouveau_falcon_init(struct nouveau_object *object)
                snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03x",
                         device->chipset, falcon->addr >> 12);
 
-               ret = request_firmware(&fw, name, &device->pdev->dev);
+               ret = request_firmware(&fw, name, nv_device_base(device));
                if (ret == 0) {
                        falcon->code.data = vmemdup(fw->data, fw->size);
                        falcon->code.size = fw->size;
@@ -138,7 +138,7 @@ _nouveau_falcon_init(struct nouveau_object *object)
                snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xd",
                         device->chipset, falcon->addr >> 12);
 
-               ret = request_firmware(&fw, name, &device->pdev->dev);
+               ret = request_firmware(&fw, name, nv_device_base(device));
                if (ret) {
                        nv_error(falcon, "unable to load firmware data\n");
                        return ret;
@@ -153,7 +153,7 @@ _nouveau_falcon_init(struct nouveau_object *object)
                snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xc",
                         device->chipset, falcon->addr >> 12);
 
-               ret = request_firmware(&fw, name, &device->pdev->dev);
+               ret = request_firmware(&fw, name, nv_device_base(device));
                if (ret) {
                        nv_error(falcon, "unable to load firmware code\n");
                        return ret;
index d3ec436d9cb5f249eff5e7146f842d325980ff8e..6f9041ced9a2b131ad0e571091b4383757b3e085 100644 (file)
@@ -86,7 +86,7 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent,
        }
 
        /* map fifo control registers */
-       chan->user = ioremap(pci_resource_start(device->pdev, bar) + addr +
+       chan->user = ioremap(nv_device_resource_start(device, bar) + addr +
                             (chan->chid * size), size);
        if (!chan->user)
                return -EFAULT;
index b24559315903f56b23dad5df1aa3cf95f9572882..d145e080899afd788f27638f580d45b108dd7425 100644 (file)
@@ -349,7 +349,7 @@ nv20_graph_init(struct nouveau_object *object)
        nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp);
 
        /* begin RAM config */
-       vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1;
+       vramsz = nv_device_resource_len(nv_device(priv), 0) - 1;
        nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
        nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
        nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
index 193a5de1b48287e05c732c28ddc066b8e4e5048a..6477fbf6a550ce84804d2b5c743b1802ed41548d 100644 (file)
@@ -484,7 +484,7 @@ nv40_graph_init(struct nouveau_object *object)
                engine->tile_prog(engine, i);
 
        /* begin RAM config */
-       vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1;
+       vramsz = nv_device_resource_len(nv_device(priv), 0) - 1;
        switch (nv_device(priv)->chipset) {
        case 0x40:
                nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
index a73ab209ea88c85121fe3580e9daa189b29de46e..6ef8bf181b2d9a324b7fc1d9ebb0bd4130b7babc 100644 (file)
@@ -1091,10 +1091,10 @@ nvc0_graph_ctor_fw(struct nvc0_graph_priv *priv, const char *fwname,
        int ret;
 
        snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname);
-       ret = request_firmware(&fw, f, &device->pdev->dev);
+       ret = request_firmware(&fw, f, nv_device_base(device));
        if (ret) {
                snprintf(f, sizeof(f), "nouveau/%s", fwname);
-               ret = request_firmware(&fw, f, &device->pdev->dev);
+               ret = request_firmware(&fw, f, nv_device_base(device));
                if (ret) {
                        nv_error(priv, "failed to load %s\n", fwname);
                        return ret;
index 5f6ede7c48928a799e3a2084371e5bb86a2388d4..92384759d2f55aaa3205b191e7d57f5efe10754f 100644 (file)
@@ -112,7 +112,7 @@ _nouveau_xtensa_init(struct nouveau_object *object)
                snprintf(name, sizeof(name), "nouveau/nv84_xuc%03x",
                         xtensa->addr >> 12);
 
-               ret = request_firmware(&fw, name, &device->pdev->dev);
+               ret = request_firmware(&fw, name, nv_device_base(device));
                if (ret) {
                        nv_warn(xtensa, "unable to load firmware %s\n", name);
                        return ret;
index 7e7acee916fb749c459e887dd6055a760e8a06d9..a8a9a9cf16cb2e8e62c6f96e68e9d8ee95aeb73b 100644 (file)
@@ -66,6 +66,7 @@ struct nouveau_device {
        struct list_head head;
 
        struct pci_dev *pdev;
+       struct platform_device *platformdev;
        u64 handle;
 
        const char *cfgopt;
@@ -142,4 +143,32 @@ nv_device_match(struct nouveau_object *object, u16 dev, u16 ven, u16 sub)
               device->pdev->subsystem_device == sub;
 }
 
+static inline bool
+nv_device_is_pci(struct nouveau_device *device)
+{
+       return device->pdev != NULL;
+}
+
+static inline struct device *
+nv_device_base(struct nouveau_device *device)
+{
+       return nv_device_is_pci(device) ? &device->pdev->dev :
+                                         &device->platformdev->dev;
+}
+
+resource_size_t
+nv_device_resource_start(struct nouveau_device *device, unsigned int bar);
+
+resource_size_t
+nv_device_resource_len(struct nouveau_device *device, unsigned int bar);
+
+dma_addr_t
+nv_device_map_page(struct nouveau_device *device, struct page *page);
+
+void
+nv_device_unmap_page(struct nouveau_device *device, dma_addr_t addr);
+
+int
+nv_device_get_irq(struct nouveau_device *device, bool stall);
+
 #endif
index 5856694d9b3b7030ccb18d479097160889fedddf..672d3c8f4145d7b235afbebedf6f1de434bc4b08 100644 (file)
@@ -3,11 +3,20 @@
 
 #include <core/device.h>
 
-#define nouveau_device_create(p,n,s,c,d,u)                                     \
-       nouveau_device_create_((p), (n), (s), (c), (d), sizeof(**u), (void **)u)
+struct platform_device;
 
-int  nouveau_device_create_(struct pci_dev *, u64 name, const char *sname,
-                           const char *cfg, const char *dbg, int, void **);
+enum nv_bus_type {
+       NOUVEAU_BUS_PCI,
+       NOUVEAU_BUS_PLATFORM,
+};
+
+#define nouveau_device_create(p,t,n,s,c,d,u)                                   \
+       nouveau_device_create_((void *)(p), (t), (n), (s), (c), (d),           \
+                              sizeof(**u), (void **)u)
+
+int  nouveau_device_create_(void *, enum nv_bus_type type, u64 name,
+                           const char *sname, const char *cfg, const char *dbg,
+                           int, void **);
 
 int nv04_identify(struct nouveau_device *);
 int nv10_identify(struct nouveau_device *);
index 3c6738edd127040337ff8fc53b6125a47e812ad7..72b176831be62ca009041d82155e21b6d9d9d1f8 100644 (file)
@@ -12,6 +12,7 @@ struct nouveau_mc_intr {
 struct nouveau_mc {
        struct nouveau_subdev base;
        bool use_msi;
+       unsigned int irq;
 };
 
 static inline struct nouveau_mc *
index 191e739f30d14f1c994db7028c759238b6604048..d0ced94ca54ceb6f755934b4495985787dcb2610 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/pci.h>
+#include <linux/platform_device.h>
 #include <linux/printk.h>
 #include <linux/bitops.h>
 #include <linux/firmware.h>
 
 #include <asm/unaligned.h>
 
-static inline int
-ffsll(u64 mask)
-{
-       int i;
-       for (i = 0; i < 64; i++) {
-               if (mask & (1ULL << i))
-                       return i + 1;
-       }
-       return 0;
-}
-
 #ifndef ioread32_native
 #ifdef __BIG_ENDIAN
 #define ioread16_native ioread16be
index 7098ddd546788c3adca970af4afc1a5a8d122d1a..bdf594116f3f2a1ab49698669ccf7a2b641c91ee 100644 (file)
@@ -118,8 +118,8 @@ nouveau_bar_create_(struct nouveau_object *parent,
        if (ret)
                return ret;
 
-       bar->iomem = ioremap(pci_resource_start(device->pdev, 3),
-                            pci_resource_len(device->pdev, 3));
+       bar->iomem = ioremap(nv_device_resource_start(device, 3),
+                            nv_device_resource_len(device, 3));
        return 0;
 }
 
index 090d594a21b36ee9633462db5f0ee838547b1557..baa2b62bd40fec21e15aee1146d0da7727566517 100644 (file)
@@ -139,7 +139,7 @@ nv50_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        /* BAR3 */
        start = 0x0100000000ULL;
-       limit = start + pci_resource_len(device->pdev, 3);
+       limit = start + nv_device_resource_len(device, 3);
 
        ret = nouveau_vm_new(device, start, limit, start, &vm);
        if (ret)
@@ -173,7 +173,7 @@ nv50_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        /* BAR1 */
        start = 0x0000000000ULL;
-       limit = start + pci_resource_len(device->pdev, 1);
+       limit = start + nv_device_resource_len(device, 1);
 
        ret = nouveau_vm_new(device, start, limit--, start, &vm);
        if (ret)
index bac5e754de35acdf838b571bf1d6e25eb8b5faec..3f30db62e6563d483d0a330aafe353692865c1c0 100644 (file)
@@ -84,7 +84,6 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
              struct nouveau_object **pobject)
 {
        struct nouveau_device *device = nv_device(parent);
-       struct pci_dev *pdev = device->pdev;
        struct nvc0_bar_priv *priv;
        struct nouveau_gpuobj *mem;
        struct nouveau_vm *vm;
@@ -107,14 +106,14 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       ret = nouveau_vm_new(device, 0, pci_resource_len(pdev, 3), 0, &vm);
+       ret = nouveau_vm_new(device, 0, nv_device_resource_len(device, 3), 0, &vm);
        if (ret)
                return ret;
 
        atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
 
        ret = nouveau_gpuobj_new(nv_object(priv), NULL,
-                                (pci_resource_len(pdev, 3) >> 12) * 8,
+                                (nv_device_resource_len(device, 3) >> 12) * 8,
                                 0x1000, NVOBJ_FLAG_ZERO_ALLOC,
                                 &vm->pgt[0].obj[0]);
        vm->pgt[0].refcount[0] = 1;
@@ -128,8 +127,8 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        nv_wo32(mem, 0x0200, lower_32_bits(priv->bar[0].pgd->addr));
        nv_wo32(mem, 0x0204, upper_32_bits(priv->bar[0].pgd->addr));
-       nv_wo32(mem, 0x0208, lower_32_bits(pci_resource_len(pdev, 3) - 1));
-       nv_wo32(mem, 0x020c, upper_32_bits(pci_resource_len(pdev, 3) - 1));
+       nv_wo32(mem, 0x0208, lower_32_bits(nv_device_resource_len(device, 3) - 1));
+       nv_wo32(mem, 0x020c, upper_32_bits(nv_device_resource_len(device, 3) - 1));
 
        /* BAR1 */
        ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0, 0,
@@ -143,7 +142,7 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       ret = nouveau_vm_new(device, 0, pci_resource_len(pdev, 1), 0, &vm);
+       ret = nouveau_vm_new(device, 0, nv_device_resource_len(device, 1), 0, &vm);
        if (ret)
                return ret;
 
@@ -156,8 +155,8 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        nv_wo32(mem, 0x0200, lower_32_bits(priv->bar[1].pgd->addr));
        nv_wo32(mem, 0x0204, upper_32_bits(priv->bar[1].pgd->addr));
-       nv_wo32(mem, 0x0208, lower_32_bits(pci_resource_len(pdev, 1) - 1));
-       nv_wo32(mem, 0x020c, upper_32_bits(pci_resource_len(pdev, 1) - 1));
+       nv_wo32(mem, 0x0208, lower_32_bits(nv_device_resource_len(device, 1) - 1));
+       nv_wo32(mem, 0x020c, upper_32_bits(nv_device_resource_len(device, 1) - 1));
 
        priv->base.alloc = nouveau_bar_alloc;
        priv->base.kmap = nvc0_bar_kmap;
index 6b56a0f4cb404c9cce29ee8e56cfee162908094a..4fe49cf4c99a37eaf32d79eecf029501cac353f7 100644 (file)
@@ -24,6 +24,8 @@
  *
  */
 
+#include <core/device.h>
+
 #define NV04_PFB_BOOT_0                                                0x00100000
 #      define NV04_PFB_BOOT_0_RAM_AMOUNT                       0x00000003
 #      define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB                  0x00000000
 #      define NV10_PFB_REFCTRL_VALID_1                         (1 << 31)
 
 static inline struct io_mapping *
-fbmem_init(struct pci_dev *pdev)
+fbmem_init(struct nouveau_device *dev)
 {
-       return io_mapping_create_wc(pci_resource_start(pdev, 1),
-                                   pci_resource_len(pdev, 1));
+       return io_mapping_create_wc(nv_device_resource_start(dev, 1),
+                                   nv_device_resource_len(dev, 1));
 }
 
 static inline void
index 7037eae46e445bd5d3278dfc70119dac180cadbb..052ad690b468da81ec1a95e04eace07834f70c88 100644 (file)
@@ -38,7 +38,7 @@ nv04_devinit_meminit(struct nouveau_devinit *devinit)
        int i;
 
        /* Map the framebuffer aperture */
-       fb = fbmem_init(nv_device(priv)->pdev);
+       fb = fbmem_init(nv_device(priv));
        if (!fb) {
                nv_error(priv, "failed to map fb\n");
                return;
index 98b7e6780dc7f4826c4eb946419d0ceb6cfb5d84..4a19c10e517809ab7b348803481bcb0c0e98a0eb 100644 (file)
@@ -53,7 +53,7 @@ nv05_devinit_meminit(struct nouveau_devinit *devinit)
        int i, v;
 
        /* Map the framebuffer aperture */
-       fb = fbmem_init(nv_device(priv)->pdev);
+       fb = fbmem_init(nv_device(priv));
        if (!fb) {
                nv_error(priv, "failed to map fb\n");
                return;
index 32b3d2131a7f0d14b0e37e8b9888e2b38cf937c5..3b8d657da2798445f620e9662467df8696304280 100644 (file)
@@ -46,7 +46,7 @@ nv10_devinit_meminit(struct nouveau_devinit *devinit)
                mem_width_count = 2;
 
        /* Map the framebuffer aperture */
-       fb = fbmem_init(nv_device(priv)->pdev);
+       fb = fbmem_init(nv_device(priv));
        if (!fb) {
                nv_error(priv, "failed to map fb\n");
                return;
index 4689ba303b0bd6620ec080fcfe9fa3defad2f3ff..04bc9732644ccd706c72fdc055d534e61272f625 100644 (file)
@@ -37,7 +37,7 @@ nv20_devinit_meminit(struct nouveau_devinit *devinit)
        struct io_mapping *fb;
 
        /* Map the framebuffer aperture */
-       fb = fbmem_init(nv_device(priv)->pdev);
+       fb = fbmem_init(nv_device(priv));
        if (!fb) {
                nv_error(priv, "failed to map fb\n");
                return;
index cbc7f00c1278905bcf24b2c7f8dc548c6dce7a22..1fc55c1e91a13b00869c9aa8a46ad2bd0f253e43 100644 (file)
@@ -250,10 +250,8 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        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))
+               priv->r100c08 = nv_device_map_page(device, priv->r100c08_page);
+               if (!priv->r100c08)
                        nv_warn(priv, "failed 0x100c08 page map\n");
        } else {
                nv_warn(priv, "failed 0x100c08 page alloc\n");
@@ -270,8 +268,7 @@ nv50_fb_dtor(struct nouveau_object *object)
        struct nv50_fb_priv *priv = (void *)object;
 
        if (priv->r100c08_page) {
-               pci_unmap_page(device->pdev, priv->r100c08, PAGE_SIZE,
-                              PCI_DMA_BIDIRECTIONAL);
+               nv_device_unmap_page(device, priv->r100c08);
                __free_page(priv->r100c08_page);
        }
 
index 45470e1f0385f4682a654e0c37cb27212d3ba8eb..0670ae33ee450d7428580c280f34051b893675e1 100644 (file)
@@ -70,8 +70,7 @@ nvc0_fb_dtor(struct nouveau_object *object)
        struct nvc0_fb_priv *priv = (void *)object;
 
        if (priv->r100c10_page) {
-               pci_unmap_page(device->pdev, priv->r100c10, PAGE_SIZE,
-                              PCI_DMA_BIDIRECTIONAL);
+               nv_device_unmap_page(device, priv->r100c10);
                __free_page(priv->r100c10_page);
        }
 
@@ -94,10 +93,8 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
        if (priv->r100c10_page) {
-               priv->r100c10 = pci_map_page(device->pdev, priv->r100c10_page,
-                                            0, PAGE_SIZE,
-                                            PCI_DMA_BIDIRECTIONAL);
-               if (pci_dma_mapping_error(device->pdev, priv->r100c10))
+               priv->r100c10 = nv_device_map_page(device, priv->r100c10_page);
+               if (!priv->r100c10)
                        return -EFAULT;
        }
 
index c33c03d2f4af2f695e50e92078ea18c800d07eec..378e05b88e6f0c4562637d00e21aed7285c5b69f 100644 (file)
@@ -111,7 +111,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent,
        snprintf(port->adapter.name, sizeof(port->adapter.name),
                 "nouveau-%s-%d", device->name, index);
        port->adapter.owner = THIS_MODULE;
-       port->adapter.dev.parent = &device->pdev->dev;
+       port->adapter.dev.parent = nv_device_base(device);
        port->index = index;
        port->func = func;
        i2c_set_adapdata(&port->adapter, i2c);
index ec0b9661d614ced3dec026e3460d3eeb07905f2e..8803809f9fc5fd8d2e87d5d2a5bd688d7b50aae5 100644 (file)
@@ -50,7 +50,6 @@ nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                  struct nouveau_object **pobject)
 {
        struct nouveau_device *device = nv_device(parent);
-       struct pci_dev *pdev = device->pdev;
        struct nv04_instmem_priv *priv;
        int ret, bar, vs;
 
@@ -60,13 +59,13 @@ nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                return ret;
 
        /* map bar */
-       if (pci_resource_len(pdev, 2))
+       if (nv_device_resource_len(device, 2))
                bar = 2;
        else
                bar = 3;
 
-       priv->iomem = ioremap(pci_resource_start(pdev, bar),
-                             pci_resource_len(pdev, bar));
+       priv->iomem = ioremap(nv_device_resource_start(device, bar),
+                             nv_device_resource_len(device, bar));
        if (!priv->iomem) {
                nv_error(priv, "unable to map PRAMIN BAR\n");
                return -EFAULT;
index b4b9943773bcfa710580244d43daf69a13d5043b..8a5555192fa5ea503d97aa11efc84ed6968c7e6d 100644 (file)
@@ -93,7 +93,7 @@ _nouveau_mc_dtor(struct nouveau_object *object)
 {
        struct nouveau_device *device = nv_device(object);
        struct nouveau_mc *pmc = (void *)object;
-       free_irq(device->pdev->irq, pmc);
+       free_irq(pmc->irq, pmc);
        if (pmc->use_msi)
                pci_disable_msi(device->pdev);
        nouveau_subdev_destroy(&pmc->base);
@@ -114,33 +114,44 @@ nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       switch (device->pdev->device & 0x0ff0) {
-       case 0x00f0:
-       case 0x02e0:
-               /* BR02? NFI how these would be handled yet exactly */
-               break;
-       default:
-               switch (device->chipset) {
-               case 0xaa: break; /* reported broken, nv also disable it */
-               default:
-                       pmc->use_msi = true;
+       if (nv_device_is_pci(device))
+               switch (device->pdev->device & 0x0ff0) {
+               case 0x00f0:
+               case 0x02e0:
+                       /* BR02? NFI how these would be handled yet exactly */
                        break;
+               default:
+                       switch (device->chipset) {
+                       case 0xaa:
+                               /* reported broken, nv also disable it */
+                               break;
+                       default:
+                               pmc->use_msi = true;
+                               break;
                }
-       }
 
-       pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI", pmc->use_msi);
-       if (pmc->use_msi && oclass->msi_rearm) {
-               pmc->use_msi = pci_enable_msi(device->pdev) == 0;
-               if (pmc->use_msi) {
-                       nv_info(pmc, "MSI interrupts enabled\n");
-                       oclass->msi_rearm(pmc);
+               pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI",
+                                              pmc->use_msi);
+
+               if (pmc->use_msi && oclass->msi_rearm) {
+                       pmc->use_msi = pci_enable_msi(device->pdev) == 0;
+                       if (pmc->use_msi) {
+                               nv_info(pmc, "MSI interrupts enabled\n");
+                               oclass->msi_rearm(pmc);
+                       }
+               } else {
+                       pmc->use_msi = false;
                }
-       } else {
-               pmc->use_msi = false;
        }
 
-       ret = request_irq(device->pdev->irq, nouveau_mc_intr,
-                         IRQF_SHARED, "nouveau", pmc);
+       ret = nv_device_get_irq(device, true);
+       if (ret < 0)
+               return ret;
+       pmc->irq = ret;
+
+       ret = request_irq(pmc->irq, nouveau_mc_intr, IRQF_SHARED, "nouveau",
+                         pmc);
+
        if (ret < 0)
                return ret;
 
index 13c5af88a6019d8b1e976dbe8c2e919b9ec8f6fc..51fcf79604173ad9a299bde564a782d63d097be4 100644 (file)
@@ -96,7 +96,7 @@ mxm_shadow_dsm(struct nouveau_mxm *mxm, u8 version)
        acpi_handle handle;
        int rev;
 
-       handle = ACPI_HANDLE(&device->pdev->dev);
+       handle = ACPI_HANDLE(nv_device_base(device));
        if (!handle)
                return false;
 
index e0be8a1a6c7c51ec34ba68f0ef310e846de16405..b13f441c64314f24581bed203a9fdffd3602f624 100644 (file)
@@ -180,12 +180,21 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
                getparam->value = device->chipset;
                break;
        case NOUVEAU_GETPARAM_PCI_VENDOR:
-               getparam->value = dev->pdev->vendor;
+               if (nv_device_is_pci(device))
+                       getparam->value = dev->pdev->vendor;
+               else
+                       getparam->value = 0;
                break;
        case NOUVEAU_GETPARAM_PCI_DEVICE:
-               getparam->value = dev->pdev->device;
+               if (nv_device_is_pci(device))
+                       getparam->value = dev->pdev->device;
+               else
+                       getparam->value = 0;
                break;
        case NOUVEAU_GETPARAM_BUS_TYPE:
+               if (!nv_device_is_pci(device))
+                       getparam->value = 3;
+               else
                if (drm_pci_device_is_agp(dev))
                        getparam->value = 0;
                else
index 2953c4e91e1ae9fea8fff60501dfa863d56c63ea..51666daddb948fd3650f6c14dd7d90963d8ce5dd 100644 (file)
@@ -75,7 +75,7 @@ nouveau_agp_enabled(struct nouveau_drm *drm)
 {
        struct drm_device *dev = drm->dev;
 
-       if (!drm_pci_device_is_agp(dev) || !dev->agp)
+       if (!dev->pdev || !drm_pci_device_is_agp(dev) || !dev->agp)
                return false;
 
        if (drm->agp.stat == UNKNOWN) {
index 4c3feaaa10375721627b4bb00c5f95f0e6eb8a9a..04564dcd795675f8d1bc1482e4658fa152042dbd 100644 (file)
@@ -2069,6 +2069,10 @@ nouveau_bios_init(struct drm_device *dev)
        struct nvbios *bios = &drm->vbios;
        int ret;
 
+       /* only relevant for PCI devices */
+       if (!dev->pdev)
+               return 0;
+
        if (!NVInitVBIOS(dev))
                return -ENODEV;
 
index 4aed1714b9ab7d289bbadc867f9af40b046825f2..b6dc85c614be402ca5d6717bea842c0448ce4b39 100644 (file)
@@ -1255,7 +1255,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
                /* fallthrough, tiled memory */
        case TTM_PL_VRAM:
                mem->bus.offset = mem->start << PAGE_SHIFT;
-               mem->bus.base = pci_resource_start(dev->pdev, 1);
+               mem->bus.base = nv_device_resource_start(nouveau_dev(dev), 1);
                mem->bus.is_iomem = true;
                if (nv_device(drm->device)->card_type >= NV_50) {
                        struct nouveau_bar *bar = nouveau_bar(drm->device);
@@ -1293,7 +1293,7 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
        struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
        struct nouveau_bo *nvbo = nouveau_bo(bo);
        struct nouveau_device *device = nv_device(drm->device);
-       u32 mappable = pci_resource_len(device->pdev, 1) >> PAGE_SHIFT;
+       u32 mappable = nv_device_resource_len(device, 1) >> PAGE_SHIFT;
        int ret;
 
        /* as long as the bo isn't in vram, and isn't tiled, we've got
@@ -1331,6 +1331,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
 {
        struct ttm_dma_tt *ttm_dma = (void *)ttm;
        struct nouveau_drm *drm;
+       struct nouveau_device *device;
        struct drm_device *dev;
        unsigned i;
        int r;
@@ -1348,6 +1349,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
        }
 
        drm = nouveau_bdev(ttm->bdev);
+       device = nv_device(drm->device);
        dev = drm->dev;
 
 #if __OS_HAS_AGP
@@ -1368,13 +1370,12 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
        }
 
        for (i = 0; i < ttm->num_pages; i++) {
-               ttm_dma->dma_address[i] = pci_map_page(dev->pdev, ttm->pages[i],
-                                                  0, PAGE_SIZE,
-                                                  PCI_DMA_BIDIRECTIONAL);
-               if (pci_dma_mapping_error(dev->pdev, ttm_dma->dma_address[i])) {
+               ttm_dma->dma_address[i] = nv_device_map_page(device,
+                                                            ttm->pages[i]);
+               if (!ttm_dma->dma_address[i]) {
                        while (--i) {
-                               pci_unmap_page(dev->pdev, ttm_dma->dma_address[i],
-                                              PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+                               nv_device_unmap_page(device,
+                                                    ttm_dma->dma_address[i]);
                                ttm_dma->dma_address[i] = 0;
                        }
                        ttm_pool_unpopulate(ttm);
@@ -1389,6 +1390,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
 {
        struct ttm_dma_tt *ttm_dma = (void *)ttm;
        struct nouveau_drm *drm;
+       struct nouveau_device *device;
        struct drm_device *dev;
        unsigned i;
        bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
@@ -1397,6 +1399,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
                return;
 
        drm = nouveau_bdev(ttm->bdev);
+       device = nv_device(drm->device);
        dev = drm->dev;
 
 #if __OS_HAS_AGP
@@ -1415,8 +1418,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
 
        for (i = 0; i < ttm->num_pages; i++) {
                if (ttm_dma->dma_address[i]) {
-                       pci_unmap_page(dev->pdev, ttm_dma->dma_address[i],
-                                      PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+                       nv_device_unmap_page(device, ttm_dma->dma_address[i]);
                }
        }
 
index cc5152be2cf121a0901d323bf41b57886b56b27a..ccb6b452d6d00e34738efdf56e5c3fcb731e923a 100644 (file)
@@ -154,7 +154,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nouveau_cli *cli,
                         * nfi why this exists, it came from the -nv ddx.
                         */
                        args.flags = NV_DMA_TARGET_PCI | NV_DMA_ACCESS_RDWR;
-                       args.start = pci_resource_start(device->pdev, 1);
+                       args.start = nv_device_resource_start(device, 1);
                        args.limit = args.start + limit;
                } else {
                        args.flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR;
index 1eb86dadeb2773468759a426e1b3e46c32727114..db19a56459f7b949eeb722a09f8ce419aeca17f7 100644 (file)
@@ -419,6 +419,7 @@ int
 nouveau_display_create(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nouveau_dev(dev);
        struct nouveau_display *disp;
        int ret, gen;
 
@@ -459,7 +460,7 @@ nouveau_display_create(struct drm_device *dev)
        }
 
        dev->mode_config.funcs = &nouveau_mode_config_funcs;
-       dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1);
+       dev->mode_config.fb_base = nv_device_resource_start(device, 1);
 
        dev->mode_config.min_width = 0;
        dev->mode_config.min_height = 0;
index eeadcac8e8f4f867f91cb820845f1770a627cc58..8f811a5f16e20452e17a4378253e4230c0367e9c 100644 (file)
@@ -82,7 +82,7 @@ module_param_named(runpm, nouveau_runtime_pm, int, 0400);
 static struct drm_driver driver;
 
 static u64
-nouveau_name(struct pci_dev *pdev)
+nouveau_pci_name(struct pci_dev *pdev)
 {
        u64 name = (u64)pci_domain_nr(pdev->bus) << 32;
        name |= pdev->bus->number << 16;
@@ -90,15 +90,30 @@ nouveau_name(struct pci_dev *pdev)
        return name | PCI_FUNC(pdev->devfn);
 }
 
+static u64
+nouveau_platform_name(struct platform_device *platformdev)
+{
+       return platformdev->id;
+}
+
+static u64
+nouveau_name(struct drm_device *dev)
+{
+       if (dev->pdev)
+               return nouveau_pci_name(dev->pdev);
+       else
+               return nouveau_platform_name(dev->platformdev);
+}
+
 static int
-nouveau_cli_create(struct pci_dev *pdev, const char *name,
+nouveau_cli_create(u64 name, const char *sname,
                   int size, void **pcli)
 {
        struct nouveau_cli *cli;
        int ret;
 
        *pcli = NULL;
-       ret = nouveau_client_create_(name, nouveau_name(pdev), nouveau_config,
+       ret = nouveau_client_create_(sname, name, nouveau_config,
                                     nouveau_debug, size, pcli);
        cli = *pcli;
        if (ret) {
@@ -282,7 +297,8 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
        remove_conflicting_framebuffers(aper, "nouveaufb", boot);
        kfree(aper);
 
-       ret = nouveau_device_create(pdev, nouveau_name(pdev), pci_name(pdev),
+       ret = nouveau_device_create(pdev, NOUVEAU_BUS_PCI,
+                                   nouveau_pci_name(pdev), pci_name(pdev),
                                    nouveau_config, nouveau_debug, &device);
        if (ret)
                return ret;
@@ -305,6 +321,12 @@ nouveau_get_hdmi_dev(struct nouveau_drm *drm)
 {
        struct pci_dev *pdev = drm->dev->pdev;
 
+       if (!pdev) {
+               DRM_INFO("not a PCI device; no HDMI");
+               drm->hdmi_device = NULL;
+               return;
+       }
+
        /* subfunction one is a hdmi audio device? */
        drm->hdmi_device = pci_get_bus_and_slot((unsigned int)pdev->bus->number,
                                                PCI_DEVFN(PCI_SLOT(pdev->devfn), 1));
@@ -330,7 +352,8 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
        struct nouveau_drm *drm;
        int ret;
 
-       ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm);
+       ret = nouveau_cli_create(nouveau_name(dev), "DRM", sizeof(*drm),
+                                (void **)&drm);
        if (ret)
                return ret;
 
@@ -346,7 +369,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
        /* make sure AGP controller is in a consistent state before we
         * (possibly) execute vbios init tables (see nouveau_agp.h)
         */
-       if (drm_pci_device_is_agp(dev) && dev->agp) {
+       if (pdev && drm_pci_device_is_agp(dev) && dev->agp) {
                /* dummy device object, doesn't init anything, but allows
                 * agp code access to registers
                 */
@@ -672,7 +695,6 @@ static int nouveau_pmops_thaw(struct device *dev)
 static int
 nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv)
 {
-       struct pci_dev *pdev = dev->pdev;
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_cli *cli;
        char name[32], tmpname[TASK_COMM_LEN];
@@ -686,7 +708,9 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv)
        get_task_comm(tmpname, current);
        snprintf(name, sizeof(name), "%s[%d]", tmpname, pid_nr(fpriv->pid));
 
-       ret = nouveau_cli_create(pdev, name, sizeof(*cli), (void **)&cli);
+       ret = nouveau_cli_create(nouveau_name(dev), name, sizeof(*cli),
+                       (void **)&cli);
+
        if (ret)
                goto out_suspend;
 
@@ -975,6 +999,25 @@ nouveau_drm_pci_driver = {
        .driver.pm = &nouveau_pm_ops,
 };
 
+int nouveau_drm_platform_probe(struct platform_device *pdev)
+{
+       struct nouveau_device *device;
+       int ret;
+
+       ret = nouveau_device_create(pdev, NOUVEAU_BUS_PLATFORM,
+                                   nouveau_platform_name(pdev),
+                                   dev_name(&pdev->dev), nouveau_config,
+                                   nouveau_debug, &device);
+
+       ret = drm_platform_init(&driver, pdev);
+       if (ret) {
+               nouveau_object_ref(NULL, (struct nouveau_object **)&device);
+               return ret;
+       }
+
+       return ret;
+}
+
 static int __init
 nouveau_drm_init(void)
 {
index 89201a17ce752357444ec9f5ad0a4a42a84a79f8..75dda2b07176143605bf97f4c62f513ce0060385 100644 (file)
@@ -30,7 +30,7 @@
 static inline struct drm_device *
 drm_device(struct device *d)
 {
-       return pci_get_drvdata(to_pci_dev(d));
+       return dev_get_drvdata(d);
 }
 
 #define snappendf(p,r,f,a...) do {                                             \
@@ -132,9 +132,10 @@ nouveau_sysfs_fini(struct drm_device *dev)
 {
        struct nouveau_sysfs *sysfs = nouveau_sysfs(dev);
        struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nv_device(drm->device);
 
        if (sysfs->ctrl) {
-               device_remove_file(&dev->pdev->dev, &dev_attr_pstate);
+               device_remove_file(nv_device_base(device), &dev_attr_pstate);
                nouveau_object_del(nv_object(drm), NVDRM_DEVICE, NVDRM_CONTROL);
        }
 
@@ -146,6 +147,7 @@ int
 nouveau_sysfs_init(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nv_device(drm->device);
        struct nouveau_sysfs *sysfs;
        int ret;
 
@@ -156,7 +158,7 @@ nouveau_sysfs_init(struct drm_device *dev)
        ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE, NVDRM_CONTROL,
                                 NV_CONTROL_CLASS, NULL, 0, &sysfs->ctrl);
        if (ret == 0)
-               device_create_file(&dev->pdev->dev, &dev_attr_pstate);
+               device_create_file(nv_device_base(device), &dev_attr_pstate);
 
        return 0;
 }
index be3a3c9feafa96d7565c2d4efe2acdaeae309b60..ab0228f640a5e86f1554402bcf5816d2e8a9a986 100644 (file)
@@ -354,21 +354,26 @@ int
 nouveau_ttm_init(struct nouveau_drm *drm)
 {
        struct drm_device *dev = drm->dev;
+       struct nouveau_device *device = nv_device(drm->device);
        u32 bits;
        int ret;
 
        bits = nouveau_vmmgr(drm->device)->dma_bits;
-       if ( drm->agp.stat == ENABLED ||
-           !pci_dma_supported(dev->pdev, DMA_BIT_MASK(bits)))
-               bits = 32;
-
-       ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(bits));
-       if (ret)
-               return ret;
-
-       ret = pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(bits));
-       if (ret)
-               pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(32));
+       if (nv_device_is_pci(device)) {
+               if (drm->agp.stat == ENABLED ||
+                    !pci_dma_supported(dev->pdev, DMA_BIT_MASK(bits)))
+                       bits = 32;
+
+               ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(bits));
+               if (ret)
+                       return ret;
+
+               ret = pci_set_consistent_dma_mask(dev->pdev,
+                                                 DMA_BIT_MASK(bits));
+               if (ret)
+                       pci_set_consistent_dma_mask(dev->pdev,
+                                                   DMA_BIT_MASK(32));
+       }
 
        ret = nouveau_ttm_global_init(drm);
        if (ret)
@@ -396,8 +401,8 @@ nouveau_ttm_init(struct nouveau_drm *drm)
                return ret;
        }
 
-       drm->ttm.mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 1),
-                                        pci_resource_len(dev->pdev, 1));
+       drm->ttm.mtrr = arch_phys_wc_add(nv_device_resource_start(device, 1),
+                                        nv_device_resource_len(device, 1));
 
        /* GART init */
        if (drm->agp.stat != ENABLED) {
index 471347edc27eb869816e5d5cfed1ccd01f4c7b6f..fb84da3cb50d50a31f905052b4b85c2cbaf54143 100644 (file)
@@ -84,6 +84,11 @@ nouveau_vga_init(struct nouveau_drm *drm)
 {
        struct drm_device *dev = drm->dev;
        bool runtime = false;
+
+       /* only relevant for PCI devices */
+       if (!dev->pdev)
+               return;
+
        vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
 
        if (nouveau_runtime_pm == 1)