summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2014-12-19 12:17:33 +0100
committerThierry Reding <treding@nvidia.com>2014-12-19 12:17:33 +0100
commit8e5789ac925110cbdadca4ef5f1404728b4a7e69 (patch)
tree6971dbc2fb01fe04e48d8669d1011631d55499ce
parenteec54027023be5d2a352eac6fd1ca45e28ced0a2 (diff)
parent5211b02134c0bac3e287f8eae88d230a384fab0f (diff)
Merge branch 'staging/host1x' into staging/master
-rw-r--r--drivers/gpu/drm/tegra/drm.c4
-rw-r--r--drivers/gpu/host1x/Makefile3
-rw-r--r--drivers/gpu/host1x/bus.c199
-rw-r--r--drivers/gpu/host1x/bus.h3
-rw-r--r--drivers/gpu/host1x/debug.c2
-rw-r--r--drivers/gpu/host1x/debug.h18
-rw-r--r--drivers/gpu/host1x/dev.c9
-rw-r--r--drivers/gpu/host1x/hw/debug_hw.c34
-rw-r--r--drivers/gpu/host1x/job.c14
-rw-r--r--include/linux/host1x.h19
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)