]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
video: tegra: host: Rework channel API
authorArto Merilainen <amerilainen@nvidia.com>
Tue, 21 Oct 2014 05:26:44 +0000 (10:56 +0530)
committerGerrit Code Review <gerrit2@nvidia.com>
Tue, 4 Nov 2014 08:26:53 +0000 (00:26 -0800)
This patch reworks the channel API to support mapping channels lazily
at submit time.

First, this change adds a possibility to give an identifier for
channel API. If channels are mapped at submit time, this identifier
is matched with the identifier stored inside the channel structure.
If the identifier matches, the channel is reused. Otherwise we
always allocate a new channel.

Second, this patch makes channel allocation to poll for a free
channel if the channel binding happens at submit time. This ensures
that the user always gets a channel

Third, nvhost_channel_map() users are adapted to use the new API. In
channel ioctl case we store the channel instance private pointer and
in hdcp use case we use the platform data pointer.

Bug 200041935

Change-Id: I0133398071fbc540c96c8224e011d92226249197
Signed-off-by: Arto Merilainen <amerilainen@nvidia.com>
drivers/video/tegra/host/bus_client.c
drivers/video/tegra/host/nvhost_channel.c
drivers/video/tegra/host/nvhost_channel.h
drivers/video/tegra/host/tsec/tsec.c

