Commit 9465d9cc authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull timer updates from Thomas Gleixner:
 "The time/timekeeping/timer folks deliver with this update:

   - Fix a reintroduced signed/unsigned issue and cleanup the whole
     signed/unsigned mess in the timekeeping core so this wont happen
     accidentaly again.

   - Add a new trace clock based on boot time

   - Prevent injection of random sleep times when PM tracing abuses the
     RTC for storage

   - Make posix timers configurable for real tiny systems

   - Add tracepoints for the alarm timer subsystem so timer based
     suspend wakeups can be instrumented

   - The usual pile of fixes and updates to core and drivers"

* 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (23 commits)
  timekeeping: Use mul_u64_u32_shr() instead of open coding it
  timekeeping: Get rid of pointless typecasts
  timekeeping: Make the conversion call chain consistently unsigned
  timekeeping_Force_unsigned_clocksource_to_nanoseconds_conversion
  alarmtimer: Add tracepoints for alarm timers
  trace: Update documentation for mono, mono_raw and boot clock
  trace: Add an option for boot clock as trace clock
  timekeeping: Add a fast and NMI safe boot clock
  timekeeping/clocksource_cyc2ns: Document intended range limitation
  timekeeping: Ignore the bogus sleep time if pm_trace is enabled
  selftests/timers: Fix spelling mistake "Asyncrhonous" -> "Asynchronous"
  clocksource/drivers/bcm2835_timer: Unmap region obtained by of_iomap
  clocksource/drivers/arm_arch_timer: Map frame with of_io_request_and_map()
  arm64: dts: rockchip: Arch counter doesn't tick in system suspend
  clocksource/drivers/arm_arch_timer: Don't assume clock runs in suspend
  posix-timers: Make them configurable
  posix_cpu_timers: Move the add_device_randomness() call to a proper place
  timer: Move sys_alarm from timer.c to itimer.c
  ptp_clock: Allow for it to be optional
  Kconfig: Regenerate *.c_shipped files after previous changes
  ...
