]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
video: tegra: host: multi channels per device
authorShridhar Rasal <srasal@nvidia.com>
Wed, 26 Mar 2014 12:39:22 +0000 (18:09 +0530)
committerTerje Bergstrom <tbergstrom@nvidia.com>
Fri, 11 Apr 2014 05:57:55 +0000 (22:57 -0700)
- Add support to have multiple channels per device.

- set max number of channels that can be assigned to
  device in platform data.
- On channel open request assign new channel to device
  till max number of channel count.
- suspend all assigned channels on device disable clk.
- un-map all channels on device release callback.

Bug 1259844
Bug 1436477

Change-Id: Ibc1de8b036cde238b292e1ffa660dc2a796f65e8
Signed-off-by: Shridhar Rasal <srasal@nvidia.com>
Reviewed-on: http://git-master/r/387096
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
drivers/video/tegra/host/bus_client.c
drivers/video/tegra/host/debug.c
drivers/video/tegra/host/nvhost_acm.c
drivers/video/tegra/host/nvhost_channel.c
drivers/video/tegra/host/nvhost_channel.h
drivers/video/tegra/host/t124/t124.c
drivers/video/tegra/host/vic03/vic03.c
include/linux/nvhost.h

index 9790ebbe05f5e7aa0622f10beaa5390da7fb42a2..b429edd95425cc3c686d8c5239ec70385e8e21b3 100644 (file)
@@ -211,7 +211,7 @@ static int __nvhost_channelopen(struct inode *inode,
                pdata = container_of(inode->i_cdev,
                                struct nvhost_device_data, cdev);
                ch = nvhost_channel_map(pdata);
-               if (!ch) {
+               if (!ch || !ch->dev) {
                        pr_err("%s: failed to map channel\n", __func__);
                        return -ENOMEM;
                }
@@ -1057,6 +1057,10 @@ int nvhost_client_device_init(struct platform_device *dev)
        struct nvhost_master *nvhost_master = nvhost_get_host(dev);
        struct nvhost_device_data *pdata = platform_get_drvdata(dev);
 
+       pdata->channels = kzalloc(pdata->num_channels *
+                                       sizeof(struct nvhost_channel *),
+                                       GFP_KERNEL);
+
        /* Create debugfs directory for the device */
        nvhost_device_debug_init(dev);
 
@@ -1111,7 +1115,6 @@ EXPORT_SYMBOL(nvhost_client_device_init);
 int nvhost_client_device_release(struct platform_device *dev)
 {
        struct nvhost_device_data *pdata = platform_get_drvdata(dev);
-       struct nvhost_channel *ch = pdata->channel;
 
        /* Release nvhost module resources */
        nvhost_module_deinit(dev);
@@ -1125,9 +1128,8 @@ int nvhost_client_device_release(struct platform_device *dev)
        /* Remove debugFS */
        nvhost_device_debug_deinit(dev);
 
-       /* Unmap nvhost channel */
-       if (ch)
-               nvhost_putchannel(ch);
+       /* Release all nvhost channel of dev*/
+       nvhost_channel_release(pdata);
 
        return 0;
 }
index a8de0158e80fd4a594de291ab2d67be4c3fc00a7..900d30a84761ff9059f762aba23ddd88b8bcf8b1 100644 (file)
@@ -56,31 +56,34 @@ static int show_channels(struct platform_device *pdev, void *data,
        struct output *o = data;
        struct nvhost_master *m;
        struct nvhost_device_data *pdata;
+       int index;
 
        if (pdev == NULL)
                return 0;
 
        m = nvhost_get_host(pdev);
        pdata = platform_get_drvdata(pdev);
-       ch = pdata->channel;
-       if (!ch) {
-               nvhost_debug_output(o, "channel already un-mapped for %s\n",
-                               pdev->name);
-               return 0;
-       }
 
-       nvhost_getchannel(ch);
-       if (ch->chid != locked_id)
-               mutex_lock(&ch->cdma.lock);
-       if (fifo)
-               nvhost_get_chip_ops()->debug.show_channel_fifo(
+       for (index = 0; index < pdata->num_channels; index++) {
+               ch = pdata->channels[index];
+               if (!ch || !ch->dev) {
+                       nvhost_debug_output(o, "%d channel of %s unmapped\n",
+                                       index + 1, pdev->name);
+                       continue;
+               }
+               nvhost_getchannel(ch);
+               if (ch->chid != locked_id)
+                       mutex_lock(&ch->cdma.lock);
+               if (fifo)
+                       nvhost_get_chip_ops()->debug.show_channel_fifo(
+                               m, ch, o, ch->chid);
+               nvhost_get_chip_ops()->debug.show_channel_cdma(
                        m, ch, o, ch->chid);
-       nvhost_get_chip_ops()->debug.show_channel_cdma(
-               m, ch, o, ch->chid);
-       if (ch->chid != locked_id)
-               mutex_unlock(&ch->cdma.lock);
+               if (ch->chid != locked_id)
+                       mutex_unlock(&ch->cdma.lock);
+               nvhost_putchannel(ch);
+       }
 
-       nvhost_putchannel(ch);
        return 0;
 }
 
index 4105b0d097bc4208cad5a6bff5b2fd5333874838..616a20daecb2f96955056b891096da499d7a747c 100644 (file)
@@ -765,8 +765,9 @@ int nvhost_module_disable_clk(struct device *dev)
        for (index = 0; index < pdata->num_clks; index++)
                clk_disable_unprepare(pdata->clk[index]);
 
-       if (pdata->channel)
-               nvhost_channel_suspend(pdata->channel);
+       for (index = 0; index < pdata->num_channels; index++)
+               if (pdata->channels[index])
+                       nvhost_channel_suspend(pdata->channels[index]);
 
        /* disable parent's clock if required */
        if (dev->parent && dev->parent != &platform_bus)
index 751473e309a06d9783166774f0bdae70c390db11..1c5129e80b80616f7b48aa687f41b10cd3b1c187 100644 (file)
@@ -87,6 +87,55 @@ struct nvhost_channel *nvhost_return_node(struct nvhost_master *host,
        return NULL;
 }
 
+/* return any one of assigned channel from device
+ * This API can be used to check if any channel assigned to device
+ */
+struct nvhost_channel *nvhost_check_channel(struct nvhost_device_data *pdata)
+{
+       int i;
+       struct nvhost_channel *ch = NULL;
+
+       for (i = 0; i < pdata->num_channels; i++) {
+               ch = pdata->channels[i];
+               if (ch && ch->dev)
+                       return ch;
+       }
+
+       return ch;
+}
+
+/* Check if more than channel needed for device and assign */
+int nvhost_channel_assign(struct nvhost_device_data *pdata,
+                         struct nvhost_channel *ch)
+{
+       int i;
+
+       for (i = 0; i < pdata->num_channels; i++) {
+               if (!pdata->channels[i]) {
+                       pdata->channels[i] = ch;
+                       pdata->num_mapped_chs++;
+                       ch->dev_chid = i;
+                       return 0;
+               }
+       }
+       dev_err(&pdata->pdev->dev, "%s: All channels assigned\n", __func__);
+
+       return -EINVAL;
+}
+
+/* Releases all channels assigned with device */
+int nvhost_channel_release(struct nvhost_device_data *pdata)
+{
+       struct nvhost_channel *ch;
+       int i;
+
+       for (i = 0; i < pdata->num_channels; i++) {
+               ch = pdata->channels[i];
+               if (ch && ch->dev)
+                       nvhost_putchannel(ch);
+       }
+       return 0;
+}
 /* Unmap channel from device and free all resources, deinit device */
 int nvhost_channel_unmap(struct nvhost_channel *ch)
 {
@@ -130,7 +179,8 @@ int nvhost_channel_unmap(struct nvhost_channel *ch)
        ch->ctxhandler = NULL;
        ch->cur_ctx = NULL;
        ch->aperture = NULL;
-       pdata->channel = NULL;
+       pdata->channels[ch->dev_chid] = NULL;
+       pdata->num_mapped_chs--;
 
        mutex_unlock(&host->chlist_mutex);
 
@@ -156,10 +206,11 @@ struct nvhost_channel *nvhost_channel_map(struct nvhost_device_data *pdata)
        mutex_lock(&host->chlist_mutex);
        max_channels = host->info.nb_channels;
 
-       /* Check if already channel assigned for device */
-       if (pdata->channel) {
-               ch = pdata->channel;
-               nvhost_getchannel(ch);
+       /* Check if already channel(s) assigned for device */
+       if (pdata->num_channels == pdata->num_mapped_chs) {
+               ch = nvhost_check_channel(pdata);
+               if (ch)
+                       nvhost_getchannel(ch);
                mutex_unlock(&host->chlist_mutex);
                return ch;
        }
@@ -190,7 +241,7 @@ struct nvhost_channel *nvhost_channel_map(struct nvhost_device_data *pdata)
        if (ch->chid == NVHOST_INVALID_CHANNEL) {
                ch->dev = pdata->pdev;
                ch->chid = index;
-               pdata->channel = ch;
+               nvhost_channel_assign(pdata, ch);
                nvhost_set_chanops(ch);
        } else {
                dev_err(&host->dev->dev, "%s: wrong channel map\n", __func__);
@@ -253,7 +304,6 @@ int nvhost_channel_init(struct nvhost_channel *ch,
                struct nvhost_master *dev)
 {
        int err;
-       struct nvhost_device_data *pdata = platform_get_drvdata(ch->dev);
 
        /* Link platform_device to nvhost_channel */
        err = channel_op(ch).init(ch, dev);
@@ -262,7 +312,6 @@ int nvhost_channel_init(struct nvhost_channel *ch,
                                ch->chid);
                return err;
        }
-       pdata->channel = ch;
 
        return nvhost_cdma_init(&ch->cdma);
 }
index ffb9f70261f78ed8fc01fbdf4737a1b91efbadf7..d2f304baa79662e7cb45f773ff598434bfd27742 100644 (file)
@@ -49,6 +49,7 @@ struct nvhost_channel {
        struct nvhost_channel_ops ops;
        atomic_t refcount;
        int chid;
+       int dev_chid;
        u32 syncpt_id;
        struct mutex reflock;
        struct mutex submitlock;
@@ -71,7 +72,9 @@ struct nvhost_channel {
 int nvhost_alloc_channels(struct nvhost_master *host);
 struct nvhost_channel *nvhost_channel_map(struct nvhost_device_data *pdata);
 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);
+struct nvhost_channel *nvhost_check_channel(struct nvhost_device_data *pdata);
 int nvhost_channel_init(struct nvhost_channel *ch,
        struct nvhost_master *dev);
 
index 2c07bf2a4a3e27fb581a6115d6f54ba7840159fe..98da4cb702d4700c134be22d8078dfb9fa081be8 100644 (file)
@@ -113,6 +113,7 @@ static struct resource isp_resources[] = {
 
 static struct platform_device tegra_isp01b_device;
 struct nvhost_device_data t124_isp_info = {
+       .num_channels   = 1,
        /* FIXME: control clocks from user space instead of hard-coding here */
        .moduleid        = NVHOST_MODULE_ISP,
        .modulemutexes   = {NVMODMUTEX_ISP_0},
@@ -150,6 +151,7 @@ static struct resource ispb_resources[] = {
 
 
 struct nvhost_device_data t124_ispb_info = {
+       .num_channels   = 1,
        /* FIXME: control clocks from user space instead of hard-coding here */
        .moduleid        = (1 << 16) | NVHOST_MODULE_ISP,
        .modulemutexes   = {NVMODMUTEX_ISP_1},
@@ -189,6 +191,7 @@ static struct resource vi_resources[] = {
 
 static struct platform_device tegra_vi01b_device;
 struct nvhost_device_data t124_vi_info = {
+       .num_channels   = 1,
        /* FIXME: resolve powergating dependency with DIS */
        /* FIXME: control clocks from user space instead of hard-coding here */
        .moduleid         = NVHOST_MODULE_VI,
@@ -226,6 +229,7 @@ static struct platform_device tegra_vi01_device = {
 };
 
 struct nvhost_device_data t124_vib_info = {
+       .num_channels   = 1,
        /* FIXME: resolve powergating dependency with DIS */
        /* FIXME: control clocks from user space instead of hard-coding here */
        .moduleid         = (1 << 16 | NVHOST_MODULE_VI),
@@ -271,6 +275,7 @@ static struct resource msenc_resources[] = {
 };
 
 struct nvhost_device_data t124_msenc_info = {
+       .num_channels   = 1,
        .version        = NVHOST_ENCODE_MSENC_VER(3, 1),
        .class          = NV_VIDEO_ENCODE_MSENC_CLASS_ID,
        .clocks         = {{"msenc", UINT_MAX, 0, TEGRA_MC_CLIENT_MSENC},
@@ -309,6 +314,7 @@ static struct resource tsec_resources[] = {
 };
 
 struct nvhost_device_data t124_tsec_info = {
+       .num_channels   = 1,
        .version       = NVHOST_ENCODE_TSEC_VER(1, 0),
        .class         = NV_TSEC_CLASS_ID,
        .exclusive     = true,
@@ -347,6 +353,7 @@ static struct resource vic03_resources[] = {
 };
 
 struct nvhost_device_data t124_vic_info = {
+       .num_channels   = 1,
        .modulemutexes          = {NVMODMUTEX_VIC},
        .clocks                 = {{"vic03", UINT_MAX, 0, TEGRA_MC_CLIENT_VIC},
                                  {"emc", UINT_MAX} },
@@ -390,6 +397,7 @@ struct platform_device tegra_vic03_device = {
  */
 
 struct nvhost_device_data t132_isp_info = {
+       .num_channels   = 1,
        /* FIXME: control clocks from user space instead of hard-coding here */
        .moduleid        = NVHOST_MODULE_ISP,
        .modulemutexes   = {NVMODMUTEX_ISP_0},
@@ -407,6 +415,7 @@ struct nvhost_device_data t132_isp_info = {
 };
 
 struct nvhost_device_data t132_ispb_info = {
+       .num_channels   = 1,
        /* FIXME: control clocks from user space instead of hard-coding here */
        .moduleid        = (1 << 16) | NVHOST_MODULE_ISP,
        .modulemutexes   = {NVMODMUTEX_ISP_1},
@@ -424,6 +433,7 @@ struct nvhost_device_data t132_ispb_info = {
 };
 
 struct nvhost_device_data t132_vi_info = {
+       .num_channels   = 1,
        /* FIXME: resolve powergating dependency with DIS */
        /* FIXME: control clocks from user space instead of hard-coding here */
        .moduleid         = NVHOST_MODULE_VI,
@@ -449,6 +459,7 @@ struct nvhost_device_data t132_vi_info = {
 };
 
 struct nvhost_device_data t132_vib_info = {
+       .num_channels   = 1,
        /* FIXME: resolve powergating dependency with DIS */
        /* FIXME: control clocks from user space instead of hard-coding here */
        .moduleid         = (1 << 16 | NVHOST_MODULE_VI),
@@ -475,6 +486,7 @@ struct nvhost_device_data t132_vib_info = {
 };
 
 struct nvhost_device_data t132_msenc_info = {
+       .num_channels   = 1,
        .version        = NVHOST_ENCODE_MSENC_VER(3, 1),
        .class          = NV_VIDEO_ENCODE_MSENC_CLASS_ID,
        .clocks         = {{"msenc", UINT_MAX, 0, TEGRA_MC_CLIENT_MSENC},
@@ -490,6 +502,7 @@ struct nvhost_device_data t132_msenc_info = {
 };
 
 struct nvhost_device_data t132_tsec_info = {
+       .num_channels   = 1,
        .version       = NVHOST_ENCODE_TSEC_VER(1, 0),
        .class         = NV_TSEC_CLASS_ID,
        .exclusive     = true,
@@ -505,6 +518,7 @@ struct nvhost_device_data t132_tsec_info = {
 
 #ifdef CONFIG_ARCH_TEGRA_VIC
 struct nvhost_device_data t132_vic_info = {
+       .num_channels   = 1,
        .modulemutexes          = {NVMODMUTEX_VIC},
        .clocks                 = {{"vic03", UINT_MAX, 0, TEGRA_MC_CLIENT_VIC},
                                  {"emc", UINT_MAX} },
index b23ca0410417aeee3e047048ca7a429f9470acea..2a62262a2df6e871d25f30a23e81b0bb8893683b 100644 (file)
@@ -599,7 +599,7 @@ int nvhost_vic03_prepare_poweroff(struct platform_device *dev)
 {
        struct nvhost_device_data *pdata = nvhost_get_devdata(dev);
        struct vic03 *v;
-       struct nvhost_channel *ch = pdata->channel;
+       struct nvhost_channel *ch = pdata->channels[0];
 
        if (ch && ch->dev) {
                mutex_lock(&ch->submitlock);
index 785192623104fe3b690c3723095e4756e57c8d9a..91f74c844ca96f34960e14763ae24bce119bb020 100644 (file)
@@ -144,7 +144,11 @@ struct nvhost_device_data {
        struct mutex    lock;           /* Power management lock */
        struct list_head client_list;   /* List of clients and rate requests */
 
-       struct nvhost_channel *channel; /* Channel assigned for the module */
+       int             num_channels;   /* Max num of channel supported */
+       int             num_mapped_chs; /* Num of channel mapped to device */
+
+       /* Channel(s) assigned for the module */
+       struct nvhost_channel **channels;
 
        /* device node for channel operations */
        dev_t cdev_region;