diff --git a/Documentation/asm-annotations.rst b/Documentation/asm-annotations.rst index 32ea57483378..76424e0431f4 100644 --- a/Documentation/asm-annotations.rst +++ b/Documentation/asm-annotations.rst @@ -100,6 +100,11 @@ Instruction Macros ~~~~~~~~~~~~~~~~~~ This section covers ``SYM_FUNC_*`` and ``SYM_CODE_*`` enumerated above. +``objtool`` requires that all code must be contained in an ELF symbol. Symbol +names that have a ``.L`` prefix do not emit symbol table entries. ``.L`` +prefixed symbols can be used within a code region, but should be avoided for +denoting a range of code via ``SYM_*_START/END`` annotations. + * ``SYM_FUNC_START`` and ``SYM_FUNC_START_LOCAL`` are supposed to be **the most frequent markings**. They are used for functions with standard calling conventions -- global and local. Like in C, they both align the functions to diff --git a/Documentation/devicetree/bindings/leds/richtek,rt8515.yaml b/Documentation/devicetree/bindings/leds/richtek,rt8515.yaml new file mode 100644 index 000000000000..68c328eec03b --- /dev/null +++ b/Documentation/devicetree/bindings/leds/richtek,rt8515.yaml @@ -0,0 +1,111 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/richtek,rt8515.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Richtek RT8515 1.5A dual channel LED driver + +maintainers: + - Linus Walleij + +description: | + The Richtek RT8515 is a dual channel (two mode) LED driver that + supports driving a white LED in flash or torch mode. The maximum + current for each mode is defined in hardware using two resistors + RFS and RTS. + +properties: + compatible: + const: richtek,rt8515 + + enf-gpios: + maxItems: 1 + description: A connection to the 'ENF' (enable flash) pin. + + ent-gpios: + maxItems: 1 + description: A connection to the 'ENT' (enable torch) pin. + + richtek,rfs-ohms: + minimum: 7680 + maximum: 367000 + description: The resistance value of the RFS resistor. This + resistors limits the maximum flash current. This must be set + for the property flash-max-microamp to work, the RFS resistor + defines the range of the dimmer setting (brightness) of the + flash LED. + + richtek,rts-ohms: + minimum: 7680 + maximum: 367000 + description: The resistance value of the RTS resistor. This + resistors limits the maximum torch current. This must be set + for the property torch-max-microamp to work, the RTS resistor + defines the range of the dimmer setting (brightness) of the + torch LED. + + led: + type: object + $ref: common.yaml# + properties: + function: true + color: true + flash-max-timeout-us: true + + flash-max-microamp: + maximum: 700000 + description: The maximum current for flash mode + is hardwired to the component using the RFS resistor to + ground. The maximum hardware current setting is calculated + according to the formula Imax = 5500 / RFS. The lowest + allowed resistance value is 7.86 kOhm giving an absolute + maximum current of 700mA. By setting this attribute in + the device tree, you can further restrict the maximum + current below the hardware limit. This requires the RFS + to be defined as it defines the maximum range. + + led-max-microamp: + maximum: 700000 + description: The maximum current for torch mode + is hardwired to the component using the RTS resistor to + ground. The maximum hardware current setting is calculated + according to the formula Imax = 5500 / RTS. The lowest + allowed resistance value is 7.86 kOhm giving an absolute + maximum current of 700mA. By setting this attribute in + the device tree, you can further restrict the maximum + current below the hardware limit. This requires the RTS + to be defined as it defines the maximum range. + + additionalProperties: false + +required: + - compatible + - ent-gpios + - enf-gpios + - led + +additionalProperties: false + +examples: + - | + #include + #include + + led-controller { + compatible = "richtek,rt8515"; + enf-gpios = <&gpio4 12 GPIO_ACTIVE_HIGH>; + ent-gpios = <&gpio4 13 GPIO_ACTIVE_HIGH>; + richtek,rfs-ohms = <16000>; + richtek,rts-ohms = <100000>; + + led { + function = LED_FUNCTION_FLASH; + color = ; + flash-max-timeout-us = <250000>; + flash-max-microamp = <150000>; + led-max-microamp = <25000>; + }; + }; + +... diff --git a/Makefile b/Makefile index 805f4e575926..87693c794856 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ VERSION = 5 PATCHLEVEL = 11 SUBLEVEL = 0 -EXTRAVERSION = -rc5 +EXTRAVERSION = -rc6 NAME = Kleptomaniac Octopus # *DOCUMENTATION* diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 6b1eca53e36c..cc7a6271b6b4 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -180,14 +180,19 @@ void notrace restore_interrupts(void) void replay_soft_interrupts(void) { - /* - * We use local_paca rather than get_paca() to avoid all - * the debug_smp_processor_id() business in this low level - * function - */ - unsigned char happened = local_paca->irq_happened; struct pt_regs regs; + /* + * Be careful here, calling these interrupt handlers can cause + * softirqs to be raised, which they may run when calling irq_exit, + * which will cause local_irq_enable() to be run, which can then + * recurse into this function. Don't keep any state across + * interrupt handler calls which may change underneath us. + * + * We use local_paca rather than get_paca() to avoid all the + * debug_smp_processor_id() business in this low level function. + */ + ppc_save_regs(®s); regs.softe = IRQS_ENABLED; @@ -209,7 +214,7 @@ again: * This is a higher priority interrupt than the others, so * replay it first. */ - if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (happened & PACA_IRQ_HMI)) { + if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (local_paca->irq_happened & PACA_IRQ_HMI)) { local_paca->irq_happened &= ~PACA_IRQ_HMI; regs.trap = 0xe60; handle_hmi_exception(®s); @@ -217,7 +222,7 @@ again: hard_irq_disable(); } - if (happened & PACA_IRQ_DEC) { + if (local_paca->irq_happened & PACA_IRQ_DEC) { local_paca->irq_happened &= ~PACA_IRQ_DEC; regs.trap = 0x900; timer_interrupt(®s); @@ -225,7 +230,7 @@ again: hard_irq_disable(); } - if (happened & PACA_IRQ_EE) { + if (local_paca->irq_happened & PACA_IRQ_EE) { local_paca->irq_happened &= ~PACA_IRQ_EE; regs.trap = 0x500; do_IRQ(®s); @@ -233,7 +238,7 @@ again: hard_irq_disable(); } - if (IS_ENABLED(CONFIG_PPC_DOORBELL) && (happened & PACA_IRQ_DBELL)) { + if (IS_ENABLED(CONFIG_PPC_DOORBELL) && (local_paca->irq_happened & PACA_IRQ_DBELL)) { local_paca->irq_happened &= ~PACA_IRQ_DBELL; if (IS_ENABLED(CONFIG_PPC_BOOK3E)) regs.trap = 0x280; @@ -245,7 +250,7 @@ again: } /* Book3E does not support soft-masking PMI interrupts */ - if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (happened & PACA_IRQ_PMI)) { + if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (local_paca->irq_happened & PACA_IRQ_PMI)) { local_paca->irq_happened &= ~PACA_IRQ_PMI; regs.trap = 0xf00; performance_monitor_exception(®s); @@ -253,8 +258,7 @@ again: hard_irq_disable(); } - happened = local_paca->irq_happened; - if (happened & ~PACA_IRQ_HARD_DIS) { + if (local_paca->irq_happened & ~PACA_IRQ_HARD_DIS) { /* * We are responding to the next interrupt, so interrupt-off * latencies should be reset here. diff --git a/arch/x86/entry/thunk_64.S b/arch/x86/entry/thunk_64.S index ccd32877a3c4..496b11ec469d 100644 --- a/arch/x86/entry/thunk_64.S +++ b/arch/x86/entry/thunk_64.S @@ -10,7 +10,7 @@ #include /* rdi: arg1 ... normal C conventions. rax is saved/restored. */ - .macro THUNK name, func, put_ret_addr_in_rdi=0 + .macro THUNK name, func SYM_FUNC_START_NOALIGN(\name) pushq %rbp movq %rsp, %rbp @@ -25,13 +25,8 @@ SYM_FUNC_START_NOALIGN(\name) pushq %r10 pushq %r11 - .if \put_ret_addr_in_rdi - /* 8(%rbp) is return addr on stack */ - movq 8(%rbp), %rdi - .endif - call \func - jmp .L_restore + jmp __thunk_restore SYM_FUNC_END(\name) _ASM_NOKPROBE(\name) .endm @@ -44,7 +39,7 @@ SYM_FUNC_END(\name) #endif #ifdef CONFIG_PREEMPTION -SYM_CODE_START_LOCAL_NOALIGN(.L_restore) +SYM_CODE_START_LOCAL_NOALIGN(__thunk_restore) popq %r11 popq %r10 popq %r9 @@ -56,6 +51,6 @@ SYM_CODE_START_LOCAL_NOALIGN(.L_restore) popq %rdi popq %rbp ret - _ASM_NOKPROBE(.L_restore) -SYM_CODE_END(.L_restore) + _ASM_NOKPROBE(__thunk_restore) +SYM_CODE_END(__thunk_restore) #endif diff --git a/drivers/firmware/efi/apple-properties.c b/drivers/firmware/efi/apple-properties.c index 34f53d898acb..e1926483ae2f 100644 --- a/drivers/firmware/efi/apple-properties.c +++ b/drivers/firmware/efi/apple-properties.c @@ -3,8 +3,9 @@ * apple-properties.c - EFI device properties on Macs * Copyright (C) 2016 Lukas Wunner * - * Note, all properties are considered as u8 arrays. - * To get a value of any of them the caller must use device_property_read_u8_array(). + * Properties are stored either as: + * u8 arrays which can be retrieved with device_property_read_u8_array() or + * booleans which can be queried with device_property_present(). */ #define pr_fmt(fmt) "apple-properties: " fmt @@ -88,8 +89,12 @@ static void __init unmarshal_key_value_pairs(struct dev_header *dev_header, entry_data = ptr + key_len + sizeof(val_len); entry_len = val_len - sizeof(val_len); - entry[i] = PROPERTY_ENTRY_U8_ARRAY_LEN(key, entry_data, - entry_len); + if (entry_len) + entry[i] = PROPERTY_ENTRY_U8_ARRAY_LEN(key, entry_data, + entry_len); + else + entry[i] = PROPERTY_ENTRY_BOOL(key); + if (dump_properties) { dev_info(dev, "property: %s\n", key); print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET, diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c index 0818d3e50734..2ffd2f354d0a 100644 --- a/drivers/i2c/busses/i2c-mt65xx.c +++ b/drivers/i2c/busses/i2c-mt65xx.c @@ -1275,7 +1275,8 @@ static int mtk_i2c_probe(struct platform_device *pdev) mtk_i2c_clock_disable(i2c); ret = devm_request_irq(&pdev->dev, irq, mtk_i2c_irq, - IRQF_TRIGGER_NONE, I2C_DRV_NAME, i2c); + IRQF_NO_SUSPEND | IRQF_TRIGGER_NONE, + I2C_DRV_NAME, i2c); if (ret < 0) { dev_err(&pdev->dev, "Request I2C IRQ %d fail\n", irq); @@ -1302,7 +1303,16 @@ static int mtk_i2c_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP -static int mtk_i2c_resume(struct device *dev) +static int mtk_i2c_suspend_noirq(struct device *dev) +{ + struct mtk_i2c *i2c = dev_get_drvdata(dev); + + i2c_mark_adapter_suspended(&i2c->adap); + + return 0; +} + +static int mtk_i2c_resume_noirq(struct device *dev) { int ret; struct mtk_i2c *i2c = dev_get_drvdata(dev); @@ -1317,12 +1327,15 @@ static int mtk_i2c_resume(struct device *dev) mtk_i2c_clock_disable(i2c); + i2c_mark_adapter_resumed(&i2c->adap); + return 0; } #endif static const struct dev_pm_ops mtk_i2c_pm = { - SET_SYSTEM_SLEEP_PM_OPS(NULL, mtk_i2c_resume) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_i2c_suspend_noirq, + mtk_i2c_resume_noirq) }; static struct platform_driver mtk_i2c_driver = { diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 849d3c5f908e..6c1d8b69a465 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -928,6 +928,9 @@ config LEDS_ACER_A500 This option enables support for the Power Button LED of Acer Iconia Tab A500. +comment "Flash and Torch LED drivers" +source "drivers/leds/flash/Kconfig" + comment "LED Triggers" source "drivers/leds/trigger/Kconfig" diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 73e603e1727e..156c0b4e60d9 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -103,5 +103,8 @@ obj-$(CONFIG_LEDS_SPI_BYTE) += leds-spi-byte.o # LED Userspace Drivers obj-$(CONFIG_LEDS_USER) += uleds.o +# Flash and Torch LED Drivers +obj-$(CONFIG_LEDS_CLASS_FLASH) += flash/ + # LED Triggers obj-$(CONFIG_LEDS_TRIGGERS) += trigger/ diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig new file mode 100644 index 000000000000..d21d273ef3da --- /dev/null +++ b/drivers/leds/flash/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0 + +if LEDS_CLASS_FLASH + +config LEDS_RT8515 + tristate "LED support for Richtek RT8515 flash/torch LED" + depends on GPIOLIB + help + This option enables support for the Richtek RT8515 flash + and torch LEDs found on some mobile phones. + + To compile this driver as a module, choose M here: the module + will be called leds-rt8515. + +endif # LEDS_CLASS_FLASH diff --git a/drivers/leds/flash/Makefile b/drivers/leds/flash/Makefile new file mode 100644 index 000000000000..e990e257f4d7 --- /dev/null +++ b/drivers/leds/flash/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_LEDS_RT8515) += leds-rt8515.o diff --git a/drivers/leds/flash/leds-rt8515.c b/drivers/leds/flash/leds-rt8515.c new file mode 100644 index 000000000000..590bfa180d10 --- /dev/null +++ b/drivers/leds/flash/leds-rt8515.c @@ -0,0 +1,397 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * LED driver for Richtek RT8515 flash/torch white LEDs + * found on some Samsung mobile phones. + * + * This is a 1.5A Boost dual channel driver produced around 2011. + * + * The component lacks a datasheet, but in the schematic picture + * from the LG P970 service manual you can see the connections + * from the RT8515 to the LED, with two resistors connected + * from the pins "RFS" and "RTS" to ground. + * + * On the LG P970: + * RFS (resistance flash setting?) is 20 kOhm + * RTS (resistance torch setting?) is 39 kOhm + * + * Some sleuthing finds us the RT9387A which we have a datasheet for: + * https://static5.arrow.com/pdfs/2014/7/27/8/21/12/794/rtt_/manual/94download_ds.jspprt9387a.jspprt9387a.pdf + * This apparently works the same way so in theory this driver + * should cover RT9387A as well. This has not been tested, please + * update the compatibles if you add RT9387A support. + * + * Linus Walleij + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* We can provide 15-700 mA out to the LED */ +#define RT8515_MIN_IOUT_MA 15 +#define RT8515_MAX_IOUT_MA 700 +/* The maximum intensity is 1-16 for flash and 1-100 for torch */ +#define RT8515_FLASH_MAX 16 +#define RT8515_TORCH_MAX 100 + +#define RT8515_TIMEOUT_US 250000U +#define RT8515_MAX_TIMEOUT_US 300000U + +struct rt8515 { + struct led_classdev_flash fled; + struct device *dev; + struct v4l2_flash *v4l2_flash; + struct mutex lock; + struct regulator *reg; + struct gpio_desc *enable_torch; + struct gpio_desc *enable_flash; + struct timer_list powerdown_timer; + u32 max_timeout; /* Flash max timeout */ + int flash_max_intensity; + int torch_max_intensity; +}; + +static struct rt8515 *to_rt8515(struct led_classdev_flash *fled) +{ + return container_of(fled, struct rt8515, fled); +} + +static void rt8515_gpio_led_off(struct rt8515 *rt) +{ + gpiod_set_value(rt->enable_flash, 0); + gpiod_set_value(rt->enable_torch, 0); +} + +static void rt8515_gpio_brightness_commit(struct gpio_desc *gpiod, + int brightness) +{ + int i; + + /* + * Toggling a GPIO line with a small delay increases the + * brightness one step at a time. + */ + for (i = 0; i < brightness; i++) { + gpiod_set_value(gpiod, 0); + udelay(1); + gpiod_set_value(gpiod, 1); + udelay(1); + } +} + +/* This is setting the torch light level */ +static int rt8515_led_brightness_set(struct led_classdev *led, + enum led_brightness brightness) +{ + struct led_classdev_flash *fled = lcdev_to_flcdev(led); + struct rt8515 *rt = to_rt8515(fled); + + mutex_lock(&rt->lock); + + if (brightness == LED_OFF) { + /* Off */ + rt8515_gpio_led_off(rt); + } else if (brightness < RT8515_TORCH_MAX) { + /* Step it up to movie mode brightness using the flash pin */ + rt8515_gpio_brightness_commit(rt->enable_torch, brightness); + } else { + /* Max torch brightness requested */ + gpiod_set_value(rt->enable_torch, 1); + } + + mutex_unlock(&rt->lock); + + return 0; +} + +static int rt8515_led_flash_strobe_set(struct led_classdev_flash *fled, + bool state) +{ + struct rt8515 *rt = to_rt8515(fled); + struct led_flash_setting *timeout = &fled->timeout; + int brightness = rt->flash_max_intensity; + + mutex_lock(&rt->lock); + + if (state) { + /* Enable LED flash mode and set brightness */ + rt8515_gpio_brightness_commit(rt->enable_flash, brightness); + /* Set timeout */ + mod_timer(&rt->powerdown_timer, + jiffies + usecs_to_jiffies(timeout->val)); + } else { + del_timer_sync(&rt->powerdown_timer); + /* Turn the LED off */ + rt8515_gpio_led_off(rt); + } + + fled->led_cdev.brightness = LED_OFF; + /* After this the torch LED will be disabled */ + + mutex_unlock(&rt->lock); + + return 0; +} + +static int rt8515_led_flash_strobe_get(struct led_classdev_flash *fled, + bool *state) +{ + struct rt8515 *rt = to_rt8515(fled); + + *state = timer_pending(&rt->powerdown_timer); + + return 0; +} + +static int rt8515_led_flash_timeout_set(struct led_classdev_flash *fled, + u32 timeout) +{ + /* The timeout is stored in the led-class-flash core */ + return 0; +} + +static const struct led_flash_ops rt8515_flash_ops = { + .strobe_set = rt8515_led_flash_strobe_set, + .strobe_get = rt8515_led_flash_strobe_get, + .timeout_set = rt8515_led_flash_timeout_set, +}; + +static void rt8515_powerdown_timer(struct timer_list *t) +{ + struct rt8515 *rt = from_timer(rt, t, powerdown_timer); + + /* Turn the LED off */ + rt8515_gpio_led_off(rt); +} + +static void rt8515_init_flash_timeout(struct rt8515 *rt) +{ + struct led_classdev_flash *fled = &rt->fled; + struct led_flash_setting *s; + + /* Init flash timeout setting */ + s = &fled->timeout; + s->min = 1; + s->max = rt->max_timeout; + s->step = 1; + /* + * Set default timeout to RT8515_TIMEOUT_US except if + * max_timeout from DT is lower. + */ + s->val = min(rt->max_timeout, RT8515_TIMEOUT_US); +} + +#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) +/* Configure the V2L2 flash subdevice */ +static void rt8515_init_v4l2_flash_config(struct rt8515 *rt, + struct v4l2_flash_config *v4l2_sd_cfg) +{ + struct led_classdev *led = &rt->fled.led_cdev; + struct led_flash_setting *s; + + strscpy(v4l2_sd_cfg->dev_name, led->dev->kobj.name, + sizeof(v4l2_sd_cfg->dev_name)); + + /* + * Init flash intensity setting: this is a linear scale + * capped from the device tree max intensity setting + * 1..flash_max_intensity + */ + s = &v4l2_sd_cfg->intensity; + s->min = 1; + s->max = rt->flash_max_intensity; + s->step = 1; + s->val = s->max; +} + +static void rt8515_v4l2_flash_release(struct rt8515 *rt) +{ + v4l2_flash_release(rt->v4l2_flash); +} + +#else +static void rt8515_init_v4l2_flash_config(struct rt8515 *rt, + struct v4l2_flash_config *v4l2_sd_cfg) +{ +} + +static void rt8515_v4l2_flash_release(struct rt8515 *rt) +{ +} +#endif + +static void rt8515_determine_max_intensity(struct rt8515 *rt, + struct fwnode_handle *led, + const char *resistance, + const char *max_ua_prop, int hw_max, + int *max_intensity_setting) +{ + u32 res = 0; /* Can't be 0 so 0 is undefined */ + u32 ua; + u32 max_ma; + int max_intensity; + int ret; + + fwnode_property_read_u32(rt->dev->fwnode, resistance, &res); + ret = fwnode_property_read_u32(led, max_ua_prop, &ua); + + /* Missing info in DT, OK go with hardware maxima */ + if (ret || res == 0) { + dev_err(rt->dev, + "either %s or %s missing from DT, using HW max\n", + resistance, max_ua_prop); + max_ma = RT8515_MAX_IOUT_MA; + max_intensity = hw_max; + goto out_assign_max; + } + + /* + * Formula from the datasheet, this is the maximum current + * defined by the hardware. + */ + max_ma = (5500 * 1000) / res; + /* + * Calculate max intensity (linear scaling) + * Formula is ((ua / 1000) / max_ma) * 100, then simplified + */ + max_intensity = (ua / 10) / max_ma; + + dev_info(rt->dev, + "current restricted from %u to %u mA, max intensity %d/100\n", + max_ma, (ua / 1000), max_intensity); + +out_assign_max: + dev_info(rt->dev, "max intensity %d/%d = %d mA\n", + max_intensity, hw_max, max_ma); + *max_intensity_setting = max_intensity; +} + +static int rt8515_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct fwnode_handle *child; + struct rt8515 *rt; + struct led_classdev *led; + struct led_classdev_flash *fled; + struct led_init_data init_data = {}; + struct v4l2_flash_config v4l2_sd_cfg = {}; + int ret; + + rt = devm_kzalloc(dev, sizeof(*rt), GFP_KERNEL); + if (!rt) + return -ENOMEM; + + rt->dev = dev; + fled = &rt->fled; + led = &fled->led_cdev; + + /* ENF - Enable Flash line */ + rt->enable_flash = devm_gpiod_get(dev, "enf", GPIOD_OUT_LOW); + if (IS_ERR(rt->enable_flash)) + return dev_err_probe(dev, PTR_ERR(rt->enable_flash), + "cannot get ENF (enable flash) GPIO\n"); + + /* ENT - Enable Torch line */ + rt->enable_torch = devm_gpiod_get(dev, "ent", GPIOD_OUT_LOW); + if (IS_ERR(rt->enable_torch)) + return dev_err_probe(dev, PTR_ERR(rt->enable_torch), + "cannot get ENT (enable torch) GPIO\n"); + + child = fwnode_get_next_available_child_node(dev->fwnode, NULL); + if (!child) { + dev_err(dev, + "No fwnode child node found for connected LED.\n"); + return -EINVAL; + } + init_data.fwnode = child; + + rt8515_determine_max_intensity(rt, child, "richtek,rfs-ohms", + "flash-max-microamp", + RT8515_FLASH_MAX, + &rt->flash_max_intensity); + rt8515_determine_max_intensity(rt, child, "richtek,rts-ohms", + "led-max-microamp", + RT8515_TORCH_MAX, + &rt->torch_max_intensity); + + ret = fwnode_property_read_u32(child, "flash-max-timeout-us", + &rt->max_timeout); + if (ret) { + rt->max_timeout = RT8515_MAX_TIMEOUT_US; + dev_warn(dev, + "flash-max-timeout-us property missing\n"); + } + timer_setup(&rt->powerdown_timer, rt8515_powerdown_timer, 0); + rt8515_init_flash_timeout(rt); + + fled->ops = &rt8515_flash_ops; + + led->max_brightness = rt->torch_max_intensity; + led->brightness_set_blocking = rt8515_led_brightness_set; + led->flags |= LED_CORE_SUSPENDRESUME | LED_DEV_CAP_FLASH; + + mutex_init(&rt->lock); + + platform_set_drvdata(pdev, rt); + + ret = devm_led_classdev_flash_register_ext(dev, fled, &init_data); + if (ret) { + dev_err(dev, "can't register LED %s\n", led->name); + mutex_destroy(&rt->lock); + return ret; + } + + rt8515_init_v4l2_flash_config(rt, &v4l2_sd_cfg); + + /* Create a V4L2 Flash device if V4L2 flash is enabled */ + rt->v4l2_flash = v4l2_flash_init(dev, child, fled, NULL, &v4l2_sd_cfg); + if (IS_ERR(rt->v4l2_flash)) { + ret = PTR_ERR(rt->v4l2_flash); + dev_err(dev, "failed to register V4L2 flash device (%d)\n", + ret); + /* + * Continue without the V4L2 flash + * (we still have the classdev) + */ + } + + return 0; +} + +static int rt8515_remove(struct platform_device *pdev) +{ + struct rt8515 *rt = platform_get_drvdata(pdev); + + rt8515_v4l2_flash_release(rt); + del_timer_sync(&rt->powerdown_timer); + mutex_destroy(&rt->lock); + + return 0; +} + +static const struct of_device_id rt8515_match[] = { + { .compatible = "richtek,rt8515", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rt8515_match); + +static struct platform_driver rt8515_driver = { + .driver = { + .name = "rt8515", + .of_match_table = rt8515_match, + }, + .probe = rt8515_probe, + .remove = rt8515_remove, +}; +module_platform_driver(rt8515_driver); + +MODULE_AUTHOR("Linus Walleij "); +MODULE_DESCRIPTION("Richtek RT8515 LED driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index 91da90cfb11d..4e7b78a84149 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -378,14 +378,15 @@ void led_trigger_event(struct led_trigger *trig, enum led_brightness brightness) { struct led_classdev *led_cdev; + unsigned long flags; if (!trig) return; - read_lock(&trig->leddev_list_lock); + read_lock_irqsave(&trig->leddev_list_lock, flags); list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) led_set_brightness(led_cdev, brightness); - read_unlock(&trig->leddev_list_lock); + read_unlock_irqrestore(&trig->leddev_list_lock, flags); } EXPORT_SYMBOL_GPL(led_trigger_event); @@ -396,11 +397,12 @@ static void led_trigger_blink_setup(struct led_trigger *trig, int invert) { struct led_classdev *led_cdev; + unsigned long flags; if (!trig) return; - read_lock(&trig->leddev_list_lock); + read_lock_irqsave(&trig->leddev_list_lock, flags); list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) { if (oneshot) led_blink_set_oneshot(led_cdev, delay_on, delay_off, @@ -408,7 +410,7 @@ static void led_trigger_blink_setup(struct led_trigger *trig, else led_blink_set(led_cdev, delay_on, delay_off); } - read_unlock(&trig->leddev_list_lock); + read_unlock_irqrestore(&trig->leddev_list_lock, flags); } void led_trigger_blink(struct led_trigger *trig, diff --git a/drivers/leds/leds-ariel.c b/drivers/leds/leds-ariel.c index bb68ba23a7d4..49e1bddaa15e 100644 --- a/drivers/leds/leds-ariel.c +++ b/drivers/leds/leds-ariel.c @@ -96,14 +96,14 @@ static int ariel_led_probe(struct platform_device *pdev) return -ENOMEM; leds[0].ec_index = EC_BLUE_LED; - leds[0].led_cdev.name = "blue:power", + leds[0].led_cdev.name = "blue:power"; leds[0].led_cdev.default_trigger = "default-on"; leds[1].ec_index = EC_AMBER_LED; - leds[1].led_cdev.name = "amber:status", + leds[1].led_cdev.name = "amber:status"; leds[2].ec_index = EC_GREEN_LED; - leds[2].led_cdev.name = "green:status", + leds[2].led_cdev.name = "green:status"; leds[2].led_cdev.default_trigger = "default-on"; for (i = 0; i < NLEDS; i++) { diff --git a/drivers/leds/leds-lm3533.c b/drivers/leds/leds-lm3533.c index b3edee703193..9dd205870525 100644 --- a/drivers/leds/leds-lm3533.c +++ b/drivers/leds/leds-lm3533.c @@ -679,7 +679,7 @@ static int lm3533_led_probe(struct platform_device *pdev) led->cdev.brightness_get = lm3533_led_get; led->cdev.blink_set = lm3533_led_blink_set; led->cdev.brightness = LED_OFF; - led->cdev.groups = lm3533_led_attribute_groups, + led->cdev.groups = lm3533_led_attribute_groups; led->id = pdev->id; mutex_init(&led->mutex); diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 51e80bc70d42..68a9ac6f2fe1 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -805,6 +805,14 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) spin_lock_irq(&rtc_lock); + /* Ensure that the RTC is accessible. Bit 0-6 must be 0! */ + if ((CMOS_READ(RTC_VALID) & 0x7f) != 0) { + spin_unlock_irq(&rtc_lock); + dev_warn(dev, "not accessible\n"); + retval = -ENXIO; + goto cleanup1; + } + if (!(flags & CMOS_RTC_FLAGS_NOFREQ)) { /* force periodic irq to CMOS reset default of 1024Hz; * diff --git a/drivers/rtc/rtc-mc146818-lib.c b/drivers/rtc/rtc-mc146818-lib.c index 972a5b9a629d..f83c13818af3 100644 --- a/drivers/rtc/rtc-mc146818-lib.c +++ b/drivers/rtc/rtc-mc146818-lib.c @@ -21,6 +21,13 @@ unsigned int mc146818_get_time(struct rtc_time *time) again: spin_lock_irqsave(&rtc_lock, flags); + /* Ensure that the RTC is accessible. Bit 0-6 must be 0! */ + if (WARN_ON_ONCE((CMOS_READ(RTC_VALID) & 0x7f) != 0)) { + spin_unlock_irqrestore(&rtc_lock, flags); + memset(time, 0xff, sizeof(*time)); + return 0; + } + /* * Check whether there is an update in progress during which the * readout is unspecified. The maximum update time is ~2ms. Poll diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 4f274f21c4ab..af64b4e6fd1f 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -324,6 +324,21 @@ pnfs_grab_inode_layout_hdr(struct pnfs_layout_hdr *lo) return NULL; } +/* + * Compare 2 layout stateid sequence ids, to see which is newer, + * taking into account wraparound issues. + */ +static bool pnfs_seqid_is_newer(u32 s1, u32 s2) +{ + return (s32)(s1 - s2) > 0; +} + +static void pnfs_barrier_update(struct pnfs_layout_hdr *lo, u32 newseq) +{ + if (pnfs_seqid_is_newer(newseq, lo->plh_barrier)) + lo->plh_barrier = newseq; +} + static void pnfs_set_plh_return_info(struct pnfs_layout_hdr *lo, enum pnfs_iomode iomode, u32 seq) @@ -335,6 +350,7 @@ pnfs_set_plh_return_info(struct pnfs_layout_hdr *lo, enum pnfs_iomode iomode, if (seq != 0) { WARN_ON_ONCE(lo->plh_return_seq != 0 && lo->plh_return_seq != seq); lo->plh_return_seq = seq; + pnfs_barrier_update(lo, seq); } } @@ -639,15 +655,6 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg, return rv; } -/* - * Compare 2 layout stateid sequence ids, to see which is newer, - * taking into account wraparound issues. - */ -static bool pnfs_seqid_is_newer(u32 s1, u32 s2) -{ - return (s32)(s1 - s2) > 0; -} - static bool pnfs_should_free_range(const struct pnfs_layout_range *lseg_range, const struct pnfs_layout_range *recall_range) @@ -984,8 +991,7 @@ pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new, new_barrier = be32_to_cpu(new->seqid); else if (new_barrier == 0) return; - if (pnfs_seqid_is_newer(new_barrier, lo->plh_barrier)) - lo->plh_barrier = new_barrier; + pnfs_barrier_update(lo, new_barrier); } static bool @@ -994,7 +1000,7 @@ pnfs_layout_stateid_blocked(const struct pnfs_layout_hdr *lo, { u32 seqid = be32_to_cpu(stateid->seqid); - return !pnfs_seqid_is_newer(seqid, lo->plh_barrier); + return !pnfs_seqid_is_newer(seqid, lo->plh_barrier) && lo->plh_barrier; } /* lget is set to 1 if called from inside send_layoutget call chain */ @@ -1183,20 +1189,17 @@ pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo, return false; set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags); pnfs_get_layout_hdr(lo); + nfs4_stateid_copy(stateid, &lo->plh_stateid); + *cred = get_cred(lo->plh_lc_cred); if (test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags)) { - nfs4_stateid_copy(stateid, &lo->plh_stateid); - *cred = get_cred(lo->plh_lc_cred); if (lo->plh_return_seq != 0) stateid->seqid = cpu_to_be32(lo->plh_return_seq); if (iomode != NULL) *iomode = lo->plh_return_iomode; pnfs_clear_layoutreturn_info(lo); - return true; - } - nfs4_stateid_copy(stateid, &lo->plh_stateid); - *cred = get_cred(lo->plh_lc_cred); - if (iomode != NULL) + } else if (iomode != NULL) *iomode = IOMODE_ANY; + pnfs_barrier_update(lo, be32_to_cpu(stateid->seqid)); return true; } @@ -1909,6 +1912,11 @@ static void nfs_layoutget_end(struct pnfs_layout_hdr *lo) wake_up_var(&lo->plh_outstanding); } +static bool pnfs_is_first_layoutget(struct pnfs_layout_hdr *lo) +{ + return test_bit(NFS_LAYOUT_FIRST_LAYOUTGET, &lo->plh_flags); +} + static void pnfs_clear_first_layoutget(struct pnfs_layout_hdr *lo) { unsigned long *bitlock = &lo->plh_flags; @@ -2383,23 +2391,34 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) goto out_forget; } - if (!pnfs_layout_is_valid(lo)) { - /* We have a completely new layout */ - pnfs_set_layout_stateid(lo, &res->stateid, lgp->cred, true); - } else if (nfs4_stateid_match_other(&lo->plh_stateid, &res->stateid)) { + if (nfs4_stateid_match_other(&lo->plh_stateid, &res->stateid)) { /* existing state ID, make sure the sequence number matches. */ if (pnfs_layout_stateid_blocked(lo, &res->stateid)) { + if (!pnfs_layout_is_valid(lo) && + pnfs_is_first_layoutget(lo)) + lo->plh_barrier = 0; dprintk("%s forget reply due to sequence\n", __func__); goto out_forget; } pnfs_set_layout_stateid(lo, &res->stateid, lgp->cred, false); - } else { + } else if (pnfs_layout_is_valid(lo)) { /* * We got an entirely new state ID. Mark all segments for the * inode invalid, and retry the layoutget */ - pnfs_mark_layout_stateid_invalid(lo, &free_me); + struct pnfs_layout_range range = { + .iomode = IOMODE_ANY, + .length = NFS4_MAX_UINT64, + }; + pnfs_set_plh_return_info(lo, IOMODE_ANY, 0); + pnfs_mark_matching_lsegs_return(lo, &lo->plh_return_segs, + &range, 0); goto out_forget; + } else { + /* We have a completely new layout */ + if (!pnfs_is_first_layoutget(lo)) + goto out_forget; + pnfs_set_layout_stateid(lo, &res->stateid, lgp->cred, true); } pnfs_get_lseg(lseg); diff --git a/include/linux/linkage.h b/include/linux/linkage.h index 5bcfbd972e97..dbf8506decca 100644 --- a/include/linux/linkage.h +++ b/include/linux/linkage.h @@ -178,6 +178,11 @@ * Objtool generates debug info for both FUNC & CODE, but needs special * annotations for each CODE's start (to describe the actual stack frame). * + * Objtool requires that all code must be contained in an ELF symbol. Symbol + * names that have a .L prefix do not emit symbol table entries. .L + * prefixed symbols can be used within a code region, but should be avoided for + * denoting a range of code via ``SYM_*_START/END`` annotations. + * * ALIAS -- does not generate debug info -- the aliased function will */ diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index 19b6dea27367..b26213ae8c1a 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -25,8 +25,7 @@ struct rpc_rqst; #define XDR_QUADLEN(l) (((l) + 3) >> 2) /* - * Generic opaque `network object.' At the kernel level, this type - * is used only by lockd. + * Generic opaque `network object.' */ #define XDR_MAX_NETOBJ 1024 struct xdr_netobj { diff --git a/kernel/entry/common.c b/kernel/entry/common.c index 378341642f94..6dd82be60df8 100644 --- a/kernel/entry/common.c +++ b/kernel/entry/common.c @@ -222,7 +222,7 @@ static inline bool report_single_step(unsigned long work) */ static inline bool report_single_step(unsigned long work) { - if (!(work & SYSCALL_WORK_SYSCALL_EMU)) + if (work & SYSCALL_WORK_SYSCALL_EMU) return false; return !!(current_thread_info()->flags & _TIF_SINGLESTEP); diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 4ecc2a959567..5f42aa5fc612 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -29,6 +29,7 @@ #include #include +#include "auth_gss_internal.h" #include "../netns.h" #include @@ -125,35 +126,6 @@ gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags); } -static const void * -simple_get_bytes(const void *p, const void *end, void *res, size_t len) -{ - const void *q = (const void *)((const char *)p + len); - if (unlikely(q > end || q < p)) - return ERR_PTR(-EFAULT); - memcpy(res, p, len); - return q; -} - -static inline const void * -simple_get_netobj(const void *p, const void *end, struct xdr_netobj *dest) -{ - const void *q; - unsigned int len; - - p = simple_get_bytes(p, end, &len, sizeof(len)); - if (IS_ERR(p)) - return p; - q = (const void *)((const char *)p + len); - if (unlikely(q > end || q < p)) - return ERR_PTR(-EFAULT); - dest->data = kmemdup(p, len, GFP_NOFS); - if (unlikely(dest->data == NULL)) - return ERR_PTR(-ENOMEM); - dest->len = len; - return q; -} - static struct gss_cl_ctx * gss_cred_get_ctx(struct rpc_cred *cred) { diff --git a/net/sunrpc/auth_gss/auth_gss_internal.h b/net/sunrpc/auth_gss/auth_gss_internal.h new file mode 100644 index 000000000000..f6d9631bd9d0 --- /dev/null +++ b/net/sunrpc/auth_gss/auth_gss_internal.h @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * linux/net/sunrpc/auth_gss/auth_gss_internal.h + * + * Internal definitions for RPCSEC_GSS client authentication + * + * Copyright (c) 2000 The Regents of the University of Michigan. + * All rights reserved. + * + */ +#include +#include +#include + +static inline const void * +simple_get_bytes(const void *p, const void *end, void *res, size_t len) +{ + const void *q = (const void *)((const char *)p + len); + if (unlikely(q > end || q < p)) + return ERR_PTR(-EFAULT); + memcpy(res, p, len); + return q; +} + +static inline const void * +simple_get_netobj(const void *p, const void *end, struct xdr_netobj *dest) +{ + const void *q; + unsigned int len; + + p = simple_get_bytes(p, end, &len, sizeof(len)); + if (IS_ERR(p)) + return p; + q = (const void *)((const char *)p + len); + if (unlikely(q > end || q < p)) + return ERR_PTR(-EFAULT); + if (len) { + dest->data = kmemdup(p, len, GFP_NOFS); + if (unlikely(dest->data == NULL)) + return ERR_PTR(-ENOMEM); + } else + dest->data = NULL; + dest->len = len; + return q; +} diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index ae9acf3a7389..1c092b05c2bb 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -21,6 +21,8 @@ #include #include +#include "auth_gss_internal.h" + #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) # define RPCDBG_FACILITY RPCDBG_AUTH #endif @@ -143,35 +145,6 @@ get_gss_krb5_enctype(int etype) return NULL; } -static const void * -simple_get_bytes(const void *p, const void *end, void *res, int len) -{ - const void *q = (const void *)((const char *)p + len); - if (unlikely(q > end || q < p)) - return ERR_PTR(-EFAULT); - memcpy(res, p, len); - return q; -} - -static const void * -simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res) -{ - const void *q; - unsigned int len; - - p = simple_get_bytes(p, end, &len, sizeof(len)); - if (IS_ERR(p)) - return p; - q = (const void *)((const char *)p + len); - if (unlikely(q > end || q < p)) - return ERR_PTR(-EFAULT); - res->data = kmemdup(p, len, GFP_NOFS); - if (unlikely(res->data == NULL)) - return ERR_PTR(-ENOMEM); - res->len = len; - return q; -} - static inline const void * get_key(const void *p, const void *end, struct krb5_ctx *ctx, struct crypto_sync_skcipher **res)