From 889235ce2b26cdd231c7a1d6005928ec42f11637 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 11 Jun 2014 23:59:16 +0000 Subject: firewire: Use ktime_get_ts() do_posix_clock_monotonic_gettime() is a leftover from the initial posix timer implementation which maps to ktime_get_ts() Signed-off-by: Thomas Gleixner Cc: John Stultz Cc: Peter Zijlstra Acked-by: Stefan Richter Link: http://lkml.kernel.org/r/20140611234607.351283464@linutronix.de Signed-off-by: Thomas Gleixner --- drivers/firewire/core-cdev.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index d7d5c8af92b9..5d997a33907e 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -1214,9 +1214,9 @@ static int ioctl_get_cycle_timer2(struct client *client, union ioctl_arg *arg) cycle_time = card->driver->read_csr(card, CSR_CYCLE_TIME); switch (a->clk_id) { - case CLOCK_REALTIME: getnstimeofday(&ts); break; - case CLOCK_MONOTONIC: do_posix_clock_monotonic_gettime(&ts); break; - case CLOCK_MONOTONIC_RAW: getrawmonotonic(&ts); break; + case CLOCK_REALTIME: getnstimeofday(&ts); break; + case CLOCK_MONOTONIC: ktime_get_ts(&ts); break; + case CLOCK_MONOTONIC_RAW: getrawmonotonic(&ts); break; default: ret = -EINVAL; } -- cgit From 58394271c610e9c65dd0165a1c1f6dec75dc5f3e Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 16 Jun 2014 11:48:45 +0200 Subject: clocksource: Add a Kconfig menu Move the clocksource Kconfig entries into their own menu, so that they don't pollute the main device driver menu. Signed-off-by: Jean Delvare Cc: Daniel Lezcano Link: http://lkml.kernel.org/r/20140616114845.343e9960@endymion.delvare Signed-off-by: Thomas Gleixner --- drivers/clocksource/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 065131cbfcc0..6a1151840510 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -1,3 +1,5 @@ +menu "Clock Source drivers" + config CLKSRC_OF bool @@ -207,3 +209,5 @@ config CLKSRC_VERSATILE counter available in the "System Registers" block of ARM Versatile, RealView and Versatile Express reference platforms. + +endmenu -- cgit From 31e912f598371bcfdffc990289029e1110f8b3f9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 28 Jan 2014 15:52:46 +0100 Subject: clocksource: sh_cmt: Drop support for legacy platform data Now that all platforms have switched to the new-style platform data, drop support for the legacy version. Signed-off-by: Laurent Pinchart Tested-by: Simon Horman --- drivers/clocksource/sh_cmt.c | 172 ++++++++++--------------------------------- 1 file changed, 40 insertions(+), 132 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index dfa780396b91..fcd38db9ce5c 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -114,9 +114,7 @@ struct sh_cmt_device { struct platform_device *pdev; const struct sh_cmt_info *info; - bool legacy; - void __iomem *mapbase_ch; void __iomem *mapbase; struct clk *clk; @@ -792,7 +790,7 @@ static int sh_cmt_register_clockevent(struct sh_cmt_channel *ch, int irq; int ret; - irq = platform_get_irq(ch->cmt->pdev, ch->cmt->legacy ? 0 : ch->index); + irq = platform_get_irq(ch->cmt->pdev, ch->index); if (irq < 0) { dev_err(&ch->cmt->pdev->dev, "ch%u: failed to get irq\n", ch->index); @@ -863,33 +861,26 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index, * Compute the address of the channel control register block. For the * timers with a per-channel start/stop register, compute its address * as well. - * - * For legacy configuration the address has been mapped explicitly. */ - if (cmt->legacy) { - ch->ioctrl = cmt->mapbase_ch; - } else { - switch (cmt->info->model) { - case SH_CMT_16BIT: - ch->ioctrl = cmt->mapbase + 2 + ch->hwidx * 6; - break; - case SH_CMT_32BIT: - case SH_CMT_48BIT: - ch->ioctrl = cmt->mapbase + 0x10 + ch->hwidx * 0x10; - break; - case SH_CMT_32BIT_FAST: - /* - * The 32-bit "fast" timer has a single channel at hwidx - * 5 but is located at offset 0x40 instead of 0x60 for - * some reason. - */ - ch->ioctrl = cmt->mapbase + 0x40; - break; - case SH_CMT_48BIT_GEN2: - ch->iostart = cmt->mapbase + ch->hwidx * 0x100; - ch->ioctrl = ch->iostart + 0x10; - break; - } + switch (cmt->info->model) { + case SH_CMT_16BIT: + ch->ioctrl = cmt->mapbase + 2 + ch->hwidx * 6; + break; + case SH_CMT_32BIT: + case SH_CMT_48BIT: + ch->ioctrl = cmt->mapbase + 0x10 + ch->hwidx * 0x10; + break; + case SH_CMT_32BIT_FAST: + /* + * The 32-bit "fast" timer has a single channel at hwidx 5 but + * is located at offset 0x40 instead of 0x60 for some reason. + */ + ch->ioctrl = cmt->mapbase + 0x40; + break; + case SH_CMT_48BIT_GEN2: + ch->iostart = cmt->mapbase + ch->hwidx * 0x100; + ch->ioctrl = ch->iostart + 0x10; + break; } if (cmt->info->width == (sizeof(ch->max_match_value) * 8)) @@ -900,12 +891,7 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index, ch->match_value = ch->max_match_value; raw_spin_lock_init(&ch->lock); - if (cmt->legacy) { - ch->timer_bit = ch->hwidx; - } else { - ch->timer_bit = cmt->info->model == SH_CMT_48BIT_GEN2 - ? 0 : ch->hwidx; - } + ch->timer_bit = cmt->info->model == SH_CMT_48BIT_GEN2 ? 0 : ch->hwidx; ret = sh_cmt_register(ch, dev_name(&cmt->pdev->dev), clockevent, clocksource); @@ -938,60 +924,12 @@ static int sh_cmt_map_memory(struct sh_cmt_device *cmt) return 0; } -static int sh_cmt_map_memory_legacy(struct sh_cmt_device *cmt) -{ - struct sh_timer_config *cfg = cmt->pdev->dev.platform_data; - struct resource *res, *res2; - - /* map memory, let mapbase_ch point to our channel */ - res = platform_get_resource(cmt->pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&cmt->pdev->dev, "failed to get I/O memory\n"); - return -ENXIO; - } - - cmt->mapbase_ch = ioremap_nocache(res->start, resource_size(res)); - if (cmt->mapbase_ch == NULL) { - dev_err(&cmt->pdev->dev, "failed to remap I/O memory\n"); - return -ENXIO; - } - - /* optional resource for the shared timer start/stop register */ - res2 = platform_get_resource(cmt->pdev, IORESOURCE_MEM, 1); - - /* map second resource for CMSTR */ - cmt->mapbase = ioremap_nocache(res2 ? res2->start : - res->start - cfg->channel_offset, - res2 ? resource_size(res2) : 2); - if (cmt->mapbase == NULL) { - dev_err(&cmt->pdev->dev, "failed to remap I/O second memory\n"); - iounmap(cmt->mapbase_ch); - return -ENXIO; - } - - /* identify the model based on the resources */ - if (resource_size(res) == 6) - cmt->info = &sh_cmt_info[SH_CMT_16BIT]; - else if (res2 && (resource_size(res2) == 4)) - cmt->info = &sh_cmt_info[SH_CMT_48BIT_GEN2]; - else - cmt->info = &sh_cmt_info[SH_CMT_32BIT]; - - return 0; -} - -static void sh_cmt_unmap_memory(struct sh_cmt_device *cmt) -{ - iounmap(cmt->mapbase); - if (cmt->mapbase_ch) - iounmap(cmt->mapbase_ch); -} - static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) { struct sh_timer_config *cfg = pdev->dev.platform_data; const struct platform_device_id *id = pdev->id_entry; - unsigned int hw_channels; + unsigned int mask; + unsigned int i; int ret; memset(cmt, 0, sizeof(*cmt)); @@ -1003,10 +941,9 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) } cmt->info = (const struct sh_cmt_info *)id->driver_data; - cmt->legacy = cmt->info ? false : true; /* Get hold of clock. */ - cmt->clk = clk_get(&cmt->pdev->dev, cmt->legacy ? "cmt_fck" : "fck"); + cmt->clk = clk_get(&cmt->pdev->dev, "fck"); if (IS_ERR(cmt->clk)) { dev_err(&cmt->pdev->dev, "cannot get clock\n"); return PTR_ERR(cmt->clk); @@ -1016,27 +953,13 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) if (ret < 0) goto err_clk_put; - /* - * Map the memory resource(s). We need to support both the legacy - * platform device configuration (with one device per channel) and the - * new version (with multiple channels per device). - */ - if (cmt->legacy) - ret = sh_cmt_map_memory_legacy(cmt); - else - ret = sh_cmt_map_memory(cmt); - + /* Map the memory resource(s). */ + ret = sh_cmt_map_memory(cmt); if (ret < 0) goto err_clk_unprepare; /* Allocate and setup the channels. */ - if (cmt->legacy) { - cmt->num_channels = 1; - hw_channels = 0; - } else { - cmt->num_channels = hweight8(cfg->channels_mask); - hw_channels = cfg->channels_mask; - } + cmt->num_channels = hweight8(cfg->channels_mask); cmt->channels = kzalloc(cmt->num_channels * sizeof(*cmt->channels), GFP_KERNEL); @@ -1045,35 +968,21 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) goto err_unmap; } - if (cmt->legacy) { - ret = sh_cmt_setup_channel(&cmt->channels[0], - cfg->timer_bit, cfg->timer_bit, - cfg->clockevent_rating != 0, - cfg->clocksource_rating != 0, cmt); + /* + * Use the first channel as a clock event device and the second channel + * as a clock source. If only one channel is available use it for both. + */ + for (i = 0, mask = cfg->channels_mask; i < cmt->num_channels; ++i) { + unsigned int hwidx = ffs(mask) - 1; + bool clocksource = i == 1 || cmt->num_channels == 1; + bool clockevent = i == 0; + + ret = sh_cmt_setup_channel(&cmt->channels[i], i, hwidx, + clockevent, clocksource, cmt); if (ret < 0) goto err_unmap; - } else { - unsigned int mask = hw_channels; - unsigned int i; - /* - * Use the first channel as a clock event device and the second - * channel as a clock source. If only one channel is available - * use it for both. - */ - for (i = 0; i < cmt->num_channels; ++i) { - unsigned int hwidx = ffs(mask) - 1; - bool clocksource = i == 1 || cmt->num_channels == 1; - bool clockevent = i == 0; - - ret = sh_cmt_setup_channel(&cmt->channels[i], i, hwidx, - clockevent, clocksource, - cmt); - if (ret < 0) - goto err_unmap; - - mask &= ~(1 << hwidx); - } + mask &= ~(1 << hwidx); } platform_set_drvdata(pdev, cmt); @@ -1082,7 +991,7 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) err_unmap: kfree(cmt->channels); - sh_cmt_unmap_memory(cmt); + iounmap(cmt->mapbase); err_clk_unprepare: clk_unprepare(cmt->clk); err_clk_put: @@ -1133,7 +1042,6 @@ static int sh_cmt_remove(struct platform_device *pdev) } static const struct platform_device_id sh_cmt_id_table[] = { - { "sh_cmt", 0 }, { "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] }, { "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] }, { "sh-cmt-32-fast", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT_FAST] }, -- cgit From de599c8843ebbdfc29a119c94af481b1de76700e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 17 Feb 2014 16:49:05 +0100 Subject: clocksource: sh_cmt: Replace global spinlock with a per-device spinlock The global spinlock is used to protect the shared start/stop register. Now that all CMT channels are handled by a single device instance, use a per-device spinlock. Signed-off-by: Laurent Pinchart Tested-by: Simon Horman --- drivers/clocksource/sh_cmt.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index fcd38db9ce5c..190c655d8352 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -118,6 +118,8 @@ struct sh_cmt_device { void __iomem *mapbase; struct clk *clk; + raw_spinlock_t lock; /* Protect the shared start/stop register */ + struct sh_cmt_channel *channels; unsigned int num_channels; @@ -299,14 +301,12 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch, return v2; } -static DEFINE_RAW_SPINLOCK(sh_cmt_lock); - static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start) { unsigned long flags, value; /* start stop register shared by multiple timer channels */ - raw_spin_lock_irqsave(&sh_cmt_lock, flags); + raw_spin_lock_irqsave(&ch->cmt->lock, flags); value = sh_cmt_read_cmstr(ch); if (start) @@ -315,7 +315,7 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start) value &= ~(1 << ch->timer_bit); sh_cmt_write_cmstr(ch, value); - raw_spin_unlock_irqrestore(&sh_cmt_lock, flags); + raw_spin_unlock_irqrestore(&ch->cmt->lock, flags); } static int sh_cmt_enable(struct sh_cmt_channel *ch, unsigned long *rate) @@ -934,6 +934,7 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) memset(cmt, 0, sizeof(*cmt)); cmt->pdev = pdev; + raw_spin_lock_init(&cmt->lock); if (!cfg) { dev_err(&cmt->pdev->dev, "missing platform data\n"); -- cgit From 681b9e852cf2d48ebd63954028814c7cece71945 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 28 Jan 2014 15:52:46 +0100 Subject: clocksource: sh_tmu: Drop support for legacy platform data Now that all platforms have switched to the new-style platform data, drop support for the legacy version. Signed-off-by: Laurent Pinchart Tested-by: Simon Horman --- drivers/clocksource/sh_tmu.c | 82 ++++++++------------------------------------ 1 file changed, 15 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index 6bd17a8f3dd4..3eee5c8c26aa 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -32,7 +32,6 @@ #include enum sh_tmu_model { - SH_TMU_LEGACY, SH_TMU, SH_TMU_SH3, }; @@ -91,8 +90,6 @@ static inline unsigned long sh_tmu_read(struct sh_tmu_channel *ch, int reg_nr) if (reg_nr == TSTR) { switch (ch->tmu->model) { - case SH_TMU_LEGACY: - return ioread8(ch->tmu->mapbase); case SH_TMU_SH3: return ioread8(ch->tmu->mapbase + 2); case SH_TMU: @@ -115,8 +112,6 @@ static inline void sh_tmu_write(struct sh_tmu_channel *ch, int reg_nr, if (reg_nr == TSTR) { switch (ch->tmu->model) { - case SH_TMU_LEGACY: - return iowrite8(value, ch->tmu->mapbase); case SH_TMU_SH3: return iowrite8(value, ch->tmu->mapbase + 2); case SH_TMU: @@ -476,27 +471,12 @@ static int sh_tmu_channel_setup(struct sh_tmu_channel *ch, unsigned int index, return 0; ch->tmu = tmu; + ch->index = index; - if (tmu->model == SH_TMU_LEGACY) { - struct sh_timer_config *cfg = tmu->pdev->dev.platform_data; - - /* - * The SH3 variant (SH770x, SH7705, SH7710 and SH7720) maps - * channel registers blocks at base + 2 + 12 * index, while all - * other variants map them at base + 4 + 12 * index. We can - * compute the index by just dividing by 12, the 2 bytes or 4 - * bytes offset being hidden by the integer division. - */ - ch->index = cfg->channel_offset / 12; - ch->base = tmu->mapbase + cfg->channel_offset; - } else { - ch->index = index; - - if (tmu->model == SH_TMU_SH3) - ch->base = tmu->mapbase + 4 + ch->index * 12; - else - ch->base = tmu->mapbase + 8 + ch->index * 12; - } + if (tmu->model == SH_TMU_SH3) + ch->base = tmu->mapbase + 4 + ch->index * 12; + else + ch->base = tmu->mapbase + 8 + ch->index * 12; ch->irq = platform_get_irq(tmu->pdev, index); if (ch->irq < 0) { @@ -526,28 +506,9 @@ static int sh_tmu_map_memory(struct sh_tmu_device *tmu) if (tmu->mapbase == NULL) return -ENXIO; - /* - * In legacy platform device configuration (with one device per channel) - * the resource points to the channel base address. - */ - if (tmu->model == SH_TMU_LEGACY) { - struct sh_timer_config *cfg = tmu->pdev->dev.platform_data; - tmu->mapbase -= cfg->channel_offset; - } - return 0; } -static void sh_tmu_unmap_memory(struct sh_tmu_device *tmu) -{ - if (tmu->model == SH_TMU_LEGACY) { - struct sh_timer_config *cfg = tmu->pdev->dev.platform_data; - tmu->mapbase += cfg->channel_offset; - } - - iounmap(tmu->mapbase); -} - static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) { struct sh_timer_config *cfg = pdev->dev.platform_data; @@ -564,8 +525,7 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) tmu->model = id->driver_data; /* Get hold of clock. */ - tmu->clk = clk_get(&tmu->pdev->dev, - tmu->model == SH_TMU_LEGACY ? "tmu_fck" : "fck"); + tmu->clk = clk_get(&tmu->pdev->dev, "fck"); if (IS_ERR(tmu->clk)) { dev_err(&tmu->pdev->dev, "cannot get clock\n"); return PTR_ERR(tmu->clk); @@ -583,10 +543,7 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) } /* Allocate and setup the channels. */ - if (tmu->model == SH_TMU_LEGACY) - tmu->num_channels = 1; - else - tmu->num_channels = hweight8(cfg->channels_mask); + tmu->num_channels = hweight8(cfg->channels_mask); tmu->channels = kzalloc(sizeof(*tmu->channels) * tmu->num_channels, GFP_KERNEL); @@ -595,23 +552,15 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) goto err_unmap; } - if (tmu->model == SH_TMU_LEGACY) { - ret = sh_tmu_channel_setup(&tmu->channels[0], 0, - cfg->clockevent_rating != 0, - cfg->clocksource_rating != 0, tmu); + /* + * Use the first channel as a clock event device and the second channel + * as a clock source. + */ + for (i = 0; i < tmu->num_channels; ++i) { + ret = sh_tmu_channel_setup(&tmu->channels[i], i, + i == 0, i == 1, tmu); if (ret < 0) goto err_unmap; - } else { - /* - * Use the first channel as a clock event device and the second - * channel as a clock source. - */ - for (i = 0; i < tmu->num_channels; ++i) { - ret = sh_tmu_channel_setup(&tmu->channels[i], i, - i == 0, i == 1, tmu); - if (ret < 0) - goto err_unmap; - } } platform_set_drvdata(pdev, tmu); @@ -620,7 +569,7 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) err_unmap: kfree(tmu->channels); - sh_tmu_unmap_memory(tmu); + iounmap(tmu->mapbase); err_clk_unprepare: clk_unprepare(tmu->clk); err_clk_put: @@ -671,7 +620,6 @@ static int sh_tmu_remove(struct platform_device *pdev) } static const struct platform_device_id sh_tmu_id_table[] = { - { "sh_tmu", SH_TMU_LEGACY }, { "sh-tmu", SH_TMU }, { "sh-tmu-sh3", SH_TMU_SH3 }, { } -- cgit From 2b027f1f0f887097b4140a71b5c1e878da1e2fd9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 17 Feb 2014 16:49:05 +0100 Subject: clocksource: sh_tmu: Replace global spinlock with a per-device spinlock The global spinlock is used to protect the shared start/stop register. Now that all TMU channels are handled by a single device instance, use a per-device spinlock. Signed-off-by: Laurent Pinchart Tested-by: Simon Horman --- drivers/clocksource/sh_tmu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index 3eee5c8c26aa..560a31acbc9c 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -61,6 +61,8 @@ struct sh_tmu_device { enum sh_tmu_model model; + raw_spinlock_t lock; /* Protect the shared start/stop register */ + struct sh_tmu_channel *channels; unsigned int num_channels; @@ -68,8 +70,6 @@ struct sh_tmu_device { bool has_clocksource; }; -static DEFINE_RAW_SPINLOCK(sh_tmu_lock); - #define TSTR -1 /* shared register */ #define TCOR 0 /* channel register */ #define TCNT 1 /* channel register */ @@ -132,7 +132,7 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_channel *ch, int start) unsigned long flags, value; /* start stop register shared by multiple timer channels */ - raw_spin_lock_irqsave(&sh_tmu_lock, flags); + raw_spin_lock_irqsave(&ch->tmu->lock, flags); value = sh_tmu_read(ch, TSTR); if (start) @@ -141,7 +141,7 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_channel *ch, int start) value &= ~(1 << ch->index); sh_tmu_write(ch, TSTR, value); - raw_spin_unlock_irqrestore(&sh_tmu_lock, flags); + raw_spin_unlock_irqrestore(&ch->tmu->lock, flags); } static int __sh_tmu_enable(struct sh_tmu_channel *ch) @@ -524,6 +524,8 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) tmu->pdev = pdev; tmu->model = id->driver_data; + raw_spin_lock_init(&tmu->lock); + /* Get hold of clock. */ tmu->clk = clk_get(&tmu->pdev->dev, "fck"); if (IS_ERR(tmu->clk)) { -- cgit From 1a5da0e43be0c07462e445549dbdd4a1731a3e11 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 4 Mar 2014 18:13:57 +0100 Subject: clocksource: sh_mtu2: Drop support for legacy platform data Now that all platforms have switched to the new-style platform data, drop support for the legacy version. Signed-off-by: Laurent Pinchart Tested-by: Wolfram Sang --- drivers/clocksource/sh_mtu2.c | 130 ++++++++++-------------------------------- 1 file changed, 31 insertions(+), 99 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index 188d4e092efc..0342e4a01c9e 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c @@ -37,7 +37,6 @@ struct sh_mtu2_channel { unsigned int index; void __iomem *base; - int irq; struct clock_event_device ced; }; @@ -51,7 +50,6 @@ struct sh_mtu2_device { struct sh_mtu2_channel *channels; unsigned int num_channels; - bool legacy; bool has_clockevent; }; @@ -162,12 +160,8 @@ static inline unsigned long sh_mtu2_read(struct sh_mtu2_channel *ch, int reg_nr) { unsigned long offs; - if (reg_nr == TSTR) { - if (ch->mtu->legacy) - return ioread8(ch->mtu->mapbase); - else - return ioread8(ch->mtu->mapbase + 0x280); - } + if (reg_nr == TSTR) + return ioread8(ch->mtu->mapbase + 0x280); offs = mtu2_reg_offs[reg_nr]; @@ -182,12 +176,8 @@ static inline void sh_mtu2_write(struct sh_mtu2_channel *ch, int reg_nr, { unsigned long offs; - if (reg_nr == TSTR) { - if (ch->mtu->legacy) - return iowrite8(value, ch->mtu->mapbase); - else - return iowrite8(value, ch->mtu->mapbase + 0x280); - } + if (reg_nr == TSTR) + return iowrite8(value, ch->mtu->mapbase + 0x280); offs = mtu2_reg_offs[reg_nr]; @@ -331,7 +321,6 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch, const char *name) { struct clock_event_device *ced = &ch->ced; - int ret; ced->name = name; ced->features = CLOCK_EVT_FEAT_PERIODIC; @@ -344,24 +333,12 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch, dev_info(&ch->mtu->pdev->dev, "ch%u: used for clock events\n", ch->index); clockevents_register_device(ced); - - ret = request_irq(ch->irq, sh_mtu2_interrupt, - IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, - dev_name(&ch->mtu->pdev->dev), ch); - if (ret) { - dev_err(&ch->mtu->pdev->dev, "ch%u: failed to request irq %d\n", - ch->index, ch->irq); - return; - } } -static int sh_mtu2_register(struct sh_mtu2_channel *ch, const char *name, - bool clockevent) +static int sh_mtu2_register(struct sh_mtu2_channel *ch, const char *name) { - if (clockevent) { - ch->mtu->has_clockevent = true; - sh_mtu2_register_clockevent(ch, name); - } + ch->mtu->has_clockevent = true; + sh_mtu2_register_clockevent(ch, name); return 0; } @@ -372,40 +349,32 @@ static int sh_mtu2_setup_channel(struct sh_mtu2_channel *ch, unsigned int index, static const unsigned int channel_offsets[] = { 0x300, 0x380, 0x000, }; - bool clockevent; + char name[6]; + int irq; + int ret; ch->mtu = mtu; - if (mtu->legacy) { - struct sh_timer_config *cfg = mtu->pdev->dev.platform_data; - - clockevent = cfg->clockevent_rating != 0; - - ch->irq = platform_get_irq(mtu->pdev, 0); - ch->base = mtu->mapbase - cfg->channel_offset; - ch->index = cfg->timer_bit; - } else { - char name[6]; - - clockevent = true; - - sprintf(name, "tgi%ua", index); - ch->irq = platform_get_irq_byname(mtu->pdev, name); - ch->base = mtu->mapbase + channel_offsets[index]; - ch->index = index; - } - - if (ch->irq < 0) { + sprintf(name, "tgi%ua", index); + irq = platform_get_irq_byname(mtu->pdev, name); + if (irq < 0) { /* Skip channels with no declared interrupt. */ - if (!mtu->legacy) - return 0; + return 0; + } - dev_err(&mtu->pdev->dev, "ch%u: failed to get irq\n", - ch->index); - return ch->irq; + ret = request_irq(irq, sh_mtu2_interrupt, + IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, + dev_name(&ch->mtu->pdev->dev), ch); + if (ret) { + dev_err(&ch->mtu->pdev->dev, "ch%u: failed to request irq %d\n", + index, irq); + return ret; } - return sh_mtu2_register(ch, dev_name(&mtu->pdev->dev), clockevent); + ch->base = mtu->mapbase + channel_offsets[index]; + ch->index = index; + + return sh_mtu2_register(ch, dev_name(&mtu->pdev->dev)); } static int sh_mtu2_map_memory(struct sh_mtu2_device *mtu) @@ -422,46 +391,19 @@ static int sh_mtu2_map_memory(struct sh_mtu2_device *mtu) if (mtu->mapbase == NULL) return -ENXIO; - /* - * In legacy platform device configuration (with one device per channel) - * the resource points to the channel base address. - */ - if (mtu->legacy) { - struct sh_timer_config *cfg = mtu->pdev->dev.platform_data; - mtu->mapbase += cfg->channel_offset; - } - return 0; } -static void sh_mtu2_unmap_memory(struct sh_mtu2_device *mtu) -{ - if (mtu->legacy) { - struct sh_timer_config *cfg = mtu->pdev->dev.platform_data; - mtu->mapbase -= cfg->channel_offset; - } - - iounmap(mtu->mapbase); -} - static int sh_mtu2_setup(struct sh_mtu2_device *mtu, struct platform_device *pdev) { - struct sh_timer_config *cfg = pdev->dev.platform_data; - const struct platform_device_id *id = pdev->id_entry; unsigned int i; int ret; mtu->pdev = pdev; - mtu->legacy = id->driver_data; - - if (mtu->legacy && !cfg) { - dev_err(&mtu->pdev->dev, "missing platform data\n"); - return -ENXIO; - } /* Get hold of clock. */ - mtu->clk = clk_get(&mtu->pdev->dev, mtu->legacy ? "mtu2_fck" : "fck"); + mtu->clk = clk_get(&mtu->pdev->dev, "fck"); if (IS_ERR(mtu->clk)) { dev_err(&mtu->pdev->dev, "cannot get clock\n"); return PTR_ERR(mtu->clk); @@ -479,10 +421,7 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu, } /* Allocate and setup the channels. */ - if (mtu->legacy) - mtu->num_channels = 1; - else - mtu->num_channels = 3; + mtu->num_channels = 3; mtu->channels = kzalloc(sizeof(*mtu->channels) * mtu->num_channels, GFP_KERNEL); @@ -491,16 +430,10 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu, goto err_unmap; } - if (mtu->legacy) { - ret = sh_mtu2_setup_channel(&mtu->channels[0], 0, mtu); + for (i = 0; i < mtu->num_channels; ++i) { + ret = sh_mtu2_setup_channel(&mtu->channels[i], i, mtu); if (ret < 0) goto err_unmap; - } else { - for (i = 0; i < mtu->num_channels; ++i) { - ret = sh_mtu2_setup_channel(&mtu->channels[i], i, mtu); - if (ret < 0) - goto err_unmap; - } } platform_set_drvdata(pdev, mtu); @@ -509,7 +442,7 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu, err_unmap: kfree(mtu->channels); - sh_mtu2_unmap_memory(mtu); + iounmap(mtu->mapbase); err_clk_unprepare: clk_unprepare(mtu->clk); err_clk_put: @@ -560,7 +493,6 @@ static int sh_mtu2_remove(struct platform_device *pdev) } static const struct platform_device_id sh_mtu2_id_table[] = { - { "sh_mtu2", 1 }, { "sh-mtu2", 0 }, { }, }; -- cgit From 8b2463d8cae2dda0c98ab5a15f25a0350a0e998d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 4 Mar 2014 15:25:56 +0100 Subject: clocksource: sh_mtu2: Replace global spinlock with a per-device spinlock The global spinlock is used to protect the shared start/stop register. Now that all MTU2 channels are handled by a single device instance, use a per-device spinlock. Signed-off-by: Laurent Pinchart Tested-by: Wolfram Sang --- drivers/clocksource/sh_mtu2.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index 0342e4a01c9e..b0c229f4b4c6 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c @@ -47,14 +47,14 @@ struct sh_mtu2_device { void __iomem *mapbase; struct clk *clk; + raw_spinlock_t lock; /* Protect the shared registers */ + struct sh_mtu2_channel *channels; unsigned int num_channels; bool has_clockevent; }; -static DEFINE_RAW_SPINLOCK(sh_mtu2_lock); - #define TSTR -1 /* shared register */ #define TCR 0 /* channel register */ #define TMDR 1 /* channel register */ @@ -192,7 +192,7 @@ static void sh_mtu2_start_stop_ch(struct sh_mtu2_channel *ch, int start) unsigned long flags, value; /* start stop register shared by multiple timer channels */ - raw_spin_lock_irqsave(&sh_mtu2_lock, flags); + raw_spin_lock_irqsave(&ch->mtu->lock, flags); value = sh_mtu2_read(ch, TSTR); if (start) @@ -201,7 +201,7 @@ static void sh_mtu2_start_stop_ch(struct sh_mtu2_channel *ch, int start) value &= ~(1 << ch->index); sh_mtu2_write(ch, TSTR, value); - raw_spin_unlock_irqrestore(&sh_mtu2_lock, flags); + raw_spin_unlock_irqrestore(&ch->mtu->lock, flags); } static int sh_mtu2_enable(struct sh_mtu2_channel *ch) @@ -402,6 +402,8 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu, mtu->pdev = pdev; + raw_spin_lock_init(&mtu->lock); + /* Get hold of clock. */ mtu->clk = clk_get(&mtu->pdev->dev, "fck"); if (IS_ERR(mtu->clk)) { -- cgit From 1768aa2f4c1248051013282c6cf63b368016cb53 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 12 Feb 2014 17:12:40 +0100 Subject: clocksource: sh_cmt: Add DT support Document DT bindings and parse them in the CMT driver. Signed-off-by: Laurent Pinchart Tested-by: Simon Horman --- drivers/clocksource/sh_cmt.c | 66 ++++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 190c655d8352..2bd13b53b727 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -122,6 +123,7 @@ struct sh_cmt_device { struct sh_cmt_channel *channels; unsigned int num_channels; + unsigned int hw_channels; bool has_clockevent; bool has_clocksource; @@ -924,10 +926,35 @@ static int sh_cmt_map_memory(struct sh_cmt_device *cmt) return 0; } +static const struct platform_device_id sh_cmt_id_table[] = { + { "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] }, + { "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] }, + { "sh-cmt-32-fast", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT_FAST] }, + { "sh-cmt-48", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT] }, + { "sh-cmt-48-gen2", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT_GEN2] }, + { } +}; +MODULE_DEVICE_TABLE(platform, sh_cmt_id_table); + +static const struct of_device_id sh_cmt_of_table[] __maybe_unused = { + { .compatible = "renesas,cmt-32", .data = &sh_cmt_info[SH_CMT_32BIT] }, + { .compatible = "renesas,cmt-32-fast", .data = &sh_cmt_info[SH_CMT_32BIT_FAST] }, + { .compatible = "renesas,cmt-48", .data = &sh_cmt_info[SH_CMT_48BIT] }, + { .compatible = "renesas,cmt-48-gen2", .data = &sh_cmt_info[SH_CMT_48BIT_GEN2] }, + { } +}; +MODULE_DEVICE_TABLE(of, sh_cmt_of_table); + +static int sh_cmt_parse_dt(struct sh_cmt_device *cmt) +{ + struct device_node *np = cmt->pdev->dev.of_node; + + return of_property_read_u32(np, "renesas,channels-mask", + &cmt->hw_channels); +} + static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) { - struct sh_timer_config *cfg = pdev->dev.platform_data; - const struct platform_device_id *id = pdev->id_entry; unsigned int mask; unsigned int i; int ret; @@ -936,13 +963,26 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) cmt->pdev = pdev; raw_spin_lock_init(&cmt->lock); - if (!cfg) { + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { + const struct of_device_id *id; + + id = of_match_node(sh_cmt_of_table, pdev->dev.of_node); + cmt->info = id->data; + + ret = sh_cmt_parse_dt(cmt); + if (ret < 0) + return ret; + } else if (pdev->dev.platform_data) { + struct sh_timer_config *cfg = pdev->dev.platform_data; + const struct platform_device_id *id = pdev->id_entry; + + cmt->info = (const struct sh_cmt_info *)id->driver_data; + cmt->hw_channels = cfg->channels_mask; + } else { dev_err(&cmt->pdev->dev, "missing platform data\n"); return -ENXIO; } - cmt->info = (const struct sh_cmt_info *)id->driver_data; - /* Get hold of clock. */ cmt->clk = clk_get(&cmt->pdev->dev, "fck"); if (IS_ERR(cmt->clk)) { @@ -960,8 +1000,7 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) goto err_clk_unprepare; /* Allocate and setup the channels. */ - cmt->num_channels = hweight8(cfg->channels_mask); - + cmt->num_channels = hweight8(cmt->hw_channels); cmt->channels = kzalloc(cmt->num_channels * sizeof(*cmt->channels), GFP_KERNEL); if (cmt->channels == NULL) { @@ -973,7 +1012,7 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) * Use the first channel as a clock event device and the second channel * as a clock source. If only one channel is available use it for both. */ - for (i = 0, mask = cfg->channels_mask; i < cmt->num_channels; ++i) { + for (i = 0, mask = cmt->hw_channels; i < cmt->num_channels; ++i) { unsigned int hwidx = ffs(mask) - 1; bool clocksource = i == 1 || cmt->num_channels == 1; bool clockevent = i == 0; @@ -1042,21 +1081,12 @@ static int sh_cmt_remove(struct platform_device *pdev) return -EBUSY; /* cannot unregister clockevent and clocksource */ } -static const struct platform_device_id sh_cmt_id_table[] = { - { "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] }, - { "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] }, - { "sh-cmt-32-fast", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT_FAST] }, - { "sh-cmt-48", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT] }, - { "sh-cmt-48-gen2", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT_GEN2] }, - { } -}; -MODULE_DEVICE_TABLE(platform, sh_cmt_id_table); - static struct platform_driver sh_cmt_device_driver = { .probe = sh_cmt_probe, .remove = sh_cmt_remove, .driver = { .name = "sh_cmt", + .of_match_table = of_match_ptr(sh_cmt_of_table), }, .id_table = sh_cmt_id_table, }; -- cgit From 3e29b5543f9250bb358169cff0594f58284ece74 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 11 Apr 2014 16:23:40 +0200 Subject: clocksource: sh_tmu: Add DT support Document DT bindings and parse them in the TMU driver. Signed-off-by: Laurent Pinchart Tested-by: Simon Horman --- drivers/clocksource/sh_tmu.c | 51 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index 560a31acbc9c..0f665b8f2461 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -509,23 +510,48 @@ static int sh_tmu_map_memory(struct sh_tmu_device *tmu) return 0; } +static int sh_tmu_parse_dt(struct sh_tmu_device *tmu) +{ + struct device_node *np = tmu->pdev->dev.of_node; + + tmu->model = SH_TMU; + tmu->num_channels = 3; + + of_property_read_u32(np, "#renesas,channels", &tmu->num_channels); + + if (tmu->num_channels != 2 && tmu->num_channels != 3) { + dev_err(&tmu->pdev->dev, "invalid number of channels %u\n", + tmu->num_channels); + return -EINVAL; + } + + return 0; +} + static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) { - struct sh_timer_config *cfg = pdev->dev.platform_data; - const struct platform_device_id *id = pdev->id_entry; unsigned int i; int ret; - if (!cfg) { - dev_err(&tmu->pdev->dev, "missing platform data\n"); - return -ENXIO; - } - tmu->pdev = pdev; - tmu->model = id->driver_data; raw_spin_lock_init(&tmu->lock); + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { + ret = sh_tmu_parse_dt(tmu); + if (ret < 0) + return ret; + } else if (pdev->dev.platform_data) { + const struct platform_device_id *id = pdev->id_entry; + struct sh_timer_config *cfg = pdev->dev.platform_data; + + tmu->model = id->driver_data; + tmu->num_channels = hweight8(cfg->channels_mask); + } else { + dev_err(&tmu->pdev->dev, "missing platform data\n"); + return -ENXIO; + } + /* Get hold of clock. */ tmu->clk = clk_get(&tmu->pdev->dev, "fck"); if (IS_ERR(tmu->clk)) { @@ -545,8 +571,6 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) } /* Allocate and setup the channels. */ - tmu->num_channels = hweight8(cfg->channels_mask); - tmu->channels = kzalloc(sizeof(*tmu->channels) * tmu->num_channels, GFP_KERNEL); if (tmu->channels == NULL) { @@ -628,11 +652,18 @@ static const struct platform_device_id sh_tmu_id_table[] = { }; MODULE_DEVICE_TABLE(platform, sh_tmu_id_table); +static const struct of_device_id sh_tmu_of_table[] __maybe_unused = { + { .compatible = "renesas,tmu" }, + { } +}; +MODULE_DEVICE_TABLE(of, sh_tmu_of_table); + static struct platform_driver sh_tmu_device_driver = { .probe = sh_tmu_probe, .remove = sh_tmu_remove, .driver = { .name = "sh_tmu", + .of_match_table = of_match_ptr(sh_tmu_of_table), }, .id_table = sh_tmu_id_table, }; -- cgit From cca8d0596c4c7acb371ea1bc5eee9b404b30516a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 4 Mar 2014 18:28:26 +0100 Subject: clocksource: sh_mtu2: Add DT support Document DT bindings and parse them in the MTU2 driver. Signed-off-by: Laurent Pinchart Tested-by: Wolfram Sang --- drivers/clocksource/sh_mtu2.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index b0c229f4b4c6..3d88698cf2b8 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -500,11 +501,18 @@ static const struct platform_device_id sh_mtu2_id_table[] = { }; MODULE_DEVICE_TABLE(platform, sh_mtu2_id_table); +static const struct of_device_id sh_mtu2_of_table[] __maybe_unused = { + { .compatible = "renesas,mtu2" }, + { } +}; +MODULE_DEVICE_TABLE(of, sh_mtu2_of_table); + static struct platform_driver sh_mtu2_device_driver = { .probe = sh_mtu2_probe, .remove = sh_mtu2_remove, .driver = { .name = "sh_mtu2", + .of_match_table = of_match_ptr(sh_mtu2_of_table), }, .id_table = sh_mtu2_id_table, }; -- cgit From 7e1391876c8f95df9241deb78fa98e799e7bb05e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 18 Jul 2014 11:36:36 +0200 Subject: clocksource: sh_mtu2: Tidy up Kconfig typo for MTU2 It should be "MTU2" instead of "TMU2" Signed-off-by: Kuninori Morimoto Acked-by: Wolfram Sang Acked-by: Simon Horman Signed-off-by: Daniel Lezcano --- drivers/clocksource/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 6a1151840510..b17c9098ba36 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -175,7 +175,7 @@ config SH_TIMER_MTU2 default SYS_SUPPORTS_SH_MTU2 help This enables build of a clockevent driver for the Multi-Function - Timer Pulse Unit 2 (TMU2) hardware available on SoCs from Renesas. + Timer Pulse Unit 2 (MTU2) hardware available on SoCs from Renesas. This hardware comes with 16 bit-timer registers. config SH_TIMER_TMU -- cgit From efd342fb0031a17758571dce42e3f373d94e2fec Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Fri, 18 Jul 2014 11:36:39 +0200 Subject: of: Provide a function to request and map memory A call to of_iomap does not request the memory region. This patch adds the function of_io_request_and_map which requests the memory region before mapping it. Signed-off-by: Matthias Brugger Suggested-by: Thomas Gleixner Suggested-by: Rob Herring Acked-by: Rob Herring Signed-off-by: Daniel Lezcano --- drivers/of/address.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'drivers') diff --git a/drivers/of/address.c b/drivers/of/address.c index 5edfcb0da37d..e3718250d66e 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -702,6 +702,42 @@ void __iomem *of_iomap(struct device_node *np, int index) } EXPORT_SYMBOL(of_iomap); +/* + * of_io_request_and_map - Requests a resource and maps the memory mapped IO + * for a given device_node + * @device: the device whose io range will be mapped + * @index: index of the io range + * @name: name of the resource + * + * Returns a pointer to the requested and mapped memory or an ERR_PTR() encoded + * error code on failure. Usage example: + * + * base = of_io_request_and_map(node, 0, "foo"); + * if (IS_ERR(base)) + * return PTR_ERR(base); + */ +void __iomem *of_io_request_and_map(struct device_node *np, int index, + char *name) +{ + struct resource res; + void __iomem *mem; + + if (of_address_to_resource(np, index, &res)) + return IOMEM_ERR_PTR(-EINVAL); + + if (!request_mem_region(res.start, resource_size(&res), name)) + return IOMEM_ERR_PTR(-EBUSY); + + mem = ioremap(res.start, resource_size(&res)); + if (!mem) { + release_mem_region(res.start, resource_size(&res)); + return IOMEM_ERR_PTR(-ENOMEM); + } + + return mem; +} +EXPORT_SYMBOL(of_io_request_and_map); + /** * of_dma_get_range - Get DMA range info * @np: device node to get DMA range info -- cgit From ecb3530dd59ddd5158bcc507d634e698130fd937 Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Fri, 18 Jul 2014 11:36:43 +0200 Subject: clocksource: Add support for the Mediatek SoCs This patch adds a clock source and clock event for the timer found on the Mediatek SoCs. The Mediatek General Purpose Timer block provides five 32 bit timers and one 64 bit timer. Two 32 bit timers are used by this driver: TIMER1: clock events supporting periodic and oneshot events TIMER2: clock source configured as a free running counter The General Purpose Timer block can be run with two clocks. A 13 MHz system clock and the RTC clock running at 32 KHz. This implementation uses the system clock with no clock source divider. The interrupts are shared between the different timers and have to be read back from a register. We just enable one interrupt for the clock event. The clock event timer is used by all cores. Signed-off-by: Matthias Brugger Acked-by: Thomas Gleixner Signed-off-by: Daniel Lezcano --- drivers/clocksource/Kconfig | 5 + drivers/clocksource/Makefile | 1 + drivers/clocksource/mtk_timer.c | 261 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 drivers/clocksource/mtk_timer.c (limited to 'drivers') diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index b17c9098ba36..497356d4dc70 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -151,6 +151,11 @@ config VF_PIT_TIMER config SYS_SUPPORTS_SH_CMT bool +config MTK_TIMER + select CLKSRC_OF + select CLKSRC_MMIO + bool + config SYS_SUPPORTS_SH_MTU2 bool diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 800b1303c236..da1ac09dc771 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o +obj-$(CONFIG_MTK_TIMER) += mtk_timer.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o diff --git a/drivers/clocksource/mtk_timer.c b/drivers/clocksource/mtk_timer.c new file mode 100644 index 000000000000..32a3d25795d3 --- /dev/null +++ b/drivers/clocksource/mtk_timer.c @@ -0,0 +1,261 @@ +/* + * Mediatek SoCs General-Purpose Timer handling. + * + * Copyright (C) 2014 Matthias Brugger + * + * Matthias Brugger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPT_IRQ_EN_REG 0x00 +#define GPT_IRQ_ENABLE(val) BIT((val) - 1) +#define GPT_IRQ_ACK_REG 0x08 +#define GPT_IRQ_ACK(val) BIT((val) - 1) + +#define TIMER_CTRL_REG(val) (0x10 * (val)) +#define TIMER_CTRL_OP(val) (((val) & 0x3) << 4) +#define TIMER_CTRL_OP_ONESHOT (0) +#define TIMER_CTRL_OP_REPEAT (1) +#define TIMER_CTRL_OP_FREERUN (3) +#define TIMER_CTRL_CLEAR (2) +#define TIMER_CTRL_ENABLE (1) +#define TIMER_CTRL_DISABLE (0) + +#define TIMER_CLK_REG(val) (0x04 + (0x10 * (val))) +#define TIMER_CLK_SRC(val) (((val) & 0x1) << 4) +#define TIMER_CLK_SRC_SYS13M (0) +#define TIMER_CLK_SRC_RTC32K (1) +#define TIMER_CLK_DIV1 (0x0) +#define TIMER_CLK_DIV2 (0x1) + +#define TIMER_CNT_REG(val) (0x08 + (0x10 * (val))) +#define TIMER_CMP_REG(val) (0x0C + (0x10 * (val))) + +#define GPT_CLK_EVT 1 +#define GPT_CLK_SRC 2 + +struct mtk_clock_event_device { + void __iomem *gpt_base; + u32 ticks_per_jiffy; + struct clock_event_device dev; +}; + +static inline struct mtk_clock_event_device *to_mtk_clk( + struct clock_event_device *c) +{ + return container_of(c, struct mtk_clock_event_device, dev); +} + +static void mtk_clkevt_time_stop(struct mtk_clock_event_device *evt, u8 timer) +{ + u32 val; + + val = readl(evt->gpt_base + TIMER_CTRL_REG(timer)); + writel(val & ~TIMER_CTRL_ENABLE, evt->gpt_base + + TIMER_CTRL_REG(timer)); +} + +static void mtk_clkevt_time_setup(struct mtk_clock_event_device *evt, + unsigned long delay, u8 timer) +{ + writel(delay, evt->gpt_base + TIMER_CMP_REG(timer)); +} + +static void mtk_clkevt_time_start(struct mtk_clock_event_device *evt, + bool periodic, u8 timer) +{ + u32 val; + + /* Acknowledge interrupt */ + writel(GPT_IRQ_ACK(timer), evt->gpt_base + GPT_IRQ_ACK_REG); + + val = readl(evt->gpt_base + TIMER_CTRL_REG(timer)); + + /* Clear 2 bit timer operation mode field */ + val &= ~TIMER_CTRL_OP(0x3); + + if (periodic) + val |= TIMER_CTRL_OP(TIMER_CTRL_OP_REPEAT); + else + val |= TIMER_CTRL_OP(TIMER_CTRL_OP_ONESHOT); + + writel(val | TIMER_CTRL_ENABLE | TIMER_CTRL_CLEAR, + evt->gpt_base + TIMER_CTRL_REG(timer)); +} + +static void mtk_clkevt_mode(enum clock_event_mode mode, + struct clock_event_device *clk) +{ + struct mtk_clock_event_device *evt = to_mtk_clk(clk); + + mtk_clkevt_time_stop(evt, GPT_CLK_EVT); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + mtk_clkevt_time_setup(evt, evt->ticks_per_jiffy, GPT_CLK_EVT); + mtk_clkevt_time_start(evt, true, GPT_CLK_EVT); + break; + case CLOCK_EVT_MODE_ONESHOT: + /* Timer is enabled in set_next_event */ + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + /* No more interrupts will occur as source is disabled */ + break; + } +} + +static int mtk_clkevt_next_event(unsigned long event, + struct clock_event_device *clk) +{ + struct mtk_clock_event_device *evt = to_mtk_clk(clk); + + mtk_clkevt_time_stop(evt, GPT_CLK_EVT); + mtk_clkevt_time_setup(evt, event, GPT_CLK_EVT); + mtk_clkevt_time_start(evt, false, GPT_CLK_EVT); + + return 0; +} + +static irqreturn_t mtk_timer_interrupt(int irq, void *dev_id) +{ + struct mtk_clock_event_device *evt = dev_id; + + /* Acknowledge timer0 irq */ + writel(GPT_IRQ_ACK(GPT_CLK_EVT), evt->gpt_base + GPT_IRQ_ACK_REG); + evt->dev.event_handler(&evt->dev); + + return IRQ_HANDLED; +} + +static void mtk_timer_global_reset(struct mtk_clock_event_device *evt) +{ + /* Disable all interrupts */ + writel(0x0, evt->gpt_base + GPT_IRQ_EN_REG); + /* Acknowledge all interrupts */ + writel(0x3f, evt->gpt_base + GPT_IRQ_ACK_REG); +} + +static void +mtk_timer_setup(struct mtk_clock_event_device *evt, u8 timer, u8 option) +{ + writel(TIMER_CTRL_CLEAR | TIMER_CTRL_DISABLE, + evt->gpt_base + TIMER_CTRL_REG(timer)); + + writel(TIMER_CLK_SRC(TIMER_CLK_SRC_SYS13M) | TIMER_CLK_DIV1, + evt->gpt_base + TIMER_CLK_REG(timer)); + + writel(0x0, evt->gpt_base + TIMER_CMP_REG(timer)); + + writel(TIMER_CTRL_OP(option) | TIMER_CTRL_ENABLE, + evt->gpt_base + TIMER_CTRL_REG(timer)); +} + +static void mtk_timer_enable_irq(struct mtk_clock_event_device *evt, u8 timer) +{ + u32 val; + + val = readl(evt->gpt_base + GPT_IRQ_EN_REG); + writel(val | GPT_IRQ_ENABLE(timer), + evt->gpt_base + GPT_IRQ_EN_REG); +} + +static void __init mtk_timer_init(struct device_node *node) +{ + struct mtk_clock_event_device *evt; + struct resource res; + unsigned long rate = 0; + struct clk *clk; + + evt = kzalloc(sizeof(*evt), GFP_KERNEL); + if (!evt) { + pr_warn("Can't allocate mtk clock event driver struct"); + return; + } + + evt->dev.name = "mtk_tick"; + evt->dev.rating = 300; + evt->dev.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; + evt->dev.set_mode = mtk_clkevt_mode; + evt->dev.set_next_event = mtk_clkevt_next_event; + evt->dev.cpumask = cpu_possible_mask; + + evt->gpt_base = of_io_request_and_map(node, 0, "mtk-timer"); + if (IS_ERR(evt->gpt_base)) { + pr_warn("Can't get resource\n"); + return; + } + + evt->dev.irq = irq_of_parse_and_map(node, 0); + if (evt->dev.irq <= 0) { + pr_warn("Can't parse IRQ"); + goto err_mem; + } + + clk = of_clk_get(node, 0); + if (IS_ERR(clk)) { + pr_warn("Can't get timer clock"); + goto err_irq; + } + + if (clk_prepare_enable(clk)) { + pr_warn("Can't prepare clock"); + goto err_clk_put; + } + rate = clk_get_rate(clk); + + if (request_irq(evt->dev.irq, mtk_timer_interrupt, + IRQF_TIMER | IRQF_IRQPOLL, "mtk_timer", evt)) { + pr_warn("failed to setup irq %d\n", evt->dev.irq); + goto err_clk_disable; + } + + evt->ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); + + mtk_timer_global_reset(evt); + + /* Configure clock source */ + mtk_timer_setup(evt, GPT_CLK_SRC, TIMER_CTRL_OP_FREERUN); + clocksource_mmio_init(evt->gpt_base + TIMER_CNT_REG(GPT_CLK_SRC), + node->name, rate, 300, 32, clocksource_mmio_readl_up); + + /* Configure clock event */ + mtk_timer_setup(evt, GPT_CLK_EVT, TIMER_CTRL_OP_REPEAT); + mtk_timer_enable_irq(evt, GPT_CLK_EVT); + + clockevents_config_and_register(&evt->dev, rate, 0x3, + 0xffffffff); + return; + +err_clk_disable: + clk_disable_unprepare(clk); +err_clk_put: + clk_put(clk); +err_irq: + irq_dispose_mapping(evt->dev.irq); +err_mem: + iounmap(evt->gpt_base); + of_address_to_resource(node, 0, &res); + release_mem_region(res.start, resource_size(&res)); +} +CLOCKSOURCE_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init); -- cgit From 40c96312dc3534d97c64d7d69acf1ea14ceff404 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Tue, 8 Jul 2014 20:39:40 +0800 Subject: clocksource: Kconfig: Let EM_TIMER_STI depend on HAS_IOMEM In 'em_sti.c', it will call devm_ioremap_resource() which need HAS_IOMEM. So need let EM_TIMER_STI depend on HAS_IOMEM, too. The related error (with allmodconfig under score): LD init/built-in.o em_sti.c:(.text.em_sti_probe+0x84): undefined reference to `devm_ioremap_resource' make: *** [vmlinux] Error 1 Signed-off-by: Chen Gang Signed-off-by: Daniel Lezcano --- drivers/clocksource/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 497356d4dc70..7ea7d7c48d72 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -194,7 +194,7 @@ config SH_TIMER_TMU config EM_TIMER_STI bool "Renesas STI timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS + depends on GENERIC_CLOCKEVENTS && HAS_IOMEM default SYS_SUPPORTS_EM_STI help This enables build of a clocksource and clockevent driver for -- cgit From 38941522ecbd2198694b742343a67ea128b44913 Mon Sep 17 00:00:00 2001 From: Zhiwu Song Date: Thu, 3 Jul 2014 20:52:51 +0800 Subject: clocksource: sirf: Fix incorrect clock enable counter for timer In the clocksource driver, we didn't explicitly enable the clock. it makes the clk reference counter wrong. We didn't encounter any hang issue because the tick's clock input has been open and is shared by some other hardware components, but if we don't enable those components in kernel, in the stage of disabling unused clk in kernel boot, Linux tick hangs. This patch fixes it. it does an explicit prepare and enable to the clock input, and increases the usage counter of the clk. Signed-off-by: Zhiwu Song Signed-off-by: Barry Song Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-marco.c | 3 +++ drivers/clocksource/timer-prima2.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/clocksource/timer-marco.c b/drivers/clocksource/timer-marco.c index dbd30398222a..330e93064692 100644 --- a/drivers/clocksource/timer-marco.c +++ b/drivers/clocksource/timer-marco.c @@ -260,6 +260,9 @@ static void __init sirfsoc_marco_timer_init(struct device_node *np) clk = of_clk_get(np, 0); BUG_ON(IS_ERR(clk)); + + BUG_ON(clk_prepare_enable(clk)); + rate = clk_get_rate(clk); BUG_ON(rate < MARCO_CLOCK_FREQ); diff --git a/drivers/clocksource/timer-prima2.c b/drivers/clocksource/timer-prima2.c index a722aac7ac02..ce18d570e1cd 100644 --- a/drivers/clocksource/timer-prima2.c +++ b/drivers/clocksource/timer-prima2.c @@ -200,6 +200,9 @@ static void __init sirfsoc_prima2_timer_init(struct device_node *np) clk = of_clk_get(np, 0); BUG_ON(IS_ERR(clk)); + + BUG_ON(clk_prepare_enable(clk)); + rate = clk_get_rate(clk); BUG_ON(rate < PRIMA2_CLOCK_FREQ); -- cgit From f0b7fabec3273c85fa2c4714762177d04f64c08e Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sun, 13 Jul 2014 08:45:13 +0400 Subject: clocksource: clps711x: Add CLPS711X clocksource driver This adds the clocksource driver for Cirrus Logic CLPS711X series SoCs. Designed primarily for migration CLPS711X subarch for multiplatform & DT, for this as the "OF" and "non-OF" calls implemented. Signed-off-by: Alexander Shiyan Acked-by: Arnd Bergmann Signed-off-by: Daniel Lezcano --- drivers/clocksource/Makefile | 1 + drivers/clocksource/clps711x-timer.c | 131 +++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 drivers/clocksource/clps711x-timer.c (limited to 'drivers') diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index da1ac09dc771..e40435d271d8 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o obj-$(CONFIG_ORION_TIMER) += time-orion.o obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o +obj-$(CONFIG_ARCH_CLPS711X) += clps711x-timer.o obj-$(CONFIG_ARCH_MARCO) += timer-marco.o obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o obj-$(CONFIG_ARCH_MXS) += mxs_timer.o diff --git a/drivers/clocksource/clps711x-timer.c b/drivers/clocksource/clps711x-timer.c new file mode 100644 index 000000000000..d83ec1f2fddc --- /dev/null +++ b/drivers/clocksource/clps711x-timer.c @@ -0,0 +1,131 @@ +/* + * Cirrus Logic CLPS711X clocksource driver + * + * Copyright (C) 2014 Alexander Shiyan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + CLPS711X_CLKSRC_CLOCKSOURCE, + CLPS711X_CLKSRC_CLOCKEVENT, +}; + +static void __iomem *tcd; + +static u64 notrace clps711x_sched_clock_read(void) +{ + return ~readw(tcd); +} + +static int __init _clps711x_clksrc_init(struct clk *clock, void __iomem *base) +{ + unsigned long rate; + + if (!base) + return -ENOMEM; + if (IS_ERR(clock)) + return PTR_ERR(clock); + + rate = clk_get_rate(clock); + + tcd = base; + + clocksource_mmio_init(tcd, "clps711x-clocksource", rate, 300, 16, + clocksource_mmio_readw_down); + + sched_clock_register(clps711x_sched_clock_read, 16, rate); + + return 0; +} + +static irqreturn_t clps711x_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static void clps711x_clockevent_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ +} + +static int __init _clps711x_clkevt_init(struct clk *clock, void __iomem *base, + unsigned int irq) +{ + struct clock_event_device *clkevt; + unsigned long rate; + + if (!irq) + return -EINVAL; + if (!base) + return -ENOMEM; + if (IS_ERR(clock)) + return PTR_ERR(clock); + + clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL); + if (!clkevt) + return -ENOMEM; + + rate = clk_get_rate(clock); + + /* Set Timer prescaler */ + writew(DIV_ROUND_CLOSEST(rate, HZ), base); + + clkevt->name = "clps711x-clockevent"; + clkevt->rating = 300; + clkevt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_C3STOP; + clkevt->set_mode = clps711x_clockevent_set_mode; + clkevt->cpumask = cpumask_of(0); + clockevents_config_and_register(clkevt, HZ, 0, 0); + + return request_irq(irq, clps711x_timer_interrupt, IRQF_TIMER, + "clps711x-timer", clkevt); +} + +void __init clps711x_clksrc_init(void __iomem *tc1_base, void __iomem *tc2_base, + unsigned int irq) +{ + struct clk *tc1 = clk_get_sys("clps711x-timer.0", NULL); + struct clk *tc2 = clk_get_sys("clps711x-timer.1", NULL); + + BUG_ON(_clps711x_clksrc_init(tc1, tc1_base)); + BUG_ON(_clps711x_clkevt_init(tc2, tc2_base, irq)); +} + +#ifdef CONFIG_CLKSRC_OF +static void __init clps711x_timer_init(struct device_node *np) +{ + unsigned int irq = irq_of_parse_and_map(np, 0); + struct clk *clock = of_clk_get(np, 0); + void __iomem *base = of_iomap(np, 0); + + switch (of_alias_get_id(np, "timer")) { + case CLPS711X_CLKSRC_CLOCKSOURCE: + BUG_ON(_clps711x_clksrc_init(clock, base)); + break; + case CLPS711X_CLKSRC_CLOCKEVENT: + BUG_ON(_clps711x_clkevt_init(clock, base, irq)); + break; + default: + break; + } +} +CLOCKSOURCE_OF_DECLARE(clps711x, "cirrus,clps711x-timer", clps711x_timer_init); +#endif -- cgit From c5421d7aa40965b9527999e65a78f71aec48f19d Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Mon, 14 Jul 2014 18:52:01 +0200 Subject: clocksource: pxa: Move PXA timer to clocksource framework Move time.c from arch/arm/mach-pxa/time.c to drivers/clocksource/pxa_timer.c. Signed-off-by: Robert Jarzmik Signed-off-by: Daniel Lezcano --- drivers/clocksource/Makefile | 1 + drivers/clocksource/pxa_timer.c | 162 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 drivers/clocksource/pxa_timer.c (limited to 'drivers') diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index e40435d271d8..7fd9fd1dff42 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_ARCH_CLPS711X) += clps711x-timer.o obj-$(CONFIG_ARCH_MARCO) += timer-marco.o obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o obj-$(CONFIG_ARCH_MXS) += mxs_timer.o +obj-$(CONFIG_ARCH_PXA) += pxa_timer.o obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o obj-$(CONFIG_ARCH_U300) += timer-u300.o obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o diff --git a/drivers/clocksource/pxa_timer.c b/drivers/clocksource/pxa_timer.c new file mode 100644 index 000000000000..fca174e3865d --- /dev/null +++ b/drivers/clocksource/pxa_timer.c @@ -0,0 +1,162 @@ +/* + * arch/arm/mach-pxa/time.c + * + * PXA clocksource, clockevents, and OST interrupt handlers. + * Copyright (c) 2007 by Bill Gatliff . + * + * Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001 + * by MontaVista Software, Inc. (Nico, your code rocks!) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * This is PXA's sched_clock implementation. This has a resolution + * of at least 308 ns and a maximum value of 208 days. + * + * The return value is guaranteed to be monotonic in that range as + * long as there is always less than 582 seconds between successive + * calls to sched_clock() which should always be the case in practice. + */ + +static u64 notrace pxa_read_sched_clock(void) +{ + return readl_relaxed(OSCR); +} + + +#define MIN_OSCR_DELTA 16 + +static irqreturn_t +pxa_ost0_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *c = dev_id; + + /* Disarm the compare/match, signal the event. */ + writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER); + writel_relaxed(OSSR_M0, OSSR); + c->event_handler(c); + + return IRQ_HANDLED; +} + +static int +pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev) +{ + unsigned long next, oscr; + + writel_relaxed(readl_relaxed(OIER) | OIER_E0, OIER); + next = readl_relaxed(OSCR) + delta; + writel_relaxed(next, OSMR0); + oscr = readl_relaxed(OSCR); + + return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0; +} + +static void +pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev) +{ + switch (mode) { + case CLOCK_EVT_MODE_ONESHOT: + writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER); + writel_relaxed(OSSR_M0, OSSR); + break; + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + /* initializing, released, or preparing for suspend */ + writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER); + writel_relaxed(OSSR_M0, OSSR); + break; + + case CLOCK_EVT_MODE_RESUME: + case CLOCK_EVT_MODE_PERIODIC: + break; + } +} + +#ifdef CONFIG_PM +static unsigned long osmr[4], oier, oscr; + +static void pxa_timer_suspend(struct clock_event_device *cedev) +{ + osmr[0] = readl_relaxed(OSMR0); + osmr[1] = readl_relaxed(OSMR1); + osmr[2] = readl_relaxed(OSMR2); + osmr[3] = readl_relaxed(OSMR3); + oier = readl_relaxed(OIER); + oscr = readl_relaxed(OSCR); +} + +static void pxa_timer_resume(struct clock_event_device *cedev) +{ + /* + * Ensure that we have at least MIN_OSCR_DELTA between match + * register 0 and the OSCR, to guarantee that we will receive + * the one-shot timer interrupt. We adjust OSMR0 in preference + * to OSCR to guarantee that OSCR is monotonically incrementing. + */ + if (osmr[0] - oscr < MIN_OSCR_DELTA) + osmr[0] += MIN_OSCR_DELTA; + + writel_relaxed(osmr[0], OSMR0); + writel_relaxed(osmr[1], OSMR1); + writel_relaxed(osmr[2], OSMR2); + writel_relaxed(osmr[3], OSMR3); + writel_relaxed(oier, OIER); + writel_relaxed(oscr, OSCR); +} +#else +#define pxa_timer_suspend NULL +#define pxa_timer_resume NULL +#endif + +static struct clock_event_device ckevt_pxa_osmr0 = { + .name = "osmr0", + .features = CLOCK_EVT_FEAT_ONESHOT, + .rating = 200, + .set_next_event = pxa_osmr0_set_next_event, + .set_mode = pxa_osmr0_set_mode, + .suspend = pxa_timer_suspend, + .resume = pxa_timer_resume, +}; + +static struct irqaction pxa_ost0_irq = { + .name = "ost0", + .flags = IRQF_TIMER | IRQF_IRQPOLL, + .handler = pxa_ost0_interrupt, + .dev_id = &ckevt_pxa_osmr0, +}; + +void __init pxa_timer_init(void) +{ + unsigned long clock_tick_rate = get_clock_tick_rate(); + + writel_relaxed(0, OIER); + writel_relaxed(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR); + + sched_clock_register(pxa_read_sched_clock, 32, clock_tick_rate); + + ckevt_pxa_osmr0.cpumask = cpumask_of(0); + + setup_irq(IRQ_OST0, &pxa_ost0_irq); + + clocksource_mmio_init(OSCR, "oscr0", clock_tick_rate, 200, 32, + clocksource_mmio_readl_up); + clockevents_config_and_register(&ckevt_pxa_osmr0, clock_tick_rate, + MIN_OSCR_DELTA * 2, 0x7fffffff); +} -- cgit From ab5354c48d58a6a72e70d37d2032206eba3b1dbb Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Mon, 14 Jul 2014 18:52:02 +0200 Subject: clocksource: pxa: Add device-tree support for PXA timer Add device-tree support to PXA platforms. The driver still needs to maintain backward non device-tree compatibility as well, which implies : - a non device-tree init function - a static registers base address in the driver Signed-off-by: Robert Jarzmik Signed-off-by: Daniel Lezcano --- drivers/clocksource/pxa_timer.c | 137 +++++++++++++++++++++++++++++----------- 1 file changed, 101 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/pxa_timer.c b/drivers/clocksource/pxa_timer.c index fca174e3865d..941f3f344e08 100644 --- a/drivers/clocksource/pxa_timer.c +++ b/drivers/clocksource/pxa_timer.c @@ -15,14 +15,30 @@ #include #include #include +#include #include +#include +#include #include #include -#include -#include -#include -#include + +#define OSMR0 0x00 /* OS Timer 0 Match Register */ +#define OSMR1 0x04 /* OS Timer 1 Match Register */ +#define OSMR2 0x08 /* OS Timer 2 Match Register */ +#define OSMR3 0x0C /* OS Timer 3 Match Register */ + +#define OSCR 0x10 /* OS Timer Counter Register */ +#define OSSR 0x14 /* OS Timer Status Register */ +#define OWER 0x18 /* OS Timer Watchdog Enable Register */ +#define OIER 0x1C /* OS Timer Interrupt Enable Register */ + +#define OSSR_M3 (1 << 3) /* Match status channel 3 */ +#define OSSR_M2 (1 << 2) /* Match status channel 2 */ +#define OSSR_M1 (1 << 1) /* Match status channel 1 */ +#define OSSR_M0 (1 << 0) /* Match status channel 0 */ + +#define OIER_E0 (1 << 0) /* Interrupt enable channel 0 */ /* * This is PXA's sched_clock implementation. This has a resolution @@ -33,9 +49,14 @@ * calls to sched_clock() which should always be the case in practice. */ +#define timer_readl(reg) readl_relaxed(timer_base + (reg)) +#define timer_writel(val, reg) writel_relaxed((val), timer_base + (reg)) + +static void __iomem *timer_base; + static u64 notrace pxa_read_sched_clock(void) { - return readl_relaxed(OSCR); + return timer_readl(OSCR); } @@ -47,8 +68,8 @@ pxa_ost0_interrupt(int irq, void *dev_id) struct clock_event_device *c = dev_id; /* Disarm the compare/match, signal the event. */ - writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER); - writel_relaxed(OSSR_M0, OSSR); + timer_writel(timer_readl(OIER) & ~OIER_E0, OIER); + timer_writel(OSSR_M0, OSSR); c->event_handler(c); return IRQ_HANDLED; @@ -59,10 +80,10 @@ pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev) { unsigned long next, oscr; - writel_relaxed(readl_relaxed(OIER) | OIER_E0, OIER); - next = readl_relaxed(OSCR) + delta; - writel_relaxed(next, OSMR0); - oscr = readl_relaxed(OSCR); + timer_writel(timer_readl(OIER) | OIER_E0, OIER); + next = timer_readl(OSCR) + delta; + timer_writel(next, OSMR0); + oscr = timer_readl(OSCR); return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0; } @@ -72,15 +93,15 @@ pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev) { switch (mode) { case CLOCK_EVT_MODE_ONESHOT: - writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER); - writel_relaxed(OSSR_M0, OSSR); + timer_writel(timer_readl(OIER) & ~OIER_E0, OIER); + timer_writel(OSSR_M0, OSSR); break; case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_SHUTDOWN: /* initializing, released, or preparing for suspend */ - writel_relaxed(readl_relaxed(OIER) & ~OIER_E0, OIER); - writel_relaxed(OSSR_M0, OSSR); + timer_writel(timer_readl(OIER) & ~OIER_E0, OIER); + timer_writel(OSSR_M0, OSSR); break; case CLOCK_EVT_MODE_RESUME: @@ -94,12 +115,12 @@ static unsigned long osmr[4], oier, oscr; static void pxa_timer_suspend(struct clock_event_device *cedev) { - osmr[0] = readl_relaxed(OSMR0); - osmr[1] = readl_relaxed(OSMR1); - osmr[2] = readl_relaxed(OSMR2); - osmr[3] = readl_relaxed(OSMR3); - oier = readl_relaxed(OIER); - oscr = readl_relaxed(OSCR); + osmr[0] = timer_readl(OSMR0); + osmr[1] = timer_readl(OSMR1); + osmr[2] = timer_readl(OSMR2); + osmr[3] = timer_readl(OSMR3); + oier = timer_readl(OIER); + oscr = timer_readl(OSCR); } static void pxa_timer_resume(struct clock_event_device *cedev) @@ -113,12 +134,12 @@ static void pxa_timer_resume(struct clock_event_device *cedev) if (osmr[0] - oscr < MIN_OSCR_DELTA) osmr[0] += MIN_OSCR_DELTA; - writel_relaxed(osmr[0], OSMR0); - writel_relaxed(osmr[1], OSMR1); - writel_relaxed(osmr[2], OSMR2); - writel_relaxed(osmr[3], OSMR3); - writel_relaxed(oier, OIER); - writel_relaxed(oscr, OSCR); + timer_writel(osmr[0], OSMR0); + timer_writel(osmr[1], OSMR1); + timer_writel(osmr[2], OSMR2); + timer_writel(osmr[3], OSMR3); + timer_writel(oier, OIER); + timer_writel(oscr, OSCR); } #else #define pxa_timer_suspend NULL @@ -142,21 +163,65 @@ static struct irqaction pxa_ost0_irq = { .dev_id = &ckevt_pxa_osmr0, }; -void __init pxa_timer_init(void) +static void pxa_timer_common_init(int irq, unsigned long clock_tick_rate) { - unsigned long clock_tick_rate = get_clock_tick_rate(); - - writel_relaxed(0, OIER); - writel_relaxed(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR); + timer_writel(0, OIER); + timer_writel(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR); sched_clock_register(pxa_read_sched_clock, 32, clock_tick_rate); ckevt_pxa_osmr0.cpumask = cpumask_of(0); - setup_irq(IRQ_OST0, &pxa_ost0_irq); + setup_irq(irq, &pxa_ost0_irq); - clocksource_mmio_init(OSCR, "oscr0", clock_tick_rate, 200, 32, - clocksource_mmio_readl_up); + clocksource_mmio_init(timer_base + OSCR, "oscr0", clock_tick_rate, 200, + 32, clocksource_mmio_readl_up); clockevents_config_and_register(&ckevt_pxa_osmr0, clock_tick_rate, - MIN_OSCR_DELTA * 2, 0x7fffffff); + MIN_OSCR_DELTA * 2, 0x7fffffff); +} + +static void __init pxa_timer_dt_init(struct device_node *np) +{ + struct clk *clk; + int irq; + + /* timer registers are shared with watchdog timer */ + timer_base = of_iomap(np, 0); + if (!timer_base) + panic("%s: unable to map resource\n", np->name); + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + pr_crit("%s: unable to get clk\n", np->name); + return; + } + clk_prepare_enable(clk); + + /* we are only interested in OS-timer0 irq */ + irq = irq_of_parse_and_map(np, 0); + if (irq <= 0) { + pr_crit("%s: unable to parse OS-timer0 irq\n", np->name); + return; + } + + pxa_timer_common_init(irq, clk_get_rate(clk)); +} +CLOCKSOURCE_OF_DECLARE(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init); + +/* + * Legacy timer init for non device-tree boards. + */ +void __init pxa_timer_nodt_init(int irq, void __iomem *base, + unsigned long clock_tick_rate) +{ + struct clk *clk; + + timer_base = base; + clk = clk_get(NULL, "OSTIMER0"); + if (clk && !IS_ERR(clk)) + clk_prepare_enable(clk); + else + pr_crit("%s: unable to get clk\n", __func__); + + pxa_timer_common_init(irq, clock_tick_rate); } -- cgit From fdb06f66d53e3c9ba7eeab3c0629c450aee76937 Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Sat, 5 Jul 2014 06:43:20 +0900 Subject: clocksource: exynos_mct: Use readl_relaxed/writel_relaxed Using the __raw functions is discouraged. Update the file to consistently use the proper functions. Signed-off-by: Doug Anderson Signed-off-by: Kukjin Kim Signed-off-by: Daniel Lezcano --- drivers/clocksource/exynos_mct.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index ab51bf20a3ed..2df03e238c1b 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -94,7 +94,7 @@ static void exynos4_mct_write(unsigned int value, unsigned long offset) u32 mask; u32 i; - __raw_writel(value, reg_base + offset); + writel_relaxed(value, reg_base + offset); if (likely(offset >= EXYNOS4_MCT_L_BASE(0))) { stat_addr = (offset & ~EXYNOS4_MCT_L_MASK) + MCT_L_WSTAT_OFFSET; @@ -144,8 +144,8 @@ static void exynos4_mct_write(unsigned int value, unsigned long offset) /* Wait maximum 1 ms until written values are applied */ for (i = 0; i < loops_per_jiffy / 1000 * HZ; i++) - if (__raw_readl(reg_base + stat_addr) & mask) { - __raw_writel(mask, reg_base + stat_addr); + if (readl_relaxed(reg_base + stat_addr) & mask) { + writel_relaxed(mask, reg_base + stat_addr); return; } @@ -157,7 +157,7 @@ static void exynos4_mct_frc_start(void) { u32 reg; - reg = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON); + reg = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON); reg |= MCT_G_TCON_START; exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON); } @@ -165,12 +165,12 @@ static void exynos4_mct_frc_start(void) static cycle_t notrace _exynos4_frc_read(void) { unsigned int lo, hi; - u32 hi2 = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_U); + u32 hi2 = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_U); do { hi = hi2; - lo = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_L); - hi2 = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_U); + lo = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_L); + hi2 = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_U); } while (hi != hi2); return ((cycle_t)hi << 32) | lo; @@ -225,7 +225,7 @@ static void exynos4_mct_comp0_stop(void) { unsigned int tcon; - tcon = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON); + tcon = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON); tcon &= ~(MCT_G_TCON_COMP0_ENABLE | MCT_G_TCON_COMP0_AUTO_INC); exynos4_mct_write(tcon, EXYNOS4_MCT_G_TCON); @@ -238,7 +238,7 @@ static void exynos4_mct_comp0_start(enum clock_event_mode mode, unsigned int tcon; cycle_t comp_cycle; - tcon = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON); + tcon = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON); if (mode == CLOCK_EVT_MODE_PERIODIC) { tcon |= MCT_G_TCON_COMP0_AUTO_INC; @@ -327,7 +327,7 @@ static void exynos4_mct_tick_stop(struct mct_clock_event_device *mevt) unsigned long mask = MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START; unsigned long offset = mevt->base + MCT_L_TCON_OFFSET; - tmp = __raw_readl(reg_base + offset); + tmp = readl_relaxed(reg_base + offset); if (tmp & mask) { tmp &= ~mask; exynos4_mct_write(tmp, offset); @@ -349,7 +349,7 @@ static void exynos4_mct_tick_start(unsigned long cycles, /* enable MCT tick interrupt */ exynos4_mct_write(0x1, mevt->base + MCT_L_INT_ENB_OFFSET); - tmp = __raw_readl(reg_base + mevt->base + MCT_L_TCON_OFFSET); + tmp = readl_relaxed(reg_base + mevt->base + MCT_L_TCON_OFFSET); tmp |= MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START | MCT_L_TCON_INTERVAL_MODE; exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET); @@ -401,7 +401,7 @@ static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) exynos4_mct_tick_stop(mevt); /* Clear the MCT tick interrupt */ - if (__raw_readl(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) { + if (readl_relaxed(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) { exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET); return 1; } else { -- cgit From 3252a646aa2cf706b2a26433a8bd9cb2e5dce410 Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Sat, 5 Jul 2014 06:43:26 +0900 Subject: clocksource: exynos_mct: Only use 32-bits where possible The MCT has a nice 64-bit counter. That means that we _can_ register as a 64-bit clocksource and sched_clock. ...but that doesn't mean we should. The 64-bit counter is read by reading two 32-bit registers. That means reading needs to be something like: - Read upper half - Read lower half - Read upper half and confirm that it hasn't changed. That wouldn't be terrible, but: - THe MCT isn't very fast to access (hundreds of nanoseconds). - The clocksource is queried _all the time_. In total system profiles of real workloads on ChromeOS, we've seen exynos_frc_read() taking 2% or more of CPU time even after optimizing the 3 reads above to 2 (see below). The MCT is clocked at ~24MHz on all known systems. That means that the 32-bit half of the counter rolls over every ~178 seconds. This inspired an optimization in ChromeOS to cache the upper half between calls, moving 3 reads to 2. ...but we can do better! Having a 32-bit timer that flips every 178 seconds is more than sufficient for Linux. Let's just use the lower half of the MCT. Times on 5420 to do 1000000 gettimeofday() calls from userspace: * Original code: 1323852 us * ChromeOS cache upper half: 1173084 us * ChromeOS + ldmia to optimize: 1045674 us * Use lower 32-bit only (this code): 1014429 us As you can see, the time used doesn't increase linearly with the number of reads and we can make 64-bit work almost as fast as 32-bit with a bit of assembly code. But since there's no real gain for 64-bit, let's go with the simplest and fastest implementation. Note: with this change roughly half the time for gettimeofday() is spent in exynos_frc_read(). The rest is timer / system call overhead. Also note: this patch disables the use of the MCT on ARM64 systems until we've sorted out how to make "cycles_t" always 32-bit. Really ARM64 systems should be using arch timers anyway. Signed-off-by: Doug Anderson Acked-by Vincent Guittot Signed-off-by: Kukjin Kim Signed-off-by: Daniel Lezcano --- drivers/clocksource/Kconfig | 1 + drivers/clocksource/exynos_mct.c | 39 ++++++++++++++++++++++++++++++++------- 2 files changed, 33 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 7ea7d7c48d72..cfd6519df661 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -127,6 +127,7 @@ config CLKSRC_METAG_GENERIC config CLKSRC_EXYNOS_MCT def_bool y if ARCH_EXYNOS + depends on !ARM64 help Support for Multi Core Timer controller on Exynos SoCs. diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 2df03e238c1b..9403061a2acc 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -162,7 +162,17 @@ static void exynos4_mct_frc_start(void) exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON); } -static cycle_t notrace _exynos4_frc_read(void) +/** + * exynos4_read_count_64 - Read all 64-bits of the global counter + * + * This will read all 64-bits of the global counter taking care to make sure + * that the upper and lower half match. Note that reading the MCT can be quite + * slow (hundreds of nanoseconds) so you should use the 32-bit (lower half + * only) version when possible. + * + * Returns the number of cycles in the global counter. + */ +static u64 exynos4_read_count_64(void) { unsigned int lo, hi; u32 hi2 = readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_U); @@ -176,9 +186,22 @@ static cycle_t notrace _exynos4_frc_read(void) return ((cycle_t)hi << 32) | lo; } +/** + * exynos4_read_count_32 - Read the lower 32-bits of the global counter + * + * This will read just the lower 32-bits of the global counter. This is marked + * as notrace so it can be used by the scheduler clock. + * + * Returns the number of cycles in the global counter (lower 32 bits). + */ +static u32 notrace exynos4_read_count_32(void) +{ + return readl_relaxed(reg_base + EXYNOS4_MCT_G_CNT_L); +} + static cycle_t exynos4_frc_read(struct clocksource *cs) { - return _exynos4_frc_read(); + return exynos4_read_count_32(); } static void exynos4_frc_resume(struct clocksource *cs) @@ -190,21 +213,23 @@ struct clocksource mct_frc = { .name = "mct-frc", .rating = 400, .read = exynos4_frc_read, - .mask = CLOCKSOURCE_MASK(64), + .mask = CLOCKSOURCE_MASK(32), .flags = CLOCK_SOURCE_IS_CONTINUOUS, .resume = exynos4_frc_resume, }; static u64 notrace exynos4_read_sched_clock(void) { - return _exynos4_frc_read(); + return exynos4_read_count_32(); } static struct delay_timer exynos4_delay_timer; static cycles_t exynos4_read_current_timer(void) { - return _exynos4_frc_read(); + BUILD_BUG_ON_MSG(sizeof(cycles_t) != sizeof(u32), + "cycles_t needs to move to 32-bit for ARM64 usage"); + return exynos4_read_count_32(); } static void __init exynos4_clocksource_init(void) @@ -218,7 +243,7 @@ static void __init exynos4_clocksource_init(void) if (clocksource_register_hz(&mct_frc, clk_rate)) panic("%s: can't register clocksource\n", mct_frc.name); - sched_clock_register(exynos4_read_sched_clock, 64, clk_rate); + sched_clock_register(exynos4_read_sched_clock, 32, clk_rate); } static void exynos4_mct_comp0_stop(void) @@ -245,7 +270,7 @@ static void exynos4_mct_comp0_start(enum clock_event_mode mode, exynos4_mct_write(cycles, EXYNOS4_MCT_G_COMP0_ADD_INCR); } - comp_cycle = exynos4_frc_read(&mct_frc) + cycles; + comp_cycle = exynos4_read_count_64() + cycles; exynos4_mct_write((u32)comp_cycle, EXYNOS4_MCT_G_COMP0_L); exynos4_mct_write((u32)(comp_cycle >> 32), EXYNOS4_MCT_G_COMP0_U); -- cgit From 5cac2f4d1c5f3eb3d981fab85d926d19f7b6b889 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 16 Jul 2014 21:04:25 +0000 Subject: input: evdev: Use ktime_mono_to_real() Convert the monotonic timestamp with ktime_mono_to_real() in evdev_events(). In evdev_queue_syn_dropped() we can call either ktime_get() or ktime_get_real() depending on the clkid. No point in having two calls for CLOCK_REALTIME. Signed-off-by: Thomas Gleixner Signed-off-by: John Stultz --- drivers/input/evdev.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index fd325ec9f064..de055451d1af 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -108,9 +108,8 @@ static void evdev_queue_syn_dropped(struct evdev_client *client) struct input_event ev; ktime_t time; - time = ktime_get(); - if (client->clkid != CLOCK_MONOTONIC) - time = ktime_sub(time, ktime_get_monotonic_offset()); + time = (client->clkid == CLOCK_MONOTONIC) ? + ktime_get() : ktime_get_real(); ev.time = ktime_to_timeval(time); ev.type = EV_SYN; @@ -202,7 +201,7 @@ static void evdev_events(struct input_handle *handle, ktime_t time_mono, time_real; time_mono = ktime_get(); - time_real = ktime_sub(time_mono, ktime_get_monotonic_offset()); + time_real = ktime_mono_to_real(time_mono); rcu_read_lock(); -- cgit From d2cb58c85ce4789caafa66fa8f1c641ab2504ead Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 16 Jul 2014 21:04:26 +0000 Subject: drm: Use ktime_mono_to_real() Convert the monotonic timestamp with ktime_mono_to_real() in drm_calc_vbltimestamp_from_scanoutpos(). In get_drm_timestamp we can call either ktime_get() or ktime_get_real() depending on drm_timestamp_monotonic. No point in having two calls into the core for CLOCK_REALTIME. Signed-off-by: Thomas Gleixner Signed-off-by: John Stultz --- drivers/gpu/drm/drm_irq.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 0de123afdb34..08ba1209228e 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -542,8 +542,8 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, const struct drm_crtc *refcrtc, const struct drm_display_mode *mode) { - ktime_t stime, etime, mono_time_offset; struct timeval tv_etime; + ktime_t stime, etime; int vbl_status; int vpos, hpos, i; int framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns; @@ -588,13 +588,6 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, vbl_status = dev->driver->get_scanout_position(dev, crtc, flags, &vpos, &hpos, &stime, &etime); - /* - * Get correction for CLOCK_MONOTONIC -> CLOCK_REALTIME if - * CLOCK_REALTIME is requested. - */ - if (!drm_timestamp_monotonic) - mono_time_offset = ktime_get_monotonic_offset(); - /* Return as no-op if scanout query unsupported or failed. */ if (!(vbl_status & DRM_SCANOUTPOS_VALID)) { DRM_DEBUG("crtc %d : scanoutpos query failed [%d].\n", @@ -633,7 +626,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, delta_ns = vpos * linedur_ns + hpos * pixeldur_ns; if (!drm_timestamp_monotonic) - etime = ktime_sub(etime, mono_time_offset); + etime = ktime_mono_to_real(etime); /* save this only for debugging purposes */ tv_etime = ktime_to_timeval(etime); @@ -664,10 +657,7 @@ static struct timeval get_drm_timestamp(void) { ktime_t now; - now = ktime_get(); - if (!drm_timestamp_monotonic) - now = ktime_sub(now, ktime_get_monotonic_offset()); - + now = drm_timestamp_monotonic ? ktime_get() : ktime_get_real(); return ktime_to_timeval(now); } -- cgit From 9e93f21b4309572c646bd8141a4853be5c031523 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 16 Jul 2014 21:04:40 +0000 Subject: connector: Use ktime_get_ns() Replace the ever recurring: ts = ktime_get_ts(); ns = timespec_to_ns(&ts); with ns = ktime_get_ns(); Signed-off-by: Thomas Gleixner Cc: Evgeniy Polyakov Signed-off-by: John Stultz --- drivers/connector/cn_proc.c | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index ccdd4c7e748b..15d06fcf0b50 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -69,7 +69,6 @@ void proc_fork_connector(struct task_struct *task) struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); - struct timespec ts; struct task_struct *parent; if (atomic_read(&proc_event_num_listeners) < 1) @@ -79,8 +78,7 @@ void proc_fork_connector(struct task_struct *task) ev = (struct proc_event *)msg->data; memset(&ev->event_data, 0, sizeof(ev->event_data)); get_seq(&msg->seq, &ev->cpu); - ktime_get_ts(&ts); /* get high res monotonic timestamp */ - ev->timestamp_ns = timespec_to_ns(&ts); + ev->timestamp_ns = ktime_get_ns(); ev->what = PROC_EVENT_FORK; rcu_read_lock(); parent = rcu_dereference(task->real_parent); @@ -102,7 +100,6 @@ void proc_exec_connector(struct task_struct *task) { struct cn_msg *msg; struct proc_event *ev; - struct timespec ts; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); if (atomic_read(&proc_event_num_listeners) < 1) @@ -112,8 +109,7 @@ void proc_exec_connector(struct task_struct *task) ev = (struct proc_event *)msg->data; memset(&ev->event_data, 0, sizeof(ev->event_data)); get_seq(&msg->seq, &ev->cpu); - ktime_get_ts(&ts); /* get high res monotonic timestamp */ - ev->timestamp_ns = timespec_to_ns(&ts); + ev->timestamp_ns = ktime_get_ns(); ev->what = PROC_EVENT_EXEC; ev->event_data.exec.process_pid = task->pid; ev->event_data.exec.process_tgid = task->tgid; @@ -130,7 +126,6 @@ void proc_id_connector(struct task_struct *task, int which_id) struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); - struct timespec ts; const struct cred *cred; if (atomic_read(&proc_event_num_listeners) < 1) @@ -156,8 +151,7 @@ void proc_id_connector(struct task_struct *task, int which_id) } rcu_read_unlock(); get_seq(&msg->seq, &ev->cpu); - ktime_get_ts(&ts); /* get high res monotonic timestamp */ - ev->timestamp_ns = timespec_to_ns(&ts); + ev->timestamp_ns = ktime_get_ns(); memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ @@ -170,7 +164,6 @@ void proc_sid_connector(struct task_struct *task) { struct cn_msg *msg; struct proc_event *ev; - struct timespec ts; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); if (atomic_read(&proc_event_num_listeners) < 1) @@ -180,8 +173,7 @@ void proc_sid_connector(struct task_struct *task) ev = (struct proc_event *)msg->data; memset(&ev->event_data, 0, sizeof(ev->event_data)); get_seq(&msg->seq, &ev->cpu); - ktime_get_ts(&ts); /* get high res monotonic timestamp */ - ev->timestamp_ns = timespec_to_ns(&ts); + ev->timestamp_ns = ktime_get_ns(); ev->what = PROC_EVENT_SID; ev->event_data.sid.process_pid = task->pid; ev->event_data.sid.process_tgid = task->tgid; @@ -197,7 +189,6 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id) { struct cn_msg *msg; struct proc_event *ev; - struct timespec ts; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); if (atomic_read(&proc_event_num_listeners) < 1) @@ -207,8 +198,7 @@ void proc_ptrace_connector(struct task_struct *task, int ptrace_id) ev = (struct proc_event *)msg->data; memset(&ev->event_data, 0, sizeof(ev->event_data)); get_seq(&msg->seq, &ev->cpu); - ktime_get_ts(&ts); /* get high res monotonic timestamp */ - ev->timestamp_ns = timespec_to_ns(&ts); + ev->timestamp_ns = ktime_get_ns(); ev->what = PROC_EVENT_PTRACE; ev->event_data.ptrace.process_pid = task->pid; ev->event_data.ptrace.process_tgid = task->tgid; @@ -232,7 +222,6 @@ void proc_comm_connector(struct task_struct *task) { struct cn_msg *msg; struct proc_event *ev; - struct timespec ts; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); if (atomic_read(&proc_event_num_listeners) < 1) @@ -242,8 +231,7 @@ void proc_comm_connector(struct task_struct *task) ev = (struct proc_event *)msg->data; memset(&ev->event_data, 0, sizeof(ev->event_data)); get_seq(&msg->seq, &ev->cpu); - ktime_get_ts(&ts); /* get high res monotonic timestamp */ - ev->timestamp_ns = timespec_to_ns(&ts); + ev->timestamp_ns = ktime_get_ns(); ev->what = PROC_EVENT_COMM; ev->event_data.comm.process_pid = task->pid; ev->event_data.comm.process_tgid = task->tgid; @@ -261,7 +249,6 @@ void proc_coredump_connector(struct task_struct *task) struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); - struct timespec ts; if (atomic_read(&proc_event_num_listeners) < 1) return; @@ -270,8 +257,7 @@ void proc_coredump_connector(struct task_struct *task) ev = (struct proc_event *)msg->data; memset(&ev->event_data, 0, sizeof(ev->event_data)); get_seq(&msg->seq, &ev->cpu); - ktime_get_ts(&ts); /* get high res monotonic timestamp */ - ev->timestamp_ns = timespec_to_ns(&ts); + ev->timestamp_ns = ktime_get_ns(); ev->what = PROC_EVENT_COREDUMP; ev->event_data.coredump.process_pid = task->pid; ev->event_data.coredump.process_tgid = task->tgid; @@ -288,7 +274,6 @@ void proc_exit_connector(struct task_struct *task) struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); - struct timespec ts; if (atomic_read(&proc_event_num_listeners) < 1) return; @@ -297,8 +282,7 @@ void proc_exit_connector(struct task_struct *task) ev = (struct proc_event *)msg->data; memset(&ev->event_data, 0, sizeof(ev->event_data)); get_seq(&msg->seq, &ev->cpu); - ktime_get_ts(&ts); /* get high res monotonic timestamp */ - ev->timestamp_ns = timespec_to_ns(&ts); + ev->timestamp_ns = ktime_get_ns(); ev->what = PROC_EVENT_EXIT; ev->event_data.exit.process_pid = task->pid; ev->event_data.exit.process_tgid = task->tgid; @@ -325,7 +309,6 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack) struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); - struct timespec ts; if (atomic_read(&proc_event_num_listeners) < 1) return; @@ -334,8 +317,7 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack) ev = (struct proc_event *)msg->data; memset(&ev->event_data, 0, sizeof(ev->event_data)); msg->seq = rcvd_seq; - ktime_get_ts(&ts); /* get high res monotonic timestamp */ - ev->timestamp_ns = timespec_to_ns(&ts); + ev->timestamp_ns = ktime_get_ns(); ev->cpu = -1; ev->what = PROC_EVENT_NONE; ev->event_data.ack.err = err; -- cgit From 154adc14b1ce941b642a3775f2423c20d55c026b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 16 Jul 2014 21:04:41 +0000 Subject: mfd: cros_ec_spi: Use ktime_get_ns() Replace the ever recurring: ts = ktime_get_ts(); ns = timespec_to_ns(&ts); with ns = ktime_get_ns(); Signed-off-by: Thomas Gleixner Acked-by: Lee Jones Signed-off-by: John Stultz --- drivers/mfd/cros_ec_spi.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c index 0b8d32829166..8c1c7cc373f8 100644 --- a/drivers/mfd/cros_ec_spi.c +++ b/drivers/mfd/cros_ec_spi.c @@ -225,7 +225,6 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, u8 *ptr; int sum; int ret = 0, final_ret; - struct timespec ts; /* * We have the shared ec_dev buffer plus we do lots of separate spi_sync @@ -239,11 +238,9 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, /* If it's too soon to do another transaction, wait */ if (ec_spi->last_transfer_ns) { - struct timespec ts; unsigned long delay; /* The delay completed so far */ - ktime_get_ts(&ts); - delay = timespec_to_ns(&ts) - ec_spi->last_transfer_ns; + delay = ktime_get_ns() - ec_spi->last_transfer_ns; if (delay < EC_SPI_RECOVERY_TIME_NS) ndelay(EC_SPI_RECOVERY_TIME_NS - delay); } @@ -280,8 +277,7 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, } final_ret = spi_sync(ec_spi->spi, &msg); - ktime_get_ts(&ts); - ec_spi->last_transfer_ns = timespec_to_ns(&ts); + ec_spi->last_transfer_ns = ktime_get_ns(); if (!ret) ret = final_ret; if (ret < 0) { -- cgit From 6d9b757c6ce850d0fb61d31f48e7bae56240643b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 16 Jul 2014 21:04:43 +0000 Subject: misc: ioc4: Use ktime_get_ns() Replace the ever recurring: ts = ktime_get_ts(); ns = timespec_to_ns(&ts); with ns = ktime_get_ns(); Signed-off-by: Thomas Gleixner Acked-by: Arnd Bergmann Acked-by: Greg Kroah-Hartman Signed-off-by: John Stultz --- drivers/misc/ioc4.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index 06f6ad29ceff..3336ddca45ac 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c @@ -145,7 +145,6 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) union ioc4_int_out int_out; union ioc4_gpcr gpcr; unsigned int state, last_state = 1; - struct timespec start_ts, end_ts; uint64_t start, end, period; unsigned int count = 0; @@ -174,10 +173,10 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) if (!last_state && state) { count++; if (count == IOC4_CALIBRATE_END) { - ktime_get_ts(&end_ts); + end = ktime_get_ns(); break; } else if (count == IOC4_CALIBRATE_DISCARD) - ktime_get_ts(&start_ts); + start = ktime_get_ns(); } last_state = state; } while (1); @@ -192,8 +191,6 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) * by which the IOC4 generates the square wave, to get the * period of an IOC4 INT_OUT count. */ - end = end_ts.tv_sec * NSEC_PER_SEC + end_ts.tv_nsec; - start = start_ts.tv_sec * NSEC_PER_SEC + start_ts.tv_nsec; period = (end - start) / (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1)); -- cgit From 14a7004671246d1b799f545335995a9897de1268 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 16 Jul 2014 21:04:44 +0000 Subject: net: mlx5: Use ktime_get_ns() This code is beyond silly: struct timespec ts = ktime_get_ts(); ktime_t ktime = timespec_to_ktime(ts); Further down the code builds the delta of two ktime_t values and converts the result to nanoseconds. Use ktime_get_ns() and replace all the nonsense. Signed-off-by: Thomas Gleixner Cc: Eli Cohen Signed-off-by: John Stultz --- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 87d1b018a9c3..67f8f5a1dc86 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -548,7 +548,7 @@ static void cmd_work_handler(struct work_struct *work) lay->status_own = CMD_OWNER_HW; set_signature(ent, !cmd->checksum_disabled); dump_command(dev, ent, 1); - ktime_get_ts(&ent->ts1); + ent->ts1 = ktime_get_ns(); /* ring doorbell after the descriptor is valid */ wmb(); @@ -637,7 +637,6 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in, { struct mlx5_cmd *cmd = &dev->cmd; struct mlx5_cmd_work_ent *ent; - ktime_t t1, t2, delta; struct mlx5_cmd_stats *stats; int err = 0; s64 ds; @@ -668,10 +667,7 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in, if (err == -ETIMEDOUT) goto out; - t1 = timespec_to_ktime(ent->ts1); - t2 = timespec_to_ktime(ent->ts2); - delta = ktime_sub(t2, t1); - ds = ktime_to_ns(delta); + ds = ent->ts2 - ent->ts1; op = be16_to_cpu(((struct mlx5_inbox_hdr *)in->first.data)->opcode); if (op < ARRAY_SIZE(cmd->stats)) { stats = &cmd->stats[op]; @@ -1135,7 +1131,6 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector) void *context; int err; int i; - ktime_t t1, t2, delta; s64 ds; struct mlx5_cmd_stats *stats; unsigned long flags; @@ -1149,7 +1144,7 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector) sem = &cmd->pages_sem; else sem = &cmd->sem; - ktime_get_ts(&ent->ts2); + ent->ts2 = ktime_get_ns(); memcpy(ent->out->first.data, ent->lay->out, sizeof(ent->lay->out)); dump_command(dev, ent, 0); if (!ent->ret) { @@ -1163,10 +1158,7 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector) } free_ent(cmd, ent->idx); if (ent->callback) { - t1 = timespec_to_ktime(ent->ts1); - t2 = timespec_to_ktime(ent->ts2); - delta = ktime_sub(t2, t1); - ds = ktime_to_ns(delta); + ds = ent->ts2 - ent->ts1; if (ent->op < ARRAY_SIZE(cmd->stats)) { stats = &cmd->stats[ent->op]; spin_lock_irqsave(&stats->lock, flags); -- cgit From d659f9b135fe26b966a6a4ad7281d35d7dbb1366 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 16 Jul 2014 21:04:47 +0000 Subject: hwmon: ibmaem: Use ktime_get_ns() Using the wall clock time for delta time calculations is wrong to begin with because wall clock time can be set from userspace and NTP. Such data wants to be based on clock monotonic. The calculations also are done on a nanosecond basis. Use the nanoseconds based interface right away. Signed-off-by: Thomas Gleixner Cc: Jean Delvare Acked-by: Jean Delvare Signed-off-by: John Stultz --- drivers/hwmon/ibmaem.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index 632f1dc0fe1f..7a8a6fbf11ff 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c @@ -842,11 +842,10 @@ static ssize_t aem_show_power(struct device *dev, struct aem_data *data = dev_get_drvdata(dev); u64 before, after, delta, time; signed long leftover; - struct timespec b, a; mutex_lock(&data->lock); update_aem_energy_one(data, attr->index); - getnstimeofday(&b); + time = ktime_get_ns(); before = data->energy[attr->index]; leftover = schedule_timeout_interruptible( @@ -858,11 +857,10 @@ static ssize_t aem_show_power(struct device *dev, } update_aem_energy_one(data, attr->index); - getnstimeofday(&a); + time = ktime_get_ns() - time; after = data->energy[attr->index]; mutex_unlock(&data->lock); - time = timespec_to_ns(&a) - timespec_to_ns(&b); delta = (after - before) * UJ_PER_MJ; return sprintf(buf, "%llu\n", -- cgit From 2044fdb03eb4e511d5028be0917899931f17461f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 16 Jul 2014 21:05:03 +0000 Subject: hangcheck-timer: Use ktime_get_ns() There is no point in having a S390 private implementation and there is no point in using the raw monotonic time. The NTP freqeuency adjustment of CLOCK_MONOTONIC is really not doing any harm for the hang check timer. Use ktime_get_ns() for everything and get rid of the timespec conversions. V2: Drop the raw monotonic and the S390 special case Signed-off-by: Thomas Gleixner Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Cc: Heiko Carstens Acked-by: Greg Kroah-Hartman Signed-off-by: John Stultz --- drivers/char/hangcheck-timer.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c index f953c96efc86..ebc4c73d8ca4 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c @@ -49,7 +49,7 @@ #include #include #include -#include +#include #define VERSION_STR "0.9.1" @@ -117,24 +117,7 @@ __setup("hcheck_reboot", hangcheck_parse_reboot); __setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks); #endif /* not MODULE */ -#if defined(CONFIG_S390) -# define HAVE_MONOTONIC -# define TIMER_FREQ 1000000000ULL -#else -# define TIMER_FREQ 1000000000ULL -#endif - -#ifdef HAVE_MONOTONIC -extern unsigned long long monotonic_clock(void); -#else -static inline unsigned long long monotonic_clock(void) -{ - struct timespec ts; - getrawmonotonic(&ts); - return timespec_to_ns(&ts); -} -#endif /* HAVE_MONOTONIC */ - +#define TIMER_FREQ 1000000000ULL /* Last time scheduled */ static unsigned long long hangcheck_tsc, hangcheck_tsc_margin; @@ -143,12 +126,11 @@ static void hangcheck_fire(unsigned long); static DEFINE_TIMER(hangcheck_ticktock, hangcheck_fire, 0, 0); - static void hangcheck_fire(unsigned long data) { unsigned long long cur_tsc, tsc_diff; - cur_tsc = monotonic_clock(); + cur_tsc = ktime_get_ns(); if (cur_tsc > hangcheck_tsc) tsc_diff = cur_tsc - hangcheck_tsc; @@ -177,7 +159,7 @@ static void hangcheck_fire(unsigned long data) tsc_diff, tsc_diff - hangcheck_tick*TIMER_FREQ); #endif mod_timer(&hangcheck_ticktock, jiffies + (hangcheck_tick*HZ)); - hangcheck_tsc = monotonic_clock(); + hangcheck_tsc = ktime_get_ns(); } @@ -185,16 +167,11 @@ static int __init hangcheck_init(void) { printk("Hangcheck: starting hangcheck timer %s (tick is %d seconds, margin is %d seconds).\n", VERSION_STR, hangcheck_tick, hangcheck_margin); -#if defined (HAVE_MONOTONIC) - printk("Hangcheck: Using monotonic_clock().\n"); -#else - printk("Hangcheck: Using getrawmonotonic().\n"); -#endif /* HAVE_MONOTONIC */ hangcheck_tsc_margin = (unsigned long long)(hangcheck_margin + hangcheck_tick); hangcheck_tsc_margin *= (unsigned long long)TIMER_FREQ; - hangcheck_tsc = monotonic_clock(); + hangcheck_tsc = ktime_get_ns(); mod_timer(&hangcheck_ticktock, jiffies + (hangcheck_tick*HZ)); return 0; -- cgit From 5ed0bdf21a85d78e04f89f15ccf227562177cbd9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 16 Jul 2014 21:05:06 +0000 Subject: drm: i915: Use nsec based interfaces Use ktime_get_raw_ns() and get rid of the back and forth timespec conversions. Signed-off-by: Thomas Gleixner Acked-by: Daniel Vetter Signed-off-by: John Stultz --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 33 ++++++++++++--------------------- drivers/gpu/drm/i915/intel_pm.c | 12 +++++------- 3 files changed, 18 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 374f964323ad..1f7700897dfc 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -931,7 +931,7 @@ struct intel_ilk_power_mgmt { unsigned long last_time1; unsigned long chipset_power; u64 last_count2; - struct timespec last_time2; + u64 last_time2; unsigned long gfx_power; u8 corr; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f36126383d26..74531caa5191 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1149,16 +1149,16 @@ static bool can_wait_boost(struct drm_i915_file_private *file_priv) static int __wait_seqno(struct intel_engine_cs *ring, u32 seqno, unsigned reset_counter, bool interruptible, - struct timespec *timeout, + s64 *timeout, struct drm_i915_file_private *file_priv) { struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; const bool irq_test_in_progress = ACCESS_ONCE(dev_priv->gpu_error.test_irq_rings) & intel_ring_flag(ring); - struct timespec before, now; DEFINE_WAIT(wait); unsigned long timeout_expire; + s64 before, now; int ret; WARN(dev_priv->pm.irqs_disabled, "IRQs disabled\n"); @@ -1166,7 +1166,7 @@ static int __wait_seqno(struct intel_engine_cs *ring, u32 seqno, if (i915_seqno_passed(ring->get_seqno(ring, true), seqno)) return 0; - timeout_expire = timeout ? jiffies + timespec_to_jiffies_timeout(timeout) : 0; + timeout_expire = timeout ? jiffies + nsecs_to_jiffies((u64)*timeout) : 0; if (INTEL_INFO(dev)->gen >= 6 && can_wait_boost(file_priv)) { gen6_rps_boost(dev_priv); @@ -1181,7 +1181,7 @@ static int __wait_seqno(struct intel_engine_cs *ring, u32 seqno, /* Record current time in case interrupted by signal, or wedged */ trace_i915_gem_request_wait_begin(ring, seqno); - getrawmonotonic(&before); + before = ktime_get_raw_ns(); for (;;) { struct timer_list timer; @@ -1230,7 +1230,7 @@ static int __wait_seqno(struct intel_engine_cs *ring, u32 seqno, destroy_timer_on_stack(&timer); } } - getrawmonotonic(&now); + now = ktime_get_raw_ns(); trace_i915_gem_request_wait_end(ring, seqno); if (!irq_test_in_progress) @@ -1239,10 +1239,9 @@ static int __wait_seqno(struct intel_engine_cs *ring, u32 seqno, finish_wait(&ring->irq_queue, &wait); if (timeout) { - struct timespec sleep_time = timespec_sub(now, before); - *timeout = timespec_sub(*timeout, sleep_time); - if (!timespec_valid(timeout)) /* i.e. negative time remains */ - set_normalized_timespec(timeout, 0, 0); + s64 tres = *timeout - (now - before); + + *timeout = tres < 0 ? 0 : tres; } return ret; @@ -2753,16 +2752,10 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) struct drm_i915_gem_wait *args = data; struct drm_i915_gem_object *obj; struct intel_engine_cs *ring = NULL; - struct timespec timeout_stack, *timeout = NULL; unsigned reset_counter; u32 seqno = 0; int ret = 0; - if (args->timeout_ns >= 0) { - timeout_stack = ns_to_timespec(args->timeout_ns); - timeout = &timeout_stack; - } - ret = i915_mutex_lock_interruptible(dev); if (ret) return ret; @@ -2787,9 +2780,9 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) goto out; /* Do this after OLR check to make sure we make forward progress polling - * on this IOCTL with a 0 timeout (like busy ioctl) + * on this IOCTL with a timeout <=0 (like busy ioctl) */ - if (!args->timeout_ns) { + if (args->timeout_ns <= 0) { ret = -ETIME; goto out; } @@ -2798,10 +2791,8 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); mutex_unlock(&dev->struct_mutex); - ret = __wait_seqno(ring, seqno, reset_counter, true, timeout, file->driver_priv); - if (timeout) - args->timeout_ns = timespec_to_ns(timeout); - return ret; + return __wait_seqno(ring, seqno, reset_counter, true, &args->timeout_ns, + file->driver_priv); out: drm_gem_object_unreference(&obj->base); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ee72807069e4..f1233f544f3e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2993,7 +2993,7 @@ static void ironlake_enable_drps(struct drm_device *dev) I915_READ(0x112e0); dev_priv->ips.last_time1 = jiffies_to_msecs(jiffies); dev_priv->ips.last_count2 = I915_READ(0x112f4); - getrawmonotonic(&dev_priv->ips.last_time2); + dev_priv->ips.last_time2 = ktime_get_raw_ns(); spin_unlock_irq(&mchdev_lock); } @@ -4314,18 +4314,16 @@ static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid) static void __i915_update_gfx_val(struct drm_i915_private *dev_priv) { - struct timespec now, diff1; - u64 diff; - unsigned long diffms; + u64 now, diff, diffms; u32 count; assert_spin_locked(&mchdev_lock); - getrawmonotonic(&now); - diff1 = timespec_sub(now, dev_priv->ips.last_time2); + now = ktime_get_raw_ns(); + diffms = now - dev_priv->ips.last_time2; + do_div(diffms, NSEC_PER_MSEC); /* Don't divide by 0 */ - diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000; if (!diffms) return; -- cgit From f166e6dcb7225c4193bcda68c9346583ed78b186 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 16 Jul 2014 21:05:07 +0000 Subject: drm: vmwgfx: Use nsec based interfaces No point in converting timespecs back and forth. Signed-off-by: Thomas Gleixner Cc: Thomas Hellstrom Signed-off-by: John Stultz --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_marker.c | 44 +++++++++++----------------------- 2 files changed, 16 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 6b252a887ae2..c886c024c637 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -159,8 +159,8 @@ struct vmw_surface { struct vmw_marker_queue { struct list_head head; - struct timespec lag; - struct timespec lag_time; + u64 lag; + u64 lag_time; spinlock_t lock; }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_marker.c b/drivers/gpu/drm/vmwgfx/vmwgfx_marker.c index 8a8725c2716c..efd1ffd68185 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_marker.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_marker.c @@ -31,14 +31,14 @@ struct vmw_marker { struct list_head head; uint32_t seqno; - struct timespec submitted; + u64 submitted; }; void vmw_marker_queue_init(struct vmw_marker_queue *queue) { INIT_LIST_HEAD(&queue->head); - queue->lag = ns_to_timespec(0); - getrawmonotonic(&queue->lag_time); + queue->lag = 0; + queue->lag_time = ktime_get_raw_ns(); spin_lock_init(&queue->lock); } @@ -62,7 +62,7 @@ int vmw_marker_push(struct vmw_marker_queue *queue, return -ENOMEM; marker->seqno = seqno; - getrawmonotonic(&marker->submitted); + marker->submitted = ktime_get_raw_ns(); spin_lock(&queue->lock); list_add_tail(&marker->head, &queue->head); spin_unlock(&queue->lock); @@ -74,14 +74,14 @@ int vmw_marker_pull(struct vmw_marker_queue *queue, uint32_t signaled_seqno) { struct vmw_marker *marker, *next; - struct timespec now; bool updated = false; + u64 now; spin_lock(&queue->lock); - getrawmonotonic(&now); + now = ktime_get_raw_ns(); if (list_empty(&queue->head)) { - queue->lag = ns_to_timespec(0); + queue->lag = 0; queue->lag_time = now; updated = true; goto out_unlock; @@ -91,7 +91,7 @@ int vmw_marker_pull(struct vmw_marker_queue *queue, if (signaled_seqno - marker->seqno > (1 << 30)) continue; - queue->lag = timespec_sub(now, marker->submitted); + queue->lag = now - marker->submitted; queue->lag_time = now; updated = true; list_del(&marker->head); @@ -104,27 +104,13 @@ out_unlock: return (updated) ? 0 : -EBUSY; } -static struct timespec vmw_timespec_add(struct timespec t1, - struct timespec t2) +static u64 vmw_fifo_lag(struct vmw_marker_queue *queue) { - t1.tv_sec += t2.tv_sec; - t1.tv_nsec += t2.tv_nsec; - if (t1.tv_nsec >= 1000000000L) { - t1.tv_sec += 1; - t1.tv_nsec -= 1000000000L; - } - - return t1; -} - -static struct timespec vmw_fifo_lag(struct vmw_marker_queue *queue) -{ - struct timespec now; + u64 now; spin_lock(&queue->lock); - getrawmonotonic(&now); - queue->lag = vmw_timespec_add(queue->lag, - timespec_sub(now, queue->lag_time)); + now = ktime_get_raw_ns(); + queue->lag += now - queue->lag_time; queue->lag_time = now; spin_unlock(&queue->lock); return queue->lag; @@ -134,11 +120,9 @@ static struct timespec vmw_fifo_lag(struct vmw_marker_queue *queue) static bool vmw_lag_lt(struct vmw_marker_queue *queue, uint32_t us) { - struct timespec lag, cond; + u64 cond = (u64) us * NSEC_PER_USEC; - cond = ns_to_timespec((s64) us * 1000); - lag = vmw_fifo_lag(queue); - return (timespec_compare(&lag, &cond) < 1); + return vmw_fifo_lag(queue) <= cond; } int vmw_wait_lag(struct vmw_private *dev_priv, -- cgit From 6438e0ddc870f282f7ad46c050c211063a574687 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 16 Jul 2014 21:05:09 +0000 Subject: wireless: ath9k: Get rid of timespec conversions We have interfaces. Remove the open coded cruft. Reduces text size along with the code. Signed-off-by: Thomas Gleixner Cc: QCA ath9k Development Cc: John W. Linville Signed-off-by: John Stultz --- drivers/net/wireless/ath/ath9k/hw.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2a8ed8375ec0..14b80b1b450c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1734,7 +1734,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, struct ath9k_hw_cal_data *caldata, bool fastcc) { struct ath_common *common = ath9k_hw_common(ah); - struct timespec ts; u32 saveLedState; u32 saveDefAntenna; u32 macStaId1; @@ -1784,8 +1783,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, /* Save TSF before chip reset, a cold reset clears it */ tsf = ath9k_hw_gettsf64(ah); - getrawmonotonic(&ts); - usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000; + usec = ktime_to_us(ktime_get_raw()); saveLedState = REG_READ(ah, AR_CFG_LED) & (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | @@ -1818,8 +1816,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, } /* Restore TSF */ - getrawmonotonic(&ts); - usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000 - usec; + usec = ktime_to_us(ktime_get_raw()) - usec; ath9k_hw_settsf64(ah, tsf + usec); if (AR_SREV_9280_20_OR_LATER(ah)) -- cgit