index bf37bf2d9ab5a69e4efbbaf50a592004c8f02274..b93158bb73b410b21912aef5340a7d18865f6856 100644 (file)
@@ -237,7 +237,7 @@ static int __nvhost_channelopen(struct inode *inode,
        if (inode) {
                pdata = container_of(inode->i_cdev,
                                struct nvhost_device_data, cdev);
-               ret = nvhost_channel_map(pdata, &ch);
+               ret = nvhost_channel_map(pdata, &ch, NULL);
                if (ret) {
                        pr_err("%s: failed to map channel, error: %d\n",
                                        __func__, ret);
@@ -289,6 +289,7 @@ static int __nvhost_channelopen(struct inode *inode,
        priv->timeout = pdata->nvhost_timeout_default;
        priv->timeout_debug_dump = true;
        mutex_init(&priv->ioctl_lock);
+       priv->pdev = pdata->pdev;
        if (!tegra_platform_is_silicon())
                priv->timeout = 0;
        mutex_unlock(&channel_lock);
index 21eac9de0037e851e359ae884b6e60a6b63936c3..d1d4faa44d45b58a84521bf3858a205c5e4a26d1 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <trace/events/nvhost.h>
 #include <linux/nvhost_ioctl.h>
+#include <linux/delay.h>
 #include <linux/nvhost.h>
 #include <linux/slab.h>
 
@@ -186,6 +187,7 @@ static int nvhost_channel_unmap_locked(struct nvhost_channel *ch)
        ch->dev = NULL;
        ch->aperture = NULL;
        ch->refcount = 0;
+       ch->identifier = NULL;
        pdata->channels[ch->dev_chid] = NULL;
 
        return 0;
@@ -193,7 +195,8 @@ static int nvhost_channel_unmap_locked(struct nvhost_channel *ch)
 
 /* Maps free channel with device */
 int nvhost_channel_map(struct nvhost_device_data *pdata,
-                       struct nvhost_channel **channel)
+                       struct nvhost_channel **channel,
+                       void *identifier)
 {
        struct nvhost_master *host = NULL;
        struct nvhost_channel *ch = NULL;
@@ -211,8 +214,16 @@ int nvhost_channel_map(struct nvhost_device_data *pdata,
        mutex_lock(&host->chlist_mutex);
        max_channels = host->info.nb_channels;
 
-       /* Check if already channel(s) assigned for device */
-       if (pdata->num_channels == pdata->num_mapped_chs) {
+       if (host->info.channel_policy == MAP_CHANNEL_ON_SUBMIT) {
+               /* check if the channel is still in use */
+               ch = *channel;
+               if (ch && ch->refcount && ch->identifier == identifier) {
+                       /* yes, client can continue using it */
+                       ch->refcount++;
+                       mutex_unlock(&host->chlist_mutex);
+                       return 0;
+               }
+       } else if (pdata->num_channels == pdata->num_mapped_chs) {
                if (pdata->exclusive) {
                        mutex_unlock(&host->chlist_mutex);
                        return -EBUSY;
@@ -225,21 +236,24 @@ int nvhost_channel_map(struct nvhost_device_data *pdata,
                return 0;
        }
 
-       index = find_next_zero_bit(&host->allocated_channels,
+       do {
+               index = find_next_zero_bit(&host->allocated_channels,
                                        max_channels, host->next_free_ch);
 
-       if (index >= max_channels) {
-               /* Reset next pointer and try */
-               host->next_free_ch = 0;
-               index = find_next_zero_bit(&host->allocated_channels,
+               if (index >= max_channels) {
+                       /* Reset next pointer and try */
+                       host->next_free_ch = 0;
+                       index = find_next_zero_bit(&host->allocated_channels,
                                        max_channels, host->next_free_ch);
+               }
                if (index >= max_channels) {
-                       pr_err("All host1x channels are mapped, BITMAP: %lu\n",
-                                       host->allocated_channels);
                        mutex_unlock(&host->chlist_mutex);
-                       return -ENOMEM;
+                       if (host->info.channel_policy != MAP_CHANNEL_ON_SUBMIT)
+                               return -ENOMEM;
+                       mdelay(1);
+                       mutex_lock(&host->chlist_mutex);
                }
-       }
+       } while (index >= max_channels);
 
        /* Get channel from list and map to device */
        ch = host->chlist[index];
@@ -251,7 +265,9 @@ int nvhost_channel_map(struct nvhost_device_data *pdata,
 
        ch->dev = pdata->pdev;
        ch->chid = index;
-       nvhost_channel_assign(pdata, ch);
+       ch->identifier = identifier;
+       if (host->info.channel_policy == MAP_CHANNEL_ON_OPEN)
+               nvhost_channel_assign(pdata, ch);
        nvhost_set_chanops(ch);
        set_bit(ch->chid, &host->allocated_channels);
        mutex_init(&ch->syncpts_lock);
index 41a937c61fa7fa6983eff0be2556943f76bdd11d..04df9e3331efbd0749903d1143e4d24ce863fd30 100644 (file)
@@ -61,13 +61,17 @@ struct nvhost_channel {
        /* channel syncpoints */
        struct mutex syncpts_lock;
        u32 syncpts[NVHOST_MODULE_MAX_SYNCPTS];
+
+       /* owner identifier */
+       void *identifier;
 };
 
 #define channel_op(ch)         (ch->ops)
 
 int nvhost_alloc_channels(struct nvhost_master *host);
 int nvhost_channel_map(struct nvhost_device_data *pdata,
-                       struct nvhost_channel **ch);
+                       struct nvhost_channel **ch,
+                       void *identifier);
 int nvhost_channel_unmap(struct nvhost_channel *ch);
 int nvhost_channel_release(struct nvhost_device_data *pdata);
 int nvhost_channel_list_free(struct nvhost_master *host);
index 5a41bdc3b090d5cbd459346c78b0bbe46ac84e91..37f222cf9cf5e7acc5d807e428ee21862c426b1c 100644 (file)
@@ -307,7 +307,7 @@ void tsec_execute_method(dma_addr_t dma_handle,
        struct nvhost_master *host = nvhost_get_host(tsec);
        channel = pdata->channels[0];
        if (!channel) {
-               err = nvhost_channel_map(pdata, &channel);
+               err = nvhost_channel_map(pdata, &channel, pdata);
                if (err)
                        nvhost_err(&tsec->dev, "Channel map failed\n");
                }