diff options
author | Thierry Reding <treding@nvidia.com> | 2014-12-19 12:17:33 +0100 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2014-12-19 12:17:33 +0100 |
commit | 8e5789ac925110cbdadca4ef5f1404728b4a7e69 (patch) | |
tree | 6971dbc2fb01fe04e48d8669d1011631d55499ce | |
parent | eec54027023be5d2a352eac6fd1ca45e28ced0a2 (diff) | |
parent | 5211b02134c0bac3e287f8eae88d230a384fab0f (diff) |
Merge branch 'staging/host1x' into staging/master
-rw-r--r-- | drivers/gpu/drm/tegra/drm.c | 4 | ||||
-rw-r--r-- | drivers/gpu/host1x/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpu/host1x/bus.c | 199 | ||||
-rw-r--r-- | drivers/gpu/host1x/bus.h | 3 | ||||
-rw-r--r-- | drivers/gpu/host1x/debug.c | 2 | ||||
-rw-r--r-- | drivers/gpu/host1x/debug.h | 18 | ||||
-rw-r--r-- | drivers/gpu/host1x/dev.c | 9 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/debug_hw.c | 34 | ||||
-rw-r--r-- | drivers/gpu/host1x/job.c | 14 | ||||
-rw-r--r-- | include/linux/host1x.h | 19 |
10 files changed, 197 insertions, 108 deletions
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index e549afeece1..272c2dca353 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -908,7 +908,9 @@ static const struct of_device_id host1x_drm_subdevs[] = { }; static struct host1x_driver host1x_drm_driver = { - .name = "drm", + .driver = { + .name = "drm", + }, .probe = host1x_drm_probe, .remove = host1x_drm_remove, .subdevs = host1x_drm_subdevs, diff --git a/drivers/gpu/host1x/Makefile b/drivers/gpu/host1x/Makefile index c1189f00444..a3e667a1b6f 100644 --- a/drivers/gpu/host1x/Makefile +++ b/drivers/gpu/host1x/Makefile @@ -1,5 +1,4 @@ host1x-y = \ - bus.o \ syncpt.o \ dev.o \ intr.o \ @@ -13,3 +12,5 @@ host1x-y = \ hw/host1x04.o obj-$(CONFIG_TEGRA_HOST1X) += host1x.o + +obj-y += bus.o diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c index aaf54859adb..28630a5e939 100644 --- a/drivers/gpu/host1x/bus.c +++ b/drivers/gpu/host1x/bus.c @@ -72,13 +72,14 @@ static void host1x_subdev_del(struct host1x_subdev *subdev) /** * host1x_device_parse_dt() - scan device tree and add matching subdevices */ -static int host1x_device_parse_dt(struct host1x_device *device) +static int host1x_device_parse_dt(struct host1x_device *device, + struct host1x_driver *driver) { struct device_node *np; int err; for_each_child_of_node(device->dev.parent->of_node, np) { - if (of_match_node(device->driver->subdevs, np) && + if (of_match_node(driver->subdevs, np) && of_device_is_available(np)) { err = host1x_subdev_add(device, np); if (err < 0) @@ -109,14 +110,12 @@ static void host1x_subdev_register(struct host1x_device *device, mutex_unlock(&device->clients_lock); mutex_unlock(&device->subdevs_lock); - /* - * When all subdevices have been registered, the composite device is - * ready to be probed. - */ if (list_empty(&device->subdevs)) { - err = device->driver->probe(device); + err = device_add(&device->dev); if (err < 0) - dev_err(&device->dev, "probe failed: %d\n", err); + dev_err(&device->dev, "failed to add: %d\n", err); + else + device->registered = true; } } @@ -124,16 +123,16 @@ static void __host1x_subdev_unregister(struct host1x_device *device, struct host1x_subdev *subdev) { struct host1x_client *client = subdev->client; - int err; /* * If all subdevices have been activated, we're about to remove the * first active subdevice, so unload the driver first. */ if (list_empty(&device->subdevs)) { - err = device->driver->remove(device); - if (err < 0) - dev_err(&device->dev, "remove failed: %d\n", err); + if (device->registered) { + device->registered = false; + device_del(&device->dev); + } } /* @@ -260,24 +259,119 @@ static int host1x_del_client(struct host1x *host1x, return -ENODEV; } +static int host1x_device_match(struct device *dev, struct device_driver *drv) +{ + return strcmp(dev_name(dev), drv->name) == 0; +} + +static int host1x_device_probe(struct device *dev) +{ + struct host1x_driver *driver = to_host1x_driver(dev->driver); + struct host1x_device *device = to_host1x_device(dev); + + if (driver->probe) + return driver->probe(device); + + return 0; +} + +static int host1x_device_remove(struct device *dev) +{ + struct host1x_driver *driver = to_host1x_driver(dev->driver); + struct host1x_device *device = to_host1x_device(dev); + + if (driver->remove) + return driver->remove(device); + + return 0; +} + +static void host1x_device_shutdown(struct device *dev) +{ + struct host1x_driver *driver = to_host1x_driver(dev->driver); + struct host1x_device *device = to_host1x_device(dev); + + if (driver->shutdown) + driver->shutdown(device); +} + +static const struct dev_pm_ops host1x_device_pm_ops = { + .suspend = pm_generic_suspend, + .resume = pm_generic_resume, + .freeze = pm_generic_freeze, + .thaw = pm_generic_thaw, + .poweroff = pm_generic_poweroff, + .restore = pm_generic_restore, +}; + static struct bus_type host1x_bus_type = { .name = "host1x", + .match = host1x_device_match, + .probe = host1x_device_probe, + .remove = host1x_device_remove, + .shutdown = host1x_device_shutdown, + .pm = &host1x_device_pm_ops, }; -int host1x_bus_init(void) +static int host1x_bus_init(void) { return bus_register(&host1x_bus_type); } +postcore_initcall(host1x_bus_init); -void host1x_bus_exit(void) +static void __host1x_device_del(struct host1x_device *device) { - bus_unregister(&host1x_bus_type); + struct host1x_subdev *subdev, *sd; + struct host1x_client *client, *cl; + + mutex_lock(&device->subdevs_lock); + + /* unregister subdevices */ + list_for_each_entry_safe(subdev, sd, &device->active, list) { + /* + * host1x_subdev_unregister() will remove the client from + * any lists, so we'll need to manually add it back to the + * list of idle clients. + * + * XXX: Alternatively, perhaps don't remove the client from + * any lists in host1x_subdev_unregister() and instead do + * that explicitly from host1x_unregister_client()? + */ + client = subdev->client; + + __host1x_subdev_unregister(device, subdev); + + /* add the client to the list of idle clients */ + mutex_lock(&clients_lock); + list_add_tail(&client->list, &clients); + mutex_unlock(&clients_lock); + } + + /* remove subdevices */ + list_for_each_entry_safe(subdev, sd, &device->subdevs, list) + host1x_subdev_del(subdev); + + mutex_unlock(&device->subdevs_lock); + + /* move clients to idle list */ + mutex_lock(&clients_lock); + mutex_lock(&device->clients_lock); + + list_for_each_entry_safe(client, cl, &device->clients, list) + list_move_tail(&client->list, &clients); + + mutex_unlock(&device->clients_lock); + mutex_unlock(&clients_lock); + + /* finally remove the device */ + list_del_init(&device->list); } static void host1x_device_release(struct device *dev) { struct host1x_device *device = to_host1x_device(dev); + __host1x_device_del(device); kfree(device); } @@ -293,6 +387,8 @@ static int host1x_device_add(struct host1x *host1x, if (!device) return -ENOMEM; + device_initialize(&device->dev); + mutex_init(&device->subdevs_lock); INIT_LIST_HEAD(&device->subdevs); INIT_LIST_HEAD(&device->active); @@ -303,24 +399,18 @@ static int host1x_device_add(struct host1x *host1x, device->dev.coherent_dma_mask = host1x->dev->coherent_dma_mask; device->dev.dma_mask = &device->dev.coherent_dma_mask; + dev_set_name(&device->dev, "%s", driver->driver.name); device->dev.release = host1x_device_release; - dev_set_name(&device->dev, "%s", driver->name); device->dev.bus = &host1x_bus_type; device->dev.parent = host1x->dev; - err = device_register(&device->dev); - if (err < 0) - return err; - - err = host1x_device_parse_dt(device); + err = host1x_device_parse_dt(device, driver); if (err < 0) { - device_unregister(&device->dev); + kfree(device); return err; } - mutex_lock(&host1x->devices_lock); list_add_tail(&device->list, &host1x->devices); - mutex_unlock(&host1x->devices_lock); mutex_lock(&clients_lock); @@ -347,51 +437,12 @@ static int host1x_device_add(struct host1x *host1x, static void host1x_device_del(struct host1x *host1x, struct host1x_device *device) { - struct host1x_subdev *subdev, *sd; - struct host1x_client *client, *cl; - - mutex_lock(&device->subdevs_lock); - - /* unregister subdevices */ - list_for_each_entry_safe(subdev, sd, &device->active, list) { - /* - * host1x_subdev_unregister() will remove the client from - * any lists, so we'll need to manually add it back to the - * list of idle clients. - * - * XXX: Alternatively, perhaps don't remove the client from - * any lists in host1x_subdev_unregister() and instead do - * that explicitly from host1x_unregister_client()? - */ - client = subdev->client; - - __host1x_subdev_unregister(device, subdev); - - /* add the client to the list of idle clients */ - mutex_lock(&clients_lock); - list_add_tail(&client->list, &clients); - mutex_unlock(&clients_lock); + if (device->registered) { + device->registered = false; + device_del(&device->dev); } - /* remove subdevices */ - list_for_each_entry_safe(subdev, sd, &device->subdevs, list) - host1x_subdev_del(subdev); - - mutex_unlock(&device->subdevs_lock); - - /* move clients to idle list */ - mutex_lock(&clients_lock); - mutex_lock(&device->clients_lock); - - list_for_each_entry_safe(client, cl, &device->clients, list) - list_move_tail(&client->list, &clients); - - mutex_unlock(&device->clients_lock); - mutex_unlock(&clients_lock); - - /* finally remove the device */ - list_del_init(&device->list); - device_unregister(&device->dev); + put_device(&device->dev); } static void host1x_attach_driver(struct host1x *host1x, @@ -409,11 +460,11 @@ static void host1x_attach_driver(struct host1x *host1x, } } - mutex_unlock(&host1x->devices_lock); - err = host1x_device_add(host1x, driver); if (err < 0) dev_err(host1x->dev, "failed to allocate device: %d\n", err); + + mutex_unlock(&host1x->devices_lock); } static void host1x_detach_driver(struct host1x *host1x, @@ -466,7 +517,8 @@ int host1x_unregister(struct host1x *host1x) return 0; } -int host1x_driver_register(struct host1x_driver *driver) +int host1x_driver_register_full(struct host1x_driver *driver, + struct module *owner) { struct host1x *host1x; @@ -483,9 +535,12 @@ int host1x_driver_register(struct host1x_driver *driver) mutex_unlock(&devices_lock); - return 0; + driver->driver.bus = &host1x_bus_type; + driver->driver.owner = owner; + + return driver_register(&driver->driver); } -EXPORT_SYMBOL(host1x_driver_register); +EXPORT_SYMBOL(host1x_driver_register_full); void host1x_driver_unregister(struct host1x_driver *driver) { diff --git a/drivers/gpu/host1x/bus.h b/drivers/gpu/host1x/bus.h index 4099e99212c..c7d976e8ead 100644 --- a/drivers/gpu/host1x/bus.h +++ b/drivers/gpu/host1x/bus.h @@ -20,9 +20,6 @@ struct host1x; -int host1x_bus_init(void); -void host1x_bus_exit(void); - int host1x_register(struct host1x *host1x); int host1x_unregister(struct host1x *host1x); diff --git a/drivers/gpu/host1x/debug.c b/drivers/gpu/host1x/debug.c index ee3d12b51c5..1696bd23e02 100644 --- a/drivers/gpu/host1x/debug.c +++ b/drivers/gpu/host1x/debug.c @@ -39,7 +39,7 @@ void host1x_debug_output(struct output *o, const char *fmt, ...) va_start(args, fmt); len = vsnprintf(o->buf, sizeof(o->buf), fmt, args); va_end(args); - o->fn(o->ctx, o->buf, len); + o->fn(o, o->buf, len); } static int show_channels(struct host1x_channel *ch, void *data, bool show_fifo) diff --git a/drivers/gpu/host1x/debug.h b/drivers/gpu/host1x/debug.h index 4595b2e0799..3a7b57ff169 100644 --- a/drivers/gpu/host1x/debug.h +++ b/drivers/gpu/host1x/debug.h @@ -23,20 +23,28 @@ struct host1x; +#define HOST1X_OUTPUT_CONT (1 << 0) + struct output { - void (*fn)(void *ctx, const char *str, size_t len); + void (*fn)(struct output *output, const char *str, size_t len); + unsigned long flags; void *ctx; char buf[256]; }; -static inline void write_to_seqfile(void *ctx, const char *str, size_t len) +static inline void write_to_seqfile(struct output *output, const char *str, size_t len) { - seq_write((struct seq_file *)ctx, str, len); + struct seq_file *s = output->ctx; + + seq_write(s, str, len); } -static inline void write_to_printk(void *ctx, const char *str, size_t len) +static inline void write_to_printk(struct output *output, const char *str, size_t len) { - pr_info("%s", str); + if (output->flags & HOST1X_OUTPUT_CONT) + pr_cont("%s", str); + else + pr_info("%s", str); } void __printf(2, 3) host1x_debug_output(struct output *o, const char *fmt, ...); diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 2529908d304..18b36410347 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -216,13 +216,9 @@ static int __init tegra_host1x_init(void) { int err; - err = host1x_bus_init(); - if (err < 0) - return err; - err = platform_driver_register(&tegra_host1x_driver); if (err < 0) - goto unregister_bus; + return err; err = platform_driver_register(&tegra_mipi_driver); if (err < 0) @@ -232,8 +228,6 @@ static int __init tegra_host1x_init(void) unregister_host1x: platform_driver_unregister(&tegra_host1x_driver); -unregister_bus: - host1x_bus_exit(); return err; } module_init(tegra_host1x_init); @@ -242,7 +236,6 @@ static void __exit tegra_host1x_exit(void) { platform_driver_unregister(&tegra_mipi_driver); platform_driver_unregister(&tegra_host1x_driver); - host1x_bus_exit(); } module_exit(tegra_host1x_exit); diff --git a/drivers/gpu/host1x/hw/debug_hw.c b/drivers/gpu/host1x/hw/debug_hw.c index 791de9351ee..d5b60a81b65 100644 --- a/drivers/gpu/host1x/hw/debug_hw.c +++ b/drivers/gpu/host1x/hw/debug_hw.c @@ -40,9 +40,12 @@ enum { static unsigned int show_channel_command(struct output *o, u32 val) { + unsigned int ret = 0; unsigned mask; unsigned subop; + o->flags |= HOST1X_OUTPUT_CONT; + switch (val >> 28) { case HOST1X_OPCODE_SETCLASS: mask = val & 0x3f; @@ -50,43 +53,47 @@ static unsigned int show_channel_command(struct output *o, u32 val) host1x_debug_output(o, "SETCL(class=%03x, offset=%03x, mask=%02x, [", val >> 6 & 0x3ff, val >> 16 & 0xfff, mask); - return hweight8(mask); + ret = hweight8(mask); } else { host1x_debug_output(o, "SETCL(class=%03x)\n", val >> 6 & 0x3ff); - return 0; } + break; case HOST1X_OPCODE_INCR: host1x_debug_output(o, "INCR(offset=%03x, [", val >> 16 & 0xfff); - return val & 0xffff; + ret = val & 0xffff; + break; case HOST1X_OPCODE_NONINCR: host1x_debug_output(o, "NONINCR(offset=%03x, [", val >> 16 & 0xfff); - return val & 0xffff; + ret = val & 0xffff; + break; case HOST1X_OPCODE_MASK: mask = val & 0xffff; host1x_debug_output(o, "MASK(offset=%03x, mask=%03x, [", val >> 16 & 0xfff, mask); - return hweight16(mask); + ret = hweight16(mask); + break; case HOST1X_OPCODE_IMM: host1x_debug_output(o, "IMM(offset=%03x, data=%03x)\n", val >> 16 & 0xfff, val & 0xffff); - return 0; + break; case HOST1X_OPCODE_RESTART: host1x_debug_output(o, "RESTART(offset=%08x)\n", val << 4); - return 0; + break; case HOST1X_OPCODE_GATHER: host1x_debug_output(o, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[", val >> 16 & 0xfff, val >> 15 & 0x1, val >> 14 & 0x1, val & 0x3fff); - return 1; + ret = 1; + break; case HOST1X_OPCODE_EXTEND: subop = val >> 24 & 0xf; @@ -98,11 +105,16 @@ static unsigned int show_channel_command(struct output *o, u32 val) val & 0xff); else host1x_debug_output(o, "EXTEND_UNKNOWN(%08x)\n", val); - return 0; + + break; default: - return 0; + break; } + + o->flags &= ~HOST1X_OUTPUT_CONT; + + return ret; } static void show_gather(struct output *o, phys_addr_t phys_addr, @@ -128,7 +140,7 @@ static void show_gather(struct output *o, phys_addr_t phys_addr, u32 val = *(map_addr + offset / 4 + i); if (!data_count) { - host1x_debug_output(o, "%08x: %08x:", addr, val); + host1x_debug_output(o, "%08x: %08x - ", addr, val); data_count = show_channel_command(o, val); } else { host1x_debug_output(o, "%08x%s", val, diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c index 63bd63f3c7d..e115bf22e5d 100644 --- a/drivers/gpu/host1x/job.c +++ b/drivers/gpu/host1x/job.c @@ -507,12 +507,16 @@ static inline int copy_gathers(struct host1x_job *job, struct device *dev) int host1x_job_pin(struct host1x_job *job, struct device *dev) { - int err; - unsigned int i, j; struct host1x *host = dev_get_drvdata(dev->parent); - DECLARE_BITMAP(waitchk_mask, host1x_syncpt_nb_pts(host)); + unsigned int num = host1x_syncpt_nb_pts(host); + unsigned long *waitchk_mask; + unsigned int i, j; + int err; + + waitchk_mask = kcalloc(sizeof(*waitchk_mask), num, GFP_KERNEL); + if (!waitchk_mask) + return -ENOMEM; - bitmap_zero(waitchk_mask, host1x_syncpt_nb_pts(host)); for (i = 0; i < job->num_waitchk; i++) { u32 syncpt_id = job->waitchk[i].syncpt_id; if (syncpt_id < host1x_syncpt_nb_pts(host)) @@ -523,6 +527,8 @@ int host1x_job_pin(struct host1x_job *job, struct device *dev) for_each_set_bit(i, waitchk_mask, host1x_syncpt_nb_pts(host)) host1x_syncpt_load(host->syncpt + i); + kfree(waitchk_mask); + /* pin memory */ err = pin_job(job); if (!err) diff --git a/include/linux/host1x.h b/include/linux/host1x.h index bb9840fd1e1..cb1df1f74f1 100644 --- a/include/linux/host1x.h +++ b/include/linux/host1x.h @@ -27,6 +27,7 @@ enum host1x_class { HOST1X_CLASS_GR2D = 0x51, HOST1X_CLASS_GR2D_SB = 0x52, HOST1X_CLASS_GR3D = 0x60, + HOST1X_CLASS_GPU = 0x61, }; struct host1x_client; @@ -250,17 +251,29 @@ void host1x_job_unpin(struct host1x_job *job); struct host1x_device; struct host1x_driver { + struct device_driver driver; + const struct of_device_id *subdevs; struct list_head list; - const char *name; int (*probe)(struct host1x_device *device); int (*remove)(struct host1x_device *device); + void (*shutdown)(struct host1x_device *device); }; -int host1x_driver_register(struct host1x_driver *driver); +static inline struct host1x_driver * +to_host1x_driver(struct device_driver *driver) +{ + return container_of(driver, struct host1x_driver, driver); +} + +int host1x_driver_register_full(struct host1x_driver *driver, + struct module *owner); void host1x_driver_unregister(struct host1x_driver *driver); +#define host1x_driver_register(driver) \ + host1x_driver_register_full(driver, THIS_MODULE) + struct host1x_device { struct host1x_driver *driver; struct list_head list; @@ -272,6 +285,8 @@ struct host1x_device { struct mutex clients_lock; struct list_head clients; + + bool registered; }; static inline struct host1x_device *to_host1x_device(struct device *dev) |