From ce0929d222f8cb18a66611642dc0661d633ce192 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 10 Nov 2017 15:40:32 +0200 Subject: gpiolib: acpi: Add quirks field to struct acpi_gpio_mapping Some broken ACPI tables might require quirks in the OS. Introduce quirks field in struct acpi_gpio_mapping. Propagate them to struct acpi_gpio_info for further use. Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Signed-off-by: Linus Walleij --- include/linux/acpi.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux/acpi.h') diff --git a/include/linux/acpi.h b/include/linux/acpi.h index dc1ebfeeb5ec..25fe77fccea0 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -978,6 +978,7 @@ struct acpi_gpio_mapping { const char *name; const struct acpi_gpio_params *data; unsigned int size; + unsigned int quirks; }; #if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB) -- cgit v1.2.3 From 1b2ca32ab0b8311da84fe692522266b32ad4315e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 10 Nov 2017 15:40:33 +0200 Subject: gpiolib: acpi: Introduce NO_RESTRICTION quirk Allow to relax IoRestriction for certain cases. One of the use case is incorrectly cooked ACPI table where interrupt pin is defined with GpioIo() macro with IoRestrictionOutputOnly. Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 13 ++++++++++--- include/linux/acpi.h | 4 ++++ 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'include/linux/acpi.h') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 711f64b9dd30..430a1475212d 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -496,11 +496,18 @@ int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info) { struct device *dev = &info->adev->dev; + enum gpiod_flags old = *flags; int ret; - ret = __acpi_gpio_update_gpiod_flags(flags, info->flags); - if (ret) - dev_dbg(dev, "Override GPIO initialization flags\n"); + ret = __acpi_gpio_update_gpiod_flags(&old, info->flags); + if (info->quirks & ACPI_GPIO_QUIRK_NO_IO_RESTRICTION) { + if (ret) + dev_warn(dev, FW_BUG "GPIO not in correct mode, fixing\n"); + } else { + if (ret) + dev_dbg(dev, "Override GPIO initialization flags\n"); + *flags = old; + } return ret; } diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 25fe77fccea0..06b6eb775115 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -978,6 +978,10 @@ struct acpi_gpio_mapping { const char *name; const struct acpi_gpio_params *data; unsigned int size; + +/* Ignore IoRestriction field */ +#define ACPI_GPIO_QUIRK_NO_IO_RESTRICTION BIT(0) + unsigned int quirks; }; -- cgit v1.2.3 From 80212a162329e590fde02d8457af16ea0ab0a55f Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Wed, 13 Dec 2017 02:20:48 -0500 Subject: ACPI / bus: Introduce acpi_get_match_data() function OF has of_device_get_match_data() function to extract driver specific data structure. Add a similar function for ACPI. Signed-off-by: Sinan Kaya Acked-by: Rafael J. Wysocki Signed-off-by: Vinod Koul --- drivers/acpi/bus.c | 18 ++++++++++++++++++ include/linux/acpi.h | 6 ++++++ 2 files changed, 24 insertions(+) (limited to 'include/linux/acpi.h') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 4d0979e02a28..f87ed3be779a 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -785,6 +785,24 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, } EXPORT_SYMBOL_GPL(acpi_match_device); +void *acpi_get_match_data(const struct device *dev) +{ + const struct acpi_device_id *match; + + if (!dev->driver) + return NULL; + + if (!dev->driver->acpi_match_table) + return NULL; + + match = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!match) + return NULL; + + return (void *)match->driver_data; +} +EXPORT_SYMBOL_GPL(acpi_get_match_data); + int acpi_match_device_ids(struct acpi_device *device, const struct acpi_device_id *ids) { diff --git a/include/linux/acpi.h b/include/linux/acpi.h index dc1ebfeeb5ec..927873751323 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -584,6 +584,7 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *), const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, const struct device *dev); +void *acpi_get_match_data(const struct device *dev); extern bool acpi_driver_match_device(struct device *dev, const struct device_driver *drv); int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *); @@ -755,6 +756,11 @@ static inline const struct acpi_device_id *acpi_match_device( return NULL; } +static inline void *acpi_get_match_data(const struct device *dev) +{ + return NULL; +} + static inline bool acpi_driver_match_device(struct device *dev, const struct device_driver *drv) { -- cgit v1.2.3 From 7c6c57f2ab2c5113844fe187a7c45c4bd76dc671 Mon Sep 17 00:00:00 2001 From: Marcin Wojtas Date: Thu, 18 Jan 2018 13:31:40 +0100 Subject: device property: Introduce fwnode_irq_get() Until now there were two very similar functions allowing to get Linux IRQ number from ACPI handle (acpi_irq_get()) and OF node (of_irq_get()). The first one appeared to be used only as a subroutine of platform_irq_get(), which (in the generic code) limited IRQ obtaining from _CRS method only to nodes associated to kernel's struct platform_device. This patch introduces a new helper routine - fwnode_irq_get(), which allows to get the IRQ number directly from the fwnode to be used as common for OF/ACPI worlds. It is usable not only for the parents fwnodes, but also for the child nodes comprising their own _CRS methods with interrupts description. In order to be able o satisfy compilation with !CONFIG_ACPI and also simplify the new code, introduce a helper macro (ACPI_HANDLE_FWNODE), with which it is possible to reach an ACPI handle directly from its fwnode. Signed-off-by: Marcin Wojtas Signed-off-by: David S. Miller --- drivers/base/property.c | 26 ++++++++++++++++++++++++++ include/linux/acpi.h | 3 +++ include/linux/property.h | 2 ++ 3 files changed, 31 insertions(+) (limited to 'include/linux/acpi.h') diff --git a/drivers/base/property.c b/drivers/base/property.c index 7c4a53d20e6d..1d6c9d99d72f 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -1229,6 +1230,31 @@ void *device_get_mac_address(struct device *dev, char *addr, int alen) } EXPORT_SYMBOL(device_get_mac_address); +/** + * fwnode_irq_get - Get IRQ directly from a fwnode + * @fwnode: Pointer to the firmware node + * @index: Zero-based index of the IRQ + * + * Returns Linux IRQ number on success. Other values are determined + * accordingly to acpi_/of_ irq_get() operation. + */ +int fwnode_irq_get(struct fwnode_handle *fwnode, unsigned int index) +{ + struct device_node *of_node = to_of_node(fwnode); + struct resource res; + int ret; + + if (IS_ENABLED(CONFIG_OF) && of_node) + return of_irq_get(of_node, index); + + ret = acpi_irq_get(ACPI_HANDLE_FWNODE(fwnode), index, &res); + if (ret) + return ret; + + return res.start; +} +EXPORT_SYMBOL(fwnode_irq_get); + /** * device_graph_get_next_endpoint - Get next endpoint firmware node * @fwnode: Pointer to the parent firmware node diff --git a/include/linux/acpi.h b/include/linux/acpi.h index dc1ebfeeb5ec..f05b9b6cd43f 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -56,6 +56,8 @@ static inline acpi_handle acpi_device_handle(struct acpi_device *adev) #define ACPI_COMPANION_SET(dev, adev) set_primary_fwnode(dev, (adev) ? \ acpi_fwnode_handle(adev) : NULL) #define ACPI_HANDLE(dev) acpi_device_handle(ACPI_COMPANION(dev)) +#define ACPI_HANDLE_FWNODE(fwnode) \ + acpi_device_handle(to_acpi_device_node(fwnode)) static inline struct fwnode_handle *acpi_alloc_fwnode_static(void) { @@ -626,6 +628,7 @@ int acpi_arch_timer_mem_init(struct arch_timer_mem *timer_mem, int *timer_count) #define ACPI_COMPANION(dev) (NULL) #define ACPI_COMPANION_SET(dev, adev) do { } while (0) #define ACPI_HANDLE(dev) (NULL) +#define ACPI_HANDLE_FWNODE(fwnode) (NULL) #define ACPI_DEVICE_CLASS(_cls, _msk) .cls = (0), .cls_msk = (0), struct fwnode_handle; diff --git a/include/linux/property.h b/include/linux/property.h index 9b133320072f..e05889fdbb14 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -103,6 +103,8 @@ struct fwnode_handle *device_get_named_child_node(struct device *dev, struct fwnode_handle *fwnode_handle_get(struct fwnode_handle *fwnode); void fwnode_handle_put(struct fwnode_handle *fwnode); +int fwnode_irq_get(struct fwnode_handle *fwnode, unsigned int index); + unsigned int device_get_child_node_count(struct device *dev); static inline bool device_property_read_bool(struct device *dev, -- cgit v1.2.3 From 0231d00082f61cfe03f2b7c27e5356f8cdf0312c Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Thu, 18 Jan 2018 10:09:51 -0500 Subject: ACPI: SPCR: Make SPCR available to x86 SPCR is currently only enabled or ARM64 and x86 can use SPCR to setup an early console. General fixes include updating Documentation & Kconfig (for x86), updating comments, and changing parse_spcr() to acpi_parse_spcr(), and earlycon_init_is_deferred to earlycon_acpi_spcr_enable to be more descriptive. On x86, many systems have a valid SPCR table but the table version is not 2 so the table version check must be a warning. On ARM64 when the kernel parameter earlycon is used both the early console and console are enabled. On x86, only the earlycon should be enabled by by default. Modify acpi_parse_spcr() to allow options for initializing the early console and console separately. Signed-off-by: Prarit Bhargava Acked-by: Ingo Molnar Reviewed-by: Mark Salter Tested-by: Mark Salter Signed-off-by: Rafael J. Wysocki --- Documentation/admin-guide/kernel-parameters.txt | 9 +++++--- arch/arm64/kernel/acpi.c | 4 ++-- arch/x86/kernel/acpi/boot.c | 3 +++ drivers/acpi/Kconfig | 7 +++++- drivers/acpi/spcr.c | 29 +++++++++++++------------ drivers/tty/serial/earlycon.c | 15 +++++-------- include/linux/acpi.h | 7 ++++-- include/linux/serial_core.h | 4 ++-- 8 files changed, 44 insertions(+), 34 deletions(-) (limited to 'include/linux/acpi.h') diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 1bdcf572c2ac..aecb1c8ef675 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -917,9 +917,12 @@ earlycon= [KNL] Output early console device and options. - When used with no options, the early console is - determined by the stdout-path property in device - tree's chosen node. + [ARM64] The early console is determined by the + stdout-path property in device tree's chosen node, + or determined by the ACPI SPCR table. + + [X86] When used with no options the early console is + determined by the ACPI SPCR table. cdns,[,options] Start an early, polled-mode console on a Cadence diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index b3162715ed78..2aa5609def27 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -230,10 +230,10 @@ void __init acpi_boot_table_init(void) done: if (acpi_disabled) { - if (earlycon_init_is_deferred) + if (earlycon_acpi_spcr_enable) early_init_dt_scan_chosen_stdout(); } else { - parse_spcr(earlycon_init_is_deferred); + acpi_parse_spcr(earlycon_acpi_spcr_enable, true); if (IS_ENABLED(CONFIG_ACPI_BGRT)) acpi_table_parse(ACPI_SIG_BGRT, acpi_parse_bgrt); } diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index ec3a286163c3..2aa92094b59d 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -1625,6 +1626,8 @@ int __init acpi_boot_init(void) if (!acpi_noirq) x86_init.pci.init = pci_acpi_init; + /* Do not enable ACPI SPCR console by default */ + acpi_parse_spcr(earlycon_acpi_spcr_enable, false); return 0; } diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 46505396869e..ddcb5f40e8ee 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -79,7 +79,12 @@ config ACPI_DEBUGGER_USER endif config ACPI_SPCR_TABLE - bool + bool "ACPI Serial Port Console Redirection Support" + default y if X86 + help + Enable support for Serial Port Console Redirection (SPCR) Table. + This table provides information about the configuration of the + earlycon console. config ACPI_LPIT bool diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c index 324b35bfe781..89e97d21a89c 100644 --- a/drivers/acpi/spcr.c +++ b/drivers/acpi/spcr.c @@ -21,7 +21,7 @@ * occasionally getting stuck as 1. To avoid the potential for a hang, check * TXFE == 0 instead of BUSY == 1. This may not be suitable for all UART * implementations, so only do so if an affected platform is detected in - * parse_spcr(). + * acpi_parse_spcr(). */ bool qdf2400_e44_present; EXPORT_SYMBOL(qdf2400_e44_present); @@ -74,19 +74,21 @@ static bool xgene_8250_erratum_present(struct acpi_table_spcr *tb) } /** - * parse_spcr() - parse ACPI SPCR table and add preferred console + * acpi_parse_spcr() - parse ACPI SPCR table and add preferred console * - * @earlycon: set up earlycon for the console specified by the table + * @enable_earlycon: set up earlycon for the console specified by the table + * @enable_console: setup the console specified by the table. * * For the architectures with support for ACPI, CONFIG_ACPI_SPCR_TABLE may be * defined to parse ACPI SPCR table. As a result of the parsing preferred - * console is registered and if @earlycon is true, earlycon is set up. + * console is registered and if @enable_earlycon is true, earlycon is set up. + * If @enable_console is true the system console is also configured. * * When CONFIG_ACPI_SPCR_TABLE is defined, this function should be called * from arch initialization code as soon as the DT/ACPI decision is made. * */ -int __init parse_spcr(bool earlycon) +int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console) { static char opts[64]; struct acpi_table_spcr *table; @@ -105,11 +107,8 @@ int __init parse_spcr(bool earlycon) if (ACPI_FAILURE(status)) return -ENOENT; - if (table->header.revision < 2) { - err = -ENOENT; - pr_err("wrong table version\n"); - goto done; - } + if (table->header.revision < 2) + pr_info("SPCR table version %d\n", table->header.revision); if (table->serial_port.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { switch (ACPI_ACCESS_BIT_WIDTH(( @@ -185,7 +184,7 @@ int __init parse_spcr(bool earlycon) */ if (qdf2400_erratum_44_present(&table->header)) { qdf2400_e44_present = true; - if (earlycon) + if (enable_earlycon) uart = "qdf2400_e44"; } @@ -205,11 +204,13 @@ int __init parse_spcr(bool earlycon) pr_info("console: %s\n", opts); - if (earlycon) + if (enable_earlycon) setup_earlycon(opts); - err = add_preferred_console(uart, 0, opts + strlen(uart) + 1); - + if (enable_console) + err = add_preferred_console(uart, 0, opts + strlen(uart) + 1); + else + err = 0; done: acpi_put_table((struct acpi_table_header *)table); return err; diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 4c8b80f1c688..870e84fb6e39 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -197,25 +197,20 @@ int __init setup_earlycon(char *buf) } /* - * When CONFIG_ACPI_SPCR_TABLE is defined, "earlycon" without parameters in - * command line does not start DT earlycon immediately, instead it defers - * starting it until DT/ACPI decision is made. At that time if ACPI is enabled - * call parse_spcr(), else call early_init_dt_scan_chosen_stdout() + * This defers the initialization of the early console until after ACPI has + * been initialized. */ -bool earlycon_init_is_deferred __initdata; +bool earlycon_acpi_spcr_enable __initdata; /* early_param wrapper for setup_earlycon() */ static int __init param_setup_earlycon(char *buf) { int err; - /* - * Just 'earlycon' is a valid param for devicetree earlycons; - * don't generate a warning from parse_early_params() in that case - */ + /* Just 'earlycon' is a valid param for devicetree and ACPI SPCR. */ if (!buf || !buf[0]) { if (IS_ENABLED(CONFIG_ACPI_SPCR_TABLE)) { - earlycon_init_is_deferred = true; + earlycon_acpi_spcr_enable = true; return 0; } else if (!buf) { return early_init_dt_scan_chosen_stdout(); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index b8f4c3c776e5..e6b98a32495f 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -1249,9 +1249,12 @@ static inline bool acpi_has_watchdog(void) { return false; } #ifdef CONFIG_ACPI_SPCR_TABLE extern bool qdf2400_e44_present; -int parse_spcr(bool earlycon); +int acpi_parse_spcr(bool enable_earlycon, bool enable_console); #else -static inline int parse_spcr(bool earlycon) { return 0; } +static inline int acpi_parse_spcr(bool enable_earlycon, bool enable_console) +{ + return 0; +} #endif #if IS_ENABLED(CONFIG_ACPI_GENERIC_GSI) diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 37b044e78333..aefd0e5115da 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -376,10 +376,10 @@ extern int of_setup_earlycon(const struct earlycon_id *match, const char *options); #ifdef CONFIG_SERIAL_EARLYCON -extern bool earlycon_init_is_deferred __initdata; +extern bool earlycon_acpi_spcr_enable __initdata; int setup_earlycon(char *buf); #else -static const bool earlycon_init_is_deferred; +static const bool earlycon_acpi_spcr_enable; static inline int setup_earlycon(char *buf) { return 0; } #endif -- cgit v1.2.3