From 7974dd1bdb43aaf5b45a915c6b439d11733450fc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:17 +1000 Subject: [PATCH] drm/nouveau/device: separate construction of pci/tegra devices Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/os.h | 3 +- .../drm/nouveau/include/nvkm/core/client.h | 4 +- .../drm/nouveau/include/nvkm/core/device.h | 30 +++-- .../gpu/drm/nouveau/include/nvkm/core/pci.h | 14 +++ .../gpu/drm/nouveau/include/nvkm/core/tegra.h | 14 +++ drivers/gpu/drm/nouveau/nouveau_drm.c | 15 +-- .../gpu/drm/nouveau/nvkm/engine/device/Kbuild | 2 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 104 ++++++++++++------ .../gpu/drm/nouveau/nvkm/engine/device/pci.c | 100 +++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/device/priv.h | 9 ++ .../drm/nouveau/nvkm/engine/device/tegra.c | 66 +++++++++++ 11 files changed, 307 insertions(+), 54 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/include/nvkm/core/pci.h create mode 100644 drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c diff --git a/drivers/gpu/drm/nouveau/include/nvif/os.h b/drivers/gpu/drm/nouveau/include/nvif/os.h index bdd05ee7ec72..54492cb5011b 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/os.h +++ b/drivers/gpu/drm/nouveau/include/nvif/os.h @@ -27,6 +27,8 @@ #include +#include + #ifndef ioread32_native #ifdef __BIG_ENDIAN #define ioread16_native ioread16be @@ -40,5 +42,4 @@ #define iowrite32_native iowrite32 #endif /* def __BIG_ENDIAN else */ #endif /* !ioread32_native */ - #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h index 977c8a85e119..dd0db88f8213 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h @@ -28,7 +28,9 @@ nvkm_client(void *obj) struct nvkm_object *client = nv_object(obj); while (client && client->parent) client = client->parent; - return (void *)client; + if (client && nv_iclass(client, NV_CLIENT_CLASS)) + return (void *)client; + return NULL; } int nvkm_client_new(const char *name, u64 device, const char *cfg, diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 875c247d4cfc..eb843e3ff005 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -65,22 +65,25 @@ enum nvkm_devidx { struct nvkm_device { struct nvkm_engine engine; + const struct nvkm_device_func *func; + const struct nvkm_device_quirk *quirk; + struct device *dev; + u64 handle; + const char *name; + const char *cfgopt; + const char *dbgopt; + struct list_head head; struct mutex mutex; int refcount; struct pci_dev *pdev; struct platform_device *platformdev; - struct device *dev; - u64 handle; void __iomem *pri; struct nvkm_event event; - const char *cfgopt; - const char *dbgopt; - const char *name; const char *cname; u64 disable_mask; @@ -150,6 +153,17 @@ struct nvkm_device { struct nouveau_platform_gpu *gpu; }; +struct nvkm_device_func { + struct nvkm_device_pci *(*pci)(struct nvkm_device *); + struct nvkm_device_tegra *(*tegra)(struct nvkm_device *); + void *(*dtor)(struct nvkm_device *); + int (*preinit)(struct nvkm_device *); + void (*fini)(struct nvkm_device *, bool suspend); +}; + +struct nvkm_device_quirk { +}; + struct nvkm_device *nvkm_device_find(u64 name); int nvkm_device_list(u64 *name, int size); @@ -214,13 +228,7 @@ enum nv_bus_type { extern struct nvkm_ofuncs nvkm_udevice_ofuncs; -int nvkm_device_new(void *, enum nv_bus_type type, u64 name, - const char *sname, const char *cfg, const char *dbg, - bool detect, bool mmio, u64 subdev_mask, - struct nvkm_device **); void nvkm_device_del(struct nvkm_device **); -int nvkm_device_init(struct nvkm_device *); -int nvkm_device_fini(struct nvkm_device *, bool suspend); /* device logging */ #define nvdev_printk_(d,l,p,f,a...) do { \ diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/pci.h b/drivers/gpu/drm/nouveau/include/nvkm/core/pci.h new file mode 100644 index 000000000000..78d41be20b8c --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/pci.h @@ -0,0 +1,14 @@ +#ifndef __NVKM_DEVICE_PCI_H__ +#define __NVKM_DEVICE_PCI_H__ +#include + +struct nvkm_device_pci { + struct nvkm_device device; + struct pci_dev *pdev; + bool suspend; +}; + +int nvkm_device_pci_new(struct pci_dev *, const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device **); +#endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h b/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h new file mode 100644 index 000000000000..162986e7f8c4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h @@ -0,0 +1,14 @@ +#ifndef __NVKM_DEVICE_TEGRA_H__ +#define __NVKM_DEVICE_TEGRA_H__ +#include + +struct nvkm_device_tegra { + struct nvkm_device device; + struct platform_device *pdev; +}; + +int nvkm_device_tegra_new(struct platform_device *, + const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device **); +#endif diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 37dbd5e1c08f..e638ae7c00c2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -32,9 +32,10 @@ #include "drmP.h" #include "drm_crtc_helper.h" -#include #include #include +#include +#include #include "nouveau_drm.h" #include "nouveau_dma.h" @@ -326,9 +327,8 @@ static int nouveau_drm_probe(struct pci_dev *pdev, remove_conflicting_framebuffers(aper, "nouveaufb", boot); kfree(aper); - ret = nvkm_device_new(pdev, NVKM_BUS_PCI, nouveau_pci_name(pdev), - pci_name(pdev), nouveau_config, nouveau_debug, - true, true, ~0ULL, &device); + ret = nvkm_device_pci_new(pdev, nouveau_config, nouveau_debug, + true, true, ~0ULL, &device); if (ret) return ret; @@ -1036,11 +1036,8 @@ nouveau_platform_device_create(struct platform_device *pdev, struct drm_device *drm; int err; - err = nvkm_device_new(pdev, NVKM_BUS_PLATFORM, - nouveau_platform_name(pdev), - dev_name(&pdev->dev), nouveau_config, - nouveau_debug, true, true, ~0ULL, - pdevice); + err = nvkm_device_tegra_new(pdev, nouveau_config, nouveau_debug, + true, true, ~0ULL, pdevice); if (err) goto err_free; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild index 47c8fe8f9e3e..91110cd2562e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild @@ -1,6 +1,8 @@ nvkm-y += nvkm/engine/device/acpi.o nvkm-y += nvkm/engine/device/base.o nvkm-y += nvkm/engine/device/ctrl.o +nvkm-y += nvkm/engine/device/pci.o +nvkm-y += nvkm/engine/device/tegra.o nvkm-y += nvkm/engine/device/user.o nvkm-y += nvkm/engine/device/nv04.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index b7892e6f080b..c7d8e2902c6c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -32,19 +32,25 @@ static DEFINE_MUTEX(nv_devices_mutex); static LIST_HEAD(nv_devices); -struct nvkm_device * -nvkm_device_find(u64 name) +static struct nvkm_device * +nvkm_device_find_locked(u64 handle) { - struct nvkm_device *device, *match = NULL; - mutex_lock(&nv_devices_mutex); + struct nvkm_device *device; list_for_each_entry(device, &nv_devices, head) { - if (device->handle == name) { - match = device; - break; - } + if (device->handle == handle) + return device; } + return NULL; +} + +struct nvkm_device * +nvkm_device_find(u64 handle) +{ + struct nvkm_device *device; + mutex_lock(&nv_devices_mutex); + device = nvkm_device_find_locked(handle); mutex_unlock(&nv_devices_mutex); - return match; + return device; } int @@ -62,6 +68,7 @@ nvkm_device_list(u64 *name, int size) } #include +#include struct nvkm_device * nv_device(void *obj) @@ -70,7 +77,8 @@ nv_device(void *obj) if (device->engine == NULL) { while (device && device->parent) { - if (nv_mclass(device) == 0x0080) { + if (!nv_iclass(device, NV_SUBDEV_CLASS) && + device->parent == &nvkm_client(device)->namedb.parent.object) { struct { struct nvkm_parent base; struct nvkm_device *device; @@ -125,6 +133,9 @@ nvkm_device_fini(struct nvkm_device *device, bool suspend) } ret = nvkm_acpi_fini(device, suspend); + + if (device->func->fini) + device->func->fini(device, suspend); fail: for (; ret && i < NVDEV_SUBDEV_NR; i++) { if ((subdev = device->subdev[i])) { @@ -140,12 +151,40 @@ fail: return ret; } +int +nvkm_device_preinit(struct nvkm_device *device) +{ + int ret; + s64 time; + + nvdev_trace(device, "preinit running...\n"); + time = ktime_to_us(ktime_get()); + + if (device->func->preinit) { + ret = device->func->preinit(device); + if (ret) + goto fail; + } + + time = ktime_to_us(ktime_get()) - time; + nvdev_trace(device, "preinit completed in %lldus\n", time); + return 0; + +fail: + nvdev_error(device, "preinit failed with %d\n", ret); + return ret; +} + int nvkm_device_init(struct nvkm_device *device) { struct nvkm_object *subdev; int ret, i = 0, c; + ret = nvkm_device_preinit(device); + if (ret) + return ret; + ret = nvkm_acpi_init(device); if (ret) goto fail; @@ -287,12 +326,6 @@ nv_device_get_irq(struct nvkm_device *device, bool stall) } } -static struct nvkm_oclass -nvkm_device_oclass = { - .ofuncs = &(struct nvkm_ofuncs) { - }, -}; - void nvkm_device_del(struct nvkm_device **pdevice) { @@ -308,20 +341,28 @@ nvkm_device_del(struct nvkm_device **pdevice) if (device->pri) iounmap(device->pri); list_del(&device->head); + + if (device->func->dtor) + *pdevice = device->func->dtor(device); mutex_unlock(&nv_devices_mutex); - nvkm_engine_destroy(&device->engine); + kfree(*pdevice); *pdevice = NULL; } } +static const struct nvkm_engine_func +nvkm_device_func = { +}; + int -nvkm_device_new(void *dev, enum nv_bus_type type, u64 name, - const char *sname, const char *cfg, const char *dbg, - bool detect, bool mmio, u64 subdev_mask, - struct nvkm_device **pdevice) +nvkm_device_ctor(const struct nvkm_device_func *func, + const struct nvkm_device_quirk *quirk, + void *dev, enum nv_bus_type type, u64 handle, + const char *name, const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device *device) { - struct nvkm_device *device; u64 mmio_base, mmio_size; u32 boot0, strap; void __iomem *map; @@ -329,17 +370,17 @@ nvkm_device_new(void *dev, enum nv_bus_type type, u64 name, int i; mutex_lock(&nv_devices_mutex); - list_for_each_entry(device, &nv_devices, head) { - if (device->handle == name) - goto done; - } + if (nvkm_device_find_locked(handle)) + goto done; - ret = nvkm_engine_create(NULL, NULL, &nvkm_device_oclass, true, - "DEVICE", "device", &device); - *pdevice = device; + ret = nvkm_engine_ctor(&nvkm_device_func, device, 0, 0, + true, &device->engine); + device->engine.subdev.object.parent = NULL; + device->func = func; if (ret) goto done; + device->quirk = quirk; switch (type) { case NVKM_BUS_PCI: device->pdev = dev; @@ -350,12 +391,11 @@ nvkm_device_new(void *dev, enum nv_bus_type type, u64 name, device->dev = &device->platformdev->dev; break; } - device->handle = name; + device->handle = handle; device->cfgopt = cfg; device->dbgopt = dbg; - device->name = sname; + device->name = name; - nv_subdev(device)->debug = nvkm_dbgopt(device->dbgopt, "DEVICE"); list_add_tail(&device->head, &nv_devices); ret = nvkm_event_init(&nvkm_device_event_func, 1, 1, &device->event); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c new file mode 100644 index 000000000000..1a1d1e584a7f --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c @@ -0,0 +1,100 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include +#include "priv.h" + +static struct nvkm_device_pci * +nvkm_device_pci(struct nvkm_device *device) +{ + return container_of(device, struct nvkm_device_pci, device); +} + +static void +nvkm_device_pci_fini(struct nvkm_device *device, bool suspend) +{ + struct nvkm_device_pci *pdev = nvkm_device_pci(device); + if (suspend) { + pci_disable_device(pdev->pdev); + pdev->suspend = true; + } +} + +static int +nvkm_device_pci_preinit(struct nvkm_device *device) +{ + struct nvkm_device_pci *pdev = nvkm_device_pci(device); + if (pdev->suspend) { + int ret = pci_enable_device(pdev->pdev); + if (ret) + return ret; + pci_set_master(pdev->pdev); + pdev->suspend = false; + } + return 0; +} + +static void * +nvkm_device_pci_dtor(struct nvkm_device *device) +{ + struct nvkm_device_pci *pdev = nvkm_device_pci(device); + pci_disable_device(pdev->pdev); + return pdev; +} + +static const struct nvkm_device_func +nvkm_device_pci_func = { + .pci = nvkm_device_pci, + .dtor = nvkm_device_pci_dtor, + .preinit = nvkm_device_pci_preinit, + .fini = nvkm_device_pci_fini, +}; + +int +nvkm_device_pci_new(struct pci_dev *pci_dev, const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device **pdevice) +{ + struct nvkm_device_pci *pdev; + int ret; + + ret = pci_enable_device(pci_dev); + if (ret) + return ret; + + if (!(pdev = kzalloc(sizeof(*pdev), GFP_KERNEL))) { + pci_disable_device(pci_dev); + return -ENOMEM; + } + *pdevice = &pdev->device; + pdev->pdev = pci_dev; + + return nvkm_device_ctor(&nvkm_device_pci_func, NULL, + pci_dev, NVKM_BUS_PCI, + (u64)pci_domain_nr(pci_dev->bus) << 32 | + pci_dev->bus->number << 16 | + PCI_SLOT(pci_dev->devfn) << 8 | + PCI_FUNC(pci_dev->devfn), NULL, + cfg, dbg, detect, mmio, subdev_mask, + &pdev->device); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h index 8d3590e7bd87..df9c1550301f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h @@ -2,6 +2,15 @@ #define __NVKM_DEVICE_PRIV_H__ #include +int nvkm_device_ctor(const struct nvkm_device_func *, + const struct nvkm_device_quirk *, + void *, enum nv_bus_type type, u64 handle, + const char *name, const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device *); +int nvkm_device_init(struct nvkm_device *); +int nvkm_device_fini(struct nvkm_device *, bool suspend); + extern struct nvkm_oclass nvkm_control_oclass[]; int nv04_identify(struct nvkm_device *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c new file mode 100644 index 000000000000..0a5e5b88fee2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -0,0 +1,66 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include +#ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER +#include "priv.h" + +static struct nvkm_device_tegra * +nvkm_device_tegra(struct nvkm_device *obj) +{ + return container_of(obj, struct nvkm_device_tegra, device); +} + +static const struct nvkm_device_func +nvkm_device_tegra_func = { + .tegra = nvkm_device_tegra, +}; + +int +nvkm_device_tegra_new(struct platform_device *pdev, + const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device **pdevice) +{ + struct nvkm_device_tegra *tdev; + + if (!(tdev = kzalloc(sizeof(*tdev), GFP_KERNEL))) + return -ENOMEM; + *pdevice = &tdev->device; + tdev->pdev = pdev; + + return nvkm_device_ctor(&nvkm_device_tegra_func, NULL, pdev, + NVKM_BUS_PLATFORM, pdev->id, NULL, + cfg, dbg, detect, mmio, subdev_mask, + &tdev->device); +} +#else +int +nvkm_device_tegra_new(struct platform_device *pdev, + const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device **pdevice) +{ + return -ENOSYS; +} +#endif -- 2.20.1