[RESEND][RFC PATCH] regulator: introduce boot protection flag
In some platforms, critical shared regulator is initialized in bootloader. But during kernel booting, the driver probing order and conflicting operations from other regulator consumers, may set the regulator in a undefined state, which will cause serious problem. This patch try to add a boot_protection flag in regulator constraints. And regulator core will postpone all operations until all consumers have taked their place. The boot_protection flag only work before late_initicall. And as other constraints liked, you can specify this flag in a board file, or in dts file. Signed-off-by: WEN Pingbo Cc: Stephen Boyd Cc: David Collins --- drivers/regulator/core.c | 106 +++--- drivers/regulator/internal.h | 2 + drivers/regulator/of_regulator.c | 3 ++ include/linux/regulator/driver.h | 3 ++ include/linux/regulator/machine.h | 1 + 5 files changed, 109 insertions(+), 6 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index fe47d38..f994a0f 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -55,6 +55,7 @@ static LIST_HEAD(regulator_map_list); static LIST_HEAD(regulator_ena_gpio_list); static LIST_HEAD(regulator_supply_alias_list); static bool has_full_constraints; +static bool regulator_has_booted; static struct dentry *debugfs_root; @@ -1030,6 +1031,13 @@ static int set_machine_constraints(struct regulator_dev *rdev, if (!rdev->constraints) return -ENOMEM; + /* +* If a regulator driver is registered after late_initcall, the +* boot_protection should be ingnored. +*/ + if (regulator_has_booted) + rdev->constraints->boot_protection = 0; + ret = machine_constraints_voltage(rdev, rdev->constraints); if (ret != 0) return ret; @@ -2195,8 +2203,14 @@ static int _regulator_disable(struct regulator_dev *rdev) if (rdev->use_count == 1 && (rdev->constraints && !rdev->constraints->always_on)) { - /* we are last user */ - if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS)) { + /* +* We are last user. +* +* If boot_protection is set, we only clear use_count, +* and regulator_init_complete() will disable it. +*/ + if (!rdev->constraints->boot_protection && + regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS)) { ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_DISABLE, NULL); @@ -2297,6 +2311,10 @@ int regulator_force_disable(struct regulator *regulator) struct regulator_dev *rdev = regulator->rdev; int ret; + WARN(rdev->constraints->boot_protection, + "disable regulator %s with boot protection flag\n", + rdev->desc->name); + mutex_lock(&rdev->mutex); regulator->uA_load = 0; ret = _regulator_force_disable(regulator->rdev); @@ -2852,6 +2870,10 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, if (ret < 0) goto out2; + /* We need to change voltage, but boot_protection is set. */ + if (rdev->constraints->boot_protection) + goto out; + if (rdev->supply && (rdev->desc->min_dropout_uV || !rdev->desc->ops->get_voltage)) { int current_supply_uV; @@ -3069,6 +3091,9 @@ int regulator_sync_voltage(struct regulator *regulator) if (ret < 0) goto out; + if (rdev->constraints->boot_protection) + goto out; + ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); out: @@ -3161,6 +3186,15 @@ int regulator_set_current_limit(struct regulator *regulator, if (ret < 0) goto out; + /* +* Stage new current value, and applied it later. +*/ + if (rdev->constraints->boot_protection) { + regulator->min_uA = min_uA; + regulator->max_uA = max_uA; + goto out; + } + ret = rdev->desc->ops->set_current_limit(rdev, min_uA, max_uA); out: mutex_unlock(&rdev->mutex); @@ -3240,6 +3274,11 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode) if (ret < 0) goto out; + if (rdev->constraints->boot_protection) { + rdev->boot_mode = mode; + goto out; + } + ret = rdev->desc->ops->set_mode(rdev, mode); out: mutex_unlock(&rdev->mutex); @@ -3306,11 +3345,14 @@ EXP
[RFC PATCH] regulator: introduce boot protection flag
In some platforms, critical shared regulator is initialized in bootloader. But during kernel booting, the driver probing order and conflicting operations from other regulator consumers, may set the regulator in a undefined state, which will cause serious problem. This patch try to add a boot_protection flag in regulator constraints. And regulator core will postpone all operations until all consumers have taked their place. The boot_protection flag only work before late_initicall. And as other constraints liked, you can specify this flag in a board file, or in dts file. Signed-off-by: WEN Pingbo --- drivers/regulator/core.c | 106 +++--- drivers/regulator/internal.h | 2 + drivers/regulator/of_regulator.c | 3 ++ include/linux/regulator/driver.h | 3 ++ include/linux/regulator/machine.h | 1 + 5 files changed, 109 insertions(+), 6 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index fe47d38..f994a0f 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -55,6 +55,7 @@ static LIST_HEAD(regulator_map_list); static LIST_HEAD(regulator_ena_gpio_list); static LIST_HEAD(regulator_supply_alias_list); static bool has_full_constraints; +static bool regulator_has_booted; static struct dentry *debugfs_root; @@ -1030,6 +1031,13 @@ static int set_machine_constraints(struct regulator_dev *rdev, if (!rdev->constraints) return -ENOMEM; + /* +* If a regulator driver is registered after late_initcall, the +* boot_protection should be ingnored. +*/ + if (regulator_has_booted) + rdev->constraints->boot_protection = 0; + ret = machine_constraints_voltage(rdev, rdev->constraints); if (ret != 0) return ret; @@ -2195,8 +2203,14 @@ static int _regulator_disable(struct regulator_dev *rdev) if (rdev->use_count == 1 && (rdev->constraints && !rdev->constraints->always_on)) { - /* we are last user */ - if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS)) { + /* +* We are last user. +* +* If boot_protection is set, we only clear use_count, +* and regulator_init_complete() will disable it. +*/ + if (!rdev->constraints->boot_protection && + regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS)) { ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_DISABLE, NULL); @@ -2297,6 +2311,10 @@ int regulator_force_disable(struct regulator *regulator) struct regulator_dev *rdev = regulator->rdev; int ret; + WARN(rdev->constraints->boot_protection, + "disable regulator %s with boot protection flag\n", + rdev->desc->name); + mutex_lock(&rdev->mutex); regulator->uA_load = 0; ret = _regulator_force_disable(regulator->rdev); @@ -2852,6 +2870,10 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, if (ret < 0) goto out2; + /* We need to change voltage, but boot_protection is set. */ + if (rdev->constraints->boot_protection) + goto out; + if (rdev->supply && (rdev->desc->min_dropout_uV || !rdev->desc->ops->get_voltage)) { int current_supply_uV; @@ -3069,6 +3091,9 @@ int regulator_sync_voltage(struct regulator *regulator) if (ret < 0) goto out; + if (rdev->constraints->boot_protection) + goto out; + ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); out: @@ -3161,6 +3186,15 @@ int regulator_set_current_limit(struct regulator *regulator, if (ret < 0) goto out; + /* +* Stage new current value, and applied it later. +*/ + if (rdev->constraints->boot_protection) { + regulator->min_uA = min_uA; + regulator->max_uA = max_uA; + goto out; + } + ret = rdev->desc->ops->set_current_limit(rdev, min_uA, max_uA); out: mutex_unlock(&rdev->mutex); @@ -3240,6 +3274,11 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode) if (ret < 0) goto out; + if (rdev->constraints->boot_protection) { + rdev->boot_mode = mode; + goto out; + } + ret = rdev->desc->ops->set_mode(rdev, mode); out: mutex_unlock(&rdev->mutex); @@ -3306,11 +3345,14 @@ EXPORT_SYMBOL_GPL(regulator_get_mode);
[RFC PATCH 2/2] regulator: add boot protection flag
In some platform, some critical shared regulator is initialized before kernel loading. But in kernel booting, the driver probing order and conflict operation from other regulator consumer, may set the regulator in a undefined state, which will cause serious problem. This patch try to add a boot_protection flag in regulator constraints. So the regulator core will prevent the specified operation during kernel booting. The boot_protection flag only work before late_initicall. And as other constraints liked, you can specify this flag in a board file, or in dts file. By default, all operations of this regulator will be rejected during kernel booting, if you add this flag in a regulator. But you still have a chance to change this, by modifying boot_valid_ops_mask. [ This patch depends on regulator_ops_is_valid patch. And some document need to add, but I want to hear some voice first. ] Signed-off-by: WEN Pingbo --- drivers/regulator/core.c | 24 +--- drivers/regulator/of_regulator.c | 29 + include/linux/regulator/machine.h | 2 ++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index fe47d38..5b9dc22 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -55,6 +55,7 @@ static LIST_HEAD(regulator_map_list); static LIST_HEAD(regulator_ena_gpio_list); static LIST_HEAD(regulator_supply_alias_list); static bool has_full_constraints; +static bool regulator_has_booted; static struct dentry *debugfs_root; @@ -139,7 +140,15 @@ static bool regulator_ops_is_valid(struct regulator_dev *rdev, int ops) return false; } - if (rdev->constraints->valid_ops_mask & ops) + /* +* Ignore regulator boot-protection, after later_initcall. +*/ + if (!regulator_has_booted && rdev->constraints->boot_protection) { + if (rdev->constraints->boot_valid_ops_mask & ops) + return true; + else + rdev_info(rdev, "rejected operation 0x%02x\n", ops); + } else if (rdev->constraints->valid_ops_mask & ops) return true; return false; @@ -868,7 +877,7 @@ static void print_constraints(struct regulator_dev *rdev) rdev_dbg(rdev, "%s\n", buf); if ((constraints->min_uV != constraints->max_uV) && - !regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) + !(constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) rdev_warn(rdev, "Voltage range but no REGULATOR_CHANGE_VOLTAGE\n"); } @@ -1309,7 +1318,8 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, * it is then we don't need to do nearly so much work for * enable/disable calls. */ - if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS) && + if (rdev->constraints && + !(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS) && _regulator_is_enabled(rdev)) regulator->always_on = true; @@ -4353,6 +4363,12 @@ static int __init regulator_late_cleanup(struct device *dev, void *data) struct regulation_constraints *c = rdev->constraints; int enabled, ret; + /* +* The kernel boot is finished, let's unset boot_protection +* Need a lock? +*/ + c->boot_protection = 0; + if (c && c->always_on) return 0; @@ -4406,6 +4422,8 @@ static int __init regulator_init_complete(void) if (of_have_populated_dt()) has_full_constraints = true; + regulator_has_booted = true; + /* If we have a full configuration then disable any regulators * we have permission to change the status for and which are * not in use or always_on. This is effectively the default diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 6b0aa80..bfec59c 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -78,6 +78,35 @@ static void of_get_regulation_constraints(struct device_node *np, if (of_property_read_bool(np, "regulator-allow-set-load")) constraints->valid_ops_mask |= REGULATOR_CHANGE_DRMS; + constraints->boot_protection = of_property_read_bool(np, + "regulator-boot-protection"); + + if (constraints->boot_protection) { + if (of_property_read_bool(np, "boot-allow-set-voltage")) + constraints->boot_valid_ops_mask |= + REGULATOR_CHANGE_VOLTAGE; + if (of_property_read_bool(np, "b
[RFC PATCH 1/2] regulator: refactor valid_ops_mask checking code
To make the code more compat and centralized, this patch add a unified function - regulator_ops_is_valid. So we can add some extra checking code easily later. Signed-off-by: WEN Pingbo --- drivers/regulator/core.c | 88 1 file changed, 29 insertions(+), 59 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e0b7642..fe47d38 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -132,6 +132,19 @@ static bool have_full_constraints(void) return has_full_constraints || of_have_populated_dt(); } +static bool regulator_ops_is_valid(struct regulator_dev *rdev, int ops) +{ + if (!rdev->constraints) { + rdev_err(rdev, "no constraints\n"); + return false; + } + + if (rdev->constraints->valid_ops_mask & ops) + return true; + + return false; +} + static inline struct regulator_dev *rdev_get_supply(struct regulator_dev *rdev) { if (rdev && rdev->supply) @@ -198,28 +211,13 @@ static struct device_node *of_get_regulator(struct device *dev, const char *supp return regnode; } -static int _regulator_can_change_status(struct regulator_dev *rdev) -{ - if (!rdev->constraints) - return 0; - - if (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS) - return 1; - else - return 0; -} - /* Platform voltage constraint check */ static int regulator_check_voltage(struct regulator_dev *rdev, int *min_uV, int *max_uV) { BUG_ON(*min_uV > *max_uV); - if (!rdev->constraints) { - rdev_err(rdev, "no constraints\n"); - return -ENODEV; - } - if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { + if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { rdev_err(rdev, "voltage operation not allowed\n"); return -EPERM; } @@ -275,11 +273,7 @@ static int regulator_check_current_limit(struct regulator_dev *rdev, { BUG_ON(*min_uA > *max_uA); - if (!rdev->constraints) { - rdev_err(rdev, "no constraints\n"); - return -ENODEV; - } - if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) { + if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_CURRENT)) { rdev_err(rdev, "current operation not allowed\n"); return -EPERM; } @@ -312,11 +306,7 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode) return -EINVAL; } - if (!rdev->constraints) { - rdev_err(rdev, "no constraints\n"); - return -ENODEV; - } - if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) { + if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_MODE)) { rdev_err(rdev, "mode operation not allowed\n"); return -EPERM; } @@ -333,20 +323,6 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode) return -EINVAL; } -/* dynamic regulator mode switching constraint check */ -static int regulator_check_drms(struct regulator_dev *rdev) -{ - if (!rdev->constraints) { - rdev_err(rdev, "no constraints\n"); - return -ENODEV; - } - if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) { - rdev_dbg(rdev, "drms operation not allowed\n"); - return -EPERM; - } - return 0; -} - static ssize_t regulator_uV_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -692,8 +668,7 @@ static int drms_uA_update(struct regulator_dev *rdev) * first check to see if we can set modes at all, otherwise just * tell the consumer everything is OK. */ - err = regulator_check_drms(rdev); - if (err < 0) + if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS)) return 0; if (!rdev->desc->ops->get_optimum_mode && @@ -893,7 +868,7 @@ static void print_constraints(struct regulator_dev *rdev) rdev_dbg(rdev, "%s\n", buf); if ((constraints->min_uV != constraints->max_uV) && - !(constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) + !regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) rdev_warn(rdev, "Voltage range but no REGULATOR_CHANGE_VOLTAGE\n"); } @@ -1334,7 +1309,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, * it is then we
[PATCH 2/3] input: evdev: add new ioctl EVIOCSIFTYPE / EVIOCGIFTYPE
This patch depends on 'introduce new evdev interface'. Userspace cat set / get evdev interface type via the two ioctl commands. And default interface type is EV_IF_LEGACY, so the old binary will work normal with new kernel. Maybe we should change this default option to encourage people to move to new interface. And since all events are stored as input_value in evdev, there are no need to flush evdev_client's buffer if we change clk_type and if_type. Signed-off-by: WEN Pingbo --- drivers/input/evdev.c | 39 +++ include/uapi/linux/input.h | 10 ++ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 170681b..090576b 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -175,7 +175,6 @@ static void evdev_queue_syn_dropped(struct evdev_client *client) static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) { - unsigned long flags; unsigned int clk_type; switch (clkid) { @@ -193,21 +192,29 @@ static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) return -EINVAL; } - if (client->clk_type != clk_type) { + if (client->clk_type != clk_type) client->clk_type = clk_type; - /* -* Flush pending events and queue SYN_DROPPED event, -* but only if the queue is not empty. -*/ - spin_lock_irqsave(&client->buffer_lock, flags); + return 0; +} - if (client->head != client->tail) { - client->packet_head = client->head = client->tail; - __evdev_queue_syn_dropped(client); - } +static int evdev_set_if_type(struct evdev_client *client, unsigned int if_type) +{ + if (client->if_type == if_type) + return 0; - spin_unlock_irqrestore(&client->buffer_lock, flags); + switch (if_type) { + case EVDEV_LEGACY: + client->if_type = EV_IF_LEGACY; + break; + case EVDEV_RAW: + client->if_type = EV_IF_RAW; + break; + case EVDEV_COMPOSITE: + client->if_type = EV_IF_COMPOSITE; + break; + default: + return -EINVAL; } return 0; @@ -1046,6 +1053,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, int __user *ip = (int __user *)p; unsigned int i, t, u, v; unsigned int size; + int if_type; int error; /* First we check for fixed-length commands */ @@ -1144,6 +1152,13 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, case EVIOCSKEYCODE_V2: return evdev_handle_set_keycode_v2(dev, p); + case EVIOCSIFTYPE: + if (get_user(if_type, ip)) + return -EFAULT; + + return evdev_set_if_type(client, if_type); + case EVIOCGIFTYPE: + return put_user(client->if_type, ip); } size = _IOC_SIZE(cmd); diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h index 79b35ff..9ae5243 100644 --- a/include/uapi/linux/input.h +++ b/include/uapi/linux/input.h @@ -234,6 +234,16 @@ struct input_mask { #define EVIOCSCLOCKID _IOW('E', 0xa0, int)/* Set clockid to be used for timestamps */ +#define EVIOCSIFTYPE _IOW('E', 0xa1, int)/* Set if_type */ +#define EVIOCGIFTYPE _IOR('E', 0xa2, int)/* Get if_type */ + +/* + * evdev interface type + */ +#define EVDEV_LEGACY 0x00 +#define EVDEV_RAW 0x01 +#define EVDEV_COMPOSITE0x02 + /* * IDs. */ -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/3] input: evdev: introduce new evdev interface
The y2038 problem in 'struct input_event' is complained too much. And after some discussion with other people, I found it's impossible to solve this in a simple way, and keep backward compatible at the same time, so we need some new y2038-safe interface here. This patch add two new evdev interface type - EV_IF_RAW and EV_IF_COMPOSITE. And leaving the old interface as EV_IF_LEGACY for compatibility. Userspace can switch between those interface seamlessly via ioctl, which will be introduced in another patch. And since evdev doesn't really interest in event timestamp, the patch has also converted input_event to input_value in evdev entirely, and move all time-related operations to input_event_to/from_user(). Signed-off-by: WEN Pingbo --- drivers/input/evdev.c| 78 --- drivers/input/input-compat.c | 148 --- drivers/input/input-compat.h | 48 ++ include/linux/input.h| 12 include/uapi/linux/input.h | 17 + 5 files changed, 176 insertions(+), 127 deletions(-) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index e9ae3d5..170681b 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -28,13 +28,6 @@ #include #include "input-compat.h" -enum evdev_clock_type { - EV_CLK_REAL = 0, - EV_CLK_MONO, - EV_CLK_BOOT, - EV_CLK_MAX -}; - struct evdev { int open; struct input_handle handle; @@ -57,10 +50,11 @@ struct evdev_client { struct evdev *evdev; struct list_head node; unsigned int clk_type; + unsigned int if_type; bool revoked; unsigned long *evmasks[EV_CNT]; unsigned int bufsize; - struct input_event buffer[]; + struct input_value buffer[]; }; static size_t evdev_get_mask_cnt(unsigned int type) @@ -113,7 +107,7 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) unsigned int i, head, num; unsigned int mask = client->bufsize - 1; bool is_report; - struct input_event *ev; + struct input_value *ev; BUG_ON(type == EV_SYN); @@ -135,7 +129,6 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) continue; } else if (head != i) { /* move entry to fill the gap */ - client->buffer[head].time = ev->time; client->buffer[head].type = ev->type; client->buffer[head].code = ev->code; client->buffer[head].value = ev->value; @@ -155,16 +148,8 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) static void __evdev_queue_syn_dropped(struct evdev_client *client) { - struct input_event ev; - ktime_t time; + struct input_value ev; - time = client->clk_type == EV_CLK_REAL ? - ktime_get_real() : - client->clk_type == EV_CLK_MONO ? - ktime_get() : - ktime_get_boottime(); - - ev.time = ktime_to_timeval(time); ev.type = EV_SYN; ev.code = SYN_DROPPED; ev.value = 0; @@ -229,7 +214,7 @@ static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) } static void __pass_event(struct evdev_client *client, -const struct input_event *event) +const struct input_value *event) { client->buffer[client->head++] = *event; client->head &= client->bufsize - 1; @@ -241,7 +226,6 @@ static void __pass_event(struct evdev_client *client, */ client->tail = (client->head - 2) & (client->bufsize - 1); - client->buffer[client->tail].time = event->time; client->buffer[client->tail].type = EV_SYN; client->buffer[client->tail].code = SYN_DROPPED; client->buffer[client->tail].value = 0; @@ -256,19 +240,15 @@ static void __pass_event(struct evdev_client *client, } static void evdev_pass_values(struct evdev_client *client, - const struct input_value *vals, unsigned int count, - ktime_t *ev_time) + const struct input_value *vals, unsigned int count) { struct evdev *evdev = client->evdev; const struct input_value *v; - struct input_event event; bool wakeup = false; if (client->revoked) return; - event.time = ktime_to_timeval(ev_time[client->clk_type]); - /* Interrupts are disabled, just acquire the lock. */ spin_lock(&client->buffer_lock); @@ -284,10 +264,7 @@ static void evdev_pass_values(struct evdev_client *client
[PATCH 3/3] uinput: convert input_event to input_value
This patch depends on 'add new evdev interface'. We should not use input_event in kernel any more. Convert it in uinput, and adapt to new api changes. Signed-off-by: WEN Pingbo --- drivers/input/misc/uinput.c | 23 +++ include/linux/uinput.h | 2 +- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 5adbced..d84c6d4 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -50,7 +50,6 @@ static int uinput_dev_event(struct input_dev *dev, udev->buff[udev->head].type = type; udev->buff[udev->head].code = code; udev->buff[udev->head].value = value; - do_gettimeofday(&udev->buff[udev->head].time); udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE; wake_up_interruptible(&udev->waitq); @@ -436,24 +435,24 @@ static int uinput_setup_device(struct uinput_device *udev, static ssize_t uinput_inject_events(struct uinput_device *udev, const char __user *buffer, size_t count) { - struct input_event ev; + struct input_value ev; size_t bytes = 0; - if (count != 0 && count < input_event_size()) + if (count != 0 && count < input_event_size(EV_IF_LEGACY)) return -EINVAL; - while (bytes + input_event_size() <= count) { + while (bytes + input_event_size(EV_IF_LEGACY) <= count) { /* * Note that even if some events were fetched successfully * we are still going to return EFAULT instead of partial * count to let userspace know that it got it's buffers * all wrong. */ - if (input_event_from_user(buffer + bytes, &ev)) + if (input_event_from_user(buffer + bytes, &ev, EV_IF_LEGACY)) return -EFAULT; input_event(udev->dev, ev.type, ev.code, ev.value); - bytes += input_event_size(); + bytes += input_event_size(EV_IF_LEGACY); } return bytes; @@ -482,7 +481,7 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer, } static bool uinput_fetch_next_event(struct uinput_device *udev, - struct input_event *event) + struct input_value *event) { bool have_event; @@ -502,16 +501,16 @@ static bool uinput_fetch_next_event(struct uinput_device *udev, static ssize_t uinput_events_to_user(struct uinput_device *udev, char __user *buffer, size_t count) { - struct input_event event; + struct input_value event; size_t read = 0; - while (read + input_event_size() <= count && + while (read + input_event_size(EV_IF_LEGACY) <= count && uinput_fetch_next_event(udev, &event)) { - if (input_event_to_user(buffer + read, &event)) + if (input_value_to_user(buffer + read, &event, EV_IF_LEGACY)) return -EFAULT; - read += input_event_size(); + read += input_event_size(EV_IF_LEGACY); } return read; @@ -523,7 +522,7 @@ static ssize_t uinput_read(struct file *file, char __user *buffer, struct uinput_device *udev = file->private_data; ssize_t retval; - if (count != 0 && count < input_event_size()) + if (count != 0 && count < input_event_size(EV_IF_LEGACY)) return -EINVAL; do { diff --git a/include/linux/uinput.h b/include/linux/uinput.h index 0994c0d..bdb6fca 100644 --- a/include/linux/uinput.h +++ b/include/linux/uinput.h @@ -66,7 +66,7 @@ struct uinput_device { unsigned char ready; unsigned char head; unsigned char tail; - struct input_event buff[UINPUT_BUFFER_SIZE]; + struct input_value buff[UINPUT_BUFFER_SIZE]; unsigned intff_effects_max; struct uinput_request *requests[UINPUT_NUM_REQUESTS]; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 0/3] introduce new evdev interface type
To solve the y2038 problem in input_event, I had some attempts before [1], and this is the second one. We can force userspace to use monotonic time in event timestamp, so the 'struct timeval' is enough to keep y2038-safe, as Arnd suggested. But we can not find a way to make kernel compatible with old binaries, which use realtime, and there are still some devices, which depend on realtime. So I get a idea to add a new evdev interface, which is y2038 safe. And userspace can switch between the old and new interface via ioctl. The patch series add three evdev interface type: - EV_IF_LEGACY send event by input_event. This is the default option, keep kernel backward compatible. - EV_IF_RAW send event by input_value, which doesn't contain a timestamp. If userspace don't need the event timestamp, EV_IF_RAW is the best choice. - EV_IF_COMPOSITE send event by input_composite_event. This is a new structure, which append a nanosecond timestamp after input_value. Since the input_value and s64 are the same size, so you can treat it as two input_value. Actually, evdev is not interesting in event timestamp, all it should do is to keep event sequences, and evdev already satisfy this. So in the kernel, the event should only store in input_value, input_event and input_composite_event is used by userspace only. I also wrote a evtest tool [2], to validate those patches. The tool create a evdev device via uinput, and inject event through evdev or uinput, with different interface type. I have run this test in my Dragonboard 410c, by this command: $ evtest -l -r -c -n 40 No problem found, all events are received normally. [1]: previous patches - https://www.spinics.net/lists/y2038/msg00959.html [2]: evtest source code - https://github.com/wengpingbo/evtest WEN Pingbo (3): input: evdev: introduce new evdev interface input: evdev: add new ioctl EVIOCSIFTYPE / EVIOCGIFTYPE uinput: convert input_event to input_value drivers/input/evdev.c| 117 -- drivers/input/input-compat.c | 148 --- drivers/input/input-compat.h | 48 ++ drivers/input/misc/uinput.c | 23 --- include/linux/input.h| 12 include/linux/uinput.h | 2 +- include/uapi/linux/input.h | 27 7 files changed, 225 insertions(+), 152 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V4] hp_sdc: convert struct timeval to ktime_t
struct timeval is not y2038 safe, convert it to ktime_t, and there is no need to handle sec and usec separately And since hp_sdc.rtv is only used for time diff, monotonic time is better here Signed-off-by: WEN Pingbo --- Version 2: Using ktime_t instead of struct timespec64 Version 3: Commit msg adjustment, and using ktime_to_ns to extract nsecs Version 4: Correct commit msg format drivers/input/serio/hp_sdc.c | 16 ++-- include/linux/hp_sdc.h | 6 +++--- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 852858e..17e3725 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -193,7 +193,7 @@ static void hp_sdc_take(int irq, void *dev_id, uint8_t status, uint8_t data) curr->seq[curr->idx++] = status; curr->seq[curr->idx++] = data; hp_sdc.rqty -= 2; - do_gettimeofday(&hp_sdc.rtv); + hp_sdc.rtv = ktime_get(); if (hp_sdc.rqty <= 0) { /* All data has been gathered. */ @@ -306,13 +306,9 @@ static void hp_sdc_tasklet(unsigned long foo) write_lock_irq(&hp_sdc.rtq_lock); if (hp_sdc.rcurr >= 0) { - struct timeval tv; + ktime_t time_diff = ktime_sub(ktime_get(), hp_sdc.rtv); - do_gettimeofday(&tv); - if (tv.tv_sec > hp_sdc.rtv.tv_sec) - tv.tv_usec += USEC_PER_SEC; - - if (tv.tv_usec - hp_sdc.rtv.tv_usec > HP_SDC_MAX_REG_DELAY) { + if (ktime_to_ns(time_diff) > HP_SDC_MAX_REG_DELAY) { hp_sdc_transaction *curr; uint8_t tmp; @@ -321,8 +317,8 @@ static void hp_sdc_tasklet(unsigned long foo) * we'll need to figure out a way to communicate * it back to the application. and be less verbose. */ - printk(KERN_WARNING PREFIX "read timeout (%ius)!\n", - (int)(tv.tv_usec - hp_sdc.rtv.tv_usec)); + printk(KERN_WARNING PREFIX "read timeout (%llins)!\n", + ktime_to_ns(time_diff)); curr->idx += hp_sdc.rqty; hp_sdc.rqty = 0; tmp = curr->seq[curr->actidx]; @@ -551,7 +547,7 @@ unsigned long hp_sdc_put(void) /* Start a new read */ hp_sdc.rqty = curr->seq[curr->idx]; - do_gettimeofday(&hp_sdc.rtv); + hp_sdc.rtv = ktime_get(); curr->idx++; /* Still need to lock here in case of spurious irq. */ write_lock_irq(&hp_sdc.rtq_lock); diff --git a/include/linux/hp_sdc.h b/include/linux/hp_sdc.h index d392975..348a9b5 100644 --- a/include/linux/hp_sdc.h +++ b/include/linux/hp_sdc.h @@ -47,9 +47,9 @@ #endif -/* No 4X status reads take longer than this (in usec). +/* No 4X status reads take longer than this (in nsec). */ -#define HP_SDC_MAX_REG_DELAY 2 +#define HP_SDC_MAX_REG_DELAY 2000 typedef void (hp_sdc_irqhook) (int irq, void *dev_id, uint8_t status, uint8_t data); @@ -281,7 +281,7 @@ typedef struct { hp_sdc_transaction *tq[HP_SDC_QUEUE_LEN]; /* All pending read/writes */ int rcurr, rqty;/* Current read transact in process */ - struct timeval rtv;/* Time when current read started */ + ktime_t rtv;/* Time when current read started */ int wcurr; /* Current write transact in process */ int dev_err;/* carries status from registration */ -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V3 2/2] hil_mlc: convert timeval to jiffies
struct timeval is not y2038 safe, and what mlc->instart do is scheduling a task in a fixed timeout, so jiffies is the simplest choice here. In hilse_donode(), the expires in mod_timer equals jiffies + intimeout - (now - instart) If we use jiffies in 'now', the expires equals instart + intimeout So, all we need to do is that making sure expires is a future timestamp before passed it to mod_timer Signed-off-by: WEN Pingbo --- Version 2: Using ktime_t to fix y2038 problem Version 3: Convert it to jiffies drivers/input/serio/hil_mlc.c| 17 +++-- drivers/input/serio/hp_sdc_mlc.c | 7 +++ include/linux/hil_mlc.h | 2 +- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index fb297aa..5428098 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -603,7 +603,7 @@ static inline void hilse_setup_input(hil_mlc *mlc, const struct hilse_node *node } mlc->istarted = 1; mlc->intimeout = node->arg; - do_gettimeofday(&(mlc->instart)); + mlc->instart = jiffies; mlc->icount = 15; memset(mlc->ipacket, 0, 16 * sizeof(hil_packet)); BUG_ON(down_trylock(&mlc->isem)); @@ -708,7 +708,7 @@ static int hilse_donode(hil_mlc *mlc) break; } mlc->ostarted = 0; - do_gettimeofday(&(mlc->instart)); + mlc->instart = jiffies; write_unlock_irqrestore(&mlc->lock, flags); nextidx = HILSEN_NEXT; break; @@ -729,18 +729,15 @@ static int hilse_donode(hil_mlc *mlc) #endif while (nextidx & HILSEN_SCHED) { - struct timeval tv; + unsigned long expires = mlc->instart + + usecs_to_jiffies(mlc->intimeout); if (!sched_long) goto sched; - do_gettimeofday(&tv); - tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec); - tv.tv_usec -= mlc->instart.tv_usec; - if (tv.tv_usec >= mlc->intimeout) goto sched; - tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / USEC_PER_SEC; - if (!tv.tv_usec) goto sched; - mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec); + if (time_after_eq(jiffies, expires)) + goto sched; + mod_timer(&hil_mlcs_kicker, expires); break; sched: tasklet_schedule(&hil_mlcs_tasklet); diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c index d50f067..b91d5bb 100644 --- a/drivers/input/serio/hp_sdc_mlc.c +++ b/drivers/input/serio/hp_sdc_mlc.c @@ -149,7 +149,6 @@ static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout) /* Try to down the semaphore */ if (down_trylock(&mlc->isem)) { - struct timeval tv; if (priv->emtestmode) { mlc->ipacket[0] = HIL_ERR_INT | (mlc->opacket & @@ -160,9 +159,9 @@ static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout) /* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */ goto wasup; } - do_gettimeofday(&tv); - tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec); - if (tv.tv_usec - mlc->instart.tv_usec > mlc->intimeout) { + + if (time_after(jiffies, + mlc->instart + usecs_to_jiffies(mlc->intimeout))) { /* printk("!%i %i", tv.tv_usec - mlc->instart.tv_usec, mlc->intimeout); diff --git a/include/linux/hil_mlc.h b/include/linux/hil_mlc.h index 29bb5e3..feb167d 100644 --- a/include/linux/hil_mlc.h +++ b/include/linux/hil_mlc.h @@ -144,7 +144,7 @@ struct hil_mlc { hil_packet ipacket[16]; hil_packet imatch; int icount; - struct timeval instart; + unsigned long instart; /* in jiffies */ suseconds_t intimeout; int ddi;/* Last operational device id */ -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V3 1/2] hil_mlc: convert timeval to time64_t
Since mlc->lcv_t is only interested in seconds, directly using time64_t here Signed-off-by: WEN Pingbo --- Version 2: Convert timeval to ktime_t Version 3: Convert it to time64_t, since it's a better choice drivers/input/serio/hil_mlc.c | 8 +++- include/linux/hil_mlc.h | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index 65605e4..fb297aa 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -274,14 +274,12 @@ static int hilse_match(hil_mlc *mlc, int unused) /* An LCV used to prevent runaway loops, forces 5 second sleep when reset. */ static int hilse_init_lcv(hil_mlc *mlc, int unused) { - struct timeval tv; + time64_t now = ktime_get_seconds(); - do_gettimeofday(&tv); - - if (mlc->lcv && (tv.tv_sec - mlc->lcv_tv.tv_sec) < 5) + if (mlc->lcv && (now - mlc->lcv_t) < 5) return -1; - mlc->lcv_tv = tv; + mlc->lcv_t = now; mlc->lcv = 0; return 0; diff --git a/include/linux/hil_mlc.h b/include/linux/hil_mlc.h index 394a840..29bb5e3 100644 --- a/include/linux/hil_mlc.h +++ b/include/linux/hil_mlc.h @@ -149,7 +149,7 @@ struct hil_mlc { int ddi;/* Last operational device id */ int lcv;/* LCV to throttle loops */ - struct timeval lcv_tv; /* Time loop was started */ + time64_tlcv_t; /* Time loop was started */ int di_map[7]; /* Maps below items to live devs */ struct hil_mlc_devinfo di[HIL_MLC_DEVMEM]; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V3] hp_sdc: convert struct timeval to ktime_t
1. struct timeval is not y2038 safe, convert it to ktime_t, and there is no need to handle sec and usec separately 2. hp_sdc.rtv is only used for time diff, monotonic time is better here Signed-off-by: WEN Pingbo --- Version 2: Using ktime_t instead of struct timespec64 Version 3: Commit msg adjustment, and using ktime_to_ns to extract nsecs drivers/input/serio/hp_sdc.c | 16 ++-- include/linux/hp_sdc.h | 6 +++--- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 852858e..17e3725 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -193,7 +193,7 @@ static void hp_sdc_take(int irq, void *dev_id, uint8_t status, uint8_t data) curr->seq[curr->idx++] = status; curr->seq[curr->idx++] = data; hp_sdc.rqty -= 2; - do_gettimeofday(&hp_sdc.rtv); + hp_sdc.rtv = ktime_get(); if (hp_sdc.rqty <= 0) { /* All data has been gathered. */ @@ -306,13 +306,9 @@ static void hp_sdc_tasklet(unsigned long foo) write_lock_irq(&hp_sdc.rtq_lock); if (hp_sdc.rcurr >= 0) { - struct timeval tv; + ktime_t time_diff = ktime_sub(ktime_get(), hp_sdc.rtv); - do_gettimeofday(&tv); - if (tv.tv_sec > hp_sdc.rtv.tv_sec) - tv.tv_usec += USEC_PER_SEC; - - if (tv.tv_usec - hp_sdc.rtv.tv_usec > HP_SDC_MAX_REG_DELAY) { + if (ktime_to_ns(time_diff) > HP_SDC_MAX_REG_DELAY) { hp_sdc_transaction *curr; uint8_t tmp; @@ -321,8 +317,8 @@ static void hp_sdc_tasklet(unsigned long foo) * we'll need to figure out a way to communicate * it back to the application. and be less verbose. */ - printk(KERN_WARNING PREFIX "read timeout (%ius)!\n", - (int)(tv.tv_usec - hp_sdc.rtv.tv_usec)); + printk(KERN_WARNING PREFIX "read timeout (%llins)!\n", + ktime_to_ns(time_diff)); curr->idx += hp_sdc.rqty; hp_sdc.rqty = 0; tmp = curr->seq[curr->actidx]; @@ -551,7 +547,7 @@ unsigned long hp_sdc_put(void) /* Start a new read */ hp_sdc.rqty = curr->seq[curr->idx]; - do_gettimeofday(&hp_sdc.rtv); + hp_sdc.rtv = ktime_get(); curr->idx++; /* Still need to lock here in case of spurious irq. */ write_lock_irq(&hp_sdc.rtq_lock); diff --git a/include/linux/hp_sdc.h b/include/linux/hp_sdc.h index d392975..348a9b5 100644 --- a/include/linux/hp_sdc.h +++ b/include/linux/hp_sdc.h @@ -47,9 +47,9 @@ #endif -/* No 4X status reads take longer than this (in usec). +/* No 4X status reads take longer than this (in nsec). */ -#define HP_SDC_MAX_REG_DELAY 2 +#define HP_SDC_MAX_REG_DELAY 2000 typedef void (hp_sdc_irqhook) (int irq, void *dev_id, uint8_t status, uint8_t data); @@ -281,7 +281,7 @@ typedef struct { hp_sdc_transaction *tq[HP_SDC_QUEUE_LEN]; /* All pending read/writes */ int rcurr, rqty;/* Current read transact in process */ - struct timeval rtv;/* Time when current read started */ + ktime_t rtv;/* Time when current read started */ int wcurr; /* Current write transact in process */ int dev_err;/* carries status from registration */ -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V2] hil_mlc: convert timeval to ktime_t
Using struct timeval will cause time overflow in 2038, replacing it with ktime_t. And we don't need to handle sec and nsec separately. Since mlc->lcv_t is only interested in seconds, directly using time64_t here. And monotonic time is better here, since the original driver don't care the wall time. In addition, the original driver try to covert usec to jiffies manually in hilse_donode(). This is not a universal and safe way, using nsecs_to_jiffies() to fix that. Signed-off-by: WEN Pingbo --- drivers/input/serio/hil_mlc.c| 28 +--- drivers/input/serio/hp_sdc_mlc.c | 8 include/linux/hil_mlc.h | 4 ++-- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index 65605e4..2746509 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -274,14 +274,12 @@ static int hilse_match(hil_mlc *mlc, int unused) /* An LCV used to prevent runaway loops, forces 5 second sleep when reset. */ static int hilse_init_lcv(hil_mlc *mlc, int unused) { - struct timeval tv; + time64_t now = ktime_get_seconds(); - do_gettimeofday(&tv); - - if (mlc->lcv && (tv.tv_sec - mlc->lcv_tv.tv_sec) < 5) + if (mlc->lcv && (now - mlc->lcv_t) < 5) return -1; - mlc->lcv_tv = tv; + mlc->lcv_t = now; mlc->lcv = 0; return 0; @@ -605,7 +603,7 @@ static inline void hilse_setup_input(hil_mlc *mlc, const struct hilse_node *node } mlc->istarted = 1; mlc->intimeout = node->arg; - do_gettimeofday(&(mlc->instart)); + mlc->instart = ktime_get(); mlc->icount = 15; memset(mlc->ipacket, 0, 16 * sizeof(hil_packet)); BUG_ON(down_trylock(&mlc->isem)); @@ -710,7 +708,7 @@ static int hilse_donode(hil_mlc *mlc) break; } mlc->ostarted = 0; - do_gettimeofday(&(mlc->instart)); + mlc->instart = ktime_get(); write_unlock_irqrestore(&mlc->lock, flags); nextidx = HILSEN_NEXT; break; @@ -731,18 +729,18 @@ static int hilse_donode(hil_mlc *mlc) #endif while (nextidx & HILSEN_SCHED) { - struct timeval tv; + ktime_t tmp = ktime_sub(ktime_get(), mlc->instart); if (!sched_long) goto sched; - do_gettimeofday(&tv); - tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec); - tv.tv_usec -= mlc->instart.tv_usec; - if (tv.tv_usec >= mlc->intimeout) goto sched; - tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / USEC_PER_SEC; - if (!tv.tv_usec) goto sched; - mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec); + if (tmp.tv64 >= (mlc->intimeout * NSEC_PER_USEC)) + goto sched; + tmp.tv64 = mlc->intimeout * NSEC_PER_USEC - tmp.tv64; + if (tmp.tv64 < NSEC_PER_USEC) + goto sched; + mod_timer(&hil_mlcs_kicker, + jiffies + nsecs_to_jiffies(tmp.tv64)); break; sched: tasklet_schedule(&hil_mlcs_tasklet); diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c index d50f067..0a27b89 100644 --- a/drivers/input/serio/hp_sdc_mlc.c +++ b/drivers/input/serio/hp_sdc_mlc.c @@ -149,7 +149,8 @@ static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout) /* Try to down the semaphore */ if (down_trylock(&mlc->isem)) { - struct timeval tv; + ktime_t tmp = ktime_sub(ktime_get(), mlc->instart); + if (priv->emtestmode) { mlc->ipacket[0] = HIL_ERR_INT | (mlc->opacket & @@ -160,9 +161,8 @@ static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout) /* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */ goto wasup; } - do_gettimeofday(&tv); - tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec); - if (tv.tv_usec - mlc->instart.tv_usec > mlc->intimeout) { + + if (tmp.tv64 > mlc->intimeout * NSEC_PER_USEC) { /* printk("!%i %i", tv.tv_usec - mlc->instart.tv_usec, mlc->intimeout); diff --git a/include/linux/hil_mlc.h b/include/linux/hil_mlc.h index 394a840..ec6 100644 --- a/include/linux/hil_mlc.h +++ b/include/linux/hil_mlc.h @@ -1
[PATCH V2] hp_sdc: fixed y2038 problem
1. Converting timeval to ktime_t, and there is no need to handle sec and usec separately 2. hp_sdc.rtv is only used for time diff, monotonic time is better here Signed-off-by: WEN Pingbo --- drivers/input/serio/hp_sdc.c | 16 ++-- include/linux/hp_sdc.h | 6 +++--- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 852858e..8ef82ee 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -193,7 +193,7 @@ static void hp_sdc_take(int irq, void *dev_id, uint8_t status, uint8_t data) curr->seq[curr->idx++] = status; curr->seq[curr->idx++] = data; hp_sdc.rqty -= 2; - do_gettimeofday(&hp_sdc.rtv); + hp_sdc.rtv = ktime_get(); if (hp_sdc.rqty <= 0) { /* All data has been gathered. */ @@ -306,13 +306,9 @@ static void hp_sdc_tasklet(unsigned long foo) write_lock_irq(&hp_sdc.rtq_lock); if (hp_sdc.rcurr >= 0) { - struct timeval tv; + ktime_t time_diff = ktime_sub(ktime_get(), hp_sdc.rtv); - do_gettimeofday(&tv); - if (tv.tv_sec > hp_sdc.rtv.tv_sec) - tv.tv_usec += USEC_PER_SEC; - - if (tv.tv_usec - hp_sdc.rtv.tv_usec > HP_SDC_MAX_REG_DELAY) { + if (time_diff.tv64 > HP_SDC_MAX_REG_DELAY) { hp_sdc_transaction *curr; uint8_t tmp; @@ -321,8 +317,8 @@ static void hp_sdc_tasklet(unsigned long foo) * we'll need to figure out a way to communicate * it back to the application. and be less verbose. */ - printk(KERN_WARNING PREFIX "read timeout (%ius)!\n", - (int)(tv.tv_usec - hp_sdc.rtv.tv_usec)); + printk(KERN_WARNING PREFIX "read timeout (%llins)!\n", + time_diff.tv64); curr->idx += hp_sdc.rqty; hp_sdc.rqty = 0; tmp = curr->seq[curr->actidx]; @@ -551,7 +547,7 @@ unsigned long hp_sdc_put(void) /* Start a new read */ hp_sdc.rqty = curr->seq[curr->idx]; - do_gettimeofday(&hp_sdc.rtv); + hp_sdc.rtv = ktime_get(); curr->idx++; /* Still need to lock here in case of spurious irq. */ write_lock_irq(&hp_sdc.rtq_lock); diff --git a/include/linux/hp_sdc.h b/include/linux/hp_sdc.h index d392975..348a9b5 100644 --- a/include/linux/hp_sdc.h +++ b/include/linux/hp_sdc.h @@ -47,9 +47,9 @@ #endif -/* No 4X status reads take longer than this (in usec). +/* No 4X status reads take longer than this (in nsec). */ -#define HP_SDC_MAX_REG_DELAY 2 +#define HP_SDC_MAX_REG_DELAY 2000 typedef void (hp_sdc_irqhook) (int irq, void *dev_id, uint8_t status, uint8_t data); @@ -281,7 +281,7 @@ typedef struct { hp_sdc_transaction *tq[HP_SDC_QUEUE_LEN]; /* All pending read/writes */ int rcurr, rqty;/* Current read transact in process */ - struct timeval rtv;/* Time when current read started */ + ktime_t rtv;/* Time when current read started */ int wcurr; /* Current write transact in process */ int dev_err;/* carries status from registration */ -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] hil_mlc: convert timeval to timespec64
Using struct timeval will cause time overflow in 2038, replacing it with a 64bit version. In addition, the origin driver try to covert usec to jiffies manually in hilse_donode(). This is not a universal and safe way, using nsecs_to_jiffies() to fix that. Signed-off-by: WEN Pingbo --- drivers/input/serio/hil_mlc.c| 31 +-- drivers/input/serio/hp_sdc_mlc.c | 10 ++ include/linux/hil_mlc.h | 4 ++-- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index 65605e4..4e3b926 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -274,14 +274,14 @@ static int hilse_match(hil_mlc *mlc, int unused) /* An LCV used to prevent runaway loops, forces 5 second sleep when reset. */ static int hilse_init_lcv(hil_mlc *mlc, int unused) { - struct timeval tv; + struct timespec64 ts64; - do_gettimeofday(&tv); + ktime_get_ts64(&ts64); - if (mlc->lcv && (tv.tv_sec - mlc->lcv_tv.tv_sec) < 5) + if (mlc->lcv && (ts64.tv_sec - mlc->lcv_ts64.tv_sec) < 5) return -1; - mlc->lcv_tv = tv; + mlc->lcv_ts64 = ts64; mlc->lcv = 0; return 0; @@ -605,7 +605,7 @@ static inline void hilse_setup_input(hil_mlc *mlc, const struct hilse_node *node } mlc->istarted = 1; mlc->intimeout = node->arg; - do_gettimeofday(&(mlc->instart)); + ktime_get_ts64(&(mlc->instart)); mlc->icount = 15; memset(mlc->ipacket, 0, 16 * sizeof(hil_packet)); BUG_ON(down_trylock(&mlc->isem)); @@ -710,7 +710,7 @@ static int hilse_donode(hil_mlc *mlc) break; } mlc->ostarted = 0; - do_gettimeofday(&(mlc->instart)); + ktime_get_ts64(&(mlc->instart)); write_unlock_irqrestore(&mlc->lock, flags); nextidx = HILSEN_NEXT; break; @@ -731,18 +731,21 @@ static int hilse_donode(hil_mlc *mlc) #endif while (nextidx & HILSEN_SCHED) { - struct timeval tv; + struct timespec64 ts64; if (!sched_long) goto sched; - do_gettimeofday(&tv); - tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec); - tv.tv_usec -= mlc->instart.tv_usec; - if (tv.tv_usec >= mlc->intimeout) goto sched; - tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / USEC_PER_SEC; - if (!tv.tv_usec) goto sched; - mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec); + ktime_get_ts64(&ts64); + ts64.tv_nsec += NSEC_PER_SEC * + (ts64.tv_sec - mlc->instart.tv_sec); + ts64.tv_nsec -= mlc->instart.tv_nsec; + if (ts64.tv_nsec >= (mlc->intimeout * NSEC_PER_USEC)) + goto sched; + ts64.tv_nsec = mlc->intimeout * NSEC_PER_USEC - ts64.tv_nsec; + if (!ts64.tv_nsec) goto sched; + mod_timer(&hil_mlcs_kicker, + jiffies + nsecs_to_jiffies(ts64.tv_nsec)); break; sched: tasklet_schedule(&hil_mlcs_tasklet); diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c index d50f067..369885d 100644 --- a/drivers/input/serio/hp_sdc_mlc.c +++ b/drivers/input/serio/hp_sdc_mlc.c @@ -149,7 +149,7 @@ static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout) /* Try to down the semaphore */ if (down_trylock(&mlc->isem)) { - struct timeval tv; + struct timespec64 ts64; if (priv->emtestmode) { mlc->ipacket[0] = HIL_ERR_INT | (mlc->opacket & @@ -160,9 +160,11 @@ static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout) /* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */ goto wasup; } - do_gettimeofday(&tv); - tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec); - if (tv.tv_usec - mlc->instart.tv_usec > mlc->intimeout) { + ktime_get_ts64(&ts64); + ts64.tv_nsec += NSEC_PER_SEC * + (ts64.tv_sec - mlc->instart.tv_sec); + if (ts64.tv_nsec - mlc->instart.tv_nsec > mlc->intimeout * + NSEC_PER_USEC) { /* printk("!%i %i", tv.tv_usec - mlc->instart.tv_usec, mlc-&
[PATCH] hp_sdc: fixed y2038 problem
Two replacements happened in this patch: 1. using timespec64 to prevent time overflow in 2038 2. using ktime_get_ts64 to avoid wall time issues(leap second, etc) Signed-off-by: WEN Pingbo --- drivers/input/serio/hp_sdc.c | 18 +- include/linux/hp_sdc.h | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 852858e..76fb7fa 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -193,7 +193,7 @@ static void hp_sdc_take(int irq, void *dev_id, uint8_t status, uint8_t data) curr->seq[curr->idx++] = status; curr->seq[curr->idx++] = data; hp_sdc.rqty -= 2; - do_gettimeofday(&hp_sdc.rtv); + ktime_get_ts64(&hp_sdc.rtv); if (hp_sdc.rqty <= 0) { /* All data has been gathered. */ @@ -306,13 +306,13 @@ static void hp_sdc_tasklet(unsigned long foo) write_lock_irq(&hp_sdc.rtq_lock); if (hp_sdc.rcurr >= 0) { - struct timeval tv; + struct timespec64 ts64; - do_gettimeofday(&tv); - if (tv.tv_sec > hp_sdc.rtv.tv_sec) - tv.tv_usec += USEC_PER_SEC; + ktime_get_ts64(&ts64); + if (ts64.tv_sec > hp_sdc.rtv.tv_sec) + ts64.tv_nsec += NSEC_PER_SEC; - if (tv.tv_usec - hp_sdc.rtv.tv_usec > HP_SDC_MAX_REG_DELAY) { + if (ts64.tv_nsec - hp_sdc.rtv.tv_nsec > HP_SDC_MAX_REG_DELAY) { hp_sdc_transaction *curr; uint8_t tmp; @@ -321,8 +321,8 @@ static void hp_sdc_tasklet(unsigned long foo) * we'll need to figure out a way to communicate * it back to the application. and be less verbose. */ - printk(KERN_WARNING PREFIX "read timeout (%ius)!\n", - (int)(tv.tv_usec - hp_sdc.rtv.tv_usec)); + printk(KERN_WARNING PREFIX "read timeout (%llins)!\n", + (s64)(ts64.tv_nsec - hp_sdc.rtv.tv_nsec)); curr->idx += hp_sdc.rqty; hp_sdc.rqty = 0; tmp = curr->seq[curr->actidx]; @@ -551,7 +551,7 @@ unsigned long hp_sdc_put(void) /* Start a new read */ hp_sdc.rqty = curr->seq[curr->idx]; - do_gettimeofday(&hp_sdc.rtv); + ktime_get_ts64(&hp_sdc.rtv); curr->idx++; /* Still need to lock here in case of spurious irq. */ write_lock_irq(&hp_sdc.rtq_lock); diff --git a/include/linux/hp_sdc.h b/include/linux/hp_sdc.h index d392975..1535640 100644 --- a/include/linux/hp_sdc.h +++ b/include/linux/hp_sdc.h @@ -47,9 +47,9 @@ #endif -/* No 4X status reads take longer than this (in usec). +/* No 4X status reads take longer than this (in nsec). */ -#define HP_SDC_MAX_REG_DELAY 2 +#define HP_SDC_MAX_REG_DELAY 2000 typedef void (hp_sdc_irqhook) (int irq, void *dev_id, uint8_t status, uint8_t data); @@ -281,7 +281,7 @@ typedef struct { hp_sdc_transaction *tq[HP_SDC_QUEUE_LEN]; /* All pending read/writes */ int rcurr, rqty;/* Current read transact in process */ - struct timeval rtv;/* Time when current read started */ + struct timespec64 rtv;/* Time when current read started */ int wcurr; /* Current write transact in process */ int dev_err;/* carries status from registration */ -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V3] dummy_hcd: replace timeval with timespec64
The millisecond of the last second will be normal if tv_sec is overflowed. But for y2038 consistency and demonstration purpose, and avoiding further risks, we need to remove 'timeval' in this driver, to avoid similair problems. Signed-off-by: Pingbo Wen Reviewed-by: Arnd Bergmann --- V3 Updates: - using ts64 variable name to avoid confusion V2 Updates: - using monotonic time here by replacing getnstimeofday() with ktime_get_ts64(), to avoid leap second issues. The frame time in USB is always 1ms, no matter what speed, so ktime_get_ts64() have enough resolution to cover this. - using NSEC_PER_MSEC instead of hard code. drivers/usb/gadget/udc/dummy_hcd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 1379ad4..2ac9a13 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -833,10 +833,10 @@ static const struct usb_ep_ops dummy_ep_ops = { /* there are both host and device side versions of this call ... */ static int dummy_g_get_frame(struct usb_gadget *_gadget) { - struct timeval tv; + struct timespec64 ts64; - do_gettimeofday(&tv); - return tv.tv_usec / 1000; + ktime_get_ts64(&ts64); + return ts64.tv_nsec / NSEC_PER_MSEC; } static int dummy_wakeup(struct usb_gadget *_gadget) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V2] dummy_hcd: replace timeval with timespec64
The millisecond of the last second will be normal if tv_sec is overflowed. But for y2038 consistency and demonstration purpose, and avoiding further risks, we need to remove 'timeval' in this driver, to avoid similair problems. V2 Updates: - using monotonic time here by replacing getnstimeofday() with ktime_get_ts64(), to avoid leap second issues. The frame time in USB is always 1ms, no matter what speed, so ktime_get_ts64() have enough resolution to cover this. - using NSEC_PER_MSEC instead of hard code. Signed-off-by: Pingbo Wen Cc: Y2038 Cc: linux-kernel@vger.kernel.org Cc: Arnd Bergmann Cc: Felipe Balbi Signed-off-by: WEN Pingbo --- drivers/usb/gadget/udc/dummy_hcd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 1379ad4..6d1ed35 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -833,10 +833,10 @@ static const struct usb_ep_ops dummy_ep_ops = { /* there are both host and device side versions of this call ... */ static int dummy_g_get_frame(struct usb_gadget *_gadget) { - struct timeval tv; + struct timespec64 tv; - do_gettimeofday(&tv); - return tv.tv_usec / 1000; + ktime_get_ts64(&tv); + return tv.tv_nsec / NSEC_PER_MSEC; } static int dummy_wakeup(struct usb_gadget *_gadget) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V2] hp_sdc_rtc: fixed y2038 problem in proc_show
hp_sdc_rtc_proc_show() use timeval to store the time, which will overflowed in 2038. This patch fixes this problem by replacing timeval with timespec64. hp_sdc_rtc_proc_show() only output string, so that userspace will work normally if we apply this patch. Not all timer in i8042 have y2038 risk(handshake, match timer, etc), Replacements in those timer are just for consistency. Version 2 Updates: - compiled in m68k gcc cross compiler(4.6.3), no extra warnings - placed s64 type cast in tv.tv_sec, making sure it work properly in both 32bit and 64bit platform. Signed-off-by: WEN Pingbo Cc: Y2038 --- drivers/input/misc/hp_sdc_rtc.c | 52 - 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index 45e0e3e..1c8c56e 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -198,7 +198,7 @@ static int64_t hp_sdc_rtc_read_i8042timer (uint8_t loadcmd, int numreg) /* Read the i8042 real-time clock */ -static inline int hp_sdc_rtc_read_rt(struct timeval *res) { +static inline int hp_sdc_rtc_read_rt(struct timespec64 *res) { int64_t raw; uint32_t tenms; unsigned int days; @@ -209,15 +209,15 @@ static inline int hp_sdc_rtc_read_rt(struct timeval *res) { tenms = (uint32_t)raw & 0xff; days = (unsigned int)(raw >> 24) & 0x; - res->tv_usec = (suseconds_t)(tenms % 100) * 1; - res->tv_sec = (time_t)(tenms / 100) + days * 86400; + res->tv_nsec = (long)(tenms % 100) * 1 * 1000; + res->tv_sec = (tenms / 100) + (time64_t)days * 86400; return 0; } /* Read the i8042 fast handshake timer */ -static inline int hp_sdc_rtc_read_fhs(struct timeval *res) { +static inline int hp_sdc_rtc_read_fhs(struct timespec64 *res) { int64_t raw; unsigned int tenms; @@ -226,15 +226,15 @@ static inline int hp_sdc_rtc_read_fhs(struct timeval *res) { tenms = (unsigned int)raw & 0x; - res->tv_usec = (suseconds_t)(tenms % 100) * 1; - res->tv_sec = (time_t)(tenms / 100); + res->tv_nsec = (long)(tenms % 100) * 1 * 1000; + res->tv_sec = (time64_t)(tenms / 100); return 0; } /* Read the i8042 match timer (a.k.a. alarm) */ -static inline int hp_sdc_rtc_read_mt(struct timeval *res) { +static inline int hp_sdc_rtc_read_mt(struct timespec64 *res) { int64_t raw; uint32_t tenms; @@ -243,15 +243,15 @@ static inline int hp_sdc_rtc_read_mt(struct timeval *res) { tenms = (uint32_t)raw & 0xff; - res->tv_usec = (suseconds_t)(tenms % 100) * 1; - res->tv_sec = (time_t)(tenms / 100); + res->tv_nsec = (long)(tenms % 100) * 1 * 1000; + res->tv_sec = (time64_t)(tenms / 100); return 0; } /* Read the i8042 delay timer */ -static inline int hp_sdc_rtc_read_dt(struct timeval *res) { +static inline int hp_sdc_rtc_read_dt(struct timespec64 *res) { int64_t raw; uint32_t tenms; @@ -260,15 +260,15 @@ static inline int hp_sdc_rtc_read_dt(struct timeval *res) { tenms = (uint32_t)raw & 0xff; - res->tv_usec = (suseconds_t)(tenms % 100) * 1; - res->tv_sec = (time_t)(tenms / 100); + res->tv_nsec = (long)(tenms % 100) * 1 * 1000; + res->tv_sec = (time64_t)(tenms / 100); return 0; } /* Read the i8042 cycle timer (a.k.a. periodic) */ -static inline int hp_sdc_rtc_read_ct(struct timeval *res) { +static inline int hp_sdc_rtc_read_ct(struct timespec64 *res) { int64_t raw; uint32_t tenms; @@ -277,8 +277,8 @@ static inline int hp_sdc_rtc_read_ct(struct timeval *res) { tenms = (uint32_t)raw & 0xff; - res->tv_usec = (suseconds_t)(tenms % 100) * 1; - res->tv_sec = (time_t)(tenms / 100); + res->tv_nsec = (long)(tenms % 100) * 1 * 1000; + res->tv_sec = (time64_t)(tenms / 100); return 0; } @@ -433,7 +433,7 @@ static int hp_sdc_rtc_proc_show(struct seq_file *m, void *v) #define YN(bit) ("no") #define NY(bit) ("yes") struct rtc_time tm; - struct timeval tv; + struct timespec64 tv; memset(&tm, 0, sizeof(struct rtc_time)); @@ -452,36 +452,36 @@ static int hp_sdc_rtc_proc_show(struct seq_file *m, void *v) if (hp_sdc_rtc_read_rt(&tv)) { seq_puts(m, "i8042 rtc\t: READ FAILED!\n"); } else { - seq_printf(m, "i8042 rtc\t: %ld.%02d seconds\n", -tv.tv_sec, (int)tv.tv_usec/1000); + seq_printf(m, "i8042 rtc\t: %lld.%02ld seconds\n", +(s64)tv.tv_sec, (long)tv.tv_nsec/100L); } if (hp_sdc_rtc_read_fhs
[PATCH] dummy_hcd: replace timeval with timespec64
The millisecond of the last second will be normal if tv_sec is overflowed. But for y2038 consistency and demonstration purpose, and avoiding further risks, we still need to fix it here, to avoid similair problems. Signed-off-by: Pingbo Wen Cc: Y2038 Cc: linux-kernel@vger.kernel.org Cc: Arnd Bergmann Cc: Felipe Balbi --- drivers/usb/gadget/udc/dummy_hcd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 1379ad4..7be721dad 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -833,10 +833,10 @@ static const struct usb_ep_ops dummy_ep_ops = { /* there are both host and device side versions of this call ... */ static int dummy_g_get_frame(struct usb_gadget *_gadget) { - struct timeval tv; + struct timespec64 tv; - do_gettimeofday(&tv); - return tv.tv_usec / 1000; + getnstimeofday64(&tv); + return tv.tv_nsec / 100L; } static int dummy_wakeup(struct usb_gadget *_gadget) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/