parents e71c3978 c029a2be
...@@ -38,6 +38,11 @@ to deliver its interrupts via SPIs. ...@@ -38,6 +38,11 @@ to deliver its interrupts via SPIs.
architecturally-defined reset values. Only supported for 32-bit architecturally-defined reset values. Only supported for 32-bit
systems which follow the ARMv7 architected reset values. systems which follow the ARMv7 architected reset values.
- arm,no-tick-in-suspend : The main counter does not tick when the system is in
low-power system suspend on some SoCs. This behavior does not match the
Architecture Reference Manual's specification that the system counter "must
be implemented in an always-on power domain."
Example: Example:
......
...@@ -113,6 +113,34 @@ applicable everywhere (see syntax). ...@@ -113,6 +113,34 @@ applicable everywhere (see syntax).
That will limit the usefulness but on the other hand avoid That will limit the usefulness but on the other hand avoid
the illegal configurations all over. the illegal configurations all over.
- weak reverse dependencies: "imply" <symbol> ["if" <expr>]
This is similar to "select" as it enforces a lower limit on another
symbol except that the "implied" symbol's value may still be set to n
from a direct dependency or with a visible prompt.
Given the following example:
config FOO
tristate
imply BAZ
config BAZ
tristate
depends on BAR
The following values are possible:
FOO BAR BAZ's default choice for BAZ
--- --- ------------- --------------
n y n N/m/y
m y m M/y/n
y y y Y/n
y n * N
This is useful e.g. with multiple drivers that want to indicate their
ability to hook into a secondary subsystem while allowing the user to
configure that subsystem out without also having to unset these drivers.
- limiting menu display: "visible if" <expr> - limiting menu display: "visible if" <expr>
This attribute is only applicable to menu blocks, if the condition is This attribute is only applicable to menu blocks, if the condition is
false, the menu block is not displayed to the user (the symbols false, the menu block is not displayed to the user (the symbols
...@@ -481,6 +509,7 @@ historical issues resolved through these different solutions. ...@@ -481,6 +509,7 @@ historical issues resolved through these different solutions.
b) Match dependency semantics: b) Match dependency semantics:
b1) Swap all "select FOO" to "depends on FOO" or, b1) Swap all "select FOO" to "depends on FOO" or,
b2) Swap all "depends on FOO" to "select FOO" b2) Swap all "depends on FOO" to "select FOO"
c) Consider the use of "imply" instead of "select"
The resolution to a) can be tested with the sample Kconfig file The resolution to a) can be tested with the sample Kconfig file
Documentation/kbuild/Kconfig.recursion-issue-01 through the removal Documentation/kbuild/Kconfig.recursion-issue-01 through the removal
......
...@@ -362,6 +362,26 @@ of ftrace. Here is a list of some of the key files: ...@@ -362,6 +362,26 @@ of ftrace. Here is a list of some of the key files:
to correlate events across hypervisor/guest if to correlate events across hypervisor/guest if
tb_offset is known. tb_offset is known.
mono: This uses the fast monotonic clock (CLOCK_MONOTONIC)
which is monotonic and is subject to NTP rate adjustments.
mono_raw:
This is the raw monotonic clock (CLOCK_MONOTONIC_RAW)
which is montonic but is not subject to any rate adjustments
and ticks at the same rate as the hardware clocksource.
boot: This is the boot clock (CLOCK_BOOTTIME) and is based on the
fast monotonic clock, but also accounts for time spent in
suspend. Since the clock access is designed for use in
tracing in the suspend path, some side effects are possible
if clock is accessed after the suspend time is accounted before
the fast mono clock is updated. In this case, the clock update
appears to happen slightly sooner than it normally would have.
Also on 32-bit systems, it's possible that the 64-bit boot offset
sees a partial update. These effects are rare and post
processing should be able to handle them. See comments in the
ktime_get_boot_fast_ns() function for more information.
To set a clock, simply echo the clock name into this file. To set a clock, simply echo the clock name into this file.
echo global > trace_clock echo global > trace_clock
......
...@@ -1029,11 +1029,16 @@ SYSCALL_DEFINE2(osf_settimeofday, struct timeval32 __user *, tv, ...@@ -1029,11 +1029,16 @@ SYSCALL_DEFINE2(osf_settimeofday, struct timeval32 __user *, tv,
return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
} }
asmlinkage long sys_ni_posix_timers(void);
SYSCALL_DEFINE2(osf_getitimer, int, which, struct itimerval32 __user *, it) SYSCALL_DEFINE2(osf_getitimer, int, which, struct itimerval32 __user *, it)
{ {
struct itimerval kit; struct itimerval kit;
int error; int error;
if (!IS_ENABLED(CONFIG_POSIX_TIMERS))
return sys_ni_posix_timers();
error = do_getitimer(which, &kit); error = do_getitimer(which, &kit);
if (!error && put_it32(it, &kit)) if (!error && put_it32(it, &kit))
error = -EFAULT; error = -EFAULT;
...@@ -1047,6 +1052,9 @@ SYSCALL_DEFINE3(osf_setitimer, int, which, struct itimerval32 __user *, in, ...@@ -1047,6 +1052,9 @@ SYSCALL_DEFINE3(osf_setitimer, int, which, struct itimerval32 __user *, in,
struct itimerval kin, kout; struct itimerval kin, kout;
int error; int error;
if (!IS_ENABLED(CONFIG_POSIX_TIMERS))
return sys_ni_posix_timers();
if (in) { if (in) {
if (get_it32(&kin, in)) if (get_it32(&kin, in))
return -EFAULT; return -EFAULT;
......
...@@ -174,6 +174,7 @@ timer { ...@@ -174,6 +174,7 @@ timer {
<GIC_PPI 14 IRQ_TYPE_LEVEL_LOW 0>, <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW 0>,
<GIC_PPI 11 IRQ_TYPE_LEVEL_LOW 0>, <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW 0>,
<GIC_PPI 10 IRQ_TYPE_LEVEL_LOW 0>; <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW 0>;
arm,no-tick-in-suspend;
}; };
xin24m: xin24m { xin24m: xin24m {
......
...@@ -64,6 +64,15 @@ void mach_get_cmos_time(struct timespec *now) ...@@ -64,6 +64,15 @@ void mach_get_cmos_time(struct timespec *now)
unsigned int status, year, mon, day, hour, min, sec, century = 0; unsigned int status, year, mon, day, hour, min, sec, century = 0;
unsigned long flags; unsigned long flags;
/*
* If pm_trace abused the RTC as storage, set the timespec to 0,
* which tells the caller that this RTC value is unusable.
*/
if (!pm_trace_rtc_valid()) {
now->tv_sec = now->tv_nsec = 0;
return;
}
spin_lock_irqsave(&rtc_lock, flags); spin_lock_irqsave(&rtc_lock, flags);
/* /*
......
...@@ -107,7 +107,7 @@ obj-$(CONFIG_INPUT) += input/ ...@@ -107,7 +107,7 @@ obj-$(CONFIG_INPUT) += input/
obj-$(CONFIG_RTC_LIB) += rtc/ obj-$(CONFIG_RTC_LIB) += rtc/
obj-y += i2c/ media/ obj-y += i2c/ media/
obj-$(CONFIG_PPS) += pps/ obj-$(CONFIG_PPS) += pps/
obj-$(CONFIG_PTP_1588_CLOCK) += ptp/ obj-y += ptp/
obj-$(CONFIG_W1) += w1/ obj-$(CONFIG_W1) += w1/
obj-y += power/ obj-y += power/
obj-$(CONFIG_HWMON) += hwmon/ obj-$(CONFIG_HWMON) += hwmon/
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/pm-trace.h> #include <linux/pm-trace.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/suspend.h>
#include <linux/mc146818rtc.h> #include <linux/mc146818rtc.h>
...@@ -74,6 +75,9 @@ ...@@ -74,6 +75,9 @@
#define DEVSEED (7919) #define DEVSEED (7919)
bool pm_trace_rtc_abused __read_mostly;
EXPORT_SYMBOL_GPL(pm_trace_rtc_abused);
static unsigned int dev_hash_value; static unsigned int dev_hash_value;
static int set_magic_time(unsigned int user, unsigned int file, unsigned int device) static int set_magic_time(unsigned int user, unsigned int file, unsigned int device)
...@@ -104,6 +108,7 @@ static int set_magic_time(unsigned int user, unsigned int file, unsigned int dev ...@@ -104,6 +108,7 @@ static int set_magic_time(unsigned int user, unsigned int file, unsigned int dev
time.tm_min = (n % 20) * 3; time.tm_min = (n % 20) * 3;
n /= 20; n /= 20;
mc146818_set_time(&time); mc146818_set_time(&time);
pm_trace_rtc_abused = true;
return n ? -1 : 0; return n ? -1 : 0;
} }
...@@ -239,9 +244,31 @@ int show_trace_dev_match(char *buf, size_t size) ...@@ -239,9 +244,31 @@ int show_trace_dev_match(char *buf, size_t size)
return ret; return ret;
} }
static int
pm_trace_notify(struct notifier_block *nb, unsigned long mode, void *_unused)
{
switch (mode) {
case PM_POST_HIBERNATION:
case PM_POST_SUSPEND:
if (pm_trace_rtc_abused) {
pm_trace_rtc_abused = false;
pr_warn("Possible incorrect RTC due to pm_trace, please use 'ntpdate' or 'rdate' to reset it.\n");
}
break;
default:
break;
}
return 0;
}
static struct notifier_block pm_trace_nb = {
.notifier_call = pm_trace_notify,
};
static int early_resume_init(void) static int early_resume_init(void)
{ {
hash_value_early_read = read_magic_time(); hash_value_early_read = read_magic_time();
register_pm_notifier(&pm_trace_nb);
return 0; return 0;
} }
......
...@@ -542,6 +542,7 @@ config HANGCHECK_TIMER ...@@ -542,6 +542,7 @@ config HANGCHECK_TIMER
config MMTIMER config MMTIMER
tristate "MMTIMER Memory mapped RTC for SGI Altix" tristate "MMTIMER Memory mapped RTC for SGI Altix"
depends on IA64_GENERIC || IA64_SGI_SN2 depends on IA64_GENERIC || IA64_SGI_SN2
depends on POSIX_TIMERS
default y default y
help help
The mmtimer device allows direct userspace access to the The mmtimer device allows direct userspace access to the
......
...@@ -81,6 +81,7 @@ static struct clock_event_device __percpu *arch_timer_evt; ...@@ -81,6 +81,7 @@ static struct clock_event_device __percpu *arch_timer_evt;
static enum ppi_nr arch_timer_uses_ppi = VIRT_PPI; static enum ppi_nr arch_timer_uses_ppi = VIRT_PPI;
static bool arch_timer_c3stop; static bool arch_timer_c3stop;
static bool arch_timer_mem_use_virtual; static bool arch_timer_mem_use_virtual;
static bool arch_counter_suspend_stop;
static bool evtstrm_enable = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM); static bool evtstrm_enable = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM);
...@@ -576,7 +577,7 @@ static struct clocksource clocksource_counter = { ...@@ -576,7 +577,7 @@ static struct clocksource clocksource_counter = {
.rating = 400, .rating = 400,
.read = arch_counter_read, .read = arch_counter_read,
.mask = CLOCKSOURCE_MASK(56), .mask = CLOCKSOURCE_MASK(56),
.flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP, .flags = CLOCK_SOURCE_IS_CONTINUOUS,
}; };
static struct cyclecounter cyclecounter = { static struct cyclecounter cyclecounter = {
...@@ -616,6 +617,8 @@ static void __init arch_counter_register(unsigned type) ...@@ -616,6 +617,8 @@ static void __init arch_counter_register(unsigned type)
arch_timer_read_counter = arch_counter_get_cntvct_mem; arch_timer_read_counter = arch_counter_get_cntvct_mem;
} }
if (!arch_counter_suspend_stop)
clocksource_counter.flags |= CLOCK_SOURCE_SUSPEND_NONSTOP;
start_count = arch_timer_read_counter(); start_count = arch_timer_read_counter();
clocksource_register_hz(&clocksource_counter, arch_timer_rate); clocksource_register_hz(&clocksource_counter, arch_timer_rate);
cyclecounter.mult = clocksource_counter.mult; cyclecounter.mult = clocksource_counter.mult;
...@@ -907,6 +910,10 @@ static int __init arch_timer_of_init(struct device_node *np) ...@@ -907,6 +910,10 @@ static int __init arch_timer_of_init(struct device_node *np)
of_property_read_bool(np, "arm,cpu-registers-not-fw-configured")) of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
arch_timer_uses_ppi = PHYS_SECURE_PPI; arch_timer_uses_ppi = PHYS_SECURE_PPI;
/* On some systems, the counter stops ticking when in suspend. */
arch_counter_suspend_stop = of_property_read_bool(np,
"arm,no-tick-in-suspend");
return arch_timer_init(); return arch_timer_init();
} }
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init);
...@@ -964,8 +971,9 @@ static int __init arch_timer_mem_init(struct device_node *np) ...@@ -964,8 +971,9 @@ static int __init arch_timer_mem_init(struct device_node *np)
} }
ret= -ENXIO; ret= -ENXIO;
base = arch_counter_base = of_iomap(best_frame, 0); base = arch_counter_base = of_io_request_and_map(best_frame, 0,
if (!base) { "arch_mem_timer");
if (IS_ERR(base)) {
pr_err("arch_timer: Can't map frame's registers\n"); pr_err("arch_timer: Can't map frame's registers\n");
goto out; goto out;
} }
......
...@@ -96,7 +96,7 @@ static int __init bcm2835_timer_init(struct device_node *node) ...@@ -96,7 +96,7 @@ static int __init bcm2835_timer_init(struct device_node *node)
ret = of_property_read_u32(node, "clock-frequency", &freq); ret = of_property_read_u32(node, "clock-frequency", &freq);
if (ret) { if (ret) {
pr_err("Can't read clock-frequency"); pr_err("Can't read clock-frequency");
return ret; goto err_iounmap;
} }
system_clock = base + REG_COUNTER_LO; system_clock = base + REG_COUNTER_LO;
...@@ -108,13 +108,15 @@ static int __init bcm2835_timer_init(struct device_node *node) ...@@ -108,13 +108,15 @@ static int __init bcm2835_timer_init(struct device_node *node)
irq = irq_of_parse_and_map(node, DEFAULT_TIMER); irq = irq_of_parse_and_map(node, DEFAULT_TIMER);
if (irq <= 0) { if (irq <= 0) {
pr_err("Can't parse IRQ"); pr_err("Can't parse IRQ");
return -EINVAL; ret = -EINVAL;
goto err_iounmap;
} }
timer = kzalloc(sizeof(*timer), GFP_KERNEL); timer = kzalloc(sizeof(*timer), GFP_KERNEL);
if (!timer) { if (!timer) {
pr_err("Can't allocate timer struct\n"); pr_err("Can't allocate timer struct\n");
return -ENOMEM; ret = -ENOMEM;
goto err_iounmap;
} }
timer->control = base + REG_CONTROL; timer->control = base + REG_CONTROL;
...@@ -133,7 +135,7 @@ static int __init bcm2835_timer_init(struct device_node *node) ...@@ -133,7 +135,7 @@ static int __init bcm2835_timer_init(struct device_node *node)
ret = setup_irq(irq, &timer->act); ret = setup_irq(irq, &timer->act);
if (ret) { if (ret) {
pr_err("Can't set up timer IRQ\n"); pr_err("Can't set up timer IRQ\n");
return ret; goto err_iounmap;
} }
clockevents_config_and_register(&timer->evt, freq, 0xf, 0xffffffff); clockevents_config_and_register(&timer->evt, freq, 0xf, 0xffffffff);
...@@ -141,6 +143,10 @@ static int __init bcm2835_timer_init(struct device_node *node) ...@@ -141,6 +143,10 @@ static int __init bcm2835_timer_init(struct device_node *node)
pr_info("bcm2835: system timer (irq = %d)\n", irq); pr_info("bcm2835: system timer (irq = %d)\n", irq);
return 0; return 0;
err_iounmap:
iounmap(base);
return ret;
} }
CLOCKSOURCE_OF_DECLARE(bcm2835, "brcm,bcm2835-system-timer", CLOCKSOURCE_OF_DECLARE(bcm2835, "brcm,bcm2835-system-timer",
bcm2835_timer_init); bcm2835_timer_init);
...@@ -58,7 +58,7 @@ config BFIN_RX_DESC_NUM ...@@ -58,7 +58,7 @@ config BFIN_RX_DESC_NUM
config BFIN_MAC_USE_HWSTAMP config BFIN_MAC_USE_HWSTAMP
bool "Use IEEE 1588 hwstamp" bool "Use IEEE 1588 hwstamp"
depends on BFIN_MAC && BF518 depends on BFIN_MAC && BF518
select PTP_1588_CLOCK imply PTP_1588_CLOCK
default y default y
---help--- ---help---
To support the IEEE 1588 Precision Time Protocol (PTP), select y here To support the IEEE 1588 Precision Time Protocol (PTP), select y here
......
...@@ -177,9 +177,9 @@ config AMD_XGBE ...@@ -177,9 +177,9 @@ config AMD_XGBE
depends on X86 || ARM64 || COMPILE_TEST depends on X86 || ARM64 || COMPILE_TEST
select BITREVERSE select BITREVERSE
select CRC32 select CRC32
select PTP_1588_CLOCK
select PHYLIB select PHYLIB
select AMD_XGBE_HAVE_ECC if X86 select AMD_XGBE_HAVE_ECC if X86
imply PTP_1588_CLOCK
---help--- ---help---
This driver supports the AMD 10GbE Ethernet device found on an This driver supports the AMD 10GbE Ethernet device found on an
AMD SoC. AMD SoC.
......
...@@ -422,7 +422,8 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata) ...@@ -422,7 +422,8 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata)
goto err_wq; goto err_wq;
} }
xgbe_ptp_register(pdata); if (IS_REACHABLE(CONFIG_PTP_1588_CLOCK))
xgbe_ptp_register(pdata);
xgbe_debugfs_init(pdata); xgbe_debugfs_init(pdata);
...@@ -448,7 +449,8 @@ void xgbe_deconfig_netdev(struct xgbe_prv_data *pdata) ...@@ -448,7 +449,8 @@ void xgbe_deconfig_netdev(struct xgbe_prv_data *pdata)
xgbe_debugfs_exit(pdata); xgbe_debugfs_exit(pdata);
xgbe_ptp_unregister(pdata); if (IS_REACHABLE(CONFIG_PTP_1588_CLOCK))
xgbe_ptp_unregister(pdata);
pdata->phy_if.phy_exit(pdata); pdata->phy_if.phy_exit(pdata);
......
...@@ -110,7 +110,7 @@ config TIGON3 ...@@ -110,7 +110,7 @@ config TIGON3
depends on PCI depends on PCI
select PHYLIB select PHYLIB
select HWMON select HWMON
select PTP_1588_CLOCK imply PTP_1588_CLOCK
---help--- ---help---
This driver supports Broadcom Tigon3 based gigabit Ethernet cards. This driver supports Broadcom Tigon3 based gigabit Ethernet cards.
...@@ -120,7 +120,7 @@ config TIGON3 ...@@ -120,7 +120,7 @@ config TIGON3
config BNX2X config BNX2X
tristate "Broadcom NetXtremeII 10Gb support" tristate "Broadcom NetXtremeII 10Gb support"
depends on PCI depends on PCI
select PTP_1588_CLOCK imply PTP_1588_CLOCK
select FW_LOADER select FW_LOADER
select ZLIB_INFLATE select ZLIB_INFLATE
select LIBCRC32C select LIBCRC32C
......
...@@ -53,7 +53,7 @@ config THUNDER_NIC_RGX ...@@ -53,7 +53,7 @@ config THUNDER_NIC_RGX
config LIQUIDIO config LIQUIDIO
tristate "Cavium LiquidIO support" tristate "Cavium LiquidIO support"
depends on 64BIT depends on 64BIT
select PTP_1588_CLOCK imply PTP_1588_CLOCK
select FW_LOADER select FW_LOADER
select LIBCRC32C select LIBCRC32C
---help--- ---help---
......
...@@ -25,7 +25,7 @@ config FEC ...@@ -25,7 +25,7 @@ config FEC
ARCH_MXC || SOC_IMX28) ARCH_MXC || SOC_IMX28)
default ARCH_MXC || SOC_IMX28 if ARM default ARCH_MXC || SOC_IMX28 if ARM
select PHYLIB select PHYLIB
select PTP_1588_CLOCK imply PTP_1588_CLOCK
---help--- ---help---
Say Y here if you want to use the built-in 10/100 Fast ethernet Say Y here if you want to use the built-in 10/100 Fast ethernet
controller on some Motorola ColdFire and Freescale i.MX processors. controller on some Motorola ColdFire and Freescale i.MX processors.
......
...@@ -58,7 +58,7 @@ config E1000E ...@@ -58,7 +58,7 @@ config E1000E
tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support" tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support"
depends on PCI && (!SPARC32 || BROKEN) depends on PCI && (!SPARC32 || BROKEN)
select CRC32 select CRC32
select PTP_1588_CLOCK imply PTP_1588_CLOCK
---help--- ---help---
This driver supports the PCI-Express Intel(R) PRO/1000 gigabit This driver supports the PCI-Express Intel(R) PRO/1000 gigabit
ethernet family of adapters. For PCI or PCI-X e1000 adapters, ethernet family of adapters. For PCI or PCI-X e1000 adapters,
...@@ -83,7 +83,7 @@ config E1000E_HWTS ...@@ -83,7 +83,7 @@ config E1000E_HWTS
config IGB config IGB
tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support" tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support"
depends on PCI depends on PCI
select PTP_1588_CLOCK imply PTP_1588_CLOCK
select I2C select I2C
select I2C_ALGOBIT select I2C_ALGOBIT
---help--- ---help---
...@@ -156,7 +156,7 @@ config IXGBE ...@@ -156,7 +156,7 @@ config IXGBE
tristate "Intel(R) 10GbE PCI Express adapters support" tristate "Intel(R) 10GbE PCI Express adapters support"
depends on PCI depends on PCI
select MDIO select MDIO
select PTP_1588_CLOCK imply PTP_1588_CLOCK
---help--- ---help---
This driver supports Intel(R) 10GbE PCI Express family of This driver supports Intel(R) 10GbE PCI Express family of
adapters. For more information on how to identify your adapter, go adapters. For more information on how to identify your adapter, go
...@@ -213,7 +213,7 @@ config IXGBEVF ...@@ -213,7 +213,7 @@ config IXGBEVF
config I40E config I40E
tristate "Intel(R) Ethernet Controller XL710 Family support" tristate "Intel(R) Ethernet Controller XL710 Family support"
select PTP_1588_CLOCK imply PTP_1588_CLOCK
depends on PCI depends on PCI
---help--- ---help---
This driver supports Intel(R) Ethernet Controller XL710 Family of This driver supports Intel(R) Ethernet Controller XL710 Family of
...@@ -264,7 +264,7 @@ config FM10K ...@@ -264,7 +264,7 @@ config FM10K
tristate "Intel(R) FM10000 Ethernet Switch Host Interface Support" tristate "Intel(R) FM10000 Ethernet Switch Host Interface Support"
default n default n
depends on PCI_MSI depends on PCI_MSI
select PTP_1588_CLOCK imply PTP_1588_CLOCK
---help--- ---help---
This driver supports Intel(R) FM10000 Ethernet Switch Host This driver supports Intel(R) FM10000 Ethernet Switch Host
Interface. For more information on how to identify your adapter, Interface. For more information on how to identify your adapter,
......
...@@ -7,7 +7,7 @@ config MLX4_EN ...@@ -7,7 +7,7 @@ config MLX4_EN
depends on MAY_USE_DEVLINK depends on MAY_USE_DEVLINK
depends on PCI depends on PCI
select MLX4_CORE select MLX4_CORE
select PTP_1588_CLOCK imply PTP_1588_CLOCK
---help--- ---help---
This driver supports Mellanox Technologies ConnectX Ethernet This driver supports Mellanox Technologies ConnectX Ethernet
devices. devices.
......
...@@ -14,7 +14,7 @@ config MLX5_CORE ...@@ -14,7 +14,7 @@ config MLX5_CORE
config MLX5_CORE_EN config MLX5_CORE_EN
bool "Mellanox Technologies ConnectX-4 Ethernet support" bool "Mellanox Technologies ConnectX-4 Ethernet support"
depends on NETDEVICES && ETHERNET && PCI && MLX5_CORE depends on NETDEVICES && ETHERNET && PCI && MLX5_CORE
select PTP_1588_CLOCK imply PTP_1588_CLOCK
default n default n
---help--- ---help---
Ethernet support in Mellanox Technologies ConnectX-4 NIC. Ethernet support in Mellanox Technologies ConnectX-4 NIC.
......
...@@ -37,7 +37,7 @@ config RAVB ...@@ -37,7 +37,7 @@ config RAVB
select MII select MII
select MDIO_BITBANG select MDIO_BITBANG
select PHYLIB select PHYLIB
select PTP_1588_CLOCK imply PTP_1588_CLOCK
help help
Renesas Ethernet AVB device driver. Renesas Ethernet AVB device driver.
This driver supports the following SoCs: This driver supports the following SoCs:
......
...@@ -21,7 +21,7 @@ config SXGBE_ETH ...@@ -21,7 +21,7 @@ config SXGBE_ETH
depends on HAS_IOMEM && HAS_DMA depends on HAS_IOMEM && HAS_DMA
select PHYLIB select PHYLIB
select CRC32 select CRC32
select PTP_1588_CLOCK imply PTP_1588_CLOCK
---help--- ---help---
This is the driver for the SXGBE 10G Ethernet IP block found on This is the driver for the SXGBE 10G Ethernet IP block found on
Samsung platforms. Samsung platforms.
......
...@@ -5,7 +5,7 @@ config SFC ...@@ -5,7 +5,7 @@ config SFC
select CRC32 select CRC32
select I2C select I2C
select I2C_ALGOBIT select I2C_ALGOBIT
select PTP_1588_CLOCK imply PTP_1588_CLOCK
---help--- ---help---
This driver supports 10/40-gigabit Ethernet cards based on This driver supports 10/40-gigabit Ethernet cards based on
the Solarflare SFC9000-family and SFC9100-family controllers. the Solarflare SFC9000-family and SFC9100-family controllers.
......
...@@ -4,7 +4,7 @@ config STMMAC_ETH ...@@ -4,7 +4,7 @@ config STMMAC_ETH
select MII select MII
select PHYLIB select PHYLIB
select CRC32 select CRC32
select PTP_1588_CLOCK imply PTP_1588_CLOCK
select RESET_CONTROLLER select RESET_CONTROLLER
---help--- ---help---
This is the driver for the Ethernet IPs are built around a This is the driver for the Ethernet IPs are built around a
......
...@@ -76,7 +76,7 @@ config TI_CPSW ...@@ -76,7 +76,7 @@ config TI_CPSW
config TI_CPTS config TI_CPTS
tristate "TI Common Platform Time Sync (CPTS) Support" tristate "TI Common Platform Time Sync (CPTS) Support"
depends on TI_CPSW || TI_KEYSTONE_NETCP depends on TI_CPSW || TI_KEYSTONE_NETCP
select PTP_1588_CLOCK imply PTP_1588_CLOCK
---help--- ---help---
This driver supports the Common Platform Time Sync unit of This driver supports the Common Platform Time Sync unit of
the CPSW Ethernet Switch and Keystone 2 1g/10g Switch Subsystem. the CPSW Ethernet Switch and Keystone 2 1g/10g Switch Subsystem.
......
...@@ -9,7 +9,7 @@ config TILE_NET ...@@ -9,7 +9,7 @@ config TILE_NET
select CRC32 select CRC32
select TILE_GXIO_MPIPE if TILEGX select TILE_GXIO_MPIPE if TILEGX
select HIGH_RES_TIMERS if TILEGX select HIGH_RES_TIMERS if TILEGX
select PTP_1588_CLOCK if TILEGX imply PTP_1588_CLOCK if TILEGX
---help--- ---help---
This is a standard Linux network device driver for the This is a standard Linux network device driver for the
on-chip Tilera Gigabit Ethernet and XAUI interfaces. on-chip Tilera Gigabit Ethernet and XAUI interfaces.
......
...@@ -6,7 +6,7 @@ menu "PTP clock support" ...@@ -6,7 +6,7 @@ menu "PTP clock support"
config PTP_1588_CLOCK config PTP_1588_CLOCK
tristate "PTP clock support" tristate "PTP clock support"
depends on NET depends on NET && POSIX_TIMERS
select PPS select PPS
select NET_PTP_CLASSIFY select NET_PTP_CLASSIFY
help help
...@@ -28,7 +28,7 @@ config PTP_1588_CLOCK ...@@ -28,7 +28,7 @@ config PTP_1588_CLOCK
config PTP_1588_CLOCK_GIANFAR config PTP_1588_CLOCK_GIANFAR
tristate "Freescale eTSEC as PTP clock" tristate "Freescale eTSEC as PTP clock"
depends on GIANFAR depends on GIANFAR
select PTP_1588_CLOCK depends on PTP_1588_CLOCK
default y default y
help help
This driver adds support for using the eTSEC as a PTP This driver adds support for using the eTSEC as a PTP
...@@ -42,7 +42,7 @@ config PTP_1588_CLOCK_GIANFAR ...@@ -42,7 +42,7 @@ config PTP_1588_CLOCK_GIANFAR
config PTP_1588_CLOCK_IXP46X config PTP_1588_CLOCK_IXP46X
tristate "Intel IXP46x as PTP clock" tristate "Intel IXP46x as PTP clock"
depends on IXP4XX_ETH depends on IXP4XX_ETH
select PTP_1588_CLOCK depends on PTP_1588_CLOCK
default y default y
help help
This driver adds support for using the IXP46X as a PTP This driver adds support for using the IXP46X as a PTP
...@@ -60,7 +60,7 @@ config DP83640_PHY ...@@ -60,7 +60,7 @@ config DP83640_PHY
tristate "Driver for the National Semiconductor DP83640 PHYTER" tristate "Driver for the National Semiconductor DP83640 PHYTER"
depends on NETWORK_PHY_TIMESTAMPING depends on NETWORK_PHY_TIMESTAMPING
depends on PHYLIB depends on PHYLIB
select PTP_1588_CLOCK depends on PTP_1588_CLOCK
---help--- ---help---
Supports the DP83640 PHYTER with IEEE 1588 features. Supports the DP83640 PHYTER with IEEE 1588 features.
...@@ -76,7 +76,7 @@ config PTP_1588_CLOCK_PCH ...@@ -76,7 +76,7 @@ config PTP_1588_CLOCK_PCH
tristate "Intel PCH EG20T as PTP clock" tristate "Intel PCH EG20T as PTP clock"
depends on X86_32 || COMPILE_TEST depends on X86_32 || COMPILE_TEST
depends on HAS_IOMEM && NET depends on HAS_IOMEM && NET
select PTP_1588_CLOCK imply PTP_1588_CLOCK
help help
This driver adds support for using the PCH EG20T as a PTP This driver adds support for using the PCH EG20T as a PTP
clock. The hardware supports time stamping of PTP packets clock. The hardware supports time stamping of PTP packets
......
...@@ -191,6 +191,13 @@ static inline void cmos_write_bank2(unsigned char val, unsigned char addr) ...@@ -191,6 +191,13 @@ static inline void cmos_write_bank2(unsigned char val, unsigned char addr)
static int cmos_read_time(struct device *dev, struct rtc_time *t) static int cmos_read_time(struct device *dev, struct rtc_time *t)
{ {
/*
* If pm_trace abused the RTC for storage, set the timespec to 0,
* which tells the caller that this RTC value is unusable.
*/
if (!pm_trace_rtc_valid())
return -EIO;
/* REVISIT: if the clock has a "century" register, use /* REVISIT: if the clock has a "century" register, use
* that instead of the heuristic in mc146818_get_time(). * that instead of the heuristic in mc146818_get_time().
* That'll make Y3K compatility (year > 2070) easy! * That'll make Y3K compatility (year > 2070) easy!
......
...@@ -1169,8 +1169,10 @@ static int de_thread(struct task_struct *tsk) ...@@ -1169,8 +1169,10 @@ static int de_thread(struct task_struct *tsk)
/* we have changed execution domain */ /* we have changed execution domain */
tsk->exit_signal = SIGCHLD; tsk->exit_signal = SIGCHLD;
#ifdef CONFIG_POSIX_TIMERS
exit_itimers(sig); exit_itimers(sig);
flush_itimer_signals(); flush_itimer_signals();
#endif
if (atomic_read(&oldsighand->count) != 1) { if (atomic_read(&oldsighand->count) != 1) {
struct sighand_struct *newsighand; struct sighand_struct *newsighand;
......
...@@ -10,7 +10,12 @@ enum alarmtimer_type { ...@@ -10,7 +10,12 @@ enum alarmtimer_type {
ALARM_REALTIME, ALARM_REALTIME,
ALARM_BOOTTIME, ALARM_BOOTTIME,
/* Supported types end here */
ALARM_NUMTYPE, ALARM_NUMTYPE,
/* Used for tracing information. No usable types. */
ALARM_REALTIME_FREEZER,
ALARM_BOOTTIME_FREEZER,
}; };
enum alarmtimer_restart { enum alarmtimer_restart {
......
...@@ -169,7 +169,10 @@ static inline u32 clocksource_hz2mult(u32 hz, u32 shift_constant) ...@@ -169,7 +169,10 @@ static inline u32 clocksource_hz2mult(u32 hz, u32 shift_constant)
* @mult: cycle to nanosecond multiplier * @mult: cycle to nanosecond multiplier
* @shift: cycle to nanosecond divisor (power of two) * @shift: cycle to nanosecond divisor (power of two)
* *
* Converts cycles to nanoseconds, using the given mult and shift. * Converts clocksource cycles to nanoseconds, using the given @mult and @shift.
* The code is optimized for performance and is not intended to work
* with absolute clocksource cycles (as those will easily overflow),
* but is only intended to be used with relative (delta) clocksource cycles.
* *
* XXX - This could use some mult_lxl_ll() asm optimization * XXX - This could use some mult_lxl_ll() asm optimization
*/ */
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <asm/mc146818rtc.h> /* register access macros */ #include <asm/mc146818rtc.h> /* register access macros */
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pm-trace.h>
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/spinlock.h> /* spinlock_t */ #include <linux/spinlock.h> /* spinlock_t */
......
#ifndef PM_TRACE_H #ifndef PM_TRACE_H
#define PM_TRACE_H #define PM_TRACE_H
#include <linux/types.h>
#ifdef CONFIG_PM_TRACE #ifdef CONFIG_PM_TRACE
#include <asm/pm-trace.h> #include <asm/pm-trace.h>
#include <linux/types.h>
extern int pm_trace_enabled; extern int pm_trace_enabled;
extern bool pm_trace_rtc_abused;
static inline bool pm_trace_rtc_valid(void)
{
return !pm_trace_rtc_abused;
}
static inline int pm_trace_is_enabled(void) static inline int pm_trace_is_enabled(void)
{ {
...@@ -24,6 +30,7 @@ extern int show_trace_dev_match(char *buf, size_t size); ...@@ -24,6 +30,7 @@ extern int show_trace_dev_match(char *buf, size_t size);
#else #else
static inline bool pm_trace_rtc_valid(void) { return true; }
static inline int pm_trace_is_enabled(void) { return 0; } static inline int pm_trace_is_enabled(void) { return 0; }
#define TRACE_DEVICE(dev) do { } while (0) #define TRACE_DEVICE(dev) do { } while (0)
......
...@@ -130,30 +130,6 @@ struct ptp_clock_info { ...@@ -130,30 +130,6 @@ struct ptp_clock_info {
struct ptp_clock; struct ptp_clock;
/**
* ptp_clock_register() - register a PTP hardware clock driver
*
* @info: Structure describing the new clock.
* @parent: Pointer to the parent device of the new clock.
*
* Returns a valid pointer on success or PTR_ERR on failure. If PHC
* support is missing at the configuration level, this function
* returns NULL, and drivers are expected to gracefully handle that
* case separately.
*/
extern struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
struct device *parent);
/**
* ptp_clock_unregister() - unregister a PTP hardware clock driver
*
* @ptp: The clock to remove from service.
*/
extern int ptp_clock_unregister(struct ptp_clock *ptp);
enum ptp_clock_events { enum ptp_clock_events {
PTP_CLOCK_ALARM, PTP_CLOCK_ALARM,
PTP_CLOCK_EXTTS, PTP_CLOCK_EXTTS,
...@@ -179,6 +155,31 @@ struct ptp_clock_event { ...@@ -179,6 +155,31 @@ struct ptp_clock_event {
}; };
}; };
#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
/**
* ptp_clock_register() - register a PTP hardware clock driver
*
* @info: Structure describing the new clock.
* @parent: Pointer to the parent device of the new clock.
*
* Returns a valid pointer on success or PTR_ERR on failure. If PHC
* support is missing at the configuration level, this function
* returns NULL, and drivers are expected to gracefully handle that
* case separately.
*/
extern struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
struct device *parent);
/**
* ptp_clock_unregister() - unregister a PTP hardware clock driver
*
* @ptp: The clock to remove from service.
*/
extern int ptp_clock_unregister(struct ptp_clock *ptp);
/** /**
* ptp_clock_event() - notify the PTP layer about an event * ptp_clock_event() - notify the PTP layer about an event
* *
...@@ -210,4 +211,20 @@ extern int ptp_clock_index(struct ptp_clock *ptp); ...@@ -210,4 +211,20 @@ extern int ptp_clock_index(struct ptp_clock *ptp);
int ptp_find_pin(struct ptp_clock *ptp, int ptp_find_pin(struct ptp_clock *ptp,
enum ptp_pin_function func, unsigned int chan); enum ptp_pin_function func, unsigned int chan);
#else
static inline struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
struct device *parent)
{ return NULL; }
static inline int ptp_clock_unregister(struct ptp_clock *ptp)
{ return 0; }
static inline void ptp_clock_event(struct ptp_clock *ptp,
struct ptp_clock_event *event)
{ }
static inline int ptp_clock_index(struct ptp_clock *ptp)
{ return -1; }
static inline int ptp_find_pin(struct ptp_clock *ptp,
enum ptp_pin_function func, unsigned int chan)
{ return -1; }
#endif
#endif #endif
...@@ -172,8 +172,6 @@ extern int do_setitimer(int which, struct itimerval *value, ...@@ -172,8 +172,6 @@ extern int do_setitimer(int which, struct itimerval *value,
struct itimerval *ovalue); struct itimerval *ovalue);
extern int do_getitimer(int which, struct itimerval *value); extern int do_getitimer(int which, struct itimerval *value);
extern unsigned int alarm_setitimer(unsigned int seconds);
extern long do_utimes(int dfd, const char __user *filename, struct timespec *times, int flags); extern long do_utimes(int dfd, const char __user *filename, struct timespec *times, int flags);
struct tms; struct tms;
......
...@@ -249,6 +249,7 @@ static inline u64 ktime_get_raw_ns(void) ...@@ -249,6 +249,7 @@ static inline u64 ktime_get_raw_ns(void)
extern u64 ktime_get_mono_fast_ns(void); extern u64 ktime_get_mono_fast_ns(void);
extern u64 ktime_get_raw_fast_ns(void); extern u64 ktime_get_raw_fast_ns(void);
extern u64 ktime_get_boot_fast_ns(void);
/* /*
* Timespec interfaces utilizing the ktime based ones * Timespec interfaces utilizing the ktime based ones
......
#undef TRACE_SYSTEM
#define TRACE_SYSTEM alarmtimer
#if !defined(_TRACE_ALARMTIMER_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_ALARMTIMER_H
#include <linux/alarmtimer.h>
#include <linux/rtc.h>
#include <linux/tracepoint.h>
TRACE_DEFINE_ENUM(ALARM_REALTIME);
TRACE_DEFINE_ENUM(ALARM_BOOTTIME);
TRACE_DEFINE_ENUM(ALARM_REALTIME_FREEZER);
TRACE_DEFINE_ENUM(ALARM_BOOTTIME_FREEZER);
#define show_alarm_type(type) __print_flags(type, " | ", \
{ 1 << ALARM_REALTIME, "REALTIME" }, \
{ 1 << ALARM_BOOTTIME, "BOOTTIME" }, \
{ 1 << ALARM_REALTIME_FREEZER, "REALTIME Freezer" }, \
{ 1 << ALARM_BOOTTIME_FREEZER, "BOOTTIME Freezer" })
TRACE_EVENT(alarmtimer_suspend,
TP_PROTO(ktime_t expires, int flag),
TP_ARGS(expires, flag),
TP_STRUCT__entry(
__field(s64, expires)
__field(unsigned char, alarm_type)
),
TP_fast_assign(
__entry->expires = expires.tv64;
__entry->alarm_type = flag;
),
TP_printk("alarmtimer type:%s expires:%llu",
show_alarm_type((1 << __entry->alarm_type)),
__entry->expires
)
);
DECLARE_EVENT_CLASS(alarm_class,
TP_PROTO(struct alarm *alarm, ktime_t now),
TP_ARGS(alarm, now),
TP_STRUCT__entry(
__field(void *, alarm)
__field(unsigned char, alarm_type)
__field(s64, expires)
__field(s64, now)
),
TP_fast_assign(
__entry->alarm = alarm;
__entry->alarm_type = alarm->type;
__entry->expires = alarm->node.expires.tv64;
__entry->now = now.tv64;
),
TP_printk("alarmtimer:%p type:%s expires:%llu now:%llu",
__entry->alarm,
show_alarm_type((1 << __entry->alarm_type)),
__entry->expires,
__entry->now
)
);
DEFINE_EVENT(alarm_class, alarmtimer_fired,
TP_PROTO(struct alarm *alarm, ktime_t now),
TP_ARGS(alarm, now)
);
DEFINE_EVENT(alarm_class, alarmtimer_start,
TP_PROTO(struct alarm *alarm, ktime_t now),
TP_ARGS(alarm, now)
);
DEFINE_EVENT(alarm_class, alarmtimer_cancel,
TP_PROTO(struct alarm *alarm, ktime_t now),
TP_ARGS(alarm, now)
);
#endif /* _TRACE_ALARMTIMER_H */
/* This part must be outside protection */
#include <trace/define_trace.h>
...@@ -1457,6 +1457,23 @@ config SYSCTL_SYSCALL ...@@ -1457,6 +1457,23 @@ config SYSCTL_SYSCALL
If unsure say N here. If unsure say N here.
config POSIX_TIMERS
bool "Posix Clocks & timers" if EXPERT
default y
help
This includes native support for POSIX timers to the kernel.
Some embedded systems have no use for them and therefore they
can be configured out to reduce the size of the kernel image.
When this option is disabled, the following syscalls won't be
available: timer_create, timer_gettime: timer_getoverrun,
timer_settime, timer_delete, clock_adjtime, getitimer,
setitimer, alarm. Furthermore, the clock_settime, clock_gettime,
clock_getres and clock_nanosleep syscalls will be limited to
CLOCK_REALTIME, CLOCK_MONOTONIC and CLOCK_BOOTTIME only.
If unsure say y.
config KALLSYMS config KALLSYMS
bool "Load all symbols for debugging/ksymoops" if EXPERT bool "Load all symbols for debugging/ksymoops" if EXPERT
default y default y
......
...@@ -307,12 +307,17 @@ static inline long put_compat_itimerval(struct compat_itimerval __user *o, ...@@ -307,12 +307,17 @@ static inline long put_compat_itimerval(struct compat_itimerval __user *o,
__put_user(i->it_value.tv_usec, &o->it_value.tv_usec))); __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
} }
asmlinkage long sys_ni_posix_timers(void);
COMPAT_SYSCALL_DEFINE2(getitimer, int, which, COMPAT_SYSCALL_DEFINE2(getitimer, int, which,
struct compat_itimerval __user *, it) struct compat_itimerval __user *, it)
{ {
struct itimerval kit; struct itimerval kit;
int error; int error;
if (!IS_ENABLED(CONFIG_POSIX_TIMERS))
return sys_ni_posix_timers();
error = do_getitimer(which, &kit); error = do_getitimer(which, &kit);
if (!error && put_compat_itimerval(it, &kit)) if (!error && put_compat_itimerval(it, &kit))
error = -EFAULT; error = -EFAULT;
...@@ -326,6 +331,9 @@ COMPAT_SYSCALL_DEFINE3(setitimer, int, which, ...@@ -326,6 +331,9 @@ COMPAT_SYSCALL_DEFINE3(setitimer, int, which,
struct itimerval kin, kout; struct itimerval kin, kout;
int error; int error;
if (!IS_ENABLED(CONFIG_POSIX_TIMERS))
return sys_ni_posix_timers();
if (in) { if (in) {
if (get_compat_itimerval(&kin, in)) if (get_compat_itimerval(&kin, in))
return -EFAULT; return -EFAULT;
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#include <linux/writeback.h> #include <linux/writeback.h>
#include <linux/shm.h> #include <linux/shm.h>
#include <linux/kcov.h> #include <linux/kcov.h>
#include <linux/random.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/unistd.h> #include <asm/unistd.h>
...@@ -91,11 +92,10 @@ static void __exit_signal(struct task_struct *tsk) ...@@ -91,11 +92,10 @@ static void __exit_signal(struct task_struct *tsk)
lockdep_tasklist_lock_is_held()); lockdep_tasklist_lock_is_held());
spin_lock(&sighand->siglock); spin_lock(&sighand->siglock);
#ifdef CONFIG_POSIX_TIMERS
posix_cpu_timers_exit(tsk); posix_cpu_timers_exit(tsk);
if (group_dead) { if (group_dead) {
posix_cpu_timers_exit_group(tsk); posix_cpu_timers_exit_group(tsk);
tty = sig->tty;
sig->tty = NULL;
} else { } else {
/* /*
* This can only happen if the caller is de_thread(). * This can only happen if the caller is de_thread().
...@@ -104,7 +104,13 @@ static void __exit_signal(struct task_struct *tsk) ...@@ -104,7 +104,13 @@ static void __exit_signal(struct task_struct *tsk)
*/ */
if (unlikely(has_group_leader_pid(tsk))) if (unlikely(has_group_leader_pid(tsk)))
posix_cpu_timers_exit_group(tsk); posix_cpu_timers_exit_group(tsk);
}
#endif
if (group_dead) {
tty = sig->tty;
sig->tty = NULL;
} else {
/* /*
* If there is any task waiting for the group exit * If there is any task waiting for the group exit
* then notify it: * then notify it:
...@@ -116,6 +122,9 @@ static void __exit_signal(struct task_struct *tsk) ...@@ -116,6 +122,9 @@ static void __exit_signal(struct task_struct *tsk)
sig->curr_target = next_thread(tsk); sig->curr_target = next_thread(tsk);
} }
add_device_randomness((const void*) &tsk->se.sum_exec_runtime,
sizeof(unsigned long long));
/* /*
* Accumulate here the counters for all threads as they die. We could * Accumulate here the counters for all threads as they die. We could
* skip the group leader because it is the last user of signal_struct, * skip the group leader because it is the last user of signal_struct,
...@@ -799,8 +808,10 @@ void __noreturn do_exit(long code) ...@@ -799,8 +808,10 @@ void __noreturn do_exit(long code)
acct_update_integrals(tsk); acct_update_integrals(tsk);
group_dead = atomic_dec_and_test(&tsk->signal->live); group_dead = atomic_dec_and_test(&tsk->signal->live);
if (group_dead) { if (group_dead) {
#ifdef CONFIG_POSIX_TIMERS
hrtimer_cancel(&tsk->signal->real_timer); hrtimer_cancel(&tsk->signal->real_timer);
exit_itimers(tsk->signal); exit_itimers(tsk->signal);
#endif
if (tsk->mm) if (tsk->mm)
setmax_mm_hiwater_rss(&tsk->signal->maxrss, tsk->mm); setmax_mm_hiwater_rss(&tsk->signal->maxrss, tsk->mm);
} }
......
...@@ -1347,8 +1347,10 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) ...@@ -1347,8 +1347,10 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
seqlock_init(&sig->stats_lock); seqlock_init(&sig->stats_lock);
prev_cputime_init(&sig->prev_cputime); prev_cputime_init(&sig->prev_cputime);
#ifdef CONFIG_POSIX_TIMERS
hrtimer_init(&sig->real_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); hrtimer_init(&sig->real_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
sig->real_timer.function = it_real_fn; sig->real_timer.function = it_real_fn;
#endif
task_lock(current->group_leader); task_lock(current->group_leader);
memcpy(sig->rlim, current->signal->rlim, sizeof sig->rlim); memcpy(sig->rlim, current->signal->rlim, sizeof sig->rlim);
......
...@@ -427,6 +427,7 @@ void flush_signals(struct task_struct *t) ...@@ -427,6 +427,7 @@ void flush_signals(struct task_struct *t)
spin_unlock_irqrestore(&t->sighand->siglock, flags); spin_unlock_irqrestore(&t->sighand->siglock, flags);
} }
#ifdef CONFIG_POSIX_TIMERS
static void __flush_itimer_signals(struct sigpending *pending) static void __flush_itimer_signals(struct sigpending *pending)
{ {
sigset_t signal, retain; sigset_t signal, retain;
...@@ -460,6 +461,7 @@ void flush_itimer_signals(void) ...@@ -460,6 +461,7 @@ void flush_itimer_signals(void)
__flush_itimer_signals(&tsk->signal->shared_pending); __flush_itimer_signals(&tsk->signal->shared_pending);
spin_unlock_irqrestore(&tsk->sighand->siglock, flags); spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
} }
#endif
void ignore_signals(struct task_struct *t) void ignore_signals(struct task_struct *t)
{ {
...@@ -567,6 +569,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) ...@@ -567,6 +569,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
if (!signr) { if (!signr) {
signr = __dequeue_signal(&tsk->signal->shared_pending, signr = __dequeue_signal(&tsk->signal->shared_pending,
mask, info); mask, info);
#ifdef CONFIG_POSIX_TIMERS
/* /*
* itimer signal ? * itimer signal ?
* *
...@@ -590,6 +593,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) ...@@ -590,6 +593,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
hrtimer_restart(tmr); hrtimer_restart(tmr);
} }
} }
#endif
} }
recalc_sigpending(); recalc_sigpending();
...@@ -611,6 +615,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) ...@@ -611,6 +615,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
*/ */
current->jobctl |= JOBCTL_STOP_DEQUEUED; current->jobctl |= JOBCTL_STOP_DEQUEUED;
} }
#ifdef CONFIG_POSIX_TIMERS
if ((info->si_code & __SI_MASK) == __SI_TIMER && info->si_sys_private) { if ((info->si_code & __SI_MASK) == __SI_TIMER && info->si_sys_private) {
/* /*
* Release the siglock to ensure proper locking order * Release the siglock to ensure proper locking order
...@@ -622,6 +627,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) ...@@ -622,6 +627,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
do_schedule_next_timer(info); do_schedule_next_timer(info);
spin_lock(&tsk->sighand->siglock); spin_lock(&tsk->sighand->siglock);
} }
#endif
return signr; return signr;
} }
......
...@@ -1416,7 +1416,8 @@ int do_prlimit(struct task_struct *tsk, unsigned int resource, ...@@ -1416,7 +1416,8 @@ int do_prlimit(struct task_struct *tsk, unsigned int resource,
* applications, so we live with it * applications, so we live with it
*/ */
if (!retval && new_rlim && resource == RLIMIT_CPU && if (!retval && new_rlim && resource == RLIMIT_CPU &&
new_rlim->rlim_cur != RLIM_INFINITY) new_rlim->rlim_cur != RLIM_INFINITY &&
IS_ENABLED(CONFIG_POSIX_TIMERS))
update_rlimit_cpu(tsk, new_rlim->rlim_cur); update_rlimit_cpu(tsk, new_rlim->rlim_cur);
out: out:
read_unlock(&tasklist_lock); read_unlock(&tasklist_lock);
......
obj-y += time.o timer.o hrtimer.o itimer.o posix-timers.o posix-cpu-timers.o obj-y += time.o timer.o hrtimer.o
obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o
obj-y += timeconv.o timecounter.o posix-clock.o alarmtimer.o obj-y += timeconv.o timecounter.o alarmtimer.o
ifeq ($(CONFIG_POSIX_TIMERS),y)
obj-y += posix-timers.o posix-cpu-timers.o posix-clock.o itimer.o
else
obj-y += posix-stubs.o
endif
obj-$(CONFIG_GENERIC_CLOCKEVENTS) += clockevents.o tick-common.o obj-$(CONFIG_GENERIC_CLOCKEVENTS) += clockevents.o tick-common.o
ifeq ($(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST),y) ifeq ($(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST),y)
......
...@@ -26,6 +26,9 @@ ...@@ -26,6 +26,9 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#define CREATE_TRACE_POINTS
#include <trace/events/alarmtimer.h>
/** /**
* struct alarm_base - Alarm timer bases * struct alarm_base - Alarm timer bases
* @lock: Lock for syncrhonized access to the base * @lock: Lock for syncrhonized access to the base
...@@ -40,7 +43,9 @@ static struct alarm_base { ...@@ -40,7 +43,9 @@ static struct alarm_base {
clockid_t base_clockid; clockid_t base_clockid;
} alarm_bases[ALARM_NUMTYPE]; } alarm_bases[ALARM_NUMTYPE];
/* freezer delta & lock used to handle clock_nanosleep triggered wakeups */ /* freezer information to handle clock_nanosleep triggered wakeups */
static enum alarmtimer_type freezer_alarmtype;
static ktime_t freezer_expires;
static ktime_t freezer_delta; static ktime_t freezer_delta;
static DEFINE_SPINLOCK(freezer_delta_lock); static DEFINE_SPINLOCK(freezer_delta_lock);
...@@ -194,6 +199,7 @@ static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer) ...@@ -194,6 +199,7 @@ static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer)
} }
spin_unlock_irqrestore(&base->lock, flags); spin_unlock_irqrestore(&base->lock, flags);
trace_alarmtimer_fired(alarm, base->gettime());
return ret; return ret;
} }
...@@ -218,15 +224,16 @@ EXPORT_SYMBOL_GPL(alarm_expires_remaining); ...@@ -218,15 +224,16 @@ EXPORT_SYMBOL_GPL(alarm_expires_remaining);
*/ */
static int alarmtimer_suspend(struct device *dev) static int alarmtimer_suspend(struct device *dev)
{ {
struct rtc_time tm; ktime_t min, now, expires;
ktime_t min, now; int i, ret, type;
unsigned long flags;
struct rtc_device *rtc; struct rtc_device *rtc;
int i; unsigned long flags;
int ret; struct rtc_time tm;
spin_lock_irqsave(&freezer_delta_lock, flags); spin_lock_irqsave(&freezer_delta_lock, flags);
min = freezer_delta; min = freezer_delta;
expires = freezer_expires;
type = freezer_alarmtype;
freezer_delta = ktime_set(0, 0); freezer_delta = ktime_set(0, 0);
spin_unlock_irqrestore(&freezer_delta_lock, flags); spin_unlock_irqrestore(&freezer_delta_lock, flags);
...@@ -247,8 +254,11 @@ static int alarmtimer_suspend(struct device *dev) ...@@ -247,8 +254,11 @@ static int alarmtimer_suspend(struct device *dev)
if (!next) if (!next)
continue; continue;
delta = ktime_sub(next->expires, base->gettime()); delta = ktime_sub(next->expires, base->gettime());
if (!min.tv64 || (delta.tv64 < min.tv64)) if (!min.tv64 || (delta.tv64 < min.tv64)) {
expires = next->expires;
min = delta; min = delta;
type = i;
}
} }
if (min.tv64 == 0) if (min.tv64 == 0)
return 0; return 0;
...@@ -258,6 +268,8 @@ static int alarmtimer_suspend(struct device *dev) ...@@ -258,6 +268,8 @@ static int alarmtimer_suspend(struct device *dev)
return -EBUSY; return -EBUSY;
} }
trace_alarmtimer_suspend(expires, type);
/* Setup an rtc timer to fire that far in the future */ /* Setup an rtc timer to fire that far in the future */
rtc_timer_cancel(rtc, &rtctimer); rtc_timer_cancel(rtc, &rtctimer);
rtc_read_time(rtc, &tm); rtc_read_time(rtc, &tm);
...@@ -295,15 +307,32 @@ static int alarmtimer_resume(struct device *dev) ...@@ -295,15 +307,32 @@ static int alarmtimer_resume(struct device *dev)
static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type) static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type)
{ {
ktime_t delta; struct alarm_base *base;
unsigned long flags; unsigned long flags;
struct alarm_base *base = &alarm_bases[type]; ktime_t delta;
switch(type) {
case ALARM_REALTIME:
base = &alarm_bases[ALARM_REALTIME];
type = ALARM_REALTIME_FREEZER;
break;
case ALARM_BOOTTIME:
base = &alarm_bases[ALARM_BOOTTIME];
type = ALARM_BOOTTIME_FREEZER;
break;
default:
WARN_ONCE(1, "Invalid alarm type: %d\n", type);
return;
}
delta = ktime_sub(absexp, base->gettime()); delta = ktime_sub(absexp, base->gettime());
spin_lock_irqsave(&freezer_delta_lock, flags); spin_lock_irqsave(&freezer_delta_lock, flags);
if (!freezer_delta.tv64 || (delta.tv64 < freezer_delta.tv64)) if (!freezer_delta.tv64 || (delta.tv64 < freezer_delta.tv64)) {
freezer_delta = delta; freezer_delta = delta;
freezer_expires = absexp;
freezer_alarmtype = type;
}
spin_unlock_irqrestore(&freezer_delta_lock, flags); spin_unlock_irqrestore(&freezer_delta_lock, flags);
} }
...@@ -342,6 +371,8 @@ void alarm_start(struct alarm *alarm, ktime_t start) ...@@ -342,6 +371,8 @@ void alarm_start(struct alarm *alarm, ktime_t start)
alarmtimer_enqueue(base, alarm); alarmtimer_enqueue(base, alarm);
hrtimer_start(&alarm->timer, alarm->node.expires, HRTIMER_MODE_ABS); hrtimer_start(&alarm->timer, alarm->node.expires, HRTIMER_MODE_ABS);
spin_unlock_irqrestore(&base->lock, flags); spin_unlock_irqrestore(&base->lock, flags);
trace_alarmtimer_start(alarm, base->gettime());
} }
EXPORT_SYMBOL_GPL(alarm_start); EXPORT_SYMBOL_GPL(alarm_start);
...@@ -390,6 +421,8 @@ int alarm_try_to_cancel(struct alarm *alarm) ...@@ -390,6 +421,8 @@ int alarm_try_to_cancel(struct alarm *alarm)
if (ret >= 0) if (ret >= 0)
alarmtimer_dequeue(base, alarm); alarmtimer_dequeue(base, alarm);
spin_unlock_irqrestore(&base->lock, flags); spin_unlock_irqrestore(&base->lock, flags);
trace_alarmtimer_cancel(alarm, base->gettime());
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(alarm_try_to_cancel); EXPORT_SYMBOL_GPL(alarm_try_to_cancel);
...@@ -846,8 +879,10 @@ static int __init alarmtimer_init(void) ...@@ -846,8 +879,10 @@ static int __init alarmtimer_init(void)
alarmtimer_rtc_timer_init(); alarmtimer_rtc_timer_init();
posix_timers_register_clock(CLOCK_REALTIME_ALARM, &alarm_clock); if (IS_ENABLED(CONFIG_POSIX_TIMERS)) {
posix_timers_register_clock(CLOCK_BOOTTIME_ALARM, &alarm_clock); posix_timers_register_clock(CLOCK_REALTIME_ALARM, &alarm_clock);
posix_timers_register_clock(CLOCK_BOOTTIME_ALARM, &alarm_clock);
}
/* Initialize alarm bases */ /* Initialize alarm bases */
alarm_bases[ALARM_REALTIME].base_clockid = CLOCK_REALTIME; alarm_bases[ALARM_REALTIME].base_clockid = CLOCK_REALTIME;
......
...@@ -1742,15 +1742,19 @@ schedule_hrtimeout_range_clock(ktime_t *expires, u64 delta, ...@@ -1742,15 +1742,19 @@ schedule_hrtimeout_range_clock(ktime_t *expires, u64 delta,
* You can set the task state as follows - * You can set the task state as follows -
* *
* %TASK_UNINTERRUPTIBLE - at least @timeout time is guaranteed to * %TASK_UNINTERRUPTIBLE - at least @timeout time is guaranteed to
* pass before the routine returns. * pass before the routine returns unless the current task is explicitly
* woken up, (e.g. by wake_up_process()).
* *
* %TASK_INTERRUPTIBLE - the routine may return early if a signal is * %TASK_INTERRUPTIBLE - the routine may return early if a signal is
* delivered to the current task. * delivered to the current task or the current task is explicitly woken
* up.
* *
* The current task state is guaranteed to be TASK_RUNNING when this * The current task state is guaranteed to be TASK_RUNNING when this
* routine returns. * routine returns.
* *
* Returns 0 when the timer has expired otherwise -EINTR * Returns 0 when the timer has expired. If the task was woken before the
* timer expired by a signal (only possible in state TASK_INTERRUPTIBLE) or
* by an explicit wakeup, it returns -EINTR.
*/ */
int __sched schedule_hrtimeout_range(ktime_t *expires, u64 delta, int __sched schedule_hrtimeout_range(ktime_t *expires, u64 delta,
const enum hrtimer_mode mode) const enum hrtimer_mode mode)
...@@ -1772,15 +1776,19 @@ EXPORT_SYMBOL_GPL(schedule_hrtimeout_range); ...@@ -1772,15 +1776,19 @@ EXPORT_SYMBOL_GPL(schedule_hrtimeout_range);
* You can set the task state as follows - * You can set the task state as follows -
* *
* %TASK_UNINTERRUPTIBLE - at least @timeout time is guaranteed to * %TASK_UNINTERRUPTIBLE - at least @timeout time is guaranteed to
* pass before the routine returns. * pass before the routine returns unless the current task is explicitly
* woken up, (e.g. by wake_up_process()).
* *
* %TASK_INTERRUPTIBLE - the routine may return early if a signal is * %TASK_INTERRUPTIBLE - the routine may return early if a signal is
* delivered to the current task. * delivered to the current task or the current task is explicitly woken
* up.
* *
* The current task state is guaranteed to be TASK_RUNNING when this * The current task state is guaranteed to be TASK_RUNNING when this
* routine returns. * routine returns.
* *
* Returns 0 when the timer has expired otherwise -EINTR * Returns 0 when the timer has expired. If the task was woken before the
* timer expired by a signal (only possible in state TASK_INTERRUPTIBLE) or
* by an explicit wakeup, it returns -EINTR.
*/ */
int __sched schedule_hrtimeout(ktime_t *expires, int __sched schedule_hrtimeout(ktime_t *expires,
const enum hrtimer_mode mode) const enum hrtimer_mode mode)
......
...@@ -238,6 +238,8 @@ int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) ...@@ -238,6 +238,8 @@ int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
return 0; return 0;
} }
#ifdef __ARCH_WANT_SYS_ALARM
/** /**
* alarm_setitimer - set alarm in seconds * alarm_setitimer - set alarm in seconds
* *
...@@ -250,7 +252,7 @@ int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) ...@@ -250,7 +252,7 @@ int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
* On 32 bit machines the seconds value is limited to (INT_MAX/2) to avoid * On 32 bit machines the seconds value is limited to (INT_MAX/2) to avoid
* negative timeval settings which would cause immediate expiry. * negative timeval settings which would cause immediate expiry.
*/ */
unsigned int alarm_setitimer(unsigned int seconds) static unsigned int alarm_setitimer(unsigned int seconds)
{ {
struct itimerval it_new, it_old; struct itimerval it_new, it_old;
...@@ -275,6 +277,17 @@ unsigned int alarm_setitimer(unsigned int seconds) ...@@ -275,6 +277,17 @@ unsigned int alarm_setitimer(unsigned int seconds)
return it_old.it_value.tv_sec; return it_old.it_value.tv_sec;
} }
/*
* For backwards compatibility? This can be done in libc so Alpha
* and all newer ports shouldn't need it.
*/
SYSCALL_DEFINE1(alarm, unsigned int, seconds)
{
return alarm_setitimer(seconds);
}
#endif
SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, value, SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, value,
struct itimerval __user *, ovalue) struct itimerval __user *, ovalue)
{ {
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/kernel_stat.h> #include <linux/kernel_stat.h>
#include <trace/events/timer.h> #include <trace/events/timer.h>
#include <linux/random.h>
#include <linux/tick.h> #include <linux/tick.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
...@@ -447,10 +446,7 @@ static void cleanup_timers(struct list_head *head) ...@@ -447,10 +446,7 @@ static void cleanup_timers(struct list_head *head)
*/ */
void posix_cpu_timers_exit(struct task_struct *tsk) void posix_cpu_timers_exit(struct task_struct *tsk)
{ {
add_device_randomness((const void*) &tsk->se.sum_exec_runtime,
sizeof(unsigned long long));
cleanup_timers(tsk->cpu_timers); cleanup_timers(tsk->cpu_timers);
} }
void posix_cpu_timers_exit_group(struct task_struct *tsk) void posix_cpu_timers_exit_group(struct task_struct *tsk)
{ {
......
/*
* Dummy stubs used when CONFIG_POSIX_TIMERS=n
*
* Created by: Nicolas Pitre, July 2016
* Copyright: (C) 2016 Linaro Limited
*
* 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 <linux/linkage.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/syscalls.h>
#include <linux/ktime.h>
#include <linux/timekeeping.h>
#include <linux/posix-timers.h>
asmlinkage long sys_ni_posix_timers(void)
{
pr_err_once("process %d (%s) attempted a POSIX timer syscall "
"while CONFIG_POSIX_TIMERS is not set\n",
current->pid, current->comm);
return -ENOSYS;
}
#define SYS_NI(name) SYSCALL_ALIAS(sys_##name, sys_ni_posix_timers)
SYS_NI(timer_create);
SYS_NI(timer_gettime);
SYS_NI(timer_getoverrun);
SYS_NI(timer_settime);
SYS_NI(timer_delete);
SYS_NI(clock_adjtime);
SYS_NI(getitimer);
SYS_NI(setitimer);
#ifdef __ARCH_WANT_SYS_ALARM
SYS_NI(alarm);
#endif
/*
* We preserve minimal support for CLOCK_REALTIME and CLOCK_MONOTONIC
* as it is easy to remain compatible with little code. CLOCK_BOOTTIME
* is also included for convenience as at least systemd uses it.
*/
SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
const struct timespec __user *, tp)
{
struct timespec new_tp;
if (which_clock != CLOCK_REALTIME)
return -EINVAL;
if (copy_from_user(&new_tp, tp, sizeof (*tp)))
return -EFAULT;
return do_sys_settimeofday(&new_tp, NULL);
}
SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock,
struct timespec __user *,tp)
{
struct timespec kernel_tp;
switch (which_clock) {
case CLOCK_REALTIME: ktime_get_real_ts(&kernel_tp); break;
case CLOCK_MONOTONIC: ktime_get_ts(&kernel_tp); break;
case CLOCK_BOOTTIME: get_monotonic_boottime(&kernel_tp); break;
default: return -EINVAL;
}
if (copy_to_user(tp, &kernel_tp, sizeof (kernel_tp)))
return -EFAULT;
return 0;
}
SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, struct timespec __user *, tp)
{
struct timespec rtn_tp = {
.tv_sec = 0,
.tv_nsec = hrtimer_resolution,
};
switch (which_clock) {
case CLOCK_REALTIME:
case CLOCK_MONOTONIC:
case CLOCK_BOOTTIME:
if (copy_to_user(tp, &rtn_tp, sizeof(rtn_tp)))
return -EFAULT;
return 0;
default:
return -EINVAL;
}
}
SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
const struct timespec __user *, rqtp,
struct timespec __user *, rmtp)
{
struct timespec t;
switch (which_clock) {
case CLOCK_REALTIME:
case CLOCK_MONOTONIC:
case CLOCK_BOOTTIME:
if (copy_from_user(&t, rqtp, sizeof (struct timespec)))
return -EFAULT;
if (!timespec_valid(&t))
return -EINVAL;
return hrtimer_nanosleep(&t, rmtp, flags & TIMER_ABSTIME ?
HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
which_clock);
default:
return -EINVAL;
}
}
#ifdef CONFIG_COMPAT
long clock_nanosleep_restart(struct restart_block *restart_block)
{
return hrtimer_nanosleep_restart(restart_block);
}
#endif
...@@ -258,10 +258,9 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock) ...@@ -258,10 +258,9 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
tk->cycle_interval = interval; tk->cycle_interval = interval;
/* Go back from cycles -> shifted ns */ /* Go back from cycles -> shifted ns */
tk->xtime_interval = (u64) interval * clock->mult; tk->xtime_interval = interval * clock->mult;
tk->xtime_remainder = ntpinterval - tk->xtime_interval; tk->xtime_remainder = ntpinterval - tk->xtime_interval;
tk->raw_interval = tk->raw_interval = (interval * clock->mult) >> clock->shift;
((u64) interval * clock->mult) >> clock->shift;
/* if changing clocks, convert xtime_nsec shift units */ /* if changing clocks, convert xtime_nsec shift units */
if (old_clock) { if (old_clock) {
...@@ -299,10 +298,10 @@ u32 (*arch_gettimeoffset)(void) = default_arch_gettimeoffset; ...@@ -299,10 +298,10 @@ u32 (*arch_gettimeoffset)(void) = default_arch_gettimeoffset;
static inline u32 arch_gettimeoffset(void) { return 0; } static inline u32 arch_gettimeoffset(void) { return 0; }
#endif #endif
static inline s64 timekeeping_delta_to_ns(struct tk_read_base *tkr, static inline u64 timekeeping_delta_to_ns(struct tk_read_base *tkr,
cycle_t delta) cycle_t delta)
{ {
s64 nsec; u64 nsec;
nsec = delta * tkr->mult + tkr->xtime_nsec; nsec = delta * tkr->mult + tkr->xtime_nsec;
nsec >>= tkr->shift; nsec >>= tkr->shift;
...@@ -311,7 +310,7 @@ static inline s64 timekeeping_delta_to_ns(struct tk_read_base *tkr, ...@@ -311,7 +310,7 @@ static inline s64 timekeeping_delta_to_ns(struct tk_read_base *tkr,
return nsec + arch_gettimeoffset(); return nsec + arch_gettimeoffset();
} }
static inline s64 timekeeping_get_ns(struct tk_read_base *tkr) static inline u64 timekeeping_get_ns(struct tk_read_base *tkr)
{ {
cycle_t delta; cycle_t delta;
...@@ -319,8 +318,8 @@ static inline s64 timekeeping_get_ns(struct tk_read_base *tkr) ...@@ -319,8 +318,8 @@ static inline s64 timekeeping_get_ns(struct tk_read_base *tkr)
return timekeeping_delta_to_ns(tkr, delta); return timekeeping_delta_to_ns(tkr, delta);
} }
static inline s64 timekeeping_cycles_to_ns(struct tk_read_base *tkr, static inline u64 timekeeping_cycles_to_ns(struct tk_read_base *tkr,
cycle_t cycles) cycle_t cycles)
{ {
cycle_t delta; cycle_t delta;
...@@ -425,6 +424,35 @@ u64 ktime_get_raw_fast_ns(void) ...@@ -425,6 +424,35 @@ u64 ktime_get_raw_fast_ns(void)
} }
EXPORT_SYMBOL_GPL(ktime_get_raw_fast_ns); EXPORT_SYMBOL_GPL(ktime_get_raw_fast_ns);
/**
* ktime_get_boot_fast_ns - NMI safe and fast access to boot clock.
*
* To keep it NMI safe since we're accessing from tracing, we're not using a
* separate timekeeper with updates to monotonic clock and boot offset
* protected with seqlocks. This has the following minor side effects:
*
* (1) Its possible that a timestamp be taken after the boot offset is updated
* but before the timekeeper is updated. If this happens, the new boot offset
* is added to the old timekeeping making the clock appear to update slightly
* earlier:
* CPU 0 CPU 1
* timekeeping_inject_sleeptime64()
* __timekeeping_inject_sleeptime(tk, delta);
* timestamp();
* timekeeping_update(tk, TK_CLEAR_NTP...);
*
* (2) On 32-bit systems, the 64-bit boot offset (tk->offs_boot) may be
* partially updated. Since the tk->offs_boot update is a rare event, this
* should be a rare occurrence which postprocessing should be able to handle.
*/
u64 notrace ktime_get_boot_fast_ns(void)
{
struct timekeeper *tk = &tk_core.timekeeper;
return (ktime_get_mono_fast_ns() + ktime_to_ns(tk->offs_boot));
}
EXPORT_SYMBOL_GPL(ktime_get_boot_fast_ns);
/* Suspend-time cycles value for halted fast timekeeper. */ /* Suspend-time cycles value for halted fast timekeeper. */
static cycle_t cycles_at_suspend; static cycle_t cycles_at_suspend;
...@@ -623,7 +651,7 @@ static void timekeeping_forward_now(struct timekeeper *tk) ...@@ -623,7 +651,7 @@ static void timekeeping_forward_now(struct timekeeper *tk)
{ {
struct clocksource *clock = tk->tkr_mono.clock; struct clocksource *clock = tk->tkr_mono.clock;
cycle_t cycle_now, delta; cycle_t cycle_now, delta;
s64 nsec; u64 nsec;
cycle_now = tk->tkr_mono.read(clock); cycle_now = tk->tkr_mono.read(clock);
delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last, tk->tkr_mono.mask); delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last, tk->tkr_mono.mask);
...@@ -652,7 +680,7 @@ int __getnstimeofday64(struct timespec64 *ts) ...@@ -652,7 +680,7 @@ int __getnstimeofday64(struct timespec64 *ts)
{ {
struct timekeeper *tk = &tk_core.timekeeper; struct timekeeper *tk = &tk_core.timekeeper;
unsigned long seq; unsigned long seq;
s64 nsecs = 0; u64 nsecs;
do { do {
seq = read_seqcount_begin(&tk_core.seq); seq = read_seqcount_begin(&tk_core.seq);
...@@ -692,7 +720,7 @@ ktime_t ktime_get(void) ...@@ -692,7 +720,7 @@ ktime_t ktime_get(void)
struct timekeeper *tk = &tk_core.timekeeper; struct timekeeper *tk = &tk_core.timekeeper;
unsigned int seq; unsigned int seq;
ktime_t base; ktime_t base;
s64 nsecs; u64 nsecs;
WARN_ON(timekeeping_suspended); WARN_ON(timekeeping_suspended);
...@@ -735,7 +763,7 @@ ktime_t ktime_get_with_offset(enum tk_offsets offs) ...@@ -735,7 +763,7 @@ ktime_t ktime_get_with_offset(enum tk_offsets offs)
struct timekeeper *tk = &tk_core.timekeeper; struct timekeeper *tk = &tk_core.timekeeper;
unsigned int seq; unsigned int seq;
ktime_t base, *offset = offsets[offs]; ktime_t base, *offset = offsets[offs];
s64 nsecs; u64 nsecs;
WARN_ON(timekeeping_suspended); WARN_ON(timekeeping_suspended);
...@@ -779,7 +807,7 @@ ktime_t ktime_get_raw(void) ...@@ -779,7 +807,7 @@ ktime_t ktime_get_raw(void)
struct timekeeper *tk = &tk_core.timekeeper; struct timekeeper *tk = &tk_core.timekeeper;
unsigned int seq; unsigned int seq;
ktime_t base; ktime_t base;
s64 nsecs; u64 nsecs;
do { do {
seq = read_seqcount_begin(&tk_core.seq); seq = read_seqcount_begin(&tk_core.seq);
...@@ -804,8 +832,8 @@ void ktime_get_ts64(struct timespec64 *ts) ...@@ -804,8 +832,8 @@ void ktime_get_ts64(struct timespec64 *ts)
{ {
struct timekeeper *tk = &tk_core.timekeeper; struct timekeeper *tk = &tk_core.timekeeper;
struct timespec64 tomono; struct timespec64 tomono;
s64 nsec;
unsigned int seq; unsigned int seq;
u64 nsec;
WARN_ON(timekeeping_suspended); WARN_ON(timekeeping_suspended);
...@@ -893,8 +921,8 @@ void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot) ...@@ -893,8 +921,8 @@ void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot)
unsigned long seq; unsigned long seq;
ktime_t base_raw; ktime_t base_raw;
ktime_t base_real; ktime_t base_real;
s64 nsec_raw; u64 nsec_raw;
s64 nsec_real; u64 nsec_real;
cycle_t now; cycle_t now;
WARN_ON_ONCE(timekeeping_suspended); WARN_ON_ONCE(timekeeping_suspended);
...@@ -1052,7 +1080,7 @@ int get_device_system_crosststamp(int (*get_time_fn) ...@@ -1052,7 +1080,7 @@ int get_device_system_crosststamp(int (*get_time_fn)
cycle_t cycles, now, interval_start; cycle_t cycles, now, interval_start;
unsigned int clock_was_set_seq = 0; unsigned int clock_was_set_seq = 0;
ktime_t base_real, base_raw; ktime_t base_real, base_raw;
s64 nsec_real, nsec_raw; u64 nsec_real, nsec_raw;
u8 cs_was_changed_seq; u8 cs_was_changed_seq;
unsigned long seq; unsigned long seq;
bool do_interp; bool do_interp;
...@@ -1365,7 +1393,7 @@ void getrawmonotonic64(struct timespec64 *ts) ...@@ -1365,7 +1393,7 @@ void getrawmonotonic64(struct timespec64 *ts)
struct timekeeper *tk = &tk_core.timekeeper; struct timekeeper *tk = &tk_core.timekeeper;
struct timespec64 ts64; struct timespec64 ts64;
unsigned long seq; unsigned long seq;
s64 nsecs; u64 nsecs;
do { do {
seq = read_seqcount_begin(&tk_core.seq); seq = read_seqcount_begin(&tk_core.seq);
...@@ -1616,7 +1644,7 @@ void timekeeping_resume(void) ...@@ -1616,7 +1644,7 @@ void timekeeping_resume(void)
struct clocksource *clock = tk->tkr_mono.clock; struct clocksource *clock = tk->tkr_mono.clock;
unsigned long flags; unsigned long flags;
struct timespec64 ts_new, ts_delta; struct timespec64 ts_new, ts_delta;
cycle_t cycle_now, cycle_delta; cycle_t cycle_now;
sleeptime_injected = false; sleeptime_injected = false;
read_persistent_clock64(&ts_new); read_persistent_clock64(&ts_new);
...@@ -1642,27 +1670,11 @@ void timekeeping_resume(void) ...@@ -1642,27 +1670,11 @@ void timekeeping_resume(void)
cycle_now = tk->tkr_mono.read(clock); cycle_now = tk->tkr_mono.read(clock);
if ((clock->flags & CLOCK_SOURCE_SUSPEND_NONSTOP) && if ((clock->flags & CLOCK_SOURCE_SUSPEND_NONSTOP) &&
cycle_now > tk->tkr_mono.cycle_last) { cycle_now > tk->tkr_mono.cycle_last) {
u64 num, max = ULLONG_MAX; u64 nsec, cyc_delta;
u32 mult = clock->mult;
u32 shift = clock->shift;
s64 nsec = 0;
cycle_delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last,
tk->tkr_mono.mask);
/*
* "cycle_delta * mutl" may cause 64 bits overflow, if the
* suspended time is too long. In that case we need do the
* 64 bits math carefully
*/
do_div(max, mult);
if (cycle_delta > max) {
num = div64_u64(cycle_delta, max);
nsec = (((u64) max * mult) >> shift) * num;
cycle_delta -= num * max;
}
nsec += ((u64) cycle_delta * mult) >> shift;
cyc_delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last,
tk->tkr_mono.mask);
nsec = mul_u64_u32_shr(cyc_delta, clock->mult, clock->shift);
ts_delta = ns_to_timespec64(nsec); ts_delta = ns_to_timespec64(nsec);
sleeptime_injected = true; sleeptime_injected = true;
} else if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) { } else if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) {
......
...@@ -1615,7 +1615,8 @@ void update_process_times(int user_tick) ...@@ -1615,7 +1615,8 @@ void update_process_times(int user_tick)
irq_work_tick(); irq_work_tick();
#endif #endif
scheduler_tick(); scheduler_tick();
run_posix_cpu_timers(p); if (IS_ENABLED(CONFIG_POSIX_TIMERS))
run_posix_cpu_timers(p);
} }
/** /**
...@@ -1676,19 +1677,6 @@ void run_local_timers(void) ...@@ -1676,19 +1677,6 @@ void run_local_timers(void)
raise_softirq(TIMER_SOFTIRQ); raise_softirq(TIMER_SOFTIRQ);
} }
#ifdef __ARCH_WANT_SYS_ALARM
/*
* For backwards compatibility? This can be done in libc so Alpha
* and all newer ports shouldn't need it.
*/
SYSCALL_DEFINE1(alarm, unsigned int, seconds)
{
return alarm_setitimer(seconds);
}
#endif
static void process_timeout(unsigned long __data) static void process_timeout(unsigned long __data)
{ {
wake_up_process((struct task_struct *)__data); wake_up_process((struct task_struct *)__data);
...@@ -1705,11 +1693,12 @@ static void process_timeout(unsigned long __data) ...@@ -1705,11 +1693,12 @@ static void process_timeout(unsigned long __data)
* You can set the task state as follows - * You can set the task state as follows -
* *
* %TASK_UNINTERRUPTIBLE - at least @timeout jiffies are guaranteed to * %TASK_UNINTERRUPTIBLE - at least @timeout jiffies are guaranteed to
* pass before the routine returns. The routine will return 0 * pass before the routine returns unless the current task is explicitly
* woken up, (e.g. by wake_up_process())".
* *
* %TASK_INTERRUPTIBLE - the routine may return early if a signal is * %TASK_INTERRUPTIBLE - the routine may return early if a signal is
* delivered to the current task. In this case the remaining time * delivered to the current task or the current task is explicitly woken
* in jiffies will be returned, or 0 if the timer expired in time * up.
* *
* The current task state is guaranteed to be TASK_RUNNING when this * The current task state is guaranteed to be TASK_RUNNING when this
* routine returns. * routine returns.
...@@ -1718,7 +1707,9 @@ static void process_timeout(unsigned long __data) ...@@ -1718,7 +1707,9 @@ static void process_timeout(unsigned long __data)
* the CPU away without a bound on the timeout. In this case the return * the CPU away without a bound on the timeout. In this case the return
* value will be %MAX_SCHEDULE_TIMEOUT. * value will be %MAX_SCHEDULE_TIMEOUT.
* *
* In all cases the return value is guaranteed to be non-negative. * Returns 0 when the timer has expired otherwise the remaining time in
* jiffies will be returned. In all cases the return value is guaranteed
* to be non-negative.
*/ */
signed long __sched schedule_timeout(signed long timeout) signed long __sched schedule_timeout(signed long timeout)
{ {
...@@ -1910,16 +1901,6 @@ unsigned long msleep_interruptible(unsigned int msecs) ...@@ -1910,16 +1901,6 @@ unsigned long msleep_interruptible(unsigned int msecs)
EXPORT_SYMBOL(msleep_interruptible); EXPORT_SYMBOL(msleep_interruptible);
static void __sched do_usleep_range(unsigned long min, unsigned long max)
{
ktime_t kmin;
u64 delta;
kmin = ktime_set(0, min * NSEC_PER_USEC);
delta = (u64)(max - min) * NSEC_PER_USEC;
schedule_hrtimeout_range(&kmin, delta, HRTIMER_MODE_REL);
}
/** /**
* usleep_range - Sleep for an approximate time * usleep_range - Sleep for an approximate time
* @min: Minimum time in usecs to sleep * @min: Minimum time in usecs to sleep
...@@ -1933,7 +1914,14 @@ static void __sched do_usleep_range(unsigned long min, unsigned long max) ...@@ -1933,7 +1914,14 @@ static void __sched do_usleep_range(unsigned long min, unsigned long max)
*/ */
void __sched usleep_range(unsigned long min, unsigned long max) void __sched usleep_range(unsigned long min, unsigned long max)
{ {
__set_current_state(TASK_UNINTERRUPTIBLE); ktime_t exp = ktime_add_us(ktime_get(), min);
do_usleep_range(min, max); u64 delta = (u64)(max - min) * NSEC_PER_USEC;
for (;;) {
__set_current_state(TASK_UNINTERRUPTIBLE);
/* Do not return before the requested sleep time has elapsed */
if (!schedule_hrtimeout_range(&exp, delta, HRTIMER_MODE_ABS))
break;
}
} }
EXPORT_SYMBOL(usleep_range); EXPORT_SYMBOL(usleep_range);
...@@ -1125,6 +1125,7 @@ static struct { ...@@ -1125,6 +1125,7 @@ static struct {
{ trace_clock, "perf", 1 }, { trace_clock, "perf", 1 },
{ ktime_get_mono_fast_ns, "mono", 1 }, { ktime_get_mono_fast_ns, "mono", 1 },
{ ktime_get_raw_fast_ns, "mono_raw", 1 }, { ktime_get_raw_fast_ns, "mono_raw", 1 },
{ ktime_get_boot_fast_ns, "boot", 1 },
ARCH_TRACE_CLOCKS ARCH_TRACE_CLOCKS
}; };
......
...@@ -85,6 +85,7 @@ struct symbol { ...@@ -85,6 +85,7 @@ struct symbol {
struct property *prop; struct property *prop;
struct expr_value dir_dep; struct expr_value dir_dep;
struct expr_value rev_dep; struct expr_value rev_dep;
struct expr_value implied;
}; };
#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) #define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
...@@ -136,6 +137,7 @@ enum prop_type { ...@@ -136,6 +137,7 @@ enum prop_type {
P_DEFAULT, /* default y */ P_DEFAULT, /* default y */
P_CHOICE, /* choice value */ P_CHOICE, /* choice value */
P_SELECT, /* select BAR */ P_SELECT, /* select BAR */
P_IMPLY, /* imply BAR */
P_RANGE, /* range 7..100 (for a symbol) */ P_RANGE, /* range 7..100 (for a symbol) */
P_ENV, /* value from environment variable */ P_ENV, /* value from environment variable */
P_SYMBOL, /* where a symbol is defined */ P_SYMBOL, /* where a symbol is defined */
......
...@@ -233,6 +233,8 @@ static void sym_check_prop(struct symbol *sym) ...@@ -233,6 +233,8 @@ static void sym_check_prop(struct symbol *sym)
{ {
struct property *prop; struct property *prop;
struct symbol *sym2; struct symbol *sym2;
char *use;
for (prop = sym->prop; prop; prop = prop->next) { for (prop = sym->prop; prop; prop = prop->next) {
switch (prop->type) { switch (prop->type) {
case P_DEFAULT: case P_DEFAULT:
...@@ -252,18 +254,20 @@ static void sym_check_prop(struct symbol *sym) ...@@ -252,18 +254,20 @@ static void sym_check_prop(struct symbol *sym)
} }
break; break;
case P_SELECT: case P_SELECT:
case P_IMPLY:
use = prop->type == P_SELECT ? "select" : "imply";
sym2 = prop_get_symbol(prop); sym2 = prop_get_symbol(prop);
if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
prop_warn(prop, prop_warn(prop,
"config symbol '%s' uses select, but is " "config symbol '%s' uses %s, but is "
"not boolean or tristate", sym->name); "not boolean or tristate", sym->name, use);
else if (sym2->type != S_UNKNOWN && else if (sym2->type != S_UNKNOWN &&
sym2->type != S_BOOLEAN && sym2->type != S_BOOLEAN &&
sym2->type != S_TRISTATE) sym2->type != S_TRISTATE)
prop_warn(prop, prop_warn(prop,
"'%s' has wrong type. 'select' only " "'%s' has wrong type. '%s' only "
"accept arguments of boolean and " "accept arguments of boolean and "
"tristate type", sym2->name); "tristate type", sym2->name, use);
break; break;
case P_RANGE: case P_RANGE:
if (sym->type != S_INT && sym->type != S_HEX) if (sym->type != S_INT && sym->type != S_HEX)
...@@ -333,6 +337,10 @@ void menu_finalize(struct menu *parent) ...@@ -333,6 +337,10 @@ void menu_finalize(struct menu *parent)
struct symbol *es = prop_get_symbol(prop); struct symbol *es = prop_get_symbol(prop);
es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
} else if (prop->type == P_IMPLY) {
struct symbol *es = prop_get_symbol(prop);
es->implied.expr = expr_alloc_or(es->implied.expr,
expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
} }
} }
} }
...@@ -612,13 +620,30 @@ static struct property *get_symbol_prop(struct symbol *sym) ...@@ -612,13 +620,30 @@ static struct property *get_symbol_prop(struct symbol *sym)
return prop; return prop;
} }
static void get_symbol_props_str(struct gstr *r, struct symbol *sym,
enum prop_type tok, const char *prefix)
{
bool hit = false;
struct property *prop;
for_all_properties(sym, prop, tok) {
if (!hit) {
str_append(r, prefix);
hit = true;
} else
str_printf(r, " && ");
expr_gstr_print(prop->expr, r);
}
if (hit)
str_append(r, "\n");
}
/* /*
* head is optional and may be NULL * head is optional and may be NULL
*/ */
static void get_symbol_str(struct gstr *r, struct symbol *sym, static void get_symbol_str(struct gstr *r, struct symbol *sym,
struct list_head *head) struct list_head *head)
{ {
bool hit;
struct property *prop; struct property *prop;
if (sym && sym->name) { if (sym && sym->name) {
...@@ -648,22 +673,20 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym, ...@@ -648,22 +673,20 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym,
} }
} }
hit = false; get_symbol_props_str(r, sym, P_SELECT, _(" Selects: "));
for_all_properties(sym, prop, P_SELECT) {
if (!hit) {
str_append(r, " Selects: ");
hit = true;
} else
str_printf(r, " && ");
expr_gstr_print(prop->expr, r);
}
if (hit)
str_append(r, "\n");
if (sym->rev_dep.expr) { if (sym->rev_dep.expr) {
str_append(r, _(" Selected by: ")); str_append(r, _(" Selected by: "));
expr_gstr_print(sym->rev_dep.expr, r); expr_gstr_print(sym->rev_dep.expr, r);
str_append(r, "\n"); str_append(r, "\n");
} }
get_symbol_props_str(r, sym, P_IMPLY, _(" Implies: "));
if (sym->implied.expr) {
str_append(r, _(" Implied by: "));
expr_gstr_print(sym->implied.expr, r);
str_append(r, "\n");
}
str_append(r, "\n\n"); str_append(r, "\n\n");
} }
......
...@@ -258,6 +258,15 @@ static void sym_calc_visibility(struct symbol *sym) ...@@ -258,6 +258,15 @@ static void sym_calc_visibility(struct symbol *sym)
sym->rev_dep.tri = tri; sym->rev_dep.tri = tri;
sym_set_changed(sym); sym_set_changed(sym);
} }
tri = no;
if (sym->implied.expr && sym->dir_dep.tri != no)
tri = expr_calc_value(sym->implied.expr);
if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
tri = yes;
if (sym->implied.tri != tri) {
sym->implied.tri = tri;
sym_set_changed(sym);
}
} }
/* /*
...@@ -397,6 +406,10 @@ void sym_calc_value(struct symbol *sym) ...@@ -397,6 +406,10 @@ void sym_calc_value(struct symbol *sym)
newval.tri = EXPR_AND(expr_calc_value(prop->expr), newval.tri = EXPR_AND(expr_calc_value(prop->expr),
prop->visible.tri); prop->visible.tri);
} }
if (sym->implied.tri != no) {
sym->flags |= SYMBOL_WRITE;
newval.tri = EXPR_OR(newval.tri, sym->implied.tri);
}
} }
calc_newval: calc_newval:
if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) { if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
...@@ -413,7 +426,8 @@ void sym_calc_value(struct symbol *sym) ...@@ -413,7 +426,8 @@ void sym_calc_value(struct symbol *sym)
} }
newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
} }
if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) if (newval.tri == mod &&
(sym_get_type(sym) == S_BOOLEAN || sym->implied.tri == yes))
newval.tri = yes; newval.tri = yes;
break; break;
case S_STRING: case S_STRING:
...@@ -498,6 +512,8 @@ bool sym_tristate_within_range(struct symbol *sym, tristate val) ...@@ -498,6 +512,8 @@ bool sym_tristate_within_range(struct symbol *sym, tristate val)
return false; return false;
if (sym->visible <= sym->rev_dep.tri) if (sym->visible <= sym->rev_dep.tri)
return false; return false;
if (sym->implied.tri == yes && val == mod)
return false;
if (sym_is_choice_value(sym) && sym->visible == yes) if (sym_is_choice_value(sym) && sym->visible == yes)
return val == yes; return val == yes;
return val >= sym->rev_dep.tri && val <= sym->visible; return val >= sym->rev_dep.tri && val <= sym->visible;
...@@ -750,6 +766,10 @@ const char *sym_get_string_default(struct symbol *sym) ...@@ -750,6 +766,10 @@ const char *sym_get_string_default(struct symbol *sym)
if (sym->type == S_BOOLEAN && val == mod) if (sym->type == S_BOOLEAN && val == mod)
val = yes; val = yes;
/* adjust the default value if this symbol is implied by another */
if (val < sym->implied.tri)
val = sym->implied.tri;
switch (sym->type) { switch (sym->type) {
case S_BOOLEAN: case S_BOOLEAN:
case S_TRISTATE: case S_TRISTATE:
...@@ -1352,6 +1372,8 @@ const char *prop_get_type_name(enum prop_type type) ...@@ -1352,6 +1372,8 @@ const char *prop_get_type_name(enum prop_type type)
return "choice"; return "choice";
case P_SELECT: case P_SELECT:
return "select"; return "select";
case P_IMPLY:
return "imply";
case P_RANGE: case P_RANGE:
return "range"; return "range";
case P_SYMBOL: case P_SYMBOL:
......
...@@ -38,6 +38,7 @@ int, T_TYPE, TF_COMMAND, S_INT ...@@ -38,6 +38,7 @@ int, T_TYPE, TF_COMMAND, S_INT
hex, T_TYPE, TF_COMMAND, S_HEX hex, T_TYPE, TF_COMMAND, S_HEX
string, T_TYPE, TF_COMMAND, S_STRING string, T_TYPE, TF_COMMAND, S_STRING
select, T_SELECT, TF_COMMAND select, T_SELECT, TF_COMMAND
imply, T_IMPLY, TF_COMMAND
range, T_RANGE, TF_COMMAND range, T_RANGE, TF_COMMAND
visible, T_VISIBLE, TF_COMMAND visible, T_VISIBLE, TF_COMMAND
option, T_OPTION, TF_COMMAND option, T_OPTION, TF_COMMAND
......
...@@ -55,10 +55,10 @@ kconf_id_hash (register const char *str, register unsigned int len) ...@@ -55,10 +55,10 @@ kconf_id_hash (register const char *str, register unsigned int len)
73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 5, 25, 25, 73, 73, 73, 73, 73, 73, 73, 10, 25, 25,
0, 0, 0, 5, 0, 0, 73, 73, 5, 0, 0, 0, 0, 5, 0, 0, 73, 73, 5, 0,
10, 5, 45, 73, 20, 20, 0, 15, 15, 73, 10, 5, 45, 73, 20, 20, 0, 15, 15, 73,
20, 5, 73, 73, 73, 73, 73, 73, 73, 73, 20, 0, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
...@@ -120,6 +120,7 @@ struct kconf_id_strings_t ...@@ -120,6 +120,7 @@ struct kconf_id_strings_t
char kconf_id_strings_str43[sizeof("hex")]; char kconf_id_strings_str43[sizeof("hex")];
char kconf_id_strings_str46[sizeof("config")]; char kconf_id_strings_str46[sizeof("config")];
char kconf_id_strings_str47[sizeof("boolean")]; char kconf_id_strings_str47[sizeof("boolean")];
char kconf_id_strings_str50[sizeof("imply")];
char kconf_id_strings_str51[sizeof("string")]; char kconf_id_strings_str51[sizeof("string")];
char kconf_id_strings_str54[sizeof("help")]; char kconf_id_strings_str54[sizeof("help")];
char kconf_id_strings_str56[sizeof("prompt")]; char kconf_id_strings_str56[sizeof("prompt")];
...@@ -157,6 +158,7 @@ static const struct kconf_id_strings_t kconf_id_strings_contents = ...@@ -157,6 +158,7 @@ static const struct kconf_id_strings_t kconf_id_strings_contents =
"hex", "hex",
"config", "config",
"boolean", "boolean",
"imply",
"string", "string",
"help", "help",
"prompt", "prompt",
...@@ -174,7 +176,7 @@ kconf_id_lookup (register const char *str, register unsigned int len) ...@@ -174,7 +176,7 @@ kconf_id_lookup (register const char *str, register unsigned int len)
{ {
enum enum
{ {
TOTAL_KEYWORDS = 34, TOTAL_KEYWORDS = 35,
MIN_WORD_LENGTH = 2, MIN_WORD_LENGTH = 2,
MAX_WORD_LENGTH = 14, MAX_WORD_LENGTH = 14,
MIN_HASH_VALUE = 2, MIN_HASH_VALUE = 2,
...@@ -205,15 +207,15 @@ kconf_id_lookup (register const char *str, register unsigned int len) ...@@ -205,15 +207,15 @@ kconf_id_lookup (register const char *str, register unsigned int len)
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_TRISTATE}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_TRISTATE},
#line 36 "scripts/kconfig/zconf.gperf" #line 36 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN},
#line 46 "scripts/kconfig/zconf.gperf" #line 47 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_OPT_DEFCONFIG_LIST,TF_OPTION}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_OPT_DEFCONFIG_LIST,TF_OPTION},
{-1}, {-1}, {-1}, {-1},
#line 44 "scripts/kconfig/zconf.gperf" #line 45 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_ON, TF_PARAM}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_ON, TF_PARAM},
#line 29 "scripts/kconfig/zconf.gperf" #line 29 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_OPTIONAL, TF_COMMAND}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_OPTIONAL, TF_COMMAND},
{-1}, {-1}, {-1}, {-1},
#line 43 "scripts/kconfig/zconf.gperf" #line 44 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_OPTION, TF_COMMAND}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_OPTION, TF_COMMAND},
#line 17 "scripts/kconfig/zconf.gperf" #line 17 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_ENDMENU, TF_COMMAND}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_ENDMENU, TF_COMMAND},
...@@ -223,9 +225,9 @@ kconf_id_lookup (register const char *str, register unsigned int len) ...@@ -223,9 +225,9 @@ kconf_id_lookup (register const char *str, register unsigned int len)
#line 23 "scripts/kconfig/zconf.gperf" #line 23 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str25, T_MENUCONFIG, TF_COMMAND}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str25, T_MENUCONFIG, TF_COMMAND},
{-1}, {-1},
#line 45 "scripts/kconfig/zconf.gperf" #line 46 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_OPT_MODULES, TF_OPTION}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_OPT_MODULES, TF_OPTION},
#line 48 "scripts/kconfig/zconf.gperf" #line 49 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_OPT_ALLNOCONFIG_Y,TF_OPTION}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_OPT_ALLNOCONFIG_Y,TF_OPTION},
#line 16 "scripts/kconfig/zconf.gperf" #line 16 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29, T_MENU, TF_COMMAND}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29, T_MENU, TF_COMMAND},
...@@ -234,10 +236,10 @@ kconf_id_lookup (register const char *str, register unsigned int len) ...@@ -234,10 +236,10 @@ kconf_id_lookup (register const char *str, register unsigned int len)
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SELECT, TF_COMMAND}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SELECT, TF_COMMAND},
#line 21 "scripts/kconfig/zconf.gperf" #line 21 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND},
#line 47 "scripts/kconfig/zconf.gperf" #line 48 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_OPT_ENV, TF_OPTION}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_OPT_ENV, TF_OPTION},
{-1}, {-1},
#line 41 "scripts/kconfig/zconf.gperf" #line 42 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35, T_RANGE, TF_COMMAND}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35, T_RANGE, TF_COMMAND},
#line 19 "scripts/kconfig/zconf.gperf" #line 19 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36, T_CHOICE, TF_COMMAND}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36, T_CHOICE, TF_COMMAND},
...@@ -247,7 +249,7 @@ kconf_id_lookup (register const char *str, register unsigned int len) ...@@ -247,7 +249,7 @@ kconf_id_lookup (register const char *str, register unsigned int len)
{-1}, {-1},
#line 18 "scripts/kconfig/zconf.gperf" #line 18 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_SOURCE, TF_COMMAND}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_SOURCE, TF_COMMAND},
#line 42 "scripts/kconfig/zconf.gperf" #line 43 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42, T_VISIBLE, TF_COMMAND}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42, T_VISIBLE, TF_COMMAND},
#line 38 "scripts/kconfig/zconf.gperf" #line 38 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str43, T_TYPE, TF_COMMAND, S_HEX}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str43, T_TYPE, TF_COMMAND, S_HEX},
...@@ -256,7 +258,9 @@ kconf_id_lookup (register const char *str, register unsigned int len) ...@@ -256,7 +258,9 @@ kconf_id_lookup (register const char *str, register unsigned int len)
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_CONFIG, TF_COMMAND}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_CONFIG, TF_COMMAND},
#line 35 "scripts/kconfig/zconf.gperf" #line 35 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47, T_TYPE, TF_COMMAND, S_BOOLEAN}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47, T_TYPE, TF_COMMAND, S_BOOLEAN},
{-1}, {-1}, {-1}, {-1}, {-1},
#line 41 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str50, T_IMPLY, TF_COMMAND},
#line 39 "scripts/kconfig/zconf.gperf" #line 39 "scripts/kconfig/zconf.gperf"
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str51, T_TYPE, TF_COMMAND, S_STRING}, {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str51, T_TYPE, TF_COMMAND, S_STRING},
{-1}, {-1}, {-1}, {-1},
...@@ -289,5 +293,5 @@ kconf_id_lookup (register const char *str, register unsigned int len) ...@@ -289,5 +293,5 @@ kconf_id_lookup (register const char *str, register unsigned int len)
} }
return 0; return 0;
} }
#line 49 "scripts/kconfig/zconf.gperf" #line 50 "scripts/kconfig/zconf.gperf"
This diff is collapsed.
...@@ -31,7 +31,7 @@ struct symbol *symbol_hash[SYMBOL_HASHSIZE]; ...@@ -31,7 +31,7 @@ struct symbol *symbol_hash[SYMBOL_HASHSIZE];
static struct menu *current_menu, *current_entry; static struct menu *current_menu, *current_entry;
%} %}
%expect 30 %expect 32
%union %union
{ {
...@@ -62,6 +62,7 @@ static struct menu *current_menu, *current_entry; ...@@ -62,6 +62,7 @@ static struct menu *current_menu, *current_entry;
%token <id>T_TYPE %token <id>T_TYPE
%token <id>T_DEFAULT %token <id>T_DEFAULT
%token <id>T_SELECT %token <id>T_SELECT
%token <id>T_IMPLY
%token <id>T_RANGE %token <id>T_RANGE
%token <id>T_VISIBLE %token <id>T_VISIBLE
%token <id>T_OPTION %token <id>T_OPTION
...@@ -124,7 +125,7 @@ stmt_list: ...@@ -124,7 +125,7 @@ stmt_list:
; ;
option_name: option_name:
T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_IMPLY | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE
; ;
common_stmt: common_stmt:
...@@ -216,6 +217,12 @@ config_option: T_SELECT T_WORD if_expr T_EOL ...@@ -216,6 +217,12 @@ config_option: T_SELECT T_WORD if_expr T_EOL
printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
}; };
config_option: T_IMPLY T_WORD if_expr T_EOL
{
menu_add_symbol(P_IMPLY, sym_lookup($2, 0), $3);
printd(DEBUG_PARSE, "%s:%d:imply\n", zconf_curname(), zconf_lineno());
};
config_option: T_RANGE symbol symbol if_expr T_EOL config_option: T_RANGE symbol symbol if_expr T_EOL
{ {
menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
...@@ -664,6 +671,11 @@ static void print_symbol(FILE *out, struct menu *menu) ...@@ -664,6 +671,11 @@ static void print_symbol(FILE *out, struct menu *menu)
expr_fprint(prop->expr, out); expr_fprint(prop->expr, out);
fputc('\n', out); fputc('\n', out);
break; break;
case P_IMPLY:
fputs( " imply ", out);
expr_fprint(prop->expr, out);
fputc('\n', out);
break;
case P_RANGE: case P_RANGE:
fputs( " range ", out); fputs( " range ", out);
expr_fprint(prop->expr, out); expr_fprint(prop->expr, out);
......
...@@ -2525,7 +2525,8 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm) ...@@ -2525,7 +2525,8 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur); rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
} }
task_unlock(current); task_unlock(current);
update_rlimit_cpu(current, rlimit(RLIMIT_CPU)); if (IS_ENABLED(CONFIG_POSIX_TIMERS))
update_rlimit_cpu(current, rlimit(RLIMIT_CPU));
} }
} }
...@@ -2555,9 +2556,11 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm) ...@@ -2555,9 +2556,11 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
*/ */
rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL); rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
if (rc) { if (rc) {
memset(&itimer, 0, sizeof itimer); if (IS_ENABLED(CONFIG_POSIX_TIMERS)) {
for (i = 0; i < 3; i++) memset(&itimer, 0, sizeof itimer);
do_setitimer(i, &itimer, NULL); for (i = 0; i < 3; i++)
do_setitimer(i, &itimer, NULL);
}
spin_lock_irq(&current->sighand->siglock); spin_lock_irq(&current->sighand->siglock);
if (!fatal_signal_pending(current)) { if (!fatal_signal_pending(current)) {
flush_sigqueue(&current->pending); flush_sigqueue(&current->pending);
......
...@@ -57,7 +57,7 @@ int main(int argv, char **argc) ...@@ -57,7 +57,7 @@ int main(int argv, char **argc)
pid_t pid; pid_t pid;
printf("Running Asyncrhonous Frequency Changing Tests...\n"); printf("Running Asynchronous Frequency Changing Tests...\n");
pid = fork(); pid = fork();
if (!pid) if (!pid)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment