[Nouveau] [PATCH] drm/nouveau: support for platform devices (original) (raw)
Alexandre Courbot gnurou at gmail.com
Mon Feb 10 22🔞00 PST 2014
- Previous message: [Nouveau] [PATCH] drm/nouveau: support for platform devices
- Next message: [PATCH v2] drm/nouveau: support for platform devices
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On Mon, Feb 10, 2014 at 8:50 PM, Thierry Reding <thierry.reding at gmail.com> wrote:
On Mon, Feb 10, 2014 at 02:53:00PM +0900, Alexandre Courbot wrote: [...]
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/base.c b/drivers/gpu/drm/nouveau/core/engine/device/base.c [...] +resourcesizet +nvdeviceresourcestart(struct nouveaudevice *device, unsigned int bar) +{ + if (nvdeviceispci(device)) { + return pciresourcestart(device->pdev, bar); + } else { + struct resource *res; + res = platformgetresource(device->platformdev, + IORESOURCEMEM, bar); + if (!res) + return 0; + return res->start; + } +} + +resourcesizet +nvdeviceresourcelen(struct nouveaudevice *device, unsigned int bar) +{ + if (nvdeviceispci(device)) { + return pciresourcelen(device->pdev, bar); + } else { + struct resource *res; + res = platformgetresource(device->platformdev, + IORESOURCEMEM, bar); + if (!res) + return 0; + return resourcesize(res); + } +} Perhaps instead of these two, something like this could be done: const struct resource * nvdeviceresource(struct nouveaudevice *device, unsigned int bar) { if (nvdeviceispci(device) return &device->pdev->resource[bar]; else return platformgetresource(device->platformdev, IORESOURCEMEM, bar); } Then the more generic resourcesize() can be used directly on the returned struct resource *. Doing so may come in handy if you ever need to display the resource for debugging purposes, since you could simply use the %pR format specifier. It could also be slightly more efficient, since the structure doesn't have to be looked up twice. But perhaps the compiler will be clever enough to optimize that away and it's not like this is called from a hot path.
I would agree with returning raw resource * if some of the consumer code did make use of struct resource * directly, but AFAICT this is not the case at all. So I thought we would better continue providing exactly what the code needs, instead of forcing it to dererence the resource itself. Also by doing so we might return NULL pointers in some code paths that do not check whether a resource is valid or not (granted, returning 0 would probably only make the code crash later).
I do see that pciresourcelen() does additional checking for BARs that have zero size (start == 0 && end == start), so it's not exactly the same, but I think there's another issue with that, see below.
+int +nouveaudeviceplatformcreate(struct platformdevice *pdev, u64 name, + const char *sname, const char *cfg, + const char *dbg, int length, void **pobject) +{ + struct nouveaudevice *device; + int ret = -EEXIST; + + mutexlock(&nvdevicesmutex); + listforeachentry(device, &nvdevices, head) { + if (device->handle == name) + goto done; + } + + ret = nouveauenginecreate(NULL, NULL, &nouveaudeviceoclass, true, + "DEVICE", "device", length, pobject); + device = *pobject; + if (ret) + goto done; + + device->platformdev = pdev; + device->handle = name; + device->cfgopt = cfg; + device->dbgopt = dbg; + device->name = sname; + + nvsubdev(device)->debug = nouveaudbgopt(device->dbgopt, "DEVICE"); + nvengine(device)->sclass = nouveaudevicesclass; + listadd(&device->head, &nvdevices); +done: + mutexunlock(&nvdevicesmutex); + return ret; +} I think there's some potential for refactoring here, since the only difference that I can spot is in whether the pdev or the platformdev fields are assigned.
That's true. Actually I wonder if it would not make more sense for nouveau_device_platform_create_() to take a void pointer and a type saying whether the device is PCI or platform, otherwise we will end up duplicating the mutex code in two functions, ending up with even more code than my current version.
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c index b24559315903..d145e080899a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c @@ -349,7 +349,7 @@ nv20graphinit(struct nouveauobject *object) nvwr32(priv, NV10PGRAPHSURFACE, tmp);
/* begin RAM config */ - vramsz = pciresourcelen(nvdevice(priv)->pdev, 0) - 1; + vramsz = nvdeviceresourcelen(nvdevice(priv), 0) - 1; In case BAR0 is of size zero (start == 0, end == start), this will cause underflow in the case of a PCI device, because pciresourcelen() will return 0. I suspect that this never happens since that code's been there since the dawn of time.
Yes, I guess for particular chips it is ok to make assumptions such as the presence of a given BAR that are, anyway, properties inherent to that chip.
diff --git a/drivers/gpu/drm/nouveau/core/include/core/device.h b/drivers/gpu/drm/nouveau/core/include/core/device.h index 7b8ea221b00d..2a3e24e1d392 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/device.h +++ b/drivers/gpu/drm/nouveau/core/include/core/device.h @@ -65,6 +65,7 @@ struct nouveaudevice { struct listhead head;
struct pcidev *pdev; + struct platformdevice *platformdev; I'm generally wondering if perhaps a better abstraction would be to store a struct device * here, perhaps with a struct nouveaudeviceops * or similar to abstract away the differences between PCI and platform devices. nouveaudevicecreate() could then take a struct device * and a struct nouveaudeviceops *, and upcasting can therefore be done within these operations, rather than sprinkling nvdeviceispci() code everywhere.
At some point I was considering having the bus abstracted as a subdev, but that sounded overkill. :) A nouveau_device_ops * would provide a nicer abstraction, but at the end of the day we would still be calling accessor functions on a nouveau_device * and this would not change much for consumer code. It would also deprive PCI-dependent code (there is still a bunch) of a convenient way to access the pci_dev * since it would need to be upcasted. And the only place where this would remove nv_device_is_pci() is device/base.c.
IMHO the current situation is still sustainable for two buses. If we had three or more, I'd go for the nouveau_device_ops * solution though.
diff --git a/drivers/gpu/drm/nouveau/nouveauabi16.c b/drivers/gpu/drm/nouveau/nouveauabi16.c [...] case NOUVEAUGETPARAMBUSTYPE: + if (!nvdeviceispci(device)) + getparam->value = 3; + else if (drmpcideviceisagp(dev)) getparam->value = 0; else This is more of a general note since this patch doesn't introduce the parameter. Perhaps it would be good to expose a symbolic name for the various types of busses in a public header?
Maybe as a separate patch, yes. Also the value of "3" for non-PCI devices is completely arbitrary.
diff --git a/drivers/gpu/drm/nouveau/nouveauchan.c b/drivers/gpu/drm/nouveau/nouveauchan.c index cc5152be2cf1..19c6e6c9fc45 100644 --- a/drivers/gpu/drm/nouveau/nouveauchan.c +++ b/drivers/gpu/drm/nouveau/nouveauchan.c @@ -154,7 +154,7 @@ nouveauchannelprep(struct nouveaudrm *drm, struct nouveaucli *cli, * nfi why this exists, it came from the -nv ddx. */ args.flags = NVDMATARGETPCI | NVDMAACCESSRDWR; - args.start = pciresourcestart(device->pdev, 1); + args.start = nvdeviceresourcelen(device, 1); Should this have been nvdeviceresourcestart()?
Absolutely. Thanks.
diff --git a/drivers/gpu/drm/nouveau/nouveaudrm.c b/drivers/gpu/drm/nouveau/nouveaudrm.c [...] @@ -345,7 +368,7 @@ nouveaudrmload(struct drmdevice *dev, unsigned long flags) /* make sure AGP controller is in a consistent state before we * (possibly) execute vbios init tables (see nouveauagp.h) */ - if (drmpcideviceisagp(dev) && dev->agp) { + if (pdev && drmpcideviceisagp(dev) && dev->agp) { Perhaps move the check for valid PCI device into drmpcideviceisagp() rather than requiring callers to check explicitly?
I think drm_pci_device_is_agp() assumes a PCI device on purpose and that the burden of checking is on the caller. Changing this behavior would imply doing the same on many other functions of drmP.h.
@@ -384,8 +407,10 @@ nouveaudrmload(struct drmdevice *dev, unsigned long flags) if (nvdevice(drm->device)->chipset == 0xc1) nvmask(device, 0x00088080, 0x00000800, 0x00000000);
- nouveauvgainit(drm); - nouveauagpinit(drm); + if (pdev) { + nouveauvgainit(drm); + nouveauagpinit(drm); + } Same here. And if you make the above change, then nouveauagpinit() will do the right thing already.
Indeed, we can probably check drm_device::pdev in the functions themselves.
if (device->cardtype >= NV50) { ret = nouveauvmnew(nvdevice(drm->device), 0, (1ULL << 40), @@ -398,9 +423,11 @@ nouveaudrmload(struct drmdevice *dev, unsigned long flags) if (ret) goto failttm;
- ret = nouveaubiosinit(dev); - if (ret) - goto failbios; + if (pdev) { + ret = nouveaubiosinit(dev); + if (ret) + goto failbios; + } nouveaubiosinit() could also check internally and return 0 if the device isn't a PCI device. One less conditional in this function.
Agreed.
@@ -963,6 +991,25 @@ nouveaudrmpcidriver = { .driver.pm = &nouveaupmops, };
+ This adds a spurious newline.
Removed.
+int nouveaudrmplatformprobe(struct platformdevice *pdev) +{ + struct nouveaudevice *device; + int ret; + + ret = nouveaudeviceplatformcreate(pdev, nouveauplatformname(pdev), + devname(&pdev->dev), nouveauconfig, + nouveaudebug, &device); + + ret = drmplatforminit(&driver, pdev); + if (ret) { + nouveauobjectref(NULL, (struct nouveauobject **)&device); + return ret; + } + + return ret; +} I think we should move the whole of gk20a probing into nouveau. Keeping one part in tegra-drm and one part in nouveau is confusing, and I can't see a reason why we'd have to keep it that way.
Yes, the current probing scheme is definitely not what we want. However since some clocks probably need to be enabled before GK20A's registers (including BOOT0) can be read, this will probably require some more changes which we need to think about, and is not directly within the scope of this patch.
Thanks for the review! I will post a v2 tomorrow. Alex.
- Previous message: [Nouveau] [PATCH] drm/nouveau: support for platform devices
- Next message: [PATCH v2] drm/nouveau: support for platform devices
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]