It is not possible for the clockevents core to know which modes (other than
those with a corresponding feature flag) are supported by a particular
implementation. And drivers are expected to handle transition to all modes
elegantly, as ->set_mode() would be issued for them unconditionally.
Now, adding support for a new mode complicates things a bit if we want to use
the legacy ->set_mode() callback. We need to closely review all clockevents
drivers to see if they would break on addition of a new mode. And after such
reviews, it is found that we have to do non-trivial changes to most of the
drivers [1].
Introduce mode-specific set_mode_*() callbacks, some of which the drivers may or
may not implement. A missing callback means the mode isn't supported by the
driver.
A driver may still choose to keep supporting the legacy ->set_mode() callback,
but ->set_mode() wouldn't be supporting any new modes beyond RESUME. If a driver
wants to get benefited by using a new mode, it would be required to migrate to
the mode specific callbacks.
The legacy ->set_mode() callback and the newly introduced mode-specific
callbacks are mutually exclusive. Only one of them should be supported by the
driver. If the legacy ->set_mode() callback is provided, all mode specific
callbacks would be ignored.
Sanity check is done at the time of registration to distinguish between optional
and required callbacks and to make error recovery and handling simpler.
Call sites calling ->set_mode() directly are also updated to use
__clockevents_set_mode() instead, as ->set_mode() may not be available anymore
for few drivers.
[1] https://lkml.org/lkml/2014/12/9/605
[2] https://lkml.org/lkml/2015/1/23/255
Reviewed-by: Preeti U Murthy <preeti(a)linux.vnet.ibm.com>
Suggested-by: Thomas Gleixner <tglx(a)linutronix.de> [2]
Signed-off-by: Viresh Kumar <viresh.kumar(a)linaro.org>
---
include/linux/clockchips.h | 21 ++++++++++--
kernel/time/clockevents.c | 84 ++++++++++++++++++++++++++++++++++++++++++++--
kernel/time/timer_list.c | 32 ++++++++++++++++--
3 files changed, 130 insertions(+), 7 deletions(-)
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index 2e4cb67f6e56..59af26b54d15 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -39,6 +39,8 @@ enum clock_event_mode {
CLOCK_EVT_MODE_PERIODIC,
CLOCK_EVT_MODE_ONESHOT,
CLOCK_EVT_MODE_RESUME,
+
+ /* Legacy ->set_mode() callback doesn't support below modes */
};
/*
@@ -81,7 +83,11 @@ enum clock_event_mode {
* @mode: operating mode assigned by the management code
* @features: features
* @retries: number of forced programming retries
- * @set_mode: set mode function
+ * @set_mode: legacy set mode function, only for modes <= CLOCK_EVT_MODE_RESUME.
+ * @set_mode_periodic: switch mode to periodic, if !set_mode
+ * @set_mode_oneshot: switch mode to oneshot, if !set_mode
+ * @set_mode_shutdown: switch mode to shutdown, if !set_mode
+ * @set_mode_resume: resume clkevt device, if !set_mode
* @broadcast: function to broadcast events
* @min_delta_ticks: minimum delta value in ticks stored for reconfiguration
* @max_delta_ticks: maximum delta value in ticks stored for reconfiguration
@@ -108,9 +114,20 @@ struct clock_event_device {
unsigned int features;
unsigned long retries;
- void (*broadcast)(const struct cpumask *mask);
+ /*
+ * Mode transition callback(s): Only one of the two groups should be
+ * defined:
+ * - set_mode(), only for modes <= CLOCK_EVT_MODE_RESUME.
+ * - set_mode_{shutdown|periodic|oneshot|resume}().
+ */
void (*set_mode)(enum clock_event_mode mode,
struct clock_event_device *);
+ int (*set_mode_periodic)(struct clock_event_device *);
+ int (*set_mode_oneshot)(struct clock_event_device *);
+ int (*set_mode_shutdown)(struct clock_event_device *);
+ int (*set_mode_resume)(struct clock_event_device *);
+
+ void (*broadcast)(const struct cpumask *mask);
void (*suspend)(struct clock_event_device *);
void (*resume)(struct clock_event_device *);
unsigned long min_delta_ticks;
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 55449909f114..cb5f24190ac2 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -94,6 +94,57 @@ u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt)
}
EXPORT_SYMBOL_GPL(clockevent_delta2ns);
+static int __clockevents_set_mode(struct clock_event_device *dev,
+ enum clock_event_mode mode)
+{
+ /* Transition with legacy set_mode() callback */
+ if (dev->set_mode) {
+ /* Legacy callback doesn't support new modes */
+ if (mode > CLOCK_EVT_MODE_RESUME)
+ return -ENOSYS;
+ dev->set_mode(mode, dev);
+ return 0;
+ }
+
+ if (dev->features & CLOCK_EVT_FEAT_DUMMY)
+ return 0;
+
+ /* Transition with new mode-specific callbacks */
+ switch (mode) {
+ case CLOCK_EVT_MODE_UNUSED:
+ /*
+ * This is an internal state, which is guaranteed to go from
+ * SHUTDOWN to UNUSED. No driver interaction required.
+ */
+ return 0;
+
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ return dev->set_mode_shutdown(dev);
+
+ case CLOCK_EVT_MODE_PERIODIC:
+ /* Core internal bug */
+ if (!(dev->features & CLOCK_EVT_FEAT_PERIODIC))
+ return -ENOSYS;
+ return dev->set_mode_periodic(dev);
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* Core internal bug */
+ if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT))
+ return -ENOSYS;
+ return dev->set_mode_oneshot(dev);
+
+ case CLOCK_EVT_MODE_RESUME:
+ /* Optional callback */
+ if (dev->set_mode_resume)
+ return dev->set_mode_resume(dev);
+ else
+ return 0;
+
+ default:
+ return -ENOSYS;
+ }
+}
+
/**
* clockevents_set_mode - set the operating mode of a clock event device
* @dev: device to modify
@@ -105,7 +156,9 @@ void clockevents_set_mode(struct clock_event_device *dev,
enum clock_event_mode mode)
{
if (dev->mode != mode) {
- dev->set_mode(mode, dev);
+ if (__clockevents_set_mode(dev, mode))
+ return;
+
dev->mode = mode;
/*
@@ -373,6 +426,31 @@ int clockevents_unbind_device(struct clock_event_device *ced, int cpu)
}
EXPORT_SYMBOL_GPL(clockevents_unbind);
+/* Sanity check of mode transition callbacks */
+static int clockevents_sanity_check(struct clock_event_device *dev)
+{
+ /* Legacy set_mode() callback */
+ if (dev->set_mode)
+ return 0;
+
+ if (dev->features & CLOCK_EVT_FEAT_DUMMY)
+ return 0;
+
+ /* New mode-specific callbacks */
+ if (!dev->set_mode_shutdown)
+ return -EINVAL;
+
+ if ((dev->features & CLOCK_EVT_FEAT_PERIODIC) &&
+ !dev->set_mode_periodic)
+ return -EINVAL;
+
+ if ((dev->features & CLOCK_EVT_FEAT_ONESHOT) &&
+ !dev->set_mode_oneshot)
+ return -EINVAL;
+
+ return 0;
+}
+
/**
* clockevents_register_device - register a clock event device
* @dev: device to register
@@ -382,6 +460,8 @@ void clockevents_register_device(struct clock_event_device *dev)
unsigned long flags;
BUG_ON(dev->mode != CLOCK_EVT_MODE_UNUSED);
+ BUG_ON(clockevents_sanity_check(dev));
+
if (!dev->cpumask) {
WARN_ON(num_possible_cpus() > 1);
dev->cpumask = cpumask_of(smp_processor_id());
@@ -449,7 +529,7 @@ int __clockevents_update_freq(struct clock_event_device *dev, u32 freq)
return clockevents_program_event(dev, dev->next_event, false);
if (dev->mode == CLOCK_EVT_MODE_PERIODIC)
- dev->set_mode(CLOCK_EVT_MODE_PERIODIC, dev);
+ return __clockevents_set_mode(dev, CLOCK_EVT_MODE_PERIODIC);
return 0;
}
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index 61ed862cdd37..2cfd19485824 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -228,9 +228,35 @@ print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu)
print_name_offset(m, dev->set_next_event);
SEQ_printf(m, "\n");
- SEQ_printf(m, " set_mode: ");
- print_name_offset(m, dev->set_mode);
- SEQ_printf(m, "\n");
+ if (dev->set_mode) {
+ SEQ_printf(m, " set_mode: ");
+ print_name_offset(m, dev->set_mode);
+ SEQ_printf(m, "\n");
+ } else {
+ if (dev->set_mode_shutdown) {
+ SEQ_printf(m, " shutdown: ");
+ print_name_offset(m, dev->set_mode_shutdown);
+ SEQ_printf(m, "\n");
+ }
+
+ if (dev->set_mode_periodic) {
+ SEQ_printf(m, " periodic: ");
+ print_name_offset(m, dev->set_mode_periodic);
+ SEQ_printf(m, "\n");
+ }
+
+ if (dev->set_mode_oneshot) {
+ SEQ_printf(m, " oneshot: ");
+ print_name_offset(m, dev->set_mode_oneshot);
+ SEQ_printf(m, "\n");
+ }
+
+ if (dev->set_mode_resume) {
+ SEQ_printf(m, " resume: ");
+ print_name_offset(m, dev->set_mode_resume);
+ SEQ_printf(m, "\n");
+ }
+ }
SEQ_printf(m, " event_handler: ");
print_name_offset(m, dev->event_handler);
--
2.3.0.rc0.44.ga94655d
Tree/Branch: next-20150212
Git describe: next-20150212
Commit: 7496ad672d Add linux-next specific files for 20150212
Build Time: 24 min 15 sec
Passed: 7 / 8 ( 87.50 %)
Failed: 1 / 8 ( 12.50 %)
Errors: 1
Warnings: 27
Section Mismatches: 0
Failed defconfigs:
arm-allmodconfig
Errors:
arm-allmodconfig
../fs/dax.c:266:2: error: implicit declaration of function 'copy_user_page' [-Werror=implicit-function-declaration]
-------------------------------------------------------------------------------
defconfigs with issues (other than build errors):
21 warnings 0 mismatches : arm64-allmodconfig
8 warnings 0 mismatches : arm-allmodconfig
4 warnings 0 mismatches : arm64-defconfig
-------------------------------------------------------------------------------
Errors summary: 1
1 ../fs/dax.c:266:2: error: implicit declaration of function 'copy_user_page' [-Werror=implicit-function-declaration]
Warnings Summary: 27
2 ../drivers/staging/sm7xxfb/sm7xxfb.c:117:19: warning: 'sm7xx_vga_setup' defined but not used [-Wunused-function]
2 ../drivers/scsi/ips.c:210:2: warning: #warning "This driver has only been tested on the x86/ia64/x86_64 platforms" [-Wcpp]
2 ../drivers/pci/host/pci-xgene.c:144:13: warning: initialization from incompatible pointer type
2 ../drivers/pci/host/pci-xgene.c:144:13: warning: (near initialization for 'xgene_pcie_ops.map_bus')
2 ../drivers/pci/host/pci-xgene.c:140:2: warning: return makes integer from pointer without a cast
2 ../drivers/pci/host/pci-xgene.c:137:3: warning: return makes integer from pointer without a cast
1 ../sound/soc/samsung/dmaengine.c:60:31: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
1 ../sound/soc/samsung/dmaengine.c:53:32: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
1 ../net/rds/iw_rdma.c:200:1: warning: the frame size of 1056 bytes is larger than 1024 bytes [-Wframe-larger-than=]
1 ../lib/lz4/lz4hc_compress.c:514:1: warning: the frame size of 1480 bytes is larger than 1024 bytes [-Wframe-larger-than=]
1 ../fs/btrfs/disk-io.c:3927:21: warning: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'unsigned int' [-Wformat=]
1 ../drivers/usb/renesas_usbhs/common.c:482:25: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
1 ../drivers/staging/fbtft/fbtft-io.c:63:4: warning: format '%d' expects argument of type 'int', but argument 4 has type 'size_t' [-Wformat=]
1 ../drivers/staging/fbtft/fbtft-io.c:110:5: warning: format '%d' expects argument of type 'int', but argument 4 has type 'size_t' [-Wformat=]
1 ../drivers/staging/fbtft/fbtft-core.c:1004:4: warning: format '%d' expects argument of type 'int', but argument 3 has type 'size_t' [-Wformat=]
1 ../drivers/staging/dgap/dgap.h:124:0: warning: "PCI_IO_SIZE" redefined
1 ../drivers/spi/spi-s3c64xx.c:336:8: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
1 ../drivers/spi/spi-s3c64xx.c:327:8: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
1 ../drivers/net/ethernet/dec/tulip/winbond-840.c:910:2: warning: #warning Processor architecture undefined [-Wcpp]
1 ../drivers/net/ethernet/dec/tulip/tulip_core.c:101:2: warning: #warning Processor architecture undefined! [-Wcpp]
1 ../drivers/mtd/chips/cfi_cmdset_0020.c:651:1: warning: the frame size of 1208 bytes is larger than 1024 bytes [-Wframe-larger-than=]
1 ../drivers/infiniband/hw/qib/qib_qp.c:44:0: warning: "BITS_PER_PAGE" redefined
1 ../drivers/gpio/gpio-74xx-mmio.c:132:16: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
1 ../drivers/block/drbd/drbd_bitmap.c:483:0: warning: "BITS_PER_PAGE_MASK" redefined
1 ../drivers/block/drbd/drbd_bitmap.c:482:0: warning: "BITS_PER_PAGE" redefined
1 ../arch/arm/mach-cns3xxx/pcie.c:266:1: warning: the frame size of 1080 bytes is larger than 1024 bytes [-Wframe-larger-than=]
1 ../arch/arm/include/asm/cmpxchg.h:205:3: warning: value computed is not used [-Wunused-value]
===============================================================================
Detailed per-defconfig build reports below:
-------------------------------------------------------------------------------
arm64-allmodconfig : PASS, 0 errors, 21 warnings, 0 section mismatches
Warnings:
../drivers/block/drbd/drbd_bitmap.c:482:0: warning: "BITS_PER_PAGE" redefined
../drivers/block/drbd/drbd_bitmap.c:483:0: warning: "BITS_PER_PAGE_MASK" redefined
../drivers/gpio/gpio-74xx-mmio.c:132:16: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
../sound/soc/samsung/dmaengine.c:53:32: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
../sound/soc/samsung/dmaengine.c:60:31: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
../drivers/infiniband/hw/qib/qib_qp.c:44:0: warning: "BITS_PER_PAGE" redefined
../drivers/pci/host/pci-xgene.c:137:3: warning: return makes integer from pointer without a cast
../drivers/pci/host/pci-xgene.c:140:2: warning: return makes integer from pointer without a cast
../drivers/pci/host/pci-xgene.c:144:13: warning: initialization from incompatible pointer type
../drivers/pci/host/pci-xgene.c:144:13: warning: (near initialization for 'xgene_pcie_ops.map_bus')
../drivers/spi/spi-s3c64xx.c:327:8: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
../drivers/spi/spi-s3c64xx.c:336:8: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
../drivers/net/ethernet/dec/tulip/winbond-840.c:910:2: warning: #warning Processor architecture undefined [-Wcpp]
../drivers/net/ethernet/dec/tulip/tulip_core.c:101:2: warning: #warning Processor architecture undefined! [-Wcpp]
../drivers/staging/dgap/dgap.h:124:0: warning: "PCI_IO_SIZE" redefined
../drivers/staging/fbtft/fbtft-core.c:1004:4: warning: format '%d' expects argument of type 'int', but argument 3 has type 'size_t' [-Wformat=]
../drivers/staging/fbtft/fbtft-io.c:63:4: warning: format '%d' expects argument of type 'int', but argument 4 has type 'size_t' [-Wformat=]
../drivers/staging/fbtft/fbtft-io.c:110:5: warning: format '%d' expects argument of type 'int', but argument 4 has type 'size_t' [-Wformat=]
../drivers/scsi/ips.c:210:2: warning: #warning "This driver has only been tested on the x86/ia64/x86_64 platforms" [-Wcpp]
../drivers/staging/sm7xxfb/sm7xxfb.c:117:19: warning: 'sm7xx_vga_setup' defined but not used [-Wunused-function]
../drivers/usb/renesas_usbhs/common.c:482:25: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
-------------------------------------------------------------------------------
arm-allmodconfig : FAIL, 1 errors, 8 warnings, 0 section mismatches
Errors:
../fs/dax.c:266:2: error: implicit declaration of function 'copy_user_page' [-Werror=implicit-function-declaration]
Warnings:
../arch/arm/mach-cns3xxx/pcie.c:266:1: warning: the frame size of 1080 bytes is larger than 1024 bytes [-Wframe-larger-than=]
../fs/btrfs/disk-io.c:3927:21: warning: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'unsigned int' [-Wformat=]
../lib/lz4/lz4hc_compress.c:514:1: warning: the frame size of 1480 bytes is larger than 1024 bytes [-Wframe-larger-than=]
../arch/arm/include/asm/cmpxchg.h:205:3: warning: value computed is not used [-Wunused-value]
../net/rds/iw_rdma.c:200:1: warning: the frame size of 1056 bytes is larger than 1024 bytes [-Wframe-larger-than=]
../drivers/mtd/chips/cfi_cmdset_0020.c:651:1: warning: the frame size of 1208 bytes is larger than 1024 bytes [-Wframe-larger-than=]
../drivers/scsi/ips.c:210:2: warning: #warning "This driver has only been tested on the x86/ia64/x86_64 platforms" [-Wcpp]
../drivers/staging/sm7xxfb/sm7xxfb.c:117:19: warning: 'sm7xx_vga_setup' defined but not used [-Wunused-function]
-------------------------------------------------------------------------------
arm64-defconfig : PASS, 0 errors, 4 warnings, 0 section mismatches
Warnings:
../drivers/pci/host/pci-xgene.c:137:3: warning: return makes integer from pointer without a cast
../drivers/pci/host/pci-xgene.c:140:2: warning: return makes integer from pointer without a cast
../drivers/pci/host/pci-xgene.c:144:13: warning: initialization from incompatible pointer type
../drivers/pci/host/pci-xgene.c:144:13: warning: (near initialization for 'xgene_pcie_ops.map_bus')
-------------------------------------------------------------------------------
Passed with no errors, warnings or mismatches:
arm64-allnoconfig
x86_64-allnoconfig
arm-allnoconfig
arm-multi_v7_defconfig
x86_64-defconfig
The following changes since commit e36f014edff70fc02b3d3d79cead1d58f289332e:
Linux 3.19-rc7 (2015-02-01 20:07:21 -0800)
are available in the git repository at:
https://git.linaro.org/people/daniel.thompson/linux.git
tags/for_jason-3.20
for you to fetch changes up to 257eaf8518a832f3b4947a8d62bf027943545d78:
debug: prevent entering debug mode on panic/exception. (2015-02-06
11:21:13 +0000)
----------------------------------------------------------------
This is all outstanding patches for kgdb shared during this development
cycle, both from myself and from Colin Cross/Kiran Raparthy.
No patch included in this pull request has any outstanding review
comments.
Bisect and build testing reported nothing except a checkpatch warning
that is better left unfixed (a long string constant spread across
multiple lines).
The result is several bug fixes:
* A regression that resulted into non-printing characters being shown
is fixed,
* A bug in the grep logic that results in failure to show the command
prompt is fixed,
* Stopping due to ttyNMI0 no longer issues a stach trace (this is a
useability fix and aligns behaviour with other user-requested
stops),
* Requests to automatically reboot the system on panic are honoured
(rather than entering the debugger).
In addition to the fixes there is also a new feature that allows the
grep logic to be reused by the pager to provide interactive forward
search.
----------------------------------------------------------------
Colin Cross (1):
debug: prevent entering debug mode on panic/exception.
Daniel Thompson (5):
kdb: Avoid printing KERN_ levels to consoles
kdb: Remove stack dump when entering kgdb due to NMI
kdb: Fix a prompt management bug when using | grep
kdb: Provide forward search at more prompt
kdb: Const qualifier for kdb_getstr's prompt argument
include/linux/kdb.h | 8 +++++++-
kernel/debug/debug_core.c | 17 ++++++++++++++++
kernel/debug/kdb/kdb_io.c | 46
+++++++++++++++++++++++++++++++-----------
kernel/debug/kdb/kdb_main.c | 12 +++++------
kernel/debug/kdb/kdb_private.h | 4 +++-
kernel/printk/printk.c | 2 +-
6 files changed, 68 insertions(+), 21 deletions(-)